Skip to content

Commit

Permalink
Only skip reflection code on JS
Browse files Browse the repository at this point in the history
- add basic support for `//> using target.platform jvm|scala-js` in Vulpix.
- if the directive is present, filter out files in compilation that dont match
  the test platform, also add a suffix to the expected check-file name.
- duplicate UnrollTestPlatformSpecific files for jvm and scala-js platforms,
  deleting the reflection code in scala-js version.
  • Loading branch information
bishabosha committed Jan 17, 2025
1 parent 5e285cd commit 297c88c
Show file tree
Hide file tree
Showing 61 changed files with 244 additions and 261 deletions.
41 changes: 37 additions & 4 deletions compiler/test/dotty/tools/utils.scala
Original file line number Diff line number Diff line change
Expand Up @@ -57,25 +57,54 @@ def assertThrows[T <: Throwable: ClassTag](p: T => Boolean)(body: => Any): Unit
case NonFatal(other) => throw AssertionError(s"Wrong exception: expected ${implicitly[ClassTag[T]]} but was ${other.getClass.getName}").tap(_.addSuppressed(other))
end assertThrows

enum TestPlatform:
case JVM, ScalaJS
override def toString: String = this match
case JVM => "jvm"
case ScalaJS => "scala-js"

object TestPlatform:
def named(s: String): TestPlatform = s match
case "jvm" => TestPlatform.JVM
case "scala-js" => TestPlatform.ScalaJS
case _ => throw IllegalArgumentException(s)

/** Famous tool names in the ecosystem. Used for tool args in test files. */
enum ToolName:
case Scala, Scalac, Java, Javac, ScalaJS, Test
case Scala, Scalac, Java, Javac, ScalaJS, Test, Target
object ToolName:
def named(s: String): ToolName = values.find(_.toString.equalsIgnoreCase(s)).getOrElse(throw IllegalArgumentException(s))

type ToolArgs = Map[ToolName, List[String]]
type PlatformFiles = Map[TestPlatform, List[String]]

/** Take a prefix of each file, extract tool args, parse, and combine.
* Arg parsing respects quotation marks. Result is a map from ToolName to the combined tokens.
*/
def toolArgsFor(files: List[JPath], charset: Charset = UTF_8): ToolArgs =
files.foldLeft(Map.empty[ToolName, List[String]]) { (res, path) =>
val (_, toolArgs) = platformAndToolArgsFor(files, charset)
toolArgs

/** Take a prefix of each file, extract tool args, parse, and combine.
* Arg parsing respects quotation marks. Result is a map from ToolName to the combined tokens.
* If the ToolName is Target, then also accumulate the file name associated with the given platform.
*/
def platformAndToolArgsFor(files: List[JPath], charset: Charset = UTF_8): (PlatformFiles, ToolArgs) =
files.foldLeft(Map.empty[TestPlatform, List[String]] -> Map.empty[ToolName, List[String]]) { (res, path) =>
val toolargs = toolArgsParse(resource(Files.lines(path, charset))(_.limit(10).toScala(List)), Some(path.toString))
toolargs.foldLeft(res) {
case (acc, (tool, args)) =>
case ((plat, acc), (tool, args)) =>
val name = ToolName.named(tool)
val tokens = CommandLineParser.tokenize(args)
acc.updatedWith(name)(v0 => v0.map(_ ++ tokens).orElse(Some(tokens)))

val plat1 = if name eq ToolName.Target then
val testPlatform = TestPlatform.named(tokens.head)
val fileName = path.toString
plat.updatedWith(testPlatform)(_.map(fileName :: _).orElse(Some(fileName :: Nil)))
else
plat

plat1 -> acc.updatedWith(name)(v0 => v0.map(_ ++ tokens).orElse(Some(tokens)))
}
}

Expand All @@ -94,6 +123,8 @@ private val toolArg = raw"(?://|/\*| \*) ?(?i:(${ToolName.values.mkString("|")})
/** Directive to specify to vulpix the options to pass to Dotty */
private val directiveOptionsArg = raw"//> using options (.*)".r.unanchored
private val directiveJavacOptions = raw"//> using javacOpt (.*)".r.unanchored
private val directiveTargetOptions = raw"//> using target.platform (jvm|scala-js)".r.unanchored
private val directiveUnknown = raw"//> using (.*)".r.unanchored

// Inspect the lines for compiler options of the form
// `//> using options args`, `// scalajs: args`, `/* scalajs: args`, ` * scalajs: args` etc.
Expand All @@ -109,6 +140,8 @@ def toolArgsParse(lines: List[String], filename: Option[String]): List[(String,S
lines.flatMap {
case directiveOptionsArg(args) => List(("scalac", args))
case directiveJavacOptions(args) => List(("javac", args))
case directiveTargetOptions(platform) => List(("target", platform))
case directiveUnknown(rest) => sys.error(s"Unknown directive: `//> using ${CommandLineParser.tokenize(rest).headOption.getOrElse("''")}`${filename.fold("")(f => s" in file $f")}")
case _ => Nil
}

Expand Down
23 changes: 20 additions & 3 deletions compiler/test/dotty/tools/vulpix/ParallelTesting.scala
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,8 @@ trait ParallelTesting extends RunnerOrchestration { self =>
/** Contains a list of failed tests to run, if list is empty no tests will run */
def failedTests: Option[List[String]]

protected def testPlatform: TestPlatform = TestPlatform.JVM

/** A test source whose files or directory of files is to be compiled
* in a specific way defined by the `Test`
*/
Expand Down Expand Up @@ -343,7 +345,11 @@ trait ParallelTesting extends RunnerOrchestration { self =>
new JFile(f.getPath.replaceFirst("\\.(scala|java)$", ".check"))
}
case ts: SeparateCompilationSource =>
Option(new JFile(ts.dir.getPath + ".check"))
val platform =
if testSource.allToolArgs.getOrElse(ToolName.Target, Nil).nonEmpty then
s".$testPlatform"
else ""
Option(new JFile(ts.dir.getPath + platform + ".check"))
}
}

Expand Down Expand Up @@ -499,7 +505,8 @@ trait ParallelTesting extends RunnerOrchestration { self =>

val files: Array[JFile] = files0.flatMap(flattenFiles)

val toolArgs = toolArgsFor(files.toList.map(_.toPath), getCharsetFromEncodingOpt(flags0))
val (platformFiles, toolArgs) =
platformAndToolArgsFor(files.toList.map(_.toPath), getCharsetFromEncodingOpt(flags0))

val spec = raw"(\d+)(\+)?".r
val testIsFiltered = toolArgs.get(ToolName.Test) match
Expand Down Expand Up @@ -557,7 +564,17 @@ trait ParallelTesting extends RunnerOrchestration { self =>
// If a test contains a Java file that cannot be parsed by Dotty's Java source parser, its
// name must contain the string "JAVA_ONLY".
val dottyFiles = files.filterNot(_.getName.contains("JAVA_ONLY")).map(_.getPath)
driver.process(allArgs ++ dottyFiles, reporter = reporter)

val dottyFiles0 =
if platformFiles.isEmpty then dottyFiles
else
val excludedFiles = platformFiles
.collect { case (plat, files) if plat != testPlatform => files }
.flatten
.toSet
dottyFiles.filterNot(excludedFiles)

driver.process(allArgs ++ dottyFiles0, reporter = reporter)

// todo a better mechanism than ONLY. test: -scala-only?
val javaFiles = files.filter(_.getName.endsWith(".java")).filterNot(_.getName.contains("SCALA_ONLY")).map(_.getPath)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,8 @@ class ScalaJSCompilationTests extends ParallelTesting {
override protected def shouldSkipTestSource(testSource: TestSource): Boolean =
testSource.allToolArgs.get(ToolName.ScalaJS).exists(_.contains("--skip"))

override protected def testPlatform: TestPlatform = TestPlatform.ScalaJS

override def runMain(classPath: String, toolArgs: ToolArgs)(implicit summaryReport: SummaryReporting): Status =
import scala.concurrent.ExecutionContext.Implicits.global

Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,10 @@
=== Unrolled Test V1 ===
Assertion passed: found "cow1" + "true0"
Assertion passed: found "cow2" + "true0"
Assertion passed: found "cow1" + "true0"
Assertion passed: found "cow2" + "true0"
Assertion passed: found "cow1" + "true0"
Assertion passed: found "cow2" + "true0"
Assertion passed: found "hello31337" + "true0"
=== Unrolled Test V2 ===
Assertion passed: found "cow1true" + "0"
Assertion passed: found "cow2true" + "0"
Assertion passed: found "cow2false" + "0"
Expand All @@ -17,12 +15,7 @@ Assertion passed: found "cow1true" + "0"
Assertion passed: found "cow2true" + "0"
Assertion passed: found "cow2false" + "0"
Assertion passed: found "hello31337false" + "0"
=== Unrolled Test V3 ===
Assertion passed: found "hello31337false12345"
as expected, no constructor for Unrolled(s: String)
public example.Unrolled(java.lang.String,int)
public example.Unrolled(java.lang.String,int,boolean)
public example.Unrolled(java.lang.String,int,boolean,long)
Assertion passed: found "cow1true0"
Assertion passed: found "cow2true0"
Assertion passed: found "cow2false0"
Expand Down
1 change: 0 additions & 1 deletion tests/run/unroll-caseclass-integration/Test_4.scala
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
//> using options -experimental
// scalajs: --skip
import unroll.*

@main def Test: Unit =
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
//> using options -experimental
//> using target.platform scala-js
package unroll

object UnrollTestPlatformSpecificV3{
def apply() = {
// do nothing for scala-js
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
//> using options -experimental
// scalajs: --skip
//> using target.platform jvm
package unroll

object UnrollTestPlatformSpecificV3{
Expand Down
13 changes: 0 additions & 13 deletions tests/run/unroll-caseclass/Test_4.scala

This file was deleted.

62 changes: 0 additions & 62 deletions tests/run/unroll-caseclass/unrolledV1_1.scala

This file was deleted.

56 changes: 0 additions & 56 deletions tests/run/unroll-caseclass/unrolledV2_2.scala

This file was deleted.

Loading

0 comments on commit 297c88c

Please sign in to comment.