Skip to content

Commit a284d62

Browse files
committed
Fix scala.runtime.{Null$, Nothing$} tasty
1 parent 6c4c506 commit a284d62

File tree

5 files changed

+42
-33
lines changed

5 files changed

+42
-33
lines changed

compiler/src/dotty/tools/dotc/classpath/DirectoryClassPath.scala

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -288,9 +288,7 @@ case class DirectoryClassPath(dir: JFile) extends JFileDirectoryLookup[ClassFile
288288

289289
protected def createFileEntry(file: AbstractFile): ClassFileEntryImpl = ClassFileEntryImpl(file)
290290
protected def isMatchingFile(f: JFile): Boolean =
291-
def isClassWithNoTasty =
292-
f.isClass && !Files.exists(f.toPath.resolveSibling(f.getName.stripSuffix(".class").stripSuffix("$") + ".tasty"))
293-
f.isTasty || isClassWithNoTasty
291+
f.isTasty || (f.isClass && f.classToTasty.isEmpty)
294292

295293
private[dotty] def classes(inPackage: PackageName): Seq[ClassFileEntry] = files(inPackage)
296294
}

compiler/src/dotty/tools/dotc/classpath/FileUtils.scala

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,15 @@ object FileUtils {
3232
* and returning given default value in other case
3333
*/
3434
def toURLs(default: => Seq[URL] = Seq.empty): Seq[URL] = if (file.file == null) default else Seq(file.toURL)
35+
36+
/** Returns the tasty file associated with this class file */
37+
def classToTasty: Option[AbstractFile] =
38+
assert(file.isClass, s"non-class: $file")
39+
val parent = file match // TODO: simplify when #3552 is fixed
40+
case file: io.ZipArchive#Entry => file.parent
41+
case _ => file.container
42+
val tastyName = classNameToTasty(file.name)
43+
Option(parent.lookupName(tastyName, directory = false))
3544
}
3645

3746
extension (file: JFile) {
@@ -41,6 +50,14 @@ object FileUtils {
4150
// FIXME: drop last condition when we stop being compatible with Scala 2.11
4251

4352
def isTasty: Boolean = file.isFile && file.getName.endsWith(SUFFIX_TASTY)
53+
54+
/** Returns the tasty file associated with this class file */
55+
def classToTasty: Option[JFile] =
56+
assert(file.isClass, s"non-class: $file")
57+
val tastyName = classNameToTasty(file.getName.stripSuffix(".class"))
58+
val tastyPath = file.toPath.resolveSibling(tastyName)
59+
if java.nio.file.Files.exists(tastyPath) then Some(tastyPath.toFile) else None
60+
4461
}
4562

4663
private val SUFFIX_CLASS = ".class"
@@ -86,4 +103,12 @@ object FileUtils {
86103
def mkFileFilter(f: JFile => Boolean): FileFilter = new FileFilter {
87104
def accept(pathname: JFile): Boolean = f(pathname)
88105
}
106+
107+
private def classNameToTasty(fileName: String): String =
108+
val className = fileName.stripSuffix(".class")
109+
if className.endsWith("$")
110+
&& className != "Null$" // scala.runtime.Null$
111+
&& className != "Nothing$" // scala.runtime.Nothing$
112+
then className.stripSuffix("$") + ".tasty"
113+
else className + ".tasty"
89114
}

compiler/src/dotty/tools/dotc/classpath/VirtualDirectoryClassPath.scala

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -53,9 +53,5 @@ case class VirtualDirectoryClassPath(dir: VirtualDirectory) extends ClassPath wi
5353

5454
protected def createFileEntry(file: AbstractFile): ClassFileEntryImpl = ClassFileEntryImpl(file)
5555
protected def isMatchingFile(f: AbstractFile): Boolean =
56-
def tastyFile: AbstractFile | Null =
57-
val tastyFileName = f.name.stripSuffix(".class").stripSuffix("$") + ".tasty"
58-
f.container.lookupName(tastyFileName, directory = false)
59-
def isClassWithNoTasty = f.isClass && tastyFile == null
60-
f.isTasty || isClassWithNoTasty
56+
f.isTasty || (f.isClass && f.classToTasty.isEmpty)
6157
}

compiler/src/dotty/tools/dotc/classpath/ZipAndJarFileLookupFactory.scala

Lines changed: 1 addition & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -61,14 +61,7 @@ object ZipAndJarClassPathFactory extends ZipAndJarFileLookupFactory {
6161

6262
override protected def createFileEntry(file: FileZipArchive#Entry): ClassFileEntryImpl = ClassFileEntryImpl(file)
6363
override protected def isRequiredFileType(file: AbstractFile): Boolean =
64-
def tastyFile: AbstractFile | Null =
65-
val parent = file match // TODO: simplify when #3552 is fixed
66-
case classfile: ZipArchive#Entry => classfile.parent
67-
case _ => file.container
68-
val tastyFileName = file.name.stripSuffix(".class").stripSuffix("$") + ".tasty"
69-
parent.lookupName(tastyFileName, directory = false)
70-
def isClassWithNoTasty = file.isClass && tastyFile == null
71-
file.isTasty || isClassWithNoTasty
64+
file.isTasty || (file.isClass && file.classToTasty.isEmpty)
7265
}
7366

7467
/**

compiler/src/dotty/tools/dotc/core/classfile/ClassfileParser.scala

Lines changed: 14 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ import scala.annotation.switch
2323
import typer.Checking.checkNonCyclic
2424
import io.{AbstractFile, ZipArchive}
2525
import scala.util.control.NonFatal
26+
import dotty.tools.dotc.classpath.FileUtils.classToTasty
2627

2728
object ClassfileParser {
2829
/** Marker trait for unpicklers that can be embedded in classfiles. */
@@ -941,23 +942,19 @@ class ClassfileParser(
941942
val attrLen = in.nextInt
942943
val bytes = in.nextBytes(attrLen)
943944
if (attrLen == 16) { // A tasty attribute with that has only a UUID (16 bytes) implies the existence of the .tasty file
944-
val parent = classfile match // TODO: simplify when #3552 is fixed
945-
case classfile: io.ZipArchive#Entry => classfile.parent
946-
case _ => classfile.container
947-
val tastyFileName = classfile.name.stripSuffix(".class") + ".tasty"
948-
val tastyFile = parent.lookupName(tastyFileName, directory = false)
949-
if tastyFile == null then
950-
report.error(em"Could not find TASTY file $tastyFileName in $parent")
951-
else
952-
val tastyLoader = new TastyLoader(tastyFile)
953-
val tastyBytes: Array[Byte] = tastyLoader.loadTastyBytes()
954-
val expectedUUID =
955-
val reader = new TastyReader(bytes, 0, 16)
956-
new UUID(reader.readUncompressedLong(), reader.readUncompressedLong())
957-
val tastyUUID =
958-
new TastyHeaderUnpickler(tastyBytes).readHeader()
959-
if (expectedUUID != tastyUUID)
960-
report.warning(s"$classfile is out of sync with its TASTy file. Loaded TASTy file. Try cleaning the project to fix this issue", NoSourcePosition)
945+
classfile.classToTasty match
946+
case None =>
947+
report.error(em"Could not find TASTY for $classfile")
948+
case Some(tastyFile) =>
949+
val tastyLoader = new TastyLoader(tastyFile)
950+
val tastyBytes: Array[Byte] = tastyLoader.loadTastyBytes()
951+
val expectedUUID =
952+
val reader = new TastyReader(bytes, 0, 16)
953+
new UUID(reader.readUncompressedLong(), reader.readUncompressedLong())
954+
val tastyUUID =
955+
new TastyHeaderUnpickler(tastyBytes).readHeader()
956+
if (expectedUUID != tastyUUID)
957+
report.warning(s"$classfile is out of sync with its TASTy file. Loaded TASTy file. Try cleaning the project to fix this issue", NoSourcePosition)
961958
return None
962959
}
963960
else

0 commit comments

Comments
 (0)