Skip to content

Commit

Permalink
Fix scala#15374: Make sure prefix of outer select has the correct cla…
Browse files Browse the repository at this point in the history
…ss 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]>
  • Loading branch information
liufengyun and dwijnand committed Jul 5, 2022
1 parent 9bb3108 commit 29b12b4
Show file tree
Hide file tree
Showing 2 changed files with 30 additions and 6 deletions.
18 changes: 12 additions & 6 deletions compiler/src/dotty/tools/dotc/inlines/Inliner.scala
Original file line number Diff line number Diff line change
Expand Up @@ -275,12 +275,18 @@ class Inliner(val call: tpd.Tree)(using Context):
// All needed this-proxies, paired-with and sorted-by nesting depth of
// the classes they represent (innermost first)
val sortedProxies = thisProxy.toList
.map((cls, proxy) => (cls.ownersIterator.length, proxy.symbol))
.map((cls, proxy) => (cls.ownersIterator.length, proxy.symbol, cls))
.sortBy(-_._1)

def outerSelect(prefix: Symbol, prefixCls: Symbol, level: Int, info: Type) =
val tpt = TypeTree(adaptToPrefix(prefixCls.appliedRef))
val qual = Typed(ref(prefix), tpt)
qual.outerSelect(level, info)

var lastSelf: Symbol = NoSymbol
var lastCls: Symbol = NoSymbol
var lastLevel: Int = 0
for ((level, selfSym) <- sortedProxies) {
for ((level, selfSym, cls) <- sortedProxies) {
val rhs = selfSym.info.dealias match
case info: TermRef
if info.isStable && (lastSelf.exists || isPureExpr(inlineCallPrefix)) =>
Expand All @@ -292,7 +298,7 @@ class Inliner(val call: tpd.Tree)(using Context):
if rhsClsSym.is(Module) && rhsClsSym.isStatic then
ref(rhsClsSym.sourceModule)
else if lastSelf.exists then
ref(lastSelf).outerSelect(lastLevel - level, selfSym.info)
outerSelect(lastSelf, lastCls, lastLevel - level, selfSym.info)
else
val pre = inlineCallPrefix match
case Super(qual, _) => qual
Expand All @@ -307,6 +313,7 @@ class Inliner(val call: tpd.Tree)(using Context):
inlining.println(i"proxy at $level: $selfSym = ${bindingsBuf.last}")
lastSelf = selfSym
lastLevel = level
lastCls = cls
}
}

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

private def adaptToPrefix(tp: Type) = tp.asSeenFrom(inlineCallPrefix.tpe, inlinedMethod.owner)

/** Populate `thisProxy` and `paramProxy` as follows:
*
* 1a. If given type refers to a static this, thisProxy binds it to corresponding global reference,
Expand All @@ -432,14 +441,11 @@ class Inliner(val call: tpd.Tree)(using Context):
private def registerType(tpe: Type): Unit = tpe match {
case tpe: ThisType if !canElideThis(tpe) && !thisProxy.contains(tpe.cls) =>
val proxyName = s"${tpe.cls.name}_this".toTermName
def adaptToPrefix(tp: Type) = tp.asSeenFrom(inlineCallPrefix.tpe, inlinedMethod.owner)
val proxyType = inlineCallPrefix.tpe.dealias.tryNormalize match {
case typeMatchResult if typeMatchResult.exists => typeMatchResult
case _ => adaptToPrefix(tpe).widenIfUnstable
}
thisProxy(tpe.cls) = newSym(proxyName, InlineProxy, proxyType).termRef
if (!tpe.cls.isStaticOwner)
registerType(inlinedMethod.owner.thisType) // make sure we have a base from which to outer-select
for (param <- tpe.cls.typeParams)
paramProxy(param.typeRef) = adaptToPrefix(param.typeRef)
case tpe: NamedType
Expand Down
18 changes: 18 additions & 0 deletions tests/run/i15374.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
class A(val x: Int):
class X:
inline def foo() = A.this.foo()

private def foo(): Int = x

class B extends A(20):
val a = new A(10)
val y: Y = new Y

class Y extends a.X

class C:
var b = new B
assert(b.y.foo() == 10)

@main
def Test = new C()

0 comments on commit 29b12b4

Please sign in to comment.