When applying a function builder to a closure to produce the final,
type-checked closure, use the new rewriteTarget() so it’s performed on
a per-target basis. Use this to eliminate some duplicating in the handling
of return types.
Pull out the core operation of rewriting a given SolutionApplicationTarget
into into a method on the ExprWalker that does the overall rewrite, so it
can be called multiple times within application.
Rather than having separate dense maps for the type mappings of each
node type (expression, type location, variable declaration, pattern) that
a TypedNode can be, have a single such map. Sometimes we end up
setting a particular node's type more than once, so cope with that
by restoring the prior type.
Move the remaining logic of typeCheckBinding, which consists of applying
the solution to the pattern, down into the normal solution application
path. typeCheckBinding() is now a thin shell over the normal
typeCheckExpression() convenience function.
Move more constraint generation logic for an expression target into a
new generateConstraints() on a solution target, so we can further
generalize the main “solve” logic.
Capture the peculiarities of contextual types vs. types used to generate
conversion constraints, as well as the behavior of “optional some” patterns
as used by if let / while let, within SolutionApplicationTarget. This allows
us to use a single target throughout setup / solving / application, rather
than mapping between two similar-but-disjoint targets.
Fix a few related issues involving the interaction with
single-expression closures:
* A single-expression closure can have a "return" in it; in such
cases, disable the function-builder transform.
* Have the function builder constraint generator look through the
"return" statement in a single-expression closure the same way as
solution application does
Fixes rdar://problem/59045763, where we rejected some well-formed code
involving a single-expression closure with a "return" keyword.
Initializer expressions are always type checked against a pattern, so also
include the pattern in the solution application target and use that to
compute the contextual type from the pattern type.
Rework most of typeCheckExpression() to use SolutionApplicationTarget,
folding more information into that data structure and sinking more
expression-checking behavior down into the more general solver and
solution-application code.
Start cleaning up the main “solve” entry point for solving an expression
and applying the solution, so it handles arbitrary solution targets.
This is another small step that doesn’t do much on its own, but will help
with unifying the various places in the code base where we run the solver.
Add the final conversion type and the flag indicating whether a given
expression is discarded to SolutionApplicationTarget, rather than
separating the arguments to the solver implementation.
If a type variable representing "function type" is a hole
or it could be bound to some concrete type with a help of
a fix, let's propagate holes to the "input" type. Doing so
provides more information to upcoming argument and result matching.
SolutionResult better captures what can happen when solving a constraint
system for the given expression occurs than the ad hoc SolutionKind return
& small vector of Solution results. Also, try to make this logic less
convoluted.
Move constraint generation for statement conditions onto the
constraint system; it doesn't really have any reason to be located
within the function builder transform.
Generalize the representation of contextual types so we can store
contextual types for more than one expression. Allow these to be
added/rolled back in solver scopes. Nothing uses this functionality
yet.
When requesting information about the contextual type of a constraint
system, do so using a given expression rather than treating it like
the global state that it is.
* If there is a disjunction associated with closure type e.g.
coercion to some other type `_ = { $0 } as (Int32) -> Void`
* If there is a disjunction associated with a collection which
could provide more context to the constraint solver.
If there is `subtype` relationship between two type variables
binding inference algorithm attempts to infer supertype bindings
transitively, but it doesn't check whether some of the new types
are already included in the set, which leads to duplicate solutions.
If there is a subtype relationship between N types we have to make
sure that type chain is attempted in reverse order because we can't
infer bindings transitively through type variables and attempting
it in any other way would miss potential bindings across the chain.
Instead of trying to hold a "global" set of type variable differences
let's use pair-wise comparison instead because in presence of generic
overloads such would be more precise.
If there are N solutions for a single generic overload we currently
relied on "local" comparison to detect the difference, but it's not
always possible to split the system to do one. Which means higher
level comparisons have to account for "local" (per overload choice)
differences as well otherwise ranking would loose precision.
`getCalleeLocator` has to be able to:
- Retrieve type for given expression via `getType`;
- Simplify given type via `simplifyType`; and
- Retrieve a selected overload choice for a given locator via `getOverloadFor`.
Even if contextual closure type has type variables inside
prefer it over disjunction because it provides a lot of
contextual information early which helps to solve the system
faster.