@@ -791,3 +791,162 @@ mod in_operator {
791791 ) ] ) ;
792792 }
793793}
794+
795+ /// `NaN` comparison, both via numeric literals (fast path) and
796+ /// via `Number` object properties (slow path through `abstract_relation`).
797+ ///
798+ #[ test]
799+ fn nan_comparisons ( ) {
800+ run_test_actions ( [
801+ TestAction :: assert ( "!(NaN == NaN)" ) ,
802+ TestAction :: assert ( "NaN != NaN" ) ,
803+ TestAction :: assert ( "!(NaN === NaN)" ) ,
804+ TestAction :: assert ( "NaN !== NaN" ) ,
805+ TestAction :: assert ( "!(NaN < 1)" ) ,
806+ TestAction :: assert ( "!(NaN > 1)" ) ,
807+ TestAction :: assert ( "!(NaN <= 1)" ) ,
808+ TestAction :: assert ( "!(NaN >= 1)" ) ,
809+ TestAction :: assert ( "!(1 < NaN)" ) ,
810+ TestAction :: assert ( "!(1 > NaN)" ) ,
811+ TestAction :: assert ( "!(1 <= NaN)" ) ,
812+ TestAction :: assert ( "!(1 >= NaN)" ) ,
813+ TestAction :: assert ( "!(NaN < NaN)" ) ,
814+ TestAction :: assert ( "!(NaN > NaN)" ) ,
815+ TestAction :: assert ( "!(NaN <= NaN)" ) ,
816+ TestAction :: assert ( "!(NaN >= NaN)" ) ,
817+ TestAction :: assert ( "!(NaN < Infinity)" ) ,
818+ TestAction :: assert ( "!(NaN > -Infinity)" ) ,
819+ TestAction :: assert ( "!(NaN < -Infinity)" ) ,
820+ TestAction :: assert ( "!(NaN > Infinity)" ) ,
821+ TestAction :: assert ( "!(new Number(NaN) < 1)" ) ,
822+ TestAction :: assert ( "!(new Number(NaN) > 1)" ) ,
823+ TestAction :: assert ( "!(new Number(NaN) <= 1)" ) ,
824+ TestAction :: assert ( "!(new Number(NaN) >= 1)" ) ,
825+ TestAction :: assert ( "!(1 < new Number(NaN))" ) ,
826+ TestAction :: assert ( "!(1 > new Number(NaN))" ) ,
827+ TestAction :: assert ( "!(1 <= new Number(NaN))" ) ,
828+ TestAction :: assert ( "!(1 >= new Number(NaN))" ) ,
829+ TestAction :: assert ( "Number.isNaN(NaN)" ) ,
830+ TestAction :: assert ( "Number.isNaN(0/0)" ) ,
831+ TestAction :: assert ( "!Number.isNaN(undefined)" ) ,
832+ TestAction :: assert ( "!Number.isNaN('NaN')" ) ,
833+ ] ) ;
834+ }
835+
836+ #[ test]
837+ fn bigint_mixed_type_operations ( ) {
838+ const MIXED_MSG : & str = "cannot mix BigInt and other types, use explicit conversions" ;
839+ run_test_actions ( [
840+ TestAction :: assert_native_error ( "1n + 1" , JsNativeErrorKind :: Type , MIXED_MSG ) ,
841+ TestAction :: assert_native_error ( "1n - 1" , JsNativeErrorKind :: Type , MIXED_MSG ) ,
842+ TestAction :: assert_native_error ( "1n * 2" , JsNativeErrorKind :: Type , MIXED_MSG ) ,
843+ TestAction :: assert_native_error ( "4n / 2" , JsNativeErrorKind :: Type , MIXED_MSG ) ,
844+ TestAction :: assert_native_error ( "5n % 2" , JsNativeErrorKind :: Type , MIXED_MSG ) ,
845+ TestAction :: assert_native_error ( "2n ** 3" , JsNativeErrorKind :: Type , MIXED_MSG ) ,
846+ TestAction :: assert_native_error ( "1 + 1n" , JsNativeErrorKind :: Type , MIXED_MSG ) ,
847+ TestAction :: assert_eq ( "'hello' + 1n" , js_str ! ( "hello1" ) ) ,
848+ TestAction :: assert_eq ( "1n + 'hello'" , js_str ! ( "1hello" ) ) ,
849+ TestAction :: assert_native_error (
850+ indoc ! { r#"
851+ let numObj = { valueOf() { return 42; }, toString() { return "42"; } };
852+ 1n + numObj
853+ "# } ,
854+ JsNativeErrorKind :: Type ,
855+ MIXED_MSG ,
856+ ) ,
857+ TestAction :: assert ( "1n < 2" ) ,
858+ TestAction :: assert ( "!(1n > 2)" ) ,
859+ TestAction :: assert ( "1n <= 1" ) ,
860+ TestAction :: assert ( "2n >= 2" ) ,
861+ TestAction :: assert ( "(2n + 3n) === 5n" ) ,
862+ TestAction :: assert ( "(10n - 4n) === 6n" ) ,
863+ TestAction :: assert ( "(3n * 4n) === 12n" ) ,
864+ TestAction :: assert ( "(10n / 3n) === 3n" ) ,
865+ TestAction :: assert ( "(10n % 3n) === 1n" ) ,
866+ TestAction :: assert ( "(2n ** 10n) === 1024n" ) ,
867+ ] ) ;
868+ }
869+
870+ #[ test]
871+ fn ushr_bigint_type_error ( ) {
872+ run_test_actions ( [
873+ TestAction :: assert_native_error (
874+ "1n >>> 0n" ,
875+ JsNativeErrorKind :: Type ,
876+ "BigInts have no unsigned right shift, use >> instead" ,
877+ ) ,
878+ TestAction :: assert_native_error (
879+ "255n >>> 4n" ,
880+ JsNativeErrorKind :: Type ,
881+ "BigInts have no unsigned right shift, use >> instead" ,
882+ ) ,
883+ TestAction :: assert ( "(8n >> 2n) === 2n" ) ,
884+ TestAction :: assert ( "(-1n >> 63n) === -1n" ) ,
885+ TestAction :: assert ( "(1n << 4n) === 16n" ) ,
886+ ] ) ;
887+ }
888+
889+ #[ test]
890+ fn instanceof_custom_has_instance ( ) {
891+ run_test_actions ( [
892+ TestAction :: assert ( indoc ! { r#"
893+ class AlwaysTrue {
894+ static [Symbol.hasInstance](_instance) {
895+ return true;
896+ }
897+ }
898+ ({} instanceof AlwaysTrue)
899+ "# } ) ,
900+ TestAction :: assert ( indoc ! { r#"
901+ class AlwaysFalse {
902+ static [Symbol.hasInstance](_instance) {
903+ return false;
904+ }
905+ }
906+ let obj = new AlwaysFalse();
907+ !(obj instanceof AlwaysFalse)
908+ "# } ) ,
909+ TestAction :: assert ( indoc ! { r#"
910+ const EvenNumber = {
911+ [Symbol.hasInstance](value) {
912+ return typeof value === 'number' && value % 2 === 0;
913+ }
914+ };
915+ (2 instanceof EvenNumber) && !(3 instanceof EvenNumber)
916+ "# } ) ,
917+ TestAction :: assert_native_error (
918+ indoc ! { r#"
919+ class Throws {
920+ static [Symbol.hasInstance](_instance) {
921+ throw new TypeError("hasInstance threw");
922+ }
923+ }
924+ ({} instanceof Throws)
925+ "# } ,
926+ JsNativeErrorKind :: Type ,
927+ "hasInstance threw" ,
928+ ) ,
929+ TestAction :: assert_native_error (
930+ "let s = new String(); s instanceof {}" ,
931+ JsNativeErrorKind :: Type ,
932+ "right-hand side of 'instanceof' is not callable" ,
933+ ) ,
934+ TestAction :: assert_native_error (
935+ "42 instanceof 'not-a-constructor'" ,
936+ JsNativeErrorKind :: Type ,
937+ "right-hand side of 'instanceof' should be an object, got `string`" ,
938+ ) ,
939+ TestAction :: assert ( indoc ! { r#"
940+ const Truthy = {
941+ [Symbol.hasInstance]() { return 1; }
942+ };
943+ ({} instanceof Truthy)
944+ "# } ) ,
945+ TestAction :: assert ( indoc ! { r#"
946+ const Falsy = {
947+ [Symbol.hasInstance]() { return 0; }
948+ };
949+ !({} instanceof Falsy)
950+ "# } ) ,
951+ ] ) ;
952+ }
0 commit comments