Skip to content

Resolve retroactive singleton method visibility changes#781

Open
alexcrocha wants to merge 1 commit into05-04-index_private_class_method___public_class_method_callsfrom
05-04-resolve_singleton_method_visibility
Open

Resolve retroactive singleton method visibility changes#781
alexcrocha wants to merge 1 commit into05-04-index_private_class_method___public_class_method_callsfrom
05-04-resolve_singleton_method_visibility

Conversation

@alexcrocha
Copy link
Copy Markdown
Contributor

@alexcrocha alexcrocha commented May 5, 2026

Part of #89 and follows #780, which indexed SingletonMethodVisibilityDefinition and left the Definition::SingletonMethodVisibility arm in resolution as a no-op.

This PR resolves retroactive private_class_method and public_class_method calls. We process visibility definitions after the main convergence loop, so the target method declaration is guaranteed to exist by the time we attach visibility.

For inherited targets like private_class_method :foo where foo comes from a parent class's singleton, we create a child-owned MethodDeclaration on the child's singleton class. This matches what #738 did for instance methods, and what CRuby reports when you ask Child.singleton_class.instance_method(:foo).owner:

class Parent
  def self.foo; end
end

class Child < Parent
  private_class_method :foo
end

Child.singleton_class.instance_method(:foo).owner
# => #<Class:Child>   (CRuby copies the method to Child when visibility changes)

Parent.singleton_class.instance_method(:foo).owner
# => #<Class:Parent>  (untouched on the parent)

Why document-scoped diagnostics

When the target doesn't resolve, we emit UndefinedSingletonMethodVisibilityTarget attached to the document, not to the singleton declaration. Walking ancestors via get_or_create_singleton_class(Foo, ...) can create Foo::<Foo> as a side effect, even when it has no real members. For class Foo; private_class_method :missing; end where Foo has no other singleton methods, that synthesized singleton class only exists to host the diagnostic. Attaching to it would leak the declaration on file delete. Document-scoped clears with the file.

In this PR

  • add resolve_singleton_method_visibilities, mirroring resolve_method_visibilities
  • wire it into handle_remaining_definitions via a new arm
  • add the Graph::visibility arm for SingletonMethodVisibility so callers can read it back
  • emit UndefinedSingletonMethodVisibilityTarget (document-scoped) when the target is missing
  • resolution tests and Ruby integration tests for direct, qualified-receiver, inherited, and undefined-target cases
  • regression test verifying the diagnostic clears when the offending file is deleted

Copy link
Copy Markdown
Contributor Author

alexcrocha commented May 5, 2026

Warning

This pull request is not mergeable via GitHub because a downstack PR is open. Once all requirements are satisfied, merge this PR as a stack on Graphite.
Learn more

This stack of pull requests is managed by Graphite. Learn more about stacking.

@alexcrocha alexcrocha changed the title Resolve singleton method visibility Resolve retroactive singleton method visibility changes May 5, 2026
@alexcrocha alexcrocha marked this pull request as ready for review May 5, 2026 22:39
@alexcrocha alexcrocha requested a review from a team as a code owner May 5, 2026 22:39
@alexcrocha alexcrocha self-assigned this May 5, 2026
@alexcrocha alexcrocha added the enhancement New feature or request label May 5, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant