@@ -182,8 +182,15 @@ object Objects:
182
182
183
183
def widen (height : Int )(using Context ): Data
184
184
185
+ def level : Int
186
+
185
187
/** Local environments can be deeply nested, therefore we need `outer`. */
186
- private case class LocalEnv (private [Env ] val params : Map [Symbol , Value ], owner : Symbol , outer : Data ) extends Data :
188
+ private case class LocalEnv (private [Env ] val params : Map [Symbol , Value ], owner : Symbol , outer : Data )(using Context ) extends Data :
189
+ val level = outer.level + 1
190
+
191
+ if (level > 3 )
192
+ report.warning(" [Internal error] Deeply nested environemnt, level = " + level + " , " + owner.show + " in " + owner.enclosingClass.show, owner.defTree)
193
+
187
194
private [Env ] val locals : mutable.Map [Symbol , Value ] = mutable.Map .empty
188
195
189
196
private [Env ] def get (x : Symbol )(using Context ): Option [Value ] =
@@ -204,6 +211,8 @@ object Objects:
204
211
end LocalEnv
205
212
206
213
object NoEnv extends Data :
214
+ val level = 0
215
+
207
216
private [Env ] def get (x : Symbol )(using Context ): Option [Value ] =
208
217
throw new RuntimeException (" Invalid usage of non-existent env" )
209
218
@@ -215,7 +224,7 @@ object Objects:
215
224
216
225
/** An empty environment can be used for non-method environments, e.g., field initializers.
217
226
*/
218
- def emptyEnv (owner : Symbol ): Data = new LocalEnv (Map .empty, owner, NoEnv )
227
+ def emptyEnv (owner : Symbol )( using Context ) : Data = new LocalEnv (Map .empty, owner, NoEnv )
219
228
220
229
def apply (x : Symbol )(using data : Data , ctx : Context ): Value = data.get(x).get
221
230
@@ -238,31 +247,31 @@ object Objects:
238
247
throw new RuntimeException (" Incorrect local environment for initializing " + x.show)
239
248
240
249
/**
241
- * Resolve the definition environment for the given local variable .
250
+ * Resolve the environment owned by the given symbol .
242
251
*
243
- * A local variable could be located in outer scope with intermixed classes between its
252
+ * The owner (e.g., method) could be located in outer scope with intermixed classes between its
244
253
* definition site and usage site.
245
254
*
246
255
* Due to widening, the corresponding environment might not exist. As a result reading the local
247
256
* variable will return `Cold` and it's forbidden to write to the local variable.
248
257
*
249
- * @param sym The symbol of the local variable
258
+ * @param meth The method which owns the environment
250
259
* @param thisV The value for `this` of the enclosing class where the local variable is referenced.
251
260
* @param env The local environment where the local variable is referenced.
252
261
*/
253
- def resolveDefinitionEnv ( sym : Symbol , thisV : Value , env : Data )(using Context ): Option [(Value , Data )] =
262
+ def resolveEnv ( owner : Symbol , thisV : Value , env : Data )(using Context ): Option [(Value , Data )] =
254
263
env match
255
264
case localEnv : LocalEnv =>
256
- if localEnv.owner == sym. owner then Some (thisV -> env)
257
- else resolveDefinitionEnv(sym , thisV, localEnv.outer)
265
+ if localEnv.owner == owner then Some (thisV -> env)
266
+ else resolveEnv(owner , thisV, localEnv.outer)
258
267
case NoEnv =>
259
268
// TODO: handle RefSet
260
269
thisV match
261
270
case ref : OfClass =>
262
- resolveDefinitionEnv(sym , ref.outer, ref.env)
271
+ resolveEnv(owner , ref.outer, ref.env)
263
272
case _ =>
264
273
None
265
- end resolveDefinitionEnv
274
+ end resolveEnv
266
275
end Env
267
276
268
277
/** Abstract heap for mutable fields
@@ -420,7 +429,15 @@ object Objects:
420
429
case _ =>
421
430
val cls = target.owner.enclosingClass.asClass
422
431
val ddef = target.defTree.asInstanceOf [DefDef ]
423
- val env2 = Env .of(ddef, args.map(_.value), if ddef.symbol.owner.isClass then Env .NoEnv else summon[Env .Data ])
432
+ val meth = ddef.symbol
433
+
434
+ val (thisV, outerEnv) =
435
+ if meth.owner.isClass then
436
+ (ref, Env .NoEnv )
437
+ else
438
+ Env .resolveEnv(meth.owner, ref, summon[Env .Data ]).getOrElse(Cold -> Env .NoEnv )
439
+
440
+ val env2 = Env .of(ddef, args.map(_.value), outerEnv)
424
441
extendTrace(ddef) {
425
442
given Env .Data = env2
426
443
eval(ddef.rhs, ref, cls, cacheResult = true )
@@ -558,8 +575,11 @@ object Objects:
558
575
// The outer can be a bottom value for top-level classes.
559
576
560
577
// Widen the outer to finitize the domain. Arguments already widened in `evalArgs`.
561
- val outerWidened = outer.widen(1 )
562
- val envWidened = if klass.owner.isClass then Env .NoEnv else summon[Env .Data ].widen(1 )
578
+ val (outerWidened, envWidened) =
579
+ if klass.owner.isClass then
580
+ (outer.widen(1 ), Env .NoEnv )
581
+ else
582
+ Env .resolveEnv(klass.owner, outer, summon[Env .Data ]).getOrElse(Cold -> Env .NoEnv )
563
583
564
584
val instance = OfClass (klass, outerWidened, ctor, args.map(_.value), envWidened, State .currentObject)
565
585
callConstructor(instance, ctor, args)
@@ -578,7 +598,7 @@ object Objects:
578
598
}
579
599
580
600
def readLocal (thisV : Value , sym : Symbol ): Contextual [Value ] = log(" reading local " + sym.show, printer, (_ : Value ).show) {
581
- Env .resolveDefinitionEnv (sym, thisV, summon[Env .Data ]) match
601
+ Env .resolveEnv (sym.owner , thisV, summon[Env .Data ]) match
582
602
case Some (thisV -> env) =>
583
603
if sym.is(Flags .Mutable ) then
584
604
thisV match
@@ -600,7 +620,7 @@ object Objects:
600
620
601
621
assert(sym.is(Flags .Mutable ), " Writing to immutable variable " + sym.show)
602
622
603
- Env .resolveDefinitionEnv (sym, thisV, summon[Env .Data ]) match
623
+ Env .resolveEnv (sym.owner , thisV, summon[Env .Data ]) match
604
624
case Some (thisV -> env) =>
605
625
thisV match
606
626
case ref : Ref =>
0 commit comments