From 65455bbcaace514ea34a30a3fc102c8ecee16498 Mon Sep 17 00:00:00 2001 From: Guillaume Martres Date: Thu, 23 Mar 2017 17:31:43 +0100 Subject: Fix #2137: Create dummy companions for top-level objects without a real one Previously, we sometimes ended up forcing a companion class symbol from a previous run or from the classpath which lead to weird issues like in `false-companion`. Even if we end up not forcing such a symbol, its presence can still lead to issue: before this commit incremental compilation of `dotty-compiler-bootstrapped` was broken because we recorded a false dependency on the non-bootstrapped `dotty-compiler` jar. The added test is currently marked pending because it does not work with JUnit (which doesn't handle separate compilation), only partest. I didn't managed to get it to work right, and this won't be necessary once our testing framework is overhauled by https://github.com/lampepfl/dotty/pull/2125 anyway, so I'll just have to remember to enable this test afterwards. --- compiler/src/dotty/tools/dotc/typer/Namer.scala | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) (limited to 'compiler/src/dotty/tools/dotc/typer') diff --git a/compiler/src/dotty/tools/dotc/typer/Namer.scala b/compiler/src/dotty/tools/dotc/typer/Namer.scala index 2cefc52a0..706e8b5bf 100644 --- a/compiler/src/dotty/tools/dotc/typer/Namer.scala +++ b/compiler/src/dotty/tools/dotc/typer/Namer.scala @@ -605,6 +605,25 @@ class Namer { typer: Typer => case EmptyTree => } } + + // If a top-level object has no companion class in the current run, we + // enter a dummy companion class symbol (`denot.isAbsent` returns true) in + // scope. This ensures that we never use a companion from a previous run + // or from the classpath. See tests/pos/false-companion for an + // example where this matters. + if (ctx.owner.is(PackageClass)) { + for (cdef @ TypeDef(moduleName, _) <- moduleDef.values) { + val moduleSym = ctx.denotNamed(moduleName.encode).symbol + if (moduleSym.isDefinedInCurrentRun) { + val className = moduleName.stripModuleClassSuffix.toTypeName + val classSym = ctx.denotNamed(className.encode).symbol + if (!classSym.isDefinedInCurrentRun) { + val absentClassSymbol = ctx.newClassSymbol(ctx.owner, className, EmptyFlags, _ => NoType) + enterSymbol(absentClassSymbol) + } + } + } + } } stats.foreach(expand) -- cgit v1.2.3