Skip to content
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

[AST] Start using conformance access paths in SubstitutionMap #8521

Merged
4 changes: 0 additions & 4 deletions include/swift/AST/DiagnosticsParse.def
Expand Up @@ -208,10 +208,6 @@ ERROR(decl_already_static,none,
ERROR(enum_case_dot_prefix,none,
"extraneous '.' in enum 'case' declaration", ())

ERROR(protocol_associatedtype_where_swift_3,none,
"where clauses on %0 are fragile; use '-swift-version 4' to experiment.", (StringRef))


// Variable getters/setters
ERROR(static_var_decl_global_scope,none,
"%select{%error|static properties|class properties}0 may only be declared on a type",
Expand Down
2 changes: 0 additions & 2 deletions include/swift/AST/GenericEnvironment.h
Expand Up @@ -142,8 +142,6 @@ class alignas(1 << DeclAlignInBits) GenericEnvironment final
};
friend class QueryArchetypeToInterfaceSubstitutions;

void populateParentMap(SubstitutionMap &subMap) const;

public:
GenericSignature *getGenericSignature() const {
return Signature;
Expand Down
5 changes: 3 additions & 2 deletions include/swift/AST/GenericSignature.h
Expand Up @@ -134,8 +134,6 @@ class alignas(1 << TypeAlignInBits) GenericSignature final
/// Retrieve the generic signature builder for the given generic signature.
GenericSignatureBuilder *getGenericSignatureBuilder(ModuleDecl &mod);

void populateParentMap(SubstitutionMap &subMap) const;

friend class ArchetypeType;

public:
Expand Down Expand Up @@ -287,6 +285,9 @@ class alignas(1 << TypeAlignInBits) GenericSignature final
/// must conform.
ConformsToArray getConformsTo(Type type, ModuleDecl &mod);

/// Determine whether the given dependent type conforms to this protocol.
bool conformsToProtocol(Type type, ProtocolDecl *proto, ModuleDecl &mod);

/// Determine whether the given dependent type is equal to a concrete type.
bool isConcreteType(Type type, ModuleDecl &mod);

Expand Down
42 changes: 15 additions & 27 deletions include/swift/AST/SubstitutionMap.h
Expand Up @@ -51,39 +51,29 @@ enum class CombineSubstitutionMaps {
};

class SubstitutionMap {
using ParentType = std::pair<CanType, AssociatedTypeDecl *>;
/// The generic signature (or full-fledged environment) for which we
/// are performing substitutions.
llvm::PointerUnion<GenericSignature *, GenericEnvironment *> genericSigOrEnv;

// FIXME: Switch to a more efficient representation.
llvm::DenseMap<SubstitutableType *, Type> subMap;
llvm::DenseMap<TypeBase *, SmallVector<ProtocolConformanceRef, 1>>
conformanceMap;
llvm::DenseMap<TypeBase *, SmallVector<ParentType, 1>> parentMap;

// Call the given function for each parent of the given type. The
// function \c fn should return an \c Optional<T>. \c forEachParent() will
// return the first non-empty \C Optional<T> returned by \c fn.
template<typename T>
Optional<T> forEachParent(
CanType type,
llvm::SmallPtrSetImpl<CanType> &visitedParents,
llvm::function_ref<Optional<T>(CanType,
AssociatedTypeDecl *)> fn) const;

// Call the given function for each conformance of the given type. The
// function \c fn should return an \c Optional<T>. \c forEachConformance()
// will return the first non-empty \C Optional<T> returned by \c fn.
template<typename T>
Optional<T> forEachConformance(
CanType type,
llvm::SmallPtrSetImpl<CanType> &visitedParents,
llvm::function_ref<Optional<T>(ProtocolConformanceRef)> fn)
const;

public:
SubstitutionMap()
: SubstitutionMap(static_cast<GenericSignature *>(nullptr)) { }

SubstitutionMap(llvm::PointerUnion<GenericSignature *, GenericEnvironment *>
genericSigOrEnv)
: genericSigOrEnv(genericSigOrEnv) { }

/// Retrieve the generic signature describing the environment in which
/// substitutions occur.
GenericSignature *getGenericSignature() const;

Optional<ProtocolConformanceRef>
lookupConformance(
CanType type, ProtocolDecl *proto,
llvm::SmallPtrSetImpl<CanType> *visitedParents = nullptr) const;
lookupConformance(CanType type, ProtocolDecl *proto) const;

bool empty() const {
return subMap.empty();
Expand Down Expand Up @@ -179,8 +169,6 @@ class SubstitutionMap {

void addSubstitution(CanSubstitutableType type, Type replacement);
void addConformance(CanType type, ProtocolConformanceRef conformance);
void addParent(CanType type, CanType parent,
AssociatedTypeDecl *assocType);
};

} // end namespace swift
Expand Down
55 changes: 2 additions & 53 deletions lib/AST/GenericEnvironment.cpp
Expand Up @@ -342,58 +342,9 @@ GenericEnvironment::getForwardingSubstitutions() const {
return getGenericSignature()->getASTContext().AllocateCopy(result);
}

void GenericEnvironment::populateParentMap(SubstitutionMap &subMap) const {
for (auto reqt : getGenericSignature()->getRequirements()) {
if (reqt.getKind() != RequirementKind::SameType)
continue;

auto first = reqt.getFirstType();
auto second = reqt.getSecondType();

auto archetype = first.subst(
QueryInterfaceTypeSubstitutions(this),
MakeAbstractConformanceForGenericType())
->getAs<ArchetypeType>();
if (!archetype)
continue;

#ifndef NDEBUG
auto secondArchetype = second.subst(
QueryInterfaceTypeSubstitutions(this),
MakeAbstractConformanceForGenericType())
->getAs<ArchetypeType>();
assert(secondArchetype == archetype);
#endif

if (auto *firstMemTy = first->getAs<DependentMemberType>()) {
auto parent = firstMemTy->getBase().subst(
QueryInterfaceTypeSubstitutions(this),
MakeAbstractConformanceForGenericType())
->getAs<ArchetypeType>();
if (parent && archetype->getParent() != parent) {
subMap.addParent(CanType(archetype),
CanType(parent),
firstMemTy->getAssocType());
}
}

if (auto *secondMemTy = second->getAs<DependentMemberType>()) {
auto parent = secondMemTy->getBase().subst(
QueryInterfaceTypeSubstitutions(this),
MakeAbstractConformanceForGenericType())
->getAs<ArchetypeType>();
if (parent && archetype->getParent() != parent) {
subMap.addParent(CanType(archetype),
CanType(parent),
secondMemTy->getAssocType());
}
}
}
}

SubstitutionMap GenericEnvironment::
getSubstitutionMap(SubstitutionList subs) const {
SubstitutionMap result;
SubstitutionMap result(const_cast<GenericEnvironment *>(this));

getGenericSignature()->enumeratePairedRequirements(
[&](Type depTy, ArrayRef<Requirement> reqts) -> bool {
Expand All @@ -419,7 +370,6 @@ getSubstitutionMap(SubstitutionList subs) const {

assert(subs.empty() && "did not use all substitutions?!");

populateParentMap(result);
result.verify();
return result;
}
Expand All @@ -428,7 +378,7 @@ SubstitutionMap
GenericEnvironment::
getSubstitutionMap(TypeSubstitutionFn subs,
GenericSignature::LookupConformanceFn lookupConformance) const {
SubstitutionMap subMap;
SubstitutionMap subMap(const_cast<GenericEnvironment *>(this));

getGenericSignature()->enumeratePairedRequirements(
[&](Type depTy, ArrayRef<Requirement> reqs) -> bool {
Expand Down Expand Up @@ -459,7 +409,6 @@ getSubstitutionMap(TypeSubstitutionFn subs,
return false;
});

populateParentMap(subMap);
subMap.verify();
return subMap;
}
53 changes: 24 additions & 29 deletions lib/AST/GenericSignature.cpp
Expand Up @@ -377,34 +377,9 @@ bool GenericSignature::enumeratePairedRequirements(
return enumerateGenericParamsUpToDependentType(CanType());
}

void GenericSignature::populateParentMap(SubstitutionMap &subMap) const {
for (auto reqt : getRequirements()) {
if (reqt.getKind() != RequirementKind::SameType)
continue;

auto first = reqt.getFirstType();
auto second = reqt.getSecondType();

if (!first->isTypeParameter() || !second->isTypeParameter())
continue;

if (auto *firstMemTy = first->getAs<DependentMemberType>()) {
subMap.addParent(second->getCanonicalType(),
firstMemTy->getBase()->getCanonicalType(),
firstMemTy->getAssocType());
}

if (auto *secondMemTy = second->getAs<DependentMemberType>()) {
subMap.addParent(first->getCanonicalType(),
secondMemTy->getBase()->getCanonicalType(),
secondMemTy->getAssocType());
}
}
}

SubstitutionMap
GenericSignature::getSubstitutionMap(SubstitutionList subs) const {
SubstitutionMap result;
SubstitutionMap result(const_cast<GenericSignature *>(this));

enumeratePairedRequirements(
[&](Type depTy, ArrayRef<Requirement> reqts) -> bool {
Expand All @@ -423,7 +398,6 @@ GenericSignature::getSubstitutionMap(SubstitutionList subs) const {
});

assert(subs.empty() && "did not use all substitutions?!");
populateParentMap(result);
result.verify();
return result;
}
Expand All @@ -432,7 +406,7 @@ SubstitutionMap
GenericSignature::
getSubstitutionMap(TypeSubstitutionFn subs,
GenericSignature::LookupConformanceFn lookupConformance) const {
SubstitutionMap subMap;
SubstitutionMap subMap(const_cast<GenericSignature *>(this));

// Enumerate all of the requirements that require substitution.
enumeratePairedRequirements([&](Type depTy, ArrayRef<Requirement> reqs) {
Expand All @@ -458,7 +432,6 @@ getSubstitutionMap(TypeSubstitutionFn subs,
return false;
});

populateParentMap(subMap);
subMap.verify();
return subMap;
}
Expand Down Expand Up @@ -581,6 +554,28 @@ SmallVector<ProtocolDecl *, 2> GenericSignature::getConformsTo(Type type,
return result;
}

bool GenericSignature::conformsToProtocol(Type type, ProtocolDecl *proto,
ModuleDecl &mod) {
// FIXME: Deal with concrete conformances here?
if (!type->isTypeParameter()) return false;

auto &builder = *getGenericSignatureBuilder(mod);
auto pa = builder.resolveArchetype(type);
if (!pa) return false;

pa = pa->getRepresentative();

// FIXME: Deal with concrete conformances here?
if (pa->isConcreteType()) return false;

// Check whether the representative conforms to this protocol.
if (auto equivClass = pa->getEquivalenceClassIfPresent())
if (equivClass->conformsTo.count(proto) > 0)
return true;

return false;
}

/// Determine whether the given dependent type is equal to a concrete type.
bool GenericSignature::isConcreteType(Type type, ModuleDecl &mod) {
return bool(getConcreteType(type, mod));
Expand Down
6 changes: 3 additions & 3 deletions lib/AST/GenericSignatureBuilder.cpp
Expand Up @@ -3530,11 +3530,11 @@ static PotentialArchetype *sameTypeDFS(PotentialArchetype *pa,
// Skip non-derived constraints.
if (!constraint.source->isDerivedRequirement()) continue;

sameTypeDFS(constraint.value, component, paToComponent);
auto newAnchor = sameTypeDFS(constraint.value, component, paToComponent);

// If this type is better than the anchor, use it for the anchor.
if (compareDependentTypes(&constraint.value, &anchor) < 0)
anchor = constraint.value;
if (compareDependentTypes(&newAnchor, &anchor) < 0)
anchor = newAnchor;
}

return anchor;
Expand Down
21 changes: 18 additions & 3 deletions lib/AST/ProtocolConformance.cpp
Expand Up @@ -473,6 +473,8 @@ NormalProtocolConformance::getAssociatedConformance(Type assocType,
LazyResolver *resolver) const {
assert(assocType->isTypeParameter() &&
"associated type must be a type parameter");
assert(!getSignatureConformances().empty() &&
"signature conformances not yet computed");

unsigned conformanceIndex = 0;
for (auto &reqt :
Expand Down Expand Up @@ -645,9 +647,22 @@ ProtocolConformanceRef
InheritedProtocolConformance::getAssociatedConformance(Type assocType,
ProtocolDecl *protocol,
LazyResolver *resolver) const {
// FIXME: Substitute!
return InheritedConformance->getAssociatedConformance(assocType, protocol,
resolver);
auto underlying =
InheritedConformance->getAssociatedConformance(assocType, protocol,
resolver);


// If the conformance is for Self, return an inherited conformance.
if (underlying.isConcrete() &&
assocType->isEqual(getProtocol()->getSelfInterfaceType())) {
auto subclassType = getType();
ASTContext &ctx = subclassType->getASTContext();
return ProtocolConformanceRef(
ctx.getInheritedConformance(subclassType,
underlying.getConcrete()));
}

return underlying;
}

const NormalProtocolConformance *
Expand Down