Related to #2705, but caused by the reverse ordering. Here the wrapper is already prepended while the original method's sig remains unevaluated, causing filtered generation to miss a signature that full generation finds.
tapioca dsl Foo can generate an untyped RBI while tapioca dsl generates a typed RBI when an already-loaded prepended method hides an unevaluated sig.
For example:
require "sorbet-runtime"
module Wrapper
def call(*args)
super
end
end
class Foo
extend T::Sig
sig { params(value: String).returns(String) }
def call(value)
value
end
prepend Wrapper
end
method = Foo.instance_method(:call)
method.owner
# => Wrapper
T::Utils.signature_for_method(method)
# => nil
T::Utils.run_all_sig_blocks
T::Utils.signature_for_method(method)
# => signature with (String) -> String
Filtered DSL generation does not call T::Utils.run_all_sig_blocks, so a DSL compiler inspecting Foo.instance_method(:call) sees the wrapper's parameters and no signature:
sig { params(args: T.untyped).returns(T.untyped) }
def call(*args); end
Unfiltered generation evaluates all pending signatures first, allowing Sorbet Runtime to associate the signature with the currently resolved wrapper:
sig { params(value: String).returns(String) }
def call(value); end
Both commands should generate the typed definition.
Related to #2705, but caused by the reverse ordering. Here the wrapper is already prepended while the original method's
sigremains unevaluated, causing filtered generation to miss a signature that full generation finds.tapioca dsl Foocan generate an untyped RBI whiletapioca dslgenerates a typed RBI when an already-loaded prepended method hides an unevaluatedsig.For example:
Filtered DSL generation does not call
T::Utils.run_all_sig_blocks, so a DSL compiler inspectingFoo.instance_method(:call)sees the wrapper's parameters and no signature:Unfiltered generation evaluates all pending signatures first, allowing Sorbet Runtime to associate the signature with the currently resolved wrapper:
Both commands should generate the typed definition.