Skip to content

Commit 004083d

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. (cherry picked from commit c6a8cbf)
1 parent 6811ce8 commit 004083d

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
@@ -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+
36243693
ConstraintSystem::TypeMatchResult
36253694
ConstraintSystem::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

Comments
 (0)