@@ -3650,6 +3650,75 @@ static ConstraintSystem::TypeMatchResult matchDeepTypeArguments(
36503650 return allMatch;
36513651}
36523652
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+
36533722ConstraintSystem::TypeMatchResult
36543723ConstraintSystem::matchDeepEqualityTypes(Type type1, Type type2,
36553724 ConstraintLocatorBuilder locator) {
@@ -3700,11 +3769,19 @@ ConstraintSystem::matchDeepEqualityTypes(Type type1, Type type2,
37003769 if (auto *existential1 = type1->getAs<ExistentialType>()) {
37013770 auto existential2 = type2->castTo<ExistentialType>();
37023771
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));
37083785
37093786 if (result.isFailure())
37103787 return result;
0 commit comments