Commit Graph

632 Commits

Author SHA1 Message Date
Slava Pestov a2ed8c66c2 Merge pull request #88875 from slavapestov/fix-rdar152143989
Sema: Don't record bogus trail changes in salvage()
2026-05-08 15:37:53 -04:00
Slava Pestov 6db1fd00e9 Sema: Don't record bogus trail changes in salvage()
In salvage(), there is a point where we're done solving, but we haven't
yet torn down ConstraintSystem::solverState, so the trail is still
active.

It was possible to cause a change to be recorded, because of the
path compression we do in TypeVariableType::getRepresentative().

We have a similar situation where we don't want to do path compression
when we're looking up a type variable's representative in the middle
of undo(). Generalize the existing UndoActive flag to Closed, and set
it after solving in salvage() as well.

While we're here, clean up an existing place where we would check
isUndoActive() to not do that anymore, so now getRepresentative() is
the only place that checks the state of the trail.

A better cleanup would be to try to refactor or eliminate SolverState
entirely, but this fix is pretty clean.

Note that the test cases are somewhat random because the exact scenario
is hard to trigger; you need to set up an invalid expression where the
type variables are set up in just the right way so that path compression
kicks in.

- Fixes rdar://152143989.
- Fixes https://github.com/swiftlang/swift/issues/81801.
- Fixes https://github.com/swiftlang/swift/issues/84884.
2026-05-06 11:51:40 -04:00
hectar-glitches 07c7e9a4a5 [NFC] Replace interleave(..., ", ") with interleaveComma in CSBindings
interleaveComma is a convenience wrapper that hardcodes ", " as the
separator. Use it in the 2 call sites in CSBindings.cpp where the
separator was being passed explicitly.
2026-05-05 01:09:39 -04:00
Slava Pestov 59adfcd02b Sema: Detect conflicting subtype bindings imposed on closure type variables
A type variable that represents the type of a closure can only be bound
to a function type, but this fact is not directly encoded in the
constraint system.

Check for the appearance of a non-sensical subtype binding on a closure
type variable in reduceBinding(), and promote the binding to exact as
soon as we detect this, since binding the type will always fail; we want
to fail as quickly as possible, before attempting any more disjunctions.

This is a generally good performance optimization, and it also addresses
a performance regression from "Sema: Filter bindings by considering
conformance constraints".

This also speeds up the expression from rdar://59008707, which also uses
Combine and is slow for similar reasons.
2026-03-10 14:51:19 -04:00
Slava Pestov 00064dce9d Sema: Strengthen Subtypes vs Supertypes case in subsumeBinding() 2026-03-10 14:47:30 -04:00
Slava Pestov 467943c4dc Sema: Strengthen Supertypes vs Subtypes case in subsumeBinding() 2026-03-10 14:47:29 -04:00
Slava Pestov 0dce1e5649 Sema: Strengthen Subtypes vs Exact case in subsumeBinding() 2026-03-10 14:47:29 -04:00
Slava Pestov e43da4d542 Sema: Strengthen Supertypes vs Exact case in subsumeBinding() 2026-03-10 14:47:29 -04:00
Slava Pestov 4a47329e51 Sema: Strengthen Exact vs Subtypes case in subsumeBinding() 2026-03-10 14:47:29 -04:00
Slava Pestov 4daf970e78 Sema: Strengthen Exact vs Supertypes case in subsumeBinding() 2026-03-10 14:47:29 -04:00
Slava Pestov eff8c42f14 Sema: Strengthen Exact vs Exact case in subsumeBinding() 2026-03-10 14:47:29 -04:00
Slava Pestov ac50d24af9 Sema: Refactor BindingSet::subsumeBinding()
This is NFC. All it does is expand out some of the if statements
to run through all combinations of (existing.Kind, binding.Kind)
in order.

This is extremely verbose, but I'm going to factor out the
common parts and also add new checks for various conditions so
I think it will be clearer in the end.
2026-03-10 14:47:29 -04:00
Slava Pestov 1f440f9a60 Sema: Turn subsumeBinding() into a method on BindingSet 2026-03-10 14:47:28 -04:00
Slava Pestov 9e3d18eb9f Sema: Recompute BindingSets when we begin salvage
In addition to the generation number, it is important to
recompute bindings when the constraint system transitions
from not doing salvage to salvage.

This fixes diagnostic regressions with an upcoming commit.
2026-03-10 14:47:28 -04:00
Slava Pestov 6c211745f6 Sema: Fix small problem in inferTransitiveKeyPathBindings()
It looks like originally, we would only infer bindings from a
KeyPath type, which has invariant generic arguments. However,
nowadays we can infer a keypath root type from a function
type as well, because we allow keypath to function conversions.

So, if we inferred the key path root type through a function type,
then in fact we cannot introduce it as an exact binding, and
we must preserve variance.

This fixes a test failure that appears with a subsequent change
I'm making.
2026-03-10 14:47:28 -04:00
Slava Pestov 227b3cb813 Sema: Filter bindings by considering conformance constraints 2026-03-10 14:47:28 -04:00
Slava Pestov bd0c1212e2 Sema: Factor out reduceBinding() from BindingSet::addBinding() 2026-03-10 10:12:59 -04:00
Slava Pestov 266ac2cffb Sema: Bring back BindingSet::Protocols 2026-03-10 10:12:58 -04:00
Slava Pestov e44f9eda97 Sema: Introduce BindingSet::isConflicting() 2026-03-10 10:12:58 -04:00
Slava Pestov bd83717764 Sema: BindingSet::Bindings can be a SmallVector
We already iterate over all existing bindings when adding a new
binding, so using a DenseSet offers no benefit.
2026-03-10 10:12:58 -04:00
Slava Pestov 4c06e137cc Sema: Favor exact binding sets over conjunctions, too 2026-03-10 10:12:57 -04:00
Kathy Gray 14f6d17d39 [CS] Improve property member lookup in presence of ProtocolCompositionTypes
Code with Protocol Composition parameters had not been taking into account
that a parameter would conform to all protocols in the composition on
member resolution and could fail to find a member for one protocol
on static lookups, resulting in a diagnostic that was incorrect even on
correct programs.

For example
```protocol P {
 static var boo
}
protocol Q {
}
func t<T: P&Q>(x: T) { }
t(.boo)```

Diagnostic of Q does not have member boo

(Yes, other diagnostics are required in this code)

This occured because P and Q were considered one path at a time.
After the change, the P&Q path is considered together instead.
2026-03-05 16:55:57 +00:00
Slava Pestov 787b273e68 Sema: Strengthen BindingSet::favoredOverConjunction()
We should delay binding the conjunction if any of the type variables it
references simplify to types that contain type variables as well.

Otherwise, if we have a result builder with a for-each loop over an Array
with a type variable element type, we might start solving the conjunction
before we bind the element type. This will fail.
2026-02-26 23:06:41 -05:00
Slava Pestov 9cf7131f23 Sema: Prefer binding sets with Exact bindings 2026-02-24 21:34:39 -05:00
Slava Pestov 049b93dce0 Sema: Fix over-eager binding with optional object constraint
If T has no subtypes, we have a constraint `$T0 conv T`, and
another constraint `$T1 optional with object type $T0`, we
must account for the possibility that $T0 is bound to
`@lvalue T`, if $T1 may be bound to an lvalue.
2026-02-24 21:34:38 -05:00
Slava Pestov 2f92ab8f4d Sema: Remove BindingSet::isDelayedByDisjunction() 2026-02-24 21:34:38 -05:00
Slava Pestov 0f7b72e995 Sema: Another spot where AllowedBindingKind::Exact is now too strict 2026-02-24 21:34:38 -05:00
Slava Pestov 4f8af94ceb Sema: Use getImpliedResultConversionKind() in inferFromRelational() 2026-02-24 21:34:38 -05:00
Slava Pestov 100867b6b3 Sema: Print lvalue state in BindingSet::dump() 2026-02-24 21:34:38 -05:00
Slava Pestov ab28031443 Sema: Consider lvalue-ness in the addBinding() subtype optimization
This was previously unsound, because if the type variable accepts
lvalue bindings, every type T has a subtype @lvalue T, and so in
some cases we would bind a type variable to an rvalue type too early.
2026-02-24 21:34:37 -05:00
Slava Pestov bea34b654f Sema: Try to guess lvalue-ness of type variable in binding inference
The result of this analysis will be used to rewrite 'subtypes of T'
into 'exact @lvalue T', fixing a soundness hole.
2026-02-24 21:34:37 -05:00
Slava Pestov b823d090ad Sema: Track LValueObject constraints in PotentialBindings
We would do stuff in the case where the type variable appeared on
the right, but just drop the constraint if the type variable was
on the left. In the latter case, record it in the new
PotentialBindings::LValuesOf vector.
2026-02-24 21:34:37 -05:00
Slava Pestov f8fbe133a1 Sema: Narrow down BindingSet::isDelayedByDisjunction() to lvalues only 2026-02-24 21:34:37 -05:00
Slava Pestov aed2b4acdd Sema: Handle UnresolvedValueMember in BindingSet::isDelayedByDisjunction() 2026-02-24 21:34:37 -05:00
Slava Pestov c2dab20402 Sema: Factor out isDelayedByDisjunction() from favoredOverDisjunction() 2026-02-24 21:34:37 -05:00
Slava Pestov d225b623dd Sema: Simplify a bit of logic in light of the previous change 2026-02-24 21:34:37 -05:00
Slava Pestov cb50072da3 Sema: Subtype bindings to types with no subtypes become Exact 2026-02-24 21:34:36 -05:00
Slava Pestov 6428ece8a8 Sema: Tweak handling of closure result type binding, which defaults to () 2026-02-24 21:34:36 -05:00
Slava Pestov 07d56569ee Sema: Change PotentialBinding equality 2026-02-24 21:34:36 -05:00
Slava Pestov ccd0f5387a Sema: Separate AllowedBindingKind::Fallback from Exact
These cases were using Exact incorrectly.
2026-02-24 21:34:36 -05:00
Slava Pestov 9d5bc0482c Sema: Exact bindings subsume Subtypes/Supertypes 2026-02-24 21:34:36 -05:00
Slava Pestov 3d9020c9a9 Sema: Reorder conditionals in BindingSet::favoredOverDisjunction() 2026-02-24 21:34:36 -05:00
Slava Pestov f85325d2f9 Sema: Clean up type join logic in BindingSet::addBinding() 2026-02-24 21:34:35 -05:00
Slava Pestov 86bc7088f4 Sema: Clean up CGFloat/Double hack in BindingSet::addBinding() 2026-02-24 21:34:35 -05:00
Slava Pestov c4527397a6 Sema: Factor out subsumeBinding() from BindingSet::addBinding() 2026-02-24 21:34:35 -05:00
Slava Pestov d2448cad45 Sema: Do lvalue check first in BindingSet::addBinding() 2026-02-24 21:34:35 -05:00
Slava Pestov d331306816 Sema: Try to clean up a hack in BindingSet::addBinding()
We would sometimes replace a binding whose type contains type
variables with one that does not. This is unsound in the general
case, but we need to to avoid performance problems and ambiguous
solutions in certain pathological cases.

I found two test cases in the test suite that exercised this
specific behavior. Extract them into their own file, and generalize
at the test case. At the same time, tweak the hack to narrow it
down a bit.
2026-02-24 21:34:35 -05:00
Slava Pestov c2cf86e644 Sema: Inline BindingSet::isViable(PotentialBinding) into addBinding() 2026-02-24 21:34:35 -05:00
Slava Pestov eed2316c56 Sema: Fix unnecessary ) in determineBestBindings() debug output 2026-02-24 21:34:35 -05:00
Slava Pestov dfd172f1f3 Sema: Don't recompute BindingSets quite as much 2026-02-20 21:59:23 -05:00