Marge Bot pushed to branch wip/marge_bot_batch_merge_job at Glasgow Haskell Compiler / GHC
Commits:
-
d4871438
by Simon Peyton Jones at 2025-09-09T00:14:59-04:00
-
80d3436c
by Andreas Klebinger at 2025-09-09T00:15:01-04:00
-
5e052e33
by sheaf at 2025-09-09T00:15:17-04:00
-
90d94d17
by Moritz Angermann at 2025-09-09T00:15:17-04:00
7 changed files:
- compiler/GHC/Core/Opt/Specialise.hs
- compiler/GHC/Tc/Utils/Unify.hs
- + testsuite/tests/linear/should_compile/T26332.hs
- testsuite/tests/linear/should_compile/all.T
- + testsuite/tests/profiling/should_compile/T26056.hs
- testsuite/tests/profiling/should_compile/all.T
- testsuite/tests/rts/exec_signals_child.c
Changes:
... | ... | @@ -1205,14 +1205,21 @@ specExpr env (Tick tickish body) |
1205 | 1205 | ---------------- Applications might generate a call instance --------------------
|
1206 | 1206 | specExpr env expr@(App {})
|
1207 | 1207 | = do { let (fun_in, args_in) = collectArgs expr
|
1208 | + ; (fun_out, uds_fun) <- specExpr env fun_in
|
|
1208 | 1209 | ; (args_out, uds_args) <- mapAndCombineSM (specExpr env) args_in
|
1209 | - ; let env_args = env `bringFloatedDictsIntoScope` ud_binds uds_args
|
|
1210 | - -- Some dicts may have floated out of args_in;
|
|
1211 | - -- they should be in scope for fireRewriteRules (#21689)
|
|
1212 | - (fun_in', args_out') = fireRewriteRules env_args fun_in args_out
|
|
1213 | - ; (fun_out', uds_fun) <- specExpr env fun_in'
|
|
1210 | + ; let uds_app = uds_fun `thenUDs` uds_args
|
|
1211 | + env_args = zapSubst env `bringFloatedDictsIntoScope` ud_binds uds_app
|
|
1212 | + -- zapSubst: we have now fully applied the substitution
|
|
1213 | + -- bringFloatedDictsIntoScope: some dicts may have floated out of
|
|
1214 | + -- args_in; they should be in scope for fireRewriteRules (#21689)
|
|
1215 | + |
|
1216 | + -- Try firing rewrite rules
|
|
1217 | + -- See Note [Fire rules in the specialiser]
|
|
1218 | + ; let (fun_out', args_out') = fireRewriteRules env_args fun_out args_out
|
|
1219 | + |
|
1220 | + -- Make a call record, and return
|
|
1214 | 1221 | ; let uds_call = mkCallUDs env fun_out' args_out'
|
1215 | - ; return (fun_out' `mkApps` args_out', uds_fun `thenUDs` uds_call `thenUDs` uds_args) }
|
|
1222 | + ; return (fun_out' `mkApps` args_out', uds_app `thenUDs` uds_call) }
|
|
1216 | 1223 | |
1217 | 1224 | ---------------- Lambda/case require dumping of usage details --------------------
|
1218 | 1225 | specExpr env e@(Lam {})
|
... | ... | @@ -1246,17 +1253,18 @@ specExpr env (Let bind body) |
1246 | 1253 | -- See Note [Specialisation modulo dictionary selectors]
|
1247 | 1254 | -- Note [ClassOp/DFun selection]
|
1248 | 1255 | -- Note [Fire rules in the specialiser]
|
1249 | -fireRewriteRules :: SpecEnv -> InExpr -> [OutExpr] -> (InExpr, [OutExpr])
|
|
1256 | +fireRewriteRules :: SpecEnv -- Substitution is already zapped
|
|
1257 | + -> OutExpr -> [OutExpr] -> (OutExpr, [OutExpr])
|
|
1250 | 1258 | fireRewriteRules env (Var f) args
|
1251 | 1259 | | let rules = getRules (se_rules env) f
|
1252 | 1260 | , Just (rule, expr) <- specLookupRule env f args activeInInitialPhase rules
|
1253 | 1261 | , let rest_args = drop (ruleArity rule) args -- See Note [Extra args in the target]
|
1254 | - zapped_subst = Core.zapSubst (se_subst env)
|
|
1255 | - expr' = simpleOptExprWith defaultSimpleOpts zapped_subst expr
|
|
1262 | + zapped_subst = se_subst env -- Just needed for the InScopeSet
|
|
1263 | + expr' = simpleOptExprWith defaultSimpleOpts zapped_subst (mkApps expr rest_args)
|
|
1256 | 1264 | -- simplOptExpr needed because lookupRule returns
|
1257 | 1265 | -- (\x y. rhs) arg1 arg2
|
1258 | 1266 | , (fun', args') <- collectArgs expr'
|
1259 | - = fireRewriteRules env fun' (args'++rest_args)
|
|
1267 | + = fireRewriteRules env fun' args'
|
|
1260 | 1268 | fireRewriteRules _ fun args = (fun, args)
|
1261 | 1269 | |
1262 | 1270 | --------------
|
... | ... | @@ -1669,10 +1677,19 @@ specCalls spec_imp env existing_rules calls_for_me fn rhs |
1669 | 1677 | ; let all_rule_bndrs = poly_qvars ++ rule_bndrs
|
1670 | 1678 | env' = env { se_subst = subst'' }
|
1671 | 1679 | |
1672 | -{-
|
|
1673 | - ; pprTrace "spec_call" (vcat
|
|
1680 | + -- Check for (a) usefulness and (b) not already covered
|
|
1681 | + -- See (SC1) in Note [Specialisations already covered]
|
|
1682 | + ; let all_rules = rules_acc ++ existing_rules
|
|
1683 | + -- all_rules: we look both in the rules_acc (generated by this invocation
|
|
1684 | + -- of specCalls), and in existing_rules (passed in to specCalls)
|
|
1685 | + already_covered = alreadyCovered env' all_rule_bndrs fn
|
|
1686 | + rule_lhs_args is_active all_rules
|
|
1687 | + |
|
1688 | +{- ; pprTrace "spec_call" (vcat
|
|
1674 | 1689 | [ text "fun: " <+> ppr fn
|
1675 | 1690 | , text "call info: " <+> ppr _ci
|
1691 | + , text "useful: " <+> ppr useful
|
|
1692 | + , text "already_covered:" <+> ppr already_covered
|
|
1676 | 1693 | , text "poly_qvars: " <+> ppr poly_qvars
|
1677 | 1694 | , text "useful: " <+> ppr useful
|
1678 | 1695 | , text "all_rule_bndrs:" <+> ppr all_rule_bndrs
|
... | ... | @@ -1681,17 +1698,13 @@ specCalls spec_imp env existing_rules calls_for_me fn rhs |
1681 | 1698 | , text "dx_binds:" <+> ppr dx_binds
|
1682 | 1699 | , text "spec_args: " <+> ppr spec_args
|
1683 | 1700 | , text "rhs_bndrs" <+> ppr rhs_bndrs
|
1684 | - , text "rhs_body" <+> ppr rhs_body ]) $
|
|
1701 | + , text "rhs_body" <+> ppr rhs_body
|
|
1702 | + , text "subst''" <+> ppr subst'' ]) $
|
|
1685 | 1703 | return ()
|
1686 | 1704 | -}
|
1687 | 1705 | |
1688 | - -- Check for (a) usefulness and (b) not already covered
|
|
1689 | - -- See (SC1) in Note [Specialisations already covered]
|
|
1690 | - ; let all_rules = rules_acc ++ existing_rules
|
|
1691 | - -- all_rules: we look both in the rules_acc (generated by this invocation
|
|
1692 | - -- of specCalls), and in existing_rules (passed in to specCalls)
|
|
1693 | - ; if not useful -- No useful specialisation
|
|
1694 | - || alreadyCovered env' all_rule_bndrs fn rule_lhs_args is_active all_rules
|
|
1706 | + ; if not useful -- No useful specialisation
|
|
1707 | + || already_covered -- Useful, but done already
|
|
1695 | 1708 | then return spec_acc
|
1696 | 1709 | else
|
1697 | 1710 | |
... | ... | @@ -1702,6 +1715,12 @@ specCalls spec_imp env existing_rules calls_for_me fn rhs |
1702 | 1715 | -- Run the specialiser on the specialised RHS
|
1703 | 1716 | ; (rhs_body', rhs_uds) <- specExpr env'' rhs_body
|
1704 | 1717 | |
1718 | +{- ; pprTrace "spec_call2" (vcat
|
|
1719 | + [ text "fun:" <+> ppr fn
|
|
1720 | + , text "rhs_body':" <+> ppr rhs_body' ]) $
|
|
1721 | + return ()
|
|
1722 | +-}
|
|
1723 | + |
|
1705 | 1724 | -- Make the RHS of the specialised function
|
1706 | 1725 | ; let spec_rhs_bndrs = spec_bndrs ++ inner_rhs_bndrs'
|
1707 | 1726 | (rhs_uds1, inner_dumped_dbs) = dumpUDs spec_rhs_bndrs rhs_uds
|
... | ... | @@ -1853,8 +1853,8 @@ where we eta-expanded that (:). But now foldr expects an argument |
1853 | 1853 | with ->{Many} and gets an argument with ->{m1} or ->{m2}, and Lint
|
1854 | 1854 | complains.
|
1855 | 1855 | |
1856 | -The easiest solution was to use tcEqMult in tc_sub_type_deep, and
|
|
1857 | -insist on equality. This is only in the DeepSubsumption code anyway.
|
|
1856 | +The easiest solution was to unify the multiplicities in tc_sub_type_deep,
|
|
1857 | +insisting on equality. This is only in the DeepSubsumption code anyway.
|
|
1858 | 1858 | |
1859 | 1859 | Note [FunTy vs non-FunTy case in tc_sub_type_deep]
|
1860 | 1860 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
... | ... | @@ -2047,10 +2047,7 @@ tc_sub_type_deep pos unify inst_orig ctxt ty_actual ty_expected |
2047 | 2047 | -- GenSigCtxt: See Note [Setting the argument context]
|
2048 | 2048 | ; res_wrap <- tc_sub_type_deep (Result pos) unify inst_orig ctxt act_res exp_res
|
2049 | 2049 | |
2050 | - -- See Note [Multiplicity in deep subsumption]
|
|
2051 | - ; tcEqMult inst_orig act_mult exp_mult
|
|
2052 | - |
|
2053 | - ; mkWpFun_FRR pos
|
|
2050 | + ; mkWpFun_FRR unify pos
|
|
2054 | 2051 | act_af act_mult act_arg act_res
|
2055 | 2052 | exp_af exp_mult exp_arg exp_res
|
2056 | 2053 | arg_wrap res_wrap
|
... | ... | @@ -2058,20 +2055,32 @@ tc_sub_type_deep pos unify inst_orig ctxt ty_actual ty_expected |
2058 | 2055 | where
|
2059 | 2056 | given_orig = GivenOrigin (SigSkol GenSigCtxt exp_arg [])
|
2060 | 2057 | |
2061 | --- | Like 'mkWpFun', except that it performs representation-polymorphism
|
|
2062 | --- checks on the argument type.
|
|
2058 | +-- | Like 'mkWpFun', except that it performs the necessary
|
|
2059 | +-- representation-polymorphism checks on the argument type in the case that
|
|
2060 | +-- we introduce a lambda abstraction.
|
|
2063 | 2061 | mkWpFun_FRR
|
2064 | - :: Position p
|
|
2062 | + :: (TcType -> TcType -> TcM TcCoercionN) -- ^ how to unify
|
|
2063 | + -> Position p
|
|
2065 | 2064 | -> FunTyFlag -> Type -> TcType -> Type -- actual FunTy
|
2066 | 2065 | -> FunTyFlag -> Type -> TcType -> Type -- expected FunTy
|
2067 | 2066 | -> HsWrapper -- ^ exp_arg ~> act_arg
|
2068 | 2067 | -> HsWrapper -- ^ act_res ~> exp_res
|
2069 | 2068 | -> TcM HsWrapper -- ^ act_funTy ~> exp_funTy
|
2070 | -mkWpFun_FRR pos act_af act_mult act_arg act_res exp_af exp_mult exp_arg exp_res arg_wrap res_wrap
|
|
2071 | - | needs_eta
|
|
2072 | - -- See Wrinkle [Representation-polymorphism checking during subtyping]
|
|
2073 | - = do { (exp_arg_co, exp_arg_frr) <- hasFixedRuntimeRep (FRRDeepSubsumption True pos) exp_arg
|
|
2074 | - ; (act_arg_co, _act_arg_frr) <- hasFixedRuntimeRep (FRRDeepSubsumption False pos) act_arg
|
|
2069 | +mkWpFun_FRR unify pos act_af act_mult act_arg act_res exp_af exp_mult exp_arg exp_res arg_wrap res_wrap
|
|
2070 | + = do { ((exp_arg_co, exp_arg_frr), (act_arg_co, _act_arg_frr)) <-
|
|
2071 | + if needs_frr_checks
|
|
2072 | + -- See Wrinkle [Representation-polymorphism checking during subtyping]
|
|
2073 | + then do { exp_frr_wrap <- hasFixedRuntimeRep (frr_ctxt True ) exp_arg
|
|
2074 | + ; act_frr_wrap <- hasFixedRuntimeRep (frr_ctxt False) act_arg
|
|
2075 | + ; return (exp_frr_wrap, act_frr_wrap) }
|
|
2076 | + else return ((mkNomReflCo exp_arg, exp_arg), (mkNomReflCo act_arg, act_arg))
|
|
2077 | + |
|
2078 | + -- Enforce equality of multiplicities (not the more natural sub-multiplicity).
|
|
2079 | + -- See Note [Multiplicity in deep subsumption]
|
|
2080 | + ; act_arg_mult_co <- unify act_mult exp_mult
|
|
2081 | + -- NB: don't use tcEqMult: that would require the evidence for
|
|
2082 | + -- equality to be Refl, but it might well not be (#26332).
|
|
2083 | + |
|
2075 | 2084 | ; let
|
2076 | 2085 | exp_arg_fun_co =
|
2077 | 2086 | mkFunCo Nominal exp_af
|
... | ... | @@ -2080,7 +2089,7 @@ mkWpFun_FRR pos act_af act_mult act_arg act_res exp_af exp_mult exp_arg exp_res |
2080 | 2089 | (mkReflCo Nominal exp_res)
|
2081 | 2090 | act_arg_fun_co =
|
2082 | 2091 | mkFunCo Nominal act_af
|
2083 | - (mkReflCo Nominal act_mult)
|
|
2092 | + act_arg_mult_co
|
|
2084 | 2093 | act_arg_co
|
2085 | 2094 | (mkReflCo Nominal act_res)
|
2086 | 2095 | arg_wrap_frr =
|
... | ... | @@ -2090,24 +2099,16 @@ mkWpFun_FRR pos act_af act_mult act_arg act_res exp_af exp_mult exp_arg exp_res |
2090 | 2099 | -- arg_wrap :: exp_arg ~> act_arg
|
2091 | 2100 | -- arg_wrap_frr :: exp_arg_frr ~> act_arg_frr
|
2092 | 2101 | |
2093 | - -- NB: because of the needs_eta guard, we know that mkWpFun will
|
|
2094 | - -- return (WpFun ...); so we might as well just use the WpFun constructor.
|
|
2095 | 2102 | ; return $
|
2096 | 2103 | mkWpCastN exp_arg_fun_co
|
2097 | 2104 | <.>
|
2098 | - WpFun arg_wrap_frr res_wrap (Scaled exp_mult exp_arg_frr)
|
|
2105 | + mkWpFun arg_wrap_frr res_wrap (Scaled exp_mult exp_arg_frr) exp_res
|
|
2099 | 2106 | <.>
|
2100 | - mkWpCastN act_arg_fun_co }
|
|
2101 | - | otherwise
|
|
2102 | - = return $
|
|
2103 | - mkWpFun arg_wrap res_wrap (Scaled exp_mult exp_arg) exp_res
|
|
2104 | - -- NB: because of 'needs_eta', this will never actually be a WpFun.
|
|
2105 | - -- mkWpFun will turn it into a WpHole or WpCast, which is why
|
|
2106 | - -- we can skip the hasFixedRuntimeRep checks in this case.
|
|
2107 | - -- See Wrinkle [Representation-polymorphism checking during subtyping]
|
|
2107 | + mkWpCastN act_arg_fun_co
|
|
2108 | + }
|
|
2108 | 2109 | where
|
2109 | - needs_eta :: Bool
|
|
2110 | - needs_eta =
|
|
2110 | + needs_frr_checks :: Bool
|
|
2111 | + needs_frr_checks =
|
|
2111 | 2112 | not (hole_or_cast arg_wrap)
|
2112 | 2113 | ||
|
2113 | 2114 | not (hole_or_cast res_wrap)
|
... | ... | @@ -2115,6 +2116,12 @@ mkWpFun_FRR pos act_af act_mult act_arg act_res exp_af exp_mult exp_arg exp_res |
2115 | 2116 | hole_or_cast WpHole = True
|
2116 | 2117 | hole_or_cast (WpCast {}) = True
|
2117 | 2118 | hole_or_cast _ = False
|
2119 | + frr_ctxt :: Bool -> FixedRuntimeRepContext
|
|
2120 | + frr_ctxt is_exp_ty =
|
|
2121 | + FRRDeepSubsumption
|
|
2122 | + { frrDSExpected = is_exp_ty
|
|
2123 | + , frrDSPosition = pos
|
|
2124 | + }
|
|
2118 | 2125 | |
2119 | 2126 | -----------------------
|
2120 | 2127 | deeplySkolemise :: SkolemInfo -> TcSigmaType
|
1 | +{-# LANGUAGE DeepSubsumption #-}
|
|
2 | +{-# LANGUAGE LinearTypes #-}
|
|
3 | + |
|
4 | +module T26332 where
|
|
5 | + |
|
6 | +import Unsafe.Coerce
|
|
7 | + |
|
8 | +toLinear
|
|
9 | + :: forall a b p q.
|
|
10 | + (a %p-> b) %1-> (a %q-> b)
|
|
11 | +toLinear f = case unsafeEqualityProof @p @q of
|
|
12 | + UnsafeRefl -> f |
... | ... | @@ -41,6 +41,7 @@ test('T19400', unless(compiler_debugged(), skip), compile, ['']) |
41 | 41 | test('T20023', normal, compile, [''])
|
42 | 42 | test('T22546', normal, compile, [''])
|
43 | 43 | test('T23025', normal, compile, ['-dlinear-core-lint'])
|
44 | +test('T26332', normal, compile, ['-O -dlinear-core-lint'])
|
|
44 | 45 | test('LinearRecUpd', normal, compile, [''])
|
45 | 46 | test('T23814', normal, compile, [''])
|
46 | 47 | test('LinearLet', normal, compile, [''])
|
1 | +module M where
|
|
2 | + |
|
3 | +import GHC.Exts ( Any )
|
|
4 | +import Unsafe.Coerce ( unsafeCoerce )
|
|
5 | + |
|
6 | +data Sigma = MkT Any
|
|
7 | + |
|
8 | +testSubList :: Maybe Bool -> Sigma -> Sigma
|
|
9 | +testSubList (Just x) final = {-# SCC "y" #-} (
|
|
10 | + let x' = seq x ()
|
|
11 | + in case testSubList Nothing final of
|
|
12 | + MkT w -> {-# SCC "x" #-}
|
|
13 | + (unsafeCoerce MkT (konst x' myHead (unsafeCoerce w))))
|
|
14 | +testSubList Nothing final = final
|
|
15 | + |
|
16 | +myHead :: [a] -> a
|
|
17 | +myHead (x:_) = x
|
|
18 | + |
|
19 | +konst :: () -> ([a] -> a) -> [a] -> a
|
|
20 | +konst _ x = x
|
|
21 | +{-# OPAQUE konst #-} |
... | ... | @@ -20,3 +20,4 @@ test('T14931', [test_opts, unless(have_dynamic(), skip)], |
20 | 20 | test('T15108', [test_opts], compile, ['-O -prof -fprof-auto'])
|
21 | 21 | test('T19894', [test_opts, extra_files(['T19894'])], multimod_compile, ['Main', '-v0 -O2 -prof -fprof-auto -iT19894'])
|
22 | 22 | test('T20938', [test_opts], compile, ['-O -prof'])
|
23 | +test('T26056', [test_opts], compile, ['-O -prof']) |
... | ... | @@ -2,8 +2,11 @@ |
2 | 2 | #include <stdio.h>
|
3 | 3 | #include <errno.h>
|
4 | 4 | |
5 | -// Prints the state of the signal handlers to stdout
|
|
6 | -int main()
|
|
5 | +// Prints the state of the signal handlers to stdout.
|
|
6 | +// NOTE: We intentionally start at signal 1 (not 0). Signal number 0 is not a
|
|
7 | +// real signal; passing 0 to sigismember/sigaction is undefined behaviour and
|
|
8 | +// on Darwin was observed to yield memory corruption / junk bytes in output.
|
|
9 | +int main(void)
|
|
7 | 10 | {
|
8 | 11 | int open = 0, i;
|
9 | 12 | sigset_t blockedsigs;
|
... | ... | @@ -11,7 +14,7 @@ int main() |
11 | 14 | printf("ChildInfo { masked = [");
|
12 | 15 | |
13 | 16 | sigprocmask(SIG_BLOCK, NULL, &blockedsigs);
|
14 | - for(i = 0; i < NSIG; ++i)
|
|
17 | + for(i = 1; i < NSIG; ++i)
|
|
15 | 18 | {
|
16 | 19 | int ret = sigismember(&blockedsigs, i);
|
17 | 20 | if(ret >= 0)
|
... | ... | @@ -26,7 +29,7 @@ int main() |
26 | 29 | printf("], handlers = [");
|
27 | 30 | |
28 | 31 | open = 0;
|
29 | - for(i = 0; i < NSIG; ++i)
|
|
32 | + for(i = 1; i < NSIG; ++i)
|
|
30 | 33 | {
|
31 | 34 | struct sigaction old;
|
32 | 35 | if(sigaction(i, NULL, &old) >= 0)
|