Skip to content

Commit a72a2bf

Browse files
committed
[GSB] Avoid recursively growing increasingly-nested potential archetypes.
In some circumstances, we could end up growing increasingly-nested potential archetypes due to a poor choice of representatives and anchors. Address this in two places: * Always prefer to use the potential archetype with a lower nesting depth (== number of nested types) to one with a greater nesting depth, so we don't accumulate more nested types onto the already-longer potential archetypes, and * Prefer archetype anchors with a lower nesting depth *except* that we always prefer archetype anchors comprised of a sequence of associated types (i.e., no concrete type declarations), which is important for canonicalization. Fixes SR-4757 / rdar://problem/31912838, as well as a regression involving infinitely-recursive potential archetypes caused by the previous commit.
1 parent b095c8a commit a72a2bf

File tree

3 files changed

+55
-20
lines changed

3 files changed

+55
-20
lines changed

lib/AST/GenericSignatureBuilder.cpp

Lines changed: 52 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1546,26 +1546,35 @@ static int compareAssociatedTypes(AssociatedTypeDecl *assocType1,
15461546
return 0;
15471547
}
15481548

1549+
/// Whether there are any concrete type declarations in the potential archetype.
1550+
static bool hasConcreteDecls(const PotentialArchetype *pa) {
1551+
auto parent = pa->getParent();
1552+
if (!parent) return false;
1553+
1554+
if (pa->getConcreteTypeDecl())
1555+
return true;
1556+
1557+
return hasConcreteDecls(parent);
1558+
}
1559+
15491560
/// Canonical ordering for dependent types in generic signatures.
15501561
static int compareDependentTypes(PotentialArchetype * const* pa,
1551-
PotentialArchetype * const* pb) {
1562+
PotentialArchetype * const* pb,
1563+
bool outermost) {
15521564
auto a = *pa, b = *pb;
15531565

15541566
// Fast-path check for equality.
15551567
if (a == b)
15561568
return 0;
15571569

1558-
// Concrete types must be ordered *after* everything else, to ensure they
1559-
// don't become representatives in the case where a concrete type is equated
1560-
// with an associated type.
1561-
if (a->getParent() && b->getParent() &&
1562-
!!a->getConcreteTypeDecl() != !!b->getConcreteTypeDecl())
1563-
return a->getConcreteTypeDecl() ? +1 : -1;
1564-
1565-
// Types that are equivalent to concrete types follow types that are still
1566-
// type parameters.
1567-
if (a->isConcreteType() != b->isConcreteType())
1568-
return a->isConcreteType() ? +1 : -1;
1570+
// If one has concrete declarations somewhere but the other does not,
1571+
// prefer the one without concrete declarations.
1572+
if (outermost) {
1573+
bool aHasConcreteDecls = hasConcreteDecls(a);
1574+
bool bHasConcreteDecls = hasConcreteDecls(b);
1575+
if (aHasConcreteDecls != bHasConcreteDecls)
1576+
return aHasConcreteDecls ? +1 : -1;
1577+
}
15691578

15701579
// Ordering is as follows:
15711580
// - Generic params
@@ -1581,9 +1590,21 @@ static int compareDependentTypes(PotentialArchetype * const* pa,
15811590
auto ppb = b->getParent();
15821591

15831592
// - by base, so t_0_n.`P.T` < t_1_m.`P.T`
1584-
if (int compareBases = compareDependentTypes(&ppa, &ppb))
1593+
if (int compareBases = compareDependentTypes(&ppa, &ppb, /*outermost=*/false))
15851594
return compareBases;
15861595

1596+
// Types that are equivalent to concrete types follow types that are still
1597+
// type parameters.
1598+
if (a->isConcreteType() != b->isConcreteType())
1599+
return a->isConcreteType() ? +1 : -1;
1600+
1601+
// Concrete types must be ordered *after* everything else, to ensure they
1602+
// don't become representatives in the case where a concrete type is equated
1603+
// with an associated type.
1604+
if (a->getParent() && b->getParent() &&
1605+
!!a->getConcreteTypeDecl() != !!b->getConcreteTypeDecl())
1606+
return a->getConcreteTypeDecl() ? +1 : -1;
1607+
15871608
// - by name, so t_n_m.`P.T` < t_n_m.`P.U`
15881609
if (int compareNames = a->getNestedName().str().compare(
15891610
b->getNestedName().str()))
@@ -1627,6 +1648,11 @@ static int compareDependentTypes(PotentialArchetype * const* pa,
16271648
llvm_unreachable("potential archetype total order failure");
16281649
}
16291650

1651+
static int compareDependentTypes(PotentialArchetype * const* pa,
1652+
PotentialArchetype * const* pb) {
1653+
return compareDependentTypes(pa, pb, /*outermost=*/true);
1654+
}
1655+
16301656
PotentialArchetype *PotentialArchetype::getArchetypeAnchor(
16311657
GenericSignatureBuilder &builder) {
16321658
// Find the best archetype within this equivalence class.
@@ -1635,6 +1661,7 @@ PotentialArchetype *PotentialArchetype::getArchetypeAnchor(
16351661
if (auto parent = getParent()) {
16361662
// For a nested type, retrieve the parent archetype anchor first.
16371663
auto parentAnchor = parent->getArchetypeAnchor(builder);
1664+
assert(parentAnchor->getNestingDepth() <= parent->getNestingDepth());
16381665
anchor = parentAnchor->getNestedArchetypeAnchor(
16391666
getNestedName(), builder,
16401667
ArchetypeResolutionKind::AlreadyKnown);
@@ -1654,7 +1681,8 @@ PotentialArchetype *PotentialArchetype::getArchetypeAnchor(
16541681
equivClass->archetypeAnchorCache.numMembers
16551682
== equivClass->members.size()) {
16561683
++NumArchetypeAnchorCacheHits;
1657-
1684+
assert(equivClass->archetypeAnchorCache.anchor->getNestingDepth()
1685+
<= rep->getNestingDepth());
16581686
return equivClass->archetypeAnchorCache.anchor;
16591687
}
16601688

@@ -1673,6 +1701,8 @@ PotentialArchetype *PotentialArchetype::getArchetypeAnchor(
16731701
}
16741702
#endif
16751703

1704+
assert(anchor->getNestingDepth() <= rep->getNestingDepth());
1705+
16761706
// Record the cache miss and update the cache.
16771707
++NumArchetypeAnchorCacheMisses;
16781708
equivClass->archetypeAnchorCache.anchor = anchor;
@@ -3304,10 +3334,15 @@ GenericSignatureBuilder::addSameTypeRequirementBetweenArchetypes(
33043334
if (T1 == T2)
33053335
return ConstraintResult::Resolved;
33063336

3337+
unsigned nestingDepth1 = T1->getNestingDepth();
3338+
unsigned nestingDepth2 = T2->getNestingDepth();
3339+
33073340
// Decide which potential archetype is to be considered the representative.
3308-
// It doesn't specifically matter which we use, but it's a minor optimization
3309-
// to prefer the canonical type.
3310-
if (compareDependentTypes(&T2, &T1) < 0) {
3341+
// We prefer potential archetypes with lower nesting depths (because it
3342+
// prevents us from unnecessarily building deeply nested potential archetypes)
3343+
// and prefer anchors because it's a minor optimization.
3344+
if (nestingDepth2 < nestingDepth1 ||
3345+
compareDependentTypes(&T2, &T1) < 0) {
33113346
std::swap(T1, T2);
33123347
std::swap(OrigT1, OrigT2);
33133348
}

test/Generics/requirement_inference.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -224,8 +224,8 @@ struct X8 : P12 {
224224

225225
struct X9<T: P12, U: P12> where T.B == U.B {
226226
// CHECK-LABEL: X9.upperSameTypeConstraint
227-
// CHECK: Generic signature: <T, U, V where U : P12, T == X8, U.B == X8.B>
228-
// CHECK: Canonical generic signature: <τ_0_0, τ_0_1, τ_1_0 where τ_0_1 : P12, τ_0_0 == X8, τ_0_1.B == X7>
227+
// CHECK: Generic signature: <T, U, V where T == X8, U : P12, U.B == X8.B>
228+
// CHECK: Canonical generic signature: <τ_0_0, τ_0_1, τ_1_0 where τ_0_0 == X8, τ_0_1 : P12, τ_0_1.B == X7>
229229
func upperSameTypeConstraint<V>(_: V) where T == X8 { }
230230
}
231231

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,5 +5,5 @@
55
// See https://swift.org/LICENSE.txt for license information
66
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
77

8-
// RUN: not --crash %target-swift-frontend %s -emit-ir
8+
// RUN: not %target-swift-frontend %s -emit-ir
99
protocol P{typealias a}{protocol A:P{{}class a{{}}typealias a:RangeReplaceableCollection

0 commit comments

Comments
 (0)