@@ -93,11 +93,11 @@ class Objects(using Context @constructorOnly):
93
93
* | UnknownValue // values whose source are unknown at compile time
94
94
* vs ::= ValueSet(Set(ve)) // set of abstract values
95
95
* Value ::= ve | vs | Package
96
- * Ref ::= ObjectRef | InstanceRef | ArrayRef // values that represent a reference to some (global or instance) object
96
+ * Ref ::= ObjectRef | InstanceRef | ArrayRef // values that represent a reference to some (global or instance) object
97
97
* RefSet ::= Set(ref) // set of refs
98
98
* Bottom ::= RefSet(Empty) // unreachable code
99
99
* ThisValue ::= Ref | RefSet // possible values for 'this'
100
- * EnvRef(meth , ownerObject) // represents environments for methods or functions
100
+ * EnvRef(tree , ownerObject) // represents environments for evaluating methods, functions, or lazy/by-name values
101
101
* EnvSet ::= Set(EnvRef)
102
102
* InstanceBody ::= (valsMap: Map[Symbol, Value],
103
103
outersMap: Map[ClassSymbol, Value],
@@ -405,13 +405,18 @@ class Objects(using Context @constructorOnly):
405
405
406
406
/** Environment for parameters */
407
407
object Env :
408
- /** Local environments can be deeply nested, therefore we need `outer`.
409
- *
410
- * For local variables in rhs of class field definitions, the `meth` is the primary constructor.
408
+ /** Represents environments for evaluating methods, functions, or lazy/by-name values
409
+ * For methods or closures, `tree` is the DefDef of the method.
410
+ * For lazy/by-name values, `tree` is the rhs of the definition or the argument passed to by-name param
411
411
*/
412
- case class EnvRef (meth : Symbol , owner : ClassSymbol )(using Trace ) extends Scope :
412
+ case class EnvRef (tree : Tree , owner : ClassSymbol )(using Trace ) extends Scope :
413
+ override def equals (that : Any ): Boolean =
414
+ that.isInstanceOf [EnvRef ] &&
415
+ (that.asInstanceOf [EnvRef ].tree eq tree) &&
416
+ (that.asInstanceOf [EnvRef ].owner == owner)
417
+
413
418
def show (using Context ) =
414
- " meth : " + meth .show + " \n " +
419
+ " tree : " + tree .show + " \n " +
415
420
" owner: " + owner.show
416
421
417
422
def valValue (sym : Symbol )(using EnvMap .EnvMapMutableData ): Value = EnvMap .readVal(this , sym)
@@ -454,36 +459,49 @@ class Objects(using Context @constructorOnly):
454
459
455
460
val NoEnv = EnvSet (Set .empty)
456
461
457
- /** An empty environment can be used for non-method environments, e.g., field initializers.
458
- *
459
- * The owner for the local environment for field initializers is the primary constructor of the
460
- * enclosing class.
461
- */
462
- def emptyEnv (meth : Symbol )(using Context , State .Data , EnvMap .EnvMapMutableData , Trace ): EnvRef =
463
- _of(Map .empty, meth, Bottom , NoEnv )
464
-
465
462
def valValue (x : Symbol )(using env : EnvRef , ctx : Context , trace : Trace , envMap : EnvMap .EnvMapMutableData ): Value =
466
463
if env.hasVal(x) then
467
464
env.valValue(x)
468
465
else
469
466
report.warning(" [Internal error] Value not found " + x.show + " \n env = " + env.show + " . " + Trace .show, Trace .position)
470
467
Bottom
471
468
472
- private [Env ] def _of (argMap : Map [Symbol , Value ], meth : Symbol , thisV : ThisValue , outerEnv : EnvSet )
469
+ /** The method of creating an Env that evaluates `tree` */
470
+ private [Env ] def _of (argMap : Map [Symbol , Value ], tree : Tree , thisV : ThisValue , outerEnv : EnvSet )
473
471
(using State .Data , EnvMap .EnvMapMutableData , Trace ): EnvRef =
474
- val env = EnvRef (meth , State .currentObject)
472
+ val env = EnvRef (tree , State .currentObject)
475
473
argMap.foreach(env.initVal(_, _))
476
474
env.initThisV(thisV)
477
475
env.initOuterEnvs(outerEnv)
478
476
env
479
477
478
+ /**
479
+ * Creates an environment that evaluates the body of a method or the body of a closure
480
+ */
481
+ def ofDefDef (ddef : DefDef , args : List [Value ], thisV : ThisValue , outerEnv : EnvSet )
482
+ (using State .Data , EnvMap .EnvMapMutableData , Trace ): EnvRef =
483
+ val params = ddef.termParamss.flatten.map(_.symbol)
484
+ assert(args.size == params.size, " arguments = " + args.size + " , params = " + params.size)
485
+ // assert(ddef.symbol.owner.is(Method) ^ (outerEnv == NoEnv), "ddef.owner = " + ddef.symbol.owner.show + ", outerEnv = " + outerEnv + ", " + ddef.source)
486
+ _of(params.zip(args).toMap, ddef, thisV, outerEnv)
487
+
488
+
489
+ /**
490
+ * Creates an environment that evaluates a lazy val with `tree` as rhs
491
+ * or evaluates a by-name parameter where `tree` is the argument tree
492
+ */
493
+ def ofByName (sym : Symbol , tree : Tree , thisV : ThisValue , outerEnv : EnvSet )
494
+ (using State .Data , EnvMap .EnvMapMutableData , Trace ): EnvRef =
495
+ assert((sym.is(Flags .Param ) && sym.info.isInstanceOf [ExprType ]) || sym.is(Flags .Lazy ));
496
+ _of(Map .empty, tree, thisV, outerEnv)
497
+
480
498
/**
481
499
* The main procedure for searching through the outer chain
482
500
* @param target The symbol to search for if `bySymbol = true`; otherwise the method symbol of the target environment
483
501
* @param scopeSet The set of scopes as starting point
484
502
* @return The scopes that contains symbol `target` or whose method is `target`,
485
503
* and the value for `C.this` where C is the enclosing class of the result scopes
486
- */
504
+ */
487
505
private [Env ] def resolveEnvRecur (
488
506
target : Symbol , envSet : EnvSet , bySymbol : Boolean = true )
489
507
: Contextual [Option [EnvSet ]] = log(" Resolving environment, target = " + target + " , envSet = " + envSet, printer) {
@@ -493,7 +511,7 @@ class Objects(using Context @constructorOnly):
493
511
if bySymbol then
494
512
envSet.envs.filter(_.hasVal(target))
495
513
else
496
- envSet.envs.filter(_.meth == target)
514
+ envSet.envs.filter(env => env.tree. isInstanceOf [ DefDef ] && env.tree. asInstanceOf [ DefDef ].symbol == target)
497
515
498
516
assert(filter.isEmpty || filter.size == envSet.envs.size, " Either all scopes or no scopes contain " + target)
499
517
if (! filter.isEmpty) then
@@ -515,19 +533,6 @@ class Objects(using Context @constructorOnly):
515
533
resolveEnvRecur(target, outerEnvsOfThis, bySymbol)
516
534
}
517
535
518
-
519
- def ofDefDef (ddef : DefDef , args : List [Value ], thisV : ThisValue , outerEnv : EnvSet )
520
- (using State .Data , EnvMap .EnvMapMutableData , Trace ): EnvRef =
521
- val params = ddef.termParamss.flatten.map(_.symbol)
522
- assert(args.size == params.size, " arguments = " + args.size + " , params = " + params.size)
523
- // assert(ddef.symbol.owner.is(Method) ^ (outerEnv == NoEnv), "ddef.owner = " + ddef.symbol.owner.show + ", outerEnv = " + outerEnv + ", " + ddef.source)
524
- _of(params.zip(args).toMap, ddef.symbol, thisV, outerEnv)
525
-
526
- def ofByName (byNameParam : Symbol , thisV : ThisValue , outerEnv : EnvSet )
527
- (using State .Data , EnvMap .EnvMapMutableData , Trace ): EnvRef =
528
- assert(byNameParam.is(Flags .Param ) && byNameParam.info.isInstanceOf [ExprType ]);
529
- _of(Map .empty, byNameParam, thisV, outerEnv)
530
-
531
536
def setLocalVal (x : Symbol , value : Value )(using scope : Scope , ctx : Context , heap : Heap .MutableData , envMap : EnvMap .EnvMapMutableData ): Unit =
532
537
assert(! x.isOneOf(Flags .Param | Flags .Mutable ), " Only local immutable variable allowed" )
533
538
scope match
@@ -692,6 +697,11 @@ class Objects(using Context @constructorOnly):
692
697
def setHeap (newHeap : Data )(using mutable : MutableData ): Unit = mutable.heap = newHeap
693
698
end Heap
694
699
700
+ /**
701
+ * Local environments can be deeply nested, therefore we need `outerEnvs`, which stores the immediate outer environment.
702
+ * If the immediate enclosing scope of an environment is a template, then `outerEnvs` is empty in EnvMap.
703
+ * We can restore outerEnvs of `this` in the heap.
704
+ */
695
705
object EnvMap :
696
706
private case class EnvBody (
697
707
valsMap : Map [Symbol , Value ],
@@ -1191,12 +1201,12 @@ class Objects(using Context @constructorOnly):
1191
1201
1192
1202
case ref : Ref =>
1193
1203
val target = if needResolve then resolve(ref.klass, field) else field
1194
- if target.is(Flags .Lazy ) then
1195
- given Scope = Env .emptyEnv(target.owner.asInstanceOf [ClassSymbol ].primaryConstructor)
1204
+ if target.is(Flags .Lazy ) then // select a lazy field
1196
1205
if ref.hasVal(target) then
1197
1206
ref.valValue(target)
1198
1207
else if target.hasSource then
1199
1208
val rhs = target.defTree.asInstanceOf [ValDef ].rhs
1209
+ given Scope = Env .ofByName(target, rhs, ref, Env .NoEnv )
1200
1210
val result = eval(rhs, ref, target.owner.asClass, cacheResult = true )
1201
1211
ref.initVal(target, result)
1202
1212
result
@@ -1358,8 +1368,8 @@ class Objects(using Context @constructorOnly):
1358
1368
def evalByNameParam (value : Value ): Contextual [Value ] = value match
1359
1369
case Fun (code, thisV, klass, scope) =>
1360
1370
val byNameEnv = scope match {
1361
- case ref : Ref => Env .ofByName(sym, thisV, Env .NoEnv )
1362
- case env : Env .EnvRef => Env .ofByName(sym, thisV, Env .EnvSet (Set (env)))
1371
+ case ref : Ref => Env .ofByName(sym, code, thisV, Env .NoEnv ) // for by-name arguments of constructors
1372
+ case env : Env .EnvRef => Env .ofByName(sym, code, thisV, Env .EnvSet (Set (env))) // for by-name arguments of methods/functions
1363
1373
}
1364
1374
given Scope = byNameEnv
1365
1375
eval(code, thisV, klass, cacheResult = true )
@@ -1389,7 +1399,7 @@ class Objects(using Context @constructorOnly):
1389
1399
else
1390
1400
if sym.is(Flags .Lazy ) then
1391
1401
val outerThis = envSet.joinThisV
1392
- given Scope = Env .ofByName(sym, outerThis, envSet)
1402
+ given Scope = Env .ofByName(sym, sym.defTree, outerThis, envSet)
1393
1403
val rhs = sym.defTree.asInstanceOf [ValDef ].rhs
1394
1404
eval(rhs, outerThis, sym.enclosingClass.asClass, cacheResult = true )
1395
1405
else
@@ -2144,7 +2154,7 @@ class Objects(using Context @constructorOnly):
2144
2154
thisV
2145
2155
else
2146
2156
// `target` must enclose `klass`
2147
- assert(klass.enclosingClassNamed (target.name) != NoSymbol , target.show + " does not enclose " + klass.show)
2157
+ assert(klass.ownersIterator.contains (target) , target.show + " does not enclose " + klass.show)
2148
2158
val outerThis = thisV match {
2149
2159
case ref : Ref => ref.outerValue(klass)
2150
2160
case refSet : RefSet => refSet.joinOuters(klass)
0 commit comments