forked from python/mypy
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathuninit.py
More file actions
70 lines (57 loc) · 2.75 KB
/
uninit.py
File metadata and controls
70 lines (57 loc) · 2.75 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
"""Insert checks for uninitialized values."""
from typing import List
from mypyc.analysis.dataflow import (
get_cfg,
cleanup_cfg,
analyze_must_defined_regs,
AnalysisDict
)
from mypyc.ir.ops import (
BasicBlock, Branch, Value, RaiseStandardError, Unreachable, Environment, Register
)
from mypyc.ir.func_ir import FuncIR
def insert_uninit_checks(ir: FuncIR) -> None:
# Remove dead blocks from the CFG, which helps avoid spurious
# checks due to unused error handling blocks.
cleanup_cfg(ir.blocks)
cfg = get_cfg(ir.blocks)
args = set(reg for reg in ir.env.regs() if ir.env.indexes[reg] < len(ir.args))
must_defined = analyze_must_defined_regs(ir.blocks, cfg, args, ir.env.regs())
ir.blocks = split_blocks_at_uninits(ir.env, ir.blocks, must_defined.before)
def split_blocks_at_uninits(env: Environment,
blocks: List[BasicBlock],
pre_must_defined: 'AnalysisDict[Value]') -> List[BasicBlock]:
new_blocks = [] # type: List[BasicBlock]
# First split blocks on ops that may raise.
for block in blocks:
ops = block.ops
block.ops = []
cur_block = block
new_blocks.append(cur_block)
for i, op in enumerate(ops):
defined = pre_must_defined[block, i]
for src in op.unique_sources():
# If a register operand is not guaranteed to be
# initialized is an operand to something other than a
# check that it is defined, insert a check.
if (isinstance(src, Register) and src not in defined
and not (isinstance(op, Branch) and op.op == Branch.IS_ERROR)):
new_block, error_block = BasicBlock(), BasicBlock()
new_block.error_handler = error_block.error_handler = cur_block.error_handler
new_blocks += [error_block, new_block]
env.vars_needing_init.add(src)
cur_block.ops.append(Branch(src,
true_label=error_block,
false_label=new_block,
op=Branch.IS_ERROR,
line=op.line))
raise_std = RaiseStandardError(
RaiseStandardError.UNBOUND_LOCAL_ERROR,
"local variable '{}' referenced before assignment".format(src.name),
op.line)
env.add_op(raise_std)
error_block.ops.append(raise_std)
error_block.ops.append(Unreachable())
cur_block = new_block
cur_block.ops.append(op)
return new_blocks