refactor(infer): delete the it/this text-scan ladder; broken syntax gets CST brace-repair#204
Merged
Conversation
There was a problem hiding this comment.
Pull request overview
This PR continues the CST lambda-triad refactor by removing the last production it/this text-scan fallback and routing it resolution through Indexer::live_doc_or_parse, making CST-based inference universal. It also addresses a real regression uncovered by the refactor (loss of element type arguments) and adds targeted regression coverage for disk-only (not live, not indexed) CST parsing.
Changes:
- Remove the backward text-scan ladder for
itinference; always resolve via CST fromlive_doc_or_parse. - Add bounded, append-only brace repair for broken syntax cases where tree-sitter produces no
lambda_literal. - Fix
extract_collection_element_typeto preserve the element type’s own type arguments (e.g.List<RegularAccount>), and simplify CST param-type plumbing by collapsingCstParamResulttoOption<String>.
Reviewed changes
Copilot reviewed 7 out of 7 changed files in this pull request and generated no comments.
Show a summary per file
| File | Description |
|---|---|
| src/resolver/infer_lines.rs | Preserve element type arguments when extracting collection element types to enable correct chained member substitution. |
| src/indexer/scope_tests.rs | Update it inference tests to use CST-backed find_it_element_type_in_lines, and add regression coverage for disk-only transient parsing. |
| src/indexer/infer/it_this.rs | Delete the production text-scan ladder; introduce CST gating + bounded brace-repair transient parses for broken syntax. |
| src/indexer/infer/it_this_tests.rs | Convert text-based it tests to full-document CST setups with explicit cursor positions; update regression test expectations to transient-parse reality. |
| src/indexer/infer/cst_lambda.rs | Remove CstParamResult tri-state and streamline CST parameter inference APIs to Option<String>; keep text-scan only under #[cfg(test)]. |
| src/indexer/infer/args.rs | Mark has_named_params_not_it as test-only now that production named-param detection is CST-based. |
| src/indexer.rs | Adjust re-exports so has_named_params_not_it is only exposed under #[cfg(test)]. |
60cbeb1 to
bf3673a
Compare
…ets CST brace-repair (drop CstParamResult ceremony)
The it gate now takes Indexer::live_doc_or_parse, making the CST path
universal (live tree for open files, transient parse for indexed/disk
files), and the backward text-scan ladder in it_this.rs is deleted.
Broken syntax is no longer a text-scan excuse: tree-sitter forms no
lambda_literal for an unclosed `{` (the brace opens an ERROR node), so a
typed gate detects ERROR-above-cursor-without-lambda and resolves against
an append-only brace-repaired transient reparse — same resolver, repaired
tree, self-verified and bounded, never cached.
Root fixes surfaced by the re-route:
- extract_collection_element_type now preserves the element's own type
arguments (Flow<List<A>> -> List<A>, not List), so the CST chain walk
can substitute through subsequent member accesses. Pinned by
inline_lambda_also_nested_in_outer_lambda, which returned a wrong
Some("List") on the CST path before.
- it_type_at_lambda gains the lambda_receiver_type_from_context branch the
deleted ladder had (calls whose callee sits on an inner call_expression
are not served by the CST signature lookups; verified still required).
Also per the slice plan:
- CstParamResult deleted — every consumer flattened to Option<String>.
- New regression test pins the ungated named-param branch of
infer_lambda_param_type_at resolving from a disk-only file (13fffc7).
- has_named_params_not_it is cfg(test): its last production caller was the
deleted ladder.
- 12 former text-fallback tests converted to index the full document and
resolve via the transient parse; regression_immutable_list_foreach_it_
text_path renamed to ..._transient_parse to describe reality.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EJsyQ1UgF8uJYR4HgpxEBB
09b0ec8 to
b1fa44e
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Task 6 of the CST lambda-triad collapse: the last text fallback — the backward text-scan ladder in
find_it_element_type_in_lines_impl— is deleted. Theitgate now routes throughIndexer::live_doc_or_parse, making the CST path universal forit/thisexactly like thethis(Task 2b), named-param (Task 5), and completion-scope (Task 7) paths before it.Broken syntax: repair the source, don't scan it
The deletion surfaced a real capability the text scan silently provided: for
items.forEach { it.name(unclosed brace — the mid-typing state), tree-sitter forms nolambda_literalat all (… → statements → ERROR → source_file), so no parse can answer. Instead of keeping a text heuristic, the ERROR case now gets append-only brace repair: a typedLambdaTreeGatedistinguishes ERROR-at/above-cursor (repair permitted) from a well-formed tree with no lambda (authoritativeNone); the repair appends}at EOF (zero offset shift — the cursor position stays valid), transient-parses (never cached intolive_trees), self-verifies the cursor now sits in alambda_literal(capped at 8 attempts), and runs the same resolver on the repaired tree.ItResolutionDoc::{Live, Repaired}keeps a repaired-tree answer from masquerading as an authoritative one.hints_survive_syntax_errornow passes via the repair branch.Root-fix found en route
extract_collection_element_typewas stripping type arguments from the element (List<RegularAccount>→List) viadotted_ident_prefix(), silently breaking nested chains (collect { it.firstOrNull()?.account?.accountId?.also { … } }— inneritresolved toListinstead ofString). It now validates via the dotted prefix but returns the full parameterized type;inline_lambda_also_nested_in_outer_lambdapins it, assertion untouched.Also deleted
CstParamResult+into_option()— after the two-state collapse every consumer mapped both variants toNone; the type stopped carrying a decision, so it's now plainOption<String>at all three producers.IT_SCAN_BACK_LINESand the ladder's helpers (re-homed to#[cfg(test)]where unit tests still exercise them directly).Plus: a
tempfile-based regression test pinning the scope.rs ungating fix from the s5 stack (named-param resolution from a disk-only file that is neither open nor indexed).Verification
cargo test --bin kmp-lsp— 1442 passed, 0 failed (baseline 1441 + 1 new regression test); clippy clean.Stacked on #202 (
refactor/cst-resolution-s7). Next: Task 8 — with this landed,lambda_receiver_type_from_context/lambda_receiver_type_named_arg_mlare down to two cst_lambda call sites; closing those deletes receiver.rs (~480 lines).🤖 Generated with Claude Code
https://claude.ai/code/session_01EJsyQ1UgF8uJYR4HgpxEBB