From 85c0527be946c1be8ce297a347a2132c7e2bb5bb Mon Sep 17 00:00:00 2001 From: Som Snytt Date: Fri, 22 Aug 2025 13:17:21 -0700 Subject: [PATCH] Error tree on outdent is zero extent Recovery on syntax error may consume remaining input, with an OUTDENT at EOF, so that the parent tree does not actually extend to EOF. Do not report spurious `def ` as ambiguous. --- .../dotty/tools/dotc/parsing/Parsers.scala | 4 +++- .../dotty/tools/dotc/parsing/Scanners.scala | 2 +- .../src/dotty/tools/dotc/typer/Checking.scala | 2 +- tests/neg/i23729.check | 14 ++++++++++++++ tests/neg/i23729.scala | 19 +++++++++++++++++++ 5 files changed, 38 insertions(+), 3 deletions(-) create mode 100644 tests/neg/i23729.check create mode 100644 tests/neg/i23729.scala diff --git a/compiler/src/dotty/tools/dotc/parsing/Parsers.scala b/compiler/src/dotty/tools/dotc/parsing/Parsers.scala index f44703a562f1..b205d3159241 100644 --- a/compiler/src/dotty/tools/dotc/parsing/Parsers.scala +++ b/compiler/src/dotty/tools/dotc/parsing/Parsers.scala @@ -411,7 +411,9 @@ object Parsers { false } - def errorTermTree(start: Offset): Tree = atSpan(Span(start, in.offset)) { unimplementedExpr } + def errorTermTree(start: Offset): Tree = + val end = if in.token == OUTDENT then start else in.offset + atSpan(Span(start, end)) { unimplementedExpr } private var inFunReturnType = false private def fromWithinReturnType[T](body: => T): T = { diff --git a/compiler/src/dotty/tools/dotc/parsing/Scanners.scala b/compiler/src/dotty/tools/dotc/parsing/Scanners.scala index ec246f7a3742..2445f4772f91 100644 --- a/compiler/src/dotty/tools/dotc/parsing/Scanners.scala +++ b/compiler/src/dotty/tools/dotc/parsing/Scanners.scala @@ -307,7 +307,7 @@ object Scanners { println(s"\nSTART SKIP AT ${sourcePos().line + 1}, $this in $currentRegion") var noProgress = 0 // Defensive measure to ensure we always get out of the following while loop - // even if source file is weirly formatted (i.e. we never reach EOF) + // even if source file is weirdly formatted (i.e. we never reach EOF) var prevOffset = offset while !atStop && noProgress < 3 do nextToken() diff --git a/compiler/src/dotty/tools/dotc/typer/Checking.scala b/compiler/src/dotty/tools/dotc/typer/Checking.scala index 7f52c871f9de..310f32f2cedb 100644 --- a/compiler/src/dotty/tools/dotc/typer/Checking.scala +++ b/compiler/src/dotty/tools/dotc/typer/Checking.scala @@ -1346,7 +1346,7 @@ trait Checking { typr.println(i"check no double declarations $cls") def checkDecl(decl: Symbol): Unit = - for other <- seen(decl.name) if !decl.isAbsent() && !other.isAbsent() do + for other <- seen(decl.name) if decl.name != nme.ERROR && !decl.isAbsent() && !other.isAbsent() do typr.println(i"conflict? $decl $other") def javaFieldMethodPair = decl.is(JavaDefined) && other.is(JavaDefined) && diff --git a/tests/neg/i23729.check b/tests/neg/i23729.check new file mode 100644 index 000000000000..2f067c42c6c1 --- /dev/null +++ b/tests/neg/i23729.check @@ -0,0 +1,14 @@ +-- [E018] Syntax Error: tests/neg/i23729.scala:17:33 ------------------------------------------------------------------- +17 | def start: List[Direction] = match self // error syntax + | ^^^^^ + | expression expected but match found + | + | longer explanation available when compiling with `-explain` +-- [E040] Syntax Error: tests/neg/i23729.scala:18:6 -------------------------------------------------------------------- +18 | case Empty => Nil // error poor recovery + | ^^^^ + | 'def' expected, but 'case' found +-- [E040] Syntax Error: tests/neg/i23729.scala:19:6 -------------------------------------------------------------------- +19 | case Node(_, l, _) => l.start :+ Left // error poor recovery + | ^^^^ + | 'def' expected, but 'case' found diff --git a/tests/neg/i23729.scala b/tests/neg/i23729.scala new file mode 100644 index 000000000000..b575cbc0c35f --- /dev/null +++ b/tests/neg/i23729.scala @@ -0,0 +1,19 @@ + +trait Collection[Self, Element]: + type Index + extension (self: Self) + def start: Index + +sealed trait Tree[+T] +object Tree: + case object Empty extends Tree[Nothing] + case class Node[+T](value: T, lhs: Tree[T], rhs: Tree[T]) extends Tree[T] + +enum Direction: + case Left, Right, Here +given [T]: Collection[Tree[T], T] with + type Index = List[Direction] + extension (self: Tree[T]) + def start: List[Direction] = match self // error syntax + case Empty => Nil // error poor recovery + case Node(_, l, _) => l.start :+ Left // error poor recovery