Skip to content

Commit 37799f4

Browse files
committed
[Type checker] Suggest @objc for ill-formed extensions of ObjC generic classes.
@objc is used as a proxy to allow 'self' to access type parameters within an extension of an Objective-C generic class. Suggest it in cases where it might make sense. Clarifies the fix for cases like rdar://problem/27796182.
1 parent 46e623a commit 37799f4

File tree

3 files changed

+21
-2
lines changed

3 files changed

+21
-2
lines changed

Diff for: include/swift/AST/DiagnosticsSema.def

+2
Original file line numberDiff line numberDiff line change
@@ -1371,6 +1371,8 @@ ERROR(objc_generic_extension_using_type_parameter,none,
13711371
"generic parameters at runtime", ())
13721372
NOTE(objc_generic_extension_using_type_parameter_here,none,
13731373
"generic parameter used here", ())
1374+
NOTE(objc_generic_extension_using_type_parameter_try_objc,none,
1375+
"add '@objc' to allow uses of 'self' within the function body", ())
13741376

13751377
// Protocols
13761378
ERROR(type_does_not_conform,none,

Diff for: lib/Sema/TypeCheckCaptures.cpp

+13-1
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
#include "swift/AST/ASTVisitor.h"
2020
#include "swift/AST/ASTWalker.h"
2121
#include "swift/AST/Decl.h"
22+
#include "swift/AST/ForeignErrorConvention.h"
2223
#include "swift/AST/ParameterList.h"
2324
#include "swift/AST/TypeWalker.h"
2425
#include "swift/Basic/Defer.h"
@@ -743,9 +744,20 @@ void TypeChecker::computeCaptures(AnyFunctionRef AFR) {
743744
// their context.
744745
if (AFD && GenericParamCaptureLoc.isValid()) {
745746
if (auto Clas = AFD->getParent()->getAsClassOrClassExtensionContext()) {
746-
if (Clas->isGenericContext() && Clas->hasClangNode()) {
747+
if (Clas->usesObjCGenericsModel()) {
747748
diagnose(AFD->getLoc(),
748749
diag::objc_generic_extension_using_type_parameter);
750+
751+
// If it's possible, suggest adding @objc.
752+
Optional<ForeignErrorConvention> errorConvention;
753+
if (!AFD->isObjC() &&
754+
isRepresentableInObjC(AFD, ObjCReason::MemberOfObjCMembersClass,
755+
errorConvention)) {
756+
diagnose(AFD->getLoc(),
757+
diag::objc_generic_extension_using_type_parameter_try_objc)
758+
.fixItInsert(AFD->getAttributeInsertionLoc(false), "@objc ");
759+
}
760+
749761
diagnose(GenericParamCaptureLoc,
750762
diag::objc_generic_extension_using_type_parameter_here);
751763
}

Diff for: test/ClangImporter/objc_bridging_generics.swift

+6-1
Original file line numberDiff line numberDiff line change
@@ -123,7 +123,7 @@ extension GenericClass {
123123
_ = T.self // expected-note{{used here}}
124124
}
125125
// expected-error@+1{{extension of a generic Objective-C class cannot access the class's generic parameters}}
126-
@objc func usesGenericParamE(_ x: Int) {
126+
@objc func usesGenericParamE(_ x: Int) {
127127
_ = x as? T // expected-note{{used here}}
128128
}
129129
// expected-error@+1{{extension of a generic Objective-C class cannot access the class's generic parameters}}
@@ -249,18 +249,22 @@ extension AnimalContainer {
249249
}
250250

251251

252+
// expected-note@+2{{add '@objc' to allow uses of 'self' within the function body}}{{3-3=@objc }}
252253
// expected-error@+1{{extension of a generic Objective-C class cannot access the class's generic parameters}}
253254
func usesGenericParamA(_ x: T) {
254255
_ = T(noise: x) // expected-note{{used here}}
255256
}
257+
// expected-note@+2{{add '@objc' to allow uses of 'self' within the function body}}{{3-3=@objc }}
256258
// expected-error@+1{{extension of a generic Objective-C class cannot access the class's generic parameters}}
257259
func usesGenericParamB() {
258260
_ = T.create() // expected-note{{used here}}
259261
}
262+
// expected-note@+2{{add '@objc' to allow uses of 'self' within the function body}}{{3-3=@objc }}
260263
// expected-error@+1{{extension of a generic Objective-C class cannot access the class's generic parameters}}
261264
func usesGenericParamC() {
262265
_ = T.apexPredator // expected-note{{used here}}
263266
}
267+
// expected-note@+2{{add '@objc' to allow uses of 'self' within the function body}}{{3-3=@objc }}
264268
// expected-error@+1{{extension of a generic Objective-C class cannot access the class's generic parameters}}
265269
func usesGenericParamD(_ x: T) {
266270
T.apexPredator = x // expected-note{{used here}}
@@ -269,6 +273,7 @@ extension AnimalContainer {
269273
// rdar://problem/27796375 -- allocating init entry points for ObjC
270274
// initializers are generated as true Swift generics, so reify type
271275
// parameters.
276+
// expected-note@+2{{add '@objc' to allow uses of 'self' within the function body}}{{3-3=@objc }}
272277
// expected-error@+1{{extension of a generic Objective-C class cannot access the class's generic parameters}}
273278
func usesGenericParamE(_ x: T) {
274279
_ = GenericClass(thing: x) // expected-note{{used here}}

0 commit comments

Comments
 (0)