Skip to content

Commit cacf552

Browse files
committed
GSB: Workaround interator invalidation issue with getMinimalConformanceSource()
In a few places we call getMinimalConformanceSource() while iterating over all equivalence classes, or the conformances of a specific equivalence class. In both cases, getMinimalConformanceSource() can modify the storage of the collection being iterated over, because it can end up calling maybeResolveEquivalenceClass(), which can introduce new constraints. Work around this by iterating a copy of the list of equivalence classes first, calling getMinimalConformanceSource() and discarding the result on each conformance source. This is a terrible workaround, but should address the issue in the meantime until I finish removing getMinimalConformanceSource(). Fixes rdar://problem/46420886 / https://bugs.swift.org/browse/SR-9398, rdar://problem/77807692.
1 parent ccf2e66 commit cacf552

File tree

2 files changed

+54
-0
lines changed

2 files changed

+54
-0
lines changed

lib/AST/GenericSignatureBuilder.cpp

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6534,6 +6534,39 @@ GenericSignatureBuilder::finalize(TypeArrayView<GenericTypeParamType> genericPar
65346534
// Process any delayed requirements that we can handle now.
65356535
processDelayedRequirements();
65366536

6537+
{
6538+
// In various places below, we iterate over the list of equivalence classes
6539+
// and call getMinimalConformanceSource(). Unfortunately, this function
6540+
// ends up calling maybeResolveEquivalenceClass(), which can delete equivalence
6541+
// classes. The workaround is to first iterate safely over a copy of the list,
6542+
// and pre-compute all minimal conformance sources, before proceeding with the
6543+
// rest of the function.
6544+
//
6545+
// FIXME: This is not even correct, because we may not have reached fixed point
6546+
// after one round of this. getMinimalConformanceSource() should be removed
6547+
// instead.
6548+
SmallVector<PotentialArchetype *, 8> equivalenceClassPAs;
6549+
for (auto &equivClass : Impl->EquivalenceClasses) {
6550+
equivalenceClassPAs.push_back(equivClass.members.front());
6551+
}
6552+
6553+
for (auto *pa : equivalenceClassPAs) {
6554+
auto &equivClass = *pa->getOrCreateEquivalenceClass(*this);
6555+
6556+
// Copy the vector and iterate over the copy to avoid iterator invalidation
6557+
// issues.
6558+
auto conformsTo = equivClass.conformsTo;
6559+
for (auto entry : conformsTo) {
6560+
for (const auto &constraint : entry.second) {
6561+
bool derivedViaConcrete = false;
6562+
(void) constraint.source->getMinimalConformanceSource(
6563+
*this, constraint.getSubjectDependentType({ }), entry.first,
6564+
derivedViaConcrete);
6565+
}
6566+
}
6567+
}
6568+
}
6569+
65376570
computeRedundantRequirements();
65386571
diagnoseRedundantRequirements();
65396572
diagnoseConflictingConcreteTypeRequirements();

test/Generics/rdar77807692.swift

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
// RUN: %target-typecheck-verify-swift
2+
// RUN: %target-swift-frontend -typecheck -debug-generic-signatures %s 2>&1 | %FileCheck %s
3+
4+
protocol P1 {
5+
associatedtype T : Hashable
6+
}
7+
8+
struct S1<Value> {}
9+
10+
extension S1 : P1 where Value : P1 {
11+
typealias T = Value.T
12+
}
13+
14+
protocol P2 {
15+
associatedtype Value: P1
16+
}
17+
18+
struct S2<X, Y: P2> where Y.Value == X {
19+
// CHECK-LABEL: Generic signature: <X, Y, T where X == S1<T>, Y : P2, T : P1, Y.Value == S1<T>>
20+
init<T>(_: T) where X == S1<T> { }
21+
}

0 commit comments

Comments
 (0)