diff --git a/temporalio/rbi/temporalio/workflow/future.rbi b/temporalio/rbi/temporalio/workflow/future.rbi index e9f96348..875724dc 100644 --- a/temporalio/rbi/temporalio/workflow/future.rbi +++ b/temporalio/rbi/temporalio/workflow/future.rbi @@ -13,7 +13,7 @@ class Temporalio::Workflow::Future attr_reader :failure sig { params(block: T.nilable(T.proc.returns(Elem))).void } - def initialize(&); end + def initialize(&block); end sig { returns(T::Boolean) } def done?; end diff --git a/temporalio/test/sig/support/sig_applicator.rbs b/temporalio/test/sig/support/sig_applicator.rbs index 8eeac6b2..aca37401 100644 --- a/temporalio/test/sig/support/sig_applicator.rbs +++ b/temporalio/test/sig/support/sig_applicator.rbs @@ -46,6 +46,7 @@ module SigApplicator def self.register_summary_hook!: -> void def self.raise_recorded_type_errors!: -> void def self.raise_instrumentation_errors!: (Accumulator acc) -> void + def self.valid_rbi_signatures?: (untyped node, Accumulator acc) -> bool def self.apply_scope: (untyped node, Accumulator acc) -> void def self.apply_method_sig: ( Module target, diff --git a/temporalio/test/support/sig_applicator.rb b/temporalio/test/support/sig_applicator.rb index f3274aab..1808f664 100644 --- a/temporalio/test/support/sig_applicator.rb +++ b/temporalio/test/support/sig_applicator.rb @@ -116,6 +116,8 @@ def apply_all! rbi_paths.each do |path| tree = RBI::Parser.parse_file(path) + next unless valid_rbi_signatures?(tree, acc) + tree.nodes.each do |node| apply_scope(node, acc) end @@ -209,6 +211,33 @@ def raise_instrumentation_errors!(acc) raise summary.chomp end + def valid_rbi_signatures?(node, acc) + valid = true + + if node.is_a?(RBI::Method) + method_param_names = node.params.map(&:name).sort + node.sigs.each do |sig| + sig_param_names = sig.params.map(&:name).sort + next if sig_param_names == method_param_names + + valid = false + method_name = node.fully_qualified_name.delete_prefix('::') + method_name = method_name.sub(/::([^:]+)\z/, '.\1') if node.is_singleton + method_name = method_name.sub('::#', '.') + acc.error "#{method_name}: signature parameters #{sig_param_names.inspect} " \ + "do not match method parameters #{method_param_names.inspect}" + end + end + + if node.respond_to?(:nodes) + node.nodes.each do |child| + valid = false unless valid_rbi_signatures?(child, acc) + end + end + + valid + end + def apply_scope(node, acc) return unless node.respond_to?(:nodes) diff --git a/temporalio/test/support/sig_applicator_test.rb b/temporalio/test/support/sig_applicator_test.rb index 93e3bbb9..0cb6781f 100644 --- a/temporalio/test/support/sig_applicator_test.rb +++ b/temporalio/test/support/sig_applicator_test.rb @@ -237,6 +237,29 @@ def self.foo(value); end end end + def test_apply_all_rejects_mismatched_params_in_skipped_class + tree = RBI::Parser.parse_string(<<~RBI) + class Temporalio::Workflow::Future + sig { params(block: T.nilable(T.proc.void)).void } + def initialize(&); end + end + RBI + + parser = RBI::Parser.singleton_class + original_parse_file = RBI::Parser.method(:parse_file) + parser.send(:define_method, :parse_file) { |_path| tree } + + error = assert_raises(RuntimeError) do + with_sig_applicator_rbi_paths(['test.rbi']) { SigApplicator.apply_all! } + end + assert_includes error.message, 'SigApplicator: 1 methods could not be instrumented:' + assert_includes error.message, + 'Temporalio::Workflow::Future#initialize: signature parameters ["block"] ' \ + 'do not match method parameters ["&block"]' + ensure + parser.send(:define_method, :parse_file, original_parse_file) + end + def test_apply_all_reads_all_rbi_paths test_class = Class.new do def self.foo(value)