Skip to content

Commit e9b297a

Browse files
authored
Merge pull request #69472 from xedin/rdar-102728938
[AST/TypeChecker] Allow existential values of Sendable be used from Objective-C
2 parents 25f4ad4 + b399479 commit e9b297a

File tree

7 files changed

+52
-9
lines changed

7 files changed

+52
-9
lines changed

include/swift/AST/DiagnosticsSema.def

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6047,8 +6047,9 @@ ERROR(invalid_objc_decl_context,none,
60476047
"@objc can only be used with members of classes, @objc protocols, and "
60486048
"concrete extensions of classes", ())
60496049
ERROR(invalid_objc_decl,none,
6050-
"only classes (and their extensions), protocols, methods, initializers, "
6051-
"properties, and subscript declarations can be declared @objc", ())
6050+
"only classes (and their extensions), non-marker protocols, methods, "
6051+
"initializers, properties, and subscript declarations can be declared"
6052+
" @objc", ())
60526053
ERROR(invalid_objc_swift_rooted_class,none,
60536054
"only classes that inherit from NSObject can be declared @objc", ())
60546055
NOTE(invalid_objc_swift_root_class_insert_nsobject,none,

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
}

lib/PrintAsClang/ModuleContentsWriter.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -326,7 +326,8 @@ class ModuleWriter {
326326
(void)addImport(CD);
327327
}
328328
} else if (auto PD = dyn_cast<ProtocolDecl>(TD)) {
329-
forwardDeclare(PD);
329+
if (!PD->isMarkerProtocol())
330+
forwardDeclare(PD);
330331
} else if (auto TAD = dyn_cast<TypeAliasDecl>(TD)) {
331332
bool imported = false;
332333
if (TAD->hasClangNode())

lib/Sema/TypeCheckAttr.cpp

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1310,9 +1310,12 @@ void AttributeChecker::visitObjCAttr(ObjCAttr *attr) {
13101310

13111311
// Only certain decls can be ObjC.
13121312
llvm::Optional<Diag<>> error;
1313-
if (isa<ClassDecl>(D) ||
1314-
isa<ProtocolDecl>(D)) {
1313+
if (isa<ClassDecl>(D)) {
13151314
/* ok */
1315+
} else if (auto *P = dyn_cast<ProtocolDecl>(D)) {
1316+
if (P->isMarkerProtocol())
1317+
error = diag::invalid_objc_decl;
1318+
/* ok on non-marker protocols */
13161319
} else if (auto Ext = dyn_cast<ExtensionDecl>(D)) {
13171320
if (!Ext->getSelfClassDecl())
13181321
error = diag::objc_extension_not_class;
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+
}

test/attr/attr_marker_protocol.swift

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,3 +67,6 @@ protocol P10 { }
6767

6868
extension Array: P10 where Element: P10, Element: P8 { }
6969
// expected-error@-1{{conditional conformance to non-marker protocol 'P10' cannot depend on conformance of 'Element' to marker protocol 'P8'}}
70+
71+
@objc @_marker protocol P11 {}
72+
// expected-error@-1 {{only classes (and their extensions), non-marker protocols, methods, initializers, properties, and subscript declarations can be declared @objc}}

0 commit comments

Comments
 (0)