diff --git a/mypy/checker.py b/mypy/checker.py index a1395df05827..c244a7a07d8a 100644 --- a/mypy/checker.py +++ b/mypy/checker.py @@ -28,7 +28,7 @@ Type, AnyType, CallableType, FunctionLike, Overloaded, TupleType, TypedDictType, Instance, NoneTyp, ErrorType, strip_type, TypeType, UnionType, TypeVarId, TypeVarType, PartialType, DeletedType, UninhabitedType, TypeVarDef, - true_only, false_only, function_type, is_named_instance, union_items + true_only, false_only, function_type, is_named_instance ) from mypy.sametypes import is_same_type, is_same_types from mypy.messages import MessageBuilder @@ -812,45 +812,44 @@ def check_overlapping_op_methods(self, # of x in __radd__ would not be A, the methods could be # non-overlapping. - for forward_item in union_items(forward_type): - if isinstance(forward_item, CallableType): - # TODO check argument kinds - if len(forward_item.arg_types) < 1: - # Not a valid operator method -- can't succeed anyway. - return + if isinstance(forward_type, CallableType): + # TODO check argument kinds + if len(forward_type.arg_types) < 1: + # Not a valid operator method -- can't succeed anyway. + return - # Construct normalized function signatures corresponding to the - # operator methods. The first argument is the left operand and the - # second operand is the right argument -- we switch the order of - # the arguments of the reverse method. - forward_tweaked = CallableType( - [forward_base, forward_item.arg_types[0]], - [nodes.ARG_POS] * 2, - [None] * 2, - forward_item.ret_type, - forward_item.fallback, - name=forward_item.name) - reverse_args = reverse_type.arg_types - reverse_tweaked = CallableType( - [reverse_args[1], reverse_args[0]], - [nodes.ARG_POS] * 2, - [None] * 2, - reverse_type.ret_type, - fallback=self.named_type('builtins.function'), - name=reverse_type.name) - - if is_unsafe_overlapping_signatures(forward_tweaked, - reverse_tweaked): - self.msg.operator_method_signatures_overlap( - reverse_class.name(), reverse_name, - forward_base.type.name(), forward_name, context) - elif isinstance(forward_item, Overloaded): - for item in forward_item.items(): - self.check_overlapping_op_methods( - reverse_type, reverse_name, reverse_class, - item, forward_name, forward_base, context) - elif not isinstance(forward_item, AnyType): - self.msg.forward_operator_not_callable(forward_name, context) + # Construct normalized function signatures corresponding to the + # operator methods. The first argument is the left operand and the + # second operand is the right argument -- we switch the order of + # the arguments of the reverse method. + forward_tweaked = CallableType( + [forward_base, forward_type.arg_types[0]], + [nodes.ARG_POS] * 2, + [None] * 2, + forward_type.ret_type, + forward_type.fallback, + name=forward_type.name) + reverse_args = reverse_type.arg_types + reverse_tweaked = CallableType( + [reverse_args[1], reverse_args[0]], + [nodes.ARG_POS] * 2, + [None] * 2, + reverse_type.ret_type, + fallback=self.named_type('builtins.function'), + name=reverse_type.name) + + if is_unsafe_overlapping_signatures(forward_tweaked, + reverse_tweaked): + self.msg.operator_method_signatures_overlap( + reverse_class.name(), reverse_name, + forward_base.type.name(), forward_name, context) + elif isinstance(forward_type, Overloaded): + for item in forward_type.items(): + self.check_overlapping_op_methods( + reverse_type, reverse_name, reverse_class, + item, forward_name, forward_base, context) + elif not isinstance(forward_type, AnyType): + self.msg.forward_operator_not_callable(forward_name, context) def check_inplace_operator_method(self, defn: FuncBase) -> None: """Check an inplace operator method such as __iadd__. diff --git a/mypy/checkexpr.py b/mypy/checkexpr.py index 6736c4f8f513..51a6f92e9ce6 100644 --- a/mypy/checkexpr.py +++ b/mypy/checkexpr.py @@ -32,7 +32,7 @@ from mypy import messages from mypy.infer import infer_type_arguments, infer_function_type_arguments from mypy import join -from mypy.meet import narrow_declared_type +from mypy.meet import meet_simple from mypy.maptype import map_instance_to_supertype from mypy.subtypes import is_subtype, is_equivalent from mypy import applytype @@ -2221,7 +2221,7 @@ def narrow_type_from_binder(self, expr: Expression, known_type: Type) -> Type: if expr.literal >= LITERAL_TYPE: restriction = self.chk.binder.get(expr) if restriction: - ans = narrow_declared_type(known_type, restriction) + ans = meet_simple(known_type, restriction) return ans return known_type diff --git a/mypy/erasetype.py b/mypy/erasetype.py index 5ea1df156c6f..9a44b0456522 100644 --- a/mypy/erasetype.py +++ b/mypy/erasetype.py @@ -76,8 +76,7 @@ def visit_typeddict_type(self, t: TypedDictType) -> Type: return t.fallback.accept(self) def visit_union_type(self, t: UnionType) -> Type: - erased_items = [erase_type(item) for item in t.items] - return UnionType.make_simplified_union(erased_items) + return AnyType() # XXX: return underlying type if only one? def visit_type_type(self, t: TypeType) -> Type: return TypeType(t.item.accept(self), line=t.line) diff --git a/mypy/join.py b/mypy/join.py index 1713cd61ea63..06d5416cd2ea 100644 --- a/mypy/join.py +++ b/mypy/join.py @@ -10,7 +10,7 @@ UninhabitedType, TypeType, true_or_false ) from mypy.maptype import map_instance_to_supertype -from mypy.subtypes import is_subtype, is_equivalent, is_subtype_ignoring_tvars, is_proper_subtype +from mypy.subtypes import is_subtype, is_equivalent, is_subtype_ignoring_tvars from mypy import experiments @@ -29,10 +29,10 @@ def join_simple(declaration: Type, s: Type, t: Type) -> Type: if isinstance(s, ErasedType): return t - if is_proper_subtype(s, t): + if is_subtype(s, t): return t - if is_proper_subtype(t, s): + if is_subtype(t, s): return s if isinstance(declaration, UnionType): diff --git a/mypy/meet.py b/mypy/meet.py index 82fec33c0cb2..22d0a709838b 100644 --- a/mypy/meet.py +++ b/mypy/meet.py @@ -25,26 +25,21 @@ def meet_types(s: Type, t: Type) -> Type: return t.accept(TypeMeetVisitor(s)) -def narrow_declared_type(declared: Type, narrowed: Type) -> Type: - """Return the declared type narrowed down to another type.""" - if declared == narrowed: - return declared - if isinstance(declared, UnionType): - return UnionType.make_simplified_union([narrow_declared_type(x, narrowed) - for x in declared.items]) - elif not is_overlapping_types(declared, narrowed, use_promotions=True): +def meet_simple(s: Type, t: Type, default_right: bool = True) -> Type: + if s == t: + return s + if isinstance(s, UnionType): + return UnionType.make_simplified_union([meet_types(x, t) for x in s.items]) + elif not is_overlapping_types(s, t, use_promotions=True): if experiments.STRICT_OPTIONAL: return UninhabitedType() else: return NoneTyp() - elif isinstance(narrowed, UnionType): - return UnionType.make_simplified_union([narrow_declared_type(declared, x) - for x in narrowed.items]) - elif isinstance(narrowed, AnyType): - return narrowed - elif isinstance(declared, (Instance, TupleType)): - return meet_types(declared, narrowed) - return narrowed + else: + if default_right: + return t + else: + return s def is_overlapping_types(t: Type, s: Type, use_promotions: bool = False) -> bool: @@ -254,10 +249,6 @@ def visit_tuple_type(self, t: TupleType) -> Type: elif (isinstance(self.s, Instance) and self.s.type.fullname() == 'builtins.tuple' and self.s.args): return t.copy_modified(items=[meet_types(it, self.s.args[0]) for it in t.items]) - elif (isinstance(self.s, Instance) and t.fallback.type == self.s.type): - # Uh oh, a broken named tuple type (https://github.com/python/mypy/issues/3016). - # Do something reasonable until that bug is fixed. - return t else: return self.default(self.s) diff --git a/mypy/subtypes.py b/mypy/subtypes.py index b96618da28eb..c98bb8e8d144 100644 --- a/mypy/subtypes.py +++ b/mypy/subtypes.py @@ -7,7 +7,6 @@ ) import mypy.applytype import mypy.constraints -from mypy.erasetype import erase_type # Circular import; done in the function instead. # import mypy.solve from mypy import messages, sametypes @@ -16,7 +15,6 @@ ARG_POS, ARG_OPT, ARG_NAMED, ARG_NAMED_OPT, ARG_STAR, ARG_STAR2, ) from mypy.maptype import map_instance_to_supertype -from mypy.sametypes import is_same_type from mypy import experiments @@ -282,15 +280,9 @@ def visit_type_type(self, left: TypeType) -> bool: def is_callable_subtype(left: CallableType, right: CallableType, ignore_return: bool = False, - ignore_pos_arg_names: bool = False, - use_proper_subtype: bool = False) -> bool: + ignore_pos_arg_names: bool = False) -> bool: """Is left a subtype of right?""" - if use_proper_subtype: - is_compat = is_proper_subtype - else: - is_compat = is_subtype - # If either function is implicitly typed, ignore positional arg names too if left.implicit or right.implicit: ignore_pos_arg_names = True @@ -317,7 +309,7 @@ def is_callable_subtype(left: CallableType, right: CallableType, return False # Check return types. - if not ignore_return and not is_compat(left.ret_type, right.ret_type): + if not ignore_return and not is_subtype(left.ret_type, right.ret_type): return False if right.is_ellipsis_args: @@ -374,7 +366,7 @@ def is_callable_subtype(left: CallableType, right: CallableType, right_by_position = right.argument_by_position(j) assert right_by_position is not None if not are_args_compatible(left_by_position, right_by_position, - ignore_pos_arg_names, use_proper_subtype): + ignore_pos_arg_names): return False j += 1 continue @@ -397,7 +389,7 @@ def is_callable_subtype(left: CallableType, right: CallableType, right_by_name = right.argument_by_name(name) assert right_by_name is not None if not are_args_compatible(left_by_name, right_by_name, - ignore_pos_arg_names, use_proper_subtype): + ignore_pos_arg_names): return False continue @@ -406,7 +398,7 @@ def is_callable_subtype(left: CallableType, right: CallableType, if left_arg is None: return False - if not are_args_compatible(left_arg, right_arg, ignore_pos_arg_names, use_proper_subtype): + if not are_args_compatible(left_arg, right_arg, ignore_pos_arg_names): return False done_with_positional = False @@ -422,11 +414,11 @@ def is_callable_subtype(left: CallableType, right: CallableType, # Check that *args and **kwargs types match in this loop if left_kind == ARG_STAR: - if right_star_type is not None and not is_compat(right_star_type, left_arg.typ): + if right_star_type is not None and not is_subtype(right_star_type, left_arg.typ): return False continue elif left_kind == ARG_STAR2: - if right_star2_type is not None and not is_compat(right_star2_type, left_arg.typ): + if right_star2_type is not None and not is_subtype(right_star2_type, left_arg.typ): return False continue @@ -457,8 +449,7 @@ def is_callable_subtype(left: CallableType, right: CallableType, def are_args_compatible( left: FormalArgument, right: FormalArgument, - ignore_pos_arg_names: bool, - use_proper_subtype: bool) -> bool: + ignore_pos_arg_names: bool) -> bool: # If right has a specific name it wants this argument to be, left must # have the same. if right.name is not None and left.name != right.name: @@ -469,12 +460,8 @@ def are_args_compatible( if right.pos is not None and left.pos != right.pos: return False # Left must have a more general type - if use_proper_subtype: - if not is_proper_subtype(right.typ, left.typ): - return False - else: - if not is_subtype(right.typ, left.typ): - return False + if not is_subtype(right.typ, left.typ): + return False # If right's argument is optional, left's must also be. if not right.required and left.required: return False @@ -509,192 +496,52 @@ def unify_generic_callable(type: CallableType, target: CallableType, def restrict_subtype_away(t: Type, s: Type) -> Type: - """Return t minus s. + """Return a supertype of (t intersect not s) - If we can't determine a precise result, return a supertype of the - ideal result (just t is a valid result). - - This is used for type inference of runtime type checks such as - isinstance. - - Currently this just removes elements of a union type. + Currently just remove elements of a union type. """ if isinstance(t, UnionType): - # Since runtime type checks will ignore type arguments, erase the types. - erased_s = erase_type(s) - new_items = [item for item in t.items - if (not is_proper_subtype(erase_type(item), erased_s) - or isinstance(item, AnyType))] + new_items = [item for item in t.items if (not is_subtype(item, s) + or isinstance(item, AnyType))] return UnionType.make_union(new_items) else: return t -def is_proper_subtype(left: Type, right: Type) -> bool: - """Is left a proper subtype of right? +def is_proper_subtype(t: Type, s: Type) -> bool: + """Check if t is a proper subtype of s? For proper subtypes, there's no need to rely on compatibility due to - Any types. Every usable type is a proper subtype of itself. + Any types. Any instance type t is also a proper subtype of t. """ - if isinstance(right, UnionType) and not isinstance(left, UnionType): - return any([is_proper_subtype(left, item) - for item in right.items]) - return left.accept(ProperSubtypeVisitor(right)) - - -class ProperSubtypeVisitor(TypeVisitor[bool]): - def __init__(self, right: Type) -> None: - self.right = right - - def visit_unbound_type(self, left: UnboundType) -> bool: - # This can be called if there is a bad type annotation. The result probably - # doesn't matter much but by returning True we simplify these bad types away - # from unions, which could filter out some bogus messages. - return True - - def visit_error_type(self, left: ErrorType) -> bool: - # This isn't a real type. - return False - - def visit_type_list(self, left: TypeList) -> bool: - assert False, 'Should not happen' - - def visit_any(self, left: AnyType) -> bool: - return isinstance(self.right, AnyType) - - def visit_none_type(self, left: NoneTyp) -> bool: - if experiments.STRICT_OPTIONAL: - return (isinstance(self.right, NoneTyp) or - is_named_instance(self.right, 'builtins.object')) - return True - - def visit_uninhabited_type(self, left: UninhabitedType) -> bool: - return True - - def visit_erased_type(self, left: ErasedType) -> bool: - # This may be encountered during type inference. The result probably doesn't - # matter much. - return True - - def visit_deleted_type(self, left: DeletedType) -> bool: - return True - - def visit_instance(self, left: Instance) -> bool: - right = self.right - if isinstance(right, Instance): - for base in left.type.mro: - if base._promote and is_proper_subtype(base._promote, right): - return True + # FIX tuple types + if isinstance(s, UnionType): + if isinstance(t, UnionType): + return all([is_proper_subtype(item, s) for item in t.items]) + else: + return any([is_proper_subtype(t, item) for item in s.items]) - if not left.type.has_base(right.type.fullname()): + if isinstance(t, Instance): + if isinstance(s, Instance): + if not t.type.has_base(s.type.fullname()): return False - def check_argument(leftarg: Type, rightarg: Type, variance: int) -> bool: + def check_argument(left: Type, right: Type, variance: int) -> bool: if variance == COVARIANT: - return is_proper_subtype(leftarg, rightarg) + return is_proper_subtype(left, right) elif variance == CONTRAVARIANT: - return is_proper_subtype(rightarg, leftarg) + return is_proper_subtype(right, left) else: - return sametypes.is_same_type(leftarg, rightarg) + return sametypes.is_same_type(left, right) # Map left type to corresponding right instances. - left = map_instance_to_supertype(left, right.type) + t = map_instance_to_supertype(t, s.type) return all(check_argument(ta, ra, tvar.variance) for ta, ra, tvar in - zip(left.args, right.args, right.type.defn.type_vars)) - return False - - def visit_type_var(self, left: TypeVarType) -> bool: - if isinstance(self.right, TypeVarType) and left.id == self.right.id: - return True - # TODO: Value restrictions - return is_proper_subtype(left.upper_bound, self.right) - - def visit_callable_type(self, left: CallableType) -> bool: - right = self.right - if isinstance(right, CallableType): - return is_callable_subtype( - left, right, - ignore_pos_arg_names=False, - use_proper_subtype=True) - elif isinstance(right, Overloaded): - return all(is_proper_subtype(left, item) - for item in right.items()) - elif isinstance(right, Instance): - return is_proper_subtype(left.fallback, right) - elif isinstance(right, TypeType): - # This is unsound, we don't check the __init__ signature. - return left.is_type_obj() and is_proper_subtype(left.ret_type, right.item) - return False - - def visit_tuple_type(self, left: TupleType) -> bool: - right = self.right - if isinstance(right, Instance): - if (is_named_instance(right, 'builtins.tuple') or - is_named_instance(right, 'typing.Iterable') or - is_named_instance(right, 'typing.Container') or - is_named_instance(right, 'typing.Sequence') or - is_named_instance(right, 'typing.Reversible')): - if not right.args: - return False - iter_type = right.args[0] - if is_named_instance(right, 'builtins.tuple') and isinstance(iter_type, AnyType): - # TODO: We shouldn't need this special case. This is currently needed - # for isinstance(x, tuple), though it's unclear why. - return True - return all(is_proper_subtype(li, iter_type) for li in left.items) - return is_proper_subtype(left.fallback, right) - elif isinstance(right, TupleType): - if len(left.items) != len(right.items): - return False - for l, r in zip(left.items, right.items): - if not is_proper_subtype(l, r): - return False - return is_proper_subtype(left.fallback, right.fallback) - return False - - def visit_typeddict_type(self, left: TypedDictType) -> bool: - right = self.right - if isinstance(right, TypedDictType): - for name, typ in left.items.items(): - if name in right.items and not is_same_type(typ, right.items[name]): - return False - for name, typ in right.items.items(): - if name not in left.items: - return False - return True - return is_proper_subtype(left.fallback, right) - - def visit_overloaded(self, left: Overloaded) -> bool: - # TODO: What's the right thing to do here? - return False - - def visit_union_type(self, left: UnionType) -> bool: - return all([is_proper_subtype(item, self.right) for item in left.items]) - - def visit_partial_type(self, left: PartialType) -> bool: - # TODO: What's the right thing to do here? - return False - - def visit_type_type(self, left: TypeType) -> bool: - # TODO: Handle metaclasses? - right = self.right - if isinstance(right, TypeType): - # This is unsound, we don't check the __init__ signature. - return is_proper_subtype(left.item, right.item) - if isinstance(right, CallableType): - # This is also unsound because of __init__. - return right.is_type_obj() and is_proper_subtype(left.item, right.ret_type) - if isinstance(right, Instance): - if right.type.fullname() == 'builtins.type': - # TODO: Strictly speaking, the type builtins.type is considered equivalent to - # Type[Any]. However, this would break the is_proper_subtype check in - # conditional_type_map for cases like isinstance(x, type) when the type - # of x is Type[int]. It's unclear what's the right way to address this. - return True - if right.type.fullname() == 'builtins.object': - return True + zip(t.args, s.args, s.type.defn.type_vars)) return False + else: + return sametypes.is_same_type(t, s) def is_more_precise(t: Type, s: Type) -> bool: diff --git a/mypy/test/testtypes.py b/mypy/test/testtypes.py index 3c1c31fd6c90..9fc6a71b5594 100644 --- a/mypy/test/testtypes.py +++ b/mypy/test/testtypes.py @@ -658,7 +658,7 @@ def test_tuples(self) -> None: self.assert_meet(self.tuple(self.fx.a, self.fx.a), self.fx.std_tuple, - self.tuple(self.fx.a, self.fx.a)) + NoneTyp()) self.assert_meet(self.tuple(self.fx.a), self.tuple(self.fx.a, self.fx.a), NoneTyp()) diff --git a/mypy/typeanal.py b/mypy/typeanal.py index 930d8eb6a6df..e33daa2eed3c 100644 --- a/mypy/typeanal.py +++ b/mypy/typeanal.py @@ -7,7 +7,7 @@ Type, UnboundType, TypeVarType, TupleType, TypedDictType, UnionType, Instance, AnyType, CallableType, NoneTyp, DeletedType, TypeList, TypeVarDef, TypeVisitor, StarType, PartialType, EllipsisType, UninhabitedType, TypeType, get_typ_args, set_typ_args, - get_type_vars, union_items + get_type_vars, ) from mypy.nodes import ( BOUND_TVAR, UNBOUND_TVAR, TYPE_ALIAS, UNBOUND_IMPORTED, @@ -109,7 +109,7 @@ def visit_unbound_type(self, t: UnboundType) -> Type: t.optional = False # We don't need to worry about double-wrapping Optionals or # wrapping Anys: Union simplification will take care of that. - return make_optional_type(self.visit_unbound_type(t)) + return UnionType.make_simplified_union([self.visit_unbound_type(t), NoneTyp()]) sym = self.lookup(t.name, t) if sym is not None: if sym.node is None: @@ -151,7 +151,7 @@ def visit_unbound_type(self, t: UnboundType) -> Type: self.fail('Optional[...] must have exactly one type argument', t) return AnyType() item = self.anal_type(t.args[0]) - return make_optional_type(item) + return UnionType.make_simplified_union([item, NoneTyp()]) elif fullname == 'typing.Callable': return self.analyze_callable_type(t) elif fullname == 'typing.Type': @@ -557,21 +557,3 @@ def visit_partial_type(self, t: PartialType) -> None: def visit_type_type(self, t: TypeType) -> None: pass - - -def make_optional_type(t: Type) -> Type: - """Return the type corresponding to Optional[t]. - - Note that we can't use normal union simplification, since this function - is called during semantic analysis and simplification only works during - type checking. - """ - if not experiments.STRICT_OPTIONAL: - return t - if isinstance(t, NoneTyp): - return t - if isinstance(t, UnionType): - items = [item for item in union_items(t) - if not isinstance(item, NoneTyp)] - return UnionType(items + [NoneTyp()], t.line, t.column) - return UnionType([t, NoneTyp()], t.line, t.column) diff --git a/mypy/types.py b/mypy/types.py index 95f59b849a48..3da1609421c3 100644 --- a/mypy/types.py +++ b/mypy/types.py @@ -996,23 +996,6 @@ def make_union(items: List[Type], line: int = -1, column: int = -1) -> Type: @staticmethod def make_simplified_union(items: List[Type], line: int = -1, column: int = -1) -> Type: - """Build union type with redundant union items removed. - - If only a single item remains, this may return a non-union type. - - Examples: - - * [int, str] -> Union[int, str] - * [int, object] -> object - * [int, int] -> int - * [int, Any] -> Union[int, Any] (Any types are not simplified away!) - * [Any, Any] -> Any - - Note: This must NOT be used during semantic analysis, since TypeInfos may not - be fully initialized. - """ - # TODO: Make this a function living somewhere outside mypy.types. Most other non-trivial - # type operations are not static methods, so this is inconsistent. while any(isinstance(typ, UnionType) for typ in items): all_items = [] # type: List[Type] for typ in items: @@ -1022,7 +1005,11 @@ def make_simplified_union(items: List[Type], line: int = -1, column: int = -1) - all_items.append(typ) items = all_items - from mypy.subtypes import is_proper_subtype + if any(isinstance(typ, AnyType) for typ in items): + return AnyType() + + from mypy.subtypes import is_subtype + from mypy.sametypes import is_same_type removed = set() # type: Set[int] for i, ti in enumerate(items): @@ -1030,8 +1017,10 @@ def make_simplified_union(items: List[Type], line: int = -1, column: int = -1) - # Keep track of the truishness info for deleted subtypes which can be relevant cbt = cbf = False for j, tj in enumerate(items): - if (i != j and is_proper_subtype(tj, ti)): - # We found a redundant item in the union. + if (i != j + and is_subtype(tj, ti) + and (not (isinstance(tj, Instance) and tj.type.fallback_to_any) + or is_same_type(ti, tj))): removed.add(j) cbt = cbt or tj.can_be_true cbf = cbf or tj.can_be_false @@ -1735,7 +1724,7 @@ def set_typ_args(tp: Type, new_args: List[Type], line: int = -1, column: int = - if isinstance(tp, TupleType): return tp.copy_modified(items=new_args) if isinstance(tp, UnionType): - return UnionType(new_args, line, column) + return UnionType.make_simplified_union(new_args, line, column) if isinstance(tp, CallableType): return tp.copy_modified(arg_types=new_args[:-1], ret_type=new_args[-1], line=line, column=column) @@ -1763,20 +1752,6 @@ def get_type_vars(typ: Type) -> List[TypeVarType]: return tvars -def union_items(typ: Type) -> List[Type]: - """Return the flattened items of a union type. - - For non-union types, return a list containing just the argument. - """ - if isinstance(typ, UnionType): - items = [] - for item in typ.items: - items.extend(union_items(item)) - return items - else: - return [typ] - - deserialize_map = { key: obj.deserialize # type: ignore for key, obj in globals().items() diff --git a/test-data/unit/check-classes.test b/test-data/unit/check-classes.test index ce2ee52d0df6..84932472c858 100644 --- a/test-data/unit/check-classes.test +++ b/test-data/unit/check-classes.test @@ -2439,9 +2439,9 @@ class A: pass class B(A): pass @overload -def f(a: Type[B]) -> int: pass # E: Overloaded function signatures 1 and 2 overlap with incompatible return types +def f(a: Type[A]) -> int: pass # E: Overloaded function signatures 1 and 2 overlap with incompatible return types @overload -def f(a: Type[A]) -> str: pass +def f(a: Type[B]) -> str: pass [builtins fixtures/classmethod.pyi] [out] diff --git a/test-data/unit/check-dynamic-typing.test b/test-data/unit/check-dynamic-typing.test index 70d6d32aa475..9529a421977a 100644 --- a/test-data/unit/check-dynamic-typing.test +++ b/test-data/unit/check-dynamic-typing.test @@ -79,8 +79,8 @@ n = 0 d in a # E: Unsupported right operand type for in ("A") d and a d or a -c = d and b # E: Incompatible types in assignment (expression has type "Union[Any, bool]", variable has type "C") -c = d or b # E: Incompatible types in assignment (expression has type "Union[Any, bool]", variable has type "C") +c = d and b # Unintuitive type inference? +c = d or b # Unintuitive type inference? c = d + a c = d - a @@ -123,8 +123,8 @@ n = 0 a and d a or d c = a in d -c = b and d # E: Incompatible types in assignment (expression has type "Union[bool, Any]", variable has type "C") -c = b or d # E: Incompatible types in assignment (expression has type "Union[bool, Any]", variable has type "C") +c = b and d # Unintuitive type inference? +c = b or d # Unintuitive type inference? b = a + d b = a / d diff --git a/test-data/unit/check-generics.test b/test-data/unit/check-generics.test index 64d010e313fd..7d035d0ed992 100644 --- a/test-data/unit/check-generics.test +++ b/test-data/unit/check-generics.test @@ -779,7 +779,7 @@ if not isinstance(s, str): z = None # type: TNode # Same as TNode[Any] z.x -z.foo() # E: Some element of union has no attribute "foo" +z.foo() # Any simplifies Union to Any now. This test should be updated after #2197 [builtins fixtures/isinstance.pyi] diff --git a/test-data/unit/check-isinstance.test b/test-data/unit/check-isinstance.test index 1490dc0bb089..973d463d6085 100644 --- a/test-data/unit/check-isinstance.test +++ b/test-data/unit/check-isinstance.test @@ -399,7 +399,6 @@ def f(x: Union[List[int], List[str], int]) -> None: a + 'x' # E: Unsupported operand types for + ("int" and "str") # type of a? - reveal_type(x) # E: Revealed type is 'Union[builtins.list[builtins.int], builtins.list[builtins.str]]' x + 1 # E: Unsupported operand types for + (likely involving Union) else: x[0] # E: Value of type "int" is not indexable @@ -911,8 +910,7 @@ def foo() -> Union[int, str, A]: pass def bar() -> None: x = foo() - x + 1 # E: Unsupported left operand type for + (some union) \ - # E: Unsupported operand types for + (likely involving Union) + x + 1 # E: Unsupported left operand type for + (some union) if isinstance(x, A): x.a else: @@ -1277,7 +1275,6 @@ if isinstance(x, A): reveal_type(x) # unreachable else: reveal_type(x) # E: Revealed type is '__main__.B' -reveal_type(x) # E: Revealed type is '__main__.B' [builtins fixtures/isinstance.pyi] [case testAssertIsinstance] @@ -1308,9 +1305,6 @@ from typing import List, Union def f(x: Union[List[int], str]) -> None: if isinstance(x, list): x[0]() - else: - reveal_type(x) # E: Revealed type is 'builtins.str' - reveal_type(x) # E: Revealed type is 'Union[builtins.list[builtins.int], builtins.str]' [builtins fixtures/isinstancelist.pyi] [out] main:4: error: "int" not callable @@ -1328,7 +1322,6 @@ if isinstance(x1, B) or isinstance(x1, C): else: reveal_type(x1) # E: Revealed type is '__main__.A' f = 0 -reveal_type(x1) # E: Revealed type is '__main__.A' x2 = A() if isinstance(x2, A) or isinstance(x2, C): reveal_type(x2) # E: Revealed type is '__main__.A' @@ -1336,7 +1329,6 @@ if isinstance(x2, A) or isinstance(x2, C): else: # unreachable 1() -reveal_type(x2) # E: Revealed type is '__main__.A' [builtins fixtures/isinstance.pyi] [out] [case testComprehensionIsInstance] @@ -1378,7 +1370,6 @@ def f(x: Union[int, str], typ: type) -> None: reveal_type(x) # E: Revealed type is 'Union[builtins.int, builtins.str]' else: reveal_type(x) # E: Revealed type is 'builtins.str' - reveal_type(x) # E: Revealed type is 'Union[builtins.int, builtins.str]' [builtins fixtures/isinstancelist.pyi] @@ -1391,7 +1382,6 @@ def f(x: Union[int, A], a: Type[A]) -> None: reveal_type(x) # E: Revealed type is 'Union[builtins.int, __main__.A]' else: reveal_type(x) # E: Revealed type is '__main__.A' - reveal_type(x) # E: Revealed type is 'Union[builtins.int, __main__.A]' [builtins fixtures/isinstancelist.pyi] @@ -1422,29 +1412,3 @@ def f(x: Union[int, A], a: Type[A]) -> None: [builtins fixtures/isinstancelist.pyi] - -[case testIsinstanceAndNarrowTypeVariable] -from typing import TypeVar - -class A: pass -class B(A): pass - -T = TypeVar('T', bound=A) - -def f(x: T) -> None: - if isinstance(x, B): - reveal_type(x) # E: Revealed type is '__main__.B' - else: - reveal_type(x) # E: Revealed type is 'T`-1' - reveal_type(x) # E: Revealed type is 'T`-1' -[builtins fixtures/isinstance.pyi] - -[case testIsinstanceAndTypeType] -from typing import Type -def f(x: Type[int]) -> None: - if isinstance(x, type): - reveal_type(x) # E: Revealed type is 'Type[builtins.int]' - else: - reveal_type(x) # Unreachable - reveal_type(x) # E: Revealed type is 'Type[builtins.int]' -[builtins fixtures/isinstancelist.pyi] diff --git a/test-data/unit/check-namedtuple.test b/test-data/unit/check-namedtuple.test index 51260733064a..71a058b24ac6 100644 --- a/test-data/unit/check-namedtuple.test +++ b/test-data/unit/check-namedtuple.test @@ -427,25 +427,3 @@ from typing import NamedTuple def f() -> None: A = NamedTuple('A', [('x', int)]) A # E: Name 'A' is not defined - -[case testNamedTupleWithImportCycle] -import a -[file a.py] -from collections import namedtuple -from b import f - -N = namedtuple('N', 'a') - -class X(N): pass -[file b.py] -import a - -def f(x: a.X) -> None: - # The type of x is broken (https://github.com/python/mypy/issues/3016) but we need to - # do something reasonable here to avoid a regression. - reveal_type(x) - x = a.X(1) - reveal_type(x) -[out] -tmp/b.py:6: error: Revealed type is 'a.X' -tmp/b.py:8: error: Revealed type is 'Tuple[Any, fallback=a.X]' diff --git a/test-data/unit/check-optional.test b/test-data/unit/check-optional.test index 05a9c93529f9..4286aab48bfd 100644 --- a/test-data/unit/check-optional.test +++ b/test-data/unit/check-optional.test @@ -75,7 +75,6 @@ if x is None: reveal_type(x) # E: Revealed type is 'builtins.None' else: reveal_type(x) # E: Revealed type is 'builtins.int' -reveal_type(x) # E: Revealed type is 'Union[builtins.int, builtins.None]' [builtins fixtures/bool.pyi] [case testAnyCanBeNone] @@ -538,10 +537,9 @@ f = lambda x: None f(0) [builtins fixtures/function.pyi] -[case testDontSimplifyNoneUnionsWithStrictOptional] +[case testUnionSimplificationWithStrictOptional] from typing import Any, TypeVar, Union -A = None # type: Any -class C(A): pass +class C(Any): pass T = TypeVar('T') S = TypeVar('S') def u(x: T, y: S) -> Union[S, T]: pass @@ -551,39 +549,9 @@ a = None # type: Any reveal_type(u(C(), None)) # E: Revealed type is 'Union[builtins.None, __main__.C*]' reveal_type(u(None, C())) # E: Revealed type is 'Union[__main__.C*, builtins.None]' -reveal_type(u(a, None)) # E: Revealed type is 'Union[builtins.None, Any]' -reveal_type(u(None, a)) # E: Revealed type is 'Union[Any, builtins.None]' +# This will be fixed later +reveal_type(u(a, None)) # E: Revealed type is 'Any' +reveal_type(u(None, a)) # E: Revealed type is 'Any' reveal_type(u(1, None)) # E: Revealed type is 'Union[builtins.None, builtins.int*]' reveal_type(u(None, 1)) # E: Revealed type is 'Union[builtins.int*, builtins.None]' - -[case testOptionalAndAnyBaseClass] -from typing import Any, Optional -A = None # type: Any -class C(A): - pass -x = None # type: Optional[C] -x.foo() # E: Some element of union has no attribute "foo" - -[case testIsinstanceAndOptionalAndAnyBase] -from typing import Any, Optional - -B = None # type: Any -class A(B): pass - -def f(a: Optional[A]): - reveal_type(a) # E: Revealed type is 'Union[__main__.A, builtins.None]' - if a is not None: - reveal_type(a) # E: Revealed type is '__main__.A' - else: - reveal_type(a) # E: Revealed type is 'builtins.None' - reveal_type(a) # E: Revealed type is 'Union[__main__.A, builtins.None]' -[builtins fixtures/isinstance.pyi] - -[case testFlattenOptionalUnion] -from typing import Optional, Union - -x: Optional[Union[int, str]] -reveal_type(x) # E: Revealed type is 'Union[builtins.int, builtins.str, builtins.None]' -y: Optional[Union[int, None]] -reveal_type(y) # E: Revealed type is 'Union[builtins.int, builtins.None]' diff --git a/test-data/unit/check-statements.test b/test-data/unit/check-statements.test index e33f3cc0a411..2ac3619c438c 100644 --- a/test-data/unit/check-statements.test +++ b/test-data/unit/check-statements.test @@ -723,11 +723,11 @@ try: except BaseException as e1: reveal_type(e1) # E: Revealed type is 'builtins.BaseException' except (E1, BaseException) as e2: - reveal_type(e2) # E: Revealed type is 'Union[Any, builtins.BaseException]' + reveal_type(e2) # E: Revealed type is 'Any' except (E1, E2) as e3: - reveal_type(e3) # E: Revealed type is 'Union[Any, __main__.E2]' + reveal_type(e3) # E: Revealed type is 'Any' except (E1, E2, BaseException) as e4: - reveal_type(e4) # E: Revealed type is 'Union[Any, builtins.BaseException]' + reveal_type(e4) # E: Revealed type is 'Any' try: pass except E1 as e1: diff --git a/test-data/unit/check-tuples.test b/test-data/unit/check-tuples.test index 08345706f0d9..c836fe8cd41e 100644 --- a/test-data/unit/check-tuples.test +++ b/test-data/unit/check-tuples.test @@ -826,7 +826,7 @@ def g(x: Union[str, Tuple[str, str]]) -> None: [builtins fixtures/tuple.pyi] [out] -[case testTupleMeetTupleAnyComplex] +[case testTupleMeetTUpleAnyComplex] from typing import Tuple, Union Pair = Tuple[int, int] diff --git a/test-data/unit/check-typeddict.test b/test-data/unit/check-typeddict.test index 74d958dee3df..78fade8c8258 100644 --- a/test-data/unit/check-typeddict.test +++ b/test-data/unit/check-typeddict.test @@ -610,60 +610,3 @@ def f() -> None: A = TypedDict('A', {'x': int}) A # E: Name 'A' is not defined [builtins fixtures/dict.pyi] - - --- Union simplification / proper subtype checks - -[case testTypedDictUnionSimplification] -from typing import TypeVar, Union, Any, cast -from mypy_extensions import TypedDict - -T = TypeVar('T') -S = TypeVar('S') -def u(x: T, y: S) -> Union[S, T]: pass - -C = TypedDict('C', {'a': int}) -D = TypedDict('D', {'a': int, 'b': int}) -E = TypedDict('E', {'a': str}) -F = TypedDict('F', {'x': int}) -G = TypedDict('G', {'a': Any}) - -c = C(a=1) -d = D(a=1, b=1) -e = E(a='') -f = F(x=1) -g = G(a=cast(Any, 1)) # Work around #2610 - -reveal_type(u(d, d)) # E: Revealed type is 'TypedDict(a=builtins.int, b=builtins.int, _fallback=typing.Mapping[builtins.str, builtins.int])' -reveal_type(u(c, d)) # E: Revealed type is 'TypedDict(a=builtins.int, _fallback=typing.Mapping[builtins.str, builtins.int])' -reveal_type(u(d, c)) # E: Revealed type is 'TypedDict(a=builtins.int, _fallback=typing.Mapping[builtins.str, builtins.int])' -reveal_type(u(c, e)) # E: Revealed type is 'Union[TypedDict(a=builtins.str, _fallback=typing.Mapping[builtins.str, builtins.str]), TypedDict(a=builtins.int, _fallback=typing.Mapping[builtins.str, builtins.int])]' -reveal_type(u(e, c)) # E: Revealed type is 'Union[TypedDict(a=builtins.int, _fallback=typing.Mapping[builtins.str, builtins.int]), TypedDict(a=builtins.str, _fallback=typing.Mapping[builtins.str, builtins.str])]' -reveal_type(u(c, f)) # E: Revealed type is 'Union[TypedDict(x=builtins.int, _fallback=typing.Mapping[builtins.str, builtins.int]), TypedDict(a=builtins.int, _fallback=typing.Mapping[builtins.str, builtins.int])]' -reveal_type(u(f, c)) # E: Revealed type is 'Union[TypedDict(a=builtins.int, _fallback=typing.Mapping[builtins.str, builtins.int]), TypedDict(x=builtins.int, _fallback=typing.Mapping[builtins.str, builtins.int])]' -reveal_type(u(c, g)) # E: Revealed type is 'Union[TypedDict(a=Any, _fallback=typing.Mapping[builtins.str, Any]), TypedDict(a=builtins.int, _fallback=typing.Mapping[builtins.str, builtins.int])]' -reveal_type(u(g, c)) # E: Revealed type is 'Union[TypedDict(a=builtins.int, _fallback=typing.Mapping[builtins.str, builtins.int]), TypedDict(a=Any, _fallback=typing.Mapping[builtins.str, Any])]' -[builtins fixtures/dict.pyi] - -[case testTypedDictUnionSimplification2] -from typing import TypeVar, Union, Mapping, Any -from mypy_extensions import TypedDict - -T = TypeVar('T') -S = TypeVar('S') -def u(x: T, y: S) -> Union[S, T]: pass - -C = TypedDict('C', {'a': int, 'b': int}) - -c = C(a=1, b=1) -m_s_i: Mapping[str, int] -m_s_s: Mapping[str, str] -m_i_i: Mapping[int, int] -m_s_a: Mapping[str, Any] - -reveal_type(u(c, m_s_i)) # E: Revealed type is 'typing.Mapping*[builtins.str, builtins.int]' -reveal_type(u(m_s_i, c)) # E: Revealed type is 'typing.Mapping*[builtins.str, builtins.int]' -reveal_type(u(c, m_s_s)) # E: Revealed type is 'Union[typing.Mapping*[builtins.str, builtins.str], TypedDict(a=builtins.int, b=builtins.int, _fallback=typing.Mapping[builtins.str, builtins.int])]' -reveal_type(u(c, m_i_i)) # E: Revealed type is 'Union[typing.Mapping*[builtins.int, builtins.int], TypedDict(a=builtins.int, b=builtins.int, _fallback=typing.Mapping[builtins.str, builtins.int])]' -reveal_type(u(c, m_s_a)) # E: Revealed type is 'Union[typing.Mapping*[builtins.str, Any], TypedDict(a=builtins.int, b=builtins.int, _fallback=typing.Mapping[builtins.str, builtins.int])]' -[builtins fixtures/dict.pyi] diff --git a/test-data/unit/check-unions.test b/test-data/unit/check-unions.test index 4f2539f10a43..f6a149e354b8 100644 --- a/test-data/unit/check-unions.test +++ b/test-data/unit/check-unions.test @@ -37,7 +37,7 @@ def f(x: Union[int, str]) -> None: [case testUnionAnyIsInstance] from typing import Any, Union -def func(v: Union[int, Any]) -> None: +def func(v:Union[int, Any]) -> None: if isinstance(v, int): reveal_type(v) # E: Revealed type is 'builtins.int' else: @@ -61,8 +61,7 @@ y = w.y z = w.y # E: Incompatible types in assignment (expression has type "int", variable has type "str") w.y = 'a' # E: Incompatible types in assignment (expression has type "str", variable has type "int") y = x.y # E: Some element of union has no attribute "y" -zz = x.y # E: Some element of union has no attribute "y" -z = zz # E: Incompatible types in assignment (expression has type "Union[int, Any]", variable has type "str") +z = x.y # E: Some element of union has no attribute "y" [builtins fixtures/isinstance.pyi] @@ -187,8 +186,9 @@ a = None # type: Any reveal_type(u(C(), None)) # E: Revealed type is '__main__.C*' reveal_type(u(None, C())) # E: Revealed type is '__main__.C*' -reveal_type(u(C(), a)) # E: Revealed type is 'Union[Any, __main__.C*]' -reveal_type(u(a, C())) # E: Revealed type is 'Union[__main__.C*, Any]' +# This will be fixed later +reveal_type(u(C(), a)) # E: Revealed type is 'Any' +reveal_type(u(a, C())) # E: Revealed type is 'Any' reveal_type(u(C(), C())) # E: Revealed type is '__main__.C*' reveal_type(u(a, a)) # E: Revealed type is 'Any' @@ -220,219 +220,3 @@ class M(Generic[V]): def f(x: M[C]) -> None: y = x.get(None) reveal_type(y) # E: Revealed type is '__main__.C' - -[case testUnionSimplificationSpecialCases] -from typing import Any, TypeVar, Union - -class C(Any): pass - -T = TypeVar('T') -S = TypeVar('S') -def u(x: T, y: S) -> Union[S, T]: pass - -a = None # type: Any - -# Base-class-Any and None, simplify -reveal_type(u(C(), None)) # E: Revealed type is '__main__.C*' -reveal_type(u(None, C())) # E: Revealed type is '__main__.C*' - -# Normal instance type and None, simplify -reveal_type(u(1, None)) # E: Revealed type is 'builtins.int*' -reveal_type(u(None, 1)) # E: Revealed type is 'builtins.int*' - -# Normal instance type and base-class-Any, no simplification -reveal_type(u(C(), 1)) # E: Revealed type is 'Union[builtins.int*, __main__.C*]' -reveal_type(u(1, C())) # E: Revealed type is 'Union[__main__.C*, builtins.int*]' - -# Normal instance type and Any, no simplification -reveal_type(u(1, a)) # E: Revealed type is 'Union[Any, builtins.int*]' -reveal_type(u(a, 1)) # E: Revealed type is 'Union[builtins.int*, Any]' - -# Any and base-class-Any, no simplificaiton -reveal_type(u(C(), a)) # E: Revealed type is 'Union[Any, __main__.C*]' -reveal_type(u(a, C())) # E: Revealed type is 'Union[__main__.C*, Any]' - -# Two normal instance types, simplify -reveal_type(u(1, object())) # E: Revealed type is 'builtins.object*' -reveal_type(u(object(), 1)) # E: Revealed type is 'builtins.object*' - -# Two normal instance types, no simplification -reveal_type(u(1, '')) # E: Revealed type is 'Union[builtins.str*, builtins.int*]' -reveal_type(u('', 1)) # E: Revealed type is 'Union[builtins.int*, builtins.str*]' - -[case testUnionSimplificationWithDuplicateItems] -from typing import Any, TypeVar, Union - -class C(Any): pass - -T = TypeVar('T') -S = TypeVar('S') -R = TypeVar('R') -def u(x: T, y: S, z: R) -> Union[R, S, T]: pass - -a = None # type: Any - -reveal_type(u(1, 1, 1)) # E: Revealed type is 'builtins.int*' -reveal_type(u(C(), C(), None)) # E: Revealed type is '__main__.C*' -reveal_type(u(a, a, 1)) # E: Revealed type is 'Union[builtins.int*, Any]' -reveal_type(u(a, C(), a)) # E: Revealed type is 'Union[Any, __main__.C*]' -reveal_type(u('', 1, 1)) # E: Revealed type is 'Union[builtins.int*, builtins.str*]' - -[case testUnionAndBinaryOperation] -from typing import Union -class A: pass -def f(x: Union[int, str, A]): - x + object() # E: Unsupported left operand type for + (some union) \ - # E: Unsupported operand types for + (likely involving Union) - -[case testNarrowingDownNamedTupleUnion] -from typing import NamedTuple, Union - -A = NamedTuple('A', [('y', int)]) -B = NamedTuple('B', [('x', int)]) -C = NamedTuple('C', [('x', int)]) - -def foo(a: Union[A, B, C]): - if isinstance(a, (B, C)): - reveal_type(a) # E: Revealed type is 'Union[Tuple[builtins.int, fallback=__main__.B], Tuple[builtins.int, fallback=__main__.C]]' - a.x - a.y # E: Some element of union has no attribute "y" - b = a # type: Union[B, C] -[builtins fixtures/isinstance.pyi] - -[case testSimplifyingUnionAndTypePromotions] -from typing import TypeVar, Union -T = TypeVar('T') -S = TypeVar('S') -def u(x: T, y: S) -> Union[S, T]: pass - -reveal_type(u(1, 2.3)) # E: Revealed type is 'builtins.float*' -reveal_type(u(2.3, 1)) # E: Revealed type is 'builtins.float*' -reveal_type(u(False, 2.2)) # E: Revealed type is 'builtins.float*' -reveal_type(u(2.2, False)) # E: Revealed type is 'builtins.float*' -[builtins fixtures/primitives.pyi] - -[case testSimplifyingUnionWithTypeTypes1] -from typing import TypeVar, Union, Type, Any - -T = TypeVar('T') -S = TypeVar('S') -def u(x: T, y: S) -> Union[S, T]: pass - -t_o = None # type: Type[object] -t_s = None # type: Type[str] -t_a = None # type: Type[Any] - -# Two identical items -reveal_type(u(t_o, t_o)) # E: Revealed type is 'Type[builtins.object]' -reveal_type(u(t_s, t_s)) # E: Revealed type is 'Type[builtins.str]' -reveal_type(u(t_a, t_a)) # E: Revealed type is 'Type[Any]' -reveal_type(u(type, type)) # E: Revealed type is 'def (x: builtins.Any) -> builtins.type' - -# One type, other non-type -reveal_type(u(t_s, 1)) # E: Revealed type is 'Union[builtins.int*, Type[builtins.str]]' -reveal_type(u(1, t_s)) # E: Revealed type is 'Union[Type[builtins.str], builtins.int*]' -reveal_type(u(type, 1)) # E: Revealed type is 'Union[builtins.int*, def (x: builtins.Any) -> builtins.type]' -reveal_type(u(1, type)) # E: Revealed type is 'Union[def (x: builtins.Any) -> builtins.type, builtins.int*]' -reveal_type(u(t_a, 1)) # E: Revealed type is 'Union[builtins.int*, Type[Any]]' -reveal_type(u(1, t_a)) # E: Revealed type is 'Union[Type[Any], builtins.int*]' -reveal_type(u(t_o, 1)) # E: Revealed type is 'Union[builtins.int*, Type[builtins.object]]' -reveal_type(u(1, t_o)) # E: Revealed type is 'Union[Type[builtins.object], builtins.int*]' - -[case testSimplifyingUnionWithTypeTypes2] -from typing import TypeVar, Union, Type, Any - -T = TypeVar('T') -S = TypeVar('S') -def u(x: T, y: S) -> Union[S, T]: pass - -t_o = None # type: Type[object] -t_s = None # type: Type[str] -t_a = None # type: Type[Any] -t = None # type: type - -# Union with object -reveal_type(u(t_o, object())) # E: Revealed type is 'builtins.object*' -reveal_type(u(object(), t_o)) # E: Revealed type is 'builtins.object*' -reveal_type(u(t_s, object())) # E: Revealed type is 'builtins.object*' -reveal_type(u(object(), t_s)) # E: Revealed type is 'builtins.object*' -reveal_type(u(t_a, object())) # E: Revealed type is 'builtins.object*' -reveal_type(u(object(), t_a)) # E: Revealed type is 'builtins.object*' - -# Union between type objects -reveal_type(u(t_o, t_a)) # E: Revealed type is 'Union[Type[Any], Type[builtins.object]]' -reveal_type(u(t_a, t_o)) # E: Revealed type is 'Union[Type[builtins.object], Type[Any]]' -reveal_type(u(t_s, t_o)) # E: Revealed type is 'Type[builtins.object]' -reveal_type(u(t_o, t_s)) # E: Revealed type is 'Type[builtins.object]' -reveal_type(u(t_o, type)) # E: Revealed type is 'Type[builtins.object]' -reveal_type(u(type, t_o)) # E: Revealed type is 'Type[builtins.object]' -reveal_type(u(t_a, t)) # E: Revealed type is 'builtins.type*' -reveal_type(u(t, t_a)) # E: Revealed type is 'builtins.type*' -# The following should arguably not be simplified, but it's unclear how to fix then -# without causing regressions elsewhere. -reveal_type(u(t_o, t)) # E: Revealed type is 'builtins.type*' -reveal_type(u(t, t_o)) # E: Revealed type is 'builtins.type*' - -[case testNotSimplifyingUnionWithMetaclass] -from typing import TypeVar, Union, Type, Any - -class M(type): pass -class M2(M): pass -class A(metaclass=M): pass - -T = TypeVar('T') -S = TypeVar('S') -def u(x: T, y: S) -> Union[S, T]: pass - -a: Any -t_a: Type[A] - -reveal_type(u(M(*a), t_a)) # E: Revealed type is 'Union[Type[__main__.A], __main__.M*]' -reveal_type(u(t_a, M(*a))) # E: Revealed type is 'Union[__main__.M*, Type[__main__.A]]' - -reveal_type(u(M2(*a), t_a)) # E: Revealed type is 'Union[Type[__main__.A], __main__.M2*]' -reveal_type(u(t_a, M2(*a))) # E: Revealed type is 'Union[__main__.M2*, Type[__main__.A]]' - -[case testSimplifyUnionWithCallable] -from typing import TypeVar, Union, Any, Callable - -T = TypeVar('T') -S = TypeVar('S') -def u(x: T, y: S) -> Union[S, T]: pass - -class C: pass -class D(C): pass - -D_C: Callable[[D], C] -A_C: Callable[[Any], C] -D_A: Callable[[D], Any] -C_C: Callable[[C], C] -D_D: Callable[[D], D] -i_C: Callable[[int], C] - -# TODO: Test argument names and kinds once we have flexible callable types. - -reveal_type(u(D_C, D_C)) # E: Revealed type is 'def (__main__.D) -> __main__.C' - -reveal_type(u(A_C, D_C)) # E: Revealed type is 'Union[def (__main__.D) -> __main__.C, def (Any) -> __main__.C]' -reveal_type(u(D_C, A_C)) # E: Revealed type is 'Union[def (Any) -> __main__.C, def (__main__.D) -> __main__.C]' - -reveal_type(u(D_A, D_C)) # E: Revealed type is 'Union[def (__main__.D) -> __main__.C, def (__main__.D) -> Any]' -reveal_type(u(D_C, D_A)) # E: Revealed type is 'Union[def (__main__.D) -> Any, def (__main__.D) -> __main__.C]' - -reveal_type(u(D_C, C_C)) # E: Revealed type is 'def (__main__.D) -> __main__.C' -reveal_type(u(C_C, D_C)) # E: Revealed type is 'def (__main__.D) -> __main__.C' - -reveal_type(u(D_C, D_D)) # E: Revealed type is 'def (__main__.D) -> __main__.C' -reveal_type(u(D_D, D_C)) # E: Revealed type is 'def (__main__.D) -> __main__.C' - -reveal_type(u(D_C, i_C)) # E: Revealed type is 'Union[def (builtins.int) -> __main__.C, def (__main__.D) -> __main__.C]' - -[case testUnionOperatorMethodSpecialCase] -from typing import Union -class C: - def __le__(self, x: 'C') -> int: ... -class D: - def __le__(self, other) -> int: ... -class E: - def __ge__(self, other: Union[C, D]) -> int: ... diff --git a/test-data/unit/fixtures/primitives.pyi b/test-data/unit/fixtures/primitives.pyi index 4b5611b0bace..3b0ba0ce3719 100644 --- a/test-data/unit/fixtures/primitives.pyi +++ b/test-data/unit/fixtures/primitives.pyi @@ -11,7 +11,7 @@ class int: def __add__(self, i: int) -> int: pass class float: pass class complex: pass -class bool(int): pass +class bool: pass class str: def __add__(self, s: str) -> str: pass def format(self, *args) -> str: pass