Skip to content

Commit b399479

Browse files
committed
[AST] Add a missing check for Sendable in single protocol existential case
`any Sendable` should be considered Objective-C capable just like it's protocol composition with other Objective-C capable types. Resolves: rdar://102728938
1 parent 1b521a5 commit b399479

File tree

3 files changed

+39
-4
lines changed

3 files changed

+39
-4
lines changed

include/swift/AST/ExistentialLayout.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,10 @@ struct ExistentialLayout {
110110
/// Zero or more primary associated type requirements from a
111111
/// ParameterizedProtocolType
112112
ArrayRef<Type> sameTypeRequirements;
113+
114+
/// Existentials allow a relaxed notion of \c ValueDecl::isObjC
115+
/// that includes `Sendable` protocol.
116+
static bool isObjCProtocol(ProtocolDecl *P);
113117
};
114118

115119
}

lib/AST/Type.cpp

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -342,7 +342,7 @@ ExistentialLayout::ExistentialLayout(CanProtocolType type) {
342342

343343
hasExplicitAnyObject = false;
344344
hasInverseCopyable = false;
345-
containsNonObjCProtocol = !protoDecl->isObjC();
345+
containsNonObjCProtocol = !isObjCProtocol(protoDecl);
346346
containsParameterized = false;
347347

348348
protocols.push_back(protoDecl);
@@ -392,9 +392,7 @@ ExistentialLayout::ExistentialLayout(CanProtocolCompositionType type) {
392392
protoDecl = parameterized->getProtocol();
393393
containsParameterized = true;
394394
}
395-
containsNonObjCProtocol |=
396-
!protoDecl->isObjC() &&
397-
!protoDecl->isSpecificProtocol(KnownProtocolKind::Sendable);
395+
containsNonObjCProtocol |= !isObjCProtocol(protoDecl);
398396
protocols.push_back(protoDecl);
399397
}
400398
}
@@ -405,6 +403,10 @@ ExistentialLayout::ExistentialLayout(CanParameterizedProtocolType type)
405403
containsParameterized = true;
406404
}
407405

406+
bool ExistentialLayout::isObjCProtocol(ProtocolDecl *P) {
407+
return P->isObjC() || P->isSpecificProtocol(KnownProtocolKind::Sendable);
408+
}
409+
408410
ExistentialLayout TypeBase::getExistentialLayout() {
409411
return getCanonicalType().getExistentialLayout();
410412
}
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
// RUN: %empty-directory(%t)
2+
// RUN: %target-swift-frontend(mock-sdk: %clang-importer-sdk) -typecheck %s -parse-as-library -emit-objc-header-path %t/swift.h
3+
// RUN: %FileCheck %s < %t/swift.h
4+
5+
// REQUIRES: concurrency
6+
// REQUIRES: asserts
7+
// REQUIRES: objc_interop
8+
9+
import Foundation
10+
11+
@objc public protocol P {}
12+
13+
@objc public class Klass : NSObject {
14+
// CHECK: - (void)test1:(NSDictionary<NSString *, id> * _Nonnull)_;
15+
@objc public func test1(_: [String: any Sendable]) {}
16+
// CHECK: - (void)test2:(NSDictionary<NSString *, id <P>> * _Nonnull)_;
17+
@objc public func test2(_: [String: any P & Sendable]) {}
18+
}
19+
20+
@objc public protocol Q {
21+
// CHECK: - (NSArray<NSDictionary<NSString *, id> *> * _Nonnull)data1 SWIFT_WARN_UNUSED_RESULT;
22+
func data1() -> [[String: any Sendable]]
23+
// CHECK: - (NSArray<id> * _Nullable)data2 SWIFT_WARN_UNUSED_RESULT;
24+
func data2() -> [any Sendable]?
25+
// CHECK: - (void)data3:(id _Nonnull)_;
26+
func data3(_: any Sendable)
27+
// CHECK: - (void)data4:(id _Nullable)_;
28+
func data4(_: (any Sendable)?)
29+
}

0 commit comments

Comments
 (0)