diff options
| author | simonpj@microsoft.com <unknown> | 2010-10-07 10:27:20 +0000 |
|---|---|---|
| committer | simonpj@microsoft.com <unknown> | 2010-10-07 10:27:20 +0000 |
| commit | 5c248c7dfa9b789df31ca5186c4f181f1e8eb42b (patch) | |
| tree | a1b7d1166cb55e53eec32dd85583f437dfdd262f /compiler | |
| parent | fb982282ff6307b342d8fbc09b58a990d76c68fb (diff) | |
| download | haskell-5c248c7dfa9b789df31ca5186c4f181f1e8eb42b.tar.gz | |
Fix Trac #4345: simplifier bug
This is another long-standing bug, in which there was a possibility
that a loop-breaker could lose its loop-breaker-hood OccInfo,
and then the simplifer re-simplified the expression. Result, either
non-termination or, in the case of #4345, an unbound identifier.
The fix is very simple, in Id.transferPolyIdInfo.
See Note [transferPolyIdInfo].
Diffstat (limited to 'compiler')
| -rw-r--r-- | compiler/basicTypes/Id.lhs | 33 |
1 files changed, 25 insertions, 8 deletions
diff --git a/compiler/basicTypes/Id.lhs b/compiler/basicTypes/Id.lhs index 1efc2732a7..36406939a8 100644 --- a/compiler/basicTypes/Id.lhs +++ b/compiler/basicTypes/Id.lhs @@ -654,29 +654,44 @@ zapFragileIdInfo = zapInfo zapFragileInfo Note [transferPolyIdInfo] ~~~~~~~~~~~~~~~~~~~~~~~~~ -Suppose we have +This transfer is used in two places: + FloatOut (long-distance let-floating) + SimplUtils.abstractFloats (short-distance let-floating) + +Consider the short-distance let-floating: f = /\a. let g = rhs in ... -where g has interesting strictness information. Then if we float thus +Then if we float thus g' = /\a. rhs - f = /\a. ...[g' a/g] + f = /\a. ...[g' a/g].... we *do not* want to lose g's * strictness information * arity * inline pragma (though that is bit more debatable) + * occurrence info + +Mostly this is just an optimisation, but it's *vital* to +transfer the occurrence info. Consider + + NonRec { f = /\a. let Rec { g* = ..g.. } in ... } + +where the '*' means 'LoopBreaker'. Then if we float we must get -It's simple to retain strictness and arity, but not so simple to retain + Rec { g'* = /\a. ...(g' a)... } + NonRec { f = /\a. ...[g' a/g]....} + +where g' is also marked as LoopBreaker. If not, terrible things +can happen if we re-simplify the binding (and the Simplifier does +sometimes simplify a term twice); see Trac #4345. + +It's not so simple to retain * worker info * rules so we simply discard those. Sooner or later this may bite us. -This transfer is used in two places: - FloatOut (long-distance let-floating) - SimplUtils.abstractFloats (short-distance let-floating) - If we abstract wrt one or more *value* binders, we must modify the arity and strictness info before transferring it. E.g. f = \x. e @@ -699,6 +714,7 @@ transferPolyIdInfo old_id abstract_wrt new_id old_info = idInfo old_id old_arity = arityInfo old_info old_inline_prag = inlinePragInfo old_info + old_occ_info = occInfo old_info new_arity = old_arity + arity_increase old_strictness = strictnessInfo old_info new_strictness = fmap (increaseStrictSigArity arity_increase) old_strictness @@ -706,4 +722,5 @@ transferPolyIdInfo old_id abstract_wrt new_id transfer new_info = new_info `setStrictnessInfo` new_strictness `setArityInfo` new_arity `setInlinePragInfo` old_inline_prag + `setOccInfo` old_occ_info \end{code} |
