This adds a meta state store that is preserved between graph switches if
the kind and name match. This is useful so that rapid graph changes
don't necessarily reset their retry count if they've only changed one
resource field.
This adds a new test functions package and also a new "fastcount"
function which counts up from zero as fast as is possible. You probably
don't want to use this in production, but it is useful for performance
and deadlock testing the resource and function engines.
There are many reasonable cases where we might want to allow a dynamic
format string. Support that situation by adding the new invariants that
are needed for those cases.
We were skipping over being fully consistent with all of the generator
invariants when running the solver. This allowed us to miss some of the
conditions that a generator might impose. Usually this caused us to be
"solved" when in fact we had an invalid program.
There were some bugs about setting resource fields that were structs
with various fields. This makes things more strict and correct. Now we
check for duplicate field names earlier (duplicates due to identical
aliases) and we also don't try and set private fields, or incorrectly
set partial structs.
Most interestingly, this also cleans up all of the resources and ensures
that each one has nicer docs and a clear struct tag for fields that we
want to use in mcl. These are mandatory now, and if you're missing the
tag, then we will ignore the field.
We also add a backup fix to avoid a panic in case we ever hit a new
unification bug that lets something through, we can at least turn it
into a runtime issue. This adds a test as well.
We want to add the equality to the main list of equalities in case it is
needed somewhere else. This doesn't have any effect on any of our test
cases, but it doesn't seem to be harmful, and it could conceivably be
useful in the future. This is a separate commit in case we want to check
if this behaviour still holds true well into the future.
These two vars are used pretty deeply through this code, so rename them
to prevent any confusion.
We also switch from a range loop to a counter so that the loop list can
be changed while it's looping.
The set of initial invariants that we see might include:
?8 = func(inputs []int, function ?4) ?3
?8 = func(inputs []int, function ?10) ?9
?8 = func arg0 []int, arg1 ?6) ?7
From this we can infer that since they are all equal, that we also know
that ?4, ?10 and ?6 must also be equal. The same is true of ?3, ?9 and
?10. Those new equalities are sometimes necessary in order to complete
the full unification.
The second interesting aspect is when we have dissimilar equalities:
?2 = func(x ?1) str
?4 = func(a int) ?5
?10 = func(a int) ?11
In this example we also have an additional equality:
?6 = ?2
From this and the above we can determine that ?2, ?4, ?6 and ?10 are all
equal. We only know about ?4, ?6, and ?10 from the direct relationship,
and we add in ?2 from the indirect (graph) relationship. These
relationships let us determine new information that ?5 and ?11 are both
str and that ?1 is an int.
Two important reminders:
1) Arg names don't have to match. It would impossible to build such a
system where this was both possible, but also let us name our
functions sanely.
2) None of this guarantees we won't find an inconsistency in our
solution. If this is found, it simply means that someone wrote code
which does not type check.
When we were running our partial unification to compare similar looking
function invariants, we would sometimes learn new information, even if
it didn't entirely solve that invariant. When this new information was
learned, it's important that we globally mark it as solved so that
others can use it to complete their invariants. When it was a critical
piece of information, this would result in new information, which would
eventually lead to that original partial invariant that we learned that
information from to becoming solved.
This presents things in a more formal way for those who are more
familiar with standard type unification syntax.
Patch created by Sam, and cleaned up by James.
This removes the `Close() error` and replaces it with a more modern
Stream API that takes a context. This removes boilerplate and makes
integration with concurrent code easier. The only downside is that there
isn't an explicit cleanup step, but only one function was even using
that and it was possible to switch it to a defer in Stream.
This also renames the functions from polyfunc to just func which we
determine by API not naming.
It's important that during unification that function types can unify
even if their arg names are different. (Their actual unnamed types must
be identical of course.) This adds a test to make sure we preserve this
behaviour.
This adds a new interpretation of the EqualityWrapFuncInvariant that can
combine two into one if their Expr1 fields are the same. We might know
different partial aspects of multiple functions. This also includes a
test. The test does not pass before this commit which adds it.
This ports TestAstFunc2 from our home-grown content storage system to
the txtar package. Since a single file can be used to represent the
entire folder hierarchy, this makes it much easier to see and edit
tests.
This removes the calling of SetValue from the engine, and instead
replaces it with the Table() API. The downside is that this is likely
slower, and the current API with locking being exposed publicly is kind
of ugly. The upside is that this might make building the new engine
easier.
Future versions might remove locking from the API if we can avoid making
any accesses to expressions. Currently this happens within Logf/SafeLogf
which is our main (only?) usage at the moment. Logging could become
smarter perhaps. Alternatively, we might pass in a "setter" function
that gets called safely from within the engine. This could wrap SetValue
and the locking functions wouldn't be part of the public API.
This adds the requirement that all function implementations provider a
String() string method so that these can be used as vertices in the
pgraph library. If we eventually move to generics for the pgraph DAG,
then this might not matter, but it's not bad that these have names
either.
This patch moves to use the sox package instead of arecord for getting
microphone data, and it also validates that both sox and rec and
installed. We also add a standalone example.
This doesn't let us have nested mcl at the moment, but we could improve
on this with an embed API for each package. For now this makes building
the project easier.
This flattens the type unification of the map function so that the
solver has more to work with. It's possible that some scenarios might
solve faster, or without recursion, after this improvement.