Zubin pushed to branch wip/27627 at Glasgow Haskell Compiler / GHC

Commits:

20 changed files:

Changes:

  • compiler/GHC/Core/Opt/Specialise.hs
    ... ... @@ -1647,6 +1647,14 @@ specCalls spec_imp env existing_rules calls_for_me fn rhs
    1647 1647
         (rhs_bndrs, rhs_body) = collectBindersPushingCo rhs
    
    1648 1648
                                 -- See Note [Account for casts in binding]
    
    1649 1649
     
    
    1650
    +    -- Binders of the stable unfolding template, if there is one.
    
    1651
    +    -- See Note [Dead args and stable unfoldings]
    
    1652
    +    unf_bndrs | isStableUnfolding fn_unf
    
    1653
    +              , Just tmpl <- maybeUnfoldingTemplate fn_unf
    
    1654
    +              = Just (fst (collectBinders tmpl))
    
    1655
    +              | otherwise
    
    1656
    +              = Nothing
    
    1657
    +
    
    1650 1658
         -- Copy InlinePragma information from the parent Id.
    
    1651 1659
         -- So if f has INLINE[1] so does spec_fn
    
    1652 1660
         spec_inl_prag
    
    ... ... @@ -1670,7 +1678,7 @@ specCalls spec_imp env existing_rules calls_for_me fn rhs
    1670 1678
                                             | otherwise    = UnspecArg
    
    1671 1679
     
    
    1672 1680
                ; (useful, subst', rule_bndrs, rule_lhs_args, spec_bndrs, dx_binds, spec_args)
    
    1673
    -                 <- specHeader this_mod subst rhs_bndrs all_call_args
    
    1681
    +                 <- specHeader this_mod subst rhs_bndrs unf_bndrs all_call_args
    
    1674 1682
                ; let env' = env { se_subst = subst' }
    
    1675 1683
     
    
    1676 1684
                -- Check for (a) usefulness and (b) not already covered
    
    ... ... @@ -2049,10 +2057,26 @@ Wrinkles
    2049 2057
     * If the function has a stable unfolding, specHeader has to come up with
    
    2050 2058
       arguments to pass to that stable unfolding, when building the stable
    
    2051 2059
       unfolding of the specialised function: this is the last field in specHeader's
    
    2052
    -  big result tuple.
    
    2060
    +  big result tuple. We pass an absent filler, but only once we have checked
    
    2061
    +  that the unfolding does not use the argument either.
    
    2062
    +  See Note [Dead args and stable unfoldings]
    
    2063
    +
    
    2064
    +Note [Dead args and stable unfoldings]
    
    2065
    +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    
    2066
    +specHeader decides an argument is dead with isDeadBinder on a binder of the
    
    2067
    +optimised RHS, then applies the filler to the stable unfolding template instead.
    
    2068
    +The two may differ, so the argument can be dead in the RHS and not in the
    
    2069
    +template. See #27703 for an instance of this. The specialised function's
    
    2070
    +unfolding then contains the filler, and any call site that inlines it evaluates
    
    2071
    +the error thunk.
    
    2053 2072
     
    
    2054
    -  The right thing to do is to produce a LitRubbish; it should rapidly
    
    2055
    -  disappear.  Rather like GHC.Core.Opt.WorkWrap.Utils.mk_absent_let.
    
    2073
    +It is not enough to ask whether the RHS binder occurs free in the template: the
    
    2074
    +template has its own binders, so it never does. We must walk the arguments in
    
    2075
    +lockstep. If the template runs out of binders, the RHS was eta-expanded past
    
    2076
    +it, and we assume the argument is used.
    
    2077
    +
    
    2078
    +DmdAnal does the same job in addUnfoldingDemands. See Wrinkle (W3) of
    
    2079
    +Note [Absence analysis for stable unfoldings and RULES].
    
    2056 2080
     
    
    2057 2081
     Note [Specialisation modulo dictionary selectors]
    
    2058 2082
     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    
    ... ... @@ -2577,6 +2601,9 @@ specHeader
    2577 2601
          :: Module      -- The module being compiled, for mkAbsentFiller
    
    2578 2602
          -> Core.Subst  -- This substitution applies to the [InBndr]
    
    2579 2603
          -> [InBndr]    -- Binders from the original function `f`
    
    2604
    +     -> Maybe [InBndr]
    
    2605
    +                    -- Binders of f's stable unfolding template, if it has one
    
    2606
    +                    -- See Note [Dead args and stable unfoldings]
    
    2580 2607
          -> [SpecArg]   -- From the CallInfo
    
    2581 2608
          -> SpecM ( Bool     -- True <=> some useful specialisation happened
    
    2582 2609
                              -- Not the same as any (isSpecDict args) because
    
    ... ... @@ -2600,13 +2627,13 @@ specHeader
    2600 2627
     
    
    2601 2628
     -- If we run out of binders, stop immediately
    
    2602 2629
     -- See Note [Specialisation Must Preserve Sharing]
    
    2603
    -specHeader _ subst [] _  = pure (False, subst, [], [], [], [], [])
    
    2604
    -specHeader _ subst _  [] = pure (False, subst, [], [], [], [], [])
    
    2630
    +specHeader _ subst [] _ _  = pure (False, subst, [], [], [], [], [])
    
    2631
    +specHeader _ subst _  _ [] = pure (False, subst, [], [], [], [], [])
    
    2605 2632
     
    
    2606 2633
     -- We want to specialise on type 'T1', and so we must construct a substitution
    
    2607 2634
     -- 'a->T1', as well as a LHS argument for the resulting RULE and unfolding
    
    2608 2635
     -- details.
    
    2609
    -specHeader mod subst (bndr:bndrs) (SpecType ty : args)
    
    2636
    +specHeader mod subst (bndr:bndrs) unf_bndrs (SpecType ty : args)
    
    2610 2637
       = do { -- Find free_tvs, the type variables to add to the binders for the rule
    
    2611 2638
              -- Namely those deeply free in `ty` that aren't in scope
    
    2612 2639
              -- See (MP2) in Note [Specialising polymorphic dictionaries]
    
    ... ... @@ -2619,7 +2646,7 @@ specHeader mod subst (bndr:bndrs) (SpecType ty : args)
    2619 2646
     
    
    2620 2647
            ; let subst2 = Core.extendTvSubst subst1 bndr ty
    
    2621 2648
            ; (useful, subst3, rule_bs, rule_args, spec_bs, dx, spec_args)
    
    2622
    -             <- specHeader mod subst2 bndrs args
    
    2649
    +             <- specHeader mod subst2 bndrs (fmap (drop 1) unf_bndrs) args
    
    2623 2650
            ; pure ( useful, subst3
    
    2624 2651
                   , free_tvs ++ rule_bs,     Type ty : rule_args
    
    2625 2652
                   , free_tvs ++ spec_bs, dx, Type ty : spec_args ) }
    
    ... ... @@ -2628,17 +2655,19 @@ specHeader mod subst (bndr:bndrs) (SpecType ty : args)
    2628 2655
     -- a substitution on it (in case the type refers to 'a'). Additionally, we need
    
    2629 2656
     -- to produce a binder, LHS argument and RHS argument for the resulting rule,
    
    2630 2657
     -- /and/ a binder for the specialised body.
    
    2631
    -specHeader mod subst (bndr:bndrs) (UnspecType : args)
    
    2658
    +specHeader mod subst (bndr:bndrs) unf_bndrs (UnspecType : args)
    
    2632 2659
       = do { let (subst1, bndr') = Core.substBndr subst bndr
    
    2633 2660
            ; (useful, subst2, rule_bs, rule_es, spec_bs, dx, spec_args)
    
    2634
    -             <- specHeader mod subst1 bndrs args
    
    2661
    +             <- specHeader mod subst1 bndrs (fmap (drop 1) unf_bndrs) args
    
    2635 2662
            ; let ty_e' = Type (mkTyVarTy bndr')
    
    2636 2663
            ; pure ( useful, subst2
    
    2637 2664
                   , bndr' : rule_bs,     ty_e' : rule_es
    
    2638 2665
                   , bndr' : spec_bs, dx, ty_e' : spec_args ) }
    
    2639 2666
     
    
    2640
    -specHeader mod subst (bndr:bndrs) (_ : args)
    
    2667
    +specHeader mod subst (bndr:bndrs) unf_bndrs (_ : args)
    
    2641 2668
       | isDeadBinder bndr
    
    2669
    +  , dead_in_unfolding unf_bndrs
    
    2670
    +      -- See Note [Dead args and stable unfoldings]
    
    2642 2671
       , let (subst1, bndr') = Core.substBndr subst (zapIdOccInfo bndr)
    
    2643 2672
       , Just filler <- mkAbsentFiller mod bndr' NotMarkedStrict
    
    2644 2673
           -- NB: mkAbsentFiller returns Nothing for a terminating type (e.g. a
    
    ... ... @@ -2647,7 +2676,8 @@ specHeader mod subst (bndr:bndrs) (_ : args)
    2647 2676
           -- See Note [Don't make fillers for dictionary types]
    
    2648 2677
           -- in GHC.Core.Opt.WorkWrap.Utils
    
    2649 2678
       = -- See Note [Drop dead args from specialisations]
    
    2650
    -    do { (useful, subst2, rule_bs, rule_es, spec_bs, dx, spec_args) <- specHeader mod subst1 bndrs args
    
    2679
    +    do { (useful, subst2, rule_bs, rule_es, spec_bs, dx, spec_args)
    
    2680
    +             <- specHeader mod subst1 bndrs (fmap (drop 1) unf_bndrs) args
    
    2651 2681
            ; pure ( useful, subst2
    
    2652 2682
                   , bndr' : rule_bs, Var bndr'   : rule_es
    
    2653 2683
                   , spec_bs,     dx, filler : spec_args ) }
    
    ... ... @@ -2655,7 +2685,7 @@ specHeader mod subst (bndr:bndrs) (_ : args)
    2655 2685
     -- Next we want to specialise the 'Eq a' dict away. We need to construct
    
    2656 2686
     -- a wildcard binder to match the dictionary (See Note [Specialising Calls] for
    
    2657 2687
     -- the nitty-gritty), as a LHS rule and unfolding details.
    
    2658
    -specHeader mod subst (bndr:bndrs) (SpecDict dict_arg : args)
    
    2688
    +specHeader mod subst (bndr:bndrs) unf_bndrs (SpecDict dict_arg : args)
    
    2659 2689
       = do { -- Make up a fresh binder to use in the RULE
    
    2660 2690
              -- It might turn into a dict binding (via bindAuxiliaryDict) which we
    
    2661 2691
              -- then float, so we use cloneIdBndr to get a completely fresh binder
    
    ... ... @@ -2666,7 +2696,8 @@ specHeader mod subst (bndr:bndrs) (SpecDict dict_arg : args)
    2666 2696
              -- Extend the substitution to map bndr :-> dict_arg, for use in the RHS
    
    2667 2697
            ; let (subst2, dx_bind, spec_dict) = bindAuxiliaryDict subst1 bndr bndr' dict_arg
    
    2668 2698
     
    
    2669
    -       ; (_, subst3, rule_bs, rule_es, spec_bs, dx, spec_args) <- specHeader mod subst2 bndrs args
    
    2699
    +       ; (_, subst3, rule_bs, rule_es, spec_bs, dx, spec_args)
    
    2700
    +             <- specHeader mod subst2 bndrs (fmap (drop 1) unf_bndrs) args
    
    2670 2701
     
    
    2671 2702
            ; let dx' = case dx_bind of { Nothing -> dx; Just d -> d : dx }
    
    2672 2703
            ; pure ( True, subst3      -- Ha!  A useful specialisation!
    
    ... ... @@ -2681,10 +2712,11 @@ specHeader mod subst (bndr:bndrs) (SpecDict dict_arg : args)
    2681 2712
     -- why 'i' doesn't appear in our RULE above. But we have no guarantee that
    
    2682 2713
     -- there aren't 'UnspecArg's which come /before/ all of the dictionaries, so
    
    2683 2714
     -- this case must be here.
    
    2684
    -specHeader mod subst (bndr:bndrs) (UnspecArg : args)
    
    2715
    +specHeader mod subst (bndr:bndrs) unf_bndrs (UnspecArg : args)
    
    2685 2716
       = do { let (subst1, bndr') = Core.substBndr subst (zapIdOccInfo bndr)
    
    2686 2717
                      -- zapIdOccInfo: see Note [Zap occ info in rule binders]
    
    2687
    -       ; (useful, subst2, rule_bs, rule_es, spec_bs, dx, spec_args) <- specHeader mod subst1 bndrs args
    
    2718
    +       ; (useful, subst2, rule_bs, rule_es, spec_bs, dx, spec_args)
    
    2719
    +             <- specHeader mod subst1 bndrs (fmap (drop 1) unf_bndrs) args
    
    2688 2720
     
    
    2689 2721
            ; let dummy_arg = varToCoreExpr bndr'
    
    2690 2722
                    -- dummy_arg is usually just (Var bndr),
    
    ... ... @@ -2698,6 +2730,14 @@ specHeader mod subst (bndr:bndrs) (UnspecArg : args)
    2698 2730
                   , bndrs ++ spec_bs, dx, dummy_arg : spec_args ) }
    
    2699 2731
     
    
    2700 2732
     
    
    2733
    +dead_in_unfolding :: Maybe [InBndr] -> Bool
    
    2734
    +-- ^ Is the argument at this position dead in the stable unfolding template?
    
    2735
    +-- Nothing means there is no stable unfolding, so no filler can escape into one.
    
    2736
    +-- If the template runs out of binders we cannot tell, so we say No.
    
    2737
    +dead_in_unfolding Nothing                 = True
    
    2738
    +dead_in_unfolding (Just (unf_bndr : _))   = isDeadBinder unf_bndr
    
    2739
    +dead_in_unfolding (Just [])               = False
    
    2740
    +
    
    2701 2741
     -- | Binds a dictionary argument to a fresh name, to preserve sharing
    
    2702 2742
     bindAuxiliaryDict
    
    2703 2743
       :: Subst
    

  • compiler/GHC/Core/Opt/WorkWrap/Utils.hs
    ... ... @@ -32,7 +32,7 @@ import GHC.Core.Multiplicity
    32 32
     import GHC.Core.Coercion
    
    33 33
     import GHC.Core.Reduction
    
    34 34
     import GHC.Core.FamInstEnv
    
    35
    -import GHC.Core.Predicate( isEqualityClass, isDictTy )
    
    35
    +import GHC.Core.Predicate( isEqualityClass )
    
    36 36
     import GHC.Core.TyCon
    
    37 37
     import GHC.Core.TyCon.Set
    
    38 38
     import GHC.Core.TyCon.RecWalk
    
    ... ... @@ -1072,7 +1072,7 @@ mkAbsentFiller mod arg str
    1072 1072
       -- evaluated or have a field projected out of it.
    
    1073 1073
       -- See (AF4) in Note [Absent fillers], and
    
    1074 1074
       -- Note [Don't make fillers for dictionary types].
    
    1075
    -  | isDictTy arg_ty
    
    1075
    +  | ConstraintLike <- typeTypeOrConstraint arg_ty
    
    1076 1076
       = Nothing
    
    1077 1077
     
    
    1078 1078
       -- The lifted case: bind 'absentError'. See (AF1) in Note [Absent fillers]
    

  • compiler/GHC/CoreToStg/Prep.hs
    ... ... @@ -1977,6 +1977,26 @@ prep up `rhs1`, we have to include not only `f1`, but all binders of the group
    1977 1977
     `f1..fn` in this set, otherwise our fix is not robust wrt. mutual recursive
    
    1978 1978
     DFuns.
    
    1979 1979
     
    
    1980
    +cpe_rec_ids is module-local, so it does not catch a recursion that goes through
    
    1981
    +an hs-boot import. Suppose Mid and Callee form a module loop, and Mid sees
    
    1982
    +Callee through its hs-boot file:
    
    1983
    +
    
    1984
    +  -- Mid.hs
    
    1985
    +  $fCAT = \ @a $dCB -> C:CA ($fxCBT $dCB) ...
    
    1986
    +  -- Callee.hs
    
    1987
    +  $fCBT = \ @a $dCB -> C:CB ($fCAT  $dCB) ...
    
    1988
    +
    
    1989
    +Neither module can see that these two call each other, so each looks
    
    1990
    +non-recursive, and we speculate the inner call in both:
    
    1991
    +
    
    1992
    +  $fCAT = \ @a $dCB -> case $fxCBT $dCB of s { __DEFAULT -> C:CA s ... }
    
    1993
    +  $fCBT = \ @a $dCB -> case $fCAT  $dCB of s { __DEFAULT -> C:CB s ... }
    
    1994
    +
    
    1995
    +Now each forces the other and the program loops. Such a cycle must cross an
    
    1996
    +hs-boot edge, so we do not speculate a call whose callee has a BootUnfolding.
    
    1997
    +Note [Inlining and hs-boot files] in GHC.CoreToIface does the same for
    
    1998
    +infinite inlining.
    
    1999
    +
    
    1980 2000
     NB: If at some point we decide to have a termination analysis for general
    
    1981 2001
     functions (#8655, !1866), we need to take similar precautions for (guarded)
    
    1982 2002
     recursive functions:
    
    ... ... @@ -2323,10 +2343,13 @@ mkNonRecFloat env lev bndr rhs
    2323 2343
         -- See Note [Controlling Speculative Evaluation]
    
    2324 2344
         call_ok_for_spec x
    
    2325 2345
           | is_rec_call x                           = False
    
    2346
    +      | is_boot_call x                          = False
    
    2326 2347
           | not (cp_specEval cfg)                   = False
    
    2327 2348
           | not (cp_specEvalDFun cfg) && isDFunId x = False
    
    2328 2349
           | otherwise                               = True
    
    2329
    -    is_rec_call = (`elemUnVarSet` cpe_rec_ids env)
    
    2350
    +    is_rec_call  = (`elemUnVarSet` cpe_rec_ids env)
    
    2351
    +    is_boot_call = isBootUnfolding . realIdUnfolding
    
    2352
    +      -- See Note [Speculative evaluation], Very Nasty Wrinkle
    
    2330 2353
     
    
    2331 2354
         -- See Note [Pin evaluatedness on floats]
    
    2332 2355
         bndr' | is_hnf    = bndr `setIdUnfolding` evaldUnfolding
    

  • testsuite/tests/core-to-stg/T27627f/Callee.hs
    1
    +{-# LANGUAGE GADTs, ConstraintKinds, ScopedTypeVariables #-}
    
    2
    +{-# OPTIONS_GHC -fno-worker-wrapper #-}
    
    3
    +module Callee where
    
    4
    +
    
    5
    +-- Not unary: a superclass field and a method field, so (Eq a) can be
    
    6
    +-- speculatively selected out of a (TC a) dictionary.
    
    7
    +class Eq a => TC a where
    
    8
    +  tcDummy :: a -> Int
    
    9
    +
    
    10
    +data W = W
    
    11
    +instance Eq W where _ == _ = True
    
    12
    +
    
    13
    +data Dict c where
    
    14
    +  Dict :: c => Dict c
    
    15
    +
    
    16
    +{-# NOINLINE discard #-}
    
    17
    +discard :: Dict c -> Int
    
    18
    +discard _ = 42
    
    19
    +
    
    20
    +-- Never forces its dictionary, so demand analysis marks it absent, and
    
    21
    +-- Caller's `a` inherits that absence.
    
    22
    +{-# NOINLINE b #-}
    
    23
    +b :: forall a. TC a => a -> Int
    
    24
    +b _ = discard (Dict :: Dict (Eq a))

  • testsuite/tests/core-to-stg/T27627f/Caller.hs
    1
    +{-# LANGUAGE TypeFamilies, ConstraintKinds, FlexibleContexts #-}
    
    2
    +{-# LANGUAGE UndecidableInstances #-}
    
    3
    +module Caller where
    
    4
    +
    
    5
    +import Callee
    
    6
    +import Data.Kind (Constraint)
    
    7
    +
    
    8
    +-- A Constraint-kinded type family.  It reduces to (TC W), so the dictionary
    
    9
    +-- `a` receives really is a (TC W) dictionary; but (F W) is not class-headed,
    
    10
    +-- so isDictTy says False.  Worker/wrapper must still not replace it with a
    
    11
    +-- filler: Callee speculates a superclass selection out of it.
    
    12
    +type family F a :: Constraint
    
    13
    +type instance F W = TC W
    
    14
    +
    
    15
    +-- Note there is no `instance TC W` in scope here: `b W` must take its
    
    16
    +-- dictionary from this Given, rather than from an instance.
    
    17
    +{-# NOINLINE a #-}
    
    18
    +a :: F W => Int -> Int
    
    19
    +a x = b W + x

  • testsuite/tests/core-to-stg/T27627f/Inst.hs
    1
    +module Inst where
    
    2
    +
    
    3
    +import Callee
    
    4
    +
    
    5
    +-- Deliberately not in Callee or Caller: see the comment in Caller.hs
    
    6
    +instance TC W where tcDummy _ = 7

  • testsuite/tests/core-to-stg/T27627f/Main.hs
    1
    +module Main where
    
    2
    +
    
    3
    +import Caller
    
    4
    +import Inst ()
    
    5
    +
    
    6
    +main :: IO ()
    
    7
    +main = print (a 1)

  • testsuite/tests/core-to-stg/T27627f/T27627f.stdout
    1
    +43

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

  • testsuite/tests/core-to-stg/T27717/Callee.hs
    1
    +{-# LANGUAGE UndecidableInstances, FlexibleInstances, FlexibleContexts #-}
    
    2
    +module Callee where
    
    3
    +
    
    4
    +import Ty
    
    5
    +import Mid
    
    6
    +
    
    7
    +instance CB a => CB (T a) where
    
    8
    +  opB _ = 2
    
    9
    +
    
    10
    +instance CB Int where
    
    11
    +  opB _ = 8

  • testsuite/tests/core-to-stg/T27717/Callee.hs-boot
    1
    +{-# LANGUAGE FlexibleInstances, UndecidableInstances #-}
    
    2
    +module Callee where
    
    3
    +
    
    4
    +import Ty
    
    5
    +
    
    6
    +instance CB a => CB (T a)
    
    7
    +instance CB Int

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

  • testsuite/tests/core-to-stg/T27717/Mid.hs
    1
    +{-# LANGUAGE UndecidableInstances, FlexibleInstances, FlexibleContexts #-}
    
    2
    +{-# LANGUAGE GADTs, ConstraintKinds, ScopedTypeVariables #-}
    
    3
    +module Mid where
    
    4
    +
    
    5
    +import Ty
    
    6
    +import {-# SOURCE #-} Callee
    
    7
    +
    
    8
    +-- $fCATa calls Callee's $fxCBT, and that calls this one back.  The cycle runs
    
    9
    +-- through the hs-boot import, so both dfuns are NonRec in their own module and
    
    10
    +-- cpe_rec_ids cannot see it.  Speculating either one loops.
    
    11
    +instance CB a => CA (T a) where
    
    12
    +  opA _ = 1
    
    13
    +
    
    14
    +instance CA Int where
    
    15
    +  opA _ = 9
    
    16
    +
    
    17
    +data Dict c where
    
    18
    +  Dict :: c => Dict c
    
    19
    +
    
    20
    +{-# NOINLINE keep #-}
    
    21
    +keep :: [Dict c] -> Int
    
    22
    +keep xs = length xs + 41
    
    23
    +
    
    24
    +{-# NOINLINE g #-}
    
    25
    +g :: forall a. CB a => a -> Int
    
    26
    +g _ = keep [Dict :: Dict (CA (T a))]

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

  • testsuite/tests/core-to-stg/T27717/Ty.hs
    1
    +{-# LANGUAGE UndecidableSuperClasses #-}
    
    2
    +module Ty where
    
    3
    +
    
    4
    +data T a = MkT a
    
    5
    +
    
    6
    +class CB a => CA a where
    
    7
    +  opA :: a -> Int
    
    8
    +
    
    9
    +class CA a => CB a where
    
    10
    +  opB :: a -> Int

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

  • 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'])