@@ -129,8 +129,6 @@ class Objects(using Context @constructorOnly):
129
129
130
130
def owner : ClassSymbol
131
131
132
- def level : Int
133
-
134
132
def show (using Context ): String
135
133
136
134
def outer (using Heap .MutableData ): ScopeSet
@@ -168,8 +166,6 @@ class Objects(using Context @constructorOnly):
168
166
case class ObjectRef private (klass : ClassSymbol )(using Trace ) extends Ref :
169
167
def owner = klass
170
168
171
- def level = 1
172
-
173
169
def show (using Context ) = " ObjectRef(" + klass.show + " )"
174
170
175
171
object ObjectRef :
@@ -184,7 +180,7 @@ class Objects(using Context @constructorOnly):
184
180
* Note that the 2nd parameter block does not take part in the definition of equality.
185
181
*/
186
182
case class OfClass private (
187
- klass : ClassSymbol , owner : ClassSymbol , ctor : Symbol , level : Int , regions : Regions .Data )(using Trace )
183
+ klass : ClassSymbol , owner : ClassSymbol , ctor : Symbol , regions : Regions .Data )(using Trace )
188
184
extends Ref :
189
185
def show (using Context ) =
190
186
" OfClass(" + klass.show + " , ctor = " + ctor.show + " , owner = " + owner + " )"
@@ -195,7 +191,7 @@ class Objects(using Context @constructorOnly):
195
191
using Context , Heap .MutableData , State .Data , Regions .Data , Trace
196
192
): OfClass =
197
193
val owner = State .currentObject
198
- val instance = new OfClass (klass, owner, ctor, outerScope.level + 1 , summon[Regions .Data ])
194
+ val instance = new OfClass (klass, owner, ctor, summon[Regions .Data ])
199
195
instance.initOuter(klass, outerScope)
200
196
instance
201
197
@@ -216,8 +212,6 @@ class Objects(using Context @constructorOnly):
216
212
217
213
def klass : ClassSymbol = defn.ArrayClass
218
214
219
- def level = 1
220
-
221
215
def show (using Context ) = " OfArray(owner = " + owner.show + " )"
222
216
223
217
def readElement (using Heap .MutableData ) = valValue(elementSymbol)
@@ -294,7 +288,6 @@ class Objects(using Context @constructorOnly):
294
288
295
289
case class ScopeSet (scopes : Set [Scope ]):
296
290
assert(scopes.forall(_.isRef) || scopes.forall(_.isEnv), " All scopes should have the same type!" )
297
- def level : Int = if scopes.isEmpty then 0 else scopes.head.level
298
291
299
292
def show (using Context ) = scopes.map(_.show).mkString(" [" , " ," , " ]" )
300
293
@@ -365,7 +358,7 @@ class Objects(using Context @constructorOnly):
365
358
obj
366
359
end doCheckObject
367
360
368
- def checkObjectAccess (clazz : ClassSymbol )(using data : Data , ctx : Context , pendingTrace : Trace , heap : Heap .MutableData ): ObjectRef | Bottom . type =
361
+ def checkObjectAccess (clazz : ClassSymbol )(using data : Data , ctx : Context , pendingTrace : Trace , heap : Heap .MutableData ): ObjectRef =
369
362
val index = data.checkingObjects.indexWhere(_.klass == clazz)
370
363
371
364
if index != - 1 then
@@ -376,7 +369,6 @@ class Objects(using Context @constructorOnly):
376
369
val cycle = data.checkingObjects.slice(index, data.checkingObjects.size)
377
370
val pos = clazz.defTree.sourcePos.focus
378
371
report.warning(" Cyclic initialization: " + cycle.map(_.klass.show).mkString(" -> " ) + " -> " + clazz.show + " . " + callTrace, pos)
379
- // Bottom
380
372
end if
381
373
data.checkingObjects(index)
382
374
else
@@ -398,10 +390,7 @@ class Objects(using Context @constructorOnly):
398
390
*
399
391
* For local variables in rhs of class field definitions, the `meth` is the primary constructor.
400
392
*/
401
- case class LocalEnv (meth : Symbol , owner : ClassSymbol , level : Int )(using Trace ) extends Scope :
402
- if (level > 3 )
403
- report.warning(" [Internal error] Deeply nested environment, level = " + level + " , " + meth.show + " in " + meth.enclosingClass.show, meth.defTree)
404
-
393
+ case class LocalEnv (meth : Symbol , owner : ClassSymbol )(using Trace ) extends Scope :
405
394
def show (using Context ) =
406
395
" meth: " + meth.show + " \n " +
407
396
" owner: " + owner.show
@@ -428,18 +417,24 @@ class Objects(using Context @constructorOnly):
428
417
429
418
private [Env ] def _of (argMap : Map [Symbol , Value ], meth : Symbol , outerSet : ScopeSet )
430
419
(using State .Data , Heap .MutableData , Trace ): LocalEnv =
431
- val env = LocalEnv (meth, State .currentObject, outerSet.level + 1 )
420
+ val env = LocalEnv (meth, State .currentObject)
432
421
argMap.foreach(env.initVal(_, _))
433
422
env.initOuter(meth, outerSet)
434
423
env
435
424
425
+ /**
426
+ * The main procedure for searching through the outer chain
427
+ * @param target The symbol to search for if `bySymbol = true`; otherwise the method symbol of the target environment
428
+ * @param scopeSet The set of scopes as starting point
429
+ * @return The scopes that contains symbol `target` or whose method is `target`,
430
+ * and the value for `C.this` where C is the enclosing class of the result scopes
431
+ */
436
432
private [Env ] def resolveEnvRecur (
437
- target : Symbol , thisV : ThisValue , scopeSet : ScopeSet , bySymbol : Boolean = true )
433
+ target : Symbol , scopeSet : ScopeSet , bySymbol : Boolean = true )
438
434
: Contextual [Option [(ThisValue , ScopeSet )]] =
439
- val targetClass = target.owner.lexicallyEnclosingClass.asClass
440
- if scopeSet.level == 0 then // all scopes are NoEnv
441
- None
435
+ if scopeSet == Env .NoEnv then None
442
436
else
437
+ val targetClass = target.owner.lexicallyEnclosingClass.asClass
443
438
val head = scopeSet.scopes.head
444
439
val filter =
445
440
if bySymbol then
@@ -449,20 +444,12 @@ class Objects(using Context @constructorOnly):
449
444
450
445
assert(filter.isEmpty || filter.size == scopeSet.scopes.size, " Either all scopes or no scopes contain " + target)
451
446
if (! filter.isEmpty) then
452
- Some (thisV, ScopeSet (filter))
453
- else if head.isRef then
454
- val currentClass = head.asInstanceOf [Ref ].klass
455
- if currentClass == targetClass then
456
- // We have reached the owner class of target but still couldn't find target
457
- None
458
- else
459
- val outerClass = currentClass.owner.lexicallyEnclosingClass.asClass
460
- val outerThis = resolveThis(outerClass, thisV, currentClass)
461
- val outerScopes = scopeSet.scopes.map(_.outer).join
462
- resolveEnvRecur(target, outerThis, outerScopes, bySymbol)
447
+ val resultSet = ScopeSet (filter)
448
+ val outerThis = resolveThisRecur(targetClass, resultSet)
449
+ Some ((outerThis, resultSet))
463
450
else
464
451
val outerScopes = scopeSet.scopes.map(_.outer).join
465
- resolveEnvRecur(target, thisV, outerScopes, bySymbol)
452
+ resolveEnvRecur(target, outerScopes, bySymbol)
466
453
467
454
468
455
def ofDefDef (ddef : DefDef , args : List [Value ], outer : ScopeSet )
@@ -508,7 +495,7 @@ class Objects(using Context @constructorOnly):
508
495
*/
509
496
def resolveEnvByValue (target : Symbol , thisV : ThisValue , scope : Scope )
510
497
(using Context , Heap .MutableData ): Contextual [Option [(ThisValue , ScopeSet )]] = log(" Resolving env by value for " + target.show + " , this = " + thisV.show + " , scope = " + scope.show, printer) {
511
- resolveEnvRecur(target, thisV, ScopeSet (Set (scope)))
498
+ resolveEnvRecur(target, ScopeSet (Set (scope)))
512
499
}
513
500
514
501
/**
@@ -527,9 +514,11 @@ class Objects(using Context @constructorOnly):
527
514
*
528
515
* @return the environment and value for `this` owned by the given method.
529
516
*/
530
- def resolveEnvByMethod (enclosing : Symbol , thisV : ThisValue , scope : Scope )(using Context , Heap .MutableData ): Contextual [Option [ (ThisValue , ScopeSet )] ] = log(" Resolving env which corresponds to method " + enclosing.show + " , this = " + thisV.show + " , scope = " + scope.show, printer) {
517
+ def resolveEnvByMethod (enclosing : Symbol , thisV : ThisValue , scope : Scope )(using Context , Heap .MutableData ): Contextual [(ThisValue , ScopeSet )] = log(" Resolving env which corresponds to method " + enclosing.show + " , this = " + thisV.show + " , scope = " + scope.show, printer) {
531
518
assert(enclosing.is(Flags .Method ), " Only method symbols allows, got " + enclosing.show)
532
- resolveEnvRecur(enclosing, thisV, ScopeSet (Set (scope)), bySymbol = false )
519
+ val result = resolveEnvRecur(enclosing, ScopeSet (Set (scope)), bySymbol = false )
520
+ assert(! result.isEmpty, " Failed to find environment for " + enclosing + " !" )
521
+ result.get
533
522
}
534
523
535
524
def withEnv [T ](env : LocalEnv )(fn : LocalEnv ?=> T ): T = fn(using env)
@@ -737,9 +726,7 @@ class Objects(using Context @constructorOnly):
737
726
738
727
given Join [ScopeSet ] with
739
728
extension (a : ScopeSet )
740
- def join (b : ScopeSet ): ScopeSet =
741
- assert(a.level == b.level, " Invalid join on scopes!" )
742
- ScopeSet (a.scopes ++ b.scopes)
729
+ def join (b : ScopeSet ): ScopeSet = ScopeSet (a.scopes ++ b.scopes)
743
730
744
731
extension (values : Iterable [Value ])
745
732
def join : Value =
@@ -857,7 +844,6 @@ class Objects(using Context @constructorOnly):
857
844
SafeValue (defn.IntType )
858
845
859
846
case ref : Ref =>
860
- val isLocal = ! meth.owner.isClass
861
847
val target =
862
848
if ! needResolve then
863
849
meth
@@ -880,14 +866,13 @@ class Objects(using Context @constructorOnly):
880
866
val cls = target.owner.enclosingClass.asClass
881
867
val ddef = target.defTree.asInstanceOf [DefDef ]
882
868
val meth = ddef.symbol
883
- val enclosingMethod = meth.owner.enclosingMethod
884
- val resolveResult =
885
- if enclosingMethod == cls.primaryConstructor then // meth is top-level method, outer is a ref
886
- Some (ref, ScopeSet (Set (ref)))
869
+ val ( thisV : ThisValue , outerEnv) =
870
+ if meth.owner.enclosingMethod == cls.primaryConstructor then
871
+ // meth is top-level method, outer is a ref
872
+ (ref, ScopeSet (Set (ref)))
887
873
else
874
+ val enclosingMethod = meth.owner.enclosingMethod
888
875
Env .resolveEnvByMethod(enclosingMethod, ref, summon[Scope ])
889
- assert(! resolveResult.isEmpty, " Cannot find environment for method " + meth.show + " !" + Trace .show)
890
- val (thisV : ThisValue , outerEnv) = resolveResult.get
891
876
892
877
val env2 = Env .ofDefDef(ddef, args.map(_.value), outerEnv)
893
878
extendTrace(ddef) {
@@ -1132,7 +1117,7 @@ class Objects(using Context @constructorOnly):
1132
1117
arr
1133
1118
else
1134
1119
// Widen the outer to finitize the domain. Arguments already widened in `evalArgs`.
1135
- val envWidened =
1120
+ val envWidened : ScopeSet =
1136
1121
outer match
1137
1122
case Package (_) => // For top-level classes
1138
1123
Env .NoEnv
@@ -1141,13 +1126,15 @@ class Objects(using Context @constructorOnly):
1141
1126
report.warning(" [Internal error] top-level class should have `Package` as outer, class = " + klass.show + " , outer = " + outer.show + " , " + Trace .show, Trace .position)
1142
1127
Env .NoEnv
1143
1128
else
1144
- val enclosingMethod = klass.owner.enclosingMethod
1145
- val outerCls = outer.asInstanceOf [Ref ].klass
1129
+ val outerCls = klass.owner.enclosingClass.asClass
1146
1130
// When `klass` is directly nested in `outerCls`, `outerCls`.enclosingMethod returns its primary constructor
1147
- if enclosingMethod == outerCls.primaryConstructor then
1148
- ScopeSet (Set (outer.asInstanceOf [Ref ]))
1131
+ if klass.owner.enclosingMethod == outerCls.primaryConstructor then
1132
+ // Don't use the parameter `outer` as the outer value, but uses `outerCls.this`
1133
+ // This eliminates infinite outer chain caused by inner classes extending outer classes.
1134
+ // See `inner-extends-outer.scala`
1135
+ resolveThis(outerCls, outer).toScopeSet
1149
1136
else
1150
- Env .resolveEnvByMethod(klass.owner.enclosingMethod, outer, summon[Scope ]).getOrElse( UnknownValue -> Env . NoEnv ). _2
1137
+ Env .resolveEnvByMethod(klass.owner.enclosingMethod, outer, summon[Scope ])._2
1151
1138
1152
1139
val instance = OfClass (klass, envWidened, ctor)
1153
1140
callConstructor(instance, ctor, args)
@@ -1249,7 +1236,7 @@ class Objects(using Context @constructorOnly):
1249
1236
// -------------------------------- algorithm --------------------------------
1250
1237
1251
1238
/** Check an individual object */
1252
- private def accessObject (classSym : ClassSymbol )(using Context , State .Data , Trace , Heap .MutableData ): ObjectRef | Bottom . type = log(" accessing " + classSym.show, printer, (_ : Value ).show) {
1239
+ private def accessObject (classSym : ClassSymbol )(using Context , State .Data , Trace , Heap .MutableData ): ObjectRef = log(" accessing " + classSym.show, printer, (_ : Value ).show) {
1253
1240
if classSym.hasSource then
1254
1241
State .checkObjectAccess(classSym)
1255
1242
else
@@ -1369,7 +1356,7 @@ class Objects(using Context @constructorOnly):
1369
1356
case TermRef (NoPrefix , _) =>
1370
1357
// resolve this for the local method
1371
1358
val enclosingClass = id.symbol.owner.enclosingClass.asClass
1372
- val thisValue2 = extendTrace(ref) { resolveThis(enclosingClass, thisV, klass ) }
1359
+ val thisValue2 = extendTrace(ref) { resolveThis(enclosingClass, thisV) }
1373
1360
// local methods are not a member, but we can reuse the method `call`
1374
1361
withTrace(trace2) { call(thisValue2, id.symbol, args, receiver = NoType , superType = NoType , needResolve = false ) }
1375
1362
case TermRef (prefix, _) =>
@@ -1386,7 +1373,7 @@ class Objects(using Context @constructorOnly):
1386
1373
case OuterSelectName (_, _) =>
1387
1374
val current = qualifier.tpe.classSymbol
1388
1375
val target = expr.tpe.widenSingleton.classSymbol.asClass
1389
- withTrace(trace2) { resolveThis(target, qual, current.asClass ) }
1376
+ withTrace(trace2) { resolveThis(target, qual) }
1390
1377
case _ =>
1391
1378
withTrace(trace2) { select(qual, expr.symbol, receiver = qualifier.tpe) }
1392
1379
@@ -1779,7 +1766,7 @@ class Objects(using Context @constructorOnly):
1779
1766
accessObject(sym.moduleClass.asClass)
1780
1767
1781
1768
else
1782
- resolveThis(tref.classSymbol.asClass, thisV, klass )
1769
+ resolveThis(tref.classSymbol.asClass, thisV)
1783
1770
1784
1771
case _ =>
1785
1772
throw new Exception (" unexpected type: " + tp + " , Trace:\n " + Trace .show)
@@ -1931,50 +1918,52 @@ class Objects(using Context @constructorOnly):
1931
1918
}
1932
1919
1933
1920
1934
- /** Resolve C.this that appear in `klass`
1921
+ /** Resolve C.this by recursively searching through the outer chain
1922
+ * @param target The class symbol for `C` for which `C.this` is to be resolved.
1923
+ * @param scopeSet The scopes as the starting point.
1924
+ */
1925
+ def resolveThisRecur (target : ClassSymbol , scopeSet : ScopeSet ): Contextual [ValueSet ] =
1926
+ if scopeSet == Env .NoEnv then
1927
+ Bottom
1928
+ else
1929
+ val head = scopeSet.scopes.head
1930
+ if head.isInstanceOf [Ref ] then
1931
+ val klass = head.asInstanceOf [Ref ].klass
1932
+ assert(scopeSet.scopes.forall(_.asInstanceOf [Ref ].klass == klass), " Multiple possible outer class?" )
1933
+ if klass == target then
1934
+ scopeSet.toValueSet
1935
+ else
1936
+ resolveThisRecur(target, scopeSet.scopes.map(_.outer).join)
1937
+ else
1938
+ resolveThisRecur(target, scopeSet.scopes.map(_.outer).join)
1939
+
1940
+ /** Resolve C.this that appear in `D.this`
1935
1941
*
1936
1942
* @param target The class symbol for `C` for which `C.this` is to be resolved.
1937
- * @param thisV The value for `D.this` where `D` is represented by the parameter `klass`.
1938
- * @param klass The enclosing class where the type `C.this` is located.
1943
+ * @param thisV The value for `D.this`.
1939
1944
* @param elideObjectAccess Whether object access should be omitted.
1940
1945
*
1941
1946
* Object access elision happens when the object access is used as a prefix
1942
1947
* in `new o.C` and `C` does not need an outer.
1943
1948
*/
1944
- def resolveThis (target : ClassSymbol , thisV : Value , klass : ClassSymbol , elideObjectAccess : Boolean = false ): Contextual [ThisValue ] = log(" resolveThis target = " + target.show + " , this = " + thisV.show, printer, (_ : Value ).show) {
1945
- def recur (scopeSet : ScopeSet ): ThisValue =
1946
- if scopeSet == Env .NoEnv then
1947
- Bottom
1948
- else
1949
- val head = scopeSet.scopes.head
1950
- if head.isInstanceOf [Ref ] then
1951
- val klass = head.asInstanceOf [Ref ].klass
1952
- assert(scopeSet.scopes.forall(_.asInstanceOf [Ref ].klass == klass), " Multiple possible outer class?" )
1953
- if klass == target then
1954
- scopeSet.toValueSet
1955
- else
1956
- recur(scopeSet.scopes.map(_.outer).join)
1957
- else
1958
- recur(scopeSet.scopes.map(_.outer).join)
1959
- end recur
1960
-
1949
+ def resolveThis (target : ClassSymbol , thisV : Value , elideObjectAccess : Boolean = false ): Contextual [ValueSet ] = log(" resolveThis target = " + target.show + " , this = " + thisV.show, printer, (_ : Value ).show) {
1961
1950
if target.is(Flags .Package ) then
1962
- val error = " [Internal error] target cannot be packages, target = " + target + " , klass = " + klass + Trace .show
1951
+ val error = " [Internal error] target cannot be packages, target = " + target + Trace .show
1963
1952
report.warning(error, Trace .position)
1964
1953
Bottom
1965
1954
else if target.isStaticObject then
1966
1955
val res = ObjectRef (target.moduleClass.asClass)
1967
- if elideObjectAccess then res
1968
- else accessObject(target)
1956
+ if elideObjectAccess then ValueSet ( Set ( res))
1957
+ else ValueSet ( Set ( accessObject(target)) )
1969
1958
else
1970
1959
thisV match
1971
1960
case Bottom => Bottom
1972
1961
case ref : Ref =>
1973
- recur( ScopeSet (Set (ref)))
1962
+ resolveThisRecur(target, ScopeSet (Set (ref)))
1974
1963
case vs : ValueSet if vs.isRefSet =>
1975
- recur( vs.toScopeSet)
1964
+ resolveThisRecur(target, vs.toScopeSet)
1976
1965
case _ =>
1977
- report.warning(" [Internal error] unexpected thisV = " + thisV + " , target = " + target.show + " , klass = " + klass.show + Trace .show, Trace .position)
1966
+ report.warning(" [Internal error] unexpected thisV = " + thisV + " , target = " + target.show + Trace .show, Trace .position)
1978
1967
Bottom
1979
1968
}
1980
1969
@@ -1988,7 +1977,7 @@ class Objects(using Context @constructorOnly):
1988
1977
val cls = tref.classSymbol.asClass
1989
1978
if tref.prefix == NoPrefix then
1990
1979
val enclosing = cls.owner.lexicallyEnclosingClass.asClass
1991
- resolveThis(enclosing, thisV, klass, elideObjectAccess = cls.isStatic)
1980
+ resolveThis(enclosing, thisV, elideObjectAccess = cls.isStatic)
1992
1981
else
1993
1982
if cls.isAllOf(Flags .JavaInterface ) then Bottom
1994
1983
else evalType(tref.prefix, thisV, klass, elideObjectAccess = cls.isStatic)
0 commit comments