Skip to content

Commit 533f2e9

Browse files
authored
Merge pull request #14633 from huonw/doc-conditional-conformances-5.0
[5.0] [IDE] Teach type checker about conditional conformance extensions.
2 parents 91ff005 + d3fdd5d commit 533f2e9

18 files changed

+830
-365
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: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
#include "swift/Basic/STLExtras.h"
1717
#include "swift/AST/AttrKind.h"
1818
#include "swift/AST/Identifier.h"
19+
#include "swift/AST/TypeOrExtensionDecl.h"
1920
#include "llvm/ADT/Optional.h"
2021
#include <limits.h>
2122
#include <vector>
@@ -36,16 +37,19 @@ enum DeclAttrKind : unsigned;
3637
class SynthesizedExtensionAnalyzer;
3738
struct PrintOptions;
3839

40+
3941
/// Necessary information for archetype transformation during printing.
4042
struct TypeTransformContext {
4143
TypeBase *BaseType;
42-
NominalTypeDecl *Nominal = nullptr;
44+
TypeOrExtensionDecl Decl;
4345

4446
explicit TypeTransformContext(Type T);
45-
explicit TypeTransformContext(NominalTypeDecl* NTD);
47+
explicit TypeTransformContext(TypeOrExtensionDecl D);
4648

4749
Type getBaseType() const;
48-
NominalTypeDecl *getNominal() const;
50+
TypeOrExtensionDecl getDecl() const;
51+
52+
DeclContext *getDeclContext() const;
4953

5054
bool isPrintingSynthesizedExtension() const;
5155
};
@@ -417,7 +421,7 @@ struct PrintOptions {
417421

418422
void setBaseType(Type T);
419423

420-
void initForSynthesizedExtension(NominalTypeDecl *D);
424+
void initForSynthesizedExtension(TypeOrExtensionDecl D);
421425

422426
void clearSynthesizedExtension();
423427

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
//===- TypeOrExtensionDecl.h - Swift Language Declaration ASTs -*- C++ -*-===//
2+
//
3+
// This source file is part of the Swift.org open source project
4+
//
5+
// Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors
6+
// Licensed under Apache License v2.0 with Runtime Library Exception
7+
//
8+
// See https://swift.org/LICENSE.txt for license information
9+
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
10+
//
11+
//===----------------------------------------------------------------------===//
12+
//
13+
// This file defines the TypeOrExtensionDecl struct, separately to Decl.h so
14+
// that this can be included in files that Decl.h includes.
15+
//
16+
//===----------------------------------------------------------------------===//
17+
18+
#ifndef SWIFT_TYPE_OR_EXTENSION_DECL_H
19+
#define SWIFT_TYPE_OR_EXTENSION_DECL_H
20+
21+
#include "llvm/ADT/PointerUnion.h"
22+
23+
namespace swift {
24+
class Decl;
25+
class NominalTypeDecl;
26+
class ExtensionDecl;
27+
class DeclContext;
28+
29+
/// \brief Describes either a nominal type declaration or an extension
30+
/// declaration.
31+
struct TypeOrExtensionDecl {
32+
// (The definitions are in Decl.cpp.)
33+
llvm::PointerUnion<NominalTypeDecl *, ExtensionDecl *> Decl;
34+
35+
TypeOrExtensionDecl() = default;
36+
37+
TypeOrExtensionDecl(NominalTypeDecl *D);
38+
TypeOrExtensionDecl(ExtensionDecl *D);
39+
40+
/// \brief Return the contained *Decl as the Decl superclass.
41+
class Decl *getAsDecl() const;
42+
/// \brief Return the contained *Decl as the DeclContext superclass.
43+
DeclContext *getAsDeclContext() const;
44+
/// \brief Return the contained NominalTypeDecl or that of the extended type
45+
/// in the ExtensionDecl.
46+
NominalTypeDecl *getBaseNominal() const;
47+
48+
/// \brief Is the contained pointer null?
49+
bool isNull() const;
50+
explicit operator bool() const { return !isNull(); }
51+
52+
bool operator==(TypeOrExtensionDecl rhs) { return Decl == rhs.Decl; }
53+
bool operator!=(TypeOrExtensionDecl rhs) { return Decl != rhs.Decl; }
54+
bool operator<(TypeOrExtensionDecl rhs) { return Decl < rhs.Decl; }
55+
};
56+
57+
} // end namespace swift
58+
59+
#endif

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: 29 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ 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

@@ -68,19 +68,26 @@ TypeTransformContext::TypeTransformContext(Type T)
6868
assert(T->mayHaveMembers());
6969
}
7070

71-
TypeTransformContext::TypeTransformContext(NominalTypeDecl *NTD)
72-
: BaseType(NTD->getDeclaredTypeInContext().getPointer()), Nominal(NTD) {}
71+
TypeTransformContext::TypeTransformContext(TypeOrExtensionDecl D)
72+
: BaseType(nullptr), Decl(D) {
73+
if (auto NTD = Decl.Decl.dyn_cast<NominalTypeDecl *>())
74+
BaseType = NTD->getDeclaredTypeInContext().getPointer();
75+
else
76+
BaseType = Decl.Decl.get<ExtensionDecl *>()->getExtendedType().getPointer();
77+
}
7378

74-
NominalTypeDecl *TypeTransformContext::getNominal() const {
75-
return Nominal;
79+
TypeOrExtensionDecl TypeTransformContext::getDecl() const { return Decl; }
80+
81+
DeclContext *TypeTransformContext::getDeclContext() const {
82+
return Decl.getAsDecl()->getDeclContext();
7683
}
7784

7885
Type TypeTransformContext::getBaseType() const {
7986
return Type(BaseType);
8087
}
8188

8289
bool TypeTransformContext::isPrintingSynthesizedExtension() const {
83-
return Nominal != nullptr;
90+
return !Decl.isNull();
8491
}
8592

8693
std::string ASTPrinter::sanitizeUtf8(StringRef Text) {
@@ -619,8 +626,7 @@ class PrintAST : public ASTVisitor<PrintAST> {
619626
#define STMT(Name, Parent) void visit##Name##Stmt(Name##Stmt *stmt);
620627
#include "swift/AST/StmtNodes.def"
621628

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

625631
void printExtension(ExtensionDecl* ExtDecl);
626632

@@ -656,8 +662,9 @@ class PrintAST : public ASTVisitor<PrintAST> {
656662
Options.TransformContext &&
657663
Options.TransformContext->isPrintingSynthesizedExtension() &&
658664
isa<ExtensionDecl>(D);
659-
if (Synthesize)
660-
Printer.setSynthesizedTarget(Options.TransformContext->getNominal());
665+
if (Synthesize) {
666+
Printer.setSynthesizedTarget(Options.TransformContext->getDecl());
667+
}
661668

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

682689
if (Synthesize) {
683-
Printer.setSynthesizedTarget(nullptr);
684-
Printer.printSynthesizedExtensionPost(
685-
cast<ExtensionDecl>(D), Options.TransformContext->getNominal(),
686-
Options.BracketOptions);
690+
Printer.setSynthesizedTarget({});
691+
Printer.printSynthesizedExtensionPost(cast<ExtensionDecl>(D),
692+
Options.TransformContext->getDecl(),
693+
Options.BracketOptions);
687694
} else {
688695
Printer.callPrintDeclPost(D, Options.BracketOptions);
689696
}
@@ -1766,14 +1773,14 @@ static void printExtendedTypeName(Type ExtendedType, ASTPrinter &Printer,
17661773
Printer.printTypeRef(ExtendedType, Nominal, Nominal->getName());
17671774
}
17681775

1769-
void PrintAST::
1770-
printSynthesizedExtension(NominalTypeDecl* Decl, ExtensionDecl *ExtDecl) {
1776+
void PrintAST::printSynthesizedExtension(Type ExtendedType,
1777+
ExtensionDecl *ExtDecl) {
17711778
if (Options.BracketOptions.shouldOpenExtension(ExtDecl)) {
17721779
printDocumentationComment(ExtDecl);
17731780
printAttributes(ExtDecl);
17741781
Printer << tok::kw_extension << " ";
17751782

1776-
printExtendedTypeName(Decl->getDeclaredType(), Printer, Options);
1783+
printExtendedTypeName(ExtendedType, Printer, Options);
17771784
printInherited(ExtDecl);
17781785

17791786
if (ExtDecl->getGenericParams())
@@ -1823,9 +1830,11 @@ void PrintAST::printExtension(ExtensionDecl *decl) {
18231830

18241831
void PrintAST::visitExtensionDecl(ExtensionDecl *decl) {
18251832
if (Options.TransformContext &&
1826-
Options.TransformContext->isPrintingSynthesizedExtension())
1827-
printSynthesizedExtension(Options.TransformContext->getNominal(), decl);
1828-
else
1833+
Options.TransformContext->isPrintingSynthesizedExtension()) {
1834+
auto extendedType =
1835+
Options.TransformContext->getBaseType()->mapTypeOutOfContext();
1836+
printSynthesizedExtension(extendedType, decl);
1837+
} else
18291838
printExtension(decl);
18301839
}
18311840

lib/AST/Decl.cpp

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5552,3 +5552,21 @@ void ClassDecl::setSuperclass(Type superclass) {
55525552
&& "superclass must be interface type");
55535553
LazySemanticInfo.Superclass.setPointerAndInt(superclass, true);
55545554
}
5555+
5556+
TypeOrExtensionDecl::TypeOrExtensionDecl(NominalTypeDecl *D) : Decl(D) {}
5557+
TypeOrExtensionDecl::TypeOrExtensionDecl(ExtensionDecl *D) : Decl(D) {}
5558+
5559+
Decl *TypeOrExtensionDecl::getAsDecl() const {
5560+
if (auto NTD = Decl.dyn_cast<NominalTypeDecl *>())
5561+
return NTD;
5562+
5563+
return Decl.get<ExtensionDecl *>();
5564+
}
5565+
DeclContext *TypeOrExtensionDecl::getAsDeclContext() const {
5566+
return getAsDecl()->getInnermostDeclContext();
5567+
}
5568+
NominalTypeDecl *TypeOrExtensionDecl::getBaseNominal() const {
5569+
return getAsDeclContext()->getAsNominalTypeOrNominalTypeExtensionContext();
5570+
}
5571+
bool TypeOrExtensionDecl::isNull() const { return Decl.isNull(); }
5572+

lib/AST/ProtocolConformance.cpp

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

388388
void NormalProtocolConformance::setSignatureConformances(

0 commit comments

Comments
 (0)