@@ -57,6 +57,14 @@ - (id)copyWithZone:(NSZone *)zone;
57
57
58
58
@end
59
59
60
+ struct EquatableWitnessTable ;
61
+
62
+ // / Calls `Equatable.==` through an `Equatable` witness table
63
+ SWIFT_CC (swift) SWIFT_RUNTIME_STDLIB_INTERNAL
64
+ bool _swift_stdlib_Equatable_isEqual_indirect(
65
+ const void *lhsValue, const void *rhsValue, const Metadata *type,
66
+ const EquatableWitnessTable *wt);
67
+
60
68
// / The fixed-size ivars of `__SwiftValue`. The actual boxed value is
61
69
// / tail-allocated.
62
70
struct SwiftValueHeader {
@@ -80,10 +88,18 @@ - (id)copyWithZone:(NSZone *)zone;
80
88
// / Returns NULL if the type does not conform.
81
89
const Metadata *getHashableBaseType () const ;
82
90
91
+ // / Get the base type that conforms to `Equatable`.
92
+ // / Returns NULL if the type does not conform.
93
+ const Metadata *getEquatableBaseType () const ;
94
+
83
95
// / Get the `Hashable` protocol witness table for the contained type.
84
96
// / Returns NULL if the type does not conform.
85
97
const hashable_support::HashableWitnessTable *getHashableConformance () const ;
86
98
99
+ // / Get the `Equatable` protocol witness table for the contained type.
100
+ // / Returns NULL if the type does not conform.
101
+ const EquatableWitnessTable *getEquatableConformance () const ;
102
+
87
103
SwiftValueHeader ()
88
104
: hashableBaseType(nullptr ), hashableConformance(nullptr ) {}
89
105
};
@@ -105,6 +121,27 @@ - (id)copyWithZone:(NSZone *)zone;
105
121
return type;
106
122
}
107
123
124
+ extern " C" const ProtocolDescriptor PROTOCOL_DESCR_SYM (SQ);
125
+ static constexpr auto &EquatableProtocolDescriptor = PROTOCOL_DESCR_SYM(SQ);
126
+
127
+ const Metadata *SwiftValueHeader::getEquatableBaseType () const {
128
+ auto witnessTable =
129
+ swift_conformsToProtocolCommon (type, &EquatableProtocolDescriptor);
130
+ if (!witnessTable) {
131
+ return nullptr ;
132
+ }
133
+ #if SWIFT_STDLIB_USE_RELATIVE_PROTOCOL_WITNESS_TABLES
134
+ const auto *conformance = lookThroughOptionalConditionalWitnessTable (
135
+ reinterpret_cast <const RelativeWitnessTable*>(witnessTable))
136
+ ->getDescription ();
137
+ #else
138
+ const auto *conformance = witnessTable->getDescription ();
139
+ #endif
140
+ const Metadata *baseTypeThatConformsToEquatable =
141
+ findConformingSuperclass (type, conformance);
142
+ return baseTypeThatConformsToEquatable;
143
+ }
144
+
108
145
const hashable_support::HashableWitnessTable *
109
146
SwiftValueHeader::getHashableConformance () const {
110
147
if (auto wt = hashableConformance.load (std::memory_order_acquire)) {
@@ -124,6 +161,14 @@ - (id)copyWithZone:(NSZone *)zone;
124
161
return wt;
125
162
}
126
163
164
+ const EquatableWitnessTable *
165
+ SwiftValueHeader::getEquatableConformance () const {
166
+ const EquatableWitnessTable *wt =
167
+ reinterpret_cast <const EquatableWitnessTable *>(
168
+ swift_conformsToProtocolCommon (type, &EquatableProtocolDescriptor));
169
+ return wt;
170
+ }
171
+
127
172
static constexpr const size_t SwiftValueHeaderOffset
128
173
= sizeof (Class ); // isa pointer
129
174
static constexpr const size_t SwiftValueMinAlignMask
@@ -300,30 +345,53 @@ - (BOOL)isEqual:(id)other {
300
345
return NO ;
301
346
}
302
347
348
+ // `other` must also be a _SwiftValue box
303
349
if (![other isKindOfClass: getSwiftValueClass ()]) {
304
350
return NO ;
305
351
}
306
352
307
353
auto selfHeader = getSwiftValueHeader (self);
308
354
auto otherHeader = getSwiftValueHeader (other);
309
355
310
- auto hashableBaseType = selfHeader->getHashableBaseType ();
311
- if (!hashableBaseType ||
312
- otherHeader->getHashableBaseType () != hashableBaseType) {
313
- return NO ;
356
+ // TODO: getHashableBaseType seems to always succeed,
357
+ // even if the type is in fact not Hashable. Why?
358
+ // Maybe we should try getting the conformance first,
359
+ // since that seems to actually fail?
360
+ auto selfHashableBaseType = selfHeader->getHashableBaseType ();
361
+ if (selfHashableBaseType) {
362
+ auto otherHashableBaseType = otherHeader->getHashableBaseType ();
363
+ if (selfHashableBaseType == otherHashableBaseType) {
364
+ auto hashableConformance = selfHeader->getHashableConformance ();
365
+ if (hashableConformance) {
366
+ return _swift_stdlib_Hashable_isEqual_indirect (
367
+ getSwiftValuePayload (self,
368
+ getSwiftValuePayloadAlignMask (selfHeader->type )),
369
+ getSwiftValuePayload (other,
370
+ getSwiftValuePayloadAlignMask (otherHeader->type )),
371
+ selfHashableBaseType, hashableConformance);
372
+ }
373
+ }
314
374
}
315
375
316
- auto hashableConformance = selfHeader->getHashableConformance ();
317
- if (!hashableConformance) {
318
- return NO ;
376
+ // TODO: As above, getEquatableBaseType seems to always succeed
377
+ // even if the type is not in fact Equatable.
378
+ auto selfEquatableBaseType = selfHeader->getEquatableBaseType ();
379
+ if (selfEquatableBaseType) {
380
+ auto otherEquatableBaseType = otherHeader->getEquatableBaseType ();
381
+ if (selfEquatableBaseType == otherEquatableBaseType) {
382
+ auto equatableConformance = selfHeader->getEquatableConformance ();
383
+ if (equatableConformance) {
384
+ return _swift_stdlib_Equatable_isEqual_indirect (
385
+ getSwiftValuePayload (self,
386
+ getSwiftValuePayloadAlignMask (selfHeader->type )),
387
+ getSwiftValuePayload (other,
388
+ getSwiftValuePayloadAlignMask (otherHeader->type )),
389
+ selfEquatableBaseType, equatableConformance);
390
+ }
391
+ }
319
392
}
320
393
321
- return _swift_stdlib_Hashable_isEqual_indirect (
322
- getSwiftValuePayload (self,
323
- getSwiftValuePayloadAlignMask (selfHeader->type )),
324
- getSwiftValuePayload (other,
325
- getSwiftValuePayloadAlignMask (otherHeader->type )),
326
- hashableBaseType, hashableConformance);
394
+ return NO ;
327
395
}
328
396
329
397
- (NSUInteger )hash {
0 commit comments