Rename `openUnboundGenericTypes` to `convertInferableTypes`. In addition to unbound generics, this method also converts placeholder types to fresh type variables.
Previously l-value binding would be paired with discovered r-value
one but that is not necessary and can cause issues with ranking
since there is no way to filter this "fallback" binding from the
set.
Since there is a conversion from `() -> T` to `() -> Void` for closures,
solver has to attempt a `Void` when other bindings (inferred from the body)
have failed.
Let's try it post factum instead of adding `Void` fallback to the
binding set after every discovered supertype binding. Old scheme
wouldn't work in incremental mode anyway because it's possible to
find a subtype binding (which makes it clear that body has to have
a result type) after a supertype and end up attempting `Void` although
it would be incorrect.
If member type is unknown (determined to be a hole) `applicable function`
of any kind or `overload choice` cannot delay attempting it because doing
so would allow solver to make forward progress.
Currently `isLiteralCoveredBy` only checks for top-level type variable or hole.
That check has to be sunk down so it could be used after optionality is stripped
away (when possible), otherwise bindings like `$T0?` are (incorrectly) determined
to cover literal requirements (because conformance check always succeeds when
attempted on a type variable).
Using existing binding with updated type would result in incorrect
behavior in incremental mode since when "originating" (new) constraint
gets retracted it would leave a stale binding behind.
Currently the pattern is to collect the type variables and then unique
them. Instead of asking clients to do uniquing, let's just accept a set
as an argument.
Any constraints which would previously cause binding inference to
fail should instead delay associated type variable and preserve
all of the collected information.
This is vital for incremental binding computation that cannot
re-introduce constraints after "failure" because it's too expensive.
Create a new namespace - `swift::constraints::inference` and associate
`PotentialBinding` with it. This way it would be possible for constraint
graph to operate on `PotentialBinding(s)` in the future.
Currently potential bindings are stored in a vector (`SmallVector`)
and every call has to pass additional set of unique types to
inference methods to unqiue the bindings. Instead let's merge
these two together and use `SetVector` for binding storage,
which would also be great for incremental mode that can't
pass additional sets around.
Doing so streamlines access to the information associated with literal
protocol requirements and allows to add more helpers.
Also cache default type in the struct itself for easy access.
One more step towards incrementality of binding inference. Instead of
trying to determine literal protocol coverage during finalization
of the bindings, let's do that as soon as new bindings and/or literal
protocol requirements are discovered.
Literal protocol requirements are handled differently from other
protocols, they require additional contextual information (such
as coverage, direct/transitive distinction), and participate in
binding inference (could be turned into default bindings).
The only possible default which could satisfy both protocols is
`Double`, otherwise it has to be some custom type which conforms
to both protocols. Either way it's best to leave `ExpressibleByFloatLiteral`
in place to get to `Double` faster or make sure that custom type
conforms to it even if it would later fail `ExpressibleByIntegerLiteral`
conformance, at least that wouldn't introduce any unviable bindings.
Since `ExpressibleByNilLiteral` doesn't have a default type,
there is no need to track it in the set of protocols that could
produce defaultable bindings if not "covered" by existing bindings.
Let's keep defaults separate from direct and transitive bindings,
that would make it easier to handle them in incremental model.
Instead of generating bindings for defaults and adding to the main
set, let's allow producer to choose what to do with them once type
variable has been picked for attempting.
Look through specifier (inout, l-value) and optional types while
checking for presence of dependent member types to avoid inferring
incorrect bindings (which could lead to infinite recursion in the
solver).
Resolves: SR-13856
Resolves: rdar://problem/71383770
As a step towards making binding inference more incremental, let's
make producer responsible for adding hole type binding instead of
doing so in `finalize`.
Wrapping bindings into optional type based on presence of
an `ExpressibleByNilLiteral` conformance requirement should
be done after type variable has been selected for attempting.
Otherwise such upfront work would be wasteful since it doesn't
affect binding ranking in any way.
Replaces `InvolvesTypeVariables` flag with a set of adjacent type
variables found during binding inference.
This approach is more suitable for incremental binding computation
because it allows to maintain a list of type variables that affect
ranking and check whether something has been resolved without having
to re-evaluate constraints associated with the given type variable.
Use `DelayedBy` in more places:
- If type variable is associated with a disjunction constraint let's
mark it as been delayed by it (until the disjunction is actually
attempted);
- Type variable is "delayed" by presence of member constraint
(of any kind) only if it stands for a member type. Such type
variable would be resolved once the member constraint is
simplified.
If type variable is still connected to `ApplicableFunction` that
means it's either an argument, result or represents a function
(member reference, operator) being applied. Regardless of exact
location such type variable should be delayed until call is
completely resolved to get additional context from parameters,
result type of a function being applied.
- 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.