From 0796461ab758f989e2da998263323e7d90d54feb Mon Sep 17 00:00:00 2001 From: Natsu Kagami Date: Sun, 24 Jan 2021 20:37:13 +0900 Subject: [PATCH 1/5] Simple case working --- .../dotty/tools/dotc/transform/init/Checking.scala | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/transform/init/Checking.scala b/compiler/src/dotty/tools/dotc/transform/init/Checking.scala index 6a8007e06516..cc2a2cbcb8a4 100644 --- a/compiler/src/dotty/tools/dotc/transform/init/Checking.scala +++ b/compiler/src/dotty/tools/dotc/transform/init/Checking.scala @@ -164,8 +164,16 @@ object Checking { case Promote(pot) => pot match { case pot: ThisRef => - PromoteThis(pot, eff.source, state2.path).toErrors - + // If we have all fields initialized, then we can promote This to hot. + val classRef = state.thisClass.info.asInstanceOf[ClassInfo].appliedRef + val allFieldsInited = classRef.fields.forall { denot => + val sym = denot.symbol + sym.isOneOf(Flags.Lazy | Flags.Deferred) || state.fieldsInited.contains(sym) + } + if (allFieldsInited) + Errors.empty + else + PromoteThis(pot, eff.source, state2.path).toErrors case _: Cold => PromoteCold(eff.source, state2.path).toErrors From e5b9210fcf40a75800a8dc1b43407e2c1ae0278a Mon Sep 17 00:00:00 2001 From: Natsu Kagami Date: Sun, 24 Jan 2021 20:38:05 +0900 Subject: [PATCH 2/5] Test for simple case --- tests/init/pos/early-promote-simple.scala | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 tests/init/pos/early-promote-simple.scala diff --git a/tests/init/pos/early-promote-simple.scala b/tests/init/pos/early-promote-simple.scala new file mode 100644 index 000000000000..8433d51cd43f --- /dev/null +++ b/tests/init/pos/early-promote-simple.scala @@ -0,0 +1,4 @@ +class P() { + val a = 1 + List(this) +} \ No newline at end of file From 27f0fdafe555ec4301d3cbbd0a46b2cc57f572a5 Mon Sep 17 00:00:00 2001 From: Natsu Kagami Date: Wed, 10 Feb 2021 21:05:26 +0900 Subject: [PATCH 3/5] Add subclasses case to test --- tests/init/pos/early-promote-simple.scala | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/tests/init/pos/early-promote-simple.scala b/tests/init/pos/early-promote-simple.scala index 8433d51cd43f..2c2992519280 100644 --- a/tests/init/pos/early-promote-simple.scala +++ b/tests/init/pos/early-promote-simple.scala @@ -1,4 +1,14 @@ class P() { val a = 1 List(this) +} + +class Outer { + class Inner { + val b = a + } + val a = 5 + val b = new Inner() + List(new Inner()) + List(b) } \ No newline at end of file From 37258d0ee09bbc08bd9476c9f4535e2bde7be8c6 Mon Sep 17 00:00:00 2001 From: Natsu Kagami Date: Wed, 10 Feb 2021 21:59:29 +0900 Subject: [PATCH 4/5] Cache safely promoted potentials --- .../tools/dotc/transform/init/Checker.scala | 1 + .../tools/dotc/transform/init/Checking.scala | 77 +++++++++++-------- 2 files changed, 44 insertions(+), 34 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/transform/init/Checker.scala b/compiler/src/dotty/tools/dotc/transform/init/Checker.scala index 7172db190ce0..61d4dcfaa952 100644 --- a/compiler/src/dotty/tools/dotc/transform/init/Checker.scala +++ b/compiler/src/dotty/tools/dotc/transform/init/Checker.scala @@ -52,6 +52,7 @@ class Checker extends MiniPhase { thisClass = cls, fieldsInited = mutable.Set.empty, parentsInited = mutable.Set.empty, + safePromoted = mutable.Set.empty, env = baseEnv.withCtx(ctx.withOwner(cls)) ) diff --git a/compiler/src/dotty/tools/dotc/transform/init/Checking.scala b/compiler/src/dotty/tools/dotc/transform/init/Checking.scala index cc2a2cbcb8a4..b08b95581c24 100644 --- a/compiler/src/dotty/tools/dotc/transform/init/Checking.scala +++ b/compiler/src/dotty/tools/dotc/transform/init/Checking.scala @@ -35,6 +35,7 @@ object Checking { thisClass: ClassSymbol, // the concrete class of `this` fieldsInited: mutable.Set[Symbol], parentsInited: mutable.Set[ClassSymbol], + safePromoted: mutable.Set[Potential], // Potentials that can be safely promoted env: Env ) { @@ -161,40 +162,7 @@ object Checking { implicit val state2: State = state.withVisited(eff) eff match { - case Promote(pot) => - pot match { - case pot: ThisRef => - // If we have all fields initialized, then we can promote This to hot. - val classRef = state.thisClass.info.asInstanceOf[ClassInfo].appliedRef - val allFieldsInited = classRef.fields.forall { denot => - val sym = denot.symbol - sym.isOneOf(Flags.Lazy | Flags.Deferred) || state.fieldsInited.contains(sym) - } - if (allFieldsInited) - Errors.empty - else - PromoteThis(pot, eff.source, state2.path).toErrors - case _: Cold => - PromoteCold(eff.source, state2.path).toErrors - - case pot @ Warm(cls, outer) => - val errors = state.test { check(Promote(outer)(eff.source)) } - if (errors.isEmpty) Errors.empty - else PromoteWarm(pot, eff.source, state2.path).toErrors - - case Fun(pots, effs) => - val errs1 = state.test { effs.flatMap { check(_) } } - val errs2 = state.test { pots.flatMap { pot => check(Promote(pot)(eff.source))(state.copy(path = Vector.empty)) } } - if (errs1.nonEmpty || errs2.nonEmpty) - UnsafePromotion(pot, eff.source, state2.path, errs1 ++ errs2).toErrors - else - Errors.empty - - case pot => - val (pots, effs) = expand(pot) - val effs2 = pots.map(Promote(_)(eff.source)) - (effs2 ++ effs).flatMap(check(_)) - } + case Promote(pot) => checkPromote(pot, eff.source) case FieldAccess(pot, field) => @@ -279,6 +247,47 @@ object Checking { } } + private def checkPromote(pot: Potential, source: Tree)(implicit state: State): Errors = + if (state.safePromoted.contains(pot)) Errors.empty + else + val errs = pot match { + case pot: ThisRef => + // If we have all fields initialized, then we can promote This to hot. + val classRef = state.thisClass.info.asInstanceOf[ClassInfo].appliedRef + val allFieldsInited = classRef.fields.forall { denot => + val sym = denot.symbol + sym.isOneOf(Flags.Lazy | Flags.Deferred) || state.fieldsInited.contains(sym) + } + if (allFieldsInited) + Errors.empty + else + PromoteThis(pot, source, state.path).toErrors + case _: Cold => + PromoteCold(source, state.path).toErrors + + case pot @ Warm(cls, outer) => + val errors = state.test { checkPromote(outer, source) } + if (errors.isEmpty) Errors.empty + else PromoteWarm(pot, source, state.path).toErrors + + case Fun(pots, effs) => + val errs1 = state.test { effs.flatMap { check(_) } } + val errs2 = state.test { pots.flatMap { pot => checkPromote(pot, source)(state.copy(path = Vector.empty)) } } + if (errs1.nonEmpty || errs2.nonEmpty) + UnsafePromotion(pot, source, state.path, errs1 ++ errs2).toErrors + else + Errors.empty + + case pot => + val (pots, effs) = expand(pot) + val effs2 = pots.map(Promote(_)(source)) + (effs2 ++ effs).flatMap(check(_)) + } + // If we can safely promote, then we don't need to check again + if (errs.isEmpty) + state.safePromoted += pot + errs + private def expand(pot: Potential)(implicit state: State): Summary = trace("expand " + pot.show, init, sum => Summary.show(sum.asInstanceOf[Summary])) { pot match { case MethodReturn(pot1, sym) => From f02b8e26de0ed806281f55544d940c8ebb4ee7bd Mon Sep 17 00:00:00 2001 From: Natsu Kagami Date: Thu, 11 Feb 2021 22:56:20 +0900 Subject: [PATCH 5/5] Make test fail again --- tests/init/neg/inner11.scala | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/init/neg/inner11.scala b/tests/init/neg/inner11.scala index 7a96a29f8a25..df5eb52a55c8 100644 --- a/tests/init/neg/inner11.scala +++ b/tests/init/neg/inner11.scala @@ -13,6 +13,7 @@ object NameKinds { type ThisInfo = Info val info: Info = new Info println(info.kind) // error + val n = 10 } } @@ -32,4 +33,4 @@ object NameKinds2 { val info: Info = new Info println(info.kind) // ok } -} \ No newline at end of file +}