Skip to content

Do not iterate via __getitem__ when __iter__ is explicitly set - #11645

Merged
Rich Chiodo (rchiodo) merged 1 commit into
microsoft:mainfrom
hsusul:fix/iter-none-getitem-fallback
Aug 24, 2026
Merged

Rich Chiodo (rchiodo) merged 1 commit into
microsoft:mainfrom
hsusul:fix/iter-none-getitem-fallback

Conversation

@hsusul

Copy link
Copy Markdown
Contributor

Summary

Test plan

  • npx jest typeEvaluator3.test.ts -t ForLoop --forceExit (from packages/pyright-internal)
  • Runtime: for _ in Foo() with __iter__ = None raises TypeError; a __getitem__-only class still iterates
  • Confirm a for loop over such a class reports a not-iterable error in the language server

CPython raises TypeError when __iter__ is None even if __getitem__ exists;
the legacy sequence protocol applies only when __iter__ is missing.
@rchiodo

Rich Chiodo (rchiodo) commented Aug 17, 2026

Copy link
Copy Markdown
Collaborator

🔒 Automated review in progress — Rich Chiodo (@rchiodo) is auto-reviewing this PR.

Comment thread packages/pyright-internal/src/analyzer/typeEvaluator.ts

@rchiodo Rich Chiodo (rchiodo) left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Approved via Review Center.

@rchiodo Rich Chiodo (rchiodo) added the review-auto:approved Automated review: no blocking findings (approval posted). label Aug 17, 2026

@rchiodo Rich Chiodo (rchiodo) left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Approved via Review Center.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Approved via Review Center.

@github-actions

Copy link
Copy Markdown
Contributor

Diff from mypy_primer, showing the effect of this PR on open source code:

sympy (https://github.com/sympy/sympy)
-   .../projects/sympy/sympy/solvers/diophantine/diophantine.py:1460:50 - error: Cannot access attribute "as_coeff_Mul" for class "Basic*"
-     Attribute "as_coeff_Mul" is unknown (reportAttributeAccessIssue)
-   .../projects/sympy/sympy/solvers/diophantine/diophantine.py:1460:50 - error: Cannot access attribute "as_coeff_Mul" for class "Relational*"
-     Attribute "as_coeff_Mul" is unknown (reportAttributeAccessIssue)
-   .../projects/sympy/sympy/solvers/ode/lie_group.py:619:61 - error: Operator "-" not supported for type "Unknown | Basic" (reportOperatorIssue)
-   .../projects/sympy/sympy/solvers/ode/nonhomogeneous.py:225:45 - error: Cannot access attribute "has" for class "tuple[Expr, int]"
-     Attribute "has" is unknown (reportAttributeAccessIssue)
+   .../projects/sympy/sympy/solvers/ode/nonhomogeneous.py:223:22 - error: No overloads for "__new__" match the provided arguments (reportCallIssue)
+   .../projects/sympy/sympy/solvers/ode/nonhomogeneous.py:223:25 - error: Argument of type "Unknown | One | NegativeOne | Zero | Integer | tuple[Expr, int]" cannot be assigned to parameter "arg" of type "Expr" in function "__new__"
+     Type "Unknown | One | NegativeOne | Zero | Integer | tuple[Expr, int]" is not assignable to type "Expr"
+       "tuple[Expr, int]" is not assignable to "Expr" (reportArgumentType)
+   .../projects/sympy/sympy/solvers/ode/nonhomogeneous.py:238:40 - error: No overloads for "__new__" match the provided arguments (reportCallIssue)
+   .../projects/sympy/sympy/solvers/ode/nonhomogeneous.py:238:50 - error: Argument of type "Unknown | One | NegativeOne | Zero | Integer | tuple[Expr, int]" cannot be assigned to parameter "arg" of type "Expr" in function "__new__"
+     Type "Unknown | One | NegativeOne | Zero | Integer | tuple[Expr, int]" is not assignable to type "Expr"
+       "tuple[Expr, int]" is not assignable to "Expr" (reportArgumentType)
-   .../projects/sympy/sympy/solvers/ode/ode.py:1433:17 - error: Argument of type "One | NegativeOne | Zero | Integer | NaN | ComplexInfinity | Rational | Infinity | NegativeInfinity | Float | Number | Expr" cannot be assigned to parameter "value" of type "Zero" in function "__setitem__"
+   .../projects/sympy/sympy/solvers/ode/ode.py:1433:17 - error: Argument of type "One | NegativeOne | Zero | Integer | Unknown | Rational | Number | Expr" cannot be assigned to parameter "value" of type "Zero" in function "__setitem__"
-     Type "One | NegativeOne | Zero | Integer | NaN | ComplexInfinity | Rational | Infinity | NegativeInfinity | Float | Number | Expr" is not assignable to type "Zero"
+     Type "One | NegativeOne | Zero | Integer | Unknown | Rational | Number | Expr" is not assignable to type "Zero"
-   .../projects/sympy/sympy/solvers/ode/ode.py:2961:17 - error: Argument of type "One | NegativeOne | Zero | Integer | NaN | ComplexInfinity | Rational | Infinity | NegativeInfinity | Float | Number | Expr" cannot be assigned to parameter "value" of type "Zero" in function "__setitem__"
+   .../projects/sympy/sympy/solvers/ode/ode.py:2961:17 - error: Argument of type "One | NegativeOne | Zero | Integer | Unknown | Rational | Number | Expr" cannot be assigned to parameter "value" of type "Zero" in function "__setitem__"
-     Type "One | NegativeOne | Zero | Integer | NaN | ComplexInfinity | Rational | Infinity | NegativeInfinity | Float | Number | Expr" is not assignable to type "Zero"
+     Type "One | NegativeOne | Zero | Integer | Unknown | Rational | Number | Expr" is not assignable to type "Zero"
+   .../projects/sympy/sympy/solvers/ode/riccati.py:275:12 - error: No overloads for "__init__" match the provided arguments (reportCallIssue)
+   .../projects/sympy/sympy/solvers/ode/riccati.py:275:17 - error: Argument of type "zip[Unknown]" cannot be assigned to parameter "iterable" of type "Iterable[list[bytes]]" in function "__init__"
+     "zip[Unknown]" is incompatible with protocol "Iterable[list[bytes]]"
+       "__iter__" is an incompatible type
+         Type "() -> zip[Unknown]" is not assignable to type "() -> Iterator[_T_co@Iterable]"
+           Function return type "zip[Unknown]" is incompatible with type "Iterator[_T_co@Iterable]"
+             "zip[Unknown]" is incompatible with protocol "Iterator[_T_co@Iterable]" (reportArgumentType)
-   .../projects/sympy/sympy/solvers/ode/riccati.py:874:51 - error: Cannot access attribute "diff" for class "Basic*"
-     Attribute "diff" is unknown (reportAttributeAccessIssue)
+   .../projects/sympy/sympy/solvers/ode/single.py:867:9 - error: Expression with type "tuple[ComplexInfinity | Unknown | Any, list[tuple[Unknown, Unknown]] | list[Unknown]] | tuple[ComplexInfinity | Unknown | Any, list[tuple[Unknown, Unknown]] | list[Unknown], list[tuple[Unknown, Unknown]] | list[Unknown]]" cannot be assigned to target tuple
+     Type "tuple[ComplexInfinity | Unknown | Any, list[tuple[Unknown, Unknown]] | list[Unknown], list[tuple[Unknown, Unknown]] | list[Unknown]]" is incompatible with target tuple
+       Tuple size mismatch; expected 2 but received 3 (reportAssignmentType)
-   .../projects/sympy/sympy/solvers/ode/single.py:2646:27 - error: Argument of type "One | NegativeOne | Zero | Integer | NaN | ComplexInfinity | Rational | Infinity | NegativeInfinity | Float | Number | Expr | Unknown | int" cannot be assigned to parameter "stop" of type "SupportsIndex" in function "__new__"
+   .../projects/sympy/sympy/solvers/ode/single.py:2646:27 - error: Argument of type "One | NegativeOne | Zero | Integer | Unknown | Rational | Number | Expr | NaN | NegativeInfinity | int" cannot be assigned to parameter "stop" of type "SupportsIndex" in function "__new__"
-     Type "One | NegativeOne | Zero | Integer | NaN | ComplexInfinity | Rational | Infinity | NegativeInfinity | Float | Number | Expr | Unknown | int" is not assignable to type "SupportsIndex"
+     Type "One | NegativeOne | Zero | Integer | Unknown | Rational | Number | Expr | NaN | NegativeInfinity | int" is not assignable to type "SupportsIndex"
-   .../projects/sympy/sympy/solvers/ode/subscheck.py:270:32 - error: Operator "-" not supported for types "Basic | Unknown | Zero | Self@Basic" and "Basic | Unknown | Zero | Self@Basic"
+   .../projects/sympy/sympy/solvers/ode/subscheck.py:270:32 - error: Operator "-" not supported for types "Basic | Unknown | Zero" and "Basic | Unknown | Zero"
-     Operator "-" not supported for types "Basic" and "Basic"
-     Operator "-" not supported for types "Basic" and "Basic*"
-     Operator "-" not supported for types "Basic*" and "Basic"
-     Operator "-" not supported for types "Basic*" and "Basic*" (reportOperatorIssue)
+     Operator "-" not supported for types "Basic" and "Basic" (reportOperatorIssue)
-   .../projects/sympy/sympy/solvers/ode/systems.py:1167:37 - error: Operator "*" not supported for types "Literal[2]" and "Unknown | Self@Basic | bool | Expr | Basic"
+   .../projects/sympy/sympy/solvers/ode/systems.py:1167:37 - error: Operator "*" not supported for types "Literal[2]" and "Unknown | Expr | Basic | bool"
-     Operator "*" not supported for types "Literal[2]" and "Basic*"
-   .../projects/sympy/sympy/solvers/ode/systems.py:1167:37 - error: Operator "*" not supported for types "Unknown | int | Expr" and "Unknown | Self@Basic | bool | Expr | Basic"
+   .../projects/sympy/sympy/solvers/ode/systems.py:1167:37 - error: Operator "*" not supported for types "Unknown | Expr | int" and "Unknown | Expr | Basic | bool"
-     Operator "*" not supported for types "int" and "Basic*"
-     Operator "*" not supported for types "int" and "Basic"
-     Operator "*" not supported for types "Expr" and "Basic*"
+     Operator "*" not supported for types "Expr" and "Basic"
-     Operator "*" not supported for types "Expr" and "Basic" (reportOperatorIssue)
+     Operator "*" not supported for types "int" and "Basic" (reportOperatorIssue)
-   .../projects/sympy/sympy/solvers/ode/systems.py:1169:30 - error: Operator "*" not supported for types "Literal[2]" and "Unknown | Self@Basic | bool | Expr | Basic"
+   .../projects/sympy/sympy/solvers/ode/systems.py:1169:30 - error: Operator "*" not supported for types "Literal[2]" and "Unknown | Expr | Basic | bool"
-     Operator "*" not supported for types "Literal[2]" and "Basic*"
-   .../projects/sympy/sympy/solvers/ode/systems.py:1169:30 - error: Operator "*" not supported for types "Unknown | int | Expr" and "Unknown | Self@Basic | bool | Expr | Basic"
+   .../projects/sympy/sympy/solvers/ode/systems.py:1169:30 - error: Operator "*" not supported for types "Unknown | Expr | int" and "Unknown | Expr | Basic | bool"
-     Operator "*" not supported for types "int" and "Basic*"
-     Operator "*" not supported for types "int" and "Basic"
-     Operator "*" not supported for types "Expr" and "Basic*"
+     Operator "*" not supported for types "Expr" and "Basic"
+     Operator "*" not supported for types "int" and "Basic" (reportOperatorIssue)
-   .../projects/sympy/sympy/solvers/ode/systems.py:1169:49 - error: Operator "*" not supported for types "Literal[2]" and "Unknown | Self@Basic | bool | Expr | Basic"
+   .../projects/sympy/sympy/solvers/ode/systems.py:1169:49 - error: Operator "*" not supported for types "Literal[2]" and "Unknown | Expr | Basic | bool"
-     Operator "*" not supported for types "Literal[2]" and "Basic*"
-   .../projects/sympy/sympy/solvers/ode/systems.py:1169:49 - error: Operator "*" not supported for types "Unknown | int | Expr" and "Unknown | Self@Basic | bool | Expr | Basic"
+   .../projects/sympy/sympy/solvers/ode/systems.py:1169:49 - error: Operator "*" not supported for types "Unknown | Expr | int" and "Unknown | Expr | Basic | bool"
-     Operator "*" not supported for types "int" and "Basic*"
-     Operator "*" not supported for types "int" and "Basic"
-     Operator "*" not supported for types "Expr" and "Basic*"
+     Operator "*" not supported for types "Expr" and "Basic"

... (truncated 1777 lines) ...

@rchiodo

Copy link
Copy Markdown
Collaborator

Verification: The relevant tests could not be fully run in the isolated environment; this review is not fully verified.

@rchiodo
Rich Chiodo (rchiodo) merged commit 1be1899 into microsoft:main Aug 24, 2026
29 of 31 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

review-auto:approved Automated review: no blocking findings (approval posted).

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Instances of classes that define __iter__ = None and __getitem__ should not be iterable.

3 participants