def visit_DictComp(self, node): new_bindings = {} no_dict = False for generator in node.generators: test_types = set() for if_ in generator.ifs: test_types.update(self.visit(if_)) test_types = normalize_test_ty(test_types) if test_types == {Cst[False]}: no_dict = True iter_types = self.visit(generator.iter) if isinstance(generator.target, ast.Name): iter_value_ty = self._iterator_value_ty(iter_types) new_bindings[generator.target.id] = iter_value_ty self.bindings.append(new_bindings) key_types = self.visit(node.key) value_types = self.visit(node.value) self.bindings.pop() if no_dict: return {Dict[set(), set()]} else: return { Dict[{astype(k) for k in key_types}, {astype(v) for v in value_types}] }
def __call__(self, left_ty, right_ty): if issubclass(left_ty, Cst): if issubclass(right_ty, Cst): return Cst[left_ty.__args__[0] is not right_ty.__args__[0]] elif astype(left_ty) == right_ty: return bool else: return Cst[True] else: left_ty = astype(left_ty) right_ty = astype(right_ty) if left_ty == right_ty: return bool else: return Cst[True]
def _handle_is(self, prev, prev_ty, comparator, comparator_ty): def filtering(val, id_, new_type): assert not isinstance(new_type, tuple) return FilteringBool[val, id_, (new_type, )] cmp_ty = set() for pty, cty in itertools.product(prev_ty, comparator_ty): rem_pty = tuple(prev_ty - {pty}) rem_cty = tuple(comparator_ty - {cty}) if pty is cty: # special handling for singleton types if issubclass(pty, (Cst, Module, Type)): tmp_ty = set() if rem_pty and isinstance(prev, ast.Name): tmp_ty.add(filtering(True, prev.id, pty)) if rem_cty and isinstance(comparator, ast.Name): tmp_ty.add(filtering(True, comparator.id, cty)) if tmp_ty: cmp_ty.update(tmp_ty) else: cmp_ty.add(Cst[True]) else: cmp_ty.add(bool) elif astype(pty) is astype(cty): if all( issubclass(ty, (Cst, Module, Type)) for ty in (cty, pty)): cmp_ty.add(Cst[False]) else: cmp_ty.add(bool) else: tmp_ty = set() if rem_pty and isinstance(prev, ast.Name): tmp_ty.add(filtering(False, prev.id, pty)) if rem_cty and isinstance(comparator, ast.Name): tmp_ty.add(filtering(False, comparator.id, cty)) if tmp_ty: cmp_ty.update(tmp_ty) else: tmp_ty = self._call(Ops[ast.Is], prev_ty, comparator_ty) cmp_ty.update(tmp_ty) return cmp_ty
def __call__(self, left_ty, right_ty): if issubclass(left_ty, TypeOf): if issubclass(right_ty, (Cst, Type)): return FilteringBool[(left_ty.__args__[0] is right_ty.__args__[0]), left_ty.__args__[1], (left_ty.__args__[0],)] elif astype(left_ty) == right_ty: return bool else: return Cst[False] if issubclass(left_ty, (Cst, Type)): if issubclass(right_ty, (Cst, Type)): return Cst[left_ty.__args__[0] is right_ty.__args__[0]] elif astype(left_ty) == right_ty: return bool else: return Cst[False] else: left_ty = astype(left_ty) right_ty = astype(right_ty) if left_ty == right_ty: return bool else: return Cst[False]
def _handle_comp(self, node, container_ty): new_bindings = {} no_element = False for generator in node.generators: test_types = set() for if_ in generator.ifs: test_types.update(self.visit(if_)) test_types = normalize_test_ty(test_types) if test_types == {Cst[False]}: no_element = True iter_types = self.visit(generator.iter) if isinstance(generator.target, ast.Name): iter_value_ty = self._iterator_value_ty(iter_types) new_bindings[generator.target.id] = iter_value_ty self.bindings.append(new_bindings) elt_types = self.visit(node.elt) self.bindings.pop() if no_element: return {container_ty[set()]} else: return {container_ty[{astype(elt_ty) for elt_ty in elt_types}]}
def visit_Loop(self, node): loop_bindings = {} self.bindings.append(loop_bindings) for stmt in node.body: prev = self.visit(stmt) if not prev: break if all(isinstance(p, (ast.Break, ast.Continue)) for p in prev): break reloop_bindings = {} if not all(isinstance(p, ast.Break) for p in prev): self.bindings.append(reloop_bindings) for stmt in node.body: prev = self.visit(stmt) if not prev: break if all(isinstance(p, (ast.Break, ast.Continue)) for p in prev): break self.bindings.pop() self.bindings.pop() for k, v in loop_bindings.items(): if k not in self.bindings[-1]: self.bindings[-1][k] = v else: self.bindings[-1][k].update(v) for k, v in reloop_bindings.items(): if k not in self.bindings[-1]: self.bindings[-1][k] = v elif not self.bindings[-1][k].issuperset(v): # get rid of constants that grows along the loop self.bindings[-1][k] = { astype(ty) for ty in self.bindings[-1][k] } if not prev: return () if all(not isinstance(p, ast.Break) for p in prev): for stmt in node.orelse: prev = self.visit(stmt) if not prev: break elif any(not isinstance(p, ast.Break) for p in prev): orelse_bindings = {} self.bindings.append(orelse_bindings) for stmt in node.orelse: prev = self.visit(stmt) if not prev: break self.bindings.pop() for k, v in orelse_bindings.items(): if k in self.bindings[-1]: self.bindings[-1][k].update(v) else: self.bindings[-1][k] = v return prev