@@ -144,56 +144,6 @@ object Semantic:
144
144
145
145
def hasField(f: Symbol) = fields.contains(f)
146
146
147
- /** The environment stores values for constructor parameters
148
- *
149
- * For performance and usability, we restrict parameters to be either `Cold`
150
- * or `Hot`.
151
- *
152
- * Despite that we have environment for evaluating expressions in secondary
153
- * constructors, we don't need to put environment as the cache key. The
154
- * reason is that constructor parameters are determined by the value of
155
- * `this` --- it suffices to make the value of `this` as part of the cache
156
- * key.
157
- *
158
- * This crucially depends on the fact that in the initialization process
159
- * there can be exactly one call to a specific constructor for a given
160
- * receiver. However, once we relax the design to allow non-hot values to
161
- * methods and functions, we have to put the environment as part of the cache
162
- * key. The reason is that given the same receiver, a method or function may
163
- * be called with different arguments -- they are not decided by the receiver
164
- * anymore.
165
- *
166
- * TODO: remove Env as it is only used to pass value from `callConstructor` -> `eval` -> `init`.
167
- * It goes through `eval` for caching (termination) purposes.
168
- */
169
- object Env:
170
- opaque type Env = Map[Symbol, Value]
171
-
172
- val empty: Env = Map.empty
173
-
174
- def apply(bindings: Map[Symbol, Value]): Env = bindings
175
-
176
- def apply(ddef: DefDef, args: List[Value])(using Context): Env =
177
- val params = ddef.termParamss.flatten.map(_.symbol)
178
- assert(args.size == params.size, "arguments = " + args.size + ", params = " + params.size)
179
- params.zip(args).toMap
180
-
181
- extension (env: Env)
182
- def lookup(sym: Symbol)(using Context): Value = env(sym)
183
-
184
- def getOrElse(sym: Symbol, default: Value)(using Context): Value = env.getOrElse(sym, default)
185
-
186
- def union(other: Env): Env = env ++ other
187
-
188
- def isHot: Boolean = env.values.forall(_ == Hot)
189
- end Env
190
-
191
- type Env = Env.Env
192
- inline def env(using env: Env) = env
193
- inline def withEnv[T](env: Env)(op: Env ?=> T): T = op(using env)
194
-
195
- import Env.*
196
-
197
147
object Promoted:
198
148
class PromotionInfo:
199
149
var isCurrentObjectPromoted: Boolean = false
@@ -399,7 +349,7 @@ object Semantic:
399
349
// ----- Checker State -----------------------------------
400
350
401
351
/** The state that threads through the interpreter */
402
- type Contextual[T] = (Env, Context, Trace, Promoted, Cache, Reporter) ?=> T
352
+ type Contextual[T] = (Context, Trace, Promoted, Cache, Reporter) ?=> T
403
353
404
354
// ----- Error Handling -----------------------------------
405
355
@@ -692,10 +642,8 @@ object Semantic:
692
642
outer.instantiate(klass, klass.primaryConstructor, args)
693
643
else
694
644
reporter.reportAll(argErrors)
695
- withEnv(if isLocal then env else Env.empty) {
696
- extendTrace(ddef) {
697
- eval(ddef.rhs, ref, cls, cacheResult = true)
698
- }
645
+ extendTrace(ddef) {
646
+ eval(ddef.rhs, ref, cls, cacheResult = true)
699
647
}
700
648
else if ref.canIgnoreMethodCall(target) then
701
649
Hot
@@ -726,15 +674,14 @@ object Semantic:
726
674
}
727
675
728
676
def callConstructor(ctor: Symbol, args: List[ArgInfo]): Contextual[Value] = log("call " + ctor.show + ", args = " + args.map(_.value.show), printer, (_: Value).show) {
729
- // init "fake" param fields for the secondary constructor
730
- def addParamsAsFields(env: Env, ref: Ref, ctorDef: DefDef) = {
731
- val paramSyms = ctorDef.termParamss.flatten.map(_.symbol)
732
- paramSyms.map { acc =>
733
- val value = env.lookup(acc)
734
- ref.updateField(acc, value)
735
- printer.println(acc.show + " initialized with " + value)
736
- }
737
- }
677
+ // init "fake" param fields for parameters of primary and secondary constructors
678
+ def addParamsAsFields(args: List[Value], ref: Ref, ctorDef: DefDef) =
679
+ val params = ctorDef.termParamss.flatten.map(_.symbol)
680
+ assert(args.size == params.size, "arguments = " + args.size + ", params = " + params.size)
681
+ for (param, value) <- params.zip(args) do
682
+ ref.updateField(param, value)
683
+ printer.println(param.show + " initialized with " + value)
684
+
738
685
value match {
739
686
case Hot | Cold | _: RefSet | _: Fun =>
740
687
report.error("unexpected constructor call, meth = " + ctor + ", value = " + value, trace.toVector.last)
@@ -744,13 +691,12 @@ object Semantic:
744
691
if ctor.hasSource then
745
692
val cls = ctor.owner.enclosingClass.asClass
746
693
val ddef = ctor.defTree.asInstanceOf[DefDef]
747
- val env2 = Env(ddef, args.map(_.value).widenArgs)
694
+ val args2 = args.map(_.value).widenArgs
695
+ addParamsAsFields(args2, ref, ddef)
748
696
if ctor.isPrimaryConstructor then
749
- given Env = env2
750
697
val tpl = cls.defTree.asInstanceOf[TypeDef].rhs.asInstanceOf[Template]
751
698
extendTrace(cls.defTree) { init(tpl, ref, cls) }
752
699
else
753
- addParamsAsFields(env2, ref, ddef)
754
700
val initCall = ddef.rhs match
755
701
case Block(call :: _, _) => call
756
702
case call => call
@@ -763,14 +709,13 @@ object Semantic:
763
709
if ctor.hasSource then
764
710
val cls = ctor.owner.enclosingClass.asClass
765
711
val ddef = ctor.defTree.asInstanceOf[DefDef]
766
- val env2 = Env(ddef, args.map(_.value).widenArgs)
712
+ val args2 = args.map(_.value).widenArgs
713
+ addParamsAsFields(args2, ref, ddef)
767
714
if ctor.isPrimaryConstructor then
768
- given Env = env2
769
715
val tpl = cls.defTree.asInstanceOf[TypeDef].rhs.asInstanceOf[Template]
770
716
extendTrace(cls.defTree) { eval(tpl, ref, cls, cacheResult = true) }
771
717
ref
772
718
else
773
- addParamsAsFields(env2, ref, ddef)
774
719
extendTrace(ddef) { eval(ddef.rhs, ref, cls, cacheResult = true) }
775
720
else if ref.canIgnoreMethodCall(ctor) then
776
721
Hot
@@ -1057,16 +1002,18 @@ object Semantic:
1057
1002
val thisRef = task.value
1058
1003
val tpl = thisRef.klass.defTree.asInstanceOf[TypeDef].rhs.asInstanceOf[Template]
1059
1004
1060
- val paramValues = tpl.constr.termParamss.flatten.map(param => param.symbol -> Hot).toMap
1061
-
1062
1005
@tailrec
1063
1006
def iterate(): Unit = {
1064
1007
given Promoted = Promoted.empty
1065
1008
given Trace = Trace.empty.add(thisRef.klass.defTree)
1066
- given Env = Env(paramValues)
1067
1009
given reporter: Reporter.BufferedReporter = new Reporter.BufferedReporter
1068
1010
1069
1011
thisRef.ensureFresh()
1012
+
1013
+ // set up constructor parameters
1014
+ for param <- tpl.constr.termParamss.flatten do
1015
+ thisRef.updateField(param.symbol, Hot)
1016
+
1070
1017
log("checking " + task) { eval(tpl, thisRef, thisRef.klass) }
1071
1018
reporter.errors.foreach(_.issue)
1072
1019
@@ -1433,7 +1380,7 @@ object Semantic:
1433
1380
/** Initialize part of an abstract object in `klass` of the inheritance chain */
1434
1381
def init(tpl: Template, thisV: Ref, klass: ClassSymbol): Contextual[Value] = log("init " + klass.show, printer, (_: Value).show) {
1435
1382
val paramsMap = tpl.constr.termParamss.flatten.map { vdef =>
1436
- vdef.name -> env.lookup (vdef.symbol)
1383
+ vdef.name -> thisV.objekt.field (vdef.symbol)
1437
1384
}.toMap
1438
1385
1439
1386
// init param fields
@@ -1446,7 +1393,7 @@ object Semantic:
1446
1393
// Tasks is used to schedule super constructor calls.
1447
1394
// Super constructor calls are delayed until all outers are set.
1448
1395
type Tasks = mutable.ArrayBuffer[() => Unit]
1449
- def superCall(tref: TypeRef, ctor: Symbol, args: List[ArgInfo], tasks: Tasks)(using Env) : Unit =
1396
+ def superCall(tref: TypeRef, ctor: Symbol, args: List[ArgInfo], tasks: Tasks): Unit =
1450
1397
val cls = tref.classSymbol.asClass
1451
1398
// update outer for super class
1452
1399
val res = outerValue(tref, thisV, klass)
@@ -1461,7 +1408,7 @@ object Semantic:
1461
1408
}
1462
1409
1463
1410
// parents
1464
- def initParent(parent: Tree, tasks: Tasks)(using Env) =
1411
+ def initParent(parent: Tree, tasks: Tasks) =
1465
1412
parent match
1466
1413
case tree @ Block(stats, NewExpr(tref, New(tpt), ctor, argss)) => // can happen
1467
1414
eval(stats, thisV, klass)
@@ -1479,8 +1426,6 @@ object Semantic:
1479
1426
// see spec 5.1 about "Template Evaluation".
1480
1427
// https://www.scala-lang.org/files/archive/spec/2.13/05-classes-and-objects.html
1481
1428
if !klass.is(Flags.Trait) then
1482
- given Env = Env.empty
1483
-
1484
1429
// outers are set first
1485
1430
val tasks = new mutable.ArrayBuffer[() => Unit]
1486
1431
@@ -1526,18 +1471,16 @@ object Semantic:
1526
1471
// class body
1527
1472
if thisV.isThisRef || !thisV.asInstanceOf[Warm].isPopulatingParams then tpl.body.foreach {
1528
1473
case vdef : ValDef if !vdef.symbol.is(Flags.Lazy) && !vdef.rhs.isEmpty =>
1529
- given Env = Env.empty
1530
1474
val res = eval(vdef.rhs, thisV, klass)
1531
1475
thisV.updateField(vdef.symbol, res)
1532
1476
fieldsChanged = true
1533
1477
1534
1478
case _: MemberDef =>
1535
1479
1536
1480
case tree =>
1537
- if fieldsChanged && thisV.isThisRef then thisV.asInstanceOf[ThisRef].tryPromoteCurrentObject()
1481
+ if fieldsChanged && thisV.isThisRef then
1482
+ thisV.asInstanceOf[ThisRef].tryPromoteCurrentObject()
1538
1483
fieldsChanged = false
1539
-
1540
- given Env = Env.empty
1541
1484
eval(tree, thisV, klass)
1542
1485
}
1543
1486
0 commit comments