Magnus pushed to branch wip/mangoiv/9.12.5-rc4 at Glasgow Haskell Compiler / GHC

Commits:

30 changed files:

Changes:

  • changelog.d/27703
    1
    +section: compiler
    
    2
    +synopsis: Fix a bug where the specialiser could drop an argument that the
    
    3
    +  function's stable unfolding still used, resulting in a runtime crash.
    
    4
    +mrs: !16519
    
    5
    +issues: #27703

  • changelog.d/27704
    1
    +section: compiler
    
    2
    +synopsis: Fix a bug where a class declared abstractly in an hs-boot file was
    
    3
    +  assumed not to be unary, so GHC speculatively evaluated a dictionary that
    
    4
    +  could be bottom, crashing the program.
    
    5
    +mrs: !16519
    
    6
    +issues: #27704

  • compiler/GHC/Core.hs
    ... ... @@ -574,6 +574,17 @@ Wrinkle (NBD1)
    574 574
       say that /all/ unary-class constraints might diverge.  Remember, almost all
    
    575 575
       classes are non-unary, and thus definitely non-bottom.
    
    576 576
     
    
    577
    +Wrinkle (NBD2)
    
    578
    +  A class declared in an hs-boot file is an AbstractTyCon inside the module
    
    579
    +  loop:
    
    580
    +      module Callee where { class UC (a :: Type) }                -- Callee.hs-boot
    
    581
    +      module Callee where { class UC a where { ucm :: a -> a } }  -- Callee.hs
    
    582
    +  isUnaryClassTyCon returns False for it, but compiling the real declaration
    
    583
    +  may reveal a UnaryClassTyCon, whose dictionary is `ucm` and can be bottom.
    
    584
    +
    
    585
    +  Speculating a superclass selection from such a dictionary crashes (#27704).
    
    586
    +  So we must treat an AbstractTyCon as possibly unary.
    
    587
    +
    
    577 588
     Note [Case expression invariants]
    
    578 589
     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    
    579 590
     Case expressions are one of the more complicated elements of the Core
    

  • compiler/GHC/Core/Opt/Specialise.hs
    ... ... @@ -20,13 +20,12 @@ import GHC.Core.Multiplicity
    20 20
     import GHC.Core.SimpleOpt( defaultSimpleOpts, simpleOptExprWith )
    
    21 21
     import GHC.Core.Predicate
    
    22 22
     import GHC.Core.Coercion( Coercion )
    
    23
    -import GHC.Core.DataCon ( StrictnessMark (..) )
    
    24
    -import GHC.Core.Opt.Monad
    
    23
    +import GHC.Core.DataCon (dataConTyCon)
    
    25 24
     
    
    26 25
     import qualified GHC.Core.Subst as Core
    
    27 26
     import GHC.Core.Unfold.Make
    
    28 27
     import GHC.Core
    
    29
    -import GHC.Core.Opt.WorkWrap.Utils ( mkAbsentFiller )
    
    28
    +import GHC.Core.Make      ( wrapFloats )
    
    30 29
     import GHC.Core.Unify     ( tcMatchTy )
    
    31 30
     import GHC.Core.Rules
    
    32 31
     import GHC.Core.Utils     ( exprIsTrivial, exprIsTopLevelBindable
    
    ... ... @@ -70,6 +69,7 @@ import GHC.Core.Unfold
    70 69
     import Data.List( partition )
    
    71 70
     import Data.List.NonEmpty ( NonEmpty (..) )
    
    72 71
     import GHC.Core.Subst (substTickish)
    
    72
    +import GHC.Core.Opt.Monad
    
    73 73
     
    
    74 74
     {-
    
    75 75
     ************************************************************************
    
    ... ... @@ -1713,7 +1713,7 @@ specCalls spec_imp env existing_rules calls_for_me fn rhs
    1713 1713
     
    
    1714 1714
                ; ( useful, rhs_env2, leftover_bndrs
    
    1715 1715
                  , rule_bndrs, rule_lhs_args
    
    1716
    -             , spec_bndrs1, dx_binds, spec_args) <- specHeader this_mod env rhs_bndrs all_call_args
    
    1716
    +             , spec_bndrs1, dx_binds, spec_args) <- specHeader env rhs_bndrs all_call_args
    
    1717 1717
     
    
    1718 1718
     --           ; pprTrace "spec_call" (vcat
    
    1719 1719
     --                [ text "fun:       "  <+> ppr fn
    
    ... ... @@ -1794,7 +1794,7 @@ specCalls spec_imp env existing_rules calls_for_me fn rhs
    1794 1794
                      spec_fn_details
    
    1795 1795
                        = case idDetails fn of
    
    1796 1796
                            JoinId join_arity _ -> JoinId (join_arity - join_arity_decr) Nothing
    
    1797
    -                       DFunId is_nt        -> DFunId is_nt
    
    1797
    +                       DFunId terminating  -> DFunId terminating
    
    1798 1798
                            _                   -> VanillaId
    
    1799 1799
     
    
    1800 1800
                ; spec_fn <- newSpecIdSM (idName fn) spec_fn_ty spec_fn_details spec_fn_info
    
    ... ... @@ -2014,49 +2014,22 @@ In the rule, d1 and d2 are just wildcards, not used in the RHS. Note
    2014 2014
     additionally that 'x' isn't captured by this rule --- we bind only
    
    2015 2015
     enough etas in order to capture all of the *specialised* arguments.
    
    2016 2016
     
    
    2017
    -Note [Drop dead args from specialisations]
    
    2018
    -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    
    2019
    -When specialising a function, it’s possible some of the arguments may
    
    2020
    -actually be dead. For example, consider:
    
    2017
    +Note [Do not drop dead args from specialisations]
    
    2018
    +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    
    2019
    +When specialising a function, some of its arguments may be dead. For example
    
    2021 2020
     
    
    2022 2021
         f :: forall a. () -> Show a => a -> String
    
    2023 2022
         f x y = show y ++ "!"
    
    2024 2023
     
    
    2025
    -We might generate the following CallInfo for `f @Int`:
    
    2026
    -
    
    2027
    -    [SpecType Int, UnspecArg, SpecDict $dShowInt, UnspecArg]
    
    2028
    -
    
    2029
    -Normally we’d include both the x and y arguments in the
    
    2030
    -specialisation, since we’re not specialising on either of them. But
    
    2031
    -that’s silly, since x is actually unused! So we might as well drop it
    
    2032
    -in the specialisation:
    
    2033
    -
    
    2034
    -    $sf :: Int -> String
    
    2035
    -    $sf y = show y ++ "!"
    
    2036
    -
    
    2037
    -    {-# RULE "SPEC f @Int" forall x. f @Int x $dShow = $sf #-}
    
    2038
    -
    
    2039
    -This doesn’t save us much, since the arg would be removed later by
    
    2040
    -worker/wrapper, anyway, but it’s easy to do.
    
    2041
    -
    
    2042
    -Wrinkles
    
    2043
    -
    
    2044
    -* Note that we only drop dead arguments if:
    
    2045
    -    1. We don’t specialise on them.
    
    2046
    -    2. They come before an argument we do specialise on.
    
    2047
    -  Doing the latter would require eta-expanding the RULE, which could
    
    2048
    -  make it match less often, so it’s not worth it. Doing the former could
    
    2049
    -  be more useful --- it would stop us from generating pointless
    
    2050
    -  specialisations --- but it’s more involved to implement and unclear if
    
    2051
    -  it actually provides much benefit in practice.
    
    2052
    -
    
    2053
    -* If the function has a stable unfolding, specHeader has to come up with
    
    2054
    -  arguments to pass to that stable unfolding, when building the stable
    
    2055
    -  unfolding of the specialised function: this is the last field in specHeader's
    
    2056
    -  big result tuple.
    
    2024
    +gives the CallInfo [SpecType Int, UnspecArg, SpecDict $dShowInt, UnspecArg]
    
    2025
    +for `f @Int`, in which `x` is dead. We used to drop such an argument from the
    
    2026
    +specialisation and pass an absent filler in its place.
    
    2057 2027
     
    
    2058
    -  The right thing to do is to produce a LitRubbish; it should rapidly
    
    2059
    -  disappear.  Rather like GHC.Core.Opt.WorkWrap.Utils.mk_absent_let.
    
    2028
    +We no longer do so, because the filler is applied to the function's stable
    
    2029
    +unfolding template rather than to its optimised RHS, and the two may differ:
    
    2030
    +the argument can be dead in the RHS and not in the template. The specialised
    
    2031
    +function's unfolding then contains the filler, and any call site that inlines
    
    2032
    +it evaluates the error thunk. See #27703 for an instance of how this goes wrong.
    
    2060 2033
     
    
    2061 2034
     Note [Specialisation modulo dictionary selectors]
    
    2062 2035
     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    
    ... ... @@ -2121,8 +2094,7 @@ since we’ll generate a RULE like
    2121 2094
         RULE "SPEC f @Int" forall x [Occ=Dead].
    
    2122 2095
           f @Int x $dShow = $sf
    
    2123 2096
     
    
    2124
    -and Core Lint complains, even though x only appears on the LHS (due to
    
    2125
    -Note [Drop dead args from specialisations]).
    
    2097
    +and Core Lint complains, even though x only appears on the LHS.
    
    2126 2098
     
    
    2127 2099
     Why is that a Lint error? Because the arguments on the LHS of a rule
    
    2128 2100
     are syntactically expressions, not patterns, so Lint treats the
    
    ... ... @@ -2564,8 +2536,7 @@ isSpecDict _ = False
    2564 2536
     --    , [T1, T2, c, i, dEqT1, dShow1]
    
    2565 2537
     --    )
    
    2566 2538
     specHeader
    
    2567
    -     :: Module      -- The module being compiled, for mkAbsentFiller
    
    2568
    -     -> SpecEnv
    
    2539
    +     :: SpecEnv
    
    2569 2540
          -> [InBndr]    -- The binders from the original function 'f'
    
    2570 2541
          -> [SpecArg]   -- From the CallInfo
    
    2571 2542
          -> SpecM ( Bool     -- True <=> some useful specialisation happened
    
    ... ... @@ -2591,7 +2562,7 @@ specHeader
    2591 2562
     -- We want to specialise on type 'T1', and so we must construct a substitution
    
    2592 2563
     -- 'a->T1', as well as a LHS argument for the resulting RULE and unfolding
    
    2593 2564
     -- details.
    
    2594
    -specHeader mod env (bndr : bndrs) (SpecType ty : args)
    
    2565
    +specHeader env (bndr : bndrs) (SpecType ty : args)
    
    2595 2566
       = do { -- Find qvars, the type variables to add to the binders for the rule
    
    2596 2567
              -- Namely those free in `ty` that aren't in scope
    
    2597 2568
              -- See (MP2) in Note [Specialising polymorphic dictionaries]
    
    ... ... @@ -2603,7 +2574,7 @@ specHeader mod env (bndr : bndrs) (SpecType ty : args)
    2603 2574
                  ty'            = substTy env1 ty
    
    2604 2575
                  env2           = extendTvSubst env1 bndr ty'
    
    2605 2576
            ; (useful, env3, leftover_bndrs, rule_bs, rule_es, bs', dx, spec_args)
    
    2606
    -            <- specHeader mod env2 bndrs args
    
    2577
    +            <- specHeader env2 bndrs args
    
    2607 2578
            ; pure ( useful
    
    2608 2579
                   , env3
    
    2609 2580
                   , leftover_bndrs
    
    ... ... @@ -2619,10 +2590,10 @@ specHeader mod env (bndr : bndrs) (SpecType ty : args)
    2619 2590
     -- a substitution on it (in case the type refers to 'a'). Additionally, we need
    
    2620 2591
     -- to produce a binder, LHS argument and RHS argument for the resulting rule,
    
    2621 2592
     -- /and/ a binder for the specialised body.
    
    2622
    -specHeader mod env (bndr : bndrs) (UnspecType : args)
    
    2593
    +specHeader env (bndr : bndrs) (UnspecType : args)
    
    2623 2594
       = do { let (env', bndr') = substBndr env bndr
    
    2624 2595
            ; (useful, env'', leftover_bndrs, rule_bs, rule_es, bs', dx, spec_args)
    
    2625
    -            <- specHeader mod env' bndrs args
    
    2596
    +            <- specHeader env' bndrs args
    
    2626 2597
            ; pure ( useful
    
    2627 2598
                   , env''
    
    2628 2599
                   , leftover_bndrs
    
    ... ... @@ -2636,14 +2607,14 @@ specHeader mod env (bndr : bndrs) (UnspecType : args)
    2636 2607
     -- Next we want to specialise the 'Eq a' dict away. We need to construct
    
    2637 2608
     -- a wildcard binder to match the dictionary (See Note [Specialising Calls] for
    
    2638 2609
     -- the nitty-gritty), as a LHS rule and unfolding details.
    
    2639
    -specHeader mod env (bndr : bndrs) (SpecDict d : args)
    
    2610
    +specHeader env (bndr : bndrs) (SpecDict d : args)
    
    2640 2611
       | not (isDeadBinder bndr)
    
    2641 2612
       , allVarSet (`elemInScopeSet` in_scope) (exprFreeVars d)
    
    2642 2613
         -- See Note [Weird special case for SpecDict]
    
    2643 2614
       = do { (env1, bndr') <- newDictBndr env bndr -- See Note [Zap occ info in rule binders]
    
    2644 2615
            ; let (env2, dx_bind, spec_dict) = bindAuxiliaryDict env1 bndr bndr' d
    
    2645 2616
            ; (_, env3, leftover_bndrs, rule_bs, rule_es, bs', dx, spec_args)
    
    2646
    -             <- specHeader mod env2 bndrs args
    
    2617
    +             <- specHeader env2 bndrs args
    
    2647 2618
            ; pure ( True      -- Ha!  A useful specialisation!
    
    2648 2619
                   , env3
    
    2649 2620
                   , leftover_bndrs
    
    ... ... @@ -2668,27 +2639,14 @@ specHeader mod env (bndr : bndrs) (SpecDict d : args)
    2668 2639
     -- why 'i' doesn't appear in our RULE above. But we have no guarantee that
    
    2669 2640
     -- there aren't 'UnspecArg's which come /before/ all of the dictionaries, so
    
    2670 2641
     -- this case must be here.
    
    2671
    -specHeader mod env (bndr : bndrs) (_ : args)
    
    2642
    +specHeader env (bndr : bndrs) (_ : args)
    
    2672 2643
         -- The "_" can be UnSpecArg, or SpecDict where the bndr is dead
    
    2673 2644
       = do { -- see Note [Zap occ info in rule binders]
    
    2674 2645
              let (env', bndr') = substBndr env (zapIdOccInfo bndr)
    
    2675 2646
            ; (useful, env'', leftover_bndrs, rule_bs, rule_es, bs', dx, spec_args)
    
    2676
    -             <- specHeader mod env' bndrs args
    
    2677
    -
    
    2678
    -       ; let -- See Note [Drop dead args from specialisations]
    
    2679
    -             -- C.f. GHC.Core.Opt.WorkWrap.Utils.mk_absent_let
    
    2680
    -             (mb_spec_bndr, spec_arg)
    
    2681
    -                | isDeadBinder bndr
    
    2682
    -                , Just filler <- mkAbsentFiller mod bndr' NotMarkedStrict
    
    2683
    -                     -- NB: mkAbsentFiller returns Nothing for a terminating type (e.g. a
    
    2684
    -                     -- dictionary), so this guard fails and we fall through, keeping the
    
    2685
    -                     -- argument instead of dropping it.
    
    2686
    -                     -- See Note [Don't make fillers for terminating types]
    
    2687
    -                     -- in GHC.Core.Opt.WorkWrap.Utils
    
    2688
    -                = (Nothing, filler)
    
    2689
    -                | otherwise
    
    2690
    -                = (Just bndr', varToCoreExpr bndr')
    
    2647
    +             <- specHeader env' bndrs args
    
    2691 2648
     
    
    2649
    +       ; let (mb_spec_bndr, spec_arg) = (Just bndr', varToCoreExpr bndr')
    
    2692 2650
            ; pure ( useful
    
    2693 2651
                   , env''
    
    2694 2652
                   , leftover_bndrs
    
    ... ... @@ -2704,12 +2662,12 @@ specHeader mod env (bndr : bndrs) (_ : args)
    2704 2662
     
    
    2705 2663
     -- If we run out of binders, stop immediately
    
    2706 2664
     -- See Note [Specialisation Must Preserve Sharing]
    
    2707
    -specHeader _ env [] _ = pure (False, env, [], [], [], [], [], [])
    
    2665
    +specHeader env [] _ = pure (False, env, [], [], [], [], [], [])
    
    2708 2666
     
    
    2709 2667
     -- Return all remaining binders from the original function. These have the
    
    2710 2668
     -- invariant that they should all correspond to unspecialised arguments, so
    
    2711 2669
     -- it's safe to stop processing at this point.
    
    2712
    -specHeader _ env bndrs []
    
    2670
    +specHeader env bndrs []
    
    2713 2671
       = pure (False, env', bndrs', [], [], [], [], [])
    
    2714 2672
       where
    
    2715 2673
         (env', bndrs') = substBndrs env bndrs
    

  • compiler/GHC/Core/TyCon.hs
    ... ... @@ -46,8 +46,9 @@ module GHC.Core.TyCon(
    46 46
             noTcTyConScopedTyVars,
    
    47 47
     
    
    48 48
             -- ** Predicates on TyCons
    
    49
    -        isAlgTyCon, isVanillaAlgTyCon,
    
    50
    -        isClassTyCon, isFamInstTyCon,
    
    49
    +        isAlgTyCon, isVanillaAlgTyCon, isClassTyCon,
    
    50
    +        isUnaryClassTyCon, isUnaryClassTyCon_maybe, isTerminatingTyCon,
    
    51
    +        isFamInstTyCon,
    
    51 52
             isPrimTyCon,
    
    52 53
             isTupleTyCon, isUnboxedTupleTyCon, isBoxedTupleTyCon,
    
    53 54
             isUnboxedSumTyCon, isPromotedTupleTyCon,
    
    ... ... @@ -2721,6 +2722,27 @@ famTyConFlav_maybe (TyCon { tyConDetails = details })
    2721 2722
       | FamilyTyCon {famTcFlav = flav} <- details = Just flav
    
    2722 2723
       | otherwise                                 = Nothing
    
    2723 2724
     
    
    2725
    +isUnaryClassTyCon :: TyCon -> Bool
    
    2726
    +isUnaryClassTyCon tc = isClassTyCon tc && isNewTyCon tc
    
    2727
    +
    
    2728
    +isTerminatingTyCon :: TyCon -> Bool
    
    2729
    +-- ^ True <=> a value of type (T t1..tn), where `T` is this TyCon, cannot be bottom.
    
    2730
    +-- The only TyCons that satisfy `isTerminatingTyCon` are non-unary class TyCons.
    
    2731
    +-- See (UCM3) in Note [Unary class magic], and
    
    2732
    +-- Note [NON-BOTTOM-DICTS invariant] in GHC.Core.
    
    2733
    +-- An AbstractTyCon returns False: it comes from an hs-boot file, and the real
    
    2734
    +-- declaration may turn out to be a unary class. See (NBD2) in that Note.
    
    2735
    +isTerminatingTyCon tc = isClassTyCon tc && not (isUnaryClassTyCon tc)
    
    2736
    +                                        && not (isAbstractTyCon tc)
    
    2737
    +
    
    2738
    +isUnaryClassTyCon_maybe :: TyCon -> Maybe (Class, DataCon)
    
    2739
    +isUnaryClassTyCon_maybe (TyCon { tyConDetails = details })
    
    2740
    +  | AlgTyCon { algTcFlavour = ClassTyCon cls _
    
    2741
    +             , algTcRhs = NewTyCon {data_con = dc} } <- details
    
    2742
    +  = Just (cls, dc)
    
    2743
    +  | otherwise
    
    2744
    +  = Nothing
    
    2745
    +
    
    2724 2746
     -- | Is this 'TyCon' that for a class instance?
    
    2725 2747
     isClassTyCon :: TyCon -> Bool
    
    2726 2748
     isClassTyCon (TyCon { tyConDetails = details })
    

  • compiler/GHC/Core/Type.hs
    ... ... @@ -2479,7 +2479,7 @@ isTerminatingType :: HasDebugCallStack => Type -> Bool
    2479 2479
     -- NB: unlifted types are not terminating types!
    
    2480 2480
     --     e.g. you can write a term (loop 1)::Int# that diverges.
    
    2481 2481
     isTerminatingType ty = case tyConAppTyCon_maybe ty of
    
    2482
    -    Just tc -> isClassTyCon tc && not (isNewTyCon tc)
    
    2482
    +    Just tc -> isTerminatingTyCon tc
    
    2483 2483
         _       -> False
    
    2484 2484
     
    
    2485 2485
     isPrimitiveType :: Type -> Bool
    

  • compiler/GHC/Core/Utils.hs
    ... ... @@ -1934,7 +1934,7 @@ app_ok fun_ok primop_ok fun args
    1934 1934
     
    
    1935 1935
       | otherwise
    
    1936 1936
       = case idDetails fun of
    
    1937
    -      DFunId new_type -> not new_type
    
    1937
    +      DFunId terminating -> terminating
    
    1938 1938
              -- DFuns terminate, unless the dict is implemented
    
    1939 1939
              -- with a newtype in which case they may not
    
    1940 1940
     
    

  • compiler/GHC/IfaceToCore.hs
    ... ... @@ -1749,8 +1749,7 @@ tcIfaceDataAlt mult con inst_tys arg_strs rhs
    1749 1749
     tcIdDetails :: Name -> Type -> IfaceIdDetails -> IfL IdDetails
    
    1750 1750
     tcIdDetails _ _  IfVanillaId = return VanillaId
    
    1751 1751
     tcIdDetails _ _  (IfWorkerLikeId dmds) = return $ WorkerLikeId dmds
    
    1752
    -tcIdDetails _ ty IfDFunId
    
    1753
    -  = return (DFunId (isNewTyCon (classTyCon cls)))
    
    1752
    +tcIdDetails _ ty IfDFunId              = return (mkDFunIdDetails cls)
    
    1754 1753
       where
    
    1755 1754
         (_, _, cls, _) = tcSplitDFunTy ty
    
    1756 1755
     
    

  • compiler/GHC/Types/Id/Info.hs
    ... ... @@ -20,6 +20,7 @@ Haskell. [WDP 94/11])
    20 20
     module GHC.Types.Id.Info (
    
    21 21
             -- * The IdDetails type
    
    22 22
             IdDetails(..), pprIdDetails, coVarDetails, isCoVarDetails,
    
    23
    +        mkDFunIdDetails,
    
    23 24
             JoinArity, isJoinIdDetails_maybe,
    
    24 25
             RecSelParent(..), recSelParentName, recSelFirstConName,
    
    25 26
             recSelParentCons, idDetailsConcreteTvs,
    
    ... ... @@ -201,9 +202,8 @@ data IdDetails
    201 202
       | TickBoxOpId TickBoxOp       -- ^ The 'Id' is for a HPC tick box (both traditional and binary)
    
    202 203
     
    
    203 204
       | DFunId Bool                 -- ^ A dictionary function.
    
    204
    -       -- Bool = True <=> the class has only one method, so may be
    
    205
    -       --                  implemented with a newtype, so it might be bad
    
    206
    -       --                  to be strict on this dictionary
    
    205
    +       -- Bool = True <=> a dictionary of this class cannot be bottom
    
    206
    +       -- See Note [NON-BOTTOM-DICTS invariant] in GHC.Core
    
    207 207
     
    
    208 208
       | CoVarId    -- ^ A coercion variable
    
    209 209
                    -- This only covers /un-lifted/ coercions, of type
    
    ... ... @@ -372,6 +372,9 @@ isJoinIdDetails_maybe :: IdDetails -> Maybe (JoinArity, (Maybe [CbvMark]))
    372 372
     isJoinIdDetails_maybe (JoinId join_arity marks) = Just (join_arity, marks)
    
    373 373
     isJoinIdDetails_maybe _                   = Nothing
    
    374 374
     
    
    375
    +mkDFunIdDetails :: Class -> IdDetails
    
    376
    +mkDFunIdDetails cls = DFunId (isTerminatingTyCon (classTyCon cls))
    
    377
    +
    
    375 378
     instance Outputable IdDetails where
    
    376 379
         ppr = pprIdDetails
    
    377 380
     
    
    ... ... @@ -388,7 +391,8 @@ pprIdDetails other = brackets (pp other)
    388 391
        pp (PrimOpId {})           = text "PrimOp"
    
    389 392
        pp (FCallId _)             = text "ForeignCall"
    
    390 393
        pp (TickBoxOpId _)         = text "TickBoxOp"
    
    391
    -   pp (DFunId nt)             = text "DFunId" <> ppWhen nt (text "(nt)")
    
    394
    +   pp (DFunId terminating)    = text "DFunId"
    
    395
    +                                <> ppWhen (not terminating) (text "(may-be-bottom)")
    
    392 396
        pp (RecSelId { sel_naughty = is_naughty })
    
    393 397
                                   = brackets $ text "RecSel" <>
    
    394 398
                                                ppWhen is_naughty (text "(naughty)")
    

  • compiler/GHC/Types/Id/Make.hs
    ... ... @@ -1849,11 +1849,10 @@ mkDictFunId :: Name -- Name to use for the dict fun;
    1849 1849
     -- See Note [Dict funs and default methods]
    
    1850 1850
     
    
    1851 1851
     mkDictFunId dfun_name tvs theta clas tys
    
    1852
    -  = mkExportedLocalId (DFunId is_nt)
    
    1852
    +  = mkExportedLocalId (mkDFunIdDetails clas)
    
    1853 1853
                           dfun_name
    
    1854 1854
                           dfun_ty
    
    1855 1855
       where
    
    1856
    -    is_nt = isNewTyCon (classTyCon clas)
    
    1857 1856
         dfun_ty = TcType.tcMkDFunSigmaTy tvs theta (mkClassPred clas tys)
    
    1858 1857
     
    
    1859 1858
     {-
    

  • testsuite/tests/core-to-stg/T27704/Callee.hs
    1
    +module Callee where
    
    2
    +
    
    3
    +import Mid
    
    4
    +
    
    5
    +-- The real UC is a *unary* class: one method, no superclasses.  So a (UC a)
    
    6
    +-- dictionary *is* the function ucm, and it can be bottom.
    
    7
    +class UC a where
    
    8
    +  ucm :: a -> a
    
    9
    +
    
    10
    +instance UC Int where
    
    11
    +  ucm = undefined
    
    12
    +
    
    13
    +instance MC Int where
    
    14
    +  mcm _ = 7

  • testsuite/tests/core-to-stg/T27704/Callee.hs-boot
    1
    +{-# LANGUAGE KindSignatures #-}
    
    2
    +module Callee where
    
    3
    +
    
    4
    +import Data.Kind (Type)
    
    5
    +
    
    6
    +-- Abstract class declaration: no context, no methods, no associated types,
    
    7
    +-- so GHC.Tc.TyCl builds an AbstractTyCon rather than a UnaryClassTyCon.
    
    8
    +class UC (a :: Type)

  • testsuite/tests/core-to-stg/T27704/Main.hs
    1
    +module Main where
    
    2
    +import Mid
    
    3
    +import Callee ()
    
    4
    +
    
    5
    +main :: IO ()
    
    6
    +main = print (f (1 :: Int))

  • testsuite/tests/core-to-stg/T27704/Mid.hs
    1
    +{-# LANGUAGE GADTs, ConstraintKinds, ScopedTypeVariables #-}
    
    2
    +module Mid where
    
    3
    +
    
    4
    +import {-# SOURCE #-} Callee
    
    5
    +
    
    6
    +class UC a => MC a where
    
    7
    +  mcm :: a -> Int
    
    8
    +
    
    9
    +data Dict c where
    
    10
    +  Dict :: c => Dict c
    
    11
    +
    
    12
    +{-# NOINLINE keep #-}
    
    13
    +keep :: [Dict c] -> Int
    
    14
    +keep xs = length xs + 41
    
    15
    +
    
    16
    +{-# NOINLINE f #-}
    
    17
    +f :: forall a. MC a => a -> Int
    
    18
    +f _ = keep [Dict :: Dict (UC a)]

  • testsuite/tests/core-to-stg/T27704/T27704.stdout
    1
    +42

  • testsuite/tests/core-to-stg/T27704/all.T
    1
    +test('T27704',
    
    2
    +     [extra_files(['Main.hs', 'Mid.hs', 'Callee.hs', 'Callee.hs-boot'])],
    
    3
    +     multimod_compile_and_run,
    
    4
    +     ['Main', '-O'])

  • testsuite/tests/core-to-stg/T27704a/Callee.hs
    1
    +module Callee where
    
    2
    +
    
    3
    +import Mid ()
    
    4
    +
    
    5
    +-- Really unary: the dictionary /is/ ucm, so it can be bottom.
    
    6
    +class UC a where
    
    7
    +  ucm :: a -> a
    
    8
    +
    
    9
    +instance UC Int where
    
    10
    +  ucm = id
    
    11
    +
    
    12
    +instance UC a => UC [a] where
    
    13
    +  ucm = error "ucm[] forced"

  • testsuite/tests/core-to-stg/T27704a/Callee.hs-boot
    1
    +{-# LANGUAGE KindSignatures #-}
    
    2
    +module Callee where
    
    3
    +
    
    4
    +import Data.Kind (Type)
    
    5
    +
    
    6
    +-- No context, no methods, no associated types, so buildAbstractClass makes an
    
    7
    +-- AbstractTyCon rather than a UnaryClassTyCon: Mid cannot see that UC is unary.
    
    8
    +class UC (a :: Type)
    
    9
    +
    
    10
    +instance UC a => UC [a]

  • testsuite/tests/core-to-stg/T27704a/Main.hs
    1
    +module Main where
    
    2
    +import Mid
    
    3
    +import Callee ()
    
    4
    +
    
    5
    +main :: IO ()
    
    6
    +main = print (f (1 :: Int))

  • testsuite/tests/core-to-stg/T27704a/Mid.hs
    1
    +{-# LANGUAGE GADTs, ScopedTypeVariables #-}
    
    2
    +module Mid where
    
    3
    +
    
    4
    +import {-# SOURCE #-} Callee
    
    5
    +
    
    6
    +data Dict c where
    
    7
    +  Dict :: c => Dict c
    
    8
    +
    
    9
    +{-# NOINLINE keep #-}
    
    10
    +keep :: [Dict c] -> Int
    
    11
    +keep xs = length xs + 41
    
    12
    +
    
    13
    +-- Builds a (UC [a]) dictionary but never forces it.  The dfun comes from the
    
    14
    +-- hs-boot file, where UC looks non-unary, so its DFunId must not claim to
    
    15
    +-- terminate: with -fspec-eval-dictfun, CorePrep would speculate it.
    
    16
    +{-# NOINLINE f #-}
    
    17
    +f :: forall a. UC a => a -> Int
    
    18
    +f _ = keep [Dict :: Dict (UC [a])]

  • testsuite/tests/core-to-stg/T27704a/T27704a.stdout
    1
    +42

  • testsuite/tests/core-to-stg/T27704a/all.T
    1
    +test('T27704a',
    
    2
    +     [extra_files(['Main.hs', 'Mid.hs', 'Callee.hs', 'Callee.hs-boot'])],
    
    3
    +     multimod_compile_and_run,
    
    4
    +     ['Main', '-O -fspec-eval-dictfun'])

  • testsuite/tests/simplCore/should_compile/T17966.stderr
    ... ... @@ -113,19 +113,15 @@ $cm_aHo
    113 113
                (show @c_aHr $dShow_aHs c_aBh))
    
    114 114
     end Rec }
    
    115 115
     
    
    116
    --- RHS size: {terms: 1, types: 0, coercions: 10, joins: 0/0}
    
    117
    -T17966.$fCBoolb [InlPrag=INLINE (sat-args=0)]
    
    118
    -  :: forall b. Show b => C Bool b
    
    119
    -[LclIdX[DFunId(nt)],
    
    120
    - Arity=5,
    
    121
    - Unf=Unf{Src=InlineStable, TopLvl=True, Value=True, ConLike=True,
    
    122
    -         WorkFree=True, Expandable=True,
    
    123
    -         Guidance=ALWAYS_IF(arity=1,unsat_ok=False,boring_ok=True)
    
    124
    -         Tmpl= $cm_aHo
    
    125
    -               `cast` (forall (b :: <*>_N).
    
    126
    -                       <Show b>_R %<'Many>_N ->_R Sym (T17966.N:C[0] <Bool>_N <b>_N)
    
    127
    -                       :: (forall {b} c. (Show b, Show c) => Bool -> b -> c -> String)
    
    128
    -                          ~R# (forall {b}. Show b => C Bool b))}]
    
    116
    +-- RHS size: {terms: 5, types: 6, coercions: 0, joins: 0/0}
    
    117
    +T17966.$fCBoolb [InlPrag=CONLIKE] :: forall b. Show b => C Bool b
    
    118
    +[LclIdX[DFunId(may-be-bottom)],
    
    119
    + Arity=1,
    
    120
    + Unf=Unf{Src=StableSystem, TopLvl=True,
    
    121
    +         Value=True, ConLike=True, WorkFree=True, Expandable=True,
    
    122
    +         Guidance=ALWAYS_IF(arity=1,unsat_ok=True,boring_ok=False)
    
    123
    +         Tmpl= \ (@b_anX) (v_B1 [Occ=Once1] :: Show b_anX) ->
    
    124
    +                 T17966.C:C @Bool @b_anX ($cm_aJp @b_anX v_B1)}]
    
    129 125
     T17966.$fCBoolb
    
    130 126
       = $cm_aHo
    
    131 127
         `cast` (forall (b :: <*>_N).
    

  • testsuite/tests/simplCore/should_compile/T7785.stderr
    ... ... @@ -37,7 +37,7 @@ $cmyfmap_aG7
    37 37
     
    
    38 38
     -- RHS size: {terms: 1, types: 0, coercions: 3, joins: 0/0}
    
    39 39
     Foo.$fMyFunctor[] [InlPrag=INLINE (sat-args=0)] :: MyFunctor []
    
    40
    -[LclIdX[DFunId(nt)],
    
    40
    +[LclIdX[DFunId(may-be-bottom)],
    
    41 41
      Arity=4,
    
    42 42
      Str=<A><A><U><SU>,
    
    43 43
      Unf=Unf{Src=InlineStable, TopLvl=True, Value=True, ConLike=True,
    

  • testsuite/tests/simplCore/should_compile/spec004.hs
    1 1
     {-# LANGUAGE RankNTypes #-}
    
    2 2
     
    
    3
    --- Dead arguments should be dropped in specialisations. See !2913.
    
    3
    +-- Dead arguments are kept in specialisations.
    
    4
    +-- See Note [Do not drop dead args from specialisations] in GHC.Core.Opt.Specialise
    
    4 5
     
    
    5 6
     module ShouldCompile where
    
    6 7
     
    

  • testsuite/tests/simplCore/should_compile/spec004.stderr
    1 1
     
    
    2 2
     ==================== Specialise ====================
    
    3 3
     Result size of Specialise
    
    4
    -  = {terms: 52, types: 41, coercions: 0, joins: 0/0}
    
    4
    +  = {terms: 39, types: 38, coercions: 0, joins: 0/0}
    
    5 5
     
    
    6
    --- RHS size: {terms: 13, types: 10, coercions: 0, joins: 0/0}
    
    7
    -$sfoo [InlPrag=NOINLINE[0]] :: Int -> [Char]
    
    8
    -[LclId, Arity=1]
    
    6
    +-- RHS size: {terms: 14, types: 11, coercions: 0, joins: 0/0}
    
    7
    +$sfoo [InlPrag=NOINLINE[0]] :: () -> Int -> [Char]
    
    8
    +[LclId, Arity=2]
    
    9 9
     $sfoo
    
    10
    -  = \ (y :: Int) ->
    
    11
    -      GHC.Base.build
    
    10
    +  = \ (ds :: ()) (y :: Int) ->
    
    11
    +      GHC.Internal.Base.build
    
    12 12
             @Char
    
    13 13
             (\ (@b) (c [OS=OneShot] :: Char -> b -> b) (n [OS=OneShot] :: b) ->
    
    14 14
                GHC.Base.foldr
    
    15 15
                  @Char
    
    16 16
                  @b
    
    17 17
                  c
    
    18
    -             (GHC.CString.unpackFoldrCString# @b "!"# c n)
    
    19
    -             (GHC.Show.$fShowInt_$cshow y))
    
    18
    +             (GHC.Internal.Types.unpackFoldrCString# @b "!"# c n)
    
    19
    +             (GHC.Internal.Show.$fShowInt_$cshow y))
    
    20 20
     
    
    21 21
     -- RHS size: {terms: 17, types: 15, coercions: 0, joins: 0/0}
    
    22 22
     foo [InlPrag=NOINLINE[0]] :: forall a. () -> Show a => a -> String
    
    ... ... @@ -25,7 +25,9 @@ foo [InlPrag=NOINLINE[0]] :: forall a. () -> Show a => a -> String
    25 25
      Unf=Unf{Src=<vanilla>, TopLvl=True, Value=True, ConLike=True,
    
    26 26
              WorkFree=True, Expandable=True, Guidance=IF_ARGS [0 30 0] 150 40},
    
    27 27
      RULES: "SPEC foo @Int" [0]
    
    28
    -            forall (ds :: ()) ($dShow :: Show Int). foo @Int ds $dShow = $sfoo]
    
    28
    +            forall (ds [Occ=Once1] :: ()) ($dShow [Occ=Dead] :: Show Int).
    
    29
    +              foo @Int ds $dShow
    
    30
    +              = $sfoo ds]
    
    29 31
     foo
    
    30 32
       = \ (@a) _ [Occ=Dead] ($dShow :: Show a) (y :: a) ->
    
    31 33
           GHC.Base.build
    
    ... ... @@ -35,44 +37,9 @@ foo
    35 37
                  @Char
    
    36 38
                  @b
    
    37 39
                  c
    
    38
    -             (GHC.CString.unpackFoldrCString# @b "!"# c n)
    
    40
    +             (GHC.Internal.Types.unpackFoldrCString# @b "!"# c n)
    
    39 41
                  (show @a $dShow y))
    
    40 42
     
    
    41
    --- RHS size: {terms: 1, types: 0, coercions: 0, joins: 0/0}
    
    42
    -$trModule :: GHC.Prim.Addr#
    
    43
    -[LclId,
    
    44
    - Unf=Unf{Src=<vanilla>, TopLvl=True, Value=True, ConLike=True,
    
    45
    -         WorkFree=True, Expandable=True, Guidance=IF_ARGS [] 20 0}]
    
    46
    -$trModule = "main"#
    
    47
    -
    
    48
    --- RHS size: {terms: 2, types: 0, coercions: 0, joins: 0/0}
    
    49
    -$trModule :: GHC.Types.TrName
    
    50
    -[LclId,
    
    51
    - Unf=Unf{Src=<vanilla>, TopLvl=True, Value=True, ConLike=True,
    
    52
    -         WorkFree=True, Expandable=True, Guidance=IF_ARGS [] 10 10}]
    
    53
    -$trModule = GHC.Types.TrNameS $trModule
    
    54
    -
    
    55
    --- RHS size: {terms: 1, types: 0, coercions: 0, joins: 0/0}
    
    56
    -$trModule :: GHC.Prim.Addr#
    
    57
    -[LclId,
    
    58
    - Unf=Unf{Src=<vanilla>, TopLvl=True, Value=True, ConLike=True,
    
    59
    -         WorkFree=True, Expandable=True, Guidance=IF_ARGS [] 50 0}]
    
    60
    -$trModule = "ShouldCompile"#
    
    61
    -
    
    62
    --- RHS size: {terms: 2, types: 0, coercions: 0, joins: 0/0}
    
    63
    -$trModule :: GHC.Types.TrName
    
    64
    -[LclId,
    
    65
    - Unf=Unf{Src=<vanilla>, TopLvl=True, Value=True, ConLike=True,
    
    66
    -         WorkFree=True, Expandable=True, Guidance=IF_ARGS [] 10 10}]
    
    67
    -$trModule = GHC.Types.TrNameS $trModule
    
    68
    -
    
    69
    --- RHS size: {terms: 3, types: 0, coercions: 0, joins: 0/0}
    
    70
    -ShouldCompile.$trModule :: GHC.Types.Module
    
    71
    -[LclIdX,
    
    72
    - Unf=Unf{Src=<vanilla>, TopLvl=True, Value=True, ConLike=True,
    
    73
    -         WorkFree=True, Expandable=True, Guidance=IF_ARGS [] 10 10}]
    
    74
    -ShouldCompile.$trModule = GHC.Types.Module $trModule $trModule
    
    75
    -
    
    76 43
     -- RHS size: {terms: 5, types: 1, coercions: 0, joins: 0/0}
    
    77 44
     bar :: String
    
    78 45
     [LclIdX,
    

  • testsuite/tests/simplCore/should_run/T27703/Lib.hs
    1
    +{-# LANGUAGE RankNTypes #-}
    
    2
    +module Lib (g) where
    
    3
    +
    
    4
    +{-# NOINLINE consume #-}
    
    5
    +consume :: Int -> Int
    
    6
    +consume n = n `seq` 0
    
    7
    +
    
    8
    +{-# RULES "consume/drop" [~1] forall n. consume n = 0 #-}
    
    9
    +
    
    10
    +-- A dead value argument (n) that comes *before* the dictionary we
    
    11
    +-- specialise on.  No implicit parameters involved.
    
    12
    +{-# INLINE [1] f #-}
    
    13
    +f :: forall a. Int -> Show a => a -> String
    
    14
    +f n y = show y ++ replicate (consume n) '!'
    
    15
    +
    
    16
    +{-# NOINLINE g #-}
    
    17
    +g :: Bool -> String
    
    18
    +g b = f 7 b ++ "."

  • testsuite/tests/simplCore/should_run/T27703/Main.hs
    1
    +module Main where
    
    2
    +import Lib
    
    3
    +
    
    4
    +main :: IO ()
    
    5
    +main = putStrLn (g True)

  • testsuite/tests/simplCore/should_run/T27703/T27703.stdout
    1
    +True.

  • testsuite/tests/simplCore/should_run/T27703/all.T
    1
    +test('T27703',
    
    2
    +     [extra_files(['Main.hs', 'Lib.hs'])],
    
    3
    +     multimod_compile_and_run,
    
    4
    +     ['Main', '-O'])