Skip to content

Fix definition_id_to_declaration_id for SelfReceiver methods#726

Merged
st0012 merged 1 commit into
mainfrom
fix-self-receiver-definition-mapping
Apr 8, 2026
Merged

Fix definition_id_to_declaration_id for SelfReceiver methods#726
st0012 merged 1 commit into
mainfrom
fix-self-receiver-definition-mapping

Conversation

@st0012
Copy link
Copy Markdown
Member

@st0012 st0012 commented Apr 3, 2026

Summary

  • definition_to_declaration_id for Method definitions used the enclosing namespace + member(str_id) lookup, which returns the wrong declaration when both def self.run and def run exist — it finds the instance method instead of the singleton method
  • This caused pending_detachments during invalidation to detach from the wrong declaration, leaving the SelfReceiver definition attached to the singleton. On re-add, add_definition panicked with "duplicate definition"
  • Fix: check for SelfReceiver and look up through the singleton class, mirroring how resolution places these methods. Same fix applied to MethodAlias with SelfReceiver (RBS alias self.x self.y)

Tests

  • resolution_for_self_method_with_same_name_instance_method — verifies definition_id_to_declaration_id maps correctly
  • resolution_for_self_method_alias_with_same_name_instance_method — same for RBS method aliases
  • no_duplicate_definition_on_identical_file_delete_readd — incremental regression test

@st0012 st0012 force-pushed the fix-self-receiver-definition-mapping branch 3 times, most recently from 447e822 to 3d8b03c Compare April 4, 2026 11:31
@st0012 st0012 marked this pull request as ready for review April 4, 2026 11:34
@st0012 st0012 requested a review from a team as a code owner April 4, 2026 11:34

/// Looks up the declaration for a `SelfReceiver` method/alias through the singleton class.
fn find_self_receiver_declaration(&self, def_id: DefinitionId, member_str_id: StringId) -> Option<&DeclarationId> {
let owner_decl_id = self.definition_id_to_declaration_id(def_id)?;
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

How about panicking early instead of returning None for these ? cases? They indicate data corruption.
The last member(...) call is the only valid case to return None I think.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Depending on resolution order, it's possible that the owner and its singleton class aren't resolved yet. In those cases, returning None is ok. If you check other branches of the caller definition_to_declaration_id function, you can see methods like name_id_to_declaration_id can return None when NameRef is unresolved as well.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Got it — owner_decl_id can be None when the owner isn't resolved yet, and singleton_class() can be None when it hasn't been created yet. I'm good to return None for these cases.

But I think declarations.get() and as_namespace() in between should never fail once we have a valid ID. It might be worth using unwrap() there to make the invariant explicit, but it's a minor point — up to you.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

That's fair. Updated 👍

@st0012 st0012 force-pushed the fix-self-receiver-definition-mapping branch from 3d8b03c to ac5a646 Compare April 6, 2026 12:12
@st0012 st0012 added the bugfix A change that fixes an existing bug label Apr 6, 2026
@st0012 st0012 self-assigned this Apr 6, 2026
@st0012 st0012 force-pushed the fix-self-receiver-definition-mapping branch from ac5a646 to 1766982 Compare April 8, 2026 10:21
Copy link
Copy Markdown
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.

Do we have tests for the connection of definition -> declaration for instance variables inside a method with receiver? E.g.:

def Foo.bar
  @baz = 1 # do we find the right declaration for @baz?
end

definition_to_declaration_id maps a definition to its owning
declaration. For Method definitions, it used the enclosing namespace
+ member lookup, which works for instance methods but returns the
wrong declaration for SelfReceiver methods (def self.foo).

When both def self.run and def run exist, member("run") on the
enclosing class finds the instance method declaration instead of
the singleton method declaration. This caused pending_detachments
during invalidation to detach from the wrong place, leaving the
SelfReceiver definition attached to the singleton declaration.
On re-add, add_definition panicked with "duplicate definition".

Fix: check for SelfReceiver and look up through the singleton class,
mirroring how resolution places these methods.
@st0012 st0012 force-pushed the fix-self-receiver-definition-mapping branch from 1766982 to 90dff59 Compare April 8, 2026 16:09
@st0012
Copy link
Copy Markdown
Member Author

st0012 commented Apr 8, 2026

@vinistock Yeah we're handling that correctly. Just added a test

@st0012 st0012 merged commit f610861 into main Apr 8, 2026
36 checks passed
@st0012 st0012 deleted the fix-self-receiver-definition-mapping branch April 8, 2026 16:57
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bugfix A change that fixes an existing bug

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants