Note [The polymorphism rule of join points]
Invariant 4 of Note [Invariants on join points] forbids a join point to be polymorphic in its return type. That is, if its type is forall a1 ... ak. t1 -> ... -> tn -> r where its join arity is k+n, none of the type parameters ai may occur free in r. In some way, this falls out of the fact that given join j @a1 ... @ak x1 ... xn = e1 in e2 then all calls to `j` are in tail-call positions of `e`, and expressions in tail-call positions in `e` have the same type as `e`. Therefore the type of `e1` -- the return type of the join point -- must be the same as the type of e2. Since the type variables aren't bound in `e2`, its type can't include them, and thus neither can the type of `e1`. This unfortunately prevents the `go` in the following code from being a join-point: iter :: forall a. Int -> (a -> a) -> a -> a iter @a n f x = go @a n f x where go :: forall a. Int -> (a -> a) -> a -> a go @a 0 _ x = x go @a n f x = go @a (n-1) f (f x) In this case, a static argument transformation would fix that (see ticket #14620): iter :: forall a. Int -> (a -> a) -> a -> a iter @a n f x = go' @a n f x where go' :: Int -> (a -> a) -> a -> a go' 0 _ x = x go' n f x = go' (n-1) f (f x) In general, loopification could be employed to do that (see #14068.) Can we simply drop the requirement, and allow `go` to be a join-point? We could, and it would work. But we could not longer apply the case-of-join-point transformation universally. This transformation would do: case (join go @a n f x = case n of 0 -> x n -> go @a (n-1) f (f x) in go @Bool n neg True) of True -> e1; False -> e2 ===> join go @a n f x = case n of 0 -> case x of True -> e1; False -> e2 n -> go @a (n-1) f (f x) in go @Bool n neg True but that is ill-typed, as `x` is type `a`, not `Bool`. This also justifies why we do not consider the `e` in `e |> co` to be in tail position: A cast changes the type, but the type must be the same. But operationally, casts are vacuous, so this is a bit unfortunate! See #14610 for ideas how to fix this.
References 1
- Invariants on join points GHC.Core
Referenced by 4
- Invariants on join points GHC.Core ×2
- GHC.Core.Type call site
- Excess polymorphism and join points GHC.Core.Type