narrowing to generic shouldn't introduce new `Any`
Bug Report
If I don't put any Any (and don't import anything with Any), there shouldn't be any Any .
But if I use isinstance to narrow to a generic, a new Any is introduced.
To Reproduce
--strict
def f(x: object) -> None:
if isinstance(x, Iterable):
reveal_type(x) # `Iterable[Any]`
# an `Any` is introduced, when I didn't put any `Any` in my code
# should be `Iterable[object]`
for y in x:
reveal_type(y) # `Any` should be `object`
print(y + 3) # not safe - should report type error
This is with --strict
It's probably ok to put this Any there in the default mode.
Also, even in --strict, if narrowing from Any, then it's ok to narrow the type variable to Any.
def g(x: Any) -> None:
if isinstance(x, Iterable):
reveal_type(x)
# `Iterable[Any]` is ok here, because we narrowed from `Any`
for y in x:
reveal_type(y) # `Any`
print(y + 3) # silenced by `Any`
# current behavior here is good - want to make sure it's not lost
def h(x: Iterable[int] | None) -> None:
if isinstance(x, Iterable):
reveal_type(x) # `Iterable[int]`
for y in x:
reveal_type(y) # `int`
print(y + 3)
Your Environment
- Mypy version used: 1.8.0
- Mypy command-line flags: --strict
- Python version used: 3.12
From https://docs.python.org/3/library/typing.html#user-defined-generic-types: "Using a generic class without specifying type parameters assumes Any for each position."
isinstance(x, Iterable) is equivalent to isinstance(x, Iterable[Any]).
That is not something that should be followed if we want type safety, and mypy already recognizes this.
With --strict this reports an error:
x: Iterable = []