def visit_If(self, node): self.check_type(node.test, Bool()) test_value = static_evaluate(node.test, self.context()) if not isinstance(test_value, UnknownValue): self.warn('constant-if-condition', node) ext_ctx = self.context() if_inferences, else_inferences = maybe_inferences(node.test, ext_ctx) # don't visit unreachable code if test_value is True: self._visit_branch(node.body, if_inferences) return if test_value is False: self._visit_branch(node.orelse, else_inferences) return if_scope = self._visit_branch(node.body, if_inferences) else_scope = self._visit_branch(node.orelse, else_inferences) diffs = set(if_scope.names()) ^ set(else_scope.names()) for diff in diffs: if diff not in self._context: self.warn('conditionally-assigned', node, diff) common = set(if_scope.names()) & set(else_scope.names()) for name in common: types = [if_scope.get_type(name), else_scope.get_type(name)] unified_type = unify_types(types) self._context.add(Symbol(name, unified_type)) if isinstance(unified_type, Unknown): if not any(isinstance(x, Unknown) for x in types): self.warn('conditional-type', node, name)
def _check_return(self, return_type, static_value=None): previous_type = self._context.get_type() new_type = (unify_types([previous_type, return_type]) if previous_type is not None else return_type) value = (static_value or UnknownValue() if previous_type is None else UnknownValue()) self._context.set_return(Symbol('return', new_type, value))