Skip to content

Commit 195840a

Browse files
oderskysmarter
authored andcommitted
Fix access of lazy vals in traits compiled by 2.12
This was a case we did not consider before. Accessing a lazy val defined in a Scala 2.12 trait accessed an implementation class which did not exist. need special treatment to avoid this. P.S. It might be preferable to change lazy vals to not generate implementation class references in the first place. I don't know enough about its internals to be able to say whether that's feasible.
1 parent 3e95734 commit 195840a

File tree

5 files changed

+43
-11
lines changed

5 files changed

+43
-11
lines changed

compiler/src/dotty/tools/dotc/core/NameOps.scala

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -132,6 +132,12 @@ object NameOps {
132132

133133
def implClassName: N = likeSpaced(name ++ tpnme.IMPL_CLASS_SUFFIX)
134134

135+
def traitOfImplClassName: N = {
136+
val suffix = tpnme.IMPL_CLASS_SUFFIX.toString
137+
assert(name.endsWith(suffix), name)
138+
likeSpaced(name.mapLast(_.dropRight(suffix.length)))
139+
}
140+
135141
def errorName: N = likeSpaced(name ++ nme.ERROR)
136142

137143
/** Map variance value -1, +1 to 0, 1 */

compiler/src/dotty/tools/dotc/transform/AugmentScala2Traits.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ class AugmentScala2Traits extends MiniPhaseTransform with IdentityDenotTransform
5555
val implClass = ctx.newCompleteClassSymbol(
5656
owner = mixin.owner,
5757
name = mixin.name.implClassName,
58-
flags = Abstract | Scala2x,
58+
flags = Abstract | Scala2x | ImplClass,
5959
parents = defn.ObjectType :: Nil,
6060
assocFile = mixin.assocFile).enteredAfter(thisTransform)
6161

compiler/src/dotty/tools/dotc/transform/LinkScala2Impls.scala

Lines changed: 16 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -85,23 +85,29 @@ class LinkScala2Impls extends MiniPhase with IdentityDenotTransformer { thisTran
8585
val impl = implMethod(sel.symbol)
8686
if (impl.exists) Apply(ref(impl), This(currentClass) :: args).withPos(app.pos)
8787
else app // could have been an abstract method in a trait linked to from a super constructor
88+
case Apply(sel, args)
89+
if sel.symbol.maybeOwner.is(ImplClass) && sel.symbol.owner.traitOfImplClass.is(Scala_2_12_Trait) =>
90+
val impl = implMethod(sel.symbol)
91+
cpy.Apply(app)(ref(impl), args)
8892
case _ =>
8993
app
9094
}
9195
}
9296

97+
/** The 2.12 implementation method of a super call or implementation class target */
9398
private def implMethod(meth: Symbol)(implicit ctx: Context): Symbol = {
94-
val (implInfo, implName) =
95-
if (meth.owner.is(Scala_2_12_Trait))
96-
(meth.owner.info, ImplMethName(meth.name.asTermName))
99+
val implName = ImplMethName(meth.name.asTermName)
100+
val cls = meth.owner
101+
if (cls.is(ImplClass))
102+
cls.traitOfImplClass.info.decl(implName).atSignature(meth.signature).symbol
103+
else if (cls.is(Scala_2_12_Trait))
104+
if (meth.isConstructor)
105+
cls.info.decl(nme.TRAIT_CONSTRUCTOR).symbol
97106
else
98-
(meth.owner.implClass.info, meth.name)
99-
if (meth.isConstructor)
100-
implInfo.decl(nme.TRAIT_CONSTRUCTOR).symbol
101-
else
102-
implInfo.decl(implName)
103-
.suchThat(c => FullParameterization.memberSignature(c.info) == meth.signature)
104-
.symbol
107+
cls.info.decl(implName)
108+
.suchThat(c => FullParameterization.memberSignature(c.info) == meth.signature)
109+
.symbol
110+
else throw new AssertionError(i"no impl method for $meth")
105111
}
106112
}
107113

compiler/src/dotty/tools/dotc/transform/SymUtils.scala

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,9 @@ class SymUtils(val self: Symbol) extends AnyVal {
115115
def implClass(implicit ctx: Context): Symbol =
116116
self.owner.info.decl(self.name.implClassName).symbol
117117

118+
def traitOfImplClass(implicit ctx: Context): Symbol =
119+
self.owner.info.decl(self.name.traitOfImplClassName).symbol
120+
118121
def annotationsCarrying(meta: ClassSymbol)(implicit ctx: Context): List[Annotation] =
119122
self.annotations.filter(_.symbol.hasAnnotation(meta))
120123

tests/run/scala2trait-lazyval.scala

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
class Foo extends scala.collection.SeqView[Int, List[Int]] {
2+
def iterator: Iterator[Int] = null
3+
def apply(idx: Int): Int = idx
4+
def length: Int = 0
5+
protected def underlying = null
6+
}
7+
8+
object Test {
9+
def main(args: Array[String]): Unit = {
10+
val f: scala.collection.TraversableViewLike[Int, List[Int], _] = new Foo
11+
new f.Transformed[Int] {
12+
def foreach[U](f: Int => U): Unit = ()
13+
// underlying is a lazy val
14+
assert(underlying == null)
15+
}
16+
}
17+
}

0 commit comments

Comments
 (0)