Currently absence of `subtyping` is the only problem detected and diagnosed specifically
for `inout` parameters, but there could be type mismatches in `inout` positions as well
and we can use `argument-to-parameter mismatch fix to detect and diagnose them.
Structurally prevent a number of common anti-patterns involving generic
signatures by separating the interface into GenericSignature and the
implementation into GenericSignatureBase. In particular, this allows
the comparison operators to be deleted which forces callers to
canonicalize the signature or ask to compare pointers explicitly.
If expression is incorrect it most likely wouldn't be able to satisfy
`Equatable` or other requirements of `~=` operator overloads, but
at the same time the main problem is related to `case` expression
itself so let's not diagnose missing conformances.
Impact of conformance failure should be rated based on use of
associated generic parameter, because a single failure could
span multiple parameters and a result.
Originally score was only increased once for conformance failure.
That is not good enough in cases when conformance is associated
with an overload choice, because in that case we can have an argument
mismatch in other choice which would have the same score impact.
This removes all calls to typesSatisfyConstraint() except for the
isConvertibleTo() check at the beginning, in the process making the
analysis a little bit more accurate.
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.