Exemplo n.º 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(pytd_utils.UnpackUnion(c1), c1.type_list)
   self.assertItemsEqual(pytd_utils.UnpackUnion(c2), [c2])
   self.assertItemsEqual(pytd_utils.UnpackUnion(c3), [c3])
Exemplo n.º 2
0
 def test_unpack_union(self):
     """Test for UnpackUnion."""
     ast = self.Parse("""
   from typing import Union
   c1 = ...  # type: Union[int, float]
   c2 = ...  # type: int
   c3 = ...  # type: list[Union[int, float]]""")
     c1 = ast.Lookup("c1").type
     c2 = ast.Lookup("c2").type
     c3 = ast.Lookup("c3").type
     six.assertCountEqual(self, pytd_utils.UnpackUnion(c1), c1.type_list)
     six.assertCountEqual(self, pytd_utils.UnpackUnion(c2), [c2])
     six.assertCountEqual(self, pytd_utils.UnpackUnion(c3), [c3])
Exemplo n.º 3
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
Exemplo n.º 4
0
    def constant_to_var(self,
                        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 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:
      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.NothingType):
            return self.vm.program.NewVariable([], [], self.vm.root_cfg_node)
        elif isinstance(pyval, pytd.Alias):
            return self.constant_to_var(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)
            elif (isinstance(pyval, abstract.AsReturnValue)
                  and isinstance(cls, pytd.NothingType)):
                return self.no_return.to_variable(node)
            var = self.vm.program.NewVariable()
            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.constant_to_value(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.constant_to_var(abstract.AsInstance(pyval.type), subst,
                                        node, source_sets,
                                        discard_concrete_values)
        result = self.constant_to_value(pyval, subst, node)
        if result is not None:
            return result.to_variable(node)
        # 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.constant_to_var(
                    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__))