Skip to content

Commit 56cf077

Browse files
authored
Merge pull request #14554 from huonw/doc-conditional-conformances
[IDE] Teach type checker about conditional conformance extensions.
2 parents e2bf32f + cb60dbe commit 56cf077

16 files changed

+772
-339
lines changed

include/swift/AST/ASTContext.h

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

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

181177
/// ASTContext - This object creates and owns the AST objects.
182178
/// 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

lib/AST/ProtocolConformance.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -407,7 +407,7 @@ void NormalProtocolConformance::differenceAndStoreConditionalRequirements() {
407407
// Find the requirements in the extension that aren't proved by the original
408408
// type, these are the ones that make the conformance conditional.
409409
ConditionalRequirements =
410-
ctxt.AllocateCopy(canExtensionSig->requirementsNotSatisfiedBy(canTypeSig));
410+
ctxt.AllocateCopy(extensionSig->requirementsNotSatisfiedBy(typeSig));
411411
}
412412

413413
void NormalProtocolConformance::setSignatureConformances(

0 commit comments

Comments
 (0)