[Git][ghc/ghc][wip/T21470] 4 commits: Various Hadrian bootstrapping fixes

Simon Peyton Jones (@simonpj) gitlab at gitlab.haskell.org
Wed Aug 31 22:08:06 UTC 2022



Simon Peyton Jones pushed to branch wip/T21470 at Glasgow Haskell Compiler / GHC


Commits:
0154bc80 by sheaf at 2022-08-30T06:05:41-04:00
Various Hadrian bootstrapping fixes

  - Don't always produce a distribution archive (#21629)
  - Use correct executable names for ghc-pkg and hsc2hs on windows
    (we were missing the .exe file extension)
  - Fix a bug where we weren't using the right archive format on Windows
    when unpacking the bootstrap sources.

Fixes #21629

- - - - -
451b1d90 by Matthew Pickering at 2022-08-30T06:06:16-04:00
ci: Attempt using normal submodule cloning strategy

We do not use any recursively cloned submodules, and this protects us
from flaky upstream remotes.

Fixes #22121

- - - - -
3b27ecba by Simon Peyton Jones at 2022-08-31T23:08:07+01:00
Make the specialiser handle polymorphic specialisation

Ticket #13873 unexpectedly showed that a SPECIALISE pragma made a
program run (a lot) slower, because less specialisation took place
overall. It turned out that the specialiser was missing opportunities
because of quantified type variables.

It was quite easy to fix. The story is given in
    Note [Specialising polymorphic dictionaries]

Two other minor fixes in the specialiser

* There is no benefit in specialising data constructor /wrappers/.
  (They can appear overloaded because they are given a dictionary
  to store in the constructor.)  Small guard in canSpecImport.

* There was a buglet in the UnspecArg case of specHeader, in the
  case where there is a dead binder. We need a LitRubbish filler
  for the specUnfolding stuff.  I expanded
  Note [Drop dead args from specialisations] to explain.

There is a 4% increase in compile time for T13056, because we generate
more specialised code.  This seems OK.

Metric Increase:
    T13056

- - - - -
cd3f0c27 by Simon Peyton Jones at 2022-08-31T23:08:07+01:00
Fix binder-swap bug

This patch fixes #21229 / #21470 properly, by avoiding doing a
binder-swap on dictionary Ids.  This is pretty subtle, and explained
in Note [Care with binder-swap on dictionaries].

This allows us to restore a feature to the specialiser that we had
to revert: see Note [Specialising polymorphic dictionaries].

I als modularised things, using a new function scrutBinderSwap_maybe
in all the places where we are (effectively) doing a binder-swap,
notably

* Simplify.Iteration.addAltUnfoldings
* SpecConstr.extendCaseBndrs

- - - - -


15 changed files:

- .gitlab-ci.yml
- .gitlab/ci.sh
- compiler/GHC/Core/Opt/OccurAnal.hs
- compiler/GHC/Core/Opt/SetLevels.hs
- compiler/GHC/Core/Opt/Simplify/Env.hs
- compiler/GHC/Core/Opt/Simplify/Iteration.hs
- compiler/GHC/Core/Opt/SpecConstr.hs
- compiler/GHC/Core/Opt/Specialise.hs
- compiler/GHC/Core/Subst.hs
- compiler/GHC/Core/TyCo/FVs.hs
- compiler/GHC/Core/Type.hs
- hadrian/bootstrap/bootstrap.py
- testsuite/tests/linters/notes.stdout
- testsuite/tests/simplCore/should_compile/T8331.stderr
- testsuite/tests/simplCore/should_compile/all.T


Changes:

=====================================
.gitlab-ci.yml
=====================================
@@ -17,7 +17,7 @@ variables:
   # Overridden by individual jobs
   CONFIGURE_ARGS: ""
 
-  GIT_SUBMODULE_STRATEGY: "recursive"
+  GIT_SUBMODULE_STRATEGY: "normal"
 
   # Makes ci.sh isolate CABAL_DIR
   HERMETIC: "YES"


=====================================
.gitlab/ci.sh
=====================================
@@ -377,8 +377,8 @@ function cleanup_submodules() {
     # On Windows submodules can inexplicably get into funky states where git
     # believes that the submodule is initialized yet its associated repository
     # is not valid. Avoid failing in this case with the following insanity.
-    git submodule sync --recursive || git submodule deinit --force --all
-    git submodule update --init --recursive
+    git submodule sync || git submodule deinit --force --all
+    git submodule update --init
     git submodule foreach git clean -xdf
   else
     info "Not cleaning submodules, not in a git repo"


=====================================
compiler/GHC/Core/Opt/OccurAnal.hs
=====================================
@@ -19,7 +19,7 @@ core expression with (hopefully) improved usage information.
 module GHC.Core.Opt.OccurAnal (
     occurAnalysePgm,
     occurAnalyseExpr,
-    zapLambdaBndrs
+    zapLambdaBndrs, scrutBinderSwap_maybe
   ) where
 
 import GHC.Prelude
@@ -27,11 +27,12 @@ import GHC.Prelude
 import GHC.Core
 import GHC.Core.FVs
 import GHC.Core.Utils   ( exprIsTrivial, isDefaultAlt, isExpandableApp,
-                          stripTicksTopE, mkTicks )
+                          mkCastMCo, mkTicks )
 import GHC.Core.Opt.Arity   ( joinRhsArity, isOneShotBndr )
 import GHC.Core.Coercion
+import GHC.Core.Predicate   ( isDictId )
 import GHC.Core.Type
-import GHC.Core.TyCo.FVs( tyCoVarsOfMCo )
+import GHC.Core.TyCo.FVs    ( tyCoVarsOfMCo )
 
 import GHC.Data.Maybe( isJust, orElse )
 import GHC.Data.Graph.Directed ( SCC(..), Node(..)
@@ -2462,8 +2463,8 @@ data OccEnv
 
            -- See Note [The binder-swap substitution]
            -- If  x :-> (y, co)  is in the env,
-           -- then please replace x by (y |> sym mco)
-           -- Invariant of course: idType x = exprType (y |> sym mco)
+           -- then please replace x by (y |> mco)
+           -- Invariant of course: idType x = exprType (y |> mco)
            , occ_bs_env  :: !(VarEnv (OutId, MCoercion))
            , occ_bs_rng  :: !VarSet   -- Vars free in the range of occ_bs_env
                    -- Domain is Global and Local Ids
@@ -2669,7 +2670,7 @@ The binder-swap is implemented by the occ_bs_env field of OccEnv.
 There are two main pieces:
 
 * Given    case x |> co of b { alts }
-  we add [x :-> (b, co)] to the occ_bs_env environment; this is
+  we add [x :-> (b, sym co)] to the occ_bs_env environment; this is
   done by addBndrSwap.
 
 * Then, at an occurrence of a variable, we look up in the occ_bs_env
@@ -2737,30 +2738,8 @@ Some tricky corners:
 (BS5) We have to apply the occ_bs_env substitution uniformly,
       including to (local) rules and unfoldings.
 
-Historical note
----------------
-We used to do the binder-swap transformation by introducing
-a proxy let-binding, thus;
-
-   case x of b { pi -> ri }
-      ==>
-   case x of b { pi -> let x = b in ri }
-
-But that had two problems:
-
-1. If 'x' is an imported GlobalId, we'd end up with a GlobalId
-   on the LHS of a let-binding which isn't allowed.  We worked
-   around this for a while by "localising" x, but it turned
-   out to be very painful #16296,
-
-2. In CorePrep we use the occurrence analyser to do dead-code
-   elimination (see Note [Dead code in CorePrep]).  But that
-   occasionally led to an unlifted let-binding
-       case x of b { DEFAULT -> let x::Int# = b in ... }
-   which disobeys one of CorePrep's output invariants (no unlifted
-   let-bindings) -- see #5433.
-
-Doing a substitution (via occ_bs_env) is much better.
+(BS6) We must be very careful with dictionaries.
+      See Note [Care with binder-swap on dictionaries]
 
 Note [Case of cast]
 ~~~~~~~~~~~~~~~~~~~
@@ -2770,6 +2749,58 @@ We'd like to eliminate the inner case.  That is the motivation for
 equation (2) in Note [Binder swap].  When we get to the inner case, we
 inline x, cancel the casts, and away we go.
 
+Note [Care with binder-swap on dictionaries]
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+This Note explains why we need isDictId in scrutBinderSwap_maybe.
+Consider this tricky example (#21229, #21470):
+
+  class Sing (b :: Bool) where sing :: Bool
+  instance Sing 'True  where sing = True
+  instance Sing 'False where sing = False
+
+  f :: forall a. Sing a => blah
+
+  h = \ @(a :: Bool) ($dSing :: Sing a)
+      let the_co =  Main.N:Sing[0] <a> :: Sing a ~R# Bool
+      case ($dSing |> the_co) of wild
+        True  -> f @'True (True |> sym the_co)
+        False -> f @a     dSing
+
+Now do a binder-swap on the case-expression:
+
+  h = \ @(a :: Bool) ($dSing :: Sing a)
+      let the_co =  Main.N:Sing[0] <a> :: Sing a ~R# Bool
+      case ($dSing |> the_co) of wild
+        True  -> f @'True (True |> sym the_co)
+        False -> f @a     (wild |> sym the_co)
+
+And now substitute `False` for `wild` (since wild=False in the False branch):
+
+  h = \ @(a :: Bool) ($dSing :: Sing a)
+      let the_co =  Main.N:Sing[0] <a> :: Sing a ~R# Bool
+      case ($dSing |> the_co) of wild
+        True  -> f @'True (True  |> sym the_co)
+        False -> f @a     (False |> sym the_co)
+
+And now we have a problem.  The specialiser will specialise (f @a d)a (for all
+vtypes a and dictionaries d!!) with the dictionary (False |> sym the_co), using
+Note [Specialising polymorphic dictionaries] in GHC.Core.Opt.Specialise.
+
+The real problem is the binder-swap.  It swaps a dictionary variable $dSing
+(of kind Constraint) for a term variable wild (of kind Type).  And that is
+dangerous: a dictionary is a /singleton/ type whereas a general term variable is
+not.  In this particular example, Bool is most certainly not a singleton type!
+
+Conclusion:
+  for a /dictionary variable/ do not perform
+  the clever cast version of the binder-swap
+
+Hence the subtle isDictId in scrutBinderSwap_maybe.
+
+What about Constraint/Constraint binder-swaps?  Maybe that would be OK, but
+I have never seen one, so I'm leaving the code as simple as possible Losing
+the binder-swap in a rare case probably has very low impact.
+
 Note [Zap case binders in proxy bindings]
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 From the original
@@ -2784,8 +2815,83 @@ binding x = cb.  See #5028.
 NB: the OccInfo on /occurrences/ really doesn't matter much; the simplifier
 doesn't use it. So this is only to satisfy the perhaps-over-picky Lint.
 
+-}
+
+addBndrSwap :: OutExpr -> Id -> OccEnv -> OccEnv
+-- See Note [The binder-swap substitution]
+addBndrSwap scrut case_bndr
+            env@(OccEnv { occ_bs_env = swap_env, occ_bs_rng = rng_vars })
+  | Just (scrut_var, mco) <- scrutBinderSwap_maybe scrut
+  , scrut_var /= case_bndr
+      -- Consider: case x of x { ... }
+      -- Do not add [x :-> x] to occ_bs_env, else lookupBndrSwap will loop
+  = env { occ_bs_env = extendVarEnv swap_env scrut_var (case_bndr', mco)
+        , occ_bs_rng = rng_vars `extendVarSet` case_bndr'
+                       `unionVarSet` tyCoVarsOfMCo mco }
+
+  | otherwise
+  = env
+  where
+    case_bndr' = zapIdOccInfo case_bndr
+                 -- See Note [Zap case binders in proxy bindings]
+
+scrutBinderSwap_maybe :: OutExpr -> Maybe (OutVar, MCoercion)
+-- If (scrutBinderSwap_maybe e = Just (v, mco), then
+--    v = e |> mco
+-- See Note [Case of cast]
+-- See Note [Care with binder-swap on dictionaries]
+--
+-- We use this same function in SpecConstr, and Simplify.Iteration,
+-- when something binder-swap-like is happening
+scrutBinderSwap_maybe (Var v)    = Just (v, MRefl)
+scrutBinderSwap_maybe (Cast (Var v) co)
+  | not (isDictId v)             = Just (v, MCo (mkSymCo co))
+        -- Cast: see Note [Case of cast]
+        -- isDictId: see Note [Care with binder-swap on dictionaries]
+scrutBinderSwap_maybe (Tick _ e) = scrutBinderSwap_maybe e  -- Drop ticks
+scrutBinderSwap_maybe _          = Nothing
+
+lookupBndrSwap :: OccEnv -> Id -> (CoreExpr, Id)
+-- See Note [The binder-swap substitution]
+-- Returns an expression of the same type as Id
+lookupBndrSwap env@(OccEnv { occ_bs_env = bs_env })  bndr
+  = case lookupVarEnv bs_env bndr of {
+       Nothing           -> (Var bndr, bndr) ;
+       Just (bndr1, mco) ->
+
+    -- Why do we iterate here?
+    -- See (BS2) in Note [The binder-swap substitution]
+    case lookupBndrSwap env bndr1 of
+      (fun, fun_id) -> (mkCastMCo fun mco, fun_id) }
+
+
+{- Historical note [Proxy let-bindings]
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+We used to do the binder-swap transformation by introducing
+a proxy let-binding, thus;
+
+   case x of b { pi -> ri }
+      ==>
+   case x of b { pi -> let x = b in ri }
+
+But that had two problems:
+
+1. If 'x' is an imported GlobalId, we'd end up with a GlobalId
+   on the LHS of a let-binding which isn't allowed.  We worked
+   around this for a while by "localising" x, but it turned
+   out to be very painful #16296,
+
+2. In CorePrep we use the occurrence analyser to do dead-code
+   elimination (see Note [Dead code in CorePrep]).  But that
+   occasionally led to an unlifted let-binding
+       case x of b { DEFAULT -> let x::Int# = b in ... }
+   which disobeys one of CorePrep's output invariants (no unlifted
+   let-bindings) -- see #5433.
+
+Doing a substitution (via occ_bs_env) is much better.
+
 Historical Note [no-case-of-case]
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 We *used* to suppress the binder-swap in case expressions when
 -fno-case-of-case is on.  Old remarks:
     "This happens in the first simplifier pass,
@@ -2844,53 +2950,8 @@ binder-swap in OccAnal:
 It's fixed by doing the binder-swap in OccAnal because we can do the
 binder-swap unconditionally and still get occurrence analysis
 information right.
--}
 
-addBndrSwap :: OutExpr -> Id -> OccEnv -> OccEnv
--- See Note [The binder-swap substitution]
-addBndrSwap scrut case_bndr
-            env@(OccEnv { occ_bs_env = swap_env, occ_bs_rng = rng_vars })
-  | Just (scrut_var, mco) <- get_scrut_var (stripTicksTopE (const True) scrut)
-  , scrut_var /= case_bndr
-      -- Consider: case x of x { ... }
-      -- Do not add [x :-> x] to occ_bs_env, else lookupBndrSwap will loop
-  = env { occ_bs_env = extendVarEnv swap_env scrut_var (case_bndr', mco)
-        , occ_bs_rng = rng_vars `extendVarSet` case_bndr'
-                       `unionVarSet` tyCoVarsOfMCo mco }
-
-  | otherwise
-  = env
-  where
-    get_scrut_var :: OutExpr -> Maybe (OutVar, MCoercion)
-    get_scrut_var (Var v)           = Just (v, MRefl)
-    get_scrut_var (Cast (Var v) co) = Just (v, MCo co) -- See Note [Case of cast]
-    get_scrut_var _                 = Nothing
-
-    case_bndr' = zapIdOccInfo case_bndr
-                 -- See Note [Zap case binders in proxy bindings]
-
-lookupBndrSwap :: OccEnv -> Id -> (CoreExpr, Id)
--- See Note [The binder-swap substitution]
--- Returns an expression of the same type as Id
-lookupBndrSwap env@(OccEnv { occ_bs_env = bs_env })  bndr
-  = case lookupVarEnv bs_env bndr of {
-       Nothing           -> (Var bndr, bndr) ;
-       Just (bndr1, mco) ->
-
-    -- Why do we iterate here?
-    -- See (BS2) in Note [The binder-swap substitution]
-    case lookupBndrSwap env bndr1 of
-      (fun, fun_id) -> (add_cast fun mco, fun_id) }
-
-  where
-    add_cast fun MRefl    = fun
-    add_cast fun (MCo co) = Cast fun (mkSymCo co)
-    -- We must switch that 'co' to 'sym co';
-    -- see the comment with occ_bs_env
-    -- No need to test for isReflCo, because 'co' came from
-    -- a (Cast e co) and hence is unlikely to be Refl
 
-{-
 ************************************************************************
 *                                                                      *
 \subsection[OccurAnal-types]{OccEnv}


=====================================
compiler/GHC/Core/Opt/SetLevels.hs
=====================================
@@ -51,17 +51,6 @@
   The simplifier tries to get rid of occurrences of x, in favour of wild,
   in the hope that there will only be one remaining occurrence of x, namely
   the scrutinee of the case, and we can inline it.
-
-  This can only work if @wild@ is an unrestricted binder. Indeed, even with the
-  extended typing rule (in the linter) for case expressions, if
-       case x of wild % 1 { p -> e}
-  is well-typed, then
-       case x of wild % 1 { p -> e[wild\x] }
-  is only well-typed if @e[wild\x] = e@ (that is, if @wild@ is not used in @e@
-  at all). In which case, it is, of course, pointless to do the substitution
-  anyway. So for a linear binder (and really anything which isn't unrestricted),
-  doing this substitution would either produce ill-typed terms or be the
-  identity.
 -}
 
 module GHC.Core.Opt.SetLevels (
@@ -1602,7 +1591,9 @@ extendCaseBndrEnv :: LevelEnv
                   -> LevelEnv
 extendCaseBndrEnv le@(LE { le_subst = subst, le_env = id_env })
                   case_bndr (Var scrut_var)
-    | Many <- varMult case_bndr
+  -- We could use OccurAnal. scrutBinderSwap_maybe here, and perhaps
+  -- get a bit more floating.  But we didn't in the past and it's
+  -- an unforced change, so I'm leaving it.
   = le { le_subst   = extendSubstWithVar subst case_bndr scrut_var
        , le_env     = add_id id_env (case_bndr, scrut_var) }
 extendCaseBndrEnv env _ _ = env


=====================================
compiler/GHC/Core/Opt/Simplify/Env.hs
=====================================
@@ -71,7 +71,8 @@ import GHC.Core.Make            ( mkWildValBinder, mkCoreLet )
 import GHC.Builtin.Types
 import GHC.Core.TyCo.Rep        ( TyCoBinder(..) )
 import qualified GHC.Core.Type as Type
-import GHC.Core.Type hiding     ( substTy, substTyVar, substTyVarBndr, extendTvSubst, extendCvSubst )
+import GHC.Core.Type hiding     ( substTy, substTyVar, substTyVarBndr, substCo
+                                , extendTvSubst, extendCvSubst )
 import qualified GHC.Core.Coercion as Coercion
 import GHC.Core.Coercion hiding ( substCo, substCoVar, substCoVarBndr )
 import GHC.Platform ( Platform )


=====================================
compiler/GHC/Core/Opt/Simplify/Iteration.hs
=====================================
@@ -22,7 +22,7 @@ import GHC.Core.Opt.Simplify.Monad
 import GHC.Core.Type hiding ( substTy, substTyVar, extendTvSubst, extendCvSubst )
 import GHC.Core.Opt.Simplify.Env
 import GHC.Core.Opt.Simplify.Utils
-import GHC.Core.Opt.OccurAnal ( occurAnalyseExpr, zapLambdaBndrs )
+import GHC.Core.Opt.OccurAnal ( occurAnalyseExpr, zapLambdaBndrs, scrutBinderSwap_maybe )
 import GHC.Core.Make       ( FloatBind, mkImpossibleExpr, castBottomExpr )
 import qualified GHC.Core.Make
 import GHC.Core.Coercion hiding ( substCo, substCoVar )
@@ -3240,19 +3240,22 @@ zapIdOccInfoAndSetEvald str v =
                          -- see Note [Case alternative occ info]
 
 addAltUnfoldings :: SimplEnv -> Maybe OutExpr -> OutId -> OutExpr -> SimplM SimplEnv
-addAltUnfoldings env scrut case_bndr con_app
+addAltUnfoldings env mb_scrut case_bndr con_app
   = do { let con_app_unf = mk_simple_unf con_app
              env1 = addBinderUnfolding env case_bndr con_app_unf
 
              -- See Note [Add unfolding for scrutinee]
-             env2 | Many <- idMult case_bndr = case scrut of
-                      Just (Var v)           -> addBinderUnfolding env1 v con_app_unf
-                      Just (Cast (Var v) co) -> addBinderUnfolding env1 v $
-                                                mk_simple_unf (Cast con_app (mkSymCo co))
-                      _                      -> env1
+             env2 | Just scrut <- mb_scrut
+                  , Just (v,mco) <- scrutBinderSwap_maybe scrut
+                  , ManyTy <- idMult case_bndr -- See discussion in #22123
+                  = addBinderUnfolding env1 v $
+                       if isReflMCo mco  -- isReflMCo: avoid calling mk_simple_unf
+                       then con_app_unf  --            twice in the common case
+                       else mk_simple_unf (mkCastMCo con_app mco)
+
                   | otherwise = env1
 
-       ; traceSmpl "addAltUnf" (vcat [ppr case_bndr <+> ppr scrut, ppr con_app])
+       ; traceSmpl "addAltUnf" (vcat [ppr case_bndr <+> ppr mb_scrut, ppr con_app])
        ; return env2 }
   where
     -- Force the opts, so that the whole SimplEnv isn't retained
@@ -3315,9 +3318,6 @@ it's also good for case-elimination -- suppose that 'f' was inlined
 and did multi-level case analysis, then we'd solve it in one
 simplifier sweep instead of two.
 
-Exactly the same issue arises in GHC.Core.Opt.SpecConstr;
-see Note [Add scrutinee to ValueEnv too] in GHC.Core.Opt.SpecConstr
-
 HOWEVER, given
   case x of y { Just a -> r1; Nothing -> r2 }
 we do not want to add the unfolding x -> y to 'x', which might seem cool,
@@ -3328,8 +3328,11 @@ piece of information.
 So instead we add the unfolding x -> Just a, and x -> Nothing in the
 respective RHSs.
 
-Since this transformation is tantamount to a binder swap, the same caveat as in
-Note [Suppressing binder-swaps on linear case] in OccurAnal apply.
+Since this transformation is tantamount to a binder swap, we use
+GHC.Core.Opt.OccurAnal.scrutBinderSwap_maybe to do the check.
+
+Exactly the same issue arises in GHC.Core.Opt.SpecConstr;
+see Note [Add scrutinee to ValueEnv too] in GHC.Core.Opt.SpecConstr
 
 
 ************************************************************************


=====================================
compiler/GHC/Core/Opt/SpecConstr.hs
=====================================
@@ -31,6 +31,7 @@ import GHC.Core.Unfold
 import GHC.Core.FVs     ( exprsFreeVarsList, exprFreeVars )
 import GHC.Core.Opt.Monad
 import GHC.Core.Opt.WorkWrap.Utils
+import GHC.Core.Opt.OccurAnal( scrutBinderSwap_maybe )
 import GHC.Core.DataCon
 import GHC.Core.Class( classTyVars )
 import GHC.Core.Coercion hiding( substCo )
@@ -1057,8 +1058,8 @@ extendCaseBndrs env scrut case_bndr con alt_bndrs
    = (env2, alt_bndrs')
  where
    live_case_bndr = not (isDeadBinder case_bndr)
-   env1 | Var v <- stripTicksTopE (const True) scrut
-                         = extendValEnv env v cval
+   env1 | Just (v, mco) <- scrutBinderSwap_maybe scrut
+        , isReflMCo mco  = extendValEnv env v cval
         | otherwise      = env  -- See Note [Add scrutinee to ValueEnv too]
    env2 | live_case_bndr = extendValEnv env1 case_bndr cval
         | otherwise      = env1
@@ -1148,6 +1149,10 @@ though the simplifier has systematically replaced uses of 'x' with 'y'
 and 'b' with 'c' in the code.  The use of 'b' in the ValueEnv came
 from outside the case.  See #4908 for the live example.
 
+It's very like the binder-swap story, so we use scrutBinderSwap_maybe
+to identify suitable scrutinees -- but only if there is no cast
+(isReflMCo) because that's all that the ValueEnv allows.
+
 Note [Avoiding exponential blowup]
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 The sc_count field of the ScEnv says how many times we are prepared to


=====================================
compiler/GHC/Core/Opt/Specialise.hs
=====================================
@@ -15,9 +15,7 @@ import GHC.Driver.Config
 import GHC.Driver.Config.Diagnostic
 import GHC.Driver.Config.Core.Rules ( initRuleOpts )
 
-import GHC.Tc.Utils.TcType hiding( substTy )
-
-import GHC.Core.Type  hiding( substTy, extendTvSubstList, zapSubst )
+import GHC.Core.Type  hiding( substTy, substCo, extendTvSubstList, zapSubst )
 import GHC.Core.Multiplicity
 import GHC.Core.Predicate
 import GHC.Core.Coercion( Coercion )
@@ -25,12 +23,15 @@ import GHC.Core.Opt.Monad
 import qualified GHC.Core.Subst as Core
 import GHC.Core.Unfold.Make
 import GHC.Core
+import GHC.Core.Make      ( mkLitRubbish )
+import GHC.Core.Unify     ( tcMatchTy )
 import GHC.Core.Rules
 import GHC.Core.Utils     ( exprIsTrivial
                           , mkCast, exprType
                           , stripTicksTop )
 import GHC.Core.FVs
-import GHC.Core.TyCo.Rep (TyCoBinder (..))
+import GHC.Core.TyCo.Rep ( TyCoBinder (..) )
+import GHC.Core.TyCo.FVs ( tyCoVarsOfTypeList )
 import GHC.Core.Opt.Arity( collectBindersPushingCo )
 
 import GHC.Builtin.Types  ( unboxedUnitTy )
@@ -770,6 +771,10 @@ spec_import top_env callers rb dict_binds cis@(CIS fn _)
 canSpecImport :: DynFlags -> Id -> Maybe CoreExpr
 -- See Note [Specialise imported INLINABLE things]
 canSpecImport dflags fn
+  | isDataConWrapId fn
+  = Nothing   -- Don't specialise data-con wrappers, even if they
+              -- have dict args; there is no benefit.
+
   | CoreUnfolding { uf_src = src, uf_tmpl = rhs } <- unf
   , isStableSource src
   = Just rhs   -- By default, specialise only imported things that have a stable
@@ -1493,12 +1498,12 @@ specCalls spec_imp env dict_binds existing_rules calls_for_me fn rhs
 
   | otherwise   -- No calls or RHS doesn't fit our preconceptions
   = warnPprTrace (not (exprIsTrivial rhs) && notNull calls_for_me)
-          "Missed specialisation opportunity" (ppr fn $$ _trace_doc) $
+          "Missed specialisation opportunity for" (ppr fn $$ trace_doc) $
           -- Note [Specialisation shape]
     -- pprTrace "specCalls: none" (ppr fn <+> ppr calls_for_me) $
     return ([], [], emptyUDs)
   where
-    _trace_doc = sep [ ppr rhs_bndrs, ppr (idInlineActivation fn) ]
+    trace_doc = sep [ ppr rhs_bndrs, ppr (idInlineActivation fn) ]
 
     fn_type   = idType fn
     fn_arity  = idArity fn
@@ -1562,8 +1567,16 @@ specCalls spec_imp env dict_binds existing_rules calls_for_me fn rhs
              else
         do { -- Run the specialiser on the specialised RHS
              -- The "1" suffix is before we maybe add the void arg
-           ; (spec_rhs1, rhs_uds) <- specLam rhs_env2 (spec_bndrs1 ++ leftover_bndrs) rhs_body
-           ; let spec_fn_ty1 = exprType spec_rhs1
+           ; (rhs_body', rhs_uds) <- specExpr rhs_env2 rhs_body
+                -- Add the { d1' = dx1; d2' = dx2 } usage stuff
+                -- to the rhs_uds; see Note [Specialising Calls]
+           ; let rhs_uds_w_dx = foldr consDictBind rhs_uds dx_binds
+                 spec_rhs_bndrs  = spec_bndrs1 ++ leftover_bndrs
+                 (spec_uds, dumped_dbs) = dumpUDs spec_rhs_bndrs rhs_uds_w_dx
+                 spec_rhs1 = mkLams spec_rhs_bndrs $
+                             wrapDictBindsE dumped_dbs rhs_body'
+
+                 spec_fn_ty1 = exprType spec_rhs1
 
                  -- Maybe add a void arg to the specialised function,
                  -- to avoid unlifted bindings
@@ -1597,10 +1610,6 @@ specCalls spec_imp env dict_binds existing_rules calls_for_me fn rhs
                                     herald fn rule_bndrs rule_lhs_args
                                     (mkVarApps (Var spec_fn) spec_bndrs)
 
-                -- Add the { d1' = dx1; d2' = dx2 } usage stuff
-                -- See Note [Specialising Calls]
-                spec_uds = foldr consDictBind rhs_uds dx_binds
-
                 simpl_opts = initSimpleOpts dflags
 
                 --------------------------------------
@@ -1615,9 +1624,12 @@ specCalls spec_imp env dict_binds existing_rules calls_for_me fn rhs
                   = (inl_prag { inl_inline = NoUserInlinePrag }, noUnfolding)
 
                   | otherwise
-                  = (inl_prag, specUnfolding simpl_opts spec_bndrs (`mkApps` spec_args)
+                  = (inl_prag, specUnfolding simpl_opts spec_bndrs spec_unf_body
                                              rule_lhs_args fn_unf)
 
+                spec_unf_body body = wrapDictBindsE dumped_dbs $
+                                     body `mkApps` spec_args
+
                 --------------------------------------
                 -- Adding arity information just propagates it a bit faster
                 --      See Note [Arity decrease] in GHC.Core.Opt.Simplify
@@ -1786,11 +1798,23 @@ in the specialisation:
     {-# RULE "SPEC f @Int" forall x. f @Int x $dShow = $sf #-}
 
 This doesn’t save us much, since the arg would be removed later by
-worker/wrapper, anyway, but it’s easy to do. Note, however, that we
-only drop dead arguments if:
+worker/wrapper, anyway, but it’s easy to do.
+
+Wrinkles
+
+* Note that we only drop dead arguments if:
+    1. We don’t specialise on them.
+    2. They come before an argument we do specialise on.
+  Doing the latter would require eta-expanding the RULE, which could
+  make it match less often, so it’s not worth it. Doing the former could
+  be more useful --- it would stop us from generating pointless
+  specialisations --- but it’s more involved to implement and unclear if
+  it actually provides much benefit in practice.
 
-  1. We don’t specialise on them.
-  2. They come before an argument we do specialise on.
+* If the function has a stable unfolding, specHeader has to come up with
+  arguments to pass to that stable unfolding, when building the stable
+  unfolding of the specialised function: this is the last field in specHeader's
+  big result tuple.
 
   The right thing to do is to produce a LitRubbish; it should rapidly
   disappear.  Rather like GHC.Core.Opt.WorkWrap.Utils.mk_absent_let.
@@ -2268,11 +2292,11 @@ instance Outputable SpecArg where
   ppr (SpecDict d) = text "SpecDict" <+> ppr d
   ppr UnspecArg    = text "UnspecArg"
 
-specArgFreeVars :: SpecArg -> VarSet
-specArgFreeVars (SpecType ty) = tyCoVarsOfType ty
-specArgFreeVars (SpecDict dx) = exprFreeVars dx
-specArgFreeVars UnspecType    = emptyVarSet
-specArgFreeVars UnspecArg     = emptyVarSet
+specArgFreeIds :: SpecArg -> IdSet
+specArgFreeIds (SpecType {}) = emptyVarSet
+specArgFreeIds (SpecDict dx) = exprFreeIds dx
+specArgFreeIds UnspecType    = emptyVarSet
+specArgFreeIds UnspecArg     = emptyVarSet
 
 isSpecDict :: SpecArg -> Bool
 isSpecDict (SpecDict {}) = True
@@ -2342,24 +2366,30 @@ specHeader
               , [OutBndr]    -- Binders for $sf
               , [DictBind]   -- Auxiliary dictionary bindings
               , [OutExpr]    -- Specialised arguments for unfolding
-                             -- Same length as "args for LHS of rule"
+                             -- Same length as "Args for LHS of rule"
               )
 
 -- We want to specialise on type 'T1', and so we must construct a substitution
 -- 'a->T1', as well as a LHS argument for the resulting RULE and unfolding
 -- details.
-specHeader env (bndr : bndrs) (SpecType t : args)
-  = do { let env' = extendTvSubstList env [(bndr, t)]
-       ; (useful, env'', leftover_bndrs, rule_bs, rule_es, bs', dx, spec_args)
-            <- specHeader env' bndrs args
+specHeader env (bndr : bndrs) (SpecType ty : args)
+  = do { let in_scope = Core.getSubstInScope (se_subst env)
+             qvars    = scopedSort $
+                        filterOut (`elemInScopeSet` in_scope) $
+                        tyCoVarsOfTypeList ty
+             (env1, qvars') = substBndrs env qvars
+             ty'            = substTy env1 ty
+             env2           = extendTvSubstList env1 [(bndr, ty')]
+       ; (useful, env3, leftover_bndrs, rule_bs, rule_es, bs', dx, spec_args)
+            <- specHeader env2 bndrs args
        ; pure ( useful
-              , env''
+              , env3
               , leftover_bndrs
-              , rule_bs
-              , Type t : rule_es
-              , bs'
+              , qvars' ++ rule_bs
+              , Type ty' : rule_es
+              , qvars' ++ bs'
               , dx
-              , Type t : spec_args
+              , Type ty' : spec_args
               )
        }
 
@@ -2415,16 +2445,28 @@ specHeader env (bndr : bndrs) (UnspecArg : args)
          let (env', bndr') = substBndr env (zapIdOccInfo bndr)
        ; (useful, env'', leftover_bndrs, rule_bs, rule_es, bs', dx, spec_args)
              <- specHeader env' bndrs args
+
+       ; let bndr_ty = idType bndr'
+
+             -- See Note [Drop dead args from specialisations]
+             -- C.f. GHC.Core.Opt.WorkWrap.Utils.mk_absent_let
+             (mb_spec_bndr, spec_arg)
+                | isDeadBinder bndr
+                , Just lit_expr <- mkLitRubbish bndr_ty
+                = (Nothing, lit_expr)
+                | otherwise
+                = (Just bndr', varToCoreExpr bndr')
+
        ; pure ( useful
               , env''
               , leftover_bndrs
               , bndr' : rule_bs
               , varToCoreExpr bndr' : rule_es
-              , if isDeadBinder bndr
-                  then bs' -- see Note [Drop dead args from specialisations]
-                  else bndr' : bs'
+              , case mb_spec_bndr of
+                  Just b' -> b' : bs'
+                  Nothing -> bs'
               , dx
-              , varToCoreExpr bndr' : spec_args
+              , spec_arg : spec_args
               )
        }
 
@@ -2550,6 +2592,60 @@ successfully specialise 'f'.
 
 So the DictBinds in (ud_binds :: OrdList DictBind) may contain
 non-dictionary bindings too.
+
+Note [Specialising polymorphic dictionaries]
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+Consider
+    class M a where { foo :: a -> Int }
+
+    instance M (ST s) where ...
+    -- dMST :: forall s. M (ST s)
+
+    wimwam :: forall a. M a => a -> Int
+    wimwam = /\a \(d::M a). body
+
+    f :: ST s -> Int
+    f = /\s \(x::ST s). wimwam @(ST s) (dMST @s) dx + 1
+
+We'd like to specialise wimwam at (ST s), thus
+    $swimwam :: forall s. ST s -> Int
+    $swimwam = /\s. body[ST s/a, (dMST @s)/d]
+
+    RULE forall s (d :: M (ST s)).
+         wimwam @(ST s) d = $swimwam @s
+
+Here are the moving parts:
+
+* We must /not/ dump the CallInfo
+    CIS wimwam (CI { ci_key = [@(ST s), dMST @s]
+                   , ci_fvs = {dMST} })
+  when we come to the /\s.  Instead, we simply let it continue to float
+  upwards. Hence ci_fvs is an IdSet, listing the /Ids/ that
+  are free in the call, but not the /TyVars/.  Hence using specArgFreeIds
+  in singleCall.
+
+  NB to be fully kosher we should explicitly quantifying the CallInfo
+  over 's', but we don't bother.  This would matter if there was an
+  enclosing binding of the same 's', which I don't expect to happen.
+
+* Whe we come to specialise the call, we must remember to quantify
+  over 's'.  That is done in the SpecType case of specHeader, where
+  we add 's' (called qvars) to the binders of the RULE and the specialised
+  function.
+
+* If we have f :: forall m. Monoid m => blah, and two calls
+     (f @(Endo b)      (d :: Monoid (Endo b))
+     (f @(Endo (c->c)) (d :: Monoid (Endo (c->c)))
+  we want to generate a specialisation only for the first.  The second
+  is just a substitution instance of the first, with no greater specialisation.
+  Hence the call to `remove_dups` in `filterCalls`.
+
+All this arose in #13873, in the unexpected form that a SPECIALISE
+pragma made the program slower!  The reason was that the specialised
+function $sinsertWith arising from the pragma looked rather like `f`
+above, and failed to specialise a call in its body like wimwam.
+Without the pragma, the original call to `insertWith` was completely
+monomorpic, and speciased in one go.
 -}
 
 instance Outputable DictBind where
@@ -2588,8 +2684,9 @@ data CallInfoSet = CIS Id (Bag CallInfo)
 data CallInfo
   = CI { ci_key  :: [SpecArg]   -- All arguments
        , ci_fvs  :: IdSet       -- Free Ids of the ci_key call
-                                -- _not_ including the main id itself, of course
+                                -- /not/ including the main id itself, of course
                                 -- NB: excluding tyvars:
+                                --     See Note [Specialising polymorphic dictionaries]
     }
 
 type DictExpr = CoreExpr
@@ -2638,7 +2735,7 @@ singleCall id args
                      unitBag (CI { ci_key  = args -- used to be tys
                                  , ci_fvs  = call_fvs }) }
   where
-    call_fvs = foldr (unionVarSet . specArgFreeVars) emptyVarSet args
+    call_fvs = foldr (unionVarSet . specArgFreeIds) emptyVarSet args
         -- The type args (tys) are guaranteed to be part of the dictionary
         -- types, because they are just the constrained types,
         -- and the dictionary is therefore sure to be bound
@@ -2968,15 +3065,15 @@ callsForMe fn uds at MkUD { ud_binds = orig_dbs, ud_calls = orig_calls }
 
 ----------------------
 filterCalls :: CallInfoSet -> FloatedDictBinds -> [CallInfo]
--- Remove dominated calls
+-- Remove dominated calls (Note [Specialising polymorphic dictionaries])
 -- and loopy DFuns (Note [Avoiding loops (DFuns)])
 filterCalls (CIS fn call_bag) (FDB { fdb_binds = dbs })
   | isDFunId fn  -- Note [Avoiding loops (DFuns)] applies only to DFuns
-  = filter ok_call unfiltered_calls
-  | otherwise         -- Do not apply it to non-DFuns
-  = unfiltered_calls  -- See Note [Avoiding loops (non-DFuns)]
+  = filter ok_call de_dupd_calls
+  | otherwise      -- Do not apply (filter ok_call) to non-DFuns
+  = de_dupd_calls  -- See Note [Avoiding loops (non-DFuns)]
   where
-    unfiltered_calls = bagToList call_bag
+    de_dupd_calls = remove_dups call_bag
 
     dump_set = foldl' go (unitVarSet fn) dbs
       -- This dump-set could also be computed by splitDictBinds
@@ -2990,6 +3087,29 @@ filterCalls (CIS fn call_bag) (FDB { fdb_binds = dbs })
 
     ok_call (CI { ci_fvs = fvs }) = fvs `disjointVarSet` dump_set
 
+remove_dups :: Bag CallInfo -> [CallInfo]
+remove_dups calls = foldr add [] calls
+  where
+    add :: CallInfo -> [CallInfo] -> [CallInfo]
+    add ci [] = [ci]
+    add ci1 (ci2:cis) | ci2 `beats_or_same` ci1 = ci2:cis
+                      | ci1 `beats_or_same` ci2 = ci1:cis
+                      | otherwise               = ci2 : add ci1 cis
+
+beats_or_same :: CallInfo -> CallInfo -> Bool
+beats_or_same (CI { ci_key = args1 }) (CI { ci_key = args2 })
+  = go args1 args2
+  where
+    go [] _ = True
+    go (arg1:args1) (arg2:args2) = go_arg arg1 arg2 && go args1 args2
+    go (_:_)        []           = False
+
+    go_arg (SpecType ty1) (SpecType ty2) = isJust (tcMatchTy ty1 ty2)
+    go_arg UnspecType     UnspecType     = True
+    go_arg (SpecDict {})  (SpecDict {})  = True
+    go_arg UnspecArg      UnspecArg      = True
+    go_arg _              _              = False
+
 ----------------------
 splitDictBinds :: FloatedDictBinds -> IdSet -> (FloatedDictBinds, OrdList DictBind, IdSet)
 -- splitDictBinds dbs bndrs returns
@@ -3020,15 +3140,18 @@ splitDictBinds (FDB { fdb_binds = dbs, fdb_bndrs = bs }) bndr_set
 
 ----------------------
 deleteCallsMentioning :: VarSet -> CallDetails -> CallDetails
--- Remove calls *mentioning* bs in any way
-deleteCallsMentioning bs calls
+-- Remove calls mentioning any Id in bndrs
+-- NB: The call is allowed to mention TyVars in bndrs
+--     Note [Specialising polymorphic dictionaries]
+--     ci_fvs are just the free /Ids/
+deleteCallsMentioning bndrs calls
   = mapDVarEnv (ciSetFilter keep_call) calls
   where
-    keep_call (CI { ci_fvs = fvs }) = fvs `disjointVarSet` bs
+    keep_call (CI { ci_fvs = fvs }) = fvs `disjointVarSet` bndrs
 
 deleteCallsFor :: [Id] -> CallDetails -> CallDetails
--- Remove calls *for* bs
-deleteCallsFor bs calls = delDVarEnvList calls bs
+-- Remove calls *for* bndrs
+deleteCallsFor bndrs calls = delDVarEnvList calls bndrs
 
 {-
 ************************************************************************


=====================================
compiler/GHC/Core/Subst.hs
=====================================
@@ -26,7 +26,8 @@ module GHC.Core.Subst (
         extendIdSubstWithClone,
         extendSubst, extendSubstList, extendSubstWithVar,
         extendSubstInScope, extendSubstInScopeList, extendSubstInScopeSet,
-        isInScope, setInScope, extendTvSubst, extendCvSubst,
+        isInScope, setInScope, getSubstInScope,
+        extendTvSubst, extendCvSubst,
         delBndr, delBndrs, zapSubst,
 
         -- ** Substituting and cloning binders
@@ -41,7 +42,6 @@ import GHC.Core
 import GHC.Core.FVs
 import GHC.Core.Seq
 import GHC.Core.Utils
-import GHC.Core.TyCo.Subst ( substCo )
 
         -- We are defining local versions
 import GHC.Core.Type hiding ( substTy )


=====================================
compiler/GHC/Core/TyCo/FVs.hs
=====================================
@@ -231,7 +231,7 @@ Recall that
     foldType :: TyCoFolder env a -> env -> Type -> a
 
     newtype Endo a = Endo (a -> a)   -- In Data.Monoid
-    instance Monoid a => Monoid (Endo a) where
+    instance Monoid (Endo a) where
        (Endo f) `mappend` (Endo g) = Endo (f.g)
 
     appEndo :: Endo a -> a -> a


=====================================
compiler/GHC/Core/Type.hs
=====================================
@@ -219,7 +219,7 @@ module GHC.Core.Type (
         substTyAddInScope,
         substTyUnchecked, substTysUnchecked, substScaledTyUnchecked, substScaledTysUnchecked,
         substThetaUnchecked, substTyWithUnchecked,
-        substCoUnchecked, substCoWithUnchecked,
+        substCo, substCoUnchecked, substCoWithUnchecked,
         substTyVarBndr, substTyVarBndrs, substTyVar, substTyVars,
         substVarBndr, substVarBndrs,
         substTyCoBndr,


=====================================
hadrian/bootstrap/bootstrap.py
=====================================
@@ -86,14 +86,17 @@ class Compiler:
 
         self.ghc_path = ghc_path.resolve()
 
+        exe = ''
+        if platform.system() == 'Windows': exe = '.exe'
+
         info = self._get_ghc_info()
         self.version = info['Project version']
         #self.lib_dir = Path(info['LibDir'])
         #self.ghc_pkg_path = (self.lib_dir / 'bin' / 'ghc-pkg').resolve()
-        self.ghc_pkg_path = (self.ghc_path.parent / 'ghc-pkg').resolve()
+        self.ghc_pkg_path = (self.ghc_path.parent / ('ghc-pkg' + exe)).resolve()
         if not self.ghc_pkg_path.is_file():
             raise TypeError(f'ghc-pkg {self.ghc_pkg_path} is not a file')
-        self.hsc2hs_path = (self.ghc_path.parent / 'hsc2hs').resolve()
+        self.hsc2hs_path = (self.ghc_path.parent / ('hsc2hs' + exe)).resolve()
         if not self.hsc2hs_path.is_file():
             raise TypeError(f'hsc2hs {self.hsc2hs_path} is not a file')
 
@@ -367,6 +370,11 @@ def main() -> None:
                         help='path to GHC')
     parser.add_argument('-s', '--bootstrap-sources', type=Path,
                         help='Path to prefetched bootstrap sources tarball')
+    parser.add_argument('--archive', dest='want_archive', action='store_true',
+                       help='produce a Hadrian distribution archive (default)')
+    parser.add_argument('--no-archive', dest='want_archive', action='store_false',
+                       help='do not produce a Hadrian distribution archive')
+    parser.set_defaults(want_archive=True)
 
     subparsers = parser.add_subparsers(dest="command")
 
@@ -381,6 +389,9 @@ def main() -> None:
 
     ghc = None
 
+    sources_fmt = 'gztar' # The archive format for the bootstrap sources archive.
+    if platform.system() == 'Windows': sources_fmt = 'zip'
+
     if args.deps is None:
       if args.bootstrap_sources is None:
         # find appropriate plan in the same directory as the script
@@ -390,7 +401,7 @@ def main() -> None:
       # We have a tarball with all the required information, unpack it and use for further
       elif args.bootstrap_sources is not None and args.command != 'list-sources':
         print(f'Unpacking {args.bootstrap_sources} to {TARBALLS}')
-        shutil.unpack_archive(args.bootstrap_sources.resolve(), TARBALLS, 'gztar')
+        shutil.unpack_archive(args.bootstrap_sources.resolve(), TARBALLS, sources_fmt)
         args.deps = TARBALLS / 'plan-bootstrap.json'
         print(f"using plan-bootstrap.json ({args.deps}) from {args.bootstrap_sources}")
       else:
@@ -428,10 +439,7 @@ def main() -> None:
 
         shutil.copyfile(args.deps, rootdir / 'plan-bootstrap.json')
 
-        fmt = 'gztar'
-        if platform.system() == 'Windows': fmt = 'zip'
-
-        archivename = shutil.make_archive(args.output, fmt, root_dir=rootdir)
+        archivename = shutil.make_archive(args.output, sources_fmt, root_dir=rootdir)
 
         print(f"""
 Bootstrap sources saved to {archivename}
@@ -475,21 +483,21 @@ Alternatively, you could use `bootstrap.py -w {ghc.ghc_path} -d {args.deps} fetc
         bootstrap(info, ghc)
         hadrian_path = (BINDIR / 'hadrian').resolve()
 
-        archive = make_archive(hadrian_path)
-
         print(dedent(f'''
             Bootstrapping finished!
 
             The resulting hadrian executable can be found at
 
                 {hadrian_path}
+        '''))
 
-            It has been archived for distribution in
-
-                {archive}
+        if args.want_archive:
+            dist_archive = make_archive(hadrian_path)
+            print(dedent(f'''
+                The Hadrian executable has been archived for distribution in
 
-            You can use this executable to build GHC.
-        '''))
+                    {dist_archive}
+            '''))
     else:
       print(f"No such command: {args.command}")
 


=====================================
testsuite/tests/linters/notes.stdout
=====================================
@@ -2,7 +2,6 @@ ref    compiler/GHC/Core/Coercion/Axiom.hs:458:2:     Note [RoughMap and rm_empt
 ref    compiler/GHC/Core/Opt/OccurAnal.hs:857:15:     Note [Loop breaking]
 ref    compiler/GHC/Core/Opt/SetLevels.hs:1598:30:     Note [Top level scope]
 ref    compiler/GHC/Core/Opt/Simplify/Iteration.hs:2666:13:     Note [Case binder next]
-ref    compiler/GHC/Core/Opt/Simplify/Iteration.hs:3288:0:     Note [Suppressing binder-swaps on linear case]
 ref    compiler/GHC/Core/Opt/Simplify/Iteration.hs:3816:8:     Note [Lambda-bound unfoldings]
 ref    compiler/GHC/Core/Opt/Simplify/Utils.hs:1282:37:     Note [Gentle mode]
 ref    compiler/GHC/Core/Opt/Specialise.hs:1611:28:     Note [Arity decrease]


=====================================
testsuite/tests/simplCore/should_compile/T8331.stderr
=====================================
@@ -1,6 +1,103 @@
 
 ==================== Tidy Core rules ====================
-"USPEC useAbstractMonad @(ReaderT Int (ST s))"
+"SPEC $c*> @(ST s) _"
+    forall (@s) (@r) ($dApplicative :: Applicative (ST s)).
+      $fApplicativeReaderT_$c*> @(ST s) @r $dApplicative
+      = ($fApplicativeReaderT3 @s @r)
+        `cast` (forall (a :: <*>_N) (b :: <*>_N).
+                <ReaderT r (ST s) a>_R
+                %<'Many>_N ->_R <ReaderT r (ST s) b>_R
+                %<'Many>_N ->_R <r>_R %<'Many>_N ->_R Sym (N:ST[0] <s>_N <b>_R)
+                                ; Sym (N:ReaderT[0] <*>_N <r>_R <ST s>_R <b>_N)
+                :: Coercible
+                     (forall {a} {b}.
+                      ReaderT r (ST s) a -> ReaderT r (ST s) b -> r -> STRep s b)
+                     (forall {a} {b}.
+                      ReaderT r (ST s) a -> ReaderT r (ST s) b -> ReaderT r (ST s) b))
+"SPEC $c<* @(ST s) _"
+    forall (@s) (@r) ($dApplicative :: Applicative (ST s)).
+      $fApplicativeReaderT_$c<* @(ST s) @r $dApplicative
+      = ($fApplicativeReaderT2 @s @r)
+        `cast` (forall (a :: <*>_N) (b :: <*>_N).
+                <ReaderT r (ST s) a>_R
+                %<'Many>_N ->_R <ReaderT r (ST s) b>_R
+                %<'Many>_N ->_R <r>_R %<'Many>_N ->_R Sym (N:ST[0] <s>_N <a>_R)
+                                ; Sym (N:ReaderT[0] <*>_N <r>_R <ST s>_R <a>_N)
+                :: Coercible
+                     (forall {a} {b}.
+                      ReaderT r (ST s) a -> ReaderT r (ST s) b -> r -> STRep s a)
+                     (forall {a} {b}.
+                      ReaderT r (ST s) a -> ReaderT r (ST s) b -> ReaderT r (ST s) a))
+"SPEC $c<*> @(ST s) _"
+    forall (@s) (@r) ($dApplicative :: Applicative (ST s)).
+      $fApplicativeReaderT5 @(ST s) @r $dApplicative
+      = ($fApplicativeReaderT6 @s @r)
+        `cast` (forall (a :: <*>_N) (b :: <*>_N).
+                <ReaderT r (ST s) (a -> b)>_R
+                %<'Many>_N ->_R <ReaderT r (ST s) a>_R
+                %<'Many>_N ->_R <r>_R
+                %<'Many>_N ->_R Sym (N:ST[0] <s>_N <b>_R)
+                :: Coercible
+                     (forall {a} {b}.
+                      ReaderT r (ST s) (a -> b) -> ReaderT r (ST s) a -> r -> STRep s b)
+                     (forall {a} {b}.
+                      ReaderT r (ST s) (a -> b) -> ReaderT r (ST s) a -> r -> ST s b))
+"SPEC $c>> @(ST s) _"
+    forall (@s) (@r) ($dMonad :: Monad (ST s)).
+      $fMonadReaderT_$c>> @(ST s) @r $dMonad
+      = $fMonadAbstractIOSTReaderT_$s$c>> @s @r
+"SPEC $c>>= @(ST s) _"
+    forall (@s) (@r) ($dMonad :: Monad (ST s)).
+      $fMonadReaderT1 @(ST s) @r $dMonad
+      = ($fMonadReaderT2 @s @r)
+        `cast` (forall (a :: <*>_N) (b :: <*>_N).
+                <ReaderT r (ST s) a>_R
+                %<'Many>_N ->_R <a -> ReaderT r (ST s) b>_R
+                %<'Many>_N ->_R <r>_R
+                %<'Many>_N ->_R Sym (N:ST[0] <s>_N <b>_R)
+                :: Coercible
+                     (forall {a} {b}.
+                      ReaderT r (ST s) a -> (a -> ReaderT r (ST s) b) -> r -> STRep s b)
+                     (forall {a} {b}.
+                      ReaderT r (ST s) a -> (a -> ReaderT r (ST s) b) -> r -> ST s b))
+"SPEC $cliftA2 @(ST s) _"
+    forall (@s) (@r) ($dApplicative :: Applicative (ST s)).
+      $fApplicativeReaderT_$cliftA2 @(ST s) @r $dApplicative
+      = ($fApplicativeReaderT1 @s @r)
+        `cast` (forall (a :: <*>_N) (b :: <*>_N) (c :: <*>_N).
+                <a -> b -> c>_R
+                %<'Many>_N ->_R <ReaderT r (ST s) a>_R
+                %<'Many>_N ->_R <ReaderT r (ST s) b>_R
+                %<'Many>_N ->_R <r>_R %<'Many>_N ->_R Sym (N:ST[0] <s>_N <c>_R)
+                                ; Sym (N:ReaderT[0] <*>_N <r>_R <ST s>_R <c>_N)
+                :: Coercible
+                     (forall {a} {b} {c}.
+                      (a -> b -> c)
+                      -> ReaderT r (ST s) a -> ReaderT r (ST s) b -> r -> STRep s c)
+                     (forall {a} {b} {c}.
+                      (a -> b -> c)
+                      -> ReaderT r (ST s) a -> ReaderT r (ST s) b -> ReaderT r (ST s) c))
+"SPEC $cp1Applicative @(ST s) _"
+    forall (@s) (@r) ($dApplicative :: Applicative (ST s)).
+      $fApplicativeReaderT_$cp1Applicative @(ST s) @r $dApplicative
+      = $fApplicativeReaderT_$s$fFunctorReaderT @s @r
+"SPEC $cp1Monad @(ST s) _"
+    forall (@s) (@r) ($dMonad :: Monad (ST s)).
+      $fMonadReaderT_$cp1Monad @(ST s) @r $dMonad
+      = $fApplicativeReaderT_$s$fApplicativeReaderT @s @r
+"SPEC $fApplicativeReaderT @(ST s) _"
+    forall (@s) (@r) ($dApplicative :: Applicative (ST s)).
+      $fApplicativeReaderT @(ST s) @r $dApplicative
+      = $fApplicativeReaderT_$s$fApplicativeReaderT @s @r
+"SPEC $fFunctorReaderT @(ST s) _"
+    forall (@s) (@r) ($dFunctor :: Functor (ST s)).
+      $fFunctorReaderT @(ST s) @r $dFunctor
+      = $fApplicativeReaderT_$s$fFunctorReaderT @s @r
+"SPEC $fMonadReaderT @(ST s) _"
+    forall (@s) (@r) ($dMonad :: Monad (ST s)).
+      $fMonadReaderT @(ST s) @r $dMonad
+      = $fMonadAbstractIOSTReaderT_$s$fMonadReaderT @s @r
+"SPEC useAbstractMonad"
     forall (@s)
            ($dMonadAbstractIOST :: MonadAbstractIOST (ReaderT Int (ST s))).
       useAbstractMonad @(ReaderT Int (ST s)) $dMonadAbstractIOST


=====================================
testsuite/tests/simplCore/should_compile/all.T
=====================================
@@ -359,7 +359,6 @@ test('T19586', normal, compile, [''])
 
 test('T19599', normal, compile, ['-O -ddump-rules'])
 test('T19599a', normal, compile, ['-O -ddump-rules'])
-test('T13873',  [expect_broken(21229), grep_errmsg(r'SPEC') ], compile, ['-O -ddump-rules'])
 
 # Look for a specialisation rule for wimwam
 test('T19672', normal, compile, ['-O2 -ddump-rules'])
@@ -428,3 +427,4 @@ test('T21948', [grep_errmsg(r'^ Arity=5') ], compile, ['-O -ddump-simpl'])
 test('T21763', only_ways(['optasm']), compile, ['-O2 -ddump-rules'])
 test('T21763a', only_ways(['optasm']), compile, ['-O2 -ddump-rules'])
 test('T22028', normal, compile, ['-O -ddump-rule-firings'])
+test('T13873',  [ grep_errmsg(r'SPEC') ], compile, ['-O -ddump-rules'])



View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/compare/8b7d4eb5b5f75a2e2b93ebbc5f3952c3ea2ace2c...cd3f0c275091944b9dc5ae4b2b5e5484cfd3b171

-- 
View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/compare/8b7d4eb5b5f75a2e2b93ebbc5f3952c3ea2ace2c...cd3f0c275091944b9dc5ae4b2b5e5484cfd3b171
You're receiving this email because of your account on gitlab.haskell.org.


-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.haskell.org/pipermail/ghc-commits/attachments/20220831/6071fbc6/attachment-0001.html>


More information about the ghc-commits mailing list