refactor(infer): delete receiver.rs — the CST path is the only resolution path#205
Merged
Hessesian merged 3 commits intoJul 4, 2026
Merged
Conversation
There was a problem hiding this comment.
Pull request overview
This PR completes the “CST lambda-triad collapse” by removing the text-based lambda receiver inference module and routing it/this/named-param typing and completion scope exclusively through CST-backed resolution, including fixes for trailing-lambda call nesting and EOF cursor positioning.
Changes:
- Delete
src/indexer/infer/receiver.rsand remove its exports/usages, consolidating lambda parameter inference throughcst_lambda_param_type_at/ CST ancestor-walk paths. - Improve callee/receiver-chain unwrapping for
f(args) { ... }nesting in bothNodeExtand CST chain resolution so call-site inference works without text heuristics. - Fix CST cursor lookup at EOF on
\n-terminated documents and add a pinning regression test.
Reviewed changes
Copilot reviewed 14 out of 14 changed files in this pull request and generated 1 comment.
Show a summary per file
| File | Description |
|---|---|
| src/indexer/node_ext.rs | Unwrap nested call_expression to recover callee/qualifier for trailing-lambda-with-args shapes. |
| src/indexer/infer/type_subst.rs | Simplify type-arg extraction helpers after receiver.rs deletion. |
| src/indexer/infer/receiver.rs | Deleted: former text-based lambda receiver/type inference path. |
| src/indexer/infer/mod.rs | Remove receiver module from infer module surface. |
| src/indexer/infer/lambda.rs | Remove lambda_type_first_input helper; rely on remaining nth/receiver helpers. |
| src/indexer/infer/lambda_tests.rs | Drop tests tied to removed lambda_type_first_input; adjust to remaining API. |
| src/indexer/infer/it_this.rs | Route it inference through CST-only cst_it_element_type; keep brace-repair flow. |
| src/indexer/infer/it_this_tests.rs | Add EOF trailing-empty-line regression test; convert many tests to CST param typing seam. |
| src/indexer/infer/cst_lambda.rs | Remove text-heuristic fallback plumbing; unify it resolution and fix cursor_node_at EOF handling. |
| src/indexer/infer/chain.rs | Unwrap nested call-expression callee chains; relocate uppercase_dotted_type_prefix. |
| src/indexer/infer/args.rs | Remove dead named-arg text extraction helper previously only used by receiver.rs. |
| src/indexer/infer/args_tests.rs | Remove tests for deleted named-arg text helper. |
| src/indexer.rs | Remove re-exports of deleted receiver/text helpers. |
| src/indexer_tests.rs | Replace text-heuristic direct tests with CST-based cursor-positioned inference assertions. |
09b0ec8 to
b1fa44e
Compare
…des; retire the text heuristics
Problem A: the completion ancestor-walk (`lambda_scope_info`) resolved each
enclosing lambda's `it` type by slicing before-brace text and calling
`lambda_receiver_type_from_context`. It now resolves the `lambda_literal` node
directly through `cst_lambda_param_type_at`, the same path the innermost lambda
and named params already use.
Problem B: `f(args) { it }` nests as `outer_call(inner_call, call_suffix{lambda})`,
so the callee lived on the inner call_expression that the CST lookups did not
unwrap. `call_fn_and_qualifier` and `resolve_callee_chain` now unwrap that inner
call, so `loadProduct(a, b) { it }` and `items.mapNotNull(::t) { it }` resolve
through the node path. Decoys `trailing_lambda_it_infer_at_cursor` and
`it_element_type_with_call_args` are RED without the text call, GREEN via nodes.
With both call sites CST-native the text-heuristic family is production-dead, and
the pre-commit clippy gate (-D dead-code) forces its removal here rather than in
the follow-up: `lambda_receiver_type_from_context` + its ~15 internal helpers,
`lambda_receiver_type_named_arg_ml`, `fun_trailing_lambda_it_type`,
`inline_lambda_param_type`, `receiver_aware_params_from_text`, and the orphaned
`extract_named_arg_name`, `lambda_type_first_input`, `first_concrete_type_arg_str`.
`it_type_at_lambda` collapses onto `cst_lambda_param_type_at`; the never-constructed
`LambdaParamKind::This` walk branch and the enum go with it (`cst_it_or_this_type`
→ `cst_it_element_type`); the duplicate inner-call unwrap in `lambda_this_ctx` is
removed. receiver.rs keeps only the three signature utilities the CST resolvers
still call — the follow-up commit relocates them and deletes the file.
Tests: the 25 it_this_tests sites that unit-tested the text heuristic now drive
the production CST resolver via `cst_param_type` (same TestDeps, real lambda
nodes); indexer_tests conversions use full-document + cursor positions. Deleted
as implementation-detail or exact CST twins: trailing_lambda_it_from_fun_def,
trailing_lambda_it_with_method_call_arg, this_in_run_resolves_to_receiver_type,
extract_named_arg_name_test, extract_named_arg_* (args_tests, 5),
lambda_type_first_input_parses_correctly.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EJsyQ1UgF8uJYR4HgpxEBB
…tion path Move-don't-rewrite relocation of the three survivors to their sole callers: `uppercase_dotted_type_prefix` → chain.rs; `fun_trailing_lambda_this_type` and `resolve_call_params` → cst_lambda.rs. receiver.rs and its `mod` declaration are gone; every deleted function verified at zero references. Also folds in the PR #202 review finding: `cursor_node_at` looked the cursor line up via `str::lines()`, which yields no final empty line for `\n`-terminated content — a cursor on the trailing empty line (end-of-file, e.g. right after typing `items.forEach {` + Enter) returned `None`, failing `it` resolution and the brace-repair gate before they could run, and emptying the completion lambda-scope stack. The trailing-gap cursor now resolves on the last character of the last content line (node ends are exclusive), whose node carries the enclosing context. Pinned by `it_resolves_on_trailing_empty_line_at_eof` (RED without the fix, GREEN with it). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01EJsyQ1UgF8uJYR4HgpxEBB
… goes tree-wide The remap used `len() - 1` as a byte column, splitting a multi-byte final codepoint. Fixing that surfaced a second hole the new pinning test caught: a trailing comment is a tree-sitter extra attached outside the ERROR node, so the chain-only gate saw no error and skipped repair for an unclosed lambda ending in `// note`. The gate now treats any parse error in the tree as license to repair when no enclosing lambda_literal exists — repair self-verifies, so over-permission still converges to authoritative None. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01EJsyQ1UgF8uJYR4HgpxEBB
8e1e657 to
7507066
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 8, the finale of the CST lambda-triad collapse: receiver.rs (518 lines) is deleted. Net −783 lines. Every lambda-typing question —
it,this, named params, completion scope — now resolves through one CST path; the text-expression inference module and all of its helpers are gone. Task 9's sweep (lambda_receiver_type_named_arg_ml, dead helpers/constants) is fully absorbed.The two problems that gated the deletion
it_typeby slicing before-brace text intolambda_receiver_type_from_context.lambda_scope_infonow resolves from thelambda_literalnode via the samecst_lambda_param_type_atthe innermost path uses;before_bracesurvives only to build the display label.it_type_at_lambdakept a text heuristic was that the node path didn't unwrap a one-level innercall_expressioncallee. Two minimal unwraps (NodeExt::call_fn_and_qualifier,resolve_callee_chain) close it at root — and subsumed a pre-existing hand-rolled unwrap inlambda_this_ctx, which is deleted. Decoys (trailing_lambda_it_infer_at_cursor,it_element_type_with_call_args) verified RED without the heuristic, GREEN via the node path, assertions untouched.Also in here
cursor_node_atusedstr::lines(), which drops the final empty line of\n-terminated content — a cursor at EOF returnedNoneand emptied the completion scope stack. Fixed with a pinning test (it_resolves_on_trailing_empty_line_at_eof).stdlib_let_generic_param_not_leakednow expectsLong?— the receiver is a plain.letonLong?, soitgenuinely isLong?; the oldLongwas the text heuristic silently stripping nullability. Reviewed and ruled correct per Kotlin semantics.uppercase_dotted_type_prefix→ chain.rs,resolve_call_params+fun_trailing_lambda_this_type→ cst_lambda.rs (bodies byte-identical).ItTypeAtLambdaandLambdaParamKind::Thisdeleted — the collapse removed type ceremony too, not just text.Verification
cargo test --bin kmp-lsp— 1433 passed, 0 failed (1442 − 10 converted-away + 1 new).cargo clippy -- -D warningsclean.find_referencing_symbols+-D dead-codegate).Stacked on #204. With this, the lambda-triad collapse (Tasks 1–9) is complete.
🤖 Generated with Claude Code
https://claude.ai/code/session_01EJsyQ1UgF8uJYR4HgpxEBB