diff --git a/compiler/src/dotty/tools/dotc/CompilationUnit.scala b/compiler/src/dotty/tools/dotc/CompilationUnit.scala index 9b12cc9ade94..3c73b1126889 100644 --- a/compiler/src/dotty/tools/dotc/CompilationUnit.scala +++ b/compiler/src/dotty/tools/dotc/CompilationUnit.scala @@ -122,7 +122,7 @@ object CompilationUnit { NoSource } else if (!source.file.exists) { - report.error(s"not found: ${source.file.path}") + report.error(s"source file not found: ${source.file.path}") NoSource } else source diff --git a/compiler/src/dotty/tools/repl/ParseResult.scala b/compiler/src/dotty/tools/repl/ParseResult.scala index bc0305c17944..5d414ecf9b34 100644 --- a/compiler/src/dotty/tools/repl/ParseResult.scala +++ b/compiler/src/dotty/tools/repl/ParseResult.scala @@ -88,7 +88,8 @@ object Settings { /** Reset the session to the initial state from when the repl program was * started */ -case object Reset extends Command { +case class Reset(arg: String) extends Command +object Reset { val command: String = ":reset" } @@ -110,7 +111,7 @@ case object Help extends Command { |:type evaluate the type of the given expression |:doc print the documentation for the given expression |:imports show import history - |:reset reset the repl to its initial state, forgetting all session entries + |:reset [options] reset the repl to its initial state, forgetting all session entries |:settings update compiler options, if possible """.stripMargin } @@ -130,7 +131,7 @@ object ParseResult { Quit.command -> (_ => Quit), Quit.alias -> (_ => Quit), Help.command -> (_ => Help), - Reset.command -> (_ => Reset), + Reset.command -> (arg => Reset(arg)), Imports.command -> (_ => Imports), Load.command -> (arg => Load(arg)), TypeOf.command -> (arg => TypeOf(arg)), diff --git a/compiler/src/dotty/tools/repl/ReplDriver.scala b/compiler/src/dotty/tools/repl/ReplDriver.scala index ceeceb12f669..eda69b7c1ed7 100644 --- a/compiler/src/dotty/tools/repl/ReplDriver.scala +++ b/compiler/src/dotty/tools/repl/ReplDriver.scala @@ -70,15 +70,21 @@ class ReplDriver(settings: Array[String], override def sourcesRequired: Boolean = false /** Create a fresh and initialized context with IDE mode enabled */ - private def initialCtx = { + private def initialCtx(settings: List[String]) = { val rootCtx = initCtx.fresh.addMode(Mode.ReadPositions | Mode.Interactive) rootCtx.setSetting(rootCtx.settings.YcookComments, true) rootCtx.setSetting(rootCtx.settings.YreadComments, true) + setupRootCtx(this.settings ++ settings, rootCtx) + } + + private def setupRootCtx(settings: Array[String], rootCtx: Context) = { setup(settings, rootCtx) match - case Some((files, ictx)) => + case Some((files, ictx)) => inContext(ictx) { shouldStart = true - ictx.base.initialize()(using ictx) + if files.nonEmpty then out.println(i"Ignoring spurious arguments: $files%, %") + ictx.base.initialize() ictx + } case None => shouldStart = false rootCtx @@ -93,8 +99,8 @@ class ReplDriver(settings: Array[String], * such, when the user enters `:reset` this method should be called to reset * everything properly */ - protected def resetToInitial(): Unit = { - rootCtx = initialCtx + protected def resetToInitial(settings: List[String] = Nil): Unit = { + rootCtx = initialCtx(settings) if (rootCtx.settings.outputDir.isDefault(using rootCtx)) rootCtx = rootCtx.fresh .setSetting(rootCtx.settings.outputDir, new VirtualDirectory("")) @@ -372,8 +378,8 @@ class ReplDriver(settings: Array[String], out.println(Help.text) state - case Reset => - resetToInitial() + case Reset(arg) => + resetToInitial(tokenize(arg)) initialState case Imports => @@ -423,14 +429,7 @@ class ReplDriver(settings: Array[String], out.println(s"${s.name} = ${if s.value == "" then "\"\"" else s.value}") state case _ => - setup(tokenize(arg).toArray, rootCtx) match - case Some((files, ictx)) => - inContext(ictx) { - if files.nonEmpty then out.println(i"Ignoring spurious arguments: $files%, %") - ictx.base.initialize()(using ictx) - rootCtx = ictx - } - case _ => + rootCtx = setupRootCtx(tokenize(arg).toArray, rootCtx) state.copy(context = rootCtx) case Quit => diff --git a/compiler/test-resources/pending/repl/i13208.scala b/compiler/test-resources/repl/i13208.scala similarity index 72% rename from compiler/test-resources/pending/repl/i13208.scala rename to compiler/test-resources/repl/i13208.scala index d56e997c406e..6401d23bcfe4 100644 --- a/compiler/test-resources/pending/repl/i13208.scala +++ b/compiler/test-resources/repl/i13208.scala @@ -1,11 +1,13 @@ // scalac: -source:future -deprecation scala> type M[X] = X match { case Int => String case _ => Int } --- Deprecation Warning: +1 warning found +-- Deprecation Warning: -------------------------------------------------------- 1 | type M[X] = X match { case Int => String case _ => Int } | ^ | `_` is deprecated for wildcard arguments of types: use `?` instead scala> type N[X] = X match { case List[_] => Int } --- Deprecation Warning: +1 warning found +-- Deprecation Warning: -------------------------------------------------------- 1 | type N[X] = X match { case List[_] => Int } | ^ | `_` is deprecated for wildcard arguments of types: use `?` instead diff --git a/compiler/test-resources/repl/reset-command b/compiler/test-resources/repl/reset-command new file mode 100644 index 000000000000..1f10820534b2 --- /dev/null +++ b/compiler/test-resources/repl/reset-command @@ -0,0 +1,15 @@ +scala> def f(thread: Thread) = thread.stop() +there were 1 deprecation warning(s); re-run with -deprecation for details +def f(thread: Thread): Unit + +scala>:reset -deprecation + +scala> def f(thread: Thread) = thread.stop() +1 warning found +-- Deprecation Warning: -------------------------------------------------------- +1 | def f(thread: Thread) = thread.stop() + | ^^^^^^^^^^^ + |method stop in class Thread is deprecated since : see corresponding Javadoc for more information. +def f(thread: Thread): Unit + +scala> diff --git a/compiler/test/dotty/tools/dotc/transform/PatmatExhaustivityTest.scala b/compiler/test/dotty/tools/dotc/transform/PatmatExhaustivityTest.scala index 7d9c77a439bf..6a9f0c74a56f 100644 --- a/compiler/test/dotty/tools/dotc/transform/PatmatExhaustivityTest.scala +++ b/compiler/test/dotty/tools/dotc/transform/PatmatExhaustivityTest.scala @@ -10,9 +10,8 @@ import reporting.TestReporter import dotty.tools.io.Directory import java.io._ -import java.nio.file.{Files, Path => JPath} +import java.nio.file.{Path => JPath} -import scala.io.Source._ import org.junit.Test class PatmatExhaustivityTest { @@ -79,22 +78,4 @@ class PatmatExhaustivityTest { println(msg) } - - // inspect given files for tool args of the form `tool: args` - // if args string ends in close comment, drop the `*` `/` - // if split, parse the args string as command line. - // (from scala.tools.partest.nest.Runner#toolArgsFor) - private def toolArgsFor(files: List[JPath]): List[String] = { - import scala.jdk.OptionConverters._ - import config.CommandLineParser.tokenize - files.flatMap { path => - val tag = "scalac:" - val endc = "*" + "/" // be forgiving of /* scalac: ... */ - def stripped(s: String) = s.substring(s.indexOf(tag) + tag.length).stripSuffix(endc) - val args = scala.util.Using.resource(Files.lines(path, scala.io.Codec.UTF8.charSet))( - _.limit(10).filter(_.contains(tag)).map(stripped).findAny.toScala - ) - args.map(tokenize).getOrElse(Nil) - } - } } diff --git a/compiler/test/dotty/tools/repl/ReplTest.scala b/compiler/test/dotty/tools/repl/ReplTest.scala index 454fe7fb34f8..5bb6298a937b 100644 --- a/compiler/test/dotty/tools/repl/ReplTest.scala +++ b/compiler/test/dotty/tools/repl/ReplTest.scala @@ -64,11 +64,13 @@ extends ReplDriver(options, new PrintStream(out, true, StandardCharsets.UTF_8.na val expectedOutput = lines.flatMap(filterEmpties) val actualOutput = { - resetToInitial() + val opts = toolArgsParse(lines.take(1)) + val (optsLine, inputLines) = if opts.isEmpty then ("", lines) else (lines.head, lines.drop(1)) + resetToInitial(opts) - assert(lines.head.startsWith(prompt), + assert(inputLines.head.startsWith(prompt), s"""Each script must start with the prompt: "$prompt"""") - val inputRes = lines.filter(_.startsWith(prompt)) + val inputRes = inputLines.filter(_.startsWith(prompt)) val buf = new ArrayBuffer[String] inputRes.foldLeft(initialState) { (state, input) => @@ -76,7 +78,7 @@ extends ReplDriver(options, new PrintStream(out, true, StandardCharsets.UTF_8.na out.linesIterator.foreach(buf.append) nstate } - buf.toList.flatMap(filterEmpties) + (optsLine :: buf.toList).flatMap(filterEmpties) } if !FileDiff.matches(actualOutput, expectedOutput) then diff --git a/compiler/test/dotty/tools/utils.scala b/compiler/test/dotty/tools/utils.scala index 84d295ea0046..868d883b5862 100644 --- a/compiler/test/dotty/tools/utils.scala +++ b/compiler/test/dotty/tools/utils.scala @@ -3,8 +3,9 @@ package tools import java.io.File import java.nio.charset.StandardCharsets.UTF_8 +import java.nio.file.{Files, Path => JPath} -import scala.io.Source +import scala.io.{Codec, Source} import scala.reflect.ClassTag import scala.util.Using.resource import scala.util.chaining.given @@ -25,11 +26,10 @@ extension (f: File) def absPath = extension (str: String) def dropExtension = str.reverse.dropWhile(_ != '.').drop(1).reverse -private def withFile[T](file: File)(action: Source => T): T = - resource(Source.fromFile(file, UTF_8.name))(action) - -def readLines(f: File): List[String] = withFile(f)(_.getLines.toList) -def readFile(f: File): String = withFile(f)(_.mkString) +private +def withFile[T](file: File)(action: Source => T)(using Codec): T = resource(Source.fromFile(file))(action) +def readLines(f: File)(using codec: Codec = Codec.UTF8): List[String] = withFile(f)(_.getLines.toList) +def readFile(f: File)(using codec: Codec = Codec.UTF8): String = withFile(f)(_.mkString) private object Unthrown extends ControlThrowable @@ -43,3 +43,24 @@ def assertThrows[T <: Throwable: ClassTag](p: T => Boolean)(body: => Any): Unit case failed: T => throw AssertionError(s"Exception failed check: $failed").tap(_.addSuppressed(failed)) case NonFatal(other) => throw AssertionError(s"Wrong exception: expected ${implicitly[ClassTag[T]]} but was ${other.getClass.getName}").tap(_.addSuppressed(other)) end assertThrows + +def toolArgsFor(files: List[JPath])(using codec: Codec = Codec.UTF8): List[String] = + files.flatMap(path => toolArgsParse(readLines(path.toFile))) + +// Inspect the first 10 of the given lines for compiler options of the form +// `// scalac: args`, `/* scalac: args`, ` * scalac: args`. +// If args string ends in close comment, drop the `*` `/`. +// If split, parse the args string as a command line. +// (from scala.tools.partest.nest.Runner#toolArgsFor) +def toolArgsParse(lines: List[String]): List[String] = { + val tag = "scalac:" + val endc = "*" + "/" // be forgiving of /* scalac: ... */ + def stripped(s: String) = s.substring(s.indexOf(tag) + tag.length).stripSuffix(endc) + val args = lines.to(LazyList).take(10).filter { s => + s.contains("// " + tag) + || s.contains("/* " + tag) + || s.contains(" * " + tag) + // but avoid picking up comments like "% scalac ./a.scala" and "$ scalac a.scala" + }.map(stripped).headOption + args.map(dotc.config.CommandLineParser.tokenize).getOrElse(Nil) +}