Skip to content

[IDE] Teach type checker about conditional conformance extensions. #14554

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Feb 13, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 0 additions & 4 deletions include/swift/AST/ASTContext.h
Original file line number Diff line number Diff line change
Expand Up @@ -174,10 +174,6 @@ class ConstraintCheckerArenaRAII {
};

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

/// ASTContext - This object creates and owns the AST objects.
/// However, this class does more than just maintain context within an AST.
Expand Down
11 changes: 6 additions & 5 deletions include/swift/AST/ASTPrinter.h
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ enum class PrintStructureKind {
class ASTPrinter {
unsigned CurrentIndentation = 0;
unsigned PendingNewlines = 0;
const NominalTypeDecl *SynthesizeTarget = nullptr;
TypeOrExtensionDecl SynthesizeTarget;

void printTextImpl(StringRef Text);

Expand Down Expand Up @@ -136,13 +136,14 @@ class ASTPrinter {

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

/// Called after printing a synthesized extension.
virtual void printSynthesizedExtensionPost(const ExtensionDecl *ED,
const NominalTypeDecl *NTD,
Optional<BracketOptions> Bracket) {}
TypeOrExtensionDecl TargetDecl,
Optional<BracketOptions> Bracket) {
}

/// Called before printing a structured entity.
///
Expand Down Expand Up @@ -213,7 +214,7 @@ class ASTPrinter {
CurrentIndentation = NumSpaces;
}

void setSynthesizedTarget(NominalTypeDecl *Target) {
void setSynthesizedTarget(TypeOrExtensionDecl Target) {
assert((!SynthesizeTarget || !Target || Target == SynthesizeTarget) &&
"unexpected change of setSynthesizedTarget");
// FIXME: this can overwrite the original target with nullptr.
Expand Down
37 changes: 33 additions & 4 deletions include/swift/AST/PrintOptions.h
Original file line number Diff line number Diff line change
Expand Up @@ -36,16 +36,45 @@ enum DeclAttrKind : unsigned;
class SynthesizedExtensionAnalyzer;
struct PrintOptions;

/// \brief Describes either a nominal type declaration or an extension
/// declaration.
struct TypeOrExtensionDecl {
llvm::PointerUnion<NominalTypeDecl *, ExtensionDecl *> Decl;

TypeOrExtensionDecl() = default;

TypeOrExtensionDecl(NominalTypeDecl *D);
TypeOrExtensionDecl(ExtensionDecl *D);

/// \brief Return the contained *Decl as the Decl superclass.
class Decl *getAsDecl() const;
/// \brief Return the contained *Decl as the DeclContext superclass.
DeclContext *getAsDeclContext() const;
/// \brief Return the contained NominalTypeDecl or that of the extended type
/// in the ExtensionDecl.
NominalTypeDecl *getBaseNominal() const;

/// \brief Is the contained pointer null?
bool isNull() const;
explicit operator bool() const { return !isNull(); }

bool operator==(TypeOrExtensionDecl rhs) { return Decl == rhs.Decl; }
bool operator!=(TypeOrExtensionDecl rhs) { return Decl != rhs.Decl; }
bool operator<(TypeOrExtensionDecl rhs) { return Decl < rhs.Decl; }
};

/// Necessary information for archetype transformation during printing.
struct TypeTransformContext {
TypeBase *BaseType;
NominalTypeDecl *Nominal = nullptr;
TypeOrExtensionDecl Decl;

explicit TypeTransformContext(Type T);
explicit TypeTransformContext(NominalTypeDecl* NTD);
explicit TypeTransformContext(TypeOrExtensionDecl D);

Type getBaseType() const;
NominalTypeDecl *getNominal() const;
TypeOrExtensionDecl getDecl() const;

DeclContext *getDeclContext() const;

bool isPrintingSynthesizedExtension() const;
};
Expand Down Expand Up @@ -421,7 +450,7 @@ struct PrintOptions {

void setBaseType(Type T);

void initForSynthesizedExtension(NominalTypeDecl *D);
void initForSynthesizedExtension(TypeOrExtensionDecl D);

void clearSynthesizedExtension();

Expand Down
14 changes: 11 additions & 3 deletions include/swift/Sema/IDETypeChecking.h
Original file line number Diff line number Diff line change
Expand Up @@ -137,10 +137,18 @@ namespace swift {
/// Creates a lazy type resolver for use in lookups.
OwnedResolver createLazyResolver(ASTContext &Ctx);

typedef std::pair<ExtensionDecl*, bool> ExtensionAndIsSynthesized;
struct ExtensionInfo {
// The extension with the declarations to apply.
ExtensionDecl *Ext;
// The extension that enables the former to apply, if any (i.e. a
// conditional
// conformance to Foo enables 'extension Foo').
ExtensionDecl *EnablingExt;
bool IsSynthesized;
};

typedef llvm::function_ref<void(ArrayRef<ExtensionAndIsSynthesized>)>
ExtensionGroupOperation;
typedef llvm::function_ref<void(ArrayRef<ExtensionInfo>)>
ExtensionGroupOperation;

class SynthesizedExtensionAnalyzer {
struct Implementation;
Expand Down
66 changes: 46 additions & 20 deletions lib/AST/ASTPrinter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -55,32 +55,56 @@ void PrintOptions::setBaseType(Type T) {
TransformContext = TypeTransformContext(T);
}

void PrintOptions::initForSynthesizedExtension(NominalTypeDecl *D) {
void PrintOptions::initForSynthesizedExtension(TypeOrExtensionDecl D) {
TransformContext = TypeTransformContext(D);
}

void PrintOptions::clearSynthesizedExtension() {
TransformContext.reset();
}

TypeOrExtensionDecl::TypeOrExtensionDecl(NominalTypeDecl *D) : Decl(D) {}
TypeOrExtensionDecl::TypeOrExtensionDecl(ExtensionDecl *D) : Decl(D) {}

Decl *TypeOrExtensionDecl::getAsDecl() const {
if (auto NTD = Decl.dyn_cast<NominalTypeDecl *>())
return NTD;

return Decl.get<ExtensionDecl *>();
}
DeclContext *TypeOrExtensionDecl::getAsDeclContext() const {
return getAsDecl()->getInnermostDeclContext();
}
NominalTypeDecl *TypeOrExtensionDecl::getBaseNominal() const {
return getAsDeclContext()->getAsNominalTypeOrNominalTypeExtensionContext();
}
bool TypeOrExtensionDecl::isNull() const { return Decl.isNull(); }

TypeTransformContext::TypeTransformContext(Type T)
: BaseType(T.getPointer()) {
assert(T->mayHaveMembers());
}

TypeTransformContext::TypeTransformContext(NominalTypeDecl *NTD)
: BaseType(NTD->getDeclaredTypeInContext().getPointer()), Nominal(NTD) {}
TypeTransformContext::TypeTransformContext(TypeOrExtensionDecl D)
: BaseType(nullptr), Decl(D) {
if (auto NTD = Decl.Decl.dyn_cast<NominalTypeDecl *>())
BaseType = NTD->getDeclaredTypeInContext().getPointer();
else
BaseType = Decl.Decl.get<ExtensionDecl *>()->getExtendedType().getPointer();
}

TypeOrExtensionDecl TypeTransformContext::getDecl() const { return Decl; }

NominalTypeDecl *TypeTransformContext::getNominal() const {
return Nominal;
DeclContext *TypeTransformContext::getDeclContext() const {
return Decl.getAsDecl()->getDeclContext();
}

Type TypeTransformContext::getBaseType() const {
return Type(BaseType);
}

bool TypeTransformContext::isPrintingSynthesizedExtension() const {
return Nominal != nullptr;
return !Decl.isNull();
}

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

void printSynthesizedExtension(NominalTypeDecl* Decl,
ExtensionDecl* ExtDecl);
void printSynthesizedExtension(Type ExtendedType, ExtensionDecl *ExtDecl);

void printExtension(ExtensionDecl* ExtDecl);

Expand Down Expand Up @@ -668,8 +691,9 @@ class PrintAST : public ASTVisitor<PrintAST> {
Options.TransformContext &&
Options.TransformContext->isPrintingSynthesizedExtension() &&
isa<ExtensionDecl>(D);
if (Synthesize)
Printer.setSynthesizedTarget(Options.TransformContext->getNominal());
if (Synthesize) {
Printer.setSynthesizedTarget(Options.TransformContext->getDecl());
}

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

if (Synthesize) {
Printer.setSynthesizedTarget(nullptr);
Printer.printSynthesizedExtensionPost(
cast<ExtensionDecl>(D), Options.TransformContext->getNominal(),
Options.BracketOptions);
Printer.setSynthesizedTarget({});
Printer.printSynthesizedExtensionPost(cast<ExtensionDecl>(D),
Options.TransformContext->getDecl(),
Options.BracketOptions);
} else {
Printer.callPrintDeclPost(D, Options.BracketOptions);
}
Expand Down Expand Up @@ -1775,14 +1799,14 @@ static void printExtendedTypeName(Type ExtendedType, ASTPrinter &Printer,
Printer.printTypeRef(ExtendedType, Nominal, Nominal->getName());
}

void PrintAST::
printSynthesizedExtension(NominalTypeDecl* Decl, ExtensionDecl *ExtDecl) {
void PrintAST::printSynthesizedExtension(Type ExtendedType,
ExtensionDecl *ExtDecl) {
if (Options.BracketOptions.shouldOpenExtension(ExtDecl)) {
printDocumentationComment(ExtDecl);
printAttributes(ExtDecl);
Printer << tok::kw_extension << " ";

printExtendedTypeName(Decl->getDeclaredType(), Printer, Options);
printExtendedTypeName(ExtendedType, Printer, Options);
printInherited(ExtDecl);

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

void PrintAST::visitExtensionDecl(ExtensionDecl *decl) {
if (Options.TransformContext &&
Options.TransformContext->isPrintingSynthesizedExtension())
printSynthesizedExtension(Options.TransformContext->getNominal(), decl);
else
Options.TransformContext->isPrintingSynthesizedExtension()) {
auto extendedType =
Options.TransformContext->getBaseType()->mapTypeOutOfContext();
printSynthesizedExtension(extendedType, decl);
} else
printExtension(decl);
}

Expand Down
2 changes: 1 addition & 1 deletion lib/AST/ProtocolConformance.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -407,7 +407,7 @@ void NormalProtocolConformance::differenceAndStoreConditionalRequirements() {
// Find the requirements in the extension that aren't proved by the original
// type, these are the ones that make the conformance conditional.
ConditionalRequirements =
ctxt.AllocateCopy(canExtensionSig->requirementsNotSatisfiedBy(canTypeSig));
ctxt.AllocateCopy(extensionSig->requirementsNotSatisfiedBy(typeSig));
}

void NormalProtocolConformance::setSignatureConformances(
Expand Down
Loading