diff --git a/compiler/src/dotty/tools/dotc/ast/MainProxies.scala b/compiler/src/dotty/tools/dotc/ast/MainProxies.scala index 8d5cd8d5d689..8024393414b8 100644 --- a/compiler/src/dotty/tools/dotc/ast/MainProxies.scala +++ b/compiler/src/dotty/tools/dotc/ast/MainProxies.scala @@ -4,13 +4,14 @@ package ast import core.* import Symbols.*, Types.*, Contexts.*, Decorators.*, util.Spans.*, Flags.*, Constants.* import StdNames.{nme, tpnme} -import ast.Trees.* +import reporting.Message import Names.Name import Comments.Comment import NameKinds.DefaultGetterName import Annotations.Annotation +import untpd.* -object MainProxies { +object MainProxies: /** Generate proxy classes for @main functions. * A function like @@ -30,66 +31,55 @@ object MainProxies { * catch case err: ParseError => showError(err) * } */ - def proxies(stats: List[tpd.Tree])(using Context): List[untpd.Tree] = { + def proxies(stats: List[tpd.Tree])(using Context): List[untpd.Tree] = import tpd.* - def mainMethods(stats: List[Tree]): List[Symbol] = stats.flatMap { + def mainMethods(stats: List[Tree]): List[Symbol] = stats.flatMap: case stat: DefDef if stat.symbol.hasAnnotation(defn.MainAnnot) => stat.symbol :: Nil case stat @ TypeDef(name, impl: Template) if stat.symbol.is(Module) => mainMethods(impl.body) case _ => Nil - } mainMethods(stats).flatMap(mainProxy) - } - import untpd.* - private def mainProxy(mainFun: Symbol)(using Context): List[TypeDef] = { + private def mainProxy(mainFun: Symbol)(using Context): List[TypeDef] = + def error(msg: Message) = report.error(msg, mainFun.sourcePos) val mainAnnotSpan = mainFun.getAnnotation(defn.MainAnnot).get.tree.span - def pos = mainFun.sourcePos val argsRef = Ident(nme.args) def addArgs(call: untpd.Tree, mt: MethodType, idx: Int): untpd.Tree = - if (mt.isImplicitMethod) { - report.error(em"@main method cannot have implicit parameters", pos) + val args = mt.paramInfos.zipWithIndex.map: (formal, n) => + val (parserSym, formalElem) = + if formal.isRepeatedParam then (defn.CLP_parseRemainingArguments, formal.argTypes.head) + else (defn.CLP_parseArgument, formal) + val arg = Apply( + TypeApply(ref(parserSym.termRef), TypeTree(formalElem) :: Nil), + argsRef :: Literal(Constant(idx + n)) :: Nil) + if formal.isRepeatedParam then repeated(arg) else arg + mt.resType match + case _ if mt.isImplicitMethod => + error(em"@main method cannot have implicit parameters") call - } - else { - val args = mt.paramInfos.zipWithIndex map { - (formal, n) => - val (parserSym, formalElem) = - if (formal.isRepeatedParam) (defn.CLP_parseRemainingArguments, formal.argTypes.head) - else (defn.CLP_parseArgument, formal) - val arg = Apply( - TypeApply(ref(parserSym.termRef), TypeTree(formalElem) :: Nil), - argsRef :: Literal(Constant(idx + n)) :: Nil) - if (formal.isRepeatedParam) repeated(arg) else arg - } - val call1 = Apply(call, args) - mt.resType match { - case restpe: MethodType => - if (mt.paramInfos.lastOption.getOrElse(NoType).isRepeatedParam) - report.error(em"varargs parameter of @main method must come last", pos) - addArgs(call1, restpe, idx + args.length) - case _ => - call1 - } - } + case restpe: MethodType => + if mt.paramInfos.lastOption.getOrElse(NoType).isRepeatedParam then + error(em"varargs parameter of @main method must come last") + addArgs(Apply(call, args), restpe, idx + args.length) + case _ => + Apply(call, args) + + var call = ref(mainFun.termRef) + mainFun.info match + case _ if !mainFun.owner.isStaticOwner => + error(em"@main method is not statically accessible") + case _: ExprType => + case mt: MethodType => + call = addArgs(call, mt, 0) + case _: PolyType => + error(em"@main method cannot have type parameters") + case _ => + error(em"@main can only annotate a method") - var result: List[TypeDef] = Nil - if (!mainFun.owner.isStaticOwner) - report.error(em"@main method is not statically accessible", pos) - else { - var call = ref(mainFun.termRef) - mainFun.info match { - case _: ExprType => - case mt: MethodType => - call = addArgs(call, mt, 0) - case _: PolyType => - report.error(em"@main method cannot have type parameters", pos) - case _ => - report.error(em"@main can only annotate a method", pos) - } + if !ctx.reporter.hasErrors then val errVar = Ident(nme.error) val handler = CaseDef( Typed(errVar, TypeTree(defn.CLP_ParseError.typeRef)), @@ -115,11 +105,6 @@ object MainProxies { val mainTempl = Template(emptyConstructor, Nil, Nil, EmptyValDef, mainMeth :: Nil) val mainCls = TypeDef(mainFun.name.toTypeName, mainTempl) .withFlags(Final | Invisible) - - if (!ctx.reporter.hasErrors) - result = mainCls.withSpan(mainAnnotSpan.toSynthetic) :: Nil - } - result - } - -} + mainCls.withSpan(mainAnnotSpan.toSynthetic) :: Nil + else Nil + end mainProxy diff --git a/compiler/test/dotty/tools/dotc/CompilationTests.scala b/compiler/test/dotty/tools/dotc/CompilationTests.scala index 74ff53b9ebf3..a4223d201f80 100644 --- a/compiler/test/dotty/tools/dotc/CompilationTests.scala +++ b/compiler/test/dotty/tools/dotc/CompilationTests.scala @@ -274,9 +274,14 @@ class CompilationTests { // Set -sourceroot such that the source code cannot be found by the compiler val libOptions = tastSourceOptions.and("-sourceroot", "tests/init-global/special") - val lib = compileFile("tests/init-global/special/tastySource/A.scala", libOptions)(group).keepOutput.checkCompile() - - compileFile("tests/init-global/special/tastySource/B.scala", tastSourceOptions.withClasspath(outDirLib))(group).checkWarnings() + val lib = compileFile("tests/init-global/special/tastySource/A.scala", libOptions) + (using group) + .keepOutput + .checkCompile() + + compileFile("tests/init-global/special/tastySource/B.scala", tastSourceOptions.withClasspath(outDirLib)) + (using group) + .checkWarnings() lib.delete() } diff --git a/compiler/test/dotty/tools/vulpix/ChildJVMMain.java b/compiler/test/dotty/tools/vulpix/ChildJVMMain.java deleted file mode 100644 index a6873ead1968..000000000000 --- a/compiler/test/dotty/tools/vulpix/ChildJVMMain.java +++ /dev/null @@ -1,51 +0,0 @@ -package dotty.tools.vulpix; - -import java.io.File; -import java.io.InputStreamReader; -import java.io.BufferedReader; -import java.net.URL; -import java.net.URLClassLoader; -import java.util.ArrayList; -import java.lang.reflect.Method; - -public class ChildJVMMain { - static final String MessageStart = "##THIS IS THE START FOR ME, HELLO##"; - static final String MessageEnd = "##THIS IS THE END FOR ME, GOODBYE##"; - - private static void runMain(String dir) throws Exception { - Method meth = null; - Object[] args = new Object[]{ new String[]{ } }; - try { - String jcp = System.getProperty("java.class.path"); - String sep = File.pathSeparator; - System.setProperty("java.class.path", jcp == null ? dir : dir + sep + jcp); - - ArrayList cp = new ArrayList<>(); - for (String path : dir.split(sep)) - cp.add(new File(path).toURI().toURL()); - - URLClassLoader ucl = new URLClassLoader(cp.toArray(new URL[cp.size()])); - - Class cls = ucl.loadClass("Test"); - meth = cls.getMethod("main", String[].class); - } - catch (Throwable e) { - // Include the failure stack trace to the test output - System.out.println(MessageStart); - e.printStackTrace(); - throw e; - } - System.out.println(MessageStart); - - meth.invoke(null, args); - } - - public static void main(String[] args) throws Exception { - BufferedReader stdin = new BufferedReader(new InputStreamReader(System.in)); - - while (true) { - runMain(stdin.readLine()); - System.out.println(MessageEnd); - } - } -} diff --git a/compiler/test/dotty/tools/vulpix/ChildJVMMain.scala b/compiler/test/dotty/tools/vulpix/ChildJVMMain.scala new file mode 100644 index 000000000000..f92985f00865 --- /dev/null +++ b/compiler/test/dotty/tools/vulpix/ChildJVMMain.scala @@ -0,0 +1,52 @@ +package dotty.tools.vulpix + +import java.io.{BufferedReader, File, InputStreamReader} +import java.net.{URL, URLClassLoader} +import java.util.ArrayList + +object ChildJVMMain: + val MessageStart = "##THIS IS THE START FOR ME, HELLO##" + val MessageEnd = "##THIS IS THE END FOR ME, GOODBYE##" + + def runMain(dir: String): Unit = + def meth = + val jcp = System.getProperty("java.class.path") + val sep = File.pathSeparator + System.setProperty("java.class.path", if jcp == null then dir else dir + sep + jcp) + + val loader = + val cp = ArrayList[URL]() + val paths = dir.split(sep) + for path <- paths do + cp.add(File(path).toURI().toURL()) + val urls = cp.toArray(Array.ofDim[URL](cp.size)) + URLClassLoader(urls) + + val cls = loader.loadClass("Test") + cls.getMethod("main", classOf[Array[String]]) + end meth + val m = + try meth + catch t => + // Include the failure stack trace to the test output + System.out.println(MessageStart) + t.printStackTrace() + throw t + System.out.println(MessageStart) + m.invoke(null, Array.empty[String]) + + def main(args: Array[String]): Unit = + inline def savingSystem[T](inline body: => T): T = + val savedIn = System.in + val savedOut = System.out + val savedErr = System.err + try body + finally + System.setIn(savedIn) + System.setOut(savedOut) + System.setErr(savedErr) + val stdin = BufferedReader(InputStreamReader(System.in)) + while true do + savingSystem: + runMain(stdin.readLine()) + println(MessageEnd) diff --git a/compiler/test/dotty/tools/vulpix/ParallelTesting.scala b/compiler/test/dotty/tools/vulpix/ParallelTesting.scala index 3a2f261a8e16..f56fecb38d26 100644 --- a/compiler/test/dotty/tools/vulpix/ParallelTesting.scala +++ b/compiler/test/dotty/tools/vulpix/ParallelTesting.scala @@ -43,6 +43,7 @@ import dotty.tools.vulpix.TestConfiguration.defaultOptions */ trait ParallelTesting extends RunnerOrchestration: import ParallelTesting.* + export Status.{Failure, Success, Timeout} /** If the running environment supports an interactive terminal, each `Test` * will be run with a progress bar and real time feedback @@ -909,25 +910,24 @@ trait ParallelTesting extends RunnerOrchestration: } } - private def verifyOutput(checkFile: Option[JFile], dir: JFile, testSource: TestSource, warnings: Int, reporters: Seq[TestReporter], logger: LoggedRunnable) = { + private def verifyOutput(checkFile: Option[JFile], dir: JFile, testSource: TestSource, warnings: Int, reporters: Seq[TestReporter], logger: LoggedRunnable) = + import testSource.{allToolArgs, runClassPath, title} if Properties.testsNoRun then addNoRunWarning() - else runMain(testSource.runClassPath, testSource.allToolArgs) match { - case Success(output) => checkFile match { - case Some(file) if file.exists => diffTest(testSource, file, output.linesIterator.toList, reporters, logger) - case _ => - } + else + runMain(runClassPath, allToolArgs) match + case Success(output) => + for file <- checkFile if file.exists do + diffTest(testSource, file, output.linesIterator.toList, reporters, logger) + case Failure("") => + echo(s"Test '$title' failed with no output") + failTestSource(testSource) case Failure(output) => - if output == "" then - echo(s"Test '${testSource.title}' failed with no output") - else - echo(s"Test '${testSource.title}' failed with output:") - echo(output) + echo(s"Test '$title' failed with output:") + echo(output) failTestSource(testSource) case Timeout => - echo("failed because test " + testSource.title + " timed out") - failTestSource(testSource, TimeoutFailure(testSource.title)) - } - } + echo(s"failed because test '$title' timed out") + failTestSource(testSource, TimeoutFailure(title)) override def onSuccess(testSource: TestSource, reporters: Seq[TestReporter], logger: LoggedRunnable) = verifyOutput(testSource.checkFile, testSource.outDir, testSource, countWarnings(reporters), reporters, logger) @@ -1292,21 +1292,19 @@ trait ParallelTesting extends RunnerOrchestration: this } - /** Extract `Failure` set and render from `Test` */ - private def reasonsForFailure(test: Test): String = { - val failureReport = - if test.failureCount == 0 then "" - else s"encountered ${test.failureCount} test failure(s):\n" - - failureReport + test.failureReasons.collect { - case test.TimeoutFailure(title) => - s" - test '$title' timed out" - case test.JavaCompilationFailure(msg) => - s" - java compilation failed with:\n${ msg.linesIterator.map(" " + _).mkString("\n") }" - case test.Generic => - " - generic failure (see test output)" - }.mkString("\n") - } + /** Extracts `Failure` set and renders from `Test`. */ + private def reasonsForFailure(test: Test): String = + if test.failureCount == 0 then "" + else + test.failureReasons.collect: + case test.TimeoutFailure(title) => + s" - test '$title' timed out" + case test.JavaCompilationFailure(msg) => + val header = " - java compilation failed with:\n" + msg.linesIterator.map(" " + _).mkString(header, "\n", "") + case test.Generic => + " - generic failure (see test output)" + .mkString(s"encountered ${test.failureCount} test failure(s):\n", "\n", "") /** Copies `file` to `dir` - taking into account if `file` is a directory, * and if so copying recursively diff --git a/compiler/test/dotty/tools/vulpix/RunnerOrchestration.scala b/compiler/test/dotty/tools/vulpix/RunnerOrchestration.scala index df4d692175f9..88061c091241 100644 --- a/compiler/test/dotty/tools/vulpix/RunnerOrchestration.scala +++ b/compiler/test/dotty/tools/vulpix/RunnerOrchestration.scala @@ -2,19 +2,18 @@ package dotty package tools package vulpix -import scala.language.unsafeNulls - -import java.io.{ File => JFile, InputStreamReader, IOException, BufferedReader, PrintStream } +import java.io.{File as JFile, InputStreamReader, IOException, BufferedReader, PrintStream} import java.nio.file.Paths -import java.nio.charset.StandardCharsets -import java.util.concurrent.atomic.AtomicBoolean +import java.nio.charset.StandardCharsets.UTF_8 import java.util.concurrent.TimeoutException import scala.concurrent.duration.Duration -import scala.concurrent.{ Await, Future } +import scala.concurrent.{Await, Future} import scala.concurrent.ExecutionContext.Implicits.global import scala.collection.mutable -import scala.compiletime.uninitialized + +import ChildJVMMain.{MessageEnd, MessageStart} +import Status.* /** Vulpix spawns JVM subprocesses (`numberOfWorkers`) in order to run tests * without compromising the main JVM @@ -35,7 +34,7 @@ import scala.compiletime.uninitialized * If this whole chain of events is not completed within `maxDuration`, the * child process is destroyed and a new child is spawned. */ -trait RunnerOrchestration { +trait RunnerOrchestration: /** The maximum amount of active runners, which contain a child JVM */ def numberOfWorkers: Int @@ -51,10 +50,6 @@ trait RunnerOrchestration { /** Open JDI connection for testing the debugger */ def debugMode: Boolean = false - /** Running a `Test` class's main method from the specified `classpath` */ - def runMain(classPath: String, toolArgs: ToolArgs)(implicit summaryReport: SummaryReporting): Status = - monitor.runMain(classPath) - /** Each method of Debuggee can be called only once, in the order of definition.*/ trait Debuggee: /** read the jdi port to connect the debugger */ @@ -64,17 +59,13 @@ trait RunnerOrchestration { /** wait until the end of the main method */ def exit(): Status - /** Provide a Debuggee for debugging the Test class's main method - * @param f the debugging flow: set breakpoints, launch main class, pause, step, evaluate, exit etc - */ - def debugMain(classPath: String)(f: Debuggee => Unit)(implicit summaryReport: SummaryReporting): Unit = - assert(debugMode, "debugMode is disabled") - monitor.debugMain(classPath)(f) - /** Kill all processes */ def cleanup() = monitor.killAll() private val monitor = new RunnerMonitor + export monitor.{debugMain/*, runMain*/} + def runMain(classPath: String, toolArgs: ToolArgs)(using SummaryReporting): Status = + monitor.runMain(classPath, toolArgs) // scala-js overrides and requires toolArgs /** The runner monitor object keeps track of child JVM processes by keeping * them in two structures - one for free, and one for busy children. @@ -84,121 +75,111 @@ trait RunnerOrchestration { * cleanup by returning the used JVM to the free list, or respawning it if * it died */ - private class RunnerMonitor { + private class RunnerMonitor: - def runMain(classPath: String)(implicit summaryReport: SummaryReporting): Status = + /** Runs a `Test` class's main method from the specified `classpath`. */ + def runMain(classPath: String, toolArgs: ToolArgs)(using SummaryReporting): Status = withRunner(_.runMain(classPath)) - def debugMain(classPath: String)(f: Debuggee => Unit)(implicit summaryReport: SummaryReporting): Unit = + /** Provide a Debuggee for debugging the Test class's main method. + * @param f the debugging flow: set breakpoints, launch main class, pause, step, evaluate, exit etc + */ + def debugMain(classPath: String)(f: Debuggee => Unit)(using SummaryReporting): Unit = withRunner(_.debugMain(classPath)(f)) private class RunnerProcess(p: Process): - private val stdout = new BufferedReader(new InputStreamReader(p.getInputStream(), StandardCharsets.UTF_8)) - private val stdin = new PrintStream(p.getOutputStream(), /* autoFlush = */ true) + private val stdout = BufferedReader(InputStreamReader(p.getInputStream(), UTF_8)) + private val stdin = PrintStream(p.getOutputStream(), /* autoFlush = */ true) def readLine(): String = stdout.readLine() match - case s"Listening for transport dt_socket at address: $port" => - throw new IOException( - s"Unexpected transport dt_socket message." + - " The port is going to be lost and no debugger will be able to connect." - ) - case line => line + case s"Listening for transport dt_socket at address: $port" => + throw IOException( + "Unexpected transport dt_socket message." + + " The port is going to be lost and no debugger will be able to connect." + ) + case line => line def printLine(line: String): Unit = stdin.println(line) def getJdiPort(): Int = stdout.readLine() match - case s"Listening for transport dt_socket at address: $port" => port.toInt - case line => throw new IOException(s"Failed getting JDI port of child JVM: got $line") + case s"Listening for transport dt_socket at address: $port" => port.toInt + case line => throw IOException(s"Failed getting JDI port of child JVM: got $line") + + def isAlive: Boolean = p.isAlive // export p.isAlive sans parens - export p.{exitValue, isAlive, destroy} + export p.{exitValue, destroy} end RunnerProcess - private class Runner(private var process: RunnerProcess): - /** Checks if `process` is still alive - * - * When `process.exitValue()` is called on an active process the caught - * exception is thrown. As such we can know if the subprocess exited or - * not. - */ - def isAlive: Boolean = - try { process.exitValue(); false } - catch case _: IllegalThreadStateException => true - - /** Destroys the underlying process and kills IO streams */ - def kill(): Unit = - if (process ne null) process.destroy() - process = null - - /** Blocks less than `maxDuration` while running `Test.main` from `dir` */ - def runMain(classPath: String): Status = - assert(process ne null, "Runner was killed and then reused without setting a new process") - awaitStatusOrRespawn(startMain(classPath)) - - def debugMain(classPath: String)(f: Debuggee => Unit): Unit = - assert(process ne null, "Runner was killed and then reused without setting a new process") + private class Runner(process: RunnerProcess): + /** Checks whether the underlying process is still alive. */ + def isAlive: Boolean = process.isAlive + + /** Destroys the underlying process and kills IO streams. */ + def kill(): Unit = process.destroy() + /** Blocks less than `maxDuration` while running `Test.main` from `dir`. */ + def runMain(classPath: String): Status = awaitStatus(startMain(classPath)) + + def debugMain(classPath: String)(f: Debuggee => Unit): Status = val debuggee = new Debuggee: - private var mainFuture: Future[Status] = null + private var mainFuture: Future[Status] | Null = null def readJdiPort(): Int = process.getJdiPort() def launch(): Unit = mainFuture = startMain(classPath) - def exit(): Status = - awaitStatusOrRespawn(mainFuture) - - try f(debuggee) - catch case e: Throwable => - // if debugging failed it is safer to respawn a new process - respawn() - throw e + def exit(): Status = awaitStatus(mainFuture.nn) + + try + f(debuggee) + debuggee.exit() + catch case e: Throwable => Failure("Bad debug") end debugMain private def startMain(classPath: String): Future[Status] = // pass classpath to running process process.printLine(classPath) - // Create a future reading the object: - Future: - val sb = new StringBuilder - - var childOutput: String = process.readLine() - - // Discard all messages until the test starts - while (childOutput != ChildJVMMain.MessageStart && childOutput != null) - childOutput = process.readLine() - childOutput = process.readLine() - - while childOutput != ChildJVMMain.MessageEnd && childOutput != null do - sb.append(childOutput).append(System.lineSeparator) - childOutput = process.readLine() - - if process.isAlive() && childOutput != null then Success(sb.toString) - else Failure(sb.toString) + def readChildOutput = + val sb = StringBuilder() + var ok = false + while + val line = process.readLine() + line != null && { + ok = line == MessageStart + !ok + } + do () // Discard all messages until the test starts + + if ok then + ok = false + var childOutput: String | Null = null + while + childOutput = process.readLine() + childOutput != null && { + ok = childOutput == MessageEnd + !ok + } + do // Collect all messages until the test ends + sb.append(childOutput).append(System.lineSeparator) + + if ok && isAlive then + Success(sb.toString) + else + Failure(sb.toString) + Future(readChildOutput) end startMain - // wait status of the main class execution, respawn if failure or timeout - private def awaitStatusOrRespawn(future: Future[Status]): Status = - val status = - try Await.result(future, maxDuration) - catch case _: TimeoutException => Timeout - // handle failures - status match - case _: Success if !safeMode => () // no need to respawn - case _ => respawn() // safeMode, failure or timeout - status - - // Makes the encapsulating RunnerMonitor spawn a new runner - private def respawn(): Unit = - process.destroy() - process = null - process = createProcess() + // wait status of the main class execution + private def awaitStatus(future: Future[Status]): Status = + try Await.result(future, maxDuration) + catch case _: TimeoutException => Timeout end Runner /** Create a process which has the classpath of the `ChildJVMMain` and the * scala library. */ private def createProcess(): RunnerProcess = - val url = classOf[ChildJVMMain].getProtectionDomain.getCodeSource.getLocation + val url = classOf[ChildJVMMain.type].getProtectionDomain.getCodeSource.getLocation val cp = Paths.get(url.toURI).toString + JFile.pathSeparator + Properties.scalaLibrary val javaBin = Paths.get(sys.props("java.home"), "bin", "java").toString val args = Seq("-Dfile.encoding=UTF-8", "-Duser.language=en", "-Duser.country=US", "-Xmx1g", "-cp", cp) ++ @@ -215,10 +196,11 @@ trait RunnerOrchestration { private val busyRunners = mutable.Set.empty[Runner] private def getRunner(): Runner = synchronized { - while (freeRunners.isEmpty && busyRunners.size >= numberOfWorkers) wait() + while freeRunners.isEmpty && busyRunners.size >= numberOfWorkers + do wait() val runner = - if (freeRunners.isEmpty) new Runner(createProcess()) + if freeRunners.isEmpty then Runner(createProcess()) else freeRunners.dequeue() busyRunners += runner @@ -232,18 +214,23 @@ trait RunnerOrchestration { notify() } - private def withRunner[T](op: Runner => T)(using summaryReport: SummaryReporting): T = - val runner = getRunner() - val result = op(runner) - freeRunner(runner) - result + private def discardRunner(runner: Runner): Unit = synchronized { + busyRunners -= runner + } - def killAll(): Unit = { + private def withRunner(op: Runner => Status)(using SummaryReporting): Status = + val runner = getRunner() + val status = op(runner) + if safeMode || !status.isSuccess then + discardRunner(runner) + else + freeRunner(runner) + status + + def killAll(): Unit = freeRunners.foreach(_.kill()) busyRunners.foreach(_.kill()) - } // On shutdown, we need to kill all runners: sys.addShutdownHook(killAll()) - } -} + end RunnerMonitor diff --git a/compiler/test/dotty/tools/vulpix/Status.scala b/compiler/test/dotty/tools/vulpix/Status.scala index 5503bb394aa4..a8eb595721a5 100644 --- a/compiler/test/dotty/tools/vulpix/Status.scala +++ b/compiler/test/dotty/tools/vulpix/Status.scala @@ -1,7 +1,9 @@ package dotty.tools package vulpix -sealed trait Status -final case class Success(output: String) extends Status -final case class Failure(output: String) extends Status -case object Timeout extends Status +enum Status: + case Success(output: String) + case Failure(output: String) + case Timeout + + def isSuccess: Boolean = this.isInstanceOf[Success] diff --git a/sjs-compiler-tests/test/scala/dotty/tools/dotc/JSRun.scala b/sjs-compiler-tests/test/scala/dotty/tools/dotc/JSRun.scala index c3a80074afe6..ca12eabd642a 100644 --- a/sjs-compiler-tests/test/scala/dotty/tools/dotc/JSRun.scala +++ b/sjs-compiler-tests/test/scala/dotty/tools/dotc/JSRun.scala @@ -7,7 +7,7 @@ import java.io.InputStream import java.nio.charset.StandardCharsets import java.nio.file.Path -import dotty.tools.vulpix.* +import dotty.tools.vulpix.*, Status.{Failure, Success} import org.scalajs.jsenv.* import org.scalajs.jsenv.nodejs.NodeJSEnv diff --git a/tests/disabled/i23245a/test_2.scala b/tests/disabled/i23245a/test_2.scala deleted file mode 100644 index faf0960c29cb..000000000000 --- a/tests/disabled/i23245a/test_2.scala +++ /dev/null @@ -1,6 +0,0 @@ - - -object Test extends logadapter.Api.SelfLogging: - def main(args: Array[String]): Unit = - summon[logadapter.LogAdapter].info("Hello") - diff --git a/tests/disabled/i23245a/api.scala b/tests/run/i23245a/api.scala similarity index 100% rename from tests/disabled/i23245a/api.scala rename to tests/run/i23245a/api.scala diff --git a/tests/run/i23245a/test_2.scala b/tests/run/i23245a/test_2.scala new file mode 100644 index 000000000000..c04ae43058b0 --- /dev/null +++ b/tests/run/i23245a/test_2.scala @@ -0,0 +1,4 @@ +object Test extends logadapter.Api.SelfLogging: + def main(args: Array[String]): Unit = + try summon[logadapter.LogAdapter].info("Hello") + catch t => t.printStackTrace(System.out) diff --git a/tests/run/i23245d/BaseTest_1.scala b/tests/run/i23245d/BaseTest_1.scala new file mode 100644 index 000000000000..4a23904cb4eb --- /dev/null +++ b/tests/run/i23245d/BaseTest_1.scala @@ -0,0 +1,13 @@ +abstract class BaseTest { + def genName(): String = "outerAccess" + trait Fixture { + lazy val service: Service = new Service { + val a = genName() + def doIt(a: String): Int = 0 + } + } +} + +trait Service { + def doIt(a: String): Int +} diff --git a/tests/run/i23245d/Test_2.scala b/tests/run/i23245d/Test_2.scala new file mode 100644 index 000000000000..9169e6668433 --- /dev/null +++ b/tests/run/i23245d/Test_2.scala @@ -0,0 +1,4 @@ +object Test extends BaseTest { + def main(args: Array[String]): Unit = + new Fixture { service.doIt("test") } +} diff --git a/tests/run/2772.scala b/tests/run/i2772.scala similarity index 83% rename from tests/run/2772.scala rename to tests/run/i2772.scala index fcde4c363b35..39c6b93489e6 100644 --- a/tests/run/2772.scala +++ b/tests/run/i2772.scala @@ -1,5 +1,6 @@ import java.io.OutputStream +// System.err is ostensibly final but cannot be inlined object Test { def main(args: Array[String]): Unit = { val oldErr = System.err diff --git a/tests/vulpix-tests/unit/timeout.scala b/tests/vulpix-tests/unit/timeout.scala index ce9c9a6693d6..e1b850d814f1 100644 --- a/tests/vulpix-tests/unit/timeout.scala +++ b/tests/vulpix-tests/unit/timeout.scala @@ -1,5 +1 @@ -object Test { - def main(args: Array[String]): Unit = { - Thread.sleep(10 * 1000) - } -} +@main def Test = Thread.sleep(1000 * 1000)