Skip to content

Commit df28ef9

Browse files
committed
Memoize: duplicate scala2 behaviour: don't create fields for final vals.
This affect initialisation order and we rely on artifacts of initialisation order in Dotty.
1 parent de9877f commit df28ef9

File tree

1 file changed

+16
-5
lines changed

1 file changed

+16
-5
lines changed

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

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -70,11 +70,22 @@ import Decorators._
7070
lazy val field = sym.field.orElse(newField).asTerm
7171
if (sym.is(Accessor, butNot = NoFieldNeeded))
7272
if (sym.isGetter) {
73-
var rhs = tree.rhs.changeOwnerAfter(sym, field, thisTransform)
74-
if (isWildcardArg(rhs)) rhs = EmptyTree
75-
val fieldDef = transformFollowing(ValDef(field, rhs))
76-
val getterDef = cpy.DefDef(tree)(rhs = transformFollowingDeep(ref(field)))
77-
Thicket(fieldDef, getterDef)
73+
def skipBlocks(t: Tree): Tree = t match {
74+
case Block(a, b) if a.forall(isIdempotentExpr) => skipBlocks(b)
75+
case _ => t
76+
}
77+
if (sym.is(Flags.Final) && skipBlocks(tree.rhs).isInstanceOf[Literal])
78+
// duplicating scalac behavior: for final vals that have rhs as constant, we do not create a field
79+
// and instead return the value. This seemingly minor optimization has huge effect on initialization
80+
// order and the values that can be observed during superconstructor call
81+
tree
82+
else {
83+
var rhs = tree.rhs.changeOwnerAfter(sym, field, thisTransform)
84+
if (isWildcardArg(rhs)) rhs = EmptyTree
85+
val fieldDef = transformFollowing(ValDef(field, rhs))
86+
val getterDef = cpy.DefDef(tree)(rhs = transformFollowingDeep(ref(field)))
87+
Thicket(fieldDef, getterDef)
88+
}
7889
}
7990
else if (sym.isSetter) {
8091
if (!sym.is(ParamAccessor)) { val Literal(Constant(())) = tree.rhs } // this is intended as an assertion

0 commit comments

Comments
 (0)