Skip to content

Commit 9d4281b

Browse files
committed
Support generic @compatibility_alias in PrintAsObjC
When @compatibility_alias is used with an ObjC generic class, this ends up importing as a generic typealias. PrintAsObjC previously didn’t handle declarations involving these types correctly; it would fail an assertion in asserts compilers, and potentially print an incorrect compatibility header in non-asserts compilers. This PR makes it so that PrintAsObjC can now correctly use generic typealiases imported from Objective-C modules. It is, of course, still not possible to declare a generic typealias in Swift that will be printed into the Objective-C header. Fixes rdar://67256866.
1 parent 28ea3e1 commit 9d4281b

File tree

4 files changed

+28
-5
lines changed

4 files changed

+28
-5
lines changed

lib/PrintAsObjC/DeclAndTypePrinter.cpp

Lines changed: 20 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1572,25 +1572,36 @@ class DeclAndTypePrinter::Implementation
15721572
}
15731573

15741574
bool printImportedAlias(const TypeAliasDecl *alias,
1575+
ArrayRef<Type> genericArgs,
15751576
Optional<OptionalTypeKind> optionalKind) {
15761577
if (!alias->hasClangNode())
15771578
return false;
15781579

15791580
if (auto *clangTypeDecl =
15801581
dyn_cast<clang::TypeDecl>(alias->getClangDecl())) {
1582+
assert(!alias->isGeneric()
1583+
&& "generic typealias backed by clang typedecl?");
1584+
15811585
maybePrintTagKeyword(alias);
15821586
os << getNameForObjC(alias);
15831587

15841588
if (isClangPointerType(clangTypeDecl))
15851589
printNullability(optionalKind);
15861590
} else if (auto *clangObjCClass
15871591
= dyn_cast<clang::ObjCInterfaceDecl>(alias->getClangDecl())){
1592+
assert(!alias->isGeneric()
1593+
&& "generic typealias backed by clang interface?");
1594+
15881595
os << clangObjCClass->getName() << " *";
15891596
printNullability(optionalKind);
15901597
} else {
15911598
auto *clangCompatAlias =
15921599
cast<clang::ObjCCompatibleAliasDecl>(alias->getClangDecl());
1593-
os << clangCompatAlias->getName() << " *";
1600+
1601+
os << clangCompatAlias->getName();
1602+
if (!genericArgs.empty())
1603+
printGenericArgs(genericArgs);
1604+
os << " *";
15941605
printNullability(optionalKind);
15951606
}
15961607

@@ -1600,10 +1611,12 @@ class DeclAndTypePrinter::Implementation
16001611
void visitTypeAliasType(TypeAliasType *aliasTy,
16011612
Optional<OptionalTypeKind> optionalKind) {
16021613
const TypeAliasDecl *alias = aliasTy->getDecl();
1614+
auto genericArgs = aliasTy->getDirectGenericArgs();
1615+
16031616
if (printIfKnownSimpleType(alias, optionalKind))
16041617
return;
16051618

1606-
if (printImportedAlias(alias, optionalKind))
1619+
if (printImportedAlias(alias, genericArgs, optionalKind))
16071620
return;
16081621

16091622
visitPart(aliasTy->getSinglyDesugaredType(), optionalKind);
@@ -1737,8 +1750,12 @@ class DeclAndTypePrinter::Implementation
17371750
}
17381751

17391752
void printGenericArgs(BoundGenericType *BGT) {
1753+
printGenericArgs(BGT->getGenericArgs());
1754+
}
1755+
1756+
void printGenericArgs(ArrayRef<Type> genericArgs) {
17401757
os << '<';
1741-
interleave(BGT->getGenericArgs(),
1758+
interleave(genericArgs,
17421759
[this](Type t) { print(t, None); },
17431760
[this] { os << ", "; });
17441761
os << '>';

lib/PrintAsObjC/ModuleContentsWriter.cpp

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,6 @@ class ReferencedTypeFinder : public TypeDeclFinder {
5757
Action visitTypeAliasType(TypeAliasType *aliasTy) override {
5858
if (aliasTy->getDecl()->hasClangNode() &&
5959
!aliasTy->getDecl()->isCompatibilityAlias()) {
60-
assert(!aliasTy->getDecl()->isGeneric());
6160
Callback(*this, aliasTy->getDecl());
6261
} else {
6362
Type(aliasTy->getSinglyDesugaredType()).walk(*this);
@@ -319,8 +318,10 @@ class ModuleWriter {
319318
} else if (auto PD = dyn_cast<ProtocolDecl>(TD)) {
320319
forwardDeclare(PD);
321320
} else if (auto TAD = dyn_cast<TypeAliasDecl>(TD)) {
321+
bool imported = false;
322322
if (TAD->hasClangNode())
323-
(void)addImport(TD);
323+
imported = addImport(TD);
324+
assert((imported || !TAD->isGeneric()) && "referencing non-imported generic typealias?");
324325
} else if (addImport(TD)) {
325326
return;
326327
} else if (auto ED = dyn_cast<EnumDecl>(TD)) {
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
// This file is meant to be included with modules turned off, compiled against
22
// the fake clang-importer-sdk.
33
#import <Foundation.h>
4+
#import <objc_generics.h>
45

56
@compatibility_alias StringCheese NSString;
7+
@compatibility_alias GymClass GenericClass;

test/PrintAsObjC/classes.swift

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -820,6 +820,9 @@ public class NonObjCClass { }
820820
// CHECK-NEXT: - (StringCheese * _Nullable)foo SWIFT_WARN_UNUSED_RESULT;
821821
@objc func foo() -> StringCheese? { return nil }
822822

823+
// CHECK-NEXT: - (GymClass<StringCheese *> * _Nullable)foosball SWIFT_WARN_UNUSED_RESULT;
824+
@objc func foosball() -> GymClass<StringCheese>? { return nil }
825+
823826
// CHECK-NEXT: - (nonnull instancetype)init OBJC_DESIGNATED_INITIALIZER;
824827
}
825828
// CHECK-NEXT: @end

0 commit comments

Comments
 (0)