Skip to content

Fix method signatures being overwritten by prepended modules - #2718

Open
DaneHarrison wants to merge 3 commits into
Shopify:mainfrom
DaneHarrison:fix/prepend-method-signature
Open

DaneHarrison wants to merge 3 commits into
Shopify:mainfrom
DaneHarrison:fix/prepend-method-signature

Conversation

@DaneHarrison

@DaneHarrison DaneHarrison commented Sep 18, 2026

Copy link
Copy Markdown

Motivation

Fixes #2072 - When a module is prepended onto a class, Tapioca generates the RBI using the prepended module's signature instead of its own.


Implementation

compile_method receives methods obtained with Module#instance_method, which follows the ancestor chain. When a
module is prepended to a class and defines the method, instance_method returns the prepended module's UnboundMethod rather than the class's own, so compile_method was compiling the wrong method.

  • method_owned_by_constant? becomes method_defined_by_constant. It walks super_method and returns the method the
    constant itself defines.

  • New signature_defined_by_constant returns the signature declared on that method. A signature is only accepted
    if signature.method.owner matches the method's owner.

  • The attr_accessor writer inference resolves the constant's own reader first, so it works in either evaluation order.


Further Considerations:

  • If both the class and the prepended module have a sig for the same name, Sorbet keeps only one per key. Whichever block runs last wins - see wrap_method_if_needed and unwrap_method
  • There are other callers to signature_of i.e under dsl, I suspect those will need to be updated as well
    • Let me know if you'd like me to do a follow up PR on this

Tests

  • No sig: a prepended module in front of the method, and multiple prepended modules
  • Cross-gem prepend matching the issue, checking both gems' RBIs
  • Sig with a prepended module that has different parameters
  • Only the prepended module has a sig (the class's method must not take it)
  • Sig evaluated before the prepend, and between two prepends
  • attr_accessor writer inference with the reader's sig evaluated before and after the prepend
  • A prepended module's sig that fails to load is reported once, against the module
  • Skipped: both the class and the prepended module have a sig (Sorbet keeps only one)

@DaneHarrison
DaneHarrison requested a review from a team as a code owner September 18, 2026 18:19
@DaneHarrison

Copy link
Copy Markdown
Author

I have signed the CLA!

@DaneHarrison
DaneHarrison marked this pull request as draft September 18, 2026 18:41
@DaneHarrison
DaneHarrison marked this pull request as ready for review September 19, 2026 05:14
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.

Tapioca does not properly attribute prepended methods

1 participant