From 1207c7b9f7c157f66a0993634df67362feec6cab Mon Sep 17 00:00:00 2001 From: ksss Date: Fri, 24 Apr 2026 10:21:32 +0900 Subject: [PATCH 1/2] Auto-generate rbs_ast_ruby_annotations_t union from config.yml The union `rbs_ast_ruby_annotations_t` was previously maintained by hand in ast.h.erb with only 6 members, while 14 annotation structs existed and were all cast to this union pointer in parser.c. This drift went unnoticed because downstream code only touches `.base` and never instantiates the union as a value. Generate the union members from the annotation entries in config.yml so future additions stay in sync automatically. As a side benefit, ruby-rbs-sys/build.rs can now allowlist the union type alone and rely on bindgen's transitive allowlisting to pull in every `rbs_ast_ruby_annotations_*_t` member, replacing the hand-maintained list of 13 individual allowlist entries (which had itself drifted by missing module_self_annotation_t). Co-Authored-By: Claude Opus 4.7 (1M context) --- include/rbs/ast.h | 10 +++++++++- rust/ruby-rbs-sys/build.rs | 16 +++------------- templates/include/rbs/ast.h.erb | 9 +++------ templates/template.rb | 11 +++++++++-- 4 files changed, 24 insertions(+), 22 deletions(-) diff --git a/include/rbs/ast.h b/include/rbs/ast.h index 53bc3fb95..feddcaf0a 100644 --- a/include/rbs/ast.h +++ b/include/rbs/ast.h @@ -941,12 +941,20 @@ typedef struct rbs_types_variable { typedef union rbs_ast_ruby_annotations { rbs_node_t base; + rbs_ast_ruby_annotations_block_param_type_annotation_t block_param_type_annotation; + rbs_ast_ruby_annotations_class_alias_annotation_t class_alias_annotation; rbs_ast_ruby_annotations_colon_method_type_annotation_t colon_method_type_annotation; + rbs_ast_ruby_annotations_double_splat_param_type_annotation_t double_splat_param_type_annotation; + rbs_ast_ruby_annotations_instance_variable_annotation_t instance_variable_annotation; rbs_ast_ruby_annotations_method_types_annotation_t method_types_annotation; + rbs_ast_ruby_annotations_module_alias_annotation_t module_alias_annotation; + rbs_ast_ruby_annotations_module_self_annotation_t module_self_annotation; rbs_ast_ruby_annotations_node_type_assertion_t node_type_assertion; + rbs_ast_ruby_annotations_param_type_annotation_t param_type_annotation; rbs_ast_ruby_annotations_return_type_annotation_t return_type_annotation; rbs_ast_ruby_annotations_skip_annotation_t skip_annotation; - rbs_ast_ruby_annotations_param_type_annotation_t param_type_annotation; + rbs_ast_ruby_annotations_splat_param_type_annotation_t splat_param_type_annotation; + rbs_ast_ruby_annotations_type_application_annotation_t type_application_annotation; } rbs_ast_ruby_annotations_t; /// `rbs_ast_symbol_t` models user-defined identifiers like class names, method names, etc. diff --git a/rust/ruby-rbs-sys/build.rs b/rust/ruby-rbs-sys/build.rs index 3b72bea6d..5ca2b6de2 100644 --- a/rust/ruby-rbs-sys/build.rs +++ b/rust/ruby-rbs-sys/build.rs @@ -103,19 +103,9 @@ fn generate_bindings(include_path: &Path) -> Result { <%- end -%> typedef union rbs_ast_ruby_annotations { rbs_node_t base; - rbs_ast_ruby_annotations_colon_method_type_annotation_t colon_method_type_annotation; - rbs_ast_ruby_annotations_method_types_annotation_t method_types_annotation; - rbs_ast_ruby_annotations_node_type_assertion_t node_type_assertion; - rbs_ast_ruby_annotations_return_type_annotation_t return_type_annotation; - rbs_ast_ruby_annotations_skip_annotation_t skip_annotation; - rbs_ast_ruby_annotations_param_type_annotation_t param_type_annotation; +<%- annotation_nodes.each do |node| -%> + <%= node.c_type_name %> <%= node.c_name.delete_prefix("rbs_ast_ruby_annotations_") %>; +<%- end -%> } rbs_ast_ruby_annotations_t; /// `rbs_ast_symbol_t` models user-defined identifiers like class names, method names, etc. diff --git a/templates/template.rb b/templates/template.rb index c44370366..b581ddbd7 100644 --- a/templates/template.rb +++ b/templates/template.rb @@ -385,9 +385,16 @@ def locals Node.new(node, fields, locations, constructor_params) end + sorted_nodes = nodes.sort_by { _1.descr.ruby_full_name } + + annotation_nodes = sorted_nodes + .select { _1.descr.ruby_full_name.start_with?("RBS::AST::Ruby::Annotations::") } + .sort_by(&:c_name) + { - nodes: nodes.sort_by { _1.descr.ruby_full_name }, - enums: enum_desc + nodes: sorted_nodes, + enums: enum_desc, + annotation_nodes: annotation_nodes, } end end From 093110e3a6d20a426948434d383e94bddfba7b2a Mon Sep 17 00:00:00 2001 From: ksss Date: Fri, 24 Apr 2026 10:28:19 +0900 Subject: [PATCH 2/2] Use regex allowlist so pinned vendor and master both build The previous `allowlist_type("rbs_ast_ruby_annotations_t")` relied on bindgen's transitive allowlisting through the union. That works against the current master (where the union lists all 14 annotation members after auto-generation), but CI vendors the pinned v4.0.2 tag via `rake rust:rbs:sync`, whose union only has 6 members. The other 7 annotation structs referenced by ruby-rbs therefore never appeared in bindings.rs, breaking `cargo test`. Switch to the regex `rbs_ast_ruby_annotations_.*` which matches every annotation struct directly (and still includes the union itself) in both the pinned vendor and the current master, preserving the auto-follow property intended by this PR. Co-Authored-By: Claude Opus 4.7 (1M context) --- rust/ruby-rbs-sys/build.rs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/rust/ruby-rbs-sys/build.rs b/rust/ruby-rbs-sys/build.rs index 5ca2b6de2..c4ff9d13c 100644 --- a/rust/ruby-rbs-sys/build.rs +++ b/rust/ruby-rbs-sys/build.rs @@ -103,9 +103,10 @@ fn generate_bindings(include_path: &Path) -> Result