Commit c9b73a05 authored by Alex D's avatar Alex D 🍄

Implement -Wredundant-bang-patterns (#17340)

Add new flag '-Wredundant-bang-patterns' that enables checks for "dead" bangs.
Dead bangs are the ones that under no circumstances can force a thunk that
wasn't already forced. Dead bangs are a form of redundant bangs. The new check
is performed in Pattern-Match Coverage Checker along with other checks (namely,
redundant and inaccessible RHSs). Given

    f :: Bool -> Int
    f True = 1
    f !x   = 2

we can detect dead bang patterns by checking whether @x ~ ⊥@ is satisfiable
where the PmBang appears in 'checkGrdTree'. If not, then clearly the bang is
dead. Such a dead bang is then indicated in the annotated pattern-match tree by
a 'RedundantSrcBang' wrapping. In 'redundantAndInaccessibles', we collect
all dead bangs to warn about.

Note that we don't want to warn for a dead bang that appears on a redundant
clause. That is because in that case, we recommend to delete the clause wholly,
including its leading pattern match.

Dead bang patterns are redundant. But there are bang patterns which are
redundant that aren't dead, for example

    f !() = 0

the bang still forces the match variable, before we attempt to match on (). But
it is redundant with the forcing done by the () match. We currently don't
detect redundant bangs that aren't dead.
parent 7aa6ef11
Pipeline #21973 passed with stages
in 334 minutes and 13 seconds
......@@ -440,6 +440,7 @@ data WarningFlag =
| Opt_WarnUnusedTypePatterns
| Opt_WarnUnusedForalls
| Opt_WarnUnusedRecordWildcards
| Opt_WarnRedundantBangPatterns
| Opt_WarnRedundantRecordWildcards
| Opt_WarnWarningsDeprecations
| Opt_WarnDeprecatedFlags
......
......@@ -3428,6 +3428,7 @@ wWarningFlagsDeps = [
flagSpec "unused-top-binds" Opt_WarnUnusedTopBinds,
flagSpec "unused-type-patterns" Opt_WarnUnusedTypePatterns,
flagSpec "unused-record-wildcards" Opt_WarnUnusedRecordWildcards,
flagSpec "redundant-bang-patterns" Opt_WarnRedundantBangPatterns,
flagSpec "redundant-record-wildcards" Opt_WarnRedundantRecordWildcards,
flagSpec "warnings-deprecations" Opt_WarnWarningsDeprecations,
flagSpec "wrong-do-bind" Opt_WarnWrongDoBind,
......
......@@ -866,14 +866,14 @@ BUT we have a special case when abs_sig is true;
-- | Should we treat this as an unlifted bind? This will be true for any
-- bind that binds an unlifted variable, but we must be careful around
-- AbsBinds. See Note [Unlifted id check in isUnliftedHsBind]. For usage
-- information, see Note [Strict binds check] is "GHC.HsToCore.Binds".
-- information, see Note [Strict binds checks] is GHC.HsToCore.Binds.
isUnliftedHsBind :: HsBind GhcTc -> Bool -- works only over typechecked binds
isUnliftedHsBind bind
| AbsBinds { abs_exports = exports, abs_sig = has_sig } <- bind
= if has_sig
then any (is_unlifted_id . abe_poly) exports
else any (is_unlifted_id . abe_mono) exports
-- If has_sig is True we wil never generate a binding for abe_mono,
-- If has_sig is True we will never generate a binding for abe_mono,
-- so we don't need to worry about it being unlifted. The abe_poly
-- binding might not be: e.g. forall a. Num a => (# a, a #)
......
This diff is collapsed.
.. _release-8-14-1:
Version 8.14.1
==============
Compiler
~~~~~~~~
- New '-Wredundant-bang-patterns' flag that enables checks for "dead" bangs.
Dead bangs are the ones that under no circumstances can force a thunk that
wasn't already forced. Dead bangs are a form of redundant bangs. The new check
is performed in Pattern-Match Coverage Checker along with other checks (namely,
redundant and inaccessible RHSs). Given: ::
f :: Bool -> Int
f True = 1
f !x = 2
we can detect dead bang patterns by checking whether ``x ~ ⊥`` is satisfiable
where the ``PmBang`` appears in 'checkGrdTree'. If not, then clearly the bang is
dead.
Note that we don't want to warn for a dead bang that appears on a redundant
clause. That is because in that case, it is recommended to delete the clause wholly,
including its leading pattern match.
Dead bang patterns are redundant. But there are bang patterns which are
redundant that aren't dead, for example: ::
f !() = 0
the bang still forces the match variable, before we attempt to match on (). But
it is redundant with the forcing done by the () match. Currently such redundant
bangs are not considered dead.
......@@ -1627,6 +1627,28 @@ of ``-W(no-)*``.
would report that the ``P{..}`` match is unused.
.. ghc-flag:: -Wredundant-bang-patterns
:shortdesc: Warn about redundant bang patterns.
:type: dynamic
:reverse: -Wno-redundant-bang-patterns
:category:
:since: 8.12.1
.. index::
single: redundant, warning, bang patterns
Report all redundant bang patterns.
For instance: ::
f :: Bool -> Bool
f True = False
f !x = x
would report that the bang on ``x`` match variable is redundant and can be removed
since the argument was already forced in the first equation.
.. ghc-flag:: -Wredundant-record-wildcards
:shortdesc: Warn about record wildcard matches when the wildcard binds no patterns.
:type: dynamic
......
{-# LANGUAGE MagicHash #-}
{-# LANGUAGE BangPatterns #-}
{-# LANGUAGE ViewPatterns #-}
{-# LANGUAGE PatternSynonyms #-}
{-# LANGUAGE RecordWildCards #-}
{-# LANGUAGE ScopedTypeVariables #-}
module T17340 where
import GHC.Exts
data A = A { a :: () }
data B = B
newtype C = C Int
pattern P = B
f_nowarn :: Bool -> Bool
f_nowarn !x = x
f :: Bool -> Bool
f True = False
f !x = x
g :: (Int, Int) -> Bool -> ()
g (a,b) True = ()
g !x False = ()
data T = MkT !Int
h :: T -> ()
h (MkT !x) = ()
k :: Bool -> Int
k True = 1
k !_ = 2 -- clause is accessible, so warn for the bang
t :: () -> Bool -> Int
t _ True = 1
t !() True = 2 -- the clause has inaccessible RHS, warn for the bang
t _ False = 3
q :: Bool -> Int
q True = 1
q !True = 2 -- clause is redundant, don't warn for the bang
q False = 3
i :: Bool -> Int
i True = 1
i !x | x = 2 -- redundant
| not x = 3 -- accessible. This one will stay alive, so warn for the bang
newtype T2 a = T2 a
w :: T2 a -> Bool -> ()
w _ True = ()
w (T2 _) True = () -- redundant
w !_ True = () -- inaccessible
w _ _ = ()
z :: T2 a -> Bool -> ()
z _ True = ()
z t2 !x | T2 _ <- t2, x = () -- redundant
| !_ <- t2, x = () -- inaccessable
T17340.hs:21:4: warning: [-Wredundant-bang-patterns]
Pattern match has redundant bang
In an equation for ‘f’: f x = ...
T17340.hs:25:4: warning: [-Wredundant-bang-patterns]
Pattern match has redundant bang
In an equation for ‘g’: g x = ...
T17340.hs:33:4: warning: [-Wredundant-bang-patterns]
Pattern match has redundant bang
In an equation for ‘k’: k _ = ...
T17340.hs:37:1: warning: [-Woverlapping-patterns (in -Wdefault)]
Pattern match has inaccessible right hand side
In an equation for ‘t’: t !() True = ...
T17340.hs:42:1: warning: [-Woverlapping-patterns (in -Wdefault)]
Pattern match is redundant
In an equation for ‘q’: q !True = ...
T17340.hs:47:4: warning: [-Wredundant-bang-patterns]
Pattern match has redundant bang
In an equation for ‘i’: i x = ...
T17340.hs:47:8: warning: [-Woverlapping-patterns (in -Wdefault)]
Pattern match is redundant
In an equation for ‘i’: i !x | x = ...
T17340.hs:53:1: warning: [-Woverlapping-patterns (in -Wdefault)]
Pattern match is redundant
In an equation for ‘w’: w (T2 _) True = ...
T17340.hs:54:1: warning: [-Woverlapping-patterns (in -Wdefault)]
Pattern match has inaccessible right hand side
In an equation for ‘w’: w !_ True = ...
T17340.hs:59:7: warning: [-Wredundant-bang-patterns]
Pattern match has redundant bang
In an equation for ‘z’: z x = ...
T17340.hs:59:11: warning: [-Woverlapping-patterns (in -Wdefault)]
Pattern match is redundant
In an equation for ‘z’: z t2 !x | T2 _ <- t2, x = ...
T17340.hs:60:11: warning: [-Woverlapping-patterns (in -Wdefault)]
Pattern match has inaccessible right hand side
In an equation for ‘z’: z t2 !x | !_ <- t2, x = ...
......@@ -120,6 +120,8 @@ test('T17977b', collect_compiler_stats('bytes allocated',10), compile,
['-fwarn-incomplete-patterns -fwarn-overlapping-patterns'])
test('T18049', normal, compile,
['-fwarn-incomplete-patterns -fwarn-overlapping-patterns'])
test('T17340', normal, compile,
['-Wredundant-bang-patterns'])
# Other tests
test('pmc001', [], compile,
......
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