Skip to content

Reduce member completion, hover and signature-help latency - #793

Merged
renkun-ken merged 11 commits into
REditorSupport:masterfrom
renkun-ken:codex/member-intelligence-performance
Oct 11, 2026
Merged

renkun-ken merged 11 commits into
REditorSupport:masterfrom
renkun-ken:codex/member-intelligence-performance

Conversation

@renkun-ken

@renkun-ken renkun-ken commented Oct 11, 2026 •

Copy link
Copy Markdown
Member

Completion, hover and signature help repeatedly replayed unrelated local assignments, re-inferred receivers and processed package defaults/delegation. Parse debounce also delayed completion after ordinary typing. This PR avoids that work while retaining static inference, structural-edit handling and production inference limits (250 ms / 20,000 nodes).

Changes

  • Index accepted source scopes, function/default ranges, statement dependencies and binding histories. Requests use range lookup, follow needed definitions and resolve retained locals lazily; incomplete syntax keeps bounded recovery.
  • Collect syntax names iteratively in C, including formal defaults and deduplicating symbols without per-node R allocation. Charge source/scope index contents to the parse-cache budget.
  • Share successful receiver analysis across providers in a per-document cache bounded to 32 entries / 4 MiB. Invalidate on edits, accepted parses and semantic metadata changes; exclude exhausted/incomplete results.
  • Skip member inference for ordinary symbols, disabled member completion and unrelated cached class metadata. Handle argument-less library() / require() and replenish scope candidates after shadow filtering.
  • Capture only each deferred local's dependencies with request-local hashed lookup. Infer outer list/literal shapes for completion enrichment without populating full member-value memos; lexical shadowing and class-producing expressions retain full inference.
  • Reuse package invocation summaries before defaults/delegation. Prepare return guarantees for short exported wrappers and methods using native-backed properties in the package worker, with deterministic staged probes bounded to 40,000 nodes and 1 MiB of summary accounting. Summaries retain class/type only; unknown variadic arguments, conditional fields, nested instance fields and replaced properties retain conservative inference.
  • Remove debounce when promoting queued parses. Completion may reuse accepted scope for a narrowly checked final-line standalone identifier edit in an ordinary R script; structural edits, class sources, defaults and literate cells use current parsing.

Benchmarks

Installed R 4.6.1/macOS arm64 measurements with production request budgets. Pairwise comparisons use the same fixture and clear the relevant caches; results from different fixture/revision pairs should not be compared directly.

Source/scope indexes versus the first performance implementation (2303aaf), 1,000 locals, 15 sequential samples:

Workload Before indexes With indexes
Cold local list receiver 25 ms 1 ms
Cold receiver inside an R6 method 26 ms 2 ms
Cold R6 empty-prefix scope completion 85 ms 70 ms
Full parse, ordinary function / R6 declaration 74 / 74 ms 69 / 70 ms

Serialized parse size grows about 2–3%; the 1,000-binding index occupies about 0.5 MiB and is charged to the parse-cache budget.

Dependency capture and completion shape inference versus 9ce3a8b, alternating 25 requests per implementation, 1,000 locals:

Workload Before follow-up With follow-up
Cold R6 scope completion 73 ms 38 ms
Warm R6 scope completion 27 ms 13 ms
Ordinary scope completion, cold / warm 1 / 1 ms 1 / 1 ms

Full completion responses agree. Separate allocation profiling reduces cold R6 completion traffic from 68.6 MB to 17.1 MB; serialized parse size and full parse medians are unchanged.

Bounded package return preparation versus 7e3e7cd, separate installed R sessions, alternating 20 requests per implementation, Polars 1.16.0 long-chain fixture. Metadata is decoded before timing. Cold invocation clears both invocation and document receiver caches; warm invocation clears only the receiver cache.

Provider Cold invocation before / after Warm invocation before / after Fully warm before / after
Completion 198.5 / 119.5 ms 126.5 / 29 ms 5 / 6 ms
Signature help 193 / 114 ms 125 / 26 ms 1 / 1 ms
Hover 186 / 109 ms 125.5 / 26 ms 1 / 1 ms

Cold p95 falls from 221.1 / 242.1 / 194.2 ms to 147.4 / 148.2 / 115.4 ms respectively. Responses agree after excluding the expected completion metadata-generation identifier change. Separate allocation profiling reduces cold completion traffic from 20.57 MB to 11.27 MB (three samples, median); only diagnostic profiling extends its deadline, and profiling is excluded from timed samples.

Polars worker preparation takes 4.824 / 5.768 seconds in this run. Summaries increase from 22 to 227, their object size from 64,096 to 660,352 bytes, and the serialized package snapshot from 4,913,841 to 5,067,466 bytes. Preparation remains outside the request path.

Validation

All 10 GitHub checks pass on aff6874: Linux/macOS/Windows R CMD checks, lint, stable/development S7 and all four coverage shards.

  • Final installed completion, hover, signature, language-feature handler, member analysis/completion/providers/source, S4, class-scope and R6-symbol suites pass. Stable S7 has three expected capability skips; development-S7 member/class-scope suites pass.
  • Regression coverage exercises indexed/fallback response equality, ordered effects, alias captures, nested/default scopes, accepted edits, serialization/cache accounting, lexical shadowing, completion limits, argument matching, variadic forwarding and conditional/nested/replaced fields. Preparation/inference never executes fixture inputs, defaults, constructors or methods.
  • Member completion/providers and R6 coverage passes 791 assertions. Final member-completion/signature coverage passes 366 assertions, including the last field-preservation regressions. Native tests include defaults, ignored attributes, duplicates and deep syntax; an additional forced-GC probe passes. No new lints; git diff --check passes.
  • Fixed concurrent coverage startup timeouts by isolating R6, Polars and signature fixtures in empty temporary workspaces. R6 awaits initial parsing before edit assertions; Polars has a coverage-specific metadata startup deadline. Immediate post-edit requests still disable retries. The original failing coverage shard subsequently passed; Cross-file signature tests explicitly await definition parsing through document-symbol replies. The final signature suite passes 70 assertions under coverage, and the complete local coverage shard 4 passes 657 assertions with one existing empty-test skip.

The PR includes production code and tests only. Benchmark scripts, CSV files and plans remain local.

@renkun-ken
renkun-ken requested a review from eitsupi October 11, 2026 00:04
@renkun-ken
renkun-ken force-pushed the codex/member-intelligence-performance branch from 5020ef8 to 9de91f6 Compare October 11, 2026 00:20
@renkun-ken
renkun-ken force-pushed the codex/member-intelligence-performance branch from 9de91f6 to 2303aaf Compare October 11, 2026 01:09

@eitsupi eitsupi left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Review by ChatGPT

I found two potential regressions that remain in the latest revision:

  1. Argument-less library() / require() calls: member_package_scope_required() accesses item$expr[[2L]] without checking the call length. Both functions allow calls without arguments, so ordinary completion, hover, or signature help may fail. Please handle these calls and add regression tests.

  2. Truncation before shadow filtering: scope_completion() now applies the candidate limit before keep_source(). When a name appears in both symbol and function candidates but one is subsequently filtered out (e.g., an enclosing function shadowed by a method-local variable), it can consume a slot and exclude another valid candidate. Please apply the limit after filtering, or replenish the candidates, and add a regression test.

Both issues should be addressed before merging.

@renkun-ken
renkun-ken requested a review from eitsupi October 11, 2026 07:01
@renkun-ken
renkun-ken merged commit ecacca7 into REditorSupport:master Oct 11, 2026
10 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants