Skip to content

Commit 29b12b4

Browse files
liufengyundwijnand
andcommitted
Fix #15374: Make sure prefix of outer select has the correct class symbol
If we have an outer select `e.outer_<hops>`, we must make sure that the class symbol of `e` is the class where the outer this is located in. Otherwise, the phase `ElimOuterSelect` would get confused. Co-authored-by: Dale Wijnand <[email protected]>
1 parent 9bb3108 commit 29b12b4

File tree

2 files changed

+30
-6
lines changed

2 files changed

+30
-6
lines changed

compiler/src/dotty/tools/dotc/inlines/Inliner.scala

+12-6
Original file line numberDiff line numberDiff line change
@@ -275,12 +275,18 @@ class Inliner(val call: tpd.Tree)(using Context):
275275
// All needed this-proxies, paired-with and sorted-by nesting depth of
276276
// the classes they represent (innermost first)
277277
val sortedProxies = thisProxy.toList
278-
.map((cls, proxy) => (cls.ownersIterator.length, proxy.symbol))
278+
.map((cls, proxy) => (cls.ownersIterator.length, proxy.symbol, cls))
279279
.sortBy(-_._1)
280280

281+
def outerSelect(prefix: Symbol, prefixCls: Symbol, level: Int, info: Type) =
282+
val tpt = TypeTree(adaptToPrefix(prefixCls.appliedRef))
283+
val qual = Typed(ref(prefix), tpt)
284+
qual.outerSelect(level, info)
285+
281286
var lastSelf: Symbol = NoSymbol
287+
var lastCls: Symbol = NoSymbol
282288
var lastLevel: Int = 0
283-
for ((level, selfSym) <- sortedProxies) {
289+
for ((level, selfSym, cls) <- sortedProxies) {
284290
val rhs = selfSym.info.dealias match
285291
case info: TermRef
286292
if info.isStable && (lastSelf.exists || isPureExpr(inlineCallPrefix)) =>
@@ -292,7 +298,7 @@ class Inliner(val call: tpd.Tree)(using Context):
292298
if rhsClsSym.is(Module) && rhsClsSym.isStatic then
293299
ref(rhsClsSym.sourceModule)
294300
else if lastSelf.exists then
295-
ref(lastSelf).outerSelect(lastLevel - level, selfSym.info)
301+
outerSelect(lastSelf, lastCls, lastLevel - level, selfSym.info)
296302
else
297303
val pre = inlineCallPrefix match
298304
case Super(qual, _) => qual
@@ -307,6 +313,7 @@ class Inliner(val call: tpd.Tree)(using Context):
307313
inlining.println(i"proxy at $level: $selfSym = ${bindingsBuf.last}")
308314
lastSelf = selfSym
309315
lastLevel = level
316+
lastCls = cls
310317
}
311318
}
312319

@@ -417,6 +424,8 @@ class Inliner(val call: tpd.Tree)(using Context):
417424
|| tpe.cls.is(Package)
418425
|| tpe.cls.isStaticOwner && !(tpe.cls.seesOpaques && inlinedMethod.isContainedIn(tpe.cls))
419426

427+
private def adaptToPrefix(tp: Type) = tp.asSeenFrom(inlineCallPrefix.tpe, inlinedMethod.owner)
428+
420429
/** Populate `thisProxy` and `paramProxy` as follows:
421430
*
422431
* 1a. If given type refers to a static this, thisProxy binds it to corresponding global reference,
@@ -432,14 +441,11 @@ class Inliner(val call: tpd.Tree)(using Context):
432441
private def registerType(tpe: Type): Unit = tpe match {
433442
case tpe: ThisType if !canElideThis(tpe) && !thisProxy.contains(tpe.cls) =>
434443
val proxyName = s"${tpe.cls.name}_this".toTermName
435-
def adaptToPrefix(tp: Type) = tp.asSeenFrom(inlineCallPrefix.tpe, inlinedMethod.owner)
436444
val proxyType = inlineCallPrefix.tpe.dealias.tryNormalize match {
437445
case typeMatchResult if typeMatchResult.exists => typeMatchResult
438446
case _ => adaptToPrefix(tpe).widenIfUnstable
439447
}
440448
thisProxy(tpe.cls) = newSym(proxyName, InlineProxy, proxyType).termRef
441-
if (!tpe.cls.isStaticOwner)
442-
registerType(inlinedMethod.owner.thisType) // make sure we have a base from which to outer-select
443449
for (param <- tpe.cls.typeParams)
444450
paramProxy(param.typeRef) = adaptToPrefix(param.typeRef)
445451
case tpe: NamedType

tests/run/i15374.scala

+18
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
class A(val x: Int):
2+
class X:
3+
inline def foo() = A.this.foo()
4+
5+
private def foo(): Int = x
6+
7+
class B extends A(20):
8+
val a = new A(10)
9+
val y: Y = new Y
10+
11+
class Y extends a.X
12+
13+
class C:
14+
var b = new B
15+
assert(b.y.foo() == 10)
16+
17+
@main
18+
def Test = new C()

0 commit comments

Comments
 (0)