Do not narrow types to Never with binder (#18972) Fixes https://github.com/python/mypy/issues/18967 Fixes https://github.com/python/mypy/issues/16494 Fixes https://github.com/python/mypy/issues/15793 Fixes https://github.com/python/mypy/issues/12949 As you can see from updated test cases, it is kind of gray area, so whether we go this way will depend on the `mypy_primer` results (and also potentially on Dropbox internal code bases, where the above issue may cause problems).
diff --git a/mypy/checkexpr.py b/mypy/checkexpr.py index 3fa4df2..008e056 100644 --- a/mypy/checkexpr.py +++ b/mypy/checkexpr.py
@@ -6277,7 +6277,13 @@ known_type, restriction, prohibit_none_typevar_overlap=True ): return None - return narrow_declared_type(known_type, restriction) + narrowed = narrow_declared_type(known_type, restriction) + if isinstance(get_proper_type(narrowed), UninhabitedType): + # If we hit this case, it means that we can't reliably mark the code as + # unreachable, but the resulting type can't be expressed in type system. + # Falling back to restriction is more intuitive in most cases. + return restriction + return narrowed return known_type def has_abstract_type_part(self, caller_type: ProperType, callee_type: ProperType) -> bool:
diff --git a/test-data/unit/check-isinstance.test b/test-data/unit/check-isinstance.test index 49140bf..058db1e 100644 --- a/test-data/unit/check-isinstance.test +++ b/test-data/unit/check-isinstance.test
@@ -1812,9 +1812,9 @@ if issubclass(fm, Foo): reveal_type(fm) # N: Revealed type is "Type[__main__.Foo]" if issubclass(fm, Bar): - reveal_type(fm) # N: Revealed type is "Never" + reveal_type(fm) # N: Revealed type is "Type[__main__.Bar]" if issubclass(fm, Baz): - reveal_type(fm) # N: Revealed type is "Never" + reveal_type(fm) # N: Revealed type is "Type[__main__.Baz]" [builtins fixtures/isinstance.pyi] [case testIsinstanceAndNarrowTypeVariable]
diff --git a/test-data/unit/check-narrowing.test b/test-data/unit/check-narrowing.test index 1856ca2..dc2cfd4 100644 --- a/test-data/unit/check-narrowing.test +++ b/test-data/unit/check-narrowing.test
@@ -1284,7 +1284,7 @@ reveal_type(a) # N: Revealed type is "__main__.A" if type(b) is t: - reveal_type(b) # N: Revealed type is "Never" + reveal_type(b) # N: Revealed type is "T`-1" else: reveal_type(b) # N: Revealed type is "__main__.B" @@ -2413,3 +2413,14 @@ reveal_type(x) # N: Revealed type is "T`-1" return x [builtins fixtures/isinstance.pyi] + +[case testDoNotNarrowToNever] +def any(): + return 1 + +def f() -> None: + x = "a" + x = any() + assert isinstance(x, int) + reveal_type(x) # N: Revealed type is "builtins.int" +[builtins fixtures/isinstance.pyi]
diff --git a/test-data/unit/check-python310.test b/test-data/unit/check-python310.test index 016f505..a25a7b7 100644 --- a/test-data/unit/check-python310.test +++ b/test-data/unit/check-python310.test
@@ -1299,7 +1299,7 @@ match m: case a if a := 1: # E: Incompatible types in assignment (expression has type "int", variable has type "str") - reveal_type(a) # N: Revealed type is "Never" + reveal_type(a) # N: Revealed type is "Literal[1]?" [case testMatchAssigningPatternGuard] m: str