[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.
This commit is contained in:
Huon Wilson
2018-02-13 01:32:24 +11:00
parent 715ca9d27d
commit cb60dbeee2
14 changed files with 870 additions and 437 deletions

View File

@@ -55,7 +55,7 @@ void PrintOptions::setBaseType(Type T) {
TransformContext = TypeTransformContext(T);
}
void PrintOptions::initForSynthesizedExtension(NominalTypeDecl *D) {
void PrintOptions::initForSynthesizedExtension(TypeOrExtensionDecl D) {
TransformContext = TypeTransformContext(D);
}
@@ -63,16 +63,40 @@ 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();
}
NominalTypeDecl *TypeTransformContext::getNominal() const {
return Nominal;
TypeOrExtensionDecl TypeTransformContext::getDecl() const { return Decl; }
DeclContext *TypeTransformContext::getDeclContext() const {
return Decl.getAsDecl()->getDeclContext();
}
Type TypeTransformContext::getBaseType() const {
@@ -80,7 +104,7 @@ Type TypeTransformContext::getBaseType() const {
}
bool TypeTransformContext::isPrintingSynthesizedExtension() const {
return Nominal != nullptr;
return !Decl.isNull();
}
std::string ASTPrinter::sanitizeUtf8(StringRef Text) {
@@ -631,8 +655,7 @@ private:
#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);
@@ -668,8 +691,9 @@ public:
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
@@ -692,10 +716,10 @@ public:
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);
}
@@ -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())
@@ -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);
}