Skip to content

Commit 04946d2

Browse files
Merge pull request #14140 from dwijnand/unpend/repl/i13208
tests: Bring tool args reading to REPL tests
2 parents d7b5353 + 89f0e7f commit 04946d2

File tree

8 files changed

+72
-51
lines changed

8 files changed

+72
-51
lines changed

compiler/src/dotty/tools/dotc/CompilationUnit.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -122,7 +122,7 @@ object CompilationUnit {
122122
NoSource
123123
}
124124
else if (!source.file.exists) {
125-
report.error(s"not found: ${source.file.path}")
125+
report.error(s"source file not found: ${source.file.path}")
126126
NoSource
127127
}
128128
else source

compiler/src/dotty/tools/repl/ParseResult.scala

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,8 @@ object Settings {
8888
/** Reset the session to the initial state from when the repl program was
8989
* started
9090
*/
91-
case object Reset extends Command {
91+
case class Reset(arg: String) extends Command
92+
object Reset {
9293
val command: String = ":reset"
9394
}
9495

@@ -110,7 +111,7 @@ case object Help extends Command {
110111
|:type <expression> evaluate the type of the given expression
111112
|:doc <expression> print the documentation for the given expression
112113
|:imports show import history
113-
|:reset reset the repl to its initial state, forgetting all session entries
114+
|:reset [options] reset the repl to its initial state, forgetting all session entries
114115
|:settings <options> update compiler options, if possible
115116
""".stripMargin
116117
}
@@ -130,7 +131,7 @@ object ParseResult {
130131
Quit.command -> (_ => Quit),
131132
Quit.alias -> (_ => Quit),
132133
Help.command -> (_ => Help),
133-
Reset.command -> (_ => Reset),
134+
Reset.command -> (arg => Reset(arg)),
134135
Imports.command -> (_ => Imports),
135136
Load.command -> (arg => Load(arg)),
136137
TypeOf.command -> (arg => TypeOf(arg)),

compiler/src/dotty/tools/repl/ReplDriver.scala

Lines changed: 14 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -70,15 +70,21 @@ class ReplDriver(settings: Array[String],
7070
override def sourcesRequired: Boolean = false
7171

7272
/** Create a fresh and initialized context with IDE mode enabled */
73-
private def initialCtx = {
73+
private def initialCtx(settings: List[String]) = {
7474
val rootCtx = initCtx.fresh.addMode(Mode.ReadPositions | Mode.Interactive)
7575
rootCtx.setSetting(rootCtx.settings.YcookComments, true)
7676
rootCtx.setSetting(rootCtx.settings.YreadComments, true)
77+
setupRootCtx(this.settings ++ settings, rootCtx)
78+
}
79+
80+
private def setupRootCtx(settings: Array[String], rootCtx: Context) = {
7781
setup(settings, rootCtx) match
78-
case Some((files, ictx)) =>
82+
case Some((files, ictx)) => inContext(ictx) {
7983
shouldStart = true
80-
ictx.base.initialize()(using ictx)
84+
if files.nonEmpty then out.println(i"Ignoring spurious arguments: $files%, %")
85+
ictx.base.initialize()
8186
ictx
87+
}
8288
case None =>
8389
shouldStart = false
8490
rootCtx
@@ -93,8 +99,8 @@ class ReplDriver(settings: Array[String],
9399
* such, when the user enters `:reset` this method should be called to reset
94100
* everything properly
95101
*/
96-
protected def resetToInitial(): Unit = {
97-
rootCtx = initialCtx
102+
protected def resetToInitial(settings: List[String] = Nil): Unit = {
103+
rootCtx = initialCtx(settings)
98104
if (rootCtx.settings.outputDir.isDefault(using rootCtx))
99105
rootCtx = rootCtx.fresh
100106
.setSetting(rootCtx.settings.outputDir, new VirtualDirectory("<REPL compilation output>"))
@@ -372,8 +378,8 @@ class ReplDriver(settings: Array[String],
372378
out.println(Help.text)
373379
state
374380

375-
case Reset =>
376-
resetToInitial()
381+
case Reset(arg) =>
382+
resetToInitial(tokenize(arg))
377383
initialState
378384

379385
case Imports =>
@@ -423,14 +429,7 @@ class ReplDriver(settings: Array[String],
423429
out.println(s"${s.name} = ${if s.value == "" then "\"\"" else s.value}")
424430
state
425431
case _ =>
426-
setup(tokenize(arg).toArray, rootCtx) match
427-
case Some((files, ictx)) =>
428-
inContext(ictx) {
429-
if files.nonEmpty then out.println(i"Ignoring spurious arguments: $files%, %")
430-
ictx.base.initialize()(using ictx)
431-
rootCtx = ictx
432-
}
433-
case _ =>
432+
rootCtx = setupRootCtx(tokenize(arg).toArray, rootCtx)
434433
state.copy(context = rootCtx)
435434

436435
case Quit =>
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,13 @@
11
// scalac: -source:future -deprecation
22
scala> type M[X] = X match { case Int => String case _ => Int }
3-
-- Deprecation Warning:
3+
1 warning found
4+
-- Deprecation Warning: --------------------------------------------------------
45
1 | type M[X] = X match { case Int => String case _ => Int }
56
| ^
67
| `_` is deprecated for wildcard arguments of types: use `?` instead
78
scala> type N[X] = X match { case List[_] => Int }
8-
-- Deprecation Warning:
9+
1 warning found
10+
-- Deprecation Warning: --------------------------------------------------------
911
1 | type N[X] = X match { case List[_] => Int }
1012
| ^
1113
| `_` is deprecated for wildcard arguments of types: use `?` instead
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
scala> def f(thread: Thread) = thread.stop()
2+
there were 1 deprecation warning(s); re-run with -deprecation for details
3+
def f(thread: Thread): Unit
4+
5+
scala>:reset -deprecation
6+
7+
scala> def f(thread: Thread) = thread.stop()
8+
1 warning found
9+
-- Deprecation Warning: --------------------------------------------------------
10+
1 | def f(thread: Thread) = thread.stop()
11+
| ^^^^^^^^^^^
12+
|method stop in class Thread is deprecated since : see corresponding Javadoc for more information.
13+
def f(thread: Thread): Unit
14+
15+
scala>

compiler/test/dotty/tools/dotc/transform/PatmatExhaustivityTest.scala

Lines changed: 1 addition & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,8 @@ import reporting.TestReporter
1010
import dotty.tools.io.Directory
1111

1212
import java.io._
13-
import java.nio.file.{Files, Path => JPath}
13+
import java.nio.file.{Path => JPath}
1414

15-
import scala.io.Source._
1615
import org.junit.Test
1716

1817
class PatmatExhaustivityTest {
@@ -79,22 +78,4 @@ class PatmatExhaustivityTest {
7978

8079
println(msg)
8180
}
82-
83-
// inspect given files for tool args of the form `tool: args`
84-
// if args string ends in close comment, drop the `*` `/`
85-
// if split, parse the args string as command line.
86-
// (from scala.tools.partest.nest.Runner#toolArgsFor)
87-
private def toolArgsFor(files: List[JPath]): List[String] = {
88-
import scala.jdk.OptionConverters._
89-
import config.CommandLineParser.tokenize
90-
files.flatMap { path =>
91-
val tag = "scalac:"
92-
val endc = "*" + "/" // be forgiving of /* scalac: ... */
93-
def stripped(s: String) = s.substring(s.indexOf(tag) + tag.length).stripSuffix(endc)
94-
val args = scala.util.Using.resource(Files.lines(path, scala.io.Codec.UTF8.charSet))(
95-
_.limit(10).filter(_.contains(tag)).map(stripped).findAny.toScala
96-
)
97-
args.map(tokenize).getOrElse(Nil)
98-
}
99-
}
10081
}

compiler/test/dotty/tools/repl/ReplTest.scala

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -64,19 +64,21 @@ extends ReplDriver(options, new PrintStream(out, true, StandardCharsets.UTF_8.na
6464

6565
val expectedOutput = lines.flatMap(filterEmpties)
6666
val actualOutput = {
67-
resetToInitial()
67+
val opts = toolArgsParse(lines.take(1))
68+
val (optsLine, inputLines) = if opts.isEmpty then ("", lines) else (lines.head, lines.drop(1))
69+
resetToInitial(opts)
6870

69-
assert(lines.head.startsWith(prompt),
71+
assert(inputLines.head.startsWith(prompt),
7072
s"""Each script must start with the prompt: "$prompt"""")
71-
val inputRes = lines.filter(_.startsWith(prompt))
73+
val inputRes = inputLines.filter(_.startsWith(prompt))
7274

7375
val buf = new ArrayBuffer[String]
7476
inputRes.foldLeft(initialState) { (state, input) =>
7577
val (out, nstate) = evaluate(state, input)
7678
out.linesIterator.foreach(buf.append)
7779
nstate
7880
}
79-
buf.toList.flatMap(filterEmpties)
81+
(optsLine :: buf.toList).flatMap(filterEmpties)
8082
}
8183

8284
if !FileDiff.matches(actualOutput, expectedOutput) then

compiler/test/dotty/tools/utils.scala

Lines changed: 27 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,9 @@ package tools
33

44
import java.io.File
55
import java.nio.charset.StandardCharsets.UTF_8
6+
import java.nio.file.{Files, Path => JPath}
67

7-
import scala.io.Source
8+
import scala.io.{Codec, Source}
89
import scala.reflect.ClassTag
910
import scala.util.Using.resource
1011
import scala.util.chaining.given
@@ -25,11 +26,10 @@ extension (f: File) def absPath =
2526
extension (str: String) def dropExtension =
2627
str.reverse.dropWhile(_ != '.').drop(1).reverse
2728

28-
private def withFile[T](file: File)(action: Source => T): T =
29-
resource(Source.fromFile(file, UTF_8.name))(action)
30-
31-
def readLines(f: File): List[String] = withFile(f)(_.getLines.toList)
32-
def readFile(f: File): String = withFile(f)(_.mkString)
29+
private
30+
def withFile[T](file: File)(action: Source => T)(using Codec): T = resource(Source.fromFile(file))(action)
31+
def readLines(f: File)(using codec: Codec = Codec.UTF8): List[String] = withFile(f)(_.getLines.toList)
32+
def readFile(f: File)(using codec: Codec = Codec.UTF8): String = withFile(f)(_.mkString)
3333

3434
private object Unthrown extends ControlThrowable
3535

@@ -43,3 +43,24 @@ def assertThrows[T <: Throwable: ClassTag](p: T => Boolean)(body: => Any): Unit
4343
case failed: T => throw AssertionError(s"Exception failed check: $failed").tap(_.addSuppressed(failed))
4444
case NonFatal(other) => throw AssertionError(s"Wrong exception: expected ${implicitly[ClassTag[T]]} but was ${other.getClass.getName}").tap(_.addSuppressed(other))
4545
end assertThrows
46+
47+
def toolArgsFor(files: List[JPath])(using codec: Codec = Codec.UTF8): List[String] =
48+
files.flatMap(path => toolArgsParse(readLines(path.toFile)))
49+
50+
// Inspect the first 10 of the given lines for compiler options of the form
51+
// `// scalac: args`, `/* scalac: args`, ` * scalac: args`.
52+
// If args string ends in close comment, drop the `*` `/`.
53+
// If split, parse the args string as a command line.
54+
// (from scala.tools.partest.nest.Runner#toolArgsFor)
55+
def toolArgsParse(lines: List[String]): List[String] = {
56+
val tag = "scalac:"
57+
val endc = "*" + "/" // be forgiving of /* scalac: ... */
58+
def stripped(s: String) = s.substring(s.indexOf(tag) + tag.length).stripSuffix(endc)
59+
val args = lines.to(LazyList).take(10).filter { s =>
60+
s.contains("// " + tag)
61+
|| s.contains("/* " + tag)
62+
|| s.contains(" * " + tag)
63+
// but avoid picking up comments like "% scalac ./a.scala" and "$ scalac a.scala"
64+
}.map(stripped).headOption
65+
args.map(dotc.config.CommandLineParser.tokenize).getOrElse(Nil)
66+
}

0 commit comments

Comments
 (0)