Skip to content

Commit 37d6d1e

Browse files
committed
Avoid cycle with top-level export and trait
Previously, the following lead to a cycle (typing the extension method requires typing its `Int` parameter, which forces completion of the package object containing the top-level definition, which forces completion of the extension method via the export clause): trait MyExtensions: extension (lhs: Int) def bash: Unit = {} object MyExtensions extends MyExtensions export MyExtensions.* val fails = 1.bash But curiously enough, simply defining `object MyExtensions` before `trait MyExtensions` was enough to work around the issue. This happened because typing the module val of the object forces the package object, this in turns forces the extension method but because of the way class completers work, this doesn't lead to a cycle. Based on this experiment, this commit simply always forces the package object before typing any definition in the package, so we don't run into a cycle no matter the order in which definitions appear.
1 parent eb8773e commit 37d6d1e

File tree

2 files changed

+10
-0
lines changed

2 files changed

+10
-0
lines changed

compiler/src/dotty/tools/dotc/typer/Typer.scala

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2542,6 +2542,10 @@ class Typer extends Namer
25422542
pid1 match
25432543
case pid1: RefTree if pkg.is(Package) =>
25442544
inContext(ctx.packageContext(tree, pkg)) {
2545+
// If it exists, complete the class containing the top-level definitions
2546+
// before typing any statement in the package to avoid cycles as in i13669.scala
2547+
val topLevelClassName = desugar.packageObjectName(ctx.source).moduleClassName
2548+
pkg.moduleClass.info.decls.lookup(topLevelClassName).ensureCompleted()
25452549
var stats1 = typedStats(tree.stats, pkg.moduleClass)._1
25462550
if (!ctx.isAfterTyper)
25472551
stats1 = stats1 ++ typedBlockStats(MainProxies.mainProxies(stats1))._1

tests/pos/i13669.scala

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
trait MyExtensions:
2+
extension (lhs: Int) def bash: Unit = {}
3+
object MyExtensions extends MyExtensions
4+
5+
export MyExtensions.*
6+
val fails = 1.bash

0 commit comments

Comments
 (0)