Sasha Bogicevic pushed to branch wip/27323 at Glasgow Haskell Compiler / GHC

Commits:

9 changed files:

Changes:

  • changelog.d/T27323
    1
    +section: compiler
    
    2
    +synopsis: Don't report compiler-generated bang patterns under -Wredundant-bang-patterns
    
    3
    +description:
    
    4
    +  With ``-XStrict``, GHC inserts bang patterns on binders. When such a bang
    
    5
    +  cannot force anything - for instance on a binder of unlifted type such as
    
    6
    +  ``Int#`` - it was reported by ``-Wredundant-bang-patterns``, even though
    
    7
    +  there is no bang in the source to remove. The warning now only reports
    
    8
    +  bangs the user actually wrote.
    
    9
    +
    
    10
    +  As part of this change, the ``XBangPat GhcTc`` extension field of
    
    11
    +  ``BangPat`` changed from ``NoExtField`` to ``Origin``, recording whether a
    
    12
    +  bang was user-written or compiler-generated. GHC API users constructing or
    
    13
    +  matching typechecked bang patterns may need a one-line adjustment.
    
    14
    +mrs: !16395
    
    15
    +issues: #27323

  • compiler/GHC/Hs/Pat.hs
    ... ... @@ -102,7 +102,11 @@ type instance XParPat GhcTc = NoExtField
    102 102
     
    
    103 103
     type instance XBangPat GhcPs = EpToken "!"
    
    104 104
     type instance XBangPat GhcRn = NoExtField
    
    105
    -type instance XBangPat GhcTc = NoExtField
    
    105
    +-- | Was this bang written by the user, or inserted by 'decideBangHood'
    
    106
    +-- because of -XStrict? Consulted by the pattern-match checker, which
    
    107
    +-- only reports user-written bangs under -Wredundant-bang-patterns.
    
    108
    +-- See Note [Dead bang patterns] in GHC.HsToCore.Pmc.Check.
    
    109
    +type instance XBangPat GhcTc = Origin
    
    106 110
     
    
    107 111
     type instance XListPat GhcPs = AnnList ()
    
    108 112
       -- After parsing, ListPat can refer to a built-in Haskell list pattern
    

  • compiler/GHC/HsToCore/Match.hs
    ... ... @@ -414,7 +414,7 @@ tidy1 :: Id -- The Id being scrutinised
    414 414
     tidy1 v g (ParPat _ pat)      = tidy1 v g (unLoc pat)
    
    415 415
     tidy1 v g (SigPat _ pat _)    = tidy1 v g (unLoc pat)
    
    416 416
     tidy1 _ _ (WildPat ty)        = return (idDsWrapper, WildPat ty)
    
    417
    -tidy1 v g (BangPat _ (L l p)) = tidy_bang_pat v g l p
    
    417
    +tidy1 v g (BangPat o (L l p)) = tidy_bang_pat v g o l p
    
    418 418
     tidy1 v g (ModifiedPat _ _ pat) = tidy1 v g (unLoc pat)
    
    419 419
     
    
    420 420
             -- case v of { x -> mr[] }
    
    ... ... @@ -530,30 +530,30 @@ tidy1 _ _ non_interesting_pat
    530 530
       = return (idDsWrapper, non_interesting_pat)
    
    531 531
     
    
    532 532
     --------------------
    
    533
    -tidy_bang_pat :: Id -> Bool -> SrcSpanAnnA -> Pat GhcTc
    
    533
    +tidy_bang_pat :: Id -> Bool -> Origin -> SrcSpanAnnA -> Pat GhcTc
    
    534 534
                   -> DsM (DsWrapper, Pat GhcTc)
    
    535 535
     
    
    536 536
     -- Discard par/sig under a bang
    
    537
    -tidy_bang_pat v g _ (ParPat _ (L l p))   = tidy_bang_pat v g l p
    
    538
    -tidy_bang_pat v g _ (SigPat _ (L l p) _) = tidy_bang_pat v g l p
    
    537
    +tidy_bang_pat v g o _ (ParPat _ (L l p))   = tidy_bang_pat v g o l p
    
    538
    +tidy_bang_pat v g o _ (SigPat _ (L l p) _) = tidy_bang_pat v g o l p
    
    539 539
     
    
    540 540
     -- Push the bang-pattern inwards, in the hope that
    
    541 541
     -- it may disappear next time
    
    542
    -tidy_bang_pat v g l (AsPat x v' p)
    
    543
    -  = tidy1 v g (AsPat x v' (L l (BangPat noExtField p)))
    
    544
    -tidy_bang_pat v g l (XPat (CoPat w p t))
    
    545
    -  = tidy1 v g (XPat $ CoPat w (BangPat noExtField (L l p)) t)
    
    546
    -tidy_bang_pat v g l (OrPat x (p:|ps)) -- push bang into first pat alt
    
    547
    -  = tidy1 v g (OrPat x (L l (BangPat noExtField p) :| ps))
    
    542
    +tidy_bang_pat v g o l (AsPat x v' p)
    
    543
    +  = tidy1 v g (AsPat x v' (L l (BangPat o p)))
    
    544
    +tidy_bang_pat v g o l (XPat (CoPat w p t))
    
    545
    +  = tidy1 v g (XPat $ CoPat w (BangPat o (L l p)) t)
    
    546
    +tidy_bang_pat v g o l (OrPat x (p:|ps)) -- push bang into first pat alt
    
    547
    +  = tidy1 v g (OrPat x (L l (BangPat o p) :| ps))
    
    548 548
     
    
    549 549
     -- Discard bang around strict pattern
    
    550
    -tidy_bang_pat v g _ p@(LitPat {})    = tidy1 v g p
    
    551
    -tidy_bang_pat v g _ p@(ListPat {})   = tidy1 v g p
    
    552
    -tidy_bang_pat v g _ p@(TuplePat {})  = tidy1 v g p
    
    553
    -tidy_bang_pat v g _ p@(SumPat {})    = tidy1 v g p
    
    550
    +tidy_bang_pat v g _ _ p@(LitPat {})    = tidy1 v g p
    
    551
    +tidy_bang_pat v g _ _ p@(ListPat {})   = tidy1 v g p
    
    552
    +tidy_bang_pat v g _ _ p@(TuplePat {})  = tidy1 v g p
    
    553
    +tidy_bang_pat v g _ _ p@(SumPat {})    = tidy1 v g p
    
    554 554
     
    
    555 555
     -- Data/newtype constructors
    
    556
    -tidy_bang_pat v g l p@(ConPat { pat_con = L _ (RealDataCon dc)
    
    556
    +tidy_bang_pat v g o l p@(ConPat { pat_con = L _ (RealDataCon dc)
    
    557 557
                                   , pat_args = args
    
    558 558
                                   , pat_con_ext = ConPatTc
    
    559 559
                                     { cpt_arg_tys = arg_tys
    
    ... ... @@ -562,7 +562,7 @@ tidy_bang_pat v g l p@(ConPat { pat_con = L _ (RealDataCon dc)
    562 562
       -- Newtypes: push bang inwards (#9844)
    
    563 563
       =
    
    564 564
         if isNewTyCon (dataConTyCon dc)
    
    565
    -      then tidy1 v g (p { pat_args = push_bang_into_newtype_arg l (scaledThing ty) args })
    
    565
    +      then tidy1 v g (p { pat_args = push_bang_into_newtype_arg l o (scaledThing ty) args })
    
    566 566
           else tidy1 v g p  -- Data types: discard the bang
    
    567 567
         where
    
    568 568
           (ty:_) = dataConInstArgTys dc arg_tys
    
    ... ... @@ -582,28 +582,29 @@ tidy_bang_pat v g l p@(ConPat { pat_con = L _ (RealDataCon dc)
    582 582
     --
    
    583 583
     -- NB: SigPatIn, ConPatIn should not happen
    
    584 584
     
    
    585
    -tidy_bang_pat _ _ l p = return (idDsWrapper, BangPat noExtField (L l p))
    
    585
    +tidy_bang_pat _ _ o l p = return (idDsWrapper, BangPat o (L l p))
    
    586 586
     
    
    587 587
     -------------------
    
    588 588
     push_bang_into_newtype_arg :: SrcSpanAnnA
    
    589
    +                           -> Origin
    
    589 590
                                -> Type -- The type of the argument we are pushing
    
    590 591
                                        -- onto
    
    591 592
                                -> HsConPatDetails GhcTc -> HsConPatDetails GhcTc
    
    592 593
     -- See Note [Bang patterns and newtypes]
    
    593 594
     -- We are transforming   !(N p)   into   (N !p)
    
    594
    -push_bang_into_newtype_arg l _ty (PrefixCon x (arg:args))
    
    595
    +push_bang_into_newtype_arg l o _ty (PrefixCon x (arg:args))
    
    595 596
       = assert (null args) $
    
    596
    -    PrefixCon x [L l (BangPat noExtField arg)]
    
    597
    -push_bang_into_newtype_arg l _ty (RecCon x rf)
    
    597
    +    PrefixCon x [L l (BangPat o arg)]
    
    598
    +push_bang_into_newtype_arg l o _ty (RecCon x rf)
    
    598 599
       | HsRecFields { rec_flds = L lf fld : flds } <- rf
    
    599 600
       , HsFieldBind { hfbRHS = arg } <- fld
    
    600 601
       = assert (null flds) $
    
    601 602
         RecCon x (rf { rec_flds = [L lf (fld { hfbRHS
    
    602
    -                                           = L l (BangPat noExtField arg) })] })
    
    603
    -push_bang_into_newtype_arg l ty (RecCon _ rf) -- If a user writes !(T {})
    
    603
    +                                           = L l (BangPat o arg) })] })
    
    604
    +push_bang_into_newtype_arg l o ty (RecCon _ rf) -- If a user writes !(T {})
    
    604 605
       | HsRecFields { rec_flds = [] } <- rf
    
    605
    -  = PrefixCon noExtField [L l (BangPat noExtField (noLocA (WildPat ty)))]
    
    606
    -push_bang_into_newtype_arg _ _ cd
    
    606
    +  = PrefixCon noExtField [L l (BangPat o (noLocA (WildPat ty)))]
    
    607
    +push_bang_into_newtype_arg _ _ _ cd
    
    607 608
       = pprPanic "push_bang_into_newtype_arg" (pprConArgs cd)
    
    608 609
     
    
    609 610
     {-
    

  • compiler/GHC/HsToCore/Pmc/Check.hs
    ... ... @@ -128,7 +128,9 @@ checkGrd grd = CA $ \inc -> case grd of
    128 128
         div <- addPhiCtNablas inc (PhiBotCt x)
    
    129 129
         matched <- addPhiCtNablas inc (PhiNotBotCt x)
    
    130 130
         -- See Note [Dead bang patterns]
    
    131
    -    -- mb_info = Just info <==> PmBang originates from bang pattern in source
    
    131
    +    -- mb_info = Just info <==> the PmBang originates from a user-written
    
    132
    +    -- bang pattern. Bangs inserted by -XStrict carry no info and are thus
    
    133
    +    -- never reported as redundant (#27323).
    
    132 134
         let bangs | Just info <- mb_info = unitOL (div, info)
    
    133 135
                   | otherwise            = NilOL
    
    134 136
         tracePm "check:Bang" (ppr x <+> ppr div)
    
    ... ... @@ -267,6 +269,22 @@ dead. So for a source bang, we add the refined Nabla and the source info to
    267 269
     the 'RedSet's 'rs_bangs'. When collecting stuff to warn, we test that Nabla for
    
    268 270
     inhabitants. If it's empty, we'll warn that it's redundant.
    
    269 271
     
    
    272
    +Crucially, we only ever warn about bangs the user wrote. With -XStrict, the
    
    273
    +compiler inserts bangs itself ('decideBangHood' in GHC.HsToCore.Utils), and
    
    274
    +such a bang is often dead. Consider (#27323)
    
    275
    +
    
    276
    +  {-# LANGUAGE MagicHash, Strict #-}
    
    277
    +  idInt# :: Int# -> Int#
    
    278
    +  idInt# x = x
    
    279
    +
    
    280
    +The binder `x` has unlifted type, so the bang that -XStrict inserts on it can
    
    281
    +never force anything. But warning would be deeply confusing: there is no bang
    
    282
    +in the source to delete! Whether a bang was user-written is recorded in the
    
    283
    +'XBangPat GhcTc' extension field ('Origin'); generated bangs desugar to a
    
    284
    +'PmBang' with no 'SrcInfo', so they still take part in divergence checking
    
    285
    +(that matters for the inaccessible-RHS warnings of #21761) but never end up
    
    286
    +in 'rs_bangs'.
    
    287
    +
    
    270 288
     Note that we don't want to warn for a dead bang that appears on a redundant
    
    271 289
     clause. That is because in that case, we recommend to delete the clause wholly,
    
    272 290
     including its leading pattern match.
    

  • compiler/GHC/HsToCore/Pmc/Desugar.hs
    ... ... @@ -18,6 +18,7 @@ import GHC.Data.FastString (unpackFS, lengthFS, mkFastStringShortText)
    18 18
     import GHC.Driver.DynFlags
    
    19 19
     import GHC.Hs
    
    20 20
     import GHC.Tc.Utils.TcMType (shortCutLit)
    
    21
    +import GHC.Types.Basic (isGenerated)
    
    21 22
     import GHC.Types.Id
    
    22 23
     import GHC.Core.ConLike
    
    23 24
     import GHC.Types.Name
    
    ... ... @@ -154,11 +155,11 @@ desugarPat x pat = case pat of
    154 155
       VarPat _ y   -> pure (mkPmLetVar (unLoc y) x)
    
    155 156
       ParPat _ p   -> desugarLPat x p
    
    156 157
       LazyPat _ _  -> pure GdEnd -- like a wildcard
    
    157
    -  BangPat _ p@(L l p') ->
    
    158
    +  BangPat orig p@(L l p') ->
    
    158 159
         -- Add the bang in front of the list, because it will happen before any
    
    159 160
         -- nested stuff.
    
    160 161
         consGrdDag (PmBang x pm_loc) <$> desugarLPat x p
    
    161
    -      where pm_loc = Just (SrcInfo (L (locA l) (ppr p')))
    
    162
    +      where pm_loc = if isGenerated orig then Nothing else Just (SrcInfo (L (locA l) (ppr p')))
    
    162 163
     
    
    163 164
       -- (x@pat)   ==>   Desugar pat with x as match var and handle impedance
    
    164 165
       --                 mismatch with incoming match var
    
    ... ... @@ -649,4 +650,12 @@ user *had* written a bang:
    649 650
     +    In an equation for ‘idV’: idV !v = ...
    
    650 651
     
    
    651 652
     So we live with the duplication.
    
    653
    +
    
    654
    +There is one wrinkle (#27323): the bang inserted by 'decideBangHood' is
    
    655
    +compiler-generated, marked 'Generated' in its 'XBangPat GhcTc' field. When
    
    656
    +'desugarPat' sees such a bang, it emits a 'PmBang' without 'SrcInfo', so
    
    657
    +that the checker performs the usual divergence check (giving the
    
    658
    +inaccessible-RHS warning above) but never reports the bang under
    
    659
    +-Wredundant-bang-patterns. See Note [Dead bang patterns] in
    
    660
    +GHC.HsToCore.Pmc.Check.
    
    652 661
     -}

  • compiler/GHC/HsToCore/Utils.hs
    ... ... @@ -53,6 +53,7 @@ import GHC.HsToCore.Monad
    53 53
     
    
    54 54
     import GHC.Core.Utils
    
    55 55
     import GHC.Core.Make
    
    56
    +import GHC.Types.Basic (Origin(Generated), GenReason(OtherExpansion), DoPmc(..))
    
    56 57
     import GHC.Types.Id.Make
    
    57 58
     import GHC.Types.Id
    
    58 59
     import GHC.Types.Literal
    
    ... ... @@ -956,6 +957,12 @@ Specifically:
    956 957
        !pat    => !pat   -- always
    
    957 958
        pat     => !pat   -- when -XStrict
    
    958 959
        pat     => pat    -- otherwise
    
    960
    +
    
    961
    +The bangs we add here are compiler-generated: we record 'Generated' in the
    
    962
    +'XBangPat GhcTc' extension field, whereas a user-written bang is typechecked
    
    963
    +to 'FromSource' (GHC.Tc.Gen.Pat). The pattern-match checker consults this
    
    964
    +field so that -Wredundant-bang-patterns only reports bangs that the user
    
    965
    +actually wrote (#27323). See Note [Dead bang patterns] in GHC.HsToCore.Pmc.Check.
    
    959 966
     -}
    
    960 967
     
    
    961 968
     
    
    ... ... @@ -975,7 +982,7 @@ decideBangHood dflags lpat
    975 982
                ParPat x p -> L l (ParPat x (go p))
    
    976 983
                LazyPat _ lp' -> lp'
    
    977 984
                BangPat _ _   -> lp
    
    978
    -           _             -> L l (BangPat noExtField lp)
    
    985
    +           _             -> L l (BangPat (Generated OtherExpansion DoPmc) lp)
    
    979 986
     
    
    980 987
     isTrueLHsExpr :: LHsExpr GhcTc -> Maybe (CoreExpr -> DsM CoreExpr)
    
    981 988
     
    

  • compiler/GHC/Tc/Gen/Pat.hs
    ... ... @@ -31,6 +31,7 @@ import GHC.Tc.Gen.Sig( TcPragEnv, lookupPragEnv, addInlinePrags )
    31 31
     import GHC.Tc.Utils.Monad
    
    32 32
     import GHC.Tc.Utils.Instantiate
    
    33 33
     import GHC.Types.FieldLabel
    
    34
    +import GHC.Types.Basic (Origin (FromSource))
    
    34 35
     import GHC.Types.Id
    
    35 36
     import GHC.Types.Var
    
    36 37
     import GHC.Types.Name
    
    ... ... @@ -627,9 +628,9 @@ tc_pat scaled_exp_pat_ty@(Scaled w_pat exp_pat_ty) penv ps_pat thing_inside =
    627 628
           { (pat', res) <- tc_lpat scaled_exp_pat_ty penv pat thing_inside
    
    628 629
           ; return (ParPat x pat', res) }
    
    629 630
     
    
    630
    -    BangPat x pat -> do
    
    631
    +    BangPat _ pat -> do
    
    631 632
           { (pat', res) <- tc_lpat scaled_exp_pat_ty penv pat thing_inside
    
    632
    -      ; return (BangPat x pat', res) }
    
    633
    +      ; return (BangPat FromSource pat', res) }
    
    633 634
     
    
    634 635
         OrPat _ pats -> do -- See Note [Implementation of OrPatterns], Typechecker (1)
    
    635 636
           { let pats_list   = NE.toList pats
    

  • testsuite/tests/pmcheck/should_compile/T27323.hs
    1
    +{-# LANGUAGE MagicHash, Strict #-}
    
    2
    +{-# OPTIONS_GHC -Wredundant-bang-patterns #-}
    
    3
    +
    
    4
    +import GHC.Prim (Int#)
    
    5
    +
    
    6
    +idInt# :: Int# -> Int#
    
    7
    +idInt# x = x
    
    8
    +
    
    9
    +main = pure ()

  • testsuite/tests/pmcheck/should_compile/all.T
    ... ... @@ -190,4 +190,5 @@ test('T24845', [], compile, [overlapping_incomplete])
    190 190
     test('T22652', [], compile, [overlapping_incomplete])
    
    191 191
     test('T22652a', [], compile, [overlapping_incomplete])
    
    192 192
     test('T24867', [], compile_fail, [overlapping_incomplete])
    
    193
    +test('T27323', normal, compile, ['-Wredundant-bang-patterns'])
    
    193 194
     test('T27360', normal, compile, [overlapping_incomplete + '-g3'])