@@ -3650,6 +3650,75 @@ static ConstraintSystem::TypeMatchResult matchDeepTypeArguments(
3650
3650
return allMatch;
3651
3651
}
3652
3652
3653
+ /// Allow `any Sendable` to match `Any` constraint while matching
3654
+ /// generic arguments i.e. `[any Sendable]` -> `[Any]` when `any Sendable`
3655
+ /// type comes from context that involves `@preconcurrency` declarations
3656
+ /// in non-strict concurrency compiler mode.
3657
+ ///
3658
+ /// Note that it's currently impossible to figure out precisely
3659
+ /// where `any Sendable` type came from.
3660
+ static bool matchSendableExistentialToAnyInGenericArgumentPosition(
3661
+ ConstraintSystem &cs, ConstraintLocatorBuilder locator) {
3662
+ auto &ctx = cs.getASTContext();
3663
+ if (ctx.isSwiftVersionAtLeast(6) ||
3664
+ ctx.LangOpts.StrictConcurrencyLevel == StrictConcurrency::Complete)
3665
+ return false;
3666
+
3667
+ auto last = locator.last();
3668
+ if (!last || !last->is<LocatorPathElt::GenericArgument>())
3669
+ return false;
3670
+
3671
+ std::function<bool(ConstraintLocator *)> isPreconcurrencyContext =
3672
+ [&](ConstraintLocator *locator) {
3673
+ if (locator->isLastElement<LocatorPathElt::ApplyArgToParam>())
3674
+ return isPreconcurrencyContext(
3675
+ cs.getConstraintLocator(simplifyLocatorToAnchor(locator)));
3676
+
3677
+ auto *calleeLoc = cs.getCalleeLocator(locator);
3678
+ if (!calleeLoc)
3679
+ return false;
3680
+
3681
+ auto selectedOverload = cs.findSelectedOverloadFor(calleeLoc);
3682
+ if (!(selectedOverload && selectedOverload->choice.isDecl()))
3683
+ return false;
3684
+
3685
+ if (!selectedOverload->choice.getDecl()->preconcurrency()) {
3686
+ // If the member is not preconcurrency, its base could be.
3687
+ if (auto *UDE =
3688
+ getAsExpr<UnresolvedDotExpr>(calleeLoc->getAnchor())) {
3689
+ return isPreconcurrencyContext(
3690
+ cs.getConstraintLocator(UDE->getBase()));
3691
+ }
3692
+ return false;
3693
+ }
3694
+
3695
+ return true;
3696
+ };
3697
+
3698
+ SmallVector<LocatorPathElt> path;
3699
+ auto anchor = locator.getLocatorParts(path);
3700
+
3701
+ // Drop all of the generic type and argument elements
3702
+ // from the locator first.
3703
+ while (!path.empty()) {
3704
+ auto last = path.back();
3705
+ if (last.is<LocatorPathElt::GenericArgument>() ||
3706
+ last.is<LocatorPathElt::GenericType>()) {
3707
+ path.pop_back();
3708
+ continue;
3709
+ }
3710
+ break;
3711
+ }
3712
+
3713
+ if (!isPreconcurrencyContext(cs.getConstraintLocator(anchor, path)))
3714
+ return false;
3715
+
3716
+ // Increase the score to make sure that if there is an overload that
3717
+ // uses `any Sendable` it would be preferred.
3718
+ cs.increaseScore(SK_EmptyExistentialConversion, locator);
3719
+ return true;
3720
+ }
3721
+
3653
3722
ConstraintSystem::TypeMatchResult
3654
3723
ConstraintSystem::matchDeepEqualityTypes(Type type1, Type type2,
3655
3724
ConstraintLocatorBuilder locator) {
@@ -3700,11 +3769,19 @@ ConstraintSystem::matchDeepEqualityTypes(Type type1, Type type2,
3700
3769
if (auto *existential1 = type1->getAs<ExistentialType>()) {
3701
3770
auto existential2 = type2->castTo<ExistentialType>();
3702
3771
3703
- auto result = matchTypes(existential1->getConstraintType(),
3704
- existential2->getConstraintType(),
3705
- ConstraintKind::Bind, subflags,
3706
- locator.withPathElement(
3707
- ConstraintLocator::ExistentialConstraintType));
3772
+ auto constraintTy1 = existential1->getConstraintType();
3773
+ auto constraintTy2 = existential2->getConstraintType();
3774
+
3775
+ if (constraintTy1->getKnownProtocol() == KnownProtocolKind::Sendable &&
3776
+ constraintTy2->isAny()) {
3777
+ if (matchSendableExistentialToAnyInGenericArgumentPosition(*this,
3778
+ locator))
3779
+ return getTypeMatchSuccess();
3780
+ }
3781
+
3782
+ auto result = matchTypes(
3783
+ constraintTy1, constraintTy2, ConstraintKind::Bind, subflags,
3784
+ locator.withPathElement(ConstraintLocator::ExistentialConstraintType));
3708
3785
3709
3786
if (result.isFailure())
3710
3787
return result;
0 commit comments