Skip to content

Commit 76f25e5

Browse files
committed
Allow @nonobjc inits in objcImpl extensions
Initializers can’t be made final, but they *can* be made @nonobjc. (This isn’t always enough to ensure they’re actually valid, but I’ll get to that in a follow-up commit.)
1 parent 2ff70e0 commit 76f25e5

File tree

3 files changed

+40
-3
lines changed

3 files changed

+40
-3
lines changed

Diff for: lib/AST/Decl.cpp

+1
Original file line numberDiff line numberDiff line change
@@ -4300,6 +4300,7 @@ isObjCMemberImplementation(const ValueDecl *VD,
43004300
? cast<AccessorDecl>(VD)->getStorage()
43014301
: VD;
43024302
return !attrDecl->isFinal()
4303+
&& !attrDecl->getAttrs().hasAttribute<NonObjCAttr>()
43034304
&& !attrDecl->getAttrs().hasAttribute<OverrideAttr>()
43044305
&& getAccessLevel() >= AccessLevel::Internal;
43054306
}

Diff for: lib/Sema/TypeCheckDeclObjC.cpp

+9-3
Original file line numberDiff line numberDiff line change
@@ -3553,9 +3553,15 @@ class ObjCImplementationChecker {
35533553
"private ");
35543554
}
35553555

3556-
diagnose(cand, diag::fixit_add_final_for_objc_implementation,
3557-
cand->getDescriptiveKind())
3558-
.fixItInsert(cand->getAttributeInsertionLoc(true), "final ");
3556+
// Initializers can't be 'final', but they can be '@nonobjc'
3557+
if (isa<ConstructorDecl>(cand))
3558+
diagnose(cand, diag::fixit_add_nonobjc_for_objc_implementation,
3559+
cand->getDescriptiveKind())
3560+
.fixItInsert(cand->getAttributeInsertionLoc(false), "@nonobjc ");
3561+
else
3562+
diagnose(cand, diag::fixit_add_final_for_objc_implementation,
3563+
cand->getDescriptiveKind())
3564+
.fixItInsert(cand->getAttributeInsertionLoc(true), "final ");
35593565
}
35603566
}
35613567
};

Diff for: test/decl/ext/objc_implementation.swift

+30
Original file line numberDiff line numberDiff line change
@@ -183,6 +183,36 @@ protocol EmptySwiftProto {}
183183
class func instanceMethod2(_: CInt) {
184184
// expected-warning@-1 {{class method 'instanceMethod2' does not match instance method declared in header; this will become an error before '@_objcImplementation' is stabilized}} {{3-9=}}
185185
}
186+
187+
public init(notFromHeader1: CInt) {
188+
// expected-warning@-1 {{initializer 'init(notFromHeader1:)' does not match any initializer declared in the headers for 'ObjCClass'; did you use the initializer's Swift name?}}
189+
// expected-note@-2 {{add 'private' or 'fileprivate' to define an Objective-C-compatible initializer not declared in the header}} {{3-9=private}}
190+
// expected-note@-3 {{add '@nonobjc' to define a Swift-only initializer}} {{3-3=@nonobjc }}
191+
}
192+
193+
public required init(notFromHeader2: CInt) {
194+
// expected-warning@-1 {{initializer 'init(notFromHeader2:)' does not match any initializer declared in the headers for 'ObjCClass'; did you use the initializer's Swift name?}}
195+
// expected-note@-2 {{add 'private' or 'fileprivate' to define an Objective-C-compatible initializer not declared in the header}} {{3-9=private}}
196+
// expected-note@-3 {{add '@nonobjc' to define a Swift-only initializer}} {{3-3=@nonobjc }}
197+
}
198+
199+
public convenience init(notFromHeader3: CInt) {
200+
// expected-warning@-1 {{initializer 'init(notFromHeader3:)' does not match any initializer declared in the headers for 'ObjCClass'; did you use the initializer's Swift name?}}
201+
// expected-note@-2 {{add 'private' or 'fileprivate' to define an Objective-C-compatible initializer not declared in the header}} {{3-9=private}}
202+
// expected-note@-3 {{add '@nonobjc' to define a Swift-only initializer}} {{3-3=@nonobjc }}
203+
}
204+
205+
@nonobjc public init(notFromHeader4: CInt) {
206+
// FIXME: Should be an error; requires a vtable entry
207+
}
208+
209+
@nonobjc public required init(notFromHeader5: CInt) {
210+
// FIXME: Should be an error; requires a vtable entry
211+
}
212+
213+
@nonobjc public convenience init(notFromHeader6: CInt) {
214+
// OK
215+
}
186216
}
187217

188218
@_objcImplementation(PresentAdditions) extension ObjCClass {

0 commit comments

Comments
 (0)