## NOINLINE and worker/wrapper

Currently we do no worker/wrapper on a NOINLINE thing. In `WorkWrap`

:

```
tryWW dflags fam_envs is_rec fn_id rhs
| isNeverActive inline_act
-- No point in worker/wrappering if the thing is never inlined!
-- Because the no-inline prag will prevent the wrapper ever
-- being inlined at a call site.
```

But if we have, say,

```
{-# NOINLINE f #-}
f (x,y) = error (show x)
g True p = f p
g False p = snd p + 1
```

then strictness analysis will discover `f`

is strict, and `g`

, but *because f has no wrapper*, the worker for

`g`

will rebox the thing. So we get```
f (x,y) = error (show x)
$wg b x y = let p = (x,y) -- Yikes! Reboxing!
in case b of
True -> f p
False -> y + 1
g b p = case p of (x,y) -> $wg b x y
```

Now, in this case the reboxing will float into the `True`

branch, an so the allocation will only happen on the error path. But it won't float inwards if there are multiple branches that call `(f p)`

, so the reboxing will happen on every call of `g`

. Disaster.

Solution: do worker/wrapper even on NOINLINE things; but move the NOINLINE pragma to the worker.

This actually happens! In `GHC.Arr`

we have

```
{-# NOINLINE indexError #-}
indexError :: Show a => (a,a) -> a -> String -> b
indexError rng i tp = error (...)
index b i | inRange b i = unsafeIndex b i
| otherwise = indexError b i "Char"
```

The `inRange`

generates multiple alternatives, which the `indexError`

is duplicated into, and exactly this phenomenon takes place. Eric (gridaphobe) offered this standalone example

```
module Err where
tabulate :: (Int -> a) -> (Int, Int) -> [Int]
tabulate f (l,u) = array (l,u) [l..u]
{-# INLINE array #-}
array :: (Int, Int) -> [Int] -> [Int]
array (l,u) is = [index (l,u) i | i <- is]
{-# INLINE index #-}
index :: (Int, Int) -> Int -> Int
index b@(l,h) i
| l <= i && i < h = 0
| otherwise = indexError b i 0
{-# NOINLINE indexError #-}
indexError :: (Int, Int) -> Int -> Int -> b
indexError rng i tp = error (show rng)
```

Compile this with GHC 8, and shudder at the terrible code we get for `$wtabulate`

.

## Trac metadata

Trac field | Value |
---|---|

Version | 8.0.1 |

Type | Bug |

TypeOfFailure | OtherFailure |

Priority | normal |

Resolution | Unresolved |

Component | Compiler |

Test case | |

Differential revisions | |

BlockedBy | |

Related | |

Blocking | |

CC | |

Operating system | |

Architecture |