@@ -3621,6 +3621,75 @@ static ConstraintSystem::TypeMatchResult matchDeepTypeArguments(
36213621 return allMatch;
36223622}
36233623
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+
36243693ConstraintSystem::TypeMatchResult
36253694ConstraintSystem::matchDeepEqualityTypes(Type type1, Type type2,
36263695 ConstraintLocatorBuilder locator) {
@@ -3671,11 +3740,19 @@ ConstraintSystem::matchDeepEqualityTypes(Type type1, Type type2,
36713740 if (auto *existential1 = type1->getAs<ExistentialType>()) {
36723741 auto existential2 = type2->castTo<ExistentialType>();
36733742
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));
36793756
36803757 if (result.isFailure())
36813758 return result;
0 commit comments