diff --git a/compiler/src/dotty/tools/dotc/core/NameOps.scala b/compiler/src/dotty/tools/dotc/core/NameOps.scala index c429f4e32882..142dd0d1f6d9 100644 --- a/compiler/src/dotty/tools/dotc/core/NameOps.scala +++ b/compiler/src/dotty/tools/dotc/core/NameOps.scala @@ -132,6 +132,12 @@ object NameOps { def implClassName: N = likeSpaced(name ++ tpnme.IMPL_CLASS_SUFFIX) + def traitOfImplClassName: N = { + val suffix = tpnme.IMPL_CLASS_SUFFIX.toString + assert(name.endsWith(suffix), name) + likeSpaced(name.mapLast(_.dropRight(suffix.length))) + } + def errorName: N = likeSpaced(name ++ nme.ERROR) /** Map variance value -1, +1 to 0, 1 */ diff --git a/compiler/src/dotty/tools/dotc/transform/AugmentScala2Traits.scala b/compiler/src/dotty/tools/dotc/transform/AugmentScala2Traits.scala index 1cca3fea5af5..c5226f756d63 100644 --- a/compiler/src/dotty/tools/dotc/transform/AugmentScala2Traits.scala +++ b/compiler/src/dotty/tools/dotc/transform/AugmentScala2Traits.scala @@ -55,7 +55,7 @@ class AugmentScala2Traits extends MiniPhaseTransform with IdentityDenotTransform val implClass = ctx.newCompleteClassSymbol( owner = mixin.owner, name = mixin.name.implClassName, - flags = Abstract | Scala2x, + flags = Abstract | Scala2x | ImplClass, parents = defn.ObjectType :: Nil, assocFile = mixin.assocFile).enteredAfter(thisTransform) diff --git a/compiler/src/dotty/tools/dotc/transform/LinkScala2Impls.scala b/compiler/src/dotty/tools/dotc/transform/LinkScala2Impls.scala index e4697a3247c1..180e48e5f84b 100644 --- a/compiler/src/dotty/tools/dotc/transform/LinkScala2Impls.scala +++ b/compiler/src/dotty/tools/dotc/transform/LinkScala2Impls.scala @@ -85,23 +85,29 @@ class LinkScala2Impls extends MiniPhase with IdentityDenotTransformer { thisTran val impl = implMethod(sel.symbol) if (impl.exists) Apply(ref(impl), This(currentClass) :: args).withPos(app.pos) else app // could have been an abstract method in a trait linked to from a super constructor + case Apply(sel, args) + if sel.symbol.maybeOwner.is(ImplClass) && sel.symbol.owner.traitOfImplClass.is(Scala_2_12_Trait) => + val impl = implMethod(sel.symbol) + cpy.Apply(app)(ref(impl), args) case _ => app } } + /** The 2.12 implementation method of a super call or implementation class target */ private def implMethod(meth: Symbol)(implicit ctx: Context): Symbol = { - val (implInfo, implName) = - if (meth.owner.is(Scala_2_12_Trait)) - (meth.owner.info, ImplMethName(meth.name.asTermName)) + val implName = ImplMethName(meth.name.asTermName) + val cls = meth.owner + if (cls.is(ImplClass)) + cls.traitOfImplClass.info.decl(implName).atSignature(meth.signature).symbol + else if (cls.is(Scala_2_12_Trait)) + if (meth.isConstructor) + cls.info.decl(nme.TRAIT_CONSTRUCTOR).symbol else - (meth.owner.implClass.info, meth.name) - if (meth.isConstructor) - implInfo.decl(nme.TRAIT_CONSTRUCTOR).symbol - else - implInfo.decl(implName) - .suchThat(c => FullParameterization.memberSignature(c.info) == meth.signature) - .symbol + cls.info.decl(implName) + .suchThat(c => FullParameterization.memberSignature(c.info) == meth.signature) + .symbol + else throw new AssertionError(i"no impl method for $meth") } } diff --git a/compiler/src/dotty/tools/dotc/transform/SymUtils.scala b/compiler/src/dotty/tools/dotc/transform/SymUtils.scala index 4f35c5e614ae..45552fea1131 100644 --- a/compiler/src/dotty/tools/dotc/transform/SymUtils.scala +++ b/compiler/src/dotty/tools/dotc/transform/SymUtils.scala @@ -115,6 +115,9 @@ class SymUtils(val self: Symbol) extends AnyVal { def implClass(implicit ctx: Context): Symbol = self.owner.info.decl(self.name.implClassName).symbol + def traitOfImplClass(implicit ctx: Context): Symbol = + self.owner.info.decl(self.name.traitOfImplClassName).symbol + def annotationsCarrying(meta: ClassSymbol)(implicit ctx: Context): List[Annotation] = self.annotations.filter(_.symbol.hasAnnotation(meta)) diff --git a/tests/run/scala2trait-lazyval.scala b/tests/run/scala2trait-lazyval.scala new file mode 100644 index 000000000000..b4c492166b52 --- /dev/null +++ b/tests/run/scala2trait-lazyval.scala @@ -0,0 +1,17 @@ +class Foo extends scala.collection.SeqView[Int, List[Int]] { + def iterator: Iterator[Int] = null + def apply(idx: Int): Int = idx + def length: Int = 0 + protected def underlying = null +} + +object Test { + def main(args: Array[String]): Unit = { + val f: scala.collection.TraversableViewLike[Int, List[Int], _] = new Foo + new f.Transformed[Int] { + def foreach[U](f: Int => U): Unit = () + // underlying is a lazy val + assert(underlying == null) + } + } +}