From 7983a2f17a271d472c172e4a3b30d61e606134a9 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Wed, 29 Sep 2021 22:21:39 +0200 Subject: [PATCH 1/2] Fix variable handling in super calls Accesses to var parameters in super calls need to refer to the constructor parameter, not the getter. Fixes #13630 --- .../src/dotty/tools/dotc/transform/Constructors.scala | 9 ++++++++- tests/run/i13630.check | 1 + tests/run/i13630.scala | 9 +++++++++ 3 files changed, 18 insertions(+), 1 deletion(-) create mode 100644 tests/run/i13630.check create mode 100644 tests/run/i13630.scala diff --git a/compiler/src/dotty/tools/dotc/transform/Constructors.scala b/compiler/src/dotty/tools/dotc/transform/Constructors.scala index 024261746265..b5b8ae7cd3e4 100644 --- a/compiler/src/dotty/tools/dotc/transform/Constructors.scala +++ b/compiler/src/dotty/tools/dotc/transform/Constructors.scala @@ -146,10 +146,16 @@ 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 override def transform(tree: Tree)(using Context): Tree = tree match { case Ident(_) | Select(This(_), _) => var sym = tree.symbol - if (sym.is(ParamAccessor, butNot = Mutable)) sym = sym.subst(accessors, paramSyms) + 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 + sym = sym.subst(accessors, paramSyms) if (sym.maybeOwner.isConstructor) ref(sym).withSpan(tree.span) else tree case Apply(fn, Nil) => val fn1 = transform(fn) @@ -161,6 +167,7 @@ class Constructors extends MiniPhase with IdentityDenotTransformer { thisPhase = } def apply(tree: Tree, prevOwner: Symbol)(using Context): Tree = + isSuperCall = isSuperConstrCall(tree) transform(tree).changeOwnerAfter(prevOwner, constr.symbol, thisPhase) } diff --git a/tests/run/i13630.check b/tests/run/i13630.check new file mode 100644 index 000000000000..64bf9740e617 --- /dev/null +++ b/tests/run/i13630.check @@ -0,0 +1 @@ +it worked diff --git a/tests/run/i13630.scala b/tests/run/i13630.scala new file mode 100644 index 000000000000..64f260262a8e --- /dev/null +++ b/tests/run/i13630.scala @@ -0,0 +1,9 @@ +class ClassWithLambda(sup: () => Long) +class ClassWithVar(var msg: String) extends ClassWithLambda(() => 1) + +object Test: + val _ = new ClassWithVar("foo") + + def main(args: Array[String]): Unit = { + println("it worked") + } \ No newline at end of file From 0210ad8553763741631d3805f788a5e169f5a5cb Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Wed, 29 Sep 2021 23:14:50 +0200 Subject: [PATCH 2/2] Reclassify test --- tests/neg/i11045.scala | 5 ----- tests/run/i11045.scala | 5 +++++ 2 files changed, 5 insertions(+), 5 deletions(-) delete mode 100644 tests/neg/i11045.scala create mode 100644 tests/run/i11045.scala diff --git a/tests/neg/i11045.scala b/tests/neg/i11045.scala deleted file mode 100644 index 1288d7ebb42a..000000000000 --- a/tests/neg/i11045.scala +++ /dev/null @@ -1,5 +0,0 @@ -abstract class Foo(x: Any) -class Boom(var x: Unit, y: Unit) extends Foo((x: Int) => x) // error: super constructor cannot be passed a self reference -@main def Test = - Boom((), ()) - diff --git a/tests/run/i11045.scala b/tests/run/i11045.scala new file mode 100644 index 000000000000..2885c7608e60 --- /dev/null +++ b/tests/run/i11045.scala @@ -0,0 +1,5 @@ +abstract class Foo(x: Any) +class Boom(var x: Unit, y: Unit) extends Foo((x: Int) => x) // was error: super constructor cannot be passed a self reference +@main def Test = + Boom((), ()) +