Skip to content

Commit 1128a98

Browse files
committed
Fix handling of final vals after rebase on top of #9261.
1 parent a771574 commit 1128a98

File tree

1 file changed

+41
-51
lines changed

1 file changed

+41
-51
lines changed

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

Lines changed: 41 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -118,61 +118,51 @@ class Memoize extends MiniPhase with IdentityDenotTransformer { thisPhase =>
118118
EmptyTree
119119
}
120120

121-
def traitSetterGetter: Symbol =
122-
/* We have to compare SimpleNames here, because the setter name only
123-
* embeds the original getter's simple name, not its semantic name.
124-
* To mitigate the issue, we first try a fast path where we look up the
125-
* simple name itself, which works for public fields.
126-
*/
127-
val TraitSetterName(_, original) = sym.name
128-
val getterSimpleName = original.getterName
129-
val ownerInfo = sym.owner.info
130-
val fastPath = ownerInfo.findDecl(getterSimpleName, excluded = Bridge)
131-
if fastPath.exists then
132-
fastPath.symbol
133-
else
134-
ownerInfo.decls.find { getter =>
135-
getter.is(Accessor, butNot = Bridge) && getter.asTerm.name.toSimpleName == getterSimpleName
136-
}
137-
138-
val constantFinalVal = sym.isAllOf(Accessor | Final, butNot = Mutable) && tree.rhs.isInstanceOf[Literal]
139-
140-
if (sym.is(Accessor, butNot = NoFieldNeeded) && !constantFinalVal
141-
&& (!sym.name.is(TraitSetterName) || traitSetterGetter.is(Accessor, butNot = NoFieldNeeded))) {
142-
val field = sym.field.orElse(newField).asTerm
143-
144-
def adaptToField(tree: Tree): Tree =
121+
if sym.is(Accessor, butNot = NoFieldNeeded) then
122+
def adaptToField(field: Symbol, tree: Tree): Tree =
145123
if (tree.isEmpty) tree else tree.ensureConforms(field.info.widen)
146124

147-
def isErasableBottomField(cls: Symbol): Boolean =
125+
def isErasableBottomField(field: Symbol, cls: Symbol): Boolean =
148126
!field.isVolatile && ((cls eq defn.NothingClass) || (cls eq defn.NullClass) || (cls eq defn.BoxedUnitClass))
149127

150-
if (sym.isGetter) {
151-
var rhs = tree.rhs.changeOwnerAfter(sym, field, thisPhase)
152-
if (isWildcardArg(rhs)) rhs = EmptyTree
153-
val fieldDef = transformFollowing(ValDef(field, adaptToField(rhs)))
154-
val rhsClass = tree.tpt.tpe.widenDealias.classSymbol
155-
val getterRhs =
156-
if (isErasableBottomField(rhsClass)) erasedBottomTree(rhsClass)
157-
else transformFollowingDeep(ref(field))(using ctx.withOwner(sym))
158-
val getterDef = cpy.DefDef(tree)(rhs = getterRhs)
159-
addAnnotations(fieldDef.denot)
160-
removeUnwantedAnnotations(sym)
161-
Thicket(fieldDef, getterDef)
162-
}
163-
else if (sym.isSetter) {
128+
if sym.isGetter then
129+
val constantFinalVal = sym.isAllOf(Accessor | Final, butNot = Mutable) && tree.rhs.isInstanceOf[Literal]
130+
if constantFinalVal then
131+
// constant final vals do not need to be transformed at all, and do not need a field
132+
tree
133+
else
134+
val field = newField.asTerm
135+
var rhs = tree.rhs.changeOwnerAfter(sym, field, thisPhase)
136+
if (isWildcardArg(rhs)) rhs = EmptyTree
137+
val fieldDef = transformFollowing(ValDef(field, adaptToField(field, rhs)))
138+
val rhsClass = tree.tpt.tpe.widenDealias.classSymbol
139+
val getterRhs =
140+
if isErasableBottomField(field, rhsClass) then erasedBottomTree(rhsClass)
141+
else transformFollowingDeep(ref(field))(using ctx.withOwner(sym))
142+
val getterDef = cpy.DefDef(tree)(rhs = getterRhs)
143+
addAnnotations(fieldDef.denot)
144+
removeUnwantedAnnotations(sym)
145+
Thicket(fieldDef, getterDef)
146+
else if sym.isSetter then
164147
if (!sym.is(ParamAccessor)) { val Literal(Constant(())) = tree.rhs } // This is intended as an assertion
165-
field.setFlag(Mutable) // Necessary for vals mixed in from Scala2 traits
166-
val initializer =
167-
if (isErasableBottomField(tree.vparamss.head.head.tpt.tpe.classSymbol)) Literal(Constant(()))
168-
else Assign(ref(field), adaptToField(ref(tree.vparamss.head.head.symbol)))
169-
val setterDef = cpy.DefDef(tree)(rhs = transformFollowingDeep(initializer)(using ctx.withOwner(sym)))
170-
removeUnwantedAnnotations(sym)
171-
setterDef
172-
}
173-
else tree // curiously, some accessors from Scala2 have ' ' suffixes. They count as
174-
// neither getters nor setters
175-
}
176-
else tree
148+
val field = sym.field
149+
if !field.exists then
150+
// When transforming the getter, we determined that no field was needed.
151+
// In that case we can keep the setter as is, with a () rhs.
152+
tree
153+
else
154+
field.setFlag(Mutable) // Necessary for vals mixed in from traits
155+
val initializer =
156+
if (isErasableBottomField(field, tree.vparamss.head.head.tpt.tpe.classSymbol)) Literal(Constant(()))
157+
else Assign(ref(field), adaptToField(field, ref(tree.vparamss.head.head.symbol)))
158+
val setterDef = cpy.DefDef(tree)(rhs = transformFollowingDeep(initializer)(using ctx.withOwner(sym)))
159+
removeUnwantedAnnotations(sym)
160+
setterDef
161+
else
162+
// Curiously, some accessors from Scala2 have ' ' suffixes.
163+
// They count as neither getters nor setters.
164+
tree
165+
else
166+
tree
177167
}
178168
}

0 commit comments

Comments
 (0)