In order to do this we need it to take a ConstraintLocator argument so
we can tell which component we want the callee for. To make it clear
that we're looking for a callee at the anchor, also rename the member
to getAnchormostCalleeLocator.
Instead of recording `TreatRValueAsLValue` fix directly inside
`matchTypes`, let's move towards recording it specifically for
each possible case in `repairFailures` which makes it a lot
easier to determine what other fixes could be applied (if any).
A "hole" is a type variable which type couldn't be determined
due to an inference failure e.g. missing member, ambiguous generic
parameter which hasn't been explicitly specified.
It is used to propagate information about failures and avoid
recording fixes which are a consequence of earlier failures e.g.
```swift
func foo<T: BinaryInteger>(_: T) {}
struct S {}
foo(S.bar) // Actual failure here is that `S` doesn't have a member
// `bar` but a consequence of that failure is that generic
// parameter `T` doesn't conform to `BinaryInteger`.
```
Such tracking makes it easier to ignore already "fixed" requirements
which have been recorded in the constraint system multiple times e.g.
a call to initializer would open both base type and initializer
method which have shared (if not the same) requirements.
There were a few places where we wanted fast testing to see whether a
particular type variable is currently of interest. Instead of building
local hash tables in those places, keep type variables in a SetVector
for efficient testing.
Functions like `isRawRepresentable*` and `conformsToKnownProtocol`
have to be be shared between CSDiag and new diagnostics framework
until relevant code is removed from the former.
Introduce the notion of "one-way" binding constraints of the form
$T0 one-way bind to $T1
which treats the type variables $T0 and $T1 as independent up until
the point where $T1 simplifies down to a concrete type, at which point
$T0 will be bound to that concrete type. $T0 won't be bound in any
other way, so type information ends up being propagated right-to-left,
only. This allows a constraint system to be broken up in more
components that are solved independently. Specifically, the connected
components algorithm now proceeds as follows:
1. Compute connected components, excluding one-way constraints from
consideration.
2. Compute a directed graph amongst the components using only the
one-way constraints, where an edge A -> B indicates that the type
variables in component A need to be solved before those in component
B.
3. Using the directed graph, compute the set of components that need
to be solved before a given component.
To utilize this, implement a new kind of solver step that handles the
propagation of partial solutions across one-way constraints. This
introduces a new kind of "split" within a connected component, where
we collect each combination of partial solutions for the input
components and (separately) try to solve the constraints in this
component. Any correct solution from any of these attempts will then
be recorded as a (partial) solution for this component.
For example, consider:
let _: Int8 = b ? Builtin.one_way(int8Or16(17)) :
Builtin.one_way(int8Or16(42\
))
where int8Or16 is overloaded with types `(Int8) -> Int8` and
`(Int16) -> Int16`. There are two one-way components (`int8Or16(17)`)
and (`int8Or16(42)`), each of which can produce a value of type `Int8`
or `Int16`. Those two components will be solved independently, and the
partial solutions for each will be fed into the component that
evaluates the ternary operator. There are four ways to attempt that
evaluation:
```
[Int8, Int8]
[Int8, Int16]
[Int16, Int8]
[Int16, Int16]
To test this, introduce a new expression builtin `Builtin.one_way(x)` that
introduces a one-way expression constraint binding the result of the
expression 'x'. The builtin is meant to be used for testing purposes,
and the one-way constraint expression itself can be synthesized by the
type checker to introduce one-way constraints later on.
Of these two, there are only two (partial) solutions that can work at
all, because the types in the ternary operator need a common
supertype:
[Int8, Int8]
[Int16, Int16]
Therefore, these are the partial solutions that will be considered the
results of the component containing the ternary expression. Note that
only one of them meets the final constraint (convertibility to
`Int8`), so the expression is well-formed.
Part of rdar://problem/50150793.
Have the constraint graph's connected-component implementation be more
self-contained, producing a vector containing each of the actual
components (where each is defined by a list of type variables and a list
of constraints). This simplifies the contract with the client
(SplitterStep) and eliminates a bunch of separate mapping steps to
interpret the results.
It also lets us enrich the Component data structure in the future.
Currently, because argument info has been collected based solely
on anchor, it would be possible to overwrite labels for expressions
like `foo[0](x)` since `ApplyExpr` uses its function expression as
a key for argument information cache, which leads to errors while
attempting optimizations based on that information.
Since `areConservativelyCompatibleArgumentLabels` is only used by
`simplifyAppliedOverloads` now, it's easy to pass arguments directly
instead of trying to form them from list of labels.
This helps with:
- Diagnostics because solver would get more choices to work with
in diagnostic mode;
- Avoid adding the same overload multiple times
(retry after label mismatch and no viable candidates);
- Unify overload handling/filtering in `simplfyAppliedOverloads`.
Since there is already a diagnostic for this `MemberAccessOnOptionalBaseFailure`
it should incorporate all related diagnostic logic and could be used from CSDiag.
Additionally, refactor some of the logic for the original add $ diagnostic
so that a lot of logic can be shared between the two. Also rename the
original fix and diagnostic to better reflect their purpose.
If solution application is attempted for one of the sub-expressions,
while diagnostics are trying to narrow down where the failure is
located, don't record that captures need to be computed for closures,
because that could fail later on as in such conditions expressions
are not guaranteed to have correct types (e.g. some types could be
set to "unresolved").
Merging partial solutions can end up assigning the same type to a
particular typed node (expression, parameter, etc.), which can lead to
unbalanced set/clear when exploring the solution space (and later on,
crashes). Don't re-insert such information.
This is the same approach taken for type variable bindings, but it's
all pretty unfortunate: partial solutions should only record
information relative to their part of the constraint system, which
would save time and memory during solving. Howver, that's too big a
change for right now.
Fixes rdar://problem/50853028.
When we perform constraint generation while solving, capture the
type mappings we generate as part of the solver scope and solutions,
rolling them back and replaying them as necessary. Otherwise, we’ll
end up with uses of stale type variables, expression/parameter/type-loc
types set twice, etc.
Fixes rdar://problem/50390449 and rdar://problem/50150314.
Use the opened type from the callee declaration to open up references to
generic function builders that contain type parameters. This allows general
use of generic function builders.
When calling a function whose parameter specifies a function builder
with a multi-statement closure argument, transform the closure into
a single expression via the function builder. Should the result
type checker, replace the closure body with the single expression.
- Add a precondition on `doesDeclRefApplyCurriedSelf` to expect
a member decl, and rename it to make the precondition explicit.
- Don't assume that not having a base type means this isn't a member
reference, as member references to static operators don't have base
types.
Resolves SR-10843.