We use simplifyConstraint() to activate other constraints, and then
examine those constraints to find related disjunctions. In examining
those active constraints, we were simplifying them in case they
failed (which would allow us to bail out earlier). In doing so, we could
potentially generate new disjunctions when we simplify an unresolved
value member constraint. If we do that, we end up collecting these new
disjunctions as part of the set of related disjunctions, but that's
problematic because as part of exiting the solver scope to roll back
changes we delete these disjunctions from the system.
Instead of actually simplifying the active constraints, just collect the
disjunctions and move the active constraints back to the inactive list.
With this change we can build the stdlib.
This is still disabled by default, and as with the previous
implementation does not pass all tests if enabled.
Rather than looking for applicable function constraints and then looking
at the bind overload disjunctions associated with those, instead
directly collect all bind overload disjunctions and revise the enabled
elements of those disjunctions by attempting to bind them simultaneously
with the elements of other disjunctions that are linked to this one
through applicable function constraints.
There are a handful of things, but the primary ones are that we really
don't want to track depth of recursion so much as whether we are
processing at the "top level" of constraints we're looking at or not so
that we can determine whether we can disable elements from a
disjunction.
Related, there are places where we can bail out earlier if we know
that *any* neighboring constraint passes.
Also updating the way we gather neighboring constraints to be
independent of the function that simplifies them. The original code was
wrong in that in bailed as soon as one of the simplifications
failed (which meant we might not gather all of them).
It turns out that for disjunctions formed for subscripts, we have an
explicit function type (e.g. ($T1)->$T2) for the LHS of the bind
overload constraint, and when a subscript is mixed with an explicit
call (e.g. x[i](2)) we end up with an applicable function constraint
where the RHS is $T2 (which is a function type itself), so this assert
was invalid.
Fundamentally the assert wasn't checking anything important, so it won't
be missed. The important check here is that the applicable function
constraint that we started with is only involved in one disjunction
since we're only returning one.
This shows up in test/Constraints/overload.swift when I run it with
-propagate-constraints enabled:
func test20886179(_ handlers: [(Int) -> Void], buttonIndex: Int) {
handlers[buttonIndex](buttonIndex)
}
This is an initial implementation of the constraint propagation pass,
disabled by default at the moment as it does not currently pass all
tests.
I have other changes that I'll hold off on for now because they are
incomplete. Without those changes, this pass doesn't really achieve
much, so this is really just a checkpoint on some progress and not
something really worth trying out at this point.
This is disabled by default but enabled under the frontend option
-propagate-constraints.
The idea here is to have a pass that enforces local consistency in our
constraint system, in order to reduce the domains of constraint
variables, speeding up the solving of the constraint system.
The initial focus will be on reducing the size of the disjunctions for
function overloads with the hope that it substantially improves the
performance of type checking many expressions.