Skip to content

Introduce Receiver enum to distinguish self vs constant method receivers#573

Merged
st0012 merged 1 commit intomainfrom
refactor-singleton-reference
Feb 26, 2026
Merged

Introduce Receiver enum to distinguish self vs constant method receivers#573
st0012 merged 1 commit intomainfrom
refactor-singleton-reference

Conversation

@st0012
Copy link
Member

@st0012 st0012 commented Feb 6, 2026

Summary

Prerequisite for #515 (anonymous Class/Module). Anonymous classes have no names, so def self.foo inside them can't be represented as Option<NameId>. SelfReceiver(DefinitionId) points directly to the enclosing definition without needing a name.

  • Replaces Option<NameId> on MethodDefinition.receiver with Receiver::SelfReceiver(DefinitionId) | ConstantReceiver(NameId), making the distinction between def self.foo and def Foo.foo explicit at the type level — previously both were NameId and indistinguishable by the time resolution runs.
  • SelfReceiver enables a direct definition_id_to_declaration_id lookup instead of going through name resolution.
  • Fixed a panic where def self.baz inside an unresolvable class (e.g., class Foo::Bar where Foo is undefined) would crash on .expect() — now silently skips orphaned methods.

@st0012 st0012 self-assigned this Feb 6, 2026
@st0012 st0012 requested a review from a team as a code owner February 6, 2026 19:19
@st0012
Copy link
Member Author

st0012 commented Feb 6, 2026

@vinistock This is the change we talked about during the pairing. It's not as big of a refactor as we thought (not making it more complicated either), but it's necessary for proper anonymous class/module's singleton methods support.

@vinistock
Copy link
Member

The current approach to get around this is to create an anonymous name for the anonymous class/module, which works for singleton methods too.

It has the benefit that we don't need two separate code paths for handling method receivers that end up being nearly identical.

Does that approach not work for this?

@st0012
Copy link
Member Author

st0012 commented Feb 6, 2026

No it won't work for #515 because at the indexing phase we don't want to create an anonymous name for all DSL definitions. And the DSL -> Anonymous class transition only happens at resolution phase, which means we'll need to associate methods to the DSL without relying on a name.

@st0012 st0012 force-pushed the refactor-singleton-reference branch 2 times, most recently from 0b71efd to dba2d8c Compare February 10, 2026 17:06
@st0012 st0012 requested a review from vinistock February 10, 2026 21:43
@st0012 st0012 force-pushed the refactor-singleton-reference branch from dba2d8c to 5b7c12c Compare February 10, 2026 21:48
@st0012 st0012 mentioned this pull request Feb 11, 2026
@st0012 st0012 force-pushed the refactor-singleton-reference branch from 5b7c12c to af1d2a0 Compare February 20, 2026 17:47
@st0012 st0012 requested a review from Morriar February 20, 2026 17:47
Copy link
Member

@vinistock vinistock left a comment

Choose a reason for hiding this comment

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

I think this PR is good, but let's not include resolution diagnostics as a part of it yet.

We need to think of resolution diagnostics in a complete way to avoid over notifying the user with several errors that are in fact just one underlying problem.

@st0012 st0012 force-pushed the refactor-singleton-reference branch 2 times, most recently from 7a2bde4 to 6669334 Compare February 25, 2026 12:24
Replace `Option<NameId>` on `MethodDefinition.receiver` with
`Option<Receiver>` where `Receiver` is either `SelfReceiver(DefinitionId)`
or `ConstantReceiver(NameId)`.

For `def self.foo`, the indexer now stores the enclosing definition's
`DefinitionId` directly instead of eagerly extracting its `NameId` via
`current_owner_name_id()`. During resolution, `SelfReceiver` uses a
direct `definition_id_to_declaration_id` lookup (single hashmap hit)
rather than going through `resolve_lexical_owner`'s recursion and
namespace checks. This is safe because `SelfReceiver` always points at
the enclosing class/module by construction.

`ConstantReceiver(NameId)` preserves the existing behavior for
`def Foo.bar`, which still requires name resolution and can fail
if the constant is undefined.
@st0012 st0012 force-pushed the refactor-singleton-reference branch from 6669334 to 19579d2 Compare February 26, 2026 17:30
@st0012 st0012 merged commit 2b1a953 into main Feb 26, 2026
27 checks passed
@st0012 st0012 deleted the refactor-singleton-reference branch February 26, 2026 17:37
@st0012 st0012 restored the refactor-singleton-reference branch February 26, 2026 18:15
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.

3 participants