summaryrefslogtreecommitdiff
path: root/compiler
diff options
context:
space:
mode:
authorsimonpj@microsoft.com <unknown>2010-10-07 10:27:20 +0000
committersimonpj@microsoft.com <unknown>2010-10-07 10:27:20 +0000
commit5c248c7dfa9b789df31ca5186c4f181f1e8eb42b (patch)
treea1b7d1166cb55e53eec32dd85583f437dfdd262f /compiler
parentfb982282ff6307b342d8fbc09b58a990d76c68fb (diff)
downloadhaskell-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.lhs33
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}