diff options
-rw-r--r-- | src/compiler/scala/tools/nsc/transform/Erasure.scala | 23 | ||||
-rw-r--r-- | src/compiler/scala/tools/nsc/typechecker/Typers.scala | 4 | ||||
-rw-r--r-- | src/reflect/scala/reflect/internal/Symbols.scala | 23 | ||||
-rw-r--r-- | test/files/run/repl-power.check | 1 | ||||
-rw-r--r-- | test/files/run/t3425.check | 4 | ||||
-rw-r--r-- | test/files/run/t3425.scala | 40 |
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)) + } + } +} + |