Skip to content

Commit 1e0eb9f

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

File tree

5 files changed

+64
-18
lines changed

5 files changed

+64
-18
lines changed

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

Lines changed: 28 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -287,11 +287,19 @@ 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+
def isRefSet = scopes.forall(_.isRef)
291+
292+
def isEnvSet = scopes.forall(_.isEnv)
291293

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

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

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

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

739+
extension (thisV: ThisValue)
740+
def toValueSet: ValueSet = thisV match
741+
case ref: Ref => ValueSet(Set(ref))
742+
case vs: ValueSet => vs
743+
731744
given Join[ScopeSet] with
732745
extension (a: ScopeSet)
733746
def join(b: ScopeSet): ScopeSet = ScopeSet(a.scopes ++ b.scopes)
@@ -1377,7 +1390,7 @@ class Objects(using Context @constructorOnly):
13771390
case OuterSelectName(_, _) =>
13781391
val current = qualifier.tpe.classSymbol
13791392
val target = expr.tpe.widenSingleton.classSymbol.asClass
1380-
withTrace(trace2) { resolveThis(target, qual) }
1393+
withTrace(trace2) { resolveThis(target, qual.asInstanceOf[ThisValue]) }
13811394
case _ =>
13821395
withTrace(trace2) { select(qual, expr.symbol, receiver = qualifier.tpe) }
13831396

@@ -1929,17 +1942,12 @@ class Objects(using Context @constructorOnly):
19291942
def resolveThisRecur(target: ClassSymbol, scopeSet: ScopeSet): Contextual[ValueSet] =
19301943
if scopeSet == Env.NoEnv then
19311944
Bottom
1945+
else if scopeSet.isRefSet then
1946+
val (matchSet, unmatchSet) = scopeSet.partitionByClass(target)
1947+
val resolveUnmatchSet = resolveThisRecur(target, unmatchSet.outers)
1948+
matchSet.toValueSet.join(resolveUnmatchSet).asInstanceOf[ValueSet]
19321949
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)
1950+
resolveThisRecur(target, scopeSet.outers)
19431951

19441952
/** Resolve C.this that appear in `D.this`
19451953
*
@@ -1950,7 +1958,7 @@ class Objects(using Context @constructorOnly):
19501958
* Object access elision happens when the object access is used as a prefix
19511959
* in `new o.C` and `C` does not need an outer.
19521960
*/
1953-
def resolveThis(target: ClassSymbol, thisV: Value, elideObjectAccess: Boolean = false): Contextual[ValueSet] = log("resolveThis target = " + target.show + ", this = " + thisV.show, printer, (_: Value).show) {
1961+
def resolveThis(target: ClassSymbol, thisV: ThisValue, elideObjectAccess: Boolean = false): Contextual[ValueSet] = log("resolveThis target = " + target.show + ", this = " + thisV.show, printer, (_: Value).show) {
19541962
if target.is(Flags.Package) then
19551963
val error = "[Internal error] target cannot be packages, target = " + target + Trace.show
19561964
report.warning(error, Trace.position)
@@ -1960,7 +1968,7 @@ class Objects(using Context @constructorOnly):
19601968
if elideObjectAccess then ValueSet(Set(res))
19611969
else ValueSet(Set(accessObject(target)))
19621970
else
1963-
thisV match
1971+
val resolveResult = thisV match
19641972
case Bottom => Bottom
19651973
case ref: Ref =>
19661974
resolveThisRecur(target, ScopeSet(Set(ref)))
@@ -1969,6 +1977,11 @@ class Objects(using Context @constructorOnly):
19691977
case _ =>
19701978
report.warning("[Internal error] unexpected thisV = " + thisV + ", target = " + target.show + Trace.show, Trace.position)
19711979
Bottom
1980+
if resolveResult == Bottom && thisV.filterClass(target) == thisV then
1981+
// `target` is not an outer class, but a parent class
1982+
thisV.toValueSet
1983+
else
1984+
resolveResult
19721985
}
19731986

19741987
/** 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)