Skip to content

Commit 1975746

Browse files
committed
[mypyc] feat: specialize isinstance for tuple of primitive types
1 parent 16cd4c5 commit 1975746

File tree

1 file changed

+54
-5
lines changed

1 file changed

+54
-5
lines changed

mypyc/irbuild/specialize.py

Lines changed: 54 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
RefExpr,
3232
StrExpr,
3333
SuperExpr,
34+
SymbolNode,
3435
TupleExpr,
3536
Var,
3637
)
@@ -587,18 +588,66 @@ def translate_isinstance(builder: IRBuilder, expr: CallExpr, callee: RefExpr) ->
587588
if not (len(expr.args) == 2 and expr.arg_kinds == [ARG_POS, ARG_POS]):
588589
return None
589590

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)
594602
if irs is not None:
595603
can_borrow = all(
596604
ir.is_ext_class and not ir.inherits_python and not ir.allow_interpreted_subclasses
597605
for ir in irs
598606
)
599-
obj = builder.accept(expr.args[0], can_borrow=can_borrow)
607+
obj = builder.accept(obj_expr, can_borrow=can_borrow)
600608
return builder.builder.isinstance_helper(obj, irs, expr.line)
601609

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+
602651
if isinstance(expr.args[1], RefExpr):
603652
node = expr.args[1].node
604653
if node:

0 commit comments

Comments
 (0)