@@ -181,6 +181,8 @@ class Semantic {
181
181
def getOrElse (sym : Symbol , default : Value )(using Context ): Value = env.getOrElse(sym, default)
182
182
183
183
def union (other : Env ): Env = env ++ other
184
+
185
+ def isHot : Boolean = env.values.exists(_ != Hot )
184
186
}
185
187
186
188
type Env = Env .Env
@@ -401,7 +403,7 @@ class Semantic {
401
403
eval(ddef.rhs, addr, cls, cacheResult = true )
402
404
else
403
405
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) {
405
407
eval(ddef.rhs, addr, cls, cacheResult = true )
406
408
}
407
409
else if addr.canIgnoreMethodCall(target) then
@@ -452,7 +454,11 @@ class Semantic {
452
454
val obj = Objekt (klass, fields = mutable.Map .empty, outers = mutable.Map (klass -> outer))
453
455
heap.update(value, obj)
454
456
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)
456
462
457
463
case Fun (body, params, thisV, klass, env) =>
458
464
report.error(" unexpected tree in instantiating a function, fun = " + body.show, source)
@@ -836,16 +842,29 @@ class Semantic {
836
842
Result (Hot , Errors .empty)
837
843
838
844
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()
840
861
841
862
case tmref : TermRef =>
842
863
cases(tmref.prefix, thisV, klass, source).select(tmref.symbol, source)
843
864
844
865
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)
849
868
850
869
case _ : TermParamRef | _ : RecThis =>
851
870
// possible from checking effects of types
@@ -891,15 +910,18 @@ class Semantic {
891
910
def init (tpl : Template , thisV : Addr , klass : ClassSymbol ): Contextual [Result ] = log(" init " + klass.show, printer, res => res.asInstanceOf [Result ].show) {
892
911
val errorBuffer = new mutable.ArrayBuffer [Error ]
893
912
913
+ val paramsMap = tpl.constr.termParamss.flatten.map { vdef =>
914
+ vdef.name -> env.lookup(vdef.symbol)
915
+ }.toMap
916
+
894
917
// 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)
900
922
}
901
923
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 =
903
925
val cls = tref.classSymbol.asClass
904
926
// update outer for super class
905
927
val res = outerValue(tref, thisV, klass, source)
@@ -913,7 +935,7 @@ class Semantic {
913
935
errorBuffer ++= res2.errors
914
936
915
937
// parents
916
- def initParent (parent : Tree ) = parent match {
938
+ def initParent (parent : Tree )( using Env ) = parent match {
917
939
case tree @ Block (stats, NewExpr (tref, New (tpt), ctor, argss)) => // can happen
918
940
eval(stats, thisV, klass).foreach { res => errorBuffer ++= res.errors }
919
941
val (erros, args) = evalArgs(argss.flatten, thisV, klass)
@@ -933,6 +955,8 @@ class Semantic {
933
955
// see spec 5.1 about "Template Evaluation".
934
956
// https://www.scala-lang.org/files/archive/spec/2.13/05-classes-and-objects.html
935
957
if ! klass.is(Flags .Trait ) then
958
+ given Env = Env .empty
959
+
936
960
// 1. first init parent class recursively
937
961
// 2. initialize traits according to linearization order
938
962
val superParent = tpl.parents.head
@@ -961,13 +985,15 @@ class Semantic {
961
985
// class body
962
986
tpl.body.foreach {
963
987
case vdef : ValDef if ! vdef.symbol.is(Flags .Lazy ) =>
988
+ given Env = Env .empty
964
989
val res = eval(vdef.rhs, thisV, klass, cacheResult = true )
965
990
errorBuffer ++= res.errors
966
991
thisV.updateField(vdef.symbol, res.value)
967
992
968
993
case _ : MemberDef =>
969
994
970
995
case tree =>
996
+ given Env = Env .empty
971
997
errorBuffer ++= eval(tree, thisV, klass).errors
972
998
}
973
999
0 commit comments