def bad_matches(self, var, other_type, node): """Match a Variable against a type. Return views that don't match. Args: var: A cfg.Variable, containing instances. other_type: An instance of BaseValue. node: A cfg.CFGNode. The position in the CFG from which we "observe" the match. Returns: A list of all the views of var that didn't match. """ bad = [] if (var.data == [self.vm.convert.unsolvable] or other_type == self.vm.convert.unsolvable): # An unsolvable matches everything. Since bad_matches doesn't need to # compute substitutions, we can return immediately. return bad views = abstract_utils.get_views([var], node) skip_future = None while True: try: view = views.send(skip_future) except StopIteration: break if self.match_var_against_type(var, other_type, {}, node, view) is None: if node.HasCombination(list(view.values())): bad.append(view) # To get complete error messages, we need to collect all bad views, so # we can't skip any. skip_future = False else: skip_future = True return bad
def bad_matches(self, var, other_type, node): """Match a Variable against a type. Return views that don't match. Args: var: A cfg.Variable, containing instances. other_type: An instance of AtomicAbstractValue. node: A cfg.CFGNode. The position in the CFG from which we "observe" the match. Returns: A list of all the views of var that didn't match. """ bad = [] views = abstract_utils.get_views([var], node, filter_strict=True) skip_future = None while True: try: view = views.send(skip_future) except StopIteration: break if self.match_var_against_type(var, other_type, {}, node, view) is None: bad.append(view) # To get complete error messages, we need to collect all bad views, so # we can't skip any. skip_future = False else: skip_future = True return bad
def test_basic(self): v1 = self._vm.program.NewVariable( [self._vm.convert.unsolvable], [], self._vm.root_cfg_node) v2 = self._vm.program.NewVariable( [self._vm.convert.int_type, self._vm.convert.str_type], [], self._vm.root_cfg_node) views = list(abstract_utils.get_views([v1, v2], self._vm.root_cfg_node)) six.assertCountEqual(self, [{v1: views[0][v1], v2: views[0][v2]}, {v1: views[1][v1], v2: views[1][v2]}], [{v1: v1.bindings[0], v2: v2.bindings[0]}, {v1: v1.bindings[0], v2: v2.bindings[1]}])
def _check_return(self, node, actual, formal): if not self.options.report_errors: return True views = abstract_utils.get_views([actual], node) # Check for typevars in the return value first, since bad_matches # expects not to get any. bad = [view for view in views if actual in view and view[actual].data.formal] if not bad: bad = self.matcher.bad_matches(actual, formal, node) if bad: self.errorlog.bad_return_type( self.frames, node, formal, actual, bad) return not bad
def _match_all_bindings(self, var, other_type, subst, node, view): """Matches all of var's bindings against other_type.""" new_substs = [] for new_view in abstract_utils.get_views([var], node): # When new_view and view have entries in common, we want to use the # entries from the old view. new_view.update(view) new_subst = self.match_var_against_type( var, other_type, subst, node, new_view) if new_subst is not None: new_substs.append(new_subst) if new_substs: return self._merge_substs(subst, new_substs) else: return None
def _check_return(self, node, actual, formal): if not self.options.report_errors: return True views = abstract_utils.get_views([actual], node) # Check for typevars in the return value first, since bad_matches # expects not to get any. bad = [view for view in views if actual in view and view[actual].data.formal] if not bad: bad = self.matcher.bad_matches(actual, formal, node) if bad: with self.convert.pytd_convert.produce_detailed_output(): combined = pytd_utils.JoinTypes( view[actual].data.to_type(node, view=view) for view in bad) self.errorlog.bad_return_type( self.frames, combined, formal.get_instance_type(node)) return not bad
def _instantiate_and_match(self, left, other_type, subst, node, view, container=None): """Instantiate and match an abstract value.""" instance = left.instantiate(node, container=container) new_substs = [] for new_view in abstract_utils.get_views([instance], node): # When new_view and view have entries in common, we want to use the # entries from the old view. new_view.update(view) new_subst = self.match_var_against_type( instance, other_type, subst, node, new_view) if new_subst is not None: new_substs.append(new_subst) if new_substs: return self._merge_substs(subst, new_substs) else: return None
def _test_optimized(self, skip_future_value, expected_num_views): v1 = self._vm.program.NewVariable([self._vm.convert.unsolvable], [], self._vm.root_cfg_node) v2 = self._vm.program.NewVariable( [self._vm.convert.int_type, self._vm.convert.str_type], [], self._vm.root_cfg_node) views = abstract_utils.get_views([v1, v2], self._vm.root_cfg_node) skip_future = None # To count the number of views. Doesn't matter what we put in here, as long # as it's one per view. view_markers = [] while True: try: view = views.send(skip_future) except StopIteration: break # Accesses v1 only, so the v2 bindings should be deduplicated when # `skip_future` is True. view_markers.append(view[v1]) skip_future = skip_future_value self.assertEqual(len(view_markers), expected_num_views)
def _match_var(self, left, right): var = self.vm.program.NewVariable() var.AddBinding(left, [], self.vm.root_cfg_node) for view in abstract_utils.get_views([var], self.vm.root_cfg_node): yield self.vm.matcher.match_var_against_type( var, right, {}, self.vm.root_cfg_node, view)