Skip to content

Fix heterogeneous TypeVarTuple constraint solving - #11595

Open
Rich Chiodo (rchiodo) wants to merge 3 commits into
mainfrom
rchiodo-fix-typevartuple-solving
Open

Fix heterogeneous TypeVarTuple constraint solving#11595
Rich Chiodo (rchiodo) wants to merge 3 commits into
mainfrom
rchiodo-fix-typevartuple-solving

Conversation

@rchiodo

Copy link
Copy Markdown
Collaborator

Summary

  • widen repeated TypeVarTuple constraints per position in non-invariant inference
  • preserve precise common supertypes when one element type subsumes another, otherwise infer an element-wise union
  • preserve invariant generic matching, tuple-length checks, and tuple shape metadata
  • cover the upstream generics_typevartuple_basic.py line 90 and generics_typevartuple_args.py line 76 conformance cases

Tests

  • cd packages/pyright-internal && npm run build
  • cd packages/pyright-internal && npx jest typeEvaluator6.test typeEvaluator2.test -t "TypeVarTuple|Solver" --forceExit --runInBand
  • cd packages/pyright-internal && npx jest typeEvaluator6.test typeEvaluator2.test -t "TypeVarTuple(4|11|32)$|Solver35$" --forceExit --runInBand
  • targeted ESLint and Prettier checks

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
@StellaHuang95

Stella Huang (StellaHuang95) commented Aug 6, 2026

Copy link
Copy Markdown
Collaborator

🔒 Automated review in progress — Stella Huang (@StellaHuang95) is auto-reviewing this PR.

@StellaHuang95

Copy link
Copy Markdown
Collaborator

The equivalent Pylance constraint-solver path still needs the same non-invariant TypeVarTuple widening and regression coverage; otherwise this upstream fix will not reach Pylance users.

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.

@StellaHuang95 Stella Huang (StellaHuang95) added the review-auto:approved Automated review: no blocking findings (approval posted). label Aug 6, 2026
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@rchiodo

Copy link
Copy Markdown
Collaborator Author

Re: the Pylance constraint-solver path — this PR targets the upstream Pyright repo. Pylance vendors Pyright as a subrepo, so this fix reaches Pylance once it's pulled downstream into the pyrx monorepo. The equivalent Pylance-side widening + regression coverage will be handled there as part of the subrepo update, since it can't be modified from this repo.

@github-actions

This comment has been minimized.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@github-actions

github-actions Bot commented Aug 7, 2026

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/ode/ode.py:610:22 - error: Cannot access attribute "pop" for class "tuple[()]"
+     Attribute "pop" is unknown (reportAttributeAccessIssue)
+   .../projects/sympy/sympy/solvers/ode/ode.py:610:22 - error: Cannot access attribute "pop" for class "tuple[str, ...]"
+     Attribute "pop" is unknown (reportAttributeAccessIssue)
+   .../projects/sympy/sympy/solvers/ode/ode.py:1579:38 - error: Object of type "None" is not subscriptable (reportOptionalSubscript)
+   .../projects/sympy/sympy/solvers/ode/ode.py:1580:38 - error: Object of type "None" is not subscriptable (reportOptionalSubscript)
+   .../projects/sympy/sympy/solvers/ode/ode.py:1590:9 - error: No overloads for "update" match the provided arguments (reportCallIssue)
+   .../projects/sympy/sympy/solvers/ode/ode.py:1590:12 - error: "update" is not a known attribute of "None" (reportOptionalMemberAccess)
+   .../projects/sympy/sympy/solvers/ode/ode.py:1590: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:1597:43 - error: Object of type "None" is not subscriptable (reportOptionalSubscript)
+   .../projects/sympy/sympy/solvers/ode/ode.py:1597:64 - error: Object of type "None" is not subscriptable (reportOptionalSubscript)
+   .../projects/sympy/sympy/solvers/ode/ode.py:1603:9 - error: No overloads for "update" match the provided arguments (reportCallIssue)
+   .../projects/sympy/sympy/solvers/ode/ode.py:1603:12 - error: "update" is not a known attribute of "None" (reportOptionalMemberAccess)
+   .../projects/sympy/sympy/solvers/ode/ode.py:1603: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:1610:43 - error: Object of type "None" is not subscriptable (reportOptionalSubscript)
+   .../projects/sympy/sympy/solvers/ode/ode.py:1610:74 - error: Object of type "None" is not subscriptable (reportOptionalSubscript)
+   .../projects/sympy/sympy/solvers/ode/ode.py:1616:9 - error: No overloads for "update" match the provided arguments (reportCallIssue)
+   .../projects/sympy/sympy/solvers/ode/ode.py:1616:12 - error: "update" is not a known attribute of "None" (reportOptionalMemberAccess)
+   .../projects/sympy/sympy/solvers/ode/ode.py:1616: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:1623:49 - error: Object of type "None" is not subscriptable (reportOptionalSubscript)
+   .../projects/sympy/sympy/solvers/ode/ode.py:1623:70 - error: Object of type "None" is not subscriptable (reportOptionalSubscript)
-   .../projects/sympy/sympy/solvers/ode/ode.py:1753:36 - error: Cannot access attribute "lhs" for class "Expr"
-     Attribute "lhs" is unknown (reportAttributeAccessIssue)
-   .../projects/sympy/sympy/solvers/ode/ode.py:1753:55 - error: Cannot access attribute "rhs" for class "Expr"
-   .../projects/sympy/sympy/solvers/ode/ode.py:1754:36 - error: Cannot access attribute "lhs" for class "Expr"
-     Attribute "lhs" is unknown (reportAttributeAccessIssue)
-   .../projects/sympy/sympy/solvers/ode/ode.py:1755:17 - error: No overloads for "__setitem__" match the provided arguments (reportCallIssue)
-   .../projects/sympy/sympy/solvers/ode/ode.py:1755: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:3442:7 - error: "update" is not a known attribute of "None" (reportOptionalMemberAccess)
+   .../projects/sympy/sympy/solvers/ode/ode.py:3442:38 - error: Object of type "None" is not subscriptable (reportOptionalSubscript)
+   .../projects/sympy/sympy/solvers/ode/ode.py:3443:7 - error: "update" is not a known attribute of "None" (reportOptionalMemberAccess)
+   .../projects/sympy/sympy/solvers/ode/ode.py:3443:38 - error: Object of type "None" is not subscriptable (reportOptionalSubscript)
+   .../projects/sympy/sympy/solvers/ode/ode.py:3444:14 - error: Object of type "None" is not subscriptable (reportOptionalSubscript)
+   .../projects/sympy/sympy/solvers/ode/ode.py:3445:14 - error: Object of type "None" is not subscriptable (reportOptionalSubscript)
+   .../projects/sympy/sympy/solvers/ode/ode.py:3446:14 - error: Object of type "None" is not subscriptable (reportOptionalSubscript)
+   .../projects/sympy/sympy/solvers/ode/ode.py:3458:50 - error: Object of type "None" is not subscriptable (reportOptionalSubscript)
+   .../projects/sympy/sympy/solvers/ode/ode.py:3459:50 - error: Object of type "None" is not subscriptable (reportOptionalSubscript)
+   .../projects/sympy/sympy/solvers/ode/ode.py:3460:50 - error: Object of type "None" is not subscriptable (reportOptionalSubscript)
+   .../projects/sympy/sympy/solvers/ode/ode.py:3500:5 - error: No overloads for "update" match the provided arguments (reportCallIssue)
+   .../projects/sympy/sympy/solvers/ode/ode.py:3500:7 - error: "update" is not a known attribute of "None" (reportOptionalMemberAccess)
+   .../projects/sympy/sympy/solvers/ode/ode.py:3500: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:3501:18 - error: Object of type "None" is not subscriptable (reportOptionalSubscript)
+   .../projects/sympy/sympy/solvers/ode/ode.py:3501:43 - error: Object of type "None" is not subscriptable (reportOptionalSubscript)
+   .../projects/sympy/sympy/solvers/ode/ode.py:3502:9 - error: Object of type "None" is not subscriptable (reportOptionalSubscript)
+   .../projects/sympy/sympy/solvers/ode/ode.py:3502:16 - error: Object of type "None" is not subscriptable (reportOptionalSubscript)
+   .../projects/sympy/sympy/solvers/ode/ode.py:3502:24 - error: Object of type "None" is not subscriptable (reportOptionalSubscript)
+   .../projects/sympy/sympy/solvers/ode/ode.py:3502:31 - error: Object of type "None" is not subscriptable (reportOptionalSubscript)
+   .../projects/sympy/sympy/solvers/ode/ode.py:3503:9 - error: Object of type "None" is not subscriptable (reportOptionalSubscript)
+   .../projects/sympy/sympy/solvers/ode/ode.py:3503:15 - error: Object of type "None" is not subscriptable (reportOptionalSubscript)
+   .../projects/sympy/sympy/solvers/ode/ode.py:3503:23 - error: Object of type "None" is not subscriptable (reportOptionalSubscript)
+   .../projects/sympy/sympy/solvers/ode/ode.py:3503:30 - error: Object of type "None" is not subscriptable (reportOptionalSubscript)
+   .../projects/sympy/sympy/solvers/ode/ode.py:3504:7 - error: "update" is not a known attribute of "None" (reportOptionalMemberAccess)
+   .../projects/sympy/sympy/solvers/ode/ode.py:3504:46 - error: Object of type "None" is not subscriptable (reportOptionalSubscript)
+   .../projects/sympy/sympy/solvers/ode/ode.py:3504:54 - error: Object of type "None" is not subscriptable (reportOptionalSubscript)
+   .../projects/sympy/sympy/solvers/ode/ode.py:3505:9 - error: Object of type "None" is not subscriptable (reportOptionalSubscript)
+   .../projects/sympy/sympy/solvers/ode/ode.py:3505:19 - error: Object of type "None" is not subscriptable (reportOptionalSubscript)
+   .../projects/sympy/sympy/solvers/ode/ode.py:3505:29 - error: Object of type "None" is not subscriptable (reportOptionalSubscript)
+   .../projects/sympy/sympy/solvers/ode/ode.py:3506:10 - error: Object of type "None" is not subscriptable (reportOptionalSubscript)
+   .../projects/sympy/sympy/solvers/ode/ode.py:3507:10 - error: Object of type "None" is not subscriptable (reportOptionalSubscript)
+   .../projects/sympy/sympy/solvers/ode/ode.py:3508:10 - error: Object of type "None" is not subscriptable (reportOptionalSubscript)
+   .../projects/sympy/sympy/solvers/ode/ode.py:3559:5 - error: No overloads for "update" match the provided arguments (reportCallIssue)
+   .../projects/sympy/sympy/solvers/ode/ode.py:3559:7 - error: "update" is not a known attribute of "None" (reportOptionalMemberAccess)

... (truncated 1217 lines) ...

@StellaHuang95

Copy link
Copy Markdown
Collaborator

The equivalent async Pylance constraint-solver path still needs a tracked follow-up to avoid divergent TypeVarTuple inference between Pyright and Pylance.

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.

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.

2 participants