def testNestedEquals(self): eq1 = booleq.Eq("a", "u") eq2 = booleq.Eq("b", "v") eq3 = booleq.Eq("c", "w") eq4 = booleq.Eq("d", "x") nested = Or([And([eq1, eq2]), And([eq3, eq4])]) self.assertEqual(nested, nested)
def testHash(self): eq1 = booleq.Eq("a", "b") eq2 = booleq.Eq("b", "c") eq3 = booleq.Eq("c", "d") self.assertEqual(hash(booleq.Eq("x", "y")), hash(booleq.Eq("y", "x"))) self.assertEqual(hash(booleq.Or([eq1, eq2, eq3])), hash(booleq.Or([eq2, eq3, eq1]))) self.assertEqual(hash(booleq.And([eq1, eq2, eq3])), hash(booleq.And([eq2, eq3, eq1])))
def testOr(self): self.assertEqual(booleq.FALSE, booleq.Or([])) self.assertEqual(booleq.TRUE, booleq.Or([booleq.TRUE])) self.assertEqual(booleq.TRUE, booleq.Or([booleq.TRUE, booleq.TRUE])) self.assertEqual(booleq.TRUE, booleq.Or([booleq.TRUE, booleq.FALSE])) self.assertEqual(booleq.Eq("a", "b"), booleq.Or([booleq.Eq("a", "b"), booleq.FALSE])) self.assertEqual(booleq.TRUE, booleq.Or([booleq.Eq("a", "b"), booleq.TRUE]))
def match_generic_against_unknown(self, t1, t2, subst): assert isinstance(t1.base_type, pytd.ClassType) base_match = booleq.Eq(t1.base_type.name, t2.name) type_params = [ self.type_parameter(t2, t1.base_type.cls, item) for item in t1.base_type.cls.template ] params = [ self.match_type_against_type(p1, p2, subst) for p1, p2 in zip(t1.parameters, type_params) ] return booleq.And([base_match] + params)
def match_unknown_against_generic(self, t1, t2, subst): assert isinstance(t2.base_type, pytd.ClassType) # No inheritance for base classes - you can only inherit from an # instantiated template, but not from a template itself. base_match = booleq.Eq(t1.name, t2.base_type.name) type_params = [ self.type_parameter(t1, t2.base_type.cls, item) for item in t2.base_type.cls.template ] params = [ self.match_type_against_type(p1, p2, subst) for p1, p2 in zip(type_params, t2.parameters) ] return booleq.And([base_match] + params)
def match_generic_against_generic(self, t1, t2, subst): """Match a pytd.GenericType against another pytd.GenericType.""" assert isinstance(t1.base_type, pytd.ClassType) assert isinstance(t2.base_type, pytd.ClassType) # We don't do inheritance for base types, since right now, inheriting from # instantiations of templated types is not supported by pytd. if (is_complete(t1.base_type.cls) and is_complete(t2.base_type.cls) and t1.base_type.cls.name != t2.base_type.cls.name): # Optimization: If the base types are incompatible, these two generic # types can never match. base_type_cmp = booleq.FALSE else: base_type_cmp = booleq.Eq(t1.base_type.name, t2.base_type.name) if base_type_cmp == booleq.FALSE: return booleq.FALSE assert len(t1.parameters) == len(t2.parameters), t1.base_type.name # Type parameters are covariant: # E.g. passing list<int> as argument for list<object> succeeds. param_cmp = [ self.match_type_against_type(p1, p2, subst) for p1, p2 in zip(t1.parameters, t2.parameters) ] return booleq.And([base_type_cmp] + param_cmp)
def testOrder(self): eq1 = booleq.Eq("a", "b") eq2 = booleq.Eq("b", "c") self.assertEqual(booleq.Or([eq1, eq2]), booleq.Or([eq2, eq1])) self.assertEqual(booleq.And([eq1, eq2]), booleq.And([eq2, eq1]))
def testEquality(self): self.assertEqual(booleq.Eq("a", "b"), booleq.Eq("b", "a")) self.assertEqual(booleq.Eq("a", "b"), booleq.Eq("a", "b")) self.assertNotEqual(booleq.Eq("a", "a"), booleq.Eq("a", "b")) self.assertNotEqual(booleq.Eq("b", "a"), booleq.Eq("b", "b"))
def match_type_against_type(self, t1, t2, subst): """Match a pytd.TYPE against another pytd.TYPE.""" t1 = self.maybe_lookup_type_param(t1, subst) t2 = self.maybe_lookup_type_param(t2, subst) # TODO: Use pytypedecl/utils:TypeMatcher to simplify this? if isinstance(t1, pytd.AnythingType) or isinstance( t2, pytd.AnythingType): # We can match anything against AnythingType return booleq.TRUE elif isinstance(t1, pytd.NothingType) and isinstance( t2, pytd.NothingType): # nothing matches against nothing. return booleq.TRUE elif isinstance(t1, pytd.NothingType) or isinstance( t2, pytd.NothingType): # We can't match anything against nothing. (Except nothing itself, above) return booleq.FALSE elif isinstance(t1, pytd.UnionType): return booleq.And( self.match_type_against_type(u, t2, subst) for u in t1.type_list) elif isinstance(t2, pytd.UnionType): return booleq.Or( self.match_type_against_type(t1, u, subst) for u in t2.type_list) elif isinstance(t1, pytd.ClassType) and isinstance(t2, StrictType): # For strict types, avoid subclasses of the left side. return booleq.Eq(t1.name, t2.name) elif isinstance(t1, pytd.ClassType): # ClassTypes are similar to Unions, except they're disjunctions: We can # match the type or any of its base classes against the formal parameter. return booleq.Or( self.match_type_against_type(t, t2, subst) for t in self.expand_superclasses(t1)) elif isinstance(t2, pytd.ClassType): # ClassTypes on the right are exactly like Unions: We can match against # this type or any of its subclasses. # TODO: # if not allow_subclass: # return self.match_type_against_type(t1, self.unclass(t2), subst) return booleq.Or( self.match_type_against_type(t1, t, subst) for t in self.expand_subclasses(t2)) assert not isinstance(t1, pytd.ClassType) assert not isinstance(t2, pytd.ClassType) if is_unknown(t1) and isinstance(t2, pytd.GenericType): return self.match_unknown_against_generic(t1, t2, subst) elif isinstance(t1, pytd.GenericType) and is_unknown(t2): return self.match_generic_against_unknown(t1, t2, subst) elif isinstance(t1, pytd.GenericType) and isinstance( t2, pytd.GenericType): return self.match_generic_against_generic(t1, t2, subst) elif isinstance(t1, pytd.GenericType): # E.g. list<...> matches against list, or even object. return self.match_type_against_type(t1.base_type, t2, subst) elif isinstance(t2, pytd.GenericType): assert t1 != t2.base_type return booleq.FALSE elif is_unknown(t1) and is_unknown(t2): return booleq.Eq(t1.name, t2.name) elif (isinstance(t1, (pytd.NamedType, StrictType)) and isinstance(t2, (pytd.NamedType, StrictType))): if is_complete(t1) and is_complete(t2) and t1.name != t2.name: # Optimization: If we know these two can never be equal, just return # false right away. return booleq.FALSE else: return booleq.Eq(t1.name, t2.name) else: raise AssertionError("Don't know how to match %s against %s" % (type(t1), type(t2)))