From 5c248c7dfa9b789df31ca5186c4f181f1e8eb42b Mon Sep 17 00:00:00 2001 From: "simonpj@microsoft.com" Date: Thu, 7 Oct 2010 10:27:20 +0000 Subject: [PATCH] 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]. --- compiler/basicTypes/Id.lhs | 33 +++++++++++++++++++++++++-------- 1 file changed, 25 insertions(+), 8 deletions(-) diff --git a/compiler/basicTypes/Id.lhs b/compiler/basicTypes/Id.lhs index 1efc273..3640693 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} -- 1.7.10.4