From 59f07be0a055b31e6c43300ea6079a6705df80bf Mon Sep 17 00:00:00 2001 From: Kacper Korban Date: Thu, 23 Sep 2021 19:28:52 +0200 Subject: [PATCH] Don't reduce inline matches, when a guard cannot be checked at compile time fixes #13570 --- .../src/dotty/tools/dotc/typer/Inliner.scala | 28 +++++++++++++------ tests/neg/i13570.check | 9 ++++++ tests/neg/i13570.scala | 8 ++++++ 3 files changed, 36 insertions(+), 9 deletions(-) create mode 100644 tests/neg/i13570.check create mode 100644 tests/neg/i13570.scala diff --git a/compiler/src/dotty/tools/dotc/typer/Inliner.scala b/compiler/src/dotty/tools/dotc/typer/Inliner.scala index 4895da94c56c..5870af1eb7ca 100644 --- a/compiler/src/dotty/tools/dotc/typer/Inliner.scala +++ b/compiler/src/dotty/tools/dotc/typer/Inliner.scala @@ -1242,6 +1242,11 @@ class Inliner(call: tpd.Tree, rhsToInline: tpd.Tree)(using Context) { */ type MatchRedux = Option[(List[MemberDef], Tree)] + /** Same as MatchRedux, but also includes a boolean + * that is true if the guard can be checked at compile time. + */ + type MatchReduxWithGuard = Option[(List[MemberDef], Tree, Boolean)] + /** Reduce an inline match * @param mtch the match tree * @param scrutinee the scrutinee expression, assumed to be pure, or @@ -1423,7 +1428,7 @@ class Inliner(call: tpd.Tree, rhsToInline: tpd.Tree)(using Context) { val scrutineeSym = newSym(InlineScrutineeName.fresh(), Synthetic, scrutType).asTerm val scrutineeBinding = normalizeBinding(ValDef(scrutineeSym, scrutinee)) - def reduceCase(cdef: CaseDef): MatchRedux = { + def reduceCase(cdef: CaseDef): MatchReduxWithGuard = { val caseBindingMap = new mutable.ListBuffer[(Symbol, MemberDef)]() def substBindings( @@ -1442,21 +1447,26 @@ class Inliner(call: tpd.Tree, rhsToInline: tpd.Tree)(using Context) { val gadtCtx = ctx.fresh.setFreshGADTBounds.addMode(Mode.GadtConstraintInference) if (reducePattern(caseBindingMap, scrutineeSym.termRef, cdef.pat)(using gadtCtx)) { val (caseBindings, from, to) = substBindings(caseBindingMap.toList, mutable.ListBuffer(), Nil, Nil) - val guardOK = cdef.guard.isEmpty || { - typer.typed(cdef.guard.subst(from, to), defn.BooleanType) match { - case ConstantValue(true) => true - case _ => false + val (guardOK, canReduceGuard) = + if cdef.guard.isEmpty then (true, true) + else typer.typed(cdef.guard.subst(from, to), defn.BooleanType) match { + case ConstantValue(v: Boolean) => (v, true) + case _ => (false, false) } - } - if (guardOK) Some((caseBindings.map(_.subst(from, to)), cdef.body.subst(from, to))) - else None + if guardOK then Some((caseBindings.map(_.subst(from, to)), cdef.body.subst(from, to), canReduceGuard)) + else if canReduceGuard then None + else Some((caseBindings.map(_.subst(from, to)), cdef.body.subst(from, to), canReduceGuard)) } else None } def recur(cases: List[CaseDef]): MatchRedux = cases match { case Nil => None - case cdef :: cases1 => reduceCase(cdef) `orElse` recur(cases1) + case cdef :: cases1 => + reduceCase(cdef) match + case None => recur(cases1) + case r @ Some((caseBindings, rhs, canReduceGuard)) if canReduceGuard => Some((caseBindings, rhs)) + case _ => None } recur(cases) diff --git a/tests/neg/i13570.check b/tests/neg/i13570.check new file mode 100644 index 000000000000..90e29476b7b1 --- /dev/null +++ b/tests/neg/i13570.check @@ -0,0 +1,9 @@ +-- Error: tests/neg/i13570.scala:8:5 ----------------------------------------------------------------------------------- +8 | jim(Seq(1,2)) // error + | ^^^^^^^^^^^^^ + | cannot reduce inline match with + | scrutinee: seq$proxy1 : (seq$proxy1 : Seq[Int]) + | patterns : case s @ _:Seq[Int] if s.isEmpty + | case s @ _:Seq[Int] + | case _ + | This location contains code that was inlined from i13570.scala:3 diff --git a/tests/neg/i13570.scala b/tests/neg/i13570.scala new file mode 100644 index 000000000000..1376dedbaf19 --- /dev/null +++ b/tests/neg/i13570.scala @@ -0,0 +1,8 @@ +object Test: + inline def jim(seq: Seq[Int]) = + inline seq match + case s: Seq[Int] if s.isEmpty => println("seq is empty") + case s: Seq[Int] => println("seq is not empty") + case _ => println("somthing hinky happened") + + jim(Seq(1,2)) // error