Retain Sentinel types for non-CONSTANT_NAME bindings - #11655
Retain Sentinel types for non-CONSTANT_NAME bindings#11655Henry Su (hsusul) wants to merge 1 commit into
Conversation
Sentinel values are unique objects, so `is`/`is not` narrowing is sound even when the name is not CONSTANT_NAME or Final.
|
🔒 Automated review in progress — Heejae Chang (@heejaechang) is auto-reviewing this PR. |
| from typing_extensions import Sentinel # pyright: ignore[reportMissingModuleSource] | ||
|
|
||
|
|
||
| Empty = Sentinel("Empty") |
There was a problem hiding this comment.
Warning · Non-blocking recommendation
📍 packages/pyright-internal/src/tests/samples/sentinel3.py:8
[unverified] The new policy relies on singleton identity while this non-Final binding remains mutable. Add adversarial coverage for reassignment and aliasing—and preferably lowercase local and module-attribute bindings—to establish that narrowing remains sound across the affected flow paths.
[verified]
|
|
||
| // Sentinel objects are singletons; retaining the literal is sound | ||
| // even when the binding is not a CONSTANT_NAME or Final. | ||
| if (isSentinelLiteral(type)) { |
There was a problem hiding this comment.
Warning · Non-blocking recommendation
📍 packages/pyright-internal/src/analyzer/typeEvaluator.ts:24658
[unverified] The corresponding Pylance async-evaluator widening branches do not contain this exception, so IDE behavior may diverge when async evaluation is enabled. Verify the scenario with a downstream async-mode Pylance regression test and mirror the evaluator change only if that path owns the behavior rather than TSP.
[verified]
| !isSentinelLiteral(destType) | ||
| ) { | ||
| destType = stripTypeForm(stripLiteralValue(destType)); | ||
| } |
There was a problem hiding this comment.
Warning · Non-blocking recommendation
The new sample exercises module-level names but not the member-access widening path modified here. Add a class or instance sentinel-member regression case so this distinct retention path is covered.
Heejae Chang (heejaechang)
left a comment
There was a problem hiding this comment.
Approved via Review Center.
Rich Chiodo (rchiodo)
left a comment
There was a problem hiding this comment.
Approved via Review Center.
Bill Schnurr (bschnurr)
left a comment
There was a problem hiding this comment.
Approved via Review Center.
Summary
CONSTANT_NAMEorFinal.is/is notnarrowing work for names likeEmpty = Sentinel("Empty"), matching the behavior already used for all-caps sentinels.Fixes #10744
Test plan
pnpm exec jest typeEvaluator2.test.ts -t "Sentinel" --forceExitinpackages/pyright-internal