Skip to content

Commit 1d42ed6

Browse files
committed
Remove custom path for best effort compilation artifacts
Now best efforttasty files will be always saved in the `<output>/META-INF/best-effort` directory, similar to the semanticdb files.
1 parent 1590d2b commit 1d42ed6

File tree

7 files changed

+58
-67
lines changed

7 files changed

+58
-67
lines changed

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

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -376,9 +376,9 @@ private sealed trait YSettings:
376376
//.withPostSetHook( _ => YprofileEnabled.value = true )
377377
val YprofileRunGcBetweenPhases: Setting[List[String]] = PhasesSetting("-Yprofile-run-gc", "Run a GC between phases - this allows heap size to be accurate at the expense of more time. Specify a list of phases, or *", "_")
378378
//.withPostSetHook( _ => YprofileEnabled.value = true )
379-
380-
val YbestEffortDir: Setting[String] = StringSetting("-Ybest-effort-dir", "dir", "Enable best-effort compilation attempting to produce tasty in case of failure to specified directory, as part of the pickler phase.", "")
381-
val YwithBestEffortTasty: Setting[Boolean] = BooleanSetting("-Ywith-best-effort-tasty", "Allow to compile from a best effort tasty files. If such file is used, the compiler will stop after the pickler phase.")
379+
380+
val YbestEffort: Setting[Boolean] = BooleanSetting("-Ybest-effort", "Enable best-effort compilation attempting to produce tasty to the META-INF/best-effort directory, regardless of errors, as part of the pickler phase.")
381+
val YwithBestEffortTasty: Setting[Boolean] = BooleanSetting("-Ywith-best-effort-tasty", "Allow to compile from best-effort tasty files. If such file is used, the compiler will stop after the pickler phase.")
382382

383383
// Experimental language features
384384
val YnoKindPolymorphism: Setting[Boolean] = BooleanSetting("-Yno-kind-polymorphism", "Disable kind polymorphism.")

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -454,7 +454,7 @@ object Contexts {
454454
def explicitNulls: Boolean = base.settings.YexplicitNulls.value
455455

456456
/** Is best-effort-dir option set? */
457-
def isBestEffort: Boolean = base.settings.YbestEffortDir.value.nonEmpty
457+
def isBestEffort: Boolean = base.settings.YbestEffort.value
458458

459459
/** Is the from-best-effort-tasty option set to true? */
460460
def withBestEffortTasty: Boolean = base.settings.YwithBestEffortTasty.value

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ import dotty.tools.dotc.core.Contexts.Context
1111

1212
object BestEffortTastyWriter:
1313

14-
def write(dir: JPath, units: List[CompilationUnit])(using Context): Unit =
14+
def write(dir: JPath, units: List[CompilationUnit])(using Context): Unit =
1515
if JFiles.exists(dir) then JFiles.createDirectories(dir)
1616

1717
units.foreach { unit =>
@@ -37,7 +37,7 @@ object BestEffortTastyWriter:
3737
case last :: Nil =>
3838
val name = last.stripSuffix("$")
3939
acc.resolve(s"$name.betasty")
40-
case pkg :: tail =>
40+
case pkg :: tail =>
4141
val next = acc.resolve(pkg)
4242
if !JFiles.exists(next) then JFiles.createDirectory(next)
4343
outputPath(tail, next)

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ import scala.annotation.internal.sharable
5151
* @param reader the reader from which to unpickle
5252
* @param posUnpicklerOpt the unpickler for positions, if it exists
5353
* @param commentUnpicklerOpt the unpickler for comments, if it exists
54-
* @param isBestEffortTasty decides whether to unpickle as a Best Effort TASTy
54+
* @param isBestEffortTasty decides whether to unpickle as a Best Effort TASTy
5555
*/
5656
class TreeUnpickler(reader: TastyReader,
5757
nameAtRef: NameTable,
@@ -1015,7 +1015,7 @@ class TreeUnpickler(reader: TastyReader,
10151015
* but skip constructor arguments. Return any trees that were partially
10161016
* parsed in this way as InferredTypeTrees.
10171017
* @param end specifies last address that can be read. Should be set for Best Effort
1018-
* TASTy compilation, otherwise should be None
1018+
* TASTy compilation, otherwise should be None
10191019
*/
10201020
def readParents(withArgs: Boolean, end: Option[Addr])(using Context): List[Tree] =
10211021
collectWhile(nextByte != SELFDEF && nextByte != DEFDEF && end.map(_ != currentAddr).getOrElse(true)) {

compiler/src/dotty/tools/dotc/transform/Pickler.scala

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,8 @@ import reporting.{ThrowingReporter, Profile, Message}
1616
import collection.mutable
1717
import util.concurrent.{Executor, Future}
1818
import compiletime.uninitialized
19-
import java.nio.file.Paths
19+
import java.nio.file.Files
20+
import scala.language.unsafeNulls
2021

2122
object Pickler {
2223
val name: String = "pickler"
@@ -162,8 +163,12 @@ class Pickler extends Phase {
162163
.addMode(Mode.ReadPositions)
163164
.addMode(Mode.PrintShowExceptions))
164165
if ctx.isBestEffort then
165-
val dir = Paths.get(ctx.settings.YbestEffortDir.value)
166-
BestEffortTastyWriter.write(dir.nn, units)
166+
val outpath =
167+
ctx.settings.outputDir.value.jpath.toAbsolutePath.normalize
168+
.resolve("META-INF")
169+
.resolve("best-effort")
170+
Files.createDirectories(outpath)
171+
BestEffortTastyWriter.write(outpath.nn, units)
167172
result
168173
}
169174

compiler/test/dotty/tools/vulpix/ParallelTesting.scala

Lines changed: 34 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -641,13 +641,13 @@ trait ParallelTesting extends RunnerOrchestration { self =>
641641
}
642642

643643
reporter
644-
644+
645645
protected def compileFromBestEffortTasty(flags0: TestFlags, suppressErrors: Boolean, targetDir: JFile): TestReporter = {
646646
val classes = flattenFiles(targetDir).filter(isBestEffortTastyFile).map(_.toString)
647647
val flags = flags0 and "-from-tasty" and "-Ywith-best-effort-tasty"
648648
val reporter = mkReporter
649649
val driver = new Driver
650-
650+
651651
driver.process(flags.all ++ classes, reporter = reporter)
652652

653653
reporter
@@ -660,7 +660,7 @@ trait ParallelTesting extends RunnerOrchestration { self =>
660660
println((flags.all ++ files0.map(_.toString) ++ Array(bestEffortDir.toString)).mkString(" "))
661661

662662
val args = Array("-classpath", flags.defaultClassPath + ":" + bestEffortDir.toString) ++ flags.options
663-
663+
664664
driver.process(args ++ files0.map(_.toString), reporter = reporter)
665665

666666
reporter
@@ -1271,20 +1271,6 @@ trait ParallelTesting extends RunnerOrchestration { self =>
12711271
targetDir
12721272
}
12731273

1274-
private def createBestEffortDirForDir(d: JFile, sourceDir: JFile, outDir: String): JFile = {
1275-
val uniqueSubdir = s"${d.getName}-best-effort"
1276-
val bestEffortDir = new JFile(outDir + s"${sourceDir.getName}${JFile.separatorChar}$uniqueSubdir")
1277-
bestEffortDir.mkdirs()
1278-
bestEffortDir
1279-
}
1280-
1281-
private def createBestEffortDirForFile(file: JFile, sourceDir: JFile, outDir: String): JFile = {
1282-
val uniqueSubdir = s"${file.getName.substring(0, file.getName.lastIndexOf('.'))}-best-effort"
1283-
val bestEffortDir = new JFile(outDir + s"${sourceDir.getName}${JFile.separatorChar}$uniqueSubdir")
1284-
bestEffortDir.mkdirs()
1285-
bestEffortDir
1286-
}
1287-
12881274
/** Make sure that directory string is as expected */
12891275
private def checkRequirements(f: String, sourceDir: JFile, outDir: String): Unit = {
12901276
require(sourceDir.isDirectory && sourceDir.exists, "passed non-directory to `compileFilesInDir`: " + sourceDir)
@@ -1487,16 +1473,16 @@ trait ParallelTesting extends RunnerOrchestration { self =>
14871473
}
14881474

14891475
/** A two step compilation test for best effort compilation pickling and unpickling.
1490-
*
1491-
* First, erroring neg test files are compiled with the `-Ybest-effort-dir` option
1492-
* to a best effort directory. If successful, then the produced Best Effort TASTy is
1493-
* re-compiled with '-Ywith-best-effort-tasty' to test the TastyReader for Best Effort TASTy.
1476+
*
1477+
* First, erroring neg test files are compiled with the `-Ybest-effort` option.
1478+
* If successful, then the produced Best Effort TASTy is re-compiled with
1479+
* '-Ywith-best-effort-tasty' to test the TastyReader for Best Effort TASTy.
14941480
*/
14951481
def compileBestEffortTastyInDir(f: String, flags: TestFlags, picklingFilter: FileFilter, unpicklingFilter: FileFilter)(
14961482
implicit testGroup: TestGroup): BestEffortCompilationTest = {
1497-
val bestEffortFlag = "-Ybest-effort-dir"
1498-
assert(!flags.options.contains(bestEffortFlag), "Best effort directory should not be added manually")
1499-
1483+
val bestEffortFlag = "-Ybest-effort"
1484+
assert(!flags.options.contains(bestEffortFlag), "Best effort compilation flag should not be added manually")
1485+
15001486
val outDir = defaultOutputDir + testGroup + JFile.separator
15011487
val sourceDir = new JFile(f)
15021488
checkRequirements(f, sourceDir, outDir)
@@ -1510,15 +1496,14 @@ trait ParallelTesting extends RunnerOrchestration { self =>
15101496
name: String,
15111497
file: JFile,
15121498
flags: TestFlags,
1513-
bestEffortDir: JFile,
15141499
outputDir: JFile
1515-
) extends JointCompilationSource(name, Array(file), flags.and(bestEffortFlag).and(bestEffortDir.toString), outputDir) {
1500+
) extends JointCompilationSource(name, Array(file), flags.and(bestEffortFlag), outputDir) {
15161501
override def buildInstructions(errors: Int, warnings: Int): String = {
15171502
s"""|
15181503
|Test '$title' compiled with a compiler crash,
15191504
|the test can be reproduced by running:
15201505
|
1521-
| sbt "scalac -Ybest-effort-dir $bestEffortDir $file"
1506+
| sbt "scalac -Ybest-effort $file"
15221507
|
15231508
|These tests can be disabled by adding `${file.getName}` to `compiler${JFile.separator}test${JFile.separator}dotc${JFile.separator}neg-best-effort-pickling.blacklist`
15241509
|""".stripMargin
@@ -1533,7 +1518,7 @@ trait ParallelTesting extends RunnerOrchestration { self =>
15331518
) extends JointCompilationSource(name, Array(file), flags, bestEffortDir, fromTasty = FromBestEffortTasty) {
15341519

15351520
override def buildInstructions(errors: Int, warnings: Int): String = {
1536-
def beTastyFiles(file: JFile): Array[JFile] =
1521+
def beTastyFiles(file: JFile): Array[JFile] =
15371522
file.listFiles.flatMap { innerFile =>
15381523
if (innerFile.isDirectory) beTastyFiles(innerFile)
15391524
else if (isBestEffortTastyFile(innerFile)) Array(innerFile)
@@ -1544,7 +1529,7 @@ trait ParallelTesting extends RunnerOrchestration { self =>
15441529
|Test '$title' compiled with a compiler crash,
15451530
|the test can be reproduced by running:
15461531
|
1547-
| sbt "scalac -Ybest-effort-dir $bestEffortDir $file"
1532+
| sbt "scalac -Ybest-effort $file"
15481533
| sbt "scalac --from-tasty -Ywith-best-effort-tasty $beTastyFilesString"
15491534
|
15501535
|These tests can be disabled by adding `${file.getName}` to `compiler${JFile.separator}test${JFile.separator}dotc${JFile.separator}neg-best-effort-unpickling.blacklist`
@@ -1553,20 +1538,22 @@ trait ParallelTesting extends RunnerOrchestration { self =>
15531538
}
15541539
}
15551540

1556-
val (bestEffortTargets, bestEffortDirs) =
1541+
val (bestEffortTargets, targetAndBestEffortDirs) =
15571542
filteredPicklingFiles.map { f =>
1558-
val bestEffortDir = createBestEffortDirForFile(f, sourceDir, outDir)
15591543
val outputDir = createOutputDirsForFile(f, sourceDir, outDir)
1544+
val bestEffortDir = new JFile(outputDir, s"META-INF${JFile.separator}best-effort")
15601545
(
1561-
BestEffortCompilation(testGroup.name, f, flags, bestEffortDir, outputDir),
1562-
bestEffortDir
1546+
BestEffortCompilation(testGroup.name, f, flags, outputDir),
1547+
(f, bestEffortDir)
15631548
)
15641549
}.unzip
1550+
val (_, bestEffortDirs) = targetAndBestEffortDirs.unzip
1551+
val fileToBestEffortDirMap = targetAndBestEffortDirs.toMap
15651552

15661553
val picklingSet = filteredPicklingFiles.toSet
15671554
val fromTastyTargets =
15681555
filteredUnpicklingFiles.filter(picklingSet.contains(_)).map { f =>
1569-
val bestEffortDir = createBestEffortDirForFile(f, sourceDir, outDir)
1556+
val bestEffortDir = fileToBestEffortDirMap(f)
15701557
new JointCompilationSourceFromBestEffortTasty(testGroup.name, f, flags, bestEffortDir)
15711558
}
15721559

@@ -1579,13 +1566,13 @@ trait ParallelTesting extends RunnerOrchestration { self =>
15791566
}
15801567

15811568
/** A two step integration test for best effort compilation.
1582-
*
1583-
* Directories found in the directory `f` represent separate tests and must contain
1569+
*
1570+
* Directories found in the directory `f` represent separate tests and must contain
15841571
* the 'err' and 'main' directories. First the (erroring) contents of the 'err'
1585-
* directory are compiled with the `Ybest-effort-dir` option with a best effort directory.
1572+
* directory are compiled with the `Ybest-effort` option.
15861573
* Then, are the contents of 'main' are compiled with the previous best effort directory
15871574
* on the classpath using the option `-Ywith-best-effort-tasty`.
1588-
*
1575+
*
15891576
*/
15901577
def compileBestEffortIntegration(f: String, flags: TestFlags)(implicit testGroup: TestGroup) = {
15911578
val sourceDir = new JFile(f)
@@ -1599,24 +1586,23 @@ trait ParallelTesting extends RunnerOrchestration { self =>
15991586
val step1SourceFiles = step1SourceDir.listFiles
16001587
val step2SourceFiles = step2SourceDir.listFiles
16011588

1602-
val outDir = defaultOutputDir + testGroup + JFile.separator
1589+
val outDir = defaultOutputDir + testGroup + JFile.separator + dir.getName().toString + JFile.separator
16031590

16041591
val step1OutDir = createOutputDirsForDir(step1SourceDir, step1SourceDir, outDir)
16051592
val step2OutDir = createOutputDirsForDir(step2SourceDir, step2SourceDir, outDir)
16061593

1607-
val bestEffortDir = createBestEffortDirForDir(dir, sourceDir, outDir)
1608-
16091594
val step1Compilation = JointCompilationSource(
1610-
testGroup.name, step1SourceFiles, flags.and("-Ybest-effort-dir").and(bestEffortDir.toString), step1OutDir, fromTasty = NotFromTasty
1595+
testGroup.name, step1SourceFiles, flags.and("-Ybest-effort"), step1OutDir, fromTasty = NotFromTasty
16111596
)
1597+
1598+
val bestEffortDir = new JFile(step1OutDir, s"META-INF${JFile.separator}best-effort")
1599+
16121600
val step2Compilation = JointCompilationSource(
1613-
testGroup.name, step2SourceFiles, flags.and("-Ywith-best-effort-tasty"), step1OutDir, fromTasty = WithBestEffortTasty(bestEffortDir)
1601+
testGroup.name, step2SourceFiles, flags.and("-Ywith-best-effort-tasty"), step2OutDir, fromTasty = WithBestEffortTasty(bestEffortDir)
16141602
)
16151603
(step1Compilation, step2Compilation, bestEffortDir)
16161604
}.unzip3
1617-
println(step1Targets)
1618-
println(step2Targets)
1619-
1605+
16201606
BestEffortCompilationTest(
16211607
new CompilationTest(step1Targets).keepOutput,
16221608
new CompilationTest(step2Targets).keepOutput,
@@ -1653,7 +1639,7 @@ trait ParallelTesting extends RunnerOrchestration { self =>
16531639
}
16541640

16551641
class BestEffortCompilationTest(step1: CompilationTest, step2: CompilationTest, bestEffortDirs: List[JFile], shouldDelete: Boolean)(implicit testGroup: TestGroup) {
1656-
1642+
16571643
def checkNoCrash()(implicit summaryReport: SummaryReporting): this.type = {
16581644
step1.checkNoCrash() // Compile all files to generate the class files with best effort tasty
16591645
step2.checkNoCrash() // Compile with best effort tasty
@@ -1717,7 +1703,7 @@ object ParallelTesting {
17171703

17181704
def isTastyFile(f: JFile): Boolean =
17191705
f.getName.endsWith(".tasty")
1720-
1706+
17211707
def isBestEffortTastyFile(f: JFile): Boolean =
17221708
f.getName.endsWith(".betasty")
17231709

docs/_docs/internals/best-effort-compilation.md

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -7,12 +7,12 @@ Best-effort compilation is a compilation mode introduced with the aim of improvi
77
tast6y-like artifacts and semanticdb files in erroring programs.
88

99
It is composed of two experimental compiler options:
10-
* `-Ybest-effort-dir dir` produces Best Effort TASTy (`.betasty`) files to a separete `dir` best effort target directory
11-
* `-Ywith-best-effort-tasty` allows to read BestEffortTASTy, and if such file is read from the classpath then
12-
limits compilation to the frontend phases
10+
* `-Ybest-effort` produces Best Effort TASTy (`.betasty`) files to the `META-INF/best-effort` directory
11+
* `-Ywith-best-effort-tasty` allows to read Best Effort TASTy files, and if such file is read from the classpath then
12+
limits compilation to the frontend phases (for use in IDEs)
1313

1414
This feature aims to force through to the typer phase regardless of errors, and then serialize tasty-like files
15-
obtained from the error trees into the best effort directory and also serialize semanticdb as normal.
15+
obtained from the error trees into the best effort directory (`META-INF/best-effort`) and also serialize semanticdb as normal.
1616

1717
The exact execution pattern is as follows:
1818

@@ -47,7 +47,7 @@ Pickler (with added printing of best effort tasty to the best effort target dire
4747
End compilation Execute latter passes
4848
```
4949

50-
This is because the IDE is able to retrieve useful info even when skipping phases like PostTyper.
50+
This is because the IDE is able to retrieve useful info even when skipping phases like PostTyper.
5151

5252
This execution structure where we skip phases depending on the errors found is motivated by the desire
5353
to avoid additionally handling errored trees in as many phases as possible, therefore also decreasing
@@ -56,12 +56,12 @@ with errors from typer and usually the IDE is able to retrieve enough informatio
5656

5757
`-Ywith-best-effort-tasty` option allows reading Best Effort TASTy files from classpath. If such file is read, then
5858
the compiler is disallowed from proceeding to any non-frontend phase. This is to be used either in combination with
59-
`-Ybest-effort-dir` option to produce Best Effort TASTy using failing dependencies, or in the Presentation Compiler
59+
`-Ybest-effort` option to produce Best Effort TASTy using failing dependencies, or in the Presentation Compiler
6060
to access symbols derived from failing projects.
6161

6262
## Best Effort TASTy format
6363

64-
The Best Effort TASTy (`.betasty`) format is a file format produced by the compiler when the `-Ybest-effort-dir` option
64+
The Best Effort TASTy (`.betasty`) format is a file format produced by the compiler when the `-Ybest-effort` option
6565
is used. It is characterised by a different header and an addition of the `ERRORtype` type, which represents errored types in
6666
the compiler. The Best Effort TASTy format also informally extends the regular TASTy grammar to allow the handling of as
6767
large amount of incorrect trees produced by the compiler as possible. Because of this informality and unlike the regular
@@ -70,7 +70,7 @@ TASTy format, the BETASTy format should stay internal to the compiler.
7070
## Testing
7171

7272
The testing procedure reuses the `tests/neg` negative tests that are usually meant to produce errors. First they are compiled
73-
with the `-Ybest-effort-dir` option (testing the TreePickler for errored trees), then later, the tree is reconstructed using
73+
with the `-Ybest-effort` option (testing the TreePickler for errored trees), then later, the tree is reconstructed using
7474
the previously created Best Effort TASTy, with `-Yread-tasty` and `-Ywith-best-effort-tasty` options. This is to test the
7575
TreeUnpickler for those Best Effort TASTy files.
7676

0 commit comments

Comments
 (0)