@@ -129,8 +129,6 @@ class Objects(using Context @constructorOnly):
129129
130130 def owner : ClassSymbol
131131
132- def level : Int
133-
134132 def show (using Context ): String
135133
136134 def outer (using Heap .MutableData ): ScopeSet
@@ -168,8 +166,6 @@ class Objects(using Context @constructorOnly):
168166 case class ObjectRef private (klass : ClassSymbol )(using Trace ) extends Ref :
169167 def owner = klass
170168
171- def level = 1
172-
173169 def show (using Context ) = " ObjectRef(" + klass.show + " )"
174170
175171 object ObjectRef :
@@ -184,7 +180,7 @@ class Objects(using Context @constructorOnly):
184180 * Note that the 2nd parameter block does not take part in the definition of equality.
185181 */
186182 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 )
188184 extends Ref :
189185 def show (using Context ) =
190186 " OfClass(" + klass.show + " , ctor = " + ctor.show + " , owner = " + owner + " )"
@@ -195,7 +191,7 @@ class Objects(using Context @constructorOnly):
195191 using Context , Heap .MutableData , State .Data , Regions .Data , Trace
196192 ): OfClass =
197193 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 ])
199195 instance.initOuter(klass, outerScope)
200196 instance
201197
@@ -216,8 +212,6 @@ class Objects(using Context @constructorOnly):
216212
217213 def klass : ClassSymbol = defn.ArrayClass
218214
219- def level = 1
220-
221215 def show (using Context ) = " OfArray(owner = " + owner.show + " )"
222216
223217 def readElement (using Heap .MutableData ) = valValue(elementSymbol)
@@ -294,7 +288,6 @@ class Objects(using Context @constructorOnly):
294288
295289 case class ScopeSet (scopes : Set [Scope ]):
296290 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
298291
299292 def show (using Context ) = scopes.map(_.show).mkString(" [" , " ," , " ]" )
300293
@@ -365,7 +358,7 @@ class Objects(using Context @constructorOnly):
365358 obj
366359 end doCheckObject
367360
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 =
369362 val index = data.checkingObjects.indexWhere(_.klass == clazz)
370363
371364 if index != - 1 then
@@ -376,7 +369,6 @@ class Objects(using Context @constructorOnly):
376369 val cycle = data.checkingObjects.slice(index, data.checkingObjects.size)
377370 val pos = clazz.defTree.sourcePos.focus
378371 report.warning(" Cyclic initialization: " + cycle.map(_.klass.show).mkString(" -> " ) + " -> " + clazz.show + " . " + callTrace, pos)
379- // Bottom
380372 end if
381373 data.checkingObjects(index)
382374 else
@@ -398,10 +390,7 @@ class Objects(using Context @constructorOnly):
398390 *
399391 * For local variables in rhs of class field definitions, the `meth` is the primary constructor.
400392 */
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 :
405394 def show (using Context ) =
406395 " meth: " + meth.show + " \n " +
407396 " owner: " + owner.show
@@ -428,18 +417,24 @@ class Objects(using Context @constructorOnly):
428417
429418 private [Env ] def _of (argMap : Map [Symbol , Value ], meth : Symbol , outerSet : ScopeSet )
430419 (using State .Data , Heap .MutableData , Trace ): LocalEnv =
431- val env = LocalEnv (meth, State .currentObject, outerSet.level + 1 )
420+ val env = LocalEnv (meth, State .currentObject)
432421 argMap.foreach(env.initVal(_, _))
433422 env.initOuter(meth, outerSet)
434423 env
435424
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+ */
436432 private [Env ] def resolveEnvRecur (
437- target : Symbol , thisV : ThisValue , scopeSet : ScopeSet , bySymbol : Boolean = true )
433+ target : Symbol , scopeSet : ScopeSet , bySymbol : Boolean = true )
438434 : 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
442436 else
437+ val targetClass = target.owner.lexicallyEnclosingClass.asClass
443438 val head = scopeSet.scopes.head
444439 val filter =
445440 if bySymbol then
@@ -449,20 +444,12 @@ class Objects(using Context @constructorOnly):
449444
450445 assert(filter.isEmpty || filter.size == scopeSet.scopes.size, " Either all scopes or no scopes contain " + target)
451446 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))
463450 else
464451 val outerScopes = scopeSet.scopes.map(_.outer).join
465- resolveEnvRecur(target, thisV, outerScopes, bySymbol)
452+ resolveEnvRecur(target, outerScopes, bySymbol)
466453
467454
468455 def ofDefDef (ddef : DefDef , args : List [Value ], outer : ScopeSet )
@@ -508,7 +495,7 @@ class Objects(using Context @constructorOnly):
508495 */
509496 def resolveEnvByValue (target : Symbol , thisV : ThisValue , scope : Scope )
510497 (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)))
512499 }
513500
514501 /**
@@ -527,9 +514,11 @@ class Objects(using Context @constructorOnly):
527514 *
528515 * @return the environment and value for `this` owned by the given method.
529516 */
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) {
531518 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
533522 }
534523
535524 def withEnv [T ](env : LocalEnv )(fn : LocalEnv ?=> T ): T = fn(using env)
@@ -737,9 +726,7 @@ class Objects(using Context @constructorOnly):
737726
738727 given Join [ScopeSet ] with
739728 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)
743730
744731 extension (values : Iterable [Value ])
745732 def join : Value =
@@ -857,7 +844,6 @@ class Objects(using Context @constructorOnly):
857844 SafeValue (defn.IntType )
858845
859846 case ref : Ref =>
860- val isLocal = ! meth.owner.isClass
861847 val target =
862848 if ! needResolve then
863849 meth
@@ -880,14 +866,13 @@ class Objects(using Context @constructorOnly):
880866 val cls = target.owner.enclosingClass.asClass
881867 val ddef = target.defTree.asInstanceOf [DefDef ]
882868 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)))
887873 else
874+ val enclosingMethod = meth.owner.enclosingMethod
888875 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
891876
892877 val env2 = Env .ofDefDef(ddef, args.map(_.value), outerEnv)
893878 extendTrace(ddef) {
@@ -1132,7 +1117,7 @@ class Objects(using Context @constructorOnly):
11321117 arr
11331118 else
11341119 // Widen the outer to finitize the domain. Arguments already widened in `evalArgs`.
1135- val envWidened =
1120+ val envWidened : ScopeSet =
11361121 outer match
11371122 case Package (_) => // For top-level classes
11381123 Env .NoEnv
@@ -1141,13 +1126,15 @@ class Objects(using Context @constructorOnly):
11411126 report.warning(" [Internal error] top-level class should have `Package` as outer, class = " + klass.show + " , outer = " + outer.show + " , " + Trace .show, Trace .position)
11421127 Env .NoEnv
11431128 else
1144- val enclosingMethod = klass.owner.enclosingMethod
1145- val outerCls = outer.asInstanceOf [Ref ].klass
1129+ val outerCls = klass.owner.enclosingClass.asClass
11461130 // 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
11491136 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
11511138
11521139 val instance = OfClass (klass, envWidened, ctor)
11531140 callConstructor(instance, ctor, args)
@@ -1249,7 +1236,7 @@ class Objects(using Context @constructorOnly):
12491236 // -------------------------------- algorithm --------------------------------
12501237
12511238 /** 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) {
12531240 if classSym.hasSource then
12541241 State .checkObjectAccess(classSym)
12551242 else
@@ -1369,7 +1356,7 @@ class Objects(using Context @constructorOnly):
13691356 case TermRef (NoPrefix , _) =>
13701357 // resolve this for the local method
13711358 val enclosingClass = id.symbol.owner.enclosingClass.asClass
1372- val thisValue2 = extendTrace(ref) { resolveThis(enclosingClass, thisV, klass ) }
1359+ val thisValue2 = extendTrace(ref) { resolveThis(enclosingClass, thisV) }
13731360 // local methods are not a member, but we can reuse the method `call`
13741361 withTrace(trace2) { call(thisValue2, id.symbol, args, receiver = NoType , superType = NoType , needResolve = false ) }
13751362 case TermRef (prefix, _) =>
@@ -1386,7 +1373,7 @@ class Objects(using Context @constructorOnly):
13861373 case OuterSelectName (_, _) =>
13871374 val current = qualifier.tpe.classSymbol
13881375 val target = expr.tpe.widenSingleton.classSymbol.asClass
1389- withTrace(trace2) { resolveThis(target, qual, current.asClass ) }
1376+ withTrace(trace2) { resolveThis(target, qual) }
13901377 case _ =>
13911378 withTrace(trace2) { select(qual, expr.symbol, receiver = qualifier.tpe) }
13921379
@@ -1779,7 +1766,7 @@ class Objects(using Context @constructorOnly):
17791766 accessObject(sym.moduleClass.asClass)
17801767
17811768 else
1782- resolveThis(tref.classSymbol.asClass, thisV, klass )
1769+ resolveThis(tref.classSymbol.asClass, thisV)
17831770
17841771 case _ =>
17851772 throw new Exception (" unexpected type: " + tp + " , Trace:\n " + Trace .show)
@@ -1931,50 +1918,52 @@ class Objects(using Context @constructorOnly):
19311918 }
19321919
19331920
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`
19351941 *
19361942 * @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`.
19391944 * @param elideObjectAccess Whether object access should be omitted.
19401945 *
19411946 * Object access elision happens when the object access is used as a prefix
19421947 * in `new o.C` and `C` does not need an outer.
19431948 */
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) {
19611950 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
19631952 report.warning(error, Trace .position)
19641953 Bottom
19651954 else if target.isStaticObject then
19661955 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)) )
19691958 else
19701959 thisV match
19711960 case Bottom => Bottom
19721961 case ref : Ref =>
1973- recur( ScopeSet (Set (ref)))
1962+ resolveThisRecur(target, ScopeSet (Set (ref)))
19741963 case vs : ValueSet if vs.isRefSet =>
1975- recur( vs.toScopeSet)
1964+ resolveThisRecur(target, vs.toScopeSet)
19761965 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)
19781967 Bottom
19791968 }
19801969
@@ -1988,7 +1977,7 @@ class Objects(using Context @constructorOnly):
19881977 val cls = tref.classSymbol.asClass
19891978 if tref.prefix == NoPrefix then
19901979 val enclosing = cls.owner.lexicallyEnclosingClass.asClass
1991- resolveThis(enclosing, thisV, klass, elideObjectAccess = cls.isStatic)
1980+ resolveThis(enclosing, thisV, elideObjectAccess = cls.isStatic)
19921981 else
19931982 if cls.isAllOf(Flags .JavaInterface ) then Bottom
19941983 else evalType(tref.prefix, thisV, klass, elideObjectAccess = cls.isStatic)
0 commit comments