Skip to content

Resolve module_function visibility#802

Merged
alexcrocha merged 1 commit into
mainfrom
05-11-resolve_module_function_visibility
Jul 17, 2026
Merged

Resolve module_function visibility#802
alexcrocha merged 1 commit into
mainfrom
05-11-resolve_module_function_visibility

Conversation

@alexcrocha

@alexcrocha alexcrocha commented May 12, 2026

Copy link
Copy Markdown
Contributor

Closes #89 and finishes the singleton-method visibility resolution work started in #780/#781/#782. This PR resolves retroactive module_function visibility:

module Foo
  def bar; end
  module_function :bar
end

Foo.bar           # public singleton method
Foo.new.bar       # NoMethodError (private instance method)

Foo#bar becomes private and Foo.bar is added as a public singleton method.

One definition per side

The indexer emits two MethodVisibility definitions at the module_function :bar call site: one for Foo#bar and one for Foo::<Foo>#bar. The singleton-side definition uses the existing SINGLETON_METHOD_VISIBILITY flag; both carry Visibility::ModuleFunction.

The definitions must remain separate because reverse lookup maps each definition to one declaration. Giving each side its own definition lets invalidation detach the instance and singleton declarations independently when the source method or module_function call is removed. The flag bits are included in MethodVisibilityDefinition::id() so the two definitions at the same source location have distinct IDs.

Resolution

The instance-side definition follows the existing method-visibility path. The singleton-side definition looks for the same instance method, then attaches a declaration to the singleton class. Graph::visibility() exposes these as Private and Public, respectively.

The singleton class is created only after the target method is found. For module_function :missing, the instance side emits the diagnostic while the singleton side stays silent, leaving no empty Foo::<Foo> namespace behind.

The existing inline form (module_function def bar; end) is unchanged. Regression coverage verifies that its singleton companion can still be changed by a later singleton visibility call.

Known difference from Ruby

Rubydex resolves each argument independently. For module_function :a, :missing, it makes Foo#a private, adds the public Foo.a, and reports :missing. Ruby makes Foo#a private before raising, but creates no singleton copies for the call. Resolving independently preserves useful information while code is incomplete in an editor.

Copy link
Copy Markdown
Contributor Author

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

@alexcrocha
alexcrocha force-pushed the 05-11-resolve_module_function_visibility branch from f1516b0 to f4f9a77 Compare May 12, 2026 16:53
@alexcrocha alexcrocha self-assigned this May 12, 2026
@alexcrocha alexcrocha added the enhancement New feature or request label May 12, 2026
@alexcrocha
alexcrocha marked this pull request as ready for review May 12, 2026 16:54
@alexcrocha
alexcrocha requested a review from a team as a code owner May 12, 2026 16:54
Comment thread rust/rubydex/src/resolution.rs Outdated
@alexcrocha
alexcrocha force-pushed the 05-11-resolve_module_function_visibility branch from f4f9a77 to cdc2a76 Compare July 10, 2026 21:12
@alexcrocha
alexcrocha requested a review from a team July 13, 2026 16:56

@vinistock vinistock 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.

Do we already support module function and the other visibility operations in the RBS indexer?

Comment thread rust/rubydex/src/resolution.rs Outdated
Comment thread rust/rubydex/src/resolution.rs Outdated
Comment thread rust/rubydex/src/resolution_tests.rs
@alexcrocha

Copy link
Copy Markdown
Contributor Author

I pushed a new commit simplifying the logic, which was a bit complex to grok. There's no more target/declaration owner split, and declaration creation is now next to the method match.

There's some duplication now, which is what I was trying to eliminate in the previous version. Let me know if this is more readable.

(Clippy complains that the function has too many lines. I'll fix it once we are happy with the shape of implementation)

@vinistock vinistock 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.

Looks good in general, I'm just wondering if we can unify the method visibility handling into a single loop

Comment thread rust/rubydex/src/resolution.rs Outdated
`module_function :bar` makes `Foo#bar` private and adds `Foo.bar` as
a public singleton method. The indexer emits two `MethodVisibility`
defs at the call site so resolution and reverse-lookup invalidation
handle each side independently.
@alexcrocha
alexcrocha force-pushed the 05-11-resolve_module_function_visibility branch from 71b877e to 320080b Compare July 16, 2026 22:25
@alexcrocha
alexcrocha requested a review from vinistock July 16, 2026 22:39
@alexcrocha
alexcrocha merged commit 8fea7dc into main Jul 17, 2026
37 checks passed
@alexcrocha
alexcrocha deleted the 05-11-resolve_module_function_visibility branch July 17, 2026 18:08
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.

Start keeping track of visibility for applicable definitions

3 participants