-
Notifications
You must be signed in to change notification settings - Fork 1.1k
Description
Compiler version
- 3.6.4 (latest stable release)
- 3.8.3-RC1-SNAPSHOT (nightly)
Minimized code
//> using scala 3.6.4
val y = new c(for baz <- if baz // x then y else new A {
val z = w } do 1)The line comment // x then y else new A { causes the parser to see if baz without a then clause. During error recovery, the parser constructs an AST where the for-comprehension's span extends one byte beyond its parent new c(...) span.
Output
-- [E040] Syntax Error: crash.scala:2:2 --
2 | val z = w } do 1)
| ^^^
| 'then' expected, but 'val' found
exception occurred while parser crash.scala
An unhandled exception was thrown in the compiler.
Please file a crash report here:
https://github.com/scala/scala3/issues/new/choose
while compiling: crash.scala
during phase: parser
compiler version: version 3.6.4
Exception in thread "main" java.lang.AssertionError: assertion failed: position error, parent span does not contain child span
parent = new c(for baz <- if baz then ??? do ???) # -1,
parent span = <8..76>,
child = for baz <- if baz then ??? do ??? # -1,
child span = [14..77]
at scala.runtime.Scala3RunTime$.assertFailed(Scala3RunTime.scala:8)
at dotty.tools.dotc.ast.Positioned.check$1(Positioned.scala:177)
at dotty.tools.dotc.ast.Positioned.check$1$$anonfun$3(Positioned.scala:207)
at scala.collection.immutable.List.foreach(List.scala:334)
at dotty.tools.dotc.ast.Positioned.check$1(Positioned.scala:207)
at dotty.tools.dotc.ast.Positioned.checkPos(Positioned.scala:228)
at dotty.tools.dotc.ast.Positioned.check$1(Positioned.scala:202)
at dotty.tools.dotc.ast.Positioned.checkPos(Positioned.scala:228)
at dotty.tools.dotc.ast.Positioned.check$1(Positioned.scala:202)
at dotty.tools.dotc.ast.Positioned.check$1$$anonfun$3(Positioned.scala:207)
at scala.collection.immutable.List.foreach(List.scala:334)
at dotty.tools.dotc.ast.Positioned.check$1(Positioned.scala:207)
at dotty.tools.dotc.ast.Positioned.checkPos(Positioned.scala:228)
at dotty.tools.dotc.parsing.Parser.parse$$anonfun$1(ParserPhase.scala:39)
at dotty.tools.dotc.core.Phases$Phase.monitor(Phases.scala:510)
at dotty.tools.dotc.parsing.Parser.parse(ParserPhase.scala:40)
...
Expectation
The compiler should parse erroneous programs without crashing. Syntax errors should be reported gracefully, and the AST position invariant (parent span contains all child spans) should be maintained even during error recovery.
Instead, the parser crashes with an AssertionError when checking position consistency of the parsed AST.
Analysis
The crash occurs in Positioned.check (Positioned.scala:177) during the parser phase:
- The line comment
//on line 1 hidesthen y else new A {, so the parser seesfor baz <- if baz— anifwithout athenclause. - On line 2, the parser encounters
val z = w } do 1)and triggers error recovery (expectingthen, gotval). - During error recovery, the parser reconstructs the AST but assigns the for-comprehension a span of
[14..77]while its parentnew c(...)gets a span of<8..76>— the child's end position (77) exceeds the parent's end position (76) by 1 byte. - The
checkPosvalidation inPositioned.scaladetects this invariant violation and throwsAssertionError.
This is a parser-phase bug - the crash happens before type checking, purely during syntax error recovery. The root cause is likely in how the error recovery mechanism computes source positions when an if-expression inside a for-generator is missing its then clause due to a line comment.