Skip to content

Conversation

@ericmarkmartin
Copy link
Contributor

Summary

Add more narrowing analysis for match statements:

  • add narrowing constraints from guard expressions
  • add negated constraints from previous predicates and guards to subsequent cases

This PR doesn't address that guards can mutate your subject, and so theoretically invalidate some of these narrowing constraints that you've previously accumulated. Some prior art on this issue here.

Test Plan

Add some new tests, and update some existing ones

@ericmarkmartin ericmarkmartin changed the title More match narrowing [red-knot] more type-narrowing in match statements Apr 8, 2025
@github-actions
Copy link
Contributor

github-actions bot commented Apr 8, 2025

mypy_primer results

No ecosystem changes detected ✅

@AlexWaygood AlexWaygood added the ty Multi-file analysis & type inference label Apr 8, 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.

Thank you, looks good!

@AlexWaygood AlexWaygood removed their request for review April 9, 2025 07:43
@carljm
Copy link
Contributor

carljm commented Apr 9, 2025

Going to go ahead and rebase this, expand the one comment slightly, and land it.

@carljm carljm force-pushed the more-match-narrowing branch from 6bb4302 to 3aba946 Compare April 9, 2025 15:42
@carljm
Copy link
Contributor

carljm commented Apr 9, 2025

Oops, never mind, after the rebase there's a recently-added test that fails with this PR, and it looks like the test is correct? With this PR, we seem to no longer realize that in

match 42:
    case {"something": M}: ...

that M may not be bound afterward.

We should add a test for this that's not part of the star-import tests, and figure out what we need to adjust in this PR in order to avoid regressing it.

I pushed my rebase and one slightly expanded comment, but I need to move on to other things for now, so I'll consider this PR back in your court.

@ericmarkmartin
Copy link
Contributor Author

Oops, never mind, after the rebase there's a recently-added test that fails with this PR, and it looks like the test is correct? With this PR, we seem to no longer realize that in

match 42:
    case {"something": M}: ...

that M may not be bound afterward.

it turns out it was just that I had copied the Stmt::If branch too closely: in the case of If, you must visit the test expression in the "no branch taken" flow because we need to evaluate the test before we can know it's False(y)

In the case of match statements, however, visiting the pattern implies undertaking symbol bindings, which we definitely don't want to track on the "no case matched" flow.

@carljm
Copy link
Contributor

carljm commented Apr 10, 2025

Thanks for revisiting this!

Looks like we are now seeing a panic in one of the corpus tests, where we enter what should be an unreachable code path. We seem to simultaneously think there is a binding visible for a symbol, while the "unbound" initial state for that symbol is also definitely-visible -- that combination shouldn't be possible.

I took a quick glance at the code changes and nothing jumped out at me; let me know if you aren't able to figure out the reason and I can take a closer look.

@ericmarkmartin ericmarkmartin force-pushed the more-match-narrowing branch 2 times, most recently from 4b09066 to 33b34d4 Compare April 18, 2025 00:05
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 for persisting with this. I pushed a couple minor simplifications I noticed, will merge once signal is green.

@carljm carljm merged commit de8f4e6 into astral-sh:main Apr 18, 2025
23 checks passed
dcreager added a commit that referenced this pull request Apr 18, 2025
* main:
  [red-knot] class bases are not affected by __future__.annotations (#17456)
  [red-knot] Add support for overloaded functions (#17366)
  [`pyupgrade`] Add fix safety section to docs (`UP036`) (#17444)
  [red-knot] more type-narrowing in match statements (#17302)
  [red-knot] Add some narrowing for assignment expressions (#17448)
  [red-knot] Understand `typing.Protocol` and `typing_extensions.Protocol` as equivalent (#17446)
  Server: Use `min` instead of `max` to limit the number of threads (#17421)
dcreager added a commit that referenced this pull request Apr 18, 2025
* main: (123 commits)
  [red-knot] Handle explicit class specialization in type expressions (#17434)
  [red-knot] allow assignment expression in call compare narrowing (#17461)
  [red-knot] fix building unions with literals and AlwaysTruthy/AlwaysFalsy (#17451)
  [red-knot] Type narrowing for assertions (take 2) (#17345)
  [red-knot] class bases are not affected by __future__.annotations (#17456)
  [red-knot] Add support for overloaded functions (#17366)
  [`pyupgrade`] Add fix safety section to docs (`UP036`) (#17444)
  [red-knot] more type-narrowing in match statements (#17302)
  [red-knot] Add some narrowing for assignment expressions (#17448)
  [red-knot] Understand `typing.Protocol` and `typing_extensions.Protocol` as equivalent (#17446)
  Server: Use `min` instead of `max` to limit the number of threads (#17421)
  [red-knot] Detect version-related syntax errors (#16379)
  [`pyflakes`] Add fix safety section (`F841`) (#17410)
  [red-knot] Add `KnownFunction` variants for `is_protocol`, `get_protocol_members` and `runtime_checkable` (#17450)
  Bump 0.11.6 (#17449)
  Auto generate `visit_source_order` (#17180)
  [red-knot] Initial tests for protocols (#17436)
  [red-knot] Dataclasses: synthesize `__init__` with proper signature (#17428)
  [red-knot] Dataclasses: support `order=True` (#17406)
  [red-knot] Super-basic generic inference at call sites (#17301)
  ...
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.

3 participants