Now only retry the constraint if at least one of the blocking holes has
some new information (either that it has been flagged invertible, or
that it is now defined). This can lead to big performance gains on
programs which use dependent types heavily.
At least as long as the number is small enough (currently set to < 100).
This is because it can open up further evaluation opportunities when
typechecking, and can make the term we're working with smaller - it also
makes display a bit neater.
Overall this makes some pathological cases of terrible performance much
better, without hurting anything else.
Flags can now be set on implementations too, where the flags get passed
to each of the methods in the implementation. We might want something a
bit more fine grained than this later. Also some small changes to the
way inlining lets is done in the compiler.
We can erase things of type %World, which opens up more possibilities of
newtype and helps optimise IO, but we need to be sure that the side
effecting operations aren't optimised away as a result because we no
longer have to inspect the newtype. Therefore, if optimising away a case
analysis on a newtype with a %World deleted, add a let binding for the
scrutinee of the case, and flag it as non-inlinable.
It's not actually used as part of any compilation pipeline yet, and I've
only tested it by eyeballing the output, but it'll be useful soon, and
it's good for it to be available to any new back ends that might need
it. It will need some optimisation.
That is, really erase the argument position rather than just putting
'erased there. It doesn't make a huge difference to the generated scheme
performance, but since we can always do this for constructors, we might
as well.
This improves runtime performance a bit since it avoids creating some
unnecessary closures (and is a preliminary step to lambda lifting, which
might help for some back ends).
Not calculating the needed space correctly, so sometimes not expanding
the buffer enough! This cause buffer data to be corrupted, leading to
issues like #114.
If IO operations don't return an updated world token, the inliner might
think they're not used at all. So if this turns out to be an overhead,
we'll have to work out another way of eliding it.
Or, more accurately, by not doing a thing that's a waste of time. After
evaluating a local, if the result isn't applied to a stack, there's no
more reduction to do, so stop there.
Still go to the explicit named representation afterwards, since that's
an easier API for a code generator, and by then the names are guaranteed
unique.