diff --git a/mypy/checker.py b/mypy/checker.py index 33705c98e10c..5df290b408f3 100644 --- a/mypy/checker.py +++ b/mypy/checker.py @@ -6591,12 +6591,19 @@ def find_isinstance_check_helper( if len(node.args) != 2: # the error will be reported elsewhere return {}, {} if literal(expr) == LITERAL_TYPE: - return conditional_types_to_typemaps( - expr, - *self.conditional_types_with_intersection( - self.lookup_type(expr), self.get_isinstance_type(node.args[1]), expr - ), + original_type = self.lookup_type(expr) + current_type = self.expr_checker.narrow_type_from_binder(expr, original_type) + yes_type, no_type = self.conditional_types_with_intersection( + original_type, self.get_isinstance_type(node.args[1]), expr ) + if ( + self.binder.get(expr) is not None + and yes_type is not None + and not has_any_type(current_type) + and is_subtype(current_type, yes_type, ignore_promotions=True) + ): + yes_type = current_type + return conditional_types_to_typemaps(expr, yes_type, no_type) elif refers_to_fullname(node.callee, "builtins.issubclass"): if len(node.args) != 2: # the error will be reported elsewhere return {}, {} @@ -9347,6 +9354,46 @@ def is_valid_inferred_type( return not typ.accept(InvalidInferredTypes()) +def has_any_type(typ: Type) -> bool: + return _has_any_type(typ, set()) + + +def _has_any_type(typ: Type, seen: set[int]) -> bool: + if id(typ) in seen: + return False + seen.add(id(typ)) + if isinstance(typ, TypeAliasType): + return any(_has_any_type(arg, seen) for arg in typ.args) + proper_type = get_proper_type(typ) + if isinstance(proper_type, AnyType): + return proper_type.type_of_any != TypeOfAny.special_form + if isinstance(proper_type, Instance): + return any(_has_any_type(arg, seen) for arg in proper_type.args) + if isinstance(proper_type, UnionType): + return any(_has_any_type(item, seen) for item in proper_type.items) + if isinstance(proper_type, TupleType): + return any(_has_any_type(item, seen) for item in proper_type.items) + if isinstance(proper_type, CallableType): + return any(_has_any_type(arg, seen) for arg in proper_type.arg_types) or _has_any_type( + proper_type.ret_type, seen + ) + if isinstance(proper_type, TypeType): + return _has_any_type(proper_type.item, seen) + if isinstance(proper_type, TypeVarType): + return any(_has_any_type(value, seen) for value in proper_type.values) or _has_any_type( + proper_type.upper_bound, seen + ) + if isinstance(proper_type, TypeVarTupleType): + return _has_any_type(proper_type.upper_bound, seen) + if isinstance(proper_type, TypedDictType): + return any(_has_any_type(item, seen) for item in proper_type.items.values()) + if isinstance(proper_type, Overloaded): + return any(_has_any_type(item, seen) for item in proper_type.items) + if isinstance(proper_type, UnpackType): + return _has_any_type(proper_type.type, seen) + return False + + class InvalidInferredTypes(BoolTypeQuery): """Find type components that are not valid for an inferred type. diff --git a/mypy/ipc.py b/mypy/ipc.py index 08ca0caf75f1..e02499302b00 100644 --- a/mypy/ipc.py +++ b/mypy/ipc.py @@ -340,7 +340,7 @@ def connection_name(self) -> str: # for AF_UNIX sockets return os.path.join(self.sock_directory, self.name) else: - name = self.sock.getsockname() + name: object = self.sock.getsockname() assert isinstance(name, str) return name diff --git a/test-data/unit/check-typeis.test b/test-data/unit/check-typeis.test index 65ee837452f5..6b63f9aa080c 100644 --- a/test-data/unit/check-typeis.test +++ b/test-data/unit/check-typeis.test @@ -26,6 +26,25 @@ def main(a: Union[Point, Line, int]) -> None: [builtins fixtures/tuple.pyi] +[case testTypeIsAndIsinstanceWithGenericAlias] +from typing import Any, Generic, TypeVar +from typing_extensions import TypeAlias, TypeIs + +T = TypeVar("T") +class Slice(Generic[T]): pass + +SliceInt: TypeAlias = Slice[int | None] +SliceStr: TypeAlias = Slice[str | None] + +def is_slice_int(obj: Any) -> TypeIs[SliceInt]: pass + +def main(obj: SliceInt | SliceStr) -> None: + if is_slice_int(obj): + pass + elif isinstance(obj, Slice): + reveal_type(obj) # N: Revealed type is "__main__.Slice[builtins.str | None]" +[builtins fixtures/isinstance.pyi] + [case testTypeIsTypeArgsNone] from typing_extensions import TypeIs def foo(a: object) -> TypeIs: # E: TypeIs must have exactly one type argument