This adds a modern type unification algorithm, which drastically
improves performance, particularly for bigger programs.
This required a change to the AST to add TypeCheck methods (for Stmt)
and Infer/Check methods (for Expr). This also changed how the functions
express their invariants, and as a result this was changed as well.
This greatly improves the way we express these invariants, and as a
result it makes adding new polymorphic functions significantly easier.
This also makes error output for the user a lot better in pretty much
all scenarios.
The one downside of this patch is that a good chunk of it is merged in
this giant single commit since it was hard to do it step-wise. That's
not the end of the world.
This couldn't be done without the guidance of Sam who helped me in
explaining, debugging, and writing all the sneaky algorithmic parts and
much more. Thanks again Sam!
Co-authored-by: Samuel Gélineau <gelisam@gmail.com>
This adds the core unification helper functions that do the core work of
solving the invariants. This includes the actual Unify, OccursCheck, and
Extract which is sometimes known as "zonk".
A few other small functions are also included.
Co-authored-by: Samuel Gélineau <gelisam@gmail.com>
When we look at unification variables from two different places, the
default printer will always start numbering them from ?1 and therefore
if we look at two unrelated systems, they might both print as ?1 when
they are in fact different pointers.
We don't collect them all by default since it's usually not necessary
except for debugging, but in those situations, we want a consistent
unification store which we can pass around to get sensible debug output.
This is used for representing a unification variable in our type during
type unification. For example, this allows us to have a [?1] or a
map{?1:[?2]} and so on...
This is a fascinating, and incredibly simple data structure. I hope I
can end up using it for more than just type unification!
Thanks to Sam who taught me about its existence.
We should run this periodically or put it in a separate job, as it's
causing the tests to fail all the time. I expect those sites may be
blocking github as they see it as a DOS.
The owner/group of a file should not be validated on the host until runtime. This removes the checks in Validate() that were happening before the execution of the resource graph (and therefore bound to fail if the system was being bootstrapped).
Plumb through the standard context.Context so that a function can be
cancelled if someone requests this. It makes it less awkward to write
simple functions that might depend on io or network access.
Unfortunately, this also breaks go-mod-upgrade with:
upgrade failed error=Error running go command to discover modules: exit
status 1 stderr=go: loading module retractions for
golang.org/x/mod@v0.16.0: version "v0.17.0" invalid: resolves to version
v0.17.1-0.20240315155916-aa51b25a4485 (v0.17.0 is not a tag) go: loading
module retractions for golang.org/x/sync@v0.6.0: version "v0.7.0"
invalid: resolves to version v0.7.1-0.20240304172602-14be23e5b48b
(v0.7.0 is not a tag)
Originally, I considered having more than one way to express the meta
param. After thinking about it for longer, it probably makes sense to
have a second meta param if necessary, and to avoid the exclusive.
This removes the exclusive from the res names and edge names. We now
require that the names should be lists of strings, however they can
still be single strings if that can be determined statically.
Programmers should explicitly wrap their variables in a string by
interpolation to force this, or in square brackets to force a list. The
former is generally preferable because it generates a small function
graph since it doesn't need to build a list.
When error messages are written to stdout, they will be considered as
output in case we want to fail from inside $( ) or backticks, and then
the error does not end up on the terminal.
Add a fold in github actions output around the ragel build.
Run the commit-message test locally, so that error can be detected
before pushing to CI. We also now accept two-letter topics.
Some minor improvement in the testing scripts.
This adds a unification optimizations API, and uses it to optimize the
embedded provisioner. With these turned on, type unification drops from
around 1m45s to 2.5s which is a 40x speedup.
This commit adds the ability to build a standalone provisioning tool.
This is the first useful public mcl code base as well. It is not
perfect, but does serve as a rough starting point to show what is
possible. In the future as the language and the engine evolve, this will
likely get more elegant, and also grow new features.
To build this, run `make clean && GOTAGS='embedded_provisioner' make`.
To run this, run `mgmt provisioner`.
This should make a maintainers life easier. (I hope!) The .release files
contain the "magic name" for the respective release type. If they start
with a # then they are skipped. You shouldn't need to keep bumping the
distro versions in the Makefile anymore.