Marge Bot pushed to branch wip/marge_bot_batch_merge_job at Glasgow Haskell Compiler / GHC
Commits:
-
fc555f08
by Simon Hengel at 2025-11-27T07:42:43-05:00
-
8d213a1c
by Simon Hengel at 2025-11-27T07:42:44-05:00
-
2bae26ae
by Simon Peyton Jones at 2025-11-27T07:42:44-05:00
-
eddea2d2
by Simon Peyton Jones at 2025-11-27T07:42:44-05:00
-
f274cc23
by Matthew Pickering at 2025-11-27T07:42:45-05:00
-
8b566aa6
by sheaf at 2025-11-27T07:42:58-05:00
15 changed files:
- compiler/GHC/Core/Opt/Arity.hs
- compiler/GHC/Core/SimpleOpt.hs
- compiler/GHC/Driver/DynFlags.hs
- compiler/GHC/Driver/Flags.hs
- compiler/GHC/Tc/Gen/App.hs
- docs/users_guide/exts/rank_polymorphism.rst
- docs/users_guide/exts/type_families.rst
- docs/users_guide/using-optimisation.rst
- rts/eventlog/EventLog.c
- testsuite/tests/rts/all.T
- + testsuite/tests/simplCore/should_compile/T26588.hs
- + testsuite/tests/simplCore/should_compile/T26589.hs
- testsuite/tests/simplCore/should_compile/T8331.stderr
- testsuite/tests/simplCore/should_compile/all.T
- utils/check-exact/ExactPrint.hs
Changes:
| ... | ... | @@ -2993,12 +2993,12 @@ pushCoValArg co |
| 2993 | 2993 | Pair tyL tyR = coercionKind co
|
| 2994 | 2994 | |
| 2995 | 2995 | pushCoercionIntoLambda
|
| 2996 | - :: HasDebugCallStack => Subst -> InVar -> InExpr -> OutCoercionR -> Maybe (OutVar, OutExpr)
|
|
| 2996 | + :: HasDebugCallStack => InScopeSet -> Var -> CoreExpr -> CoercionR -> Maybe (Var, CoreExpr)
|
|
| 2997 | 2997 | -- This implements the Push rule from the paper on coercions
|
| 2998 | 2998 | -- (\x. e) |> co
|
| 2999 | 2999 | -- ===>
|
| 3000 | 3000 | -- (\x'. e |> co')
|
| 3001 | -pushCoercionIntoLambda subst x e co
|
|
| 3001 | +pushCoercionIntoLambda in_scope x e co
|
|
| 3002 | 3002 | | assert (not (isTyVar x) && not (isCoVar x)) True
|
| 3003 | 3003 | , Pair s1s2 t1t2 <- coercionKind co
|
| 3004 | 3004 | , Just {} <- splitFunTy_maybe s1s2
|
| ... | ... | @@ -3011,9 +3011,9 @@ pushCoercionIntoLambda subst x e co |
| 3011 | 3011 | -- Should we optimize the coercions here?
|
| 3012 | 3012 | -- Otherwise they might not match too well
|
| 3013 | 3013 | x' = x `setIdType` t1 `setIdMult` w1
|
| 3014 | - in_scope' = substInScopeSet subst `extendInScopeSet` x'
|
|
| 3014 | + in_scope' = in_scope `extendInScopeSet` x'
|
|
| 3015 | 3015 | subst' =
|
| 3016 | - extendIdSubst (setInScope subst in_scope')
|
|
| 3016 | + extendIdSubst (setInScope emptySubst in_scope')
|
|
| 3017 | 3017 | x
|
| 3018 | 3018 | (mkCast (Var x') (mkSymCo co1))
|
| 3019 | 3019 | -- We substitute x' for x, except we need to preserve types.
|
| ... | ... | @@ -393,12 +393,19 @@ simple_app env e0@(Lam {}) as0@(_:_) |
| 393 | 393 | = wrapLet mb_pr $ do_beta env'' body as
|
| 394 | 394 | where (env', b') = subst_opt_bndr env b
|
| 395 | 395 | |
| 396 | - do_beta env e@(Lam b body) as@(CastIt co:rest)
|
|
| 397 | - -- See Note [Desugaring unlifted newtypes]
|
|
| 396 | + -- See Note [Eliminate casts in function position]
|
|
| 397 | + do_beta env e@(Lam b _) as@(CastIt out_co:rest)
|
|
| 398 | 398 | | isNonCoVarId b
|
| 399 | - , Just (b', body') <- pushCoercionIntoLambda (soe_subst env) b body co
|
|
| 399 | + -- Optimise the inner lambda to make it an 'OutExpr', which makes it
|
|
| 400 | + -- possible to call 'pushCoercionIntoLambda' with the 'OutCoercion' 'co'.
|
|
| 401 | + -- This is kind of horrible, as for nested casted lambdas with a big body,
|
|
| 402 | + -- we will repeatedly optimise the body (once for each binder). However,
|
|
| 403 | + -- we need to do this to avoid mixing 'InExpr' and 'OutExpr', or two
|
|
| 404 | + -- 'InExpr' with different environments (getting this wrong caused #26588 & #26589.)
|
|
| 405 | + , Lam out_b out_body <- simple_app env e []
|
|
| 406 | + , Just (b', body') <- pushCoercionIntoLambda (soeInScope env) out_b out_body out_co
|
|
| 400 | 407 | = do_beta (soeZapSubst env) (Lam b' body') rest
|
| 401 | - -- soeZapSubst: pushCoercionIntoLambda applies the substitution
|
|
| 408 | + -- soeZapSubst: we've already optimised everything (the lambda and 'rest') by now.
|
|
| 402 | 409 | | otherwise
|
| 403 | 410 | = rebuild_app env (simple_opt_expr env e) as
|
| 404 | 411 | |
| ... | ... | @@ -511,7 +518,31 @@ TL;DR: To avoid the rest of the compiler pipeline seeing these bad lambas, we |
| 511 | 518 | rely on the simple optimiser to both inline the newtype unfolding and
|
| 512 | 519 | subsequently deal with the resulting lambdas (either beta-reducing them
|
| 513 | 520 | altogether or pushing coercions into them so that they satisfy the
|
| 514 | -representation-polymorphism invariants).
|
|
| 521 | +representation-polymorphism invariants). See Note [Eliminate casts in function position].
|
|
| 522 | + |
|
| 523 | +[Alternative approach] (GHC ticket #26608)
|
|
| 524 | + |
|
| 525 | + We could instead, in the typechecker, emit a special form (a new constructor
|
|
| 526 | + of XXExprGhcTc) for instantiations of representation-polymorphic unlifted
|
|
| 527 | + newtypes (whether applied to a value argument or not):
|
|
| 528 | + |
|
| 529 | + UnliftedNT :: DataCon -> [Type] -> Coercion -> XXExprGhcTc
|
|
| 530 | + |
|
| 531 | + where "UnliftedNT nt_con [ty1, ...] co" represents the expression:
|
|
| 532 | + |
|
| 533 | + ( nt_con @ty1 ... ) |> co
|
|
| 534 | + |
|
| 535 | + The desugarer would then turn these AST nodes into appropriate Core, doing
|
|
| 536 | + what the simple optimiser does today:
|
|
| 537 | + - inline the compulsory unfolding of the newtype constructor
|
|
| 538 | + - apply it to its type arguments and beta reduce
|
|
| 539 | + - push the coercion into the resulting lambda
|
|
| 540 | + |
|
| 541 | + This would have several advantages:
|
|
| 542 | + - the desugarer would never produce "invalid" Core that needs to be
|
|
| 543 | + tidied up by the simple optimiser,
|
|
| 544 | + - the ugly and inefficient implementation described in
|
|
| 545 | + Note [Eliminate casts in function position] could be removed.
|
|
| 515 | 546 | |
| 516 | 547 | Wrinkle [Unlifted newtypes with wrappers]
|
| 517 | 548 | |
| ... | ... | @@ -717,50 +748,49 @@ rhss here. |
| 717 | 748 | |
| 718 | 749 | Note [Eliminate casts in function position]
|
| 719 | 750 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
| 720 | -Consider the following program:
|
|
| 751 | +Due to the current implementation strategy for representation-polymorphic
|
|
| 752 | +unlifted newtypes, as described in Note [Desugaring unlifted newtypes], we rely
|
|
| 753 | +on the simple optimiser to push coercions into lambdas, such as in the following
|
|
| 754 | +example:
|
|
| 721 | 755 | |
| 722 | 756 | type R :: Type -> RuntimeRep
|
| 723 | - type family R a where { R Float = FloatRep; R Double = DoubleRep }
|
|
| 724 | - type F :: forall (a :: Type) -> TYPE (R a)
|
|
| 725 | - type family F a where { F Float = Float# ; F Double = Double# }
|
|
| 757 | + type family R a where { R Int = IntRep }
|
|
| 758 | + type F :: forall a -> TYPE (R a)
|
|
| 759 | + type family F a where { F Int = Int# }
|
|
| 726 | 760 | |
| 727 | - type N :: forall (a :: Type) -> TYPE (R a)
|
|
| 728 | 761 | newtype N a = MkN (F a)
|
| 729 | 762 | |
| 730 | -As MkN is a newtype, its unfolding is a lambda which wraps its argument
|
|
| 731 | -in a cast:
|
|
| 732 | - |
|
| 733 | - MkN :: forall (a :: Type). F a -> N a
|
|
| 734 | - MkN = /\a \(x::F a). x |> co_ax
|
|
| 735 | - -- recall that F a :: TYPE (R a)
|
|
| 736 | - |
|
| 737 | -This is a representation-polymorphic lambda, in which the binder has an unknown
|
|
| 738 | -representation (R a). We can't compile such a lambda on its own, but we can
|
|
| 739 | -compile instantiations, such as `MkN @Float` or `MkN @Double`.
|
|
| 763 | +Now, an instantiated occurrence of 'MkN', such as 'MkN @Int' (whether applied
|
|
| 764 | +to a value argument or not) will lead, after inlining the compulsory unfolding
|
|
| 765 | +of 'MkN', to a lambda fo the form:
|
|
| 740 | 766 | |
| 741 | -Our strategy to avoid running afoul of the representation-polymorphism
|
|
| 742 | -invariants of Note [Representation polymorphism invariants] in GHC.Core is thus:
|
|
| 767 | + ( \ ( x :: F Int ) -> body ) |> co
|
|
| 743 | 768 | |
| 744 | - 1. Give the newtype a compulsory unfolding (it has no binding, as we can't
|
|
| 745 | - define lambdas with representation-polymorphic value binders in source Haskell).
|
|
| 746 | - 2. Rely on the optimiser to beta-reduce away any representation-polymorphic
|
|
| 747 | - value binders.
|
|
| 769 | + where
|
|
| 770 | + co :: ( F Int -> res ) ~# ( Int# -> res )
|
|
| 748 | 771 | |
| 749 | -For example, consider the application
|
|
| 772 | +The problem is that we now have a lambda abstraction whose binder does not have a
|
|
| 773 | +fixed RuntimeRep in the sense of Note [Fixed RuntimeRep] in GHC.Tc.Utils.Concrete.
|
|
| 750 | 774 | |
| 751 | - MkN @Float 34.0#
|
|
| 775 | +However, if we use 'pushCoercionIntoLambda', we end up with:
|
|
| 752 | 776 | |
| 753 | -After inlining MkN we'll get
|
|
| 777 | + ( \ ( x' :: Int# ) -> body' )
|
|
| 754 | 778 | |
| 755 | - ((/\a \(x:F a). x |> co_ax) @Float) |> co 34#
|
|
| 779 | +which satisfies the representation-polymorphism invariants of
|
|
| 780 | +Note [Representation polymorphism invariants] in GHC.Core.
|
|
| 756 | 781 | |
| 757 | -where co :: (F Float -> N Float) ~ (Float# ~ N Float)
|
|
| 782 | +In conclusion:
|
|
| 758 | 783 | |
| 759 | -But to actually beta-reduce that lambda, we need to push the 'co'
|
|
| 760 | -inside the `\x` with pushCoercionIntoLambda. Hence the extra
|
|
| 761 | -equation for Cast-of-Lam in simple_app.
|
|
| 784 | + 1. The simple optimiser must push casts into lambdas.
|
|
| 785 | + 2. It must also deal with a situation such as (MkN @Int) |> co, where we first
|
|
| 786 | + inline the compulsory unfolding of N. This means the simple optimiser must
|
|
| 787 | + "peel off" the casts and optimise the inner expression first, to determine
|
|
| 788 | + whether it is a lambda abstraction or not.
|
|
| 762 | 789 | |
| 763 | -This is regrettably delicate.
|
|
| 790 | +This is regrettably delicate. If we could make sure the typechecker/desugarer
|
|
| 791 | +did not produce these bad lambdas in the first place (as described in
|
|
| 792 | +[Alternative approach] in Note [Desugaring unlifted newtypes]), we could
|
|
| 793 | +get rid of this ugly logic.
|
|
| 764 | 794 | |
| 765 | 795 | Note [Preserve join-binding arity]
|
| 766 | 796 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
| ... | ... | @@ -1673,7 +1703,7 @@ exprIsLambda_maybe ise@(ISE in_scope_set _) (Cast casted_e co) |
| 1673 | 1703 | -- this implies that x is not in scope in gamma (makes this code simpler)
|
| 1674 | 1704 | , not (isTyVar x) && not (isCoVar x)
|
| 1675 | 1705 | , assert (not $ x `elemVarSet` tyCoVarsOfCo co) True
|
| 1676 | - , Just (x',e') <- pushCoercionIntoLambda (mkEmptySubst in_scope_set) x e co
|
|
| 1706 | + , Just (x',e') <- pushCoercionIntoLambda in_scope_set x e co
|
|
| 1677 | 1707 | , let res = Just (x',e',ts)
|
| 1678 | 1708 | = --pprTrace "exprIsLambda_maybe:Cast" (vcat [ppr casted_e,ppr co,ppr res)])
|
| 1679 | 1709 | res
|
| ... | ... | @@ -1268,6 +1268,7 @@ optLevelFlags -- see Note [Documenting optimisation flags] |
| 1268 | 1268 | , ([1,2], Opt_CfgBlocklayout) -- Experimental
|
| 1269 | 1269 | |
| 1270 | 1270 | , ([1,2], Opt_Specialise)
|
| 1271 | + , ([1,2], Opt_PolymorphicSpecialisation) -- Now on by default (#23559)
|
|
| 1271 | 1272 | , ([1,2], Opt_CrossModuleSpecialise)
|
| 1272 | 1273 | , ([1,2], Opt_InlineGenerics)
|
| 1273 | 1274 | , ([1,2], Opt_Strictness)
|
| ... | ... | @@ -909,6 +909,7 @@ optimisationFlags = EnumSet.fromList |
| 909 | 909 | , Opt_SpecialiseAggressively
|
| 910 | 910 | , Opt_CrossModuleSpecialise
|
| 911 | 911 | , Opt_StaticArgumentTransformation
|
| 912 | + , Opt_PolymorphicSpecialisation
|
|
| 912 | 913 | , Opt_CSE
|
| 913 | 914 | , Opt_StgCSE
|
| 914 | 915 | , Opt_StgLiftLams
|
| ... | ... | @@ -749,13 +749,13 @@ tcInstFun do_ql inst_final (tc_fun, fun_ctxt) fun_sigma rn_args |
| 749 | 749 | go1 _pos acc fun_ty []
|
| 750 | 750 | | XExpr (ConLikeTc (RealDataCon dc)) <- tc_fun
|
| 751 | 751 | , isNewDataCon dc
|
| 752 | - , [Scaled _ arg_ty] <- dataConOrigArgTys dc
|
|
| 752 | + , [Scaled _ orig_arg_ty] <- dataConOrigArgTys dc
|
|
| 753 | 753 | , n_val_args == 0
|
| 754 | 754 | -- If we're dealing with an unsaturated representation-polymorphic
|
| 755 | 755 | -- UnliftedNewype, then perform a representation-polymorphism check.
|
| 756 | 756 | -- See Note [Representation-polymorphism checks for unsaturated unlifted newtypes]
|
| 757 | 757 | -- in GHC.Tc.Utils.Concrete.
|
| 758 | - , not $ typeHasFixedRuntimeRep arg_ty
|
|
| 758 | + , not $ typeHasFixedRuntimeRep orig_arg_ty
|
|
| 759 | 759 | = do { (wrap_co, arg_ty, res_ty) <-
|
| 760 | 760 | matchActualFunTy (FRRRepPolyUnliftedNewtype dc)
|
| 761 | 761 | (Just $ HsExprTcThing tc_fun)
|
| ... | ... | @@ -195,7 +195,7 @@ For example: :: |
| 195 | 195 | g3c :: Int -> forall x y. y -> x -> x
|
| 196 | 196 | |
| 197 | 197 | f4 :: (Int -> forall a. (Eq a, Show a) => a -> a) -> Bool
|
| 198 | - g4 :: Int -> forall x. (Show x, Eq x) => x -> x) -> Bool
|
|
| 198 | + g4 :: Int -> forall x. (Show x, Eq x) => x -> x
|
|
| 199 | 199 | |
| 200 | 200 | Then the application ``f3 g3a`` is well-typed, because ``g3a`` has a type that matches the type
|
| 201 | 201 | expected by ``f3``. But ``f3 g3b`` is not well typed, because the foralls are in different places.
|
| ... | ... | @@ -680,7 +680,7 @@ thus: :: |
| 680 | 680 | When doing so, we (optionally) may drop the "``family``" keyword.
|
| 681 | 681 | |
| 682 | 682 | The type parameters must all be type variables, of course, and some (but
|
| 683 | -not necessarily all) of then can be the class parameters. Each class
|
|
| 683 | +not necessarily all) of them can be the class parameters. Each class
|
|
| 684 | 684 | parameter may only be used at most once per associated type, but some
|
| 685 | 685 | may be omitted and they may be in an order other than in the class head.
|
| 686 | 686 | Hence, the following contrived example is admissible: ::
|
| ... | ... | @@ -1325,10 +1325,7 @@ as such you shouldn't need to set any of them explicitly. A flag |
| 1325 | 1325 | :reverse: -fno-polymorphic-specialisation
|
| 1326 | 1326 | :category:
|
| 1327 | 1327 | |
| 1328 | - :default: off
|
|
| 1329 | - |
|
| 1330 | - Warning, this feature is highly experimental and may lead to incorrect runtime
|
|
| 1331 | - results. Use at your own risk (:ghc-ticket:`23469`, :ghc-ticket:`23109`, :ghc-ticket:`21229`, :ghc-ticket:`23445`).
|
|
| 1328 | + :default: on
|
|
| 1332 | 1329 | |
| 1333 | 1330 | Enable specialisation of function calls to known dictionaries with free type variables.
|
| 1334 | 1331 | The created specialisation will abstract over the type variables free in the dictionary.
|
| ... | ... | @@ -491,13 +491,7 @@ endEventLogging(void) |
| 491 | 491 | |
| 492 | 492 | eventlog_enabled = false;
|
| 493 | 493 | |
| 494 | - // Flush all events remaining in the buffers.
|
|
| 495 | - //
|
|
| 496 | - // N.B. Don't flush if shutting down: this was done in
|
|
| 497 | - // finishCapEventLogging and the capabilities have already been freed.
|
|
| 498 | - if (getSchedState() != SCHED_SHUTTING_DOWN) {
|
|
| 499 | - flushEventLog(NULL);
|
|
| 500 | - }
|
|
| 494 | + flushEventLog(NULL);
|
|
| 501 | 495 | |
| 502 | 496 | ACQUIRE_LOCK(&eventBufMutex);
|
| 503 | 497 | |
| ... | ... | @@ -1626,15 +1620,24 @@ void flushEventLog(Capability **cap USED_IF_THREADS) |
| 1626 | 1620 | return;
|
| 1627 | 1621 | }
|
| 1628 | 1622 | |
| 1623 | + // N.B. Don't flush if shutting down: this was done in
|
|
| 1624 | + // finishCapEventLogging and the capabilities have already been freed.
|
|
| 1625 | + // This can also race against the shutdown if the flush is triggered by the
|
|
| 1626 | + // ticker thread. (#26573)
|
|
| 1627 | + if (getSchedState() == SCHED_SHUTTING_DOWN) {
|
|
| 1628 | + return;
|
|
| 1629 | + }
|
|
| 1630 | + |
|
| 1629 | 1631 | ACQUIRE_LOCK(&eventBufMutex);
|
| 1630 | 1632 | printAndClearEventBuf(&eventBuf);
|
| 1631 | 1633 | RELEASE_LOCK(&eventBufMutex);
|
| 1632 | 1634 | |
| 1633 | 1635 | #if defined(THREADED_RTS)
|
| 1634 | - Task *task = getMyTask();
|
|
| 1636 | + Task *task = newBoundTask();
|
|
| 1635 | 1637 | stopAllCapabilitiesWith(cap, task, SYNC_FLUSH_EVENT_LOG);
|
| 1636 | 1638 | flushAllCapsEventsBufs();
|
| 1637 | 1639 | releaseAllCapabilities(getNumCapabilities(), cap ? *cap : NULL, task);
|
| 1640 | + exitMyTask();
|
|
| 1638 | 1641 | #else
|
| 1639 | 1642 | flushLocalEventsBuf(getCapability(0));
|
| 1640 | 1643 | #endif
|
| ... | ... | @@ -2,6 +2,11 @@ test('testblockalloc', |
| 2 | 2 | [c_src, only_ways(['normal','threaded1']), extra_run_opts('+RTS -I0')],
|
| 3 | 3 | compile_and_run, [''])
|
| 4 | 4 | |
| 5 | +test('numeric_version_eventlog_flush',
|
|
| 6 | + [ignore_stdout, req_ghc_with_threaded_rts],
|
|
| 7 | + run_command,
|
|
| 8 | + ['{compiler} --numeric-version +RTS -l --eventlog-flush-interval=1 -RTS'])
|
|
| 9 | + |
|
| 5 | 10 | test('testmblockalloc',
|
| 6 | 11 | [c_src, only_ways(['normal','threaded1']), extra_run_opts('+RTS -I0 -xr0.125T'),
|
| 7 | 12 | when(arch('wasm32'), skip)], # MBlocks can't be freed on wasm32, see Note [Megablock allocator on wasm] in rts
|
| 1 | +module T26588 ( getOptionSettingFromText ) where
|
|
| 2 | + |
|
| 3 | +import Control.Applicative ( Const(..) )
|
|
| 4 | +import Data.Map (Map)
|
|
| 5 | +import qualified Data.Map.Strict as Map
|
|
| 6 | + |
|
| 7 | +------------------------------------------------------------------------
|
|
| 8 | +-- ConfigState
|
|
| 9 | + |
|
| 10 | +data ConfigLeaf
|
|
| 11 | +data ConfigTrie = ConfigTrie !(Maybe ConfigLeaf) !ConfigMap
|
|
| 12 | + |
|
| 13 | +type ConfigMap = Map Int ConfigTrie
|
|
| 14 | + |
|
| 15 | +freshLeaf :: [Int] -> ConfigLeaf -> ConfigTrie
|
|
| 16 | +freshLeaf [] l = ConfigTrie (Just l) mempty
|
|
| 17 | +freshLeaf (a:as) l = ConfigTrie Nothing (Map.singleton a (freshLeaf as l))
|
|
| 18 | + |
|
| 19 | +adjustConfigTrie :: Functor t => [Int] -> (Maybe ConfigLeaf -> t (Maybe ConfigLeaf)) -> Maybe (ConfigTrie) -> t (Maybe ConfigTrie)
|
|
| 20 | +adjustConfigTrie as f Nothing = fmap (freshLeaf as) <$> f Nothing
|
|
| 21 | +adjustConfigTrie (a:as) f (Just (ConfigTrie x m)) = Just . ConfigTrie x <$> adjustConfigMap a as f m
|
|
| 22 | +adjustConfigTrie [] f (Just (ConfigTrie x m)) = g <$> f x
|
|
| 23 | + where g Nothing | Map.null m = Nothing
|
|
| 24 | + g x' = Just (ConfigTrie x' m)
|
|
| 25 | + |
|
| 26 | +adjustConfigMap :: Functor t => Int -> [Int] -> (Maybe ConfigLeaf -> t (Maybe ConfigLeaf)) -> ConfigMap -> t ConfigMap
|
|
| 27 | +adjustConfigMap a as f = Map.alterF (adjustConfigTrie as f) a
|
|
| 28 | + |
|
| 29 | +getOptionSettingFromText :: Int -> [Int] -> ConfigMap -> IO ()
|
|
| 30 | +getOptionSettingFromText p ps = getConst . adjustConfigMap p ps f
|
|
| 31 | + where
|
|
| 32 | + f _ = Const (return ()) |
| 1 | +module T26589 ( executeTest ) where
|
|
| 2 | + |
|
| 3 | +-- base
|
|
| 4 | +import Data.Coerce ( coerce )
|
|
| 5 | +import Data.Foldable ( foldMap )
|
|
| 6 | + |
|
| 7 | +--------------------------------------------------------------------------------
|
|
| 8 | + |
|
| 9 | +newtype Traversal f = Traversal { getTraversal :: f () }
|
|
| 10 | + |
|
| 11 | +instance Applicative f => Semigroup (Traversal f) where
|
|
| 12 | + Traversal f1 <> Traversal f2 = Traversal $ f1 *> f2
|
|
| 13 | +instance Applicative f => Monoid (Traversal f) where
|
|
| 14 | + mempty = Traversal $ pure ()
|
|
| 15 | + |
|
| 16 | +newtype Seq a = Seq (FingerTree (Elem a))
|
|
| 17 | +newtype Elem a = Elem { getElem :: a }
|
|
| 18 | + |
|
| 19 | +data FingerTree a
|
|
| 20 | + = EmptyT
|
|
| 21 | + | Deep !a (FingerTree a) !a
|
|
| 22 | + |
|
| 23 | +executeTest :: Seq () -> IO ()
|
|
| 24 | +executeTest fins = destroyResources
|
|
| 25 | + where
|
|
| 26 | + destroyResources :: IO ()
|
|
| 27 | + destroyResources =
|
|
| 28 | + getTraversal $
|
|
| 29 | + flip foldMap1 fins $ \ _ ->
|
|
| 30 | + Traversal $ return ()
|
|
| 31 | + |
|
| 32 | +foldMap1 :: forall m a. Monoid m => (a -> m) -> Seq a -> m
|
|
| 33 | +foldMap1 = coerce (foldMap2 :: (Elem a -> m) -> FingerTree (Elem a) -> m)
|
|
| 34 | + |
|
| 35 | +foldMap2 :: Monoid m => (Elem a -> m) -> FingerTree (Elem a) -> m
|
|
| 36 | +foldMap2 _ EmptyT = mempty
|
|
| 37 | +foldMap2 f' (Deep pr' m' sf') = f' pr' <> foldMapTree f' m' <> f' sf'
|
|
| 38 | + where
|
|
| 39 | + foldMapTree :: Monoid m => (a -> m) -> FingerTree a -> m
|
|
| 40 | + foldMapTree _ EmptyT = mempty
|
|
| 41 | + foldMapTree f (Deep pr m sf) =
|
|
| 42 | + f pr <>
|
|
| 43 | + foldMapTree f m <>
|
|
| 44 | + f sf |
| 1 | 1 | |
| 2 | 2 | ==================== Tidy Core rules ====================
|
| 3 | +"SPEC $c*> @(ST s) @_"
|
|
| 4 | + forall (@s) (@r) ($dApplicative :: Applicative (ST s)).
|
|
| 5 | + $fApplicativeReaderT_$c*> @(ST s) @r $dApplicative
|
|
| 6 | + = ($fApplicativeReaderT2 @s @r)
|
|
| 7 | + `cast` (forall (a ::~ <*>_N) (b ::~ <*>_N).
|
|
| 8 | + <ReaderT r (ST s) a>_R
|
|
| 9 | + ->_R <ReaderT r (ST s) b>_R
|
|
| 10 | + ->_R <r>_R ->_R Sym (N:ST <s>_N <b>_R)
|
|
| 11 | + ; Sym (N:ReaderT <*>_N <r>_R <ST s>_R <b>_N)
|
|
| 12 | + :: Coercible
|
|
| 13 | + (forall a b.
|
|
| 14 | + ReaderT r (ST s) a -> ReaderT r (ST s) b -> r -> STRep s b)
|
|
| 15 | + (forall a b.
|
|
| 16 | + ReaderT r (ST s) a -> ReaderT r (ST s) b -> ReaderT r (ST s) b))
|
|
| 17 | +"SPEC $c<$ @(ST s) @_"
|
|
| 18 | + forall (@s) (@r) ($dFunctor :: Functor (ST s)).
|
|
| 19 | + $fFunctorReaderT_$c<$ @(ST s) @r $dFunctor
|
|
| 20 | + = ($fApplicativeReaderT6 @s @r)
|
|
| 21 | + `cast` (forall (a ::~ <*>_N) (b ::~ <*>_N).
|
|
| 22 | + <a>_R
|
|
| 23 | + ->_R <ReaderT r (ST s) b>_R
|
|
| 24 | + ->_R <r>_R ->_R Sym (N:ST <s>_N <a>_R)
|
|
| 25 | + ; Sym (N:ReaderT <*>_N <r>_R <ST s>_R <a>_N)
|
|
| 26 | + :: Coercible
|
|
| 27 | + (forall a b. a -> ReaderT r (ST s) b -> r -> STRep s a)
|
|
| 28 | + (forall a b. a -> ReaderT r (ST s) b -> ReaderT r (ST s) a))
|
|
| 29 | +"SPEC $c<* @(ST s) @_"
|
|
| 30 | + forall (@s) (@r) ($dApplicative :: Applicative (ST s)).
|
|
| 31 | + $fApplicativeReaderT_$c<* @(ST s) @r $dApplicative
|
|
| 32 | + = ($fApplicativeReaderT1 @s @r)
|
|
| 33 | + `cast` (forall (a ::~ <*>_N) (b ::~ <*>_N).
|
|
| 34 | + <ReaderT r (ST s) a>_R
|
|
| 35 | + ->_R <ReaderT r (ST s) b>_R
|
|
| 36 | + ->_R <r>_R ->_R Sym (N:ST <s>_N <a>_R)
|
|
| 37 | + ; Sym (N:ReaderT <*>_N <r>_R <ST s>_R <a>_N)
|
|
| 38 | + :: Coercible
|
|
| 39 | + (forall a b.
|
|
| 40 | + ReaderT r (ST s) a -> ReaderT r (ST s) b -> r -> STRep s a)
|
|
| 41 | + (forall a b.
|
|
| 42 | + ReaderT r (ST s) a -> ReaderT r (ST s) b -> ReaderT r (ST s) a))
|
|
| 43 | +"SPEC $c<*> @(ST s) @_"
|
|
| 44 | + forall (@s) (@r) ($dApplicative :: Applicative (ST s)).
|
|
| 45 | + $fApplicativeReaderT9 @(ST s) @r $dApplicative
|
|
| 46 | + = ($fApplicativeReaderT4 @s @r)
|
|
| 47 | + `cast` (forall (a ::~ <*>_N) (b ::~ <*>_N).
|
|
| 48 | + <ReaderT r (ST s) (a -> b)>_R
|
|
| 49 | + ->_R <ReaderT r (ST s) a>_R
|
|
| 50 | + ->_R <r>_R
|
|
| 51 | + ->_R Sym (N:ST <s>_N <b>_R)
|
|
| 52 | + :: Coercible
|
|
| 53 | + (forall a b.
|
|
| 54 | + ReaderT r (ST s) (a -> b) -> ReaderT r (ST s) a -> r -> STRep s b)
|
|
| 55 | + (forall a b.
|
|
| 56 | + ReaderT r (ST s) (a -> b) -> ReaderT r (ST s) a -> r -> ST s b))
|
|
| 57 | +"SPEC $c>> @(ST s) @_"
|
|
| 58 | + forall (@s) (@r) ($dMonad :: Monad (ST s)).
|
|
| 59 | + $fMonadReaderT1 @(ST s) @r $dMonad
|
|
| 60 | + = $fMonadAbstractIOSTReaderT_$s$c>> @s @r
|
|
| 61 | +"SPEC $c>>= @(ST s) @_"
|
|
| 62 | + forall (@s) (@r) ($dMonad :: Monad (ST s)).
|
|
| 63 | + $fMonadReaderT2 @(ST s) @r $dMonad
|
|
| 64 | + = ($fMonadAbstractIOSTReaderT2 @s @r)
|
|
| 65 | + `cast` (forall (a ::~ <*>_N) (b ::~ <*>_N).
|
|
| 66 | + <ReaderT r (ST s) a>_R
|
|
| 67 | + ->_R <a -> ReaderT r (ST s) b>_R
|
|
| 68 | + ->_R <r>_R
|
|
| 69 | + ->_R Sym (N:ST <s>_N <b>_R)
|
|
| 70 | + :: Coercible
|
|
| 71 | + (forall a b.
|
|
| 72 | + ReaderT r (ST s) a -> (a -> ReaderT r (ST s) b) -> r -> STRep s b)
|
|
| 73 | + (forall a b.
|
|
| 74 | + ReaderT r (ST s) a -> (a -> ReaderT r (ST s) b) -> r -> ST s b))
|
|
| 75 | +"SPEC $cfmap @(ST s) @_"
|
|
| 76 | + forall (@s) (@r) ($dFunctor :: Functor (ST s)).
|
|
| 77 | + $fFunctorReaderT_$cfmap @(ST s) @r $dFunctor
|
|
| 78 | + = ($fApplicativeReaderT7 @s @r)
|
|
| 79 | + `cast` (forall (a ::~ <*>_N) (b ::~ <*>_N).
|
|
| 80 | + <a -> b>_R
|
|
| 81 | + ->_R <ReaderT r (ST s) a>_R
|
|
| 82 | + ->_R <r>_R ->_R Sym (N:ST <s>_N <b>_R)
|
|
| 83 | + ; Sym (N:ReaderT <*>_N <r>_R <ST s>_R <b>_N)
|
|
| 84 | + :: Coercible
|
|
| 85 | + (forall a b. (a -> b) -> ReaderT r (ST s) a -> r -> STRep s b)
|
|
| 86 | + (forall a b. (a -> b) -> ReaderT r (ST s) a -> ReaderT r (ST s) b))
|
|
| 87 | +"SPEC $cliftA2 @(ST s) @_"
|
|
| 88 | + forall (@s) (@r) ($dApplicative :: Applicative (ST s)).
|
|
| 89 | + $fApplicativeReaderT_$cliftA2 @(ST s) @r $dApplicative
|
|
| 90 | + = ($fApplicativeReaderT3 @s @r)
|
|
| 91 | + `cast` (forall (a ::~ <*>_N) (b ::~ <*>_N) (c ::~ <*>_N).
|
|
| 92 | + <a -> b -> c>_R
|
|
| 93 | + ->_R <ReaderT r (ST s) a>_R
|
|
| 94 | + ->_R <ReaderT r (ST s) b>_R
|
|
| 95 | + ->_R <r>_R ->_R Sym (N:ST <s>_N <c>_R)
|
|
| 96 | + ; Sym (N:ReaderT <*>_N <r>_R <ST s>_R <c>_N)
|
|
| 97 | + :: Coercible
|
|
| 98 | + (forall a b c.
|
|
| 99 | + (a -> b -> c)
|
|
| 100 | + -> ReaderT r (ST s) a -> ReaderT r (ST s) b -> r -> STRep s c)
|
|
| 101 | + (forall a b c.
|
|
| 102 | + (a -> b -> c)
|
|
| 103 | + -> ReaderT r (ST s) a -> ReaderT r (ST s) b -> ReaderT r (ST s) c))
|
|
| 104 | +"SPEC $cp1Applicative @(ST s) @_"
|
|
| 105 | + forall (@s) (@r) ($dApplicative :: Applicative (ST s)).
|
|
| 106 | + $fApplicativeReaderT_$cp1Applicative @(ST s) @r $dApplicative
|
|
| 107 | + = $fApplicativeReaderT_$s$fFunctorReaderT @s @r
|
|
| 108 | +"SPEC $cp1Monad @(ST s) @_"
|
|
| 109 | + forall (@s) (@r) ($dMonad :: Monad (ST s)).
|
|
| 110 | + $fMonadReaderT_$cp1Monad @(ST s) @r $dMonad
|
|
| 111 | + = $fApplicativeReaderT_$s$fApplicativeReaderT @s @r
|
|
| 112 | +"SPEC $cpure @(ST s) @_"
|
|
| 113 | + forall (@s) (@r) ($dApplicative :: Applicative (ST s)).
|
|
| 114 | + $fApplicativeReaderT_$cpure @(ST s) @r $dApplicative
|
|
| 115 | + = ($fApplicativeReaderT5 @s @r)
|
|
| 116 | + `cast` (forall (a ::~ <*>_N).
|
|
| 117 | + <a>_R
|
|
| 118 | + ->_R <r>_R ->_R Sym (N:ST <s>_N <a>_R)
|
|
| 119 | + ; Sym (N:ReaderT <*>_N <r>_R <ST s>_R <a>_N)
|
|
| 120 | + :: Coercible
|
|
| 121 | + (forall a. a -> r -> STRep s a)
|
|
| 122 | + (forall a. a -> ReaderT r (ST s) a))
|
|
| 123 | +"SPEC $creturn @(ST s) @_"
|
|
| 124 | + forall (@s) (@r) ($dMonad :: Monad (ST s)).
|
|
| 125 | + $fMonadReaderT_$creturn @(ST s) @r $dMonad
|
|
| 126 | + = ($fApplicativeReaderT5 @s @r)
|
|
| 127 | + `cast` (forall (a ::~ <*>_N).
|
|
| 128 | + <a>_R
|
|
| 129 | + ->_R <r>_R ->_R Sym (N:ST <s>_N <a>_R)
|
|
| 130 | + ; Sym (N:ReaderT <*>_N <r>_R <ST s>_R <a>_N)
|
|
| 131 | + :: Coercible
|
|
| 132 | + (forall a. a -> r -> STRep s a)
|
|
| 133 | + (forall a. a -> ReaderT r (ST s) a))
|
|
| 134 | +"SPEC $fApplicativeReaderT @(ST s) @_"
|
|
| 135 | + forall (@s) (@r) ($dApplicative :: Applicative (ST s)).
|
|
| 136 | + $fApplicativeReaderT @(ST s) @r $dApplicative
|
|
| 137 | + = $fApplicativeReaderT_$s$fApplicativeReaderT @s @r
|
|
| 138 | +"SPEC $fFunctorReaderT @(ST s) @_"
|
|
| 139 | + forall (@s) (@r) ($dFunctor :: Functor (ST s)).
|
|
| 140 | + $fFunctorReaderT @(ST s) @r $dFunctor
|
|
| 141 | + = $fApplicativeReaderT_$s$fFunctorReaderT @s @r
|
|
| 142 | +"SPEC $fMonadReaderT @(ST s) @_"
|
|
| 143 | + forall (@s) (@r) ($dMonad :: Monad (ST s)).
|
|
| 144 | + $fMonadReaderT @(ST s) @r $dMonad
|
|
| 145 | + = $fMonadAbstractIOSTReaderT_$s$fMonadReaderT @s @r
|
|
| 3 | 146 | "USPEC useAbstractMonad @(ReaderT Int (ST s))"
|
| 4 | 147 | forall (@s)
|
| 5 | 148 | ($dMonadAbstractIOST :: MonadAbstractIOST (ReaderT Int (ST s))).
|
| ... | ... | @@ -544,6 +544,9 @@ test('T25883b', normal, compile_grep_core, ['']) |
| 544 | 544 | test('T25883c', normal, compile_grep_core, [''])
|
| 545 | 545 | test('T25883d', [extra_files(['T25883d_import.hs'])], multimod_compile_filter, ['T25883d', '-O -ddump-simpl -dno-typeable-binds -dsuppress-all -dsuppress-uniques', r'grep -e "y ="'])
|
| 546 | 546 | |
| 547 | +test('T26588', normal, compile, ['-package containers -O'])
|
|
| 548 | +test('T26589', normal, compile, ['-O'])
|
|
| 549 | + |
|
| 547 | 550 | test('T25976', [grep_errmsg('Dead Code')], compile, ['-O -ddump-simpl -dsuppress-uniques -dno-typeable-binds'])
|
| 548 | 551 | |
| 549 | 552 | test('T25965', normal, compile, ['-O'])
|
| ... | ... | @@ -19,6 +19,13 @@ |
| 19 | 19 | {-# LANGUAGE UndecidableInstances #-} -- For the (StmtLR GhcPs GhcPs (LocatedA (body GhcPs))) ExactPrint instance
|
| 20 | 20 | {-# OPTIONS_GHC -Wno-incomplete-uni-patterns -Wno-incomplete-record-updates #-}
|
| 21 | 21 | |
| 22 | +-- We switch off specialisation in this module. Otherwise we get lots of functions
|
|
| 23 | +-- specialised on lots of (GHC syntax tree) data types. Compilation time allocation
|
|
| 24 | +-- (at least with -fpolymorphic-specialisation; see !15058) blows up from 17G to 108G.
|
|
| 25 | +-- Bad! ExactPrint is not a performance-critical module so it's not worth taking the
|
|
| 26 | +-- largely-fruitless hit in compile time.
|
|
| 27 | +{-# OPTIONS_GHC -fno-specialise #-}
|
|
| 28 | + |
|
| 22 | 29 | module ExactPrint
|
| 23 | 30 | (
|
| 24 | 31 | ExactPrint(..)
|