Commit bec5350d authored by Georgios Karachalias's avatar Georgios Karachalias Committed by Ben Gamari
Browse files

Adding flags: -ffull-guard-reasoning and too-many-guards

Introduction of two new flags, for more precise control over the new
pattern match checker's behaviour when reasoning about guards. This is
supposed to address #11195 (and maybe more performance bugs related to
the NP-Hardness of coverage checking).

Expected behaviour:

  * When `-ffull-guard-reasoning` is on, run the new pattern match
    checker in its full power

  * When `-ffull-guard-reasoning` is off (the default), for every
    match, check a metric to see whether pattern match checking for it
    has high probability of being non performant (at the the moment we
    check whether the number of guards is over 20 but I would like to
    use a more precise measure in the future). If the probability is

    - Oversimplify the guards (less expressive but more performant)
      and run the checker, and

    - Issue a warning about the simplification that happened.

A new flag `-Wtoo-many-guards/-Wno-too-many-guards` suppresses the
warning about the simplification (useful when combined with -Werror).

Test Plan: validate

Reviewers: goldfire, austin, hvr, bgamari

Reviewed By: bgamari

Subscribers: mpickering, thomie

Differential Revision:

GHC Trac Issues: #11195
parent 07b3be76
This diff is collapsed.
......@@ -47,7 +47,7 @@ import Name
import Outputable
import BasicTypes ( isGenerated )
import Control.Monad( unless )
import Control.Monad( when, unless )
import qualified Data.Map as Map
......@@ -688,11 +688,25 @@ matchWrapper ctxt mb_scr (MG { mg_alts = L _ matches
; eqns_info <- mapM (mk_eqn_info new_vars) matches
-- pattern match check warnings
; unless (isGenerated origin) $
-- See Note [Type and Term Equality Propagation]
addTmCsDs (genCaseTmCs1 mb_scr new_vars) $
dsPmWarn dflags (DsMatchContext ctxt locn) $
checkMatches new_vars matches
; unless (isGenerated origin) $ do
when (isAnyPmCheckEnabled dflags (DsMatchContext ctxt locn)) $ do
-- Count the number of guards that can fail
guards <- computeNoGuards matches
let simplify = not (gopt Opt_FullGuardReasoning dflags)
&& (guards > maximum_failing_guards)
-- See Note [Type and Term Equality Propagation]
addTmCsDs (genCaseTmCs1 mb_scr new_vars) $
dsPmWarn dflags (DsMatchContext ctxt locn) $
checkMatches simplify new_vars matches
when (not (gopt Opt_FullGuardReasoning dflags)
&& wopt Opt_WarnTooManyGuards dflags
&& guards > maximum_failing_guards)
(warnManyGuards (DsMatchContext ctxt locn))
; result_expr <- handleWarnings $
matchEquations ctxt new_vars eqns_info rhs_ty
{-# LANGUAGE CPP, ScopedTypeVariables, MagicHash, UnboxedTuples #-}
#if __GLASGOW_HASKELL__ > 710
{-# OPTIONS_GHC -ffull-guard-reasoning #-}
......@@ -481,6 +481,8 @@ data GeneralFlag
| Opt_DistrustAllPackages
| Opt_PackageTrust
-- pm checking with guards
| Opt_FullGuardReasoning
deriving (Eq, Show, Enum)
data WarningFlag =
......@@ -502,6 +504,7 @@ data WarningFlag =
| Opt_WarnMissingLocalSigs
| Opt_WarnNameShadowing
| Opt_WarnOverlappingPatterns
| Opt_WarnTooManyGuards
| Opt_WarnTypeDefaults
| Opt_WarnMonomorphism
| Opt_WarnUnusedTopBinds
......@@ -2356,6 +2359,7 @@ dynamic_flags = [
, defGhcFlag "no-rtsopts" (NoArg (setRtsOptsEnabled RtsOptsNone))
, defGhcFlag "no-rtsopts-suggestions"
(noArg (\d -> d {rtsOptsSuggestions = False} ))
, defGhcFlag "main-is" (SepArg setMainIs)
, defGhcFlag "haddock" (NoArg (setGeneralFlag Opt_Haddock))
, defGhcFlag "haddock-opts" (hasArg addHaddockOpts)
......@@ -2875,6 +2879,7 @@ wWarningFlags = [
flagSpec "orphans" Opt_WarnOrphans,
flagSpec "overflowed-literals" Opt_WarnOverflowedLiterals,
flagSpec "overlapping-patterns" Opt_WarnOverlappingPatterns,
flagSpec "too-many-guards" Opt_WarnTooManyGuards,
flagSpec "missed-specialisations" Opt_WarnMissedSpecs,
flagSpec "all-missed-specialisations" Opt_WarnAllMissedSpecs,
flagSpec' "safe" Opt_WarnSafe setWarnSafe,
......@@ -3007,7 +3012,8 @@ fFlags = [
flagSpec "unbox-strict-fields" Opt_UnboxStrictFields,
flagSpec "vectorisation-avoidance" Opt_VectorisationAvoidance,
flagSpec "vectorise" Opt_Vectorise,
flagSpec "worker-wrapper" Opt_WorkerWrapper
flagSpec "worker-wrapper" Opt_WorkerWrapper,
flagSpec "full-guard-reasoning" Opt_FullGuardReasoning
-- | These @-f\<blah\>@ flags can all be reversed with @-fno-\<blah\>@
......@@ -3399,6 +3405,7 @@ optLevelFlags -- see Note [Documenting optimisation flags]
standardWarnings :: [WarningFlag]
standardWarnings -- see Note [Documenting warning flags]
= [ Opt_WarnOverlappingPatterns,
-- | Constants describing the DWARF format. Most of this simply
-- mirrors /usr/include/dwarf.h.
#if __GLASGOW_HASKELL__ > 710
{-# OPTIONS_GHC -ffull-guard-reasoning #-}
module Dwarf.Constants where
-- (c) The University of Glasgow 2006
{-# OPTIONS_GHC -fno-warn-overlapping-patterns -fno-warn-incomplete-patterns #-}
-- Inexplicably, this module takes 10GB of memory to compile with the new
-- (Nov '15) pattern-match check. This needs to be fixed. But we need
-- to be able to compile in the meantime.
#if __GLASGOW_HASKELL__ > 710
{-# OPTIONS_GHC -Wno-too-many-guards #-}
-- This module used to take 10GB of memory to compile with the new
-- (Nov '15) pattern-match check. In order to be able to compile it,
-- do not enable -ffull-guard-reasoning. Instead, simplify the guards
-- (default behaviour when guards are too many) but suppress the
-- "too-many-guards" warning (-Werror is on).
module OptCoercion ( optCoercion, checkAxInstCo ) where
......@@ -246,6 +246,16 @@ Compiler
To avoid warnings, unused type variables should be prefixed or replaced with
- Added the ``-Wtoo-many-guards`` flag. When enabled, this will issue a
warning if a pattern match contains too many guards (over 20 at the
moment). It is enabled by default but makes a difference only if pattern
match checking is also enabled.
- Added the ``-ffull-guard-reasoning`` flag. When enabled, pattern match
checking tries its best to reason about guards. Since the additional
expressivity may come with a high price in terms of compilation time and
memory consumption, it is turned off by default.
......@@ -381,11 +381,15 @@ Bugs in GHC
yield points are inserted at every function entrypoint (at the expense of a
bit of performance).
- GHC can warn about non-exhaustive or overlapping patterns (see
:ref:`options-sanity`), and usually does so correctly. But not
always. It gets confused by string patterns, and by guards, and can
then emit bogus warnings. The entire overlap-check code needs an
overhaul really.
- GHC's updated exhaustiveness and coverage checker (see
:ref:`options-sanity`) is quite expressive but with a rather high
performance cost (in terms of both time and memory consumption), mainly
due to guards. Two flags have been introduced to give more control to
the user over guard reasoning: ``-Wtoo-many-guards``
and ``-ffull-guard-reasoning`` (see :ref:`options-sanity`).
When ``-ffull-guard-reasoning`` is on, pattern match checking for guards
runs in full power, which may run out of memory/substantially increase
compilation time.
- GHC does not allow you to have a data type with a context that
mentions type variables that are not data type parameters. For
......@@ -538,6 +538,36 @@ of ``-W(no-)*``.
This option isn't enabled by default because it can be very noisy,
and it often doesn't indicate a bug in the program.
.. index::
single: -Wtoo-many-guards
single: too many guards, warning
The option ``-Wtoo-many-guards`` warns about places where a
pattern match contains too many guards (over 20 at the moment).
It is enabled by default but has an effect only if any form of
exhaustivness/overlapping checking is enabled (one of
``-Woverlapping-patterns``). The warning can be suppressed by
enabling either ``-Wno-too-many-guards``, which just hides the
warning, or ``-ffull-guard-reasoning``.
.. index::
single: -ffull-guard-reasoning
single: guard reasoning, warning
The option ``-ffull-guard-reasoning`` forces pattern match checking
to run in full. This gives more precise warnings concerning pattern
guards but in most cases increases memory consumption and
compilation time. Hence, it is off by default. Enabling
``-ffull-guard-reasoning`` also implies ``-Wno-too-many-guards``.
Note that (like ``-Wtoo-many-guards``) ``-ffull-guard-reasoning``
makes a difference only if pattern match checking is already
.. index::
single: -Wmissing-fields
{-# LANGUAGE Trustworthy #-}
{-# LANGUAGE CPP, NoImplicitPrelude #-}
{-# OPTIONS_GHC -ffull-guard-reasoning #-}
-- |
#if __GLASGOW_HASKELL__ > 710
{-# OPTIONS_GHC -Wno-too-many-guards #-}
module Test where
foo :: Double -> Int
......@@ -222,6 +222,11 @@ warningsOptions =
, flagType = DynamicFlag
, flagReverse = "-Wno-tabs"
, flag { flagName = "-Wtoo-many-guards"
, flagDescription = "warn when a match has too many guards"
, flagType = DynamicFlag
, flagReverse = "-Wno-too-many-guards"
, flag { flagName = "-Wtype-defaults"
, flagDescription = "warn when defaulting happens"
, flagType = DynamicFlag
......@@ -364,4 +369,12 @@ warningsOptions =
, flagType = DynamicFlag
, flagReverse = "-Wno-deriving-typeable"
, flag { flagName = "-ffull-guard-reasoning"
, flagDescription =
"enable the full reasoning of the pattern match checker "++
"concerning guards, for more precise exhaustiveness/coverage "++
, flagType = DynamicFlag
, flagReverse = "-fno-full-guard-reasoning"
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment