summaryrefslogtreecommitdiff
path: root/src/compiler/scala/tools/nsc/typechecker/Typers.scala
diff options
context:
space:
mode:
Diffstat (limited to 'src/compiler/scala/tools/nsc/typechecker/Typers.scala')
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Typers.scala85
1 files changed, 38 insertions, 47 deletions
diff --git a/src/compiler/scala/tools/nsc/typechecker/Typers.scala b/src/compiler/scala/tools/nsc/typechecker/Typers.scala
index a2aca45e8f..757107a9b6 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Typers.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Typers.scala
@@ -3926,54 +3926,45 @@ trait Typers extends Modes with Adaptations with Tags {
*
*/
def mkInvoke(cxTree: Tree, tree: Tree, qual: Tree, name: Name): Option[Tree] = {
- debuglog(s"mkInvoke($cxTree, $tree, $qual, $name)")
+ log(s"dyna.mkInvoke($cxTree, $tree, $qual, $name)")
+ val treeSelection = treeInfo.methPart(tree)
+ def isDesugaredApply = treeSelection match {
+ case Select(`qual`, nme.apply) => true
+ case _ => false
+ }
acceptsApplyDynamicWithType(qual, name) map { tp =>
- // tp eq NoType => can call xxxDynamic, but not passing any type args (unless specified explicitly by the user)
- // in scala-virtualized, when not NoType, tp is passed as type argument (for selection on a staged Struct)
-
- // strip off type application -- we're not doing much with outer,
- // so don't bother preserving cxTree's attributes etc
- val cxTree1 = cxTree match {
- case t: ValOrDefDef => t.rhs
- case t => t
- }
- val cxTree2 = cxTree1 match {
- case Typed(t, tpe) => t // ignore outer type annotation
- case t => t
- }
- val (outer, explicitTargs) = cxTree2 match {
- case TypeApply(fun, targs) => (fun, targs)
- case Apply(TypeApply(fun, targs), args) => (Apply(fun, args), targs)
- case Select(TypeApply(fun, targs), nme) => (Select(fun, nme), targs)
- case t => (t, Nil)
- }
- def hasNamedArg(as: List[Tree]) = as.collectFirst{case AssignOrNamedArg(lhs, rhs) =>}.nonEmpty
-
- def desugaredApply = tree match {
- case Select(`qual`, nme.apply) => true
- case _ => false
+ // If tp == NoType, pass only explicit type arguments to applyXXX. Not used at all
+ // here - it is for scala-virtualized, where tp will be passed as an argument (for
+ // selection on a staged Struct)
+ def hasNamed(args: List[Tree]): Boolean = args exists (_.isInstanceOf[AssignOrNamedArg])
+ // not supported: foo.bar(a1,..., an: _*)
+ def hasStar(args: List[Tree]) = treeInfo.isWildcardStarArgList(args)
+ def applyOp(args: List[Tree]) = if (hasNamed(args)) nme.applyDynamicNamed else nme.applyDynamic
+ def matches(t: Tree) = isDesugaredApply || treeInfo.methPart(t) == treeSelection
+
+ /** Note that the trees which arrive here are potentially some distance from
+ * the trees of direct interest. `cxTree` is some enclosing expression which
+ * may apparently be arbitrarily larger than `tree`; and `tree` itself is
+ * too small, having at least in some cases lost its explicit type parameters.
+ * This logic is designed to use `tree` to pinpoint the immediately surrounding
+ * Apply/TypeApply/Select node, and only then creates the dynamic call.
+ * See SI-6731 among others.
+ */
+ def findSelection(t: Tree): Option[(TermName, Tree)] = t match {
+ case Apply(fn, args) if hasStar(args) => DynamicVarArgUnsupported(tree, applyOp(args)) ; None
+ case Apply(fn, args) if matches(fn) => Some((applyOp(args), fn))
+ case Assign(lhs, _) if matches(lhs) => Some((nme.updateDynamic, lhs))
+ case _ if matches(t) => Some((nme.selectDynamic, t))
+ case _ => t.children flatMap findSelection headOption
}
- // note: context.tree includes at most one Apply node
- // thus, we can't use it to detect we're going to receive named args in expressions such as:
- // qual.sel(a)(a2, arg2 = "a2")
- val oper = outer match {
- case Apply(q, as) if q == tree || desugaredApply =>
- val oper =
- if (hasNamedArg(as)) nme.applyDynamicNamed
- else nme.applyDynamic
- // not supported: foo.bar(a1,..., an: _*)
- if (treeInfo.isWildcardStarArgList(as)) {
- DynamicVarArgUnsupported(tree, oper)
- return Some(setError(tree))
- } else oper
- case Assign(`tree`, _) => nme.updateDynamic
- case _ => nme.selectDynamic
+ findSelection(cxTree) match {
+ case Some((opName, tapply)) =>
+ val targs = treeInfo.typeArguments(tapply)
+ val fun = gen.mkTypeApply(Select(qual, opName), targs)
+ atPos(qual.pos)(Apply(fun, Literal(Constant(name.decode)) :: Nil))
+ case _ =>
+ setError(tree)
}
-
- val dynSel = Select(qual, oper)
- val tappSel = if (explicitTargs.nonEmpty) TypeApply(dynSel, explicitTargs) else dynSel
-
- atPos(qual.pos)(Apply(tappSel, List(Literal(Constant(name.decode)))))
}
}
@@ -3981,7 +3972,7 @@ trait Typers extends Modes with Adaptations with Tags {
silent(typeTree) match {
case SilentResultValue(r) => r
case SilentTypeError(err) => DynamicRewriteError(tree, err)
- }
+ }
}
}
@@ -5375,7 +5366,7 @@ trait Typers extends Modes with Adaptations with Tags {
case tt @ TypeTree() => tree setOriginal tt.original
case _ => tree
}
- }
+ }
else
// we should get here only when something before failed
// and we try again (@see tryTypedApply). In that case we can assign