Skip to content

Fixed bug in mixed gradual tuple assignment logic that's affecting sh…#11371

Merged
rchiodo merged 3 commits intomicrosoft:mainfrom
jorenham:gh-11127
Apr 8, 2026
Merged

Fixed bug in mixed gradual tuple assignment logic that's affecting sh…#11371
rchiodo merged 3 commits intomicrosoft:mainfrom
jorenham:gh-11127

Conversation

@jorenham
Copy link
Copy Markdown
Contributor

@jorenham jorenham commented Apr 8, 2026

…ape-typing in NumPy. This fixes #11127

@jorenham
Copy link
Copy Markdown
Contributor Author

jorenham commented Apr 8, 2026

@microsoft-github-policy-service agree

Comment thread packages/pyright-internal/src/analyzer/tuples.ts
Comment thread packages/pyright-internal/src/tests/samples/tuple1.py
@github-actions
Copy link
Copy Markdown
Contributor

github-actions bot commented Apr 8, 2026

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:176:44 - error: Cannot access attribute "expand" for class "Basic"
+     Attribute "expand" is unknown (reportAttributeAccessIssue)
+   .../projects/sympy/sympy/solvers/diophantine/tests/test_diophantine.py:314:30 - error: Cannot access attribute "as_independent" for class "Basic"
+     Attribute "as_independent" is unknown (reportAttributeAccessIssue)
+   .../projects/sympy/sympy/solvers/diophantine/tests/test_diophantine.py:383:30 - error: Cannot access attribute "as_independent" for class "Basic"
+     Attribute "as_independent" is unknown (reportAttributeAccessIssue)
+   .../projects/sympy/sympy/solvers/ode/hypergeometric.py:247:67 - error: Operator "**" not supported for types "Basic" and "Literal[2]" (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 "CRootOf | tuple[Expr, int]" cannot be assigned to parameter "arg" of type "Expr" in function "__new__"
-     Type "CRootOf | 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 "CRootOf | tuple[Expr, int]" cannot be assigned to parameter "arg" of type "Expr" in function "__new__"
-     Type "CRootOf | 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:468:28 - error: Argument of type "Unknown | None" cannot be assigned to parameter "expr" of type "Expr" in function "make_args"
+   .../projects/sympy/sympy/solvers/ode/nonhomogeneous.py:468:28 - error: Argument of type "Expr | Unknown | None" cannot be assigned to parameter "expr" of type "Expr" in function "make_args"
-     Type "Unknown | None" is not assignable to type "Expr"
+     Type "Expr | Unknown | None" is not assignable to type "Expr"
+   .../projects/sympy/sympy/solvers/ode/ode.py:1516:38 - error: Object of type "None" is not subscriptable (reportOptionalSubscript)
+   .../projects/sympy/sympy/solvers/ode/ode.py:1517:38 - error: Object of type "None" is not subscriptable (reportOptionalSubscript)
+   .../projects/sympy/sympy/solvers/ode/ode.py:1527:9 - error: No overloads for "update" match the provided arguments (reportCallIssue)
+   .../projects/sympy/sympy/solvers/ode/ode.py:1527:12 - error: "update" is not a known attribute of "None" (reportOptionalMemberAccess)
+   .../projects/sympy/sympy/solvers/ode/ode.py:1527:19 - error: Argument of type "Unknown | dict[Unknown, Unknown] | None" cannot be assigned to parameter "m" of type "Iterable[tuple[str, Unknown]]" in function "update"
+     Type "Unknown | dict[Unknown, Unknown] | None" is not assignable to type "Iterable[tuple[str, Unknown]]"
+       "None" is incompatible with protocol "Iterable[tuple[str, Unknown]]"
+         "__iter__" is not present (reportArgumentType)
+   .../projects/sympy/sympy/solvers/ode/ode.py:1534:43 - error: Object of type "None" is not subscriptable (reportOptionalSubscript)
+   .../projects/sympy/sympy/solvers/ode/ode.py:1534:64 - error: Object of type "None" is not subscriptable (reportOptionalSubscript)
+   .../projects/sympy/sympy/solvers/ode/ode.py:1540:9 - error: No overloads for "update" match the provided arguments (reportCallIssue)
+   .../projects/sympy/sympy/solvers/ode/ode.py:1540:12 - error: "update" is not a known attribute of "None" (reportOptionalMemberAccess)
+   .../projects/sympy/sympy/solvers/ode/ode.py:1540:19 - error: Argument of type "Unknown | dict[Unknown, Unknown] | None" cannot be assigned to parameter "m" of type "Iterable[tuple[str, Unknown]]" in function "update"
+     Type "Unknown | dict[Unknown, Unknown] | None" is not assignable to type "Iterable[tuple[str, Unknown]]"
+       "None" is incompatible with protocol "Iterable[tuple[str, Unknown]]"
+         "__iter__" is not present (reportArgumentType)
+   .../projects/sympy/sympy/solvers/ode/ode.py:1547:43 - error: Object of type "None" is not subscriptable (reportOptionalSubscript)
+   .../projects/sympy/sympy/solvers/ode/ode.py:1547:74 - error: Object of type "None" is not subscriptable (reportOptionalSubscript)
+   .../projects/sympy/sympy/solvers/ode/ode.py:1553:9 - error: No overloads for "update" match the provided arguments (reportCallIssue)
+   .../projects/sympy/sympy/solvers/ode/ode.py:1553:12 - error: "update" is not a known attribute of "None" (reportOptionalMemberAccess)
+   .../projects/sympy/sympy/solvers/ode/ode.py:1553:19 - error: Argument of type "Unknown | dict[Unknown, Unknown] | None" cannot be assigned to parameter "m" of type "Iterable[tuple[str, Unknown]]" in function "update"
+     Type "Unknown | dict[Unknown, Unknown] | None" is not assignable to type "Iterable[tuple[str, Unknown]]"
+       "None" is incompatible with protocol "Iterable[tuple[str, Unknown]]"
+         "__iter__" is not present (reportArgumentType)
+   .../projects/sympy/sympy/solvers/ode/ode.py:1560:49 - error: Object of type "None" is not subscriptable (reportOptionalSubscript)
+   .../projects/sympy/sympy/solvers/ode/ode.py:1560:70 - error: Object of type "None" is not subscriptable (reportOptionalSubscript)
-   .../projects/sympy/sympy/solvers/ode/ode.py:1690:36 - error: Cannot access attribute "lhs" for class "Expr"
-     Attribute "lhs" is unknown (reportAttributeAccessIssue)
-   .../projects/sympy/sympy/solvers/ode/ode.py:1690:55 - error: Cannot access attribute "rhs" for class "Expr"
-     Attribute "rhs" is unknown (reportAttributeAccessIssue)
-   .../projects/sympy/sympy/solvers/ode/ode.py:1691:36 - error: Cannot access attribute "lhs" for class "Expr"
-     Attribute "lhs" is unknown (reportAttributeAccessIssue)
-   .../projects/sympy/sympy/solvers/ode/ode.py:1692:17 - error: No overloads for "__setitem__" match the provided arguments (reportCallIssue)
-   .../projects/sympy/sympy/solvers/ode/ode.py:1692:17 - error: Argument of type "Equality | BooleanFalse | BooleanTrue | Unknown | Expr" cannot be assigned to parameter "value" of type "Equality | BooleanFalse | BooleanTrue" in function "__setitem__"
-     Type "Equality | BooleanFalse | BooleanTrue | Unknown | Expr" is not assignable to type "Equality | BooleanFalse | BooleanTrue"
-       Type "Expr" is not assignable to type "Equality | BooleanFalse | BooleanTrue"
-         "Expr" is not assignable to "Equality"
-         "Expr" is not assignable to "BooleanFalse"
-         "Expr" is not assignable to "BooleanTrue" (reportArgumentType)
+   .../projects/sympy/sympy/solvers/ode/ode.py:3379:7 - error: "update" is not a known attribute of "None" (reportOptionalMemberAccess)
+   .../projects/sympy/sympy/solvers/ode/ode.py:3379:38 - error: Object of type "None" is not subscriptable (reportOptionalSubscript)
+   .../projects/sympy/sympy/solvers/ode/ode.py:3380:7 - error: "update" is not a known attribute of "None" (reportOptionalMemberAccess)
+   .../projects/sympy/sympy/solvers/ode/ode.py:3380:38 - error: Object of type "None" is not subscriptable (reportOptionalSubscript)
+   .../projects/sympy/sympy/solvers/ode/ode.py:3381:14 - error: Object of type "None" is not subscriptable (reportOptionalSubscript)
+   .../projects/sympy/sympy/solvers/ode/ode.py:3382:14 - error: Object of type "None" is not subscriptable (reportOptionalSubscript)
+   .../projects/sympy/sympy/solvers/ode/ode.py:3383:14 - error: Object of type "None" is not subscriptable (reportOptionalSubscript)
+   .../projects/sympy/sympy/solvers/ode/ode.py:3395:50 - error: Object of type "None" is not subscriptable (reportOptionalSubscript)
+   .../projects/sympy/sympy/solvers/ode/ode.py:3396:50 - error: Object of type "None" is not subscriptable (reportOptionalSubscript)
+   .../projects/sympy/sympy/solvers/ode/ode.py:3397:50 - error: Object of type "None" is not subscriptable (reportOptionalSubscript)
+   .../projects/sympy/sympy/solvers/ode/ode.py:3437:5 - error: No overloads for "update" match the provided arguments (reportCallIssue)
+   .../projects/sympy/sympy/solvers/ode/ode.py:3437:7 - error: "update" is not a known attribute of "None" (reportOptionalMemberAccess)
+   .../projects/sympy/sympy/solvers/ode/ode.py:3437:14 - error: Argument of type "Unknown | dict[Unknown, Unknown] | None" cannot be assigned to parameter "m" of type "Iterable[tuple[str, Unknown]]" in function "update"
+     Type "Unknown | dict[Unknown, Unknown] | None" is not assignable to type "Iterable[tuple[str, Unknown]]"
+       "None" is incompatible with protocol "Iterable[tuple[str, Unknown]]"
+         "__iter__" is not present (reportArgumentType)
+   .../projects/sympy/sympy/solvers/ode/ode.py:3438:18 - error: Object of type "None" is not subscriptable (reportOptionalSubscript)
+   .../projects/sympy/sympy/solvers/ode/ode.py:3438:43 - error: Object of type "None" is not subscriptable (reportOptionalSubscript)
+   .../projects/sympy/sympy/solvers/ode/ode.py:3439:9 - error: Object of type "None" is not subscriptable (reportOptionalSubscript)
+   .../projects/sympy/sympy/solvers/ode/ode.py:3439:16 - error: Object of type "None" is not subscriptable (reportOptionalSubscript)
+   .../projects/sympy/sympy/solvers/ode/ode.py:3439:24 - error: Object of type "None" is not subscriptable (reportOptionalSubscript)

... (truncated 1230 lines) ...

spark (https://github.com/apache/spark)
-   .../projects/spark/python/pyspark/pandas/indexes/base.py:1656:16 - error: Type "tuple[Any, Any, *tuple[Any, ...]] | Any" is not assignable to return type "Scalar | Tuple[Scalar, ...]"
-     Type "tuple[Any, Any, *tuple[Any, ...]] | Any" is not assignable to type "Scalar | Tuple[Scalar, ...]"
-       Type "tuple[Any, Any, *tuple[Any, ...]]" is not assignable to type "Scalar | Tuple[Scalar, ...]"
-         "tuple[Any, Any, *tuple[Any, ...]]" is not assignable to "int"
-         "tuple[Any, Any, *tuple[Any, ...]]" is not assignable to "float"
-         "tuple[Any, Any, *tuple[Any, ...]]" is not assignable to "bool"
-         "tuple[Any, Any, *tuple[Any, ...]]" is not assignable to "str"
-         "tuple[Any, Any, *tuple[Any, ...]]" is not assignable to "bytes"
-         "tuple[Any, Any, *tuple[Any, ...]]" is not assignable to "Decimal"
-     ... (reportReturnType)
-   .../projects/spark/python/pyspark/pandas/indexes/base.py:1697:16 - error: Type "tuple[Any, Any, *tuple[Any, ...]] | Any" is not assignable to return type "Scalar | Tuple[Scalar, ...]"
-     Type "tuple[Any, Any, *tuple[Any, ...]] | Any" is not assignable to type "Scalar | Tuple[Scalar, ...]"
-       Type "tuple[Any, Any, *tuple[Any, ...]]" is not assignable to type "Scalar | Tuple[Scalar, ...]"
-         "tuple[Any, Any, *tuple[Any, ...]]" is not assignable to "int"
-         "tuple[Any, Any, *tuple[Any, ...]]" is not assignable to "float"
-         "tuple[Any, Any, *tuple[Any, ...]]" is not assignable to "bool"
-         "tuple[Any, Any, *tuple[Any, ...]]" is not assignable to "str"
-         "tuple[Any, Any, *tuple[Any, ...]]" is not assignable to "bytes"
-         "tuple[Any, Any, *tuple[Any, ...]]" is not assignable to "Decimal"
-     ... (reportReturnType)
-   .../projects/spark/python/pyspark/pandas/indexing.py:1384:28 - error: Invalid conditional operand of type "Series[Unknown]"
-     Method __bool__ for type "Series[Unknown]" returns type "NoReturn" rather than "bool" (reportGeneralTypeIssues)
- 31686 errors, 931 warnings, 0 informations
+ 31683 errors, 931 warnings, 0 informations

scipy-stubs (https://github.com/scipy/scipy-stubs)
+ .../projects/scipy-stubs/scipy-stubs/interpolate/_interpolate.pyi
+   .../projects/scipy-stubs/scipy-stubs/interpolate/_interpolate.pyi:23:98 - error: Unnecessary "# pyright: ignore" rule: "reportInvalidTypeForm" (reportUnnecessaryTypeIgnoreComment)
+ .../projects/scipy-stubs/scipy-stubs/special/_multiufuncs.pyi
+   .../projects/scipy-stubs/scipy-stubs/special/_multiufuncs.pyi:38:85 - error: Unnecessary "# pyright: ignore" rule: "reportInvalidTypeForm" (reportUnnecessaryTypeIgnoreComment)
+   .../projects/scipy-stubs/scipy-stubs/special/_multiufuncs.pyi:39:85 - error: Unnecessary "# pyright: ignore" rule: "reportInvalidTypeForm" (reportUnnecessaryTypeIgnoreComment)
+   .../projects/scipy-stubs/scipy-stubs/special/_multiufuncs.pyi:48:90 - error: Unnecessary "# pyright: ignore" rule: "reportInvalidTypeForm" (reportUnnecessaryTypeIgnoreComment)
+   .../projects/scipy-stubs/scipy-stubs/special/_multiufuncs.pyi:49:90 - error: Unnecessary "# pyright: ignore" rule: "reportInvalidTypeForm" (reportUnnecessaryTypeIgnoreComment)
+ .../projects/scipy-stubs/scipy-stubs/stats/_distribution_infrastructure.pyi
+   .../projects/scipy-stubs/scipy-stubs/stats/_distribution_infrastructure.pyi:308:96 - error: Unnecessary "# pyright: ignore" rule: "reportInvalidTypeForm" (reportUnnecessaryTypeIgnoreComment)
+   .../projects/scipy-stubs/scipy-stubs/stats/_distribution_infrastructure.pyi:309:101 - error: Unnecessary "# pyright: ignore" rule: "reportInvalidTypeForm" (reportUnnecessaryTypeIgnoreComment)
+ .../projects/scipy-stubs/scipy-stubs/stats/_multivariate.pyi
+   .../projects/scipy-stubs/scipy-stubs/stats/_multivariate.pyi:46:98 - error: Unnecessary "# pyright: ignore" rule: "reportInvalidTypeForm" (reportUnnecessaryTypeIgnoreComment)
+   .../projects/scipy-stubs/scipy-stubs/stats/_multivariate.pyi:47:103 - error: Unnecessary "# pyright: ignore" rule: "reportInvalidTypeForm" (reportUnnecessaryTypeIgnoreComment)
- 34 errors, 0 warnings, 0 informations
+ 43 errors, 0 warnings, 0 informations

@rchiodo rchiodo merged commit 7f29b00 into microsoft:main Apr 8, 2026
15 of 16 checks passed
@rchiodo
Copy link
Copy Markdown
Collaborator

rchiodo commented Apr 8, 2026

Thanks for the PR. Hopefully we'll ship a new version soon. We're attempting to get to 100% type checker conformance before we ship again but those PRs should go in soon too.

gramster pushed a commit to gramster/pyright that referenced this pull request Apr 9, 2026
microsoft#11371)

* Fixed bug in mixed gradual tuple assignment logic that's affecting shape-typing in NumPy. This addresses microsoft#11127

* add negative test case for mixed gradual tuple assignment

* add explanatory comment as requested in review
@jorenham jorenham deleted the gh-11127 branch April 9, 2026 08:20
@jorenham
Copy link
Copy Markdown
Contributor Author

jorenham commented Apr 9, 2026

We're attempting to get to 100% type checker conformance before we ship again but those PRs should go in soon too.

Wow that's quite ambitious.

Especially if you consider #10232, which would be a pretty significant breaking change for libraries that use a lot of overloads (like numpy and scipy-stubs). There has also been a recent proposal about changing the overload spec and corresponding conformance tests (https://discuss.python.org/t/spec-change-ambiguous-arguments-in-overload-call-evaluation/106891).
So although I'm all for conforming to the spec; are you sure that going for 100% conformance in the short term is the way to go?

@rchiodo
Copy link
Copy Markdown
Collaborator

rchiodo commented Apr 9, 2026

I don't think 100% conformance is set in stone, we'd just like to fix the ones that we can fix in the short term. @gramster has a bunch of open PRs that are attempting that.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

tuple[int, int, *tuple[Any, ...]] should be assignable to tuple[int, ...]

2 participants