Commit Graph

51 Commits

Author SHA1 Message Date
Slava Pestov
2230c3a17e Sema: Split up gatherConstraints() into gatherAllConstraints() and gatherNearbyConstraints()
The two GatherKinds no longer share any implementation, so there's
no point keeping the logic together. Doing this also allows removing
the acceptConstraintFn from gatherAllConstraints(), which further
simplifies depthFirstSearch().
2025-01-27 10:27:00 -05:00
Slava Pestov
1aff26eaa6 Sema: Store BindingSet inside the ConstraintGraphNode
Building the DenseMap in determineBestBindings() is extremely
expensive.

Also rename getCurrentBindings() to getPotentialBindings().
2025-01-15 22:30:32 -05:00
Pavel Yaskevich
e3987beffb [CSOptimizer] Literal arguments should cause score reset only for operators
Resetting score to `0.1` is intended to make sure that the
solver picks the outermost disjunction in literal chains like
`1 + 2 + 3 ...` because that would provide context to the
inner choices.

Resolves: https://github.com/swiftlang/swift/issues/78371
Resolves: rdar://142105691
2025-01-09 11:28:24 -08:00
Pavel Yaskevich
6c82892c3c [CSOptimizer] NFC: check whether a choice is of operator instead of whole disjunction 2025-01-09 10:39:18 -08:00
Pavel Yaskevich
8a304f88c6 [CSOptimizer] Extend candidate/parameter matching to support array literals
Match `[...]` to Array<...> and/or `ExpressibleByArrayLiteral`
conforming types. This is very helpful for expressions like:
`[...] + [...]`.
2024-12-25 12:51:01 -08:00
Pavel Yaskevich
0737542da8 [CSOptimizer] Favor choices that don't require application
When disjunction is not applied, don't only bump its score
but also favor all of the choices that don't require application
because selection algorithm uses that for comparison.

This is important for situation when property is overload with
a method i.e. `Array.count`.
2024-12-24 17:12:36 -08:00
Pavel Yaskevich
bc3a15fbe6 [CSOptimizer] Disable CGFloat -> Double conversion for unary operators
Some of the unary operators, i.e. prefix `-`, don't have
CGFloat variants and expect generic `FloatingPoint` overload
to match CGFloat type. Let's not attempt `CGFloat` -> `Double`
conversion for unary operators because it always leads
to a worse solutions vs. generic overloads.
2024-12-18 00:22:49 -08:00
Pavel Yaskevich
860ae08d1b [CSOptimizer] Mark bitwise operators as supported 2024-12-17 16:44:18 -08:00
Pavel Yaskevich
43ca7dfff9 [CSOptimizer] Simplify handling of non-applied disjunctions
If a disjunction doesn't have an application, let's prefer
it if it's passed as an argument to an operator application
or involved in a member chain, in such situations attempting
a disjunction could provide context to parent call/member chain.

If disjunction is passed as an unapplied reference to some
parameter i.e. `<base>.map(String.init(describing:))` we don't
favor it for now because optimizer cannot do enough checking
to determine whether preferring such disjunction would help
make forward progress in solving by pruning some space or
providing additional context.
2024-12-17 16:44:06 -08:00
Pavel Yaskevich
95b47aead6 [CSOptimizer] Reduce overload types before ranking
This would make sure that any same-type requirements to a concrete
type are substituted with such types which is especially important
for SIMD operators like `&{+, -}` because they have `Scalar == (U)Int*`
requirements.
2024-12-17 11:36:42 -08:00
Pavel Yaskevich
56d6635e46 [CSOptimizer] Implement special prioritization rules for result builder contexts
Prioritize `build{Block, Expression, ...}` and any chained
members that are connected to individual builder elements
i.e. `ForEach(...) { ... }.padding(...)`, once `ForEach`
is resolved, `padding` should be prioritized because its
requirements can help prune the solution space before the
body is checked.
2024-12-17 11:36:42 -08:00
Pavel Yaskevich
bf8ae3bc1b [CSOptimizer] Allow only widening CGFloat->Double conversions while matching candidate arguments
Allow CGFloat -> Double widening conversions between
candidate argument types and parameter types. This would
make sure that Double is always preferred over CGFloat
when using literals and ranking supported disjunction
choices. Narrowing conversion (Double -> CGFloat) should
be delayed as much as possible.
2024-12-17 11:36:42 -08:00
Pavel Yaskevich
87cd5f8733 [CSOptimizer] Add support for chained members without arguments
If disjunction represents a member reference that has no arguments
applied, let's score that as `1` to indicate that it should be priorized.

This helps in situations like `a.b + 1` where resolving `a.b` member
chain helps to establish context for `+`.
2024-12-17 11:36:41 -08:00
Pavel Yaskevich
867e64182f [CSOptimizer] Mark compiler synthesized disjunctions as optimized
If a disjunction has favored choices, let's mark it as optimized
with a high score to make sure that such disjunctions are prioritized
since only disjunctions that could have their choices fovored
independently from the optimization algorithm are compiler synthesized
ones for things like IUO references, explicit coercions etc.
2024-12-17 11:36:41 -08:00
Pavel Yaskevich
15c773b9d7 [CSOptimizer] Make a light-weight generic overload check if some requirements are unsatisfiable
If some of the requirements of a generic overload reference other
generic parameters, the optimizer won't be able to satisfy them
because it only has candidates for one (current) parameter. In
cases like that, let's fallback to a light-weight protocol conformance
check instead of skipping an overload choice altogether.
2024-12-17 11:36:41 -08:00
Pavel Yaskevich
c2a55886f0 [CSOptimizer] Fix selectDisjunction to use favored choices even if disjunction was not optimized
Some disjunctions e.g. explicit coercions, compositions of restrictions,
and implicit CGFloat initializers have favored choices set independently
from optimization algorithm, `selectDisjunction` should account for
such situations.
2024-12-17 11:36:41 -08:00
Pavel Yaskevich
9fb73143f6 [CSOptimizer] Limit "old" behavior compatibility to unlabeled unary arguments
`favorMatchingOverloadExprs` used `getUnlabeledUnaryExpr` and we
need to mimic that exactly because there is code that relies on
this behavior now.
2024-12-17 11:36:41 -08:00
Pavel Yaskevich
2fdd4b6c35 [CSOptimizer] Allow literal arguments to match parameters that conform to ExpressibleBy{Integer, Float}Literal
`scoreCandidateMatch` needs to reflect the fact that literal can
assume any type that conforms to `ExpressibleBy{Integer, Float}Literal`
protocol but since such bindings are non-default and alway produce
a worse solution vs. default literal types if all of the arguments
are literals let's use only exact matches otherwise there is a chance
of "over-favoring" and creating more work for ranking.
2024-12-17 11:36:41 -08:00
Pavel Yaskevich
9b62c84a4f [CSOptimizer] Adjust scoreCandidateMatch to indicate when match cannot be decided
It is not always possible to match candidate types against corresponding
parameter types for certain overloads i.e. when parameter is an associated type.

`scoreCandidateMatch` needs to be able to indicate that to the caller
to allow it to move to the next parameter (if any) without failing the
overload choice when the match cannot be established.
2024-12-17 11:36:41 -08:00
Pavel Yaskevich
6caf1ccbb2 [CSOptimizer] Fix Double<->CGFloat implicit conversion support when arguments are literals
Passing Double to CGFloat as well as vice versa constitutes an exact match.
2024-12-17 11:36:41 -08:00
Pavel Yaskevich
e30587bda4 [CSOptimizer] A more comprehensive generic overload checking when candidates are fully resolved
Use `checkGenericRequirements` to check whether all of the requirements
placed on a particular parameter match, that gives us a lot of confidence
that the overload should be favored.
2024-12-17 11:36:40 -08:00
Pavel Yaskevich
a3a3ec4fe0 [CSOptimizer] Restore old hack behavior which used to favor overloads based on arity matches
This maintains an "old hack" behavior where overloads  of some
`OverloadedDeclRef` calls were favored purely based on number of
argument and (non-defaulted) parameters matching.

This is important to maintain source compatibility.
2024-12-17 11:36:40 -08:00
Pavel Yaskevich
802f5cd105 [CSOptimizer] Desugar types before checking for equality 2024-12-17 11:36:40 -08:00
Pavel Yaskevich
f2a6677a6d [CSOptimizer] Infer argument candidates from calls to Double and CGFloat constructors
Helps situations like `1 + {Double, CGFloat}(...)` by inferring
a type for the second operand of `+` based on a type being constructed.

Currently limited to Double and CGFloat only since we need to
support implicit `Double<->CGFloat` conversion.

Helps situations like `1 + CGFloat(...)` by inferring a type for
the second operand of `+` based on a type being constructed.
Currently limited to known integer, floating-point and CGFloat types
since we know how they are structured.
2024-12-17 11:36:40 -08:00
Pavel Yaskevich
59109c2d60 [CSOptimizer] Score all of the overload choices matching on literals uniformly
Regardless of whether an overload choice matched on one or more
literal candidate types assign it a fixed score to make sure that
we always prefer outmost disjunction in cases like `test(1 + 2 + 3)`
since it gives us a better chance to prune once there is a contextual
type.
2024-12-17 11:36:40 -08:00
Pavel Yaskevich
6fb6d1cf90 [CSOptimizer] Enable ranking of Int*, Float{80} and Double initializers 2024-12-17 11:36:40 -08:00
Pavel Yaskevich
8818d399f9 [CSOptimizer] Rank disjunctions based on score only if both sides are supported 2024-12-17 11:36:40 -08:00
Pavel Yaskevich
3996b25fbd [CSOptimizer] Rank results of operators regardless of whether anything is known about parameters
When operators are chained it's possible that we don't know anything
about parameter(s) but result is known from the context, we should
use that information.
2024-12-17 11:36:40 -08:00
Pavel Yaskevich
23589add74 [CSOptimizer] Average score should reflect number of defaulted parameters 2024-12-17 11:36:40 -08:00
Pavel Yaskevich
8a918e2369 [CSOptimizer] Don't optimize (implicit) calls with code completion arguments
`containsIDEInspectionTarget` doesn't work for implicit argument
lists, but luckily implicit code completion expressions cannot
be injected into arguments, so we can check whether whether they
appear at an argument position and prevent optimization.
2024-12-17 11:36:40 -08:00
Pavel Yaskevich
deca9b61c5 [CSOptimizer] attempt to rank only standard/simd operators and fully concrete overload sets 2024-12-17 11:36:39 -08:00
Pavel Yaskevich
3819ddfb40 [CSOptimizer] Record best scores for each disjunction and use them in selectDisjunction
If there is no single best disjunction use best scores first
to determine minimum with fallback to favored and/or active
choice counts.
2024-12-17 11:36:39 -08:00
Pavel Yaskevich
cf05405eae [CSOptimizer] Let determineBestChoicesInContext return the best disjunction if one is available
If there is one overall best disjunction, let's attempt it first.
2024-12-17 11:36:39 -08:00
Pavel Yaskevich
527de22bec [CSOptimizer] Emulate old behavior related to favoring of unary calls to members
Preserves old behavior where for unary calls to members
the solver would not consider choices that didn't match on
the number of parameters (regardless of defaults) and only
exact matches were favored.
2024-12-17 11:36:39 -08:00
Pavel Yaskevich
d69b6a0594 [CSOptimizer] Prefer homogeneous arithmetic operator overloads when argument(s) or result match
This is an opportunistic optimization based on the operator
use patterns where homogeneous operators are the most
heavily used ones.
2024-12-17 11:36:39 -08:00
Pavel Yaskevich
1760bd1f1e [CSOptimizer] Remove an outdated optimization to compare resolved argument types with all else equal
This is already accounted for by `determineBestChoicesInContext`
and reflected in the overall score, which means that we no longer
need to use this in vacuum.
2024-12-17 11:36:39 -08:00
Pavel Yaskevich
c429f5b9ec [CSOptimizer] NFC: Switch from llvm::Optional to std::optional post-rebase 2024-12-17 11:36:39 -08:00
Pavel Yaskevich
2869dff995 [CSOptimizer] Increase score when type matches opaque type
Since erasure of a concrete type into an existential value yields
score of 1, we need to bump the score in cases where a type
passed to a generic parameter satisfies all of its protocol
conformance requirements and that parameter represents an
opaque type.
2024-12-17 11:36:39 -08:00
Pavel Yaskevich
0fc6806922 [CSOptimizer] NFC: Switch to llvm::Optional 2024-12-17 11:36:39 -08:00
Pavel Yaskevich
da65333d41 [CSOptimizer] NFC: Adjust conformance check to use ConstraintSystem::lookupConformance 2024-12-17 11:36:38 -08:00
Pavel Yaskevich
957a5f4270 [CSOptimizer] Treat all type parameters equally
Dependent members just like generic parameter types could
have associated protocol conformances which give us a glimpse
into whether arguments could possibly match.
2024-12-17 11:36:38 -08:00
Pavel Yaskevich
11b897b32f [CSOptimizer] Relax candidate type requirements from equality to set of no-impact conversions
Candidate is viable (with some score) if:

- Candidate is exactly equal to a parameter type
- Candidate type differs from a parameter type only in optionality
- Parameter is a generic parameter type and all conformances are matched by a candidate type
- Candidate tuples matches a parameter tuple on arity
- Candidate is an `Array<T>` and parameter is an `Unsafe*Pointer`
- Candidate is a subclass of a parameter class type
- Candidate is a concrete type and parameter is its existential value (except Any)
2024-12-17 11:36:38 -08:00
Pavel Yaskevich
cb1cb2018d [CSOptimizer] Use matchCallArguments to establish argument-to-parameter relationships
This helps to find defaulted parameter positions as well.
2024-12-17 11:36:38 -08:00
Pavel Yaskevich
14e2a16fce [CSOptimizer] Don't attempt to optimize calls with code completion token(s) in argument position 2024-12-17 11:36:38 -08:00
Pavel Yaskevich
bc5f70a9a3 [CSOptimizer] Allow generic operator overloads without associated type parameters 2024-12-17 11:36:38 -08:00
Pavel Yaskevich
7c1c46d4e4 [CSOptimizer] Make sure that all parameters without arguments are defaulted 2024-12-17 11:36:38 -08:00
Pavel Yaskevich
e404ed722a [CSStep] Don't favor choices until the disjunction is picked 2024-12-17 11:36:38 -08:00
Pavel Yaskevich
a094c3ebb0 [CSOptimizer] Keep track of mismatches while evaluating candidates 2024-12-17 11:36:38 -08:00
Pavel Yaskevich
c2f7451c7b [CSOptimizer] Favor SIMD related arithmetic operator choices if argument is SIMD<N> type 2024-12-17 11:36:38 -08:00
Pavel Yaskevich
672ae3d252 [CSOptimizer] Initial implementation of disjunction choice favoring algorithm
This algorithm attempts to ensure that the solver always picks a disjunction
it knows the most about given the previously deduced type information.

For example in chains of operators like: `let _: (Double) -> Void = { 1 * 2 + $0 - 5 }`

The solver is going to start from `2 + $0` because `$0` is known to be `Double` and
then proceed to `1 * ...` and only after that to `... - 5`.

The algorithm is pretty simple:

- Collect "candidate" types for each argument
  - If argument is bound then the set going to be represented by just one type
  - Otherwise:
    - Collect all the possible bindings
    - Add default literal type (if any)

- Collect "candidate" types for result

- For each disjunction in the current scope:
  - Compute a favoring score for each viable* overload choice:
    - Compute score for each parameter:
      - Match parameter flags to argument flags
      - Match parameter types to a set of candidate argument types
        - If it's an exact match
          - Concrete type: score = 1.0
          - Literal default: score = 0.3
        - Highest scored candidate type wins.
      - If none of the candidates match and they are all non-literal
        remove overload choice from consideration.

    - Average the score by dividing it by the number of parameters
      to avoid disfavoring disjunctions with fewer arguments.

    - Match result type to a set of candidates; add 1 to the score
      if one of the candidate types matches exactly.

  - The best choice score becomes a disjunction score

- Compute disjunction scores for all of the disjunctions in scope.

- Pick disjunction with the best overall score and favor choices with
  the best local candidate scores (if some candidates have equal scores).

- Viable overloads include:
  - non-disfavored
  - non-disabled
  - available
  - non-generic (with current exception to SIMD)
2024-12-17 11:36:38 -08:00