@@ -35,7 +35,7 @@ object Dynamic {
3535 * The first matching rule of is applied.
3636 *
3737 * 2. Translates member selections on structural types to calls of `selectDynamic`
38- * or `selectDynamicMethod ` on a `Selectable` instance. @See handleStructural.
38+ * or `applyDynamic ` on a `Selectable` instance. @See handleStructural.
3939 *
4040 */
4141trait Dynamic { self : Typer with Applications =>
@@ -113,53 +113,65 @@ trait Dynamic { self: Typer with Applications =>
113113 }
114114
115115 /** Handle reflection-based dispatch for members of structural types.
116- * Given `x.a`, where `x` is of (widened) type `T` and `x.a` is of type `U`:
117116 *
118- * If `U` is a value type, map `x.a` to the equivalent of:
117+ * Given `x.a`, where `x` is of (widened) type `T` (a value type or a nullary method type),
118+ * and `x.a` is of type `U`, map `x.a` to the equivalent of:
119119 *
120- * (x: Selectable).selectDynamic("a").asInstanceOf[U]
120+ * (x: Selectable).selectDynamic("a").asInstanceOf[U]
121121 *
122- * If `U` is a method type (T1,...,Tn)R, map `x.a` to the equivalent of:
122+ * Given `x.a(arg1, ..., argn)`, where `x.a` is of (widened) type (T1, ..., Tn)R,
123+ * map `x.a(arg1, ..., argn)` to the equivalent of:
123124 *
124- * (x: Selectable).selectDynamicMethod ("a", CT1, ..., CTn).asInstanceOf[(T1, ...,Tn) => R]
125+ * (x:selectable).applyDynamic ("a", CT1, ..., CTn)(arg1, ..., argn).asInstanceOf[ R]
125126 *
126- * where CT1,...,CTn are the class tags representing the erasure of T1,...,Tn.
127+ * where CT1, ..., CTn are the class tags representing the erasure of T1, ..., Tn.
127128 *
128129 * It's an error if U is neither a value nor a method type, or a dependent method
129- * type, or of too large arity (limit is Definitions.MaxStructuralMethodArity) .
130+ * type.
130131 */
131132 def handleStructural (tree : Tree )(implicit ctx : Context ): Tree = {
132- val Select (qual, name) = tree
133133
134- def structuralCall (selectorName : TermName , formals : List [Tree ]) = {
134+ def structuralCall (qual : Tree , name : Name , selectorName : TermName , ctags : List [Tree ], args : Option [ List [ Tree ] ]) = {
135135 val selectable = adapt(qual, defn.SelectableType )
136- val scall = untpd.Apply (
137- untpd.TypedSplice (selectable.select(selectorName)).withPos(tree.pos),
138- (Literal (Constant (name.toString)) :: formals).map(untpd.TypedSplice (_)))
136+
137+ // ($qual: Selectable).$selectorName("$name", ..$ctags)
138+ val base =
139+ untpd.Apply (
140+ untpd.TypedSplice (selectable.select(selectorName)).withPos(tree.pos),
141+ (Literal (Constant (name.toString)) :: ctags).map(untpd.TypedSplice (_)))
142+
143+ val scall = args match {
144+ case None => base
145+ case Some (args) => untpd.Apply (base, args)
146+ }
147+
139148 typed(scall)
140149 }
141150
142- def fail (reason : String ) =
151+ def fail (name : Name , reason : String ) =
143152 errorTree(tree, em " Structural access not allowed on method $name because it $reason" )
144153
145- tree.tpe.widen match {
146- case tpe : MethodType =>
147- if (tpe.isParamDependent)
148- fail(i " has a method type with inter-parameter dependencies " )
149- else if (tpe.paramNames.length > Definitions .MaxStructuralMethodArity )
150- fail(i """ takes too many parameters.
151- |Structural types only support methods taking up to ${Definitions .MaxStructuralMethodArity } arguments """ )
154+ val tpe = tree.tpe.widen
155+ tree match {
156+ case Apply (fun @ Select (qual, name), args) =>
157+ val funTpe = fun.tpe.widen.asInstanceOf [MethodType ]
158+ if (funTpe.isParamDependent)
159+ fail(name, i " has a method type with inter-parameter dependencies " )
152160 else {
153- val ctags = tpe .paramInfos.map(pt =>
161+ val ctags = funTpe .paramInfos.map(pt =>
154162 implicitArgTree(defn.ClassTagType .appliedTo(pt :: Nil ), tree.pos.endPos))
155- structuralCall(nme.selectDynamicMethod , ctags) .asInstance(tpe.toFunctionType() )
163+ structuralCall(qual, name, nme.applyDynamic , ctags, Some (args)) .asInstance(tpe.resultType )
156164 }
157- case tpe : ValueType =>
158- structuralCall(nme.selectDynamic, Nil ).asInstance(tpe)
159- case tpe : PolyType =>
160- fail(" is polymorphic" )
161- case tpe =>
162- fail(i " has an unsupported type: $tpe" )
165+ case Select (qual, name) if tpe.isValueType =>
166+ structuralCall(qual, name, nme.selectDynamic, Nil , None ).asInstance(tpe)
167+ case Select (_, _) if ! tpe.isParameterless =>
168+ // We return the tree unchanged; The structural call will be handled when we take care of the
169+ // enclosing application.
170+ tree
171+ case Select (_, name) if tpe.isInstanceOf [PolyType ] =>
172+ fail(name, " is polymorphic" )
173+ case Select (_, name) =>
174+ fail(name, i " has an unsupported type: ${tree.tpe.widen}" )
163175 }
164176 }
165177}
0 commit comments