Skip to content

Commit 752aa64

Browse files
committed
Sema: Add BindingSet::operator==
This will be used for debugging.
1 parent c5a742b commit 752aa64

File tree

2 files changed

+91
-37
lines changed

2 files changed

+91
-37
lines changed

include/swift/Sema/CSBindings.h

Lines changed: 4 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -583,44 +583,11 @@ class BindingSet {
583583

584584
static BindingScore formBindingScore(const BindingSet &b);
585585

586-
/// Compare two sets of bindings, where \c x < y indicates that
587-
/// \c x is a better set of bindings that \c y.
588-
friend bool operator<(const BindingSet &x, const BindingSet &y) {
589-
auto xScore = formBindingScore(x);
590-
auto yScore = formBindingScore(y);
586+
bool operator==(const BindingSet &other);
591587

592-
if (xScore < yScore)
593-
return true;
594-
595-
if (yScore < xScore)
596-
return false;
597-
598-
auto xDefaults = x.getNumViableDefaultableBindings();
599-
auto yDefaults = y.getNumViableDefaultableBindings();
600-
601-
// If there is a difference in number of default types,
602-
// prioritize bindings with fewer of them.
603-
if (xDefaults != yDefaults)
604-
return xDefaults < yDefaults;
605-
606-
// If neither type variable is a "hole" let's check whether
607-
// there is a subtype relationship between them and prefer
608-
// type variable which represents superclass first in order
609-
// for "subtype" type variable to attempt more bindings later.
610-
// This is required because algorithm can't currently infer
611-
// bindings for subtype transitively through superclass ones.
612-
if (!(std::get<0>(xScore) && std::get<0>(yScore))) {
613-
if (x.Info.isSubtypeOf(y.getTypeVariable()))
614-
return false;
615-
616-
if (y.Info.isSubtypeOf(x.getTypeVariable()))
617-
return true;
618-
}
619-
620-
// As a last resort, let's check if the bindings are
621-
// potentially incomplete, and if so, let's de-prioritize them.
622-
return x.isPotentiallyIncomplete() < y.isPotentiallyIncomplete();
623-
}
588+
/// Compare two sets of bindings, where \c this < other indicates that
589+
/// \c this is a better set of bindings that \c other.
590+
bool operator<(const BindingSet &other);
624591

625592
void dump(llvm::raw_ostream &out, unsigned indent) const;
626593

lib/Sema/CSBindings.cpp

Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -953,6 +953,56 @@ void BindingSet::addLiteralRequirement(Constraint *constraint) {
953953
Literals.insert({protocol, std::move(literal)});
954954
}
955955

956+
bool BindingSet::operator==(const BindingSet &other) {
957+
if (AdjacentVars != other.AdjacentVars)
958+
return false;
959+
960+
if (Bindings.size() != other.Bindings.size())
961+
return false;
962+
963+
for (auto i : indices(Bindings)) {
964+
const auto &x = Bindings[i];
965+
const auto &y = other.Bindings[i];
966+
967+
if (x.BindingType.getPointer() != y.BindingType.getPointer() ||
968+
x.Kind != y.Kind)
969+
return false;
970+
}
971+
972+
if (Literals.size() != other.Literals.size())
973+
return false;
974+
975+
for (auto pair : Literals) {
976+
auto found = other.Literals.find(pair.first);
977+
if (found == other.Literals.end())
978+
return false;
979+
980+
const auto &x = pair.second;
981+
const auto &y = found->second;
982+
983+
if (x.Source != y.Source ||
984+
x.DefaultType.getPointer() != y.DefaultType.getPointer() ||
985+
x.IsDirectRequirement != y.IsDirectRequirement) {
986+
return false;
987+
}
988+
}
989+
990+
if (Defaults.size() != other.Defaults.size())
991+
return false;
992+
993+
for (auto pair : Defaults) {
994+
auto found = other.Defaults.find(pair.first);
995+
if (found == other.Defaults.end() ||
996+
pair.second != found->second)
997+
return false;
998+
}
999+
1000+
if (TransitiveProtocols != other.TransitiveProtocols)
1001+
return false;
1002+
1003+
return true;
1004+
}
1005+
9561006
BindingSet::BindingScore BindingSet::formBindingScore(const BindingSet &b) {
9571007
// If there are no bindings available but this type
9581008
// variable represents a closure - let's consider it
@@ -973,6 +1023,43 @@ BindingSet::BindingScore BindingSet::formBindingScore(const BindingSet &b) {
9731023
-numNonDefaultableBindings);
9741024
}
9751025

1026+
bool BindingSet::operator<(const BindingSet &other) {
1027+
auto xScore = formBindingScore(*this);
1028+
auto yScore = formBindingScore(other);
1029+
1030+
if (xScore < yScore)
1031+
return true;
1032+
1033+
if (yScore < xScore)
1034+
return false;
1035+
1036+
auto xDefaults = getNumViableDefaultableBindings();
1037+
auto yDefaults = other.getNumViableDefaultableBindings();
1038+
1039+
// If there is a difference in number of default types,
1040+
// prioritize bindings with fewer of them.
1041+
if (xDefaults != yDefaults)
1042+
return xDefaults < yDefaults;
1043+
1044+
// If neither type variable is a "hole" let's check whether
1045+
// there is a subtype relationship between them and prefer
1046+
// type variable which represents superclass first in order
1047+
// for "subtype" type variable to attempt more bindings later.
1048+
// This is required because algorithm can't currently infer
1049+
// bindings for subtype transitively through superclass ones.
1050+
if (!(std::get<0>(xScore) && std::get<0>(yScore))) {
1051+
if (Info.isSubtypeOf(other.getTypeVariable()))
1052+
return false;
1053+
1054+
if (other.Info.isSubtypeOf(getTypeVariable()))
1055+
return true;
1056+
}
1057+
1058+
// As a last resort, let's check if the bindings are
1059+
// potentially incomplete, and if so, let's de-prioritize them.
1060+
return isPotentiallyIncomplete() < other.isPotentiallyIncomplete();
1061+
}
1062+
9761063
std::optional<BindingSet> ConstraintSystem::determineBestBindings(
9771064
llvm::function_ref<void(const BindingSet &)> onCandidate) {
9781065
// Look for potential type variable bindings.

0 commit comments

Comments
 (0)