Skip to content

Commit 77fb829

Browse files
committed
Don't reduce inline matches, when a guard cannot be checked at compile
time fixes #13570
1 parent aaac006 commit 77fb829

File tree

3 files changed

+39
-5
lines changed

3 files changed

+39
-5
lines changed

compiler/src/dotty/tools/dotc/typer/Inliner.scala

Lines changed: 22 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1242,6 +1242,11 @@ class Inliner(call: tpd.Tree, rhsToInline: tpd.Tree)(using Context) {
12421242
*/
12431243
type MatchRedux = Option[(List[MemberDef], Tree)]
12441244

1245+
/** Same as MatchRedux, but also includes a boolean
1246+
* that is true if the guard can be checked at compile time.
1247+
*/
1248+
type MatchReduxWithGuard = Option[(List[MemberDef], Tree, Boolean)]
1249+
12451250
/** Reduce an inline match
12461251
* @param mtch the match tree
12471252
* @param scrutinee the scrutinee expression, assumed to be pure, or
@@ -1423,7 +1428,7 @@ class Inliner(call: tpd.Tree, rhsToInline: tpd.Tree)(using Context) {
14231428
val scrutineeSym = newSym(InlineScrutineeName.fresh(), Synthetic, scrutType).asTerm
14241429
val scrutineeBinding = normalizeBinding(ValDef(scrutineeSym, scrutinee))
14251430

1426-
def reduceCase(cdef: CaseDef): MatchRedux = {
1431+
def reduceCase(cdef: CaseDef): MatchReduxWithGuard = {
14271432
val caseBindingMap = new mutable.ListBuffer[(Symbol, MemberDef)]()
14281433

14291434
def substBindings(
@@ -1442,21 +1447,33 @@ class Inliner(call: tpd.Tree, rhsToInline: tpd.Tree)(using Context) {
14421447
val gadtCtx = ctx.fresh.setFreshGADTBounds.addMode(Mode.GadtConstraintInference)
14431448
if (reducePattern(caseBindingMap, scrutineeSym.termRef, cdef.pat)(using gadtCtx)) {
14441449
val (caseBindings, from, to) = substBindings(caseBindingMap.toList, mutable.ListBuffer(), Nil, Nil)
1450+
val typedGuard = typer.typed(cdef.guard.subst(from, to), defn.BooleanType)
14451451
val guardOK = cdef.guard.isEmpty || {
1446-
typer.typed(cdef.guard.subst(from, to), defn.BooleanType) match {
1452+
typedGuard match {
14471453
case ConstantValue(true) => true
1454+
case x => false
1455+
}
1456+
}
1457+
val canReduceGuard = cdef.guard.isEmpty || {
1458+
typedGuard match {
1459+
case ConstantValue(_) => true
14481460
case _ => false
14491461
}
14501462
}
1451-
if (guardOK) Some((caseBindings.map(_.subst(from, to)), cdef.body.subst(from, to)))
1452-
else None
1463+
if guardOK then Some((caseBindings.map(_.subst(from, to)), cdef.body.subst(from, to), canReduceGuard))
1464+
else if canReduceGuard then None
1465+
else Some((caseBindings.map(_.subst(from, to)), cdef.body.subst(from, to), canReduceGuard))
14531466
}
14541467
else None
14551468
}
14561469

14571470
def recur(cases: List[CaseDef]): MatchRedux = cases match {
14581471
case Nil => None
1459-
case cdef :: cases1 => reduceCase(cdef) `orElse` recur(cases1)
1472+
case cdef :: cases1 =>
1473+
reduceCase(cdef) match
1474+
case None => recur(cases1)
1475+
case r @ Some((caseBindings, rhs, canReduceGuard)) if canReduceGuard => Some((caseBindings, rhs))
1476+
case _ => None
14601477
}
14611478

14621479
recur(cases)

tests/neg/i13570.check

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
-- Error: tests/neg/i13570.scala:8:5 -----------------------------------------------------------------------------------
2+
8 | jim(Seq(1,2)) // error
3+
| ^^^^^^^^^^^^^
4+
| cannot reduce inline match with
5+
| scrutinee: seq$proxy1 : (seq$proxy1 : Seq[Int])
6+
| patterns : case s @ _:Seq[Int] if s.isEmpty
7+
| case s @ _:Seq[Int]
8+
| case _
9+
| This location contains code that was inlined from i13570.scala:3

tests/neg/i13570.scala

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
object Test:
2+
inline def jim(seq: Seq[Int]) =
3+
inline seq match
4+
case s: Seq[Int] if s.isEmpty => println("seq is empty")
5+
case s: Seq[Int] => println("seq is not empty")
6+
case _ => println("somthing hinky happened")
7+
8+
jim(Seq(1,2)) // error

0 commit comments

Comments
 (0)