Skip to content

Commit 398b99a

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. (cherry picked from commit a72a2bf)
1 parent 2167a3f commit 398b99a

File tree

3 files changed

+63
-19
lines changed

3 files changed

+63
-19
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;
@@ -3300,10 +3330,15 @@ GenericSignatureBuilder::addSameTypeRequirementBetweenArchetypes(
33003330
if (T1 == T2)
33013331
return ConstraintResult::Resolved;
33023332

3333+
unsigned nestingDepth1 = T1->getNestingDepth();
3334+
unsigned nestingDepth2 = T2->getNestingDepth();
3335+
33033336
// Decide which potential archetype is to be considered the representative.
3304-
// It doesn't specifically matter which we use, but it's a minor optimization
3305-
// to prefer the canonical type.
3306-
if (compareDependentTypes(&T2, &T1) < 0) {
3337+
// We prefer potential archetypes with lower nesting depths (because it
3338+
// prevents us from unnecessarily building deeply nested potential archetypes)
3339+
// and prefer anchors because it's a minor optimization.
3340+
if (nestingDepth2 < nestingDepth1 ||
3341+
compareDependentTypes(&T2, &T1) < 0) {
33073342
std::swap(T1, T2);
33083343
std::swap(OrigT1, OrigT2);
33093344
}

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

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
// This source file is part of the Swift.org open source project
2+
// Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors
3+
// Licensed under Apache License v2.0 with Runtime Library Exception
4+
//
5+
// See https://swift.org/LICENSE.txt for license information
6+
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
7+
8+
// RUN: not %target-swift-frontend %s -emit-ir
9+
protocol P{typealias a}{protocol A:P{{}class a{{}}typealias a:RangeReplaceableCollection

0 commit comments

Comments
 (0)