예제 #1
0
 def testJoinNothingType(self):
     """Test that JoinTypes() removes or collapses 'nothing'."""
     a = pytd.NamedType("a")
     nothing = pytd.NothingType()
     self.assertEquals(utils.JoinTypes([a, nothing]), a)
     self.assertEquals(utils.JoinTypes([nothing]), nothing)
     self.assertEquals(utils.JoinTypes([nothing, nothing]), nothing)
예제 #2
0
    def p_classdef(self, p):
        """classdef : CLASS NAME template parents COLON INDENT class_funcs DEDENT"""
        #             1     2    3        4       5     6
        funcdefs = [x for x in p[7] if isinstance(x, NameAndSig)]
        constants = [x for x in p[7] if isinstance(x, pytd.Constant)]
        if (set(f.name for f in funcdefs) | set(c.name for c in constants) !=
                set(d.name for d in p[7])):
            # TODO: raise a syntax error right when the identifier is defined.
            raise make_syntax_error(self, 'Duplicate identifier(s)', p)
        # Check that template parameter names are unique:
        template_names = {t.name for t in p[3]}
        for _, sig in funcdefs:
            for t in sig.template:
                if t.name in template_names:
                    raise make_syntax_error(
                        self, 'Duplicate template parameter %s' % t.name, p)

        if p[4] == [pytd.NothingType()]:
            bases = ()
        else:
            # Everything implicitly subclasses "object"
            bases = tuple(p[4]) or (pytd.NamedType('object'), )
        cls = pytd.Class(name=p[2],
                         parents=bases,
                         methods=tuple(MergeSignatures(funcdefs)),
                         constants=tuple(constants),
                         template=tuple(p[3]))
        p[0] = cls.Visit(visitors.AdjustSelf())
예제 #3
0
 def testEmptyTuple(self):
   ty = self.InferDedent("""
     def f():
       return ()
     f()
   """)
   self.assertHasOnlySignatures(ty.Lookup("f"),
                                ((),
                                 pytd.GenericType(self.tuple,
                                                  (pytd.NothingType(),))))
예제 #4
0
 def testOrder(self):
     # pytd types' primary sort key is the class name, second sort key is
     # the contents when interpreted as a (named)tuple.
     nodes = [
         pytd.AnythingType(),
         pytd.GenericType(self.list, (self.int, )),
         pytd.NamedType("int"),
         pytd.NothingType(),
         pytd.UnionType(self.float),
         pytd.UnionType(self.int)
     ]
     for n1, n2 in zip(nodes[:-1], nodes[1:]):
         self.assertLess(n1, n2)
         self.assertLessEqual(n1, n2)
         self.assertGreater(n2, n1)
         self.assertGreaterEqual(n2, n1)
     for p in itertools.permutations(nodes):
         self.assertEquals(list(sorted(p)), nodes)
예제 #5
0
    def VisitUnionType(self, union):
        """Push unions down into containers.

    This collects similar container types in unions and merges them into
    single instances with the union type pushed down to the element_type level.

    Arguments:
      union: A pytd.Union instance. Might appear in a parameter, a return type,
        a constant type, etc.

    Returns:
      A simplified pytd.Union.
    """
        if not any(isinstance(t, pytd.GenericType) for t in union.type_list):
            # Optimization: If we're not going to change anything, return original.
            return union
        union = utils.JoinTypes(union.type_list)  # flatten
        if not isinstance(union, pytd.UnionType):
            union = pytd.UnionType((union, ))
        collect = {}
        for t in union.type_list:
            if isinstance(t, pytd.GenericType):
                if t.base_type in collect:
                    collect[t.base_type] = tuple(
                        utils.JoinTypes([p1, p2])
                        for p1, p2 in zip(collect[t.base_type], t.parameters))
                else:
                    collect[t.base_type] = t.parameters
        result = pytd.NothingType()
        done = set()
        for t in union.type_list:
            if isinstance(t, pytd.GenericType):
                if t.base_type in done:
                    continue  # already added
                add = t.Replace(parameters=collect[t.base_type])
                done.add(t.base_type)
            else:
                add = t
            result = utils.JoinTypes([result, add])
        return result
예제 #6
0
    def testTypeMatcher(self):
        """Test for the TypeMatcher class."""
        class MyTypeMatcher(utils.TypeMatcher):
            def default_match(self, t1, t2, mykeyword):
                assert mykeyword == "foobar"
                return t1 == t2

            def match_function_against_function(self, f1, f2, mykeyword):
                assert mykeyword == "foobar"
                return all(
                    self.match(sig1, sig2, mykeyword)
                    for sig1, sig2 in zip(f1.signatures, f2.signatures))

        s1 = pytd.Signature((), pytd.NothingType(), (), (), False)
        s2 = pytd.Signature((), pytd.AnythingType(), (), (), False)
        match1 = MyTypeMatcher().match(pytd.Function("f1", (s1, s2)),
                                       pytd.Function("f2", (s1, s2)),
                                       mykeyword="foobar")
        self.assertEquals(match1, True)
        match2 = MyTypeMatcher().match(pytd.Function("f1", (s1, s2)),
                                       pytd.Function("f2", (s2, s2)),
                                       mykeyword="foobar")
        self.assertEquals(match2, False)
예제 #7
0
def JoinTypes(types):
    """Combine a list of types into a union type, if needed.

  Leaves singular return values alone, or wraps a UnionType around them if there
  are multiple ones, or if there are no elements in the list (or only
  NothingType) return NothingType.

  Arguments:
    types: A list of types. This list might contain other UnionTypes. If
    so, they are flattened.

  Returns:
    A type that represents the union of the types passed in. Order is preserved.
  """
    queue = collections.deque(types)
    seen = set()
    new_types = []
    while queue:
        t = queue.popleft()
        if isinstance(t, pytd.UnionType):
            queue.extendleft(reversed(t.type_list))
        elif isinstance(t, pytd.NothingType):
            pass
        elif t not in seen:
            new_types.append(t)
            seen.add(t)

    if len(new_types) == 1:
        return new_types.pop()
    elif any(isinstance(t, pytd.AnythingType) for t in new_types):
        return pytd.AnythingType()
    elif new_types:
        return pytd.UnionType(
            tuple(new_types))  # tuple() to make unions hashable
    else:
        return pytd.NothingType()
예제 #8
0
 def p_type_nothing(self, p):
     """type : NOTHING"""
     p[0] = pytd.NothingType()
예제 #9
0
 def testNothing(self):
     m = type_match.TypeMatch({})
     eq = m.match_type_against_type(pytd.NothingType(), pytd.NamedType("A"),
                                    {})
     self.assertEquals(eq, booleq.FALSE)