Skip to content

Commit c4c63fc

Browse files
committed
Fix problem with badly initialized context
1 parent 25aa624 commit c4c63fc

File tree

17 files changed

+101
-85
lines changed

17 files changed

+101
-85
lines changed

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

+16-9
Original file line numberDiff line numberDiff line change
@@ -66,10 +66,16 @@ class Driver {
6666

6767
protected def command: CompilerCommand = ScalacCommand
6868

69-
def setup(args: Array[String], rootCtx: Context): (Option[List[AbstractFile]], Context) = {
69+
/** Setup context with initialized settings from CLI arguments, then check if there are any settings that
70+
* would change the default behaviour of the compiler.
71+
*
72+
* @return If there is no setting like `-help` preventing us from continuing compilation,
73+
* this method returns a list of files to compile and an updated Context.
74+
* If compilation should be interrupted, this method returns None.
75+
*/
76+
def setup(args: Array[String], rootCtx: Context): Option[(List[AbstractFile], Context)] = {
7077
val ictx = rootCtx.fresh
71-
val settings = config.ScalaSettings()
72-
val summary = command.distill(args, settings, settings.defaultState)
78+
val summary = command.distill(args, ictx.settings)(ictx.settingsState)(using ictx)
7379
ictx.setSettings(summary.sstate)
7480
MacroClassLoader.init(ictx)
7581
Positioned.init(using ictx)
@@ -78,9 +84,9 @@ class Driver {
7884
if !ctx.settings.YdropComments.value || ctx.mode.is(Mode.ReadComments) then
7985
ictx.setProperty(ContextDoc, new ContextDocstrings)
8086
val fileNamesOrNone = command.checkUsage(summary, sourcesRequired)(using ctx.settings)(using ctx.settingsState)
81-
fileNamesOrNone.fold((None, ictx)) { fileNames =>
87+
fileNamesOrNone.map { fileNames =>
8288
val files = fileNames.map(ctx.getFile)
83-
(Some(files), fromTastySetup(files))
89+
(files, fromTastySetup(files))
8490
}
8591
}
8692
}
@@ -187,10 +193,11 @@ class Driver {
187193
* if compilation succeeded.
188194
*/
189195
def process(args: Array[String], rootCtx: Context): Reporter = {
190-
val (files, compileCtx) = setup(args, rootCtx)
191-
files.fold(compileCtx.reporter) {
192-
doCompile(newCompiler(using compileCtx), _)(using compileCtx)
193-
}
196+
setup(args, rootCtx) match
197+
case Some((files, compileCtx)) =>
198+
doCompile(newCompiler(using compileCtx), files)(using compileCtx)
199+
case None =>
200+
rootCtx.reporter
194201
}
195202

196203
def main(args: Array[String]): Unit = {

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

+15-15
Original file line numberDiff line numberDiff line change
@@ -40,21 +40,21 @@ class Resident extends Driver {
4040

4141
final override def process(args: Array[String], rootCtx: Context): Reporter = {
4242
@tailrec def loop(args: Array[String], prevCtx: Context): Reporter = {
43-
var (possibleFiles, ctx) = setup(args, prevCtx)
44-
if possibleFiles.isDefined then
45-
inContext(ctx) {
46-
doCompile(residentCompiler, possibleFiles.get) // using more complex constructs like fold or map instead of get will make @tailrec complain
47-
}
48-
var nextCtx = ctx
49-
var line = getLine()
50-
while (line == reset) {
51-
nextCtx = rootCtx
52-
line = getLine()
53-
}
54-
if (line.startsWith(quit)) ctx.reporter
55-
else loop(line split "\\s+", nextCtx)
56-
else
57-
ctx.reporter
43+
setup(args, prevCtx) match
44+
case Some((files, ctx)) =>
45+
inContext(ctx) {
46+
doCompile(residentCompiler, files)
47+
}
48+
var nextCtx = ctx
49+
var line = getLine()
50+
while (line == reset) {
51+
nextCtx = rootCtx
52+
line = getLine()
53+
}
54+
if (line.startsWith(quit)) ctx.reporter
55+
else loop(line split "\\s+", nextCtx)
56+
case None =>
57+
prevCtx.reporter
5858
}
5959
loop(args, rootCtx)
6060
}

compiler/src/dotty/tools/dotc/config/CliCommand.scala

+8-8
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ trait CliCommand:
4040
"""
4141

4242
/** Distill arguments into summary detailing settings, errors and files to main */
43-
def distill(args: Array[String], sg: Settings.SettingGroup, ss: SettingsState): ArgsSummary =
43+
def distill(args: Array[String], sg: Settings.SettingGroup)(ss: SettingsState = sg.defaultState)(using Context): ArgsSummary =
4444
/**
4545
* Expands all arguments starting with @ to the contents of the
4646
* file named like each argument.
@@ -49,20 +49,20 @@ trait CliCommand:
4949
def stripComment(s: String) = s takeWhile (_ != '#')
5050
val path = Paths.get(arg stripPrefix "@")
5151
if (!Files.exists(path))
52-
throw new java.io.FileNotFoundException("argument file %s could not be found" format path.getFileName)
53-
54-
val lines = Files.readAllLines(path) // default to UTF-8 encoding
55-
56-
val params = lines.asScala map stripComment mkString " "
57-
CommandLineParser.tokenize(params)
52+
report.error(s"Argument file ${path.getFileName} could not be found")
53+
Nil
54+
else
55+
val lines = Files.readAllLines(path) // default to UTF-8 encoding
56+
val params = lines.asScala map stripComment mkString " "
57+
CommandLineParser.tokenize(params)
5858

5959
// expand out @filename to the contents of that filename
6060
def expandedArguments = args.toList flatMap {
6161
case x if x startsWith "@" => expandArg(x)
6262
case x => List(x)
6363
}
6464

65-
sg.processArguments(expandedArguments, ss, processAll = true)
65+
sg.processArguments(expandedArguments, processAll = true, settingsState = ss)
6666

6767
/** Creates a help message for a subset of options based on cond */
6868
protected def availableOptionsMsg(cond: Setting[?] => Boolean)(using settings: ConcreteSettings)(using SettingsState): String =

compiler/src/dotty/tools/dotc/config/CompilerCommand.scala

+1-1
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ import Properties._
1010
import scala.collection.JavaConverters._
1111

1212
abstract class CompilerCommand extends CliCommand:
13-
final type ConcreteSettings = ScalaSettings
13+
type ConcreteSettings = ScalaSettings
1414

1515
final def helpMsg(using settings: ScalaSettings)(using SettingsState, Context): String =
1616
if (settings.help.value) usageMessage

compiler/src/dotty/tools/dotc/config/PathResolver.scala

+1-1
Original file line numberDiff line numberDiff line change
@@ -144,7 +144,7 @@ object PathResolver {
144144
}
145145
else inContext(ContextBase().initialCtx) {
146146
val ArgsSummary(sstate, rest, errors, warnings) =
147-
ctx.settings.processArguments(args.toList, ctx.settingsState, true)
147+
ctx.settings.processArguments(args.toList, true, ctx.settingsState)
148148
errors.foreach(println)
149149
val pr = new PathResolver()(using ctx.fresh.setSettings(sstate))
150150
println(" COMMAND: 'scala %s'".format(args.mkString(" ")))

compiler/src/dotty/tools/dotc/config/Settings.scala

+1-1
Original file line numberDiff line numberDiff line change
@@ -244,7 +244,7 @@ object Settings {
244244
}
245245
}
246246

247-
def processArguments(arguments: List[String], settingsState: SettingsState, processAll: Boolean): ArgsSummary =
247+
def processArguments(arguments: List[String], processAll: Boolean, settingsState: SettingsState = defaultState): ArgsSummary =
248248
processArguments(ArgsSummary(settingsState, arguments, Nil, Nil), processAll, Nil)
249249

250250
def publish[T](settingf: Int => Setting[T]): Setting[T] = {

compiler/src/dotty/tools/dotc/decompiler/IDEDecompilerDriver.scala

+1-1
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ class IDEDecompilerDriver(val settings: List[String]) extends dotc.Driver {
1919
val rootCtx = initCtx.fresh.addMode(Mode.Interactive | Mode.ReadPositions | Mode.ReadComments)
2020
rootCtx.setSetting(rootCtx.settings.YretainTrees, true)
2121
rootCtx.setSetting(rootCtx.settings.fromTasty, true)
22-
val ctx = setup(settings.toArray :+ "dummy.scala", rootCtx)._2
22+
val ctx = setup(settings.toArray :+ "dummy.scala", rootCtx).get._2
2323
ctx.initialize()(using ctx)
2424
ctx
2525
}

compiler/src/dotty/tools/dotc/decompiler/Main.scala

+1-1
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ object Main extends dotc.Driver {
1818
new TASTYDecompiler
1919
}
2020

21-
override def setup(args0: Array[String], rootCtx: Context): (Option[List[AbstractFile]], Context) = {
21+
override def setup(args0: Array[String], rootCtx: Context): Option[(List[AbstractFile], Context)] = {
2222
var args = args0.filter(a => a != "-decompile")
2323
if (!args.contains("-from-tasty")) args = "-from-tasty" +: args
2424
if (args.contains("-d")) args = "-color:never" +: args

compiler/src/dotty/tools/dotc/interactive/InteractiveDriver.scala

+3-1
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,9 @@ class InteractiveDriver(val settings: List[String]) extends Driver {
3232
val rootCtx = initCtx.fresh.addMode(Mode.ReadPositions).addMode(Mode.Interactive).addMode(Mode.ReadComments)
3333
rootCtx.setSetting(rootCtx.settings.YretainTrees, true)
3434
rootCtx.setSetting(rootCtx.settings.YcookComments, true)
35-
val ctx = setup(settings.toArray, rootCtx)._2
35+
val ctx = setup(settings.toArray, rootCtx) match
36+
case Some((_, ctx)) => ctx
37+
case None => rootCtx
3638
ctx.initialize()(using ctx)
3739
ctx
3840
}

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

+10-8
Original file line numberDiff line numberDiff line change
@@ -68,10 +68,14 @@ class ReplDriver(settings: Array[String],
6868
private def initialCtx = {
6969
val rootCtx = initCtx.fresh.addMode(Mode.ReadPositions | Mode.Interactive | Mode.ReadComments)
7070
rootCtx.setSetting(rootCtx.settings.YcookComments, true)
71-
val (files, ictx) = setup(settings, rootCtx)
72-
shouldStart = files.isDefined
73-
ictx.base.initialize()(using ictx)
74-
ictx
71+
setup(settings, rootCtx) match
72+
case Some((files, ictx)) =>
73+
shouldStart = true
74+
ictx.base.initialize()(using ictx)
75+
ictx
76+
case None =>
77+
shouldStart = false
78+
rootCtx
7579
}
7680

7781
/** the initial, empty state of the REPL session */
@@ -105,11 +109,9 @@ class ReplDriver(settings: Array[String],
105109

106110
/** Try to run REPL if there is nothing that prevents us doing so.
107111
*
108-
* Possible reason for unsuccessful run are raised flags in CLI like --help or --version
112+
* Possible reason for unsuccessful run are raised flags in CLI like --help or --version
109113
*/
110-
final def tryRunning = if shouldStart then
111-
println("Starting scala3 REPL...")
112-
runUntilQuit()
114+
final def tryRunning = if shouldStart then runUntilQuit()
113115

114116
/** Run REPL with `state` until `:quit` command found
115117
*

compiler/src/dotty/tools/scripting/ScriptingDriver.scala

+24-24
Original file line numberDiff line numberDiff line change
@@ -19,30 +19,30 @@ import sys.process._
1919
class ScriptingDriver(compilerArgs: Array[String], scriptFile: File, scriptArgs: Array[String]) extends Driver:
2020
def compileAndRun(pack:(Path, String, String) => Boolean = null): Unit =
2121
val outDir = Files.createTempDirectory("scala3-scripting")
22-
val (toCompileOrNone, rootCtx) = setup(compilerArgs :+ scriptFile.getAbsolutePath, initCtx.fresh)
23-
toCompileOrNone.map { toCompile =>
24-
given Context = rootCtx.fresh.setSetting(rootCtx.settings.outputDir,
25-
new PlainDirectory(Directory(outDir)))
26-
27-
if doCompile(newCompiler, toCompile).hasErrors then
28-
throw ScriptingException("Errors encountered during compilation")
29-
30-
try
31-
val (mainClass, mainMethod) = detectMainClassAndMethod(outDir, ctx.settings.classpath.value, scriptFile)
32-
val invokeMain: Boolean =
33-
Option(pack) match
34-
case Some(func) =>
35-
func(outDir, ctx.settings.classpath.value, mainClass)
36-
case None =>
37-
true
38-
end match
39-
if invokeMain then mainMethod.invoke(null, scriptArgs)
40-
catch
41-
case e: java.lang.reflect.InvocationTargetException =>
42-
throw e.getCause
43-
finally
44-
deleteFile(outDir.toFile)
45-
}
22+
setup(compilerArgs :+ scriptFile.getAbsolutePath, initCtx.fresh) match
23+
case Some((toCompile, rootCtx)) =>
24+
given Context = rootCtx.fresh.setSetting(rootCtx.settings.outputDir,
25+
new PlainDirectory(Directory(outDir)))
26+
27+
if doCompile(newCompiler, toCompile).hasErrors then
28+
throw ScriptingException("Errors encountered during compilation")
29+
30+
try
31+
val (mainClass, mainMethod) = detectMainClassAndMethod(outDir, ctx.settings.classpath.value, scriptFile)
32+
val invokeMain: Boolean =
33+
Option(pack) match
34+
case Some(func) =>
35+
func(outDir, ctx.settings.classpath.value, mainClass)
36+
case None =>
37+
true
38+
end match
39+
if invokeMain then mainMethod.invoke(null, scriptArgs)
40+
catch
41+
case e: java.lang.reflect.InvocationTargetException =>
42+
throw e.getCause
43+
finally
44+
deleteFile(outDir.toFile)
45+
case None =>
4646
end compileAndRun
4747

4848
private def deleteFile(target: File): Unit =

compiler/test/dotty/tools/dotc/ScalaCommandTest.scala

+10-5
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import org.junit.Assert._
55
import org.junit.Rule
66
import org.junit.rules.TemporaryFolder
77
import dotty.tools.dotc.config.Settings._
8+
import core.Contexts.{Context, ContextBase}
89

910
class ScalaCommandTest:
1011

@@ -13,27 +14,31 @@ class ScalaCommandTest:
1314
@Rule
1415
def temporaryFolder = _temporaryFolder
1516

16-
@Test def `Simple one parameter`: Unit =
17+
@Test def `Simple one parameter`: Unit = inContext {
1718
val settings = config.ScalaSettings()
1819
val args = "-cp path/to/classes1:other/path/to/classes2 files".split(" ")
19-
val summary = ScalacCommand.distill(args, settings, settings.defaultState)
20+
val summary = ScalacCommand.distill(args, settings)()
2021
given SettingsState = summary.sstate
2122
assertEquals("path/to/classes1:other/path/to/classes2", settings.classpath.value)
2223
assertEquals("files" :: Nil, summary.arguments)
24+
}
2325

24-
@Test def `Unfold @file`: Unit =
26+
@Test def `Unfold @file`: Unit = inContext {
2527
val settings = config.ScalaSettings()
2628
val file = temporaryFolder.newFile("config")
2729
val writer = java.io.FileWriter(file);
2830
writer.write("-sourceroot myNewRoot someMoreFiles");
2931
writer.close();
30-
val args = s"-cp path/to/classes1:other/path/to/classes2 @$file someFiles".split(" ")
31-
val summary = ScalacCommand.distill(args, settings, settings.defaultState)
32+
val args = s"-cp path/to/classes1:other/path/to/classes2 @${file} someFiles".split(" ")
33+
val summary = ScalacCommand.distill(args, settings)()
3234

3335
given SettingsState = summary.sstate
3436
assertEquals("path/to/classes1:other/path/to/classes2", settings.classpath.value)
3537
assertEquals("myNewRoot", settings.sourceroot.value)
3638
assertEquals("someMoreFiles" :: "someFiles" :: Nil, summary.arguments)
39+
}
40+
41+
private def inContext(f: Context ?=> Unit) = f(using (new ContextBase).initialCtx.fresh)
3742

3843
extension [T](setting: Setting[T])
3944
private def value(using ss: SettingsState): T = setting.valueIn(ss)

compiler/test/dotty/tools/dotc/SettingsTests.scala

+6-6
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ class SettingsTests {
4747

4848
inContext {
4949
val args = List("-foo", "b", "-bar", "1")
50-
val summary = Settings.processArguments(args, Settings.defaultState, true)
50+
val summary = Settings.processArguments(args, true)
5151
assertTrue(summary.errors.isEmpty)
5252
given SettingsState = summary.sstate
5353
assertEquals("b", Settings.foo.value)
@@ -65,7 +65,7 @@ class SettingsTests {
6565

6666
inContext {
6767
val args = List("-foo", "b", "-bar", "1", "-baz", "5")
68-
val summary = Settings.processArguments(args, Settings.defaultState, true)
68+
val summary = Settings.processArguments(args, true)
6969
assertTrue(summary.errors.isEmpty)
7070
given SettingsState = summary.sstate
7171
assertEquals("b", Settings.foo.value)
@@ -75,15 +75,15 @@ class SettingsTests {
7575

7676
inContext {
7777
val args = List("-foo:b")
78-
val summary = Settings.processArguments(args, Settings.defaultState, true)
78+
val summary = Settings.processArguments(args, true)
7979
assertTrue(summary.errors.isEmpty)
8080
given SettingsState = summary.sstate
8181
assertEquals("b", Settings.foo.value)
8282
}
8383

8484
inContext {
8585
val args = List("-foo", "c", "-bar", "3", "-baz", "-1")
86-
val summary = Settings.processArguments(args, Settings.defaultState, true)
86+
val summary = Settings.processArguments(args, true)
8787
val expectedErrors = List(
8888
"c is not a valid choice for -foo",
8989
"3 is not a valid choice for -bar",
@@ -94,14 +94,14 @@ class SettingsTests {
9494

9595
inContext {
9696
val args = List("-foo:c")
97-
val summary = Settings.processArguments(args, Settings.defaultState, true)
97+
val summary = Settings.processArguments(args, true)
9898
val expectedErrors = List("c is not a valid choice for -foo")
9999
assertEquals(expectedErrors, summary.errors)
100100
}
101101

102102
inContext {
103103
val args = List("-quux", "a", "-quuz", "0")
104-
val summary = Settings.processArguments(args, Settings.defaultState, true)
104+
val summary = Settings.processArguments(args, true)
105105
val expectedErrors = List(
106106
"a is not a valid choice for -quux",
107107
"0 is not a valid choice for -quuz",

compiler/test/dotty/tools/dotc/core/tasty/CommentPicklingTest.scala

+1-1
Original file line numberDiff line numberDiff line change
@@ -107,7 +107,7 @@ class CommentPicklingTest {
107107
private class UnpicklingDriver extends Driver {
108108
override def initCtx = super.initCtx.addMode(Mode.ReadComments)
109109
def unpickle[T](args: Array[String], files: List[File])(fn: (List[tpd.Tree], Context) => T): T = {
110-
implicit val (_, ctx: Context) = setup(args, initCtx)
110+
implicit val ctx: Context = setup(args, initCtx).map(_._2).getOrElse(initCtx)
111111
ctx.initialize()
112112
val trees = files.flatMap { f =>
113113
val unpickler = new DottyUnpickler(f.toByteArray())

sbt-bridge/src/dotty/tools/xsbt/CompilerBridgeDriver.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ synchronized public void run(VirtualFile[] sources, AnalysisCallback callback, L
6060
.setReporter(reporter)
6161
.setSbtCallback(callback);
6262

63-
Contexts.Context context = setup(args, initialCtx)._2;
63+
Contexts.Context context = setup(args, initialCtx).map(t -> t._2).getOrElse(() -> initialCtx);
6464

6565
if (ScalacCommand.isHelpFlag(context.settings(), context.settingsState())) {
6666
throw new InterfaceCompileFailed(args, new Problem[0], StopInfoError);

scaladoc/src/dotty/tools/scaladoc/Scaladoc.scala

+1-1
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,7 @@ object Scaladoc:
7676
given CompilerContext = newContext
7777
val ss = ScaladocSettings()
7878
import ss._
79-
val summary = ScaladocCommand.distill(args, ss, ss.defaultState)
79+
val summary = ScaladocCommand.distill(args, ss)()
8080
val argumentFilesOrNone = ScaladocCommand.checkUsage(summary, true)(using ss)(using summary.sstate)
8181

8282
extension[T](arg: Setting[T])

staging/src/scala/quoted/staging/QuoteDriver.scala

+1-1
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ private class QuoteDriver(appClassloader: ClassLoader) extends Driver:
3333
new VirtualDirectory("<quote compilation output>")
3434
end outDir
3535

36-
val (_, ctx0: Context) = setup(settings.compilerArgs.toArray :+ "dummy.scala", initCtx.fresh)
36+
val ctx0 = setup(settings.compilerArgs.toArray :+ "dummy.scala", initCtx.fresh).get._2
3737
val ctx = setCompilerSettings(ctx0.fresh.setSetting(ctx0.settings.outputDir, outDir), settings)
3838

3939
new QuoteCompiler().newRun(ctx).compileExpr(exprBuilder) match

0 commit comments

Comments
 (0)