Skip to content

Commit 2a53433

Browse files
committed
Soften @impl warnings only for early adopters
Adopting @implementation turns all of the warnings into errors.
1 parent 29b5a92 commit 2a53433

File tree

4 files changed

+20
-9
lines changed

4 files changed

+20
-9
lines changed

docs/ReferenceGuides/UnderscoredAttributes.md

+5-6
Original file line numberDiff line numberDiff line change
@@ -779,6 +779,11 @@ of a header as non-`Sendable` so that you can make spot exceptions with
779779

780780
## `@_objcImplementation(CategoryName)`
781781

782+
A pre-stable form of `@implementation`. The main difference between them is that
783+
many things that are errors with `@implementation` are warnings with
784+
`@_objcImplementation`, which permitted workarounds for compiler bugs and
785+
changes in compiler behavior.
786+
782787
Declares an extension that defines an implementation for the Objective-C
783788
category `CategoryName` on the class in question, or for the main `@interface`
784789
if the argument list is omitted.
@@ -841,12 +846,6 @@ Notes:
841846

842847
* We don't currently plan to support ObjC generics.
843848

844-
* Eventually, we want the main `@_objcImplementation` extension to be able to
845-
declare stored properties that aren't in the interface. We also want
846-
`final` stored properties to be allowed to be resilent Swift types, but
847-
it's not clear how to achieve that without boxing them in `__SwiftValue`
848-
(which we might do as a stopgap).
849-
850849
* We should think about ObjC "direct" members, but that would probably
851850
require a way to spell this in Swift.
852851

lib/Sema/TypeCheckDeclObjC.cpp

+11-3
Original file line numberDiff line numberDiff line change
@@ -2810,9 +2810,11 @@ class ObjCImplementationChecker {
28102810
typename detail::PassArgument<ArgTypes>::type... Args) {
28112811
auto diag = diags.diagnose(loc, diagID, std::forward<ArgTypes>(Args)...);
28122812

2813-
// WORKAROUND (5.9): Soften newly-introduced errors to make things easier
2814-
// for early adopters.
2815-
if (diags.declaredDiagnosticKindFor(diagID.ID) == DiagnosticKind::Error)
2813+
// Early adopters using the '@_objcImplementation' syntax may have had the
2814+
// ObjCImplementationChecker evolve out from under them. Soften their errors
2815+
// to warnings so we don't break their projects.
2816+
if (isEarlyAdopter
2817+
&& diags.declaredDiagnosticKindFor(diagID.ID) == DiagnosticKind::Error)
28162818
diag.wrapIn(diag::wrap_objc_implementation_will_become_error);
28172819

28182820
return diag;
@@ -2823,12 +2825,18 @@ class ObjCImplementationChecker {
28232825
/// Candidates with their explicit ObjC names, if any.
28242826
llvm::SmallDenseMap<ValueDecl *, ObjCSelector, 16> unmatchedCandidates;
28252827

2828+
bool isEarlyAdopter;
2829+
28262830
public:
28272831
ObjCImplementationChecker(Decl *D)
28282832
: diags(D->getASTContext().Diags)
28292833
{
28302834
assert(!D->hasClangNode() && "passed interface, not impl, to checker");
28312835

2836+
isEarlyAdopter = D->getAttrs()
2837+
.getAttribute<ObjCImplementationAttr>(/*AllowInvalid=*/true)
2838+
->isEarlyAdopter();
2839+
28322840
if (auto func = dyn_cast<AbstractFunctionDecl>(D)) {
28332841
addCandidate(D);
28342842
addRequirement(D->getImplementedObjCDecl());
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,13 @@
11
// RUN: not %target-swift-frontend(mock-sdk: %clang-importer-sdk-nosource) -typecheck %s -import-objc-header %S/Inputs/objc_implementation.h 2>&1 | %FileCheck --check-prefixes NO,CHECK %s
22
// RUN: not %target-swift-frontend(mock-sdk: %clang-importer-sdk-nosource) -typecheck %s -import-objc-header %S/Inputs/objc_implementation.h -enable-experimental-feature CImplementation 2>&1 | %FileCheck --check-prefixes YES,C,CHECK %s
33

4+
// YES-DAG: cdecl_implementation_features.swift:[[@LINE+4]]:{{[0-9]+}}: warning: global function 'CImplFunc1' of type '(Double) -> ()' does not match type '(Int32) -> Void' declared by the header; this will become an error after adopting '@implementation'
45
// NO-DAG: cdecl_implementation_features.swift:[[@LINE+3]]:{{[0-9]+}}: error: '_objcImplementation' attribute is only valid when experimental feature CImplementation is enabled
56
// YES-NOT: cdecl_implementation_features.swift:[[@LINE+2]]:{{[0-9]+}}: warning: warning-only '@_objcImplementation' spelling is deprecated; use '@implementation' instead
67
// TODO: When @implementation @_cdecl stabilizes, YES-NOT on the line above will become YES-DAG
78
@_objcImplementation @_cdecl("CImplFunc1") func CImplFunc1(_: Double) {}
89

10+
// YES-DAG: cdecl_implementation_features.swift:[[@LINE+3]]:{{[0-9]+}}: error: global function 'CImplFunc2' of type '(Double) -> ()' does not match type '(Int32) -> Void' declared by the header{{$}}
911
// NO-DAG: cdecl_implementation_features.swift:[[@LINE+2]]:{{[0-9]+}}: error: 'implementation' attribute is only valid when experimental feature CImplementation is enabled
1012
// YES-NOT: cdecl_implementation_features.swift:[[@LINE+1]]:{{[0-9]+}}: error: 'implementation' attribute is only valid when experimental feature CImplementation is enabled
1113
@implementation @_cdecl("CImplFunc2") func CImplFunc2(_: Double) {}

test/decl/ext/objc_implementation_features.swift

+2
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,12 @@
33
// RUN: not %target-swift-frontend(mock-sdk: %clang-importer-sdk-nosource) -typecheck %s -import-objc-header %S/Inputs/objc_implementation.h 2>&1 | %FileCheck --check-prefixes NO,CHECK %s
44
// RUN: not %target-swift-frontend(mock-sdk: %clang-importer-sdk-nosource) -typecheck %s -import-objc-header %S/Inputs/objc_implementation.h -enable-experimental-feature ObjCImplementation 2>&1 | %FileCheck --check-prefixes YES,CHECK %s
55

6+
// CHECK-DAG: objc_implementation_features.swift:[[@LINE+3]]:{{[0-9]+}}: warning: extension for main class interface should provide implementation for instance method 'subclassMethod(fromHeader1:)'; this will become an error after adopting '@implementation'
67
// NO-NOT: objc_implementation_features.swift:[[@LINE+2]]:{{[0-9]+}}: warning: warning-only '@_objcImplementation' spelling is deprecated; use '@implementation' instead
78
// YES-DAG: objc_implementation_features.swift:[[@LINE+1]]:{{[0-9]+}}: warning: warning-only '@_objcImplementation' spelling is deprecated; use '@implementation' instead
89
@_objcImplementation extension ObjCSubclass {}
910

11+
// CHECK-DAG: objc_implementation_features.swift:[[@LINE+3]]:{{[0-9]+}}: error: extension for main class interface should provide implementation for initializer 'init()'{{$}}
1012
// NO-DAG: objc_implementation_features.swift:[[@LINE+2]]:{{[0-9]+}}: error: 'implementation' attribute is only valid when experimental feature ObjCImplementation is enabled
1113
// YES-NOT: objc_implementation_features.swift:[[@LINE+1]]:{{[0-9]+}}: error: 'implementation' attribute is only valid when experimental feature ObjCImplementation is enabled
1214
@implementation extension ObjCBasicInitClass {}

0 commit comments

Comments
 (0)