Skip to content

Commit b06beab

Browse files
authored
[mypyc] Infer more precise error kinds for some ops (#13524)
During the error handling transform we have access to always defined attributes, which allows us to infer that certain attribute operations will never fail. This can improve performance and reduce the size of the generated code.
1 parent a9bc366 commit b06beab

File tree

3 files changed

+44
-0
lines changed

3 files changed

+44
-0
lines changed

mypyc/ir/pprint.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,7 @@ def borrow_prefix(self, op: Op) -> str:
119119
def visit_set_attr(self, op: SetAttr) -> str:
120120
if op.is_init:
121121
assert op.error_kind == ERR_NEVER
122+
if op.error_kind == ERR_NEVER:
122123
# Initialization and direct struct access can never fail
123124
return self.format("%r.%s = %r", op.obj, op.attr, op.src)
124125
else:

mypyc/test-data/exceptions.test

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -545,6 +545,31 @@ L3:
545545
r3 = <error> :: int64
546546
return r3
547547

548+
[case testExceptionWithNativeAttributeGetAndSet]
549+
class C:
550+
def __init__(self, x: int) -> None:
551+
self.x = x
552+
553+
def foo(c: C, x: int) -> None:
554+
c.x = x - c.x
555+
[out]
556+
def C.__init__(self, x):
557+
self :: __main__.C
558+
x :: int
559+
L0:
560+
inc_ref x :: int
561+
self.x = x
562+
return 1
563+
def foo(c, x):
564+
c :: __main__.C
565+
x, r0, r1 :: int
566+
r2 :: bool
567+
L0:
568+
r0 = borrow c.x
569+
r1 = CPyTagged_Subtract(x, r0)
570+
c.x = r1
571+
return 1
572+
548573
[case testExceptionWithLowLevelIntAttribute]
549574
from mypy_extensions import i32, i64
550575

mypyc/transform/exceptions.py

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,10 +23,12 @@
2323
Branch,
2424
CallC,
2525
ComparisonOp,
26+
GetAttr,
2627
Integer,
2728
LoadErrorValue,
2829
RegisterOp,
2930
Return,
31+
SetAttr,
3032
Value,
3133
)
3234
from mypyc.ir.rtypes import bool_rprimitive
@@ -40,6 +42,7 @@ def insert_exception_handling(ir: FuncIR) -> None:
4042
# block. The block just returns an error value.
4143
error_label = None
4244
for block in ir.blocks:
45+
adjust_error_kinds(block)
4346
can_raise = any(op.can_raise() for op in block.ops)
4447
if can_raise:
4548
error_label = add_handler_block(ir)
@@ -145,3 +148,18 @@ def primitive_call(desc: CFunctionDescription, args: list[Value], line: int) ->
145148
desc.error_kind,
146149
line,
147150
)
151+
152+
153+
def adjust_error_kinds(block: BasicBlock) -> None:
154+
"""Infer more precise error_kind attributes for ops.
155+
156+
We have access here to more information than what was available
157+
when the IR was initially built.
158+
"""
159+
for op in block.ops:
160+
if isinstance(op, GetAttr):
161+
if op.class_type.class_ir.is_always_defined(op.attr):
162+
op.error_kind = ERR_NEVER
163+
if isinstance(op, SetAttr):
164+
if op.class_type.class_ir.is_always_defined(op.attr):
165+
op.error_kind = ERR_NEVER

0 commit comments

Comments
 (0)