Attempting to pre-compute a set of referenced type variables
upfront is incorrect because parameter(s) and/or result type
could be bound before conjunction is attempted. Let's compute
a set of referenced variables before each element gets attempted.
It helps to simply handling of outer constrants because they have
to be added to the constraint system before scope is created but
constraint graph have to get updated after to make sure that
incremental binding inference already knows about types inferred
from conjunction.
`SplitterStep` doesn't filter solutions if it results in a single
component (which is does for conjunction elements), so the solutions
have to be filtered manually after each element is done.
Iterate over all of the elements one-by-one and make sure that
each results in a single solution, otherwise fail the conjunction step.
Once all of the elements are handled either stop or,
if conjunction step has been performed in isolation,
return all of the outer constraints back to the system
and attempt to solve for outer context - that should
produce one or more solutions for conjunction to be
considered successfully solved.
Instead of crashing in release builds, let's simplify fail the
step and let type-checker produce a fallback diagnostic. Maintain
a trap in debug builds to make it easier to investigate the root
cause of the issue.
Resolves: rdar://56167233
Start treating the null {Can}GenericSignature as a regular signature
with no requirements and no parameters. This not only makes for a much
safer abstraction, but allows us to simplify a lot of the clients of
GenericSignature that would previously have to check for null before
using the abstraction.
Currently all `ComponentSteps` created by `DependentComponentSplitterStep` share the same `Solutions` vector. Because of this, the `ComponentStep`s might modify solutions created by previous `ComponentStep`s. Use different `Solutions` vectors for each `ComponentStep` to avoid sharing information between the `ComponentStep`s.
The concrete manifestation in the added test case is that the `Bar` overload gets added to `Solutions`, it’s score gets reduced by its `ComponentStep` original score, then the `Foo` overload gets added to `Solutions` and both solutions have their score decreased by the `OriginalScore` of `Foo`’s `ComponentStep`, causing `Bar`’s score to underflow.
Fixes rdar://78780840 [SR-14692]
Not all of the unary operators have `CGFloat` overloads,
so in order to preserve previous behavior (and overall
best solution) with implicit Double<->CGFloat conversion
we need to allow attempting generic operators for such cases.
```swift
let _: CGFloat = -.pi / 2
```
`-` doesn't have `CGFloat` overload (which might be an oversight),
so in order to preserve type-checking behavior solver can't be
allowed to pick `-(Double) -> Double` based on overload of `/`,
the best possible solution would be with `/` as `(CGFloat, CGFloat) -> CGFloat`
and `-` on a `FloatingPoint` protocol.
- Prefer CGFloat -> Double over the other way around to avoid
ambiguities;
- Every new conversion impacts the score by factor of number of
previously applied conversions to make it possible to select
solutions that require the least such conversions.
- Prefer concrete overloads with Double <-> CGFloat conversion
over generic ones.
Augment `DisjunctionChoice::{shouldSkip, shouldStopAt}` to check
for presence of implicit value conversions, and if score indicates
that there is at least one of those was attempted - downgrade
importance of a last successful choice.
The existing overloading rules strongly prefer async functions within
async contexts, and synchronous functions in synchronous contexts.
However, when there are other differences in the
signature, particularly parameters of function type that differ in
async vs. synchronous, the overloading rule would force the use of the
synchronous function even in cases where the synchronous function
would be better. An example:
func f(_: (Int) -> Int) { }
func f(_: (Int) async -> Int) async { }
func g(_ x: Int) -> Int { -x }
func h() async {
f(g) // currently selects async f, want to select synchronous f
}
Effect the semantics change by splitting the "sync/async mismatch"
score in the constraint system into an "async in sync mismatch" score
that is mostly disqualifying (because the call will always fail) and a
less-important score for "sync used in an async context", which also
includes conversion from a synchronous function to an asynchronous
one. This way, only synchronous functions are still considered within
a synchronous context, but we get more natural overloading behavior
within an asynchronous context. The end result is intended to be
equivalent to what one would get with reasync:
func f(_: (Int) async -> Int) async { ... }
Addresses rdar://74289867.
for arithmetic operators.
Only sort overloads that are related, e.g. Sequence
overloads. Further, choose which generic overloads
to attempt first based on whether any known argument types
conform to one of the standard arithmetic protocols.
attempt the most specific choices first. Then, if the solver finds
a solution with one choice, it can skip any subsequent choices that
can be unconditionally used in place of the successful chioce and produce
the same solution.
disjunction choice that does not introduce conversions, check to see
if known argument types satisfy generic operator conformance requirements
early, and skip the overload choice if any requirements fail.
This helps the solver avoid exploring way too much search space when
the right solution involves a generic operator, but the argument types
are known up front, such as `collection + collection + collection`.