Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,37 @@ void hashSetValueType() {
}
}

@Test
void nonEquatableReferenceTypeFallsBackToIdentity() {
// MySwiftClass does not conform to Swift's `Equatable`, so the JNI
// bridge should fall back to identity equality.
try (var arena = SwiftArena.ofConfined()) {
var a = MySwiftClass.init(42, 1, arena);
var b = MySwiftClass.init(42, 1, arena);
assertEquals(a, a);
assertEquals(b, b);
// Different instances with equal field values must NOT be equal,
// since the type is not Equatable
assertNotEquals(a, b);
assertNotEquals(b, a);
assertNotEquals(a, "foo");
}
}

@Test
void nonEquatableReferenceTypeHashSetUsesIdentity() {
try (var arena = SwiftArena.ofConfined()) {
var a = MySwiftClass.init(42, 1, arena);
var b = MySwiftClass.init(42, 1, arena);
var set = new HashSet<>(List.of(a, b));
assertTrue(set.contains(a));
assertTrue(set.contains(b));
// Two distinct instances of a non-Equatable class are distinct
// entries in the set
assertEquals(2, set.size());
}
}

@Test
void hashSetReferenceType() {
try (var arena = SwiftArena.ofConfined()) {
Expand Down
7 changes: 5 additions & 2 deletions Sources/SwiftJava/SwiftObjects.swift
Original file line number Diff line number Diff line change
Expand Up @@ -101,20 +101,23 @@ extension SwiftObjects {

@JavaMethod
public static func equals(environment: UnsafeMutablePointer<JNIEnv?>!, lhsPointer: Int64, lhsTypePointer: Int64, rhsPointer: Int64, rhsTypePointer: Int64) -> Bool {
// Fallback for non-equatable types (such as classes)
let isPointerIdentityEqual = lhsTypePointer == rhsTypePointer && lhsPointer == rhsPointer

guard let lhsType$ = UnsafeRawPointer(bitPattern: Int(lhsTypePointer)) else {
fatalError("lhsType metadata address was null")
}
let lhsMetatype = unsafeBitCast(lhsType$, to: Any.Type.self)
guard let lhsMetatype = lhsMetatype as? (any Equatable.Type) else {
return false
return isPointerIdentityEqual
}

guard let rhsType$ = UnsafeRawPointer(bitPattern: Int(rhsTypePointer)) else {
fatalError("rhsType metadata address was null")
}
let rhsMetatype = unsafeBitCast(rhsType$, to: Any.Type.self)
guard let rhsMetatype = rhsMetatype as? (any Equatable.Type) else {
return false
return isPointerIdentityEqual
}

func perform<L: Equatable, R: Equatable>(lhsType: L.Type, rhsType: R.Type) -> Bool {
Expand Down
Loading