Skip to content

Commit ba5f4f0

Browse files
committed
Refactoring accessLocal
1 parent ccab4eb commit ba5f4f0

File tree

3 files changed

+46
-44
lines changed

3 files changed

+46
-44
lines changed

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,13 +37,13 @@ class Checker extends Phase {
3737

3838
val traverser = new TreeTraverser {
3939
override def traverse(tree: Tree)(using Context): Unit =
40+
traverseChildren(tree)
4041
tree match {
4142
case tdef: MemberDef =>
4243
// self-type annotation ValDef has no symbol
4344
if tdef.name != nme.WILDCARD then
4445
tdef.symbol.defTree = tree
4546
case _ =>
46-
traverseChildren(tree)
4747
}
4848
}
4949

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@ object Errors {
6969

7070
/** Promote `this` under initialization to fully-initialized */
7171
case class PromoteError(msg: String, source: Tree, trace: Seq[Tree]) extends Error {
72-
def show(using Context): String = "Promote the value under initialization to fully-initialized. " + msg + "."
72+
def show(using Context): String = "Cannot prove that the value is fully initialized. " + msg + "."
7373
}
7474

7575
case class AccessCold(field: Symbol, source: Tree, trace: Seq[Tree]) extends Error {

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

Lines changed: 44 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -406,7 +406,6 @@ class Semantic {
406406
given Trace = trace1
407407
val cls = target.owner.enclosingClass.asClass
408408
val ddef = target.defTree.asInstanceOf[DefDef]
409-
// try early promotion here; if returns error, returns cold
410409
val env2 = Env(ddef, args.map(_.value).widenArgs)
411410
if target.isPrimaryConstructor then
412411
given Env = env2
@@ -497,6 +496,46 @@ class Semantic {
497496
Result(value2, errors)
498497
}
499498
}
499+
500+
def accessLocal(tmref: TermRef, klass: ClassSymbol, source: Tree): Contextual[Result] =
501+
val sym = tmref.symbol
502+
503+
def default() = Result(Hot, Nil)
504+
505+
if sym.is(Flags.Param) && sym.owner.isConstructor then
506+
// instances of local classes inside secondary constructors cannot
507+
// reach here, as those values are abstracted by Cold instead of Warm.
508+
// This enables us to simplify the domain without sacrificing
509+
// expressiveness nor soundess, as local classes inside secondary
510+
// constructors are uncommon.
511+
if sym.isContainedIn(klass) then
512+
Result(env.lookup(sym), Nil)
513+
else
514+
// We don't know much about secondary constructor parameters in outer scope.
515+
// It's always safe to approximate them with `Cold`.
516+
Result(Cold, Nil)
517+
else if sym.is(Flags.Param) then
518+
default()
519+
else
520+
sym.defTree match {
521+
case vdef: ValDef =>
522+
// resolve this for local variable
523+
val enclosingClass = sym.owner.enclosingClass.asClass
524+
val thisValue2 = resolveThis(enclosingClass, value, klass, source)
525+
thisValue2 match {
526+
case Hot => Result(Hot, Errors.empty)
527+
528+
case Cold => Result(Cold, Nil)
529+
530+
case addr: Addr => eval(vdef.rhs, addr, klass)
531+
532+
case _ =>
533+
report.error("unexpected defTree when accessing local variable, sym = " + sym.show + ", defTree = " + sym.defTree.show, source)
534+
default()
535+
}
536+
537+
case _ => default()
538+
}
500539
end extension
501540

502541
// ----- Promotion ----------------------------------------------------
@@ -685,7 +724,7 @@ class Semantic {
685724
}
686725

687726
/** Evaluate a list of expressions */
688-
def eval(exprs: List[Tree], thisV: Addr, klass: ClassSymbol): Contextual[List[Result]] =
727+
def eval(exprs: List[Tree], thisV: Addr, klass: ClassSymbol): Contextual[List[Result]] =
689728
exprs.map { expr => eval(expr, thisV, klass) }
690729

691730
/** Evaluate arguments of methods */
@@ -848,8 +887,7 @@ class Semantic {
848887
case vdef : ValDef =>
849888
// local val definition
850889
// TODO: support explicit @cold annotation for local definitions
851-
eval(vdef.rhs, thisV, klass, true)
852-
// .ensureHot("Local definitions may only hold initialized values", vdef)
890+
eval(vdef.rhs, thisV, klass, cacheResult = true)
853891

854892
case ddef : DefDef =>
855893
// local method
@@ -877,44 +915,8 @@ class Semantic {
877915
Result(Hot, Errors.empty)
878916

879917
case tmref: TermRef if tmref.prefix == NoPrefix =>
880-
val sym = tmref.symbol
881-
882-
def default() = Result(Hot, Nil)
883-
884-
if sym.is(Flags.Param) && sym.owner.isConstructor then
885-
// instances of local classes inside secondary constructors cannot
886-
// reach here, as those values are abstracted by Cold instead of Warm.
887-
// This enables us to simplify the domain without sacrificing
888-
// expressiveness nor soundess, as local classes inside secondary
889-
// constructors are uncommon.
890-
if sym.isContainedIn(klass) then
891-
Result(env.lookup(sym), Nil)
892-
else
893-
// We don't know much about secondary constructor parameters in outer scope.
894-
// It's always safe to approximate them with `Cold`.
895-
Result(Cold, Nil)
896-
else
897-
sym.defTree match {
898-
case vdef: ValDef => {
899-
// resolve this for local variable
900-
val enclosingClass = sym.owner.enclosingClass.asClass
901-
val thisValue2 = resolveThis(enclosingClass, thisV, klass, source)
902-
thisValue2 match {
903-
case Hot => Result(Hot, Errors.empty)
904-
case Cold => {
905-
val error = AccessCold(sym, source, trace.toVector)
906-
Result(Hot, error :: Nil)
907-
}
908-
case addr: Addr => {
909-
val res = eval(vdef.rhs, addr, klass)
910-
if res.value.promote("Try promote", source).isEmpty then Result(Hot, Errors.empty) else res
911-
}
912-
case _ => ???
913-
}
914-
}
915-
case _ => default()
916-
}
917-
918+
thisV.accessLocal(tmref, klass, source)
919+
918920
case tmref: TermRef =>
919921
cases(tmref.prefix, thisV, klass, source).select(tmref.symbol, source)
920922

0 commit comments

Comments
 (0)