Skip to content

Commit fc4e78b

Browse files
authored
Merge pull request #2630 from Shopify/kaan/fix-rbs-rewriter-bootsnap-default
Restore `Bootsnap` fallback for RBS rewriting
2 parents 0c9e666 + 042fc36 commit fc4e78b

2 files changed

Lines changed: 89 additions & 2 deletions

File tree

lib/tapioca/rbs/rewriter.rb

Lines changed: 30 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -58,9 +58,37 @@ def setup(**_kwargs)
5858
rescue LoadError
5959
# Bootsnap is not in the bundle, skip iseq caching.
6060
end
61-
end
6261

63-
require "require-hooks/setup"
62+
require "require-hooks/setup"
63+
else
64+
require "require-hooks/setup"
65+
66+
begin
67+
# Disable Bootsnap's iseq cache unless TAPIOCA_RBS_CACHE=1 enabled the separate cache above.
68+
#
69+
# This is necessary because host apps can call Bootsnap.setup after tapioca loads this file. When that happens,
70+
# Bootsnap installs `load_iseq` and serves files from its cache, which bypasses RequireHooks.source_transform.
71+
# Preloading bootsnap's iseq support lets us override `load_iseq` before setup installs it, preserving the default
72+
# RBS rewrite behavior at the cost of slower app boot.
73+
require "bootsnap"
74+
require "bootsnap/compile_cache/iseq"
75+
76+
module Bootsnap
77+
module CompileCache
78+
module ISeq
79+
module InstructionSequenceMixin
80+
#: (String) -> RubyVM::InstructionSequence
81+
def load_iseq(path)
82+
super if defined?(super) # Disable Bootsnap's hook, but trigger any others.
83+
end
84+
end
85+
end
86+
end
87+
end
88+
rescue LoadError
89+
# Bootsnap is not in the bundle, we don't need to do anything.
90+
end
91+
end
6492

6593
# We need to include `T::Sig` very early to make sure that the `sig` method is available since gems using RBS comments
6694
# are unlikely to include `T::Sig` in their own classes.

spec/tapioca/cli/dsl_spec.rb

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -680,6 +680,65 @@ class Post
680680
assert_success_status(result)
681681
end
682682

683+
it "preserves RBS comment rewriting when the host sets up Bootsnap without TAPIOCA_RBS_CACHE" do
684+
@project.write!("lib/00_bootsnap.rb", <<~RB)
685+
require "bootsnap"
686+
Bootsnap.setup(cache_dir: File.join(Dir.pwd, "tmp/cache/host-bootsnap"))
687+
RB
688+
689+
@project.write!("lib/post.rb", <<~RB)
690+
# typed: strict
691+
692+
class Post
693+
#: -> String
694+
def title
695+
"hello"
696+
end
697+
end
698+
RB
699+
700+
@project.write!("lib/compilers/rbs_comment_compiler.rb", <<~RB)
701+
require "post"
702+
703+
class RbsCommentCompiler < Tapioca::Dsl::Compiler
704+
extend T::Sig
705+
extend T::Generic
706+
707+
ConstantType = type_member { { fixed: T.class_of(::Post) } }
708+
709+
sig { override.void }
710+
def decorate
711+
root.create_path(constant) do |klass|
712+
create_method_from_def(klass, constant.instance_method(:title))
713+
end
714+
end
715+
716+
sig { override.returns(T::Enumerable[T::Module[T.anything]]) }
717+
def self.gather_constants
718+
[::Post]
719+
end
720+
end
721+
RB
722+
723+
result = @project.tapioca("dsl Post --only RbsCommentCompiler")
724+
725+
assert_empty_stderr(result)
726+
assert_project_file_equal("sorbet/rbi/dsl/post.rbi", <<~RBI)
727+
# typed: true
728+
729+
# DO NOT EDIT MANUALLY
730+
# This is an autogenerated file for dynamic methods in `Post`.
731+
# Please instead update this file by running `bin/tapioca dsl Post`.
732+
733+
734+
class Post
735+
sig { returns(::String) }
736+
def title; end
737+
end
738+
RBI
739+
assert_success_status(result)
740+
end
741+
683742
it "raises when the host calls Bootsnap.setup under TAPIOCA_RBS_CACHE=1" do
684743
@project.write!("lib/post.rb", <<~RB)
685744
require "bootsnap"

0 commit comments

Comments
 (0)