Skip to content

Commit 6169318

Browse files
committed
Fix ExpandPrivate interaction with inlining
The inliner duplicates trees and their symbols when expanding inline definitions at call sites. When the RHS of the inline definition contains a class definition its Symbol is duplicated, I believe correctly, preserving the original position and associated source file. The tree is duplicated, I believe also correctly, with its source attribute reflecting that the tree has been expanded in the call site source file. In most circumstances the potential mismatch between the souce of the Symbol and the source of its defining tree is handled: in Symbol#source the source of the defining tree will be used prior to erasure if the tree is non-empty, which ensures that the source as viewed via the Symbol will be the same as the source as viewed via the tree. Things can go awry after erasure, however. In ExpandPrivate there is a same-source-file test relaxing access controls to private members of module classes. Because this happens after erasure it's possible that if a class definition has been inlined into a module and members attempt to access a definition in the module (eg. something synthetic which has been lifted into the module) the same-source-file test will fail because the source of the class symbol will now be seen as the source of the inline definition rather than the source of the inlined call site. This is the scenario exercised in the included test. The inlined refinement and by-name argument are both essential (the latter is responsible for the private synthetic term which is lifted out into the module and then incorrectly reported as inaccessible from the inlined body). In the real code from which this was reduced the refinement was actually the expansion of a polymorphic function type, but as the test shows there's nothing specific to polymorphic function types here. The simplest approach to fixing this appears to be in ExpandPrivate where if the accessing symbol (on the context.owner side) doesn't have a matching source file we fall back to checking against the source file of the current compilation unit.
1 parent 646e433 commit 6169318

File tree

3 files changed

+15
-3
lines changed

3 files changed

+15
-3
lines changed

compiler/src/dotty/tools/dotc/transform/ExpandPrivate.scala

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import Decorators._
1212
import ast.Trees._
1313
import MegaPhase._
1414
import java.io.File.separatorChar
15+
import util.SourceFile
1516

1617
import ValueClasses._
1718

@@ -84,9 +85,12 @@ class ExpandPrivate extends MiniPhase with IdentityDenotTransformer { thisPhase
8485
(j < 0 || p1(j) == separatorChar)
8586
}
8687

87-
assert(d.symbol.source.exists &&
88-
ctx.owner.source.exists &&
89-
isSimilar(d.symbol.source.path, ctx.owner.source.path),
88+
lazy val dPath = d.symbol.source.path
89+
90+
def check(src: SourceFile): Boolean =
91+
src.exists && isSimilar(dPath, src.path)
92+
93+
assert(d.symbol.source.exists && (check(ctx.owner.source) || check(ctx.compilationUnit.source)),
9094
s"private ${d.symbol.showLocated} in ${d.symbol.source} accessed from ${ctx.owner.showLocated} in ${ctx.owner.source}")
9195
d.ensureNotPrivate.installAfter(thisPhase)
9296
}

tests/pos/inline-joint/defn.scala

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
object Foo {
2+
inline def foo = new { bar(0) }
3+
4+
def bar(i: => Int): Unit = ()
5+
}

tests/pos/inline-joint/use.scala

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
object Test {
2+
val v = Foo.foo
3+
}

0 commit comments

Comments
 (0)