@@ -35,6 +35,7 @@ object Checking {
3535 thisClass : ClassSymbol , // the concrete class of `this`
3636 fieldsInited : mutable.Set [Symbol ],
3737 parentsInited : mutable.Set [ClassSymbol ],
38+ safePromoted : mutable.Set [Potential ], // Potentials that can be safely promoted
3839 env : Env
3940 ) {
4041
@@ -161,32 +162,7 @@ object Checking {
161162 implicit val state2 : State = state.withVisited(eff)
162163
163164 eff match {
164- case Promote (pot) =>
165- pot match {
166- case pot : ThisRef =>
167- PromoteThis (pot, eff.source, state2.path).toErrors
168-
169- case _ : Cold =>
170- PromoteCold (eff.source, state2.path).toErrors
171-
172- case pot @ Warm (cls, outer) =>
173- val errors = state.test { check(Promote (outer)(eff.source)) }
174- if (errors.isEmpty) Errors .empty
175- else PromoteWarm (pot, eff.source, state2.path).toErrors
176-
177- case Fun (pots, effs) =>
178- val errs1 = state.test { effs.flatMap { check(_) } }
179- val errs2 = state.test { pots.flatMap { pot => check(Promote (pot)(eff.source))(state.copy(path = Vector .empty)) } }
180- if (errs1.nonEmpty || errs2.nonEmpty)
181- UnsafePromotion (pot, eff.source, state2.path, errs1 ++ errs2).toErrors
182- else
183- Errors .empty
184-
185- case pot =>
186- val (pots, effs) = expand(pot)
187- val effs2 = pots.map(Promote (_)(eff.source))
188- (effs2 ++ effs).flatMap(check(_))
189- }
165+ case Promote (pot) => checkPromote(pot, eff.source)
190166
191167 case FieldAccess (pot, field) =>
192168
@@ -271,6 +247,47 @@ object Checking {
271247 }
272248 }
273249
250+ private def checkPromote (pot : Potential , source : Tree )(implicit state : State ): Errors =
251+ if (state.safePromoted.contains(pot)) Errors .empty
252+ else
253+ val errs = pot match {
254+ case pot : ThisRef =>
255+ // If we have all fields initialized, then we can promote This to hot.
256+ val classRef = state.thisClass.info.asInstanceOf [ClassInfo ].appliedRef
257+ val allFieldsInited = classRef.fields.forall { denot =>
258+ val sym = denot.symbol
259+ sym.isOneOf(Flags .Lazy | Flags .Deferred ) || state.fieldsInited.contains(sym)
260+ }
261+ if (allFieldsInited)
262+ Errors .empty
263+ else
264+ PromoteThis (pot, source, state.path).toErrors
265+ case _ : Cold =>
266+ PromoteCold (source, state.path).toErrors
267+
268+ case pot @ Warm (cls, outer) =>
269+ val errors = state.test { checkPromote(outer, source) }
270+ if (errors.isEmpty) Errors .empty
271+ else PromoteWarm (pot, source, state.path).toErrors
272+
273+ case Fun (pots, effs) =>
274+ val errs1 = state.test { effs.flatMap { check(_) } }
275+ val errs2 = state.test { pots.flatMap { pot => checkPromote(pot, source)(state.copy(path = Vector .empty)) } }
276+ if (errs1.nonEmpty || errs2.nonEmpty)
277+ UnsafePromotion (pot, source, state.path, errs1 ++ errs2).toErrors
278+ else
279+ Errors .empty
280+
281+ case pot =>
282+ val (pots, effs) = expand(pot)
283+ val effs2 = pots.map(Promote (_)(source))
284+ (effs2 ++ effs).flatMap(check(_))
285+ }
286+ // If we can safely promote, then we don't need to check again
287+ if (errs.isEmpty)
288+ state.safePromoted += pot
289+ errs
290+
274291 private def expand (pot : Potential )(implicit state : State ): Summary = trace(" expand " + pot.show, init, sum => Summary .show(sum.asInstanceOf [Summary ])) {
275292 pot match {
276293 case MethodReturn (pot1, sym) =>
0 commit comments