Skip to content

Commit 409581c

Browse files
author
Harlan Haskins
authored
[ModuleInterface] Escape Type and Protocol when they're type members (#24111) (#24241)
Previously, we wouldn't escape `Type` and `Protocol` at all in the ASTPrinter, which lead to unfortunate build failures while compiling an interface. Instead, make sure we escape them whenever we print a name that's a type member. Except for methods, which are erroneously allowed to be called `Type` and `Protocol`. rdar://49858651
1 parent b98b8a4 commit 409581c

File tree

3 files changed

+109
-20
lines changed

3 files changed

+109
-20
lines changed

include/swift/AST/ASTPrinter.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,8 @@ enum class PrintNameContext {
4444
Normal,
4545
/// Keyword context, where no keywords are escaped.
4646
Keyword,
47+
/// Type member context, e.g. properties or enum cases.
48+
TypeMember,
4749
/// Generic parameter context, where 'Self' is not escaped.
4850
GenericParameter,
4951
/// Class method return type, where 'Self' is not escaped.

lib/AST/ASTPrinter.cpp

Lines changed: 34 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -376,16 +376,26 @@ ASTPrinter &operator<<(ASTPrinter &printer, tok keyword) {
376376

377377
/// Determine whether to escape the given keyword in the given context.
378378
static bool escapeKeywordInContext(StringRef keyword, PrintNameContext context){
379+
380+
bool isKeyword = llvm::StringSwitch<bool>(keyword)
381+
#define KEYWORD(KW) \
382+
.Case(#KW, true)
383+
#include "swift/Syntax/TokenKinds.def"
384+
.Default(false);
385+
379386
switch (context) {
380387
case PrintNameContext::Normal:
381388
case PrintNameContext::Attribute:
382-
return true;
389+
return isKeyword;
383390
case PrintNameContext::Keyword:
384391
return false;
385392

386393
case PrintNameContext::ClassDynamicSelf:
387394
case PrintNameContext::GenericParameter:
388-
return keyword != "Self";
395+
return isKeyword && keyword != "Self";
396+
397+
case PrintNameContext::TypeMember:
398+
return isKeyword || !canBeMemberName(keyword);
389399

390400
case PrintNameContext::FunctionParameterExternal:
391401
case PrintNameContext::FunctionParameterLocal:
@@ -404,19 +414,13 @@ void ASTPrinter::printName(Identifier Name, PrintNameContext Context) {
404414
printNamePost(Context);
405415
return;
406416
}
407-
bool IsKeyword = llvm::StringSwitch<bool>(Name.str())
408-
#define KEYWORD(KW) \
409-
.Case(#KW, true)
410-
#include "swift/Syntax/TokenKinds.def"
411-
.Default(false);
412417

413-
if (IsKeyword)
414-
IsKeyword = escapeKeywordInContext(Name.str(), Context);
418+
bool shouldEscapeKeyword = escapeKeywordInContext(Name.str(), Context);
415419

416-
if (IsKeyword)
420+
if (shouldEscapeKeyword)
417421
*this << "`";
418422
*this << Name.str();
419-
if (IsKeyword)
423+
if (shouldEscapeKeyword)
420424
*this << "`";
421425

422426
printNamePost(Context);
@@ -1012,6 +1016,14 @@ static bool mustPrintPropertyName(VarDecl *decl, PrintOptions opts) {
10121016
return false;
10131017
}
10141018

1019+
/// Gets the print name context of a given decl, choosing between TypeMember
1020+
/// and Normal, depending if this decl lives in a nominal type decl.
1021+
static PrintNameContext getTypeMemberPrintNameContext(const Decl *d) {
1022+
return d->getDeclContext()->isTypeContext() ?
1023+
PrintNameContext::TypeMember :
1024+
PrintNameContext::Normal;
1025+
}
1026+
10151027
void PrintAST::printPattern(const Pattern *pattern) {
10161028
switch (pattern->getKind()) {
10171029
case PatternKind::Any:
@@ -1025,7 +1037,8 @@ void PrintAST::printPattern(const Pattern *pattern) {
10251037
// FIXME: This always returns true now, because of the FIXMEs listed in
10261038
// mustPrintPropertyName.
10271039
if (mustPrintPropertyName(decl, Options))
1028-
Printer.printName(named->getBoundName());
1040+
Printer.printName(named->getBoundName(),
1041+
getTypeMemberPrintNameContext(decl));
10291042
else
10301043
Printer << "_";
10311044
});
@@ -2231,7 +2244,7 @@ void PrintAST::visitTypeAliasDecl(TypeAliasDecl *decl) {
22312244
printContextIfNeeded(decl);
22322245
recordDeclLoc(decl,
22332246
[&]{
2234-
Printer.printName(decl->getName());
2247+
Printer.printName(decl->getName(), getTypeMemberPrintNameContext(decl));
22352248
}, [&]{ // Signature
22362249
printGenericDeclGenericParams(decl);
22372250
});
@@ -2264,7 +2277,7 @@ void PrintAST::visitAssociatedTypeDecl(AssociatedTypeDecl *decl) {
22642277
Printer << tok::kw_associatedtype << " ";
22652278
recordDeclLoc(decl,
22662279
[&]{
2267-
Printer.printName(decl->getName());
2280+
Printer.printName(decl->getName(), PrintNameContext::TypeMember);
22682281
});
22692282

22702283
auto proto = decl->getProtocol();
@@ -2305,7 +2318,7 @@ void PrintAST::visitEnumDecl(EnumDecl *decl) {
23052318
printContextIfNeeded(decl);
23062319
recordDeclLoc(decl,
23072320
[&]{
2308-
Printer.printName(decl->getName());
2321+
Printer.printName(decl->getName(), getTypeMemberPrintNameContext(decl));
23092322
}, [&]{ // Signature
23102323
printGenericDeclGenericParams(decl);
23112324
});
@@ -2333,7 +2346,7 @@ void PrintAST::visitStructDecl(StructDecl *decl) {
23332346
printContextIfNeeded(decl);
23342347
recordDeclLoc(decl,
23352348
[&]{
2336-
Printer.printName(decl->getName());
2349+
Printer.printName(decl->getName(), getTypeMemberPrintNameContext(decl));
23372350
}, [&]{ // Signature
23382351
printGenericDeclGenericParams(decl);
23392352
});
@@ -2361,7 +2374,7 @@ void PrintAST::visitClassDecl(ClassDecl *decl) {
23612374
printContextIfNeeded(decl);
23622375
recordDeclLoc(decl,
23632376
[&]{
2364-
Printer.printName(decl->getName());
2377+
Printer.printName(decl->getName(), getTypeMemberPrintNameContext(decl));
23652378
}, [&]{ // Signature
23662379
printGenericDeclGenericParams(decl);
23672380
});
@@ -2494,7 +2507,7 @@ void PrintAST::visitVarDecl(VarDecl *decl) {
24942507
printContextIfNeeded(decl);
24952508
recordDeclLoc(decl,
24962509
[&]{
2497-
Printer.printName(decl->getName());
2510+
Printer.printName(decl->getName(), getTypeMemberPrintNameContext(decl));
24982511
});
24992512
if (decl->hasInterfaceType()) {
25002513
Printer << ": ";
@@ -2750,7 +2763,8 @@ void PrintAST::visitFuncDecl(FuncDecl *decl) {
27502763
if (!decl->hasName()) {
27512764
Printer << "<anonymous>";
27522765
} else {
2753-
Printer.printName(decl->getName());
2766+
Printer.printName(decl->getName(),
2767+
getTypeMemberPrintNameContext(decl));
27542768
if (decl->isOperator())
27552769
Printer << " ";
27562770
}
@@ -2788,7 +2802,7 @@ void PrintAST::visitFuncDecl(FuncDecl *decl) {
27882802
void PrintAST::printEnumElement(EnumElementDecl *elt) {
27892803
recordDeclLoc(elt,
27902804
[&]{
2791-
Printer.printName(elt->getName());
2805+
Printer.printName(elt->getName(), getTypeMemberPrintNameContext(elt));
27922806
});
27932807

27942808
if (auto *PL = elt->getParameterList()) {
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
// RUN: %target-swift-frontend -typecheck -emit-module-interface-path - %s | %FileCheck %s
2+
3+
// CHECK: public let Type: Swift.Int
4+
public let Type = 0
5+
6+
// CHECK: public struct A {
7+
public struct A {
8+
// CHECK-NEXT: public struct `Type` {
9+
// CHECK-NEXT: }
10+
public struct `Type` {}
11+
// CHECK-NEXT: }
12+
}
13+
14+
// CHECK: public class B {
15+
public class B {
16+
// CHECK-NEXT: public class `Type` {
17+
// CHECK: }
18+
public class `Type` {}
19+
20+
// CHECK-NEXT: @_hasInitialValue public var `Type`: Swift.Int
21+
public var `Type` = 0
22+
// CHECK: }
23+
}
24+
25+
// CHECK: public struct C {
26+
public struct C {
27+
// CHECK: public enum `Type` {
28+
public enum `Type` {
29+
// CHECK: }
30+
}
31+
// CHECK-NEXT: }
32+
}
33+
34+
// CHECK: public struct D {
35+
public struct D {
36+
// CHECK: public typealias `Type` = Int
37+
public typealias `Type` = Int
38+
// CHECK-NEXT: }
39+
}
40+
41+
// CHECK: public protocol BestProtocol {
42+
public protocol BestProtocol {
43+
// CHECK-NEXT: associatedtype `Type`
44+
associatedtype `Type`
45+
// CHECK-NEXT: }
46+
}
47+
48+
// CHECK: public enum CoolEnum {
49+
public enum CoolEnum {
50+
// CHECK-NEXT: case `Type`
51+
case `Type`
52+
// CHECK-NEXT: case `Protocol`
53+
case `Protocol`
54+
// CHECK-NEXT: case `init`
55+
case `init`
56+
// CHECK-NEXT: case `self`
57+
case `self`
58+
59+
// We allow Type and Protocol as method names, but we should still print them
60+
// escaped in case we tighten this restriction.
61+
// CHECK-NEXT: public func `Type`()
62+
public func Type() {}
63+
// CHECK-NEXT: public func `Protocol`()
64+
public func Protocol() {}
65+
// CHECK: }
66+
}
67+
68+
// CHECK: public enum UncoolEnum {
69+
public enum UncoolEnum {
70+
// CHECK-NEXT: case `Type`, `Protocol`
71+
case `Type`, `Protocol`
72+
// CHECK: }
73+
}

0 commit comments

Comments
 (0)