Skip to content

Commit 20e3464

Browse files
committed
TypeWitnessSystem: Add an 'IsAmbiguous' flag to EquivalenceClass
1 parent 4c68ecf commit 20e3464

File tree

2 files changed

+51
-21
lines changed

2 files changed

+51
-21
lines changed

lib/Sema/TypeCheckProtocol.h

Lines changed: 26 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -937,17 +937,37 @@ class TypeWitnessSystem final {
937937
/// Equivalence classes are used on demand to express equivalences between
938938
/// witness candidates and reflect changes to resolved types across their
939939
/// members.
940-
struct EquivalenceClass final {
941-
/// The resolved type for witness candidates belonging to this equivalence
942-
/// class. The resolved type may be a type parameter, but cannot directly
943-
/// pertain to a name variable in the system; instead, witness candidates
944-
/// that should resolve to the same type share an equivalence class.
945-
Type ResolvedTy;
940+
class EquivalenceClass final {
941+
/// The pointer:
942+
/// - The resolved type for witness candidates belonging to this equivalence
943+
/// class. The resolved type may be a type parameter, but cannot directly
944+
/// pertain to a name variable in the owning system; instead, witness
945+
/// candidates that should resolve to the same type share an equivalence
946+
/// class.
947+
/// The int:
948+
/// - A flag indicating whether the resolved type is ambiguous. When set,
949+
/// the resolved type is null.
950+
llvm::PointerIntPair<Type, 1, bool> ResolvedTyAndIsAmbiguous;
951+
952+
public:
953+
EquivalenceClass(Type ty) : ResolvedTyAndIsAmbiguous(ty, false) {}
946954

947955
EquivalenceClass(const EquivalenceClass &) = delete;
948956
EquivalenceClass(EquivalenceClass &&) = delete;
949957
EquivalenceClass &operator=(const EquivalenceClass &) = delete;
950958
EquivalenceClass &operator=(EquivalenceClass &&) = delete;
959+
960+
Type getResolvedType() const {
961+
return ResolvedTyAndIsAmbiguous.getPointer();
962+
}
963+
void setResolvedType(Type ty);
964+
965+
bool isAmbiguous() const {
966+
return ResolvedTyAndIsAmbiguous.getInt();
967+
}
968+
void setAmbiguous() {
969+
ResolvedTyAndIsAmbiguous = {nullptr, true};
970+
}
951971
};
952972

953973
/// A type witness candidate for a name variable.

lib/Sema/TypeCheckProtocolInference.cpp

Lines changed: 25 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -2156,6 +2156,13 @@ auto AssociatedTypeInference::solve(ConformanceChecker &checker)
21562156
return None;
21572157
}
21582158

2159+
void TypeWitnessSystem::EquivalenceClass::setResolvedType(Type ty) {
2160+
assert(ty && "cannot resolve to a null type");
2161+
assert(!isAmbiguous() && "must not set resolved type when ambiguous");
2162+
2163+
ResolvedTyAndIsAmbiguous.setPointer(ty);
2164+
}
2165+
21592166
TypeWitnessSystem::TypeWitnessSystem(
21602167
ArrayRef<AssociatedTypeDecl *> assocTypes) {
21612168
for (auto *assocType : assocTypes) {
@@ -2177,7 +2184,7 @@ Type TypeWitnessSystem::getResolvedTypeWitness(Identifier name) const {
21772184
assert(this->TypeWitnesses.count(name));
21782185

21792186
if (auto *equivClass = this->TypeWitnesses.lookup(name).EquivClass) {
2180-
return equivClass->ResolvedTy;
2187+
return equivClass->getResolvedType();
21812188
}
21822189

21832190
return Type();
@@ -2219,15 +2226,16 @@ void TypeWitnessSystem::addTypeWitness(Identifier name, Type type) {
22192226
//
22202227
// If we already have a resolved type, keep going only if the new one is
22212228
// better.
2222-
if (tyWitness.EquivClass && tyWitness.EquivClass->ResolvedTy) {
2223-
if (!isBetterResolvedType(type, tyWitness.EquivClass->ResolvedTy)) {
2229+
if (tyWitness.EquivClass && tyWitness.EquivClass->getResolvedType()) {
2230+
if (!isBetterResolvedType(type, tyWitness.EquivClass->getResolvedType())) {
22242231
return;
22252232
}
22262233
}
22272234

22282235
// If we can find an existing equivalence class for this type, use it.
22292236
for (auto *const equivClass : this->EquivalenceClasses) {
2230-
if (equivClass->ResolvedTy && equivClass->ResolvedTy->isEqual(type)) {
2237+
if (equivClass->getResolvedType() &&
2238+
equivClass->getResolvedType()->isEqual(type)) {
22312239
if (tyWitness.EquivClass) {
22322240
mergeEquivalenceClasses(equivClass, tyWitness.EquivClass);
22332241
} else {
@@ -2239,9 +2247,9 @@ void TypeWitnessSystem::addTypeWitness(Identifier name, Type type) {
22392247
}
22402248

22412249
if (tyWitness.EquivClass) {
2242-
tyWitness.EquivClass->ResolvedTy = type;
2250+
tyWitness.EquivClass->setResolvedType(type);
22432251
} else {
2244-
auto *equivClass = new EquivalenceClass{type};
2252+
auto *equivClass = new EquivalenceClass(type);
22452253
this->EquivalenceClasses.insert(equivClass);
22462254

22472255
tyWitness.EquivClass = equivClass;
@@ -2308,8 +2316,10 @@ void TypeWitnessSystem::dump(
23082316

23092317
const auto *eqClass = this->TypeWitnesses.lookup(name).EquivClass;
23102318
if (eqClass) {
2311-
if (eqClass->ResolvedTy) {
2312-
out << eqClass->ResolvedTy;
2319+
if (eqClass->getResolvedType()) {
2320+
out << eqClass->getResolvedType();
2321+
} else if (eqClass->isAmbiguous()) {
2322+
out << "(ambiguous)";
23132323
} else {
23142324
out << "(unresolved)";
23152325
}
@@ -2349,7 +2359,7 @@ void TypeWitnessSystem::addEquivalence(Identifier name1, Identifier name2) {
23492359
tyWitness1.EquivClass = tyWitness2.EquivClass;
23502360
} else {
23512361
// Neither has an associated equivalence class.
2352-
auto *equivClass = new EquivalenceClass{nullptr};
2362+
auto *equivClass = new EquivalenceClass(nullptr);
23532363
this->EquivalenceClasses.insert(equivClass);
23542364

23552365
tyWitness1.EquivClass = equivClass;
@@ -2365,13 +2375,13 @@ void TypeWitnessSystem::mergeEquivalenceClasses(
23652375
}
23662376

23672377
// Merge the second resolved type into the first.
2368-
if (equivClass1->ResolvedTy && equivClass2->ResolvedTy) {
2369-
if (isBetterResolvedType(equivClass2->ResolvedTy,
2370-
equivClass1->ResolvedTy)) {
2371-
equivClass1->ResolvedTy = equivClass2->ResolvedTy;
2378+
if (equivClass1->getResolvedType() && equivClass2->getResolvedType()) {
2379+
if (isBetterResolvedType(equivClass2->getResolvedType(),
2380+
equivClass1->getResolvedType())) {
2381+
equivClass1->setResolvedType(equivClass2->getResolvedType());
23722382
}
2373-
} else if (equivClass2->ResolvedTy) {
2374-
equivClass1->ResolvedTy = equivClass2->ResolvedTy;
2383+
} else if (equivClass2->getResolvedType()) {
2384+
equivClass1->setResolvedType(equivClass2->getResolvedType());
23752385
}
23762386

23772387
// Migrate members of the second equivalence class to the first.

0 commit comments

Comments
 (0)