Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 1 addition & 8 deletions mypy/checker.py
Original file line number Diff line number Diff line change
Expand Up @@ -6395,14 +6395,7 @@ def iterable_item_type(self, instance: Instance) -> Type:
# in case there is no explicit base class.
return item_type
# Try also structural typing.
ret_type, _ = self.expr_checker.check_method_call_by_name(
"__iter__", instance, [], [], instance
)
ret_type = get_proper_type(ret_type)
if isinstance(ret_type, Instance):
iterator = map_instance_to_supertype(ret_type, self.lookup_typeinfo("typing.Iterator"))
item_type = iterator.args[0]
return item_type
return self.analyze_iterable_item_type_without_expression(instance, instance)[1]

def function_type(self, func: FuncBase) -> FunctionLike:
return function_type(func, self.named_type("builtins.function"))
Expand Down
34 changes: 34 additions & 0 deletions test-data/unit/check-inference.test
Original file line number Diff line number Diff line change
Expand Up @@ -380,6 +380,8 @@ class Nums(Iterable[int]):
def __iter__(self): pass
def __next__(self): pass
a, b = Nums()
reveal_type(a) # N: Revealed type is "builtins.int"
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The other option here is to infer Any, because of def __iter__(self): pass

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yup, but as discussed in the issue, two long-standing tests fail if I make that change, so I'd rather not make that behaviour change in this PR 👍

reveal_type(b) # N: Revealed type is "builtins.int"
if int():
a = b = 1
if int():
Expand All @@ -388,6 +390,38 @@ if int():
b = '' # E: Incompatible types in assignment (expression has type "str", variable has type "int")
[builtins fixtures/for.pyi]

[case testInferringTypesFromIterableStructuralSubtyping1]
from typing import Iterator
class Nums:
def __iter__(self) -> Iterator[int]: pass
def __next__(self) -> int: pass
Comment thread
AlexWaygood marked this conversation as resolved.
Outdated
a, b = Nums()
reveal_type(a) # N: Revealed type is "builtins.int"
reveal_type(b) # N: Revealed type is "builtins.int"
if int():
a = b = 1
if int():
a = '' # E: Incompatible types in assignment (expression has type "str", variable has type "int")
if int():
b = '' # E: Incompatible types in assignment (expression has type "str", variable has type "int")
[builtins fixtures/for.pyi]

[case testInferringTypesFromIterableStructuralSubtyping2]
from typing import Self
class Nums:
def __iter__(self) -> Self: pass
def __next__(self) -> int: pass
a, b = Nums()
reveal_type(a) # N: Revealed type is "builtins.int"
reveal_type(b) # N: Revealed type is "builtins.int"
if int():
a = b = 1
if int():
a = '' # E: Incompatible types in assignment (expression has type "str", variable has type "int")
if int():
b = '' # E: Incompatible types in assignment (expression has type "str", variable has type "int")
[builtins fixtures/tuple.pyi]


-- Type variable inference for generic functions
-- ---------------------------------------------
Expand Down