Skip to content

fix(resolve): bind an extension's own type param from a plain receiver - #328

Merged
Hessesian merged 2 commits into
mainfrom
fix/extension-receiver-type-param-subst
Oct 5, 2026
Merged

Hessesian merged 2 commits into
mainfrom
fix/extension-receiver-type-param-subst

Conversation

@Hessesian

Copy link
Copy Markdown
Owner

Problem

fun <T : Any> T?.required(field: String): T (Moneta's NullableScope) inferred its return type as the literal "T", so textModel.required("textModel").title searched for title on a class named T and missed.

Root cause (two independent bugs, both hidden by #318's test)

  1. The parser stores extension_receiver_type only when the receiver has generics, so a plain T? receiver was empty and CallableInfo had nothing to bind T against. CallableInfo now uses SymbolEntry::declared_extension_receiver() (full type if generic, else base name).
  2. A real extension is not a method of its receiver's type, so receiver_based_method never matched and the return came from SignatureDerived, which never substituted from the receiver. It now does for .-calls (callee_receiver_type extracted and shared).

Tests

  • callable_info_reports_a_non_generic_type_param_receiver (red before)
  • resolve_call_expr_type_substitutes_extension_receiver_for_a_signature_derived_return (red before)
  • cargo test (2015), clippy -D warnings, fmt clean

Verification

Literal repro InitUseCase.kt:56:47 in Moneta now resolves (was a Gap); minimal fixture went FilteredCandidate -> resolved. Aggregate Moneta recall is flat (~91.9% member): this is one small slice of the title gap; the rest are separate causes being handled in follow-up PRs.

🤖 Generated with Claude Code

…r (T?.required)

`fun <T : Any> T?.required(): T` inferred its return as the literal "T", so
`textModel.required("x").title` looked `title` up on a class named "T".

Two causes, both hidden by #318's test (its mock supplied data a real index
never does, and it exercised the wrong strategy):
- the parser stores extension_receiver_type only for generic receivers, so a
  plain `T?` receiver was empty and CallableInfo carried nothing to bind T
  against; CallableInfo now uses SymbolEntry::declared_extension_receiver
- a real extension is not a method of its receiver's type, so the return came
  from the SignatureDerived strategy, which never substituted from the
  receiver; it now does, for `.`-calls

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Copilot review overview

🟡 Changes recommended

Receiver nullability and same-named callable collisions can produce incorrect inferred types.

Review effort: Balanced
Findings: 2 Medium severity · 1 Low severity

Open (3)
What changed in this PR

Adds generic return-type substitution for extension functions with plain type-parameter receivers.

Changes:

  • Adds declared extension-receiver lookup.
  • Applies receiver substitution to signature-derived returns.
  • Adds regression tests for T?.required().
File Description
src/​types.rs Adds declared receiver accessor.
src/​indexer.rs Uses declared receivers in callable metadata.
src/​indexer/​infer/​chain.rs Extends receiver-based substitution.
src/​indexer/​infer/​mod_tests.rs Tests signature-derived substitution.
src/​indexer_tests.rs Tests plain receiver metadata.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread src/indexer/infer/chain.rs
Comment thread src/indexer/infer/chain.rs
Comment thread src/indexer/infer/chain.rs Outdated
…hable callable info, naming)

- T? vs T receivers bind a whole-receiver type param by declared nullability;
  the parser now keeps the receiver's ? marker (CACHE_VERSION 33)
- find_fun_callable_info prefers the declaration reachable from the call site
  over an unrelated same-named generic
- rename subst -> substitution in the new code

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
@Hessesian
Hessesian merged commit 35835b8 into main Oct 5, 2026
4 checks passed
@Hessesian
Hessesian deleted the fix/extension-receiver-type-param-subst branch October 5, 2026 14:51
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