-
Notifications
You must be signed in to change notification settings - Fork 136
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
More effectively determine method ownership for RBI generation #896
Conversation
lib/tapioca/gem/listeners/methods.rb
Outdated
# Widen the type of `method` to be nilable | ||
method = T.let(method, T.nilable(UnboundMethod)) | ||
|
||
loop do |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Would while method
here work and allow us to remove the break
?
lib/tapioca/gem/listeners/methods.rb
Outdated
# | ||
# This method implements a better way of checking whether a constant defines a method. | ||
# It walks up the ancestor tree via the `super_method` method; if any of the super | ||
# methods are owned by the constant, it means that the constant declares the method. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could we have this comment on top of the method as documentation rather than inside?
add_ruby_file("foo.rb", <<~RUBY) | ||
module Foo | ||
def bar | ||
super |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we add an example that does not call super
? 🙏
lib/tapioca/gem/listeners/methods.rb
Outdated
@@ -66,7 +66,7 @@ def compile_directly_owned_methods(tree, module_name, mod, for_visibility = [:pu | |||
end | |||
def compile_method(tree, symbol_name, constant, method, visibility = RBI::Public.new) | |||
return unless method | |||
return unless method.owner == constant | |||
return unless method_defined_by_constant?(method, constant) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I know that I had named this method but looking at it again, it feels like method_owned_by_constant?
would be a more appropriate name, since we are doing ownerships checks.
5b4bf06
to
a0ab5d9
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Amazing thanks! 🎉
Motivation
This issue was discovered by @paracycle while investigating #890, but it is technically unrelated to mixin generation.
While generating RBIs for a method, tapioca implements a check to determine which constant "owns" or defines that method. We only want to generate RBIs for a method on the module or class that defines it, not any that just happen to inherit it.
Historically, we have been checking the
method.owner
and verifying that it matches the class/module for which we are generating RBIs. However, this check misses one particular case: when a method is also defined on a prepended module, it will always appear as if it belongs to the prepended module, even when it is also defined on the class that prepends the module.This means that tapioca will not generate RBI for that method on the class that defines it.
Implementation
This code was originally written by @paracycle on commit 80faabc. I've just cleaned it up and moved it to the correct spot.
Instead of just checking the method owner, this implementation walks up the ancestor chain via the
super_method
method, checking if any of the super methods are owned by the constant. If that is the case, that means the constant also defines the method, and we should generate RBIs for this method on the constant.Tests
I have added a test which fails without the changes but passes with the changes included.
Tophatting
I tested this change by generating gem and dsl RBIs on Shopify core using this branch of tapioca and verifying that the change did not introduce any new typing issues.