diff options
author | Guillaume Martres <smarter@ubuntu.com> | 2017-03-23 17:31:43 +0100 |
---|---|---|
committer | Guillaume Martres <smarter@ubuntu.com> | 2017-03-23 21:11:17 +0100 |
commit | 65455bbcaace514ea34a30a3fc102c8ecee16498 (patch) | |
tree | 0255ecba500bc6011652d9c6c6e80b128ae9b5a3 | |
parent | 6ab7c1da8987806e0e3cbc820781b6ef955c109b (diff) | |
download | dotty-65455bbcaace514ea34a30a3fc102c8ecee16498.tar.gz dotty-65455bbcaace514ea34a30a3fc102c8ecee16498.tar.bz2 dotty-65455bbcaace514ea34a30a3fc102c8ecee16498.zip |
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.
5 files changed, 36 insertions, 0 deletions
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) diff --git a/tests/pending/pos/false-companion/00_outerinnerTest_2.scala b/tests/pending/pos/false-companion/00_outerinnerTest_2.scala new file mode 100644 index 000000000..8f5802343 --- /dev/null +++ b/tests/pending/pos/false-companion/00_outerinnerTest_2.scala @@ -0,0 +1,5 @@ +package outer +package inner +object Test { + val x: Foo = new Foo +} diff --git a/tests/pending/pos/false-companion/01_outerinnerFoo_2.scala b/tests/pending/pos/false-companion/01_outerinnerFoo_2.scala new file mode 100644 index 000000000..111f7fcd5 --- /dev/null +++ b/tests/pending/pos/false-companion/01_outerinnerFoo_2.scala @@ -0,0 +1,5 @@ +package outer +package inner +object Foo { + // val a: Int = 1 +} diff --git a/tests/pending/pos/false-companion/outerFoo_1.scala b/tests/pending/pos/false-companion/outerFoo_1.scala new file mode 100644 index 000000000..8c2ef109c --- /dev/null +++ b/tests/pending/pos/false-companion/outerFoo_1.scala @@ -0,0 +1,2 @@ +package outer +class Foo diff --git a/tests/pending/pos/false-companion/outerinnerFoo_1.scala b/tests/pending/pos/false-companion/outerinnerFoo_1.scala new file mode 100644 index 000000000..29f3df724 --- /dev/null +++ b/tests/pending/pos/false-companion/outerinnerFoo_1.scala @@ -0,0 +1,5 @@ +package outer +package inner +object Foo { + val a: Int = 1 +} |