Skip to content

Commit 828ab6d

Browse files
authored
Merge pull request #33573 from brentdax/how-forward-of-you-2-electric-boogaloo
Support generic @compatibility_alias in PrintAsObjC
2 parents 39d4e01 + 9d4281b commit 828ab6d

File tree

7 files changed

+61
-6
lines changed

7 files changed

+61
-6
lines changed

include/swift/AST/ClangNode.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
#ifndef SWIFT_CLANGNODE_H
1414
#define SWIFT_CLANGNODE_H
1515

16+
#include "swift/Basic/Debug.h"
1617
#include "llvm/ADT/PointerUnion.h"
1718

1819
namespace clang {
@@ -98,6 +99,8 @@ class ClangNode {
9899
clang::SourceLocation getLocation() const;
99100
clang::SourceRange getSourceRange() const;
100101

102+
SWIFT_DEBUG_DUMP;
103+
101104
void *getOpaqueValue() const { return Ptr.getOpaqueValue(); }
102105
static inline ClangNode getFromOpaqueValue(void *VP) {
103106
ClangNode N;

include/swift/AST/Decl.h

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2996,11 +2996,29 @@ class TypeAliasDecl : public GenericTypeDecl {
29962996
/// Retrieve a sugared interface type containing the structure of the interface
29972997
/// type before any semantic validation has occured.
29982998
Type getStructuralType() const;
2999-
2999+
3000+
/// Whether the typealias forwards perfectly to its underlying type.
3001+
///
3002+
/// If true, this typealias was created by ClangImporter to preserve source
3003+
/// compatibility with a previous language version's name for a type. Many
3004+
/// checks in Sema look through compatibility aliases even when they would
3005+
/// operate on other typealiases.
3006+
///
3007+
/// \warning This has absolutely nothing to do with the Objective-C
3008+
/// \c compatibility_alias keyword.
30003009
bool isCompatibilityAlias() const {
30013010
return Bits.TypeAliasDecl.IsCompatibilityAlias;
30023011
}
30033012

3013+
/// Sets whether the typealias forwards perfectly to its underlying type.
3014+
///
3015+
/// Marks this typealias as having been created by ClangImporter to preserve
3016+
/// source compatibility with a previous language version's name for a type.
3017+
/// Many checks in Sema look through compatibility aliases even when they
3018+
/// would operate on other typealiases.
3019+
///
3020+
/// \warning This has absolutely nothing to do with the Objective-C
3021+
/// \c compatibility_alias keyword.
30043022
void markAsCompatibilityAlias(bool newValue = true) {
30053023
Bits.TypeAliasDecl.IsCompatibilityAlias = newValue;
30063024
}

lib/AST/Decl.cpp

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,17 @@ const clang::Module *ClangNode::getClangModule() const {
116116
return nullptr;
117117
}
118118

119+
void ClangNode::dump() const {
120+
if (auto D = getAsDecl())
121+
D->dump();
122+
else if (auto M = getAsMacro())
123+
M->dump();
124+
else if (auto M = getAsModule())
125+
M->dump();
126+
else
127+
llvm::errs() << "ClangNode contains nullptr\n";
128+
}
129+
119130
// Only allow allocation of Decls using the allocator in ASTContext.
120131
void *Decl::operator new(size_t Bytes, const ASTContext &C,
121132
unsigned Alignment) {

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)