Skip to content

Commit 5c6b6de

Browse files
committed
use new zinc api for virtualfile
[Cherry-picked a7cec5f][modified]
1 parent 79cec4b commit 5c6b6de

File tree

25 files changed

+198
-128
lines changed

25 files changed

+198
-128
lines changed

compiler/src/dotty/tools/backend/jvm/CodeGen.scala

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ import scala.tools.asm
3030
import scala.tools.asm.tree._
3131
import tpd._
3232
import dotty.tools.io.AbstractFile
33-
import dotty.tools.dotc.util.NoSourcePosition
33+
import dotty.tools.dotc.util.{NoSourcePosition, SourceFile}
3434

3535

3636
class CodeGen(val int: DottyBackendInterface, val primitives: DottyPrimitives)( val bTypes: BTypesFromSymbols[int.type]) { self =>
@@ -106,7 +106,7 @@ class CodeGen(val int: DottyBackendInterface, val primitives: DottyPrimitives)(
106106
}
107107

108108
// Creates a callback that will be evaluated in PostProcessor after creating a file
109-
private def onFileCreated(cls: ClassNode, claszSymbol: Symbol, sourceFile: interfaces.SourceFile): AbstractFile => Unit = clsFile => {
109+
private def onFileCreated(cls: ClassNode, claszSymbol: Symbol, sourceFile: SourceFile): AbstractFile => Unit = clsFile => {
110110
val (fullClassName, isLocal) = atPhase(sbtExtractDependenciesPhase) {
111111
(ExtractDependencies.classNameAsString(claszSymbol), claszSymbol.isLocal)
112112
}
@@ -116,10 +116,10 @@ class CodeGen(val int: DottyBackendInterface, val primitives: DottyPrimitives)(
116116
ctx.compilerCallback.onClassGenerated(sourceFile, convertAbstractFile(clsFile), className)
117117

118118
if (ctx.sbtCallback != null) {
119-
val jSourceFile = sourceFile.jfile.orElse(null)
119+
val jSourceFile = sourceFile.underlyingZincFile
120120
val cb = ctx.sbtCallback
121-
if (isLocal) cb.generatedLocalClass(jSourceFile, clsFile.file)
122-
else cb.generatedNonLocalClass(jSourceFile, clsFile.file, className, fullClassName)
121+
if (isLocal) cb.generatedLocalClass(jSourceFile, clsFile.jpath)
122+
else cb.generatedNonLocalClass(jSourceFile, clsFile.jpath, className, fullClassName)
123123
}
124124
}
125125

compiler/src/dotty/tools/dotc/config/ScalaSettings.scala

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -325,6 +325,7 @@ private sealed trait YSettings:
325325
val YdebugTypeError: Setting[Boolean] = BooleanSetting("-Ydebug-type-error", "Print the stack trace when a TypeError is caught", false)
326326
val YdebugError: Setting[Boolean] = BooleanSetting("-Ydebug-error", "Print the stack trace when any error is caught.", false)
327327
val YdebugUnpickling: Setting[Boolean] = BooleanSetting("-Ydebug-unpickling", "Print the stack trace when an error occurs when reading Tasty.", false)
328+
val YdebugVirtualFiles: Setting[Boolean] = BooleanSetting("-Ydebug-virtual-files", "Debug usage of virtual files, e.g. remote cache in sbt", false)
328329
val YtermConflict: Setting[String] = ChoiceSetting("-Yresolve-term-conflict", "strategy", "Resolve term conflicts", List("package", "object", "error"), "error")
329330
val Ylog: Setting[List[String]] = PhasesSetting("-Ylog", "Log operations during")
330331
val YlogClasspath: Setting[Boolean] = BooleanSetting("-Ylog-classpath", "Output information about what classpath is being applied.")

compiler/src/dotty/tools/dotc/core/Contexts.scala

Lines changed: 20 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -39,22 +39,25 @@ import util.Store
3939
import xsbti.AnalysisCallback
4040
import plugins._
4141
import java.util.concurrent.atomic.AtomicInteger
42+
import java.util.Map as JMap
4243
import java.nio.file.InvalidPathException
4344

45+
4446
object Contexts {
4547

46-
private val (compilerCallbackLoc, store1) = Store.empty.newLocation[CompilerCallback]()
47-
private val (sbtCallbackLoc, store2) = store1.newLocation[AnalysisCallback]()
48-
private val (printerFnLoc, store3) = store2.newLocation[Context => Printer](new RefinedPrinter(_))
49-
private val (settingsStateLoc, store4) = store3.newLocation[SettingsState]()
50-
private val (compilationUnitLoc, store5) = store4.newLocation[CompilationUnit]()
51-
private val (runLoc, store6) = store5.newLocation[Run | Null]()
52-
private val (profilerLoc, store7) = store6.newLocation[Profiler]()
53-
private val (notNullInfosLoc, store8) = store7.newLocation[List[NotNullInfo]]()
54-
private val (importInfoLoc, store9) = store8.newLocation[ImportInfo | Null]()
55-
private val (typeAssignerLoc, store10) = store9.newLocation[TypeAssigner](TypeAssigner)
48+
private val (compilerCallbackLoc, store1) = Store.empty.newLocation[CompilerCallback]()
49+
private val (sbtCallbackLoc, store2) = store1.newLocation[AnalysisCallback]()
50+
private val (printerFnLoc, store3) = store2.newLocation[Context => Printer](new RefinedPrinter(_))
51+
private val (settingsStateLoc, store4) = store3.newLocation[SettingsState]()
52+
private val (compilationUnitLoc, store5) = store4.newLocation[CompilationUnit]()
53+
private val (runLoc, store6) = store5.newLocation[Run | Null]()
54+
private val (profilerLoc, store7) = store6.newLocation[Profiler]()
55+
private val (notNullInfosLoc, store8) = store7.newLocation[List[NotNullInfo]]()
56+
private val (importInfoLoc, store9) = store8.newLocation[ImportInfo | Null]()
57+
private val (typeAssignerLoc, store10) = store9.newLocation[TypeAssigner](TypeAssigner)
58+
private val (zincVirtualFilesLoc, store11) = store10.newLocation[JMap[String, xsbti.VirtualFile] | Null]()
5659

57-
private val initialStore = store10
60+
private val initialStore = store11
5861

5962
/** The current context */
6063
inline def ctx(using ctx: Context): Context = ctx
@@ -164,9 +167,12 @@ object Contexts {
164167
/** The compiler callback implementation, or null if no callback will be called. */
165168
def compilerCallback: CompilerCallback = store(compilerCallbackLoc)
166169

167-
/** The sbt callback implementation if we are run from sbt, null otherwise */
170+
/** The Zinc callback implementation if we are run from Zinc, null otherwise */
168171
def sbtCallback: AnalysisCallback = store(sbtCallbackLoc)
169172

173+
/** A map from absolute path to VirtualFile if we are run from Zinc, null otherwise */
174+
def zincVirtualFiles: JMap[String, xsbti.VirtualFile] | Null = store(zincVirtualFilesLoc)
175+
170176
/** The current plain printer */
171177
def printerFn: Context => Printer = store(printerFnLoc)
172178

@@ -665,6 +671,8 @@ object Contexts {
665671

666672
def setCompilerCallback(callback: CompilerCallback): this.type = updateStore(compilerCallbackLoc, callback)
667673
def setSbtCallback(callback: AnalysisCallback): this.type = updateStore(sbtCallbackLoc, callback)
674+
def setZincVirtualFiles(map: JMap[String, xsbti.VirtualFile]): this.type =
675+
updateStore(zincVirtualFilesLoc, map)
668676
def setPrinterFn(printer: Context => Printer): this.type = updateStore(printerFnLoc, printer)
669677
def setSettings(settingsState: SettingsState): this.type = updateStore(settingsStateLoc, settingsState)
670678
def setRun(run: Run | Null): this.type = updateStore(runLoc, run)

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ object APIUtils {
3737
def registerDummyClass(classSym: ClassSymbol)(using Context): Unit = {
3838
if (ctx.sbtCallback != null) {
3939
val classLike = emptyClassLike(classSym)
40-
ctx.sbtCallback.api(ctx.compilationUnit.source.file.file, classLike)
40+
ctx.sbtCallback.api(ctx.compilationUnit.source.underlyingZincFile, classLike)
4141
}
4242
}
4343

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

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -65,17 +65,17 @@ class ExtractAPI extends Phase {
6565

6666
override def run(using Context): Unit = {
6767
val unit = ctx.compilationUnit
68-
val sourceFile = unit.source.file
68+
val sourceFile = unit.source
6969
if (ctx.sbtCallback != null)
70-
ctx.sbtCallback.startSource(sourceFile.file)
70+
ctx.sbtCallback.startSource(sourceFile.underlyingZincFile)
7171

7272
val apiTraverser = new ExtractAPICollector
7373
val classes = apiTraverser.apiSource(unit.tpdTree)
7474
val mainClasses = apiTraverser.mainClasses
7575

7676
if (ctx.settings.YdumpSbtInc.value) {
7777
// Append to existing file that should have been created by ExtractDependencies
78-
val pw = new PrintWriter(File(sourceFile.jpath).changeExtension("inc").toFile
78+
val pw = new PrintWriter(File(sourceFile.file.jpath).changeExtension("inc").toFile
7979
.bufferedWriter(append = true), true)
8080
try {
8181
classes.foreach(source => pw.println(DefaultShowAPI(source)))
@@ -85,8 +85,8 @@ class ExtractAPI extends Phase {
8585
if ctx.sbtCallback != null &&
8686
!ctx.compilationUnit.suspendedAtInliningPhase // already registered before this unit was suspended
8787
then
88-
classes.foreach(ctx.sbtCallback.api(sourceFile.file, _))
89-
mainClasses.foreach(ctx.sbtCallback.mainClass(sourceFile.file, _))
88+
classes.foreach(ctx.sbtCallback.api(sourceFile.underlyingZincFile, _))
89+
mainClasses.foreach(ctx.sbtCallback.mainClass(sourceFile.underlyingZincFile, _))
9090
}
9191
}
9292

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

Lines changed: 16 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ package sbt
44
import scala.language.unsafeNulls
55

66
import java.io.File
7+
import java.nio.file.Path
78
import java.util.{Arrays, EnumSet}
89

910
import dotty.tools.dotc.ast.tpd
@@ -18,6 +19,7 @@ import dotty.tools.dotc.core.Denotations.StaleSymbol
1819
import dotty.tools.dotc.core.Types._
1920
import dotty.tools.dotc.transform.SymUtils._
2021
import dotty.tools.dotc.util.{SrcPos, NoSourcePosition}
22+
import dotty.tools.uncheckedNN
2123
import dotty.tools.io
2224
import dotty.tools.io.{AbstractFile, PlainFile, ZipArchive}
2325
import xsbti.UseScope
@@ -55,7 +57,7 @@ class ExtractDependencies extends Phase {
5557

5658
override def isRunnable(using Context): Boolean = {
5759
def forceRun = ctx.settings.YdumpSbtInc.value || ctx.settings.YforceSbtPhases.value
58-
super.isRunnable && (ctx.sbtCallback != null || forceRun)
60+
super.isRunnable && (ctx.sbtCallback != null && ctx.sbtCallback.enabled() || forceRun)
5961
}
6062

6163
// Check no needed. Does not transform trees
@@ -90,7 +92,7 @@ class ExtractDependencies extends Phase {
9092
} finally pw.close()
9193
}
9294

93-
if (ctx.sbtCallback != null) {
95+
if (ctx.sbtCallback != null && ctx.sbtCallback.enabled()) {
9496
collector.usedNames.foreach {
9597
case (clazz, usedNames) =>
9698
val className = classNameAsString(clazz)
@@ -111,17 +113,17 @@ class ExtractDependencies extends Phase {
111113
*/
112114
def recordDependency(dep: ClassDependency)(using Context): Unit = {
113115
val fromClassName = classNameAsString(dep.from)
114-
val sourceFile = ctx.compilationUnit.source.file.file
116+
val zincSourceFile = ctx.compilationUnit.source.underlyingZincFile
115117

116-
def binaryDependency(file: File, binaryClassName: String) =
117-
ctx.sbtCallback.binaryDependency(file, binaryClassName, fromClassName, sourceFile, dep.context)
118+
def binaryDependency(file: Path, binaryClassName: String) =
119+
ctx.sbtCallback.binaryDependency(file, binaryClassName, fromClassName, zincSourceFile, dep.context)
118120

119121
def processExternalDependency(depFile: AbstractFile, binaryClassName: String) = {
120122
depFile match {
121123
case ze: ZipArchive#Entry => // The dependency comes from a JAR
122124
ze.underlyingSource match
123-
case Some(zip) if zip.file != null =>
124-
binaryDependency(zip.file, binaryClassName)
125+
case Some(zip) if zip.jpath != null =>
126+
binaryDependency(zip.jpath, binaryClassName)
125127
case _ =>
126128
case pf: PlainFile => // The dependency comes from a class file
127129
// FIXME: pf.file is null for classfiles coming from the modulepath
@@ -130,21 +132,25 @@ class ExtractDependencies extends Phase {
130132
// java.io.File, this means that we cannot record dependencies coming
131133
// from the modulepath. For now this isn't a big deal since we only
132134
// support having the standard Java library on the modulepath.
133-
if pf.file != null then
134-
binaryDependency(pf.file, binaryClassName)
135+
if pf.jpath != null then
136+
binaryDependency(pf.jpath, binaryClassName)
135137
case _ =>
136138
internalError(s"Ignoring dependency $depFile of unknown class ${depFile.getClass}}", dep.from.srcPos)
137139
}
138140
}
139141

140142
val depFile = dep.to.associatedFile
141143
if (depFile != null) {
144+
def depIsSameSource =
145+
val depVF: xsbti.VirtualFile | Null = ctx.zincVirtualFiles.uncheckedNN.get(depFile.absolutePath)
146+
depVF != null && depVF.id() == zincSourceFile.id()
147+
142148
// Cannot ignore inheritance relationship coming from the same source (see sbt/zinc#417)
143149
def allowLocal = dep.context == DependencyByInheritance || dep.context == LocalDependencyByInheritance
144150
if (depFile.extension == "class") {
145151
// Dependency is external -- source is undefined
146152
processExternalDependency(depFile, dep.to.binaryClassName)
147-
} else if (allowLocal || depFile.file != sourceFile) {
153+
else if (allowLocal || !depIsSameSource /* old: depFile.file != sourceFile.file */) {
148154
// We cannot ignore dependencies coming from the same source file because
149155
// the dependency info needs to propagate. See source-dependencies/trait-trait-211.
150156
val toClassName = classNameAsString(dep.to)

compiler/src/dotty/tools/dotc/util/SourceFile.scala

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,33 @@ class SourceFile(val file: AbstractFile, computeContent: => Array[Char]) extends
6464
import SourceFile._
6565

6666
private var myContent: Array[Char] | Null = null
67+
private var myUnderlyingZincFile: xsbti.VirtualFile | Null = null
68+
69+
def underlyingZincFile(using Context): xsbti.VirtualFile =
70+
val local = myUnderlyingZincFile
71+
if local == null then
72+
// usually without -sourcepath then the `underlying` will be set by Zinc.
73+
val maybeUnderlying = file.underlying
74+
val underlying0 =
75+
if maybeUnderlying == null then
76+
// When we have `-sourcepath` set then the file could come from the filesystem,
77+
// rather than a zinc managed file, so then we need to check if we have a virtual file for it.
78+
// TODO: we should consider in the future if there is a use case for sourcepath to possibly be
79+
// made of virtual files.
80+
val fromLookup = ctx.zincVirtualFiles.uncheckedNN.get(file.absolutePath)
81+
if fromLookup != null then
82+
fromLookup
83+
else
84+
sys.error(s"no underlying file for ${file.absolutePath}, possible paths = ${ctx.zincVirtualFiles.keySet}")
85+
else maybeUnderlying
86+
if ctx.settings.YdebugVirtualFiles.value then
87+
val isVirtual = !underlying0.isInstanceOf[xsbti.PathBasedFile]
88+
println(s"found underlying zinc file ${underlying0.id} for ${file.absolutePath} [virtual = $isVirtual]")
89+
90+
myUnderlyingZincFile = underlying0
91+
underlying0
92+
else
93+
local
6794

6895
/** The contents of the original source file. Note that this can be empty, for example when
6996
* the source is read from Tasty. */

compiler/src/dotty/tools/io/AbstractFile.scala

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,9 @@ abstract class AbstractFile extends Iterable[AbstractFile] {
118118
/** Returns the underlying Path if any and null otherwise. */
119119
def jpath: JPath
120120

121+
/** Overridden in sbt-bridge ZincPlainFile and ZincVirtualFile */
122+
def underlying: xsbti.VirtualFile | Null = null
123+
121124
/** An underlying source, if known. Mostly, a zip/jar file. */
122125
def underlyingSource: Option[AbstractFile] = None
123126

project/Build.scala

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -551,7 +551,7 @@ object Build {
551551
// get libraries onboard
552552
libraryDependencies ++= Seq(
553553
"org.scala-lang.modules" % "scala-asm" % "9.5.0-scala-1", // used by the backend
554-
Dependencies.oldCompilerInterface, // we stick to the old version to avoid deprecation warnings
554+
Dependencies.compilerInterface,
555555
"org.jline" % "jline-reader" % "3.19.0", // used by the REPL
556556
"org.jline" % "jline-terminal" % "3.19.0",
557557
"org.jline" % "jline-terminal-jna" % "3.19.0", // needed for Windows
@@ -668,7 +668,8 @@ object Build {
668668
val dottyTastyInspector = jars("scala3-tasty-inspector")
669669
val dottyInterfaces = jars("scala3-interfaces")
670670
val tastyCore = jars("tasty-core")
671-
run(insertClasspathInArgs(args1, List(dottyCompiler, dottyInterfaces, asm, dottyStaging, dottyTastyInspector, tastyCore).mkString(File.pathSeparator)))
671+
val compilerInterface = findArtifactPath(externalDeps, "compiler-interface")
672+
run(insertClasspathInArgs(args1, List(dottyCompiler, dottyInterfaces, asm, dottyStaging, dottyTastyInspector, tastyCore, compilerInterface).mkString(File.pathSeparator)))
672673
} else run(args)
673674
},
674675

@@ -707,7 +708,8 @@ object Build {
707708
val dottyTastyInspector = jars("scala3-tasty-inspector")
708709
val tastyCore = jars("tasty-core")
709710
val asm = findArtifactPath(externalDeps, "scala-asm")
710-
extraClasspath ++= Seq(dottyCompiler, dottyInterfaces, asm, dottyStaging, dottyTastyInspector, tastyCore)
711+
val compilerInterface = findArtifactPath(externalDeps, "compiler-interface")
712+
extraClasspath ++= Seq(dottyCompiler, dottyInterfaces, asm, dottyStaging, dottyTastyInspector, tastyCore, compilerInterface)
711713
}
712714

713715
val fullArgs = main :: (if (printTasty) args else insertClasspathInArgs(args, extraClasspath.mkString(File.pathSeparator)))
@@ -1051,8 +1053,7 @@ object Build {
10511053
// when sbt reads the settings.
10521054
Test / test := (LocalProject("scala3-sbt-bridge-tests") / Test / test).value,
10531055

1054-
// The `newCompilerInterface` is backward compatible with the `oldCompilerInterface`
1055-
libraryDependencies += Dependencies.newCompilerInterface % Provided
1056+
libraryDependencies += Dependencies.compilerInterface % Provided
10561057
)
10571058

10581059
// We use a separate project for the bridge tests since they can only be run

project/Dependencies.scala

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,5 @@ object Dependencies {
2828
"com.vladsch.flexmark" % "flexmark-ext-yaml-front-matter" % flexmarkVersion,
2929
)
3030

31-
val newCompilerInterface = "org.scala-sbt" % "compiler-interface" % "1.9.0"
32-
val oldCompilerInterface = "org.scala-sbt" % "compiler-interface" % "1.3.5"
31+
val compilerInterface = "org.scala-sbt" % "compiler-interface" % "1.9.0"
3332
}

sbt-bridge/src/dotty/tools/xsbt/CompilerBridgeDriver.java

Lines changed: 30 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919

2020
import java.io.IOException;
2121
import java.util.Comparator;
22+
import java.util.HashMap;
2223
import java.util.Arrays;
2324

2425
public class CompilerBridgeDriver extends Driver {
@@ -51,14 +52,40 @@ public boolean sourcesRequired() {
5152
}
5253

5354
synchronized public void run(VirtualFile[] sources, AnalysisCallback callback, Logger log, Reporter delegate) {
54-
DelegatingReporter reporter = new DelegatingReporter(delegate);
55+
// convert sources to a HashMap from this.id to itself
56+
HashMap<String, VirtualFile> sourcesMap = new HashMap<>();
57+
58+
VirtualFile[] sortedSources = new VirtualFile[sources.length];
59+
System.arraycopy(sources, 0, sortedSources, 0, sources.length);
60+
Arrays.sort(sortedSources, (x0, x1) -> x0.id().compareTo(x1.id()));
61+
62+
ListBuffer<AbstractFile> sourcesBuffer = new ListBuffer<>();
63+
64+
for (int i = 0; i < sources.length; i++) {
65+
VirtualFile source = sortedSources[i];
66+
AbstractFile abstractFile = asDottyFile(source);
67+
sourcesBuffer.append(abstractFile);
68+
sourcesMap.put(abstractFile.absolutePath(), source);
69+
}
70+
71+
DelegatingReporter reporter = new DelegatingReporter(delegate, sourceFile -> {
72+
String pathId = sourceFile.file().absolutePath();
73+
VirtualFile source = sourcesMap.get(pathId);
74+
75+
if (source != null)
76+
return source.id();
77+
else
78+
return pathId;
79+
});
80+
5581
try {
5682
log.debug(this::infoOnCachedCompiler);
5783

5884
Contexts.Context initialCtx = initCtx()
5985
.fresh()
6086
.setReporter(reporter)
61-
.setSbtCallback(callback);
87+
.setSbtCallback(callback)
88+
.setZincVirtualFiles(sourcesMap);
6289

6390
Contexts.Context context = setup(args, initialCtx).map(t -> t._2).getOrElse(() -> initialCtx);
6491

@@ -70,28 +97,13 @@ synchronized public void run(VirtualFile[] sources, AnalysisCallback callback, L
7097
log.debug(this::prettyPrintCompilationArguments);
7198
Compiler compiler = newCompiler(context);
7299

73-
VirtualFile[] sortedSources = new VirtualFile[sources.length];
74-
System.arraycopy(sources, 0, sortedSources, 0, sources.length);
75-
Arrays.sort(
76-
sortedSources,
77-
new Comparator<VirtualFile>() {
78-
@Override
79-
public int compare(VirtualFile x0, VirtualFile x1) {
80-
return x0.id().compareTo(x1.id());
81-
}
82-
}
83-
);
84-
85-
ListBuffer<AbstractFile> sourcesBuffer = new ListBuffer<>();
86-
for (VirtualFile file: sortedSources)
87-
sourcesBuffer.append(asDottyFile(file));
88100
doCompile(compiler, sourcesBuffer.toList(), context);
89101

90102
for (xsbti.Problem problem: delegate.problems()) {
91103
callback.problem(problem.category(), problem.position(), problem.message(), problem.severity(),
92104
true);
93105
}
94-
} else {
106+
} else {
95107
delegate.printSummary();
96108
}
97109

0 commit comments

Comments
 (0)