This is part one of addressing the present issues with emplacing type
directly where type variables should be reused. Now, when an
`Index<Type>` is converted to a variable in solving, we leave the
converted variable in the `Type`'s place. Specifically, we keep an index
to a `Cell<Type>`.
Note that this transformation is only temporary, it will be removed once
we merge this with the `Type` SoA representation, but it is needed in
the meantime as I transform the `Constrain` API to get rid of
type-emplacement.
Programs like
```
after : ({} -> a), ({} -> b) -> ({} -> b)
fx = after (\{} -> {}) \{} -> if Bool.true then fx {} else {}
```
are legal because they always decay to functions, even if they may not
look like functions syntactically. Rather than using a syntactic check
to check for illegally-recursive functions, we should only perform such
checks after we know the types of values.
Closes#4291
Every type can have `Eq.isEq` derived for it, as long as
- it does not transitively contain a function
- it does not transitively contain a floating point value
- it does not transitively contain an opaque type that does not support
`Eq`
The mutual-recursion checks does not admit types that are not function
types; because Roc is strict, only functional values can be involved in
mutual recursion. However, this check was exercised by checking the head
constructor of a type, which is not the correct way to do it. Aliases
and opaque types may in fact be function types as well, so we must chase
their actual contents.
Closes#4246
Previously we would construct the shapes of unions used in the pattern
tree for exhaustiveness checking using the type of the branch patterns,
rather than the type of the condition variable. Clearly we want to
always use the condition variable, otherwise some branches will be
seen as exhaustive, when they are not!
To do this, we now index into the condition variable while refying the
patterns to build the tree for exhaustiveness checking.
Closes#4068