Simon Peyton Jones pushed to branch wip/T26989 at Glasgow Haskell Compiler / GHC
Commits:
-
9ec89815
by Simon Peyton Jones at 2026-04-28T11:48:38+01:00
-
bd1503ad
by Simon Peyton Jones at 2026-04-28T11:50:14+01:00
4 changed files:
- compiler/GHC/Core/Opt/Arity.hs
- compiler/GHC/Core/Opt/Simplify/Iteration.hs
- compiler/GHC/Core/TyCo/Subst.hs
- compiler/GHC/Tc/Types/Evidence.hs
Changes:
| ... | ... | @@ -2875,43 +2875,44 @@ pushCoArg :: CoercionR -> CoreArg -> Maybe (CoreArg, MCoercion) |
| 2875 | 2875 | -- 'co' is always Representational
|
| 2876 | 2876 | pushCoArg co arg
|
| 2877 | 2877 | | Type ty <- arg
|
| 2878 | - = do { (ty', m_co') <- pushCoTyArg co ty
|
|
| 2878 | + = do { (_, ty', m_co') <- pushCoTyArg co ty
|
|
| 2879 | 2879 | ; return (Type ty', m_co') }
|
| 2880 | 2880 | | otherwise
|
| 2881 | - = do { (arg_mco, m_co') <- pushCoValArg co
|
|
| 2881 | + = do { (_, arg_mco, m_co') <- pushCoValArg co
|
|
| 2882 | 2882 | ; let arg_mco' = checkReflexiveMCo arg_mco
|
| 2883 | 2883 | -- checkReflexiveMCo: see Note [Check for reflexive casts in eta expansion]
|
| 2884 | 2884 | -- The coercion is very often (arg_co -> res_co), but without
|
| 2885 | 2885 | -- the argument coercion actually being ReflCo
|
| 2886 | 2886 | ; return (arg `mkCastMCo` arg_mco', m_co') }
|
| 2887 | 2887 | |
| 2888 | -pushCoTyArg :: CoercionR -> Type -> Maybe (Type, MCoercionR)
|
|
| 2888 | +pushCoTyArg :: CoercionR -> Type -> Maybe (Type, Type, MCoercionR)
|
|
| 2889 | 2889 | -- We have (fun |> co) @ty
|
| 2890 | 2890 | -- Push the coercion through to return
|
| 2891 | 2891 | -- (fun @ty') |> co'
|
| 2892 | 2892 | -- 'co' is always Representational
|
| 2893 | 2893 | -- If the returned coercion is Nothing, then it would have been reflexive;
|
| 2894 | 2894 | -- it's faster not to compute it, though.
|
| 2895 | -pushCoTyArg co ty
|
|
| 2895 | +pushCoTyArg co arg_ty
|
|
| 2896 | 2896 | -- The following is inefficient - don't do `eqType` here, the coercion
|
| 2897 | 2897 | -- optimizer will take care of it. See #14737.
|
| 2898 | 2898 | -- -- | tyL `eqType` tyR
|
| 2899 | 2899 | -- -- = Just (ty, Nothing)
|
| 2900 | 2900 | |
| 2901 | - | isReflCo co
|
|
| 2902 | - = Just (ty, MRefl)
|
|
| 2901 | + | Just (ty, _) <- isReflCo_maybe co
|
|
| 2902 | + = Just (ty, arg_ty, MRefl)
|
|
| 2903 | 2903 | |
| 2904 | 2904 | | isForAllTy_ty tyL
|
| 2905 | - = assertPpr (isForAllTy_ty tyR) (ppr co $$ ppr ty) $
|
|
| 2906 | - Just (ty `mkCastTy` co1, MCo co2)
|
|
| 2905 | + = assertPpr (isForAllTy_ty tyR) (ppr co $$ ppr arg_ty) $
|
|
| 2906 | + Just (tyL, arg_ty `mkCastTy` co1, MCo co2)
|
|
| 2907 | 2907 | |
| 2908 | 2908 | | otherwise
|
| 2909 | 2909 | = Nothing
|
| 2910 | 2910 | where
|
| 2911 | - Pair tyL tyR = coercionKind co
|
|
| 2912 | - -- co :: tyL ~R tyR
|
|
| 2913 | - -- tyL = forall (a1 :: k1). ty1
|
|
| 2914 | - -- tyR = forall (a2 :: k2). ty2
|
|
| 2911 | + -- co :: tyL ~R tyR
|
|
| 2912 | + -- tyL = forall (a1 :: k1). ty1
|
|
| 2913 | + -- tyR = forall (a2 :: k2). ty2
|
|
| 2914 | + tyL = coercionLKind co
|
|
| 2915 | + tyR = coercionRKind co -- Used only in asssertions and debug messages
|
|
| 2915 | 2916 | |
| 2916 | 2917 | co1 = mkSymCo (mkSelCo SelForAll co)
|
| 2917 | 2918 | -- co1 :: k2 ~N k1
|
| ... | ... | @@ -2919,30 +2920,32 @@ pushCoTyArg co ty |
| 2919 | 2920 | -- kinds of the types related by a coercion between forall-types.
|
| 2920 | 2921 | -- See the SelCo case in GHC.Core.Lint.
|
| 2921 | 2922 | |
| 2922 | - co2 = mkInstCo co (mkGReflLeftCo Nominal ty co1)
|
|
| 2923 | - -- co2 :: ty1[ (ty|>co1)/a1 ] ~R ty2[ ty/a2 ]
|
|
| 2923 | + co2 = mkInstCo co (mkGReflLeftCo Nominal arg_ty co1)
|
|
| 2924 | + -- co2 :: ty1[ (arg_ty|>co1)/a1 ] ~R ty2[ arg_ty/a2 ]
|
|
| 2924 | 2925 | -- Arg of mkInstCo is always nominal, hence Nominal
|
| 2925 | 2926 | |
| 2926 | --- | If @pushCoValArg co = Just (co_arg, co_res)@, then
|
|
| 2927 | +-- | If @pushCoValArg co = Just (tyL, co_arg, co_res)@, then
|
|
| 2927 | 2928 | --
|
| 2928 | --- > (\x.body) |> co = (\y. let { x = y |> co_arg } in body) |> co_res)
|
|
| 2929 | +-- co :: tyL ~R# tyR
|
|
| 2930 | +-- and
|
|
| 2931 | +-- (\x.body) |> co = (\y. let { x = y |> co_arg } in body) |> co_res)
|
|
| 2929 | 2932 | --
|
| 2930 | 2933 | -- or, equivalently
|
| 2931 | 2934 | --
|
| 2932 | --- > (fun |> co) arg = (fun (arg |> co_arg)) |> co_res
|
|
| 2935 | +-- (fun |> co) arg = (fun (arg |> co_arg)) |> co_res
|
|
| 2933 | 2936 | --
|
| 2934 | 2937 | -- If the LHS is well-typed, then so is the RHS. In particular, the argument
|
| 2935 | 2938 | -- @arg |> co_arg@ is guaranteed to have a fixed 'RuntimeRep', in the sense of
|
| 2936 | 2939 | -- Note [Fixed RuntimeRep] in GHC.Tc.Utils.Concrete.
|
| 2937 | -pushCoValArg :: CoercionR -> Maybe (MCoercionR, MCoercionR)
|
|
| 2940 | +pushCoValArg :: CoercionR -> Maybe (Type, MCoercionR, MCoercionR)
|
|
| 2938 | 2941 | pushCoValArg co
|
| 2939 | 2942 | -- The following is inefficient - don't do `eqType` here, the coercion
|
| 2940 | 2943 | -- optimizer will take care of it. See #14737.
|
| 2941 | 2944 | -- -- | tyL `eqType` tyR
|
| 2942 | 2945 | -- -- = Just (mkRepReflCo arg, Nothing)
|
| 2943 | 2946 | |
| 2944 | - | isReflCo co
|
|
| 2945 | - = Just (MRefl, MRefl)
|
|
| 2947 | + | Just (ty, _) <- isReflCo_maybe co
|
|
| 2948 | + = Just (ty, MRefl, MRefl)
|
|
| 2946 | 2949 | |
| 2947 | 2950 | | isFunTy tyL
|
| 2948 | 2951 | , (_, co1, co2) <- decomposeFunCo co
|
| ... | ... | @@ -2961,7 +2964,7 @@ pushCoValArg co |
| 2961 | 2964 | (vcat [ text "co:" <+> ppr co
|
| 2962 | 2965 | , text "old_arg_ty:" <+> ppr old_arg_ty
|
| 2963 | 2966 | , text "new_arg_ty:" <+> ppr new_arg_ty ]) $
|
| 2964 | - Just (coToMCo (mkSymCo co1), coToMCo co2)
|
|
| 2967 | + Just (tyL, coToMCo (mkSymCo co1), coToMCo co2)
|
|
| 2965 | 2968 | -- Critically, coToMCo to checks for ReflCo; the whole coercion may not
|
| 2966 | 2969 | -- be reflexive, but either of its components might be
|
| 2967 | 2970 | -- We could use isReflexiveCo, but it's not clear if the benefit
|
| ... | ... | @@ -2970,9 +2973,12 @@ pushCoValArg co |
| 2970 | 2973 | | otherwise
|
| 2971 | 2974 | = Nothing
|
| 2972 | 2975 | where
|
| 2973 | - old_arg_ty = funArgTy tyR
|
|
| 2976 | + tyL = coercionLKind co
|
|
| 2974 | 2977 | new_arg_ty = funArgTy tyL
|
| 2975 | - Pair tyL tyR = coercionKind co
|
|
| 2978 | + |
|
| 2979 | + -- These two are used only in assertions and debug messages
|
|
| 2980 | + tyR = coercionRKind co
|
|
| 2981 | + old_arg_ty = funArgTy tyR
|
|
| 2976 | 2982 | |
| 2977 | 2983 | pushCoercionIntoLambda
|
| 2978 | 2984 | :: HasDebugCallStack => InScopeSet -> Var -> CoreExpr -> CoercionR -> Maybe (Var, CoreExpr)
|
| ... | ... | @@ -17,8 +17,7 @@ import GHC.Driver.Flags |
| 17 | 17 | import GHC.Core
|
| 18 | 18 | import GHC.Core.Opt.Simplify.Monad
|
| 19 | 19 | import GHC.Core.Opt.ConstantFold
|
| 20 | -import GHC.Core.Type hiding ( substCo, substTy, substTyVar, extendTvSubst, extendCvSubst )
|
|
| 21 | -import GHC.Core.TyCo.Compare( eqType )
|
|
| 20 | +import GHC.Core.Opt.Stats ( Tick(..) )
|
|
| 22 | 21 | import GHC.Core.Opt.Simplify.Env
|
| 23 | 22 | import GHC.Core.Opt.Simplify.Inline
|
| 24 | 23 | import GHC.Core.Opt.Simplify.Utils
|
| ... | ... | @@ -26,11 +25,14 @@ import GHC.Core.Opt.OccurAnal ( occurAnalyseExpr, zapLambdaBndrs ) |
| 26 | 25 | import GHC.Core.Make ( FloatBind, mkImpossibleExpr, castBottomExpr )
|
| 27 | 26 | import qualified GHC.Core.Make
|
| 28 | 27 | import GHC.Core.Coercion hiding ( substCo, substCoVar )
|
| 28 | +import qualified GHC.Core.Coercion as Coercion
|
|
| 29 | 29 | import GHC.Core.Reduction
|
| 30 | 30 | import GHC.Core.Coercion.Opt ( optCoercion )
|
| 31 | +import GHC.Core.Type hiding ( substCo, substTy, substTyVar, extendTvSubst, extendCvSubst )
|
|
| 32 | +import GHC.Core.TyCo.Compare( eqType )
|
|
| 33 | +import GHC.Core.TyCo.Subst( isEmptyTvSubst )
|
|
| 31 | 34 | import GHC.Core.FamInstEnv ( FamInstEnv, topNormaliseType_maybe )
|
| 32 | 35 | import GHC.Core.DataCon
|
| 33 | -import GHC.Core.Opt.Stats ( Tick(..) )
|
|
| 34 | 36 | import GHC.Core.Ppr ( pprCoreExpr )
|
| 35 | 37 | import GHC.Core.Unfold
|
| 36 | 38 | import GHC.Core.Unfold.Make
|
| ... | ... | @@ -1399,16 +1401,38 @@ simplCoercionF env co cont |
| 1399 | 1401 | |
| 1400 | 1402 | simplCoercion :: SimplEnv -> InCoercion -> SimplM OutCoercion
|
| 1401 | 1403 | simplCoercion env co
|
| 1402 | - = do { let opt_co | reSimplifying env = substCo env co
|
|
| 1403 | - | otherwise = optCoercion opts subst co
|
|
| 1404 | - -- If (reSimplifying env) is True we have already simplified
|
|
| 1405 | - -- this coercion once, and we don't want do so again; doing
|
|
| 1406 | - -- so repeatedly risks non-linear behaviour
|
|
| 1407 | - -- See Note [Inline depth] in GHC.Core.Opt.Simplify.Env
|
|
| 1408 | - ; seqCo opt_co `seq` return opt_co }
|
|
| 1404 | + = seqCo opt_co `seq` return opt_co
|
|
| 1409 | 1405 | where
|
| 1406 | + -- See Note [Optimising coercions]
|
|
| 1407 | + -- NB: substCo has a short-cut when both type and coercion substs are empty
|
|
| 1408 | + opt_co | subst_only = Coercion.substCo subst co
|
|
| 1409 | + | otherwise = optCoercion opts subst co
|
|
| 1410 | + |
|
| 1410 | 1411 | subst = getTCvSubst env
|
| 1411 | 1412 | opts = seOptCoercionOpts env
|
| 1413 | + subst_only = isEmptyTvSubst subst || reSimplifying env
|
|
| 1414 | + |
|
| 1415 | +{- Note [Optimising coercions]
|
|
| 1416 | +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
| 1417 | +Some programs have very big coercions and we'd like to avoid repeatedly
|
|
| 1418 | +re-optimising them:
|
|
| 1419 | + |
|
| 1420 | +* If the type-substitution is empty (common when no further transformations
|
|
| 1421 | + are taking place) then there is generally no point in re-optimising.
|
|
| 1422 | + If there is a type substitution, however, Refls may appear.
|
|
| 1423 | + Example where this isEmptyTCvSubst test really helped: aT5030.
|
|
| 1424 | + |
|
| 1425 | + Actually, if this is a "freshly-made" coercion (one built in the previous
|
|
| 1426 | + iteration of the Simplifier, or a previous pass) then perhaps optimisations
|
|
| 1427 | + /could/ occur; but we check for reflexivity in `rebuild_go`, and that's the
|
|
| 1428 | + big win. Otherwise having a bigger-than necessary coercion is no so bad.
|
|
| 1429 | + |
|
| 1430 | +* (reSimplifying env) is True we are in the body of an inlined function
|
|
| 1431 | + so we (conservatively) and we don't want do so again; doing so repeatedly
|
|
| 1432 | + risks non-linear behaviour. See Note [Inline depth] in GHC.Core.Opt.Simplify.Env.
|
|
| 1433 | + |
|
| 1434 | + But if the inlining did a type substitution maybe we should re-optimise?
|
|
| 1435 | +-}
|
|
| 1412 | 1436 | |
| 1413 | 1437 | -----------------------------------
|
| 1414 | 1438 | -- | Push a TickIt context outwards past applications and cases, as
|
| ... | ... | @@ -1742,6 +1766,9 @@ pushCast :: SimplEnv -> OutCoercion -> SimplCont -> SimplM SimplCont |
| 1742 | 1766 | pushCast env co cont
|
| 1743 | 1767 | = go co True cont
|
| 1744 | 1768 | where
|
| 1769 | + |
|
| 1770 | + -- ToDo: pushCast Refl (ApplylToVal arg1 (ApplyToVal arg2 ...))
|
|
| 1771 | + -- will do lots of unnecessary work.
|
|
| 1745 | 1772 | go :: OutCoercion -> Bool -> SimplCont -> SimplM SimplCont
|
| 1746 | 1773 | go co1 _ (CastIt { sc_co = co2, sc_cont = cont }) -- See Note [Optimising reflexivity]
|
| 1747 | 1774 | = go (mkTransCo co1 co2) False cont
|
| ... | ... | @@ -1749,12 +1776,12 @@ pushCast env co cont |
| 1749 | 1776 | -- See Note [Avoid re-simplifying coercions]
|
| 1750 | 1777 | |
| 1751 | 1778 | go co co_is_opt (ApplyToTy { sc_arg_ty = arg_ty, sc_cont = tail })
|
| 1752 | - | Just (arg_ty', m_co') <- pushCoTyArg co arg_ty
|
|
| 1779 | + | Just (tyL, arg_ty', m_co') <- pushCoTyArg co arg_ty
|
|
| 1753 | 1780 | = {-#SCC "addCoerce-pushCoTyArg" #-}
|
| 1754 | 1781 | do { tail' <- go_mco m_co' co_is_opt tail
|
| 1755 | 1782 | ; return (ApplyToTy { sc_arg_ty = arg_ty'
|
| 1756 | 1783 | , sc_cont = tail'
|
| 1757 | - , sc_hole_ty = coercionLKind co }) }
|
|
| 1784 | + , sc_hole_ty = tyL }) }
|
|
| 1758 | 1785 | -- NB! As the cast goes past, the
|
| 1759 | 1786 | -- type of the hole changes (#16312)
|
| 1760 | 1787 | |
| ... | ... | @@ -1768,16 +1795,14 @@ pushCast env co cont |
| 1768 | 1795 | = -- pushCoValArg duplicates the coercion, so optimise first
|
| 1769 | 1796 | go (optOutCoercion (zapSubstEnv env) co co_is_opt) True cont
|
| 1770 | 1797 | |
| 1771 | --- ToDo: return coercionLKind. And similarly pushCoTyArg
|
|
| 1772 | - |
|
| 1773 | - | Just (m_co1, m_co2) <- pushCoValArg co
|
|
| 1798 | + | Just (tyL, m_co1, m_co2) <- pushCoValArg co
|
|
| 1774 | 1799 | = {-#SCC "addCoerce-pushCoValArg" #-}
|
| 1775 | - do { tail' <- go_mco m_co2 co_is_opt tail
|
|
| 1800 | + do { tail' <- go_mco m_co2 True tail
|
|
| 1776 | 1801 | ; return (ApplyToVal { sc_arg = arg
|
| 1777 | 1802 | , sc_env = arg_se
|
| 1778 | 1803 | , sc_cast = arg_mco `mkTransMCo` m_co1
|
| 1779 | 1804 | , sc_cont = tail'
|
| 1780 | - , sc_hole_ty = coercionLKind co }) }
|
|
| 1805 | + , sc_hole_ty = tyL }) }
|
|
| 1781 | 1806 | |
| 1782 | 1807 | go co co_is_opt cont
|
| 1783 | 1808 | | isReflCo co = return cont -- Having this at the end makes a huge
|
| ... | ... | @@ -1785,8 +1810,6 @@ pushCast env co cont |
| 1785 | 1810 | -- See Note [Optimising reflexivity]
|
| 1786 | 1811 | | otherwise = return (CastIt { sc_co = co, sc_opt = co_is_opt, sc_cont = cont })
|
| 1787 | 1812 | |
| 1788 | --- ToDo: pushCast Refl (ApplylToVal arg1 (ApplyToVal arg2 ...)) will do lots of unnecessary work.
|
|
| 1789 | - |
|
| 1790 | 1813 | -- If the first parameter is MRefl, then simplifying revealed a
|
| 1791 | 1814 | -- reflexive coercion. Omit.
|
| 1792 | 1815 | go_mco :: MOutCoercion -> Bool -> SimplCont -> SimplM SimplCont
|
| ... | ... | @@ -12,7 +12,7 @@ module GHC.Core.TyCo.Subst |
| 12 | 12 | -- * Substitutions
|
| 13 | 13 | Subst(..), TvSubstEnv, CvSubstEnv, IdSubstEnv,
|
| 14 | 14 | emptyIdSubstEnv, emptyTvSubstEnv, emptyCvSubstEnv, composeTCvSubst,
|
| 15 | - emptySubst, mkEmptySubst, isEmptyTCvSubst, isEmptySubst,
|
|
| 15 | + emptySubst, mkEmptySubst, isEmptyTvSubst, isEmptyTCvSubst, isEmptySubst,
|
|
| 16 | 16 | mkSubst, mkTCvSubst, mkTvSubst, mkCvSubst, mkIdSubst,
|
| 17 | 17 | getTvSubstEnv, getIdSubstEnv,
|
| 18 | 18 | getCvSubstEnv, substInScopeSet, setInScope, getSubstRangeTyCoFVs,
|
| ... | ... | @@ -262,6 +262,11 @@ isEmptySubst :: Subst -> Bool |
| 262 | 262 | isEmptySubst (Subst _ id_env tv_env cv_env)
|
| 263 | 263 | = isEmptyVarEnv id_env && isEmptyVarEnv tv_env && isEmptyVarEnv cv_env
|
| 264 | 264 | |
| 265 | +-- | Checks if the type substitution (only) is empty
|
|
| 266 | +isEmptyTvSubst :: Subst -> Bool
|
|
| 267 | +isEmptyTvSubst (Subst _ _ tv_env _)
|
|
| 268 | + = isEmptyVarEnv tv_env
|
|
| 269 | + |
|
| 265 | 270 | -- | Checks whether the tyvar and covar environments are empty.
|
| 266 | 271 | -- This function should be used over 'isEmptySubst' when substituting
|
| 267 | 272 | -- for types, because types currently do not contain expressions; we can
|
| ... | ... | @@ -59,7 +59,6 @@ import GHC.Tc.Utils.TcType |
| 59 | 59 | import GHC.Core
|
| 60 | 60 | import GHC.Core.Coercion.Axiom
|
| 61 | 61 | import GHC.Core.Coercion
|
| 62 | -import GHC.Core.Utils( mkCast )
|
|
| 63 | 62 | import GHC.Core.Ppr () -- Instance OutputableBndr TyVar
|
| 64 | 63 | import GHC.Core.Predicate
|
| 65 | 64 | import GHC.Core.Type
|
| ... | ... | @@ -932,7 +931,8 @@ evCastE ee co |
| 932 | 931 | | assertPpr (coercionRole co == Representational)
|
| 933 | 932 | (vcat [text "Coercion of wrong role passed to evCastE:", ppr ee, ppr co]) $
|
| 934 | 933 | isReflCo co = ee
|
| 935 | - | otherwise = mkCast ee co
|
|
| 934 | + | otherwise = Cast ee co -- Do not call mkCast because its assertion
|
|
| 935 | + -- checks fail on un-zonked terms (#27219)
|
|
| 936 | 936 | |
| 937 | 937 | evDFunApp :: DFunId -> [Type] -> [EvExpr] -> EvTerm
|
| 938 | 938 | -- Dictionary instance application, including when the "dictionary function"
|