Skip to content

Commit a335cd8

Browse files
committed
Fix #9424: Add releaseFence() call when mixing in a trait val.
This is a forward port of relevant parts of the upstream PR scala/scala#7028
1 parent 1978a25 commit a335cd8

File tree

2 files changed

+31
-1
lines changed

2 files changed

+31
-1
lines changed

compiler/src/dotty/tools/dotc/core/StdNames.scala

+1
Original file line numberDiff line numberDiff line change
@@ -562,6 +562,7 @@ object StdNames {
562562
val reflect: N = "reflect"
563563
val reflectiveSelectable: N = "reflectiveSelectable"
564564
val reify : N = "reify"
565+
val releaseFence : N = "releaseFence"
565566
val rootMirror : N = "rootMirror"
566567
val run: N = "run"
567568
val runOrElse: N = "runOrElse"

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

+30-1
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,16 @@ import NameKinds.TraitSetterName
1616
import NameOps._
1717
import Flags._
1818
import Decorators._
19+
import StdNames.nme
20+
21+
import util.Store
1922

2023
object Memoize {
2124
val name: String = "memoize"
25+
26+
private final class MyState {
27+
val classesThatNeedReleaseFence = new util.HashSet[Symbol]
28+
}
2229
}
2330

2431
/** Provides the implementations of all getters and setters, introducing
@@ -37,10 +44,17 @@ object Memoize {
3744
* --> <accessor> <mods> def x_=(y: T): Unit = x = y
3845
*/
3946
class Memoize extends MiniPhase with IdentityDenotTransformer { thisPhase =>
47+
import Memoize.MyState
4048
import ast.tpd._
4149

4250
override def phaseName: String = Memoize.name
4351

52+
private var MyState: Store.Location[MyState] = _
53+
private def myState(using Context): MyState = ctx.store(MyState)
54+
55+
override def initContext(ctx: FreshContext): Unit =
56+
MyState = ctx.addLocation[MyState]()
57+
4458
/* Makes sure that, after getters and constructors gen, there doesn't
4559
* exist non-deferred definitions that are not implemented. */
4660
override def checkPostCondition(tree: Tree)(using Context): Unit = {
@@ -69,6 +83,17 @@ class Memoize extends MiniPhase with IdentityDenotTransformer { thisPhase =>
6983
*/
7084
override def runsAfter: Set[String] = Set(Mixin.name)
7185

86+
override def prepareForUnit(tree: Tree)(using Context): Context =
87+
ctx.fresh.updateStore(MyState, new MyState())
88+
89+
override def transformTemplate(tree: Template)(using Context): Tree =
90+
val cls = ctx.owner.asClass
91+
if myState.classesThatNeedReleaseFence.contains(cls) then
92+
val releaseFenceCall = ref(defn.staticsMethodRef(nme.releaseFence)).appliedToNone
93+
cpy.Template(tree)(tree.constr, tree.parents, Nil, tree.self, tree.body :+ releaseFenceCall)
94+
else
95+
tree
96+
7297
override def transformDefDef(tree: DefDef)(using Context): Tree = {
7398
val sym = tree.symbol
7499

@@ -154,7 +179,11 @@ class Memoize extends MiniPhase with IdentityDenotTransformer { thisPhase =>
154179
// See tests/run/traitValOverriddenByParamAccessor.scala
155180
tree
156181
else
157-
field.setFlag(Mutable) // Necessary for vals mixed in from traits
182+
if !field.is(Mutable) then
183+
// This is a val mixed in from a trait.
184+
// We make it mutable, and mark the class as needing a releaseFence() in the constructor
185+
field.setFlag(Mutable)
186+
myState.classesThatNeedReleaseFence += sym.owner
158187
val initializer =
159188
if (isErasableBottomField(field, tree.vparamss.head.head.tpt.tpe.classSymbol)) Literal(Constant(()))
160189
else Assign(ref(field), adaptToField(field, ref(tree.vparamss.head.head.symbol)))

0 commit comments

Comments
 (0)