rbs 4.0.1 → 4.1.0.pre.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (50) hide show
  1. checksums.yaml +4 -4
  2. data/.github/dependabot.yml +2 -0
  3. data/.github/workflows/bundle-update.yml +4 -1
  4. data/.github/workflows/dependabot.yml +1 -1
  5. data/.github/workflows/milestone.yml +80 -0
  6. data/.github/workflows/ruby.yml +34 -0
  7. data/.github/workflows/rust.yml +93 -7
  8. data/.gitignore +4 -0
  9. data/CHANGELOG.md +21 -0
  10. data/Rakefile +209 -2
  11. data/config.yml +24 -0
  12. data/core/builtin.rbs +1 -0
  13. data/core/class.rbs +5 -3
  14. data/core/kernel.rbs +26 -11
  15. data/core/ruby_vm.rbs +40 -0
  16. data/docs/inline.md +29 -1
  17. data/docs/rust.md +96 -0
  18. data/ext/rbs_extension/ast_translation.c +21 -0
  19. data/ext/rbs_extension/class_constants.c +2 -0
  20. data/ext/rbs_extension/class_constants.h +1 -0
  21. data/ext/rbs_extension/extconf.rb +1 -0
  22. data/include/rbs/ast.h +314 -297
  23. data/include/rbs/defines.h +13 -0
  24. data/include/rbs/lexer.h +1 -0
  25. data/lib/rbs/annotate/rdoc_annotator.rb +27 -31
  26. data/lib/rbs/ast/ruby/annotations.rb +42 -0
  27. data/lib/rbs/ast/ruby/declarations.rb +11 -1
  28. data/lib/rbs/ast/ruby/members.rb +28 -0
  29. data/lib/rbs/cli.rb +3 -5
  30. data/lib/rbs/collection/config/lockfile_generator.rb +16 -3
  31. data/lib/rbs/environment.rb +6 -0
  32. data/lib/rbs/inline_parser.rb +49 -25
  33. data/lib/rbs/rewriter.rb +70 -0
  34. data/lib/rbs/test/type_check.rb +6 -1
  35. data/lib/rbs/version.rb +1 -1
  36. data/lib/rbs.rb +1 -0
  37. data/sig/annotate/rdoc_annotater.rbs +12 -9
  38. data/sig/ast/ruby/annotations.rbs +49 -0
  39. data/sig/ast/ruby/members.rbs +15 -0
  40. data/sig/collection/config/lockfile_generator.rbs +2 -0
  41. data/sig/inline_parser.rbs +2 -0
  42. data/sig/manifest.yaml +0 -1
  43. data/sig/rewriter.rbs +45 -0
  44. data/src/ast.c +109 -85
  45. data/src/lexer.c +137 -114
  46. data/src/lexer.re +1 -0
  47. data/src/lexstate.c +1 -0
  48. data/src/parser.c +55 -5
  49. data/stdlib/openssl/0/openssl.rbs +2 -2
  50. metadata +7 -3
data/core/kernel.rbs CHANGED
@@ -182,9 +182,9 @@ module Kernel : BasicObject
182
182
  # c(4) #=> []
183
183
  # c(5) #=> nil
184
184
  #
185
- def self?.caller: (Integer start_or_range, ?Integer length) -> ::Array[String]?
186
- | (::Range[Integer] start_or_range) -> ::Array[String]?
187
- | () -> ::Array[String]
185
+ def self?.caller: () -> Array[String]
186
+ | (int start, ?int? length) -> Array[String]?
187
+ | (range[int] range) -> Array[String]?
188
188
 
189
189
  # <!--
190
190
  # rdoc-file=vm_backtrace.c
@@ -207,9 +207,9 @@ module Kernel : BasicObject
207
207
  # Optionally you can pass a range, which will return an array containing the
208
208
  # entries within the specified range.
209
209
  #
210
- def self?.caller_locations: (Integer start_or_range, ?Integer length) -> ::Array[Thread::Backtrace::Location]?
211
- | (::Range[Integer] start_or_range) -> ::Array[Thread::Backtrace::Location]?
212
- | () -> ::Array[Thread::Backtrace::Location]
210
+ def self?.caller_locations: () -> Array[Thread::Backtrace::Location]
211
+ | (int start, ?int? length) -> Array[Thread::Backtrace::Location]?
212
+ | (range[int] range) -> Array[Thread::Backtrace::Location]?
213
213
 
214
214
  # <!--
215
215
  # rdoc-file=vm_eval.c
@@ -314,6 +314,16 @@ module Kernel : BasicObject
314
314
  #
315
315
  def self?.block_given?: () -> bool
316
316
 
317
+ alias self.iterator? self.block_given?
318
+
319
+ # <!--
320
+ # rdoc-file=vm_eval.c
321
+ # - iterator? -> true or false
322
+ # -->
323
+ # Deprecated. Use block_given? instead.
324
+ #
325
+ alias iterator? block_given?
326
+
317
327
  # <!--
318
328
  # rdoc-file=vm_eval.c
319
329
  # - local_variables -> array
@@ -326,7 +336,7 @@ module Kernel : BasicObject
326
336
  # end
327
337
  # local_variables #=> [:fred, :i]
328
338
  #
329
- def self?.local_variables: () -> ::Array[Symbol]
339
+ def self?.local_variables: () -> Array[Symbol]
330
340
 
331
341
  # <!--
332
342
  # rdoc-file=random.c
@@ -788,7 +798,7 @@ module Kernel : BasicObject
788
798
  #
789
799
  # Files that are currently being loaded must not be registered for autoload.
790
800
  #
791
- def self?.autoload: (interned _module, String filename) -> NilClass
801
+ def self?.autoload: (interned const, path filename) -> nil
792
802
 
793
803
  # <!--
794
804
  # rdoc-file=load.c
@@ -812,7 +822,7 @@ module Kernel : BasicObject
812
822
  # autoload?(:B) #=> "b"
813
823
  # end
814
824
  #
815
- def self?.autoload?: (interned name) -> String?
825
+ def self?.autoload?: (interned name, ?boolish inherit) -> String?
816
826
 
817
827
  # <!--
818
828
  # rdoc-file=proc.c
@@ -1193,7 +1203,7 @@ module Kernel : BasicObject
1193
1203
  #
1194
1204
  # global_variables.grep /std/ #=> [:$stdin, :$stdout, :$stderr]
1195
1205
  #
1196
- def self?.global_variables: () -> ::Array[Symbol]
1206
+ def self?.global_variables: () -> Array[Symbol]
1197
1207
 
1198
1208
  # <!--
1199
1209
  # rdoc-file=load.c
@@ -1843,7 +1853,12 @@ module Kernel : BasicObject
1843
1853
  # ----------------|---------------------------------------------
1844
1854
  # <code>'-'</code>|Whether the entities exist and are identical.
1845
1855
  #
1846
- def self?.test: (String | Integer cmd, String | IO file1, ?String | IO file2) -> (TrueClass | FalseClass | Time | nil | Integer)
1856
+ def self?.test: ('b' | 'c' | 'd' | 'e' | 'f' | 'g' | 'G' | 'k' | 'l' | 'o' | 'O' | 'p' | 'r' | 'R' | 'S' | 'u' | 'w' | 'W' | 'x' | 'X' | 'z' |
1857
+ 98 | 99 | 100 | 101 | 102 | 103 | 71 | 107 | 108 | 111 | 79 | 112 | 114 | 82 | 83 | 117 | 119 | 87 | 120 | 88 | 122, path filepath) -> bool
1858
+ | ('s' | 115, path filepath) -> Integer?
1859
+ | ('A' | 'M' | 'C' | 65 | 77 | 67, path filepath) -> Time
1860
+ | ('<' | '=' | '>' | '-' | 60 | 61 | 62 | 45, path filepath1, path filepath2) -> bool
1861
+ | (String | int cmd, path filepath1, ?path filepath2) -> (bool | Time | Integer | nil)
1847
1862
 
1848
1863
  # <!--
1849
1864
  # rdoc-file=vm_eval.c
data/core/ruby_vm.rbs CHANGED
@@ -371,6 +371,46 @@ class RubyVM::InstructionSequence < Object
371
371
  # event_symbol] pair.
372
372
  #
373
373
  def trace_points: () -> Array[untyped]
374
+
375
+ # <!--
376
+ # rdoc-file=iseq.c
377
+ # - of(p1)
378
+ # -->
379
+ # Returns the instruction sequence containing the given proc or method.
380
+ #
381
+ # For example, using irb:
382
+ #
383
+ # # a proc
384
+ # > p = proc { num = 1 + 2 }
385
+ # > RubyVM::InstructionSequence.of(p)
386
+ # > #=> <RubyVM::InstructionSequence:block in irb_binding@(irb)>
387
+ #
388
+ # # for a method
389
+ # > def foo(bar); puts bar; end
390
+ # > RubyVM::InstructionSequence.of(method(:foo))
391
+ # > #=> <RubyVM::InstructionSequence:foo@(irb)>
392
+ #
393
+ # Using ::compile_file:
394
+ #
395
+ # # /tmp/iseq_of.rb
396
+ # def hello
397
+ # puts "hello, world"
398
+ # end
399
+ #
400
+ # $a_global_proc = proc { str = 'a' + 'b' }
401
+ #
402
+ # # in irb
403
+ # > require '/tmp/iseq_of.rb'
404
+ #
405
+ # # first the method hello
406
+ # > RubyVM::InstructionSequence.of(method(:hello))
407
+ # > #=> #<RubyVM::InstructionSequence:0x007fb73d7cb1d0>
408
+ #
409
+ # # then the global proc
410
+ # > RubyVM::InstructionSequence.of($a_global_proc)
411
+ # > #=> #<RubyVM::InstructionSequence:0x007fb73d7caf78>
412
+ #
413
+ def self.of: (Proc | Method | UnboundMethod body) -> RubyVM::InstructionSequence?
374
414
  end
375
415
 
376
416
  # <!-- rdoc-file=ast.rb -->
data/docs/inline.md CHANGED
@@ -123,10 +123,38 @@ end
123
123
 
124
124
  This creates the types `::API`, `::API::V1`, and `::API::V1::Resources`.
125
125
 
126
+ ### `module-self` constraint
127
+
128
+ The `module-self` constraint declares which classes or modules the module can be mixed into.
129
+
130
+ ```ruby
131
+ # @rbs module-self: _Each[String]
132
+ module Enumerable2
133
+ end
134
+ ```
135
+
136
+ This is equivalent to `module Enumerable2 : _Each[String]` in RBS, meaning `Enumerable2` can only be included in classes that satisfy the `_Each[String]` interface.
137
+
138
+ Multiple `module-self` constraints can be declared with separate annotations:
139
+
140
+ ```ruby
141
+ # @rbs module-self: _Each[String]
142
+ # @rbs module-self: Comparable
143
+ module StringCollection
144
+ end
145
+ ```
146
+
147
+ You can add a description after `--`:
148
+
149
+ ```ruby
150
+ # @rbs module-self: Minitest::Test -- depending on assertion methods
151
+ module TestHelper
152
+ end
153
+ ```
154
+
126
155
  ### Current Limitations
127
156
 
128
157
  - Generic module definitions are not supported
129
- - Module self-type constraints are not supported
130
158
 
131
159
  ## Method Definitions
132
160
 
data/docs/rust.md ADDED
@@ -0,0 +1,96 @@
1
+ # Rust Crates
2
+
3
+ RBS provides two Rust crates:
4
+
5
+ - **`ruby-rbs-sys`** -- Low-level FFI bindings to the RBS C parser
6
+ - **`ruby-rbs`** -- High-level safe Rust API for parsing RBS signatures
7
+
8
+ Both crates are published to [crates.io](https://crates.io/) and are developed within the `rust/` directory of this repository.
9
+
10
+ ## Vendored RBS Source
11
+
12
+ The Rust crates depend on the RBS C parser source code (`include/`, `src/`) and configuration (`config.yml`) from this repository. These files are vendored into each crate's `vendor/rbs/` directory, which is managed by Rake tasks and not tracked by git.
13
+
14
+ The file `rust/rbs_version` records which version of RBS the Rust crates are pinned to.
15
+
16
+ ## Setup
17
+
18
+ After cloning the repository, set up the vendored source before building the Rust crates:
19
+
20
+ ```bash
21
+ rake rust:rbs:sync # Uses the pinned version from rust/rbs_version
22
+ ```
23
+
24
+ Then build and test:
25
+
26
+ ```bash
27
+ cd rust
28
+ cargo test
29
+ ```
30
+
31
+ ## Rake Tasks
32
+
33
+ ### `rake rust:rbs:sync`
34
+
35
+ Copies the source files from the pinned version into each crate's `vendor/rbs/`. The copied files are made read-only to prevent accidental edits.
36
+
37
+ ### `rake rust:rbs:pin[VERSION]`
38
+
39
+ Records a git tag in `rust/rbs_version`. For example:
40
+
41
+ ```bash
42
+ rake rust:rbs:pin[v4.0.3]
43
+ ```
44
+
45
+ ### `rake rust:publish:ruby-rbs-sys` / `rake rust:publish:ruby-rbs`
46
+
47
+ Publishes each crate to crates.io individually. Each task:
48
+
49
+ 1. Verifies `rust/rbs_version` is set
50
+ 2. Verifies vendor directories contain real files (not symlinks)
51
+ 3. Verifies the git working tree is clean
52
+ 4. Creates a release branch and commits the vendor files
53
+ 5. Runs a dry-run to check packaging
54
+ 6. Publishes the crate
55
+
56
+ Set `RBS_RUST_PUBLISH_DRY_RUN=1` to only run the dry-run step and skip the actual publish to crates.io. This is used in CI to verify that the crates can be packaged correctly.
57
+
58
+ ### `rake rust:rbs:symlink`
59
+
60
+ If your development needs unreleased version of RBS source code, use `rake rust:rbs:symlink` to set up symlinks in vendor directories to refer the worktree source code. Changes to the C parser source are immediately reflected in Rust builds.
61
+
62
+ ## Publishing Workflow
63
+
64
+ 1. Pin the RBS version to release against:
65
+
66
+ ```bash
67
+ rake rust:rbs:pin[v4.0.3]
68
+ ```
69
+
70
+ 2. Sync the vendored source:
71
+
72
+ ```bash
73
+ rake rust:rbs:sync
74
+ ```
75
+
76
+ 3. Update crate versions in `rust/ruby-rbs-sys/Cargo.toml` and `rust/ruby-rbs/Cargo.toml`.
77
+
78
+ 4. Build and test:
79
+
80
+ ```bash
81
+ cd rust && cargo test
82
+ ```
83
+
84
+ 5. Commit the version changes and `rust/rbs_version`:
85
+
86
+ ```bash
87
+ git add rust/rbs_version rust/ruby-rbs-sys/Cargo.toml rust/ruby-rbs/Cargo.toml
88
+ git commit -m "Bump Rust crate versions"
89
+ ```
90
+
91
+ 6. Publish each crate:
92
+
93
+ ```bash
94
+ rake rust:publish:ruby-rbs-sys
95
+ rake rust:publish:ruby-rbs
96
+ ```
@@ -947,6 +947,27 @@ VALUE rbs_struct_to_ruby_value(rbs_translation_context_t ctx, rbs_node_t *instan
947
947
  &h
948
948
  );
949
949
  }
950
+ case RBS_AST_RUBY_ANNOTATIONS_MODULE_SELF_ANNOTATION: {
951
+ rbs_ast_ruby_annotations_module_self_annotation_t *node = (rbs_ast_ruby_annotations_module_self_annotation_t *) instance;
952
+
953
+ VALUE h = rb_hash_new();
954
+ rb_hash_aset(h, ID2SYM(rb_intern("location")), rbs_location_range_to_ruby_location(ctx, node->base.location));
955
+ rb_hash_aset(h, ID2SYM(rb_intern("prefix_location")), rbs_location_range_to_ruby_location(ctx, node->prefix_location));
956
+ rb_hash_aset(h, ID2SYM(rb_intern("keyword_location")), rbs_location_range_to_ruby_location(ctx, node->keyword_location));
957
+ rb_hash_aset(h, ID2SYM(rb_intern("colon_location")), rbs_location_range_to_ruby_location(ctx, node->colon_location));
958
+ rb_hash_aset(h, ID2SYM(rb_intern("name")), rbs_struct_to_ruby_value(ctx, (rbs_node_t *) node->name)); // rbs_type_name
959
+ rb_hash_aset(h, ID2SYM(rb_intern("args")), rbs_node_list_to_ruby_array(ctx, node->args));
960
+ rb_hash_aset(h, ID2SYM(rb_intern("open_bracket_location")), rbs_location_range_to_ruby_location(ctx, node->open_bracket_location)); // optional
961
+ rb_hash_aset(h, ID2SYM(rb_intern("close_bracket_location")), rbs_location_range_to_ruby_location(ctx, node->close_bracket_location)); // optional
962
+ rb_hash_aset(h, ID2SYM(rb_intern("args_comma_locations")), rbs_location_range_list_to_ruby_array(ctx, node->args_comma_locations));
963
+ rb_hash_aset(h, ID2SYM(rb_intern("comment_location")), rbs_location_range_to_ruby_location(ctx, node->comment_location)); // optional
964
+
965
+ return CLASS_NEW_INSTANCE(
966
+ RBS_AST_Ruby_Annotations_ModuleSelfAnnotation,
967
+ 1,
968
+ &h
969
+ );
970
+ }
950
971
  case RBS_AST_RUBY_ANNOTATIONS_NODE_TYPE_ASSERTION: {
951
972
  rbs_ast_ruby_annotations_node_type_assertion_t *node = (rbs_ast_ruby_annotations_node_type_assertion_t *) instance;
952
973
 
@@ -54,6 +54,7 @@ VALUE RBS_AST_Ruby_Annotations_DoubleSplatParamTypeAnnotation;
54
54
  VALUE RBS_AST_Ruby_Annotations_InstanceVariableAnnotation;
55
55
  VALUE RBS_AST_Ruby_Annotations_MethodTypesAnnotation;
56
56
  VALUE RBS_AST_Ruby_Annotations_ModuleAliasAnnotation;
57
+ VALUE RBS_AST_Ruby_Annotations_ModuleSelfAnnotation;
57
58
  VALUE RBS_AST_Ruby_Annotations_NodeTypeAssertion;
58
59
  VALUE RBS_AST_Ruby_Annotations_ParamTypeAnnotation;
59
60
  VALUE RBS_AST_Ruby_Annotations_ReturnTypeAnnotation;
@@ -147,6 +148,7 @@ void rbs__init_constants(void) {
147
148
  IMPORT_CONSTANT(RBS_AST_Ruby_Annotations_InstanceVariableAnnotation, RBS_AST_Ruby_Annotations, "InstanceVariableAnnotation");
148
149
  IMPORT_CONSTANT(RBS_AST_Ruby_Annotations_MethodTypesAnnotation, RBS_AST_Ruby_Annotations, "MethodTypesAnnotation");
149
150
  IMPORT_CONSTANT(RBS_AST_Ruby_Annotations_ModuleAliasAnnotation, RBS_AST_Ruby_Annotations, "ModuleAliasAnnotation");
151
+ IMPORT_CONSTANT(RBS_AST_Ruby_Annotations_ModuleSelfAnnotation, RBS_AST_Ruby_Annotations, "ModuleSelfAnnotation");
150
152
  IMPORT_CONSTANT(RBS_AST_Ruby_Annotations_NodeTypeAssertion, RBS_AST_Ruby_Annotations, "NodeTypeAssertion");
151
153
  IMPORT_CONSTANT(RBS_AST_Ruby_Annotations_ParamTypeAnnotation, RBS_AST_Ruby_Annotations, "ParamTypeAnnotation");
152
154
  IMPORT_CONSTANT(RBS_AST_Ruby_Annotations_ReturnTypeAnnotation, RBS_AST_Ruby_Annotations, "ReturnTypeAnnotation");
@@ -62,6 +62,7 @@ extern VALUE RBS_AST_Ruby_Annotations_DoubleSplatParamTypeAnnotation;
62
62
  extern VALUE RBS_AST_Ruby_Annotations_InstanceVariableAnnotation;
63
63
  extern VALUE RBS_AST_Ruby_Annotations_MethodTypesAnnotation;
64
64
  extern VALUE RBS_AST_Ruby_Annotations_ModuleAliasAnnotation;
65
+ extern VALUE RBS_AST_Ruby_Annotations_ModuleSelfAnnotation;
65
66
  extern VALUE RBS_AST_Ruby_Annotations_NodeTypeAssertion;
66
67
  extern VALUE RBS_AST_Ruby_Annotations_ParamTypeAnnotation;
67
68
  extern VALUE RBS_AST_Ruby_Annotations_ReturnTypeAnnotation;
@@ -16,6 +16,7 @@ append_cflags [
16
16
  '-Wimplicit-fallthrough',
17
17
  '-Wunused-result',
18
18
  '-Wc++-compat',
19
+ '-Wnullable-to-nonnull-conversion',
19
20
  ]
20
21
 
21
22
  if ENV['DEBUG']