Skip to content

Commit cb60dbe

Browse files
committed
[IDE] Teach type checker about conditional conformance extensions.
Before conditional conformances, the archetypes in conformance extensions (i.e. extension Foo: SomeProtocol) were equivalent to those in the type decl, with the same protocol bounds and so on. The code for printing "synthesized" members relied on this fact. This commit teaches that code to deal with archetypes in the conditional conformance extension when required. Fixes rdar://problem/36553066 and SR-6930.
1 parent 715ca9d commit cb60dbe

File tree

14 files changed

+754
-321
lines changed

14 files changed

+754
-321
lines changed

include/swift/AST/ASTContext.h

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -174,10 +174,6 @@ class ConstraintCheckerArenaRAII {
174174
};
175175

176176
class SILLayout; // From SIL
177-
/// \brief Describes either a nominal type declaration or an extension
178-
/// declaration.
179-
typedef llvm::PointerUnion<NominalTypeDecl *, ExtensionDecl *>
180-
TypeOrExtensionDecl;
181177

182178
/// ASTContext - This object creates and owns the AST objects.
183179
/// However, this class does more than just maintain context within an AST.

include/swift/AST/ASTPrinter.h

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,7 @@ enum class PrintStructureKind {
8484
class ASTPrinter {
8585
unsigned CurrentIndentation = 0;
8686
unsigned PendingNewlines = 0;
87-
const NominalTypeDecl *SynthesizeTarget = nullptr;
87+
TypeOrExtensionDecl SynthesizeTarget;
8888

8989
void printTextImpl(StringRef Text);
9090

@@ -136,13 +136,14 @@ class ASTPrinter {
136136

137137
/// Called before printing a synthesized extension.
138138
virtual void printSynthesizedExtensionPre(const ExtensionDecl *ED,
139-
const NominalTypeDecl *NTD,
139+
TypeOrExtensionDecl NTD,
140140
Optional<BracketOptions> Bracket) {}
141141

142142
/// Called after printing a synthesized extension.
143143
virtual void printSynthesizedExtensionPost(const ExtensionDecl *ED,
144-
const NominalTypeDecl *NTD,
145-
Optional<BracketOptions> Bracket) {}
144+
TypeOrExtensionDecl TargetDecl,
145+
Optional<BracketOptions> Bracket) {
146+
}
146147

147148
/// Called before printing a structured entity.
148149
///
@@ -213,7 +214,7 @@ class ASTPrinter {
213214
CurrentIndentation = NumSpaces;
214215
}
215216

216-
void setSynthesizedTarget(NominalTypeDecl *Target) {
217+
void setSynthesizedTarget(TypeOrExtensionDecl Target) {
217218
assert((!SynthesizeTarget || !Target || Target == SynthesizeTarget) &&
218219
"unexpected change of setSynthesizedTarget");
219220
// FIXME: this can overwrite the original target with nullptr.

include/swift/AST/PrintOptions.h

Lines changed: 33 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -36,16 +36,45 @@ enum DeclAttrKind : unsigned;
3636
class SynthesizedExtensionAnalyzer;
3737
struct PrintOptions;
3838

39+
/// \brief Describes either a nominal type declaration or an extension
40+
/// declaration.
41+
struct TypeOrExtensionDecl {
42+
llvm::PointerUnion<NominalTypeDecl *, ExtensionDecl *> Decl;
43+
44+
TypeOrExtensionDecl() = default;
45+
46+
TypeOrExtensionDecl(NominalTypeDecl *D);
47+
TypeOrExtensionDecl(ExtensionDecl *D);
48+
49+
/// \brief Return the contained *Decl as the Decl superclass.
50+
class Decl *getAsDecl() const;
51+
/// \brief Return the contained *Decl as the DeclContext superclass.
52+
DeclContext *getAsDeclContext() const;
53+
/// \brief Return the contained NominalTypeDecl or that of the extended type
54+
/// in the ExtensionDecl.
55+
NominalTypeDecl *getBaseNominal() const;
56+
57+
/// \brief Is the contained pointer null?
58+
bool isNull() const;
59+
explicit operator bool() const { return !isNull(); }
60+
61+
bool operator==(TypeOrExtensionDecl rhs) { return Decl == rhs.Decl; }
62+
bool operator!=(TypeOrExtensionDecl rhs) { return Decl != rhs.Decl; }
63+
bool operator<(TypeOrExtensionDecl rhs) { return Decl < rhs.Decl; }
64+
};
65+
3966
/// Necessary information for archetype transformation during printing.
4067
struct TypeTransformContext {
4168
TypeBase *BaseType;
42-
NominalTypeDecl *Nominal = nullptr;
69+
TypeOrExtensionDecl Decl;
4370

4471
explicit TypeTransformContext(Type T);
45-
explicit TypeTransformContext(NominalTypeDecl* NTD);
72+
explicit TypeTransformContext(TypeOrExtensionDecl D);
4673

4774
Type getBaseType() const;
48-
NominalTypeDecl *getNominal() const;
75+
TypeOrExtensionDecl getDecl() const;
76+
77+
DeclContext *getDeclContext() const;
4978

5079
bool isPrintingSynthesizedExtension() const;
5180
};
@@ -421,7 +450,7 @@ struct PrintOptions {
421450

422451
void setBaseType(Type T);
423452

424-
void initForSynthesizedExtension(NominalTypeDecl *D);
453+
void initForSynthesizedExtension(TypeOrExtensionDecl D);
425454

426455
void clearSynthesizedExtension();
427456

include/swift/Sema/IDETypeChecking.h

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -137,10 +137,18 @@ namespace swift {
137137
/// Creates a lazy type resolver for use in lookups.
138138
OwnedResolver createLazyResolver(ASTContext &Ctx);
139139

140-
typedef std::pair<ExtensionDecl*, bool> ExtensionAndIsSynthesized;
140+
struct ExtensionInfo {
141+
// The extension with the declarations to apply.
142+
ExtensionDecl *Ext;
143+
// The extension that enables the former to apply, if any (i.e. a
144+
// conditional
145+
// conformance to Foo enables 'extension Foo').
146+
ExtensionDecl *EnablingExt;
147+
bool IsSynthesized;
148+
};
141149

142-
typedef llvm::function_ref<void(ArrayRef<ExtensionAndIsSynthesized>)>
143-
ExtensionGroupOperation;
150+
typedef llvm::function_ref<void(ArrayRef<ExtensionInfo>)>
151+
ExtensionGroupOperation;
144152

145153
class SynthesizedExtensionAnalyzer {
146154
struct Implementation;

lib/AST/ASTPrinter.cpp

Lines changed: 46 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -55,32 +55,56 @@ void PrintOptions::setBaseType(Type T) {
5555
TransformContext = TypeTransformContext(T);
5656
}
5757

58-
void PrintOptions::initForSynthesizedExtension(NominalTypeDecl *D) {
58+
void PrintOptions::initForSynthesizedExtension(TypeOrExtensionDecl D) {
5959
TransformContext = TypeTransformContext(D);
6060
}
6161

6262
void PrintOptions::clearSynthesizedExtension() {
6363
TransformContext.reset();
6464
}
6565

66+
TypeOrExtensionDecl::TypeOrExtensionDecl(NominalTypeDecl *D) : Decl(D) {}
67+
TypeOrExtensionDecl::TypeOrExtensionDecl(ExtensionDecl *D) : Decl(D) {}
68+
69+
Decl *TypeOrExtensionDecl::getAsDecl() const {
70+
if (auto NTD = Decl.dyn_cast<NominalTypeDecl *>())
71+
return NTD;
72+
73+
return Decl.get<ExtensionDecl *>();
74+
}
75+
DeclContext *TypeOrExtensionDecl::getAsDeclContext() const {
76+
return getAsDecl()->getInnermostDeclContext();
77+
}
78+
NominalTypeDecl *TypeOrExtensionDecl::getBaseNominal() const {
79+
return getAsDeclContext()->getAsNominalTypeOrNominalTypeExtensionContext();
80+
}
81+
bool TypeOrExtensionDecl::isNull() const { return Decl.isNull(); }
82+
6683
TypeTransformContext::TypeTransformContext(Type T)
6784
: BaseType(T.getPointer()) {
6885
assert(T->mayHaveMembers());
6986
}
7087

71-
TypeTransformContext::TypeTransformContext(NominalTypeDecl *NTD)
72-
: BaseType(NTD->getDeclaredTypeInContext().getPointer()), Nominal(NTD) {}
88+
TypeTransformContext::TypeTransformContext(TypeOrExtensionDecl D)
89+
: BaseType(nullptr), Decl(D) {
90+
if (auto NTD = Decl.Decl.dyn_cast<NominalTypeDecl *>())
91+
BaseType = NTD->getDeclaredTypeInContext().getPointer();
92+
else
93+
BaseType = Decl.Decl.get<ExtensionDecl *>()->getExtendedType().getPointer();
94+
}
95+
96+
TypeOrExtensionDecl TypeTransformContext::getDecl() const { return Decl; }
7397

74-
NominalTypeDecl *TypeTransformContext::getNominal() const {
75-
return Nominal;
98+
DeclContext *TypeTransformContext::getDeclContext() const {
99+
return Decl.getAsDecl()->getDeclContext();
76100
}
77101

78102
Type TypeTransformContext::getBaseType() const {
79103
return Type(BaseType);
80104
}
81105

82106
bool TypeTransformContext::isPrintingSynthesizedExtension() const {
83-
return Nominal != nullptr;
107+
return !Decl.isNull();
84108
}
85109

86110
std::string ASTPrinter::sanitizeUtf8(StringRef Text) {
@@ -631,8 +655,7 @@ class PrintAST : public ASTVisitor<PrintAST> {
631655
#define STMT(Name, Parent) void visit##Name##Stmt(Name##Stmt *stmt);
632656
#include "swift/AST/StmtNodes.def"
633657

634-
void printSynthesizedExtension(NominalTypeDecl* Decl,
635-
ExtensionDecl* ExtDecl);
658+
void printSynthesizedExtension(Type ExtendedType, ExtensionDecl *ExtDecl);
636659

637660
void printExtension(ExtensionDecl* ExtDecl);
638661

@@ -668,8 +691,9 @@ class PrintAST : public ASTVisitor<PrintAST> {
668691
Options.TransformContext &&
669692
Options.TransformContext->isPrintingSynthesizedExtension() &&
670693
isa<ExtensionDecl>(D);
671-
if (Synthesize)
672-
Printer.setSynthesizedTarget(Options.TransformContext->getNominal());
694+
if (Synthesize) {
695+
Printer.setSynthesizedTarget(Options.TransformContext->getDecl());
696+
}
673697

674698
// We want to print a newline before doc comments. Swift code already
675699
// handles this, but we need to insert it for clang doc comments when not
@@ -692,10 +716,10 @@ class PrintAST : public ASTVisitor<PrintAST> {
692716
ASTVisitor::visit(D);
693717

694718
if (Synthesize) {
695-
Printer.setSynthesizedTarget(nullptr);
696-
Printer.printSynthesizedExtensionPost(
697-
cast<ExtensionDecl>(D), Options.TransformContext->getNominal(),
698-
Options.BracketOptions);
719+
Printer.setSynthesizedTarget({});
720+
Printer.printSynthesizedExtensionPost(cast<ExtensionDecl>(D),
721+
Options.TransformContext->getDecl(),
722+
Options.BracketOptions);
699723
} else {
700724
Printer.callPrintDeclPost(D, Options.BracketOptions);
701725
}
@@ -1775,14 +1799,14 @@ static void printExtendedTypeName(Type ExtendedType, ASTPrinter &Printer,
17751799
Printer.printTypeRef(ExtendedType, Nominal, Nominal->getName());
17761800
}
17771801

1778-
void PrintAST::
1779-
printSynthesizedExtension(NominalTypeDecl* Decl, ExtensionDecl *ExtDecl) {
1802+
void PrintAST::printSynthesizedExtension(Type ExtendedType,
1803+
ExtensionDecl *ExtDecl) {
17801804
if (Options.BracketOptions.shouldOpenExtension(ExtDecl)) {
17811805
printDocumentationComment(ExtDecl);
17821806
printAttributes(ExtDecl);
17831807
Printer << tok::kw_extension << " ";
17841808

1785-
printExtendedTypeName(Decl->getDeclaredType(), Printer, Options);
1809+
printExtendedTypeName(ExtendedType, Printer, Options);
17861810
printInherited(ExtDecl);
17871811

17881812
if (ExtDecl->getGenericParams())
@@ -1832,9 +1856,11 @@ void PrintAST::printExtension(ExtensionDecl *decl) {
18321856

18331857
void PrintAST::visitExtensionDecl(ExtensionDecl *decl) {
18341858
if (Options.TransformContext &&
1835-
Options.TransformContext->isPrintingSynthesizedExtension())
1836-
printSynthesizedExtension(Options.TransformContext->getNominal(), decl);
1837-
else
1859+
Options.TransformContext->isPrintingSynthesizedExtension()) {
1860+
auto extendedType =
1861+
Options.TransformContext->getBaseType()->mapTypeOutOfContext();
1862+
printSynthesizedExtension(extendedType, decl);
1863+
} else
18381864
printExtension(decl);
18391865
}
18401866

0 commit comments

Comments
 (0)