@@ -73,27 +73,38 @@ def merge_state(a, b):
73
73
# Update the state based on block contents, while validating
74
74
# that no access to uninitialized variables will be done.
75
75
for insn in block .instructions :
76
+ def pred_at_fault (env , var_name ):
77
+ # Find out where the uninitialized state comes from.
78
+ for pred , pred_state in zip (forward_edge_preds , pred_states ):
79
+ if not pred_state [env ][var_name ]:
80
+ return pred
81
+
82
+ # It's the entry block and it was never initialized.
83
+ return None
84
+
76
85
if isinstance (insn , (ir .SetLocal , ir .GetLocal )) and \
77
86
"." not in insn .var_name :
78
87
env , var_name = insn .environment (), insn .var_name
79
- assert env in block_state
80
- assert var_name in block_state [env ]
81
88
82
- if isinstance (insn , ir .SetLocal ):
83
- # We've just initialized it.
84
- block_state [env ][var_name ] = True
85
- else : # isinstance(insn, ir.GetLocal)
89
+ # Make sure that the variable is defined in the scope of this function.
90
+ if env in block_state and var_name in block_state [env ]:
91
+ if isinstance (insn , ir .SetLocal ):
92
+ # We've just initialized it.
93
+ block_state [env ][var_name ] = True
94
+ else : # isinstance(insn, ir.GetLocal)
95
+ if not block_state [env ][var_name ]:
96
+ # Oops, accessing it uninitialized.
97
+ self ._uninitialized_access (insn , var_name ,
98
+ pred_at_fault (env , var_name ))
99
+
100
+ if isinstance (insn , ir .Closure ):
101
+ env = insn .environment ()
102
+ for var_name in block_state [env ]:
86
103
if not block_state [env ][var_name ]:
87
- # Oops, accessing it uninitialized. Find out where
88
- # the uninitialized state comes from.
89
- pred_at_fault = None
90
- for pred , pred_state in zip (forward_edge_preds , pred_states ):
91
- if not pred_state [env ][var_name ]:
92
- pred_at_fault = pred
93
- assert pred_at_fault is not None
94
-
95
- # Report the error.
96
- self ._uninitialized_access (insn , pred_at_fault )
104
+ # A closure would capture this variable while it is not always
105
+ # initialized. Note that this check is transitive.
106
+ self ._uninitialized_access (insn , var_name ,
107
+ pred_at_fault (env , var_name ))
97
108
98
109
# Save the state.
99
110
state [block ] = block_state
@@ -103,19 +114,35 @@ def merge_state(a, b):
103
114
for block in func .basic_blocks :
104
115
traverse (block )
105
116
106
- def _uninitialized_access (self , insn , pred_at_fault ):
107
- uninitialized_loc = None
108
- for pred_insn in reversed (pred_at_fault .instructions ):
109
- if pred_insn .loc is not None :
110
- uninitialized_loc = pred_insn .loc .begin ()
111
- break
112
- assert uninitialized_loc is not None
113
-
114
- note = diagnostic .Diagnostic ("note" ,
115
- "variable is not initialized when control flows from this point" , {},
116
- uninitialized_loc )
117
- diag = diagnostic .Diagnostic ("error" ,
118
- "variable '{name}' is not always initialized at this point" ,
119
- {"name" : insn .var_name },
120
- insn .loc , notes = [note ])
117
+ def _uninitialized_access (self , insn , var_name , pred_at_fault ):
118
+ if pred_at_fault is not None :
119
+ uninitialized_loc = None
120
+ for pred_insn in reversed (pred_at_fault .instructions ):
121
+ if pred_insn .loc is not None :
122
+ uninitialized_loc = pred_insn .loc .begin ()
123
+ break
124
+ assert uninitialized_loc is not None
125
+
126
+ note = diagnostic .Diagnostic ("note" ,
127
+ "variable is not initialized when control flows from this point" , {},
128
+ uninitialized_loc )
129
+ else :
130
+ note = None
131
+
132
+ if note is not None :
133
+ notes = [note ]
134
+ else :
135
+ notes = []
136
+
137
+ if isinstance (insn , ir .Closure ):
138
+ diag = diagnostic .Diagnostic ("error" ,
139
+ "variable '{name}' can be captured in a closure uninitialized here" ,
140
+ {"name" : var_name },
141
+ insn .loc , notes = notes )
142
+ else :
143
+ diag = diagnostic .Diagnostic ("error" ,
144
+ "variable '{name}' is not always initialized here" ,
145
+ {"name" : var_name },
146
+ insn .loc , notes = notes )
147
+
121
148
self .engine .process (diag )
0 commit comments