Skip to content

Commit a419221

Browse files
committed
[GSB] Use term rewriting to compute anchors of equivalence classes.
Fully rewriting a given type will produce the canonical representation of that type, because all rewrite rules take a step toward a more-canonical type. Use this approach to compute the anchor of an equivalence class, replacing the existing ad hoc approach of enumerating known potential archetypes—which was overly dependent on having the “right” set of potential archetypes already computed.
1 parent 3804f8a commit a419221

File tree

2 files changed

+64
-63
lines changed

2 files changed

+64
-63
lines changed

include/swift/AST/GenericSignatureBuilder.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -819,6 +819,12 @@ class GenericSignatureBuilder {
819819
bool simplifyType(GenericParamKey base,
820820
SmallVectorImpl<AssociatedTypeDecl *> &path);
821821

822+
/// Simplify the given type down to its anchor.
823+
///
824+
/// \returns null if the type involved dependent member types that
825+
/// don't have associated types.
826+
Type simplifyType(Type type);
827+
822828
/// Verify the correctness of the given generic signature.
823829
///
824830
/// This routine will test that the given generic signature is both minimal

lib/AST/GenericSignatureBuilder.cpp

Lines changed: 58 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -2042,22 +2042,6 @@ TypeDecl *EquivalenceClass::lookupNestedType(
20422042
return populateResult((nestedTypeNameCache[name] = std::move(entry)));
20432043
}
20442044

2045-
/// Determine whether any part of this potential archetype's path to the
2046-
/// root contains the given equivalence class.
2047-
static bool pathContainsEquivalenceClass(GenericSignatureBuilder &builder,
2048-
PotentialArchetype *pa,
2049-
EquivalenceClass *equivClass) {
2050-
// Chase the potential archetype up to the root.
2051-
for (; pa; pa = pa->getParent()) {
2052-
// Check whether this potential archetype is in the given equivalence
2053-
// class.
2054-
if (pa->getOrCreateEquivalenceClass(builder) == equivClass)
2055-
return true;
2056-
}
2057-
2058-
return false;
2059-
}
2060-
20612045
Type EquivalenceClass::getAnchor(
20622046
GenericSignatureBuilder &builder,
20632047
TypeArrayView<GenericTypeParamType> genericParams) {
@@ -2097,54 +2081,26 @@ Type EquivalenceClass::getAnchor(
20972081

20982082
// If we saw a generic parameter, ignore any nested types.
20992083
if (bestGenericParam) continue;
2100-
2101-
// If the nested type doesn't have an associated type, skip it.
2102-
auto assocType = member->getResolvedAssociatedType();
2103-
if (!assocType) continue;
2104-
2105-
// Dig out the equivalence class of the parent.
2106-
auto parentEquivClass =
2107-
member->getParent()->getOrCreateEquivalenceClass(builder);
2108-
2109-
// If the path from this member to the root contains this equivalence
2110-
// class, it cannot be part of the anchor.
2111-
if (pathContainsEquivalenceClass(builder, member->getParent(), this))
2112-
continue;
2113-
2114-
// Take the best associated type for this equivalence class.
2115-
assocType = assocType->getAssociatedTypeAnchor();
2116-
auto &bestAssocType = nestedTypes[parentEquivClass];
2117-
if (!bestAssocType ||
2118-
compareAssociatedTypes(assocType, bestAssocType) < 0)
2119-
bestAssocType = assocType;
21202084
}
21212085

21222086
// If we found a generic parameter, return that.
21232087
if (bestGenericParam)
21242088
return bestGenericParam;
21252089

2126-
// Determine the best anchor among the parent equivalence classes.
2127-
Type bestParentAnchor;
2128-
AssociatedTypeDecl *bestAssocType = nullptr;
2129-
std::pair<EquivalenceClass *, Identifier> bestNestedType;
2130-
for (const auto &nestedType : nestedTypes) {
2131-
auto parentAnchor = nestedType.first->getAnchor(builder, genericParams);
2132-
if (!bestParentAnchor ||
2133-
compareDependentTypes(parentAnchor, bestParentAnchor) < 0) {
2134-
bestParentAnchor = parentAnchor;
2135-
bestAssocType = nestedType.second;
2136-
}
2137-
}
2138-
2139-
// Form the anchor type.
2140-
Type anchorType = DependentMemberType::get(bestParentAnchor, bestAssocType);
2090+
// Form the anchor.
2091+
for (auto member : members) {
2092+
auto anchorType =
2093+
builder.simplifyType(member->getDependentType(genericParams));
2094+
if (!anchorType) continue;
21412095

2142-
// Record the cache miss and update the cache.
2143-
++NumArchetypeAnchorCacheMisses;
2144-
archetypeAnchorCache.anchor = anchorType;
2145-
archetypeAnchorCache.numMembers = members.size();
2096+
// Record the cache miss and update the cache.
2097+
++NumArchetypeAnchorCacheMisses;
2098+
archetypeAnchorCache.anchor = anchorType;
2099+
archetypeAnchorCache.numMembers = members.size();
2100+
return anchorType;
2101+
}
21462102

2147-
return anchorType;
2103+
llvm_unreachable("Unable to compute anchor");
21482104
}
21492105

21502106
Type EquivalenceClass::getTypeInContext(GenericSignatureBuilder &builder,
@@ -3254,19 +3210,48 @@ unpackPath(PotentialArchetype *type,
32543210
return type->getGenericParamKey();
32553211
}
32563212

3257-
/// Form a dependent type with the (canonical) generic parameter for the given
3258-
/// parameter key, then following the path of associated types.
3259-
static Type formDependentType(ASTContext &ctx, GenericParamKey genericParam,
3213+
/// Unpack the given dependent type into a path from a generic parameter
3214+
/// through a sequence of associated type declarations.
3215+
///
3216+
/// \returns the generic parameter at the root of the type, or NULL if
3217+
/// this is not a well-formed dependent member type. along the path doesn't
3218+
/// have an associated type.
3219+
static GenericTypeParamType *
3220+
unpackPath(Type type, SmallVectorImpl<AssociatedTypeDecl *> &path) {
3221+
if (auto depMemTy = type->getAs<DependentMemberType>()) {
3222+
auto result = unpackPath(depMemTy->getBase(), path);
3223+
if (!result) return nullptr;
3224+
3225+
auto assocType = depMemTy->getAssocType();
3226+
if (!assocType) return nullptr;
3227+
3228+
path.push_back(assocType);
3229+
return result;
3230+
}
3231+
3232+
return type->getAs<GenericTypeParamType>();
3233+
}
3234+
3235+
/// Form a dependent type with the given generic parameter, then following the
3236+
/// path of associated types.
3237+
static Type formDependentType(GenericTypeParamType *base,
32603238
ArrayRef<AssociatedTypeDecl *> path) {
3261-
return std::accumulate(path.begin(), path.end(),
3262-
Type(GenericTypeParamType::get(genericParam.Depth,
3263-
genericParam.Index,
3264-
ctx)),
3239+
return std::accumulate(path.begin(), path.end(), Type(base),
32653240
[](Type type, AssociatedTypeDecl *assocType) -> Type {
32663241
return DependentMemberType::get(type, assocType);
32673242
});
32683243
}
32693244

3245+
/// Form a dependent type with the (canonical) generic parameter for the given
3246+
/// parameter key, then following the path of associated types.
3247+
static Type formDependentType(ASTContext &ctx, GenericParamKey genericParam,
3248+
ArrayRef<AssociatedTypeDecl *> path) {
3249+
return formDependentType(GenericTypeParamType::get(genericParam.Depth,
3250+
genericParam.Index,
3251+
ctx),
3252+
path);
3253+
}
3254+
32703255
RewriteTreeNode *
32713256
GenericSignatureBuilder::Implementation::getRewriteTreeRootIfPresent(
32723257
const EquivalenceClass *equivClass) {
@@ -3390,6 +3375,16 @@ bool GenericSignatureBuilder::simplifyType(
33903375
return simplified;
33913376
}
33923377

3378+
Type GenericSignatureBuilder::simplifyType(Type type) {
3379+
SmallVector<AssociatedTypeDecl *, 4> path;
3380+
auto base = unpackPath(type, path);
3381+
if (!base) return nullptr;
3382+
3383+
if (!simplifyType(base, path)) return type;
3384+
3385+
return formDependentType(base, path);
3386+
}
3387+
33933388
#pragma mark Equivalence classes
33943389
EquivalenceClass::EquivalenceClass(PotentialArchetype *representative)
33953390
: recursiveConcreteType(false), invalidConcreteType(false),

0 commit comments

Comments
 (0)