Skip to content

Commit fe24fd3

Browse files
Merge pull request #13601 from KacperFKorban/fix-i13570
Don't reduce inline matches, when a guard cannot be checked at compile time
2 parents 01f040b + 59f07be commit fe24fd3

File tree

3 files changed

+36
-9
lines changed

3 files changed

+36
-9
lines changed

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

Lines changed: 19 additions & 9 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,26 @@ 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)
1445-
val guardOK = cdef.guard.isEmpty || {
1446-
typer.typed(cdef.guard.subst(from, to), defn.BooleanType) match {
1447-
case ConstantValue(true) => true
1448-
case _ => false
1450+
val (guardOK, canReduceGuard) =
1451+
if cdef.guard.isEmpty then (true, true)
1452+
else typer.typed(cdef.guard.subst(from, to), defn.BooleanType) match {
1453+
case ConstantValue(v: Boolean) => (v, true)
1454+
case _ => (false, false)
14491455
}
1450-
}
1451-
if (guardOK) Some((caseBindings.map(_.subst(from, to)), cdef.body.subst(from, to)))
1452-
else None
1456+
if guardOK then Some((caseBindings.map(_.subst(from, to)), cdef.body.subst(from, to), canReduceGuard))
1457+
else if canReduceGuard then None
1458+
else Some((caseBindings.map(_.subst(from, to)), cdef.body.subst(from, to), canReduceGuard))
14531459
}
14541460
else None
14551461
}
14561462

14571463
def recur(cases: List[CaseDef]): MatchRedux = cases match {
14581464
case Nil => None
1459-
case cdef :: cases1 => reduceCase(cdef) `orElse` recur(cases1)
1465+
case cdef :: cases1 =>
1466+
reduceCase(cdef) match
1467+
case None => recur(cases1)
1468+
case r @ Some((caseBindings, rhs, canReduceGuard)) if canReduceGuard => Some((caseBindings, rhs))
1469+
case _ => None
14601470
}
14611471

14621472
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)