[CSSimplify] Skip member access on existential checks if base is existential only due to marker protocols

If the base type is composed with marker protocol(s) i.e.
`<<Type>> & Sendable`, let's skip this check because such
compositions are always opened and simplified down to a
superclass bound post-Sema.

Resolves: rdar://148782046
This commit is contained in:
Pavel Yaskevich
2025-08-04 16:56:51 -07:00
parent 3879a47b52
commit 387b4ff2d3
2 changed files with 48 additions and 13 deletions

View File

@@ -10431,22 +10431,33 @@ performMemberLookup(ConstraintKind constraintKind, DeclNameRef memberName,
}
const auto isUnsupportedExistentialMemberAccess = [&] {
// We may not be able to derive a well defined type for an existential
// member access if the member's signature references 'Self'.
if (instanceTy->isExistentialType()) {
switch (isMemberAvailableOnExistential(instanceTy, decl)) {
case ExistentialMemberAccessLimitation::Unsupported:
// TODO: Write-only accesses are not supported yet.
case ExistentialMemberAccessLimitation::WriteOnly:
return true;
if (!instanceTy->isExistentialType())
return false;
case ExistentialMemberAccessLimitation::ReadOnly:
case ExistentialMemberAccessLimitation::None:
break;
}
// If the base type is composed with marker protocol(s) i.e.
// `<<Type>> & Sendable`, let's skip this check because such
// compositions are always opened and simplified down to a
// superclass bound post-Sema.
if (auto *existential = instanceTy->getAs<ExistentialType>()) {
auto *compositionTy =
existential->getConstraintType()->getAs<ProtocolCompositionType>();
if (compositionTy &&
!compositionTy->withoutMarkerProtocols()->isExistentialType())
return false;
}
return false;
// We may not be able to derive a well defined type for an existential
// member access if the member's signature references 'Self'.
switch (isMemberAvailableOnExistential(instanceTy, decl)) {
case ExistentialMemberAccessLimitation::Unsupported:
// TODO: Write-only accesses are not supported yet.
case ExistentialMemberAccessLimitation::WriteOnly:
return true;
case ExistentialMemberAccessLimitation::ReadOnly:
case ExistentialMemberAccessLimitation::None:
return false;
}
};
// See if we have an instance method, instance member or static method,

View File

@@ -58,3 +58,27 @@ do {
generic(Int.self)
// CHECK: D<Int>
}
protocol Q {
func update(_: [Self])
}
extension Q {
func update(_ arr: [Self]) { print(Self.self) }
}
do {
class Parent : Q {}
class Subclass: Parent {}
func test(_ v: Parent & Sendable) {
v.update([])
}
test(Subclass())
// CHECK: Subclass
let sendableV: any Subclass & Sendable = Subclass()
test(sendableV)
// CHECK: Subclass
}