def join_types(s: Type, t: Type) -> Type: """Return the least upper bound of s and t. For example, the join of 'int' and 'object' is 'object'. """ if (s.can_be_true, s.can_be_false) != (t.can_be_true, t.can_be_false): # if types are restricted in different ways, use the more general versions s = true_or_false(s) t = true_or_false(t) if isinstance(s, AnyType): return s if isinstance(s, ErasedType): return t if isinstance(s, UnionType) and not isinstance(t, UnionType): s, t = t, s if isinstance(s, NoneTyp) and not isinstance(t, NoneTyp): s, t = t, s if isinstance(s, UninhabitedType) and not isinstance(t, UninhabitedType): s, t = t, s # Use a visitor to handle non-trivial cases. return t.accept(TypeJoinVisitor(s))
def join_simple(declaration: Optional[Type], s: Type, t: Type) -> Type: """Return a simple least upper bound given the declared type.""" if (s.can_be_true, s.can_be_false) != (t.can_be_true, t.can_be_false): # if types are restricted in different ways, use the more general versions s = true_or_false(s) t = true_or_false(t) if isinstance(s, AnyType): return s if isinstance(s, ErasedType): return t if is_proper_subtype(s, t): return t if is_proper_subtype(t, s): return s if isinstance(declaration, UnionType): return UnionType.make_simplified_union([s, t]) if isinstance(s, NoneTyp) and not isinstance(t, NoneTyp): s, t = t, s if isinstance(s, UninhabitedType) and not isinstance(t, UninhabitedType): s, t = t, s value = t.accept(TypeJoinVisitor(s)) if value is None: # XXX this code path probably should be avoided. # It seems to happen when a line (x = y) is a type error, and # it's not clear that assuming that x is arbitrary afterward # is a good idea. return declaration if declaration is None or is_subtype(value, declaration): return value return declaration
def join_simple(declaration: Optional[Type], s: Type, t: Type) -> ProperType: """Return a simple least upper bound given the declared type.""" declaration = get_proper_type(declaration) s = get_proper_type(s) t = get_proper_type(t) if (s.can_be_true, s.can_be_false) != (t.can_be_true, t.can_be_false): # if types are restricted in different ways, use the more general versions s = true_or_false(s) t = true_or_false(t) if isinstance(s, AnyType): return s if isinstance(s, ErasedType): return t if is_proper_subtype(s, t): return t if is_proper_subtype(t, s): return s if isinstance(declaration, UnionType): return UnionType.make_simplified_union([s, t]) if isinstance(s, NoneType) and not isinstance(t, NoneType): s, t = t, s if isinstance(s, UninhabitedType) and not isinstance(t, UninhabitedType): s, t = t, s value = t.accept(TypeJoinVisitor(s)) if declaration is None or is_subtype(value, declaration): return value return declaration