@@ -16,7 +16,9 @@ import scala.collection.mutable, mutable.ArrayBuffer, mutable.ListBuffer
1616import scala .io .{Codec , Source }
1717import scala .jdk .CollectionConverters .*
1818import scala .util .{Random , Try , Using }
19- import scala .collection .mutable .ListBuffer
19+ import scala .util .control .NonFatal
20+ import scala .util .matching .Regex
21+ import scala .util .Properties .{isJavaAtLeast , javaSpecVersion }
2022
2123import dotc .{Compiler , Driver }
2224import dotty .tools .dotc .CoverageSupport
@@ -27,6 +29,7 @@ import dotc.reporting.{Reporter, TestReporter}
2729import dotc .reporting .Diagnostic
2830import dotc .util .{SourceFile , SourcePosition , Spans , NoSourcePosition }
2931import io .AbstractFile
32+ import util .chaining .*
3033
3134/** A parallel testing suite whose goal is to integrate nicely with JUnit
3235 *
@@ -199,16 +202,15 @@ trait ParallelTesting extends RunnerOrchestration with CoverageSupport:
199202 flags : TestFlags ,
200203 outDir : JFile
201204 )(using val group : TestGroup ) extends TestSource {
205+ import SeparateCompilationSource .*
202206 case class Group (ordinal : Int , compiler : String )
203207
204- lazy val compilationGroups : List [(Group , Array [JFile ])] =
205- val Compiler = """ c([\d\.]+)""" .r
206- val Ordinal = """ (\d+)""" .r
208+ lazy val compilationGroups : List [(Group , Array [JFile ])] = {
207209 def groupFor (file : JFile ): Group =
208210 val groupSuffix = file.getName.dropWhile(_ != '_' ).stripSuffix(" .scala" ).stripSuffix(" .java" )
209211 val groupSuffixParts = groupSuffix.split(" _" )
210- val ordinal = groupSuffixParts.collectFirst { case Ordinal (n) => n.toInt }.getOrElse(Int .MinValue )
211- val compiler = groupSuffixParts.collectFirst { case Compiler (c) => c }.getOrElse(" " )
212+ val ordinal = groupSuffixParts.collectFirst { case GroupOrdinal (n) => n.toInt }.getOrElse(Int .MinValue )
213+ val compiler = groupSuffixParts.collectFirst { case CompilerVersion (c) => c }.getOrElse(" " )
212214 Group (ordinal, compiler)
213215
214216 dir.listFiles
@@ -217,15 +219,32 @@ trait ParallelTesting extends RunnerOrchestration with CoverageSupport:
217219 .toList
218220 .sortBy { (g, _) => (g.ordinal, g.compiler) }
219221 .map { (g, f) => (g, f.sorted) }
222+ }
220223
221224 def sourceFiles = compilationGroups.map(_._2).flatten.toArray
222225
223226 def checkFileBasePathCandidates : Array [String ] =
224227 Array (dir.getPath)
225228 }
229+ object SeparateCompilationSource :
230+ val CompilerVersion = """ c([\d\.]+)""" .r
231+ val HasCompilerVersion = """ _c([\d\.]+)""" .r.unanchored
232+ val GroupOrdinal = """ (\d+)""" .r
226233
234+ /** Skip if there are no sources, such as in a spurious directory,
235+ * or when compiling with a legacy compiler which may not run under this jdk.
236+ */
227237 protected def shouldSkipTestSource (testSource : TestSource ): Boolean =
228- testSource.sourceFiles.length == 0
238+ val files = testSource.sourceFiles
239+ files.length == 0
240+ ||
241+ ! TestConfiguration .usingBaselineJava
242+ &&
243+ testSource.match
244+ case separate : SeparateCompilationSource =>
245+ separate.compilationGroups.exists((group, _) => group.compiler.nonEmpty)
246+ case _ =>
247+ files.exists(f => SeparateCompilationSource .HasCompilerVersion .matches(f.getName))
229248
230249 protected def shouldReRun (testSource : TestSource ): Boolean =
231250 failedTests.forall(rerun => testSource match {
@@ -246,7 +265,15 @@ trait ParallelTesting extends RunnerOrchestration with CoverageSupport:
246265 Try (testSource match {
247266 case testSource @ JointCompilationSource (name, files, flags, outDir, fromTasty, decompilation) =>
248267 val reporter = fromTasty match
249- case NotFromTasty => compile(testSource.sourceFiles, flags, outDir)
268+ case NotFromTasty =>
269+ if testSource.sourceFiles.length == 1 then
270+ testSource.sourceFiles(0 ).getName match
271+ case SeparateCompilationSource .HasCompilerVersion (version) =>
272+ val compiler = version.stripSuffix(" ." )
273+ compileWithOtherCompiler(compiler, testSource.sourceFiles, flags, outDir)
274+ case _ => compile(testSource.sourceFiles, flags, outDir)
275+ else
276+ compile(testSource.sourceFiles, flags, outDir)
250277 case FromTasty => compileFromTasty(flags, outDir)
251278 case FromBestEffortTasty => compileFromBestEffortTasty(flags, outDir)
252279 case WithBestEffortTasty (bestEffortDir) => compileWithBestEffortTasty(testSource.sourceFiles, bestEffortDir, flags, outDir)
@@ -487,7 +514,6 @@ trait ParallelTesting extends RunnerOrchestration with CoverageSupport:
487514 throw e
488515
489516 protected def compile (files0 : Array [JFile ], flags0 : TestFlags , targetDir : JFile ): TestReporter = {
490- import scala .util .Properties .*
491517
492518 def flattenFiles (f : JFile ): Array [JFile ] =
493519 if (f.isDirectory) f.listFiles.flatMap(flattenFiles)
@@ -630,7 +656,7 @@ trait ParallelTesting extends RunnerOrchestration with CoverageSupport:
630656 case Nil => Nil
631657 flags.copy(options = loop(flags.options.toList).toArray)
632658
633- protected def compileWithOtherCompiler (compiler : String , files : Array [JFile ], flags : TestFlags , targetDir : JFile ): TestReporter =
659+ protected def compileWithOtherCompiler (compiler : String , files : Array [JFile ], flags : TestFlags , targetDir : JFile ): TestReporter = {
634660 def artifactClasspath (organizationName : String , moduleName : String ) =
635661 import coursier .*
636662 val dep = Dependency (
@@ -690,6 +716,8 @@ trait ParallelTesting extends RunnerOrchestration with CoverageSupport:
690716 }
691717
692718 reporter
719+ }
720+ end compileWithOtherCompiler
693721
694722 protected def compileFromBestEffortTasty (flags0 : TestFlags , targetDir : JFile ): TestReporter = {
695723 val classes = flattenFiles(targetDir).filter(isBestEffortTastyFile).map(_.toString)
@@ -1532,6 +1560,8 @@ trait ParallelTesting extends RunnerOrchestration with CoverageSupport:
15321560 * target all files are grouped according to the file suffix `_X` where `X`
15331561 * is a number. These groups are then ordered in ascending order based on
15341562 * the value of `X` and each group is compiled one after the other.
1563+ * A file can request compilation by a legacy compiler via a version suffix:
1564+ * `A_1_c3.2.0.scala` in group 1 is compiled by 3.2.0 when testing under the minimum supported JDK.
15351565 *
15361566 * For this function to work as expected, we use the same convention for
15371567 * directory layout as the old partest. That is:
@@ -1555,8 +1585,14 @@ trait ParallelTesting extends RunnerOrchestration with CoverageSupport:
15551585 ! isPicklerTest || source.compilationGroups.length == 1
15561586 }
15571587 val targets =
1558- files.map(f => JointCompilationSource (testGroup.name, Array (f), flags, createOutputDirsForFile(f, sourceDir, outDir))) ++
1559- dirs.map { dir => SeparateCompilationSource (testGroup.name, dir, flags, createOutputDirsForDir(dir, sourceDir, outDir)) }.filter(picklerDirFilter)
1588+ files.map: f =>
1589+ val out = createOutputDirsForFile(f, sourceDir, outDir)
1590+ JointCompilationSource (testGroup.name, Array (f), flags, out)
1591+ ++
1592+ dirs.map: dir =>
1593+ val out = createOutputDirsForDir(dir, sourceDir, outDir)
1594+ SeparateCompilationSource (testGroup.name, dir, flags, out)
1595+ .filter(picklerDirFilter)
15601596
15611597 // Create a CompilationTest and let the user decide whether to execute a pos or a neg test
15621598 new CompilationTest (targets)
0 commit comments