diff options
author | Simon Peyton Jones <simonpj@microsoft.com> | 2022-06-29 16:43:36 +0100 |
---|---|---|
committer | Zubin <zubin.duggal@gmail.com> | 2022-07-12 13:26:52 +0000 |
commit | 6e8d90560b4a9269c56f7c1ee4d29d1077680f7b (patch) | |
tree | 1de4f2a15e6de26e7e0a65f350d88cedb370df82 | |
parent | 460505345e500eb902da9737c75c077d5fc5ef66 (diff) | |
download | haskell-6e8d90560b4a9269c56f7c1ee4d29d1077680f7b.tar.gz |
Edit Note [idArity varies independently of dmdTypeDepth]
...and refer to it in GHC.Core.Lint.lintLetBind.
Fixes #21452
-rw-r--r-- | compiler/GHC/Core/Lint.hs | 15 | ||||
-rw-r--r-- | compiler/GHC/Core/Opt/DmdAnal.hs | 32 | ||||
-rw-r--r-- | compiler/GHC/Core/Opt/Simplify.hs | 6 | ||||
-rw-r--r-- | compiler/GHC/Types/Id/Info.hs | 5 |
4 files changed, 34 insertions, 24 deletions
diff --git a/compiler/GHC/Core/Lint.hs b/compiler/GHC/Core/Lint.hs index 7486086406..00636ec444 100644 --- a/compiler/GHC/Core/Lint.hs +++ b/compiler/GHC/Core/Lint.hs @@ -640,7 +640,8 @@ lintLetBind top_lvl rec_flag binder rhs rhs_ty ppr (typeArity (idType binder)) <> colon <+> ppr binder) - -- See Note [Check arity on bottoming functions] + -- See Note [idArity varies independently of dmdTypeDepth] + -- in GHC.Core.Opt.DmdAnal ; case splitDmdSig (idDmdSig binder) of (demands, result_info) | isDeadEndDiv result_info -> checkL (demands `lengthAtLeast` idArity binder) @@ -648,6 +649,7 @@ lintLetBind top_lvl rec_flag binder rhs rhs_ty text "exceeds arity imposed by the strictness signature" <+> ppr (idDmdSig binder) <> colon <+> ppr binder) + _ -> return () ; addLoc (RuleOf binder) $ mapM_ (lintCoreRule binder binder_ty) (idCoreRules binder) @@ -724,15 +726,8 @@ lintIdUnfolding _ _ _ = return () -- Do not Lint unstable unfoldings, because that leads -- to exponential behaviour; c.f. GHC.Core.FVs.idUnfoldingVars -{- -Note [Check arity on bottoming functions] -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -If a function has a strictness signature like [S]b, it claims to -return bottom when applied to one argument. So its arity should not -be greater than 1! We check this claim in Lint. - -Note [Checking for INLINE loop breakers] -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +{- Note [Checking for INLINE loop breakers] +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ It's very suspicious if a strong loop breaker is marked INLINE. However, the desugarer generates instance methods with INLINE pragmas diff --git a/compiler/GHC/Core/Opt/DmdAnal.hs b/compiler/GHC/Core/Opt/DmdAnal.hs index 59d18fefaf..d41b97ac87 100644 --- a/compiler/GHC/Core/Opt/DmdAnal.hs +++ b/compiler/GHC/Core/Opt/DmdAnal.hs @@ -1177,18 +1177,27 @@ complexity. Note [idArity varies independently of dmdTypeDepth] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +In general, an Id `f` has two independently varying attributes: + +* f's idArity, and +* the dmdTypeDepth of f's demand signature + +For example, if f's demand signature is <L><L>, f's arity could be +greater than, or less than 2. Why? Because both are conservative +approximations: + +* Arity n means "does no work until applied to at least n args" + (e.g. (f x1..xm) is cheap to bring to HNF for m<n) + +* Dmd sig with n args means "here is how to transform the incoming demand + when applied to n args". This is /semantic/ property, unrelated to + arity. See GHC.Types.Demand Note [Understanding DmdType and DmdSig] + We used to check in GHC.Core.Lint that dmdTypeDepth <= idArity for a let-bound identifier. But that means we would have to zap demand signatures every time we -reset or decrease arity. That's an unnecessary dependency, because - - * The demand signature captures a semantic property that is independent of - what the binding's current arity is - * idArity is analysis information itself, thus volatile - * We already *have* dmdTypeDepth, wo why not just use it to encode the - threshold for when to unleash the signature - (cf. Note [Understanding DmdType and DmdSig] in GHC.Types.Demand) +reset or decrease arity. -Consider the following expression, for example: +For example, consider the following expression, for example: (let go x y = `x` seq ... in go) |> co @@ -1201,6 +1210,11 @@ coercion into the binding, leading to an arity decrease: With the CoreLint check, we would have to zap `go`'s perfectly viable strictness signature. +However, in the case of a /bottoming/ signature, f : <L><L>b, we /can/ +say that f's arity is no greater than 2, because it'd be false to say +that f does no work when applied to 3 args. Lint checks this constraint, +in `GHC.Core.Lint.lintLetBind`. + Note [Demand analysis for trivial right-hand sides] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Consider diff --git a/compiler/GHC/Core/Opt/Simplify.hs b/compiler/GHC/Core/Opt/Simplify.hs index d26fd28de2..0f842be2d3 100644 --- a/compiler/GHC/Core/Opt/Simplify.hs +++ b/compiler/GHC/Core/Opt/Simplify.hs @@ -1025,9 +1025,9 @@ to eta-expand to in ...(f a b c)... But now f's strictness signature has too short an arity; see -GHC.Core.Lint Note [Check arity on bottoming functions]. -Fortuitously, the same strictness-signature-fixup code gives the -function a new strictness signature with the right number of +GHC.Core.Opt.DmdAnal Note [idArity varies independently of dmdTypeDepth]. +Fortuitously, the same strictness-signature-fixup code +gives the function a new strictness signature with the right number of arguments. Example in stranal/should_compile/EtaExpansion. Note [Setting the demand info] diff --git a/compiler/GHC/Types/Id/Info.hs b/compiler/GHC/Types/Id/Info.hs index 5834fa8b06..a35845f612 100644 --- a/compiler/GHC/Types/Id/Info.hs +++ b/compiler/GHC/Types/Id/Info.hs @@ -353,8 +353,9 @@ data IdInfo occInfo :: OccInfo, -- ^ How the 'Id' occurs in the program dmdSigInfo :: DmdSig, - -- ^ A strictness signature. Digests how a function uses its arguments - -- if applied to at least 'arityInfo' arguments. + -- ^ A strictness signature. Describes how a function uses its arguments + -- See Note [idArity varies independently of dmdTypeDepth] + -- in GHC.Core.Opt.DmdAnal cprSigInfo :: CprSig, -- ^ Information on whether the function will ultimately return a -- freshly allocated constructor. |