Special case for builtins.isinstance. Prevent coercions on the thing we are checking the instance of - there is no need to coerce something to a new type before checking what type it is, and the coercion could lead to bugs.
(builder: IRBuilder, expr: CallExpr, callee: RefExpr)
| 718 | |
| 719 | @specialize_function("builtins.isinstance") |
| 720 | def translate_isinstance(builder: IRBuilder, expr: CallExpr, callee: RefExpr) -> Value | None: |
| 721 | """Special case for builtins.isinstance. |
| 722 | |
| 723 | Prevent coercions on the thing we are checking the instance of - |
| 724 | there is no need to coerce something to a new type before checking |
| 725 | what type it is, and the coercion could lead to bugs. |
| 726 | """ |
| 727 | if not (len(expr.args) == 2 and expr.arg_kinds == [ARG_POS, ARG_POS]): |
| 728 | return None |
| 729 | |
| 730 | obj_expr = expr.args[0] |
| 731 | type_expr = expr.args[1] |
| 732 | |
| 733 | if isinstance(type_expr, TupleExpr) and not type_expr.items: |
| 734 | # we can compile this case to a noop |
| 735 | return builder.false() |
| 736 | |
| 737 | if isinstance(type_expr, (RefExpr, TupleExpr)): |
| 738 | builder.types[obj_expr] = AnyType(TypeOfAny.from_error) |
| 739 | |
| 740 | irs = builder.flatten_classes(type_expr) |
| 741 | if irs is not None: |
| 742 | can_borrow = all( |
| 743 | ir.is_ext_class and not ir.inherits_python and not ir.allow_interpreted_subclasses |
| 744 | for ir in irs |
| 745 | ) |
| 746 | obj = builder.accept(obj_expr, can_borrow=can_borrow) |
| 747 | return builder.builder.isinstance_helper(obj, irs, expr.line) |
| 748 | |
| 749 | if isinstance(type_expr, RefExpr): |
| 750 | node = type_expr.node |
| 751 | if node: |
| 752 | desc = isinstance_primitives.get(node.fullname) |
| 753 | if desc: |
| 754 | obj = builder.accept(obj_expr) |
| 755 | return builder.primitive_op(desc, [obj], expr.line) |
| 756 | |
| 757 | elif isinstance(type_expr, TupleExpr): |
| 758 | node_names: list[str] = [] |
| 759 | for item in type_expr.items: |
| 760 | if not isinstance(item, RefExpr): |
| 761 | return None |
| 762 | if item.node is None: |
| 763 | return None |
| 764 | if item.node.fullname not in node_names: |
| 765 | node_names.append(item.node.fullname) |
| 766 | |
| 767 | descs = [isinstance_primitives.get(fullname) for fullname in node_names] |
| 768 | if None in descs: |
| 769 | # not all types are primitive types, abort |
| 770 | return None |
| 771 | |
| 772 | obj = builder.accept(obj_expr) |
| 773 | |
| 774 | retval = Register(bool_rprimitive) |
| 775 | pass_block = BasicBlock() |
| 776 | fail_block = BasicBlock() |
| 777 | exit_block = BasicBlock() |
nothing calls this directly
no test coverage detected
searching dependent graphs…