Skip to content

Commit 2bc8470

Browse files
authored
Merge pull request #14634 from huonw/doc-conditional-conformances-4.1
[4.1] [IDE] Teach type checker about conditional conformance extensions.
2 parents 1a88e86 + f883c48 commit 2bc8470

19 files changed

+805
-339
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

include/swift/AST/TypeAlignments.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ namespace swift {
3737
class ExtensionDecl;
3838
class GenericEnvironment;
3939
class GenericTypeParamDecl;
40+
class NominalTypeDecl;
4041
class NormalProtocolConformance;
4142
class OperatorDecl;
4243
class Pattern;
@@ -90,6 +91,7 @@ LLVM_DECLARE_TYPE_ALIGNMENT(swift::OperatorDecl, swift::DeclAlignInBits)
9091
LLVM_DECLARE_TYPE_ALIGNMENT(swift::ProtocolDecl, swift::DeclAlignInBits)
9192
LLVM_DECLARE_TYPE_ALIGNMENT(swift::TypeDecl, swift::DeclAlignInBits)
9293
LLVM_DECLARE_TYPE_ALIGNMENT(swift::ValueDecl, swift::DeclAlignInBits)
94+
LLVM_DECLARE_TYPE_ALIGNMENT(swift::NominalTypeDecl, swift::DeclAlignInBits)
9395
LLVM_DECLARE_TYPE_ALIGNMENT(swift::ExtensionDecl, swift::DeclAlignInBits)
9496

9597
LLVM_DECLARE_TYPE_ALIGNMENT(swift::TypeBase, swift::TypeAlignInBits)
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
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 "swift/AST/TypeAlignments.h"
22+
#include "llvm/ADT/PointerUnion.h"
23+
24+
namespace swift {
25+
26+
/// \brief Describes either a nominal type declaration or an extension
27+
/// declaration.
28+
struct TypeOrExtensionDecl {
29+
// (The definitions are in Decl.cpp.)
30+
llvm::PointerUnion<NominalTypeDecl *, ExtensionDecl *> Decl;
31+
32+
TypeOrExtensionDecl() = default;
33+
34+
TypeOrExtensionDecl(NominalTypeDecl *D);
35+
TypeOrExtensionDecl(ExtensionDecl *D);
36+
37+
/// \brief Return the contained *Decl as the Decl superclass.
38+
class Decl *getAsDecl() const;
39+
/// \brief Return the contained *Decl as the DeclContext superclass.
40+
DeclContext *getAsDeclContext() const;
41+
/// \brief Return the contained NominalTypeDecl or that of the extended type
42+
/// in the ExtensionDecl.
43+
NominalTypeDecl *getBaseNominal() const;
44+
45+
/// \brief Is the contained pointer null?
46+
bool isNull() const;
47+
explicit operator bool() const { return !isNull(); }
48+
49+
bool operator==(TypeOrExtensionDecl rhs) { return Decl == rhs.Decl; }
50+
bool operator!=(TypeOrExtensionDecl rhs) { return Decl != rhs.Decl; }
51+
bool operator<(TypeOrExtensionDecl rhs) { return Decl < rhs.Decl; }
52+
};
53+
54+
} // end namespace swift
55+
56+
#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: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5584,3 +5584,20 @@ void ClassDecl::setSuperclass(Type superclass) {
55845584
&& "superclass must be interface type");
55855585
LazySemanticInfo.Superclass.setPointerAndInt(superclass, true);
55865586
}
5587+
5588+
TypeOrExtensionDecl::TypeOrExtensionDecl(NominalTypeDecl *D) : Decl(D) {}
5589+
TypeOrExtensionDecl::TypeOrExtensionDecl(ExtensionDecl *D) : Decl(D) {}
5590+
5591+
Decl *TypeOrExtensionDecl::getAsDecl() const {
5592+
if (auto NTD = Decl.dyn_cast<NominalTypeDecl *>())
5593+
return NTD;
5594+
5595+
return Decl.get<ExtensionDecl *>();
5596+
}
5597+
DeclContext *TypeOrExtensionDecl::getAsDeclContext() const {
5598+
return getAsDecl()->getInnermostDeclContext();
5599+
}
5600+
NominalTypeDecl *TypeOrExtensionDecl::getBaseNominal() const {
5601+
return getAsDeclContext()->getAsNominalTypeOrNominalTypeExtensionContext();
5602+
}
5603+
bool TypeOrExtensionDecl::isNull() const { return Decl.isNull(); }

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)