Skip to content

Commit 12648d6

Browse files
committed
[ConstraintSystem] Track all generic requirements fixed along current path
Such tracking makes it easier to ignore already "fixed" requirements which have been recorded in the constraint system multiple times e.g. a call to initializer would open both base type and initializer method which have shared (if not the same) requirements.
1 parent 661f636 commit 12648d6

File tree

3 files changed

+46
-4
lines changed

3 files changed

+46
-4
lines changed

lib/Sema/CSSimplify.cpp

Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2484,8 +2484,14 @@ bool ConstraintSystem::repairFailures(
24842484
if (lhs->hasDependentMember() || rhs->hasDependentMember())
24852485
break;
24862486

2487-
if (auto *fix = fixRequirementFailure(*this, lhs, rhs, anchor, path))
2487+
auto reqKind = static_cast<RequirementKind>(elt.getValue2());
2488+
if (hasFixedRequirement(lhs, reqKind, rhs))
2489+
return true;
2490+
2491+
if (auto *fix = fixRequirementFailure(*this, lhs, rhs, anchor, path)) {
2492+
recordFixedRequirement(lhs, reqKind, rhs);
24882493
conversionsOrFixes.push_back(fix);
2494+
}
24892495
break;
24902496
}
24912497

@@ -3756,6 +3762,11 @@ ConstraintSystem::SolutionKind ConstraintSystem::simplifyConformsToConstraint(
37563762
if (type->isVoid() || type->isUninhabited())
37573763
return SolutionKind::Error;
37583764

3765+
auto protocolTy = protocol->getDeclaredType();
3766+
// If this conformance has been fixed already, let's just consider this done.
3767+
if (hasFixedRequirement(type, RequirementKind::Conformance, protocolTy))
3768+
return SolutionKind::Solved;
3769+
37593770
// If this is a generic requirement let's try to record that
37603771
// conformance is missing and consider this a success, which
37613772
// makes it much easier to diagnose problems like that.
@@ -3768,10 +3779,14 @@ ConstraintSystem::SolutionKind ConstraintSystem::simplifyConformsToConstraint(
37683779

37693780
if (path.back().isTypeParameterRequirement() ||
37703781
path.back().isConditionalRequirement()) {
3771-
if (auto *fix = fixRequirementFailure(
3772-
*this, type, protocol->getDeclaredType(), anchor, path)) {
3773-
if (!recordFix(fix))
3782+
if (auto *fix =
3783+
fixRequirementFailure(*this, type, protocolTy, anchor, path)) {
3784+
if (!recordFix(fix)) {
3785+
// Record this conformance requirement as "fixed".
3786+
recordFixedRequirement(type, RequirementKind::Conformance,
3787+
protocolTy);
37743788
return SolutionKind::Solved;
3789+
}
37753790
}
37763791
}
37773792

lib/Sema/CSSolver.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -455,6 +455,7 @@ ConstraintSystem::SolverScope::SolverScope(ConstraintSystem &cs)
455455
numSavedBindings = cs.solverState->savedBindings.size();
456456
numConstraintRestrictions = cs.ConstraintRestrictions.size();
457457
numFixes = cs.Fixes.size();
458+
numFixedRequirements = cs.FixedRequirements.size();
458459
numDisjunctionChoices = cs.DisjunctionChoices.size();
459460
numOpenedTypes = cs.OpenedTypes.size();
460461
numOpenedExistentialTypes = cs.OpenedExistentialTypes.size();
@@ -507,6 +508,10 @@ ConstraintSystem::SolverScope::~SolverScope() {
507508
// Remove any opened types.
508509
truncate(cs.OpenedTypes, numOpenedTypes);
509510

511+
// Remove any conformances solver had to fix along
512+
// the current path.
513+
truncate(cs.FixedRequirements, numFixedRequirements);
514+
510515
// Remove any opened existential types.
511516
truncate(cs.OpenedExistentialTypes, numOpenedExistentialTypes);
512517

lib/Sema/ConstraintSystem.h

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -637,6 +637,8 @@ class Solution {
637637
/// The list of member references which couldn't be resolved,
638638
/// and had to be assumed based on their use.
639639
llvm::SmallVector<ConstraintLocator *, 4> MissingMembers;
640+
llvm::SmallVector<std::pair<GenericSignature *, unsigned>, 4>
641+
FixedRequirements;
640642

641643
/// The set of disjunction choices used to arrive at this solution,
642644
/// which informs constraint application.
@@ -1119,6 +1121,23 @@ class ConstraintSystem {
11191121
SmallVector<std::pair<ConstraintLocator *, ArrayRef<OpenedType>>, 4>
11201122
OpenedTypes;
11211123

1124+
/// The list of all generic requirements fixed along the current
1125+
/// solver path.
1126+
using FixedRequirement = std::tuple<TypeBase *, RequirementKind, TypeBase *>;
1127+
SmallVector<FixedRequirement, 4> FixedRequirements;
1128+
1129+
bool hasFixedRequirement(Type lhs, RequirementKind kind, Type rhs) {
1130+
auto reqInfo = std::make_tuple(lhs.getPointer(), kind, rhs.getPointer());
1131+
return llvm::any_of(
1132+
FixedRequirements,
1133+
[&reqInfo](const FixedRequirement &entry) { return entry == reqInfo; });
1134+
}
1135+
1136+
void recordFixedRequirement(Type lhs, RequirementKind kind, Type rhs) {
1137+
FixedRequirements.push_back(
1138+
std::make_tuple(lhs.getPointer(), kind, rhs.getPointer()));
1139+
}
1140+
11221141
/// A mapping from constraint locators to the opened existential archetype
11231142
/// used for the 'self' of an existential type.
11241143
SmallVector<std::pair<ConstraintLocator *, OpenedArchetypeType *>, 4>
@@ -1614,6 +1633,9 @@ class ConstraintSystem {
16141633
/// The length of \c Fixes.
16151634
unsigned numFixes;
16161635

1636+
/// The length of \c FixedRequirements.
1637+
unsigned numFixedRequirements;
1638+
16171639
/// The length of \c DisjunctionChoices.
16181640
unsigned numDisjunctionChoices;
16191641

0 commit comments

Comments
 (0)