Skip to content

Commit 0faa404

Browse files
committed
Handle access of parameters in constructors
1 parent 632b7d3 commit 0faa404

File tree

1 file changed

+40
-14
lines changed

1 file changed

+40
-14
lines changed

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

Lines changed: 40 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -181,6 +181,8 @@ class Semantic {
181181
def getOrElse(sym: Symbol, default: Value)(using Context): Value = env.getOrElse(sym, default)
182182

183183
def union(other: Env): Env = env ++ other
184+
185+
def isHot: Boolean = env.values.exists(_ != Hot)
184186
}
185187

186188
type Env = Env.Env
@@ -401,7 +403,7 @@ class Semantic {
401403
eval(ddef.rhs, addr, cls, cacheResult = true)
402404
else
403405
val errors = args.flatMap { arg => arg.promote("May only use initialized value as arguments", arg.source) }
404-
use(Env.empty) {
406+
use(if isLocal then env else Env.empty) {
405407
eval(ddef.rhs, addr, cls, cacheResult = true)
406408
}
407409
else if addr.canIgnoreMethodCall(target) then
@@ -452,7 +454,11 @@ class Semantic {
452454
val obj = Objekt(klass, fields = mutable.Map.empty, outers = mutable.Map(klass -> outer))
453455
heap.update(value, obj)
454456
val res = value.call(ctor, args, superType = NoType, source)
455-
Result(value, res.errors)
457+
458+
// Abstract instances of local classes inside 2nd constructor as Cold
459+
// This way, we avoid complicating the domain for Warm unnecessarily
460+
if !env.isHot then Result(Cold, res.errors)
461+
else Result(value, res.errors)
456462

457463
case Fun(body, params, thisV, klass, env) =>
458464
report.error("unexpected tree in instantiating a function, fun = " + body.show, source)
@@ -836,16 +842,29 @@ class Semantic {
836842
Result(Hot, Errors.empty)
837843

838844
case tmref: TermRef if tmref.prefix == NoPrefix =>
839-
Result(Hot, Errors.empty)
845+
val sym = tmref.symbol
846+
847+
def default() = Result(Hot, Nil)
848+
849+
if sym.is(Flags.Param) then
850+
if sym.owner.isConstructor then
851+
// instances of local classes inside secondary constructors cannot
852+
// reach here, as those values are abstracted by Cold instead of Warm.
853+
// This enables us to simplify the domain without sacrificing
854+
// expressiveness nor soundess, as local classes inside secondary
855+
// constructors are uncommon.
856+
Result(env.lookup(sym), Nil)
857+
else
858+
default()
859+
else
860+
default()
840861

841862
case tmref: TermRef =>
842863
cases(tmref.prefix, thisV, klass, source).select(tmref.symbol, source)
843864

844865
case tp @ ThisType(tref) =>
845-
if tref.symbol.is(Flags.Package) then Result(Hot, Errors.empty)
846-
else
847-
val value = resolveThis(tref.classSymbol.asClass, thisV, klass, source)
848-
Result(value, Errors.empty)
866+
val value = resolveThis(tref.classSymbol.asClass, thisV, klass, source)
867+
Result(value, Errors.empty)
849868

850869
case _: TermParamRef | _: RecThis =>
851870
// possible from checking effects of types
@@ -891,15 +910,18 @@ class Semantic {
891910
def init(tpl: Template, thisV: Addr, klass: ClassSymbol): Contextual[Result] = log("init " + klass.show, printer, res => res.asInstanceOf[Result].show) {
892911
val errorBuffer = new mutable.ArrayBuffer[Error]
893912

913+
val paramsMap = tpl.constr.termParamss.flatten.map { vdef =>
914+
vdef.name -> env.lookup(vdef.symbol)
915+
}.toMap
916+
894917
// init param fields
895-
klass.paramAccessors.foreach { acc =>
896-
if (!acc.is(Flags.Method)) {
897-
printer.println(acc.show + " initialized")
898-
thisV.updateField(acc, Hot)
899-
}
918+
klass.paramGetters.foreach { acc =>
919+
val value = paramsMap(acc.name.toTermName)
920+
thisV.updateField(acc, value)
921+
printer.println(acc.show + " initialized with " + value)
900922
}
901923

902-
def superCall(tref: TypeRef, ctor: Symbol, args: List[Value], source: Tree): Unit =
924+
def superCall(tref: TypeRef, ctor: Symbol, args: List[Value], source: Tree)(using Env): Unit =
903925
val cls = tref.classSymbol.asClass
904926
// update outer for super class
905927
val res = outerValue(tref, thisV, klass, source)
@@ -913,7 +935,7 @@ class Semantic {
913935
errorBuffer ++= res2.errors
914936

915937
// parents
916-
def initParent(parent: Tree) = parent match {
938+
def initParent(parent: Tree)(using Env) = parent match {
917939
case tree @ Block(stats, NewExpr(tref, New(tpt), ctor, argss)) => // can happen
918940
eval(stats, thisV, klass).foreach { res => errorBuffer ++= res.errors }
919941
val (erros, args) = evalArgs(argss.flatten, thisV, klass)
@@ -933,6 +955,8 @@ class Semantic {
933955
// see spec 5.1 about "Template Evaluation".
934956
// https://www.scala-lang.org/files/archive/spec/2.13/05-classes-and-objects.html
935957
if !klass.is(Flags.Trait) then
958+
given Env = Env.empty
959+
936960
// 1. first init parent class recursively
937961
// 2. initialize traits according to linearization order
938962
val superParent = tpl.parents.head
@@ -961,13 +985,15 @@ class Semantic {
961985
// class body
962986
tpl.body.foreach {
963987
case vdef : ValDef if !vdef.symbol.is(Flags.Lazy) =>
988+
given Env = Env.empty
964989
val res = eval(vdef.rhs, thisV, klass, cacheResult = true)
965990
errorBuffer ++= res.errors
966991
thisV.updateField(vdef.symbol, res.value)
967992

968993
case _: MemberDef =>
969994

970995
case tree =>
996+
given Env = Env.empty
971997
errorBuffer ++= eval(tree, thisV, klass).errors
972998
}
973999

0 commit comments

Comments
 (0)