コード例 #1
0
ファイル: function.py プロジェクト: srittau/pytype
 def _expand_typed_star(self, vm, node, star, count):
   """Convert *xs: Sequence[T] -> [T, T, ...]."""
   if not count:
     return []
   p = abstract_utils.merged_type_parameter(node, star, abstract_utils.T)
   if not p.bindings:
     # TODO(b/159052609): This shouldn't happen. For some reason,
     # namedtuple instances don't have any bindings in T; see
     # tests/py3/test_unpack:TestUnpack.test_unpack_namedtuple.
     return [vm.new_unsolvable(node) for _ in range(count)]
   return [p.AssignToNewVariable(node) for _ in range(count)]
コード例 #2
0
ファイル: function.py プロジェクト: srittau/pytype
  def _unpack_and_match_args(self, node, vm, match_signature, starargs_tuple):
    """Match args against a signature with unpacking."""
    posargs = self.posargs
    namedargs = self.namedargs
    # As we have the function signature we will attempt to adjust the
    # starargs into the missing posargs.
    pre = []
    post = []
    stars = collections.deque(starargs_tuple)
    while stars and not abstract_utils.is_var_splat(stars[0]):
      pre.append(stars.popleft())
    while stars and not abstract_utils.is_var_splat(stars[-1]):
      post.append(stars.pop())
    post.reverse()
    n_matched = len(posargs) + len(pre) + len(post)
    required_posargs = 0
    for p in match_signature.param_names:
      if p in namedargs or p in match_signature.defaults:
        break
      required_posargs += 1
    posarg_delta = required_posargs - n_matched

    if stars and not post:
      star = stars[-1]
      if match_signature.varargs_name:
        # If the invocation ends with `*args`, return it to match against *args
        # in the function signature. For f(<k args>, *xs, ..., *ys), transform
        # to f(<k args>, *ys) since ys is an indefinite tuple anyway and will
        # match against all remaining posargs.
        return posargs + tuple(pre), abstract_utils.unwrap_splat(star)
      else:
        # If we do not have a `*args` in match_signature, just expand the
        # terminal splat to as many args as needed and then drop it.
        mid = self._expand_typed_star(vm, node, star, posarg_delta)
        return posargs + tuple(pre + mid), None
    elif posarg_delta <= len(stars):
      # We have too many args; don't do *xs expansion. Go back to matching from
      # the start and treat every entry in starargs_tuple as length 1.
      n_params = len(match_signature.param_names)
      all_args = posargs + starargs_tuple
      if not match_signature.varargs_name:
        # If the function sig has no *args, return everything in posargs
        pos = _splats_to_any(all_args, vm)
        return pos, None
      # Don't unwrap splats here because f(*xs, y) is not the same as f(xs, y).
      # TODO(mdemello): Ideally, since we are matching call f(*xs, y) against
      # sig f(x, y) we should raise an error here.
      pos = _splats_to_any(all_args[:n_params], vm)
      star = []
      for var in all_args[n_params:]:
        if abstract_utils.is_var_splat(var):
          star.append(
              abstract_utils.merged_type_parameter(node, var, abstract_utils.T))
        else:
          star.append(var)
      if star:
        return pos, vm.convert.tuple_to_value(star).to_variable(node)
      else:
        return pos, None
    elif stars:
      if len(stars) == 1:
        # Special case (<pre>, *xs) and (*xs, <post>) to fill in the type of xs
        # in every remaining arg.
        mid = self._expand_typed_star(vm, node, stars[0], posarg_delta)
      else:
        # If we have (*xs, <k args>, *ys) remaining, and more than k+2 params to
        # match, don't try to match the intermediate params to any range, just
        # match all k+2 to Any
        mid = [vm.new_unsolvable(node) for _ in range(posarg_delta)]
      return posargs + tuple(pre + mid + post), None
    else:
      # We have **kwargs but no *args in the invocation
      return posargs + tuple(pre), None
コード例 #3
0
ファイル: function.py プロジェクト: djyou/pytype
  def _unpack_and_match_args(self, node, vm, match_signature, starargs_tuple):
    """Match args against a signature with unpacking."""

    posargs = self.posargs
    # As we have the function signature we will attempt to adjust the
    # starargs into the missing posargs.
    pre = []
    post = []
    stars = collections.deque(starargs_tuple)
    while stars and not abstract_utils.is_var_splat(stars[0]):
      pre.append(stars.popleft())
    while stars and not abstract_utils.is_var_splat(stars[-1]):
      post.append(stars.pop())
    post.reverse()
    n_matched = len(posargs) + len(pre) + len(post)
    posarg_delta = len(match_signature.param_names) - n_matched
    if stars and not post:
      # If the invocation ends with `*args`, return it to match against *args in
      # the function signature. For f(<k args>, *xs, ..., *ys), transform to
      # f(<k args>, *ys) since ys is an indefinite tuple anyway and will match
      # against all remaining posargs.
      return posargs + tuple(pre), abstract_utils.unwrap_splat(stars[-1])
    elif posarg_delta <= len(stars):
      # We have too many args; don't do *xs expansion. Go back to matching from
      # the start and treat every entry in starargs_tuple as length 1.
      n_params = len(match_signature.param_names)
      all_args = posargs + starargs_tuple
      # Don't unwrap splats here because f(*xs, y) is not the same as f(xs, y).
      # TODO(mdemello): Ideally, since we are matching call f(*xs, y) against
      # sig f(x, y) we should raise an error here.
      pos = _splats_to_any(all_args[:n_params], vm)
      star = []
      for var in all_args[n_params:]:
        if abstract_utils.is_var_splat(var):
          star.append(
              abstract_utils.merged_type_parameter(node, var, abstract_utils.T))
        else:
          star.append(var)
      if star:
        return pos, vm.convert.tuple_to_value(star).to_variable(node)
      else:
        return pos, None
    elif stars:
      if len(stars) == 1:
        # Special case (*xs, <post>) to fill in the type of xs in every arg
        p = abstract_utils.merged_type_parameter(
            node, stars[0], abstract_utils.T)
        if not p.bindings:
          # TODO(b/159052609): This shouldn't happen. For some reason,
          # namedtuple instances don't have any bindings in T; see
          # tests/py3/test_unpack:TestUnpack.test_unpack_namedtuple.
          p.AddBinding(vm.convert.unsolvable)
        mid = [p.AssignToNewVariable(node) for _ in range(posarg_delta)]
      else:
        # If we have (*xs, <k args>, *ys) remaining, and more than k+2 params to
        # match, don't try to match the intermediate params to any range, just
        # match all k+2 to Any
        mid = [vm.new_unsolvable(node) for _ in range(posarg_delta)]
      return posargs + tuple(pre + mid + post), None
    else:
      # We have **kwargs but no *args in the invocation
      return posargs + tuple(pre), None