Skip to content

Commit cb47acd

Browse files
authored
Merge pull request #11278 from natsukagami/early-promote-this
Init: Promote `this` after all its fields have been initialized
2 parents 4124ce0 + f02b8e2 commit cb47acd

File tree

4 files changed

+60
-27
lines changed

4 files changed

+60
-27
lines changed

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ class Checker extends MiniPhase {
5252
thisClass = cls,
5353
fieldsInited = mutable.Set.empty,
5454
parentsInited = mutable.Set.empty,
55+
safePromoted = mutable.Set.empty,
5556
env = baseEnv.withCtx(ctx.withOwner(cls))
5657
)
5758

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

Lines changed: 43 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -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) =>

tests/init/neg/inner11.scala

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ object NameKinds {
1313
type ThisInfo = Info
1414
val info: Info = new Info
1515
println(info.kind) // error
16+
val n = 10
1617
}
1718
}
1819

@@ -32,4 +33,4 @@ object NameKinds2 {
3233
val info: Info = new Info
3334
println(info.kind) // ok
3435
}
35-
}
36+
}
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
class P() {
2+
val a = 1
3+
List(this)
4+
}
5+
6+
class Outer {
7+
class Inner {
8+
val b = a
9+
}
10+
val a = 5
11+
val b = new Inner()
12+
List(new Inner())
13+
List(b)
14+
}

0 commit comments

Comments
 (0)