Skip to content

Commit 400b6c2

Browse files
committed
Scala.js: Add neg tests for bad uses of reflect.Selectable.
We add some infrastructure to be able to perform neg tests that are specific to Scala.js. Such tests require the scalajs-library jar and the dotty-libraryJS jar on the classpath, and must be compiled with the `-scalajs` option. We use this infrastructure to test existing compile errors reported for unsupported uses of `reflect.Selectable` in Scala.js.
1 parent 212b8af commit 400b6c2

File tree

5 files changed

+103
-1
lines changed

5 files changed

+103
-1
lines changed

compiler/test/dotty/Properties.scala

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,9 @@ object Properties {
4848
/** dotty-library jar */
4949
def dottyLibrary: String = sys.props("dotty.tests.classes.dottyLibrary")
5050

51+
/** dotty-library-js jar */
52+
def dottyLibraryJS: String = sys.props("dotty.tests.classes.dottyLibraryJS")
53+
5154
/** dotty-compiler jar */
5255
def dottyCompiler: String = sys.props("dotty.tests.classes.dottyCompiler")
5356

@@ -74,4 +77,7 @@ object Properties {
7477

7578
/** jline-reader jar */
7679
def jlineReader: String = sys.props("dotty.tests.classes.jlineReader")
80+
81+
/** scalajs-library jar */
82+
def scalaJSLibrary: String = sys.props("dotty.tests.classes.scalaJSLibrary")
7783
}
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
package dotty
2+
package tools
3+
package dotc
4+
5+
import org.junit.{ Test, BeforeClass, AfterClass }
6+
import org.junit.experimental.categories.Category
7+
8+
import scala.concurrent.duration._
9+
import vulpix._
10+
11+
@Category(Array(classOf[ScalaJSCompilationTests]))
12+
class ScalaJSCompilationTests extends ParallelTesting {
13+
import ParallelTesting._
14+
import TestConfiguration._
15+
import ScalaJSCompilationTests._
16+
import CompilationTest.aggregateTests
17+
18+
// Test suite configuration --------------------------------------------------
19+
20+
def maxDuration = 60.seconds
21+
def numberOfSlaves = 5
22+
def safeMode = Properties.testsSafeMode
23+
def isInteractive = SummaryReport.isInteractive
24+
def testFilter = Properties.testsFilter
25+
def updateCheckFiles: Boolean = Properties.testsUpdateCheckfile
26+
27+
// Negative tests ------------------------------------------------------------
28+
29+
@Test def negScalaJS: Unit = {
30+
implicit val testGroup: TestGroup = TestGroup("negScalaJS")
31+
aggregateTests(
32+
compileFilesInDir("tests/neg-scalajs", scalaJSOptions),
33+
).checkExpectedErrors()
34+
}
35+
}
36+
37+
object ScalaJSCompilationTests {
38+
implicit val summaryReport: SummaryReporting = new SummaryReport
39+
@AfterClass def cleanup(): Unit = summaryReport.echoSummary()
40+
}

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

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,11 @@ object TestConfiguration {
4444
lazy val withTastyInspectorClasspath =
4545
withCompilerClasspath + File.pathSeparator + mkClasspath(List(Properties.dottyTastyInspector))
4646

47+
lazy val scalaJSClasspath = mkClasspath(List(
48+
Properties.scalaJSLibrary,
49+
Properties.dottyLibraryJS
50+
))
51+
4752
def mkClasspath(classpaths: List[String]): String =
4853
classpaths.map({ p =>
4954
val file = new java.io.File(p)
@@ -61,6 +66,8 @@ object TestConfiguration {
6166
defaultOptions.withClasspath(withStagingClasspath).withRunClasspath(withStagingClasspath)
6267
lazy val withTastyInspectorOptions =
6368
defaultOptions.withClasspath(withTastyInspectorClasspath).withRunClasspath(withTastyInspectorClasspath)
69+
lazy val scalaJSOptions =
70+
defaultOptions.and("-scalajs").withClasspath(scalaJSClasspath)
6471
val allowDeepSubtypes = defaultOptions without "-Yno-deep-subtypes"
6572
val allowDoubleBindings = defaultOptions without "-Yno-double-bindings"
6673
val picklingOptions = defaultOptions and (

project/Build.scala

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -526,19 +526,22 @@ object Build {
526526
(sourceManaged in Compile).value
527527
}
528528
val externalDeps = externalCompilerClasspathTask.value
529+
val externalJSDeps = (externalDependencyClasspath in (LocalProject("dotty-library-bootstrappedJS"), Compile)).value
529530
val jars = packageAll.value
530531

531532
Seq(
532533
"-Ddotty.tests.dottyCompilerManagedSources=" + managedSrcDir,
533534
"-Ddotty.tests.classes.dottyInterfaces=" + jars("dotty-interfaces"),
534535
"-Ddotty.tests.classes.dottyLibrary=" + jars("dotty-library"),
536+
"-Ddotty.tests.classes.dottyLibraryJS=" + jars("dotty-library-js"),
535537
"-Ddotty.tests.classes.dottyCompiler=" + jars("dotty-compiler"),
536538
"-Ddotty.tests.classes.tastyCore=" + jars("tasty-core"),
537539
"-Ddotty.tests.classes.compilerInterface=" + findArtifactPath(externalDeps, "compiler-interface"),
538540
"-Ddotty.tests.classes.scalaLibrary=" + findArtifactPath(externalDeps, "scala-library"),
539541
"-Ddotty.tests.classes.scalaAsm=" + findArtifactPath(externalDeps, "scala-asm"),
540542
"-Ddotty.tests.classes.jlineTerminal=" + findArtifactPath(externalDeps, "jline-terminal"),
541543
"-Ddotty.tests.classes.jlineReader=" + findArtifactPath(externalDeps, "jline-reader"),
544+
"-Ddotty.tests.classes.scalaJSLibrary=" + findArtifactPath(externalJSDeps, "scalajs-library_2.13"),
542545
)
543546
},
544547

@@ -705,7 +708,8 @@ object Build {
705708
// running the compiler, we should always have the bootstrapped
706709
// library on the compiler classpath since the non-bootstrapped one
707710
// may not be binary-compatible.
708-
"dotty-library" -> packageBin.in(`dotty-library-bootstrapped`, Compile).value
711+
"dotty-library" -> packageBin.in(`dotty-library-bootstrapped`, Compile).value,
712+
"dotty-library-js" -> packageBin.in(`dotty-library-bootstrappedJS`, Compile).value,
709713
).mapValues(_.getAbsolutePath)
710714
}
711715
}.value,
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
import scala.reflect.{ClassTag, Selectable => ReflectSel}
2+
import ReflectSel.reflectiveSelectable
3+
4+
object Test {
5+
/* Make sure that an explicit desugaring of the legit cases actually compiles,
6+
* ensuring that the error cases we test are actually testing the right things.
7+
*/
8+
def sanityCheck(): Unit = {
9+
val receiver: Any = ???
10+
reflectiveSelectable(receiver).selectDynamic("foo") // OK
11+
reflectiveSelectable(receiver).applyDynamic("foo")() // OK
12+
reflectiveSelectable(receiver).applyDynamic("foo", ClassTag(classOf[String]), ClassTag(classOf[List[_]]))("bar", Nil) // OK
13+
}
14+
15+
def badReceider(): Unit = {
16+
val receiver: ReflectSel = ???
17+
receiver.selectDynamic("foo") // error
18+
receiver.applyDynamic("foo")() // error
19+
}
20+
21+
def nonLiteralMethodName(): Unit = {
22+
val receiver: Any = ???
23+
val methodName: String = "foo"
24+
reflectiveSelectable(receiver).selectDynamic(methodName) // error
25+
reflectiveSelectable(receiver).applyDynamic(methodName)() // error
26+
}
27+
28+
def nonLiteralClassTag(): Unit = {
29+
val receiver: Any = ???
30+
val myClassTag: ClassTag[String] = ClassTag(classOf[String])
31+
reflectiveSelectable(receiver).applyDynamic("foo", myClassTag, ClassTag(classOf[List[_]]))("bar", Nil) // error
32+
}
33+
34+
def classTagVarArgs(): Unit = {
35+
val receiver: Any = ???
36+
val classTags: List[ClassTag[_]] = List(ClassTag(classOf[String]), ClassTag(classOf[List[_]]))
37+
reflectiveSelectable(receiver).applyDynamic("foo", classTags: _*)("bar", Nil) // error
38+
}
39+
40+
def argsVarArgs(): Unit = {
41+
val receiver: Any = ???
42+
val args: List[Any] = List("bar", Nil)
43+
reflectiveSelectable(receiver).applyDynamic("foo", ClassTag(classOf[String]), ClassTag(classOf[List[_]]))(args: _*) // error
44+
}
45+
}

0 commit comments

Comments
 (0)