There have been multiple instances where I had the need to iterate over
type variables, only to discover that the traversal order is arbitrary.
This commit fixes that by adding SortedMapping, which utilizes BTreeMap
internally to guarantee a traversal order. All instances of VarMap are
now refactored to use this to ensure that type variables are iterated in
the order of its variable ID, which should be monotonically incremented
by the unifier.
A lot of refactoring was performed, specifically with relaxing
expression codegen to return Option in case where ellipsis are used
within a subexpression.
All allocas for temporary objects are now placed in the beginning of the
function. Allocas for on-temporary objects are not modified because
these variables may appear in a loop and thus must be uniquely
allocated by different allocas.
Previously, the IR which sets up the call to the target function will
have its debug location pointing at the last argument of the function
call instead of the function call itself.
All allocas for temporary objects are now placed in the beginning of the
function. Allocas for on-temporary objects are not modified because
these variables may appear in a loop and thus must be uniquely
represented.
All parameters with a structure type in extern functions are marked as
`byref` instead of `byval`, as most ABIs require the first several
arguments to be passed in registers before spilling into the stack.
`byval` breaks this contract by explicitly requiring all arguments to be
passed in the stack, breaking interop with libraries written in other
languages.
In LLVM, i1 represents a 1-byte integer with a single valid bit; The
rest of the 7 upper bits are undefined. This causes problems when
using these variables in memory operations (e.g. memcpy/memmove as
needed by List slicing and assignment).
We fix this by treating all local boolean variables as i8 so that they
are well-defined for memory operations. Function ABIs will continue to
use i1, as memory operations cannot be directly performed on function
arguments or return types, instead they are always converted back into
local boolean variables (which are i8s anyways).
Fixes#315.
Because it is unclear which variables are expressions and
subexpressions, all variables which are previously anonymous are named
using (1) the control flow statement if available, (2) the possible name
of the variable as inferred from the variable name in Rust, and (3) the
"addr" prefix to indicate that the values are pointers. These three
strings are joint together using '.', forming "for.i.addr" for instance.