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 match_signature_against_function(self, sig, f, subst, skip_self=False): # TODO: We should abort after the first matching signature, to get # more precise types in the presence of overloading. # TODO ... except it's possible that further computation will # invalidate the first matching signature, so we need # a way to preserve the alternatives and backtrack # through them if necessary return booleq.And( booleq.Or( self.match_signature_against_signature( sig, s, subst, skip_self) for s in f.signatures) for inner_sig in sig.Visit(optimize.ExpandSignatures()))
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 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 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)))