rbs 4.1.3-java → 4.2.0.pre.1-java

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 (59) hide show
  1. checksums.yaml +4 -4
  2. data/.gitattributes +1 -0
  3. data/.github/workflows/bundle-update.yml +2 -2
  4. data/.github/workflows/c-check.yml +2 -2
  5. data/.github/workflows/changelog.yml +121 -0
  6. data/.github/workflows/comments.yml +2 -2
  7. data/.github/workflows/dependabot.yml +1 -1
  8. data/.github/workflows/jruby.yml +3 -3
  9. data/.github/workflows/release-gems.yml +6 -7
  10. data/.github/workflows/ruby.yml +6 -6
  11. data/.github/workflows/rust.yml +12 -12
  12. data/.github/workflows/truffleruby.yml +2 -2
  13. data/.github/workflows/typecheck.yml +2 -2
  14. data/.github/workflows/wasm.yml +3 -3
  15. data/.github/workflows/windows.yml +2 -2
  16. data/CHANGELOG.md +27 -0
  17. data/Rakefile +50 -21
  18. data/config.yml +5 -0
  19. data/docs/CONTRIBUTING.md +1 -1
  20. data/docs/release.md +57 -1
  21. data/docs/stdlib.md +8 -0
  22. data/docs/syntax.md +12 -0
  23. data/ext/rbs_extension/ast_translation.c +15 -0
  24. data/ext/rbs_extension/class_constants.c +2 -0
  25. data/ext/rbs_extension/class_constants.h +1 -0
  26. data/ext/rbs_extension/main.c +55 -19
  27. data/include/rbs/ast.h +21 -13
  28. data/include/rbs/defines.h +2 -2
  29. data/include/rbs/lexer.h +13 -12
  30. data/include/rbs/parser.h +37 -3
  31. data/lib/rbs/ast/declarations.rb +1 -1
  32. data/lib/rbs/ast/type_param.rb +1 -1
  33. data/lib/rbs/definition_builder/ancestor_builder.rb +8 -5
  34. data/lib/rbs/definition_builder/method_builder.rb +4 -4
  35. data/lib/rbs/definition_builder.rb +5 -2
  36. data/lib/rbs/environment/class_entry.rb +12 -0
  37. data/lib/rbs/environment/module_entry.rb +26 -1
  38. data/lib/rbs/parser_aux.rb +2 -2
  39. data/lib/rbs/types.rb +44 -2
  40. data/lib/rbs/version.rb +1 -1
  41. data/lib/rbs/wasm/parser.rb +62 -25
  42. data/lib/rbs/wasm/rbs_parser.wasm +0 -0
  43. data/lib/rbs/wasm/runtime.rb +19 -4
  44. data/lib/rbs/wasm/serialization_schema.rb +3 -2
  45. data/schema/function.json +12 -1
  46. data/sig/environment/class_entry.rbs +6 -0
  47. data/sig/environment/module_entry.rbs +15 -0
  48. data/sig/parser.rbs +4 -4
  49. data/sig/types.rbs +11 -1
  50. data/src/ast.c +17 -1
  51. data/src/lexer.c +1562 -1560
  52. data/src/lexer.re +50 -18
  53. data/src/lexstate.c +2 -1
  54. data/src/parser.c +130 -70
  55. data/src/serialize.c +20 -13
  56. data/src/util/rbs_encoding.c +195 -49
  57. data/wasm/README.md +20 -4
  58. data/wasm/rbs_wasm.c +93 -37
  59. metadata +3 -1
data/docs/release.md CHANGED
@@ -77,6 +77,10 @@ on their own GitHub releases.
77
77
  Sort the list into the sections below. `rake gem:changelog:json` prints the same pull requests with
78
78
  the changed files, labels, and body of each, which is what the sorting is based on.
79
79
 
80
+ Both tasks reach GitHub through `gh`, which a Claude Code on the web session cannot do. See
81
+ [Assembling the changelog without `gh`](#assembling-the-changelog-without-gh), which runs them on a
82
+ runner instead.
83
+
80
84
  ```markdown
81
85
  ## X.Y.Z (YYYY-MM-DD)
82
86
 
@@ -97,7 +101,8 @@ The sections always appear in this order; delete the ones that end up empty, whi
97
101
  on a small release. Two things scale with the size of the release:
98
102
 
99
103
  - **Summary paragraphs**, above the first section. A patch release usually has none, 4.1.0 has four
100
- paragraphs, and 4.0.0 has nine.
104
+ paragraphs, and 4.0.0 has nine. A prerelease has none whatever its size: the cycle it belongs to
105
+ is summarized once, on the release proper that folds it in.
101
106
  - **A list of the types whose signatures changed**, as the first line of `### Signature updates`,
102
107
  written as `**Updated classes/modules/methods:**` followed by the names in backticks. Used on
103
108
  `X.Y.0` releases only.
@@ -195,6 +200,11 @@ opposite places:
195
200
  cherry-picked from `master` — see [Backports](#backports). The `aaa-` prefix carries no meaning
196
201
  beyond sorting the release branches to the top of the branch list.
197
202
 
203
+ The branch carries its own release tooling, since that is read from the ref rather than from
204
+ `master`: the `gem:` tasks, and `changelog.yml` for the changelog. Branching from `master`
205
+ brings both along; what needs watching is a later change to either, which reaches this line
206
+ only if it is cherry-picked here too.
207
+
198
208
  2. **Bump `master`** to `X.(Y+1).0.dev`, in a pull request with `Gemfile.lock` regenerated and
199
209
  labeled `skip-changelog` like the release pull request itself. `4.1` was started exactly this
200
210
  way: `aaa-4.0.x` was branched at the commit before `Start 4.1 development`, which set
@@ -227,6 +237,52 @@ it, the only pull request a backported commit is associated with is the one that
227
237
  backport, which says nothing about the change and is the same for every commit it brought over —
228
238
  that is why the 4.0.3 changelog credits its three entries to the same pull request.
229
239
 
240
+ The entry names that pull request and adds the one that carried the backport:
241
+
242
+ ```markdown
243
+ * {title} ([#{original}](https://github.com/ruby/rbs/pull/{original}), Backported in [#{backport}](https://github.com/ruby/rbs/pull/{backport}))
244
+ ```
245
+
246
+ `gem:changelog` prints this form on its own, from the same `-x` trailer: the origin it resolves is
247
+ the first link, and the pull request of the cherry-pick in front of it is the second. On the
248
+ development line nothing is a cherry-pick, so entries there keep the plain single link.
249
+
250
+ The second link is what keeps the entry from reading as a mistake. The original pull request is
251
+ against `master`, so it is listed again when the development line ships — and with nothing to tell
252
+ the two apart, the same link under two version headings looks like a change written into the wrong
253
+ section. #1923 is the pair to look at: plain under 3.6.0.pre.1, annotated under 3.5.2, which
254
+ backported it.
255
+
256
+ ## Assembling the changelog without `gh`
257
+
258
+ `gem:changelog` and `gem:changelog:json` reach GitHub through `gh`, so they cannot run from a
259
+ Claude Code on the web session. `api.github.com` refuses anything the shell does there, and the
260
+ refusal is keyed on the session rather than on the client, so installing `gh` does not help:
261
+
262
+ ```console
263
+ $ curl -s -o /dev/null -w '%{http_code}' https://api.github.com/repos/ruby/rbs
264
+ 403
265
+ ```
266
+
267
+ Nothing else about the release is affected. `gem:check_release` and `gem:tag` read git and the
268
+ working tree, `gem:gh_release` runs on a runner, and git itself reaches github.com normally —
269
+ clone, fetch and push all work.
270
+
271
+ So the task is run where it does work. Dispatch
272
+ [`changelog.yml`](../.github/workflows/changelog.yml), which runs it on a runner, and read the list
273
+ from the run summary, the log, or the `changelog` artifact.
274
+
275
+ | Input | Value |
276
+ | --- | --- |
277
+ | The ref selector | The branch the changelog is for: `aaa-X.Y.x` for a patch release, `master` otherwise |
278
+ | `version` | Where the changelog starts, when that should not follow `RBS::VERSION`. It names the release before the one being written, so `4.1.2` produces the 4.1.3 changelog |
279
+ | `format` | `list` for the template, `json` for the pull request details the sections are sorted from |
280
+
281
+ The ref is not incidental the way it is for `release-gems.yml`: it picks the history being
282
+ described *and* the copy of the task that describes it. So a release branch needs `changelog.yml`
283
+ on it, the same way it needs the release tasks — dispatching on a ref without the file fails with
284
+ `Workflow does not have 'workflow_dispatch' trigger`, since the trigger is read from the ref.
285
+
230
286
  ## Notes
231
287
 
232
288
  - Prereleases (`X.Y.Z.pre.N`) are only installed with `gem install rbs --pre`;
data/docs/stdlib.md CHANGED
@@ -15,6 +15,14 @@ $ bundle exec rake 'generate:stdlib_test[String]'
15
15
  Created: test/stdlib/String_test.rb
16
16
  ```
17
17
 
18
+ Core signatures are loaded by default. To generate a test for a class defined in standard library signatures,
19
+ pass the paths containing those signatures and their dependencies after the class name.
20
+
21
+ ```console
22
+ $ bundle exec rake 'generate:stdlib_test[CSV::Row,stdlib/csv/0,stdlib/forwardable/0]'
23
+ Created: test/stdlib/CSV_Row_test.rb
24
+ ```
25
+
18
26
  It generates `test/stdlib/[class_name]_test.rb`.
19
27
  The test scripts would look like the following:
20
28
 
data/docs/syntax.md CHANGED
@@ -48,6 +48,18 @@ _proc_ ::= `^` _parameters?_ _self-type-binding?_ _block?_ `->` _type_
48
48
  | `^` `(` `?` `)` `->` _type_ # Proc type with untyped parameter
49
49
  ```
50
50
 
51
+ `\w` above, and everywhere else in this document, is `[a-zA-Z0-9_]` together
52
+ with every character outside ASCII -- the same set Ruby takes into an
53
+ identifier. So `ServicioÚltimaVez` is a class name and `nombre_único` is an
54
+ alias name.
55
+
56
+ The leading character is the exception. RBS reads it to tell a class name from
57
+ an interface name from an alias name, so where it makes that distinction it has
58
+ to be ASCII: `class 日本語` is a class in Ruby but not a name RBS can write.
59
+ Nowhere else is restricted -- a method name, a variable name, an instance
60
+ variable name and a class variable name may all open with any character Ruby
61
+ accepts.
62
+
51
63
  ### Class instance type
52
64
 
53
65
  Class instance type denotes _an instance of a class_.
@@ -1636,6 +1636,7 @@ VALUE rbs_struct_to_ruby_value(rbs_translation_context_t ctx, rbs_node_t *instan
1636
1636
  VALUE arg_required_keywords = rbs_hash_to_ruby_hash(ctx, node->required_keywords);
1637
1637
  VALUE arg_optional_keywords = rbs_hash_to_ruby_hash(ctx, node->optional_keywords);
1638
1638
  VALUE arg_rest_keywords = rbs_struct_to_ruby_value(ctx, (rbs_node_t *) node->rest_keywords); // rbs_node
1639
+ VALUE arg_forwarding = rbs_struct_to_ruby_value(ctx, (rbs_node_t *) node->forwarding); // rbs_node
1639
1640
  VALUE arg_return_type = rbs_struct_to_ruby_value(ctx, (rbs_node_t *) node->return_type); // rbs_node
1640
1641
 
1641
1642
  // Claim the shared kwargs hash, clear it, fill it, and hand it to `.new`.
@@ -1649,9 +1650,23 @@ VALUE rbs_struct_to_ruby_value(rbs_translation_context_t ctx, rbs_node_t *instan
1649
1650
  rb_hash_aset(h, ID2SYM(rb_intern("required_keywords")), arg_required_keywords);
1650
1651
  rb_hash_aset(h, ID2SYM(rb_intern("optional_keywords")), arg_optional_keywords);
1651
1652
  rb_hash_aset(h, ID2SYM(rb_intern("rest_keywords")), arg_rest_keywords);
1653
+ rb_hash_aset(h, ID2SYM(rb_intern("forwarding")), arg_forwarding);
1652
1654
  rb_hash_aset(h, ID2SYM(rb_intern("return_type")), arg_return_type);
1653
1655
  return CLASS_NEW_INSTANCE(RBS_Types_Function, 1, &h);
1654
1656
  }
1657
+ case RBS_TYPES_FUNCTION_FORWARDING_PARAM: {
1658
+ rbs_types_function_forwarding_param_t *node = (rbs_types_function_forwarding_param_t *) instance;
1659
+
1660
+ // Compute child VALUEs into locals variables first, before any recursion into `rbs_struct_to_ruby_value()`.
1661
+ VALUE arg_location = rbs_location_range_to_ruby_location(ctx, node->base.location);
1662
+
1663
+ // Claim the shared kwargs hash, clear it, fill it, and hand it to `.new`.
1664
+ // Must not recurse between `rb_hash_clear()` and `CLASS_NEW_INSTANCE()`.
1665
+ VALUE h = ctx.reusable_kwargs_hash;
1666
+ rb_hash_clear(h);
1667
+ rb_hash_aset(h, ID2SYM(rb_intern("location")), arg_location);
1668
+ return CLASS_NEW_INSTANCE(RBS_Types_Function_ForwardingParam, 1, &h);
1669
+ }
1655
1670
  case RBS_TYPES_FUNCTION_PARAM: {
1656
1671
  rbs_types_function_param_t *node = (rbs_types_function_param_t *) instance;
1657
1672
 
@@ -79,6 +79,7 @@ VALUE RBS_Types_Block;
79
79
  VALUE RBS_Types_ClassInstance;
80
80
  VALUE RBS_Types_ClassSingleton;
81
81
  VALUE RBS_Types_Function;
82
+ VALUE RBS_Types_Function_ForwardingParam;
82
83
  VALUE RBS_Types_Function_Param;
83
84
  VALUE RBS_Types_Interface;
84
85
  VALUE RBS_Types_Intersection;
@@ -173,6 +174,7 @@ void rbs__init_constants(void) {
173
174
  IMPORT_CONSTANT(RBS_Types_ClassInstance, RBS_Types, "ClassInstance");
174
175
  IMPORT_CONSTANT(RBS_Types_ClassSingleton, RBS_Types, "ClassSingleton");
175
176
  IMPORT_CONSTANT(RBS_Types_Function, RBS_Types, "Function");
177
+ IMPORT_CONSTANT(RBS_Types_Function_ForwardingParam, RBS_Types_Function, "ForwardingParam");
176
178
  IMPORT_CONSTANT(RBS_Types_Function_Param, RBS_Types_Function, "Param");
177
179
  IMPORT_CONSTANT(RBS_Types_Interface, RBS_Types, "Interface");
178
180
  IMPORT_CONSTANT(RBS_Types_Intersection, RBS_Types, "Intersection");
@@ -87,6 +87,7 @@ extern VALUE RBS_Types_Block;
87
87
  extern VALUE RBS_Types_ClassInstance;
88
88
  extern VALUE RBS_Types_ClassSingleton;
89
89
  extern VALUE RBS_Types_Function;
90
+ extern VALUE RBS_Types_Function_ForwardingParam;
90
91
  extern VALUE RBS_Types_Function_Param;
91
92
  extern VALUE RBS_Types_Interface;
92
93
  extern VALUE RBS_Types_Intersection;
@@ -146,44 +146,80 @@ static VALUE parse_type_try(VALUE a) {
146
146
  return rbs_struct_to_ruby_value(ctx, type);
147
147
  }
148
148
 
149
- static void validate_position_range(int start_pos, int end_pos) {
149
+ /**
150
+ * `end_pos` may point past the end of the buffer: clamping with a large
151
+ * number instead of measuring the buffer is ordinary, and the lexer stops at
152
+ * the end on its own.
153
+ * */
154
+ static void validate_position_range(VALUE string, int start_pos, int end_pos) {
150
155
  if (start_pos < 0 || end_pos < 0) {
151
156
  rb_raise(rb_eArgError, "negative position range: %d...%d", start_pos, end_pos);
152
157
  }
153
158
  if (start_pos > end_pos) {
154
159
  rb_raise(rb_eArgError, "invalid position range: %d...%d", start_pos, end_pos);
155
160
  }
161
+
162
+ long size = RSTRING_LEN(string);
163
+ if ((long) start_pos > size) {
164
+ rb_raise(rb_eArgError, "position range starts past the end of the buffer: %d...%d, buffer is %ld bytes", start_pos, end_pos, size);
165
+ }
156
166
  }
157
167
 
158
168
  static rbs_lexer_t *alloc_lexer_from_buffer(rbs_allocator_t *allocator, VALUE string, rb_encoding *encoding, int start_pos, int end_pos) {
159
- validate_position_range(start_pos, end_pos);
169
+ validate_position_range(string, start_pos, end_pos);
160
170
 
161
171
  const char *encoding_name = rb_enc_name(encoding);
162
172
 
163
- return rbs_lexer_new(
173
+ rbs_lexer_t *lexer = rbs_lexer_new(
164
174
  allocator,
165
175
  rbs_string_from_ruby_string(string),
166
176
  rbs_encoding_find((const uint8_t *) encoding_name, (const uint8_t *) (encoding_name + strlen(encoding_name))),
167
177
  start_pos,
168
178
  end_pos
169
179
  );
180
+
181
+ if (lexer == NULL) {
182
+ rb_raise(rb_eArgError, "position range starts inside a character: %d...%d", start_pos, end_pos);
183
+ }
184
+
185
+ return lexer;
170
186
  }
171
187
 
172
- static rbs_parser_t *alloc_parser_from_buffer(VALUE buffer, int start_pos, int end_pos) {
173
- validate_position_range(start_pos, end_pos);
188
+ // Build the parser options from the arguments the `_parse_*` entry points
189
+ // receive. The optional syntax these enable is not part of the public
190
+ // `RBS::Parser` API, so only the private entry points pass them through.
191
+ static rbs_parser_options_t parser_options(VALUE enable_forwarding_params) {
192
+ return (rbs_parser_options_t) {
193
+ .enable_forwarding_params = RB_TEST(enable_forwarding_params),
194
+ };
195
+ }
174
196
 
197
+ static rbs_parser_t *alloc_parser_from_buffer_with_options(VALUE buffer, int start_pos, int end_pos, rbs_parser_options_t options) {
175
198
  VALUE string = rb_funcall(buffer, rb_intern("content"), 0);
176
199
  StringValue(string);
177
200
 
201
+ validate_position_range(string, start_pos, end_pos);
202
+
178
203
  rb_encoding *encoding = rb_enc_get(string);
179
204
  const char *encoding_name = rb_enc_name(encoding);
180
205
 
181
- return rbs_parser_new(
206
+ rbs_parser_t *parser = rbs_parser_new_with_options(
182
207
  rbs_string_from_ruby_string(string),
183
208
  rbs_encoding_find((const uint8_t *) encoding_name, (const uint8_t *) (encoding_name + strlen(encoding_name))),
184
209
  start_pos,
185
- end_pos
210
+ end_pos,
211
+ options
186
212
  );
213
+
214
+ if (parser == NULL) {
215
+ rb_raise(rb_eArgError, "position range starts inside a character: %d...%d", start_pos, end_pos);
216
+ }
217
+
218
+ return parser;
219
+ }
220
+
221
+ static rbs_parser_t *alloc_parser_from_buffer(VALUE buffer, int start_pos, int end_pos) {
222
+ return alloc_parser_from_buffer_with_options(buffer, start_pos, end_pos, (rbs_parser_options_t) { 0 });
187
223
  }
188
224
 
189
225
  static VALUE rbsparser_parse_type(VALUE self, VALUE buffer, VALUE start_pos, VALUE end_pos, VALUE variables, VALUE require_eof, VALUE void_allowed, VALUE self_allowed, VALUE classish_allowed) {
@@ -232,12 +268,12 @@ static VALUE parse_method_type_try(VALUE a) {
232
268
  return rbs_struct_to_ruby_value(ctx, (rbs_node_t *) method_type);
233
269
  }
234
270
 
235
- static VALUE rbsparser_parse_method_type(VALUE self, VALUE buffer, VALUE start_pos, VALUE end_pos, VALUE variables, VALUE require_eof) {
271
+ static VALUE rbsparser_parse_method_type(VALUE self, VALUE buffer, VALUE start_pos, VALUE end_pos, VALUE variables, VALUE require_eof, VALUE enable_forwarding_params) {
236
272
  VALUE string = rb_funcall(buffer, rb_intern("content"), 0);
237
273
  StringValue(string);
238
274
  rb_encoding *encoding = rb_enc_get(string);
239
275
 
240
- rbs_parser_t *parser = alloc_parser_from_buffer(buffer, FIX2INT(start_pos), FIX2INT(end_pos));
276
+ rbs_parser_t *parser = alloc_parser_from_buffer_with_options(buffer, FIX2INT(start_pos), FIX2INT(end_pos), parser_options(enable_forwarding_params));
241
277
  declare_type_variables(parser, variables, buffer);
242
278
  struct parse_method_type_arg arg = {
243
279
  .buffer = buffer,
@@ -271,12 +307,12 @@ static VALUE parse_signature_try(VALUE a) {
271
307
  return rbs_struct_to_ruby_value(ctx, (rbs_node_t *) signature);
272
308
  }
273
309
 
274
- static VALUE rbsparser_parse_signature(VALUE self, VALUE buffer, VALUE start_pos, VALUE end_pos) {
310
+ static VALUE rbsparser_parse_signature(VALUE self, VALUE buffer, VALUE start_pos, VALUE end_pos, VALUE enable_forwarding_params) {
275
311
  VALUE string = rb_funcall(buffer, rb_intern("content"), 0);
276
312
  StringValue(string);
277
313
  rb_encoding *encoding = rb_enc_get(string);
278
314
 
279
- rbs_parser_t *parser = alloc_parser_from_buffer(buffer, FIX2INT(start_pos), FIX2INT(end_pos));
315
+ rbs_parser_t *parser = alloc_parser_from_buffer_with_options(buffer, FIX2INT(start_pos), FIX2INT(end_pos), parser_options(enable_forwarding_params));
280
316
  struct parse_signature_arg arg = {
281
317
  .buffer = buffer,
282
318
  .encoding = encoding,
@@ -364,12 +400,12 @@ static VALUE parse_method_type_to_bytes_try(VALUE a) {
364
400
  return serialized_node_to_string(parser, (rbs_node_t *) method_type);
365
401
  }
366
402
 
367
- static VALUE rbsparser_parse_method_type_to_bytes(VALUE self, VALUE buffer, VALUE start_pos, VALUE end_pos, VALUE variables, VALUE require_eof) {
403
+ static VALUE rbsparser_parse_method_type_to_bytes(VALUE self, VALUE buffer, VALUE start_pos, VALUE end_pos, VALUE variables, VALUE require_eof, VALUE enable_forwarding_params) {
368
404
  VALUE string = rb_funcall(buffer, rb_intern("content"), 0);
369
405
  StringValue(string);
370
406
  rb_encoding *encoding = rb_enc_get(string);
371
407
 
372
- rbs_parser_t *parser = alloc_parser_from_buffer(buffer, FIX2INT(start_pos), FIX2INT(end_pos));
408
+ rbs_parser_t *parser = alloc_parser_from_buffer_with_options(buffer, FIX2INT(start_pos), FIX2INT(end_pos), parser_options(enable_forwarding_params));
373
409
  declare_type_variables(parser, variables, buffer);
374
410
  struct parse_method_type_arg arg = {
375
411
  .buffer = buffer,
@@ -397,12 +433,12 @@ static VALUE parse_signature_to_bytes_try(VALUE a) {
397
433
  return serialized_node_to_string(parser, (rbs_node_t *) signature);
398
434
  }
399
435
 
400
- static VALUE rbsparser_parse_signature_to_bytes(VALUE self, VALUE buffer, VALUE start_pos, VALUE end_pos) {
436
+ static VALUE rbsparser_parse_signature_to_bytes(VALUE self, VALUE buffer, VALUE start_pos, VALUE end_pos, VALUE enable_forwarding_params) {
401
437
  VALUE string = rb_funcall(buffer, rb_intern("content"), 0);
402
438
  StringValue(string);
403
439
  rb_encoding *encoding = rb_enc_get(string);
404
440
 
405
- rbs_parser_t *parser = alloc_parser_from_buffer(buffer, FIX2INT(start_pos), FIX2INT(end_pos));
441
+ rbs_parser_t *parser = alloc_parser_from_buffer_with_options(buffer, FIX2INT(start_pos), FIX2INT(end_pos), parser_options(enable_forwarding_params));
406
442
  struct parse_signature_arg arg = {
407
443
  .buffer = buffer,
408
444
  .encoding = encoding,
@@ -587,11 +623,11 @@ void rbs__init_parser(void) {
587
623
  rb_gc_register_mark_object(EMPTY_HASH);
588
624
 
589
625
  rb_define_singleton_method(RBS_Parser, "_parse_type", rbsparser_parse_type, 8);
590
- rb_define_singleton_method(RBS_Parser, "_parse_method_type", rbsparser_parse_method_type, 5);
591
- rb_define_singleton_method(RBS_Parser, "_parse_signature", rbsparser_parse_signature, 3);
626
+ rb_define_singleton_method(RBS_Parser, "_parse_method_type", rbsparser_parse_method_type, 6);
627
+ rb_define_singleton_method(RBS_Parser, "_parse_signature", rbsparser_parse_signature, 4);
592
628
  rb_define_singleton_method(RBS_Parser, "_parse_type_to_bytes", rbsparser_parse_type_to_bytes, 8);
593
- rb_define_singleton_method(RBS_Parser, "_parse_method_type_to_bytes", rbsparser_parse_method_type_to_bytes, 5);
594
- rb_define_singleton_method(RBS_Parser, "_parse_signature_to_bytes", rbsparser_parse_signature_to_bytes, 3);
629
+ rb_define_singleton_method(RBS_Parser, "_parse_method_type_to_bytes", rbsparser_parse_method_type_to_bytes, 6);
630
+ rb_define_singleton_method(RBS_Parser, "_parse_signature_to_bytes", rbsparser_parse_signature_to_bytes, 4);
595
631
  rb_define_singleton_method(RBS_Parser, "_parse_type_params", rbsparser_parse_type_params, 4);
596
632
  rb_define_singleton_method(RBS_Parser, "_parse_inline_leading_annotation", rbsparser_parse_inline_leading_annotation, 4);
597
633
  rb_define_singleton_method(RBS_Parser, "_parse_inline_trailing_annotation", rbsparser_parse_inline_trailing_annotation, 4);
data/include/rbs/ast.h CHANGED
@@ -125,18 +125,19 @@ enum rbs_node_type {
125
125
  RBS_TYPES_CLASS_INSTANCE = 63,
126
126
  RBS_TYPES_CLASS_SINGLETON = 64,
127
127
  RBS_TYPES_FUNCTION = 65,
128
- RBS_TYPES_FUNCTION_PARAM = 66,
129
- RBS_TYPES_INTERFACE = 67,
130
- RBS_TYPES_INTERSECTION = 68,
131
- RBS_TYPES_LITERAL = 69,
132
- RBS_TYPES_OPTIONAL = 70,
133
- RBS_TYPES_PROC = 71,
134
- RBS_TYPES_RECORD = 72,
135
- RBS_TYPES_RECORD_FIELD_TYPE = 73,
136
- RBS_TYPES_TUPLE = 74,
137
- RBS_TYPES_UNION = 75,
138
- RBS_TYPES_UNTYPED_FUNCTION = 76,
139
- RBS_TYPES_VARIABLE = 77,
128
+ RBS_TYPES_FUNCTION_FORWARDING_PARAM = 66,
129
+ RBS_TYPES_FUNCTION_PARAM = 67,
130
+ RBS_TYPES_INTERFACE = 68,
131
+ RBS_TYPES_INTERSECTION = 69,
132
+ RBS_TYPES_LITERAL = 70,
133
+ RBS_TYPES_OPTIONAL = 71,
134
+ RBS_TYPES_PROC = 72,
135
+ RBS_TYPES_RECORD = 73,
136
+ RBS_TYPES_RECORD_FIELD_TYPE = 74,
137
+ RBS_TYPES_TUPLE = 75,
138
+ RBS_TYPES_UNION = 76,
139
+ RBS_TYPES_UNTYPED_FUNCTION = 77,
140
+ RBS_TYPES_VARIABLE = 78,
140
141
  RBS_AST_SYMBOL,
141
142
  };
142
143
 
@@ -854,9 +855,15 @@ typedef struct rbs_types_function {
854
855
  struct rbs_hash *RBS_NONNULL required_keywords;
855
856
  struct rbs_hash *RBS_NONNULL optional_keywords;
856
857
  struct rbs_node *RBS_NULLABLE rest_keywords;
858
+ struct rbs_node *RBS_NULLABLE forwarding;
857
859
  struct rbs_node *RBS_NONNULL return_type;
858
860
  } rbs_types_function_t;
859
861
 
862
+ typedef struct rbs_types_function_forwarding_param {
863
+ rbs_node_t base;
864
+
865
+ } rbs_types_function_forwarding_param_t;
866
+
860
867
  typedef struct rbs_types_function_param {
861
868
  rbs_node_t base;
862
869
 
@@ -1030,7 +1037,8 @@ rbs_types_bases_void_t *RBS_NONNULL rbs_types_bases_void_new(rbs_allocator_t *RB
1030
1037
  rbs_types_block_t *RBS_NONNULL rbs_types_block_new(rbs_allocator_t *RBS_NONNULL allocator, rbs_location_range location, rbs_node_t *RBS_NONNULL type, bool required, rbs_node_t *RBS_NULLABLE self_type);
1031
1038
  rbs_types_class_instance_t *RBS_NONNULL rbs_types_class_instance_new(rbs_allocator_t *RBS_NONNULL allocator, rbs_location_range location, rbs_type_name_t *RBS_NONNULL name, rbs_node_list_t *RBS_NONNULL args, rbs_location_range name_range);
1032
1039
  rbs_types_class_singleton_t *RBS_NONNULL rbs_types_class_singleton_new(rbs_allocator_t *RBS_NONNULL allocator, rbs_location_range location, rbs_type_name_t *RBS_NONNULL name, rbs_node_list_t *RBS_NONNULL args, rbs_location_range name_range);
1033
- rbs_types_function_t *RBS_NONNULL rbs_types_function_new(rbs_allocator_t *RBS_NONNULL allocator, rbs_location_range location, rbs_node_list_t *RBS_NONNULL required_positionals, rbs_node_list_t *RBS_NONNULL optional_positionals, rbs_node_t *RBS_NULLABLE rest_positionals, rbs_node_list_t *RBS_NONNULL trailing_positionals, rbs_hash_t *RBS_NONNULL required_keywords, rbs_hash_t *RBS_NONNULL optional_keywords, rbs_node_t *RBS_NULLABLE rest_keywords, rbs_node_t *RBS_NONNULL return_type);
1040
+ rbs_types_function_t *RBS_NONNULL rbs_types_function_new(rbs_allocator_t *RBS_NONNULL allocator, rbs_location_range location, rbs_node_list_t *RBS_NONNULL required_positionals, rbs_node_list_t *RBS_NONNULL optional_positionals, rbs_node_t *RBS_NULLABLE rest_positionals, rbs_node_list_t *RBS_NONNULL trailing_positionals, rbs_hash_t *RBS_NONNULL required_keywords, rbs_hash_t *RBS_NONNULL optional_keywords, rbs_node_t *RBS_NULLABLE rest_keywords, rbs_node_t *RBS_NULLABLE forwarding, rbs_node_t *RBS_NONNULL return_type);
1041
+ rbs_types_function_forwarding_param_t *RBS_NONNULL rbs_types_function_forwarding_param_new(rbs_allocator_t *RBS_NONNULL allocator, rbs_location_range location);
1034
1042
  rbs_types_function_param_t *RBS_NONNULL rbs_types_function_param_new(rbs_allocator_t *RBS_NONNULL allocator, rbs_location_range location, rbs_node_t *RBS_NONNULL type, rbs_ast_symbol_t *RBS_NULLABLE name);
1035
1043
  rbs_types_interface_t *RBS_NONNULL rbs_types_interface_new(rbs_allocator_t *RBS_NONNULL allocator, rbs_location_range location, rbs_type_name_t *RBS_NONNULL name, rbs_node_list_t *RBS_NONNULL args, rbs_location_range name_range);
1036
1044
  rbs_types_intersection_t *RBS_NONNULL rbs_types_intersection_new(rbs_allocator_t *RBS_NONNULL allocator, rbs_location_range location, rbs_node_list_t *RBS_NONNULL types);
@@ -69,9 +69,9 @@
69
69
  **********************************************************************************************************************/
70
70
 
71
71
  #if defined(_MSC_VER)
72
- #define NODISCARD _Check_return_
72
+ #define RBS_NODISCARD _Check_return_
73
73
  #else
74
- #define NODISCARD __attribute__((warn_unused_result))
74
+ #define RBS_NODISCARD __attribute__((warn_unused_result))
75
75
  #endif
76
76
 
77
77
  /**
data/include/rbs/lexer.h CHANGED
@@ -72,18 +72,19 @@ enum RBSTokenType {
72
72
  kRETURN, /* return */
73
73
  kMODULESELF, /* module-self */
74
74
 
75
- tLIDENT, /* Identifiers starting with lower case */
76
- tUIDENT, /* Identifiers starting with upper case */
77
- tULIDENT, /* Identifiers starting with `_` followed by upper case */
78
- tULLIDENT, /* Identifiers starting with `_` followed by lower case */
79
- tGIDENT, /* Identifiers starting with `$` */
80
- tAIDENT, /* Identifiers starting with `@` */
81
- tA2IDENT, /* Identifiers starting with `@@` */
82
- tBANGIDENT, /* Identifiers ending with `!` */
83
- tEQIDENT, /* Identifiers ending with `=` */
84
- tQIDENT, /* Quoted identifier */
85
- pAREF_OPR, /* [] */
86
- tOPERATOR, /* Operator identifier */
75
+ tLIDENT, /* Identifiers starting with lower case */
76
+ tUIDENT, /* Identifiers starting with upper case */
77
+ tULIDENT, /* Identifiers starting with `_` followed by upper case */
78
+ tULLIDENT, /* Identifiers starting with `_` followed by lower case */
79
+ tNONASCIIIDENT, /* Identifiers starting with a character outside ASCII */
80
+ tGIDENT, /* Identifiers starting with `$` */
81
+ tAIDENT, /* Identifiers starting with `@` */
82
+ tA2IDENT, /* Identifiers starting with `@@` */
83
+ tBANGIDENT, /* Identifiers ending with `!` */
84
+ tEQIDENT, /* Identifiers ending with `=` */
85
+ tQIDENT, /* Quoted identifier */
86
+ pAREF_OPR, /* [] */
87
+ tOPERATOR, /* Operator identifier */
87
88
 
88
89
  tCOMMENT, /* Comment */
89
90
  tLINECOMMENT, /* Comment of all line */
data/include/rbs/parser.h CHANGED
@@ -40,6 +40,21 @@ typedef struct rbs_error_t {
40
40
  bool syntax_error;
41
41
  } rbs_error_t;
42
42
 
43
+ /**
44
+ * Options that control which syntax the parser accepts.
45
+ *
46
+ * Zero-initializing the struct gives the default configuration, where
47
+ * every optional syntax is disabled.
48
+ * */
49
+ typedef struct {
50
+ /**
51
+ * Accept `(...)` forwarding parameters in method types.
52
+ *
53
+ * The syntax is experimental and disabled by default.
54
+ * */
55
+ bool enable_forwarding_params;
56
+ } rbs_parser_options_t;
57
+
43
58
  /**
44
59
  * An RBS parser is a LL(3) parser.
45
60
  * */
@@ -57,6 +72,8 @@ typedef struct {
57
72
  rbs_constant_pool_t constant_pool;
58
73
  rbs_allocator_t *allocator;
59
74
  rbs_error_t *error;
75
+
76
+ rbs_parser_options_t options;
60
77
  } rbs_parser_t;
61
78
 
62
79
  /**
@@ -80,7 +97,7 @@ void rbs_parser_push_typevar_table(rbs_parser_t *parser, bool reset);
80
97
  /**
81
98
  * Insert new type variable into the latest table.
82
99
  * */
83
- NODISCARD bool rbs_parser_insert_typevar(rbs_parser_t *parser, rbs_constant_id_t id);
100
+ RBS_NODISCARD bool rbs_parser_insert_typevar(rbs_parser_t *parser, rbs_constant_id_t id);
84
101
 
85
102
  /**
86
103
  * Allocate new rbs_lexer_t object.
@@ -89,8 +106,13 @@ NODISCARD bool rbs_parser_insert_typevar(rbs_parser_t *parser, rbs_constant_id_t
89
106
  * VALUE string = rb_funcall(buffer, rb_intern("content"), 0);
90
107
  * rbs_lexer_new(string, 0, 31) // New rbs_lexer_t with buffer content
91
108
  * ```
109
+ *
110
+ * Returns `NULL` when `start_pos` is not the first byte of a character in
111
+ * `string` -- inside one, or past the end of the buffer. The lexer reaches
112
+ * `start_pos` a character at a time, so nowhere else is a position it can
113
+ * start from.
92
114
  * */
93
- rbs_lexer_t *rbs_lexer_new(rbs_allocator_t *, rbs_string_t string, const rbs_encoding_t *encoding, int start_pos, int end_pos);
115
+ RBS_NODISCARD rbs_lexer_t *rbs_lexer_new(rbs_allocator_t *, rbs_string_t string, const rbs_encoding_t *encoding, int start_pos, int end_pos);
94
116
 
95
117
  /**
96
118
  * Allocate new rbs_parser_t object.
@@ -98,8 +120,20 @@ rbs_lexer_t *rbs_lexer_new(rbs_allocator_t *, rbs_string_t string, const rbs_enc
98
120
  * ```
99
121
  * rbs_parser_new(buffer, string, encoding, 0, 1);
100
122
  * ```
123
+ *
124
+ * Returns `NULL` for a `start_pos` that `rbs_lexer_new` rejects.
125
+ * */
126
+ RBS_NODISCARD rbs_parser_t *rbs_parser_new(rbs_string_t string, const rbs_encoding_t *encoding, int start_pos, int end_pos);
127
+
128
+ /**
129
+ * Allocate new rbs_parser_t object with the given options.
130
+ *
131
+ * `rbs_parser_new` is equivalent to passing a zero-initialized
132
+ * `rbs_parser_options_t`, which disables every optional syntax.
133
+ *
134
+ * Returns `NULL` for a `start_pos` that `rbs_lexer_new` rejects.
101
135
  * */
102
- rbs_parser_t *rbs_parser_new(rbs_string_t string, const rbs_encoding_t *encoding, int start_pos, int end_pos);
136
+ RBS_NODISCARD rbs_parser_t *rbs_parser_new_with_options(rbs_string_t string, const rbs_encoding_t *encoding, int start_pos, int end_pos, rbs_parser_options_t options);
103
137
  void rbs_parser_free(rbs_parser_t *parser);
104
138
 
105
139
  /**
@@ -163,7 +163,7 @@ module RBS
163
163
  alias eql? ==
164
164
 
165
165
  def hash
166
- self.class.hash ^ name.hash ^ args.hash ^ location.hash
166
+ self.class.hash ^ name.hash ^ args.hash
167
167
  end
168
168
 
169
169
  def to_json(state = nil)
@@ -114,7 +114,7 @@ module RBS
114
114
  def self.rename(params, new_names:)
115
115
  raise unless params.size == new_names.size
116
116
 
117
- subst = Substitution.build(new_names, Types::Variable.build(new_names))
117
+ subst = Substitution.build(params.map(&:name), Types::Variable.build(new_names))
118
118
 
119
119
  params.map.with_index do |param, index|
120
120
  new_name = new_names[index]
@@ -179,7 +179,13 @@ module RBS
179
179
 
180
180
  super_types = with_super_classes.map do |decl|
181
181
  super_class = decl.super_class or raise
182
- Types::ClassInstance.new(name: super_class.name, args: super_class.args, location: nil)
182
+ args = super_class.args
183
+
184
+ if align_params = entry.align_params(decl)
185
+ args = args.map {|type| type.sub(align_params) }
186
+ end
187
+
188
+ Types::ClassInstance.new(name: super_class.name, args: args, location: nil)
183
189
  end
184
190
 
185
191
  super_types.uniq!
@@ -473,10 +479,7 @@ module RBS
473
479
 
474
480
  def mixin_ancestors(entry, type_name, included_modules:, included_interfaces:, extended_modules:, prepended_modules:, extended_interfaces:)
475
481
  entry.each_decl do |decl|
476
- align_params = Substitution.build(
477
- decl.type_params.each.map(&:name),
478
- entry.type_params.map {|param| Types::Variable.new(name: param.name, location: param.location) }
479
- )
482
+ align_params = entry.align_params(decl)
480
483
 
481
484
  mixin_ancestors0(decl,
482
485
  type_name,
@@ -104,7 +104,7 @@ module RBS
104
104
  type = Types::ClassInstance.new(name: type_name, args: args, location: nil)
105
105
  Methods.new(type: type).tap do |methods|
106
106
  entry.each_decl do |decl|
107
- subst = Substitution.build(decl.type_params.each.map(&:name), args)
107
+ subst = entry.align_params(decl)
108
108
  case decl
109
109
  when AST::Declarations::Base
110
110
  each_rbs_member_with_accessibility(decl.members) do |member, accessibility|
@@ -115,14 +115,14 @@ module RBS
115
115
  build_method(
116
116
  methods,
117
117
  type,
118
- member: member.update(overloads: member.overloads.map {|overload| overload.sub(subst) }),
118
+ member: subst ? member.update(overloads: member.overloads.map {|overload| overload.sub(subst) }) : member,
119
119
  accessibility: member.visibility || accessibility
120
120
  )
121
121
  when :singleton_instance
122
122
  build_method(
123
123
  methods,
124
124
  type,
125
- member: member.update(overloads: member.overloads.map {|overload| overload.sub(subst) }),
125
+ member: subst ? member.update(overloads: member.overloads.map {|overload| overload.sub(subst) }) : member,
126
126
  accessibility: :private
127
127
  )
128
128
  end
@@ -130,7 +130,7 @@ module RBS
130
130
  if member.kind == :instance
131
131
  build_attribute(methods,
132
132
  type,
133
- member: member.update(type: member.type.sub(subst)),
133
+ member: subst ? member.update(type: member.type.sub(subst)) : member,
134
134
  accessibility: member.visibility || accessibility)
135
135
  end
136
136
  when AST::Members::Alias
@@ -124,10 +124,13 @@ module RBS
124
124
  end
125
125
 
126
126
  entry = env.class_decls[type_name] or raise "Unknown name for build_instance: #{type_name}"
127
- args = entry.type_params.map {|param| Types::Variable.new(name: param.name, location: param.location) }
128
127
 
129
128
  entry.each_decl do |decl|
130
- subst_ = subst + Substitution.build(decl.type_params.each.map(&:name), args)
129
+ if align_params = entry.align_params(decl)
130
+ subst_ = subst + align_params
131
+ else
132
+ subst_ = subst
133
+ end
131
134
 
132
135
  decl.members.each do |member|
133
136
  case member
@@ -64,6 +64,18 @@ module RBS
64
64
  end
65
65
  end
66
66
  end
67
+
68
+ def align_params(decl)
69
+ entry_params = type_params
70
+ decl_param_names = decl.type_params.map(&:name)
71
+
72
+ return nil if decl_param_names == entry_params.map(&:name)
73
+
74
+ Substitution.build(
75
+ decl_param_names,
76
+ entry_params.map {|param| Types::Variable.new(name: param.name, location: param.location) }
77
+ )
78
+ end
67
79
  end
68
80
  end
69
81
  end