Skip to content

Use conformance access paths in IRGen #8072

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 4 commits into from
Mar 14, 2017
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
31 changes: 26 additions & 5 deletions include/swift/AST/ProtocolConformance.h
Original file line number Diff line number Diff line change
Expand Up @@ -229,6 +229,18 @@ class alignas(1 << DeclAlignInBits) ProtocolConformance {
/// Retrieve the complete set of protocol conformances for directly inherited
/// protocols.
const InheritedConformanceMap &getInheritedConformances() const;

/// Given a dependent type expressed in terms of the self parameter,
/// map it into the context of this conformance.
Type getAssociatedType(Type assocType,
LazyResolver *resolver = nullptr) const;

/// Given that the requirement signature of the protocol directly states
/// that the given dependent type must conform to the given protocol,
/// return its associated conformance.
ProtocolConformanceRef
getAssociatedConformance(Type assocType, ProtocolDecl *protocol,
LazyResolver *resolver = nullptr) const;

/// Get the generic parameters open on the conforming type.
GenericEnvironment *getGenericEnvironment() const;
Expand Down Expand Up @@ -441,11 +453,6 @@ class NormalProtocolConformance : public ProtocolConformance,
const Substitution &substitution,
TypeDecl *typeDecl) const;

/// Given a dependent type expressed in terms of the self parameter,
/// map it into the context of this conformance.
Type getAssociatedType(Type assocType,
LazyResolver *resolver = nullptr) const;

/// Given that the requirement signature of the protocol directly states
/// that the given dependent type must conform to the given protocol,
/// return its associated conformance.
Expand Down Expand Up @@ -611,6 +618,13 @@ class SpecializedProtocolConformance : public ProtocolConformance,
return GenericConformance->getInheritedConformances();
}

/// Given that the requirement signature of the protocol directly states
/// that the given dependent type must conform to the given protocol,
/// return its associated conformance.
ProtocolConformanceRef
getAssociatedConformance(Type assocType, ProtocolDecl *protocol,
LazyResolver *resolver = nullptr) const;

/// Determine whether the witness for the given requirement
/// is either the default definition or was otherwise deduced.
bool usesDefaultDefinition(AssociatedTypeDecl *requirement) const {
Expand Down Expand Up @@ -709,6 +723,13 @@ class InheritedProtocolConformance : public ProtocolConformance,
return InheritedConformance->getWitness(requirement, resolver);
}

/// Given that the requirement signature of the protocol directly states
/// that the given dependent type must conform to the given protocol,
/// return its associated conformance.
ProtocolConformanceRef
getAssociatedConformance(Type assocType, ProtocolDecl *protocol,
LazyResolver *resolver = nullptr) const;

/// Retrieve the protocol conformances directly-inherited protocols.
const InheritedConformanceMap &getInheritedConformances() const {
return InheritedConformance->getInheritedConformances();
Expand Down
12 changes: 12 additions & 0 deletions include/swift/AST/ProtocolConformanceRef.h
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,18 @@ class ProtocolConformanceRef {
TypeSubstitutionFn subs,
LookupConformanceFn conformances) const;

/// Given a dependent type (expressed in terms of this conformance's
/// protocol), follow it from the conforming type.
Type getAssociatedType(Type origType, Type dependentType,
LazyResolver *resolver = nullptr) const;

/// Given a dependent type (expressed in terms of this conformance's
/// protocol) and conformance, follow it from the conforming type.
ProtocolConformanceRef
getAssociatedConformance(Type origType, Type dependentType,
ProtocolDecl *requirement,
LazyResolver *resolver = nullptr) const;

void dump() const;
void dump(llvm::raw_ostream &out, unsigned indent = 0) const;

Expand Down
1 change: 1 addition & 0 deletions lib/AST/ASTDumper.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2611,6 +2611,7 @@ void ProtocolConformanceRef::dump(llvm::raw_ostream &out,
out.indent(indent) << "(abstract_conformance protocol="
<< getAbstract()->getName();
PrintWithColorRAII(out, ParenthesisColor) << ')';
out << '\n';
}
}

Expand Down
80 changes: 74 additions & 6 deletions lib/AST/ProtocolConformance.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -397,13 +397,22 @@ void NormalProtocolConformance::setTypeWitness(
TypeWitnesses[assocType] = std::make_pair(substitution, typeDecl);
}

Type NormalProtocolConformance::getAssociatedType(Type assocType,
LazyResolver *resolver) const {
Type ProtocolConformance::getAssociatedType(Type assocType,
LazyResolver *resolver) const {
assert(assocType->isTypeParameter() &&
"associated type must be a type parameter");

ProtocolConformanceRef ref(const_cast<ProtocolConformance*>(this));
return ref.getAssociatedType(getType(), assocType, resolver);
}

Type ProtocolConformanceRef::getAssociatedType(Type conformingType,
Type assocType,
LazyResolver *resolver) const {
assert(!isConcrete() || getConcrete()->getType()->isEqual(conformingType));

auto type = assocType->getCanonicalType();
auto proto = getProtocol();
auto proto = getRequirement();

#if false
// Fast path for generic parameters.
Expand All @@ -421,13 +430,43 @@ Type NormalProtocolConformance::getAssociatedType(Type assocType,
#endif

// General case: consult the substitution map.
auto self = const_cast<NormalProtocolConformance *>(this);
auto substMap =
SubstitutionMap::getProtocolSubstitutions(proto, getType(),
ProtocolConformanceRef(self));
SubstitutionMap::getProtocolSubstitutions(proto, conformingType, *this);
return type.subst(substMap);
}

ProtocolConformanceRef
ProtocolConformanceRef::getAssociatedConformance(Type conformingType,
Type assocType,
ProtocolDecl *protocol,
LazyResolver *resolver) const {
// If this is a concrete conformance, look up the associated conformance.
if (isConcrete()) {
auto conformance = getConcrete();
assert(conformance->getType()->isEqual(conformingType));
return conformance->getAssociatedConformance(assocType, protocol, resolver);
}

// Otherwise, apply the substitution {self -> conformingType}
// to the abstract conformance requirement laid upon the dependent type
// by the protocol.
auto subMap =
SubstitutionMap::getProtocolSubstitutions(getRequirement(),
conformingType, *this);
auto abstractConf = ProtocolConformanceRef(protocol);
return abstractConf.subst(assocType,
QuerySubstitutionMap{subMap},
LookUpConformanceInSubstitutionMap(subMap));
}

ProtocolConformanceRef
ProtocolConformance::getAssociatedConformance(Type assocType,
ProtocolDecl *protocol,
LazyResolver *resolver) const {
CONFORMANCE_SUBCLASS_DISPATCH(getAssociatedConformance,
(assocType, protocol, resolver))
}

ProtocolConformanceRef
NormalProtocolConformance::getAssociatedConformance(Type assocType,
ProtocolDecl *protocol,
Expand Down Expand Up @@ -582,6 +621,35 @@ SpecializedProtocolConformance::getWitness(ValueDecl *requirement,
return GenericConformance->getWitness(requirement, resolver);
}

ProtocolConformanceRef
SpecializedProtocolConformance::getAssociatedConformance(Type assocType,
ProtocolDecl *protocol,
LazyResolver *resolver) const {
ProtocolConformanceRef conformance =
GenericConformance->getAssociatedConformance(assocType, protocol, resolver);

auto genericEnv = GenericConformance->getGenericEnvironment();
auto subMap = genericEnv->getSubstitutionMap(GenericSubstitutions);

Type origType =
(conformance.isConcrete()
? conformance.getConcrete()->getType()
: GenericConformance->getAssociatedType(assocType, resolver));

return conformance.subst(origType,
QuerySubstitutionMap{subMap},
LookUpConformanceInSubstitutionMap(subMap));
}

ProtocolConformanceRef
InheritedProtocolConformance::getAssociatedConformance(Type assocType,
ProtocolDecl *protocol,
LazyResolver *resolver) const {
// FIXME: Substitute!
return InheritedConformance->getAssociatedConformance(assocType, protocol,
resolver);
}

const NormalProtocolConformance *
ProtocolConformance::getRootNormalConformance() const {
const ProtocolConformance *C = this;
Expand Down
15 changes: 7 additions & 8 deletions lib/IRGen/Fulfillment.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
#include "swift/AST/SubstitutionMap.h"
#include "swift/SIL/TypeLowering.h"
#include "GenericRequirement.h"
#include "ProtocolInfo.h"

using namespace swift;
using namespace irgen;
Expand Down Expand Up @@ -179,22 +180,20 @@ bool FulfillmentMap::searchWitnessTable(IRGenModule &IGM,

bool hadFulfillment = false;

auto nextInheritedIndex = 0;
for (auto inherited : protocol->getInheritedProtocols()) {
auto index = nextInheritedIndex++;
auto &pi = IGM.getProtocolInfo(protocol);

// Ignore protocols that don't have witness tables.
if (!Lowering::TypeConverter::protocolRequiresWitnessTable(inherited))
continue;
for (auto &entry : pi.getWitnessEntries()) {
if (!entry.isBase()) continue;

ProtocolDecl *inherited = entry.getBase();
MetadataPath inheritedPath = path;
inheritedPath.addInheritedProtocolComponent(index);
inheritedPath.addInheritedProtocolComponent(pi.getBaseWitnessIndex(&entry));
hadFulfillment |= searchWitnessTable(IGM, type, inherited,
source, std::move(inheritedPath),
keys, interestingConformances);
}

// If we're not limited the set of interesting conformances, or if
// If we're not limiting the set of interesting conformances, or if
// this is an interesting conformance, record it.
if (!interestingConformances || interestingConformances->count(protocol)) {
hadFulfillment |= addFulfillment({type, protocol}, source, std::move(path));
Expand Down
Loading