Skip to content

Conversation

@mtshiba
Copy link
Collaborator

@mtshiba mtshiba commented Aug 14, 2025

Summary

This PR closes astral-sh/ty#955.

Test Plan

New test cases in narrowing/conditionals/nested.md.

@github-actions
Copy link
Contributor

Diagnostic diff on typing conformance tests

Changes were detected when running ty on typing conformance tests
--- old-output.txt	2025-08-14 06:00:34.776618614 +0000
+++ new-output.txt	2025-08-14 06:00:34.846619163 +0000
@@ -1,5 +1,5 @@
 WARN ty is pre-release software and not ready for production use. Expect to encounter bugs, missing features, and fatal errors.
-fatal[panic] Panicked at /home/runner/.cargo/git/checkouts/salsa-e6f3bb7c2a062968/918d35d/src/function/execute.rs:215:25 when checking `/home/runner/work/ruff/ruff/typing/conformance/tests/aliases_typealiastype.py`: `infer_definition_types(Id(1da61)): execute: too many cycle iterations`
+fatal[panic] Panicked at /home/runner/.cargo/git/checkouts/salsa-e6f3bb7c2a062968/918d35d/src/function/execute.rs:215:25 when checking `/home/runner/work/ruff/ruff/typing/conformance/tests/aliases_typealiastype.py`: `infer_definition_types(Id(50b5)): execute: too many cycle iterations`
 _directives_deprecated_library.py:15:31: error[invalid-return-type] Function always implicitly returns `None`, which is not assignable to return type `int`
 _directives_deprecated_library.py:30:26: error[invalid-return-type] Function always implicitly returns `None`, which is not assignable to return type `str`
 _directives_deprecated_library.py:36:41: error[invalid-return-type] Function always implicitly returns `None`, which is not assignable to return type `Self@__add__`

@github-actions
Copy link
Contributor

mypy_primer results

Changes were detected when running on open source projects
schemathesis (https://github.com/schemathesis/schemathesis)
- src/schemathesis/hooks.py:66:29: warning[redundant-cast] Value is already of type `str`
- Found 271 diagnostics
+ Found 270 diagnostics
No memory usage changes detected ✅

if x is not None:
def closure():
reveal_type(x) # revealed: str | None
x = None
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Upon closer analysis, it seems that whether or not narrowing is applied to x depends on whether the closure is exposed or just consumed in the scope (This PR does not take this into account and always assumes that the closure is exposed).

def f(x: str | None):
    def _():
        if x is not None:
            def closure():
                reveal_type(x)  # revealed: str | None
            return closure  # expose a closure
    x = None

def f(x: str | None):
    def _():
        if x is not None:
            def closure():
                reveal_type(x)  # revealed: str
            return closure()  # just consume a closure
    x = None

To achieve this, an additional mechanism would be required to determine whether a closure is exposed (pyright does not seem to implement this). This would likely be a future work.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, I think in general we consider escape analysis for closures to be out of scope. Perhaps we could tackle it someday, but it's not needed now.

@AlexWaygood AlexWaygood added the ty Multi-file analysis & type inference label Aug 14, 2025
Copy link
Contributor

@carljm carljm left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks great, thank you!

if x is not None:
def closure():
reveal_type(x) # revealed: str | None
x = None
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, I think in general we consider escape analysis for closures to be out of scope. Perhaps we could tackle it someday, but it's not needed now.

@carljm carljm merged commit 0e5577a into astral-sh:main Aug 15, 2025
39 checks passed
@mtshiba mtshiba deleted the fix-lazy-nested-narrowing branch August 15, 2025 01:28
dcreager added a commit that referenced this pull request Aug 15, 2025
* main:
  [ty] Represent `NamedTuple` as an opaque special form, not a class (#19915)
  [ty] Remove incorrect type narrowing for `if type(x) is C[int]` (#19926)
  Bump Rust MSRV to 1.87 (#19924)
  Add `else`-branch narrowing for `if type(a) is A` when `A` is `@final` (#19925)
  [ty] Sync vendored typeshed stubs (#19923)
  [ty] fix lazy snapshot sweeping in nested scopes (#19908)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

ty Multi-file analysis & type inference

Projects

None yet

Development

Successfully merging this pull request may close these issues.

lazy snapshot sweeping needs to invalidate constraints in nested scopes

3 participants