Skip to content

Commit c16e4b2

Browse files
committed
Make sure all non-deferred methods are implemented
Checked by a new post condition after memoize. Two bugs were detected and fixed by the condition (1) Memoize did not implement getters and setters of ParamAccessors (2) ResolveSuper did not implement super accessors in non-trait classes.
1 parent 5ff3d0f commit c16e4b2

File tree

3 files changed

+44
-24
lines changed

3 files changed

+44
-24
lines changed

src/dotty/tools/dotc/transform/Memoize.scala

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,12 @@ import Decorators._
4343
*/
4444
override def runsAfter: Set[Class[_ <: Phase]] = Set(classOf[Mixin])
4545

46+
override def checkPostCondition(tree: Tree)(implicit ctx: Context): Unit = tree match {
47+
case tree: DefDef if !tree.symbol.is(Lazy | Deferred) =>
48+
assert(!tree.rhs.isEmpty, i"unimplemented: $tree")
49+
case _ =>
50+
}
51+
4652
override def prepareForDefDef(tree: DefDef)(implicit ctx: Context) = {
4753
val sym = tree.symbol
4854
if (sym.isGetter && !sym.is(NoFieldNeeded)) {
@@ -74,13 +80,13 @@ import Decorators._
7480
Thicket(fieldDef, getterDef)
7581
}
7682
else if (sym.isSetter) {
77-
val Literal(Constant(())) = tree.rhs
83+
if (!sym.is(ParamAccessor)) { val Literal(Constant(())) = tree.rhs }
7884
val initializer = Assign(ref(field), ref(tree.vparamss.head.head.symbol))
7985
cpy.DefDef(tree)(rhs = transformFollowingDeep(initializer))
8086
}
8187
else tree // curiously, some accessors from Scala2 have ' ' suffixes. They count as
8288
// neither getters nor setters
8389
else tree
8490
}
85-
private val NoFieldNeeded = Lazy | Deferred | ParamAccessor | JavaDefined
91+
private val NoFieldNeeded = Lazy | Deferred | JavaDefined
8692
}

src/dotty/tools/dotc/transform/ResolveSuper.scala

Lines changed: 34 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -50,32 +50,32 @@ class ResolveSuper extends MiniPhaseTransform with IdentityDenotTransformer { th
5050

5151
override def treeTransformPhase = thisTransform.next
5252

53+
/** Returns the symbol that is accessed by a super-accessor in a mixin composition.
54+
*
55+
* @param base The class in which everything is mixed together
56+
* @param member The symbol statically referred to by the superaccessor in the trait
57+
*/
58+
private def rebindSuper(base: Symbol, acc: Symbol)(implicit ctx: Context): Symbol = {
59+
var bcs = base.info.baseClasses.dropWhile(acc.owner != _).tail
60+
var sym: Symbol = NoSymbol
61+
val SuperAccessorName(memberName) = acc.name: Name // dotty deviation: ": Name" needed otherwise pattern type is neither a subtype nor a supertype of selector type
62+
ctx.debuglog(i"starting rebindsuper from $base of ${acc.showLocated}: ${acc.info} in $bcs, name = $memberName")
63+
while (bcs.nonEmpty && sym == NoSymbol) {
64+
val other = bcs.head.info.nonPrivateDecl(memberName)
65+
if (ctx.settings.debug.value)
66+
ctx.log(i"rebindsuper ${bcs.head} $other deferred = ${other.symbol.is(Deferred)}")
67+
sym = other.matchingDenotation(base.thisType, base.thisType.memberInfo(acc)).symbol
68+
bcs = bcs.tail
69+
}
70+
assert(sym.exists)
71+
sym
72+
}
73+
5374
override def transformTemplate(impl: Template)(implicit ctx: Context, info: TransformerInfo) = {
5475
val cls = impl.symbol.owner.asClass
5576
val ops = new MixinOps(cls, thisTransform)
5677
import ops._
5778

58-
/** Returns the symbol that is accessed by a super-accessor in a mixin composition.
59-
*
60-
* @param base The class in which everything is mixed together
61-
* @param member The symbol statically referred to by the superaccessor in the trait
62-
*/
63-
def rebindSuper(base: Symbol, acc: Symbol): Symbol = {
64-
var bcs = cls.info.baseClasses.dropWhile(acc.owner != _).tail
65-
var sym: Symbol = NoSymbol
66-
val SuperAccessorName(memberName) = acc.name: Name // dotty deviation: ": Name" needed otherwise pattern type is neither a subtype nor a supertype of selector type
67-
ctx.debuglog(i"starting rebindsuper from $cls of ${acc.showLocated}: ${acc.info} in $bcs, name = $memberName")
68-
while (bcs.nonEmpty && sym == NoSymbol) {
69-
val other = bcs.head.info.nonPrivateDecl(memberName)
70-
if (ctx.settings.debug.value)
71-
ctx.log(i"rebindsuper ${bcs.head} $other deferred = ${other.symbol.is(Deferred)}")
72-
sym = other.matchingDenotation(cls.thisType, cls.thisType.memberInfo(acc)).symbol
73-
bcs = bcs.tail
74-
}
75-
assert(sym.exists)
76-
sym
77-
}
78-
7979
def superAccessors(mixin: ClassSymbol): List[Tree] =
8080
for (superAcc <- mixin.decls.filter(_ is SuperAccessor).toList)
8181
yield polyDefDef(implementation(superAcc.asTerm), forwarder(rebindSuper(cls, superAcc)))
@@ -94,5 +94,18 @@ class ResolveSuper extends MiniPhaseTransform with IdentityDenotTransformer { th
9494

9595
cpy.Template(impl)(body = overrides ::: impl.body)
9696
}
97+
98+
override def transformDefDef(ddef: DefDef)(implicit ctx: Context, info: TransformerInfo) = {
99+
val meth = ddef.symbol.asTerm
100+
if (meth.is(SuperAccessor, butNot = Deferred)) {
101+
assert(ddef.rhs.isEmpty)
102+
val cls = meth.owner.asClass
103+
val ops = new MixinOps(cls, thisTransform)
104+
import ops._
105+
polyDefDef(meth, forwarder(rebindSuper(cls, meth)))
106+
}
107+
else ddef
108+
}
109+
97110
private val PrivateOrDeferred = Private | Deferred
98111
}

src/dotty/tools/dotc/transform/SuperAccessors.scala

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -89,8 +89,9 @@ class SuperAccessors extends MacroTransform with IdentityDenotTransformer { this
8989

9090
val superAcc = clazz.info.decl(supername).suchThat(_.signature == sym.signature).symbol orElse {
9191
ctx.debuglog(s"add super acc ${sym.showLocated} to $clazz")
92+
val maybeDeferred = if (clazz is Trait) Deferred else EmptyFlags
9293
val acc = ctx.newSymbol(
93-
clazz, supername, SuperAccessor | Private | Artifact | Method,
94+
clazz, supername, SuperAccessor | Private | Artifact | Method | maybeDeferred,
9495
ensureMethodic(sel.tpe.widenSingleton), coord = sym.coord).enteredAfter(thisTransformer)
9596
// Diagnostic for SI-7091
9697
if (!accDefs.contains(clazz))

0 commit comments

Comments
 (0)