@@ -3621,6 +3621,75 @@ static ConstraintSystem::TypeMatchResult matchDeepTypeArguments(
3621
3621
return allMatch;
3622
3622
}
3623
3623
3624
+ /// Allow `any Sendable` to match `Any` constraint while matching
3625
+ /// generic arguments i.e. `[any Sendable]` -> `[Any]` when `any Sendable`
3626
+ /// type comes from context that involves `@preconcurrency` declarations
3627
+ /// in non-strict concurrency compiler mode.
3628
+ ///
3629
+ /// Note that it's currently impossible to figure out precisely
3630
+ /// where `any Sendable` type came from.
3631
+ static bool matchSendableExistentialToAnyInGenericArgumentPosition(
3632
+ ConstraintSystem &cs, ConstraintLocatorBuilder locator) {
3633
+ auto &ctx = cs.getASTContext();
3634
+ if (ctx.isSwiftVersionAtLeast(6) ||
3635
+ ctx.LangOpts.StrictConcurrencyLevel == StrictConcurrency::Complete)
3636
+ return false;
3637
+
3638
+ auto last = locator.last();
3639
+ if (!last || !last->is<LocatorPathElt::GenericArgument>())
3640
+ return false;
3641
+
3642
+ std::function<bool(ConstraintLocator *)> isPreconcurrencyContext =
3643
+ [&](ConstraintLocator *locator) {
3644
+ if (locator->isLastElement<LocatorPathElt::ApplyArgToParam>())
3645
+ return isPreconcurrencyContext(
3646
+ cs.getConstraintLocator(simplifyLocatorToAnchor(locator)));
3647
+
3648
+ auto *calleeLoc = cs.getCalleeLocator(locator);
3649
+ if (!calleeLoc)
3650
+ return false;
3651
+
3652
+ auto selectedOverload = cs.findSelectedOverloadFor(calleeLoc);
3653
+ if (!(selectedOverload && selectedOverload->choice.isDecl()))
3654
+ return false;
3655
+
3656
+ if (!selectedOverload->choice.getDecl()->preconcurrency()) {
3657
+ // If the member is not preconcurrency, its base could be.
3658
+ if (auto *UDE =
3659
+ getAsExpr<UnresolvedDotExpr>(calleeLoc->getAnchor())) {
3660
+ return isPreconcurrencyContext(
3661
+ cs.getConstraintLocator(UDE->getBase()));
3662
+ }
3663
+ return false;
3664
+ }
3665
+
3666
+ return true;
3667
+ };
3668
+
3669
+ SmallVector<LocatorPathElt> path;
3670
+ auto anchor = locator.getLocatorParts(path);
3671
+
3672
+ // Drop all of the generic type and argument elements
3673
+ // from the locator first.
3674
+ while (!path.empty()) {
3675
+ auto last = path.back();
3676
+ if (last.is<LocatorPathElt::GenericArgument>() ||
3677
+ last.is<LocatorPathElt::GenericType>()) {
3678
+ path.pop_back();
3679
+ continue;
3680
+ }
3681
+ break;
3682
+ }
3683
+
3684
+ if (!isPreconcurrencyContext(cs.getConstraintLocator(anchor, path)))
3685
+ return false;
3686
+
3687
+ // Increase the score to make sure that if there is an overload that
3688
+ // uses `any Sendable` it would be preferred.
3689
+ cs.increaseScore(SK_EmptyExistentialConversion, locator);
3690
+ return true;
3691
+ }
3692
+
3624
3693
ConstraintSystem::TypeMatchResult
3625
3694
ConstraintSystem::matchDeepEqualityTypes(Type type1, Type type2,
3626
3695
ConstraintLocatorBuilder locator) {
@@ -3671,11 +3740,19 @@ ConstraintSystem::matchDeepEqualityTypes(Type type1, Type type2,
3671
3740
if (auto *existential1 = type1->getAs<ExistentialType>()) {
3672
3741
auto existential2 = type2->castTo<ExistentialType>();
3673
3742
3674
- auto result = matchTypes(existential1->getConstraintType(),
3675
- existential2->getConstraintType(),
3676
- ConstraintKind::Bind, subflags,
3677
- locator.withPathElement(
3678
- ConstraintLocator::ExistentialConstraintType));
3743
+ auto constraintTy1 = existential1->getConstraintType();
3744
+ auto constraintTy2 = existential2->getConstraintType();
3745
+
3746
+ if (constraintTy1->getKnownProtocol() == KnownProtocolKind::Sendable &&
3747
+ constraintTy2->isAny()) {
3748
+ if (matchSendableExistentialToAnyInGenericArgumentPosition(*this,
3749
+ locator))
3750
+ return getTypeMatchSuccess();
3751
+ }
3752
+
3753
+ auto result = matchTypes(
3754
+ constraintTy1, constraintTy2, ConstraintKind::Bind, subflags,
3755
+ locator.withPathElement(ConstraintLocator::ExistentialConstraintType));
3679
3756
3680
3757
if (result.isFailure())
3681
3758
return result;
0 commit comments