|
31 | 31 | RefExpr, |
32 | 32 | StrExpr, |
33 | 33 | SuperExpr, |
| 34 | + SymbolNode, |
34 | 35 | TupleExpr, |
35 | 36 | Var, |
36 | 37 | ) |
@@ -587,18 +588,66 @@ def translate_isinstance(builder: IRBuilder, expr: CallExpr, callee: RefExpr) -> |
587 | 588 | if not (len(expr.args) == 2 and expr.arg_kinds == [ARG_POS, ARG_POS]): |
588 | 589 | return None |
589 | 590 |
|
590 | | - if isinstance(expr.args[1], (RefExpr, TupleExpr)): |
591 | | - builder.types[expr.args[0]] = AnyType(TypeOfAny.from_error) |
592 | | - |
593 | | - irs = builder.flatten_classes(expr.args[1]) |
| 591 | + obj_expr = expr.args[0] |
| 592 | + type_expr = expr.args[1] |
| 593 | + |
| 594 | + if isinstance(type_expr, TupleExpr) and not type_expr.items: |
| 595 | + # we can compile this case to a noop |
| 596 | + return builder.false() |
| 597 | + |
| 598 | + if isinstance(type_expr, (RefExpr, TupleExpr)): |
| 599 | + builder.types[obj_expr] = AnyType(TypeOfAny.from_error) |
| 600 | + |
| 601 | + irs = builder.flatten_classes(type_expr) |
594 | 602 | if irs is not None: |
595 | 603 | can_borrow = all( |
596 | 604 | ir.is_ext_class and not ir.inherits_python and not ir.allow_interpreted_subclasses |
597 | 605 | for ir in irs |
598 | 606 | ) |
599 | | - obj = builder.accept(expr.args[0], can_borrow=can_borrow) |
| 607 | + obj = builder.accept(obj_expr, can_borrow=can_borrow) |
600 | 608 | return builder.builder.isinstance_helper(obj, irs, expr.line) |
601 | 609 |
|
| 610 | + if isinstance(type_expr, TupleExpr): |
| 611 | + nodes: list[SymbolNode | None] = [] |
| 612 | + for item in type_expr.items: |
| 613 | + if not isinstance(item, RefExpr): |
| 614 | + return None |
| 615 | + if item.node is None: |
| 616 | + return None |
| 617 | + if item.node.fullname not in nodes: |
| 618 | + nodes.append(item.node.fullname) |
| 619 | + |
| 620 | + descs = [isinstance_primitives.get(fullname) for fullname in nodes] |
| 621 | + |
| 622 | + obj = builder.accept(expr.args[0]) |
| 623 | + |
| 624 | + retval = Register(bool_rprimitive) |
| 625 | + pass_block = BasicBlock() |
| 626 | + fail_block = BasicBlock() |
| 627 | + exit_block = BasicBlock() |
| 628 | + |
| 629 | + # Chain the checks: if any succeed, jump to pass_block; else, continue |
| 630 | + for i, desc in enumerate(descs): |
| 631 | + is_last = (i == len(descs) - 1) |
| 632 | + next_block = fail_block if is_last else BasicBlock() |
| 633 | + builder.add_bool_branch(builder.primitive_op(desc, [obj], expr.line), pass_block, next_block) |
| 634 | + if not is_last: |
| 635 | + builder.activate_block(next_block) |
| 636 | + |
| 637 | + # If any check passed |
| 638 | + builder.activate_block(pass_block) |
| 639 | + builder.assign(retval, builder.true(), expr.line) |
| 640 | + builder.goto(exit_block) |
| 641 | + |
| 642 | + # If all checks failed |
| 643 | + builder.activate_block(fail_block) |
| 644 | + builder.assign(retval, builder.false(), expr.line) |
| 645 | + builder.goto(exit_block) |
| 646 | + |
| 647 | + # Return the result |
| 648 | + builder.activate_block(exit_block) |
| 649 | + return retval |
| 650 | + |
602 | 651 | if isinstance(expr.args[1], RefExpr): |
603 | 652 | node = expr.args[1].node |
604 | 653 | if node: |
|
0 commit comments