Simon Peyton Jones pushed to branch wip/T26989 at Glasgow Haskell Compiler / GHC
Commits:
-
27d8694f
by Simon Peyton Jones at 2026-04-11T22:05:02+01:00
6 changed files:
- compiler/GHC/Core.hs
- compiler/GHC/Core/Opt/OccurAnal.hs
- compiler/GHC/Core/Opt/Simplify/Iteration.hs
- compiler/GHC/Core/Opt/Simplify/Utils.hs
- compiler/GHC/Core/Rules.hs
- compiler/GHC/IfaceToCore.hs
Changes:
| ... | ... | @@ -1968,6 +1968,11 @@ Given this decision it's vital that we do *always* do it. |
| 1968 | 1968 | occurrence in f out of scope. This happened in #8892, where the unfolding
|
| 1969 | 1969 | in question was a DFun unfolding.
|
| 1970 | 1970 | |
| 1971 | +Wrinkles
|
|
| 1972 | + |
|
| 1973 | +(OUR1) For a RULE, say,
|
|
| 1974 | + forall x y. f (x,y) = x+y
|
|
| 1975 | +ToDO
|
|
| 1971 | 1976 | |
| 1972 | 1977 | ************************************************************************
|
| 1973 | 1978 | * *
|
| ... | ... | @@ -27,7 +27,8 @@ core expression with (hopefully) improved usage information. |
| 27 | 27 | |
| 28 | 28 | module GHC.Core.Opt.OccurAnal (
|
| 29 | 29 | occurAnalysePgm,
|
| 30 | - occurAnalyseExpr, occurAnalyseExpr_Prep,
|
|
| 30 | + occurAnalyseExpr, occurAnalyseBndrsAndExpr,
|
|
| 31 | + occurAnalyseExpr_Prep,
|
|
| 31 | 32 | zapLambdaBndrs
|
| 32 | 33 | ) where
|
| 33 | 34 | |
| ... | ... | @@ -85,6 +86,14 @@ occurAnalyseExpr expr = expr' |
| 85 | 86 | where
|
| 86 | 87 | WUD _ expr' = occAnal initOccEnv expr
|
| 87 | 88 | |
| 89 | +occurAnalyseBndrsAndExpr :: [Var] -> CoreExpr -> ([Var], CoreExpr)
|
|
| 90 | +-- Occur-anal (\bs.e), but taking and returning `bs` and `e` separately
|
|
| 91 | +occurAnalyseBndrsAndExpr bndrs expr
|
|
| 92 | + = (bndrs', expr')
|
|
| 93 | + where
|
|
| 94 | + WUD usage expr' = occAnal initOccEnv expr
|
|
| 95 | + bndrs' = tagLamBinders usage bndrs
|
|
| 96 | + |
|
| 88 | 97 | -- | A version of 'occurAnalyseExpr' suitable for CorePrep.
|
| 89 | 98 | --
|
| 90 | 99 | -- Different from 'occurAnalyseExpr' due to (JCT3)
|
| ... | ... | @@ -1219,9 +1219,21 @@ simplExprF1 _ (Type ty) cont |
| 1219 | 1219 | simplExprF1 env (Var v) cont = {-#SCC "simplInId" #-} simplInId env v cont
|
| 1220 | 1220 | simplExprF1 env (Lit lit) cont = {-#SCC "rebuild" #-} rebuild env (Lit lit) cont
|
| 1221 | 1221 | simplExprF1 env (Tick t expr) cont = {-#SCC "simplTick" #-} simplTick env t expr cont
|
| 1222 | -simplExprF1 env (Cast body co) cont = {-#SCC "simplCast" #-} simplCast env body co cont
|
|
| 1223 | 1222 | simplExprF1 env (Coercion co) cont = {-#SCC "simplCoercionF" #-} simplCoercionF env co cont
|
| 1224 | 1223 | |
| 1224 | +simplExprF1 env (Cast body co) cont
|
|
| 1225 | + = do { co1 <- {-#SCC "simplCast-simplCoercion" #-}
|
|
| 1226 | + simplCoercion env co
|
|
| 1227 | + |
|
| 1228 | + ; cont1 <- {-#SCC "simplCast-addCoerce" #-}
|
|
| 1229 | + if isReflCo co1
|
|
| 1230 | + then return cont -- See Note [Optimising reflexivity]
|
|
| 1231 | + else pushCast env co1 cont
|
|
| 1232 | + -- True <=> co1 is optimised
|
|
| 1233 | + |
|
| 1234 | + ; {-#SCC "simplCast-simplExprF" #-}
|
|
| 1235 | + simplExprF env body cont1 }
|
|
| 1236 | + |
|
| 1225 | 1237 | simplExprF1 env (App fun arg) cont
|
| 1226 | 1238 | = {-#SCC "simplExprF1-App" #-} case arg of
|
| 1227 | 1239 | Type ty -> do { -- The argument type will (almost) certainly be used
|
| ... | ... | @@ -1567,6 +1579,10 @@ rebuild_go env expr cont |
| 1567 | 1579 | Stop {} -> return (emptyFloats env, expr)
|
| 1568 | 1580 | TickIt t cont -> rebuild_go env (mkTick t expr) cont
|
| 1569 | 1581 | CastIt { sc_co = co, sc_opt = opt, sc_cont = cont }
|
| 1582 | + | isReflexiveCo co' -- Worth trying this because casts can
|
|
| 1583 | + -- get stacked up by simplCast
|
|
| 1584 | + -> rebuild_go env expr cont
|
|
| 1585 | + | otherwise
|
|
| 1570 | 1586 | -> rebuild_go env (mkCast expr co') cont
|
| 1571 | 1587 | -- NB: mkCast implements the (Coercion co |> g) optimisation
|
| 1572 | 1588 | where
|
| ... | ... | @@ -1689,9 +1705,8 @@ on each successive composition -- that's at least quadratic. So: |
| 1689 | 1705 | * In `addCoerce` (in `simplCast`) if we combine this new coercion with
|
| 1690 | 1706 | an existing once, we build a CastIt for (co1 ; co2) with sc_opt=False.
|
| 1691 | 1707 | |
| 1692 | -* When unpacking a CastIt, in `rebuildCall` and `rebuild`, we optimise
|
|
| 1693 | - the (presumably composed) coercion if sc_opt=False; this is done
|
|
| 1694 | - by `optOutCoercion`.
|
|
| 1708 | +* When unpacking a CastIt, in `rebuild`, we optimise the (presumably
|
|
| 1709 | + composed) coercion if sc_opt=False; this is done by `optOutCoercion`.
|
|
| 1695 | 1710 | |
| 1696 | 1711 | * When duplicating a continuation in `mkDupableContWithDmds`, before
|
| 1697 | 1712 | duplicating a CastIt, optimise the coercion. Otherwise we'll end up
|
| ... | ... | @@ -1708,76 +1723,70 @@ optOutCoercion env co already_optimised |
| 1708 | 1723 | empty_subst = mkEmptySubst (seInScope env)
|
| 1709 | 1724 | opts = seOptCoercionOpts env
|
| 1710 | 1725 | |
| 1711 | -simplCast :: SimplEnv -> InExpr -> InCoercion -> SimplCont
|
|
| 1712 | - -> SimplM (SimplFloats, OutExpr)
|
|
| 1713 | -simplCast env body co0 cont0
|
|
| 1714 | - = do { co1 <- {-#SCC "simplCast-simplCoercion" #-} simplCoercion env co0
|
|
| 1715 | - ; cont1 <- {-#SCC "simplCast-addCoerce" #-}
|
|
| 1716 | - if isReflCo co1
|
|
| 1717 | - then return cont0 -- See Note [Optimising reflexivity]
|
|
| 1718 | - else addCoerce co1 True cont0
|
|
| 1719 | - -- True <=> co1 is optimised
|
|
| 1720 | - ; {-#SCC "simplCast-simplExprF" #-} simplExprF env body cont1 }
|
|
| 1726 | +pushCast :: SimplEnv -> OutCoercion -> SimplCont -> SimplM SimplCont
|
|
| 1727 | +pushCast env co cont
|
|
| 1728 | + = go co True cont
|
|
| 1721 | 1729 | where
|
| 1730 | + go :: OutCoercion -> Bool -> SimplCont -> SimplM SimplCont
|
|
| 1731 | + go co1 _ (CastIt { sc_co = co2, sc_cont = cont }) -- See Note [Optimising reflexivity]
|
|
| 1732 | + = go (mkTransCo co1 co2) False cont
|
|
| 1733 | + -- False: (mkTransCo co1 co2) is not fully optimised
|
|
| 1734 | + -- See Note [Avoid re-simplifying coercions]
|
|
| 1735 | + |
|
| 1736 | + go co co_is_opt (ApplyToTy { sc_arg_ty = arg_ty, sc_cont = tail })
|
|
| 1737 | + | Just (arg_ty', m_co') <- pushCoTyArg co arg_ty
|
|
| 1738 | + = {-#SCC "addCoerce-pushCoTyArg" #-}
|
|
| 1739 | + do { tail' <- go_mco m_co' co_is_opt tail
|
|
| 1740 | + ; return (ApplyToTy { sc_arg_ty = arg_ty'
|
|
| 1741 | + , sc_cont = tail'
|
|
| 1742 | + , sc_hole_ty = coercionLKind co }) }
|
|
| 1743 | + -- NB! As the cast goes past, the
|
|
| 1744 | + -- type of the hole changes (#16312)
|
|
| 1745 | + |
|
| 1746 | + -- (f |> co) e ===> (f (e |> co1)) |> co2
|
|
| 1747 | + -- where co :: (s1->s2) ~ (t1->t2)
|
|
| 1748 | + -- co1 :: t1 ~ s1
|
|
| 1749 | + -- co2 :: s2 ~ t2
|
|
| 1750 | + go co co_is_opt cont@(ApplyToVal { sc_arg = arg, sc_env = arg_se
|
|
| 1751 | + , sc_dup = dup, sc_cont = tail
|
|
| 1752 | + , sc_hole_ty = fun_ty })
|
|
| 1753 | + | not co_is_opt
|
|
| 1754 | + = -- pushCoValArg duplicates the coercion, so optimise first
|
|
| 1755 | + go (optOutCoercion (zapSubstEnv env) co co_is_opt) True cont
|
|
| 1756 | + |
|
| 1757 | + | Just (m_co1, m_co2) <- pushCoValArg co
|
|
| 1758 | + = {-#SCC "addCoerce-pushCoValArg" #-}
|
|
| 1759 | + do { tail' <- go_mco m_co2 co_is_opt tail
|
|
| 1760 | + ; case m_co1 of {
|
|
| 1761 | + MRefl -> return (cont { sc_cont = tail'
|
|
| 1762 | + , sc_hole_ty = coercionLKind co }) ;
|
|
| 1763 | + -- See Note [Avoiding simplifying repeatedly]
|
|
| 1764 | + |
|
| 1765 | + MCo co1 ->
|
|
| 1766 | + do { (dup', arg_se', arg') <- simplLazyArg env dup fun_ty Nothing arg_se arg
|
|
| 1767 | + -- When we build the ApplyTo we can't mix the OutCoercion
|
|
| 1768 | + -- 'co' with the InExpr 'arg', so we simplify
|
|
| 1769 | + -- to make it all consistent. It's a bit messy.
|
|
| 1770 | + -- But it isn't a common case.
|
|
| 1771 | + -- Example of use: #995
|
|
| 1772 | + ; return (ApplyToVal { sc_arg = mkCast arg' co1
|
|
| 1773 | + , sc_env = arg_se'
|
|
| 1774 | + , sc_dup = dup'
|
|
| 1775 | + , sc_cont = tail'
|
|
| 1776 | + , sc_hole_ty = coercionLKind co }) } } }
|
|
| 1777 | + |
|
| 1778 | + go co co_is_opt cont
|
|
| 1779 | + | isReflCo co = return cont -- Having this at the end makes a huge
|
|
| 1780 | + -- difference in T12227, for some reason
|
|
| 1781 | + -- See Note [Optimising reflexivity]
|
|
| 1782 | + | otherwise = return (CastIt { sc_co = co, sc_opt = co_is_opt, sc_cont = cont })
|
|
| 1783 | + |
|
| 1722 | 1784 | |
| 1723 | 1785 | -- If the first parameter is MRefl, then simplifying revealed a
|
| 1724 | 1786 | -- reflexive coercion. Omit.
|
| 1725 | - addCoerceM :: MOutCoercion -> Bool -> SimplCont -> SimplM SimplCont
|
|
| 1726 | - addCoerceM MRefl _ cont = return cont
|
|
| 1727 | - addCoerceM (MCo co) opt cont = addCoerce co opt cont
|
|
| 1728 | - |
|
| 1729 | - addCoerce :: OutCoercion -> Bool -> SimplCont -> SimplM SimplCont
|
|
| 1730 | - addCoerce co1 _ (CastIt { sc_co = co2, sc_cont = cont }) -- See Note [Optimising reflexivity]
|
|
| 1731 | - = addCoerce (mkTransCo co1 co2) False cont
|
|
| 1732 | - -- False: (mkTransCo co1 co2) is not fully optimised
|
|
| 1733 | - -- See Note [Avoid re-simplifying coercions]
|
|
| 1734 | - |
|
| 1735 | - addCoerce co co_is_opt (ApplyToTy { sc_arg_ty = arg_ty, sc_cont = tail })
|
|
| 1736 | - | Just (arg_ty', m_co') <- pushCoTyArg co arg_ty
|
|
| 1737 | - = {-#SCC "addCoerce-pushCoTyArg" #-}
|
|
| 1738 | - do { tail' <- addCoerceM m_co' co_is_opt tail
|
|
| 1739 | - ; return (ApplyToTy { sc_arg_ty = arg_ty'
|
|
| 1740 | - , sc_cont = tail'
|
|
| 1741 | - , sc_hole_ty = coercionLKind co }) }
|
|
| 1742 | - -- NB! As the cast goes past, the
|
|
| 1743 | - -- type of the hole changes (#16312)
|
|
| 1744 | - |
|
| 1745 | - -- (f |> co) e ===> (f (e |> co1)) |> co2
|
|
| 1746 | - -- where co :: (s1->s2) ~ (t1->t2)
|
|
| 1747 | - -- co1 :: t1 ~ s1
|
|
| 1748 | - -- co2 :: s2 ~ t2
|
|
| 1749 | - addCoerce co co_is_opt cont@(ApplyToVal { sc_arg = arg, sc_env = arg_se
|
|
| 1750 | - , sc_dup = dup, sc_cont = tail
|
|
| 1751 | - , sc_hole_ty = fun_ty })
|
|
| 1752 | - | not co_is_opt -- pushCoValArg duplicates the coercion, so optimise first
|
|
| 1753 | - = addCoerce (optOutCoercion (zapSubstEnv env) co co_is_opt) True cont
|
|
| 1754 | - |
|
| 1755 | - | Just (m_co1, m_co2) <- pushCoValArg co
|
|
| 1756 | - = {-#SCC "addCoerce-pushCoValArg" #-}
|
|
| 1757 | - do { tail' <- addCoerceM m_co2 co_is_opt tail
|
|
| 1758 | - ; case m_co1 of {
|
|
| 1759 | - MRefl -> return (cont { sc_cont = tail'
|
|
| 1760 | - , sc_hole_ty = coercionLKind co }) ;
|
|
| 1761 | - -- See Note [Avoiding simplifying repeatedly]
|
|
| 1762 | - |
|
| 1763 | - MCo co1 ->
|
|
| 1764 | - do { (dup', arg_se', arg') <- simplLazyArg env dup fun_ty Nothing arg_se arg
|
|
| 1765 | - -- When we build the ApplyTo we can't mix the OutCoercion
|
|
| 1766 | - -- 'co' with the InExpr 'arg', so we simplify
|
|
| 1767 | - -- to make it all consistent. It's a bit messy.
|
|
| 1768 | - -- But it isn't a common case.
|
|
| 1769 | - -- Example of use: #995
|
|
| 1770 | - ; return (ApplyToVal { sc_arg = mkCast arg' co1
|
|
| 1771 | - , sc_env = arg_se'
|
|
| 1772 | - , sc_dup = dup'
|
|
| 1773 | - , sc_cont = tail'
|
|
| 1774 | - , sc_hole_ty = coercionLKind co }) } } }
|
|
| 1775 | - |
|
| 1776 | - addCoerce co co_is_opt cont
|
|
| 1777 | - | isReflCo co = return cont -- Having this at the end makes a huge
|
|
| 1778 | - -- difference in T12227, for some reason
|
|
| 1779 | - -- See Note [Optimising reflexivity]
|
|
| 1780 | - | otherwise = return (CastIt { sc_co = co, sc_opt = co_is_opt, sc_cont = cont })
|
|
| 1787 | + go_mco :: MOutCoercion -> Bool -> SimplCont -> SimplM SimplCont
|
|
| 1788 | + go_mco MRefl _ cont = return cont
|
|
| 1789 | + go_mco (MCo co) opt cont = go co opt cont
|
|
| 1781 | 1790 | |
| 1782 | 1791 | simplLazyArg :: SimplEnvIS -- ^ Used only for its InScopeSet
|
| 1783 | 1792 | -> DupFlag
|
| ... | ... | @@ -2293,14 +2302,21 @@ simplInId env var cont |
| 2293 | 2302 | ---------------------------------------------------------
|
| 2294 | 2303 | simplOutExpr :: SimplEnvIS -> OutExpr -> SimplCont -> SimplM (SimplFloats, OutExpr)
|
| 2295 | 2304 | simplOutExpr env expr cont
|
| 2296 | - = case fun of
|
|
| 2297 | - Var v -> simplOutId env v cont'
|
|
| 2298 | - Lam {} | not (null args) -> simplLam env occ_fun cont' -- We have a beta-redex
|
|
| 2299 | - _ -> rebuild_go env expr cont
|
|
| 2300 | - where
|
|
| 2301 | - (fun, args) = collectArgs expr
|
|
| 2302 | - cont' = pushArgs env Simplified (exprType fun) args cont
|
|
| 2303 | - occ_fun = occurAnalyseExpr fun -- ToDo:explain; c.f. Note [Occurrence-analyse after rule firing]
|
|
| 2305 | + | Lam {} <- expr
|
|
| 2306 | + , hasArgs cont
|
|
| 2307 | + = simplLam env (occurAnalyseExpr expr) cont
|
|
| 2308 | + -- ToDo:explain; c.f. Note [Occurrence-analyse after rule firing]
|
|
| 2309 | + |
|
| 2310 | + | Cast e co <- expr -- The inlined expression may be (x |> co)
|
|
| 2311 | + -- and the cast may cancel with `cont`
|
|
| 2312 | + = do { cont' <- pushCast env co cont
|
|
| 2313 | + ; simplOutExpr env e cont' }
|
|
| 2314 | + |
|
| 2315 | + | (Var v, args) <- collectArgs expr
|
|
| 2316 | + = simplOutId env v (pushArgs env (idType v) args cont)
|
|
| 2317 | + |
|
| 2318 | + | otherwise
|
|
| 2319 | + = rebuild_go env expr cont
|
|
| 2304 | 2320 | |
| 2305 | 2321 | ---------------------------------------------------------
|
| 2306 | 2322 | simplOutId :: SimplEnvIS -> OutId -> SimplCont -> SimplM (SimplFloats, OutExpr)
|
| ... | ... | @@ -2654,7 +2670,7 @@ fireRuleAFTER env rule_match arg_specs cont |
| 2654 | 2670 | , rm_binds = wrap, rm_bndrs = bndrs } <- rule_match
|
| 2655 | 2671 | = do { let env' = env `addNewInScopeIds` bndrs
|
| 2656 | 2672 | ; (floats, e') <- simplExprF env' rhs $
|
| 2657 | - pushArgs env' Simplified (exprType rhs) rhs_args $
|
|
| 2673 | + pushArgs env' (exprType rhs) rhs_args $
|
|
| 2658 | 2674 | pushArgSpecs env' (drop (ruleArity rule) arg_specs) cont
|
| 2659 | 2675 | ; return $
|
| 2660 | 2676 | if isEmptyBindWrapper wrap -- Not very pretty
|
| ... | ... | @@ -25,7 +25,7 @@ module GHC.Core.Opt.Simplify.Utils ( |
| 25 | 25 | isSimplified, contIsStop,
|
| 26 | 26 | contIsDupable, contResultType, contHoleType, contHoleScaling,
|
| 27 | 27 | contIsTrivial, contArgs, contIsRhs,
|
| 28 | - countArgs, contOutArgs, dropContArgs,
|
|
| 28 | + hasArgs, countArgs, contOutArgs, dropContArgs,
|
|
| 29 | 29 | mkBoringStop, mkRhsStop, mkLazyArgStop,
|
| 30 | 30 | interestingCallContext,
|
| 31 | 31 | |
| ... | ... | @@ -384,17 +384,17 @@ isStrictArgInfo (ArgInfo { ai_dmds = dmds }) |
| 384 | 384 | | dmd:_ <- dmds = isStrUsedDmd dmd
|
| 385 | 385 | | otherwise = False
|
| 386 | 386 | |
| 387 | -pushArgs :: SimplEnvIS -> DupFlag -> Type -> [OutExpr] -> SimplCont -> SimplCont
|
|
| 388 | -pushArgs _env _dup _fun_ty [] cont
|
|
| 387 | +pushArgs :: SimplEnvIS -> Type -> [OutExpr] -> SimplCont -> SimplCont
|
|
| 388 | +pushArgs _env _fun_ty [] cont
|
|
| 389 | 389 | = cont
|
| 390 | -pushArgs env dup fun_ty (arg:args) cont
|
|
| 390 | +pushArgs env fun_ty (arg:args) cont
|
|
| 391 | 391 | | Type ty <- arg
|
| 392 | 392 | = ApplyToTy { sc_hole_ty = fun_ty, sc_arg_ty = ty
|
| 393 | - , sc_cont = pushArgs env dup (piResultTy fun_ty ty) args cont }
|
|
| 393 | + , sc_cont = pushArgs env (piResultTy fun_ty ty) args cont }
|
|
| 394 | 394 | | otherwise
|
| 395 | - = ApplyToVal { sc_dup = dup, sc_hole_ty = fun_ty
|
|
| 395 | + = ApplyToVal { sc_dup = Simplified, sc_hole_ty = fun_ty
|
|
| 396 | 396 | , sc_arg = arg, sc_env = env
|
| 397 | - , sc_cont = pushArgs env dup (funResultTy fun_ty) args cont}
|
|
| 397 | + , sc_cont = pushArgs env (funResultTy fun_ty) args cont}
|
|
| 398 | 398 | |
| 399 | 399 | pushArgSpecs :: SimplEnvIS -- Barely needed, since sc_dup = Simplified
|
| 400 | 400 | -> [ArgSpec] -- In normal, forward order
|
| ... | ... | @@ -522,6 +522,12 @@ contHoleScaling (ApplyToVal { sc_cont = k }) = contHoleScaling k |
| 522 | 522 | contHoleScaling (TickIt _ k) = contHoleScaling k
|
| 523 | 523 | |
| 524 | 524 | -------------------
|
| 525 | +hasArgs :: SimplCont -> Bool
|
|
| 526 | +-- True <=> some leading arguments
|
|
| 527 | +hasArgs (ApplyToTy {}) = True
|
|
| 528 | +hasArgs (ApplyToVal {}) = True
|
|
| 529 | +hasArgs _ = False
|
|
| 530 | + |
|
| 525 | 531 | countArgs :: SimplCont -> Int
|
| 526 | 532 | -- Count all arguments, including types, coercions,
|
| 527 | 533 | -- and other values; skipping over casts.
|
| ... | ... | @@ -65,7 +65,7 @@ import GHC.Core.Tidy ( tidyRules ) |
| 65 | 65 | import GHC.Core.Map.Expr ( eqCoreExpr )
|
| 66 | 66 | import GHC.Core.Opt.Arity( etaExpandToJoinPointRule )
|
| 67 | 67 | import GHC.Core.Make ( mkCoreLams )
|
| 68 | -import GHC.Core.Opt.OccurAnal( occurAnalyseExpr )
|
|
| 68 | +import GHC.Core.Opt.OccurAnal( occurAnalyseBndrsAndExpr )
|
|
| 69 | 69 | import GHC.Core.Rules.Config (roBuiltinRules)
|
| 70 | 70 | |
| 71 | 71 | import GHC.Tc.Utils.TcType ( tcSplitTyConApp_maybe )
|
| ... | ... | @@ -200,16 +200,18 @@ mkRule this_mod is_auto is_local name act fn bndrs args rhs |
| 200 | 200 | = Rule { ru_name = name
|
| 201 | 201 | , ru_act = act
|
| 202 | 202 | , ru_fn = fn
|
| 203 | - , ru_bndrs = bndrs
|
|
| 203 | + , ru_bndrs = bndrs'
|
|
| 204 | 204 | , ru_args = args
|
| 205 | - , ru_rhs = occurAnalyseExpr rhs
|
|
| 206 | - -- See Note [OccInfo in unfoldings and rules]
|
|
| 205 | + , ru_rhs = rhs'
|
|
| 207 | 206 | , ru_rough = roughTopNames args
|
| 208 | 207 | , ru_origin = this_mod
|
| 209 | 208 | , ru_orphan = orph
|
| 210 | 209 | , ru_auto = is_auto
|
| 211 | 210 | , ru_local = is_local }
|
| 212 | 211 | where
|
| 212 | + (bndrs', rhs') = occurAnalyseBndrsAndExpr bndrs rhs
|
|
| 213 | + -- See Note [OccInfo in unfoldings and rules]
|
|
| 214 | + |
|
| 213 | 215 | -- Compute orphanhood. See Note [Orphans] in GHC.Core.InstEnv
|
| 214 | 216 | -- A rule is an orphan only if none of the variables
|
| 215 | 217 | -- mentioned on its left-hand side are locally defined
|
| ... | ... | @@ -76,7 +76,7 @@ import GHC.Core.Predicate( isUnaryClass ) |
| 76 | 76 | import GHC.Core.TyCon
|
| 77 | 77 | import GHC.Core.ConLike
|
| 78 | 78 | import GHC.Core.DataCon
|
| 79 | -import GHC.Core.Opt.OccurAnal ( occurAnalyseExpr )
|
|
| 79 | +import GHC.Core.Opt.OccurAnal ( occurAnalyseBndrsAndExpr )
|
|
| 80 | 80 | import GHC.Core.Ppr
|
| 81 | 81 | |
| 82 | 82 | import GHC.Hs.Extension ( GhcRn )
|
| ... | ... | @@ -1418,18 +1418,22 @@ tcIfaceRule (IfaceRule {ifRuleName = name, ifActivation = act, ifRuleBndrs = bnd |
| 1418 | 1418 | (emptyBag, errs) }
|
| 1419 | 1419 | ; return (bndrs', args', rhs') }
|
| 1420 | 1420 | ; let mb_tcs = map ifTopFreeName args
|
| 1421 | + (bndrs_occ, rhs_occ) = occurAnalyseBndrsAndExpr bndrs' rhs'
|
|
| 1422 | + -- See Note [OccInfo in unfoldings and rules]
|
|
| 1421 | 1423 | ; this_mod <- getIfModule
|
| 1422 | - ; return (Rule { ru_name = name, ru_fn = fn,
|
|
| 1423 | - ru_act = act,
|
|
| 1424 | - ru_bndrs = bndrs', ru_args = args',
|
|
| 1425 | - ru_rhs = occurAnalyseExpr rhs',
|
|
| 1426 | - ru_rough = mb_tcs,
|
|
| 1427 | - ru_origin = this_mod,
|
|
| 1428 | - ru_orphan = orph,
|
|
| 1429 | - ru_auto = auto,
|
|
| 1430 | - ru_local = False }) } -- An imported RULE is never for a local Id
|
|
| 1431 | - -- or, even if it is (module loop, perhaps)
|
|
| 1432 | - -- we'll just leave it in the non-local set
|
|
| 1424 | + ; return (Rule { ru_name = name
|
|
| 1425 | + , ru_fn = fn
|
|
| 1426 | + , ru_act = act
|
|
| 1427 | + , ru_bndrs = bndrs_occ
|
|
| 1428 | + , ru_args = args'
|
|
| 1429 | + , ru_rhs = rhs_occ
|
|
| 1430 | + , ru_rough = mb_tcs
|
|
| 1431 | + , ru_origin = this_mod
|
|
| 1432 | + , ru_orphan = orph
|
|
| 1433 | + , ru_auto = auto
|
|
| 1434 | + , ru_local = False }) }
|
|
| 1435 | + -- ru_local=False: an imported RULE is never for a local Id or, even if
|
|
| 1436 | + -- it is (module loop, perhaps) we'll just leave it in the non-local set
|
|
| 1433 | 1437 | where
|
| 1434 | 1438 | -- This function *must* mirror exactly what Rules.roughTopNames does
|
| 1435 | 1439 | -- We could have stored the ru_rough field in the iface file
|