Skip to content

Commit c4e152c

Browse files
committed
Soften objcImpl implicit final errors to warnings
Before the change from @_objcImplementation to @objc @implementation, if a member was unrepresentable in ObjC, it would become implicitly `final`. After that change, this is now an error. We do want a diagnostic here, but we don’t want to break backwards compatibility for early adopters. Soften the error to a warning when the old @objcImplementation syntax is used. Fixes rdar://129247349.
1 parent b3e7a23 commit c4e152c

File tree

3 files changed

+19
-3
lines changed

3 files changed

+19
-3
lines changed

lib/Sema/TypeCheckDeclObjC.cpp

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,13 @@ using namespace swift;
3838
DiagnosticBehavior
3939
swift::behaviorLimitForObjCReason(ObjCReason reason, ASTContext &ctx) {
4040
switch(reason) {
41+
case ObjCReason::MemberOfObjCImplementationExtension:
42+
// If they're using the old syntax, soften to a warning.
43+
if (cast<ObjCImplementationAttr>(reason.getAttr())->isEarlyAdopter())
44+
return DiagnosticBehavior::Warning;
45+
46+
LLVM_FALLTHROUGH;
47+
4148
case ObjCReason::ExplicitlyCDecl:
4249
case ObjCReason::ExplicitlyDynamic:
4350
case ObjCReason::ExplicitlyObjC:
@@ -51,7 +58,6 @@ swift::behaviorLimitForObjCReason(ObjCReason reason, ASTContext &ctx) {
5158
case ObjCReason::WitnessToObjC:
5259
case ObjCReason::ImplicitlyObjC:
5360
case ObjCReason::MemberOfObjCExtension:
54-
case ObjCReason::MemberOfObjCImplementationExtension:
5561
return DiagnosticBehavior::Unspecified;
5662

5763
case ObjCReason::ExplicitlyIBInspectable:

test/decl/ext/objc_implementation.swift

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -232,6 +232,11 @@ protocol EmptySwiftProto {}
232232
// rdar://122280735 - crash when the parameter of a block property needs @escaping
233233
let rdar122280735: (() -> ()) -> Void = { _ in }
234234
// expected-error@-1 {{property 'rdar122280735' of type '(() -> ()) -> Void' does not match type '(@escaping () -> Void) -> Void' declared by the header}}
235+
236+
private func privateNonObjCMethod(_: EmptySwiftProto) {
237+
// expected-error@-1 {{method cannot be in an @objc @implementation extension of a class (without final or @nonobjc) because the type of the parameter cannot be represented in Objective-C}}
238+
// expected-note@-2 {{protocol-constrained type containing protocol 'EmptySwiftProto' cannot be represented in Objective-C}}
239+
}
235240
}
236241

237242
@objc(PresentAdditions) @implementation extension ObjCClass {

test/decl/ext/objc_implementation_early_adopter.swift

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -229,6 +229,11 @@ protocol EmptySwiftProto {}
229229
// rdar://122280735 - crash when the parameter of a block property needs @escaping
230230
let rdar122280735: (() -> ()) -> Void = { _ in }
231231
// expected-warning@-1 {{property 'rdar122280735' of type '(() -> ()) -> Void' does not match type '(@escaping () -> Void) -> Void' declared by the header}}
232+
233+
private func privateNonObjCMethod(_: EmptySwiftProto) {
234+
// expected-warning@-1 {{method cannot be in an @objc @implementation extension of a class (without final or @nonobjc) because the type of the parameter cannot be represented in Objective-C}}
235+
// expected-note@-2 {{protocol-constrained type containing protocol 'EmptySwiftProto' cannot be represented in Objective-C}}
236+
}
232237
}
233238

234239
@_objcImplementation(PresentAdditions) extension ObjCClass {
@@ -428,8 +433,8 @@ protocol EmptySwiftProto {}
428433
func nullableResult() -> Any { fatalError() } // expected-warning {{instance method 'nullableResult()' of type '() -> Any' does not match type '() -> Any?' declared by the header}}
429434
func nullableArgument(_: Any) {} // expected-warning {{instance method 'nullableArgument' of type '(Any) -> ()' does not match type '(Any?) -> Void' declared by the header}}
430435

431-
func nonPointerResult() -> CInt! { fatalError() } // expected-error{{method cannot be in an @objc @implementation extension of a class (without final or @nonobjc) because its result type cannot be represented in Objective-C}}
432-
func nonPointerArgument(_: CInt!) {} // expected-error {{method cannot be in an @objc @implementation extension of a class (without final or @nonobjc) because the type of the parameter cannot be represented in Objective-C}}
436+
func nonPointerResult() -> CInt! { fatalError() } // expected-warning{{method cannot be in an @objc @implementation extension of a class (without final or @nonobjc) because its result type cannot be represented in Objective-C}}
437+
func nonPointerArgument(_: CInt!) {} // expected-warning {{method cannot be in an @objc @implementation extension of a class (without final or @nonobjc) because the type of the parameter cannot be represented in Objective-C}}
433438
}
434439

435440
// Intentionally using `@_objcImplementation` for this test; do not upgrade!

0 commit comments

Comments
 (0)