- Keep track of all constraints which caused a particular type variable to
be de-prioritized.
- Convert a property to a method which would determine whether
given set of potential bindings is "fully bound" and has to
be delayed until certain constraints are simplified.
Instead of attempting to join only the last recorded supertype
binding, let's attempt to join any previously recorded supertype
binding with an incoming one to make sure that set contains only
the most viable types.
successfully finding a solution by favoring operators already bound
elsewhere.
Favoring existing operator bindings often lets the solver find a solution
fast, but it's not necessarily the best solution.
func foo(a: Int, b: Int) {}
func foo(a: String) {}
// Int and String should both be valid, despite the missing argument for the
// first overload since the second arg may just have not been written yet.
foo(a: <complete here>
func bar(a: (Int) -> ()) {}
func bar(a: (String, Int) -> ()) {}
// $0 being of type String should be valid, rather than just Int, since $1 may
// just have not been written yet.
bar { $0.<complete here> }
This is necessary in order to have access to private members of
a `ConstraintSystem` for testing purposes, such as logic related
to potential binding computation.
Implements iterative protocol requirement inference through
subtype, conversion and equivalence relationships.
This algorithm doesn't depend on a type variable finalization
order (which is currently the order of type variable introduction).
If a given type variable doesn't yet have its transitive protocol
requirements inferred, algorithm would use iterative depth-first
walk through its supertypes and equivalences and incrementally
infer transitive protocols for each type variable involved,
transferring new information down the chain e.g.
T1 T3
\ /
T4 T5
\ /
T2
Here `T1`, `T3` are supertypes of `T4`, `T4` and `T5`
are supertypes of `T2`.
Let's assume that algorithm starts at `T2` and none of the involved
type variables have their protocol requirements inferred yet.
First, it would consider supertypes of `T2` which are `T4` and `T5`,
since `T5` is the last in the chain algorithm would transfer its
direct protocol requirements to `T2`. `T4` has supertypes `T1` and
`T3` - they transfer their direct protocol requirements to `T4`
and `T4` transfers its direct and transitive (from `T1` and `T3`)
protocol requirements to `T2`. At this point all the type variables
in subtype chain have their transitive protocol requirements resolved
and cached so they don't have to be re-inferred later.
Instead of recording all of the binding "sources" let's only record
subtype, supertype and equivalence relationships which didn't materialize
as bindings (because other side is a type variable).
This is the only information necessary to infer transitive bindings
and protocol requirements.
While inferring bindings, let's record not only the fact that current
type variable is a subtype of some other type variable but track
constraint which establishes this relationship.