Skip to content

Commit 2dfc28f

Browse files
committed
add todo, address comments
1 parent ea75836 commit 2dfc28f

File tree

3 files changed

+55
-50
lines changed

3 files changed

+55
-50
lines changed

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

Lines changed: 52 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -421,72 +421,80 @@ class DependencyRecorder {
421421
usedNames.names.foreach:
422422
case (usedName, scopes) =>
423423
cb.usedName(className, usedName.toString, scopes)
424-
classDependencies.foreach(recordClassDependency(cb, _))
424+
val siblingClassfiles = new mutable.HashMap[PlainFile, Path]
425+
classDependencies.foreach(recordClassDependency(cb, _, siblingClassfiles))
425426
clear()
426427

427-
private val _siblingClassfiles = new mutable.HashMap[PlainFile, Path]
428+
/** Clear all state. */
429+
def clear(): Unit =
430+
_usedNames.clear()
431+
_classDependencies.clear()
432+
lastOwner = NoSymbol
433+
lastDepSource = NoSymbol
434+
_responsibleForImports = NoSymbol
435+
436+
/** Handles dependency on given symbol by trying to figure out if represents a term
437+
* that is coming from either source code (not necessarily compiled in this compilation
438+
* run) or from class file and calls respective callback method.
439+
*/
440+
private def recordClassDependency(cb: interfaces.IncrementalCallback, dep: ClassDependency,
441+
siblingClassfiles: mutable.Map[PlainFile, Path])(using Context): Unit = {
442+
val fromClassName = classNameAsString(dep.fromClass)
443+
val sourceFile = ctx.compilationUnit.source
428444

429-
extension (pf: PlainFile)
430-
/**Constructs a sibling class to the `jpath`.
445+
/**For a `.tasty` file, constructs a sibling class to the `jpath`.
431446
* Does not validate if it exists as a real file.
447+
*
448+
* Because classpath scanning looks for tasty files first, `dep.fromClass` will be
449+
* associated to a `.tasty` file. However Zinc records all dependencies either based on `.jar` or `.class` files,
450+
* where classes are in directories on the filesystem.
451+
*
452+
* So if the dependency comes from an upstream `.tasty` file and it was not packaged in a jar, then
453+
* we need to call this to resolve the classfile that will eventually exist at runtime.
454+
*
432455
* The way this works is that by the end of compilation analysis,
433-
* there should be a corresponding NonLocalClass sent to zinc with the same class file name.
456+
* we should have called `cb.generatedNonLocalClass` with the same class file name.
434457
*
435458
* FIXME: we still need a way to resolve the correct classfile when we split tasty and classes between
436459
* different outputs (e.g. stdlib-bootstrapped).
437460
*/
438-
private def siblingClass: Path =
439-
_siblingClassfiles.getOrElseUpdate(pf, {
461+
def cachedSiblingClass(pf: PlainFile): Path =
462+
siblingClassfiles.getOrElseUpdate(pf, {
440463
val jpath = pf.jpath
441464
jpath.getParent.resolve(jpath.getFileName.toString.stripSuffix(".tasty") + ".class")
442465
})
443466

444-
/** Clear all state. */
445-
def clear(): Unit =
446-
_usedNames.clear()
447-
_classDependencies.clear()
448-
_siblingClassfiles.clear()
449-
lastOwner = NoSymbol
450-
lastDepSource = NoSymbol
451-
_responsibleForImports = NoSymbol
452-
453-
/** Handles dependency on given symbol by trying to figure out if represents a term
454-
* that is coming from either source code (not necessarily compiled in this compilation
455-
* run) or from class file and calls respective callback method.
456-
*/
457-
private def recordClassDependency(cb: interfaces.IncrementalCallback, dep: ClassDependency)(using Context): Unit = {
458-
val fromClassName = classNameAsString(dep.fromClass)
459-
val sourceFile = ctx.compilationUnit.source
460-
461467
def binaryDependency(path: Path, binaryClassName: String) =
462468
cb.binaryDependency(path, binaryClassName, fromClassName, sourceFile, dep.context)
463469

464-
def processExternalDependency(depFile: AbstractFile, binaryClassName: String, convertTasty: Boolean) = {
465-
depFile match {
466-
case ze: ZipArchive#Entry => // The dependency comes from a JAR
467-
ze.underlyingSource match
468-
case Some(zip) if zip.jpath != null =>
469-
binaryDependency(zip.jpath, binaryClassName)
470-
case _ =>
471-
case pf: PlainFile => // The dependency comes from a class file, Zinc handles JRT filesystem
472-
binaryDependency(if convertTasty then pf.siblingClass else pf.jpath, binaryClassName)
473-
case _ =>
474-
internalError(s"Ignoring dependency $depFile of unknown class ${depFile.getClass}}", dep.fromClass.srcPos)
475-
}
476-
}
477-
478-
val depFile = dep.toClass.associatedFile
470+
val depClass = dep.toClass
471+
val depFile = depClass.associatedFile
479472
if depFile != null then {
480473
// Cannot ignore inheritance relationship coming from the same source (see sbt/zinc#417)
481474
def allowLocal = dep.context == DependencyByInheritance || dep.context == LocalDependencyByInheritance
482-
if depFile.hasTastyExtension then
483-
processExternalDependency(depFile, dep.toClass.binaryClassName, convertTasty = true)
484-
else if depFile.hasClassExtension then
485-
processExternalDependency(depFile, dep.toClass.binaryClassName, convertTasty = false)
475+
val isTasty = depFile.hasTastyExtension
476+
477+
def processExternalDependency() = {
478+
val binaryClassName = depClass.binaryClassName
479+
depFile match {
480+
case ze: ZipArchive#Entry => // The dependency comes from a JAR
481+
ze.underlyingSource match
482+
case Some(zip) if zip.jpath != null =>
483+
binaryDependency(zip.jpath, binaryClassName)
484+
case _ =>
485+
case pf: PlainFile => // The dependency comes from a class file, Zinc handles JRT filesystem
486+
binaryDependency(if isTasty then cachedSiblingClass(pf) else pf.jpath, binaryClassName)
487+
case _ =>
488+
internalError(s"Ignoring dependency $depFile of unknown class ${depFile.getClass}}", dep.fromClass.srcPos)
489+
}
490+
}
491+
492+
if isTasty || depFile.hasClassExtension then
493+
processExternalDependency()
486494
else if allowLocal || depFile != sourceFile.file then
487495
// We cannot ignore dependencies coming from the same source file because
488496
// the dependency info needs to propagate. See source-dependencies/trait-trait-211.
489-
val toClassName = classNameAsString(dep.toClass)
497+
val toClassName = classNameAsString(depClass)
490498
cb.classDependency(toClassName, fromClassName, dep.context)
491499
}
492500
}

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

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -97,8 +97,10 @@ abstract class AbstractFile extends Iterable[AbstractFile] {
9797
/** Returns the path of this abstract file in a canonical form. */
9898
def canonicalPath: String = if (jpath == null) path else jpath.normalize.toString
9999

100-
/** Checks extension case insensitively. */
100+
/** Checks extension case insensitively. TODO: change to enum */
101101
def hasExtension(other: String): Boolean = extension == other.toLowerCase
102+
103+
/** Returns the extension of this abstract file. TODO: store as an enum to avoid costly comparisons */
102104
val extension: String = Path.extension(name)
103105

104106
/** The absolute file, if this is a relative file. */

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

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -113,11 +113,6 @@ class PlainFile(val givenPath: Path) extends AbstractFile {
113113
null
114114
}
115115

116-
final def fakeSibling(name: String): AbstractFile = {
117-
val child = givenPath.parent / name
118-
new PlainFile(child)
119-
}
120-
121116
/** Does this abstract file denote an existing file? */
122117
def create(): Unit = if (!exists) givenPath.createFile()
123118

0 commit comments

Comments
 (0)