@@ -142,7 +142,7 @@ def register_summary_hook!
142142 def raise_instrumentation_errors! ( errors )
143143 return if errors . empty?
144144
145- summary = + "SigApplicator: #{ errors . size } methods could not be instrumented:\n "
145+ summary = "SigApplicator: #{ errors . size } methods could not be instrumented:\n "
146146 errors . each { |error | summary << " #{ error } \n " }
147147 raise summary . chomp
148148 end
@@ -169,7 +169,7 @@ def apply_scope(node, errors)
169169 case child
170170 when RBI ::Method
171171 target = child . is_singleton ? klass . singleton_class : klass
172- result = apply_method_sig ( target , class_name , child , errors )
172+ result = apply_method_sig ( target , class_name , child , errors , sig_eval_scope : klass )
173173 if result == :skipped
174174 skipped += 1
175175 elsif result
@@ -179,7 +179,14 @@ def apply_scope(node, errors)
179179 child . nodes . each do |scn |
180180 next unless scn . is_a? ( RBI ::Method )
181181
182- result = apply_method_sig ( klass . singleton_class , class_name , scn , errors , class_method : true )
182+ result = apply_method_sig (
183+ klass . singleton_class ,
184+ class_name ,
185+ scn ,
186+ errors ,
187+ class_method : true ,
188+ sig_eval_scope : klass
189+ )
183190 if result == :skipped
184191 skipped += 1
185192 elsif result
@@ -191,11 +198,12 @@ def apply_scope(node, errors)
191198 [ applied , skipped ]
192199 end
193200
194- def apply_method_sig ( target , class_name , method_node , errors , class_method : false )
201+ def apply_method_sig ( target , class_name , method_node , errors , class_method : false , sig_eval_scope : target )
195202 return false if method_node . sigs . empty?
196203
197204 method_name = method_node . name . to_sym
198- separator = class_method || method_node . is_singleton ? '.' : '#'
205+ singleton_method = class_method || method_node . is_singleton
206+ separator = singleton_method ? '.' : '#'
199207 full_name = "#{ class_name } #{ separator } #{ method_name } "
200208
201209 return :skipped if SKIP_METHODS . include? ( full_name )
@@ -214,10 +222,11 @@ def apply_method_sig(target, class_name, method_node, errors, class_method: fals
214222 method_node . sigs . each do |sig |
215223 # RBI::Sig#string serializes back to valid T::Sig DSL source
216224 sig_source = sig . string
217- # Anonymous block params (def foo(&)) need `"&":` instead of `block:`
218- sig_source = rewrite_block_param ( sig_source ) if has_anon_block
225+ # Anonymous block params (def foo(&)) need `"&":` instead of the RBI
226+ # block parameter name.
227+ sig_source = rewrite_block_param ( sig_source , method_node , sig ) if has_anon_block
219228 begin
220- target . class_eval ( sig_source )
229+ apply_sig_source ( sig_eval_scope , target , sig_source , singleton_method )
221230 target . send ( :define_method , method_name , original )
222231
223232 # Force eager sig validation so mismatches are caught now rather than
@@ -240,10 +249,28 @@ def anonymous_block?(method)
240249 block_param && ( block_param [ 1 ] . nil? || block_param [ 1 ] == :& )
241250 end
242251
243- # Rewrites `block: <type>` to `"&": <type>` in a sig source string
244- # so sorbet-runtime matches the anonymous block parameter.
245- def rewrite_block_param ( sig_source )
246- sig_source . sub ( /\b block:\s / , '"&": ' )
252+ def apply_sig_source ( sig_eval_scope , target , sig_source , singleton_method )
253+ if singleton_method
254+ sig_eval_scope . class_eval ( <<~RUBY , __FILE__ , __LINE__ + 1 )
255+ class << self
256+ #{ sig_source } # #{ sig_source }
257+ end
258+ RUBY
259+ else
260+ target . class_eval ( sig_source )
261+ end
262+ end
263+
264+ # Rewrites the RBI block parameter name to `"&": <type>` so
265+ # sorbet-runtime matches the anonymous block parameter.
266+ def rewrite_block_param ( sig_source , method_node , sig )
267+ block_param_name =
268+ method_node . params . find { |param | param . is_a? ( RBI ::BlockParam ) } &.name ||
269+ sig . params . find { |param | param . type &.include? ( 'T.proc' ) } &.name
270+
271+ return sig_source unless block_param_name
272+
273+ sig_source . sub ( /\b #{ Regexp . escape ( block_param_name ) } :\s / , '"&": ' )
247274 end
248275
249276 # Determines whether a method should be skipped for sig application based
0 commit comments