Skip to content

Commit 7e5beee

Browse files
authored
Fix position for unreachable case warning in irrefutable 'val-else' #1339 (#1369)
### Problem ```scala def main() = { val (a, b) = (1, 2) else panic("unreachable") } ``` report `Unreachable case` at `main` instead of else (see #1339)
1 parent daffa30 commit 7e5beee

3 files changed

Lines changed: 50 additions & 7 deletions

File tree

effekt/jvm/src/test/scala/effekt/ParserTests.scala

Lines changed: 40 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -576,11 +576,50 @@ class ParserTests extends munit.FunSuite {
576576
)
577577
),
578578
None,
579-
Span(source,0,pos(7), Synthesized)
579+
Span(source,0,pos(7))
580580
),Span(source,0,pos.last, Synthesized));
581581
assertEquals(parseStmts(source.content), expected)
582582
}
583583

584+
test("val-else") {
585+
val (source, pos) =
586+
raw"""val (left, right) = list else { return 0 }; return left
587+
| ↑↑ ↑ ↑ ↑↑ ↑ ↑ ↑ ↑ ↑↑ ↑ ↑ ↑ ↑
588+
|""".sourceAndPositions
589+
val expected = Return(Match(
590+
List(Var(IdRef(List(), "list", Span(source, pos(6), pos(7))), Span(source, pos(6), pos(7)))),
591+
List(
592+
MatchClause(
593+
TagPattern(
594+
IdRef(List("effekt"), "Tuple2", Span(source, pos(0), pos(5), Synthesized)),
595+
List(
596+
AnyPattern(IdDef("left", Span(source, pos(1), pos(2))), Span(source, pos(1), pos(2))),
597+
AnyPattern(IdDef("right", Span(source, pos(3), pos(4))), Span(source, pos(3), pos(4)))
598+
),
599+
Span(source, pos(0), pos(5))
600+
),
601+
List(),
602+
Return(
603+
Var(IdRef(List(), "left", Span(source, pos(14), pos(15))), Span(source, pos(14), pos(15))),
604+
Span(source, pos(13), pos(15))
605+
),
606+
Span(source, pos(0), pos(7))
607+
)
608+
),
609+
Some(
610+
BlockStmt(
611+
Return(
612+
IntLit(0, Span(source, pos(10), pos(11))),
613+
Span(source, pos(9), pos(11))
614+
),
615+
Span(source, pos(8), pos(12))
616+
)
617+
),
618+
Span(source, 0, pos(12))
619+
), Span(source, 0, pos.last, Synthesized));
620+
assertEquals(parseStmts(source.content), expected)
621+
}
622+
584623
test("Semicolon insertion") {
585624
parseStmts("f(); return x")
586625
parseStmts(

effekt/shared/src/main/scala/effekt/Parser.scala

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -357,7 +357,7 @@ class Parser(tokens: Seq[Token], source: Source) {
357357
}
358358

359359
val clause = MatchClause(pattern, guards, body, Span(source, pattern.span.from, body.span.to, Synthesized))
360-
val matchExpr = Match(scrutinees, List(clause), fallback, withSpan.synthesized)
360+
val matchExpr = Match(scrutinees, List(clause), fallback, withSpan)
361361
val matchBody = Return(matchExpr, withSpan.synthesized)
362362
BlockLiteral(Nil, vparams, Nil, matchBody, withSpan.synthesized)
363363
}
@@ -573,11 +573,11 @@ class Parser(tokens: Seq[Token], source: Source) {
573573
case p ~ guards =>
574574
// matches do not support doc comments, so we ignore `info`
575575
val sc = expr()
576-
val endPos = pos()
577576
val default = when(`else`) { Some(stmt()) } { None }
577+
val endPos = pos()
578578
val body = semi() ~> stmts(inBraces)
579579
val clause = MatchClause(p, guards, body, Span(source, p.span.from, sc.span.to))
580-
val matching = Match(List(sc), List(clause), default, Span(source, startPos, endPos, Synthesized))
580+
val matching = Match(List(sc), List(clause), default, Span(source, startPos, endPos))
581581
Return(matching, span().synthesized)
582582
}
583583

@@ -1291,9 +1291,9 @@ class Parser(tokens: Seq[Token], source: Source) {
12911291
names.zip(argSpans).map{ (name, span) => Var(IdRef(Nil, name, span.synthesized), span.synthesized) },
12921292
cs.unspan,
12931293
None,
1294-
span().synthesized
1294+
span()
12951295
), span().synthesized),
1296-
span().synthesized
1296+
span()
12971297
)
12981298

12991299
case _ =>

effekt/shared/src/main/scala/effekt/typer/ExhaustivityChecker.scala

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -191,7 +191,11 @@ object ExhaustivityChecker {
191191
}
192192

193193
def reportRedundant()(using C: ErrorReporter): Unit = redundant.foreach { p =>
194-
C.at(p) { C.warning(pp"Unreachable case.") }
194+
val target = p.pattern match {
195+
case AnyPattern(_, _) | IgnorePattern(_) => p.body
196+
case _ => p
197+
}
198+
C.at(target) { C.warning(pp"Unreachable case.") }
195199
}
196200

197201
def report()(using C: ErrorReporter): Unit = {

0 commit comments

Comments
 (0)