Skip to content

Commit 137e468

Browse files
committed
Use a simpler strategy for finding the Equatable conformance to use
1 parent 8cc0fe7 commit 137e468

File tree

1 file changed

+24
-34
lines changed

1 file changed

+24
-34
lines changed

stdlib/public/runtime/SwiftObject.mm

Lines changed: 24 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -398,46 +398,36 @@ - (BOOL)isEqual:(id)other {
398398

399399
// Get Swift type for self and other
400400
auto selfMetadata = _swift_getClassOfAllocated(self);
401-
auto otherMetadata = _swift_getClassOfAllocated(other);
402401

403-
// Find common parent class
404-
const ClassMetadata * parentMetadata = NULL;
405-
if (selfMetadata == otherMetadata) {
406-
parentMetadata = selfMetadata;
407-
} else {
408-
// Collect parents of self
409-
std::unordered_set<const ClassMetadata *> selfAncestors;
410-
for (auto m = selfMetadata; m != NULL; m = m->Superclass) {
411-
selfAncestors.emplace(m);
412-
}
413-
// Find first parent of other that is also a parent of self
414-
for (auto m = otherMetadata; m != NULL; m = m->Superclass) {
415-
if (selfAncestors.find(m) != selfAncestors.end()) {
416-
parentMetadata = m;
417-
break;
418-
}
419-
}
420-
// If there's no common parent class, we can't compare them
421-
if (parentMetadata == NULL) {
422-
return NO;
423-
}
424-
}
425-
// Note: Because `self` subclasses SwiftObject, we know parentMetadata
426-
// must be a Swift type or SwiftObject itself.
427-
428-
// This will work for types that implement Hashable or only Equatable.
429-
// In the latter case, there is a risk that `-hash` and `-isEqual:` might
430-
// be incompatible. See notes above for `-hash`
402+
// We use Equatable conformance, which will also work for types that implement
403+
// Hashable. If the type implements Equatable but not Hashable, there is a
404+
// risk that `-hash` and `-isEqual:` might be incompatible. See notes above
405+
// for `-hash`
431406
auto equatableConformance =
432-
reinterpret_cast<const equatable_support::EquatableWitnessTable *>(
433-
swift_conformsToProtocolCommon(
434-
parentMetadata, &equatable_support::EquatableProtocolDescriptor));
407+
swift_conformsToProtocolCommon(
408+
selfMetadata, &equatable_support::EquatableProtocolDescriptor);
435409
if (equatableConformance == NULL) {
436410
return NO;
437411
}
438412

439-
return _swift_stdlib_Equatable_isEqual_indirect(
440-
&self, &other, parentMetadata, equatableConformance);
413+
// Is the other object a subclass of the parent that
414+
// actually defined this conformance?
415+
auto conformingParent =
416+
findConformingSuperclass(selfMetadata, equatableConformance->getDescription());
417+
auto otherMetadata = _swift_getClassOfAllocated(other);
418+
if (_swift_class_isSubclass(otherMetadata, conformingParent)) {
419+
// We now have an equatable conformance of a common parent
420+
// of both object types:
421+
return _swift_stdlib_Equatable_isEqual_indirect(
422+
&self,
423+
&other,
424+
conformingParent,
425+
reinterpret_cast<const equatable_support::EquatableWitnessTable *>(
426+
equatableConformance)
427+
);
428+
}
429+
430+
return NO;
441431
}
442432

443433
- (id)performSelector:(SEL)aSelector {

0 commit comments

Comments
 (0)