Skip to content

Commit c6a8cbf

Browse files
committed
[CSSimplify] Allow any Sendable to match Any while matching generic arguments
Allow `any Sendable` to match `Any` constraint while matching generic arguments i.e. `[any Sendable]` -> `[Any]` when `any Sendable` type comes from context that involves `@preconcurrency` declarations in non-strict concurrency compiler mode. Note that it's currently impossible to figure out precisely where `any Sendable` type came from.
1 parent 17093b3 commit c6a8cbf

File tree

1 file changed

+82
-5
lines changed

1 file changed

+82
-5
lines changed

lib/Sema/CSSimplify.cpp

Lines changed: 82 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -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+
36533722
ConstraintSystem::TypeMatchResult
36543723
ConstraintSystem::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

Comments
 (0)