From 5fcc131e1343ad689e36548fb485c1279a44381b Mon Sep 17 00:00:00 2001 From: Guillaume Martres Date: Tue, 9 Feb 2021 18:23:19 +0100 Subject: [PATCH] Incremental compilation: handle constructor proxies I noticed that repeatedly runnning `sbt compile` in dotty lead to the same files being compiled over and over even though nothing changed, running `sbt "debug; compile"` revealed messages like this: [debug] Invalidating '${BASE}/compiler/target/scala-3.0.0-RC1/classes/dotty/tools/dotc/typer/Namer.class' because could not find class dotty.tools.dotc.typer.Namer$ on the classpath. Indeed, Namer does not have a companion object so there's no `Namer$.class` file, but sbt was looking for one because we registered such a companion with `ctx.sbtCallback.binaryDependency`, this happened because we created a fake companion object for the purpose of holding constructor proxies (fake apply methods that forward to a constructor). The fix is to special-case such references, just like we already special-cased references to the fake companion of Java classes. --- .../tools/dotc/sbt/ExtractDependencies.scala | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/sbt/ExtractDependencies.scala b/compiler/src/dotty/tools/dotc/sbt/ExtractDependencies.scala index 52e7cb2a6633..860e9e3e6c4c 100644 --- a/compiler/src/dotty/tools/dotc/sbt/ExtractDependencies.scala +++ b/compiler/src/dotty/tools/dotc/sbt/ExtractDependencies.scala @@ -150,10 +150,19 @@ class ExtractDependencies extends Phase { builder.append(".") } val flatName = dep.to.flatName - // We create fake companion object symbols to hold the static members - // of Java classes, make sure to use the name of the actual Java class - // here. - val clsFlatName = if (dep.to.is(JavaDefined)) flatName.stripModuleClassSuffix else flatName + // Some companion objects are fake (that is, they're a compiler fiction + // that doesn't correspond to a class that exists at runtime), this + // can happen in two cases: + // - If a Java class has static members. + // - If we create constructor proxies for a class (see NamerOps#addConstructorProxies). + // + // In both cases it's vital that we don't send the object name to + // zinc: when sbt is restarted, zinc will inspect the binary + // dependencies to see if they're still on the classpath, if it + // doesn't find them it will invalidate whatever referenced them, so + // any reference to a fake companion will lead to extra recompilations. + // Instead, use the class name since it's guaranteed to exist at runtime. + val clsFlatName = if (dep.to.isOneOf(JavaDefined | ConstructorProxy)) flatName.stripModuleClassSuffix else flatName builder.append(clsFlatName.mangledString) builder.toString }