1"""Utilities for abstract.py.""" 2 3import collections 4import hashlib 5import logging 6from typing import Any, Collection, Dict, Iterable, Mapping, Optional, Sequence, Tuple, Union 7 8from pytype import datatypes 9from pytype import utils 10from pytype.pyc import opcodes 11from pytype.pyc import pyc 12from pytype.pytd import mro 13from pytype.typegraph import cfg 14from pytype.typegraph import cfg_utils 15 16log = logging.getLogger(__name__) 17 18# We can't import abstract here due to a circular dep. 19_BaseValue = Any # abstract.BaseValue 20_TypeParameter = Any # abstract.TypeParameter 21 22# Type parameter names matching the ones in builtins.pytd and typing.pytd. 23T = "_T" 24T2 = "_T2" 25K = "_K" 26V = "_V" 27ARGS = "_ARGS" 28RET = "_RET" 29 30# TODO(rechen): Stop supporting all variants except _HAS_DYNAMIC_ATTRIBUTES. 31DYNAMIC_ATTRIBUTE_MARKERS = [ 32 "HAS_DYNAMIC_ATTRIBUTES", 33 "_HAS_DYNAMIC_ATTRIBUTES", 34 "has_dynamic_attributes", 35] 36 37# A dummy container object for use in instantiating type parameters. 38# A container is needed to preserve type parameter names for error messages 39# and for sub_(one_)annotation(s). 40DUMMY_CONTAINER = object() 41 42# Names defined on every module/class that should be ignored in most cases. 43TOP_LEVEL_IGNORE = frozenset({ 44 "__builtins__", 45 "__doc__", 46 "__file__", 47 "__future__", 48 "__module__", 49 "__name__", 50 "__annotations__", 51 "google_type_annotations", 52}) 53CLASS_LEVEL_IGNORE = frozenset({ 54 "__builtins__", 55 "__class__", 56 "__module__", 57 "__name__", 58 "__qualname__", 59 "__slots__", 60 "__annotations__", 61}) 62 63 64class ConversionError(ValueError): 65 pass 66 67 68class EvaluationError(Exception): 69 """Used to signal an errorlog error during type name evaluation.""" 70 71 @property 72 def errors(self): 73 return utils.message(self) 74 75 @property 76 def details(self): 77 return "\n".join(error.message for error in self.errors) 78 79 80class GenericTypeError(Exception): 81 """The error for user-defined generic types.""" 82 83 def __init__(self, annot, error): 84 super().__init__(annot, error) 85 self.annot = annot 86 self.error = error 87 88 89class AsInstance: 90 """Wrapper, used for marking things that we want to convert to an instance.""" 91 92 def __init__(self, cls): 93 self.cls = cls 94 95 96class AsReturnValue(AsInstance): 97 """Specially mark return values, to handle NoReturn properly.""" 98 99 100# For lazy evaluation of ParameterizedClass.formal_type_parameters 101LazyFormalTypeParameters = collections.namedtuple( 102 "LazyFormalTypeParameters", ("template", "parameters", "subst")) 103 104 105# Sentinel for get_atomic_value 106class _None: 107 pass 108 109 110def get_atomic_value(variable, constant_type=None, default=_None()): 111 """Get the atomic value stored in this variable.""" 112 if len(variable.bindings) == 1: 113 v, = variable.bindings 114 if isinstance(v.data, constant_type or object): 115 return v.data # success 116 if not isinstance(default, _None): 117 # If a default is specified, we return it instead of failing. 118 return default 119 # Determine an appropriate failure message. 120 if not variable.bindings: 121 raise ConversionError("Cannot get atomic value from empty variable.") 122 bindings = variable.bindings 123 name = bindings[0].data.vm.convert.constant_name(constant_type) 124 raise ConversionError( 125 "Cannot get atomic value %s from variable. %s %s" 126 % (name, variable, [b.data for b in bindings])) 127 128 129def get_atomic_python_constant(variable, constant_type=None): 130 """Get the concrete atomic Python value stored in this variable. 131 132 This is used for things that are stored in cfg.Variable, but we 133 need the actual data in order to proceed. E.g. function / class definitions. 134 135 Args: 136 variable: A cfg.Variable. It can only have one possible value. 137 constant_type: Optionally, the required type of the constant. 138 Returns: 139 A Python constant. (Typically, a string, a tuple, or a code object.) 140 Raises: 141 ConversionError: If the value in this Variable is purely abstract, i.e. 142 doesn't store a Python value, or if it has more than one possible value. 143 """ 144 atomic = get_atomic_value(variable) 145 return atomic.vm.convert.value_to_constant(atomic, constant_type) 146 147 148def get_views(variables, node): 149 """Get all possible views of the given variables at a particular node. 150 151 For performance reasons, this method uses node.CanHaveCombination for 152 filtering. For a more precise check, you can call 153 node.HasCombination(list(view.values())). Do so judiciously, as the latter 154 method can be very slow. 155 156 This function can be used either as a regular generator or in an optimized way 157 to yield only functionally unique views: 158 views = get_views(...) 159 skip_future = None 160 while True: 161 try: 162 view = views.send(skip_future) 163 except StopIteration: 164 break 165 ... 166 The caller should set `skip_future` to True when it is safe to skip 167 equivalent future views and False otherwise. 168 169 Args: 170 variables: The variables. 171 node: The node. 172 173 Yields: 174 A datatypes.AcessTrackingDict mapping variables to bindings. 175 """ 176 try: 177 combinations = cfg_utils.deep_variable_product(variables) 178 except cfg_utils.TooComplexError: 179 combinations = ((var.AddBinding(node.program.default_data, [], node) 180 for var in variables),) 181 seen = [] # the accessed subsets of previously seen views 182 for combination in combinations: 183 view = {value.variable: value for value in combination} 184 if any(subset <= view.items() for subset in seen): 185 # Optimization: This view can be skipped because it matches the accessed 186 # subset of a previous one. 187 log.info("Skipping view (already seen): %r", view) 188 continue 189 combination = list(view.values()) 190 if not node.CanHaveCombination(combination): 191 log.info("Skipping combination (unreachable): %r", combination) 192 continue 193 view = datatypes.AccessTrackingDict(view) 194 skip_future = yield view 195 if skip_future: 196 # Skip future views matching this accessed subset. 197 seen.append(view.accessed_subset.items()) 198 199 200def get_signatures(func): 201 """Gets the given function's signatures.""" 202 if func.isinstance_PyTDFunction(): 203 return [sig.signature for sig in func.signatures] 204 elif func.isinstance_InterpreterFunction(): 205 return [f.signature for f in func.signature_functions()] 206 elif func.isinstance_BoundFunction(): 207 sigs = get_signatures(func.underlying) 208 return [sig.drop_first_parameter() for sig in sigs] # drop "self" 209 elif func.isinstance_ClassMethod() or func.isinstance_StaticMethod(): 210 return get_signatures(func.method) 211 elif func.isinstance_SimpleFunction(): 212 return [func.signature] 213 else: 214 raise NotImplementedError(func.__class__.__name__) 215 216 217def func_name_is_class_init(name): 218 """Return True if |name| is that of a class' __init__ method.""" 219 # Python 3's MAKE_FUNCTION byte code takes an explicit fully qualified 220 # function name as an argument and that is used for the function name. 221 # On the other hand, Python 2's MAKE_FUNCTION does not take any name 222 # argument so we pick the name from the code object. This name is not 223 # fully qualified. Hence, constructor names in Python 3 are fully 224 # qualified ending in '.__init__', and constructor names in Python 2 225 # are all '__init__'. So, we identify a constructor by matching its 226 # name with one of these patterns. 227 return name == "__init__" or name.endswith(".__init__") 228 229 230def equivalent_to(binding, cls): 231 """Whether binding.data is equivalent to cls, modulo parameterization.""" 232 return (binding.data.isinstance_Class() and 233 binding.data.full_name == cls.full_name) 234 235 236def apply_mutations(node, get_mutations): 237 """Apply mutations yielded from a get_mutations function.""" 238 log.info("Applying mutations") 239 num_mutations = 0 240 for obj, name, value in get_mutations(): 241 if not num_mutations: 242 # mutations warrant creating a new CFG node 243 node = node.ConnectNew(node.name) 244 num_mutations += 1 245 obj.merge_instance_type_parameter(node, name, value) 246 log.info("Applied %d mutations", num_mutations) 247 return node 248 249 250def get_template(val): 251 """Get the value's class template.""" 252 if val.isinstance_Class(): 253 res = {t.full_name for t in val.template} 254 if val.isinstance_ParameterizedClass(): 255 res.update(get_template(val.base_cls)) 256 elif val.isinstance_PyTDClass() or val.isinstance_InterpreterClass(): 257 for base in val.bases(): 258 base = get_atomic_value(base, default=val.vm.convert.unsolvable) 259 res.update(get_template(base)) 260 return res 261 elif val.cls: 262 return get_template(val.cls) 263 else: 264 return set() 265 266 267def get_mro_bases(bases, vm): 268 """Get bases for MRO computation.""" 269 mro_bases = [] 270 has_user_generic = False 271 for base_var in bases: 272 if not base_var.data: 273 continue 274 # A base class is a Variable. If it has multiple options, we would 275 # technically get different MROs. But since ambiguous base classes are rare 276 # enough, we instead just pick one arbitrary option per base class. 277 base = get_atomic_value(base_var, default=vm.convert.unsolvable) 278 mro_bases.append(base) 279 # check if it contains user-defined generic types 280 if (base.isinstance_ParameterizedClass() and 281 base.full_name != "typing.Generic"): 282 has_user_generic = True 283 # if user-defined generic type exists, we won't add `typing.Generic` to 284 # the final result list 285 if has_user_generic: 286 return [b for b in mro_bases if b.full_name != "typing.Generic"] 287 else: 288 return mro_bases 289 290 291def _merge_type(t0, t1, name, cls): 292 """Merge two types. 293 294 Rules: Type `Any` can match any type, we will return the other type if one 295 of them is `Any`. Return the sub-class if the types have inheritance 296 relationship. 297 298 Args: 299 t0: The first type. 300 t1: The second type. 301 name: Type parameter name. 302 cls: The class_mixin.Class on which any error should be reported. 303 Returns: 304 A type. 305 Raises: 306 GenericTypeError: if the types don't match. 307 """ 308 if t0 is None or t0.isinstance_Unsolvable(): 309 return t1 310 if t1 is None or t1.isinstance_Unsolvable(): 311 return t0 312 # t0 is parent of t1 313 if t0 in t1.mro: 314 return t1 315 # t1 is parent of t0 316 if t1 in t0.mro: 317 return t0 318 raise GenericTypeError(cls, "Conflicting value for TypeVar %s" % name) 319 320 321def parse_formal_type_parameters( 322 base, prefix, formal_type_parameters, container=None): 323 """Parse type parameters from base class. 324 325 Args: 326 base: base class. 327 prefix: the full name of subclass of base class. 328 formal_type_parameters: the mapping of type parameter name to its type. 329 container: An abstract value whose class template is used when prefix=None 330 to decide how to handle type parameters that are aliased to other type 331 parameters. Values that are in the class template are kept, while all 332 others are ignored. 333 334 Raises: 335 GenericTypeError: If the lazy types of type parameter don't match 336 """ 337 def merge(t0, t1, name): 338 return _merge_type(t0, t1, name, base) 339 340 if base.isinstance_ParameterizedClass(): 341 if base.full_name == "typing.Generic": 342 return 343 if (base.base_cls.isinstance_InterpreterClass() or 344 base.base_cls.isinstance_PyTDClass()): 345 # merge the type parameters info from base class 346 formal_type_parameters.merge_from( 347 base.base_cls.all_formal_type_parameters, merge) 348 params = base.get_formal_type_parameters() 349 if getattr(container, "cls", None): 350 container_template = container.cls.template 351 else: 352 container_template = () 353 for name, param in params.items(): 354 if param.isinstance_TypeParameter(): 355 # We have type parameter renaming, e.g., 356 # class List(Generic[T]): pass 357 # class Foo(List[U]): pass 358 if prefix: 359 formal_type_parameters.add_alias( 360 name, prefix + "." + param.name, merge) 361 elif param in container_template: 362 formal_type_parameters[name] = param 363 else: 364 # We have either a non-formal parameter, e.g., 365 # class Foo(List[int]), or a non-1:1 parameter mapping, e.g., 366 # class Foo(List[K or V]). Initialize the corresponding instance 367 # parameter appropriately. 368 if name not in formal_type_parameters: 369 formal_type_parameters[name] = param 370 else: 371 # Two unrelated containers happen to use the same type 372 # parameter but with different types. 373 last_type = formal_type_parameters[name] 374 formal_type_parameters[name] = merge(last_type, param, name) 375 else: 376 if base.isinstance_InterpreterClass() or base.isinstance_PyTDClass(): 377 # merge the type parameters info from base class 378 formal_type_parameters.merge_from( 379 base.all_formal_type_parameters, merge) 380 if base.template: 381 # handle unbound type parameters 382 for item in base.template: 383 if item.isinstance_TypeParameter(): 384 # This type parameter will be set as `ANY`. 385 name = full_type_name(base, item.name) 386 if name not in formal_type_parameters: 387 formal_type_parameters[name] = None 388 389 390def full_type_name(val, name): 391 """Compute complete type parameter name with scope. 392 393 Args: 394 val: The object with type parameters. 395 name: The short type parameter name (e.g., T). 396 397 Returns: 398 The full type parameter name (e.g., List.T). 399 """ 400 if val.isinstance_Instance(): 401 return full_type_name(val.cls, name) 402 # The type is in current `class` 403 for t in val.template: 404 if t.name == name: 405 return val.full_name + "." + name 406 elif t.full_name == name: 407 return t.full_name 408 # The type is instantiated in `base class` 409 for t in val.all_template_names: 410 if t.split(".")[-1] == name or t == name: 411 return t 412 return name 413 414 415def maybe_extract_tuple(t): 416 """Returns a tuple of Variables.""" 417 values = t.data 418 if len(values) > 1: 419 return (t,) 420 v, = values 421 if not v.isinstance_Tuple(): 422 return (t,) 423 return v.pyval 424 425 426def compute_template(val): 427 """Compute the precedence list of template parameters according to C3. 428 429 1. For the base class list, if it contains `typing.Generic`, then all the 430 type parameters should be provided. That means we don't need to parse extra 431 base class and then we can get all the type parameters. 432 2. If there is no `typing.Generic`, parse the precedence list according to 433 C3 based on all the base classes. 434 3. If `typing.Generic` exists, it must contain at least one type parameters. 435 And there is at most one `typing.Generic` in the base classes. Report error 436 if the check fails. 437 438 Args: 439 val: The abstract.BaseValue to compute a template for. 440 441 Returns: 442 parsed type parameters 443 444 Raises: 445 GenericTypeError: if the type annotation for generic type is incorrect 446 """ 447 if val.isinstance_PyTDClass(): 448 return [val.vm.convert.constant_to_value(itm.type_param) 449 for itm in val.pytd_cls.template] 450 elif not val.isinstance_InterpreterClass(): 451 return () 452 bases = [get_atomic_value(base, default=val.vm.convert.unsolvable) 453 for base in val.bases()] 454 template = [] 455 456 # Compute the number of `typing.Generic` and collect the type parameters 457 for base in bases: 458 if base.full_name == "typing.Generic": 459 if base.isinstance_PyTDClass(): 460 raise GenericTypeError(val, "Cannot inherit from plain Generic") 461 if template: 462 raise GenericTypeError( 463 val, "Cannot inherit from Generic[...] multiple times") 464 for item in base.template: 465 param = base.formal_type_parameters.get(item.name) 466 template.append(param.with_module(val.full_name)) 467 468 if template: 469 # All type parameters in the base classes should appear in 470 # `typing.Generic` 471 for base in bases: 472 if base.full_name != "typing.Generic": 473 if base.isinstance_ParameterizedClass(): 474 for item in base.template: 475 param = base.formal_type_parameters.get(item.name) 476 if param.isinstance_TypeParameter(): 477 t = param.with_module(val.full_name) 478 if t not in template: 479 raise GenericTypeError( 480 val, "Generic should contain all the type variables") 481 else: 482 # Compute template parameters according to C3 483 seqs = [] 484 for base in bases: 485 if base.isinstance_ParameterizedClass(): 486 seq = [] 487 for item in base.template: 488 param = base.formal_type_parameters.get(item.name) 489 if param.isinstance_TypeParameter(): 490 seq.append(param.with_module(val.full_name)) 491 seqs.append(seq) 492 try: 493 template.extend(mro.MergeSequences(seqs)) 494 except ValueError as e: 495 raise GenericTypeError( 496 val, "Illegal type parameter order in class %s" % val.name) from e 497 498 return template 499 500 501def _hash_dict(vardict, names): 502 """Hash a dictionary. 503 504 This contains the keys and the full hashes of the data in the values. 505 506 Arguments: 507 vardict: A dictionary mapping str to Variable. 508 names: If this is non-None, the snapshot will include only those 509 dictionary entries whose keys appear in names. 510 511 Returns: 512 A hash of the dictionary. 513 """ 514 if names is not None: 515 vardict = {name: vardict[name] for name in names.intersection(vardict)} 516 m = hashlib.md5() 517 for name, var in sorted(vardict.items()): 518 m.update(str(name).encode("utf-8")) 519 for value in var.bindings: 520 m.update(value.data.get_fullhash()) 521 return m.digest() 522 523 524def hash_all_dicts(*hash_args): 525 """Convenience method for hashing a sequence of dicts.""" 526 return hashlib.md5(b"".join(_hash_dict(*args) for args in hash_args)).digest() 527 528 529def _matches_generator(type_obj, allowed_types): 530 """Check if type_obj matches a Generator/AsyncGenerator type.""" 531 if type_obj.isinstance_Union(): 532 return all(_matches_generator(sub_type, allowed_types) 533 for sub_type in type_obj.options) 534 else: 535 base_cls = type_obj 536 if type_obj.isinstance_ParameterizedClass(): 537 base_cls = type_obj.base_cls 538 return ((base_cls.isinstance_PyTDClass() and 539 base_cls.name in allowed_types) or 540 base_cls.isinstance_AMBIGUOUS_OR_EMPTY()) 541 542 543def matches_generator(type_obj): 544 allowed_types = ("generator", "Iterable", "Iterator") 545 return _matches_generator(type_obj, allowed_types) 546 547 548def matches_async_generator(type_obj): 549 allowed_types = ("asyncgenerator", "AsyncIterable", "AsyncIterator") 550 return _matches_generator(type_obj, allowed_types) 551 552 553def var_map(func, var): 554 return (func(v) for v in var.data) 555 556 557def eval_expr(vm, node, f_globals, f_locals, expr): 558 """Evaluate an expression with the given node and globals.""" 559 # This is used to resolve type comments and late annotations. 560 # 561 # We don't chain node and f_globals as we want to remain in the context 562 # where we've just finished evaluating the module. This would prevent 563 # nasty things like: 564 # 565 # def f(a: "A = 1"): 566 # pass 567 # 568 # def g(b: "A"): 569 # pass 570 # 571 # Which should simply complain at both annotations that 'A' is not defined 572 # in both function annotations. Chaining would cause 'b' in 'g' to yield a 573 # different error message. 574 log.info("Evaluating expr: %r", expr) 575 576 # Any errors logged here will have a filename of None and a linenumber of 1 577 # when what we really want is to allow the caller to handle/log the error 578 # themselves. Thus we checkpoint the errorlog and then restore and raise 579 # an exception if anything was logged. 580 with vm.errorlog.checkpoint() as record: 581 try: 582 code = vm.compile_src(expr, mode="eval") 583 except pyc.CompileError as e: 584 # We keep only the error message, since the filename and line number are 585 # for a temporary file. 586 vm.errorlog.python_compiler_error(None, 0, e.error) 587 ret = vm.new_unsolvable(node) 588 else: 589 _, _, _, ret = vm.run_bytecode(node, code, f_globals, f_locals) 590 log.info("Finished evaluating expr: %r", expr) 591 if record.errors: 592 # Annotations are constants, so tracebacks aren't needed. 593 e = EvaluationError([error.drop_traceback() for error in record.errors]) 594 else: 595 e = None 596 return ret, e 597 598 599def check_classes(var, check): 600 """Check whether the cls of each value in `var` is a class and passes `check`. 601 602 Args: 603 var: A cfg.Variable or empty. 604 check: (BaseValue) -> bool. 605 606 Returns: 607 Whether the check passes. 608 """ 609 return var and all( 610 v.cls.isinstance_Class() and check(v.cls) for v in var.data if v.cls) 611 612 613def match_type_container(typ, container_type_name: Union[str, Tuple[str, ...]]): 614 """Unpack the type parameter from ContainerType[T].""" 615 if typ is None: 616 return None 617 if isinstance(container_type_name, str): 618 container_type_name = (container_type_name,) 619 if not (typ.isinstance_ParameterizedClass() and 620 typ.full_name in container_type_name): 621 return None 622 param = typ.get_formal_type_parameter(T) 623 return param 624 625 626def get_annotations_dict(members): 627 """Get __annotations__ from a members map. 628 629 Returns None rather than {} if the dict does not exist so that callers always 630 have a reference to the actual dictionary, and can mutate it if needed. 631 632 Args: 633 members: A dict of member name to variable 634 635 Returns: 636 members['__annotations__'] unpacked as a python dict, or None 637 """ 638 if "__annotations__" not in members: 639 return None 640 annots_var = members["__annotations__"] 641 try: 642 annots = get_atomic_value(annots_var) 643 except ConversionError: 644 return None 645 return annots if annots.isinstance_AnnotationsDict() else None 646 647 648class Local: 649 """A possibly annotated local variable.""" 650 651 def __init__( 652 self, 653 node, 654 op: Optional[opcodes.Opcode], 655 typ: Optional[_BaseValue], 656 orig: Optional[cfg.Variable], 657 vm): 658 self._ops = [op] 659 if typ: 660 self.typ = vm.program.NewVariable([typ], [], node) 661 else: 662 # Creating too many variables bloats the typegraph, hurting performance, 663 # so we use None instead of an empty variable. 664 self.typ = None 665 self.orig = orig 666 self.vm = vm 667 668 @property 669 def stack(self): 670 return self.vm.simple_stack(self._ops[-1]) 671 672 def update(self, node, op, typ, orig): 673 """Update this variable's annotation and/or value.""" 674 if op in self._ops: 675 return 676 self._ops.append(op) 677 if typ: 678 if self.typ: 679 self.typ.AddBinding(typ, [], node) 680 else: 681 self.typ = self.vm.program.NewVariable([typ], [], node) 682 if orig: 683 self.orig = orig 684 685 def get_type(self, node, name): 686 """Gets the variable's annotation.""" 687 if not self.typ: 688 return None 689 values = self.typ.Data(node) 690 if len(values) > 1: 691 self.vm.errorlog.ambiguous_annotation(self.stack, values, name) 692 return self.vm.convert.unsolvable 693 elif values: 694 return values[0] 695 else: 696 return None 697 698 699def is_literal(annot: Optional[_BaseValue]): 700 if not annot: 701 return False 702 if annot.isinstance_Union(): 703 return all(is_literal(o) for o in annot.options) 704 return annot.isinstance_LiteralClass() 705 706 707def is_concrete_dict(val: _BaseValue): 708 return val.isinstance_Dict() and not val.could_contain_anything 709 710 711def is_concrete_list(val: _BaseValue): 712 return val.isinstance_List() and not val.could_contain_anything 713 714 715def is_concrete(val: _BaseValue): 716 return (val.isinstance_PythonConstant() and 717 not getattr(val, "could_contain_anything", False)) 718 719 720def is_indefinite_iterable(val: _BaseValue): 721 """True if val is a non-concrete instance of typing.Iterable.""" 722 instance = val.isinstance_Instance() 723 concrete = is_concrete(val) 724 cls_instance = val.cls and val.cls.isinstance_Class() 725 if not (instance and cls_instance and not concrete): 726 return False 727 for cls in val.cls.mro: 728 if cls.full_name == "builtins.str": 729 return False 730 elif cls.full_name == "builtins.tuple": 731 # A tuple's cls attribute may point to either PyTDClass(tuple) or 732 # TupleClass; only the former is indefinite. 733 return cls.isinstance_PyTDClass() 734 elif cls.full_name == "typing.Iterable": 735 return True 736 return False 737 738 739def is_var_indefinite_iterable(var): 740 """True if all bindings of var are indefinite sequences.""" 741 return all(is_indefinite_iterable(x) for x in var.data) 742 743 744def merged_type_parameter(node, var, param): 745 if not var.bindings: 746 return node.program.NewVariable() 747 if is_var_splat(var): 748 var = unwrap_splat(var) 749 params = [v.get_instance_type_parameter(param) for v in var.data] 750 return var.data[0].vm.join_variables(node, params) 751 752 753def is_var_splat(var): 754 if var.data and var.data[0].isinstance_Splat(): 755 # A splat should never have more than one binding, since we create and use 756 # it immediately. 757 assert len(var.bindings) == 1 758 return True 759 return False 760 761 762def unwrap_splat(var): 763 return var.data[0].iterable 764 765 766def is_callable(value: _BaseValue): 767 """Returns whether 'value' is a callable.""" 768 if (value.isinstance_Function() or 769 value.isinstance_BoundFunction() or 770 value.isinstance_ClassMethod() or 771 value.isinstance_ClassMethodInstance() or 772 value.isinstance_StaticMethod() or 773 value.isinstance_StaticMethodInstance()): 774 return True 775 if not value.cls or not value.cls.isinstance_Class(): 776 return False 777 _, attr = value.vm.attribute_handler.get_attribute( 778 value.vm.root_node, value.cls, "__call__") 779 return attr is not None 780 781 782def expand_type_parameter_instances(bindings: Iterable[cfg.Binding]): 783 bindings = list(bindings) 784 while bindings: 785 b = bindings.pop(0) 786 if b.data.isinstance_TypeParameterInstance(): 787 param_value = b.data.instance.get_instance_type_parameter(b.data.name) 788 if param_value.bindings: 789 bindings = param_value.bindings + bindings 790 continue 791 yield b 792 793 794def get_type_parameter_substitutions( 795 val: _BaseValue, type_params: Iterable[_TypeParameter] 796) -> Mapping[str, cfg.Variable]: 797 """Get values for type_params from val's type parameters.""" 798 subst = {} 799 for p in type_params: 800 if val.isinstance_Class(): 801 param_value = val.get_formal_type_parameter(p.name).instantiate( 802 val.vm.root_node) 803 else: 804 param_value = val.get_instance_type_parameter(p.name) 805 subst[p.full_name] = param_value 806 return subst 807 808 809def build_generic_template( 810 type_params: Sequence[_BaseValue], base_type: _BaseValue 811) -> Tuple[Sequence[str], Sequence[_TypeParameter]]: 812 """Build a typing.Generic template from a sequence of type parameters.""" 813 if not all(item.isinstance_TypeParameter() for item in type_params): 814 base_type.vm.errorlog.invalid_annotation( 815 base_type.vm.frames, base_type, 816 "Parameters to Generic[...] must all be type variables") 817 type_params = [item for item in type_params 818 if item.isinstance_TypeParameter()] 819 820 template = [item.name for item in type_params] 821 822 if len(set(template)) != len(template): 823 base_type.vm.errorlog.invalid_annotation( 824 base_type.vm.frames, base_type, 825 "Parameters to Generic[...] must all be unique") 826 827 return template, type_params 828 829 830def is_generic_protocol(val: _BaseValue) -> bool: 831 return (val.isinstance_ParameterizedClass() and 832 val.full_name == "typing.Protocol") 833 834 835def combine_substs( 836 substs1: Optional[Collection[Dict[str, cfg.Variable]]], 837 substs2: Optional[Collection[Dict[str, cfg.Variable]]] 838) -> Collection[Dict[str, cfg.Variable]]: 839 """Combines the two collections of type parameter substitutions.""" 840 if substs1 and substs2: 841 return tuple({**sub1, **sub2} for sub1 in substs1 for sub2 in substs2) # pylint: disable=g-complex-comprehension 842 elif substs1: 843 return substs1 844 elif substs2: 845 return substs2 846 else: 847 return () 848 849 850def _flatten(value, classes): 851 """Flatten the contents of value into classes. 852 853 If value is a Class, it is appended to classes. 854 If value is a PythonConstant of type tuple, then each element of the tuple 855 that has a single binding is also flattened. 856 Any other type of value, or tuple elements that have multiple bindings are 857 ignored. 858 859 Args: 860 value: An abstract value. 861 classes: A list to be modified. 862 863 Returns: 864 True iff a value was ignored during flattening. 865 """ 866 # Used by special_builtins.IsInstance and IsSubclass 867 if value.isinstance_AnnotationClass(): 868 value = value.base_cls 869 if value.isinstance_Class(): 870 # A single class, no ambiguity. 871 classes.append(value) 872 return False 873 elif value.isinstance_Tuple(): 874 # A tuple, need to process each element. 875 ambiguous = False 876 for var in value.pyval: 877 if (len(var.bindings) != 1 or 878 _flatten(var.bindings[0].data, classes)): 879 # There were either multiple bindings or ambiguity deeper in the 880 # recursion. 881 ambiguous = True 882 return ambiguous 883 else: 884 return True 885 886 887def check_against_mro(vm, target, class_spec): 888 """Check if any of the classes are in the target's MRO. 889 890 Args: 891 vm: The virtual machine. 892 target: A BaseValue whose MRO will be checked. 893 class_spec: A Class or PythonConstant tuple of classes (i.e. the second 894 argument to isinstance or issubclass). 895 896 Returns: 897 True if any class in classes is found in the target's MRO, 898 False if no match is found and None if it's ambiguous. 899 """ 900 # Determine the flattened list of classes to check. 901 classes = [] 902 ambiguous = _flatten(class_spec, classes) 903 904 for c in classes: 905 if vm.matcher(None).match_from_mro(target, c, allow_compat_builtins=False): 906 return True # A definite match. 907 # No matches, return result depends on whether flatten() was 908 # ambiguous. 909 return None if ambiguous else False 910