Skip to content

use new zinc 1.8 api for VirtualFile #18137

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 10 commits into from
Jul 23, 2023
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 3 additions & 6 deletions compiler/src/dotty/tools/backend/jvm/CodeGen.scala
Original file line number Diff line number Diff line change
Expand Up @@ -115,12 +115,9 @@ class CodeGen(val int: DottyBackendInterface, val primitives: DottyPrimitives)(
if (ctx.compilerCallback != null)
ctx.compilerCallback.onClassGenerated(sourceFile, convertAbstractFile(clsFile), className)

if (ctx.sbtCallback != null) {
val jSourceFile = sourceFile.jfile.orElse(null)
val cb = ctx.sbtCallback
if (isLocal) cb.generatedLocalClass(jSourceFile, clsFile.file)
else cb.generatedNonLocalClass(jSourceFile, clsFile.file, className, fullClassName)
}
ctx.withIncCallback: cb =>
if (isLocal) cb.generatedLocalClass(sourceFile, clsFile.jpath)
else cb.generatedNonLocalClass(sourceFile, clsFile.jpath, className, fullClassName)
}

/** Convert a `dotty.tools.io.AbstractFile` into a
Expand Down
2 changes: 1 addition & 1 deletion compiler/src/dotty/tools/dotc/CompilationUnit.scala
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,7 @@ object CompilationUnit {
/** Make a compilation unit for top class `clsd` with the contents of the `unpickled` tree */
def apply(clsd: ClassDenotation, unpickled: Tree, forceTrees: Boolean)(using Context): CompilationUnit =
val file = clsd.symbol.associatedFile.nn
apply(SourceFile(file, Array.empty[Char]), unpickled, forceTrees)
apply(ctx.getEmptySource(file), unpickled, forceTrees)

/** Make a compilation unit, given picked bytes and unpickled tree */
def apply(source: SourceFile, unpickled: Tree, forceTrees: Boolean)(using Context): CompilationUnit = {
Expand Down
63 changes: 47 additions & 16 deletions compiler/src/dotty/tools/dotc/core/Contexts.scala
Original file line number Diff line number Diff line change
Expand Up @@ -34,27 +34,28 @@ import scala.annotation.internal.sharable

import DenotTransformers.DenotTransformer
import dotty.tools.dotc.profile.Profiler
import dotty.tools.dotc.sbt.interfaces.IncrementalCallback
import util.Property.Key
import util.Store
import xsbti.AnalysisCallback
import plugins._
import java.util.concurrent.atomic.AtomicInteger
import java.nio.file.InvalidPathException

object Contexts {

private val (compilerCallbackLoc, store1) = Store.empty.newLocation[CompilerCallback]()
private val (sbtCallbackLoc, store2) = store1.newLocation[AnalysisCallback]()
private val (printerFnLoc, store3) = store2.newLocation[Context => Printer](new RefinedPrinter(_))
private val (settingsStateLoc, store4) = store3.newLocation[SettingsState]()
private val (compilationUnitLoc, store5) = store4.newLocation[CompilationUnit]()
private val (runLoc, store6) = store5.newLocation[Run | Null]()
private val (profilerLoc, store7) = store6.newLocation[Profiler]()
private val (notNullInfosLoc, store8) = store7.newLocation[List[NotNullInfo]]()
private val (importInfoLoc, store9) = store8.newLocation[ImportInfo | Null]()
private val (typeAssignerLoc, store10) = store9.newLocation[TypeAssigner](TypeAssigner)
private val (compilerCallbackLoc, store1) = Store.empty.newLocation[CompilerCallback]()
private val (incCallbackLoc, store2) = store1.newLocation[IncrementalCallback | Null]()
private val (printerFnLoc, store3) = store2.newLocation[Context => Printer](new RefinedPrinter(_))
private val (settingsStateLoc, store4) = store3.newLocation[SettingsState]()
private val (compilationUnitLoc, store5) = store4.newLocation[CompilationUnit]()
private val (runLoc, store6) = store5.newLocation[Run | Null]()
private val (profilerLoc, store7) = store6.newLocation[Profiler]()
private val (notNullInfosLoc, store8) = store7.newLocation[List[NotNullInfo]]()
private val (importInfoLoc, store9) = store8.newLocation[ImportInfo | Null]()
private val (typeAssignerLoc, store10) = store9.newLocation[TypeAssigner](TypeAssigner)
private val (zincInitialFilesLoc, store11) = store10.newLocation[util.ReadOnlySet[AbstractFile] | Null]()

private val initialStore = store10
private val initialStore = store11

/** The current context */
inline def ctx(using ctx: Context): Context = ctx
Expand Down Expand Up @@ -164,8 +165,19 @@ object Contexts {
/** The compiler callback implementation, or null if no callback will be called. */
def compilerCallback: CompilerCallback = store(compilerCallbackLoc)

/** The sbt callback implementation if we are run from sbt, null otherwise */
def sbtCallback: AnalysisCallback = store(sbtCallbackLoc)
/** The Zinc callback implementation if we are run from Zinc, null otherwise */
def incCallback: IncrementalCallback | Null = store(incCallbackLoc)
def zincInitialFiles: util.ReadOnlySet[AbstractFile] | Null = store(zincInitialFilesLoc)

/** Run `op` if there exists an incremental callback */
inline def withIncCallback(inline op: IncrementalCallback => Unit): Unit =
val local = incCallback
if local != null then op(local)

def incrementalEnabled: Boolean =
val local = incCallback
if local != null then local.enabled
else false

/** The current plain printer */
def printerFn: Context => Printer = store(printerFnLoc)
Expand Down Expand Up @@ -234,9 +246,27 @@ object Contexts {
/** Sourcefile corresponding to given abstract file, memoized */
def getSource(file: AbstractFile, codec: => Codec = Codec(settings.encoding.value)) = {
util.Stats.record("Context.getSource")
base.sources.getOrElseUpdate(file, SourceFile(file, codec))
computeCachedSource(file)(SourceFile(_, codec))
}

/** empty Sourcefile associated to given abstract file, memoized */
def getEmptySource(file: AbstractFile) = {
util.Stats.record("Context.getEmptySource")
computeCachedSource(file)(SourceFile(_, Array.empty[Char]))
}

private inline def computeCachedSource(file: AbstractFile)(inline mkSource: AbstractFile => SourceFile): SourceFile =
base.sources.getOrElseUpdate(file, {
val zincSources = zincInitialFiles
val cachedFile =
if zincSources != null then zincSources.lookup(file) match
case null => file
case cached: AbstractFile => cached
else
file
mkSource(cachedFile)
})

/** SourceFile with given path name, memoized */
def getSource(path: TermName): SourceFile = getFile(path) match
case NoAbstractFile => NoSource
Expand Down Expand Up @@ -664,7 +694,8 @@ object Contexts {
}

def setCompilerCallback(callback: CompilerCallback): this.type = updateStore(compilerCallbackLoc, callback)
def setSbtCallback(callback: AnalysisCallback): this.type = updateStore(sbtCallbackLoc, callback)
def setIncCallback(callback: IncrementalCallback): this.type = updateStore(incCallbackLoc, callback)
def setZincInitialFiles(zincInitialFiles: util.ReadOnlySet[AbstractFile]): this.type = updateStore(zincInitialFilesLoc, zincInitialFiles)
def setPrinterFn(printer: Context => Printer): this.type = updateStore(printerFnLoc, printer)
def setSettings(settingsState: SettingsState): this.type = updateStore(settingsStateLoc, settingsState)
def setRun(run: Run | Null): this.type = updateStore(runLoc, run)
Expand Down
4 changes: 2 additions & 2 deletions compiler/src/dotty/tools/dotc/sbt/APIUtils.scala
Original file line number Diff line number Diff line change
Expand Up @@ -35,9 +35,9 @@ object APIUtils {
* a dummy empty class can be registered instead, using this method.
*/
def registerDummyClass(classSym: ClassSymbol)(using Context): Unit = {
if (ctx.sbtCallback != null) {
ctx.withIncCallback { cb =>
val classLike = emptyClassLike(classSym)
ctx.sbtCallback.api(ctx.compilationUnit.source.file.file, classLike)
cb.api(ctx.compilationUnit.source, classLike)
}
}

Expand Down
19 changes: 9 additions & 10 deletions compiler/src/dotty/tools/dotc/sbt/ExtractAPI.scala
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ class ExtractAPI extends Phase {

override def isRunnable(using Context): Boolean = {
def forceRun = ctx.settings.YdumpSbtInc.value || ctx.settings.YforceSbtPhases.value
super.isRunnable && (ctx.sbtCallback != null || forceRun)
super.isRunnable && (ctx.incrementalEnabled || forceRun)
}

// Check no needed. Does not transform trees
Expand All @@ -65,28 +65,27 @@ class ExtractAPI extends Phase {

override def run(using Context): Unit = {
val unit = ctx.compilationUnit
val sourceFile = unit.source.file
if (ctx.sbtCallback != null)
ctx.sbtCallback.startSource(sourceFile.file)
val sourceFile = unit.source
ctx.withIncCallback: cb =>
cb.startSource(sourceFile)

val apiTraverser = new ExtractAPICollector
val classes = apiTraverser.apiSource(unit.tpdTree)
val mainClasses = apiTraverser.mainClasses

if (ctx.settings.YdumpSbtInc.value) {
// Append to existing file that should have been created by ExtractDependencies
val pw = new PrintWriter(File(sourceFile.jpath).changeExtension("inc").toFile
val pw = new PrintWriter(File(sourceFile.file.jpath).changeExtension("inc").toFile
.bufferedWriter(append = true), true)
try {
classes.foreach(source => pw.println(DefaultShowAPI(source)))
} finally pw.close()
}

if ctx.sbtCallback != null &&
!ctx.compilationUnit.suspendedAtInliningPhase // already registered before this unit was suspended
then
classes.foreach(ctx.sbtCallback.api(sourceFile.file, _))
mainClasses.foreach(ctx.sbtCallback.mainClass(sourceFile.file, _))
ctx.withIncCallback: cb =>
if !ctx.compilationUnit.suspendedAtInliningPhase then // already registered before this unit was suspended
classes.foreach(cb.api(sourceFile, _))
mainClasses.foreach(cb.mainClass(sourceFile, _))
}
}

Expand Down
43 changes: 24 additions & 19 deletions compiler/src/dotty/tools/dotc/sbt/ExtractDependencies.scala
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ package sbt
import scala.language.unsafeNulls

import java.io.File
import java.nio.file.Path
import java.util.{Arrays, EnumSet}

import dotty.tools.dotc.ast.tpd
Expand Down Expand Up @@ -56,7 +57,7 @@ class ExtractDependencies extends Phase {

override def isRunnable(using Context): Boolean = {
def forceRun = ctx.settings.YdumpSbtInc.value || ctx.settings.YforceSbtPhases.value
super.isRunnable && (ctx.sbtCallback != null || forceRun)
super.isRunnable && (ctx.incrementalEnabled || forceRun)
}

// Check no needed. Does not transform trees
Expand Down Expand Up @@ -91,15 +92,16 @@ class ExtractDependencies extends Phase {
} finally pw.close()
}

if (ctx.sbtCallback != null) {
collector.usedNames.foreach {
case (clazz, usedNames) =>
val className = classNameAsString(clazz)
usedNames.names.foreach {
case (usedName, scopes) =>
ctx.sbtCallback.usedName(className, usedName.toString, scopes)
}
}
if (ctx.incrementalEnabled) {
ctx.withIncCallback: cb =>
collector.usedNames.foreach {
case (clazz, usedNames) =>
val className = classNameAsString(clazz)
usedNames.names.foreach {
case (usedName, scopes) =>
cb.usedName(className, usedName.toString, scopes)
}
}

collector.dependencies.foreach(recordDependency)
}
Expand All @@ -112,17 +114,17 @@ class ExtractDependencies extends Phase {
*/
def recordDependency(dep: ClassDependency)(using Context): Unit = {
val fromClassName = classNameAsString(dep.from)
val sourceFile = ctx.compilationUnit.source.file.file
val sourceFile = ctx.compilationUnit.source

def binaryDependency(file: File, binaryClassName: String) =
ctx.sbtCallback.binaryDependency(file, binaryClassName, fromClassName, sourceFile, dep.context)
def binaryDependency(file: Path, binaryClassName: String) =
ctx.withIncCallback(_.binaryDependency(file, binaryClassName, fromClassName, sourceFile, dep.context))

def processExternalDependency(depFile: AbstractFile, binaryClassName: String) = {
depFile match {
case ze: ZipArchive#Entry => // The dependency comes from a JAR
ze.underlyingSource match
case Some(zip) if zip.file != null =>
binaryDependency(zip.file, binaryClassName)
case Some(zip) if zip.jpath != null =>
binaryDependency(zip.jpath, binaryClassName)
case _ =>
case pf: PlainFile => // The dependency comes from a class file
// FIXME: pf.file is null for classfiles coming from the modulepath
Expand All @@ -131,15 +133,18 @@ class ExtractDependencies extends Phase {
// java.io.File, this means that we cannot record dependencies coming
// from the modulepath. For now this isn't a big deal since we only
// support having the standard Java library on the modulepath.
if pf.file != null then
binaryDependency(pf.file, binaryClassName)
if pf.jpath != null then
binaryDependency(pf.jpath, binaryClassName)
case _ =>
internalError(s"Ignoring dependency $depFile of unknown class ${depFile.getClass}}", dep.from.srcPos)
}
}

val depFile = dep.to.associatedFile
if (depFile != null) {
def depIsSameSource =
depFile.absolutePath == sourceFile.file.absolutePath

// Cannot ignore inheritance relationship coming from the same source (see sbt/zinc#417)
def allowLocal = dep.context == DependencyByInheritance || dep.context == LocalDependencyByInheritance
val depClassFile =
Expand All @@ -148,11 +153,11 @@ class ExtractDependencies extends Phase {
if (depClassFile != null) {
// Dependency is external -- source is undefined
processExternalDependency(depClassFile, dep.to.binaryClassName)
} else if (allowLocal || depFile.file != sourceFile) {
} else if (allowLocal || !depIsSameSource /* old: depFile.file != sourceFile.file */) {
// We cannot ignore dependencies coming from the same source file because
// the dependency info needs to propagate. See source-dependencies/trait-trait-211.
val toClassName = classNameAsString(dep.to)
ctx.sbtCallback.classDependency(toClassName, fromClassName, dep.context)
ctx.withIncCallback(_.classDependency(toClassName, fromClassName, dep.context))
}
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
package dotty.tools.dotc.sbt.interfaces;

import dotty.tools.dotc.interfaces.SourceFile;

import java.util.EnumSet;
import java.nio.file.Path;

/* User code should not implement this interface, it is intended to be a wrapper around xsbti.AnalysisCallback. */
public interface IncrementalCallback {
default void api(SourceFile sourceFile, xsbti.api.ClassLike classApi) {
}

default void startSource(SourceFile sourceFile) {
}

default void mainClass(SourceFile sourceFile, String className) {
}

default boolean enabled() {
return false;
}

default void usedName(String className, String name, EnumSet<xsbti.UseScope> useScopes) {
}

default void binaryDependency(Path onBinaryEntry, String onBinaryClassName, String fromClassName,
SourceFile fromSourceFile, xsbti.api.DependencyContext context) {
}

default void classDependency(String onClassName, String sourceClassName, xsbti.api.DependencyContext context) {
}

default void generatedLocalClass(SourceFile source, Path classFile) {
}

default void generatedNonLocalClass(SourceFile source, Path classFile, String binaryClassName,
String srcClassName) {
}
}
Loading