From 84395cf4fe23f4cfeb2e211f0837661726258b03 Mon Sep 17 00:00:00 2001 From: Jelle Zijlstra Date: Mon, 17 May 2021 20:58:23 -0700 Subject: [PATCH 1/7] failing test case --- test-data/unit/check-typeguard.test | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/test-data/unit/check-typeguard.test b/test-data/unit/check-typeguard.test index 52beb2836485..7428a2d5540c 100644 --- a/test-data/unit/check-typeguard.test +++ b/test-data/unit/check-typeguard.test @@ -294,3 +294,18 @@ class C: class D(C): def is_float(self, a: object) -> bool: pass # E: Signature of "is_float" incompatible with supertype "C" [builtins fixtures/tuple.pyi] + +[case testTypeGuardInAnd] +from typing import Any +from typing_extensions import TypeGuard +import types +def isclass(a: object) -> bool: + pass +def ismethod(a: object) -> TypeGuard[float]: + pass +def isclassmethod(obj: Any) -> bool: + if ismethod(obj) and obj.__self__ is not None and isclass(obj.__self__): # E: "float" has no attribute "__self__" + return True + + return False +[builtins fixtures/classmethod.pyi] From acc5b9efca2d545d158de77062ea9db1dd7a41e0 Mon Sep 17 00:00:00 2001 From: Jelle Zijlstra Date: Mon, 17 May 2021 21:22:25 -0700 Subject: [PATCH 2/7] fix the bug --- mypy/sametypes.py | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/mypy/sametypes.py b/mypy/sametypes.py index 024333a13ec8..b7a02799fc73 100644 --- a/mypy/sametypes.py +++ b/mypy/sametypes.py @@ -1,7 +1,7 @@ from typing import Sequence from mypy.types import ( - Type, UnboundType, AnyType, NoneType, TupleType, TypedDictType, + Type, TypeGuardType, UnboundType, AnyType, NoneType, TupleType, TypedDictType, UnionType, CallableType, TypeVarType, Instance, TypeVisitor, ErasedType, Overloaded, PartialType, DeletedType, UninhabitedType, TypeType, LiteralType, ProperType, get_proper_type, TypeAliasType) @@ -10,6 +10,14 @@ def is_same_type(left: Type, right: Type) -> bool: """Is 'left' the same type as 'right'?""" + + # TypeGuard are not ProperTypes so we must treat them specially. + if isinstance(left, TypeGuardType): + if not isinstance(right, TypeGuardType): + return False + else: + return is_same_type(left.type_guard, right.type_guard) + left = get_proper_type(left) right = get_proper_type(right) From 2e5116aa5c0cf293fab8a030f897ab3c5a1b1193 Mon Sep 17 00:00:00 2001 From: Jelle Zijlstra Date: Mon, 17 May 2021 21:30:58 -0700 Subject: [PATCH 3/7] another case --- test-data/unit/check-typeguard.test | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/test-data/unit/check-typeguard.test b/test-data/unit/check-typeguard.test index 7428a2d5540c..fa340cb04044 100644 --- a/test-data/unit/check-typeguard.test +++ b/test-data/unit/check-typeguard.test @@ -303,9 +303,15 @@ def isclass(a: object) -> bool: pass def ismethod(a: object) -> TypeGuard[float]: pass +def isfunction(a: object) -> TypeGuard[str]: + pass def isclassmethod(obj: Any) -> bool: if ismethod(obj) and obj.__self__ is not None and isclass(obj.__self__): # E: "float" has no attribute "__self__" return True return False +def coverage(obj: Any) -> bool: + if not (ismethod(obj) or isfunction(obj)): + return True + return False [builtins fixtures/classmethod.pyi] From 91e9364e50109ae3b5d62686150e1747aa52f608 Mon Sep 17 00:00:00 2001 From: Jelle Zijlstra Date: Mon, 17 May 2021 21:45:40 -0700 Subject: [PATCH 4/7] bite the bullet and build the visitors --- mypy/constraints.py | 5 ++++- mypy/erasetype.py | 5 ++++- mypy/expandtype.py | 5 ++++- mypy/fixup.py | 5 ++++- mypy/indirection.py | 3 +++ mypy/join.py | 5 ++++- mypy/meet.py | 5 ++++- mypy/sametypes.py | 13 ++++++------- mypy/server/astdiff.py | 5 ++++- mypy/server/astmerge.py | 5 ++++- mypy/server/deps.py | 5 ++++- mypy/subtypes.py | 9 ++++++++- mypy/type_visitor.py | 12 +++++++++++- mypy/typeanal.py | 5 ++++- mypy/types.py | 20 +++++++++++++------- mypy/typetraverser.py | 5 ++++- 16 files changed, 85 insertions(+), 27 deletions(-) diff --git a/mypy/constraints.py b/mypy/constraints.py index 7e1de292abec..8beee0983dc4 100644 --- a/mypy/constraints.py +++ b/mypy/constraints.py @@ -4,7 +4,7 @@ from typing_extensions import Final from mypy.types import ( - CallableType, Type, TypeVisitor, UnboundType, AnyType, NoneType, TypeVarType, Instance, + CallableType, Type, TypeGuardType, TypeVisitor, UnboundType, AnyType, NoneType, TypeVarType, Instance, TupleType, TypedDictType, UnionType, Overloaded, ErasedType, PartialType, DeletedType, UninhabitedType, TypeType, TypeVarId, TypeQuery, is_named_instance, TypeOfAny, LiteralType, ProperType, get_proper_type, TypeAliasType @@ -534,6 +534,9 @@ def visit_union_type(self, template: UnionType) -> List[Constraint]: def visit_type_alias_type(self, template: TypeAliasType) -> List[Constraint]: assert False, "This should be never called, got {}".format(template) + def visit_type_guard_type(self, template: TypeGuardType) -> List[Constraint]: + assert False, "This should be never called, got {}".format(template) + def infer_against_any(self, types: Iterable[Type], any_type: AnyType) -> List[Constraint]: res = [] # type: List[Constraint] for t in types: diff --git a/mypy/erasetype.py b/mypy/erasetype.py index 7a56eceacf5f..0dc764e1f3ce 100644 --- a/mypy/erasetype.py +++ b/mypy/erasetype.py @@ -1,7 +1,7 @@ from typing import Optional, Container, Callable from mypy.types import ( - Type, TypeVisitor, UnboundType, AnyType, NoneType, TypeVarId, Instance, TypeVarType, + Type, TypeGuardType, TypeVisitor, UnboundType, AnyType, NoneType, TypeVarId, Instance, TypeVarType, CallableType, TupleType, TypedDictType, UnionType, Overloaded, ErasedType, PartialType, DeletedType, TypeTranslator, UninhabitedType, TypeType, TypeOfAny, LiteralType, ProperType, get_proper_type, TypeAliasType @@ -90,6 +90,9 @@ def visit_union_type(self, t: UnionType) -> ProperType: from mypy.typeops import make_simplified_union return make_simplified_union(erased_items) + def visit_type_guard_type(self, t: TypeGuardType) -> ProperType: + return TypeGuardType(t.type_guard.accept(self)) + def visit_type_type(self, t: TypeType) -> ProperType: return TypeType.make_normalized(t.item.accept(self), line=t.line) diff --git a/mypy/expandtype.py b/mypy/expandtype.py index f98e0750743b..c9a1a2430afb 100644 --- a/mypy/expandtype.py +++ b/mypy/expandtype.py @@ -1,7 +1,7 @@ from typing import Dict, Iterable, List, TypeVar, Mapping, cast from mypy.types import ( - Type, Instance, CallableType, TypeVisitor, UnboundType, AnyType, + Type, Instance, CallableType, TypeGuardType, TypeVisitor, UnboundType, AnyType, NoneType, TypeVarType, Overloaded, TupleType, TypedDictType, UnionType, ErasedType, PartialType, DeletedType, UninhabitedType, TypeType, TypeVarId, FunctionLike, TypeVarDef, LiteralType, get_proper_type, ProperType, @@ -126,6 +126,9 @@ def visit_union_type(self, t: UnionType) -> Type: from mypy.typeops import make_simplified_union # asdf return make_simplified_union(self.expand_types(t.items), t.line, t.column) + def visit_type_guard_type(self, t: TypeGuardType) -> ProperType: + return TypeGuardType(t.type_guard.accept(self)) + def visit_partial_type(self, t: PartialType) -> Type: return t diff --git a/mypy/fixup.py b/mypy/fixup.py index b90dba971e4f..f995ad36f0f6 100644 --- a/mypy/fixup.py +++ b/mypy/fixup.py @@ -9,7 +9,7 @@ TypeVarExpr, ClassDef, Block, TypeAlias, ) from mypy.types import ( - CallableType, Instance, Overloaded, TupleType, TypedDictType, + CallableType, Instance, Overloaded, TupleType, TypeGuardType, TypedDictType, TypeVarType, UnboundType, UnionType, TypeVisitor, LiteralType, TypeType, NOT_READY, TypeAliasType, AnyType, TypeOfAny, TypeVarDef ) @@ -254,6 +254,9 @@ def visit_union_type(self, ut: UnionType) -> None: for it in ut.items: it.accept(self) + def visit_type_guard_type(self, t: TypeGuardType) -> None: + t.type_guard.accept(self) + def visit_void(self, o: Any) -> None: pass # Nothing to descend into. diff --git a/mypy/indirection.py b/mypy/indirection.py index 307628c2abc5..aff942ce9393 100644 --- a/mypy/indirection.py +++ b/mypy/indirection.py @@ -97,6 +97,9 @@ def visit_literal_type(self, t: types.LiteralType) -> Set[str]: def visit_union_type(self, t: types.UnionType) -> Set[str]: return self._visit(t.items) + def visit_type_guard_type(self, t: types.TypeGuardType) -> Set[str]: + return self._visit(t.type_guard) + def visit_partial_type(self, t: types.PartialType) -> Set[str]: return set() diff --git a/mypy/join.py b/mypy/join.py index d4e6051b55af..df4525667d26 100644 --- a/mypy/join.py +++ b/mypy/join.py @@ -4,7 +4,7 @@ from typing import List, Optional from mypy.types import ( - Type, AnyType, NoneType, TypeVisitor, Instance, UnboundType, TypeVarType, CallableType, + Type, AnyType, NoneType, TypeGuardType, TypeVisitor, Instance, UnboundType, TypeVarType, CallableType, TupleType, TypedDictType, ErasedType, UnionType, FunctionLike, Overloaded, LiteralType, PartialType, DeletedType, UninhabitedType, TypeType, TypeOfAny, get_proper_type, ProperType, get_proper_types, TypeAliasType, PlaceholderType @@ -340,6 +340,9 @@ def visit_type_type(self, t: TypeType) -> ProperType: def visit_type_alias_type(self, t: TypeAliasType) -> ProperType: assert False, "This should be never called, got {}".format(t) + def visit_type_guard_type(self, t: TypeGuardType) -> ProperType: + assert False, "This should be never called, got {}".format(t) + def join(self, s: Type, t: Type) -> ProperType: return join_types(s, t) diff --git a/mypy/meet.py b/mypy/meet.py index 6170396517b9..3f997247e29d 100644 --- a/mypy/meet.py +++ b/mypy/meet.py @@ -5,7 +5,7 @@ is_similar_callables, combine_similar_callables, join_type_list, unpack_callback_protocol ) from mypy.types import ( - Type, AnyType, TypeVisitor, UnboundType, NoneType, TypeVarType, Instance, CallableType, + Type, AnyType, TypeGuardType, TypeVisitor, UnboundType, NoneType, TypeVarType, Instance, CallableType, TupleType, TypedDictType, ErasedType, UnionType, PartialType, DeletedType, UninhabitedType, TypeType, TypeOfAny, Overloaded, FunctionLike, LiteralType, ProperType, get_proper_type, get_proper_types, TypeAliasType @@ -648,6 +648,9 @@ def visit_type_type(self, t: TypeType) -> ProperType: def visit_type_alias_type(self, t: TypeAliasType) -> ProperType: assert False, "This should be never called, got {}".format(t) + def visit_type_guard_type(self, t: TypeGuardType) -> ProperType: + assert False, "This should be never called, got {}".format(t) + def meet(self, s: Type, t: Type) -> ProperType: return meet_types(s, t) diff --git a/mypy/sametypes.py b/mypy/sametypes.py index b7a02799fc73..f599cc2f7b14 100644 --- a/mypy/sametypes.py +++ b/mypy/sametypes.py @@ -11,13 +11,6 @@ def is_same_type(left: Type, right: Type) -> bool: """Is 'left' the same type as 'right'?""" - # TypeGuard are not ProperTypes so we must treat them specially. - if isinstance(left, TypeGuardType): - if not isinstance(right, TypeGuardType): - return False - else: - return is_same_type(left.type_guard, right.type_guard) - left = get_proper_type(left) right = get_proper_type(right) @@ -158,6 +151,12 @@ def visit_union_type(self, left: UnionType) -> bool: else: return False + def visit_type_guard_type(self, left: TypeGuardType) -> bool: + if isinstance(self.right, TypeGuardType): + return is_same_type(left.type_guard, self.right.type_guard) + else: + return False + def visit_overloaded(self, left: Overloaded) -> bool: if isinstance(self.right, Overloaded): return is_same_types(left.items(), self.right.items()) diff --git a/mypy/server/astdiff.py b/mypy/server/astdiff.py index 9893092882b5..f74f3f35c7e1 100644 --- a/mypy/server/astdiff.py +++ b/mypy/server/astdiff.py @@ -57,7 +57,7 @@ class level -- these are handled at attribute level (say, 'mod.Cls.method' FuncBase, OverloadedFuncDef, FuncItem, MypyFile, UNBOUND_IMPORTED ) from mypy.types import ( - Type, TypeVisitor, UnboundType, AnyType, NoneType, UninhabitedType, + Type, TypeGuardType, TypeVisitor, UnboundType, AnyType, NoneType, UninhabitedType, ErasedType, DeletedType, Instance, TypeVarType, CallableType, TupleType, TypedDictType, UnionType, Overloaded, PartialType, TypeType, LiteralType, TypeAliasType ) @@ -335,6 +335,9 @@ def visit_union_type(self, typ: UnionType) -> SnapshotItem: normalized = tuple(sorted(items)) return ('UnionType', normalized) + def visit_type_guard_type(self, typ: TypeGuardType) -> SnapshotItem: + return ('TypeGuardType', snapshot_type(typ.type_guard)) + def visit_overloaded(self, typ: Overloaded) -> SnapshotItem: return ('Overloaded', snapshot_types(typ.items())) diff --git a/mypy/server/astmerge.py b/mypy/server/astmerge.py index 1c411886ac7d..70689003b6be 100644 --- a/mypy/server/astmerge.py +++ b/mypy/server/astmerge.py @@ -57,7 +57,7 @@ from mypy.traverser import TraverserVisitor from mypy.types import ( Type, SyntheticTypeVisitor, Instance, AnyType, NoneType, CallableType, ErasedType, DeletedType, - TupleType, TypeType, TypeVarType, TypedDictType, UnboundType, UninhabitedType, UnionType, + TupleType, TypeGuardType, TypeType, TypeVarType, TypedDictType, UnboundType, UninhabitedType, UnionType, Overloaded, TypeVarDef, TypeList, CallableArgument, EllipsisType, StarType, LiteralType, RawExpressionType, PartialType, PlaceholderType, TypeAliasType ) @@ -389,6 +389,9 @@ def visit_erased_type(self, t: ErasedType) -> None: def visit_deleted_type(self, typ: DeletedType) -> None: pass + def visit_type_guard_type(self, typ: TypeGuardType) -> None: + raise RuntimeError + def visit_partial_type(self, typ: PartialType) -> None: raise RuntimeError diff --git a/mypy/server/deps.py b/mypy/server/deps.py index 78acc1d9e376..89679b1d21b3 100644 --- a/mypy/server/deps.py +++ b/mypy/server/deps.py @@ -94,7 +94,7 @@ class 'mod.Cls'. This can also refer to an attribute inherited from a ) from mypy.traverser import TraverserVisitor from mypy.types import ( - Type, Instance, AnyType, NoneType, TypeVisitor, CallableType, DeletedType, PartialType, + Type, Instance, AnyType, NoneType, TypeGuardType, TypeVisitor, CallableType, DeletedType, PartialType, TupleType, TypeType, TypeVarType, TypedDictType, UnboundType, UninhabitedType, UnionType, FunctionLike, Overloaded, TypeOfAny, LiteralType, ErasedType, get_proper_type, ProperType, TypeAliasType) @@ -970,6 +970,9 @@ def visit_unbound_type(self, typ: UnboundType) -> List[str]: def visit_uninhabited_type(self, typ: UninhabitedType) -> List[str]: return [] + def visit_type_guard_type(self, typ: TypeGuardType) -> List[str]: + return typ.type_guard.accept(self) + def visit_union_type(self, typ: UnionType) -> List[str]: triggers = [] for item in typ.items: diff --git a/mypy/subtypes.py b/mypy/subtypes.py index c3b8b82a3c2c..8c67b2d15baf 100644 --- a/mypy/subtypes.py +++ b/mypy/subtypes.py @@ -4,7 +4,7 @@ from typing_extensions import Final from mypy.types import ( - Type, AnyType, UnboundType, TypeVisitor, FormalArgument, NoneType, + Type, AnyType, TypeGuardType, UnboundType, TypeVisitor, FormalArgument, NoneType, Instance, TypeVarType, CallableType, TupleType, TypedDictType, UnionType, Overloaded, ErasedType, PartialType, DeletedType, UninhabitedType, TypeType, is_named_instance, FunctionLike, TypeOfAny, LiteralType, get_proper_type, TypeAliasType @@ -475,6 +475,9 @@ def visit_overloaded(self, left: Overloaded) -> bool: def visit_union_type(self, left: UnionType) -> bool: return all(self._is_subtype(item, self.orig_right) for item in left.items) + def visit_type_guard_type(self, left: TypeGuardType) -> bool: + raise RuntimeError("TypeGuard should not appear here") + def visit_partial_type(self, left: PartialType) -> bool: # This is indeterminate as we don't really know the complete type yet. raise RuntimeError @@ -1374,6 +1377,10 @@ def visit_overloaded(self, left: Overloaded) -> bool: def visit_union_type(self, left: UnionType) -> bool: return all([self._is_proper_subtype(item, self.orig_right) for item in left.items]) + def visit_type_guard_type(self, left: TypeGuardType) -> bool: + # TODO: What's the right thing to do here? + return False + def visit_partial_type(self, left: PartialType) -> bool: # TODO: What's the right thing to do here? return False diff --git a/mypy/type_visitor.py b/mypy/type_visitor.py index 8a95ceb049af..a0e6299a5a8a 100644 --- a/mypy/type_visitor.py +++ b/mypy/type_visitor.py @@ -19,7 +19,7 @@ T = TypeVar('T') from mypy.types import ( - Type, AnyType, CallableType, Overloaded, TupleType, TypedDictType, LiteralType, + Type, AnyType, CallableType, Overloaded, TupleType, TypeGuardType, TypedDictType, LiteralType, RawExpressionType, Instance, NoneType, TypeType, UnionType, TypeVarType, PartialType, DeletedType, UninhabitedType, TypeVarLikeDef, UnboundType, ErasedType, StarType, EllipsisType, TypeList, CallableArgument, @@ -103,6 +103,10 @@ def visit_type_type(self, t: TypeType) -> T: def visit_type_alias_type(self, t: TypeAliasType) -> T: pass + @abstractmethod + def visit_type_guard_type(self, t: TypeGuardType) -> T: + pass + @trait @mypyc_attr(allow_interpreted_subclasses=True) @@ -220,6 +224,9 @@ def visit_union_type(self, t: UnionType) -> Type: def translate_types(self, types: Iterable[Type]) -> List[Type]: return [t.accept(self) for t in types] + def visit_type_guard_type(self, t: TypeGuardType) -> Type: + return TypeGuardType(t.type_guard.accept(self)) + def translate_variables(self, variables: Sequence[TypeVarLikeDef]) -> Sequence[TypeVarLikeDef]: return variables @@ -319,6 +326,9 @@ def visit_star_type(self, t: StarType) -> T: def visit_union_type(self, t: UnionType) -> T: return self.query_types(t.items) + def visit_type_guard_type(self, t: TypeGuardType) -> T: + return t.type_guard.accept(self) + def visit_overloaded(self, t: Overloaded) -> T: return self.query_types(t.items()) diff --git a/mypy/typeanal.py b/mypy/typeanal.py index ab32c5c8fa44..c3c7105ce2d0 100644 --- a/mypy/typeanal.py +++ b/mypy/typeanal.py @@ -12,7 +12,7 @@ from mypy.messages import MessageBuilder, quote_type_string, format_type_bare from mypy.options import Options from mypy.types import ( - Type, UnboundType, TypeVarType, TupleType, TypedDictType, UnionType, Instance, AnyType, + Type, TypeGuardType, UnboundType, TypeVarType, TupleType, TypedDictType, UnionType, Instance, AnyType, CallableType, NoneType, ErasedType, DeletedType, TypeList, TypeVarDef, SyntheticTypeVisitor, StarType, PartialType, EllipsisType, UninhabitedType, TypeType, CallableArgument, TypeQuery, union_items, TypeOfAny, LiteralType, RawExpressionType, @@ -542,6 +542,9 @@ def visit_callable_type(self, t: CallableType, nested: bool = True) -> Type: ) return ret + def visit_type_guard_type(self, t: TypeGuardType) -> Type: + return t + def anal_type_guard(self, t: Type) -> Optional[Type]: if isinstance(t, UnboundType): sym = self.lookup_qualified(t.name, t) diff --git a/mypy/types.py b/mypy/types.py index bf138f343b5a..5cf71cbca15f 100644 --- a/mypy/types.py +++ b/mypy/types.py @@ -270,7 +270,14 @@ def copy_modified(self, *, self.line, self.column) -class TypeGuardType(Type): +class ProperType(Type): + """Not a type alias. + + Every type except TypeAliasType must inherit from this type. + """ + + +class TypeGuardType(ProperType): """Only used by find_instance_check() etc.""" def __init__(self, type_guard: Type): super().__init__(line=type_guard.line, column=type_guard.column) @@ -279,12 +286,8 @@ def __init__(self, type_guard: Type): def __repr__(self) -> str: return "TypeGuard({})".format(self.type_guard) - -class ProperType(Type): - """Not a type alias. - - Every type except TypeAliasType must inherit from this type. - """ + def accept(self, visitor: 'TypeVisitor[T]') -> T: + return visitor.visit_type_guard_type(self) class TypeVarId: @@ -2185,6 +2188,9 @@ def visit_union_type(self, t: UnionType) -> str: s = self.list_str(t.items) return 'Union[{}]'.format(s) + def visit_type_guard_type(self, t: TypeGuardType) -> str: + return 'TypeGuard[{}]'.format(t.type_guard.accept(self)) + def visit_partial_type(self, t: PartialType) -> str: if t.type is None: return '' diff --git a/mypy/typetraverser.py b/mypy/typetraverser.py index 8d7459f7a551..a305139b0cb0 100644 --- a/mypy/typetraverser.py +++ b/mypy/typetraverser.py @@ -3,7 +3,7 @@ from mypy_extensions import trait from mypy.types import ( - Type, SyntheticTypeVisitor, AnyType, UninhabitedType, NoneType, ErasedType, DeletedType, + Type, SyntheticTypeVisitor, AnyType, TypeGuardType, UninhabitedType, NoneType, ErasedType, DeletedType, TypeVarType, LiteralType, Instance, CallableType, TupleType, TypedDictType, UnionType, Overloaded, TypeType, CallableArgument, UnboundType, TypeList, StarType, EllipsisType, PlaceholderType, PartialType, RawExpressionType, TypeAliasType @@ -62,6 +62,9 @@ def visit_typeddict_type(self, t: TypedDictType) -> None: def visit_union_type(self, t: UnionType) -> None: self.traverse_types(t.items) + def visit_type_guard_type(self, t: TypeGuardType) -> None: + t.type_guard.accept(self) + def visit_overloaded(self, t: Overloaded) -> None: self.traverse_types(t.items()) From 1724438958975b34d66fb1bb1b627e263d7c985f Mon Sep 17 00:00:00 2001 From: Jelle Zijlstra Date: Tue, 18 May 2021 05:48:44 -0700 Subject: [PATCH 5/7] fix lint --- mypy/constraints.py | 4 ++-- mypy/erasetype.py | 4 ++-- mypy/join.py | 4 ++-- mypy/meet.py | 4 ++-- mypy/server/astmerge.py | 4 ++-- mypy/server/deps.py | 5 +++-- mypy/typeanal.py | 4 ++-- mypy/typetraverser.py | 4 ++-- 8 files changed, 17 insertions(+), 16 deletions(-) diff --git a/mypy/constraints.py b/mypy/constraints.py index 8beee0983dc4..074f038a30bc 100644 --- a/mypy/constraints.py +++ b/mypy/constraints.py @@ -4,10 +4,10 @@ from typing_extensions import Final from mypy.types import ( - CallableType, Type, TypeGuardType, TypeVisitor, UnboundType, AnyType, NoneType, TypeVarType, Instance, + CallableType, Type, TypeVisitor, UnboundType, AnyType, NoneType, TypeVarType, Instance, TupleType, TypedDictType, UnionType, Overloaded, ErasedType, PartialType, DeletedType, UninhabitedType, TypeType, TypeVarId, TypeQuery, is_named_instance, TypeOfAny, LiteralType, - ProperType, get_proper_type, TypeAliasType + ProperType, get_proper_type, TypeAliasType, TypeGuardType ) from mypy.maptype import map_instance_to_supertype import mypy.subtypes diff --git a/mypy/erasetype.py b/mypy/erasetype.py index 0dc764e1f3ce..70b7c3b6de32 100644 --- a/mypy/erasetype.py +++ b/mypy/erasetype.py @@ -1,10 +1,10 @@ from typing import Optional, Container, Callable from mypy.types import ( - Type, TypeGuardType, TypeVisitor, UnboundType, AnyType, NoneType, TypeVarId, Instance, TypeVarType, + Type, TypeVisitor, UnboundType, AnyType, NoneType, TypeVarId, Instance, TypeVarType, CallableType, TupleType, TypedDictType, UnionType, Overloaded, ErasedType, PartialType, DeletedType, TypeTranslator, UninhabitedType, TypeType, TypeOfAny, LiteralType, ProperType, - get_proper_type, TypeAliasType + get_proper_type, TypeAliasType, TypeGuardType ) from mypy.nodes import ARG_STAR, ARG_STAR2 diff --git a/mypy/join.py b/mypy/join.py index df4525667d26..53a1fce973dc 100644 --- a/mypy/join.py +++ b/mypy/join.py @@ -4,10 +4,10 @@ from typing import List, Optional from mypy.types import ( - Type, AnyType, NoneType, TypeGuardType, TypeVisitor, Instance, UnboundType, TypeVarType, CallableType, + Type, AnyType, NoneType, TypeVisitor, Instance, UnboundType, TypeVarType, CallableType, TupleType, TypedDictType, ErasedType, UnionType, FunctionLike, Overloaded, LiteralType, PartialType, DeletedType, UninhabitedType, TypeType, TypeOfAny, get_proper_type, - ProperType, get_proper_types, TypeAliasType, PlaceholderType + ProperType, get_proper_types, TypeAliasType, PlaceholderType, TypeGuardType ) from mypy.maptype import map_instance_to_supertype from mypy.subtypes import ( diff --git a/mypy/meet.py b/mypy/meet.py index 3f997247e29d..558de6ec92c9 100644 --- a/mypy/meet.py +++ b/mypy/meet.py @@ -5,10 +5,10 @@ is_similar_callables, combine_similar_callables, join_type_list, unpack_callback_protocol ) from mypy.types import ( - Type, AnyType, TypeGuardType, TypeVisitor, UnboundType, NoneType, TypeVarType, Instance, CallableType, + Type, AnyType, TypeVisitor, UnboundType, NoneType, TypeVarType, Instance, CallableType, TupleType, TypedDictType, ErasedType, UnionType, PartialType, DeletedType, UninhabitedType, TypeType, TypeOfAny, Overloaded, FunctionLike, LiteralType, - ProperType, get_proper_type, get_proper_types, TypeAliasType + ProperType, get_proper_type, get_proper_types, TypeAliasType, TypeGuardType ) from mypy.subtypes import is_equivalent, is_subtype, is_callable_compatible, is_proper_subtype from mypy.erasetype import erase_type diff --git a/mypy/server/astmerge.py b/mypy/server/astmerge.py index 70689003b6be..8b9726019224 100644 --- a/mypy/server/astmerge.py +++ b/mypy/server/astmerge.py @@ -57,9 +57,9 @@ from mypy.traverser import TraverserVisitor from mypy.types import ( Type, SyntheticTypeVisitor, Instance, AnyType, NoneType, CallableType, ErasedType, DeletedType, - TupleType, TypeGuardType, TypeType, TypeVarType, TypedDictType, UnboundType, UninhabitedType, UnionType, + TupleType, TypeType, TypeVarType, TypedDictType, UnboundType, UninhabitedType, UnionType, Overloaded, TypeVarDef, TypeList, CallableArgument, EllipsisType, StarType, LiteralType, - RawExpressionType, PartialType, PlaceholderType, TypeAliasType + RawExpressionType, PartialType, PlaceholderType, TypeAliasType, TypeGuardType ) from mypy.util import get_prefix, replace_object_state from mypy.typestate import TypeState diff --git a/mypy/server/deps.py b/mypy/server/deps.py index 89679b1d21b3..9aee82664bd2 100644 --- a/mypy/server/deps.py +++ b/mypy/server/deps.py @@ -94,10 +94,11 @@ class 'mod.Cls'. This can also refer to an attribute inherited from a ) from mypy.traverser import TraverserVisitor from mypy.types import ( - Type, Instance, AnyType, NoneType, TypeGuardType, TypeVisitor, CallableType, DeletedType, PartialType, + Type, Instance, AnyType, NoneType, TypeVisitor, CallableType, DeletedType, PartialType, TupleType, TypeType, TypeVarType, TypedDictType, UnboundType, UninhabitedType, UnionType, FunctionLike, Overloaded, TypeOfAny, LiteralType, ErasedType, get_proper_type, ProperType, - TypeAliasType) + TypeAliasType, TypeGuardType +) from mypy.server.trigger import make_trigger, make_wildcard_trigger from mypy.util import correct_relative_import from mypy.scope import Scope diff --git a/mypy/typeanal.py b/mypy/typeanal.py index c3c7105ce2d0..8e2adfd56fbb 100644 --- a/mypy/typeanal.py +++ b/mypy/typeanal.py @@ -12,9 +12,9 @@ from mypy.messages import MessageBuilder, quote_type_string, format_type_bare from mypy.options import Options from mypy.types import ( - Type, TypeGuardType, UnboundType, TypeVarType, TupleType, TypedDictType, UnionType, Instance, AnyType, + Type, UnboundType, TypeVarType, TupleType, TypedDictType, UnionType, Instance, AnyType, CallableType, NoneType, ErasedType, DeletedType, TypeList, TypeVarDef, SyntheticTypeVisitor, - StarType, PartialType, EllipsisType, UninhabitedType, TypeType, + StarType, PartialType, EllipsisType, UninhabitedType, TypeType, TypeGuardType, CallableArgument, TypeQuery, union_items, TypeOfAny, LiteralType, RawExpressionType, PlaceholderType, Overloaded, get_proper_type, TypeAliasType, TypeVarLikeDef, ParamSpecDef ) diff --git a/mypy/typetraverser.py b/mypy/typetraverser.py index a305139b0cb0..e8f22a62e7c4 100644 --- a/mypy/typetraverser.py +++ b/mypy/typetraverser.py @@ -3,10 +3,10 @@ from mypy_extensions import trait from mypy.types import ( - Type, SyntheticTypeVisitor, AnyType, TypeGuardType, UninhabitedType, NoneType, ErasedType, DeletedType, + Type, SyntheticTypeVisitor, AnyType, UninhabitedType, NoneType, ErasedType, DeletedType, TypeVarType, LiteralType, Instance, CallableType, TupleType, TypedDictType, UnionType, Overloaded, TypeType, CallableArgument, UnboundType, TypeList, StarType, EllipsisType, - PlaceholderType, PartialType, RawExpressionType, TypeAliasType + PlaceholderType, PartialType, RawExpressionType, TypeAliasType, TypeGuardType ) From dace8afb3c505fd85fcf8a6205397c7832f8166b Mon Sep 17 00:00:00 2001 From: Jelle Zijlstra Date: Wed, 19 May 2021 07:01:29 -0700 Subject: [PATCH 6/7] error in subtype visitor --- mypy/subtypes.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/mypy/subtypes.py b/mypy/subtypes.py index 8c67b2d15baf..e86375e6965e 100644 --- a/mypy/subtypes.py +++ b/mypy/subtypes.py @@ -1378,8 +1378,7 @@ def visit_union_type(self, left: UnionType) -> bool: return all([self._is_proper_subtype(item, self.orig_right) for item in left.items]) def visit_type_guard_type(self, left: TypeGuardType) -> bool: - # TODO: What's the right thing to do here? - return False + raise RuntimeError("TypeGuard should not be used in subtype checks") def visit_partial_type(self, left: PartialType) -> bool: # TODO: What's the right thing to do here? From 892e6564cb5cea2df8cda5eade9dd45f6d7aaa58 Mon Sep 17 00:00:00 2001 From: Jelle Zijlstra Date: Wed, 19 May 2021 07:10:24 -0700 Subject: [PATCH 7/7] proper implementation instead --- mypy/subtypes.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/mypy/subtypes.py b/mypy/subtypes.py index e86375e6965e..ffcaf8f2bc92 100644 --- a/mypy/subtypes.py +++ b/mypy/subtypes.py @@ -1378,7 +1378,12 @@ def visit_union_type(self, left: UnionType) -> bool: return all([self._is_proper_subtype(item, self.orig_right) for item in left.items]) def visit_type_guard_type(self, left: TypeGuardType) -> bool: - raise RuntimeError("TypeGuard should not be used in subtype checks") + if isinstance(self.right, TypeGuardType): + # TypeGuard[bool] is a subtype of TypeGuard[int] + return self._is_proper_subtype(left.type_guard, self.right.type_guard) + else: + # TypeGuards aren't a subtype of anything else for now (but see #10489) + return False def visit_partial_type(self, left: PartialType) -> bool: # TODO: What's the right thing to do here?