Skip to content

Commit edfa805

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 00ddaa1 commit edfa805

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
@@ -170,10 +170,6 @@ class ConstraintCheckerArenaRAII {
170170
};
171171

172172
class SILLayout; // From SIL
173-
/// \brief Describes either a nominal type declaration or an extension
174-
/// declaration.
175-
typedef llvm::PointerUnion<NominalTypeDecl *, ExtensionDecl *>
176-
TypeOrExtensionDecl;
177173

178174
/// ASTContext - This object creates and owns the AST objects.
179175
/// 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
};
@@ -417,7 +446,7 @@ struct PrintOptions {
417446

418447
void setBaseType(Type T);
419448

420-
void initForSynthesizedExtension(NominalTypeDecl *D);
449+
void initForSynthesizedExtension(TypeOrExtensionDecl D);
421450

422451
void clearSynthesizedExtension();
423452

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) {
@@ -619,8 +643,7 @@ class PrintAST : public ASTVisitor<PrintAST> {
619643
#define STMT(Name, Parent) void visit##Name##Stmt(Name##Stmt *stmt);
620644
#include "swift/AST/StmtNodes.def"
621645

622-
void printSynthesizedExtension(NominalTypeDecl* Decl,
623-
ExtensionDecl* ExtDecl);
646+
void printSynthesizedExtension(Type ExtendedType, ExtensionDecl *ExtDecl);
624647

625648
void printExtension(ExtensionDecl* ExtDecl);
626649

@@ -656,8 +679,9 @@ class PrintAST : public ASTVisitor<PrintAST> {
656679
Options.TransformContext &&
657680
Options.TransformContext->isPrintingSynthesizedExtension() &&
658681
isa<ExtensionDecl>(D);
659-
if (Synthesize)
660-
Printer.setSynthesizedTarget(Options.TransformContext->getNominal());
682+
if (Synthesize) {
683+
Printer.setSynthesizedTarget(Options.TransformContext->getDecl());
684+
}
661685

662686
// We want to print a newline before doc comments. Swift code already
663687
// handles this, but we need to insert it for clang doc comments when not
@@ -680,10 +704,10 @@ class PrintAST : public ASTVisitor<PrintAST> {
680704
ASTVisitor::visit(D);
681705

682706
if (Synthesize) {
683-
Printer.setSynthesizedTarget(nullptr);
684-
Printer.printSynthesizedExtensionPost(
685-
cast<ExtensionDecl>(D), Options.TransformContext->getNominal(),
686-
Options.BracketOptions);
707+
Printer.setSynthesizedTarget({});
708+
Printer.printSynthesizedExtensionPost(cast<ExtensionDecl>(D),
709+
Options.TransformContext->getDecl(),
710+
Options.BracketOptions);
687711
} else {
688712
Printer.callPrintDeclPost(D, Options.BracketOptions);
689713
}
@@ -1766,14 +1790,14 @@ static void printExtendedTypeName(Type ExtendedType, ASTPrinter &Printer,
17661790
Printer.printTypeRef(ExtendedType, Nominal, Nominal->getName());
17671791
}
17681792

1769-
void PrintAST::
1770-
printSynthesizedExtension(NominalTypeDecl* Decl, ExtensionDecl *ExtDecl) {
1793+
void PrintAST::printSynthesizedExtension(Type ExtendedType,
1794+
ExtensionDecl *ExtDecl) {
17711795
if (Options.BracketOptions.shouldOpenExtension(ExtDecl)) {
17721796
printDocumentationComment(ExtDecl);
17731797
printAttributes(ExtDecl);
17741798
Printer << tok::kw_extension << " ";
17751799

1776-
printExtendedTypeName(Decl->getDeclaredType(), Printer, Options);
1800+
printExtendedTypeName(ExtendedType, Printer, Options);
17771801
printInherited(ExtDecl);
17781802

17791803
if (ExtDecl->getGenericParams())
@@ -1823,9 +1847,11 @@ void PrintAST::printExtension(ExtensionDecl *decl) {
18231847

18241848
void PrintAST::visitExtensionDecl(ExtensionDecl *decl) {
18251849
if (Options.TransformContext &&
1826-
Options.TransformContext->isPrintingSynthesizedExtension())
1827-
printSynthesizedExtension(Options.TransformContext->getNominal(), decl);
1828-
else
1850+
Options.TransformContext->isPrintingSynthesizedExtension()) {
1851+
auto extendedType =
1852+
Options.TransformContext->getBaseType()->mapTypeOutOfContext();
1853+
printSynthesizedExtension(extendedType, decl);
1854+
} else
18291855
printExtension(decl);
18301856
}
18311857

0 commit comments

Comments
 (0)