summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/compiler/scala/tools/nsc/transform/Erasure.scala23
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Typers.scala4
-rw-r--r--src/reflect/scala/reflect/internal/Symbols.scala23
-rw-r--r--test/files/run/repl-power.check1
-rw-r--r--test/files/run/t3425.check4
-rw-r--r--test/files/run/t3425.scala40
6 files changed, 77 insertions, 18 deletions
diff --git a/src/compiler/scala/tools/nsc/transform/Erasure.scala b/src/compiler/scala/tools/nsc/transform/Erasure.scala
index ac79c60254..fd22801897 100644
--- a/src/compiler/scala/tools/nsc/transform/Erasure.scala
+++ b/src/compiler/scala/tools/nsc/transform/Erasure.scala
@@ -974,7 +974,6 @@ abstract class Erasure extends AddInterfaces
case Select(qual, _) => qual
case TypeApply(Select(qual, _), _) => qual
}
-
def preEraseAsInstanceOf = {
(fn: @unchecked) match {
case TypeApply(Select(qual, _), List(targ)) =>
@@ -1032,8 +1031,9 @@ abstract class Erasure extends AddInterfaces
preEraseAsInstanceOf
} else if (fn.symbol == Any_isInstanceOf) {
preEraseIsInstanceOf
- } else if (fn.symbol.owner.isRefinementClass && !fn.symbol.isOverridingSymbol) {
- // !!! Another spot where we produce overloaded types (see test run/t6301)
+ } else if (fn.symbol.isOnlyRefinementMember) {
+ // !!! Another spot where we produce overloaded types (see test pos/t6301)
+ log(s"${fn.symbol.fullLocationString} originates in refinement class - call will be implemented via reflection.")
ApplyDynamic(qualifier, args) setSymbol fn.symbol setPos tree.pos
} else if (fn.symbol.isMethodWithExtension && !fn.symbol.tpe.isErroneous) {
Apply(gen.mkAttributedRef(extensionMethods.extensionMethod(fn.symbol)), qualifier :: args)
@@ -1161,12 +1161,19 @@ abstract class Erasure extends AddInterfaces
preErase(fun)
case Select(qual, name) =>
- val owner = tree.symbol.owner
- // println("preXform: "+ (tree, tree.symbol, tree.symbol.owner, tree.symbol.owner.isRefinementClass))
+ val sym = tree.symbol
+ val owner = sym.owner
if (owner.isRefinementClass) {
- val overridden = tree.symbol.nextOverriddenSymbol
- assert(overridden != NoSymbol, tree.symbol)
- tree.symbol = overridden
+ sym.allOverriddenSymbols filterNot (_.owner.isRefinementClass) match {
+ case overridden :: _ =>
+ log(s"${sym.fullLocationString} originates in refinement class - replacing with ${overridden.fullLocationString}.")
+ tree.symbol = overridden
+ case Nil =>
+ // Ideally this should not be reached or reachable; anything which would
+ // get here should have been caught in the surrounding Apply.
+ devWarning(s"Failed to rewrite reflective apply - now don't know what to do with " + tree)
+ return treeCopy.Select(tree, gen.mkAttributedCast(qual, qual.tpe.widen), name)
+ }
}
def isAccessible(sym: Symbol) = localTyper.context.isAccessible(sym, sym.owner.thisType)
diff --git a/src/compiler/scala/tools/nsc/typechecker/Typers.scala b/src/compiler/scala/tools/nsc/typechecker/Typers.scala
index 8511428d90..f879d11b0b 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Typers.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Typers.scala
@@ -2873,8 +2873,8 @@ trait Typers extends Adaptations with Tags {
templ updateAttachment att.copy(stats = stats1)
for (stat <- stats1 if stat.isDef && stat.symbol.isOverridingSymbol)
stat.symbol setFlag OVERRIDE
- }
- }
+ }
+ }
def typedImport(imp : Import) : Import = (transformed remove imp) match {
case Some(imp1: Import) => imp1
diff --git a/src/reflect/scala/reflect/internal/Symbols.scala b/src/reflect/scala/reflect/internal/Symbols.scala
index af20b8b756..8343ae6b07 100644
--- a/src/reflect/scala/reflect/internal/Symbols.scala
+++ b/src/reflect/scala/reflect/internal/Symbols.scala
@@ -892,16 +892,23 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
/** Is this a term symbol only defined in a refinement (so that it needs
* to be accessed by reflection)?
*/
- def isOnlyRefinementMember: Boolean = (
- isTerm && // type members are not affected
- owner.isRefinementClass && // owner must be a refinement class
- (owner.info decl name) == this && // symbol must be explicitly declared in the refinement (not synthesized from glb)
- !isOverridingSymbol && // symbol must not override a symbol in a base class
- !isConstant // symbol must not be a constant. Question: Can we exclude @inline methods as well?
+ def isOnlyRefinementMember = (
+ isTerm // Type members are unaffected
+ && owner.isRefinementClass // owner must be a refinement class
+ && isPossibleInRefinement // any overridden symbols must also have refinement class owners
+ && !isConstant // Must not be a constant. Question: Can we exclude @inline methods as well?
+ && isDeclaredByOwner // Must be explicitly declared in the refinement (not synthesized from glb)
)
+ // "(owner.info decl name) == this" is inadequate, because "name" might
+ // be overloaded in owner - and this might be an overloaded symbol.
+ // TODO - make this cheaper and see where else we should be doing something similar.
+ private def isDeclaredByOwner = (owner.info decl name).alternatives exists (alternatives contains _)
final def isStructuralRefinementMember = owner.isStructuralRefinement && isPossibleInRefinement && isPublic
- final def isPossibleInRefinement = !isConstructor && !isOverridingSymbol
+ final def isPossibleInRefinement = (
+ !isConstructor
+ && allOverriddenSymbols.forall(_.owner.isRefinementClass) // this includes allOverriddenSymbols.isEmpty
+ )
/** A a member of class `base` is incomplete if
* (1) it is declared deferred or
@@ -3430,7 +3437,7 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
@tailrec private[scala] final
def allSymbolsHaveOwner(syms: List[Symbol], owner: Symbol): Boolean = syms match {
case sym :: rest => sym.owner == owner && allSymbolsHaveOwner(rest, owner)
- case _ => true
+ case _ => true
}
diff --git a/test/files/run/repl-power.check b/test/files/run/repl-power.check
index 9d63ecde94..1abb8e9d14 100644
--- a/test/files/run/repl-power.check
+++ b/test/files/run/repl-power.check
@@ -14,6 +14,7 @@ scala> global.emptyValDef // "it is imported twice in the same scope by ..."
res0: $r.global.emptyValDef.type = private val _ = _
scala> val tp = ArrayClass[scala.util.Random] // magic with tags
+warning: there were 1 feature warning(s); re-run with -feature for details
tp: $r.global.Type = Array[scala.util.Random]
scala> tp.memberType(Array_apply) // evidence
diff --git a/test/files/run/t3425.check b/test/files/run/t3425.check
new file mode 100644
index 0000000000..5be779bd74
--- /dev/null
+++ b/test/files/run/t3425.check
@@ -0,0 +1,4 @@
+123
+456
+789
+789
diff --git a/test/files/run/t3425.scala b/test/files/run/t3425.scala
new file mode 100644
index 0000000000..6505ee6e24
--- /dev/null
+++ b/test/files/run/t3425.scala
@@ -0,0 +1,40 @@
+object Other {
+ abstract class Foo {
+ type R1 <: { def x: Any }
+ type R2 <: R1 { def x: Int }
+
+ def f(x: R2) = x.x
+ }
+
+ abstract class Bar {
+ trait R0 { def x: Any }
+ type R1 <: R0 { def x: AnyVal }
+ type R2 <: R1 { def x: Int }
+
+ def f(x: R2) = x.x
+ }
+}
+object Test {
+ trait A
+ trait B
+ def x(a: (A { val y: Int }) with B { val y: Int }) = a.y
+
+ class C extends A with B {
+ val y = 456
+ }
+
+ class Bippy { def x: Int = 789 }
+
+ def main(args: Array[String]): Unit = {
+ println(x(new A with B { val y = 123 }))
+ println(x(new C))
+
+ { val foo = new Other.Foo { type R1 = Bippy ; type R2 = Bippy }
+ println(foo.f(new Bippy))
+ }
+ { val bar = new Other.Bar { type R1 = Bippy with R0 ; type R2 = R1 }
+ println(bar.f(new Bippy with bar.R0))
+ }
+ }
+}
+