@@ -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,40 +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- // If we have all fields initialized, then we can promote This to hot.
168- val classRef = state.thisClass.info.asInstanceOf [ClassInfo ].appliedRef
169- val allFieldsInited = classRef.fields.forall { denot =>
170- val sym = denot.symbol
171- sym.isOneOf(Flags .Lazy | Flags .Deferred ) || state.fieldsInited.contains(sym)
172- }
173- if (allFieldsInited)
174- Errors .empty
175- else
176- PromoteThis (pot, eff.source, state2.path).toErrors
177- case _ : Cold =>
178- PromoteCold (eff.source, state2.path).toErrors
179-
180- case pot @ Warm (cls, outer) =>
181- val errors = state.test { check(Promote (outer)(eff.source)) }
182- if (errors.isEmpty) Errors .empty
183- else PromoteWarm (pot, eff.source, state2.path).toErrors
184-
185- case Fun (pots, effs) =>
186- val errs1 = state.test { effs.flatMap { check(_) } }
187- val errs2 = state.test { pots.flatMap { pot => check(Promote (pot)(eff.source))(state.copy(path = Vector .empty)) } }
188- if (errs1.nonEmpty || errs2.nonEmpty)
189- UnsafePromotion (pot, eff.source, state2.path, errs1 ++ errs2).toErrors
190- else
191- Errors .empty
192-
193- case pot =>
194- val (pots, effs) = expand(pot)
195- val effs2 = pots.map(Promote (_)(eff.source))
196- (effs2 ++ effs).flatMap(check(_))
197- }
165+ case Promote (pot) => checkPromote(pot, eff.source)
198166
199167 case FieldAccess (pot, field) =>
200168
@@ -279,6 +247,47 @@ object Checking {
279247 }
280248 }
281249
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+
282291 private def expand (pot : Potential )(implicit state : State ): Summary = trace(" expand " + pot.show, init, sum => Summary .show(sum.asInstanceOf [Summary ])) {
283292 pot match {
284293 case MethodReturn (pot1, sym) =>
0 commit comments