Skip to content

Commit

Permalink
Merge pull request #15592 from dotty-staging/fix-15374
Browse files Browse the repository at this point in the history
Fix #15374: Make sure prefix of outer select has the correct class symbol
  • Loading branch information
odersky authored Jul 6, 2022
2 parents ddabbe6 + ad698a5 commit 6a62bb7
Show file tree
Hide file tree
Showing 2 changed files with 31 additions and 7 deletions.
20 changes: 13 additions & 7 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: Tree, prefixCls: Symbol, hops: Int, info: Type) =
val tpt = TypeTree(adaptToPrefix(prefixCls.appliedRef))
val qual = Typed(prefix, tpt)
qual.outerSelect(hops, 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,13 +298,13 @@ 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(ref(lastSelf), lastCls, lastLevel - level, selfSym.info)
else
val pre = inlineCallPrefix match
case Super(qual, _) => qual
case pre => pre
val preLevel = inlinedMethod.owner.ownersIterator.length
if preLevel > level then pre.outerSelect(preLevel - level, selfSym.info)
if preLevel > level then outerSelect(pre, inlinedMethod.owner, preLevel - level, selfSym.info)
else pre

val binding = accountForOpaques(
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 6a62bb7

Please sign in to comment.