[ty] Ignore rejected assignments for synthesized bindings#25340
Conversation
Typing conformance resultsNo changes detected ✅Current numbersThe percentage of diagnostics emitted that were expected errors held steady at 91.94%. The percentage of expected errors that received a diagnostic held steady at 87.09%. The number of fully passing files held steady at 92/134. |
|
| Lint rule | Added | Removed | Changed |
|---|---|---|---|
invalid-argument-type |
0 | 1 | 0 |
| Total | 0 | 1 | 0 |
Raw diff:
paasta (https://github.com/yelp/paasta)
- paasta_tools/frameworks/native_service_config.py:229:17 error[invalid-argument-type] Argument to bound method `list.append` is incorrect: Expected `dict[str, str | dict[str, int | float]]`, found `dict[str, str | dict[str, int | float] | dict[str, int | float | list[dict[str, int]]]]`f0ebbbe to
2f1767b
Compare
Memory usage reportSummary
Significant changesClick to expand detailed breakdownprefect
sphinx
trio
flake8
|
Merging this PR will improve performance by 7.69%
Performance Changes
Tip Curious why this is faster? Use the CodSpeed MCP and ask your agent. Comparing Footnotes
|
|
Hate this diff. |
7a2dcf7 to
5153c2b
Compare
af63962 to
b01775e
Compare
This comment was marked as resolved.
This comment was marked as resolved.
|
I was hoping to snipe someone into it by posting about how much I didn't like the approach in Slack. |
d9f1196 to
3921ec4
Compare
3921ec4 to
1436111
Compare
b01775e to
08d6118
Compare
1436111 to
58247e2
Compare
sharkdp
left a comment
There was a problem hiding this comment.
Took me a while to understand, but I think it makes sense to do it this way.
Thank you.
There was a problem hiding this comment.
This looks completely unrelated to the changes in this PR... accidentally committed?
| /// The fallback type for missing expressions/bindings/declarations or recursive type inference. | ||
| cycle_recovery: Option<Type<'db>>, | ||
|
|
||
| /// Whether refinements derived from the right-hand side of this definition were discarded. |
There was a problem hiding this comment.
"this definition" was a bit surprising to me given that a TypeInferenceBuilder could also be created for a non-definition region. Maybe it should be clarified here ("If the type inference region refers to a definition, ...")
| } | ||
|
|
||
| fn discard_descendant_refinements_for(&mut self, definition: Definition<'db>) { | ||
| if matches!(self.region, InferenceRegion::Definition(region) if region == definition) { |
There was a problem hiding this comment.
Nit: region is not a region
| if matches!(self.region, InferenceRegion::Definition(region) if region == definition) { | |
| if matches!(self.region, InferenceRegion::Definition(d) if d == definition) { |
| cycle_recovery: Option<Type<'db>>, | ||
|
|
||
| /// Whether refinements derived from the right-hand side of this definition were discarded. | ||
| discards_descendant_refinements: bool, |
There was a problem hiding this comment.
My understanding is that this flag says: this inference builder refers to a definition which resulted in an invalid-assignment error.
If that's true, I would prefer a less cryptic name like is_definition_with_invalid_assignment or invalid_assignment_definition?
| /// Such bindings describe refinement information derived from the right-hand side of their | ||
| /// enclosing assignment. If inference discards RHS-derived refinements for that assignment, its | ||
| /// synthesized descendants must not participate in place resolution either. |
There was a problem hiding this comment.
This goes over my head. I feel like a Python code example (from the PR description or a test) with a brief explanation would be more helpful than this prose description.
| .finish_definition() | ||
| } | ||
|
|
||
| /// Returns `true` if a synthesized dictionary-key binding has been discarded. |
There was a problem hiding this comment.
| /// Returns `true` if a synthesized dictionary-key binding has been discarded. | |
| /// Returns `true` if the definition refers to a dictionary-key binding that resulted in an invalid-assignment. |
There was a problem hiding this comment.
similar here: are these changes related to the PR?
| // The enclosing write already invalidated earlier child refinements. This | ||
| // rejected synthesized binding must not establish new RHS-derived precision. |
There was a problem hiding this comment.
.. what? 😄
Doesn't this branch here mean that we skip a synthesized "x["a"] = 1" binding if the enclosing (real) x = {"a": 1} assignment (from which the synthesized was derived) was invalid?
Why does this refer to "invalidated earlier child refinements"? I understand that an assignment to x invalidates "earlier child refinements" like x["a"] = "foo", but how is that related to this branch?
Maybe
| // The enclosing write already invalidated earlier child refinements. This | |
| // rejected synthesized binding must not establish new RHS-derived precision. | |
| // This synthesized binding was derived from a dictionary assignment | |
| // `d = {...}` that was invalid. We discard it such that the lookup of the | |
| // place `d[key]` can fail. A fallback place for `d[key]` can then be looked | |
| // up on `d` directly. |
e4ee3c2 to
d12b7e2
Compare
d12b7e2 to
9984e4e
Compare
* main: [`pydocstyle`] Improve discoverability of rules enabled for each convention (#24973) [ty] Deduplicate retained use-def place states (#25450) [ty] reduce features of low-level crates depended on by `ty_python_semantic` (#25524) [ty] Fix narrowing enum literal unions by member identity (#25520) [ty] Test tagged union narrowing for named tuples (#25519) [ty] Disallow file-system access in `ty_python_core` (#25518) [ty] Nominal Tagged Union Narrowing (#24916) Commit `scripts/uv.lock` (#25517) Fix potential index out of range in `LineIndex` computation (#25492) [ty] Sync vendored typeshed stubs (#25514) [ty] Add disjointness for protocol method members (#25315) [ty] Use compact sets for more immutable fields (#25476) [ty] Derive `Default` for `FunctionDecoratorInference` (#25482) [ty] Ignore rejected assignments for synthesized bindings (#25340) [ty] Handle cycles in function decorator inference (#25475) docs: fix typo `bin/active` → `bin/activate` in tutorial (#25473) [ty] Narrow bound method overloads by receiver (#24707)
Summary
Prior to this change, we were retaining "known key" bindings from the right-hand side of an assignment even when the enclosing assignment was rejected. For example:
So we're respecting the new type information from
x = {"a": "bad"}... But an invalid assignment shouldn't contribute new type information!In other words, we want to ignore the known-key bindings that we get from the dict assignment when the overall assignment is invalid.
Doing so is pretty ugly because the index is built solely from syntax (e.g., we create definitions from
x = {"a": "bad"}), but we're trying to reject those definitions later during inference, using information we don't have at the time of definition creation. I tried a variety of approaches but this ended up being the cheapest and least invasive thing I could find.