diff --git a/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/meta/EqualsNode.java b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/meta/EqualsNode.java index 06aa91ab52ed..879043a6f15a 100644 --- a/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/meta/EqualsNode.java +++ b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/meta/EqualsNode.java @@ -214,22 +214,16 @@ boolean equalsStrings(Object selfString, Object otherString, } catch (UnsupportedMessageException e) { throw new IllegalStateException(e); } - return Normalizer.compare( - selfJavaString, - otherJavaString, - Normalizer.FOLD_CASE_DEFAULT - ) == 0; + return Normalizer.compare(selfJavaString, otherJavaString, Normalizer.FOLD_CASE_DEFAULT) == 0; } - @Specialization( - guards = "isPrimitive(self, strings) != isPrimitive(other, strings)" - ) - boolean equalsDifferent(Object self, Object other, @CachedLibrary(limit = "10") InteropLibrary strings) { + @Specialization(guards = "isPrimitive(self, interop) != isPrimitive(other, interop)") + boolean equalsDifferent( + Object self, Object other, @CachedLibrary(limit = "10") InteropLibrary interop) { return false; } /** Equals for Atoms and AtomConstructors */ - @Specialization boolean equalsAtomConstructors(AtomConstructor self, AtomConstructor other) { return self == other; @@ -237,20 +231,21 @@ boolean equalsAtomConstructors(AtomConstructor self, AtomConstructor other) { @Specialization boolean equalsAtoms(Atom self, Atom other, @Cached EqualsAtomNode equalsNode) { - return equalsNode.execute(self, other); + return self == other || equalsNode.execute(self, other); } - - @Specialization(guards = "isNotPrimitive(self, other, strings, warnings)") + + @Specialization(guards = "isNotPrimitive(self, other, interop, warnings)") boolean equalsComplex( - Object self, Object other, - @Cached EqualsComplexNode complex, - @CachedLibrary(limit = "10") InteropLibrary strings, - @CachedLibrary(limit = "10") WarningsLibrary warnings - ) { - return complex.execute(self, other); + Object self, + Object other, + @Cached EqualsComplexNode equalsComplex, + @CachedLibrary(limit = "10") InteropLibrary interop, + @CachedLibrary(limit = "10") WarningsLibrary warnings) { + return self == other || equalsComplex.execute(self, other); } - static boolean isNotPrimitive(Object a, Object b, InteropLibrary strings, WarningsLibrary warnings) { + static boolean isNotPrimitive( + Object a, Object b, InteropLibrary interop, WarningsLibrary warnings) { if (a instanceof AtomConstructor && b instanceof AtomConstructor) { return false; } @@ -260,22 +255,22 @@ static boolean isNotPrimitive(Object a, Object b, InteropLibrary strings, Warnin if (warnings.hasWarnings(a) || warnings.hasWarnings(b)) { return true; } - return !isPrimitive(a, strings) && !isPrimitive(b, strings); + return !isPrimitive(a, interop) && !isPrimitive(b, interop); } /** - * Return true iff object is a primitive value used in some specializations - * guard. By primitive value we mean any value that can be present in Enso, so, - * for example, not Integer, as that cannot be present in Enso. - * All the primitive types should be handled in their corresponding specializations. - * See {@link org.enso.interpreter.node.expression.builtin.interop.syntax.HostValueToEnsoNode}. + * Return true iff object is a primitive value used in some specializations guard. By primitive + * value we mean any value that can be present in Enso, so, for example, not Integer, as that + * cannot be present in Enso. All the primitive types should be handled in their corresponding + * specializations. See {@link + * org.enso.interpreter.node.expression.builtin.interop.syntax.HostValueToEnsoNode}. */ - static boolean isPrimitive(Object object, InteropLibrary strings) { - return object instanceof Boolean || - object instanceof Long || - object instanceof Double || - object instanceof EnsoBigInteger || - object instanceof Text || - strings.isString(object); + static boolean isPrimitive(Object object, InteropLibrary interop) { + return object instanceof Boolean + || object instanceof Long + || object instanceof Double + || object instanceof EnsoBigInteger + || object instanceof Text + || interop.isString(object); } } diff --git a/test/Tests/src/Semantic/Equals_Spec.enso b/test/Tests/src/Semantic/Equals_Spec.enso index 151ed10911ac..f7a80350c408 100644 --- a/test/Tests/src/Semantic/Equals_Spec.enso +++ b/test/Tests/src/Semantic/Equals_Spec.enso @@ -33,6 +33,16 @@ type Child_Comparator Comparable.from (_:Child) = Child_Comparator +## Type that violates reflexivity +type My_Nan + Value val + +type My_Nan_Comparator + compare _ _ = Nothing + hash _ = 0 + +Comparable.from (_:My_Nan) = My_Nan_Comparator + type Parent Value child @@ -159,6 +169,14 @@ spec = four_field = FourFieldType.Value 1 2 3 4 (rect == four_field).should_be_false + Test.specify "Any.== should check for Meta.is_same_object" <| + obj_1 = My_Nan.Value 42 + obj_2 = My_Nan.Value 42 + obj_1 == obj_2 . should_be_false + Meta.is_same_object obj_1 obj_2 . should_be_false + obj_1 == obj_1 . should_be_true + Meta.is_same_object obj_1 obj_1 . should_be_true + Test.specify "should handle `==` on types" <| (Child == Child).should_be_true (Child == Point).should_be_false