[ty] Avoid expression_type calls for syntax error targets in unpacking assignment#24663
[ty] Avoid expression_type calls for syntax error targets in unpacking assignment#24663charliermarsh wants to merge 3 commits intomainfrom
expression_type calls for syntax error targets in unpacking assignment#24663Conversation
Typing conformance resultsNo changes detected ✅Current numbersThe percentage of diagnostics emitted that were expected errors held steady at 87.94%. The percentage of expected errors that received a diagnostic held steady at 83.36%. The number of fully passing files held steady at 79/133. |
Memory usage reportMemory usage unchanged ✅ |
c67765d to
be47d0e
Compare
|
|
Hmm, where's the dodgy |
|
Is that preferred? I guess I would've thought recording an expression was preferred :) |
|
Regardless I will track it down now. |
|
We tried for a while to maintain the invariant that every node in the AST should have a type stored for it. But we gave up on it a while back because it proved nearly impossible to maintain it. |
|
And yeah, preferring non-panicking APIs to fix server crashes is the approach we took in #18455, for example |
|
So should nothing be using |
expression_type calls for syntax error targets in unpacking assignment
|
Not sure without looking at all uses, but it seems unlikely we have many cases where we can be sure that an expression already has a type. Glancing at this PR, it seems like it might be worth having a |
df2db96 to
3c6fbe7
Compare
|
Added. |
|
I still feel like I'm missing a full understanding of the problem here. Why does this cause ty to crash in the server context but not on the CLI? What server API is it that's leading to us calling |
|
(It's related to completions -- I'll add a more complete explanation to the summary of the exact call stack.) |
|
Okay, so... Recall that for Semantic indexing visits all the sub-expressions on the left-hand side of that tuple, and creates an Then, when aggregating completions in the LSP, we call But... the So it's ultimately a discrepancy between the symbols populated during semantic indexing (which includes the empty name) and the inferences created when we unpack the tuple (which doesn't). This doesn't affect type-checking because we never call |
3c6fbe7 to
dddecee
Compare
|
What do you think of #24697 as an alternative fix, that tackles the problem via improve our parser error recovery for invalid syntax cases? (All Claude generated -- basically just created by me repeatedly prompting it to look at the fundamental cause of why the semantic index and the type inferencer were walking the AST in different ways.) |
|
Here's a comparative review of the two PRs FWIW, also by Claude (but with a new context) DetailsComparative Review: PR #24663 vs PR #24697Both PRs fix the same LSP panic from astral-sh/ty#3283: typing The shared root cause
What each PR actually changes (relative to its merge base)#24663 (Charlie) — downstream, defensive fix
#24697 (Alex) — root-cause, parser fix
How the approaches compareCorrectness. #24697 removes the lie — Test strength. Both share two diagnostic tests. #24697's third test ( Blast radius. #24697 touches a shared parser helper. The three updated snapshots are all API hygiene. #24663 removes the Residual user-visible effect. With #24663, after typing Commit message / framing. #24697's commit message is explicit about the root cause and the alignment with the existing semantic-indexing Minor observations
Recommendation#24697 is the better fix. It's smaller, addresses the root cause, aligns two walkers that had drifted apart, fits the existing A reasonable combined path: land #24697 as the fix, and optionally keep #24663's API rename (drop the call-site changes and the "malformed targets" comment, since they'd no longer be the motivation). But if picking one, take #24697. |
|
That feels closer to my first fix (make sure we infer types for the names we collect), but from the other direction (make sure we don't collect names that we won't infer types for). With that change, given |
|
I guess my feeling on reflection is that my initial fix feels the most correct to me :) |
Summary
We parse
something, not = (1, 2)as (on the LHS) a name target (something) and a unary target (not) followed by an empty name. As a result, we never visit thenotor its name, which means we never infer or record a type for that malformed subtree inUnpackResult.Later, an
expression_type(...)lookup for any subexpression can miss and panic.Closes astral-sh/ty#3283.