Zubin pushed to branch wip/9.12.3-backports at Glasgow Haskell Compiler / GHC
Commits:
-
24710c4c
by Sebastian Graf at 2025-09-02T17:19:41+05:30
-
aa52a199
by Zubin Duggal at 2025-09-02T17:19:41+05:30
-
ac9ab53d
by Ben Gamari at 2025-09-02T17:19:41+05:30
-
d2b40901
by Simon Peyton Jones at 2025-09-02T17:19:41+05:30
-
2b0f2f43
by Andreas Klebinger at 2025-09-02T17:19:41+05:30
-
68a1a88f
by Teo Camarasu at 2025-09-02T17:19:41+05:30
-
670cbe9d
by Teo Camarasu at 2025-09-02T17:19:41+05:30
-
ab0a766c
by Reed Mullanix at 2025-09-02T17:19:41+05:30
-
9edb71d5
by Ben Gamari at 2025-09-02T17:19:41+05:30
24 changed files:
- .gitlab/rel_eng/fetch-gitlab-artifacts/fetch_gitlab.py
- compiler/GHC/CmmToLlvm/Base.hs
- compiler/GHC/Core/Opt/CprAnal.hs
- compiler/GHC/Core/Opt/WorkWrap/Utils.hs
- compiler/GHC/Driver/Errors/Ppr.hs
- compiler/GHC/Tc/Solver/Equality.hs
- configure.ac
- libraries/base/changelog.md
- libraries/ghc-bignum/changelog.md
- libraries/ghc-bignum/src/GHC/Num/Natural.hs
- rts/Messages.c
- rts/StgMiscClosures.cmm
- rts/Updates.h
- + testsuite/tests/cpranal/sigs/T25944.hs
- + testsuite/tests/cpranal/sigs/T25944.stderr
- testsuite/tests/cpranal/sigs/all.T
- + testsuite/tests/numeric/should_run/T26230.hs
- + testsuite/tests/numeric/should_run/T26230.stdout
- testsuite/tests/numeric/should_run/all.T
- + testsuite/tests/partial-sigs/should_compile/T26256.hs
- + testsuite/tests/partial-sigs/should_compile/T26256.stderr
- testsuite/tests/partial-sigs/should_compile/all.T
- + testsuite/tests/typecheck/should_compile/T26256a.hs
- testsuite/tests/typecheck/should_compile/all.T
Changes:
| ... | ... | @@ -134,6 +134,9 @@ def fetch_artifacts(release: str, pipeline_id: int, |
| 134 | 134 | logging.info(f'extracted docs {f} to {dest}')
|
| 135 | 135 | index_path = destdir / 'docs' / 'index.html'
|
| 136 | 136 | index_path.replace(dest / 'index.html')
|
| 137 | + pdfs = list(destdir.glob('*.pdf'))
|
|
| 138 | + for f in pdfs:
|
|
| 139 | + f.replace(dest / f.name)
|
|
| 137 | 140 | elif job.name == 'hackage-doc-tarball':
|
| 138 | 141 | dest = dest_dir / 'hackage_docs'
|
| 139 | 142 | logging.info(f'moved hackage_docs to {dest}')
|
| ... | ... | @@ -526,10 +526,10 @@ generateExternDecls = do |
| 526 | 526 | modifyEnv $ \env -> env { envAliases = emptyUniqSet }
|
| 527 | 527 | return (concat defss, [])
|
| 528 | 528 | |
| 529 | --- | Is a variable one of the special @$llvm@ globals?
|
|
| 529 | +-- | Is a variable one of the special @\@llvm@ globals?
|
|
| 530 | 530 | isBuiltinLlvmVar :: LlvmVar -> Bool
|
| 531 | 531 | isBuiltinLlvmVar (LMGlobalVar lbl _ _ _ _ _) =
|
| 532 | - "$llvm" `isPrefixOf` unpackFS lbl
|
|
| 532 | + "llvm." `isPrefixOf` unpackFS lbl
|
|
| 533 | 533 | isBuiltinLlvmVar _ = False
|
| 534 | 534 | |
| 535 | 535 | -- | Here we take a global variable definition, rename it with a
|
| 1 | +{-# LANGUAGE MultiWayIf #-}
|
|
| 1 | 2 | |
| 2 | 3 | -- | Constructed Product Result analysis. Identifies functions that surely
|
| 3 | 4 | -- return heap-allocated records on every code path, so that we can eliminate
|
| ... | ... | @@ -22,12 +23,15 @@ import GHC.Types.Demand |
| 22 | 23 | import GHC.Types.Cpr
|
| 23 | 24 | import GHC.Types.Unique.MemoFun
|
| 24 | 25 | |
| 26 | +import GHC.Core
|
|
| 25 | 27 | import GHC.Core.FamInstEnv
|
| 26 | 28 | import GHC.Core.DataCon
|
| 27 | 29 | import GHC.Core.Type
|
| 28 | 30 | import GHC.Core.Utils
|
| 29 | -import GHC.Core
|
|
| 31 | +import GHC.Core.Coercion
|
|
| 32 | +import GHC.Core.Reduction
|
|
| 30 | 33 | import GHC.Core.Seq
|
| 34 | +import GHC.Core.TyCon
|
|
| 31 | 35 | import GHC.Core.Opt.WorkWrap.Utils
|
| 32 | 36 | |
| 33 | 37 | import GHC.Data.Graph.UnVar -- for UnVarSet
|
| ... | ... | @@ -216,9 +220,13 @@ cprAnal' _ (Type ty) = (topCprType, Type ty) -- Doesn't happen, in fact |
| 216 | 220 | cprAnal' _ (Coercion co) = (topCprType, Coercion co)
|
| 217 | 221 | |
| 218 | 222 | cprAnal' env (Cast e co)
|
| 219 | - = (cpr_ty, Cast e' co)
|
|
| 223 | + = (cpr_ty', Cast e' co)
|
|
| 220 | 224 | where
|
| 221 | 225 | (cpr_ty, e') = cprAnal env e
|
| 226 | + cpr_ty'
|
|
| 227 | + | cpr_ty == topCprType = topCprType -- cheap case first
|
|
| 228 | + | isRecNewTyConApp env (coercionRKind co) = topCprType -- See Note [CPR for recursive data constructors]
|
|
| 229 | + | otherwise = cpr_ty
|
|
| 222 | 230 | |
| 223 | 231 | cprAnal' env (Tick t e)
|
| 224 | 232 | = (cpr_ty, Tick t e')
|
| ... | ... | @@ -384,6 +392,19 @@ cprTransformDataConWork env con args |
| 384 | 392 | mAX_CPR_SIZE :: Arity
|
| 385 | 393 | mAX_CPR_SIZE = 10
|
| 386 | 394 | |
| 395 | +isRecNewTyConApp :: AnalEnv -> Type -> Bool
|
|
| 396 | +-- See Note [CPR for recursive newtype constructors]
|
|
| 397 | +isRecNewTyConApp env ty
|
|
| 398 | + --- | pprTrace "isRecNewTyConApp" (ppr ty) False = undefined
|
|
| 399 | + | Just (tc, tc_args) <- splitTyConApp_maybe ty =
|
|
| 400 | + if | Just (HetReduction (Reduction _ rhs) _) <- topReduceTyFamApp_maybe (ae_fam_envs env) tc tc_args
|
|
| 401 | + -> isRecNewTyConApp env rhs
|
|
| 402 | + | Just dc <- newTyConDataCon_maybe tc
|
|
| 403 | + -> ae_rec_dc env dc == DefinitelyRecursive
|
|
| 404 | + | otherwise
|
|
| 405 | + -> False
|
|
| 406 | + | otherwise = False
|
|
| 407 | + |
|
| 387 | 408 | --
|
| 388 | 409 | -- * Bindings
|
| 389 | 410 | --
|
| ... | ... | @@ -407,12 +428,18 @@ cprFix orig_env orig_pairs |
| 407 | 428 | | otherwise = orig_pairs
|
| 408 | 429 | init_env = extendSigEnvFromIds orig_env (map fst init_pairs)
|
| 409 | 430 | |
| 431 | + -- If fixed-point iteration does not yield a result we use this instead
|
|
| 432 | + -- See Note [Safe abortion in the fixed-point iteration]
|
|
| 433 | + abort :: (AnalEnv, [(Id,CoreExpr)])
|
|
| 434 | + abort = step (nonVirgin orig_env) [(setIdCprSig id topCprSig, rhs) | (id, rhs) <- orig_pairs ]
|
|
| 435 | + |
|
| 410 | 436 | -- The fixed-point varies the idCprSig field of the binders and and their
|
| 411 | 437 | -- entries in the AnalEnv, and terminates if that annotation does not change
|
| 412 | 438 | -- any more.
|
| 413 | 439 | loop :: Int -> AnalEnv -> [(Id,CoreExpr)] -> (AnalEnv, [(Id,CoreExpr)])
|
| 414 | 440 | loop n env pairs
|
| 415 | 441 | | found_fixpoint = (reset_env', pairs')
|
| 442 | + | n == 10 = pprTraceUserWarning (text "cprFix aborts. This is not terrible, but worth reporting a GHC issue." <+> ppr (map fst pairs)) $ abort
|
|
| 416 | 443 | | otherwise = loop (n+1) env' pairs'
|
| 417 | 444 | where
|
| 418 | 445 | -- In all but the first iteration, delete the virgin flag
|
| ... | ... | @@ -511,8 +538,9 @@ cprAnalBind env id rhs |
| 511 | 538 | -- possibly trim thunk CPR info
|
| 512 | 539 | rhs_ty'
|
| 513 | 540 | -- See Note [CPR for thunks]
|
| 514 | - | stays_thunk = trimCprTy rhs_ty
|
|
| 515 | - | otherwise = rhs_ty
|
|
| 541 | + | rhs_ty == topCprType = topCprType -- cheap case first
|
|
| 542 | + | stays_thunk = trimCprTy rhs_ty
|
|
| 543 | + | otherwise = rhs_ty
|
|
| 516 | 544 | -- See Note [Arity trimming for CPR signatures]
|
| 517 | 545 | sig = mkCprSigForArity (idArity id) rhs_ty'
|
| 518 | 546 | -- See Note [OPAQUE pragma]
|
| ... | ... | @@ -631,7 +659,7 @@ data AnalEnv |
| 631 | 659 | , ae_fam_envs :: FamInstEnvs
|
| 632 | 660 | -- ^ Needed when expanding type families and synonyms of product types.
|
| 633 | 661 | , ae_rec_dc :: DataCon -> IsRecDataConResult
|
| 634 | - -- ^ Memoised result of 'GHC.Core.Opt.WorkWrap.Utils.isRecDataCon'
|
|
| 662 | + -- ^ Memoised result of 'GHC.Core.Opt.WorkWrap.Utils.isRecDataType
|
|
| 635 | 663 | }
|
| 636 | 664 | |
| 637 | 665 | instance Outputable AnalEnv where
|
| ... | ... | @@ -1034,10 +1062,11 @@ Eliminating the shared 'c' binding in the process. And then |
| 1034 | 1062 | |
| 1035 | 1063 | What can we do about it?
|
| 1036 | 1064 | |
| 1037 | - A. Don't CPR functions that return a *recursive data type* (the list in this
|
|
| 1038 | - case). This is the solution we adopt. Rationale: the benefit of CPR on
|
|
| 1039 | - recursive data structures is slight, because it only affects the outer layer
|
|
| 1040 | - of a potentially massive data structure.
|
|
| 1065 | + A. Don't give recursive data constructors or casts representing recursive newtype constructors
|
|
| 1066 | + the CPR property (the list in this case). This is the solution we adopt.
|
|
| 1067 | + Rationale: the benefit of CPR on recursive data structures is slight,
|
|
| 1068 | + because it only affects the outer layer of a potentially massive data
|
|
| 1069 | + structure.
|
|
| 1041 | 1070 | B. Don't CPR any *recursive function*. That would be quite conservative, as it
|
| 1042 | 1071 | would also affect e.g. the factorial function.
|
| 1043 | 1072 | C. Flat CPR only for recursive functions. This prevents the asymptotic
|
| ... | ... | @@ -1047,10 +1076,15 @@ What can we do about it? |
| 1047 | 1076 | `c` in the second eqn of `replicateC`). But we'd need to know which paths
|
| 1048 | 1077 | were hot. We want such static branch frequency estimates in #20378.
|
| 1049 | 1078 | |
| 1050 | -We adopt solution (A) It is ad-hoc, but appears to work reasonably well.
|
|
| 1051 | -Deciding what a "recursive data constructor" is is quite tricky and ad-hoc, too:
|
|
| 1052 | -See Note [Detecting recursive data constructors]. We don't have to be perfect
|
|
| 1053 | -and can simply keep on unboxing if unsure.
|
|
| 1079 | +We adopt solution (A). It is ad-hoc, but appears to work reasonably well.
|
|
| 1080 | +Specifically:
|
|
| 1081 | + |
|
| 1082 | +* For data constructors, in `cprTransformDataConWork` we check for a recursive
|
|
| 1083 | + data constructor by calling `ae_rec_dc env`, which is just a memoised version
|
|
| 1084 | + of `isRecDataCon`. See Note [Detecting recursive data constructors]
|
|
| 1085 | +* For newtypes, in the `Cast` case of `cprAnal`, we check for a recursive newtype
|
|
| 1086 | + by calling `isRecNewTyConApp`, which in turn calls `ae_rec_dc env`.
|
|
| 1087 | + See Note [CPR for recursive newtype constructors]
|
|
| 1054 | 1088 | |
| 1055 | 1089 | Note [Detecting recursive data constructors]
|
| 1056 | 1090 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
| ... | ... | @@ -1067,12 +1101,15 @@ looks inside the following class of types, represented by `ty` (and responds |
| 1067 | 1101 | types of its data constructors and check `tc_args` for recursion.
|
| 1068 | 1102 | C. If `ty = F tc_args`, `F` is a `FamTyCon` and we can reduce `F tc_args` to
|
| 1069 | 1103 | `rhs`, look into the `rhs` type.
|
| 1104 | + D. If `ty = f a`, then look into `f` and `a`
|
|
| 1105 | + E. If `ty = ty' |> co`, then look into `ty'`
|
|
| 1070 | 1106 | |
| 1071 | 1107 | A few perhaps surprising points:
|
| 1072 | 1108 | |
| 1073 | 1109 | 1. It deems any function type as non-recursive, because it's unlikely that
|
| 1074 | 1110 | a recursion through a function type builds up a recursive data structure.
|
| 1075 | - 2. It doesn't look into kinds or coercion types because there's nothing to unbox.
|
|
| 1111 | + 2. It doesn't look into kinds, literals or coercion types because we are
|
|
| 1112 | + ultimately looking for value-level recursion.
|
|
| 1076 | 1113 | Same for promoted data constructors.
|
| 1077 | 1114 | 3. We don't care whether an AlgTyCon app `T tc_args` is fully saturated or not;
|
| 1078 | 1115 | we simply look at its definition/DataCons and its field tys and look for
|
| ... | ... | @@ -1145,6 +1182,22 @@ I've played with the idea to make points (1) through (3) of 'isRecDataCon' |
| 1145 | 1182 | configurable like (4) to enable more re-use throughout the compiler, but haven't
|
| 1146 | 1183 | found a killer app for that yet, so ultimately didn't do that.
|
| 1147 | 1184 | |
| 1185 | +Note [CPR for recursive newtype constructors]
|
|
| 1186 | +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
| 1187 | +A newtype constructor is considered recursive iff the data constructor of the
|
|
| 1188 | +equivalent datatype definition is recursive.
|
|
| 1189 | +See Note [CPR for recursive data constructors].
|
|
| 1190 | +Detection is a bit complicated by the fact that newtype constructor applications
|
|
| 1191 | +reflect as Casts in Core:
|
|
| 1192 | + |
|
| 1193 | + newtype List a = C (Maybe (a, List a))
|
|
| 1194 | + xs = C (Just (0, C Nothing))
|
|
| 1195 | + ==> {desugar to Core}
|
|
| 1196 | + xs = Just (0, Nothing |> sym N:List) |> sym N:List
|
|
| 1197 | + |
|
| 1198 | +So the check for `isRecNewTyConApp` is in the Cast case of `cprAnal` rather than
|
|
| 1199 | +in `cprTransformDataConWork` as for data constructors.
|
|
| 1200 | + |
|
| 1148 | 1201 | Note [CPR examples]
|
| 1149 | 1202 | ~~~~~~~~~~~~~~~~~~~
|
| 1150 | 1203 | Here are some examples (stranal/should_compile/T10482a) of the
|
| ... | ... | @@ -63,6 +63,7 @@ import Data.List ( unzip4 ) |
| 63 | 63 | |
| 64 | 64 | import GHC.Types.RepType
|
| 65 | 65 | import GHC.Unit.Types
|
| 66 | +import GHC.Core.TyCo.Rep
|
|
| 66 | 67 | |
| 67 | 68 | {-
|
| 68 | 69 | ************************************************************************
|
| ... | ... | @@ -1426,23 +1427,29 @@ isRecDataCon fam_envs fuel orig_dc |
| 1426 | 1427 | | arg_ty <- map scaledThing (dataConRepArgTys dc) ]
|
| 1427 | 1428 | |
| 1428 | 1429 | go_arg_ty :: IntWithInf -> TyConSet -> Type -> IsRecDataConResult
|
| 1429 | - go_arg_ty fuel visited_tcs ty
|
|
| 1430 | - --- | pprTrace "arg_ty" (ppr ty) False = undefined
|
|
| 1430 | + go_arg_ty fuel visited_tcs ty = -- pprTrace "arg_ty" (ppr ty) $
|
|
| 1431 | + case coreFullView ty of
|
|
| 1432 | + TyConApp tc tc_args -> go_tc_app fuel visited_tcs tc tc_args
|
|
| 1433 | + -- See Note [Detecting recursive data constructors], points (B) and (C)
|
|
| 1431 | 1434 | |
| 1432 | - | Just (_tcv, ty') <- splitForAllTyCoVar_maybe ty
|
|
| 1433 | - = go_arg_ty fuel visited_tcs ty'
|
|
| 1435 | + ForAllTy _ ty' -> go_arg_ty fuel visited_tcs ty'
|
|
| 1434 | 1436 | -- See Note [Detecting recursive data constructors], point (A)
|
| 1435 | 1437 | |
| 1436 | - | Just (tc, tc_args) <- splitTyConApp_maybe ty
|
|
| 1437 | - = go_tc_app fuel visited_tcs tc tc_args
|
|
| 1438 | + CastTy ty' _ -> go_arg_ty fuel visited_tcs ty'
|
|
| 1438 | 1439 | |
| 1439 | - | otherwise
|
|
| 1440 | - = NonRecursiveOrUnsure
|
|
| 1440 | + AppTy f a -> go_arg_ty fuel visited_tcs f `combineIRDCR` go_arg_ty fuel visited_tcs a
|
|
| 1441 | + -- See Note [Detecting recursive data constructors], point (D)
|
|
| 1442 | + |
|
| 1443 | + FunTy{} -> NonRecursiveOrUnsure
|
|
| 1444 | + -- See Note [Detecting recursive data constructors], point (1)
|
|
| 1445 | + |
|
| 1446 | + -- (TyVarTy{} | LitTy{} | CastTy{})
|
|
| 1447 | + _ -> NonRecursiveOrUnsure
|
|
| 1441 | 1448 | |
| 1442 | 1449 | go_tc_app :: IntWithInf -> TyConSet -> TyCon -> [Type] -> IsRecDataConResult
|
| 1443 | 1450 | go_tc_app fuel visited_tcs tc tc_args =
|
| 1444 | 1451 | case tyConDataCons_maybe tc of
|
| 1445 | - --- | pprTrace "tc_app" (vcat [ppr tc, ppr tc_args]) False = undefined
|
|
| 1452 | + ---_ | pprTrace "tc_app" (vcat [ppr tc, ppr tc_args]) False -> undefined
|
|
| 1446 | 1453 | _ | Just (HetReduction (Reduction _ rhs) _) <- topReduceTyFamApp_maybe fam_envs tc tc_args
|
| 1447 | 1454 | -- This is the only place where we look at tc_args, which might have
|
| 1448 | 1455 | -- See Note [Detecting recursive data constructors], point (C) and (5)
|
| ... | ... | @@ -276,7 +276,7 @@ instance Diagnostic DriverMessage where |
| 276 | 276 | ++ llvmVersionStr supportedLlvmVersionLowerBound
|
| 277 | 277 | ++ " and "
|
| 278 | 278 | ++ llvmVersionStr supportedLlvmVersionUpperBound
|
| 279 | - ++ ") and reinstall GHC to make -fllvm work")
|
|
| 279 | + ++ ") and reinstall GHC to ensure -fllvm works")
|
|
| 280 | 280 | |
| 281 | 281 | diagnosticReason = \case
|
| 282 | 282 | DriverUnknownMessage m
|
| ... | ... | @@ -347,7 +347,7 @@ instance Diagnostic DriverMessage where |
| 347 | 347 | DriverInstantiationNodeInDependencyGeneration {}
|
| 348 | 348 | -> ErrorWithoutFlag
|
| 349 | 349 | DriverNoConfiguredLLVMToolchain
|
| 350 | - -> ErrorWithoutFlag
|
|
| 350 | + -> WarningWithoutFlag
|
|
| 351 | 351 | |
| 352 | 352 | diagnosticHints = \case
|
| 353 | 353 | DriverUnknownMessage m
|
| ... | ... | @@ -193,12 +193,8 @@ zonkEqTypes ev eq_rel ty1 ty2 |
| 193 | 193 | then tycon tc1 tys1 tys2
|
| 194 | 194 | else bale_out ty1 ty2
|
| 195 | 195 | |
| 196 | - go ty1 ty2
|
|
| 197 | - | Just (ty1a, ty1b) <- tcSplitAppTyNoView_maybe ty1
|
|
| 198 | - , Just (ty2a, ty2b) <- tcSplitAppTyNoView_maybe ty2
|
|
| 199 | - = do { res_a <- go ty1a ty2a
|
|
| 200 | - ; res_b <- go ty1b ty2b
|
|
| 201 | - ; return $ combine_rev mkAppTy res_b res_a }
|
|
| 196 | + -- If you are temppted to add a case for AppTy/AppTy, be careful
|
|
| 197 | + -- See Note [zonkEqTypes and the PKTI]
|
|
| 202 | 198 | |
| 203 | 199 | go ty1@(LitTy lit1) (LitTy lit2)
|
| 204 | 200 | | lit1 == lit2
|
| ... | ... | @@ -274,6 +270,32 @@ zonkEqTypes ev eq_rel ty1 ty2 |
| 274 | 270 | combine_rev f (Right tys) (Right ty) = Right (f ty tys)
|
| 275 | 271 | |
| 276 | 272 | |
| 273 | +{- Note [zonkEqTypes and the PKTI]
|
|
| 274 | +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
| 275 | +Because `zonkEqTypes` does /partial/ zonking, we need to be very careful
|
|
| 276 | +to maintain the Purely Kinded Type Invariant: see GHC.Tc.Gen/HsType
|
|
| 277 | +HsNote [The Purely Kinded Type Invariant (PKTI)].
|
|
| 278 | + |
|
| 279 | +In #26256 we try to solve this equality constraint:
|
|
| 280 | + Int :-> Maybe Char ~# k0 Int (m0 Char)
|
|
| 281 | +where m0 and k0 are unification variables, and
|
|
| 282 | + m0 :: Type -> Type
|
|
| 283 | +It happens that m0 was already unified
|
|
| 284 | + m0 := (w0 :: kappa)
|
|
| 285 | +where kappa is another unification variable that is also already unified:
|
|
| 286 | + kappa := Type->Type.
|
|
| 287 | +So the original type satisifed the PKTI, but a partially-zonked form
|
|
| 288 | + k0 Int (w0 Char)
|
|
| 289 | +does not!! (This a bit reminiscent of Note [mkAppTyM].)
|
|
| 290 | + |
|
| 291 | +The solution I have adopted is simply to make `zonkEqTypes` bale out on `AppTy`.
|
|
| 292 | +After all, it's only supposed to be a quick hack to see if two types are already
|
|
| 293 | +equal; if we bale out we'll just get into the "proper" canonicaliser.
|
|
| 294 | + |
|
| 295 | +The only tricky thing about this approach is that it relies on /omitting/
|
|
| 296 | +code -- for the AppTy/AppTy case! Hence this Note
|
|
| 297 | +-}
|
|
| 298 | + |
|
| 277 | 299 | {- *********************************************************************
|
| 278 | 300 | * *
|
| 279 | 301 | * canonicaliseEquality
|
| ... | ... | @@ -351,15 +351,23 @@ fi |
| 351 | 351 | |
| 352 | 352 | dnl ** Building a cross compiler?
|
| 353 | 353 | dnl --------------------------------------------------------------
|
| 354 | -CrossCompiling=NO
|
|
| 355 | -# If 'host' and 'target' differ, then this means we are building a cross-compiler.
|
|
| 356 | -if test "$target" != "$host" ; then
|
|
| 357 | - CrossCompiling=YES
|
|
| 358 | - cross_compiling=yes # This tells configure that it can accept just 'target',
|
|
| 359 | - # otherwise you get
|
|
| 360 | - # configure: error: cannot run C compiled programs.
|
|
| 361 | - # If you meant to cross compile, use `--host'.
|
|
| 354 | +dnl We allow the user to override this since the target/host check
|
|
| 355 | +dnl can get this wrong in some particular cases. See #26236.
|
|
| 356 | +if test -z "$CrossCompiling" ; then
|
|
| 357 | + CrossCompiling=NO
|
|
| 358 | + # If 'host' and 'target' differ, then this means we are building a cross-compiler.
|
|
| 359 | + if test "$target" != "$host" ; then
|
|
| 360 | + CrossCompiling=YES
|
|
| 361 | + fi
|
|
| 362 | +fi
|
|
| 363 | +if test "$CrossCompiling" = "YES"; then
|
|
| 364 | + # This tells configure that it can accept just 'target',
|
|
| 365 | + # otherwise you get
|
|
| 366 | + # configure: error: cannot run C compiled programs.
|
|
| 367 | + # If you meant to cross compile, use `--host'.
|
|
| 368 | + cross_compiling=yes
|
|
| 362 | 369 | fi
|
| 370 | + |
|
| 363 | 371 | if test "$BuildPlatform" != "$HostPlatform" ; then
|
| 364 | 372 | AC_MSG_ERROR([
|
| 365 | 373 | You've selected:
|
| 1 | 1 | # Changelog for [`base` package](http://hackage.haskell.org/package/base)
|
| 2 | 2 | |
| 3 | +## 4.21.2.0 *Sept 2024*
|
|
| 4 | + * Fix bug where `naturalAndNot` was incorrectly truncating results ([CLC proposal #350](github.com/haskell/core-libraries-committee/issues/350))
|
|
| 5 | + |
|
| 3 | 6 | ## 4.21.1.0 *Sept 2024*
|
| 4 | 7 | * Fix incorrect results of `integerPowMod` when the base is 0 and the exponent is negative, and `integerRecipMod` when the modulus is zero ([#26017](https://gitlab.haskell.org/ghc/ghc/-/issues/26017)).
|
| 5 | 8 |
| ... | ... | @@ -4,6 +4,7 @@ |
| 4 | 4 | |
| 5 | 5 | - Expose backendName
|
| 6 | 6 | - Add `naturalSetBit[#]` (#21173), `naturalClearBit[#]` (#21175), `naturalComplementBit[#]` (#21181)
|
| 7 | +- Fix bug where `naturalAndNot` was incorrectly truncating results (#26230)
|
|
| 7 | 8 | |
| 8 | 9 | ## 1.2
|
| 9 | 10 |
| ... | ... | @@ -488,7 +488,7 @@ naturalAndNot :: Natural -> Natural -> Natural |
| 488 | 488 | {-# NOINLINE naturalAndNot #-}
|
| 489 | 489 | naturalAndNot (NS n) (NS m) = NS (n `and#` not# m)
|
| 490 | 490 | naturalAndNot (NS n) (NB m) = NS (n `and#` not# (bigNatToWord# m))
|
| 491 | -naturalAndNot (NB n) (NS m) = NS (bigNatToWord# n `and#` not# m)
|
|
| 491 | +naturalAndNot (NB n) (NS m) = NB (bigNatAndNotWord# n m)
|
|
| 492 | 492 | naturalAndNot (NB n) (NB m) = naturalFromBigNat# (bigNatAndNot n m)
|
| 493 | 493 | |
| 494 | 494 | naturalOr :: Natural -> Natural -> Natural
|
| ... | ... | @@ -180,13 +180,22 @@ uint32_t messageBlackHole(Capability *cap, MessageBlackHole *msg) |
| 180 | 180 | bh_info != &stg_CAF_BLACKHOLE_info &&
|
| 181 | 181 | bh_info != &__stg_EAGER_BLACKHOLE_info &&
|
| 182 | 182 | bh_info != &stg_WHITEHOLE_info) {
|
| 183 | - // if it is a WHITEHOLE, then a thread is in the process of
|
|
| 184 | - // trying to BLACKHOLE it. But we know that it was once a
|
|
| 185 | - // BLACKHOLE, so there is at least a valid pointer in the
|
|
| 186 | - // payload, so we can carry on.
|
|
| 187 | 183 | return 0;
|
| 188 | 184 | }
|
| 189 | 185 | |
| 186 | + // If we see a WHITEHOLE then we should wait for it to turn into a BLACKHOLE.
|
|
| 187 | + // Otherwise we might look at the indirectee and segfault.
|
|
| 188 | + // See "Exception handling" in Note [Thunks, blackholes, and indirections]
|
|
| 189 | + // We might be looking at a *fresh* THUNK being WHITEHOLE-d so we can't
|
|
| 190 | + // guarantee that the indirectee is a valid pointer.
|
|
| 191 | +#if defined(THREADED_RTS)
|
|
| 192 | + if (bh_info == &stg_WHITEHOLE_info) {
|
|
| 193 | + while(ACQUIRE_LOAD(&bh->header.info) == &stg_WHITEHOLE_info) {
|
|
| 194 | + busy_wait_nop();
|
|
| 195 | + }
|
|
| 196 | + }
|
|
| 197 | +#endif
|
|
| 198 | + |
|
| 190 | 199 | // The blackhole must indirect to a TSO, a BLOCKING_QUEUE, an IND,
|
| 191 | 200 | // or a value.
|
| 192 | 201 | StgClosure *p;
|
| ... | ... | @@ -31,6 +31,7 @@ import CLOSURE ENT_VIA_NODE_ctr; |
| 31 | 31 | import CLOSURE RtsFlags;
|
| 32 | 32 | import CLOSURE stg_BLOCKING_QUEUE_CLEAN_info;
|
| 33 | 33 | import CLOSURE stg_BLOCKING_QUEUE_DIRTY_info;
|
| 34 | +import CLOSURE stg_END_TSO_QUEUE_closure;
|
|
| 34 | 35 | import CLOSURE stg_IND_info;
|
| 35 | 36 | import CLOSURE stg_MSG_BLACKHOLE_info;
|
| 36 | 37 | import CLOSURE stg_TSO_info;
|
| ... | ... | @@ -574,6 +575,9 @@ retry: |
| 574 | 575 | |
| 575 | 576 | MessageBlackHole_tso(msg) = CurrentTSO;
|
| 576 | 577 | MessageBlackHole_bh(msg) = node;
|
| 578 | + // Ensure that the link field is a valid closure,
|
|
| 579 | + // since we might turn this into an indirection in wakeBlockingQueue()
|
|
| 580 | + MessageBlackHole_link(msg) = stg_END_TSO_QUEUE_closure;
|
|
| 577 | 581 | SET_HDR(msg, stg_MSG_BLACKHOLE_info, CCS_SYSTEM);
|
| 578 | 582 | // messageBlackHole has appropriate memory barriers when this object is exposed.
|
| 579 | 583 | // See Note [Heap memory barriers].
|
| ... | ... | @@ -333,6 +333,10 @@ |
| 333 | 333 | * `AP_STACK` closure recording the aborted execution state.
|
| 334 | 334 | * See `RaiseAsync.c:raiseAsync` for details.
|
| 335 | 335 | *
|
| 336 | + * This can combine with indirection shortcutting during GC to replace a BLACKHOLE
|
|
| 337 | + * with a fresh THUNK. We should be very careful here since the THUNK will have an
|
|
| 338 | + * undefined value in the indirectee field. Looking at the indirectee field can then
|
|
| 339 | + * lead to a segfault such as #26205.
|
|
| 336 | 340 | *
|
| 337 | 341 | * CAFs
|
| 338 | 342 | * ----
|
| 1 | +{-# LANGUAGE UndecidableInstances, LambdaCase #-}
|
|
| 2 | + |
|
| 3 | +-- | This file starts with a small reproducer for #25944 that is easy to debug
|
|
| 4 | +-- and then continues with a much larger MWE that is faithful to the original
|
|
| 5 | +-- issue.
|
|
| 6 | +module T25944 (foo, bar, popMinOneT, popMinOne) where
|
|
| 7 | + |
|
| 8 | +import Data.Functor.Identity ( Identity(..) )
|
|
| 9 | +import Data.Coerce
|
|
| 10 | + |
|
| 11 | +data ListCons a b = Nil | a :- !b
|
|
| 12 | +newtype Fix f = Fix (f (Fix f)) -- Rec
|
|
| 13 | + |
|
| 14 | +foo :: Fix (ListCons a) -> Fix (ListCons a) -> Fix (ListCons a)
|
|
| 15 | +foo a b = go a
|
|
| 16 | + where
|
|
| 17 | + -- The outer loop arranges it so that the base case `go as` of `go2` is
|
|
| 18 | + -- bottom on the first iteration of the loop.
|
|
| 19 | + go (Fix Nil) = Fix Nil
|
|
| 20 | + go (Fix (a :- as)) = Fix (a :- go2 b)
|
|
| 21 | + where
|
|
| 22 | + go2 (Fix Nil) = go as
|
|
| 23 | + go2 (Fix (b :- bs)) = Fix (b :- go2 bs)
|
|
| 24 | + |
|
| 25 | +bar :: Int -> (Fix (ListCons Int), Int)
|
|
| 26 | +bar n = (foo (Fix Nil) (Fix Nil), n) -- should still have CPR property
|
|
| 27 | + |
|
| 28 | +-- Now the actual reproducer from #25944:
|
|
| 29 | + |
|
| 30 | +newtype ListT m a = ListT { runListT :: m (ListCons a (ListT m a)) }
|
|
| 31 | + |
|
| 32 | +cons :: Applicative m => a -> ListT m a -> ListT m a
|
|
| 33 | +cons x xs = ListT (pure (x :- xs))
|
|
| 34 | + |
|
| 35 | +nil :: Applicative m => ListT m a
|
|
| 36 | +nil = ListT (pure Nil)
|
|
| 37 | + |
|
| 38 | +instance Functor m => Functor (ListT m) where
|
|
| 39 | + fmap f (ListT m) = ListT (go <$> m)
|
|
| 40 | + where
|
|
| 41 | + go Nil = Nil
|
|
| 42 | + go (a :- m) = f a :- (f <$> m)
|
|
| 43 | + |
|
| 44 | +foldListT :: ((ListCons a (ListT m a) -> c) -> m (ListCons a (ListT m a)) -> b)
|
|
| 45 | + -> (a -> b -> c)
|
|
| 46 | + -> c
|
|
| 47 | + -> ListT m a -> b
|
|
| 48 | +foldListT r c n = r h . runListT
|
|
| 49 | + where
|
|
| 50 | + h Nil = n
|
|
| 51 | + h (x :- ListT xs) = c x (r h xs)
|
|
| 52 | +{-# INLINE foldListT #-}
|
|
| 53 | + |
|
| 54 | +mapListT :: forall a m b. Monad m => (a -> ListT m b -> ListT m b) -> ListT m b -> ListT m a -> ListT m b
|
|
| 55 | +mapListT =
|
|
| 56 | + foldListT
|
|
| 57 | + ((coerce ::
|
|
| 58 | + ((ListCons a (ListT m a) -> m (ListCons b (ListT m b))) -> m (ListCons a (ListT m a)) -> m (ListCons b (ListT m b))) ->
|
|
| 59 | + ((ListCons a (ListT m a) -> ListT m b) -> m (ListCons a (ListT m a)) -> ListT m b))
|
|
| 60 | + (=<<))
|
|
| 61 | +{-# INLINE mapListT #-}
|
|
| 62 | + |
|
| 63 | +instance Monad m => Applicative (ListT m) where
|
|
| 64 | + pure x = cons x nil
|
|
| 65 | + {-# INLINE pure #-}
|
|
| 66 | + liftA2 f xs ys = mapListT (\x zs -> mapListT (cons . f x) zs ys) nil xs
|
|
| 67 | + {-# INLINE liftA2 #-}
|
|
| 68 | + |
|
| 69 | +instance Monad m => Monad (ListT m) where
|
|
| 70 | + xs >>= f = mapListT (flip (mapListT cons) . f) nil xs
|
|
| 71 | + {-# INLINE (>>=) #-}
|
|
| 72 | + |
|
| 73 | +infixr 5 :<
|
|
| 74 | +data Node w a b = Leaf a | !w :< b
|
|
| 75 | + deriving (Functor)
|
|
| 76 | + |
|
| 77 | +bimapNode f g (Leaf x) = Leaf (f x)
|
|
| 78 | +bimapNode f g (x :< xs) = x :< g xs
|
|
| 79 | + |
|
| 80 | +newtype HeapT w m a = HeapT { runHeapT :: ListT m (Node w a (HeapT w m a)) }
|
|
| 81 | + |
|
| 82 | +-- | The 'Heap' type, specialised to the 'Identity' monad.
|
|
| 83 | +type Heap w = HeapT w Identity
|
|
| 84 | + |
|
| 85 | +instance Functor m => Functor (HeapT w m) where
|
|
| 86 | + fmap f = HeapT . fmap (bimapNode f (fmap f)) . runHeapT
|
|
| 87 | + |
|
| 88 | +instance Monad m => Applicative (HeapT w m) where
|
|
| 89 | + pure = HeapT . pure . Leaf
|
|
| 90 | + (<*>) = liftA2 id
|
|
| 91 | + |
|
| 92 | +instance Monad m => Monad (HeapT w m) where
|
|
| 93 | + HeapT m >>= f = HeapT (m >>= g)
|
|
| 94 | + where
|
|
| 95 | + g (Leaf x) = runHeapT (f x)
|
|
| 96 | + g (w :< xs) = pure (w :< (xs >>= f))
|
|
| 97 | + |
|
| 98 | +popMinOneT :: forall w m a. (Monoid w, Monad m) => HeapT w m a -> m (Maybe ((a, w), HeapT w m a))
|
|
| 99 | +popMinOneT = go mempty [] . runHeapT
|
|
| 100 | + where
|
|
| 101 | + go' :: w -> Maybe (w, HeapT w m a) -> m (Maybe ((a, w), HeapT w m a))
|
|
| 102 | + go' a Nothing = pure Nothing
|
|
| 103 | + go' a (Just (w, HeapT xs)) = go (a <> w) [] xs
|
|
| 104 | + |
|
| 105 | + go :: w -> [(w, HeapT w m a)] -> ListT m (Node w a (HeapT w m a)) -> m (Maybe ((a, w), HeapT w m a))
|
|
| 106 | + go w a (ListT xs) = xs >>= \case
|
|
| 107 | + Nil -> go' w (undefined)
|
|
| 108 | + Leaf x :- xs -> pure (Just ((x, w), undefined >> HeapT (foldl (\ys (yw,y) -> ListT (pure ((yw :< y) :- ys))) xs a)))
|
|
| 109 | + (u :< x) :- xs -> go w ((u,x) : a) xs
|
|
| 110 | +{-# INLINE popMinOneT #-}
|
|
| 111 | + |
|
| 112 | +popMinOne :: Monoid w => Heap w a -> Maybe ((a, w), Heap w a)
|
|
| 113 | +popMinOne = runIdentity . popMinOneT
|
|
| 114 | +{-# INLINE popMinOne #-} |
| 1 | + |
|
| 2 | +==================== Cpr signatures ====================
|
|
| 3 | +T25944.$fApplicativeHeapT:
|
|
| 4 | +T25944.$fApplicativeListT:
|
|
| 5 | +T25944.$fFunctorHeapT:
|
|
| 6 | +T25944.$fFunctorListT:
|
|
| 7 | +T25944.$fFunctorNode:
|
|
| 8 | +T25944.$fMonadHeapT:
|
|
| 9 | +T25944.$fMonadListT:
|
|
| 10 | +T25944.bar: 1
|
|
| 11 | +T25944.foo:
|
|
| 12 | +T25944.popMinOne: 2(1(1,))
|
|
| 13 | +T25944.popMinOneT:
|
|
| 14 | +T25944.runHeapT:
|
|
| 15 | +T25944.runListT:
|
|
| 16 | + |
|
| 17 | + |
| ... | ... | @@ -12,3 +12,4 @@ test('T16040', normal, compile, ['']) |
| 12 | 12 | test('T19232', normal, compile, [''])
|
| 13 | 13 | test('T19398', normal, compile, [''])
|
| 14 | 14 | test('T19822', normal, compile, [''])
|
| 15 | +test('T25944', normal, compile, ['']) |
| 1 | +import Data.Bits
|
|
| 2 | +import GHC.Num.Natural
|
|
| 3 | + |
|
| 4 | +main = do
|
|
| 5 | + print $ naturalAndNot ((2 ^ 4) .|. (2 ^ 3)) (2 ^ 3)
|
|
| 6 | + print $ naturalAndNot ((2 ^ 129) .|. (2 ^ 65)) (2 ^ 65)
|
|
| 7 | + print $ naturalAndNot ((2 ^ 4) .|. (2 ^ 3)) ((2 ^ 65) .|. (2 ^ 3))
|
|
| 8 | + print $ naturalAndNot ((2 ^ 65) .|. (2 ^ 3)) (2 ^ 3) |
| 1 | +16
|
|
| 2 | +680564733841876926926749214863536422912
|
|
| 3 | +16
|
|
| 4 | +36893488147419103232 |
| ... | ... | @@ -87,3 +87,4 @@ test('T24066', normal, compile_and_run, ['']) |
| 87 | 87 | test('div01', normal, compile_and_run, [''])
|
| 88 | 88 | test('T24245', normal, compile_and_run, [''])
|
| 89 | 89 | test('T25653', normal, compile_and_run, [''])
|
| 90 | +test('T26230', normal, compile_and_run, ['']) |
| 1 | +{-# LANGUAGE GHC2021 #-}
|
|
| 2 | +{-# LANGUAGE TypeFamilies #-}
|
|
| 3 | +{-# LANGUAGE PartialTypeSignatures #-}
|
|
| 4 | + |
|
| 5 | +module M (go) where
|
|
| 6 | + |
|
| 7 | +import Data.Kind
|
|
| 8 | + |
|
| 9 | +type Apply :: (Type -> Type) -> Type
|
|
| 10 | +data Apply m
|
|
| 11 | + |
|
| 12 | +type (:->) :: Type -> Type -> Type
|
|
| 13 | +type family (:->) where (:->) = (->)
|
|
| 14 | + |
|
| 15 | +f :: forall (k :: Type -> Type -> Type) (m :: Type -> Type).
|
|
| 16 | + k Int (m Char) -> k Bool (Apply m)
|
|
| 17 | +f = f
|
|
| 18 | + |
|
| 19 | +x :: Int :-> Maybe Char
|
|
| 20 | +x = x
|
|
| 21 | + |
|
| 22 | +go :: Bool -> _ _
|
|
| 23 | +go = f x |
| 1 | +T26256.hs:22:15: warning: [GHC-88464] [-Wpartial-type-signatures (in -Wdefault)]
|
|
| 2 | + • Found type wildcard ‘_’ standing for ‘Apply :: (* -> *) -> *’
|
|
| 3 | + • In the type signature: go :: Bool -> _ _
|
|
| 4 | + |
|
| 5 | +T26256.hs:22:17: warning: [GHC-88464] [-Wpartial-type-signatures (in -Wdefault)]
|
|
| 6 | + • Found type wildcard ‘_’ standing for ‘Maybe :: * -> *’
|
|
| 7 | + • In the first argument of ‘_’, namely ‘_’
|
|
| 8 | + In the type signature: go :: Bool -> _ _ |
| ... | ... | @@ -108,3 +108,4 @@ test('T21667', normal, compile, ['']) |
| 108 | 108 | test('T22065', normal, compile, [''])
|
| 109 | 109 | test('T16152', normal, compile, [''])
|
| 110 | 110 | test('T20076', expect_broken(20076), compile, [''])
|
| 111 | +test('T26256', normal, compile, ['']) |
| 1 | +{-# LANGUAGE GHC2021 #-}
|
|
| 2 | +{-# LANGUAGE TypeFamilies #-}
|
|
| 3 | + |
|
| 4 | +module T26256 (go) where
|
|
| 5 | + |
|
| 6 | +import Data.Kind
|
|
| 7 | + |
|
| 8 | +class Cat k where (<<<) :: k a b -> k x a -> k x b
|
|
| 9 | +instance Cat (->) where (<<<) = (.)
|
|
| 10 | +class Pro k p where pro :: k a b s t -> p a b -> p s t
|
|
| 11 | +data Hiding o a b s t = forall e. Hiding (s -> o e a)
|
|
| 12 | +newtype Apply e a = Apply (e a)
|
|
| 13 | + |
|
| 14 | +type (:->) :: Type -> Type -> Type
|
|
| 15 | +type family (:->) where
|
|
| 16 | + (:->) = (->)
|
|
| 17 | + |
|
| 18 | +go :: (Pro (Hiding Apply) p) => (s :-> e a) -> p a b -> p s t
|
|
| 19 | +go sea = pro (Hiding (Apply <<< sea)) |
| ... | ... | @@ -935,3 +935,4 @@ test('T24845a', normal, compile, ['']) |
| 935 | 935 | test('T23501a', normal, compile, [''])
|
| 936 | 936 | test('T23501b', normal, compile, [''])
|
| 937 | 937 | test('T25597', normal, compile, [''])
|
| 938 | +test('T26256a', normal, compile, ['']) |