Skip to content

Commit 9ba9b14

Browse files
authored
Merge pull request #2139 from dotty-staging/fix/false-companion
Fix #2137: Create dummy companions for top-level objects without a real one
2 parents d9dedc5 + b641181 commit 9ba9b14

File tree

6 files changed

+39
-3
lines changed

6 files changed

+39
-3
lines changed

compiler/src/dotty/tools/dotc/sbt/ExtractDependencies.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -175,7 +175,7 @@ private class ExtractDependenciesCollector(implicit val ctx: Context) extends tp
175175
override def traverse(tree: Tree)(implicit ctx: Context): Unit = {
176176
tree match {
177177
case Import(expr, selectors) =>
178-
def lookupImported(name: Name) = expr.tpe.select(name).typeSymbol
178+
def lookupImported(name: Name) = expr.tpe.member(name).symbol
179179
def addImported(name: Name) = {
180180
// importing a name means importing both a term and a type (if they exist)
181181
addDependency(lookupImported(name.toTermName))

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

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -570,8 +570,8 @@ class Namer { typer: Typer =>
570570

571571
/** Create links between companion object and companion class */
572572
def createLinks(classTree: TypeDef, moduleTree: TypeDef)(implicit ctx: Context) = {
573-
val claz = ctx.denotNamed(classTree.name.encode).symbol
574-
val modl = ctx.denotNamed(moduleTree.name.encode).symbol
573+
val claz = ctx.effectiveScope.lookup(classTree.name.encode)
574+
val modl = ctx.effectiveScope.lookup(moduleTree.name.encode)
575575
ctx.synthesizeCompanionMethod(nme.COMPANION_CLASS_METHOD, claz, modl).entered
576576
ctx.synthesizeCompanionMethod(nme.COMPANION_MODULE_METHOD, modl, claz).entered
577577
}
@@ -605,6 +605,25 @@ class Namer { typer: Typer =>
605605
case EmptyTree =>
606606
}
607607
}
608+
609+
// If a top-level object has no companion class in the current run, we
610+
// enter a dummy companion class symbol (`denot.isAbsent` returns true) in
611+
// scope. This ensures that we never use a companion from a previous run
612+
// or from the classpath. See tests/pos/false-companion for an
613+
// example where this matters.
614+
if (ctx.owner.is(PackageClass)) {
615+
for (cdef @ TypeDef(moduleName, _) <- moduleDef.values) {
616+
val moduleSym = ctx.effectiveScope.lookup(moduleName.encode)
617+
if (moduleSym.isDefinedInCurrentRun) {
618+
val className = moduleName.stripModuleClassSuffix.toTypeName
619+
val classSym = ctx.effectiveScope.lookup(className.encode)
620+
if (!classSym.isDefinedInCurrentRun) {
621+
val absentClassSymbol = ctx.newClassSymbol(ctx.owner, className, EmptyFlags, _ => NoType)
622+
enterSymbol(absentClassSymbol)
623+
}
624+
}
625+
}
626+
}
608627
}
609628

610629
stats.foreach(expand)
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
package outer
2+
package inner
3+
object Test {
4+
val x: Foo = new Foo
5+
}
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
package outer
2+
package inner
3+
object Foo {
4+
// val a: Int = 1
5+
}
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
package outer
2+
class Foo
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
package outer
2+
package inner
3+
object Foo {
4+
val a: Int = 1
5+
}

0 commit comments

Comments
 (0)