Skip to content

Fix constrained TypeVar inference for Never - #11737

Open
Bill Schnurr (bschnurr) wants to merge 4 commits into
microsoft:mainfrom
bschnurr:fix/issue-11736
Open

Bill Schnurr (bschnurr) wants to merge 4 commits into
microsoft:mainfrom
bschnurr:fix/issue-11736

Conversation

@bschnurr

Copy link
Copy Markdown
Member

Summary

  • distinguish a matched Never constraint from the Never sentinel returned when no constrained TypeVar option matches
  • preserve existing handling for Any, incompatible inputs, and Never passed to TypeVars without an explicit Never constraint
  • add regression coverage for constraint ordering, aliases, nested and contravariant uses, and repeated inference

Fixes #11736

Tests

  • pnpm --dir packages/pyright-internal exec jest typeEvaluator2.test --forceExit
  • pnpm --dir packages/pyright-internal run build
  • targeted ESLint and Prettier checks

Distinguish a matched Never constraint from mapSubtypes returning Never when no constraints match.

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

This comment has been minimized.

Only preserve a Never solver result when the source is Never and the TypeVar explicitly declares Never, avoiding conditional-type inference changes found by mypy_primer.

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

This comment has been minimized.

Require the concrete source to exactly match a declared constraint before treating a Never solver result as explicit.

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

This comment has been minimized.

Distinguish user-declared Never constraints from synthetic Never results so constrained inference changes only for the intended case.

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

This comment has been minimized.

@rchiodo

Rich Chiodo (rchiodo) commented Sep 11, 2026

Copy link
Copy Markdown
Collaborator

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

@github-actions

This comment has been minimized.

@rchiodo

Copy link
Copy Markdown
Collaborator

Result: 🔴 could-not-verify

Verification details

Verification: Isolated verification observed failures that were not classified as caused by this PR: Dependency and test discovery preflight. The relevant tests could not be fully run in the isolated environment; this review is not fully verified.

Summary: No meaningful test execution was possible in the disposable environment. Dependency preparation could not start because `pnpm` was unavailable, and the targeted Jest test could not start because `node` was unavailable. The PR adds focused regression coverage for explicit `Never` constraints, including ordering, aliases, nested and contravariant inference, repeated inference, and preserved fallback behavior. The build was also unavailable for the same missing runtime.

Test runs: 1 failed, 2 not run

  • ⚠️ Not run | typeEvaluator2 ConstrainedTypeVar21 regression | node ./node_modules/jest/bin/jest.js src/tests/typeEvaluator2.test.ts --runInBand --forceExit
  • Failed | unrelated to this PR | Dependency and test discovery preflight | printf '%s\n' '== changed files ==' && git diff --name-status HEAD^ -- && printf '%s\n' '== dependency state ==' && if [ -x packages/pyright-internal/node_modules/.bin/jest ]; then echo 'package-local jest: present'; else echo 'package-local jest: missing'; fi && pnpm --version && printf '%s\n' '== targeted test registration ==' && grep -n "ConstrainedTypeVar21" packages/pyright-internal/src/tests/typeEvaluator2.test.ts
  • ⚠️ Not run | Offline dependency bootstrap | pnpm install --offline --frozen-lockfile
⚠️ typeEvaluator2 ConstrainedTypeVar21 regression diagnostic output
/bin/sh: 1: node: not found
Dependency and test discovery preflight diagnostic output
== changed files ==
warning: Not a git repository. Use --no-index to compare two paths outside a working tree
⚠️ Offline dependency bootstrap diagnostic output
/bin/sh: 1: pnpm: not found

@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 Sep 11, 2026
@github-actions

This comment has been minimized.

@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: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/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 "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/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__"
+     Type "One | NegativeOne | Zero | Integer | NaN | ComplexInfinity | Rational | Infinity | NegativeInfinity | Float | Number | Expr | Unknown | int" is not assignable to type "SupportsIndex"
+       "Expr" is incompatible with protocol "SupportsIndex"
+         "__index__" is not present (reportArgumentType)
-   .../projects/sympy/sympy/solvers/ode/single.py:2652:9 - error: Operator "+=" not supported for types "Unknown | Any | Zero | One | NegativeOne | Integer | NaN | ComplexInfinity | Rational | Infinity | NegativeInfinity | Float | Number | Expr" and "Basic | Any | Unknown"
+   .../projects/sympy/sympy/solvers/ode/single.py:2652:9 - error: Operator "+=" not supported for types "One | NegativeOne | Zero | Integer | NaN | ComplexInfinity | Rational | Infinity | NegativeInfinity | Float | Number | Expr | Any | Unknown" and "Basic | Any | Unknown"
-   .../projects/sympy/sympy/solvers/solveset.py:776:18 - error: Argument of type "Unknown | None" cannot be assigned to parameter "expr" of type "Expr" in function "together"
+   .../projects/sympy/sympy/solvers/solveset.py:776:18 - error: Argument of type "Expr | Unknown | None" cannot be assigned to parameter "expr" of type "Expr" in function "together"
-     Type "Unknown | None" is not assignable to type "Expr"
+     Type "Expr | Unknown | None" is not assignable to type "Expr"
-   .../projects/sympy/sympy/stats/crv_types.py:2546:9 - error: Method "_cdf" overrides class "SingleContinuousDistribution" in an incompatible manner
-     Return type mismatch: base method returns type "None", override returns type "ComplexInfinity | Unknown"
-       Type "ComplexInfinity | Unknown" is not assignable to type "None"
-         "ComplexInfinity" is not assignable to "None" (reportIncompatibleMethodOverride)
-   .../projects/sympy/sympy/stats/crv_types.py:2725:9 - error: Method "_cdf" overrides class "SingleContinuousDistribution" in an incompatible manner
-     Return type mismatch: base method returns type "None", override returns type "Expr | Unknown"
-       Type "Expr | Unknown" is not assignable to type "None"
-         "Expr" is not assignable to "None" (reportIncompatibleMethodOverride)
-   .../projects/sympy/sympy/stats/drv.py:269:22 - error: Argument of type "Generator[Self@Basic | tuple[Unknown, ...] | Unknown | Sum | Expr | ZeroMatrix | Zero | NaN | Piecewise | Basic | int | None, None, None]" cannot be assigned to parameter "iterable" of type "Iterable[_SupportsSumNoDefaultT@sum]" in function "sum"
+   .../projects/sympy/sympy/stats/drv.py:269:22 - error: Argument of type "Generator[Self@Basic | tuple[Unknown, ...] | Unknown | Sum | Expr | ZeroMatrix | Add | Zero | NaN | Piecewise | Basic | int | None, None, None]" cannot be assigned to parameter "iterable" of type "Iterable[_SupportsSumNoDefaultT@sum]" in function "sum"
-     "Generator[Self@Basic | tuple[Unknown, ...] | Unknown | Sum | Expr | ZeroMatrix | Zero | NaN | Piecewise | Basic | int | None, None, None]" is not assignable to "Iterable[_SupportsSumNoDefaultT@sum]"
+     "Generator[Self@Basic | tuple[Unknown, ...] | Unknown | Sum | Expr | ZeroMatrix | Add | Zero | NaN | Piecewise | Basic | int | None, None, None]" is not assignable to "Iterable[_SupportsSumNoDefaultT@sum]"
-       Type parameter "_T_co@Iterable" is covariant, but "Self@Basic | tuple[Unknown, ...] | Unknown | Sum | Expr | ZeroMatrix | Zero | NaN | Piecewise | Basic | int | None" is not a subtype of "_SupportsSumNoDefaultT@sum"
+       Type parameter "_T_co@Iterable" is covariant, but "Self@Basic | tuple[Unknown, ...] | Unknown | Sum | Expr | ZeroMatrix | Add | Zero | NaN | Piecewise | Basic | int | None" is not a subtype of "_SupportsSumNoDefaultT@sum"
-         Type "Self@Basic | tuple[Unknown, ...] | Unknown | Sum | Expr | ZeroMatrix | Zero | NaN | Piecewise | Basic | int | None" is not assignable to type "_SupportsSumWithNoDefaultGiven"
+         Type "Self@Basic | tuple[Unknown, ...] | Unknown | Sum | Expr | ZeroMatrix | Add | Zero | NaN | Piecewise | Basic | int | None" is not assignable to type "_SupportsSumWithNoDefaultGiven"
-           Type "Basic* | tuple[Unknown, ...] | Unknown | Sum | Expr | ZeroMatrix | Zero | NaN | Piecewise | Basic | int | None" is not assignable to type "_SupportsSumWithNoDefaultGiven"
+           Type "Basic* | tuple[Unknown, ...] | Unknown | Sum | Expr | ZeroMatrix | Add | Zero | NaN | Piecewise | Basic | int | None" is not assignable to type "_SupportsSumWithNoDefaultGiven"
-   .../projects/sympy/sympy/stats/drv_types.py:293:16 - error: Operator "*" not supported for types "Expr" and "tuple[Unknown, ...] | Unknown | Self@Basic | Sum | Expr | ZeroMatrix | Zero | NaN | Piecewise | Basic"
+   .../projects/sympy/sympy/stats/drv_types.py:293:16 - error: Operator "*" not supported for types "Expr" and "tuple[Unknown, ...] | Unknown | Self@Basic | Sum | Expr | ZeroMatrix | Add | Zero | NaN | Piecewise | Basic"
-   .../projects/sympy/sympy/stats/rv.py:473:25 - error: Argument of type "Expr | Lambda | Zero | One | Integral | Unknown | Probability | Self@Basic | tuple[Unknown, ...] | Sum | ZeroMatrix | NaN | Piecewise | Basic | int | NegativeOne | Integer | ComplexInfinity | Rational | Infinity | NegativeInfinity | Float | Number" cannot be assigned to parameter "args" of type "Expr | complex" in function "__new__"
+   .../projects/sympy/sympy/stats/rv.py:473:25 - error: Argument of type "Expr | Lambda | Zero | One | Integral | Unknown | Probability | Self@Basic | tuple[Unknown, ...] | Sum | ZeroMatrix | Add | NaN | Piecewise | Basic | int | NegativeOne | Integer | ComplexInfinity | Rational | Infinity | NegativeInfinity | Float | Number" cannot be assigned to parameter "args" of type "Expr | complex" in function "__new__"
-     Type "Expr | Lambda | Zero | One | Integral | Unknown | Probability | Self@Basic | tuple[Unknown, ...] | Sum | ZeroMatrix | NaN | Piecewise | Basic | int | NegativeOne | Integer | ComplexInfinity | Rational | Infinity | NegativeInfinity | Float | Number" is not assignable to type "Expr | complex"
+     Type "Expr | Lambda | Zero | One | Integral | Unknown | Probability | Self@Basic | tuple[Unknown, ...] | Sum | ZeroMatrix | Add | NaN | Piecewise | Basic | int | NegativeOne | Integer | ComplexInfinity | Rational | Infinity | NegativeInfinity | Float | Number" is not assignable to type "Expr | complex"
-   .../projects/sympy/sympy/stats/stochastic_process_types.py:1839:25 - error: Argument of type "tuple[Unknown, ...] | Unknown | Self@Basic | Sum | Expr | ZeroMatrix | Zero | NaN | Piecewise | Basic | Integral | Any | int" cannot be assigned to parameter "args" of type "Expr | complex" in function "__new__"
+   .../projects/sympy/sympy/stats/stochastic_process_types.py:1839:25 - error: Argument of type "tuple[Unknown, ...] | Unknown | Self@Basic | Sum | Expr | ZeroMatrix | Add | Zero | NaN | Piecewise | Basic | Integral | Any | int" cannot be assigned to parameter "args" of type "Expr | complex" in function "__new__"

... (truncated 1400 lines) ...

@heejaechang

Heejae Chang (heejaechang) commented Sep 15, 2026

Copy link
Copy Markdown
Collaborator

🟢 Pyright CLI QA — 5c23cd29 — verdict: green

Automated CLI checks compared this change with its base revision.
5 focused check(s) completed.

No new behavior difference was detected.

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.

This branch has not been deployed

No deployments
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.

TypeVar with Never as an option and unexpected reportArgumentType

3 participants