Skip to content

Commit 798fd49

Browse files
author
EnzeXing
committed
Rewrite resolveThis; removed assertions
1 parent ef37ebf commit 798fd49

File tree

5 files changed

+69
-18
lines changed

5 files changed

+69
-18
lines changed

compiler/src/dotty/tools/dotc/transform/init/Objects.scala

Lines changed: 33 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -287,11 +287,22 @@ class Objects(using Context @constructorOnly):
287287
def toScopeSet: ScopeSet = ScopeSet(values.asInstanceOf[Set[Scope]])
288288

289289
case class ScopeSet(scopes: Set[Scope]):
290-
assert(scopes.forall(_.isRef) || scopes.forall(_.isEnv), "All scopes should have the same type!")
290+
// assert(scopes.forall(_.isRef) || scopes.forall(_.isEnv), "All scopes should have the same type!")
291+
292+
def isRefSet = scopes.forall(_.isRef)
293+
294+
def isEnvSet = scopes.forall(_.isEnv)
291295

292296
def show(using Context) = scopes.map(_.show).mkString("[", ",", "]")
293297

294-
def toValueSet: ValueSet = ValueSet(scopes.asInstanceOf[Set[ValueElement]])
298+
def toValueSet: ValueSet =
299+
assert(isRefSet, "Cannot convert scopeSet " + this.show + "to ValueSet!")
300+
ValueSet(scopes.asInstanceOf[Set[ValueElement]])
301+
302+
def partitionByClass(target: ClassSymbol): (ScopeSet, ScopeSet) =
303+
// assert(isRefSet, "Invalid partition on scopeSet " + this.show)
304+
val (matchSet, unmatchSet) = scopes.partition(s => s.isRef && s.asRef.klass == target)
305+
(ScopeSet(matchSet), ScopeSet(unmatchSet))
295306

296307
def lookupSymbol(sym: Symbol)(using Heap.MutableData) = scopes.map(_.valValue(sym)).join
297308

@@ -728,6 +739,11 @@ class Objects(using Context @constructorOnly):
728739
case fun: Fun =>
729740
if klass.isOneOf(AbstractOrTrait) && klass.baseClasses.exists(defn.isFunctionClass) then fun else Bottom
730741

742+
extension (thisV: ThisValue)
743+
def toValueSet: ValueSet = thisV match
744+
case ref: Ref => ValueSet(Set(ref))
745+
case vs: ValueSet => vs
746+
731747
given Join[ScopeSet] with
732748
extension (a: ScopeSet)
733749
def join(b: ScopeSet): ScopeSet = ScopeSet(a.scopes ++ b.scopes)
@@ -870,6 +886,7 @@ class Objects(using Context @constructorOnly):
870886
val cls = target.owner.enclosingClass.asClass
871887
val ddef = target.defTree.asInstanceOf[DefDef]
872888
val meth = ddef.symbol
889+
// println("Before resolving environment, cls = " + cls + ", meth = " + meth)
873890
val (thisV : ThisValue, outerEnv) =
874891
if meth.owner.enclosingMethod == cls.primaryConstructor then
875892
// meth is top-level method, outer is a ref
@@ -1377,7 +1394,7 @@ class Objects(using Context @constructorOnly):
13771394
case OuterSelectName(_, _) =>
13781395
val current = qualifier.tpe.classSymbol
13791396
val target = expr.tpe.widenSingleton.classSymbol.asClass
1380-
withTrace(trace2) { resolveThis(target, qual) }
1397+
withTrace(trace2) { resolveThis(target, qual.asInstanceOf[ThisValue]) }
13811398
case _ =>
13821399
withTrace(trace2) { select(qual, expr.symbol, receiver = qualifier.tpe) }
13831400

@@ -1927,19 +1944,15 @@ class Objects(using Context @constructorOnly):
19271944
* @param scopeSet The scopes as the starting point.
19281945
*/
19291946
def resolveThisRecur(target: ClassSymbol, scopeSet: ScopeSet): Contextual[ValueSet] =
1947+
// println("scopeSet = " + scopeSet)
19301948
if scopeSet == Env.NoEnv then
19311949
Bottom
1950+
else if scopeSet.isRefSet then
1951+
val (matchSet, unmatchSet) = scopeSet.partitionByClass(target)
1952+
val resolveUnmatchSet = resolveThisRecur(target, unmatchSet.outers)
1953+
matchSet.toValueSet.join(resolveUnmatchSet).asInstanceOf[ValueSet]
19321954
else
1933-
val head = scopeSet.scopes.head
1934-
if head.isInstanceOf[Ref] then
1935-
val klass = head.asInstanceOf[Ref].klass
1936-
assert(scopeSet.scopes.forall(_.asInstanceOf[Ref].klass == klass), "Multiple possible outer class?")
1937-
if klass == target then
1938-
scopeSet.toValueSet
1939-
else
1940-
resolveThisRecur(target, scopeSet.outers)
1941-
else
1942-
resolveThisRecur(target, scopeSet.outers)
1955+
resolveThisRecur(target, scopeSet.outers)
19431956

19441957
/** Resolve C.this that appear in `D.this`
19451958
*
@@ -1950,7 +1963,7 @@ class Objects(using Context @constructorOnly):
19501963
* Object access elision happens when the object access is used as a prefix
19511964
* in `new o.C` and `C` does not need an outer.
19521965
*/
1953-
def resolveThis(target: ClassSymbol, thisV: Value, elideObjectAccess: Boolean = false): Contextual[ValueSet] = log("resolveThis target = " + target.show + ", this = " + thisV.show, printer, (_: Value).show) {
1966+
def resolveThis(target: ClassSymbol, thisV: ThisValue, elideObjectAccess: Boolean = false): Contextual[ValueSet] = log("resolveThis target = " + target.show + ", this = " + thisV.show, printer, (_: Value).show) {
19541967
if target.is(Flags.Package) then
19551968
val error = "[Internal error] target cannot be packages, target = " + target + Trace.show
19561969
report.warning(error, Trace.position)
@@ -1960,7 +1973,7 @@ class Objects(using Context @constructorOnly):
19601973
if elideObjectAccess then ValueSet(Set(res))
19611974
else ValueSet(Set(accessObject(target)))
19621975
else
1963-
thisV match
1976+
val resolveResult = thisV match
19641977
case Bottom => Bottom
19651978
case ref: Ref =>
19661979
resolveThisRecur(target, ScopeSet(Set(ref)))
@@ -1969,6 +1982,11 @@ class Objects(using Context @constructorOnly):
19691982
case _ =>
19701983
report.warning("[Internal error] unexpected thisV = " + thisV + ", target = " + target.show + Trace.show, Trace.position)
19711984
Bottom
1985+
if resolveResult == Bottom && thisV.filterClass(target) == thisV then
1986+
// `target` is not an outer class, but a parent class
1987+
thisV.toValueSet
1988+
else
1989+
resolveResult
19721990
}
19731991

19741992
/** Compute the outer value that corresponds to `tref.prefix`

compiler/test/dotc/neg-init-global-scala2-library-tasty.excludelist

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,4 @@ global-list.scala
1515
t5366.scala
1616
mutable-read7.scala
1717
t9115.scala
18-
Color.scala
19-
unapplySeq-implicit-arg2.scala
20-
unapplySeq-implicit-arg3.scala
18+
Color.scala
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
abstract class T {
2+
def foo() = {
3+
def bar() = 5
4+
bar()
5+
}
6+
}
7+
8+
class A extends T {}
9+
class B extends T {}
10+
class C extends T {}
11+
12+
object O {
13+
val a = new A
14+
val b = new B
15+
val c = new C
16+
val d = a.foo()
17+
val e = b.foo()
18+
val f = c.foo()
19+
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
-- Warning: tests/init-global/warn/resolve-parent-this.scala:7:21 ------------------------------------------------------
2+
7 | val a: Int = foo().a // warn
3+
| ^^^^^^^
4+
| Access uninitialized field value a. Calling trace:
5+
| ├── object O extends Delegate { [ resolve-parent-this.scala:6 ]
6+
| │ ^
7+
| └── val a: Int = foo().a // warn [ resolve-parent-this.scala:7 ]
8+
| ^^^^^^^
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
class Delegate {
2+
def foo() = f
3+
val f: O.type = O
4+
}
5+
6+
object O extends Delegate {
7+
val a: Int = foo().a // warn
8+
}

0 commit comments

Comments
 (0)