y: 0), (x: 100, y: 42)] let origin = (x: 0, y: 0) // error: type '(x: Int, y: Int)' cannot conform to 'Equatable'; // only struct/enum/class types can conform to protocols if points.contains(origin) { // do some serious calculations here } // error: type '(x: Int, y: Int)' cannot conform to 'Comparable'; // only struct/enum/class types can conform to protocols let sortedPoints = points.sorted() // error: type '(x: Int, y: Int)' cannot conform to 'Hashable'; // only struct/enum/class types can conform to protocols let uniquePoints = Set(points) 3
Int, longitude: Int) } // error: type 'Restaurant' does not conform to protocol 'Equatable' extension Restaurant: Equatable {} // error: type 'Restaurant' does not conform to protocol 'Hashable' extension Restaurant: Hashable {} 4
{ lhs == rhs } // Ok, Int is Equatable thus the tuples are Equatable isEqual((1, 2, 3), (1, 2, 3)) // true struct EmptyStruct {} // error: type '(EmptyStruct, Int, Int)' does not conform to protocol 'Equatable' // note: value of type 'EmptyStruct' does not conform to protocol 'Equatable', // preventing conformance of '(EmptyStruct, Int, Int)' to 'Equatable' isEqual((EmptyStruct(), 1, 2), (EmptyStruct(), 1, 2)) // We don't take into account the labels for equality. isEqual((x: 0, y: 0), (0, 0)) // true 7
{ lhs < rhs } let origin = (x: 0, y: 0) let randomPoint = (x: Int.random(in: 1 ... 10), y: Int.random(in: 1 ... 10)) // In this case, the first element of origin is 0 and the first element // of randomPoint is somewhere between 1 and 10, so they are not equal. // origin's element is less than randomPoint's, thus true. isLessThan(origin, randomPoint) // true // We don't take into account the labels for comparison. isLessThan((x: 0, y: 0), (1, 0)) // true 8
2), (x: 0, y: 0)] let uniquePoints = Set(points) // Create a grid system to hold game entities. var grid = [(x: Int, y: Int): Entity]() for point in uniquePoints { grid[point]?.move(up: 10) } // We don't take into account the labels for hash value. (x: 0, y: 0).hashValue == (0, 0).hashValue // true grid[(x: 100, y: 200)] = Entity(name: "Pam") print(grid[(100, 200)]) // Entity(name: "Pam") 9
Metadata *Self, void *witnessTable) { auto tuple = cast<TupleTypeMetadata>(Self); auto table = reinterpret_cast<void**>(witnessTable); // Loop through all elements, and check if both tuples element is equal. for (size_t i = 0; i != tuple->NumElements; i += 1) { auto elt = tuple->getElement(i); // Get the element conformance from the private data in the witness table. auto conformance = reinterpret_cast<const WitnessTable *>(table[-1 - i]); auto value1 = reinterpret_cast<OpaqueValue *>( reinterpret_cast<char *>(tuple1) + elt.Offset); auto value2 = reinterpret_cast<OpaqueValue *>( reinterpret_cast<char *>(tuple2) + elt.Offset); // Grab the specific witness for this element type. auto equatableTable = reinterpret_cast<void * const *>(conformance); auto equalsWitness = equatableTable[WitnessTableFirstRequirementOffset]; auto equals = reinterpret_cast<StaticInfixWitness *>(equalsWitness); // Call the equal function auto result = equals(value1, value2, elt.Type, elt.Type, conformance); // If the values aren't equal, this tuple isn't equal. :) if (!result) return false; } // Otherwise this tuple has value equality with all elements. return true; } https://github.com/apple/swift/pull/28833/files#diff-c289d2fa8030a8b0648018ab48d060bb32554aa01b96399c406702089ef0033cR148-R184 22
" .local __swift_tupleEquatable_private\n" " .comm __swift_tupleEquatable_private, 128, 16\n" " .protected " TUPLE_EQUATABLE_CONF "\n" " .type " TUPLE_EQUATABLE_CONF ", @object\n" " .section .rodata\n" #elif defined(__MACH__) " .zerofill __DATA, __bss, __swift_tupleEquatable_private, 128, 4\n" " .section __TEXT, __const\n" #elif defined(_WIN32) " .lcomm __swift_tupleEquatable_private, 128, 16\n" " .section .rdata, \"dr\"\n" #pragma comment(linker, "/EXPORT:_swift_tupleEquatable_conf,DATA") #endif " .globl " TUPLE_EQUATABLE_CONF "\n" " .p2align 2\n" TUPLE_EQUATABLE_CONF ":\n" // This is an indirectable relative reference to the GOT entry for the // Equatable protocol descriptor. " .long " INDIRECT_RELREF_GOTPCREL(EQUATABLE_DESCRIPTOR_SYMBOL) "\n" // 769 is the MetadataKind::Tuple " .long 769\n" // This indicates that we have no witness table pattern. We use a generic // witness table for builtin conformances. " .long 0\n" // 196640 are the ConformanceFlags with the type reference bit set to // MetadataKind, the has resilient witness bit, and the generic witness table // bit. " .long 196640\n" // This 1 is the ResilientWitnessesHeader indicating we have 1 resilient // witness. " .long 1\n" // This is an indirectable relative reference to the GOT entry for the // Equatable == method descriptor. " .long " INDIRECT_RELREF_GOTPCREL(EQUATABLE_EE_METHOD_DESCRIPTOR) "\n" // This is a direct relative reference to the equals witness defined below. " .long (" TUPLE_EQUATABLE_EQUALS ") - .\n" // The witness table size in words. " .short 0\n" // The witness table private size in words & requires instantiation. " .short 1\n" // The witness table instantiator function. " .long 0\n" // This is a direct relative reference to the private data for the // conformance. " .long __swift_tupleEquatable_private - .\n" #if defined(__ELF__) " .size " TUPLE_EQUATABLE_CONF ", 40\n" #endif ); 23
Builtin conformances are different because they don't use a mangled name // for their conformance descriptors. For now, we use predefined symbol names // just in case in the future we have some conflict between actual // conformances and these builtin ones. if (isa<BuiltinProtocolConformance>(conformance)) { auto &ctx = conformance->getType()->getASTContext(); if (conformance->getType()->is<TupleType>()) { auto equatable = ctx.getProtocol(KnownProtocolKind::Equatable); auto comparable = ctx.getProtocol(KnownProtocolKind::Comparable); auto hashable = ctx.getProtocol(KnownProtocolKind::Hashable); if (conformance->getProtocol() == equatable) { return "_swift_tupleEquatable_conf"; } if (conformance->getProtocol() == comparable) { return "_swift_tupleComparable_conf"; } if (conformance->getProtocol() == hashable) { return "_swift_tupleHashable_conf"; } llvm_unreachable("mangling conformance descriptor for unknown tuple \ protocol"); } llvm_unreachable("mangling conformance descriptor for unknown builtin type"); } ... } 25