From 0ea6a0a1a2b6560e4037fbbfe2b549fdd3eef66d 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 | 3 +-- tests/neg/i23729.scala | 19 +++++++++++++++++++ 4 files changed, 24 insertions(+), 4 deletions(-) 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 c4a77f17060c..e05c5f79b228 100644 --- a/compiler/src/dotty/tools/dotc/parsing/Parsers.scala +++ b/compiler/src/dotty/tools/dotc/parsing/Parsers.scala @@ -409,7 +409,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 52e03de60dea..9b9500779b22 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 990eb01b999e..9090f8335ac9 100644 --- a/compiler/src/dotty/tools/dotc/typer/Checking.scala +++ b/compiler/src/dotty/tools/dotc/typer/Checking.scala @@ -1339,7 +1339,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()) { + 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) && @@ -1356,7 +1356,6 @@ trait Checking { if decl.hasDefaultParams && other.hasDefaultParams then report.error(em"two or more overloaded variants of $decl have default arguments", decl.srcPos) decl.resetFlag(HasDefaultParams) - } if (!excludeFromDoubleDeclCheck(decl)) seen(decl.name) = decl :: seen(decl.name) } 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