Skip to content

Commit 9a48fed

Browse files
committed
Sema: Add BindingSet::operator==
This will be used for debugging.
1 parent bed95dd commit 9a48fed

File tree

2 files changed

+91
-37
lines changed

2 files changed

+91
-37
lines changed

Diff for: include/swift/Sema/CSBindings.h

+4-37
Original file line numberDiff line numberDiff line change
@@ -588,44 +588,11 @@ class BindingSet {
588588

589589
static BindingScore formBindingScore(const BindingSet &b);
590590

591-
/// Compare two sets of bindings, where \c x < y indicates that
592-
/// \c x is a better set of bindings that \c y.
593-
friend bool operator<(const BindingSet &x, const BindingSet &y) {
594-
auto xScore = formBindingScore(x);
595-
auto yScore = formBindingScore(y);
591+
bool operator==(const BindingSet &other);
596592

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

630597
void dump(llvm::raw_ostream &out, unsigned indent) const;
631598

Diff for: lib/Sema/CSBindings.cpp

+87
Original file line numberDiff line numberDiff line change
@@ -960,6 +960,56 @@ void BindingSet::addLiteralRequirement(Constraint *constraint) {
960960
Literals.insert({protocol, std::move(literal)});
961961
}
962962

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

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

0 commit comments

Comments
 (0)