Skip to content

Commit ef187af

Browse files
committed
Sema: Diagnose init calls as uses of generic params.
We currently emit the allocating initializer of an @objc initializer of a generic ObjC class as a true generic function rather than pseudogeneric (rdar://problem/27796375). This would be a breaking change and has nonobvious tradeoffs if we "fix" it, so for the time being, just diagnose attempts to invoke an initializer from inside an @objc generic extension method. It's easy to work around by as!-casting the result of constructing the upper bound type. Fixes rdar://problem/26867815.
1 parent 18d5fdb commit ef187af

File tree

2 files changed

+26
-4
lines changed

2 files changed

+26
-4
lines changed

lib/Sema/TypeCheckCaptures.cpp

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -199,6 +199,13 @@ class FindCapturedVars : public ASTWalker {
199199
std::pair<bool, Expr *> walkToDeclRefExpr(DeclRefExpr *DRE) {
200200
auto *D = DRE->getDecl();
201201

202+
// Capture the generic parameters of the decl.
203+
if (!AFR.isObjC() || !D->isObjC() || isa<ConstructorDecl>(D)) {
204+
for (auto sub : DRE->getDeclRef().getSubstitutions()) {
205+
checkType(sub.getReplacement(), DRE->getLoc());
206+
}
207+
}
208+
202209
// DC is the DeclContext where D was defined
203210
// CurDC is the DeclContext where D was referenced
204211
auto DC = D->getDeclContext();
@@ -430,17 +437,22 @@ class FindCapturedVars : public ASTWalker {
430437
&& !E->getType()->is<AnyMetatypeType>());
431438

432439
// Accessing @objc members doesn't require type metadata.
440+
// rdar://problem/27796375 -- allocating init entry points for ObjC
441+
// initializers are generated as true Swift generics, so reify type
442+
// parameters.
433443
if (auto memberRef = dyn_cast<MemberRefExpr>(E))
434444
return !memberRef->getMember().getDecl()->hasClangNode();
435445

436446
if (auto applyExpr = dyn_cast<ApplyExpr>(E)) {
437447
if (auto methodApply = dyn_cast<ApplyExpr>(applyExpr->getFn())) {
438448
if (auto callee = dyn_cast<DeclRefExpr>(methodApply->getFn())) {
439-
return !callee->getDecl()->isObjC();
449+
return !callee->getDecl()->isObjC()
450+
|| isa<ConstructorDecl>(callee->getDecl());
440451
}
441452
}
442453
if (auto callee = dyn_cast<DeclRefExpr>(applyExpr->getFn())) {
443-
return !callee->getDecl()->isObjC();
454+
return !callee->getDecl()->isObjC()
455+
|| isa<ConstructorDecl>(callee->getDecl());
444456
}
445457
}
446458

test/ClangModules/objc_bridging_generics.swift

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -265,6 +265,14 @@ extension AnimalContainer {
265265
T.apexPredator = x // expected-note{{used here}}
266266
}
267267

268+
// rdar://problem/27796375 -- allocating init entry points for ObjC
269+
// initializers are generated as true Swift generics, so reify type
270+
// parameters.
271+
// expected-error@+1{{extension of a generic Objective-C class cannot access the class's generic parameters}}
272+
func usesGenericParamE(_ x: T) {
273+
_ = GenericClass(thing: x) // expected-note{{used here}}
274+
}
275+
268276
func checkThatMethodsAreObjC() {
269277
_ = #selector(AnimalContainer.doesntUseGenericParam1)
270278
_ = #selector(AnimalContainer.doesntUseGenericParam2)
@@ -283,9 +291,11 @@ extension AnimalContainer {
283291

284292
extension PettableContainer {
285293
func doesntUseGenericParam(_ x: T, _ y: T.Type) {
286-
_ = type(of: x).init(fur: x).other()
294+
// TODO: rdar://problem/27796375--allocating entry points are emitted as
295+
// true generics.
296+
// _ = type(of: x).init(fur: x).other()
287297
_ = type(of: x).adopt().other()
288-
_ = y.init(fur: x).other()
298+
// _ = y.init(fur: x).other()
289299
_ = y.adopt().other()
290300
x.pet()
291301
x.pet(with: x)

0 commit comments

Comments
 (0)