Andreas Klebinger pushed to branch wip/andreask/spec_tyfams at Glasgow Haskell Compiler / GHC

Commits:

15 changed files:

Changes:

  • compiler/GHC/Core/Opt/Specialise.hs
    1
    +{-# LANGUAGE MultiWayIf #-}
    
    2
    +
    
    1 3
     {-
    
    2 4
     (c) The GRASP/AQUA Project, Glasgow University, 1993-1998
    
    3 5
     
    
    ... ... @@ -14,9 +16,9 @@ import GHC.Driver.Config.Diagnostic
    14 16
     import GHC.Driver.Config.Core.Rules ( initRuleOpts )
    
    15 17
     
    
    16 18
     import GHC.Core.Type  hiding( substTy, substCo, extendTvSubst, zapSubst )
    
    17
    -import GHC.Core.Multiplicity
    
    18
    -import GHC.Core.SimpleOpt( defaultSimpleOpts, simpleOptExprWith )
    
    19
    +import GHC.Core.SimpleOpt( defaultSimpleOpts, simpleOptExprWith, exprIsConApp_maybe )
    
    19 20
     import GHC.Core.Predicate
    
    21
    +import GHC.Core.Class( classMethods )
    
    20 22
     import GHC.Core.Coercion( Coercion )
    
    21 23
     import GHC.Core.Opt.Monad
    
    22 24
     import qualified GHC.Core.Subst as Core
    
    ... ... @@ -26,12 +28,12 @@ import GHC.Core.Make ( mkLitRubbish )
    26 28
     import GHC.Core.Unify     ( tcMatchTy )
    
    27 29
     import GHC.Core.Rules
    
    28 30
     import GHC.Core.Utils     ( exprIsTrivial, exprIsTopLevelBindable
    
    29
    -                          , mkCast, exprType
    
    31
    +                          , mkCast, exprType, exprIsHNF
    
    30 32
                               , stripTicksTop, mkInScopeSetBndrs )
    
    31 33
     import GHC.Core.FVs
    
    32 34
     import GHC.Core.TyCo.FVs ( tyCoVarsOfTypeList )
    
    33 35
     import GHC.Core.Opt.Arity( collectBindersPushingCo )
    
    34
    --- import GHC.Core.Ppr( pprIds )
    
    36
    +import GHC.Core.Ppr( pprIds )
    
    35 37
     
    
    36 38
     import GHC.Builtin.Types  ( unboxedUnitTy )
    
    37 39
     
    
    ... ... @@ -64,8 +66,11 @@ import GHC.Unit.Module.ModGuts
    64 66
     import GHC.Core.Unfold
    
    65 67
     
    
    66 68
     import Data.List( partition )
    
    67
    --- import Data.List.NonEmpty ( NonEmpty (..) )
    
    68 69
     import GHC.Core.Subst (substTickish)
    
    70
    +import GHC.Core.TyCon (tyConClass_maybe)
    
    71
    +import GHC.Core.DataCon (dataConTyCon)
    
    72
    +
    
    73
    +import Control.Monad
    
    69 74
     
    
    70 75
     {-
    
    71 76
     ************************************************************************
    
    ... ... @@ -1585,9 +1590,9 @@ specCalls spec_imp env existing_rules calls_for_me fn rhs
    1585 1590
     --      switch off specialisation for inline functions
    
    1586 1591
     
    
    1587 1592
       = -- pprTrace "specCalls: some" (vcat
    
    1588
    -    --   [ text "function" <+> ppr fn
    
    1589
    -    --    , text "calls:" <+> ppr calls_for_me
    
    1590
    -    --    , text "subst" <+> ppr (se_subst env) ]) $
    
    1593
    +    --  [ text "function" <+> ppr fn
    
    1594
    +    --  , text "calls:" <+> ppr calls_for_me
    
    1595
    +    --  , text "subst" <+> ppr (se_subst env) ]) $
    
    1591 1596
         foldlM spec_call ([], [], emptyUDs) calls_for_me
    
    1592 1597
     
    
    1593 1598
       | otherwise   -- No calls or RHS doesn't fit our preconceptions
    
    ... ... @@ -1635,21 +1640,21 @@ specCalls spec_imp env existing_rules calls_for_me fn rhs
    1635 1640
                  , rule_bndrs, rule_lhs_args
    
    1636 1641
                  , spec_bndrs1, dx_binds, spec_args) <- specHeader env rhs_bndrs all_call_args
    
    1637 1642
     
    
    1638
    ---           ; pprTrace "spec_call" (vcat
    
    1639
    ---                [ text "fun:       "  <+> ppr fn
    
    1640
    ---                , text "call info: "  <+> ppr _ci
    
    1641
    ---                , text "useful:    "  <+> ppr useful
    
    1642
    ---                , text "rule_bndrs:"  <+> ppr rule_bndrs
    
    1643
    ---                , text "lhs_args:  "  <+> ppr rule_lhs_args
    
    1644
    ---                , text "spec_bndrs1:" <+> ppr spec_bndrs1
    
    1645
    ---                , text "leftover_bndrs:" <+> pprIds leftover_bndrs
    
    1646
    ---                , text "spec_args: "  <+> ppr spec_args
    
    1647
    ---                , text "dx_binds:  "  <+> ppr dx_binds
    
    1648
    ---                , text "rhs_bndrs"     <+> ppr rhs_bndrs
    
    1649
    ---                , text "rhs_body"     <+> ppr rhs_body
    
    1650
    ---                , text "rhs_env2:  "  <+> ppr (se_subst rhs_env2)
    
    1651
    ---                , ppr dx_binds ]) $
    
    1652
    ---             return ()
    
    1643
    +          ; when False $ pprTrace "spec_call" (vcat
    
    1644
    +               [ text "fun:       "  <+> ppr fn
    
    1645
    +               , text "call info: "  <+> ppr _ci
    
    1646
    +               , text "useful:    "  <+> ppr useful
    
    1647
    +               , text "rule_bndrs:"  <+> ppr rule_bndrs
    
    1648
    +               , text "lhs_args:  "  <+> ppr rule_lhs_args
    
    1649
    +               , text "spec_bndrs1:" <+> ppr spec_bndrs1
    
    1650
    +               , text "leftover_bndrs:" <+> pprIds leftover_bndrs
    
    1651
    +               , text "spec_args: "  <+> ppr spec_args
    
    1652
    +               , text "dx_binds:  "  <+> ppr dx_binds
    
    1653
    +               , text "rhs_bndrs"     <+> ppr rhs_bndrs
    
    1654
    +               , text "rhs_body"     <+> ppr rhs_body
    
    1655
    +               , text "rhs_env2:  "  <+> ppr (se_subst rhs_env2)
    
    1656
    +               , ppr dx_binds ]) $
    
    1657
    +            return ()
    
    1653 1658
     
    
    1654 1659
                ; let all_rules = rules_acc ++ existing_rules
    
    1655 1660
                      -- all_rules: we look both in the rules_acc (generated by this invocation
    
    ... ... @@ -3043,30 +3048,15 @@ mkCallUDs' env f args
    3043 3048
         -- For "invisibleFunArg", which are the type-class dictionaries,
    
    3044 3049
         -- we decide on a case by case basis if we want to specialise
    
    3045 3050
         -- on this argument; if so, SpecDict, if not UnspecArg
    
    3046
    -    mk_spec_arg arg (Anon pred af)
    
    3051
    +    mk_spec_arg arg (Anon _pred af)
    
    3047 3052
           | isInvisibleFunArg af
    
    3048
    -      , interestingDict arg (scaledThing pred)
    
    3053
    +      , interestingDict env arg
    
    3054
    +      -- , interestingDict arg (scaledThing pred)
    
    3049 3055
                   -- See Note [Interesting dictionary arguments]
    
    3050 3056
           = SpecDict arg
    
    3051 3057
     
    
    3052 3058
           | otherwise = UnspecArg
    
    3053 3059
     
    
    3054
    -{-
    
    3055
    -Note [Ticks on applications]
    
    3056
    -~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    
    3057
    -Ticks such as source location annotations can sometimes make their way
    
    3058
    -onto applications (see e.g. #21697). So if we see something like
    
    3059
    -
    
    3060
    -    App (Tick _ f) e
    
    3061
    -
    
    3062
    -we need to descend below the tick to find what the real function being
    
    3063
    -applied is.
    
    3064
    -
    
    3065
    -The resulting RULE also has to be able to match this annotated use
    
    3066
    -site, so we only look through ticks that RULE matching looks through
    
    3067
    -(see Note [Tick annotations in RULE matching] in GHC.Core.Rules).
    
    3068
    --}
    
    3069
    -
    
    3070 3060
     wantCallsFor :: SpecEnv -> Id -> Bool
    
    3071 3061
     -- See Note [wantCallsFor]
    
    3072 3062
     wantCallsFor _env f
    
    ... ... @@ -3086,8 +3076,60 @@ wantCallsFor _env f
    3086 3076
           WorkerLikeId {}  -> True
    
    3087 3077
           RepPolyId {}     -> True
    
    3088 3078
     
    
    3089
    -{- Note [wantCallsFor]
    
    3090
    -~~~~~~~~~~~~~~~~~~~~~~
    
    3079
    +interestingDict :: SpecEnv -> CoreExpr -> Bool
    
    3080
    +-- This is a subtle and important function
    
    3081
    +-- See Note [Interesting dictionary arguments]
    
    3082
    +interestingDict env (Var v)  -- See (ID3) and (ID5)
    
    3083
    +  | Just rhs <- maybeUnfoldingTemplate (idUnfolding v)
    
    3084
    +  -- might fail for loop breaker dicts but that seems fine.
    
    3085
    +  = interestingDict env rhs
    
    3086
    +
    
    3087
    +interestingDict env arg  -- Main Plan: use exprIsConApp_maybe
    
    3088
    +  | Cast inner_arg _ <- arg  -- See (ID5)
    
    3089
    +  = if | isConstraintKind $ typeKind $ exprType inner_arg
    
    3090
    +       -- If coercions were always homo-kinded, we'd know
    
    3091
    +       -- that this would be the only case
    
    3092
    +       -> interestingDict env inner_arg
    
    3093
    +
    
    3094
    +       -- Check for an implicit parameter at the top
    
    3095
    +       | Just (cls,_) <- getClassPredTys_maybe arg_ty
    
    3096
    +       , isIPClass cls      -- See (ID4)
    
    3097
    +       -> False
    
    3098
    +
    
    3099
    +       -- Otherwise we are unwrapping a unary type class
    
    3100
    +       | otherwise
    
    3101
    +       -> exprIsHNF arg   -- See (ID7)
    
    3102
    +
    
    3103
    +  | Just (_, _, data_con, _tys, args) <- exprIsConApp_maybe in_scope_env arg
    
    3104
    +  , Just cls <- tyConClass_maybe (dataConTyCon data_con)
    
    3105
    +  , not_ip_like                  -- See (ID4)
    
    3106
    +  = if null (classMethods cls)   -- See (ID6)
    
    3107
    +    then any (interestingDict env) args
    
    3108
    +    else True
    
    3109
    +
    
    3110
    +  | otherwise
    
    3111
    +  = not (exprIsTrivial arg) && not_ip_like  -- See (ID8)
    
    3112
    +  where
    
    3113
    +    arg_ty       = exprType arg
    
    3114
    +    not_ip_like  = not (couldBeIPLike arg_ty)
    
    3115
    +    in_scope_env = ISE (substInScopeSet $ se_subst env) realIdUnfolding
    
    3116
    +
    
    3117
    +{- Note [Ticks on applications]
    
    3118
    +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    
    3119
    +Ticks such as source location annotations can sometimes make their way
    
    3120
    +onto applications (see e.g. #21697). So if we see something like
    
    3121
    +
    
    3122
    +    App (Tick _ f) e
    
    3123
    +
    
    3124
    +we need to descend below the tick to find what the real function being
    
    3125
    +applied is.
    
    3126
    +
    
    3127
    +The resulting RULE also has to be able to match this annotated use
    
    3128
    +site, so we only look through ticks that RULE matching looks through
    
    3129
    +(see Note [Tick annotations in RULE matching] in GHC.Core.Rules).
    
    3130
    +
    
    3131
    +Note [wantCallsFor]
    
    3132
    +~~~~~~~~~~~~~~~~~~~
    
    3091 3133
     `wantCallsFor env f` says whether the Specialiser should collect calls for
    
    3092 3134
     function `f`; other thing being equal, the fewer calls we collect the better. It
    
    3093 3135
     is False for things we can't specialise:
    
    ... ... @@ -3113,44 +3155,91 @@ collect usage info for imported overloaded functions.
    3113 3155
     
    
    3114 3156
     Note [Interesting dictionary arguments]
    
    3115 3157
     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    
    3116
    -In `mkCallUDs` we only use `SpecDict` for dictionaries of which
    
    3117
    -`interestingDict` holds.  Otherwise we use `UnspecArg`.  Two reasons:
    
    3118
    -
    
    3119
    -* Consider this
    
    3120
    -       \a.\d:Eq a.  let f = ... in ...(f d)...
    
    3121
    -  There really is not much point in specialising f wrt the dictionary d,
    
    3122
    -  because the code for the specialised f is not improved at all, because
    
    3123
    -  d is lambda-bound.  We simply get junk specialisations.
    
    3124
    -
    
    3125
    -* Consider this (#25703):
    
    3126
    -     f :: (Eq a, Show b) => a -> b -> INt
    
    3127
    -     goo :: forall x. (Eq x) => x -> blah
    
    3128
    -     goo @x (d:Eq x) (arg:x) = ...(f @x @Int d $fShowInt)...
    
    3129
    -  If we built a `ci_key` with a (SpecDict d) for `d`, we would end up
    
    3130
    -  discarding the call at the `\d`.  But if we use `UnspecArg` for that
    
    3131
    -  uninteresting `d`, we'll get a `ci_key` of
    
    3132
    -      f @x @Int UnspecArg (SpecDict $fShowInt)
    
    3133
    -  and /that/ can float out to f's definition and specialise nicely.
    
    3134
    -  Hooray.  (NB: the call can float only if `-fpolymorphic-specialisation`
    
    3135
    -  is on; otherwise it'll be trapped by the `\@x -> ...`.)(
    
    3136
    -
    
    3137
    -What is "interesting"?  (See `interestingDict`.)  Just that it has *some*
    
    3138
    -structure.  But what about variables?  We look in the variable's /unfolding/.
    
    3139
    -And that means that we must be careful to ensure that dictionaries /have/
    
    3140
    -unfoldings,
    
    3141
    -
    
    3142
    -* cloneBndrSM discards non-Stable unfoldings
    
    3143
    -* specBind updates the unfolding after specialisation
    
    3144
    -  See Note [Update unfolding after specialisation]
    
    3145
    -* bindAuxiliaryDict adds an unfolding for an aux dict
    
    3146
    -  see Note [Specialisation modulo dictionary selectors]
    
    3147
    -* specCase adds unfoldings for the new bindings it creates
    
    3148
    -
    
    3149
    -We accidentally lost accurate tracking of local variables for a long
    
    3150
    -time, because cloned variables didn't have unfoldings. But makes a
    
    3151
    -massive difference in a few cases, eg #5113. For nofib as a
    
    3152
    -whole it's only a small win: 2.2% improvement in allocation for ansi,
    
    3153
    -1.2% for bspt, but mostly 0.0!  Average 0.1% increase in binary size.
    
    3158
    +Consider this
    
    3159
    +         \a.\d:Eq a.  let f = ... in ...(f d)...
    
    3160
    +There really is not much point in specialising f wrt the dictionary d,
    
    3161
    +because the code for the specialised f is not improved at all, because
    
    3162
    +d is lambda-bound.  We simply get junk specialisations.
    
    3163
    +
    
    3164
    +What is "interesting"?  Our Main Plan is to use `exprIsConApp_maybe` to see
    
    3165
    +if the argument is a dictionary constructor applied to some arguments, in which
    
    3166
    +case we can clearly specialise. But there are wrinkles:
    
    3167
    +
    
    3168
    +(ID1) Note that we look at the argument /term/, not its /type/.  Suppose the
    
    3169
    +  argument is
    
    3170
    +         (% d1, d2 %) |> co
    
    3171
    +  where co :: (% Eq [a], Show [a] %) ~ F Int a, and `F` is a type family.
    
    3172
    +  Then its type (F Int a) looks very un-informative, but the term is super
    
    3173
    +  helpful.  See #19747 (where missing this point caused a 70x slow down)
    
    3174
    +  and #7785.
    
    3175
    +
    
    3176
    +(ID2) Note that the Main Plan works fine for an argument that is a DFun call,
    
    3177
    +   e.g.    $fOrdList $dOrdInt
    
    3178
    +   because `exprIsConApp_maybe` cleverly deals with DFunId applications.  Good!
    
    3179
    +
    
    3180
    +(ID3) For variables, we look in the variable's /unfolding/.  And that means
    
    3181
    +   that we must be careful to ensure that dictionaries /have/ unfoldings:
    
    3182
    +   * cloneBndrSM discards non-Stable unfoldings
    
    3183
    +   * specBind updates the unfolding after specialisation
    
    3184
    +     See Note [Update unfolding after specialisation]
    
    3185
    +   * bindAuxiliaryDict adds an unfolding for an aux dict
    
    3186
    +     see Note [Specialisation modulo dictionary selectors]
    
    3187
    +   * specCase adds unfoldings for the new bindings it creates
    
    3188
    +
    
    3189
    +   We accidentally lost accurate tracking of local variables for a long
    
    3190
    +   time, because cloned variables didn't have unfoldings. But makes a
    
    3191
    +   massive difference in a few cases, eg #5113. For nofib as a
    
    3192
    +   whole it's only a small win: 2.2% improvement in allocation for ansi,
    
    3193
    +   1.2% for bspt, but mostly 0.0!  Average 0.1% increase in binary size.
    
    3194
    +
    
    3195
    +(ID4) We must be very careful not to specialise on a "dictionary" that is, or contains
    
    3196
    +   an implicit parameter, because implicit parameters are emphatically not singleton
    
    3197
    +   types.  See #25999:
    
    3198
    +     useImplicit :: (?i :: Int) => Int
    
    3199
    +     useImplicit = ?i + 1
    
    3200
    +
    
    3201
    +     foo = let ?i = 1 in (useImplicit, let ?i = 2 in useImplicit)
    
    3202
    +   Both calls to `useImplicit` are at type `?i::Int`, but they pass different values.
    
    3203
    +   We must not specialise on implicit parameters!  Hence the call to `couldBeIPLike`.
    
    3204
    +
    
    3205
    +(ID5) Suppose the argument is (e |> co).  Can we rely on `exprIsConApp_maybe` to deal
    
    3206
    +   with the coercion.  No!  That only works if (co :: C t1 ~ C t2) with the same type
    
    3207
    +   constructor at the top of both sides.  But see the example in (ID1), where that
    
    3208
    +   is not true.  For thes same reason, we can't rely on `exprIsConApp_maybe` to look
    
    3209
    +   through unfoldings (because there might be a cast inside), hence dealing with
    
    3210
    +   expandable unfoldings in `interestingDict` directly.
    
    3211
    +
    
    3212
    +(ID6) The Main Plan says that it's worth specialising if the argument is an application
    
    3213
    +   of a dictionary contructor.  But what if the dictionary has no methods?  Then we
    
    3214
    +   gain nothing by specialising, unless the /superclasses/ are interesting.   A case
    
    3215
    +   in point is constraint tuples (% d1, .., dn %); a constraint N-tuple is a class
    
    3216
    +   with N superclasses and no methods.
    
    3217
    +
    
    3218
    +(ID7) A unary (single-method) class is currently represented by (meth |> co).  We
    
    3219
    +   will unwrap the cast (see (ID5)) and then want to reply "yes" if the method
    
    3220
    +   has any struture.  We rather arbitrarily use `exprIsHNF` for this.  (We plan a
    
    3221
    +   new story for unary classes, see #23109, and this special case will become
    
    3222
    +   irrelevant.)
    
    3223
    +
    
    3224
    +(ID8) Sadly, if `exprIsConApp_maybe` says Nothing, we still want to treat a
    
    3225
    +   non-trivial argument as interesting. In T19695 we have this:
    
    3226
    +      askParams :: Monad m => blah
    
    3227
    +      mhelper   :: MonadIO m => blah
    
    3228
    +      mhelper (d:MonadIO m) = ...(askParams @m ($p1 d))....
    
    3229
    +   where `$p1` is the superclass selector for `MonadIO`.  Now, if `mhelper` is
    
    3230
    +   specialised at `Handler` we'll get this call in the specialised `$smhelper`:
    
    3231
    +            askParams @Handler ($p1 $fMonadIOHandler)
    
    3232
    +   and we /definitely/ want to specialise that, even though the argument isn't
    
    3233
    +   visibly a dictionary application.  In fact the specialiser fires the superclass
    
    3234
    +   selector rule (see Note [Fire rules in the specialiser]), so we get
    
    3235
    +            askParams @Handler ($cp1MonadIO $fMonadIOIO)
    
    3236
    +   but it /still/ doesn't look like a dictionary application.
    
    3237
    +
    
    3238
    +   Conclusion: we optimistically assume that any non-trivial argument is worth
    
    3239
    +   specialising on.
    
    3240
    +
    
    3241
    +   So why do the `exprIsConApp_maybe` and `Cast` stuff? Because we want to look
    
    3242
    +   under type-family casts (ID1) and constraint tuples (ID6).
    
    3154 3243
     
    
    3155 3244
     Note [Update unfolding after specialisation]
    
    3156 3245
     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    
    ... ... @@ -3178,6 +3267,7 @@ Consider (#21848)
    3178 3267
     Now `f` turns into:
    
    3179 3268
     
    
    3180 3269
       f @a @b (dd :: D a) (ds :: Show b) a b
    
    3270
    +
    
    3181 3271
          = let dc :: D a = %p1 dd  -- Superclass selection
    
    3182 3272
            in meth @a dc ....
    
    3183 3273
               meth @a dc ....
    
    ... ... @@ -3193,27 +3283,6 @@ in the NonRec case of specBind. (This is too exotic to trouble with
    3193 3283
     the Rec case.)
    
    3194 3284
     -}
    
    3195 3285
     
    
    3196
    -interestingDict :: CoreExpr -> Type -> Bool
    
    3197
    --- A dictionary argument is interesting if it has *some* structure,
    
    3198
    --- see Note [Interesting dictionary arguments]
    
    3199
    --- NB: "dictionary" arguments include constraints of all sorts,
    
    3200
    ---     including equality constraints; hence the Coercion case
    
    3201
    --- To make this work, we need to ensure that dictionaries have
    
    3202
    --- unfoldings in them.
    
    3203
    -interestingDict arg arg_ty
    
    3204
    -  | not (typeDeterminesValue arg_ty) = False   -- See Note [Type determines value]
    
    3205
    -  | otherwise                        = go arg
    
    3206
    -  where
    
    3207
    -    go (Var v)               =  hasSomeUnfolding (idUnfolding v)
    
    3208
    -                             || isDataConWorkId v
    
    3209
    -    go (Type _)              = False
    
    3210
    -    go (Coercion _)          = False
    
    3211
    -    go (App fn (Type _))     = go fn
    
    3212
    -    go (App fn (Coercion _)) = go fn
    
    3213
    -    go (Tick _ a)            = go a
    
    3214
    -    go (Cast e _)            = go e
    
    3215
    -    go _                     = True
    
    3216
    -
    
    3217 3286
     thenUDs :: UsageDetails -> UsageDetails -> UsageDetails
    
    3218 3287
     thenUDs (MkUD {ud_binds = db1, ud_calls = calls1})
    
    3219 3288
             (MkUD {ud_binds = db2, ud_calls = calls2})
    

  • compiler/GHC/Core/Predicate.hs
    ... ... @@ -24,7 +24,7 @@ module GHC.Core.Predicate (
    24 24
       classMethodTy, classMethodInstTy,
    
    25 25
     
    
    26 26
       -- Implicit parameters
    
    27
    -  isIPLikePred, mentionsIP, isIPTyCon, isIPClass,
    
    27
    +  couldBeIPLike, mightMentionIP, isIPTyCon, isIPClass,
    
    28 28
       isCallStackTy, isCallStackPred, isCallStackPredTy,
    
    29 29
       isExceptionContextPred, isExceptionContextTy,
    
    30 30
       isIPPred_maybe,
    
    ... ... @@ -126,9 +126,12 @@ isDictTy ty = isClassPred pred
    126 126
       where
    
    127 127
         (_, pred) = splitInvisPiTys ty
    
    128 128
     
    
    129
    +-- | Is the type *guaranteed* to determine the value?
    
    130
    +--
    
    131
    +-- Might say No even if the type does determine the value. (See the Note)
    
    129 132
     typeDeterminesValue :: Type -> Bool
    
    130 133
     -- See Note [Type determines value]
    
    131
    -typeDeterminesValue ty = isDictTy ty && not (isIPLikePred ty)
    
    134
    +typeDeterminesValue ty = isDictTy ty && not (couldBeIPLike ty)
    
    132 135
     
    
    133 136
     getClassPredTys :: HasDebugCallStack => PredType -> (Class, [Type])
    
    134 137
     getClassPredTys ty = case getClassPredTys_maybe ty of
    
    ... ... @@ -171,6 +174,10 @@ So we treat implicit params just like ordinary arguments for the
    171 174
     purposes of specialisation.  Note that we still want to specialise
    
    172 175
     functions with implicit params if they have *other* dicts which are
    
    173 176
     class params; see #17930.
    
    177
    +
    
    178
    +It's also not always possible to infer that a type determines the value
    
    179
    +if type families are in play. See #19747 for one such example.
    
    180
    +
    
    174 181
     -}
    
    175 182
     
    
    176 183
     -- --------------------- Equality predicates ---------------------------------
    
    ... ... @@ -421,44 +428,44 @@ isCallStackTy ty
    421 428
       | otherwise
    
    422 429
       = False
    
    423 430
     
    
    424
    --- --------------------- isIPLike and mentionsIP  --------------------------
    
    431
    +-- --------------------- couldBeIPLike and mightMentionIP  --------------------------
    
    425 432
     --                 See Note [Local implicit parameters]
    
    426 433
     
    
    427
    -isIPLikePred :: Type -> Bool
    
    434
    +couldBeIPLike :: Type -> Bool
    
    428 435
     -- Is `pred`, or any of its superclasses, an implicit parameter?
    
    429 436
     -- See Note [Local implicit parameters]
    
    430
    -isIPLikePred pred =
    
    431
    -  mentions_ip_pred initIPRecTc (const True) (const True) pred
    
    432
    -
    
    433
    -mentionsIP :: (Type -> Bool) -- ^ predicate on the string
    
    434
    -           -> (Type -> Bool) -- ^ predicate on the type
    
    435
    -           -> Class
    
    436
    -           -> [Type] -> Bool
    
    437
    --- ^ @'mentionsIP' str_cond ty_cond cls tys@ returns @True@ if:
    
    437
    +couldBeIPLike pred
    
    438
    +  = might_mention_ip1 initIPRecTc (const True) (const True) pred
    
    439
    +
    
    440
    +mightMentionIP :: (Type -> Bool) -- ^ predicate on the string
    
    441
    +               -> (Type -> Bool) -- ^ predicate on the type
    
    442
    +               -> Class
    
    443
    +               -> [Type] -> Bool
    
    444
    +-- ^ @'mightMentionIP' str_cond ty_cond cls tys@ returns @True@ if:
    
    438 445
     --
    
    439 446
     --    - @cls tys@ is of the form @IP str ty@, where @str_cond str@ and @ty_cond ty@
    
    440 447
     --      are both @True@,
    
    441 448
     --    - or any superclass of @cls tys@ has this property.
    
    442 449
     --
    
    443 450
     -- See Note [Local implicit parameters]
    
    444
    -mentionsIP = mentions_ip initIPRecTc
    
    451
    +mightMentionIP = might_mention_ip initIPRecTc
    
    445 452
     
    
    446
    -mentions_ip :: RecTcChecker -> (Type -> Bool) -> (Type -> Bool) -> Class -> [Type] -> Bool
    
    447
    -mentions_ip rec_clss str_cond ty_cond cls tys
    
    453
    +might_mention_ip :: RecTcChecker -> (Type -> Bool) -> (Type -> Bool) -> Class -> [Type] -> Bool
    
    454
    +might_mention_ip rec_clss str_cond ty_cond cls tys
    
    448 455
       | Just (str_ty, ty) <- isIPPred_maybe cls tys
    
    449 456
       = str_cond str_ty && ty_cond ty
    
    450 457
       | otherwise
    
    451
    -  = or [ mentions_ip_pred rec_clss str_cond ty_cond (classMethodInstTy sc_sel_id tys)
    
    458
    +  = or [ might_mention_ip1 rec_clss str_cond ty_cond (classMethodInstTy sc_sel_id tys)
    
    452 459
            | sc_sel_id <- classSCSelIds cls ]
    
    453 460
     
    
    454 461
     
    
    455
    -mentions_ip_pred :: RecTcChecker -> (Type -> Bool) -> (Type -> Bool) -> Type -> Bool
    
    456
    -mentions_ip_pred rec_clss str_cond ty_cond ty
    
    462
    +might_mention_ip1 :: RecTcChecker -> (Type -> Bool) -> (Type -> Bool) -> Type -> Bool
    
    463
    +might_mention_ip1 rec_clss str_cond ty_cond ty
    
    457 464
       | Just (cls, tys) <- getClassPredTys_maybe ty
    
    458 465
       , let tc = classTyCon cls
    
    459 466
       , Just rec_clss' <- if isTupleTyCon tc then Just rec_clss
    
    460 467
                           else checkRecTc rec_clss tc
    
    461
    -  = mentions_ip rec_clss' str_cond ty_cond cls tys
    
    468
    +  = might_mention_ip rec_clss' str_cond ty_cond cls tys
    
    462 469
       | otherwise
    
    463 470
       = False -- Includes things like (D []) where D is
    
    464 471
               -- a Constraint-ranged family; #7785
    
    ... ... @@ -471,7 +478,7 @@ initIPRecTc = setRecTcMaxBound 1 initRecTc
    471 478
     See also wrinkle (SIP1) in Note [Shadowing of implicit parameters] in
    
    472 479
     GHC.Tc.Solver.Dict.
    
    473 480
     
    
    474
    -The function isIPLikePred tells if this predicate, or any of its
    
    481
    +The function couldBeIPLike tells if this predicate, or any of its
    
    475 482
     superclasses, is an implicit parameter.
    
    476 483
     
    
    477 484
     Why are implicit parameters special?  Unlike normal classes, we can
    
    ... ... @@ -479,7 +486,7 @@ have local instances for implicit parameters, in the form of
    479 486
        let ?x = True in ...
    
    480 487
     So in various places we must be careful not to assume that any value
    
    481 488
     of the right type will do; we must carefully look for the innermost binding.
    
    482
    -So isIPLikePred checks whether this is an implicit parameter, or has
    
    489
    +So couldBeIPLike checks whether this is an implicit parameter, or has
    
    483 490
     a superclass that is an implicit parameter.
    
    484 491
     
    
    485 492
     Several wrinkles
    
    ... ... @@ -520,16 +527,16 @@ Small worries (Sept 20):
    520 527
       think nothing does.
    
    521 528
     * I'm a little concerned about type variables; such a variable might
    
    522 529
       be instantiated to an implicit parameter.  I don't think this
    
    523
    -  matters in the cases for which isIPLikePred is used, and it's pretty
    
    530
    +  matters in the cases for which couldBeIPLike is used, and it's pretty
    
    524 531
       obscure anyway.
    
    525 532
     * The superclass hunt stops when it encounters the same class again,
    
    526 533
       but in principle we could have the same class, differently instantiated,
    
    527 534
       and the second time it could have an implicit parameter
    
    528 535
     I'm going to treat these as problems for another day. They are all exotic.
    
    529 536
     
    
    530
    -Note [Using typesAreApart when calling mentionsIP]
    
    531
    -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    
    532
    -We call 'mentionsIP' in two situations:
    
    537
    +Note [Using typesAreApart when calling mightMentionIP]
    
    538
    +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    
    539
    +We call 'mightMentionIP' in two situations:
    
    533 540
     
    
    534 541
       (1) to check that a predicate does not contain any implicit parameters
    
    535 542
           IP str ty, for a fixed literal str and any type ty,
    

  • compiler/GHC/Tc/Solver.hs
    ... ... @@ -1914,7 +1914,7 @@ growThetaTyVars theta tcvs
    1914 1914
       | otherwise  = transCloVarSet mk_next seed_tcvs
    
    1915 1915
       where
    
    1916 1916
         seed_tcvs = tcvs `unionVarSet` tyCoVarsOfTypes ips
    
    1917
    -    (ips, non_ips) = partition isIPLikePred theta
    
    1917
    +    (ips, non_ips) = partition couldBeIPLike theta
    
    1918 1918
                              -- See Note [Inheriting implicit parameters]
    
    1919 1919
     
    
    1920 1920
         mk_next :: VarSet -> VarSet -- Maps current set to newly-grown ones
    

  • compiler/GHC/Tc/Solver/Dict.hs
    ... ... @@ -749,7 +749,7 @@ shortCutSolver dflags ev_w ev_i
    749 749
         -- programs should typecheck regardless of whether we take this step or
    
    750 750
         -- not. See Note [Shortcut solving]
    
    751 751
     
    
    752
    -  , not (isIPLikePred (ctEvPred ev_w))   -- Not for implicit parameters (#18627)
    
    752
    +  , not (couldBeIPLike (ctEvPred ev_w))   -- Not for implicit parameters (#18627)
    
    753 753
     
    
    754 754
       , not (xopt LangExt.IncoherentInstances dflags)
    
    755 755
         -- If IncoherentInstances is on then we cannot rely on coherence of proofs
    

  • compiler/GHC/Tc/Solver/InertSet.hs
    ... ... @@ -2040,10 +2040,10 @@ solveOneFromTheOther ct_i ct_w
    2040 2040
          is_wsc_orig_w = isWantedSuperclassOrigin orig_w
    
    2041 2041
     
    
    2042 2042
          different_level_strategy  -- Both Given
    
    2043
    -       | isIPLikePred pred = if lvl_w `strictlyDeeperThan` lvl_i then KeepWork  else KeepInert
    
    2044
    -       | otherwise         = if lvl_w `strictlyDeeperThan` lvl_i then KeepInert else KeepWork
    
    2043
    +       | couldBeIPLike pred = if lvl_w `strictlyDeeperThan` lvl_i then KeepWork  else KeepInert
    
    2044
    +       | otherwise          = if lvl_w `strictlyDeeperThan` lvl_i then KeepInert else KeepWork
    
    2045 2045
            -- See Note [Replacement vs keeping] part (1)
    
    2046
    -       -- For the isIPLikePred case see Note [Shadowing of implicit parameters]
    
    2046
    +       -- For the couldBeIPLike case see Note [Shadowing of implicit parameters]
    
    2047 2047
            --                               in GHC.Tc.Solver.Dict
    
    2048 2048
     
    
    2049 2049
          same_level_strategy -- Both Given
    

  • compiler/GHC/Tc/Solver/Monad.hs
    ... ... @@ -401,8 +401,8 @@ updInertDicts dict_ct@(DictCt { di_cls = cls, di_ev = ev, di_tys = tys })
    401 401
         -- an implicit parameter (?str :: ty) for the given 'str' and any type 'ty'?
    
    402 402
         does_not_mention_ip_for :: Type -> DictCt -> Bool
    
    403 403
         does_not_mention_ip_for str_ty (DictCt { di_cls = cls, di_tys = tys })
    
    404
    -      = not $ mentionsIP (not . typesAreApart str_ty) (const True) cls tys
    
    405
    -        -- See Note [Using typesAreApart when calling mentionsIP]
    
    404
    +      = not $ mightMentionIP (not . typesAreApart str_ty) (const True) cls tys
    
    405
    +        -- See Note [Using typesAreApart when calling mightMentionIP]
    
    406 406
             -- in GHC.Core.Predicate
    
    407 407
     
    
    408 408
     updInertIrreds :: IrredCt -> TcS ()
    
    ... ... @@ -534,7 +534,7 @@ updSolvedDicts what dict_ct@(DictCt { di_cls = cls, di_tys = tys, di_ev = ev })
    534 534
       = do { is_callstack    <- is_tyConTy isCallStackTy        callStackTyConName
    
    535 535
            ; is_exceptionCtx <- is_tyConTy isExceptionContextTy exceptionContextTyConName
    
    536 536
            ; let contains_callstack_or_exceptionCtx =
    
    537
    -               mentionsIP
    
    537
    +               mightMentionIP
    
    538 538
                      (const True)
    
    539 539
                         -- NB: the name of the call-stack IP is irrelevant
    
    540 540
                         -- e.g (?foo :: CallStack) counts!
    
    ... ... @@ -552,9 +552,9 @@ updSolvedDicts what dict_ct@(DictCt { di_cls = cls, di_tys = tys, di_ev = ev })
    552 552
     
    
    553 553
         -- Return a predicate that decides whether a type is CallStack
    
    554 554
         -- or ExceptionContext, accounting for e.g. type family reduction, as
    
    555
    -    -- per Note [Using typesAreApart when calling mentionsIP].
    
    555
    +    -- per Note [Using typesAreApart when calling mightMentionIP].
    
    556 556
         --
    
    557
    -    -- See Note [Using isCallStackTy in mentionsIP].
    
    557
    +    -- See Note [Using isCallStackTy in mightMentionIP].
    
    558 558
         is_tyConTy :: (Type -> Bool) -> Name -> TcS (Type -> Bool)
    
    559 559
         is_tyConTy is_eq tc_name
    
    560 560
           = do { (mb_tc, _) <- wrapTcS $ TcM.tryTc $ TcM.tcLookupTyCon tc_name
    
    ... ... @@ -582,14 +582,14 @@ in a different context!
    582 582
     See also Note [Shadowing of implicit parameters], which deals with a similar
    
    583 583
     problem with Given implicit parameter constraints.
    
    584 584
     
    
    585
    -Note [Using isCallStackTy in mentionsIP]
    
    586
    -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    
    585
    +Note [Using isCallStackTy in mightMentionIP]
    
    586
    +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    
    587 587
     To implement Note [Don't add HasCallStack constraints to the solved set],
    
    588 588
     we need to check whether a constraint contains a HasCallStack or HasExceptionContext
    
    589 589
     constraint. We do this using the 'mentionsIP' function, but as per
    
    590
    -Note [Using typesAreApart when calling mentionsIP] we don't want to simply do:
    
    590
    +Note [Using typesAreApart when calling mightMentionIP] we don't want to simply do:
    
    591 591
     
    
    592
    -  mentionsIP
    
    592
    +  mightMentionIP
    
    593 593
         (const True) -- (ignore the implicit parameter string)
    
    594 594
         (isCallStackTy <||> isExceptionContextTy)
    
    595 595
     
    

  • compiler/GHC/Tc/Utils/TcType.hs
    ... ... @@ -155,7 +155,7 @@ module GHC.Tc.Utils.TcType (
    155 155
       mkTyConTy, mkTyVarTy, mkTyVarTys,
    
    156 156
       mkTyCoVarTy, mkTyCoVarTys,
    
    157 157
     
    
    158
    -  isClassPred, isEqPred, isIPLikePred, isEqClassPred,
    
    158
    +  isClassPred, isEqPred, couldBeIPLike, isEqClassPred,
    
    159 159
       isEqualityClass, mkClassPred,
    
    160 160
       tcSplitQuantPredTy, tcSplitDFunTy, tcSplitDFunHead, tcSplitMethodTy,
    
    161 161
       isRuntimeRepVar, isFixedRuntimeRepKind,
    
    ... ... @@ -1819,7 +1819,7 @@ pickCapturedPreds
    1819 1819
     pickCapturedPreds qtvs theta
    
    1820 1820
       = filter captured theta
    
    1821 1821
       where
    
    1822
    -    captured pred = isIPLikePred pred || (tyCoVarsOfType pred `intersectsVarSet` qtvs)
    
    1822
    +    captured pred = couldBeIPLike pred || (tyCoVarsOfType pred `intersectsVarSet` qtvs)
    
    1823 1823
     
    
    1824 1824
     
    
    1825 1825
     -- Superclasses
    

  • testsuite/tests/perf/should_run/SpecTyFamRun.hs
    1
    +{-# OPTIONS_GHC -fspecialise-aggressively #-}
    
    2
    +{-# OPTIONS_GHC -fno-spec-constr #-}
    
    3
    +module Main(main) where
    
    4
    +
    
    5
    +import SpecTyFam_Import (specMe, MaybeShowNum)
    
    6
    +import GHC.Exts
    
    7
    +
    
    8
    +-- We want to see a specialization of `specMe` which doesn't take a dictionary at runtime.
    
    9
    +
    
    10
    +{-# NOINLINE foo #-}
    
    11
    +foo :: Int -> (String,Int)
    
    12
    +-- We want specMe to be specialized, but not inlined
    
    13
    +foo x = specMe True x
    
    14
    +
    
    15
    +main = print $ sum $ map (snd . foo) [1..1000 :: Int]

  • testsuite/tests/perf/should_run/SpecTyFamRun.stdout
    1
    +500500

  • testsuite/tests/perf/should_run/SpecTyFam_Import.hs
    1
    +{-# LANGUAGE TypeFamilies #-}
    
    2
    +{-# LANGUAGE BangPatterns #-}
    
    3
    +
    
    4
    +module SpecTyFam_Import (specMe, MaybeShowNum) where
    
    5
    +
    
    6
    +import Data.Kind
    
    7
    +
    
    8
    +type family MaybeShowNum a n :: Constraint where
    
    9
    +  MaybeShowNum a n = (Show a, Num n)
    
    10
    +
    
    11
    +{-# INLINABLE specMe #-}
    
    12
    +specMe :: (Integral n, MaybeShowNum a n) => a -> n -> (String,n)
    
    13
    +specMe s !n = (show s, n+1 `div` 2)

  • testsuite/tests/perf/should_run/all.T
    ... ... @@ -423,3 +423,12 @@ test('ByteCodeAsm',
    423 423
                    ],
    
    424 424
                    compile_and_run,
    
    425 425
                    ['-package ghc'])
    
    426
    +
    
    427
    +# Check that $s$wspecMe doesn't have any dictionary args after specialization in addition to perf stats
    
    428
    +# See also #19747
    
    429
    +test('SpecTyFamRun', [ grep_errmsg(r'foo')
    
    430
    +                    , extra_files(['SpecTyFam_Import.hs'])
    
    431
    +                    , only_ways(['optasm'])
    
    432
    +                    , collect_stats('bytes allocated', 5)],
    
    433
    +     multimod_compile_and_run,
    
    434
    +     ['SpecTyFamRun', '-O2'])

  • testsuite/tests/simplCore/should_compile/T26051.hs
    1
    +{-# OPTIONS_GHC -fspecialise-aggressively #-}
    
    2
    +{-# OPTIONS_GHC -fno-spec-constr #-}
    
    3
    +
    
    4
    +module T26051(main, foo) where
    
    5
    +
    
    6
    +import T26051_Import (specMe, MaybeShowNum)
    
    7
    +import GHC.Exts
    
    8
    +
    
    9
    +-- We want to see a specialization of `specMe` which doesn't take a dictionary at runtime.
    
    10
    +
    
    11
    +{-# OPAQUE foo #-}
    
    12
    +foo :: Int -> (String,Int)
    
    13
    +foo x = specMe True x
    
    14
    +
    
    15
    +main = print $ sum $ map (snd . foo) [1..1000 :: Int]

  • testsuite/tests/simplCore/should_compile/T26051.stderr
    1
    +[1 of 2] Compiling T26051_Import    ( T26051_Import.hs, T26051_Import.o )
    
    2
    +
    
    3
    +==================== Specialise ====================
    
    4
    +Result size of Specialise = {terms: 31, types: 39, coercions: 8, joins: 0/1}
    
    5
    +
    
    6
    +-- RHS size: {terms: 30, types: 27, coercions: 8, joins: 0/1}
    
    7
    +specMe [InlPrag=INLINABLE] :: forall n a. (Integral n, MaybeShowNum a n) => a -> n -> (String, n)
    
    8
    +[LclIdX,
    
    9
    + Arity=4,
    
    10
    + Unf=Unf{Src=StableUser, TopLvl=True, Value=True, ConLike=True, WorkFree=True, Expandable=True, Guidance=IF_ARGS [30 0 0 20] 260 10
    
    11
    +         Tmpl= \ (@n) (@a) ($dIntegral [Occ=Once1] :: Integral n) (irred :: MaybeShowNum a n) (eta [Occ=Once1] :: a) (eta [Occ=Once1] :: n) ->
    
    12
    +                 let {
    
    13
    +                   $dNum :: Num n
    
    14
    +                   [LclId, Unf=Unf{Src=<vanilla>, TopLvl=False, Value=False, ConLike=False, WorkFree=False, Expandable=True, Guidance=IF_ARGS [] 20 0}]
    
    15
    +                   $dNum = GHC.Internal.Classes.$p1CTuple2 @(Show a) @(Num n) (irred `cast` (Sub (T26051_Import.D:R:MaybeShowNum[0] <a>_N <n>_N) :: MaybeShowNum a n ~R# (Show a, Num n))) } in
    
    16
    +                 case eta of n [Occ=Once1] { __DEFAULT -> (show @a (GHC.Internal.Classes.$p0CTuple2 @(Show a) @(Num n) (irred `cast` (Sub (T26051_Import.D:R:MaybeShowNum[0] <a>_N <n>_N) :: MaybeShowNum a n ~R# (Show a, Num n)))) eta, + @n $dNum n (div @n $dIntegral (fromInteger @n $dNum (GHC.Internal.Bignum.Integer.IS 1#)) (fromInteger @n $dNum (GHC.Internal.Bignum.Integer.IS 2#)))) }}]
    
    17
    +specMe
    
    18
    +  = \ (@n) (@a) ($dIntegral :: Integral n) (irred :: MaybeShowNum a n) (eta :: a) (eta :: n) ->
    
    19
    +      let {
    
    20
    +        $dNum :: Num n
    
    21
    +        [LclId, Unf=Unf{Src=<vanilla>, TopLvl=False, Value=False, ConLike=False, WorkFree=False, Expandable=True, Guidance=IF_ARGS [] 20 0}]
    
    22
    +        $dNum = GHC.Internal.Classes.$p1CTuple2 @(Show a) @(Num n) (irred `cast` (Sub (T26051_Import.D:R:MaybeShowNum[0] <a>_N <n>_N) :: MaybeShowNum a n ~R# (Show a, Num n))) } in
    
    23
    +      case eta of n { __DEFAULT -> (show @a (GHC.Internal.Classes.$p0CTuple2 @(Show a) @(Num n) (irred `cast` (Sub (T26051_Import.D:R:MaybeShowNum[0] <a>_N <n>_N) :: MaybeShowNum a n ~R# (Show a, Num n)))) eta, + @n $dNum n (div @n $dIntegral (fromInteger @n $dNum (GHC.Internal.Bignum.Integer.IS 1#)) (fromInteger @n $dNum (GHC.Internal.Bignum.Integer.IS 2#)))) }
    
    24
    +
    
    25
    +
    
    26
    +
    
    27
    +[2 of 2] Compiling T26051           ( T26051.hs, T26051.o )
    
    28
    +
    
    29
    +==================== Specialise ====================
    
    30
    +Result size of Specialise = {terms: 84, types: 86, coercions: 13, joins: 0/1}
    
    31
    +
    
    32
    +Rec {
    
    33
    +-- RHS size: {terms: 3, types: 4, coercions: 0, joins: 0/0}
    
    34
    +$dCTuple2 :: (Show Bool, Num Int)
    
    35
    +[LclId, Unf=Unf{Src=<vanilla>, TopLvl=False, Value=True, ConLike=True, WorkFree=True, Expandable=True, Guidance=IF_ARGS [] 10 10}]
    
    36
    +$dCTuple2 = (GHC.Internal.Show.$fShowBool, GHC.Internal.Num.$fNumInt)
    
    37
    +
    
    38
    +-- RHS size: {terms: 19, types: 9, coercions: 0, joins: 0/1}
    
    39
    +$s$wspecMe [InlPrag=INLINABLE[2]] :: Bool -> Int -> (# String, Int #)
    
    40
    +[LclId, Arity=2]
    
    41
    +$s$wspecMe
    
    42
    +  = \ (eta [Occ=Once1] :: Bool) (eta1 [Occ=Once1] :: Int) ->
    
    43
    +      let {
    
    44
    +        $dNum :: Num Int
    
    45
    +        [LclId, Unf=Unf{Src=<vanilla>, TopLvl=False, Value=True, ConLike=True, WorkFree=True, Expandable=True, Guidance=ALWAYS_IF(arity=0,unsat_ok=True,boring_ok=True)}]
    
    46
    +        $dNum = GHC.Internal.Num.$fNumInt } in
    
    47
    +      case eta1 of n1 [Occ=Once1] { __DEFAULT -> (# GHC.Internal.Show.$fShowBool_$cshow eta, GHC.Internal.Num.$fNumInt_$c+ n1 (GHC.Internal.Real.$fIntegralInt_$cdiv (GHC.Internal.Num.$fNumInt_$cfromInteger (GHC.Internal.Bignum.Integer.IS 1#)) (GHC.Internal.Num.$fNumInt_$cfromInteger (GHC.Internal.Bignum.Integer.IS 2#))) #) }
    
    48
    +
    
    49
    +-- RHS size: {terms: 12, types: 13, coercions: 5, joins: 0/0}
    
    50
    +$sspecMe [InlPrag=INLINABLE[2]] :: Bool -> Int -> (String, Int)
    
    51
    +[LclId,
    
    52
    + Arity=2,
    
    53
    + Unf=Unf{Src=StableSystem, TopLvl=True, Value=True, ConLike=True, WorkFree=True, Expandable=True, Guidance=ALWAYS_IF(arity=2,unsat_ok=True,boring_ok=False)
    
    54
    +         Tmpl= \ (eta [Occ=Once1] :: Bool) (eta1 [Occ=Once1] :: Int) -> case T26051_Import.$wspecMe @Int @Bool GHC.Internal.Real.$fIntegralInt ($dCTuple2 `cast` (Sub (Sym (T26051_Import.D:R:MaybeShowNum[0] <Bool>_N <Int>_N)) :: (Show Bool, Num Int) ~R# MaybeShowNum Bool Int)) eta eta1 of { (# ww [Occ=Once1], ww1 [Occ=Once1] #) -> (ww, ww1) }}]
    
    55
    +$sspecMe = \ (eta [Occ=Once1] :: Bool) (eta1 [Occ=Once1] :: Int) -> case T26051_Import.$wspecMe @Int @Bool GHC.Internal.Real.$fIntegralInt ($dCTuple2 `cast` (Sub (Sym (T26051_Import.D:R:MaybeShowNum[0] <Bool>_N <Int>_N)) :: (Show Bool, Num Int) ~R# MaybeShowNum Bool Int)) eta eta1 of { (# ww [Occ=Once1], ww1 [Occ=Once1] #) -> (ww, ww1) }
    
    56
    +end Rec }
    
    57
    +
    
    58
    +-- RHS size: {terms: 6, types: 3, coercions: 5, joins: 0/0}
    
    59
    +foo [InlPrag=OPAQUE] :: Int -> (String, Int)
    
    60
    +[LclIdX, Arity=1, Unf=Unf{Src=<vanilla>, TopLvl=False, Value=True, ConLike=True, WorkFree=True, Expandable=True, Guidance=IF_ARGS [0] 50 0}]
    
    61
    +foo = \ (x :: Int) -> specMe @Int @Bool GHC.Internal.Real.$fIntegralInt ($dCTuple2 `cast` (Sub (Sym (T26051_Import.D:R:MaybeShowNum[0] <Bool>_N <Int>_N)) :: (Show Bool, Num Int) ~R# MaybeShowNum Bool Int)) GHC.Internal.Types.True x
    
    62
    +
    
    63
    +-- RHS size: {terms: 37, types: 26, coercions: 0, joins: 0/0}
    
    64
    +main :: State# RealWorld -> (# State# RealWorld, () #)
    
    65
    +[LclId, Arity=1, Unf=Unf{Src=<vanilla>, TopLvl=False, Value=True, ConLike=True, WorkFree=True, Expandable=True, Guidance=IF_ARGS [0] 301 0}]
    
    66
    +main = \ (eta [OS=OneShot] :: State# RealWorld) -> GHC.Internal.IO.Handle.Text.hPutStr2 GHC.Internal.IO.StdHandles.stdout (case GHC.Internal.Enum.eftIntFB @(Int -> Int) (GHC.Internal.Base.mapFB @Int @(Int -> Int) @Int (\ (ds :: Int) (ds1 [OS=OneShot] :: Int -> Int) (v [OS=OneShot] :: Int) -> case v of { I# ipv -> ds1 (case ds of { I# y -> GHC.Internal.Types.I# (+# ipv y) }) }) (\ (x :: Int) -> case foo x of { (_ [Occ=Dead], y) -> y })) (breakpoint @Int) 1# 1000# (GHC.Internal.Types.I# 0#) of { I# n -> GHC.Internal.Show.itos n (GHC.Internal.Types.[] @Char) }) GHC.Internal.Types.True eta
    
    67
    +
    
    68
    +-- RHS size: {terms: 1, types: 0, coercions: 3, joins: 0/0}
    
    69
    +main :: IO ()
    
    70
    +[LclIdX, Arity=1, Unf=Unf{Src=<vanilla>, TopLvl=False, Value=True, ConLike=True, WorkFree=True, Expandable=True, Guidance=ALWAYS_IF(arity=0,unsat_ok=True,boring_ok=True)}]
    
    71
    +main = main `cast` (Sym (GHC.Internal.Types.N:IO <()>_R) :: (State# RealWorld -> (# State# RealWorld, () #)) ~R# IO ())
    
    72
    +
    
    73
    +
    
    74
    +------ Local rules for imported ids --------
    
    75
    +"SPEC/T26051 $wspecMe @Int @Bool" [2] forall ($dIntegral :: Integral Int) (irred :: MaybeShowNum Bool Int). T26051_Import.$wspecMe @Int @Bool $dIntegral irred = $s$wspecMe
    
    76
    +"SPEC/T26051 specMe @Int @Bool" [2] forall ($dIntegral :: Integral Int) (irred :: MaybeShowNum Bool Int). specMe @Int @Bool $dIntegral irred = $sspecMe
    
    77
    +
    
    78
    +

  • testsuite/tests/simplCore/should_compile/T26051_Import.hs
    1
    +{-# LANGUAGE TypeFamilies #-}
    
    2
    +{-# LANGUAGE BangPatterns #-}
    
    3
    +{-# LANGUAGE ImplicitParams #-}
    
    4
    +
    
    5
    +module T26051_Import (specMe, MaybeShowNum) where
    
    6
    +
    
    7
    +import Data.Kind
    
    8
    +
    
    9
    +type family MaybeShowNum a n :: Constraint where
    
    10
    +  MaybeShowNum a n = (Show a, Num n)
    
    11
    +
    
    12
    +{-# INLINABLE specMe #-}
    
    13
    +specMe :: (Integral n, MaybeShowNum a n) => a -> n -> (String,n)
    
    14
    +specMe s !n = (show s, n+1 `div` 2)

  • testsuite/tests/simplCore/should_compile/all.T
    ... ... @@ -548,3 +548,9 @@ test('T25965', normal, compile, ['-O'])
    548 548
     test('T25703',  [grep_errmsg(r'SPEC')], compile, ['-O -fpolymorphic-specialisation -ddump-rule-firings'])
    
    549 549
     test('T25703a', [grep_errmsg(r'SPEC')], compile, ['-O -fpolymorphic-specialisation -ddump-rule-firings'])
    
    550 550
     
    
    551
    +# Check that $s$wspecMe doesn't have any dictionary args after specialization in addition to perf stats
    
    552
    +test('T26051',   [ grep_errmsg(r'\$wspecMe')
    
    553
    +                    , extra_files(['T26051_Import.hs'])
    
    554
    +                    , only_ways(['optasm'])],
    
    555
    +     multimod_compile,
    
    556
    +     ['T26051', '-O2 -ddump-spec -dsuppress-uniques -dno-typeable-binds -dppr-cols=1000'])