Skip to content

Commit 49ea080

Browse files
committed
Patch Void type handling in Sorbet runtime for correct return types
Since sorbet/sorbet#10064 was merged, for any sig that declares `.void.checked(:tests)`, the runtime will treat the return type as `T.anything` instead of `void` and thus break Tapioca's signature generation for methods that use this pattern. This commit adds a patch to the Sorbet runtime to ensure that the return type is correctly treated as `void` in these cases, allowing Tapioca to generate accurate signatures.
1 parent 4e4c02f commit 49ea080

4 files changed

Lines changed: 65 additions & 1 deletion

File tree

lib/tapioca/internal.rb

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
require "tapioca/sorbet_ext/name_patch"
1414
require "tapioca/sorbet_ext/generic_name_patch"
1515
require "tapioca/sorbet_ext/proc_bind_patch"
16+
require "tapioca/sorbet_ext/void_patch"
1617
require "tapioca/runtime/generic_type_registry"
1718

1819
# The rewriter needs to be loaded very early so RBS comments within Tapioca itself are rewritten
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
# typed: true
2+
# frozen_string_literal: true
3+
4+
# If Signature has `effective_return_type`, then `return_type` always returns the correct type.
5+
# Ref: https://github.com/sorbet/sorbet/pull/10121
6+
return if T::Private::Methods::Signature.method_defined?(:effective_return_type)
7+
8+
module T
9+
module Private
10+
module Methods
11+
module DeclBuilderPatch
12+
def void
13+
super.tap do
14+
@_real_returns_is_void = true
15+
end
16+
end
17+
18+
def finalize!
19+
super.tap do
20+
#: self as untyped
21+
decl.returns = T::Private::Types::Void::Private::INSTANCE if @_real_returns_is_void
22+
end
23+
end
24+
end
25+
26+
DeclBuilder.prepend(DeclBuilderPatch)
27+
end
28+
end
29+
end

sorbet/rbi/shims/sorbet.rbi

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,13 @@ module T::Private
1414
def self.sealed_module?(mod); end
1515
end
1616

17-
class Types::NotTyped < T::Types::Base; end
17+
module Types
18+
class NotTyped < T::Types::Base; end
19+
20+
module Void::Private
21+
INSTANCE = T.let(T.unsafe(nil), T::Private::Types::Void)
22+
end
23+
end
1824

1925
module Methods
2026
ARG_NOT_PROVIDED = T.let(T.unsafe(nil), Object)
@@ -53,6 +59,8 @@ module T::Private
5359
def finalized; end
5460
def finalized=(finalized); end
5561
end
62+
63+
class Signature; end
5664
end
5765

5866
module DeclState

spec/tapioca/gem/pipeline_spec.rb

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4627,6 +4627,32 @@ def foo; end
46274627
assert_equal(output, compiled)
46284628
end
46294629

4630+
it "compiles methods with .void.checked(:tests) properly" do
4631+
add_ruby_file("bar.rb", <<~RUBY)
4632+
class Bar
4633+
extend T::Sig
4634+
4635+
sig { params(x: Integer).void.checked(:tests) }
4636+
def initialize(x); end
4637+
4638+
sig { void.checked(:tests) }
4639+
def foo; end
4640+
end
4641+
RUBY
4642+
4643+
output = template(<<~RBI)
4644+
class Bar
4645+
sig { params(x: ::Integer).void }
4646+
def initialize(x); end
4647+
4648+
sig { void }
4649+
def foo; end
4650+
end
4651+
RBI
4652+
4653+
assert_equal(output, compile)
4654+
end
4655+
46304656
it "compiles constants with nil values" do
46314657
add_ruby_file("foo.rb", <<~RUBY)
46324658
class Foo

0 commit comments

Comments
 (0)