From f3b58cfc66f0b337423192f3b6626322669311e8 Mon Sep 17 00:00:00 2001 From: Jan Chyb Date: Tue, 18 Feb 2025 12:38:50 +0100 Subject: [PATCH 1/2] Bring back pattern match exhaustivity checking for macros Also move the -Werror reporting until after the suspended warning reporting - this was needed for the added test to work (as previously the compilation would not error out even if -Werror was used). --- compiler/src/dotty/tools/dotc/Run.scala | 2 +- .../tools/dotc/transform/PatternMatcher.scala | 5 ++++- .../tools/dotc/transform/patmat/Space.scala | 6 ++++- tests/neg-macros/i22212.check | 22 +++++++++++++++++++ tests/neg-macros/i22212/Macro_1.scala | 15 +++++++++++++ tests/neg-macros/i22212/Test_2.scala | 3 +++ 6 files changed, 50 insertions(+), 3 deletions(-) create mode 100644 tests/neg-macros/i22212.check create mode 100644 tests/neg-macros/i22212/Macro_1.scala create mode 100644 tests/neg-macros/i22212/Test_2.scala diff --git a/compiler/src/dotty/tools/dotc/Run.scala b/compiler/src/dotty/tools/dotc/Run.scala index e505ace061a4..7d8c0ec88994 100644 --- a/compiler/src/dotty/tools/dotc/Run.scala +++ b/compiler/src/dotty/tools/dotc/Run.scala @@ -385,10 +385,10 @@ class Run(comp: Compiler, ictx: Context) extends ImplicitRunInfo with Constraint runPhases(allPhases = fusedPhases)(using runCtx) cancelAsyncTasty() - ctx.reporter.finalizeReporting() if (!ctx.reporter.hasErrors) Rewrites.writeBack() suppressions.runFinished(hasErrors = ctx.reporter.hasErrors) + ctx.reporter.finalizeReporting() while (finalizeActions.nonEmpty && canProgress()) { val action = finalizeActions.remove(0) action() diff --git a/compiler/src/dotty/tools/dotc/transform/PatternMatcher.scala b/compiler/src/dotty/tools/dotc/transform/PatternMatcher.scala index ee608a4297bf..31345770a638 100644 --- a/compiler/src/dotty/tools/dotc/transform/PatternMatcher.scala +++ b/compiler/src/dotty/tools/dotc/transform/PatternMatcher.scala @@ -46,10 +46,13 @@ class PatternMatcher extends MiniPhase { case rt => tree.tpe val translated = new Translator(matchType, this).translateMatch(tree) - // Skip analysis on inlined code (eg pos/i19157) + // Skip unreachability analysis on inlined code (eg pos/i19157) if !tpd.enclosingInlineds.nonEmpty then // check exhaustivity and unreachability SpaceEngine.checkMatch(tree) + else + // only check exhaustivity + SpaceEngine.checkMatchExhaustivityOnly(tree) translated.ensureConforms(matchType) } diff --git a/compiler/src/dotty/tools/dotc/transform/patmat/Space.scala b/compiler/src/dotty/tools/dotc/transform/patmat/Space.scala index 612b1e06f1c6..f44d7cb568f9 100644 --- a/compiler/src/dotty/tools/dotc/transform/patmat/Space.scala +++ b/compiler/src/dotty/tools/dotc/transform/patmat/Space.scala @@ -972,6 +972,10 @@ object SpaceEngine { end checkReachability def checkMatch(m: Match)(using Context): Unit = - if exhaustivityCheckable(m.selector) then checkExhaustivity(m) + checkMatchExhaustivityOnly(m) if reachabilityCheckable(m.selector) then checkReachability(m) + + def checkMatchExhaustivityOnly(m: Match)(using Context): Unit = + if exhaustivityCheckable(m.selector) then checkExhaustivity(m) + } diff --git a/tests/neg-macros/i22212.check b/tests/neg-macros/i22212.check new file mode 100644 index 000000000000..d2310ebe2d9b --- /dev/null +++ b/tests/neg-macros/i22212.check @@ -0,0 +1,22 @@ + +-- [E029] Pattern Match Exhaustivity Warning: tests/neg-macros/i22212/Test_2.scala:2:34 -------------------------------- + 2 |@main def main() = Macro.makeMatch() + | ^^^^^^^^^^^^^^^^^ + | match may not be exhaustive. + | + | It would fail on pattern case: Baz + |-------------------------------------------------------------------------------------------------------------------- + |Inline stack trace + |- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + |This location contains code that was inlined from Macro_1.scala:11 +11 | (_: Foo) match + | ^^^^^^ + |- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + |This location contains code that was inlined from Macro_1.scala:11 +11 | (_: Foo) match + | ^ +12 | case Bar => () + -------------------------------------------------------------------------------------------------------------------- + | + | longer explanation available when compiling with `-explain` +No warnings can be incurred under -Werror (or -Xfatal-warnings) diff --git a/tests/neg-macros/i22212/Macro_1.scala b/tests/neg-macros/i22212/Macro_1.scala new file mode 100644 index 000000000000..da64bdce9cc6 --- /dev/null +++ b/tests/neg-macros/i22212/Macro_1.scala @@ -0,0 +1,15 @@ +import scala.quoted._ + +sealed trait Foo +case object Bar extends Foo +case object Baz extends Foo + +object Macro { + inline def makeMatch() = ${makeMatchImpl} + def makeMatchImpl(using Quotes) = { + '{ + (_: Foo) match + case Bar => () + } + } +} diff --git a/tests/neg-macros/i22212/Test_2.scala b/tests/neg-macros/i22212/Test_2.scala new file mode 100644 index 000000000000..fe8e51affbcc --- /dev/null +++ b/tests/neg-macros/i22212/Test_2.scala @@ -0,0 +1,3 @@ +//> using options -Xfatal-warnings +@main def main() = Macro.makeMatch() +// nopos-error: No warnings can be incurred under -Werror (or -Xfatal-warnings) From f28b9c1d757a3f0a62c1a88e8e26864f8cbe688d Mon Sep 17 00:00:00 2001 From: Dale Wijnand Date: Mon, 24 Feb 2025 12:59:58 +0000 Subject: [PATCH 2/2] Move reachability skip to reachabilityCheckable --- compiler/src/dotty/tools/dotc/Run.scala | 2 +- .../tools/dotc/transform/PatternMatcher.scala | 9 ++------ .../tools/dotc/transform/patmat/Space.scala | 7 ++---- tests/neg-macros/i22212.check | 22 ------------------- tests/neg-macros/i22212/Test_2.scala | 3 --- tests/warn/i22212.check | 21 ++++++++++++++++++ tests/warn/i22212/Data_1.scala | 3 +++ .../{neg-macros => warn}/i22212/Macro_1.scala | 4 ---- tests/warn/i22212/Test_2.scala | 3 +++ 9 files changed, 32 insertions(+), 42 deletions(-) delete mode 100644 tests/neg-macros/i22212.check delete mode 100644 tests/neg-macros/i22212/Test_2.scala create mode 100644 tests/warn/i22212.check create mode 100644 tests/warn/i22212/Data_1.scala rename tests/{neg-macros => warn}/i22212/Macro_1.scala (71%) create mode 100644 tests/warn/i22212/Test_2.scala diff --git a/compiler/src/dotty/tools/dotc/Run.scala b/compiler/src/dotty/tools/dotc/Run.scala index 7d8c0ec88994..e505ace061a4 100644 --- a/compiler/src/dotty/tools/dotc/Run.scala +++ b/compiler/src/dotty/tools/dotc/Run.scala @@ -385,10 +385,10 @@ class Run(comp: Compiler, ictx: Context) extends ImplicitRunInfo with Constraint runPhases(allPhases = fusedPhases)(using runCtx) cancelAsyncTasty() + ctx.reporter.finalizeReporting() if (!ctx.reporter.hasErrors) Rewrites.writeBack() suppressions.runFinished(hasErrors = ctx.reporter.hasErrors) - ctx.reporter.finalizeReporting() while (finalizeActions.nonEmpty && canProgress()) { val action = finalizeActions.remove(0) action() diff --git a/compiler/src/dotty/tools/dotc/transform/PatternMatcher.scala b/compiler/src/dotty/tools/dotc/transform/PatternMatcher.scala index 31345770a638..250d4844d2b3 100644 --- a/compiler/src/dotty/tools/dotc/transform/PatternMatcher.scala +++ b/compiler/src/dotty/tools/dotc/transform/PatternMatcher.scala @@ -46,13 +46,8 @@ class PatternMatcher extends MiniPhase { case rt => tree.tpe val translated = new Translator(matchType, this).translateMatch(tree) - // Skip unreachability analysis on inlined code (eg pos/i19157) - if !tpd.enclosingInlineds.nonEmpty then - // check exhaustivity and unreachability - SpaceEngine.checkMatch(tree) - else - // only check exhaustivity - SpaceEngine.checkMatchExhaustivityOnly(tree) + // check exhaustivity and unreachability + SpaceEngine.checkMatch(tree) translated.ensureConforms(matchType) } diff --git a/compiler/src/dotty/tools/dotc/transform/patmat/Space.scala b/compiler/src/dotty/tools/dotc/transform/patmat/Space.scala index f44d7cb568f9..8ab5c93b1d68 100644 --- a/compiler/src/dotty/tools/dotc/transform/patmat/Space.scala +++ b/compiler/src/dotty/tools/dotc/transform/patmat/Space.scala @@ -922,6 +922,7 @@ object SpaceEngine { !sel.tpe.hasAnnotation(defn.UncheckedAnnot) && !sel.tpe.widen.isRef(defn.QuotedExprClass) && !sel.tpe.widen.isRef(defn.QuotedTypeClass) + && tpd.enclosingInlineds.isEmpty // Skip reachability on inlined code (eg i19157/i22212) def checkReachability(m: Match)(using Context): Unit = trace(i"checkReachability($m)"): val selTyp = toUnderlying(m.selector.tpe).dealias @@ -972,10 +973,6 @@ object SpaceEngine { end checkReachability def checkMatch(m: Match)(using Context): Unit = - checkMatchExhaustivityOnly(m) - if reachabilityCheckable(m.selector) then checkReachability(m) - - def checkMatchExhaustivityOnly(m: Match)(using Context): Unit = if exhaustivityCheckable(m.selector) then checkExhaustivity(m) - + if reachabilityCheckable(m.selector) then checkReachability(m) } diff --git a/tests/neg-macros/i22212.check b/tests/neg-macros/i22212.check deleted file mode 100644 index d2310ebe2d9b..000000000000 --- a/tests/neg-macros/i22212.check +++ /dev/null @@ -1,22 +0,0 @@ - --- [E029] Pattern Match Exhaustivity Warning: tests/neg-macros/i22212/Test_2.scala:2:34 -------------------------------- - 2 |@main def main() = Macro.makeMatch() - | ^^^^^^^^^^^^^^^^^ - | match may not be exhaustive. - | - | It would fail on pattern case: Baz - |-------------------------------------------------------------------------------------------------------------------- - |Inline stack trace - |- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |This location contains code that was inlined from Macro_1.scala:11 -11 | (_: Foo) match - | ^^^^^^ - |- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |This location contains code that was inlined from Macro_1.scala:11 -11 | (_: Foo) match - | ^ -12 | case Bar => () - -------------------------------------------------------------------------------------------------------------------- - | - | longer explanation available when compiling with `-explain` -No warnings can be incurred under -Werror (or -Xfatal-warnings) diff --git a/tests/neg-macros/i22212/Test_2.scala b/tests/neg-macros/i22212/Test_2.scala deleted file mode 100644 index fe8e51affbcc..000000000000 --- a/tests/neg-macros/i22212/Test_2.scala +++ /dev/null @@ -1,3 +0,0 @@ -//> using options -Xfatal-warnings -@main def main() = Macro.makeMatch() -// nopos-error: No warnings can be incurred under -Werror (or -Xfatal-warnings) diff --git a/tests/warn/i22212.check b/tests/warn/i22212.check new file mode 100644 index 000000000000..d81ec1ffeff8 --- /dev/null +++ b/tests/warn/i22212.check @@ -0,0 +1,21 @@ + +-- [E029] Pattern Match Exhaustivity Warning: tests/warn/i22212/Test_2.scala:3:19 -------------------------------------- +3 | Macro.makeMatch() // warn: match may not be exhaustive. + | ^^^^^^^^^^^^^^^^^ + | match may not be exhaustive. + | + | It would fail on pattern case: Baz + |--------------------------------------------------------------------------------------------------------------------- + |Inline stack trace + |- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + |This location contains code that was inlined from Macro_1.scala:7 +7 | (_: Foo) match + | ^^^^^^ + |- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + |This location contains code that was inlined from Macro_1.scala:7 +7 | (_: Foo) match + | ^ +8 | case Bar => () + --------------------------------------------------------------------------------------------------------------------- + | + | longer explanation available when compiling with `-explain` diff --git a/tests/warn/i22212/Data_1.scala b/tests/warn/i22212/Data_1.scala new file mode 100644 index 000000000000..1f14d9e2d3eb --- /dev/null +++ b/tests/warn/i22212/Data_1.scala @@ -0,0 +1,3 @@ +sealed trait Foo +case object Bar extends Foo +case object Baz extends Foo diff --git a/tests/neg-macros/i22212/Macro_1.scala b/tests/warn/i22212/Macro_1.scala similarity index 71% rename from tests/neg-macros/i22212/Macro_1.scala rename to tests/warn/i22212/Macro_1.scala index da64bdce9cc6..9fcd9a2273ac 100644 --- a/tests/neg-macros/i22212/Macro_1.scala +++ b/tests/warn/i22212/Macro_1.scala @@ -1,9 +1,5 @@ import scala.quoted._ -sealed trait Foo -case object Bar extends Foo -case object Baz extends Foo - object Macro { inline def makeMatch() = ${makeMatchImpl} def makeMatchImpl(using Quotes) = { diff --git a/tests/warn/i22212/Test_2.scala b/tests/warn/i22212/Test_2.scala new file mode 100644 index 000000000000..8990a85ff066 --- /dev/null +++ b/tests/warn/i22212/Test_2.scala @@ -0,0 +1,3 @@ +object Test: + def main(args: Array[String]): Unit = + Macro.makeMatch() // warn: match may not be exhaustive.