Skip to content

Commit 4166d76

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 3e1e9fa commit 4166d76

File tree

2 files changed

+52
-0
lines changed

2 files changed

+52
-0
lines changed

lib/AST/GenericSignatureBuilder.cpp

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6379,6 +6379,37 @@ GenericSignatureBuilder::finalize(TypeArrayView<GenericTypeParamType> genericPar
63796379
// Process any delayed requirements that we can handle now.
63806380
processDelayedRequirements();
63816381

6382+
{
6383+
// In various places below, we iterate over the list of equivalence classes
6384+
// and call getMinimalConformanceSource(). Unfortunately, this function
6385+
// ends up calling maybeResolveEquivalenceClass(), which can delete equivalence
6386+
// classes. The workaround is to first iterate safely over a copy of the list,
6387+
// and pre-compute all minimal conformance sources, before proceeding with the
6388+
// rest of the function.
6389+
//
6390+
// FIXME: This is not even correct, because we may not have reached fixed point
6391+
// after one round of this. getMinimalConformanceSource() should be removed
6392+
// instead.
6393+
SmallVector<PotentialArchetype *, 8> equivalenceClassPAs;
6394+
for (auto &equivClass : Impl->EquivalenceClasses) {
6395+
equivalenceClassPAs.push_back(equivClass.members.front());
6396+
}
6397+
6398+
for (auto *pa : equivalenceClassPAs) {
6399+
auto &equivClass = *pa->getOrCreateEquivalenceClass(*this);
6400+
6401+
// Copy the vector and iterate over the copy to avoid iterator invalidation
6402+
// issues.
6403+
auto conformsTo = equivClass.conformsTo;
6404+
for (auto entry : conformsTo) {
6405+
for (const auto &constraint : entry.second) {
6406+
(void) constraint.source->getMinimalConformanceSource(
6407+
*this, constraint.getSubjectDependentType({ }), entry.first);
6408+
}
6409+
}
6410+
}
6411+
}
6412+
63826413
computeRedundantRequirements(requirementSignatureSelfProto);
63836414
diagnoseProtocolRefinement(requirementSignatureSelfProto);
63846415
diagnoseRedundantRequirements();

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)