Skip to content

Commit 047f9e8

Browse files
authored
Merge pull request #16052 from jckarter/objc-generic-objc-protocol
Sema: Relax restriction on @objc conformances for lightweight generics.
2 parents 18683f3 + 7cf6b75 commit 047f9e8

File tree

3 files changed

+64
-8
lines changed

3 files changed

+64
-8
lines changed

lib/Sema/TypeCheckProtocol.cpp

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1495,15 +1495,21 @@ checkIndividualConformance(NormalProtocolConformance *conformance,
14951495
return conformance;
14961496
}
14971497
// And... even if it isn't conditional, we still don't currently support
1498-
// @objc protocols in extensions.
1498+
// @objc protocols in extensions of Swift generic classes, because there's
1499+
// no stable Objective-C class object to install the protocol conformance
1500+
// category onto.
14991501
if (isa<ExtensionDecl>(DC)) {
15001502
if (auto genericT = T->getGenericAncestor()) {
1501-
auto isSubclass = !genericT->isEqual(T);
1502-
auto genericTIsGeneric = (bool)genericT->getAnyGeneric()->getGenericParams();
1503-
TC.diagnose(ComplainLoc, diag::objc_protocol_in_generic_extension, T,
1504-
ProtoType, isSubclass, genericTIsGeneric);
1505-
conformance->setInvalid();
1506-
return conformance;
1503+
if (!cast<ClassDecl>(genericT->getAnyNominal())
1504+
->usesObjCGenericsModel()) {
1505+
auto isSubclass = !genericT->isEqual(T);
1506+
auto genericTIsGeneric = (bool)genericT->getAnyGeneric()
1507+
->getGenericParams();
1508+
TC.diagnose(ComplainLoc, diag::objc_protocol_in_generic_extension, T,
1509+
ProtoType, isSubclass, genericTIsGeneric);
1510+
conformance->setInvalid();
1511+
return conformance;
1512+
}
15071513
}
15081514
}
15091515
}
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
@import Foundation;
2+
3+
@interface OBJCGeneric<T> : NSObject
4+
@end
5+
6+
@interface OBJCGenericSubclass<T, U>: OBJCGeneric<T>
7+
@end
8+
9+
@interface OBJCNongenericSubclass: OBJCGenericSubclass<id, id>
10+
@end
11+
12+
@protocol OBJCProtocol1
13+
@end
14+
15+
@protocol OBJCProtocol2
16+
@end
17+
18+
@protocol OBJCProtocol3
19+
@end

test/decl/ext/extension-generic-objc-protocol.swift

Lines changed: 32 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,12 @@
1-
// RUN: %target-swift-frontend -typecheck -verify %s
1+
// RUN: %target-swift-frontend -import-objc-header %S/Inputs/extension-generic-objc-protocol.h -typecheck -verify %s
22

33
// REQUIRES: objc_interop
44

55
import Foundation
66

77
@objc protocol P {}
8+
@objc protocol Q {}
9+
@objc protocol R {}
810

911
public class C1<T> {}
1012
extension C1: P {}
@@ -27,3 +29,32 @@ class SubInner: Outer<Int>.Inner2 {}
2729

2830
extension SubInner: P {}
2931
// expected-error@-1 {{conformance of subclass of a class from generic context 'SubInner' to @objc protocol 'P' cannot be in an extension}}
32+
33+
// Lightweight generic ObjC classes can still be extended to conform.
34+
35+
extension OBJCGeneric: OBJCProtocol1 {}
36+
extension OBJCGeneric: P {}
37+
extension OBJCGenericSubclass: OBJCProtocol2 {}
38+
extension OBJCGenericSubclass: Q {}
39+
extension OBJCNongenericSubclass: OBJCProtocol3 {}
40+
extension OBJCNongenericSubclass: R {}
41+
42+
public class SwiftSubclassOfObjCGeneric: OBJCGeneric<AnyObject> {}
43+
44+
extension SwiftSubclassOfObjCGeneric: OBJCProtocol2 {}
45+
extension SwiftSubclassOfObjCGeneric: Q {}
46+
47+
public class SwiftGenericSubclassOfObjCGeneric<T: AnyObject>
48+
: OBJCGeneric<AnyObject>
49+
{}
50+
51+
extension SwiftGenericSubclassOfObjCGeneric: OBJCProtocol2 {} // expected-error {{cannot be in an extension}}
52+
extension SwiftGenericSubclassOfObjCGeneric: Q {} // expected-error {{cannot be in an extension}}
53+
54+
public class SwiftNongenericSubclassOfGenericSubclassOfObjCGeneric
55+
: SwiftGenericSubclassOfObjCGeneric<AnyObject>
56+
{}
57+
58+
extension SwiftNongenericSubclassOfGenericSubclassOfObjCGeneric: OBJCProtocol3 {} // expected-error {{cannot be in an extension}}
59+
extension SwiftNongenericSubclassOfGenericSubclassOfObjCGeneric: R {} // expected-error {{cannot be in an extension}}
60+

0 commit comments

Comments
 (0)