summaryrefslogtreecommitdiff
path: root/src/compiler/scala
diff options
context:
space:
mode:
Diffstat (limited to 'src/compiler/scala')
-rw-r--r--src/compiler/scala/reflect/reify/Errors.scala8
-rw-r--r--src/compiler/scala/tools/nsc/ast/Trees.scala2
-rw-r--r--src/compiler/scala/tools/nsc/ast/parser/Parsers.scala2
-rw-r--r--src/compiler/scala/tools/nsc/transform/Erasure.scala40
-rw-r--r--src/compiler/scala/tools/nsc/transform/UnCurry.scala2
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/ContextErrors.scala28
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Implicits.scala16
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Macros.scala13
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/PatternMatching.scala6
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/RefChecks.scala4
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/SuperAccessors.scala4
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/TreeCheckers.scala8
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Typers.scala83
13 files changed, 104 insertions, 112 deletions
diff --git a/src/compiler/scala/reflect/reify/Errors.scala b/src/compiler/scala/reflect/reify/Errors.scala
index 0ff098e1da..3a68794c97 100644
--- a/src/compiler/scala/reflect/reify/Errors.scala
+++ b/src/compiler/scala/reflect/reify/Errors.scala
@@ -27,10 +27,10 @@ trait Errors {
}
def CannotConvertManifestToTagWithoutScalaReflect(tpe: Type, manifestInScope: Tree) = {
- val msg = s"""
- |to create a type tag here, it is necessary to interoperate with the manifest `$manifestInScope` in scope.
- |however manifest -> typetag conversion requires Scala reflection, which is not present on the classpath.
- |to proceed put scala-reflect.jar on your compilation classpath and recompile.""".trim.stripMargin
+ val msg =
+ sm"""to create a type tag here, it is necessary to interoperate with the manifest `$manifestInScope` in scope.
+ |however manifest -> typetag conversion requires Scala reflection, which is not present on the classpath.
+ |to proceed put scala-reflect.jar on your compilation classpath and recompile."""
throw new ReificationException(defaultErrorPosition, msg)
}
diff --git a/src/compiler/scala/tools/nsc/ast/Trees.scala b/src/compiler/scala/tools/nsc/ast/Trees.scala
index c78c40dcd3..e796258967 100644
--- a/src/compiler/scala/tools/nsc/ast/Trees.scala
+++ b/src/compiler/scala/tools/nsc/ast/Trees.scala
@@ -56,7 +56,7 @@ trait Trees extends scala.reflect.internal.Trees { self: Global =>
* The class `C` is stored as a tree attachment.
*/
case class InjectDerivedValue(arg: Tree)
- extends SymTree
+ extends SymTree with TermTree
class PostfixSelect(qual: Tree, name: Name) extends Select(qual, name)
diff --git a/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala b/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala
index f430f1fc34..9bb7e1c3df 100644
--- a/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala
+++ b/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala
@@ -1898,7 +1898,7 @@ self =>
case _ =>
}
val typeAppliedTree = in.token match {
- case LBRACKET => atPos(start, in.offset)(TypeApply(convertToTypeId(t), typeArgs()))
+ case LBRACKET => atPos(start, in.offset)(AppliedTypeTree(convertToTypeId(t), typeArgs()))
case _ => t
}
in.token match {
diff --git a/src/compiler/scala/tools/nsc/transform/Erasure.scala b/src/compiler/scala/tools/nsc/transform/Erasure.scala
index cfc3d0a377..ba799f9186 100644
--- a/src/compiler/scala/tools/nsc/transform/Erasure.scala
+++ b/src/compiler/scala/tools/nsc/transform/Erasure.scala
@@ -437,19 +437,19 @@ abstract class Erasure extends AddInterfaces
noclash = false
unit.error(
if (member.owner == root) member.pos else root.pos,
- s"""bridge generated for member ${fulldef(member)}
- |which overrides ${fulldef(other)}
- |clashes with definition of $what;
- |both have erased type ${exitingPostErasure(bridge.tpe)}""".stripMargin)
+ sm"""bridge generated for member ${fulldef(member)}
+ |which overrides ${fulldef(other)}
+ |clashes with definition of $what;
+ |both have erased type ${exitingPostErasure(bridge.tpe)}""")
}
for (bc <- root.baseClasses) {
if (settings.debug.value)
exitingPostErasure(println(
- s"""check bridge overrides in $bc
- ${bc.info.nonPrivateDecl(bridge.name)}
- ${site.memberType(bridge)}
- ${site.memberType(bc.info.nonPrivateDecl(bridge.name) orElse IntClass)}
- ${(bridge.matchingSymbol(bc, site))}""".stripMargin))
+ sm"""check bridge overrides in $bc
+ |${bc.info.nonPrivateDecl(bridge.name)}
+ |${site.memberType(bridge)}
+ |${site.memberType(bc.info.nonPrivateDecl(bridge.name) orElse IntClass)}
+ |${(bridge.matchingSymbol(bc, site))}"""))
def overriddenBy(sym: Symbol) =
sym.matchingSymbol(bc, site).alternatives filter (sym => !sym.isBridge)
@@ -693,7 +693,7 @@ abstract class Erasure extends AddInterfaces
adaptToType(unbox(tree, pt), pt)
else if (isPrimitiveValueType(tree.tpe) && !isPrimitiveValueType(pt)) {
adaptToType(box(tree, pt.toString), pt)
- } else if (tree.tpe.isInstanceOf[MethodType] && tree.tpe.params.isEmpty) {
+ } else if (isMethodTypeWithEmptyParams(tree.tpe)) {
// [H] this assert fails when trying to typecheck tree !(SomeClass.this.bitmap) for single lazy val
//assert(tree.symbol.isStable, "adapt "+tree+":"+tree.tpe+" to "+pt)
adaptToType(Apply(tree, List()) setPos tree.pos setType tree.tpe.resultType, pt)
@@ -774,16 +774,21 @@ abstract class Erasure extends AddInterfaces
else if (!isPrimitiveValueType(qual1.tpe) && isPrimitiveValueMember(tree.symbol))
qual1 = unbox(qual1, tree.symbol.owner.tpe)
- if (isPrimitiveValueMember(tree.symbol) && !isPrimitiveValueType(qual1.tpe))
+ def selectFrom(qual: Tree) = treeCopy.Select(tree, qual, name)
+
+ if (isPrimitiveValueMember(tree.symbol) && !isPrimitiveValueType(qual1.tpe)) {
tree.symbol = NoSymbol
- else if (qual1.tpe.isInstanceOf[MethodType] && qual1.tpe.params.isEmpty) {
+ selectFrom(qual1)
+ } else if (isMethodTypeWithEmptyParams(qual1.tpe)) {
assert(qual1.symbol.isStable, qual1.symbol);
- qual1 = Apply(qual1, List()) setPos qual1.pos setType qual1.tpe.resultType
+ val applied = Apply(qual1, List()) setPos qual1.pos setType qual1.tpe.resultType
+ adaptMember(selectFrom(applied))
} else if (!(qual1.isInstanceOf[Super] || (qual1.tpe.typeSymbol isSubClass tree.symbol.owner))) {
assert(tree.symbol.owner != ArrayClass)
- qual1 = cast(qual1, tree.symbol.owner.tpe)
+ selectFrom(cast(qual1, tree.symbol.owner.tpe))
+ } else {
+ selectFrom(qual1)
}
- treeCopy.Select(tree, qual1, name)
}
case SelectFromArray(qual, name, erasure) =>
var qual1 = typedQualifier(qual)
@@ -861,6 +866,11 @@ abstract class Erasure extends AddInterfaces
tree1
}
}
+
+ private def isMethodTypeWithEmptyParams(tpe: Type) = tpe match {
+ case MethodType(Nil, _) => true
+ case _ => false
+ }
}
/** The erasure transformer */
diff --git a/src/compiler/scala/tools/nsc/transform/UnCurry.scala b/src/compiler/scala/tools/nsc/transform/UnCurry.scala
index 4f889a1d86..8ae9490dbe 100644
--- a/src/compiler/scala/tools/nsc/transform/UnCurry.scala
+++ b/src/compiler/scala/tools/nsc/transform/UnCurry.scala
@@ -371,7 +371,7 @@ abstract class UnCurry extends InfoTransform
}
val isDefinedAtMethodDef = {
- val methSym = anonClass.newMethod(nme.isDefinedAt, fun.pos, FINAL)
+ val methSym = anonClass.newMethod(nme.isDefinedAt, fun.pos, FINAL | SYNTHETIC)
val params = methSym newSyntheticValueParams formals
methSym setInfoAndEnter MethodType(params, BooleanClass.tpe)
diff --git a/src/compiler/scala/tools/nsc/typechecker/ContextErrors.scala b/src/compiler/scala/tools/nsc/typechecker/ContextErrors.scala
index bfc9f08553..a6d11f13d4 100644
--- a/src/compiler/scala/tools/nsc/typechecker/ContextErrors.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/ContextErrors.scala
@@ -106,9 +106,9 @@ trait ContextErrors {
s"$name extends Any, not AnyRef"
)
if (isPrimitiveValueType(found) || isTrivialTopType(tp)) "" else "\n" +
- s"""|Note that $what.
- |Such types can participate in value classes, but instances
- |cannot appear in singleton types or in reference comparisons.""".stripMargin
+ sm"""|Note that $what.
+ |Such types can participate in value classes, but instances
+ |cannot appear in singleton types or in reference comparisons."""
}
import ErrorUtils._
@@ -1125,9 +1125,9 @@ trait ContextErrors {
(isView: Boolean, pt: Type, tree: Tree)(implicit context0: Context) = {
if (!info1.tpe.isErroneous && !info2.tpe.isErroneous) {
def coreMsg =
- s"""| $pre1 ${info1.sym.fullLocationString} of type ${info1.tpe}
- | $pre2 ${info2.sym.fullLocationString} of type ${info2.tpe}
- | $trailer""".stripMargin
+ sm"""| $pre1 ${info1.sym.fullLocationString} of type ${info1.tpe}
+ | $pre2 ${info2.sym.fullLocationString} of type ${info2.tpe}
+ | $trailer"""
def viewMsg = {
val found :: req :: _ = pt.typeArgs
def explanation = {
@@ -1138,19 +1138,19 @@ trait ContextErrors {
// involving Any, are further explained from foundReqMsg.
if (AnyRefClass.tpe <:< req) (
if (sym == AnyClass || sym == UnitClass) (
- s"""|Note: ${sym.name} is not implicitly converted to AnyRef. You can safely
- |pattern match `x: AnyRef` or cast `x.asInstanceOf[AnyRef]` to do so.""".stripMargin
+ sm"""|Note: ${sym.name} is not implicitly converted to AnyRef. You can safely
+ |pattern match `x: AnyRef` or cast `x.asInstanceOf[AnyRef]` to do so."""
)
else boxedClass get sym map (boxed =>
- s"""|Note: an implicit exists from ${sym.fullName} => ${boxed.fullName}, but
- |methods inherited from Object are rendered ambiguous. This is to avoid
- |a blanket implicit which would convert any ${sym.fullName} to any AnyRef.
- |You may wish to use a type ascription: `x: ${boxed.fullName}`.""".stripMargin
+ sm"""|Note: an implicit exists from ${sym.fullName} => ${boxed.fullName}, but
+ |methods inherited from Object are rendered ambiguous. This is to avoid
+ |a blanket implicit which would convert any ${sym.fullName} to any AnyRef.
+ |You may wish to use a type ascription: `x: ${boxed.fullName}`."""
) getOrElse ""
)
else
- s"""|Note that implicit conversions are not applicable because they are ambiguous:
- |${coreMsg}are possible conversion functions from $found to $req""".stripMargin
+ sm"""|Note that implicit conversions are not applicable because they are ambiguous:
+ |${coreMsg}are possible conversion functions from $found to $req"""
}
typeErrorMsg(found, req, infer.isPossiblyMissingArgs(found, req)) + (
if (explanation == "") "" else "\n" + explanation
diff --git a/src/compiler/scala/tools/nsc/typechecker/Implicits.scala b/src/compiler/scala/tools/nsc/typechecker/Implicits.scala
index eb45f9b847..739e28bf0c 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Implicits.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Implicits.scala
@@ -1298,17 +1298,17 @@ trait Implicits {
else {
if (ReflectRuntimeUniverse == NoSymbol) {
// todo. write a test for this
- context.error(pos, s"""
- |to create a manifest here, it is necessary to interoperate with the type tag `$tagInScope` in scope.
- |however typetag -> manifest conversion requires Scala reflection, which is not present on the classpath.
- |to proceed put scala-reflect.jar on your compilation classpath and recompile.""".trim.stripMargin)
+ context.error(pos,
+ sm"""to create a manifest here, it is necessary to interoperate with the type tag `$tagInScope` in scope.
+ |however typetag -> manifest conversion requires Scala reflection, which is not present on the classpath.
+ |to proceed put scala-reflect.jar on your compilation classpath and recompile.""")
return SearchFailure
}
if (resolveClassTag(pos, tp, allowMaterialization = true) == EmptyTree) {
- context.error(pos, s"""
- |to create a manifest here, it is necessary to interoperate with the type tag `$tagInScope` in scope.
- |however typetag -> manifest conversion requires a class tag for the corresponding type to be present.
- |to proceed add a class tag to the type `$tp` (e.g. by introducing a context bound) and recompile.""".trim.stripMargin)
+ context.error(pos,
+ sm"""to create a manifest here, it is necessary to interoperate with the type tag `$tagInScope` in scope.
+ |however typetag -> manifest conversion requires a class tag for the corresponding type to be present.
+ |to proceed add a class tag to the type `$tp` (e.g. by introducing a context bound) and recompile.""")
return SearchFailure
}
val cm = typed(Ident(ReflectRuntimeCurrentMirror))
diff --git a/src/compiler/scala/tools/nsc/typechecker/Macros.scala b/src/compiler/scala/tools/nsc/typechecker/Macros.scala
index 4b534b0d2e..e40d978e6d 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Macros.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Macros.scala
@@ -117,16 +117,9 @@ trait Macros extends scala.tools.reflect.FastTrack with Traces {
}
def pickle(macroImplRef: Tree): Tree = {
- val macroImpl = macroImplRef.symbol
+ val MacroImplReference(owner, macroImpl, targs) = macroImplRef
val paramss = macroImpl.paramss
- // this logic relies on the assumptions that were valid for the old macro prototype
- // namely that macro implementations can only be defined in top-level classes and modules
- // with the new prototype that materialized in a SIP, macros need to be statically accessible, which is different
- // for example, a macro def could be defined in a trait that is implemented by an object
- // there are some more clever cases when seemingly non-static method ends up being statically accessible
- // however, the code below doesn't account for these guys, because it'd take a look of time to get it right
- // for now I leave it as a todo and move along to more the important stuff
// todo. refactor when fixing SI-5498
def className: String = {
def loop(sym: Symbol): String = sym match {
@@ -138,7 +131,7 @@ trait Macros extends scala.tools.reflect.FastTrack with Traces {
loop(sym.owner) + separator + sym.javaSimpleName.toString
}
- loop(macroImpl.owner.enclClass)
+ loop(owner)
}
def signature: List[Int] = {
@@ -159,7 +152,7 @@ trait Macros extends scala.tools.reflect.FastTrack with Traces {
// I just named it "macro", because it's macro-related, but I could as well name it "foobar"
val nucleus = Ident(newTermName("macro"))
val wrapped = Apply(nucleus, payload map { case (k, v) => Assign(pickleAtom(k), pickleAtom(v)) })
- val pickle = gen.mkTypeApply(wrapped, treeInfo.typeArguments(macroImplRef.duplicate))
+ val pickle = gen.mkTypeApply(wrapped, targs map (_.duplicate))
// assign NoType to all freshly created AST nodes
// otherwise pickler will choke on tree.tpe being null
diff --git a/src/compiler/scala/tools/nsc/typechecker/PatternMatching.scala b/src/compiler/scala/tools/nsc/typechecker/PatternMatching.scala
index c5245c4e9e..42c34526d7 100644
--- a/src/compiler/scala/tools/nsc/typechecker/PatternMatching.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/PatternMatching.scala
@@ -1151,7 +1151,7 @@ trait PatternMatching extends Transform with TypingTransformers with ast.TreeDSL
// ExplicitOuter replaces `Select(q, outerSym) OBJ_EQ expectedPrefix` by `Select(q, outerAccessor(outerSym.owner)) OBJ_EQ expectedPrefix`
// if there's an outer accessor, otherwise the condition becomes `true` -- TODO: can we improve needsOuterTest so there's always an outerAccessor?
- val outer = expectedTp.typeSymbol.newMethod(vpmName.outer) setInfo expectedTp.prefix setFlag SYNTHETIC | ARTIFACT
+ val outer = expectedTp.typeSymbol.newMethod(vpmName.outer, newFlags = SYNTHETIC | ARTIFACT) setInfo expectedTp.prefix
(Select(codegen._asInstanceOf(testedBinder, expectedTp), outer)) OBJ_EQ expectedOuter
}
@@ -1413,7 +1413,7 @@ trait PatternMatching extends Transform with TypingTransformers with ast.TreeDSL
// assert(owner ne null); assert(owner ne NoSymbol)
def freshSym(pos: Position, tp: Type = NoType, prefix: String = "x") =
- NoSymbol.newTermSymbol(freshName(prefix), pos) setInfo tp
+ NoSymbol.newTermSymbol(freshName(prefix), pos, newFlags = SYNTHETIC) setInfo tp
def newSynthCaseLabel(name: String) =
NoSymbol.newLabel(freshName(name), NoPosition) setFlag treeInfo.SYNTH_CASE_FLAGS
@@ -3600,7 +3600,7 @@ trait PatternMatching extends Transform with TypingTransformers with ast.TreeDSL
*/
def matcher(scrut: Tree, scrutSym: Symbol, restpe: Type)(cases: List[Casegen => Tree], matchFailGen: Option[Tree => Tree]): Tree = {
val matchEnd = newSynthCaseLabel("matchEnd")
- val matchRes = NoSymbol.newValueParameter(newTermName("x"), NoPosition, SYNTHETIC) setInfo restpe.withoutAnnotations
+ val matchRes = NoSymbol.newValueParameter(newTermName("x"), NoPosition, newFlags = SYNTHETIC) setInfo restpe.withoutAnnotations
matchEnd setInfo MethodType(List(matchRes), restpe)
def newCaseSym = newSynthCaseLabel("case") setInfo MethodType(Nil, restpe)
diff --git a/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala b/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala
index 7a7c7c7d25..0ae225ccee 100644
--- a/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala
@@ -1382,8 +1382,8 @@ abstract class RefChecks extends InfoTransform with scala.reflect.internal.trans
private def checkCompileTimeOnly(sym: Symbol, pos: Position) = {
if (sym.isCompileTimeOnly) {
def defaultMsg =
- s"""|Reference to ${sym.fullLocationString} should not have survived past type checking,
- |it should have been processed and eliminated during expansion of an enclosing macro.""".stripMargin
+ sm"""Reference to ${sym.fullLocationString} should not have survived past type checking,
+ |it should have been processed and eliminated during expansion of an enclosing macro."""
// The getOrElse part should never happen, it's just here as a backstop.
unit.error(pos, sym.compileTimeOnlyMessage getOrElse defaultMsg)
}
diff --git a/src/compiler/scala/tools/nsc/typechecker/SuperAccessors.scala b/src/compiler/scala/tools/nsc/typechecker/SuperAccessors.scala
index 5fb9a5e67e..0992cd7955 100644
--- a/src/compiler/scala/tools/nsc/typechecker/SuperAccessors.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/SuperAccessors.scala
@@ -525,8 +525,8 @@ abstract class SuperAccessors extends transform.Transform with transform.TypingT
}
def isJavaProtected = host.isTrait && sym.isJavaDefined && {
restrictionError(pos, unit,
- s"""|$clazz accesses protected $sym inside a concrete trait method.
- |Add an accessor in a class extending ${sym.enclClass} as a workaround.""".stripMargin
+ sm"""$clazz accesses protected $sym inside a concrete trait method.
+ |Add an accessor in a class extending ${sym.enclClass} as a workaround."""
)
true
}
diff --git a/src/compiler/scala/tools/nsc/typechecker/TreeCheckers.scala b/src/compiler/scala/tools/nsc/typechecker/TreeCheckers.scala
index be7554abe2..fb95c952d2 100644
--- a/src/compiler/scala/tools/nsc/typechecker/TreeCheckers.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/TreeCheckers.scala
@@ -268,11 +268,9 @@ abstract class TreeCheckers extends Analyzer {
if (sym.owner != currentOwner) {
val expected = currentOwner.ownerChain find (x => cond(x)) getOrElse { fail("DefTree can't find owner: ") ; NoSymbol }
if (sym.owner != expected)
- fail("""|
- | currentOwner chain: %s
- | symbol chain: %s""".stripMargin.format(
- currentOwner.ownerChain take 3 mkString " -> ",
- sym.ownerChain mkString " -> ")
+ fail(sm"""|
+ | currentOwner chain: ${currentOwner.ownerChain take 3 mkString " -> "}
+ | symbol chain: ${sym.ownerChain mkString " -> "}"""
)
}
}
diff --git a/src/compiler/scala/tools/nsc/typechecker/Typers.scala b/src/compiler/scala/tools/nsc/typechecker/Typers.scala
index 42c7d4a6b8..e534e36a0d 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Typers.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Typers.scala
@@ -3763,54 +3763,45 @@ trait Typers extends Modes with Adaptations with Tags {
*
*/
def mkInvoke(cxTree: Tree, tree: Tree, qual: Tree, name: Name): Option[Tree] = {
- debuglog(s"dyna.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)))))
}
}
@@ -5015,7 +5006,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