@@ -93,11 +93,11 @@ class Objects(using Context @constructorOnly):
9393 * | UnknownValue // values whose source are unknown at compile time
9494 * vs ::= ValueSet(Set(ve)) // set of abstract values
9595 * 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
9797 * RefSet ::= Set(ref) // set of refs
9898 * Bottom ::= RefSet(Empty) // unreachable code
9999 * 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
101101 * EnvSet ::= Set(EnvRef)
102102 * InstanceBody ::= (valsMap: Map[Symbol, Value],
103103 outersMap: Map[ClassSymbol, Value],
@@ -405,13 +405,18 @@ class Objects(using Context @constructorOnly):
405405
406406 /** Environment for parameters */
407407 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
411411 */
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+
413418 def show (using Context ) =
414- " meth : " + meth .show + " \n " +
419+ " tree : " + tree .show + " \n " +
415420 " owner: " + owner.show
416421
417422 def valValue (sym : Symbol )(using EnvMap .EnvMapMutableData ): Value = EnvMap .readVal(this , sym)
@@ -454,36 +459,49 @@ class Objects(using Context @constructorOnly):
454459
455460 val NoEnv = EnvSet (Set .empty)
456461
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-
465462 def valValue (x : Symbol )(using env : EnvRef , ctx : Context , trace : Trace , envMap : EnvMap .EnvMapMutableData ): Value =
466463 if env.hasVal(x) then
467464 env.valValue(x)
468465 else
469466 report.warning(" [Internal error] Value not found " + x.show + " \n env = " + env.show + " . " + Trace .show, Trace .position)
470467 Bottom
471468
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 )
473471 (using State .Data , EnvMap .EnvMapMutableData , Trace ): EnvRef =
474- val env = EnvRef (meth , State .currentObject)
472+ val env = EnvRef (tree , State .currentObject)
475473 argMap.foreach(env.initVal(_, _))
476474 env.initThisV(thisV)
477475 env.initOuterEnvs(outerEnv)
478476 env
479477
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+
480498 /**
481499 * The main procedure for searching through the outer chain
482500 * @param target The symbol to search for if `bySymbol = true`; otherwise the method symbol of the target environment
483501 * @param scopeSet The set of scopes as starting point
484502 * @return The scopes that contains symbol `target` or whose method is `target`,
485503 * and the value for `C.this` where C is the enclosing class of the result scopes
486- */
504+ */
487505 private [Env ] def resolveEnvRecur (
488506 target : Symbol , envSet : EnvSet , bySymbol : Boolean = true )
489507 : Contextual [Option [EnvSet ]] = log(" Resolving environment, target = " + target + " , envSet = " + envSet, printer) {
@@ -493,7 +511,7 @@ class Objects(using Context @constructorOnly):
493511 if bySymbol then
494512 envSet.envs.filter(_.hasVal(target))
495513 else
496- envSet.envs.filter(_.meth == target)
514+ envSet.envs.filter(env => env.tree. isInstanceOf [ DefDef ] && env.tree. asInstanceOf [ DefDef ].symbol == target)
497515
498516 assert(filter.isEmpty || filter.size == envSet.envs.size, " Either all scopes or no scopes contain " + target)
499517 if (! filter.isEmpty) then
@@ -515,19 +533,6 @@ class Objects(using Context @constructorOnly):
515533 resolveEnvRecur(target, outerEnvsOfThis, bySymbol)
516534 }
517535
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-
531536 def setLocalVal (x : Symbol , value : Value )(using scope : Scope , ctx : Context , heap : Heap .MutableData , envMap : EnvMap .EnvMapMutableData ): Unit =
532537 assert(! x.isOneOf(Flags .Param | Flags .Mutable ), " Only local immutable variable allowed" )
533538 scope match
@@ -692,6 +697,11 @@ class Objects(using Context @constructorOnly):
692697 def setHeap (newHeap : Data )(using mutable : MutableData ): Unit = mutable.heap = newHeap
693698 end Heap
694699
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+ */
695705 object EnvMap :
696706 private case class EnvBody (
697707 valsMap : Map [Symbol , Value ],
@@ -1191,12 +1201,12 @@ class Objects(using Context @constructorOnly):
11911201
11921202 case ref : Ref =>
11931203 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
11961205 if ref.hasVal(target) then
11971206 ref.valValue(target)
11981207 else if target.hasSource then
11991208 val rhs = target.defTree.asInstanceOf [ValDef ].rhs
1209+ given Scope = Env .ofByName(target, rhs, ref, Env .NoEnv )
12001210 val result = eval(rhs, ref, target.owner.asClass, cacheResult = true )
12011211 ref.initVal(target, result)
12021212 result
@@ -1358,8 +1368,8 @@ class Objects(using Context @constructorOnly):
13581368 def evalByNameParam (value : Value ): Contextual [Value ] = value match
13591369 case Fun (code, thisV, klass, scope) =>
13601370 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
13631373 }
13641374 given Scope = byNameEnv
13651375 eval(code, thisV, klass, cacheResult = true )
@@ -1389,7 +1399,7 @@ class Objects(using Context @constructorOnly):
13891399 else
13901400 if sym.is(Flags .Lazy ) then
13911401 val outerThis = envSet.joinThisV
1392- given Scope = Env .ofByName(sym, outerThis, envSet)
1402+ given Scope = Env .ofByName(sym, sym.defTree, outerThis, envSet)
13931403 val rhs = sym.defTree.asInstanceOf [ValDef ].rhs
13941404 eval(rhs, outerThis, sym.enclosingClass.asClass, cacheResult = true )
13951405 else
@@ -2144,7 +2154,7 @@ class Objects(using Context @constructorOnly):
21442154 thisV
21452155 else
21462156 // `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)
21482158 val outerThis = thisV match {
21492159 case ref : Ref => ref.outerValue(klass)
21502160 case refSet : RefSet => refSet.joinOuters(klass)
0 commit comments