Skip to content

Commit 3fccd63

Browse files
committed
Implement promotion
1 parent 5a3e3d1 commit 3fccd63

File tree

4 files changed

+72
-15
lines changed

4 files changed

+72
-15
lines changed

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

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -342,7 +342,7 @@ object Checking {
342342
for (eff <- buffer.toList) {
343343
val errs = check(eff)
344344
if !errs.isEmpty then
345-
return UnsafePromotion(warm, eff.source, state.path, errs.toList).toErrors
345+
return UnsafePromotion(eff.source, state.path, errs.toList).toErrors
346346
}
347347
Errors.empty
348348

@@ -355,7 +355,7 @@ object Checking {
355355
Errors.empty
356356
else pot match {
357357
case pot: ThisRef =>
358-
PromoteThis(pot, eff.source, state.path).toErrors
358+
PromoteThis(eff.source, state.path).toErrors
359359

360360
case _: Cold =>
361361
PromoteCold(eff.source, state.path).toErrors
@@ -374,7 +374,7 @@ object Checking {
374374
}
375375

376376
if (errs1.nonEmpty || errs2.nonEmpty)
377-
UnsafePromotion(pot, eff.source, state.path, errs1 ++ errs2).toErrors
377+
UnsafePromotion(eff.source, state.path, errs1 ++ errs2).toErrors
378378
else
379379
Errors.empty
380380

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

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ import Types._, Symbols._, Contexts._
1212
import Effects._, Potentials._
1313

1414
object Errors {
15-
type Errors = List[Error]
15+
type Errors = Seq[Error]
1616
val empty: Errors = Nil
1717

1818
def show(errs: Errors)(using Context): String =
@@ -70,12 +70,12 @@ object Errors {
7070
}
7171

7272
/** Promote `this` under initialization to fully-initialized */
73-
case class PromoteThis(pot: ThisRef, source: Tree, trace: Vector[Tree]) extends Error {
73+
case class PromoteThis(source: Tree, trace: Vector[Tree]) extends Error {
7474
def show(using Context): String = "Promote the value under initialization to fully-initialized."
7575
}
7676

7777
/** Promote `this` under initialization to fully-initialized */
78-
case class PromoteWarm(pot: Warm, source: Tree, trace: Vector[Tree]) extends Error {
78+
case class PromoteWarm(source: Tree, trace: Vector[Tree]) extends Error {
7979
def show(using Context): String =
8080
"Promoting the value under initialization to fully-initialized."
8181
}
@@ -102,7 +102,7 @@ object Errors {
102102
}
103103

104104
/** Promote a value under initialization to fully-initialized */
105-
case class UnsafePromotion(pot: Potential, source: Tree, trace: Vector[Tree], errors: Errors) extends Error {
105+
case class UnsafePromotion(source: Tree, trace: Vector[Tree], errors: Errors) extends Error {
106106
assert(errors.nonEmpty)
107107

108108
override def issue(using Context): Unit =

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

Lines changed: 64 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -45,8 +45,7 @@ class Semantic {
4545
* of the heap, we may handle it in a simple way.
4646
*/
4747
case class ThisRef(klass: ClassSymbol)(val fields: mutable.Map[Symbol, Value]) extends Value {
48-
def updateField(field: Symbol, value: Value): Unit =
49-
fields(field) = value
48+
var allFieldsInitialized: Boolean = false
5049
}
5150

5251
/** An object with all fields initialized but reaches objects under initialization
@@ -99,11 +98,8 @@ class Semantic {
9998

10099
def +(error: Error): Result = this.copy(errors = this.errors :+ error)
101100

102-
def ensureHot(msg: String, source: Tree)(using Trace): Result =
103-
if value == Hot then this
104-
else
105-
// TODO: define a new error
106-
this + PromoteCold(source, trace)
101+
def ensureHot(msg: String, source: Tree)(using Context, Trace): Result =
102+
this ++ value.promote(msg, source)
107103

108104
def select(f: Symbol, source: Tree)(using Context, Trace): Result =
109105
value.select(f, source) ++ errors
@@ -270,6 +266,67 @@ class Semantic {
270266
}
271267
end extension
272268

269+
extension (value: Value)
270+
def canDirectlyPromote(using Context): Boolean =
271+
value match
272+
case Hot => true
273+
case Cold => false
274+
275+
case warm: Warm =>
276+
warm.outer.canDirectlyPromote
277+
278+
case thisRef: ThisRef =>
279+
thisRef.allFieldsInitialized || {
280+
// If we have all fields initialized, then we can promote This to hot.
281+
thisRef.allFieldsInitialized = thisRef.klass.appliedRef.fields.forall { denot =>
282+
val sym = denot.symbol
283+
sym.isOneOf(Flags.Lazy | Flags.Deferred) || thisRef.fields.contains(sym)
284+
}
285+
thisRef.allFieldsInitialized
286+
}
287+
288+
case fun: Fun => false
289+
290+
case RefSet(refs) =>
291+
refs.forall(_.canDirectlyPromote)
292+
293+
end canDirectlyPromote
294+
295+
/** Promotion of values to hot */
296+
def promote(msg: String, source: Tree)(using Context, Trace): List[Error] =
297+
value match
298+
case Hot => Nil
299+
300+
case Cold => PromoteCold(source, trace) :: Nil
301+
302+
case thisRef: ThisRef =>
303+
if thisRef.canDirectlyPromote then Nil
304+
else PromoteThis(source, trace) :: Nil
305+
306+
case warm: Warm =>
307+
if warm.outer.canDirectlyPromote then Nil
308+
else PromoteWarm(source, trace) :: Nil
309+
310+
case Fun(body, thisV, klass) =>
311+
val res = eval(body, thisV, klass)
312+
val errors2 = res.value.promote(msg, source)
313+
if (res.errors.nonEmpty || errors2.nonEmpty)
314+
UnsafePromotion(source, trace, res.errors ++ errors2) :: Nil
315+
else
316+
Nil
317+
318+
case RefSet(refs) =>
319+
refs.flatMap(_.promote(msg, source))
320+
end extension
321+
322+
extension (ref: ThisRef | Warm)
323+
def updateField(field: Symbol, value: Value): Unit =
324+
ref match
325+
case thisRef: ThisRef => thisRef.fields(field) = value
326+
case warm: Warm => // ignore
327+
end extension
328+
329+
273330
// ----- Semantic definition --------------------------------
274331

275332
/** Evaluate an expression with the given value for `this` in a given class `klass`

tests/init/neg/function1.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ class Foo {
44
val fun2: Int => Int = n => 1 + n + list.size
55
fun2(5)
66

7-
List(5, 9).map(n => 2 + n + list.size)
7+
List(5, 9).map(n => 2 + n + list.size) // error
88

99
final val list = List(1, 2, 3) // error
1010

0 commit comments

Comments
 (0)