Skip to content

Commit 7d9fef7

Browse files
authored
Merge pull request scala#11103 from som-snytt/issue/13115-leading-parser-crash
Load package objects when failing early
2 parents 177b745 + d42e037 commit 7d9fef7

File tree

4 files changed

+109
-14
lines changed

4 files changed

+109
-14
lines changed

src/compiler/scala/tools/nsc/Global.scala

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1378,7 +1378,7 @@ class Global(var currentSettings: Settings, reporter0: Reporter)
13781378
*/
13791379
val parserPhase = phaseNamed("parser")
13801380
val namerPhase = phaseNamed("namer")
1381-
// val packageobjectsPhase = phaseNamed("packageobjects")
1381+
val packageobjectsPhase = phaseNamed("packageobjects")
13821382
val typerPhase = phaseNamed("typer")
13831383
// val inlineclassesPhase = phaseNamed("inlineclasses")
13841384
// val superaccessorsPhase = phaseNamed("superaccessors")
@@ -1484,7 +1484,7 @@ class Global(var currentSettings: Settings, reporter0: Reporter)
14841484
showDef(splitClassAndPhase(settings.Xshowobj.value, term = true), declsOnly = false, globalPhase)
14851485
}
14861486

1487-
// Similarly, this will only be created under -Yshow-syms.
1487+
// Similarly, this will only be created under -Vsymbols.
14881488
object trackerFactory extends SymbolTrackers {
14891489
val global: Global.this.type = Global.this
14901490
lazy val trackers = currentRun.units.toList map (x => SymbolTracker(x))
@@ -1564,6 +1564,9 @@ class Global(var currentSettings: Settings, reporter0: Reporter)
15641564
if (timePhases)
15651565
informTime(globalPhase.description, phaseTimer.nanos)
15661566

1567+
if (reporter.hasErrors && !isPast(packageobjectsPhase))
1568+
packageobjectsPhase.run()
1569+
15671570
// progress update
15681571
if (settings.Xprint.containsPhase(globalPhase) || settings.printLate.value && runIsAt(cleanupPhase)) {
15691572
// print trees

src/compiler/scala/tools/nsc/typechecker/Analyzer.scala

Lines changed: 11 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -75,11 +75,11 @@ trait Analyzer extends AnyRef
7575
val openPackageObjectsTraverser = new InternalTraverser {
7676
override def traverse(tree: Tree): Unit = tree match {
7777
case ModuleDef(_, _, _) =>
78-
if (tree.symbol.name == nme.PACKAGEkw) {
79-
// we've actually got a source file
80-
deferredOpen.subtractOne(tree.symbol.owner)
81-
82-
openPackageModule(tree.symbol, tree.symbol.owner)
78+
val sym = tree.symbol
79+
if (sym.name == nme.PACKAGEkw) {
80+
val owner = sym.owner
81+
deferredOpen.subtractOne(owner) // we've actually got a source file
82+
openPackageModule(sym, owner)
8383
}
8484
case ClassDef(_, _, _, _) => () // make it fast
8585
case _ => tree.traverse(this)
@@ -93,13 +93,12 @@ trait Analyzer extends AnyRef
9393
override def run(): Unit = {
9494
super.run()
9595

96-
for (sym <- deferredOpen.toVector) {
97-
if (deferredOpen.remove(sym)) {
98-
// this can remove entries from `deferredOpen`, hence the copy to a vector
99-
// and the check of `remove` return value
100-
openPackageModule(sym)
101-
}
102-
}
96+
// openPackageModule can remove entries from `deferredOpen`, so make a defensive copy first,
97+
// and then check whether `remove` says the sym is still deferred.
98+
// `force` the open because we might be called earlier if the run is bailing on an early error.
99+
for (sym <- deferredOpen.toVector)
100+
if (deferredOpen.remove(sym))
101+
openPackageModule(sym, force = true)
103102
}
104103
}
105104
}

test/files/run/t13115.check

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
Doing first compilation
2+
scripteditor:7: error: ')' expected but '}' found.
3+
}
4+
^
5+
Compilation failed!
6+
Compilation successful!
7+
scripteditor:4: error: not found: value printlnx
8+
printlnx("Hi there!")
9+
^
10+
Compilation failed!
11+
scripteditor:7: error: ')' expected but '}' found.
12+
}
13+
^
14+
Compilation failed!
15+
16+
17+
Doing last compilation
18+
Compilation successful!

test/files/run/t13115.scala

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
///> using dep org.scala-lang:scala-compiler:2.13.7
2+
3+
import scala.tools.nsc.{Global, Settings}
4+
import scala.reflect.internal.util.BatchSourceFile
5+
import scala.tools.nsc.io.VirtualDirectory
6+
7+
object Test {
8+
val virtualDirectory = new VirtualDirectory("(memory)", None)
9+
val settings = new Settings()
10+
settings.usejavacp.value = true
11+
settings.outputDirs.setSingleOutput(virtualDirectory)
12+
//settings.processArgumentString("-Vdebug-type-error -deprecation -Vsymbols -Xdev -Vprint:_ -Vdebug -Vlog:_")
13+
val global = new Global(settings)
14+
15+
def main(args: Array[String]): Unit = {
16+
val codeWithNoError =
17+
"""
18+
class Hello1 {
19+
def hello(): Unit = {
20+
println("Hi there!")
21+
}
22+
}
23+
"""
24+
25+
val codeWithBenignError =
26+
"""
27+
class Hello2 {
28+
def hello(): Unit = {
29+
printlnx("Hi there!")
30+
}
31+
}
32+
"""
33+
34+
val codeWithDeadlyError =
35+
"""
36+
class Hello3 {
37+
def pic = 20
38+
def makePic(s: Int = {
39+
pic
40+
}
41+
}
42+
"""
43+
44+
val code2WithNoError =
45+
"""
46+
class Hello4 {
47+
def hello(): Unit = {
48+
val x = Seq(1, 2, 3)
49+
println(x)
50+
}
51+
}
52+
"""
53+
54+
println("Doing first compilation")
55+
compileCode(codeWithDeadlyError) // early error broke package object loading
56+
compileCode(codeWithNoError)
57+
compileCode(codeWithBenignError)
58+
compileCode(codeWithDeadlyError)
59+
60+
println("\n\nDoing last compilation")
61+
compileCode(code2WithNoError)
62+
}
63+
64+
def compileCode(code: String): Unit = {
65+
val run = new global.Run
66+
val sourceFile = new BatchSourceFile("scripteditor", code)
67+
global.reporter.reset()
68+
run.compileSources(List(sourceFile))
69+
if (global.reporter.hasErrors) {
70+
println("Compilation failed!")
71+
} else {
72+
println("Compilation successful!")
73+
}
74+
}
75+
}

0 commit comments

Comments
 (0)