Exemplo n.º 1
0
 def _getargs(self, node, args):
     self.match_args(node, args)
     sig, = self.signatures
     callargs = {
         name: var
         for name, var, _ in sig.signature.iter_args(args)
     }
     # typing.NamedTuple doesn't support rename or verbose
     name_var = callargs["typename"]
     fields_var = callargs["fields"]
     fields = abstract_utils.get_atomic_python_constant(fields_var)
     # The fields is a list of tuples, so we need to deeply unwrap them.
     fields = [abstract_utils.get_atomic_python_constant(t) for t in fields]
     # We need the actual string for the field names and the AtomicAbstractValue
     # for the field types.
     names = []
     types = []
     for field in fields:
         if (len(field) != 2 or any(not self._is_str_instance(v)
                                    for v in field[0].data)):
             # Note that we don't need to check field[1] because both 'str'
             # (forward reference) and 'type' are valid for it.
             sig, = self.signatures
             bad_param = function.BadParam(name="fields",
                                           expected=self._fields_type)
             raise function.WrongArgTypes(sig.signature, args, self.vm,
                                          bad_param)
         name, typ = field
         names.append(abstract_utils.get_atomic_python_constant(name))
         types.append(abstract_utils.get_atomic_value(typ))
     return name_var, names, types
Exemplo n.º 2
0
  def compute_subst(self, node, formal_args, arg_dict, view, alias_map=None):
    """Compute information about type parameters using one-way unification.

    Given the arguments of a function call, try to find a substitution that
    matches them against the specified formal parameters.

    Args:
      node: The current CFG node.
      formal_args: An iterable of (name, value) pairs of formal arguments.
      arg_dict: A map of strings to pytd.Bindings instances.
      view: A mapping of Variable to Value.
      alias_map: Optionally, a datatypes.UnionFind, which stores all the type
        renaming information, mapping of type parameter name to its
        representative.
    Returns:
      A tuple (subst, name), with "subst" the datatypes.HashableDict if we found
      a working substition, None otherwise, and "name" the bad parameter in case
      subst=None.
    """
    if not arg_dict:
      # A call with no arguments always succeeds.
      assert not formal_args
      return datatypes.AliasingDict(), None
    subst = datatypes.AliasingDict()
    if alias_map:
      subst.uf = alias_map
    self._set_error_subst(None)
    for name, formal in formal_args:
      actual = arg_dict[name]
      subst = self._match_value_against_type(actual, formal, subst, node, view)
      if subst is None:
        formal = self.vm.annotations_util.sub_one_annotation(
            node, formal, [self._error_subst or {}])
        return None, function.BadParam(name=name, expected=formal)
    return datatypes.HashableDict(subst), None
Exemplo n.º 3
0
 def call(self, node, _, args):
     result = self.vm.program.NewVariable()
     num_args = len(args.posargs)
     if num_args == 0 and self.vm.PY3:
         # The implicit type argument is available in a freevar named '__class__'.
         cls_var = None
         # If we are in a list comprehension we want the enclosing frame.
         index = -1
         while self.vm.frames[index].f_code.co_name == "<listcomp>":
             index -= 1
         frame = self.vm.frames[index]
         for i, free_var in enumerate(frame.f_code.co_freevars):
             if free_var == abstract.BuildClass.CLOSURE_NAME:
                 cls_var = frame.cells[len(frame.f_code.co_cellvars) + i]
                 break
         if not (cls_var and cls_var.bindings):
             self.vm.errorlog.invalid_super_call(
                 self.vm.frames,
                 message="Missing __class__ closure for super call.",
                 details=
                 "Is 'super' being called from a method defined in a class?"
             )
             return node, self.vm.new_unsolvable(node)
         # The implicit super object argument is the first positional argument to
         # the function calling 'super'.
         self_arg = frame.first_posarg
         if not self_arg:
             self.vm.errorlog.invalid_super_call(
                 self.vm.frames,
                 message="Missing 'self' argument to 'super' call.")
             return node, self.vm.new_unsolvable(node)
         super_objects = self_arg.bindings
     elif 1 <= num_args <= 2:
         cls_var = args.posargs[0]
         super_objects = args.posargs[1].bindings if num_args == 2 else [
             None
         ]
     else:
         raise function.WrongArgCount(self._SIGNATURE, args, self.vm)
     for cls in cls_var.bindings:
         if not isinstance(
                 cls.data,
             (class_mixin.Class, abstract.AMBIGUOUS_OR_EMPTY)):
             bad = function.BadParam(name="cls",
                                     expected=self.vm.convert.type_type)
             raise function.WrongArgTypes(self._SIGNATURE,
                                          args,
                                          self.vm,
                                          bad_param=bad)
         for obj in super_objects:
             if obj:
                 result.AddBinding(
                     SuperInstance(cls.data, obj.data, self.vm), [cls, obj],
                     node)
             else:
                 result.AddBinding(SuperInstance(cls.data, None, self.vm),
                                   [cls], node)
     return node, result
Exemplo n.º 4
0
  def compute_subst(self, node, formal_args, arg_dict, view, alias_map=None):
    """Compute information about type parameters using one-way unification.

    Given the arguments of a function call, try to find a substitution that
    matches them against the specified formal parameters.

    Args:
      node: The current CFG node.
      formal_args: An iterable of (name, value) pairs of formal arguments.
      arg_dict: A map of strings to pytd.Bindings instances.
      view: A mapping of Variable to Value.
      alias_map: Optionally, a datatypes.UnionFind, which stores all the type
        renaming information, mapping of type parameter name to its
        representative.
    Returns:
      A tuple (subst, name), with "subst" the datatypes.HashableDict if we found
      a working substition, None otherwise, and "name" the bad parameter in case
      subst=None.
    """
    if not arg_dict:
      # A call with no arguments always succeeds.
      assert not formal_args
      return datatypes.AliasingDict(), None
    subst = datatypes.AliasingDict()
    if alias_map:
      subst.uf = alias_map
    self._set_error_subst(None)
    self_subst = None
    for name, formal in formal_args:
      actual = arg_dict[name]
      subst = self._match_value_against_type(actual, formal, subst, node, view)
      if subst is None:
        formal = self.vm.annotations_util.sub_one_annotation(
            node, formal, [self._error_subst or {}])
        return None, function.BadParam(name=name, expected=formal)
      if name == "self":
        self_subst = subst
    if self_subst:
      # Type parameters matched from a 'self' arg are class parameters whose
      # values have been declared by the user, e.g.:
      #   x = Container[int](__any_object__)
      # We should keep the 'int' value rather than using Union[int, Unknown].
      for name, value in self_subst.items():
        if any(not isinstance(v, abstract.Empty) for v in value.data):
          subst[name] = value
    return datatypes.HashableDict(subst), None
Exemplo n.º 5
0
 def make(cls, vm):
   typing_ast = vm.loader.import_name("typing")
   # Because NamedTuple is a special case for the pyi parser, typing.pytd has
   # "_NamedTuple" instead. Replace the name of the returned function so that
   # error messages will correctly display "typing.NamedTuple".
   pyval = typing_ast.Lookup("typing._NamedTuple")
   pyval = pyval.Replace(name="typing.NamedTuple")
   self = super().make("NamedTuple", vm, pyval)
   # NamedTuple's fields arg has type Sequence[Sequence[Union[str, type]]],
   # which doesn't provide precise enough type-checking, so we have to do
   # some of our own in _getargs. _NamedTupleFields is an alias to
   # List[Tuple[str, type]], which gives a more understandable error message.
   fields_pyval = typing_ast.Lookup("typing._NamedTupleFields").type
   fields_type = vm.convert.constant_to_value(fields_pyval, {}, vm.root_node)
   # pylint: disable=protected-access
   self._fields_param = function.BadParam(name="fields", expected=fields_type)
   return self