Skip to content

Commit

Permalink
Avoid too eager transform of $outer for lhs & accessor rhs (#18949)
Browse files Browse the repository at this point in the history
Fix #18927 

The transformer in `mapOuter` in `Constructors` was transforming trees
it should not:
```scala
   override def transform(tree: Tree)(using Context) = tree match {
        [....]
        case tree: RefTree if tree.symbol.is(ParamAccessor) && tree.symbol.name == nme.OUTER =>
          ref(outerParam)
       [...]
 ```
There were two problems:
 - This case transformed LHS of `$outer` assignments in constructors. So, instead of setting the `$outer` field in the current class with the constructor, it was replaced with the $outer of the outer class. That resulted in not assigning any value to the `$outer` in inner class, and double assignment to the val in outer class.
 - LHS of the accessor def was also transformed, so it was evaluated to the `$outer` of the outer class.

This only happened when the nested class is created in the secondary constructor, as the primary constructor is not transformed (only the template body)
  • Loading branch information
odersky authored Nov 17, 2023
2 parents 7d2cad5 + 2ff4ba7 commit 3b974c5
Show file tree
Hide file tree
Showing 2 changed files with 19 additions and 0 deletions.
5 changes: 5 additions & 0 deletions compiler/src/dotty/tools/dotc/transform/Constructors.scala
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import Symbols.*
import Decorators.*
import DenotTransformers.*
import collection.mutable
import Types.*

object Constructors {
val name: String = "constructors"
Expand Down Expand Up @@ -197,6 +198,10 @@ class Constructors extends MiniPhase with IdentityDenotTransformer { thisPhase =
) &&
fn.symbol.info.resultType.classSymbol == outerParam.info.classSymbol =>
ref(outerParam)
case Assign(lhs, rhs) if lhs.symbol.name == nme.OUTER => // not transform LHS of assignment to $outer field
cpy.Assign(tree)(lhs, super.transform(rhs))
case dd: DefDef if dd.name.endsWith(nme.OUTER.asSimpleName) => // not transform RHS of outer accessor
dd
case tree: RefTree if tree.symbol.is(ParamAccessor) && tree.symbol.name == nme.OUTER =>
ref(outerParam)
case _ =>
Expand Down
14 changes: 14 additions & 0 deletions tests/pos/i18927.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
class A

class B {
val a = new A

class C(i: Int) {
def this() = {
this(1)
class Inner() {
println(a)
}
}
}
}

0 comments on commit 3b974c5

Please sign in to comment.