Skip to content

Treat assignments in unreachable code as local bindings - #11666

Open
Henry Su (hsusul) wants to merge 2 commits into
microsoft:mainfrom
hsusul:fix/unreachable-local-binding
Open

Treat assignments in unreachable code as local bindings#11666
Henry Su (hsusul) wants to merge 2 commits into
microsoft:mainfrom
hsusul:fix/unreachable-local-binding

Conversation

@hsusul

Copy link
Copy Markdown
Contributor

Summary

  • Fixes Local variables in unused code are not detected #11449.
  • CPython makes a name local for the whole function if it is assigned anywhere in the function body, including after return.
  • The binder skipped unreachable statements, so those names were treated as globals and UnboundLocalError was missed. Nested nonlocal lookups into such names also failed.

Test plan

  • npx jest typeEvaluator2.test.ts -t "Unbound" --forceExit (from packages/pyright-internal)
  • npx jest typeEvaluator1.test.ts -t "Unreachable1" --forceExit
  • Confirm a read before an assignment that appears after return reports an unbound variable in the language server

CPython treats any assignment in a function as making the name local, even
after a return. Skipping those statements left later-assigned names looking
global and hid UnboundLocalError.

Fixes microsoft#11449
@rchiodo

Rich Chiodo (rchiodo) commented Aug 24, 2026

Copy link
Copy Markdown
Collaborator

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

GlobalNode,
IfNode,
ImportAsNode,
ImportFromAsNode,

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.

Issue · Please address or respond

ImportFromAsNode is unused by this change, so this will fail unused-import checks. Remove the import.

return false;
}

override visitFunction(node: FunctionNode): boolean {

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.

Warning · Non-blocking recommendation

This walker skips function/class headers but descends into lambda bodies. That misses assignment expressions in decorators, defaults, and class bases that bind in the enclosing scope, while incorrectly treating assignment expressions in a lambda body as enclosing-scope bindings. Please handle those scope boundaries explicitly and add regressions for both cases.

this._bindName(node.d.target);
}
return true;
}

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.

Issue · Please address or respond

UnreachableNameBinder does not process global or nonlocal declarations. Consequently, an unreachable global x; x = ... or nonlocal x; x = ... binds the assignment directly in the current scope, incorrectly making it local. Preserve the declarations' binding semantics before binding targets and cover unreachable declaration cases.

@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) added the review-auto:changes-requested Automated review: posted blocking findings to address. label Aug 24, 2026
// local for the entire function). Nested functions and classes are skipped
// because DummyScopeGenerator already created their scopes.
class UnreachableNameBinder extends ParseTreeWalker {
constructor(

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.

Warning · Non-blocking recommendation

Unreachable global and nonlocal directives are not processed, so a later assignment can be bound to the current local scope rather than the declared scope. Handle these directives before binding targets and add focused unreachable-directive coverage.


override visitPatternCapture(node: PatternCaptureNode): boolean {
this._bindName(node.d.target);
return false;

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.

Warning · Non-blocking recommendation

UnreachableNameBinder has no lambda scope boundary. Walking lambda: (x := 1) will bind x in the enclosing scope even though the assignment expression belongs to the lambda's scope. Skip lambda bodies and add a regression case.

override visitTypeAlias(node: TypeAliasNode): boolean {
this._bindName(node.d.name);
return false;
}

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.

Warning · Non-blocking recommendation

Returning false for nested functions and classes skips decorators, default values, bases, and keywords, which are evaluated in the enclosing scope. Assignment expressions in those header expressions therefore miss their enclosing binding; traverse the headers while excluding only nested bodies.

this._bindName(node.d.target);
return false;
}
}

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.

Warning · Non-blocking recommendation

This new visitor duplicates the primary binder's syntax and scope classification, and the missing directive and scope-boundary cases already demonstrate drift. Reuse or centralize the scope-aware binding classification so future syntax additions do not update only one path.

@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) 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 review-auto:approved Automated review: no blocking findings (approval posted). and removed review-auto:changes-requested Automated review: posted blocking findings to address. labels Aug 24, 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.

Please address the comments in the binder.ts

@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) added review-auto:changes-requested Automated review: posted blocking findings to address. and removed review-auto:approved Automated review: no blocking findings (approval posted). labels Aug 25, 2026
@hsusul

Copy link
Copy Markdown
Contributor Author

Addressed the binder feedback in 3268d67:

  • removed the unused ImportFromAsNode import;
  • process unreachable global and nonlocal directives before binding targets;
  • traverse enclosing-scope function, class, and lambda header expressions while excluding nested bodies;
  • added regressions for unreachable directives, lambda body/default boundaries, function defaults/decorators, and class bases/decorators.

Validation passed for the focused Unbound tests (7/7), neighboring Unreachable1 test, pnpm run check, pnpm run typecheck, and git diff --check.

The full internal Jest run passed 69/71 suites and 2,716/2,718 tests. The two failures were in unrelated areas: DataClassReplace1 in typeEvaluator4.test.ts and Builtins1 in typeEvaluator1.test.ts. Neither failure touches the changed files or binder behavior in this revision.

I kept the broader binding-classification centralization suggestion out of this targeted correctness fix to avoid expanding the PR beyond the demonstrated scope-boundary and directive issues.

this._bindName(node.d.target);
return false;
}
}

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.

Warning · Non-blocking recommendation

UnreachableNameBinder independently classifies binding syntax and scope boundaries. Centralize or reuse the primary binder's scope-aware classification so future syntax changes cannot silently diverge.

[verified]

@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) added review-auto:approved Automated review: no blocking findings (approval posted). and removed review-auto:changes-requested Automated review: posted blocking findings to address. labels Aug 26, 2026
@github-actions

Copy link
Copy Markdown
Contributor

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

pybind11 (https://github.com/pybind/pybind11)
-   .../projects/pybind11/tests/test_iostream.py:13:20 - error: "getwindowsversion" is not a known attribute of module "sys" (reportAttributeAccessIssue)
-   .../projects/pybind11/tests/test_multiple_interpreters.py:37:52 - error: "create" is not a known attribute of module "concurrent.interpreters" (reportAttributeAccessIssue)
-   .../projects/pybind11/tests/test_multiple_interpreters.py:40:34 - error: "Interpreter" is not a known attribute of module "concurrent.interpreters" (reportAttributeAccessIssue)
-   .../projects/pybind11/tests/test_multiple_interpreters.py:50:33 - error: "ExecutionFailed" is not a known attribute of module "concurrent.interpreters" (reportAttributeAccessIssue)
-   .../projects/pybind11/tests/test_multiple_interpreters.py:161:41 - error: "create" is not a known attribute of module "concurrent.interpreters" (reportAttributeAccessIssue)
-   .../projects/pybind11/tests/test_multiple_interpreters.py:162:41 - error: "create" is not a known attribute of module "concurrent.interpreters" (reportAttributeAccessIssue)
-   .../projects/pybind11/tests/test_multiple_interpreters.py:165:26 - error: "ExecutionFailed" is not a known attribute of module "concurrent.interpreters" (reportAttributeAccessIssue)
-   .../projects/pybind11/tests/test_multiple_interpreters.py:170:31 - error: "create_queue" is not a known attribute of module "concurrent.interpreters" (reportAttributeAccessIssue)
-   .../projects/pybind11/tests/test_multiple_interpreters.py:269:42 - error: "create" is not a known attribute of module "concurrent.interpreters" (reportAttributeAccessIssue)
- 344 errors, 12 warnings, 0 informations
+ 335 errors, 12 warnings, 0 informations

bandersnatch (https://github.com/pypa/bandersnatch)
- .../projects/bandersnatch/src/bandersnatch/master.py
-   .../projects/bandersnatch/src/bandersnatch/master.py:18:43 - error: "WindowsSelectorEventLoopPolicy" is not a known attribute of module "asyncio" (reportAttributeAccessIssue)
- 75 errors, 5 warnings, 0 informations
+ 74 errors, 5 warnings, 0 informations

sympy (https://github.com/sympy/sympy)
-   .../projects/sympy/sympy/external/gmpy.py:56:5 - warning: "HAS_GMPY" is specified in __all__ but is not present in module (reportUnsupportedDunderAll)
-   .../projects/sympy/sympy/printing/preview.py:49:12 - error: "startfile" is not a known attribute of module "os" (reportAttributeAccessIssue)
-   .../projects/sympy/sympy/solvers/bivariate.py:135:15 - error: Operator "-" not supported for "None" (reportOptionalOperand)
-   .../projects/sympy/sympy/solvers/bivariate.py:139:17 - error: Operator "-" not supported for type "Basic | Unknown" (reportOperatorIssue)
-   .../projects/sympy/sympy/solvers/bivariate.py:144:23 - error: Operator "-" not supported for "None" (reportOptionalOperand)
-   .../projects/sympy/sympy/solvers/deutils.py:234:14 - error: Operator "not in" not supported for types "str" and "Unknown | int"
-     Operator "not in" not supported for types "str" and "int" (reportOperatorIssue)
-   .../projects/sympy/sympy/solvers/diophantine/diophantine.py:423:38 - error: Argument of type "Unknown | Expr | Literal[0]" cannot be assigned to parameter "expr" of type "Expr" in function "make_args"
+   .../projects/sympy/sympy/solvers/diophantine/diophantine.py:423:38 - error: Argument of type "int | Expr" cannot be assigned to parameter "expr" of type "Expr" in function "make_args"
-     Type "Unknown | Expr | Literal[0]" is not assignable to type "Expr"
+     Type "int | Expr" is not assignable to type "Expr"
-       "Literal[0]" is not assignable to "Expr" (reportArgumentType)
+       "int" is not assignable to "Expr" (reportArgumentType)
+   .../projects/sympy/sympy/solvers/diophantine/diophantine.py:504:19 - error: Operator "**" not supported for types "Unknown | Basic" and "Literal[2]"
+     Operator "**" not supported for types "Basic" and "Literal[2]" (reportOperatorIssue)
+   .../projects/sympy/sympy/solvers/diophantine/diophantine.py:505:19 - error: Operator "*" not supported for types "Unknown | Basic" and "Unknown | Basic"
+     Operator "*" not supported for types "Basic" and "Basic" (reportOperatorIssue)
+   .../projects/sympy/sympy/solvers/diophantine/diophantine.py:506:19 - error: Operator "**" not supported for types "Unknown | Basic" and "Literal[2]"
+     Operator "**" not supported for types "Basic" and "Literal[2]" (reportOperatorIssue)
+   .../projects/sympy/sympy/solvers/diophantine/diophantine.py:569:42 - error: Operator "*" not supported for types "int" and "Unknown | Basic"
+     Operator "*" not supported for types "int" and "Basic" (reportOperatorIssue)
+   .../projects/sympy/sympy/solvers/diophantine/diophantine.py:569:50 - error: Operator "*" not supported for types "Expr" and "Unknown | Basic"
+     Operator "*" not supported for types "Expr" and "Basic" (reportOperatorIssue)
+   .../projects/sympy/sympy/solvers/diophantine/diophantine.py:725:42 - error: Operator "**" not supported for types "Unknown | Basic" and "Literal[2]"
+     Operator "**" not supported for types "Basic" and "Literal[2]" (reportOperatorIssue)
+   .../projects/sympy/sympy/solvers/diophantine/diophantine.py:735:19 - error: Operator "**" not supported for types "Unknown | Basic" and "Literal[2]"
+     Operator "**" not supported for types "Basic" and "Literal[2]" (reportOperatorIssue)
+   .../projects/sympy/sympy/solvers/diophantine/diophantine.py:736:19 - error: Operator "**" not supported for types "Unknown | Basic" and "Literal[2]"
+     Operator "**" not supported for types "Basic" and "Literal[2]" (reportOperatorIssue)
+   .../projects/sympy/sympy/solvers/diophantine/diophantine.py:737:19 - error: Operator "**" not supported for types "Unknown | Basic" and "Literal[2]"
+     Operator "**" not supported for types "Basic" and "Literal[2]" (reportOperatorIssue)
+   .../projects/sympy/sympy/solvers/diophantine/diophantine.py:814:47 - error: Operator "**" not supported for types "Unknown | Basic" and "Literal[2]"
+     Operator "**" not supported for types "Basic" and "Literal[2]" (reportOperatorIssue)
+   .../projects/sympy/sympy/solvers/diophantine/diophantine.py:841:26 - error: Operator "**" not supported for types "Unknown | Basic" and "Literal[2]"
+     Operator "**" not supported for types "Basic" and "Literal[2]" (reportOperatorIssue)
+   .../projects/sympy/sympy/solvers/diophantine/diophantine.py:842:22 - error: Operator "*" not supported for types "Unknown | Basic" and "Unknown | Basic"
+     Operator "*" not supported for types "Basic" and "Basic" (reportOperatorIssue)
+   .../projects/sympy/sympy/solvers/diophantine/diophantine.py:843:36 - error: Operator "*" not supported for types "int" and "Unknown | Basic"
+     Operator "*" not supported for types "int" and "Basic" (reportOperatorIssue)
+   .../projects/sympy/sympy/solvers/diophantine/diophantine.py:843:42 - error: Operator "*" not supported for types "Unknown | Basic" and "Unknown | Basic"
+     Operator "*" not supported for types "Basic" and "Basic" (reportOperatorIssue)
+   .../projects/sympy/sympy/solvers/diophantine/diophantine.py:843:51 - error: Operator "*" not supported for types "int" and "Unknown | Basic"
+     Operator "*" not supported for types "int" and "Basic" (reportOperatorIssue)
+   .../projects/sympy/sympy/solvers/diophantine/diophantine.py:843:57 - error: Operator "*" not supported for types "Unknown | Basic" and "Unknown | Basic"
+     Operator "*" not supported for types "Basic" and "Basic" (reportOperatorIssue)
+   .../projects/sympy/sympy/solvers/diophantine/diophantine.py:843:66 - error: Operator "*" not supported for types "Unknown | Basic" and "Unknown | Basic"
+     Operator "*" not supported for types "Basic" and "Basic" (reportOperatorIssue)
+   .../projects/sympy/sympy/solvers/diophantine/diophantine.py:845:53 - error: Operator "*" not supported for types "Unknown | Basic" and "Unknown | Basic"
+     Operator "*" not supported for types "Basic" and "Basic" (reportOperatorIssue)
+   .../projects/sympy/sympy/solvers/diophantine/diophantine.py:854:18 - error: Operator "**" not supported for types "Unknown | Basic" and "Literal[2]"
+     Operator "**" not supported for types "Basic" and "Literal[2]" (reportOperatorIssue)
+   .../projects/sympy/sympy/solvers/diophantine/diophantine.py:856:22 - error: Operator "**" not supported for types "Unknown | Basic" and "Literal[2]"
+     Operator "**" not supported for types "Basic" and "Literal[2]" (reportOperatorIssue)
+   .../projects/sympy/sympy/solvers/diophantine/diophantine.py:865:22 - error: Operator "*" not supported for types "Unknown | Basic" and "Unknown | Basic"
+     Operator "*" not supported for types "Basic" and "Basic" (reportOperatorIssue)
+   .../projects/sympy/sympy/solvers/diophantine/diophantine.py:865:36 - error: Operator "*" not supported for types "Unknown | Basic" and "Unknown | Basic"
+     Operator "*" not supported for types "Basic" and "Basic" (reportOperatorIssue)
+   .../projects/sympy/sympy/solvers/diophantine/diophantine.py:867:27 - error: Operator "**" not supported for types "Unknown | Basic" and "Literal[2]"
+     Operator "**" not supported for types "Basic" and "Literal[2]" (reportOperatorIssue)
+   .../projects/sympy/sympy/solvers/diophantine/diophantine.py:868:27 - error: Operator "*" not supported for types "Unknown | Basic" and "Unknown | Basic"
+     Operator "*" not supported for types "Basic" and "Basic" (reportOperatorIssue)
+   .../projects/sympy/sympy/solvers/diophantine/diophantine.py:869:27 - error: Operator "*" not supported for types "Unknown | Basic" and "Unknown | Basic"
+     Operator "*" not supported for types "Basic" and "Basic" (reportOperatorIssue)
+   .../projects/sympy/sympy/solvers/diophantine/diophantine.py:870:27 - error: Operator "**" not supported for types "Unknown | Basic" and "Literal[2]"
+     Operator "**" not supported for types "Basic" and "Literal[2]" (reportOperatorIssue)
+   .../projects/sympy/sympy/solvers/diophantine/diophantine.py:871:27 - error: Operator "*" not supported for types "Unknown | Basic" and "Unknown | Basic"
+     Operator "*" not supported for types "Basic" and "Basic" (reportOperatorIssue)
+   .../projects/sympy/sympy/solvers/diophantine/diophantine.py:872:27 - error: Operator "**" not supported for types "Unknown | Basic" and "Literal[2]"
+     Operator "**" not supported for types "Basic" and "Literal[2]" (reportOperatorIssue)
+   .../projects/sympy/sympy/solvers/diophantine/diophantine.py:876:24 - error: Operator "**" not supported for types "Unknown | Basic" and "Literal[2]"
+     Operator "**" not supported for types "Basic" and "Literal[2]" (reportOperatorIssue)
+   .../projects/sympy/sympy/solvers/diophantine/diophantine.py:877:24 - error: Operator "**" not supported for types "Unknown | Basic" and "Literal[2]"
+     Operator "**" not supported for types "Basic" and "Literal[2]" (reportOperatorIssue)
+   .../projects/sympy/sympy/solvers/diophantine/diophantine.py:878:24 - error: Operator "**" not supported for types "Unknown | Basic" and "Literal[2]"
+     Operator "**" not supported for types "Basic" and "Literal[2]" (reportOperatorIssue)
+   .../projects/sympy/sympy/solvers/diophantine/diophantine.py:879:24 - error: Operator "*" not supported for types "Unknown | Basic" and "Unknown | Basic"
+     Operator "*" not supported for types "Basic" and "Basic" (reportOperatorIssue)
+   .../projects/sympy/sympy/solvers/diophantine/diophantine.py:880:24 - error: Operator "*" not supported for types "Unknown | Basic" and "Unknown | Basic"
+     Operator "*" not supported for types "Basic" and "Basic" (reportOperatorIssue)
+   .../projects/sympy/sympy/solvers/diophantine/diophantine.py:881:24 - error: Operator "*" not supported for types "Unknown | Basic" and "Unknown | Basic"
+     Operator "*" not supported for types "Basic" and "Basic" (reportOperatorIssue)
+   .../projects/sympy/sympy/solvers/diophantine/diophantine.py:888:37 - error: Operator "*" not supported for types "int" and "Unknown | None"

... (truncated 1666 lines) ...

scikit-learn (https://github.com/scikit-learn/scikit-learn)
+   .../projects/scikit-learn/sklearn/preprocessing/tests/test_data.py:733:9 - error: No overloads for "assert_array_less" match the provided arguments (reportCallIssue)
-     Operator "+" not supported for types "bytes" and "float64" when expected type is "_NumericArrayLike"
+   .../projects/scikit-learn/sklearn/preprocessing/tests/test_data.py:733:33 - error: Argument of type "float | Unknown | complex | bytes | Any" cannot be assigned to parameter "y" of type "_NumericArrayLike" in function "assert_array_less"
+     Type "float | Unknown | complex | bytes | Any" is not assignable to type "_NumericArrayLike"
+       Type "bytes" is not assignable to type "_NumericArrayLike"
+         "bytes" is incompatible with protocol "_SupportsArray[dtype[numpy.bool[builtins.bool] | number[Any, int | float | complex]]]"
+           "__array__" is not present
+         "bytes" is incompatible with protocol "_NestedSequence[_SupportsArray[dtype[numpy.bool[builtins.bool] | number[Any, int | float | complex]]]]"
+           "__getitem__" is an incompatible type
+             No overloaded function matches type "(index: int, /) -> (_T_co@_NestedSequence | _NestedSequence[_T_co@_NestedSequence])"
+           "__contains__" is an incompatible type
+     ... (reportArgumentType)
- 17157 errors, 466 warnings, 0 informations
+ 17159 errors, 466 warnings, 0 informations

prefect (https://github.com/PrefectHQ/prefect)
-   .../projects/prefect/src/prefect/cli/version.py:96:30 - error: Cannot access attribute "get" for class "PackageMetadata"
-     Attribute "get" is unknown (reportAttributeAccessIssue)
-   .../projects/prefect/src/prefect/cli/version.py:98:42 - error: Cannot access attribute "get" for class "PackageMetadata"
-     Attribute "get" is unknown (reportAttributeAccessIssue)
-   .../projects/prefect/src/prefect/runner/_process_manager.py:32:27 - error: "WinDLL" is not a known attribute of module "ctypes" (reportAttributeAccessIssue)
-   .../projects/prefect/src/prefect/runner/_process_manager.py:71:39 - error: "WinDLL" is not a known attribute of module "ctypes" (reportAttributeAccessIssue)
-   .../projects/prefect/src/prefect/runner/_process_manager.py:75:27 - error: "WinDLL" is not a known attribute of module "ctypes" (reportAttributeAccessIssue)
-   .../projects/prefect/src/prefect/runner/_process_manager.py:193:29 - error: "CTRL_BREAK_EVENT" is not a known attribute of module "signal" (reportAttributeAccessIssue)
-   .../projects/prefect/src/prefect/runner/_process_manager.py:197:26 - error: "WinError" is not a known attribute of module "ctypes" (reportAttributeAccessIssue)
-   .../projects/prefect/src/prefect/runner/_process_manager.py:197:42 - error: "get_last_error" is not a known attribute of module "ctypes" (reportAttributeAccessIssue)
-   .../projects/prefect/src/prefect/runner/_process_manager.py:209:22 - error: "WinError" is not a known attribute of module "ctypes" (reportAttributeAccessIssue)
-   .../projects/prefect/src/prefect/runner/_process_manager.py:209:38 - error: "get_last_error" is not a known attribute of module "ctypes" (reportAttributeAccessIssue)
-   .../projects/prefect/src/prefect/runner/_process_manager.py:222:26 - error: "WinError" is not a known attribute of module "ctypes" (reportAttributeAccessIssue)
-   .../projects/prefect/src/prefect/runner/_process_manager.py:222:42 - error: "get_last_error" is not a known attribute of module "ctypes" (reportAttributeAccessIssue)
-   .../projects/prefect/src/prefect/runner/_process_manager.py:232:26 - error: "WinError" is not a known attribute of module "ctypes" (reportAttributeAccessIssue)
-   .../projects/prefect/src/prefect/runner/_process_manager.py:232:42 - error: "get_last_error" is not a known attribute of module "ctypes" (reportAttributeAccessIssue)
-   .../projects/prefect/src/prefect/runner/_process_manager.py:235:30 - error: "WinError" is not a known attribute of module "ctypes" (reportAttributeAccessIssue)
-   .../projects/prefect/src/prefect/runner/_process_manager.py:235:46 - error: "get_last_error" is not a known attribute of module "ctypes" (reportAttributeAccessIssue)
-   .../projects/prefect/src/prefect/workers/base.py:1361:40 - error: Cannot access attribute "get" for class "PackageMetadata"
-     Attribute "get" is unknown (reportAttributeAccessIssue)
- 6008 errors, 201 warnings, 0 informations
+ 5991 errors, 201 warnings, 0 informations

pyodide (https://github.com/pyodide/pyodide)
-   .../projects/pyodide/src/py/_pyodide/jsbind.py:235:28 - error: Cannot access attribute "__get__" for class "MethodType"
-     Attribute "__get__" is unknown (reportAttributeAccessIssue)
-   .../projects/pyodide/src/py/pyodide/console.py:510:13 - error: "last_exc" is not a known attribute of module "sys" (reportAttributeAccessIssue)
-   .../projects/pyodide/src/py/pyodide/console.py:532:13 - error: "last_exc" is not a known attribute of module "sys" (reportAttributeAccessIssue)
- 848 errors, 24 warnings, 0 informations
+ 845 errors, 24 warnings, 0 informations

comtypes (https://github.com/enthought/comtypes)
-   .../projects/comtypes/comtypes/_memberspec.py:472:24 - error: "WINFUNCTYPE" is not a known attribute of module "ctypes" (reportAttributeAccessIssue)
-   .../projects/comtypes/comtypes/_memberspec.py:479:48 - error: "HRESULT" is not a known attribute of module "ctypes" (reportAttributeAccessIssue)
-   .../projects/comtypes/comtypes/_vtbl.py:49:26 - error: "WindowsError" is not defined (reportUndefinedVariable)
+   .../projects/comtypes/comtypes/_vtbl.py:49:26 - error: "WindowsError" is unbound (reportUnboundVariable)
-   .../projects/comtypes/comtypes/automation.py:574:23 - error: "WinDLL" is not defined (reportUndefinedVariable)
-   .../projects/comtypes/comtypes/automation.py:580:13 - error: "OleDLL" is not defined (reportUndefinedVariable)
-   .../projects/comtypes/comtypes/automation.py:584:30 - error: "HRESULT" is not defined (reportUndefinedVariable)
-   .../projects/comtypes/comtypes/automation.py:588:25 - error: "HRESULT" is not defined (reportUndefinedVariable)
-   .../projects/comtypes/comtypes/automation.py:592:24 - error: "HRESULT" is not defined (reportUndefinedVariable)
-   .../projects/comtypes/comtypes/automation.py:596:27 - error: "HRESULT" is not defined (reportUndefinedVariable)
-   .../projects/comtypes/comtypes/automation.py:682:9 - error: "HRESULT" is not defined (reportUndefinedVariable)
-   .../projects/comtypes/comtypes/automation.py:688:19 - error: "HRESULT" is not defined (reportUndefinedVariable)
-   .../projects/comtypes/comtypes/automation.py:689:19 - error: "HRESULT" is not defined (reportUndefinedVariable)
-   .../projects/comtypes/comtypes/automation.py:691:13 - error: "HRESULT" is not defined (reportUndefinedVariable)
-   .../projects/comtypes/comtypes/automation.py:778:23 - error: "HRESULT" is not defined (reportUndefinedVariable)
-   .../projects/comtypes/comtypes/automation.py:781:13 - error: "HRESULT" is not defined (reportUndefinedVariable)
-   .../projects/comtypes/comtypes/automation.py:791:13 - error: "HRESULT" is not defined (reportUndefinedVariable)
-   .../projects/comtypes/comtypes/automation.py:796:13 - error: "HRESULT" is not defined (reportUndefinedVariable)
-   .../projects/comtypes/comtypes/automation.py:961:5 - error: "HRESULT" is not defined (reportUndefinedVariable)
-   .../projects/comtypes/comtypes/client/_code_cache.py:89:19 - error: "OleDLL" is not a known attribute of module "ctypes" (reportAttributeAccessIssue)
-   .../projects/comtypes/comtypes/client/_events.py:398:24 - error: Cannot access attribute "winerror" for class "OSError"
-     Attribute "winerror" is unknown (reportAttributeAccessIssue)
- .../projects/comtypes/comtypes/client/_generate.py
-   .../projects/comtypes/comtypes/client/_generate.py:141:21 - error: "OpenKey" is not a known attribute of module "winreg" (reportAttributeAccessIssue)
-   .../projects/comtypes/comtypes/client/_generate.py:141:36 - error: "HKEY_CLASSES_ROOT" is not a known attribute of module "winreg" (reportAttributeAccessIssue)
-   .../projects/comtypes/comtypes/client/_generate.py:142:28 - error: "EnumValue" is not a known attribute of module "winreg" (reportAttributeAccessIssue)
-   .../projects/comtypes/comtypes/client/_generate.py:143:21 - error: "OpenKey" is not a known attribute of module "winreg" (reportAttributeAccessIssue)
-   .../projects/comtypes/comtypes/client/_generate.py:143:36 - error: "HKEY_CLASSES_ROOT" is not a known attribute of module "winreg" (reportAttributeAccessIssue)
-   .../projects/comtypes/comtypes/client/_generate.py:144:26 - error: "EnumValue" is not a known attribute of module "winreg" (reportAttributeAccessIssue)
-   .../projects/comtypes/comtypes/client/_generate.py:150:25 - error: "OpenKey" is not a known attribute of module "winreg" (reportAttributeAccessIssue)
-   .../projects/comtypes/comtypes/client/_generate.py:150:40 - error: "HKEY_CLASSES_ROOT" is not a known attribute of module "winreg" (reportAttributeAccessIssue)
-   .../projects/comtypes/comtypes/client/_generate.py:151:56 - error: "EnumKey" is not a known attribute of module "winreg" (reportAttributeAccessIssue)
- .../projects/comtypes/comtypes/server/inprocserver.py
-   .../projects/comtypes/comtypes/server/inprocserver.py:57:18 - error: "OpenKey" is not a known attribute of module "winreg" (reportAttributeAccessIssue)
-   .../projects/comtypes/comtypes/server/inprocserver.py:57:33 - error: "HKEY_CLASSES_ROOT" is not a known attribute of module "winreg" (reportAttributeAccessIssue)
-   .../projects/comtypes/comtypes/server/inprocserver.py:59:26 - error: "QueryValueEx" is not a known attribute of module "winreg" (reportAttributeAccessIssue)
-   .../projects/comtypes/comtypes/server/inprocserver.py:68:26 - error: "QueryValueEx" is not a known attribute of module "winreg" (reportAttributeAccessIssue)
-   .../projects/comtypes/comtypes/server/inprocserver.py:94:23 - error: "OpenKey" is not a known attribute of module "winreg" (reportAttributeAccessIssue)
-   .../projects/comtypes/comtypes/server/inprocserver.py:94:38 - error: "HKEY_CLASSES_ROOT" is not a known attribute of module "winreg" (reportAttributeAccessIssue)
-   .../projects/comtypes/comtypes/server/inprocserver.py:101:27 - error: "QueryValueEx" is not a known attribute of module "winreg" (reportAttributeAccessIssue)
-   .../projects/comtypes/comtypes/server/inprocserver.py:108:30 - error: "QueryValueEx" is not a known attribute of module "winreg" (reportAttributeAccessIssue)
-   .../projects/comtypes/comtypes/server/inprocserver.py:111:22 - error: "REG_SZ" is not a known attribute of module "winreg" (reportAttributeAccessIssue)
-   .../projects/comtypes/comtypes/server/inprocserver.py:113:24 - error: "REG_MULTI_SZ" is not a known attribute of module "winreg" (reportAttributeAccessIssue)
-   .../projects/comtypes/comtypes/server/register.py:70:26 - error: Cannot access attribute "winerror" for class "OSError"
-     Attribute "winerror" is unknown (reportAttributeAccessIssue)
-   .../projects/comtypes/comtypes/server/register.py:108:20 - error: "DeleteKey" is not a known attribute of module "winreg" (reportAttributeAccessIssue)
-   .../projects/comtypes/comtypes/server/register.py:144:27 - error: "OpenKey" is not a known attribute of module "winreg" (reportAttributeAccessIssue)
-   .../projects/comtypes/comtypes/server/register.py:145:20 - error: "DeleteKey" is not a known attribute of module "winreg" (reportAttributeAccessIssue)
-   .../projects/comtypes/comtypes/server/register.py:156:23 - error: "CreateKey" is not a known attribute of module "winreg" (reportAttributeAccessIssue)
-   .../projects/comtypes/comtypes/server/register.py:162:16 - error: "SetValueEx" is not a known attribute of module "winreg" (reportAttributeAccessIssue)
-   .../projects/comtypes/comtypes/server/register.py:162:56 - error: "REG_MULTI_SZ" is not a known attribute of module "winreg" (reportAttributeAccessIssue)
-   .../projects/comtypes/comtypes/server/register.py:165:20 - error: "SetValueEx" is not a known attribute of module "winreg" (reportAttributeAccessIssue)
-   .../projects/comtypes/comtypes/server/register.py:165:60 - error: "REG_SZ" is not a known attribute of module "winreg" (reportAttributeAccessIssue)
-   .../projects/comtypes/comtypes/server/register.py:169:24 - error: "DeleteValue" is not a known attribute of module "winreg" (reportAttributeAccessIssue)
-   .../projects/comtypes/comtypes/server/register.py:193:24 - error: "CreateKey" is not a known attribute of module "winreg" (reportAttributeAccessIssue)
-   .../projects/comtypes/comtypes/server/register.py:194:20 - error: "SetValueEx" is not a known attribute of module "winreg" (reportAttributeAccessIssue)
-   .../projects/comtypes/comtypes/server/register.py:194:58 - error: "REG_SZ" is not a known attribute of module "winreg" (reportAttributeAccessIssue)
-   .../projects/comtypes/comtypes/test/__init__.py:27:18 - error: "OleDLL" is not a known attribute of module "ctypes" (reportAttributeAccessIssue)
-   .../projects/comtypes/comtypes/test/test_GUID.py:33:32 - error: "WindowsError" is not defined (reportUndefinedVariable)
+   .../projects/comtypes/comtypes/test/test_GUID.py:33:32 - error: "WindowsError" is unbound (reportUnboundVariable)
-   .../projects/comtypes/comtypes/test/test_GUID.py:41:32 - error: "WindowsError" is not defined (reportUndefinedVariable)
+   .../projects/comtypes/comtypes/test/test_GUID.py:41:32 - error: "WindowsError" is unbound (reportUnboundVariable)
-   .../projects/comtypes/comtypes/test/test_GUID.py:49:32 - error: "WindowsError" is not defined (reportUndefinedVariable)
+   .../projects/comtypes/comtypes/test/test_GUID.py:49:32 - error: "WindowsError" is unbound (reportUnboundVariable)
- .../projects/comtypes/comtypes/test/test_classfactory.py
-   .../projects/comtypes/comtypes/test/test_classfactory.py:64:39 - error: Cannot access attribute "winerror" for class "OSError"
-     Attribute "winerror" is unknown (reportAttributeAccessIssue)
-   .../projects/comtypes/comtypes/test/test_comserver.py:27:14 - error: Cannot access attribute "winerror" for class "OSError"
-     Attribute "winerror" is unknown (reportAttributeAccessIssue)
-   .../projects/comtypes/comtypes/test/test_dispinterface.py:20:14 - error: Cannot access attribute "winerror" for class "OSError"
-     Attribute "winerror" is unknown (reportAttributeAccessIssue)
- .../projects/comtypes/comtypes/test/test_findgendir.py
-   .../projects/comtypes/comtypes/test/test_findgendir.py:47:52 - error: "dllhandle" is not a known attribute of module "sys" (reportAttributeAccessIssue)
-   .../projects/comtypes/comtypes/test/test_getactiveobj.py:70:32 - error: "WindowsError" is not defined (reportUndefinedVariable)
+   .../projects/comtypes/comtypes/test/test_getactiveobj.py:70:32 - error: "WindowsError" is unbound (reportUnboundVariable)
-   .../projects/comtypes/comtypes/test/test_getactiveobj.py:78:32 - error: "WindowsError" is not defined (reportUndefinedVariable)

... (truncated 42 lines) ...

aiohttp (https://github.com/aio-libs/aiohttp)
-   .../projects/aiohttp/aiohttp/resolver.py:25:30 - error: "AI_MASK" is not a known attribute of module "socket" (reportAttributeAccessIssue)
- 65 errors, 4 warnings, 0 informations
+ 64 errors, 4 warnings, 0 informations

mitmproxy (https://github.com/mitmproxy/mitmproxy)
-   .../projects/mitmproxy/mitmproxy/contentviews/_compat.py:29:35 - error: Variable not allowed in type expression (reportInvalidTypeForm)
+   .../projects/mitmproxy/test/mitmproxy/contentviews/test__api.py:61:50 - error: Cannot access attribute "__value__" for class "UnionType"
+     Attribute "__value__" is unknown (reportAttributeAccessIssue)
+ .../projects/mitmproxy/web/gen/backend_consts.py
+   .../projects/mitmproxy/web/gen/backend_consts.py:21:45 - error: Cannot access attribute "__value__" for class "UnionType"
+     Attribute "__value__" is unknown (reportAttributeAccessIssue)
- 2329 errors, 321 warnings, 0 informations
+ 2330 errors, 321 warnings, 0 informations

anyio (https://github.com/agronholm/anyio)
+   .../projects/anyio/src/anyio/_backends/_asyncio.py:504:40 - error: "BaseExceptionGroup" is unbound (reportUnboundVariable)
+   .../projects/anyio/src/anyio/_backends/_asyncio.py:505:60 - error: Cannot access attribute "split" for class "BaseException"
+     Attribute "split" is unknown (reportAttributeAccessIssue)
+   .../projects/anyio/src/anyio/_backends/_asyncio.py:505:60 - error: "split" is not a known attribute of "None" (reportOptionalMemberAccess)
+   .../projects/anyio/src/anyio/_backends/_asyncio.py:815:27 - error: "BaseExceptionGroup" is unbound (reportUnboundVariable)
+   .../projects/anyio/src/anyio/_backends/_asyncio.py:2321:23 - error: "BaseExceptionGroup" is unbound (reportUnboundVariable)
+   .../projects/anyio/src/anyio/_backends/_trio.py:245:16 - error: "BaseExceptionGroup" is unbound (reportUnboundVariable)
+ .../projects/anyio/src/anyio/_core/_exceptions.py
+   .../projects/anyio/src/anyio/_core/_exceptions.py:86:30 - error: "BaseExceptionGroup" is unbound (reportUnboundVariable)
+   .../projects/anyio/src/anyio/_core/_exceptions.py:87:30 - error: Cannot access attribute "exceptions" for class "BaseException"
+     Attribute "exceptions" is unknown (reportAttributeAccessIssue)
+   .../projects/anyio/src/anyio/_core/_sockets.py:263:22 - error: "ExceptionGroup" is unbound (reportUnboundVariable)
+   .../projects/anyio/src/anyio/_core/_sockets.py:432:16 - error: "ExceptionGroup" is unbound (reportUnboundVariable)
+   .../projects/anyio/src/anyio/pytest_plugin.py:293:24 - error: "ExceptionGroup" is unbound (reportUnboundVariable)
- 45 errors, 1 warning, 0 informations
+ 56 errors, 1 warning, 0 informations

starlette (https://github.com/encode/starlette)
+ .../projects/starlette/starlette/_utils.py

... (truncated 353 lines) ...```

@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.

This change is causing two failures:

Summary of all failing tests
FAIL src/tests/typeEvaluator1.test.ts (69.67 s)
● Builtins1

assert.fail(received, expected)

Message:
  frozendict should not be in builtins scope

  258 |         if (symbolInfo && symbolInfo.isBeyondExecutionScope) {
  259 |             if (symbolMap.get(builtinName) === undefined) {
> 260 |                 assert.fail(`${builtinName} should not be in builtins scope`);
      |                        ^
  261 |             }
  262 |         }
  263 |     }

  at Object.<anonymous> (src/tests/typeEvaluator1.test.ts:260:24)

FAIL src/tests/typeEvaluator4.test.ts (68.719 s)
● DataClassReplace1

assert.fail(received, expected)

Message:
  Expected 10 errors, got 7

  190 |     if (results[0].errors.length !== errorCount) {
  191 |         logDiagnostics(results[0].errors);
> 192 |         assert.fail(`Expected ${errorCount} errors, got ${results[0].errors.length}`);
      |                ^
  193 |     }
  194 |
  195 |     if (results[0].warnings.length !== warningCount) {

  at Object.validateResults (src/tests/testUtils.ts:192:16)
  at Object.<anonymous> (src/tests/typeEvaluator4.test.ts:427:15)

@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.

Result: could-not-verify

Summary: The PR adds `Unbound7`, covering unreachable assignments, directives, nested scopes, defaults, decorators, and class bases. No tests executed because the isolated container image was unavailable and local execution was unauthorized. Verification is therefore blocked by the environment, not a known test failure.

Test runs: 1 not run

  • ⚠️ Not run | Targeted unbound and unreachable binder tests | cd packages\pyright-internal && pnpm exec jest typeEvaluator2.test.ts -t "Unbound" --runInBand && pnpm exec jest typeEvaluator1.test.ts -t "Unreachable1" --runInBand
⚠️ Targeted unbound and unreachable binder tests diagnostic output
Container verification could not start: no trusted sandbox image is configured for microsoft/pyright, and local execution was not authorized.

@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.

@bschnurr Bill Schnurr (bschnurr) left a comment

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.

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.

Local variables in unused code are not detected

3 participants