Initial vector type support

Vector types are actually composed of three different types:

- Uniform vectors are constructed using (Vectorof) and consist of a
  vector containing all of the same element. This type is unstable and
  degrades to (Vectorof <any>) for storage locations.

- Specific vectors are constructed using (Vector) and denote of a vector
  of known length and a known type for each element. This type is also
  unstable and degrades to a (Vector <any> ...) with the same number of
  elements as the original vector. This is useful as a vector's length
  can be used to optimise in-bounds vector access in the future

- The exisiting vector SchemeTypeAtom is the preferred alias for
  (Vectorof <any>) but behaves identically as far as type checking

These types support full type recursion in the same way that pairs due.
This validates that the recursive type infrastructure is general enough
to support other types.

Due to their unstable nature these types will generally decrease
performance as the vector needs to be explicitly checked for a type. It
is useful for type safety and documentation, however.

Type checking of uniform vectors introduced a new ps.ForAll plan step
which checks that a predicate holds true for an entire array. This
wasn't easy to accomplish using normal Scheme tail recursion as vector
types can't be easily "sliced" in to a smaller vector and there's no way
to tell if the end of the vector has been reached without explicitly
passing an index. There would also be no way to track the generated
vector data "pseudo-predicates" with the exisiting type check data
structures.
compiler: Fix recursive vector type contructors

The (Vector) and (Vectorof) constructors were increasing the recursion
depth by one themselves. This is broken as extractSchemeTypeRef
increases the recursion count itself.

This also adds a functional test for recursive vector type predicates.
compiler: ps.LoadVectorElement definition fixes

- Don't consider vector loads nullipotent. Vector contents are mutable
  so we can't merge vector loads to the same index. This is hard to
  trigger as LoadVectorElement is only used for type checks at the
  moment but once there's (vector-ref) planning this would become an
  issue

- Rename our result temp value in renamed(). We don't rename result
  values current but this is technically wrong..
compiler: Add planning for vector functions

This adds planning for (vector), (make-vector), (vector-ref) and
(vector-set!). The latter two are quite limited. Both vector access
functions require that the index is a constant integer and that the
length of the vector is known through its type.

(vector-set!) has the additional restriction that it can only work on
allocated values (i.e. not constants). This adds a "knownAllocated" flag
to CellValue that (make-vector) and (vector) set to true that allows
(vector-set!) to know it can safely write to the vector. In practice
this means that (vector-set!) will only be planned inline if it's
immediately initialising a vector that was just allocated.
compiler: SImplify unconditional ForAll IR

(make-vector) now uses ForAll without any loop body condition to allow
early breaks. The IR it generated worked but was a bit silly. Instead
split GenForAll to its own function and have it detect and simplify
loops without an exit condition

With optimisation this should result in the same assembler but it's
easier to read the IR this way.