Skip to content

Commit c999a87

Browse files
committed
Sema: Fold identical solutions at the end
1 parent 83cb420 commit c999a87

File tree

2 files changed

+49
-12
lines changed

2 files changed

+49
-12
lines changed

lib/Sema/AssociatedTypeInference.cpp

Lines changed: 18 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -752,6 +752,16 @@ struct InferredTypeWitnessesSolution {
752752
LLVM_ATTRIBUTE_USED
753753
#endif
754754
void dump(llvm::raw_ostream &out) const;
755+
756+
bool operator==(const InferredTypeWitnessesSolution &other) const {
757+
for (const auto &otherTypeWitness : other.TypeWitnesses) {
758+
auto typeWitness = TypeWitnesses.find(otherTypeWitness.first);
759+
if (!typeWitness->second.first->isEqual(otherTypeWitness.second.first))
760+
return false;
761+
}
762+
763+
return true;
764+
}
755765
};
756766

757767
void InferredTypeWitnessesSolution::dump(llvm::raw_ostream &out) const {
@@ -3059,17 +3069,7 @@ void AssociatedTypeInference::findSolutionsRec(
30593069

30603070
// We fold away non-viable solutions that have the same type witnesses.
30613071
if (invalid) {
3062-
auto matchesSolution = [&](const InferredTypeWitnessesSolution &other) {
3063-
for (const auto &otherTypeWitness : other.TypeWitnesses) {
3064-
auto typeWitness = solution.TypeWitnesses.find(otherTypeWitness.first);
3065-
if (!typeWitness->second.first->isEqual(otherTypeWitness.second.first))
3066-
return false;
3067-
}
3068-
3069-
return true;
3070-
};
3071-
3072-
if (llvm::any_of(nonViableSolutions, matchesSolution)) {
3072+
if (llvm::find(nonViableSolutions, solution) != nonViableSolutions.end()) {
30733073
LLVM_DEBUG(llvm::dbgs() << std::string(valueWitnesses.size(), '+')
30743074
<< "+ Duplicate invalid solution found\n";);
30753075
++NumDuplicateSolutionStates;
@@ -3871,7 +3871,13 @@ auto AssociatedTypeInference::solve()
38713871
}
38723872
}
38733873

3874-
// Happy case: we found exactly one viable solution.
3874+
// If we still have multiple solutions, they might have identical
3875+
// type witnesses.
3876+
while (solutions.size() > 1 && solutions.front() == solutions.back()) {
3877+
solutions.pop_back();
3878+
}
3879+
3880+
// Happy case: we found exactly one unique viable solution.
38753881
if (solutions.size() == 1) {
38763882
// Form the resulting solution.
38773883
auto &typeWitnesses = solutions.front().TypeWitnesses;
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
// RUN: %target-typecheck-verify-swift
2+
3+
public protocol Q1 {}
4+
public protocol Q2 {}
5+
6+
protocol P1 {
7+
associatedtype A
8+
func f<T: Q1>(_: T) -> A
9+
}
10+
11+
protocol P2 {
12+
associatedtype A
13+
func f<T: Q2>(_: T) -> A
14+
}
15+
16+
struct S1 {}
17+
struct S2 {}
18+
19+
// Associated type inference isn't smart enough to reason about the
20+
// requirement on `T`, so it considers both overloads of f() as viable
21+
// witnesses. However, they infer the same binding 'A := S2', so
22+
// it's fine.
23+
24+
extension S1: P1 {
25+
public func f<T: Q1>(_: T) -> S2 {}
26+
}
27+
28+
extension S1: P2 {
29+
public func f<T: Q2>(_: T) -> S2 {}
30+
}
31+

0 commit comments

Comments
 (0)