Skip to content

Commit 9383fd6

Browse files
committed
Fix treatment of parameter selections via this in constructors.
Fixes #15723
1 parent 6c7acf9 commit 9383fd6

File tree

3 files changed

+24
-8
lines changed

3 files changed

+24
-8
lines changed

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

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -149,17 +149,21 @@ class Constructors extends MiniPhase with IdentityDenotTransformer { thisPhase =
149149
// (2) If the parameter accessor reference was to an alias getter,
150150
// drop the () when replacing by the parameter.
151151
object intoConstr extends TreeMap {
152-
private var isSuperCall = false
152+
private var inSuperCall = false
153153
override def transform(tree: Tree)(using Context): Tree = tree match {
154154
case Ident(_) | Select(This(_), _) =>
155155
var sym = tree.symbol
156-
if sym.is(ParamAccessor) && (!sym.is(Mutable) || isSuperCall)
157-
// Variables need to go through the getter since they might have been updated,
158-
// except if we are in a super call, since then the virtual getter call would
159-
// be illegal.
160-
then
156+
def isOverridableSelect = tree.isInstanceOf[Select] && !sym.isEffectivelyFinal
157+
def keepUnlessInSuperCall = sym.is(Mutable) || isOverridableSelect
158+
// If true, switch to constructor parameters only in the super call.
159+
// Variables need to go through the getter since they might have been updated.
160+
// References via this need to use the getter as well as long as that getter
161+
// can be overriddem. This is needed to handle overrides correctly. See run/i15723.scala.
162+
// But in a supercall we need to switch to parameters in any case since then
163+
// calling the virtual getter would be illegal.
164+
if sym.is(ParamAccessor) && (!keepUnlessInSuperCall || inSuperCall) then
161165
sym = sym.subst(accessors, paramSyms)
162-
if (sym.maybeOwner.isConstructor) ref(sym).withSpan(tree.span) else tree
166+
if sym.maybeOwner.isConstructor then ref(sym).withSpan(tree.span) else tree
163167
case Apply(fn, Nil) =>
164168
val fn1 = transform(fn)
165169
if ((fn1 ne fn) && fn1.symbol.is(Param) && fn1.symbol.owner.isPrimaryConstructor)
@@ -170,7 +174,7 @@ class Constructors extends MiniPhase with IdentityDenotTransformer { thisPhase =
170174
}
171175

172176
def apply(tree: Tree, prevOwner: Symbol)(using Context): Tree =
173-
isSuperCall = isSuperConstrCall(tree)
177+
inSuperCall = isSuperConstrCall(tree)
174178
transform(tree).changeOwnerAfter(prevOwner, constr.symbol, thisPhase)
175179
}
176180

tests/run/i15723.check

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
20
2+
20

tests/run/i15723.scala

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
class B(val y: Int) {
2+
println(this.y)
3+
foo()
4+
def foo() = println(this.y)
5+
}
6+
class C(override val y: Int) extends B(10)
7+
8+
object Test extends App {
9+
new C(20)
10+
}

0 commit comments

Comments
 (0)