Skip to content

Commit 99df102

Browse files
committed
Try to check warm values immediately
1 parent b27d58b commit 99df102

File tree

1 file changed

+36
-25
lines changed

1 file changed

+36
-25
lines changed

compiler/src/dotty/tools/dotc/transform/init/Semantic.scala

Lines changed: 36 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -122,11 +122,10 @@ object Semantic {
122122
// Somehow Dotty uses the one in the class parameters
123123
given Heap = state.heap
124124
if objekt.outers.size <= 1 then
125-
val tpl = klass.defTree.asInstanceOf[TypeDef].rhs.asInstanceOf[Template]
126-
val termParamss = ctor.defTree.asInstanceOf[DefDef].termParamss
127-
val paramValues = termParamss.flatten.zip(args).map((param, v) => param.symbol -> v).toMap
128-
given Env = Env(paramValues)
129-
init(tpl, this, klass)
125+
state.populateWarm {
126+
val tpl = klass.defTree.asInstanceOf[TypeDef].rhs.asInstanceOf[Template]
127+
this.callConstructor(ctor, args.map(arg => ArgInfo(arg, EmptyTree)), tpl)
128+
}
130129
end if
131130
this
132131
}
@@ -184,8 +183,6 @@ object Semantic {
184183
*/
185184
def prepare(heapBefore: Heap)(using State, Context) =
186185
this.map.keys.foreach {
187-
case thisRef: ThisRef =>
188-
this.map = this.map - thisRef
189186
case warm: Warm if !heapBefore.contains(warm) =>
190187
this.map = this.map - warm
191188
given Env = Env.empty
@@ -195,6 +192,13 @@ object Semantic {
195192
case _ =>
196193
}
197194

195+
// ThisRef might be used in `ensureInit`
196+
this.map.keys.foreach {
197+
case thisRef: ThisRef =>
198+
this.map = this.map - thisRef
199+
case _ =>
200+
}
201+
198202
override def toString() = map.toString()
199203
}
200204

@@ -426,7 +430,16 @@ object Semantic {
426430

427431
// ----- State --------------------------------------------
428432
/** Global state of the checker */
429-
class State(val cache: Cache, val heap: Heap, val workList: WorkList)
433+
class State(val cache: Cache, val heap: Heap, val workList: WorkList, var isPopulatingWarm: Boolean = false) {
434+
// TODO: problematic for nested `init`.
435+
def populateWarm[T](fun: State ?=> T) = {
436+
val last = isPopulatingWarm
437+
isPopulatingWarm = true
438+
val res = fun(using this)
439+
isPopulatingWarm = last
440+
res
441+
}
442+
}
430443

431444
given (using s: State): Heap = s.heap
432445
given (using s: State): Cache = s.cache
@@ -608,7 +621,7 @@ object Semantic {
608621
report.error("unexpected constructor call, meth = " + ctor + ", value = " + value, source)
609622
Result(Hot, Nil)
610623

611-
case ref: Warm =>
624+
case ref: Warm if state.isPopulatingWarm =>
612625
val trace1 = trace.add(source)
613626
if ctor.hasSource then
614627
given Trace = trace1
@@ -627,20 +640,18 @@ object Semantic {
627640
else
628641
Result(Hot, Nil)
629642

630-
case ref: ThisRef =>
643+
case ref: Ref =>
631644
val trace1 = trace.add(source)
632645
if ctor.hasSource then
633646
given Trace = trace1
634647
val cls = ctor.owner.enclosingClass.asClass
635648
val ddef = ctor.defTree.asInstanceOf[DefDef]
636-
val env2 = Env(ddef, args.map(_.value).widenArgs)
649+
given Env= Env(ddef, args.map(_.value).widenArgs)
637650
if ctor.isPrimaryConstructor then
638-
given Env = env2
639651
val tpl = cls.defTree.asInstanceOf[TypeDef].rhs.asInstanceOf[Template]
640652
val res = withTrace(trace.add(cls.defTree)) { eval(tpl, ref, cls, cacheResult = true) }
641653
Result(ref, res.errors)
642654
else
643-
given Env = env2
644655
eval(ddef.rhs, ref, cls, cacheResult = true)
645656
else if ref.canIgnoreMethodCall(ctor) then
646657
Result(Hot, Nil)
@@ -670,29 +681,29 @@ object Semantic {
670681
Result(Hot, Errors.empty)
671682
else
672683
val outer = Hot
673-
val warm = Warm(klass, outer, ctor, args2).ensureInit()
684+
val warm = Warm(klass, outer, ctor, args2)
674685
val argInfos2 = args.zip(args2).map { (argInfo, v) => argInfo.copy(value = v) }
675-
val task = ThisRef(klass, outer, ctor, args2)
676-
this.addTask(task)
677-
Result(warm, Errors.empty)
686+
val res = warm.callConstructor(ctor, argInfos2, source)
687+
Result(warm, res.errors)
678688

679689
case Cold =>
680690
val error = CallCold(ctor, source, trace1.toVector)
681691
Result(Hot, error :: Nil)
682692

683693
case ref: Ref =>
684694
given Trace = trace1
685-
// widen the outer to finitize addresses
695+
// widen the outer to finitize the domain
686696
val outer = ref match
687-
case Warm(_, _: Warm, _, _) => Cold
697+
case warm @ Warm(_, _: Ref, _, _) =>
698+
// the widened warm object might not exist in the heap
699+
warm.copy(outer = Cold).ensureObjectExists().ensureInit()
688700
case _ => ref
689701

690702
val argsWidened = args.map(_.value).widenArgs
691703
val argInfos2 = args.zip(argsWidened).map { (argInfo, v) => argInfo.copy(value = v) }
692-
val warm = Warm(klass, outer, ctor, argsWidened).ensureInit()
693-
val task = ThisRef(klass, outer, ctor, argsWidened)
694-
this.addTask(task)
695-
Result(warm, Errors.empty)
704+
val warm = Warm(klass, outer, ctor, argsWidened)
705+
val res = warm.callConstructor(ctor, argInfos2, source)
706+
Result(warm, res.errors)
696707

697708
case Fun(body, thisV, klass, env) =>
698709
report.error("unexpected tree in instantiating a function, fun = " + body.show, source)
@@ -1389,7 +1400,7 @@ object Semantic {
13891400
var fieldsChanged = true
13901401

13911402
// class body
1392-
if (!thisV.isWarm) tpl.body.foreach {
1403+
if !state.isPopulatingWarm then tpl.body.foreach {
13931404
case vdef : ValDef if !vdef.symbol.is(Flags.Lazy) && !vdef.rhs.isEmpty =>
13941405
given Env = Env.empty
13951406
val res = eval(vdef.rhs, thisV, klass)
@@ -1400,7 +1411,7 @@ object Semantic {
14001411
case _: MemberDef =>
14011412

14021413
case tree =>
1403-
if fieldsChanged then thisV.asInstanceOf[ThisRef].tryPromoteCurrentObject
1414+
if fieldsChanged && !thisV.isWarm then thisV.asInstanceOf[ThisRef].tryPromoteCurrentObject
14041415
fieldsChanged = false
14051416

14061417
given Env = Env.empty

0 commit comments

Comments
 (0)