@@ -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