Exemple #1
0
 def testUnpackUnion(self):
     """Test for UnpackUnion."""
     ast = self.Parse("""
   c1 = ...  # type: int or float
   c2 = ...  # type: int
   c3 = ...  # type: list[int or float]""")
     c1 = ast.Lookup("c1").type
     c2 = ast.Lookup("c2").type
     c3 = ast.Lookup("c3").type
     self.assertItemsEqual(utils.UnpackUnion(c1), c1.type_list)
     self.assertItemsEqual(utils.UnpackUnion(c2), [c2])
     self.assertItemsEqual(utils.UnpackUnion(c3), [c3])
Exemple #2
0
 def SignatureHasReturnType(cls, sig, return_type):
   for desired_type in pytd_utils.UnpackUnion(return_type):
     if desired_type == return_type:
       return True
     elif isinstance(sig.return_type, pytd.UnionType):
       return desired_type in sig.return_type.type_list
     else:
       return False
Exemple #3
0
  def convert_constant(self, name, pyval, subst=None, node=None,
                       source_sets=None, discard_concrete_values=False):
    """Convert a constant to a Variable.

    This converts a constant to a cfg.Variable. Unlike
    convert_constant_to_value, it can handle things that need to be represented
    as a Variable with multiple possible values (i.e., a union type), like
    pytd.Function.

    Args:
      name: The name to give the new variable.
      pyval: The Python constant to convert. Can be a PyTD definition or a
        builtin constant.
      subst: The current type parameters.
      node: The current CFG node. (For instances)
      source_sets: An iterator over instances of SourceSet (or just tuples).
      discard_concrete_values: Whether concrete values should be discarded from
        type parameters.
    Returns:
      A cfg.Variable.
    Raises:
      TypeParameterError: if conversion is attempted on a type parameter without
        a substitution.
      ValueError: if pytype is not of a known type.
    """
    source_sets = source_sets or [[]]
    node = node or self.vm.root_cfg_node
    if isinstance(pyval, pytd.UnionType):
      options = [self.convert_constant_to_value(pytd.Print(t), t, subst, node)
                 for t in pyval.type_list]
      return self.vm.program.NewVariable(name, options, [],
                                         self.vm.root_cfg_node)
    elif isinstance(pyval, pytd.NothingType):
      return self.vm.program.NewVariable(name, [], [], self.vm.root_cfg_node)
    elif isinstance(pyval, pytd.Alias):
      return self.convert_constant(pytd.Print(pyval), pyval.type, subst,
                                   node, source_sets, discard_concrete_values)
    elif isinstance(pyval, abstract.AsInstance):
      cls = pyval.cls
      if isinstance(cls, pytd.AnythingType):
        return self.create_new_unsolvable(node, "?")
      if hasattr(cls, "name"):
        name = cls.name
      else:
        name = cls.__class__.__name__
      var = self.vm.program.NewVariable(name)
      for t in pytd_utils.UnpackUnion(cls):
        if isinstance(t, pytd.TypeParameter):
          if not subst or t.name not in subst:
            raise self.TypeParameterError(t.name)
          else:
            for v in subst[t.name].bindings:
              for source_set in source_sets:
                var.AddBinding(self._get_maybe_abstract_instance(v.data)
                               if discard_concrete_values else v.data,
                               source_set + [v], node)
        elif isinstance(t, pytd.NothingType):
          pass
        else:
          value = self.convert_constant_to_value(
              name, abstract.AsInstance(t), subst, node)
          for source_set in source_sets:
            var.AddBinding(value, source_set, node)
      return var
    elif isinstance(pyval, pytd.Constant):
      return self.convert_constant(
          name, abstract.AsInstance(pyval.type), subst, node, source_sets,
          discard_concrete_values)
    result = self.convert_constant_to_value(name, pyval, subst, node)
    if result is not None:
      return result.to_variable(self.vm.root_cfg_node, name)
    # There might still be bugs on the abstract intepreter when it returns,
    # e.g. a list of values instead of a list of types:
    assert pyval.__class__ != cfg.Variable, pyval
    if pyval.__class__ == tuple:
      # TODO(ampere): This does not allow subclasses. Handle namedtuple
      # correctly.
      # This case needs to go at the end because many things are actually also
      # tuples.
      return self.build_tuple(
          self.vm.root_cfg_node,
          (self.convert_constant("tuple[%d]" % i, v, subst, node, source_sets,
                                 discard_concrete_values)
           for i, v in enumerate(pyval)))
    raise ValueError(
        "Cannot convert {} to an abstract value".format(pyval.__class__))