diff --git a/mypyc/irbuild/specialize.py b/mypyc/irbuild/specialize.py index b490c2a52e57..3015640fb3fd 100644 --- a/mypyc/irbuild/specialize.py +++ b/mypyc/irbuild/specialize.py @@ -83,19 +83,26 @@ join_formatted_strings, tokenizer_format_call, ) +from mypyc.primitives.bytes_ops import isinstance_bytearray, isinstance_bytes from mypyc.primitives.dict_ops import ( dict_items_op, dict_keys_op, dict_setdefault_spec_init_op, dict_values_op, + isinstance_dict, ) +from mypyc.primitives.float_ops import isinstance_float +from mypyc.primitives.int_ops import isinstance_int from mypyc.primitives.list_ops import isinstance_list, new_list_set_item_op +from mypyc.primitives.misc_ops import isinstance_bool +from mypyc.primitives.set_ops import isinstance_frozenset, isinstance_set from mypyc.primitives.str_ops import ( + isinstance_str, str_encode_ascii_strict, str_encode_latin1_strict, str_encode_utf8_strict, ) -from mypyc.primitives.tuple_ops import new_tuple_set_item_op +from mypyc.primitives.tuple_ops import isinstance_tuple, new_tuple_set_item_op # Specializers are attempted before compiling the arguments to the # function. Specializers can return None to indicate that they failed @@ -546,7 +553,19 @@ def gen_inner_stmts() -> None: return retval -isinstance_primitives: Final = {"builtins.list": isinstance_list} +isinstance_primitives: Final = { + "builtins.bool": isinstance_bool, + "builtins.bytearray": isinstance_bytearray, + "builtins.bytes": isinstance_bytes, + "builtins.dict": isinstance_dict, + "builtins.float": isinstance_float, + "builtins.frozenset": isinstance_frozenset, + "builtins.int": isinstance_int, + "builtins.list": isinstance_list, + "builtins.set": isinstance_set, + "builtins.str": isinstance_str, + "builtins.tuple": isinstance_tuple, +} @specialize_function("builtins.isinstance") diff --git a/mypyc/primitives/bytes_ops.py b/mypyc/primitives/bytes_ops.py index 1afd196cff84..c88e89d1a2ba 100644 --- a/mypyc/primitives/bytes_ops.py +++ b/mypyc/primitives/bytes_ops.py @@ -2,9 +2,10 @@ from __future__ import annotations -from mypyc.ir.ops import ERR_MAGIC +from mypyc.ir.ops import ERR_MAGIC, ERR_NEVER from mypyc.ir.rtypes import ( RUnion, + bit_rprimitive, bytes_rprimitive, c_int_rprimitive, c_pyssize_t_rprimitive, @@ -35,6 +36,15 @@ error_kind=ERR_MAGIC, ) +# translate isinstance(obj, bytes) +isinstance_bytes = function_op( + name="builtins.isinstance", + arg_types=[object_rprimitive], + return_type=bit_rprimitive, + c_function_name="PyBytes_Check", + error_kind=ERR_NEVER, +) + # bytearray(obj) function_op( name="builtins.bytearray", @@ -44,6 +54,15 @@ error_kind=ERR_MAGIC, ) +# translate isinstance(obj, bytearray) +isinstance_bytearray = function_op( + name="builtins.isinstance", + arg_types=[object_rprimitive], + return_type=bit_rprimitive, + c_function_name="PyByteArray_Check", + error_kind=ERR_NEVER, +) + # bytes ==/!= (return -1/0/1) bytes_compare = custom_op( arg_types=[bytes_rprimitive, bytes_rprimitive], diff --git a/mypyc/primitives/dict_ops.py b/mypyc/primitives/dict_ops.py index 3f289c3c6f08..ac928bb0eb50 100644 --- a/mypyc/primitives/dict_ops.py +++ b/mypyc/primitives/dict_ops.py @@ -71,6 +71,15 @@ error_kind=ERR_MAGIC, ) +# translate isinstance(obj, dict) +isinstance_dict = function_op( + name="builtins.isinstance", + arg_types=[object_rprimitive], + return_type=bit_rprimitive, + c_function_name="PyDict_Check", + error_kind=ERR_NEVER, +) + # dict[key] dict_get_item_op = method_op( name="__getitem__", diff --git a/mypyc/primitives/float_ops.py b/mypyc/primitives/float_ops.py index 14e8d4caf09c..542192add542 100644 --- a/mypyc/primitives/float_ops.py +++ b/mypyc/primitives/float_ops.py @@ -4,6 +4,7 @@ from mypyc.ir.ops import ERR_MAGIC, ERR_MAGIC_OVERLAPPING, ERR_NEVER from mypyc.ir.rtypes import ( + bit_rprimitive, bool_rprimitive, float_rprimitive, int_rprimitive, @@ -166,3 +167,12 @@ c_function_name="CPyFloat_IsNaN", error_kind=ERR_NEVER, ) + +# translate isinstance(obj, float) +isinstance_float = function_op( + name="builtins.isinstance", + arg_types=[object_rprimitive], + return_type=bit_rprimitive, + c_function_name="PyFloat_Check", + error_kind=ERR_NEVER, +) diff --git a/mypyc/primitives/int_ops.py b/mypyc/primitives/int_ops.py index 9b8b48da602d..d723c9b63a86 100644 --- a/mypyc/primitives/int_ops.py +++ b/mypyc/primitives/int_ops.py @@ -296,3 +296,12 @@ def int_unary_op(name: str, c_function_name: str) -> PrimitiveDescription: c_function_name="CPyUInt8_Overflow", error_kind=ERR_ALWAYS, ) + +# translate isinstance(obj, int) +isinstance_int = function_op( + name="builtints.isinstance", + arg_types=[object_rprimitive], + return_type=bit_rprimitive, + c_function_name="PyLong_Check", + error_kind=ERR_NEVER, +) diff --git a/mypyc/primitives/list_ops.py b/mypyc/primitives/list_ops.py index 57cb541fdbb8..516d9e1a4e02 100644 --- a/mypyc/primitives/list_ops.py +++ b/mypyc/primitives/list_ops.py @@ -56,7 +56,7 @@ extra_int_constants=[(0, int_rprimitive)], ) -# isinstance(obj, list) +# translate isinstance(obj, list) isinstance_list = function_op( name="builtins.isinstance", arg_types=[object_rprimitive], diff --git a/mypyc/primitives/misc_ops.py b/mypyc/primitives/misc_ops.py index 7494b46790ce..114a5f0a9823 100644 --- a/mypyc/primitives/misc_ops.py +++ b/mypyc/primitives/misc_ops.py @@ -191,6 +191,15 @@ truncated_type=bool_rprimitive, ) +# isinstance(obj, bool) +isinstance_bool = function_op( + name="builtins.isinstance", + arg_types=[object_rprimitive], + return_type=bit_rprimitive, + c_function_name="PyBool_Check", + error_kind=ERR_NEVER, +) + # slice(start, stop, step) new_slice_op = function_op( name="builtins.slice", diff --git a/mypyc/primitives/set_ops.py b/mypyc/primitives/set_ops.py index eb7c9b46609d..786de008746d 100644 --- a/mypyc/primitives/set_ops.py +++ b/mypyc/primitives/set_ops.py @@ -2,7 +2,7 @@ from __future__ import annotations -from mypyc.ir.ops import ERR_FALSE, ERR_MAGIC +from mypyc.ir.ops import ERR_FALSE, ERR_MAGIC, ERR_NEVER from mypyc.ir.rtypes import ( bit_rprimitive, bool_rprimitive, @@ -64,6 +64,24 @@ error_kind=ERR_MAGIC, ) +# translate isinstance(obj, set) +isinstance_set = function_op( + name="builtins.isinstance", + arg_types=[object_rprimitive], + return_type=bit_rprimitive, + c_function_name="PySet_Check", + error_kind=ERR_NEVER, +) + +# translate isinstance(obj, frozenset) +isinstance_frozenset = function_op( + name="builtins.isinstance", + arg_types=[object_rprimitive], + return_type=bit_rprimitive, + c_function_name="PyFrozenSet_Check", + error_kind=ERR_NEVER, +) + # item in set set_in_op = binary_op( name="in", diff --git a/mypyc/primitives/str_ops.py b/mypyc/primitives/str_ops.py index 37dbdf21bb5d..31f361719765 100644 --- a/mypyc/primitives/str_ops.py +++ b/mypyc/primitives/str_ops.py @@ -48,6 +48,15 @@ error_kind=ERR_MAGIC, ) +# translate isinstance(obj, str) +isinstance_str = function_op( + name="builtins.isinstance", + arg_types=[object_rprimitive], + return_type=bit_rprimitive, + c_function_name="PyUnicode_Check", + error_kind=ERR_NEVER, +) + # str1 + str2 binary_op( name="+", diff --git a/mypyc/primitives/tuple_ops.py b/mypyc/primitives/tuple_ops.py index e680b6943d84..d95161acf853 100644 --- a/mypyc/primitives/tuple_ops.py +++ b/mypyc/primitives/tuple_ops.py @@ -8,6 +8,7 @@ from mypyc.ir.ops import ERR_MAGIC, ERR_NEVER from mypyc.ir.rtypes import ( + bit_rprimitive, c_pyssize_t_rprimitive, int_rprimitive, list_rprimitive, @@ -83,6 +84,15 @@ error_kind=ERR_MAGIC, ) +# translate isinstance(obj, tuple) +isinstance_tuple = function_op( + name="builtins.isinstance", + arg_types=[object_rprimitive], + return_type=bit_rprimitive, + c_function_name="PyTuple_Check", + error_kind=ERR_NEVER, +) + # tuple + tuple binary_op( name="+", diff --git a/mypyc/test-data/irbuild-basic.test b/mypyc/test-data/irbuild-basic.test index ea1b3d06869a..4a7d315ec836 100644 --- a/mypyc/test-data/irbuild-basic.test +++ b/mypyc/test-data/irbuild-basic.test @@ -1581,24 +1581,18 @@ def main() -> None: [out] def foo(x): x :: union[int, str] - r0 :: object - r1 :: i32 - r2 :: bit - r3 :: bool - r4 :: __main__.B - r5 :: __main__.A + r0 :: bit + r1 :: __main__.B + r2 :: __main__.A L0: - r0 = load_address PyLong_Type - r1 = PyObject_IsInstance(x, r0) - r2 = r1 >= 0 :: signed - r3 = truncate r1: i32 to builtins.bool - if r3 goto L1 else goto L2 :: bool + r0 = PyLong_Check(x) + if r0 goto L1 else goto L2 :: bool L1: - r4 = B() - return r4 + r1 = B() + return r1 L2: - r5 = A() - return r5 + r2 = A() + return r2 def main(): r0 :: object r1 :: __main__.A @@ -3389,16 +3383,11 @@ def f(x: object) -> bool: return isinstance(x, bool) [out] def f(x): - x, r0 :: object - r1 :: i32 - r2 :: bit - r3 :: bool + x :: object + r0 :: bit L0: - r0 = load_address PyBool_Type - r1 = PyObject_IsInstance(x, r0) - r2 = r1 >= 0 :: signed - r3 = truncate r1: i32 to builtins.bool - return r3 + r0 = PyBool_Check(x) + return r0 [case testRangeObject] def range_object() -> None: diff --git a/mypyc/test-data/irbuild-i64.test b/mypyc/test-data/irbuild-i64.test index c59e306b09df..e55c3bfe2acc 100644 --- a/mypyc/test-data/irbuild-i64.test +++ b/mypyc/test-data/irbuild-i64.test @@ -2046,27 +2046,21 @@ L2: return r6 def narrow2(x): x :: union[__main__.C, i64] - r0 :: object - r1 :: i32 - r2 :: bit - r3 :: bool - r4 :: i64 - r5 :: __main__.C - r6 :: i64 + r0 :: bit + r1 :: i64 + r2 :: __main__.C + r3 :: i64 L0: - r0 = load_address PyLong_Type - r1 = PyObject_IsInstance(x, r0) - r2 = r1 >= 0 :: signed - r3 = truncate r1: i32 to builtins.bool - if r3 goto L1 else goto L2 :: bool + r0 = PyLong_Check(x) + if r0 goto L1 else goto L2 :: bool L1: - r4 = unbox(i64, x) - return r4 + r1 = unbox(i64, x) + return r1 L2: - r5 = borrow cast(__main__.C, x) - r6 = r5.a + r2 = borrow cast(__main__.C, x) + r3 = r2.a keep_alive x - return r6 + return r3 [case testI64ConvertBetweenTuples_64bit] from __future__ import annotations diff --git a/mypyc/test-data/irbuild-isinstance.test b/mypyc/test-data/irbuild-isinstance.test index 78da2e9c1e19..30adfe61e384 100644 --- a/mypyc/test-data/irbuild-isinstance.test +++ b/mypyc/test-data/irbuild-isinstance.test @@ -4,16 +4,11 @@ def is_int(value: object) -> bool: [out] def is_int(value): - value, r0 :: object - r1 :: i32 - r2 :: bit - r3 :: bool + value :: object + r0 :: bit L0: - r0 = load_address PyLong_Type - r1 = PyObject_IsInstance(value, r0) - r2 = r1 >= 0 :: signed - r3 = truncate r1: i32 to builtins.bool - return r3 + r0 = PyLong_Check(value) + return r0 [case testIsinstanceNotBool1] def is_not_bool(value: object) -> bool: @@ -21,17 +16,12 @@ def is_not_bool(value: object) -> bool: [out] def is_not_bool(value): - value, r0 :: object - r1 :: i32 - r2 :: bit - r3, r4 :: bool + value :: object + r0, r1 :: bit L0: - r0 = load_address PyBool_Type - r1 = PyObject_IsInstance(value, r0) - r2 = r1 >= 0 :: signed - r3 = truncate r1: i32 to builtins.bool - r4 = r3 ^ 1 - return r4 + r0 = PyBool_Check(value) + r1 = r0 ^ 1 + return r1 [case testIsinstanceIntAndNotBool] # This test is to ensure that 'value' doesn't get coerced to int when we are @@ -41,32 +31,22 @@ def is_not_bool_and_is_int(value: object) -> bool: [out] def is_not_bool_and_is_int(value): - value, r0 :: object - r1 :: i32 - r2 :: bit - r3, r4 :: bool - r5 :: object - r6 :: i32 - r7 :: bit - r8, r9 :: bool + value :: object + r0 :: bit + r1 :: bool + r2, r3 :: bit L0: - r0 = load_address PyLong_Type - r1 = PyObject_IsInstance(value, r0) - r2 = r1 >= 0 :: signed - r3 = truncate r1: i32 to builtins.bool - if r3 goto L2 else goto L1 :: bool + r0 = PyLong_Check(value) + if r0 goto L2 else goto L1 :: bool L1: - r4 = r3 + r1 = r0 goto L3 L2: - r5 = load_address PyBool_Type - r6 = PyObject_IsInstance(value, r5) - r7 = r6 >= 0 :: signed - r8 = truncate r6: i32 to builtins.bool - r9 = r8 ^ 1 - r4 = r9 + r2 = PyBool_Check(value) + r3 = r2 ^ 1 + r1 = r3 L3: - return r4 + return r1 [case testBorrowSpecialCaseWithIsinstance] class C: @@ -107,3 +87,105 @@ L1: keep_alive x L2: return 1 + +[case testBytes] +from typing import Any + +def is_bytes(x: Any) -> bool: + return isinstance(x, bytes) + +def is_bytearray(x: Any) -> bool: + return isinstance(x, bytearray) + +[out] +def is_bytes(x): + x :: object + r0 :: bit +L0: + r0 = PyBytes_Check(x) + return r0 +def is_bytearray(x): + x :: object + r0 :: bit +L0: + r0 = PyByteArray_Check(x) + return r0 + +[case testDict] +from typing import Any + +def is_dict(x: Any) -> bool: + return isinstance(x, dict) + +[out] +def is_dict(x): + x :: object + r0 :: bit +L0: + r0 = PyDict_Check(x) + return r0 + +[case testFloat] +from typing import Any + +def is_float(x: Any) -> bool: + return isinstance(x, float) + +[out] +def is_float(x): + x :: object + r0 :: bit +L0: + r0 = PyFloat_Check(x) + return r0 + +[case testSet] +from typing import Any + +def is_set(x: Any) -> bool: + return isinstance(x, set) + +def is_frozenset(x: Any) -> bool: + return isinstance(x, frozenset) + +[out] +def is_set(x): + x :: object + r0 :: bit +L0: + r0 = PySet_Check(x) + return r0 +def is_frozenset(x): + x :: object + r0 :: bit +L0: + r0 = PyFrozenSet_Check(x) + return r0 + +[case testStr] +from typing import Any + +def is_str(x: Any) -> bool: + return isinstance(x, str) + +[out] +def is_str(x): + x :: object + r0 :: bit +L0: + r0 = PyUnicode_Check(x) + return r0 + +[case testTuple] +from typing import Any + +def is_tuple(x: Any) -> bool: + return isinstance(x, tuple) + +[out] +def is_tuple(x): + x :: object + r0 :: bit +L0: + r0 = PyTuple_Check(x) + return r0 diff --git a/mypyc/test-data/irbuild-optional.test b/mypyc/test-data/irbuild-optional.test index 75c008586999..b81465d362ba 100644 --- a/mypyc/test-data/irbuild-optional.test +++ b/mypyc/test-data/irbuild-optional.test @@ -251,28 +251,22 @@ def f(x: Union[int, A]) -> int: [out] def f(x): x :: union[int, __main__.A] - r0 :: object - r1 :: i32 - r2 :: bit - r3 :: bool - r4, r5 :: int - r6 :: __main__.A - r7 :: int + r0 :: bit + r1, r2 :: int + r3 :: __main__.A + r4 :: int L0: - r0 = load_address PyLong_Type - r1 = PyObject_IsInstance(x, r0) - r2 = r1 >= 0 :: signed - r3 = truncate r1: i32 to builtins.bool - if r3 goto L1 else goto L2 :: bool + r0 = PyLong_Check(x) + if r0 goto L1 else goto L2 :: bool L1: - r4 = unbox(int, x) - r5 = CPyTagged_Add(r4, 2) - return r5 + r1 = unbox(int, x) + r2 = CPyTagged_Add(r1, 2) + return r2 L2: - r6 = borrow cast(__main__.A, x) - r7 = r6.a + r3 = borrow cast(__main__.A, x) + r4 = r3.a keep_alive x - return r7 + return r4 L3: unreachable diff --git a/mypyc/test-data/run-bools.test b/mypyc/test-data/run-bools.test index 3409665bfb37..b34fedebaa9f 100644 --- a/mypyc/test-data/run-bools.test +++ b/mypyc/test-data/run-bools.test @@ -228,3 +228,29 @@ def test_mix() -> None: print((y or 0) and True) [out] 0 + +[case testIsInstance] +from typing import Any +def test_built_in() -> None: + true: Any = True + false: Any = False + assert isinstance(true, bool) + assert isinstance(false, bool) + + assert not isinstance(set(), bool) + assert not isinstance((), bool) + assert not isinstance((True, False), bool) + assert not isinstance({False, True}, bool) + assert not isinstance(int() + 1, bool) + assert not isinstance(str() + 'False', bool) + +def test_user_defined() -> None: + from userdefinedbool import bool + + b: Any = True + assert isinstance(bool(), bool) + assert not isinstance(b, bool) + +[file userdefinedbool.py] +class bool: + pass diff --git a/mypyc/test-data/run-bytes.test b/mypyc/test-data/run-bytes.test index bee6b6fe9f76..5a285320c849 100644 --- a/mypyc/test-data/run-bytes.test +++ b/mypyc/test-data/run-bytes.test @@ -323,3 +323,54 @@ class A: def test_bytes_dunder() -> None: assert b'%b' % A() == b'aaa' assert b'%s' % A() == b'aaa' + +[case testIsInstance] +from copysubclass import subbytes, subbytearray +from typing import Any +def test_bytes() -> None: + b: Any = b'' + assert isinstance(b, bytes) + assert isinstance(b + b'123', bytes) + assert isinstance(b + b'\xff', bytes) + assert isinstance(subbytes(), bytes) + assert isinstance(subbytes(b + b'123'), bytes) + assert isinstance(subbytes(b + b'\xff'), bytes) + + assert not isinstance(set(), bytes) + assert not isinstance((), bytes) + assert not isinstance((b'1',b'2',b'3'), bytes) + assert not isinstance({b'a',b'b'}, bytes) + assert not isinstance(int() + 1, bytes) + assert not isinstance(str() + 'a', bytes) + +def test_user_defined_bytes() -> None: + from userdefinedbytes import bytes + + assert isinstance(bytes(), bytes) + assert not isinstance(b'\x7f', bytes) + +def test_bytearray() -> None: + assert isinstance(bytearray(), bytearray) + assert isinstance(bytearray(b'123'), bytearray) + assert isinstance(bytearray(b'\xff'), bytearray) + assert isinstance(subbytearray(), bytearray) + assert isinstance(subbytearray(bytearray(b'123')), bytearray) + assert isinstance(subbytearray(bytearray(b'\xff')), bytearray) + + assert not isinstance(set(), bytearray) + assert not isinstance((), bytearray) + assert not isinstance((bytearray(b'1'),bytearray(b'2'),bytearray(b'3')), bytearray) + assert not isinstance([bytearray(b'a'),bytearray(b'b')], bytearray) + assert not isinstance(int() + 1, bytearray) + assert not isinstance(str() + 'a', bytearray) + +[file copysubclass.py] +class subbytes(bytes): + pass + +class subbytearray(bytearray): + pass + +[file userdefinedbytes.py] +class bytes: + pass diff --git a/mypyc/test-data/run-dicts.test b/mypyc/test-data/run-dicts.test index 2a3be188ad00..2b75b32c906e 100644 --- a/mypyc/test-data/run-dicts.test +++ b/mypyc/test-data/run-dicts.test @@ -336,3 +336,35 @@ def test_dict_to_bool() -> None: for x in tmp_list: assert is_true(x) assert not is_false(x) + +[case testIsInstance] +from copysubclass import subc +def test_built_in() -> None: + assert isinstance({}, dict) + assert isinstance({'one': 1, 'two': 2}, dict) + assert isinstance({1: 1, 'two': 2}, dict) + assert isinstance(subc(), dict) + assert isinstance(subc({'a': 1, 'b': 2}), dict) + assert isinstance(subc({1: 'a', 2: 'b'}), dict) + + assert not isinstance(set(), dict) + assert not isinstance((), dict) + assert not isinstance((1,2,3), dict) + assert not isinstance({'a','b'}, dict) + assert not isinstance(int() + 1, dict) + assert not isinstance(str() + 'a', dict) + +def test_user_defined() -> None: + from userdefineddict import dict + + assert isinstance(dict(), dict) + assert not isinstance({1: dict()}, dict) + +[file copysubclass.py] +from typing import Any +class subc(dict[Any, Any]): + pass + +[file userdefineddict.py] +class dict: + pass diff --git a/mypyc/test-data/run-floats.test b/mypyc/test-data/run-floats.test index 49620f6448c7..424d52cdb0d5 100644 --- a/mypyc/test-data/run-floats.test +++ b/mypyc/test-data/run-floats.test @@ -512,3 +512,34 @@ def test_implement_trait_attribute() -> None: a.y = 8.0 assert a.x == 7 assert a.y == 8 + +[case testIsInstance] +from copysubclass import subc +from testutil import float_vals +from typing import Any +def test_built_in() -> None: + for f in float_vals: + assert isinstance(float(0) + f, float) + assert isinstance(subc(f), float) + + assert not isinstance(set(), float) + assert not isinstance((), float) + assert not isinstance((1.0, 2.0), float) + assert not isinstance({3.14}, float) + assert not isinstance(int() + 1, float) + assert not isinstance(str() + '4.2', float) + +def test_user_defined() -> None: + from userdefinedfloat import float + + f: Any = 3.14 + assert isinstance(float(), float) + assert not isinstance(f, float) + +[file copysubclass.py] +class subc(float): + pass + +[file userdefinedfloat.py] +class float: + pass diff --git a/mypyc/test-data/run-integers.test b/mypyc/test-data/run-integers.test index d575e141b567..1163c9d942f7 100644 --- a/mypyc/test-data/run-integers.test +++ b/mypyc/test-data/run-integers.test @@ -538,3 +538,37 @@ def test_int_bool_min_max() -> None: assert min(u, z) == -10 assert max(u, y) == False assert max(u, z) == True + +[case testIsInstance] +from copysubclass import subc +from typing import Any +def test_built_in() -> None: + i: Any = 0 + assert isinstance(i + 0, int) + assert isinstance(i + 9223372036854775808, int) + assert isinstance(i + -9223372036854775808, int) + assert isinstance(subc(), int) + assert isinstance(subc(9223372036854775808), int) + assert isinstance(subc(-9223372036854775808), int) + + assert not isinstance(set(), int) + assert not isinstance((), int) + assert not isinstance((1,2,3), int) + assert not isinstance({1,2}, int) + assert not isinstance(float(0) + 1.0, int) + assert not isinstance(str() + '1', int) + +def test_user_defined() -> None: + from userdefinedint import int + + i: Any = 42 + assert isinstance(int(), int) + assert not isinstance(i, int) + +[file copysubclass.py] +class subc(int): + pass + +[file userdefinedint.py] +class int: + pass diff --git a/mypyc/test-data/run-sets.test b/mypyc/test-data/run-sets.test index 68edd1e6b77d..2668d63bcdac 100644 --- a/mypyc/test-data/run-sets.test +++ b/mypyc/test-data/run-sets.test @@ -265,3 +265,55 @@ def test_in_set() -> None: def test_for_set() -> None: assert not s ^ {None, False, 1, 2.0, "3", b"4", 5j, (6,), CONST}, s + +[case testIsInstance] +from copysubclass import subset, subfrozenset +def test_built_in_set() -> None: + assert isinstance(set(), set) + assert isinstance({'one', 'two'}, set) + assert isinstance({'a', 1}, set) + assert isinstance(subset(), set) + assert isinstance(subset({'one', 'two'}), set) + assert isinstance(subset({'a', 1}), set) + + assert not isinstance(frozenset(), set) + assert not isinstance({}, set) + assert not isinstance([], set) + assert not isinstance((1,2,3), set) + assert not isinstance({1:'a', 2:'b'}, set) + assert not isinstance(int() + 1, set) + assert not isinstance(str() + 'a', set) + +def test_user_defined_set() -> None: + from userdefinedset import set + + assert isinstance(set(), set) + assert not isinstance({set()}, set) + +def test_built_in_frozenset() -> None: + assert isinstance(frozenset(), frozenset) + assert isinstance(frozenset({'one', 'two'}), frozenset) + assert isinstance(frozenset({'a', 1}), frozenset) + assert isinstance(subfrozenset(), frozenset) + assert isinstance(subfrozenset({'one', 'two'}), frozenset) + assert isinstance(subfrozenset({'a', 1}), frozenset) + + assert not isinstance(set(), frozenset) + assert not isinstance({}, frozenset) + assert not isinstance([], frozenset) + assert not isinstance((1,2,3), frozenset) + assert not isinstance({1:'a', 2:'b'}, frozenset) + assert not isinstance(int() + 1, frozenset) + assert not isinstance(str() + 'a', frozenset) + +[file copysubclass.py] +from typing import Any +class subset(set[Any]): + pass + +class subfrozenset(frozenset[Any]): + pass + +[file userdefinedset.py] +class set: + pass diff --git a/mypyc/test-data/run-strings.test b/mypyc/test-data/run-strings.test index 6551d9c352df..8a914c08bfb2 100644 --- a/mypyc/test-data/run-strings.test +++ b/mypyc/test-data/run-strings.test @@ -964,3 +964,38 @@ def test_count_multi_start_end_emoji() -> None: assert string.count("😴😴😴", 0, 12) == 1, string.count("😴😴😴", 0, 12) assert string.count("🚀🚀🚀", 0, 12) == 2, string.count("🚀🚀🚀", 0, 12) assert string.count("ñññ", 0, 12) == 1, string.count("ñññ", 0, 12) + +[case testIsInstance] +from copysubclass import subc +from typing import Any +def test_built_in() -> None: + s: Any = str() + assert isinstance(s, str) + assert isinstance(s + "test", str) + assert isinstance(s + "ñññ", str) + assert isinstance(subc(), str) + assert isinstance(subc("test"), str) + assert isinstance(subc("ñññ"), str) + + assert not isinstance(set(), str) + assert not isinstance((), str) + assert not isinstance(('a','b'), str) + assert not isinstance({'a','b'}, str) + assert not isinstance(int() + 1, str) + assert not isinstance(['a','b'], str) + +def test_user_defined() -> None: + from userdefinedstr import str + + s: Any = "str" + assert isinstance(str(), str) + assert not isinstance(s, str) + +[file copysubclass.py] +from typing import Any +class subc(str): + pass + +[file userdefinedstr.py] +class str: + pass diff --git a/mypyc/test-data/run-tuples.test b/mypyc/test-data/run-tuples.test index fe9a8dff08c6..ea0a1cb8d852 100644 --- a/mypyc/test-data/run-tuples.test +++ b/mypyc/test-data/run-tuples.test @@ -294,3 +294,35 @@ def test_multiply() -> None: assert (1,) * 3 == res assert 3 * (1,) == res assert multiply((1,), 3) == res + +[case testIsInstance] +from copysubclass import subc +def test_built_in() -> None: + assert isinstance((), tuple) + assert isinstance((1, 2), tuple) + assert isinstance(('a', 'b', 'c'), tuple) + assert isinstance(subc(()), tuple) + assert isinstance(subc((1, 2)), tuple) + assert isinstance(subc(('a', 'b', 'c')), tuple) + + assert not isinstance(set(), tuple) + assert not isinstance({}, tuple) + assert not isinstance([1,2,3], tuple) + assert not isinstance({'a','b'}, tuple) + assert not isinstance(int() + 1, tuple) + assert not isinstance(str() + 'a', tuple) + +def test_user_defined() -> None: + from userdefinedtuple import tuple + + assert isinstance(tuple(), tuple) + assert not isinstance((1, tuple()), tuple) + +[file copysubclass.py] +from typing import Any +class subc(tuple[Any]): + pass + +[file userdefinedtuple.py] +class tuple: + pass