Skip to content

Commit

Permalink
Fix treatment of parameter selections via this in constructors.
Browse files Browse the repository at this point in the history
  • Loading branch information
odersky committed Jul 22, 2022
1 parent 6c7acf9 commit 9383fd6
Show file tree
Hide file tree
Showing 3 changed files with 24 additions and 8 deletions.
20 changes: 12 additions & 8 deletions compiler/src/dotty/tools/dotc/transform/Constructors.scala
Original file line number Diff line number Diff line change
Expand Up @@ -149,17 +149,21 @@ class Constructors extends MiniPhase with IdentityDenotTransformer { thisPhase =
// (2) If the parameter accessor reference was to an alias getter,
// drop the () when replacing by the parameter.
object intoConstr extends TreeMap {
private var isSuperCall = false
private var inSuperCall = false
override def transform(tree: Tree)(using Context): Tree = tree match {
case Ident(_) | Select(This(_), _) =>
var sym = tree.symbol
if sym.is(ParamAccessor) && (!sym.is(Mutable) || isSuperCall)
// Variables need to go through the getter since they might have been updated,
// except if we are in a super call, since then the virtual getter call would
// be illegal.
then
def isOverridableSelect = tree.isInstanceOf[Select] && !sym.isEffectivelyFinal
def keepUnlessInSuperCall = sym.is(Mutable) || isOverridableSelect
// If true, switch to constructor parameters only in the super call.
// Variables need to go through the getter since they might have been updated.
// References via this need to use the getter as well as long as that getter
// can be overriddem. This is needed to handle overrides correctly. See run/i15723.scala.
// But in a supercall we need to switch to parameters in any case since then
// calling the virtual getter would be illegal.
if sym.is(ParamAccessor) && (!keepUnlessInSuperCall || inSuperCall) then
sym = sym.subst(accessors, paramSyms)
if (sym.maybeOwner.isConstructor) ref(sym).withSpan(tree.span) else tree
if sym.maybeOwner.isConstructor then ref(sym).withSpan(tree.span) else tree
case Apply(fn, Nil) =>
val fn1 = transform(fn)
if ((fn1 ne fn) && fn1.symbol.is(Param) && fn1.symbol.owner.isPrimaryConstructor)
Expand All @@ -170,7 +174,7 @@ class Constructors extends MiniPhase with IdentityDenotTransformer { thisPhase =
}

def apply(tree: Tree, prevOwner: Symbol)(using Context): Tree =
isSuperCall = isSuperConstrCall(tree)
inSuperCall = isSuperConstrCall(tree)
transform(tree).changeOwnerAfter(prevOwner, constr.symbol, thisPhase)
}

Expand Down
2 changes: 2 additions & 0 deletions tests/run/i15723.check
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
20
20
10 changes: 10 additions & 0 deletions tests/run/i15723.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
class B(val y: Int) {
println(this.y)
foo()
def foo() = println(this.y)
}
class C(override val y: Int) extends B(10)

object Test extends App {
new C(20)
}

0 comments on commit 9383fd6

Please sign in to comment.