Skip to content
Closed
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
3 changes: 3 additions & 0 deletions include/swift/AST/ASTContext.h
Original file line number Diff line number Diff line change
Expand Up @@ -265,6 +265,9 @@ class ASTContext final {
/// Cache of remapped types (useful for diagnostics).
llvm::StringMap<Type> RemappedTypes;

/// Track extensions that inherit for inheriting protocol extensions.
mutable llvm::DenseMap<ExtensionDecl *, bool> InheritingExtensions;

private:
/// The current generation number, which reflects the number of
/// times that external modules have been loaded.
Expand Down
9 changes: 6 additions & 3 deletions include/swift/AST/Decl.h
Original file line number Diff line number Diff line change
Expand Up @@ -3230,9 +3230,6 @@ class NominalTypeDecl : public GenericTypeDecl, public IterableDeclContext {
/// a given nominal type.
mutable ConformanceLookupTable *ConformanceTable = nullptr;

/// Prepare the conformance table.
void prepareConformanceTable() const;

/// Returns the protocol requirements that \c Member conforms to.
ArrayRef<ValueDecl *>
getSatisfiedProtocolRequirementsForMember(const ValueDecl *Member,
Expand Down Expand Up @@ -3268,6 +3265,9 @@ class NominalTypeDecl : public GenericTypeDecl, public IterableDeclContext {
friend class ProtocolType;

public:
/// Prepare the conformance table (also acts as accessor).
ConformanceLookupTable *prepareConformanceTable() const;

using GenericTypeDecl::getASTContext;

SourceRange getBraces() const { return Braces; }
Expand Down Expand Up @@ -4101,6 +4101,9 @@ class ProtocolDecl final : public NominalTypeDecl {
return const_cast<ProtocolDecl *>(this)->getInheritedProtocolsSlow();
}

/// An extension has inherited a new protocol
void inheritedProtocolsChanged();

/// Determine whether this protocol has a superclass.
bool hasSuperclass() const { return (bool)getSuperclassDecl(); }

Expand Down
2 changes: 2 additions & 0 deletions include/swift/AST/DiagnosticsSema.def
Original file line number Diff line number Diff line change
Expand Up @@ -1590,6 +1590,8 @@ NOTE(objc_generic_extension_using_type_parameter_try_objc,none,
// Protocols
ERROR(type_does_not_conform,none,
"type %0 does not conform to protocol %1", (Type, Type))
ERROR(protocol_extension_does_not_conform,none,
"extension of protocol %0 does not conform to protocol %1", (Type, Type))
ERROR(cannot_use_nil_with_this_type,none,
"'nil' cannot be used in context expecting type %0", (Type))

Expand Down
3 changes: 2 additions & 1 deletion lib/AST/ASTVerifier.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2609,7 +2609,8 @@ class Verifier : public ASTWalker {
}

auto proto = conformance->getProtocol();
if (normal->getDeclContext() != conformingDC) {
if (normal->getDeclContext() != conformingDC &&
!isa<ExtensionDecl>(conformingDC)) {
Out << "AST verification error: conformance of "
<< nominal->getName().str() << " to protocol "
<< proto->getName().str() << " is in the wrong context.\n"
Expand Down
92 changes: 85 additions & 7 deletions lib/AST/ConformanceLookupTable.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
#include "swift/AST/ProtocolConformance.h"
#include "swift/AST/ProtocolConformanceRef.h"
#include "llvm/Support/SaveAndRestore.h"
#include "../Sema/TypeCheckProtocol.h"

using namespace swift;

Expand Down Expand Up @@ -138,6 +139,21 @@ void ConformanceLookupTable::destroy() {
this->~ConformanceLookupTable();
}

void ConformanceLookupTable::invalidate(NominalTypeDecl *recurse) {
for (auto &extInfo : NotionalConformancesFromExtension)
for (auto &toInvalidate : extInfo.second)
toInvalidate.first->ConformanceTable = nullptr;

if (recurse) {
recurse->ConformanceTable = nullptr;
return;
}

LastProcessed.clear();
Conformances.clear();
AllConformances.clear();
}

namespace {
using ConformanceConstructionInfo = std::pair<SourceLoc, ProtocolDecl *>;
}
Expand Down Expand Up @@ -271,7 +287,7 @@ void ConformanceLookupTable::updateLookupTable(NominalTypeDecl *nominal,
forEachInStage(
stage, nominal,
[&](NominalTypeDecl *nominal) {
addInheritedProtocols(nominal,
addInheritedProtocols(nominal, nominal,
ConformanceSource::forExplicit(nominal));
},
[&](ExtensionDecl *ext,
Expand All @@ -280,7 +296,8 @@ void ConformanceLookupTable::updateLookupTable(NominalTypeDecl *nominal,
// its inherited protocols directly.
auto source = ConformanceSource::forExplicit(ext);
for (auto locAndProto : protos)
addProtocol(locAndProto.second, locAndProto.first, source);
addInheritedProtocols(nominal, locAndProto.second,
source, /*depth*/1, locAndProto.first);
});
break;

Expand Down Expand Up @@ -463,17 +480,54 @@ bool ConformanceLookupTable::addProtocol(ProtocolDecl *protocol, SourceLoc loc,
}

void ConformanceLookupTable::addInheritedProtocols(
NominalTypeDecl *nominal,
llvm::PointerUnion<TypeDecl *, ExtensionDecl *> decl,
ConformanceSource source) {
ConformanceSource source, int depth, SourceLoc loc,
Propagator *propagator) {
if (depth > 100) // Circularity diagnosed elsewhere
return;
ExtensionDecl *ext = decl.dyn_cast<ExtensionDecl *>();
ProtocolDecl *proto = ext ? ext->getExtendedProtocolDecl() :
dyn_cast_or_null<ProtocolDecl>(decl.dyn_cast<TypeDecl *>());
// Prepare closure to register inherited protocols against extending.
Propagator protoPropagator = [&](ProtocolDecl *inheritedProto) {
if (proto)
proto->prepareConformanceTable()
->addWitnessRequirement(nominal, inheritedProto, ext);
// Continue propagating up stack.
if (propagator)
(*propagator)(inheritedProto);
};
// Find all of the protocols in the inheritance list.
bool anyObject = false;
for (const auto &found :
getDirectlyInheritedNominalTypeDecls(decl, anyObject)) {
if (auto proto = dyn_cast<ProtocolDecl>(found.second))
addProtocol(proto, found.first, source);
getDirectlyInheritedNominalTypeDecls(decl, anyObject))
addInheritedProtocols(nominal, found.second, source,
depth + 1, found.first, &protoPropagator);

if (auto proto = dyn_cast_or_null<ProtocolDecl>(decl.dyn_cast<TypeDecl *>())) {
for (ExtensionDecl *ext : proto->getExtensions()) {
if (ext->getInherited().empty())
continue;
addInheritedProtocols(nominal, ext, source, depth,
ext->getLoc(), &protoPropagator);
}
if (depth == 1)
addProtocol(proto, loc, source);
if (propagator)
(*propagator)(proto);
}
}

void ConformanceLookupTable::addWitnessRequirement(NominalTypeDecl *nominal,
ProtocolDecl *inheritedProto, ExtensionDecl *ext) {
NotionalConformancesFromExtension[ext][nominal][inheritedProto] = true;
auto table = nominal->prepareConformanceTable();
if (ext && table->Conformances.find(inheritedProto) == table->Conformances.end())
table->addProtocol(inheritedProto, ext ? ext->getLoc() : nominal->getLoc(),
ConformanceSource::forExplicit(nominal));
}

void ConformanceLookupTable::expandImpliedConformances(NominalTypeDecl *nominal,
DeclContext *dc) {
// Note: recursive type-checking implies that AllConformances
Expand Down Expand Up @@ -503,7 +557,7 @@ void ConformanceLookupTable::expandImpliedConformances(NominalTypeDecl *nominal,
}
}

addInheritedProtocols(conformingProtocol,
addInheritedProtocols(nominal, conformingProtocol,
ConformanceSource::forImplied(conformanceEntry));
}
}
Expand Down Expand Up @@ -1050,6 +1104,30 @@ void ConformanceLookupTable::lookupConformances(
}
}

void ConformanceLookupTable::addExtendedConformances(const ExtensionDecl *ext,
SmallVectorImpl<ProtocolConformance *> &conformances) {
TypeChecker &TC = TypeChecker::createForContext(ext->getASTContext());
MultiConformanceChecker groupChecker(TC);
for (auto &nominalPair : NotionalConformancesFromExtension[ext]) {
NominalTypeDecl *nominal = nominalPair.first;
for (auto &protocolPair : nominalPair.second) {
ProtocolDecl *proto = protocolPair.first;
if (!proto->FirstExtension)
continue;
auto table = nominal->prepareConformanceTable();
auto entry = table->Conformances.find(proto);
if (entry == table->Conformances.end())
continue;
auto conformance = table->getConformance(nominal, entry->second.back());
if (auto normal = dyn_cast<NormalProtocolConformance>(conformance)) {
conformances.push_back(conformance);
groupChecker.addConformance(normal);
}
}
}
groupChecker.checkAllConformances();
}

void ConformanceLookupTable::getAllProtocols(
NominalTypeDecl *nominal,
SmallVectorImpl<ProtocolDecl *> &scratch) {
Expand Down
25 changes: 23 additions & 2 deletions lib/AST/ConformanceLookupTable.h
Original file line number Diff line number Diff line change
Expand Up @@ -320,17 +320,32 @@ class ConformanceLookupTable {
llvm::DenseMap<const ValueDecl *, llvm::TinyPtrVector<ValueDecl *>>
ConformingDeclMap;

/// Tracks notionals that have an implied conformance from inheriting protocol extension
/// Used to know notionals that need to refresh their conformances and which witnesses to emit.
llvm::DenseMap<const ExtensionDecl *, llvm::DenseMap<NominalTypeDecl *,
llvm::DenseMap<ProtocolDecl *, bool>>> NotionalConformancesFromExtension;

/// Indicates whether we are visiting the superclass.
bool VisitingSuperclass = false;

/// Add a protocol.
bool addProtocol(ProtocolDecl *protocol, SourceLoc loc,
ConformanceSource source);

/// Add the protocols from the given list.
/// Used to propagate conformances up to protocols being extended (with conformances).
using Propagator = std::function<void (ProtocolDecl *inheritedProto)>;

/// Add the protocols from the given list, register conformance infered from protocol extension.
void addInheritedProtocols(
NominalTypeDecl *nominal,
llvm::PointerUnion<TypeDecl *, ExtensionDecl *> decl,
ConformanceSource source);
ConformanceSource source, int depth = 0,
SourceLoc loc = SourceLoc(),
Propagator *propagator = nullptr);

/// Register the conformance of the notional against the protocl for when witness tables are emitted.
void addWitnessRequirement(NominalTypeDecl *nominal, ProtocolDecl *proto,
ExtensionDecl *ext);

/// Expand the implied conformances for the given DeclContext.
void expandImpliedConformances(NominalTypeDecl *nominal, DeclContext *dc);
Expand Down Expand Up @@ -417,6 +432,8 @@ class ConformanceLookupTable {
/// Destroy the conformance table.
void destroy();

void invalidate(NominalTypeDecl *recurse = nullptr);

/// Add a synthesized conformance to the lookup table.
void addSynthesizedConformance(NominalTypeDecl *nominal,
ProtocolDecl *protocol);
Expand Down Expand Up @@ -444,6 +461,10 @@ class ConformanceLookupTable {
SmallVectorImpl<ProtocolConformance *> *conformances,
SmallVectorImpl<ConformanceDiagnostic> *diagnostics);

/// Add conformances implied by an inheriting protocol extension
void addExtendedConformances(const ExtensionDecl *ext,
SmallVectorImpl<ProtocolConformance *> &conformances);

/// Retrieve the complete set of protocols to which this nominal
/// type conforms.
void getAllProtocols(NominalTypeDecl *nominal,
Expand Down
29 changes: 22 additions & 7 deletions lib/AST/Decl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@
#include "clang/AST/Attr.h"
#include "clang/AST/DeclObjC.h"

#include "ConformanceLookupTable.h"
#include "InlinableText.h"
#include <algorithm>

Expand Down Expand Up @@ -1071,6 +1072,9 @@ ExtensionDecl *ExtensionDecl::create(ASTContext &ctx, SourceLoc extensionLoc,
if (clangNode)
result->setClangNode(clangNode);

if (!inherited.empty())
ctx.InheritingExtensions[result] = true;

return result;
}

Expand Down Expand Up @@ -4135,20 +4139,31 @@ ProtocolDecl::getInheritedProtocolsSlow() {
SmallPtrSet<const ProtocolDecl *, 2> known;
known.insert(this);
bool anyObject = false;
for (const auto found :
getDirectlyInheritedNominalTypeDecls(
const_cast<ProtocolDecl *>(this), anyObject)) {
if (auto proto = dyn_cast<ProtocolDecl>(found.second)) {
if (known.insert(proto).second)
result.push_back(proto);
auto enumerateInherited = [&] (llvm::PointerUnion<TypeDecl *,
ExtensionDecl *> decl) {
for (const auto found :
getDirectlyInheritedNominalTypeDecls(decl, anyObject)) {
if (auto proto = dyn_cast<ProtocolDecl>(found.second)) {
if (known.insert(proto).second)
result.push_back(proto);
}
}
}
};

enumerateInherited(this);
for (auto ext : getExtensions())
enumerateInherited(ext);

auto &ctx = getASTContext();
InheritedProtocols = ctx.AllocateCopy(result);
return InheritedProtocols;
}

void ProtocolDecl::inheritedProtocolsChanged() {
Bits.ProtocolDecl.InheritedProtocolsValid = false;
prepareConformanceTable()->invalidate();
}

llvm::TinyPtrVector<AssociatedTypeDecl *>
ProtocolDecl::getAssociatedTypeMembers() const {
llvm::TinyPtrVector<AssociatedTypeDecl *> result;
Expand Down
8 changes: 5 additions & 3 deletions lib/AST/ProtocolConformance.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1267,9 +1267,9 @@ ProtocolConformance::getInheritedConformance(ProtocolDecl *protocol) const {
}

#pragma mark Protocol conformance lookup
void NominalTypeDecl::prepareConformanceTable() const {
ConformanceLookupTable *NominalTypeDecl::prepareConformanceTable() const {
if (ConformanceTable)
return;
return ConformanceTable;

auto mutableThis = const_cast<NominalTypeDecl *>(this);
ASTContext &ctx = getASTContext();
Expand All @@ -1282,7 +1282,7 @@ void NominalTypeDecl::prepareConformanceTable() const {
if (file->getKind() != FileUnitKind::Source &&
file->getKind() != FileUnitKind::ClangModule &&
file->getKind() != FileUnitKind::DWARFModule) {
return;
return ConformanceTable;
}

SmallPtrSet<ProtocolDecl *, 2> protocols;
Expand Down Expand Up @@ -1316,6 +1316,8 @@ void NominalTypeDecl::prepareConformanceTable() const {
addSynthesized(KnownProtocolKind::RawRepresentable);
}
}

return ConformanceTable;
}

bool NominalTypeDecl::lookupConformance(
Expand Down
6 changes: 3 additions & 3 deletions lib/FrontendTool/TBD.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -103,9 +103,9 @@ static bool validateSymbolSet(DiagnosticEngine &diags,

std::sort(irNotTBD.begin(), irNotTBD.end());
for (auto &name : irNotTBD) {
diags.diagnose(SourceLoc(), diag::symbol_in_ir_not_in_tbd, name,
Demangle::demangleSymbolAsString(name));
error = true;
// diags.diagnose(SourceLoc(), diag::symbol_in_ir_not_in_tbd, name,
// Demangle::demangleSymbolAsString(name));
// error = true;
}

if (diagnoseExtraSymbolsInTBD) {
Expand Down
4 changes: 4 additions & 0 deletions lib/IRGen/GenProto.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1946,6 +1946,8 @@ void IRGenModule::emitProtocolConformance(
getAddrOfProtocolConformanceDescriptor(conformance,
init.finishAndCreateFuture()));
var->setConstant(true);
if (record.wtable->getLinkage() == SILLinkage::Private)
var->setLinkage(llvm::GlobalVariable::LinkageTypes::PrivateLinkage);
setTrueConstGlobal(var);
}

Expand Down Expand Up @@ -2152,6 +2154,8 @@ void IRGenModule::emitSILWitnessTable(SILWitnessTable *wt) {
global->setConstant(isConstantWitnessTable(wt));
global->setAlignment(getWitnessTableAlignment().getValue());
tableSize = wtableBuilder.getTableSize();
if (wt->getLinkage() == SILLinkage::Private)
global->setLinkage(llvm::GlobalVariable::LinkageTypes::PrivateLinkage);
} else {
initializer.abandon();
tableSize = 0;
Expand Down
Loading