Skip to content

Commit 69d94d8

Browse files
committed
use an enum to store file extensions
1 parent 0702a5d commit 69d94d8

21 files changed

+160
-67
lines changed

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: 23 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ import scala.language.unsafeNulls
88

99
import java.io.{File => JFile, FileFilter}
1010
import java.net.URL
11-
import dotty.tools.io.AbstractFile
11+
import dotty.tools.io.{AbstractFile, FileExtension}
1212

1313
/**
1414
* Common methods related to Java files and abstract files used in the context of classpath
@@ -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.hasExtension(FileExtension.Class)
2423

25-
def hasTastyExtension: Boolean = file.hasExtension("tasty")
24+
def hasTastyExtension: Boolean = file.hasExtension(FileExtension.Tasty)
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.hasExtension(FileExtension.Scala) || file.hasExtension(FileExtension.Java))
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: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import scala.language.unsafeNulls
55

66
import core.Contexts.*
77

8-
import dotty.tools.io.{AbstractFile, Directory, JarArchive, PlainDirectory}
8+
import dotty.tools.io.{AbstractFile, Directory, JarArchive, PlainDirectory, FileExtension}
99

1010
import annotation.tailrec
1111
import collection.mutable.ArrayBuffer
@@ -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 == FileExtension.Jar
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

compiler/src/dotty/tools/dotc/fromtasty/Debug.scala

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import scala.language.unsafeNulls
66

77
import scala.util.control.NonFatal
88

9-
import dotty.tools.io.Directory
9+
import dotty.tools.io.{Directory, FileExtension}
1010

1111
import java.io.{File => JFile}
1212
import java.nio.file.{Files, Paths}
@@ -40,7 +40,7 @@ object Debug {
4040

4141
val tastyFiles =
4242
Directory(fromSourcesOut).walk
43-
.filter(x => x.isFile && "tasty".equalsIgnoreCase(x.extension))
43+
.filter(x => x.isFile && x.ext == FileExtension.Tasty)
4444
.map(_.toString)
4545
.toList
4646

compiler/src/dotty/tools/dotc/fromtasty/TASTYRun.scala

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ package fromtasty
44

55
import scala.language.unsafeNulls
66

7-
import io.{JarArchive, AbstractFile, Path}
7+
import io.{JarArchive, AbstractFile, Path, FileExtension}
88
import core.Contexts.*
99
import core.Decorators.em
1010
import java.io.File
@@ -19,14 +19,14 @@ class TASTYRun(comp: Compiler, ictx: Context) extends Run(comp, ictx) {
1919
val fromTastyIgnoreList = ctx.settings.YfromTastyIgnoreList.value.toSet
2020
// Resolve class names of tasty and jar files
2121
val classNames = files.flatMap { file =>
22-
file.extension match
23-
case "jar" =>
22+
file.ext match
23+
case FileExtension.Jar =>
2424
JarArchive.open(Path(file.path), create = false).allFileNames()
2525
.map(_.stripPrefix(File.separator)) // change paths from absolute to relative
26-
.filter(e => Path.extension(e) == "tasty" && !fromTastyIgnoreList(e))
26+
.filter(e => Path.fileExtension(e) == FileExtension.Tasty && !fromTastyIgnoreList(e))
2727
.map(e => e.stripSuffix(".tasty").replace(File.separator, "."))
2828
.toList
29-
case "tasty" => TastyFileUtil.getClassName(file)
29+
case FileExtension.Tasty => TastyFileUtil.getClassName(file)
3030
case _ =>
3131
report.error(em"File extension is not `tasty` or `jar`: ${file.path}")
3232
Nil

compiler/src/dotty/tools/dotc/fromtasty/TastyFileUtil.scala

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,8 @@ import scala.language.unsafeNulls
55

66
import dotty.tools.dotc.core.tasty.TastyClassName
77
import dotty.tools.dotc.core.StdNames.nme.EMPTY_PACKAGE
8-
import dotty.tools.io.AbstractFile
8+
import dotty.tools.io.{AbstractFile, FileExtension}
9+
import dotty.tools.dotc.classpath.FileUtils.hasTastyExtension
910

1011
object TastyFileUtil {
1112
/** Get the class path of a tasty file
@@ -34,7 +35,7 @@ object TastyFileUtil {
3435
*/
3536
def getClassName(file: AbstractFile): Option[String] = {
3637
assert(file.exists)
37-
assert(file.extension == "tasty")
38+
assert(file.hasTastyExtension)
3839
val bytes = file.toByteArray
3940
val names = new TastyClassName(bytes).readName()
4041
names.map { case (packageName, className) =>

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ import Names.*
1818
import NameOps.*
1919
import inlines.Inlines
2020
import transform.ValueClasses
21-
import dotty.tools.io.File
21+
import dotty.tools.io.{File, FileExtension}
2222
import java.io.PrintWriter
2323

2424

@@ -76,7 +76,7 @@ class ExtractAPI extends Phase {
7676

7777
if (ctx.settings.YdumpSbtInc.value) {
7878
// Append to existing file that should have been created by ExtractDependencies
79-
val pw = new PrintWriter(File(sourceFile.file.jpath).changeExtension("inc").toFile
79+
val pw = new PrintWriter(File(sourceFile.file.jpath).changeExtension(FileExtension.Inc).toFile
8080
.bufferedWriter(append = true), true)
8181
try {
8282
classes.foreach(source => pw.println(DefaultShowAPI(source)))

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

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ import java.nio.file.Path
88
import java.util.{Arrays, EnumSet}
99

1010
import dotty.tools.dotc.ast.tpd
11-
import dotty.tools.dotc.classpath.FileUtils.{isTasty, hasClassExtension, hasTastyExtension}
11+
import dotty.tools.dotc.classpath.FileUtils.{hasClassExtension, hasTastyExtension}
1212
import dotty.tools.dotc.core.Contexts.*
1313
import dotty.tools.dotc.core.Decorators.*
1414
import dotty.tools.dotc.core.Flags.*
@@ -21,7 +21,7 @@ import dotty.tools.dotc.core.Types.*
2121

2222
import dotty.tools.dotc.util.{SrcPos, NoSourcePosition}
2323
import dotty.tools.io
24-
import dotty.tools.io.{AbstractFile, PlainFile, ZipArchive, NoAbstractFile}
24+
import dotty.tools.io.{AbstractFile, PlainFile, ZipArchive, NoAbstractFile, FileExtension}
2525
import xsbti.UseScope
2626
import xsbti.api.DependencyContext
2727
import xsbti.api.DependencyContext.*
@@ -84,7 +84,7 @@ class ExtractDependencies extends Phase {
8484
Arrays.sort(deps)
8585
Arrays.sort(names)
8686

87-
val pw = io.File(unit.source.file.jpath).changeExtension("inc").toFile.printWriter()
87+
val pw = io.File(unit.source.file.jpath).changeExtension(FileExtension.Inc).toFile.printWriter()
8888
// val pw = Console.out
8989
try {
9090
pw.println("Used Names:")
@@ -495,7 +495,7 @@ class DependencyRecorder {
495495
if depFile != null then {
496496
// Cannot ignore inheritance relationship coming from the same source (see sbt/zinc#417)
497497
def allowLocal = depCtx == DependencyByInheritance || depCtx == LocalDependencyByInheritance
498-
val isTasty = depFile.hasTastyExtension
498+
val isTastyOrSig = depFile.hasTastyExtension
499499

500500
def processExternalDependency() = {
501501
val binaryClassName = depClass.binaryClassName
@@ -506,13 +506,13 @@ class DependencyRecorder {
506506
binaryDependency(zip.jpath, binaryClassName)
507507
case _ =>
508508
case pf: PlainFile => // The dependency comes from a class file, Zinc handles JRT filesystem
509-
binaryDependency(if isTasty then cachedSiblingClass(pf) else pf.jpath, binaryClassName)
509+
binaryDependency(if isTastyOrSig then cachedSiblingClass(pf) else pf.jpath, binaryClassName)
510510
case _ =>
511511
internalError(s"Ignoring dependency $depFile of unknown class ${depFile.getClass}}", fromClass.srcPos)
512512
}
513513
}
514514

515-
if isTasty || depFile.hasClassExtension then
515+
if isTastyOrSig || depFile.hasClassExtension then
516516
processExternalDependency()
517517
else if allowLocal || depFile != sourceFile.file then
518518
// We cannot ignore dependencies coming from the same source file because
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
package dotty.tools.dotc.util
2+
3+
object EnumFlags:
4+
5+
opaque type FlagSet[E <: reflect.Enum] = Int
6+
7+
object FlagSet:
8+
9+
extension [E <: reflect.Enum](set: FlagSet[E])
10+
def is(flag: E): Boolean = (set & (1 << flag.ordinal)) != 0
11+
def |(flag: E): FlagSet[E] = (set | (1 << flag.ordinal))
12+
13+
def empty[E <: reflect.Enum]: FlagSet[E] =
14+
0

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

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -97,11 +97,18 @@ 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. TODO: change to enum */
100+
/** Checks extension case insensitively. */
101+
def hasExtension(other: FileExtension): Boolean = ext == other
102+
103+
/** Checks extension case insensitively. */
104+
@deprecated("use overload with FileExtension")
101105
def hasExtension(other: String): Boolean = extension == other.toLowerCase
102106

103-
/** Returns the extension of this abstract file. TODO: store as an enum to avoid costly comparisons */
104-
val extension: String = Path.extension(name)
107+
/** Returns the extension of this abstract file. */
108+
val ext: FileExtension = Path.fileExtension(name)
109+
110+
/** Returns the extension of this abstract file as a String. */
111+
def extension: String = ext.toLowerCase
105112

106113
/** The absolute file, if this is a relative file. */
107114
def absolute: AbstractFile
@@ -129,7 +136,7 @@ abstract class AbstractFile extends Iterable[AbstractFile] {
129136
}
130137

131138
/** Does this abstract file represent something which can contain classfiles? */
132-
def isClassContainer: Boolean = isDirectory || (jpath != null && (extension == "jar" || extension == "zip"))
139+
def isClassContainer: Boolean = isDirectory || (jpath != null && ext.isJarOrZip)
133140

134141
/** Create a file on disk, if one does not exist already. */
135142
def create(): Unit

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ object File {
4040
class File(jpath: JPath)(implicit constructorCodec: Codec) extends Path(jpath) with Streamable.Chars {
4141
override val creationCodec: io.Codec = constructorCodec
4242

43-
override def addExtension(ext: String): File = super.addExtension(ext).toFile
43+
override def addExtension(ext: FileExtension): File = super.addExtension(ext).toFile
4444
override def toAbsolute: File = if (isAbsolute) this else super.toAbsolute.toFile
4545
override def toDirectory: Directory = new Directory(jpath)
4646
override def toFile: File = this

0 commit comments

Comments
 (0)