Skip to content

Commit 8cdabe4

Browse files
committed
use an enum to store file extensions,
This caches common file extensions, while still being extensible. Also fixes many operations with unexpected behavior (manipulation of file extensions where toLowerCase behaves differently with certain locales.)
1 parent 183487b commit 8cdabe4

File tree

29 files changed

+207
-86
lines changed

29 files changed

+207
-86
lines changed

compiler/src/dotty/tools/dotc/CompilationUnit.scala

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -28,13 +28,16 @@ class CompilationUnit protected (val source: SourceFile, val info: CompilationUn
2828
var tpdTree: tpd.Tree = tpd.EmptyTree
2929

3030
/** Is this the compilation unit of a Java file */
31-
def isJava: Boolean = source.file.name.endsWith(".java")
31+
def isJava: Boolean = source.file.ext.isJava
3232

3333
/** Is this the compilation unit of a Java file, or TASTy derived from a Java file */
34-
def typedAsJava = isJava || {
35-
val infoNN = info
36-
infoNN != null && infoNN.tastyInfo.exists(_.attributes.isJava)
37-
}
34+
def typedAsJava =
35+
val ext = source.file.ext
36+
ext.isJavaOrTasty && (ext.isJava || tastyInfo.exists(_.attributes.isJava))
37+
38+
def tastyInfo: Option[TastyInfo] =
39+
val local = info
40+
if local == null then None else local.tastyInfo
3841

3942

4043
/** The source version for this unit, as determined by a language import */

compiler/src/dotty/tools/dotc/Driver.scala

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import core.Comments.{ContextDoc, ContextDocstrings}
66
import core.Contexts.*
77
import core.{MacroClassLoader, TypeError}
88
import dotty.tools.dotc.ast.Positioned
9-
import dotty.tools.io.AbstractFile
9+
import dotty.tools.io.{AbstractFile, FileExtension}
1010
import reporting.*
1111
import core.Decorators.*
1212
import config.Feature
@@ -98,9 +98,9 @@ class Driver {
9898
if !file.exists then
9999
report.error(em"File does not exist: ${file.path}")
100100
None
101-
else file.extension match
102-
case "jar" => Some(file.path)
103-
case "tasty" =>
101+
else file.ext match
102+
case FileExtension.Jar => Some(file.path)
103+
case FileExtension.Tasty =>
104104
TastyFileUtil.getClassPath(file) match
105105
case Some(classpath) => Some(classpath)
106106
case _ =>

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -284,7 +284,7 @@ case class DirectoryClassPath(dir: JFile) extends JFileDirectoryLookup[ClassFile
284284

285285
protected def createFileEntry(file: AbstractFile): ClassFileEntryImpl = ClassFileEntryImpl(file)
286286
protected def isMatchingFile(f: JFile): Boolean =
287-
f.isTasty || (f.isClass && f.classToTasty.isEmpty)
287+
f.isTasty || (f.isClass && !f.hasSiblingTasty)
288288

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

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

Lines changed: 22 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -17,49 +17,52 @@ object FileUtils {
1717
extension (file: AbstractFile) {
1818
def isPackage: Boolean = file.isDirectory && mayBeValidPackage(file.name)
1919

20-
def isClass: Boolean = !file.isDirectory && hasClassExtension && !file.name.endsWith("$class.class")
21-
// FIXME: drop last condition when we stop being compatible with Scala 2.11
20+
def isClass: Boolean = !file.isDirectory && hasClassExtension
2221

23-
def hasClassExtension: Boolean = file.hasExtension("class")
22+
def hasClassExtension: Boolean = file.ext.isClass
2423

25-
def hasTastyExtension: Boolean = file.hasExtension("tasty")
24+
def hasTastyExtension: Boolean = file.ext.isTasty
2625

2726
def isTasty: Boolean = !file.isDirectory && hasTastyExtension
2827

2928
def isScalaBinary: Boolean = file.isClass || file.isTasty
3029

31-
def isScalaOrJavaSource: Boolean = !file.isDirectory && (file.hasExtension("scala") || file.hasExtension("java"))
30+
def isScalaOrJavaSource: Boolean = !file.isDirectory && file.ext.isScalaOrJava
3231

3332
// TODO do we need to check also other files using ZipMagicNumber like in scala.tools.nsc.io.Jar.isJarOrZip?
34-
def isJarOrZip: Boolean = file.hasExtension("jar") || file.hasExtension("zip")
33+
def isJarOrZip: Boolean = file.ext.isJarOrZip
3534

3635
/**
3736
* Safe method returning a sequence containing one URL representing this file, when underlying file exists,
3837
* and returning given default value in other case
3938
*/
4039
def toURLs(default: => Seq[URL] = Seq.empty): Seq[URL] = if (file.file == null) default else Seq(file.toURL)
4140

42-
/** Returns the tasty file associated with this class file */
43-
def classToTasty: Option[AbstractFile] =
44-
assert(file.isClass, s"non-class: $file")
45-
val tastyName = classNameToTasty(file.name)
46-
Option(file.resolveSibling(tastyName))
41+
/**
42+
* Returns if there is an existing sibling `.tasty` file.
43+
*/
44+
def hasSiblingTasty: Boolean =
45+
assert(file.hasClassExtension, s"non-class: $file")
46+
file.resolveSibling(classNameToTasty(file.name)) != null
4747
}
4848

4949
extension (file: JFile) {
5050
def isPackage: Boolean = file.isDirectory && mayBeValidPackage(file.getName)
5151

52-
def isClass: Boolean = file.isFile && file.getName.endsWith(SUFFIX_CLASS) && !file.getName.endsWith("$class.class")
53-
// FIXME: drop last condition when we stop being compatible with Scala 2.11
52+
def isClass: Boolean = file.isFile && hasClassExtension
53+
54+
def hasClassExtension: Boolean = file.getName.endsWith(SUFFIX_CLASS)
5455

5556
def isTasty: Boolean = file.isFile && file.getName.endsWith(SUFFIX_TASTY)
5657

57-
/** Returns the tasty file associated with this class file */
58-
def classToTasty: Option[JFile] =
59-
assert(file.isClass, s"non-class: $file")
60-
val tastyName = classNameToTasty(file.getName.stripSuffix(".class"))
61-
val tastyPath = file.toPath.resolveSibling(tastyName)
62-
if java.nio.file.Files.exists(tastyPath) then Some(tastyPath.toFile) else None
58+
/**
59+
* Returns if there is an existing sibling `.tasty` file.
60+
*/
61+
def hasSiblingTasty: Boolean =
62+
assert(file.hasClassExtension, s"non-class: $file")
63+
val path = file.toPath
64+
val tastyPath = path.resolveSibling(classNameToTasty(file.getName))
65+
java.nio.file.Files.exists(tastyPath)
6366

6467
}
6568

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,5 +50,5 @@ case class VirtualDirectoryClassPath(dir: VirtualDirectory) extends ClassPath wi
5050

5151
protected def createFileEntry(file: AbstractFile): ClassFileEntryImpl = ClassFileEntryImpl(file)
5252
protected def isMatchingFile(f: AbstractFile): Boolean =
53-
f.isTasty || (f.isClass && f.classToTasty.isEmpty)
53+
f.isTasty || (f.isClass && !f.hasSiblingTasty)
5454
}

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ object ZipAndJarClassPathFactory extends ZipAndJarFileLookupFactory {
5252

5353
override protected def createFileEntry(file: FileZipArchive#Entry): ClassFileEntryImpl = ClassFileEntryImpl(file)
5454
override protected def isRequiredFileType(file: AbstractFile): Boolean =
55-
file.isTasty || (file.isClass && file.classToTasty.isEmpty)
55+
file.isTasty || (file.isClass && !file.hasSiblingTasty)
5656
}
5757

5858
/**

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -162,7 +162,7 @@ object Settings:
162162
else setString(arg2, args2)
163163
case (OutputTag, arg :: args) =>
164164
val path = Directory(arg)
165-
val isJar = path.extension == "jar"
165+
val isJar = path.ext.isJar
166166
if (!isJar && !path.isDirectory)
167167
fail(s"'$arg' does not exist or is not a directory or .jar file", args)
168168
else {

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import java.nio.channels.ClosedByInterruptException
77

88
import scala.util.control.NonFatal
99

10-
import dotty.tools.dotc.classpath.FileUtils.isTasty
10+
import dotty.tools.dotc.classpath.FileUtils.hasTastyExtension
1111
import dotty.tools.io.{ ClassPath, ClassRepresentation, AbstractFile }
1212
import dotty.tools.backend.jvm.DottyBackendInterface.symExtensions
1313

@@ -198,7 +198,7 @@ object SymbolLoaders {
198198
enterToplevelsFromSource(owner, nameOf(classRep), src)
199199
case (Some(bin), _) =>
200200
val completer =
201-
if bin.isTasty then ctx.platform.newTastyLoader(bin)
201+
if bin.hasTastyExtension then ctx.platform.newTastyLoader(bin)
202202
else ctx.platform.newClassLoader(bin)
203203
enterClassAndModule(owner, nameOf(classRep), completer)
204204
}

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +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
26+
import dotty.tools.dotc.classpath.FileUtils.hasSiblingTasty
2727

2828
import scala.compiletime.uninitialized
2929

@@ -1142,7 +1142,7 @@ class ClassfileParser(
11421142

11431143
if (scan(tpnme.TASTYATTR)) {
11441144
val hint =
1145-
if classfile.classToTasty.isDefined then "This is likely a bug in the compiler. Please report."
1145+
if classfile.hasSiblingTasty then "This is likely a bug in the compiler. Please report."
11461146
else "This `.tasty` file is missing. Try cleaning the project to fix this issue."
11471147
report.error(s"Loading Scala 3 binary from $classfile. It should have been loaded from `.tasty` file. $hint", NoSourcePosition)
11481148
return None

compiler/src/dotty/tools/dotc/core/tasty/TastyPrinter.scala

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import util.Spans.offsetToInt
1212
import dotty.tools.tasty.TastyFormat.{ASTsSection, PositionsSection, CommentsSection, AttributesSection}
1313
import java.nio.file.{Files, Paths}
1414
import dotty.tools.io.{JarArchive, Path}
15+
import dotty.tools.dotc.classpath.FileUtils.hasTastyExtension
1516

1617
object TastyPrinter:
1718

@@ -47,7 +48,7 @@ object TastyPrinter:
4748
else if arg.endsWith(".jar") then
4849
val jar = JarArchive.open(Path(arg), create = false)
4950
try
50-
for file <- jar.iterator() if file.name.endsWith(".tasty") do
51+
for file <- jar.iterator() if file.hasTastyExtension do
5152
printTasty(s"$arg ${file.path}", file.toByteArray)
5253
finally jar.close()
5354
else

0 commit comments

Comments
 (0)