rbs 4.1.0 → 4.1.2

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.
data/docs/release.md CHANGED
@@ -1,69 +1,247 @@
1
1
  # Releasing RBS
2
2
 
3
+ A release is a pull request and one workflow run. Everything that leaves the
4
+ repository — the tag, both gems, and the GitHub release — is produced by the
5
+ `Release gems` workflow, so nothing has to be built or pushed from a laptop.
6
+
3
7
  Each release ships **two gems**:
4
8
 
5
- | Gem | Platform | Parser | How it is built |
6
- | --- | --- | --- | --- |
7
- | `rbs-X.Y.Z.gem` | `ruby` (MRI) | C extension | `rake release` (re-builds it) |
8
- | `rbs-X.Y.Z-java.gem` | `java` (JRuby) | WebAssembly (`lib/rbs/wasm`) | Docker image, pushed manually |
9
+ | Gem | Platform | Parser |
10
+ | --- | --- | --- |
11
+ | `rbs-X.Y.Z.gem` | `ruby` (MRI) | C extension, compiled on install |
12
+ | `rbs-X.Y.Z-java.gem` | `java` (JRuby) | `rbs_parser.wasm`, built by the workflow |
9
13
 
10
14
  The `-java` gem contains no native code — just `rbs_parser.wasm`. The Chicory/ASM
11
15
  jars it needs are not shipped in the gem; they are declared as `jar-dependencies`
12
16
  requirements and fetched from Maven when the gem is installed. So the gem can be
13
17
  built once in any environment and runs on every JRuby.
14
18
 
19
+ There are three kinds of release, and they differ in what gets written up:
20
+
21
+ | Version | CHANGELOG section | GitHub release |
22
+ | --- | --- | --- |
23
+ | `X.Y.Z` | The whole cycle since the previous release proper, prereleases included | Published |
24
+ | `X.Y.Z.pre.N` | What changed since `X.Y.Z.pre.N-1` | Published, marked as a prerelease |
25
+ | `X.Y.Z.dev.N` | None | None |
26
+
27
+ `.dev.N` releases are cut from the development line for people who need a change
28
+ early, so they are gems and tags and nothing else.
29
+
15
30
  ## Prerequisites
16
31
 
17
- - Push rights to the `rbs` gem on RubyGems (`gem signin`). If your account has
18
- MFA enabled, `gem push` / `rake release` will prompt for an OTP.
19
- - Docker, for the `-java` gem. The WASI SDK is baked into the image, so there is
20
- nothing to install on the host.
32
+ Push rights to the `rbs` gem on RubyGems are **not** needed: the workflow
33
+ authenticates through a trusted publisher registered for this repository and
34
+ `release-gems.yml`. What is needed is write access to the repository, since that
35
+ is what lets you dispatch the workflow.
21
36
 
22
37
  ## Steps
23
38
 
24
- ### 1. Release the `ruby` gem
39
+ The release pull request in step 1 is merged by a person who has reviewed it. Its merge commit is
40
+ what step 2 dispatches, tags, and pushes to RubyGems, and none of that can be taken back — so
41
+ prepare that pull request and stop there, rather than merging it and carrying on to step 2.
42
+
43
+ The bump that starts a new minor is the only other pull request that sets `RBS::VERSION`. It
44
+ publishes nothing and another bump undoes it, so one opened on an explicit request can go through
45
+ on its own.
25
46
 
26
- Once the version is bumped and committed, run on CRuby:
47
+ ### 1. Prepare the release
48
+
49
+ Open a pull request that carries everything the release needs:
50
+
51
+ - `lib/rbs/version.rb` — set `RBS::VERSION` to the version being released.
52
+ - `Gemfile.lock` — run `bundle install` after the bump; the lockfile records the version too.
53
+ - `CHANGELOG.md` — add a section for the new version, directly under the `# CHANGELOG` heading.
54
+ Sections are newest first.
55
+
56
+ Label the pull request `skip-changelog`. It carries no change of its own, and without the label it
57
+ shows up in the next release's list — that is why 4.1.0's changelog contains a `Version 4.1.0`
58
+ entry.
59
+
60
+ `rake gem:changelog` lists the pull requests merged since the last release, already formatted:
27
61
 
28
62
  ```console
29
- $ bundle exec rake release
63
+ $ bundle exec rake gem:changelog | pbcopy
30
64
  ```
31
65
 
32
- This re-builds the `ruby`-platform gem and then:
66
+ Where it starts follows `RBS::VERSION`, so bump the version first: a prerelease starts from the
67
+ latest tag, and a release proper skips the prerelease tags and starts from the previous release
68
+ proper. Pass a version to override it (`rake 'gem:changelog[4.1.0]'`). Only the list goes to
69
+ STDOUT, so it pipes cleanly. Pull requests labeled `skip-changelog` are left out and reported on
70
+ STDERR, and pull requests that only touch `rust/` are left out because the crates have their own
71
+ release cycle.
33
72
 
34
- - creates the tag `vX.Y.Z`,
35
- - pushes the current branch and the tag to `origin`,
36
- - pushes the gem to RubyGems,
37
- - runs `release:note`, which opens a GitHub **draft** release (with
38
- `--prerelease` for `*.pre.*` versions) and prints the remaining manual steps.
73
+ On a release proper, the `X.Y.Z.pre.N` sections above the previous release are replaced by the one
74
+ section being written their pull requests are in it, and the notes they were published with stay
75
+ on their own GitHub releases.
39
76
 
40
- ### 2. Build and push the `java` gem
77
+ Sort the list into the sections below. `rake gem:changelog:json` prints the same pull requests with
78
+ the changed files, labels, and body of each, which is what the sorting is based on.
41
79
 
42
- The `java` gem is not built by `rake release`, so build and push it manually:
80
+ ```markdown
81
+ ## X.Y.Z (YYYY-MM-DD)
43
82
 
44
- ```console
45
- # Build from the committed state (the gemspec's file list comes from `git ls-files`).
46
- $ docker build -f Dockerfile.jruby -t rbs-jruby .
83
+ ### Signature updates
47
84
 
48
- # Build rbs_parser.wasm and the -java gem into ./pkg on the host. The Chicory/ASM
49
- # jars are not bundled; they are fetched from Maven when the gem is installed.
50
- $ docker run --rm -e RBS_PLATFORM=java -v "$PWD/pkg:/out" rbs-jruby \
51
- gem build rbs.gemspec -o /out/rbs-X.Y.Z-java.gem
85
+ ### Language updates
52
86
 
53
- $ gem push pkg/rbs-X.Y.Z-java.gem
87
+ ### Library changes
88
+
89
+ #### rbs prototype
90
+
91
+ #### rbs collection
92
+
93
+ ### Miscellaneous
54
94
  ```
55
95
 
56
- Optionally confirm it installs and runs on JRuby before pushing:
96
+ The sections always appear in this order; delete the ones that end up empty, which is most of them
97
+ on a small release. Two things scale with the size of the release:
98
+
99
+ - **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.
101
+ - **A list of the types whose signatures changed**, as the first line of `### Signature updates`,
102
+ written as `**Updated classes/modules/methods:**` followed by the names in backticks. Used on
103
+ `X.Y.0` releases only.
104
+
105
+ The date is the day the gem is released, matching the `vX.Y.Z` tag — not the day this pull request
106
+ is opened. Fix it up before step 2 if the pull request sat for a few days.
107
+
108
+ ### 2. Run the `Release gems` workflow
109
+
110
+ Once the pull request is merged, dispatch
111
+ [`release-gems.yml`](../.github/workflows/release-gems.yml) from the Actions tab with two inputs:
112
+
113
+ | Input | Value |
114
+ | --- | --- |
115
+ | `commit` | The full 40-character SHA of the merge commit, taken from the merged pull request |
116
+ | `version` | `X.Y.Z`, without the leading `v` |
117
+
118
+ The ref selector picks which copy of the workflow file runs, not what gets released — leave it on
119
+ `master`. Everything is built from `commit`, so the run is unaffected by whatever lands on `master`
120
+ in the meantime, and a patch release cut from a release branch is dispatched the same way as any
121
+ other: the workflow does not care which branch the commit is on.
122
+
123
+ The two inputs say the same thing twice, once as a commit and once as a name, and the run stops
124
+ before anything is built unless they agree with each other and with the repository:
125
+
126
+ - `commit` has to be a full SHA that some branch contains,
127
+ - `version` has to be the `RBS::VERSION` that commit declares,
128
+ - CHANGELOG.md has to start with a section for `version` (skipped for `.dev.N`, which is not
129
+ written up),
130
+ - `vX.Y.Z` must not exist yet.
131
+
132
+ It then:
133
+
134
+ - builds `rbs-X.Y.Z.gem`,
135
+ - compiles `rbs_parser.wasm` and builds `rbs-X.Y.Z-java.gem`,
136
+ - checks both: platforms, the C extension on one and its absence on the other, and that the wasm
137
+ module made it into the `java` gem,
138
+ - installs the `java` gem on JRuby and parses with it, so the WebAssembly runtime is exercised
139
+ before anything is published,
140
+ - uploads both gems as an artifact,
141
+ - tags `commit` as `vX.Y.Z` and pushes the tag,
142
+ - pushes both gems to RubyGems through trusted publishing,
143
+ - publishes the GitHub release with the notes from CHANGELOG.md, skipping this last step for
144
+ `.dev.N` versions.
145
+
146
+ The tag is created once both gems are known to build and run, and before anything is published: a
147
+ tag can be deleted, while a version pushed to RubyGems can only be yanked.
148
+
149
+ Checking the `dry_run` box runs everything up to the artifact and stops — no tag, no gems pushed,
150
+ no release — which is how the build is exercised without releasing. `version` still has to match
151
+ the commit, so a dry run is also how a release is rehearsed before it is cut.
152
+
153
+ ## The version on `master`
154
+
155
+ `RBS::VERSION` on `master` is read one of two ways, told apart by how the version ends:
156
+
157
+ | On `master` | Means |
158
+ | --- | --- |
159
+ | `X.Y.0.dev` — a bare `.dev` | `X.Y.0` is being developed |
160
+ | A complete version — `X.Y.Z`, `X.Y.Z.pre.N`, `X.Y.Z.dev.N` | The version *after* the one named is being developed |
161
+
162
+ So `4.1.1` on `master` is not a claim that `master` is 4.1.1. It says 4.1.1 has shipped and what
163
+ comes after it is being worked on. `4.1.2.dev.1` says the same thing about itself: that release is
164
+ out, and the line continues towards 4.1.2.
165
+
166
+ Both become true the moment the release is tagged, so **nothing has to be done to `master` after a
167
+ release**. `4.0.1` was followed by `4.0.2` with no version change in between, and `4.1.2.dev.1` is
168
+ what `master` carries today.
169
+
170
+ The bare `X.Y.0.dev` is the exception because it is the one version that names a target rather than
171
+ a predecessor: a new minor is developed towards `X.Y.0` for a long time, before it is known whether
172
+ the next thing to ship is `X.Y.0.pre.1` or `X.Y.0` itself. Setting it is the only version change
173
+ that has to be made deliberately.
174
+
175
+ `rake gem:changelog` reads `RBS::VERSION` too, to decide where the next changelog starts — but the
176
+ version is set to the one being released before the changelog is generated, so it sees that rather
177
+ than whatever `master` was carrying.
178
+
179
+ ## Starting a new minor
180
+
181
+ `master` is the development line of one minor at a time. Moving it from `X.Y` to `X.(Y+1)` is not
182
+ part of any one release — it is the decision that the `X.Y` line is done, taken whenever that
183
+ becomes true — and it is the one moment the version on `master` is changed by hand. Two changes, in
184
+ opposite places:
185
+
186
+ 1. **Branch the line being left behind**, from the last `master` commit that belongs to it:
187
+
188
+ ```console
189
+ $ git switch --create aaa-X.Y.x <that commit>
190
+ $ git push -u origin aaa-X.Y.x
191
+ ```
192
+
193
+ Branch from the commit *before* the bump below, so the branch keeps the version its line was
194
+ released under. Patch releases of `X.Y` are cut from here from now on, with their changes
195
+ cherry-picked from `master` — see [Backports](#backports). The `aaa-` prefix carries no meaning
196
+ beyond sorting the release branches to the top of the branch list.
197
+
198
+ 2. **Bump `master`** to `X.(Y+1).0.dev`, in a pull request with `Gemfile.lock` regenerated and
199
+ labeled `skip-changelog` like the release pull request itself. `4.1` was started exactly this
200
+ way: `aaa-4.0.x` was branched at the commit before `Start 4.1 development`, which set
201
+ `RBS::VERSION` to `4.1.0.dev`.
202
+
203
+ Two loose ends that are easy to forget:
204
+
205
+ - **The release note of the new line.** `rake gem:gh_release` links every published release to
206
+ `https://github.com/ruby/rbs/wiki/Release-Note-X.Y`, built from the version number without
207
+ checking that the page is there. Nothing has to be written when the line starts — the page comes
208
+ together as the first release proper of the line comes into view — but it does have to exist by
209
+ the time that release is published, or its notes link to an empty page.
210
+ - **Release branches that are done.** A branch is worth keeping only while its line might still
211
+ get a patch. The ones that exist do not cover every line that ever had one — `3.8.1` shipped and
212
+ there is no `aaa-3.8.x` — so this is housekeeping rather than a rule, but starting a new minor is
213
+ the natural moment to look at the bottom of the branch list and delete what has been superseded.
214
+
215
+ ## Backports
216
+
217
+ A patch release is cut from a release branch (`aaa-X.Y.x`), and what it carries beyond the previous
218
+ release is cherry-picked from the development line. Cherry-pick with `-x`:
57
219
 
58
220
  ```console
59
- $ docker run --rm -v "$PWD/pkg:/pkg" -w /tmp rbs-jruby bash -c \
60
- 'gem install /pkg/rbs-X.Y.Z-java.gem && ruby -e "require %q{rbs}; puts [RUBY_ENGINE, RBS::VERSION].join(%q{ })"'
221
+ $ git cherry-pick -x <commit>
61
222
  ```
62
223
 
224
+ `-x` records the commit the change was copied from, and that recorded line is what `rake
225
+ gem:changelog` follows to reach the pull request the change was written and reviewed in. Without
226
+ it, the only pull request a backported commit is associated with is the one that carried the
227
+ backport, which says nothing about the change and is the same for every commit it brought over —
228
+ that is why the 4.0.3 changelog credits its three entries to the same pull request.
229
+
63
230
  ## Notes
64
231
 
65
232
  - Prereleases (`X.Y.Z.pre.N`) are only installed with `gem install rbs --pre`;
66
233
  a plain `gem install rbs` is unaffected. On JRuby, `gem install rbs [--pre]`
67
234
  resolves to the `-java` gem automatically.
68
- - The Dockerfile pins the WASI SDK / Chicory / ASM versions to match the
69
- `wasm` and `jruby` CI workflows. Keep them in sync when bumping.
235
+ - The WASI SDK version is pinned in `wasm.yml`, `jruby.yml`, `release-gems.yml`, and
236
+ `Dockerfile.jruby`, each carrying its own copy. Keep them in sync when bumping. The
237
+ Chicory/ASM versions are not duplicated: they are the `jar` requirements in
238
+ `rbs.gemspec`, which is where the workflow, `Dockerfile.jruby` and `gem install` all
239
+ read them from.
240
+ - `rake 'gem:check_release[X.Y.Z]'` and `rake gem:tag` are what the workflow runs to
241
+ check the release and to create the tag. Both work locally, which is the fallback
242
+ if the tag ever has to be created by hand.
243
+ - Those two tasks and `rake gem:gh_release` come from the Rakefile of the commit
244
+ being released, not from the branch the workflow was dispatched from. Releasing
245
+ from a release branch (`aaa-X.Y.x`) therefore needs the release tooling on that
246
+ branch as well; without it the run fails on the missing task, before publishing
247
+ anything.
data/include/rbs/ast.h CHANGED
@@ -583,7 +583,7 @@ typedef struct rbs_ast_ruby_annotations_class_alias_annotation {
583
583
 
584
584
  rbs_location_range prefix_location;
585
585
  rbs_location_range keyword_location;
586
- struct rbs_type_name *RBS_NONNULL type_name;
586
+ struct rbs_type_name *RBS_NULLABLE type_name;
587
587
  rbs_location_range type_name_location;
588
588
  } rbs_ast_ruby_annotations_class_alias_annotation_t;
589
589
 
@@ -631,7 +631,7 @@ typedef struct rbs_ast_ruby_annotations_module_alias_annotation {
631
631
 
632
632
  rbs_location_range prefix_location;
633
633
  rbs_location_range keyword_location;
634
- struct rbs_type_name *RBS_NONNULL type_name;
634
+ struct rbs_type_name *RBS_NULLABLE type_name;
635
635
  rbs_location_range type_name_location;
636
636
  } rbs_ast_ruby_annotations_module_alias_annotation_t;
637
637
 
@@ -998,12 +998,12 @@ rbs_ast_members_prepend_t *RBS_NONNULL rbs_ast_members_prepend_new(rbs_allocator
998
998
  rbs_ast_members_private_t *RBS_NONNULL rbs_ast_members_private_new(rbs_allocator_t *RBS_NONNULL allocator, rbs_location_range location);
999
999
  rbs_ast_members_public_t *RBS_NONNULL rbs_ast_members_public_new(rbs_allocator_t *RBS_NONNULL allocator, rbs_location_range location);
1000
1000
  rbs_ast_ruby_annotations_block_param_type_annotation_t *RBS_NONNULL rbs_ast_ruby_annotations_block_param_type_annotation_new(rbs_allocator_t *RBS_NONNULL allocator, rbs_location_range location, rbs_location_range prefix_location, rbs_location_range ampersand_location, rbs_location_range name_location, rbs_location_range colon_location, rbs_location_range question_location, rbs_location_range type_location, rbs_node_t *RBS_NONNULL type_, rbs_location_range comment_location);
1001
- rbs_ast_ruby_annotations_class_alias_annotation_t *RBS_NONNULL rbs_ast_ruby_annotations_class_alias_annotation_new(rbs_allocator_t *RBS_NONNULL allocator, rbs_location_range location, rbs_location_range prefix_location, rbs_location_range keyword_location, rbs_type_name_t *RBS_NONNULL type_name, rbs_location_range type_name_location);
1001
+ rbs_ast_ruby_annotations_class_alias_annotation_t *RBS_NONNULL rbs_ast_ruby_annotations_class_alias_annotation_new(rbs_allocator_t *RBS_NONNULL allocator, rbs_location_range location, rbs_location_range prefix_location, rbs_location_range keyword_location, rbs_type_name_t *RBS_NULLABLE type_name, rbs_location_range type_name_location);
1002
1002
  rbs_ast_ruby_annotations_colon_method_type_annotation_t *RBS_NONNULL rbs_ast_ruby_annotations_colon_method_type_annotation_new(rbs_allocator_t *RBS_NONNULL allocator, rbs_location_range location, rbs_location_range prefix_location, rbs_node_list_t *RBS_NONNULL annotations, rbs_node_t *RBS_NONNULL method_type);
1003
1003
  rbs_ast_ruby_annotations_double_splat_param_type_annotation_t *RBS_NONNULL rbs_ast_ruby_annotations_double_splat_param_type_annotation_new(rbs_allocator_t *RBS_NONNULL allocator, rbs_location_range location, rbs_location_range prefix_location, rbs_location_range star2_location, rbs_location_range name_location, rbs_location_range colon_location, rbs_node_t *RBS_NONNULL param_type, rbs_location_range comment_location);
1004
1004
  rbs_ast_ruby_annotations_instance_variable_annotation_t *RBS_NONNULL rbs_ast_ruby_annotations_instance_variable_annotation_new(rbs_allocator_t *RBS_NONNULL allocator, rbs_location_range location, rbs_location_range prefix_location, rbs_ast_symbol_t *RBS_NONNULL ivar_name, rbs_location_range ivar_name_location, rbs_location_range colon_location, rbs_node_t *RBS_NONNULL type, rbs_location_range comment_location);
1005
1005
  rbs_ast_ruby_annotations_method_types_annotation_t *RBS_NONNULL rbs_ast_ruby_annotations_method_types_annotation_new(rbs_allocator_t *RBS_NONNULL allocator, rbs_location_range location, rbs_location_range prefix_location, rbs_node_list_t *RBS_NONNULL overloads, rbs_location_range_list_t *RBS_NONNULL vertical_bar_locations, rbs_location_range dot3_location);
1006
- rbs_ast_ruby_annotations_module_alias_annotation_t *RBS_NONNULL rbs_ast_ruby_annotations_module_alias_annotation_new(rbs_allocator_t *RBS_NONNULL allocator, rbs_location_range location, rbs_location_range prefix_location, rbs_location_range keyword_location, rbs_type_name_t *RBS_NONNULL type_name, rbs_location_range type_name_location);
1006
+ rbs_ast_ruby_annotations_module_alias_annotation_t *RBS_NONNULL rbs_ast_ruby_annotations_module_alias_annotation_new(rbs_allocator_t *RBS_NONNULL allocator, rbs_location_range location, rbs_location_range prefix_location, rbs_location_range keyword_location, rbs_type_name_t *RBS_NULLABLE type_name, rbs_location_range type_name_location);
1007
1007
  rbs_ast_ruby_annotations_module_self_annotation_t *RBS_NONNULL rbs_ast_ruby_annotations_module_self_annotation_new(rbs_allocator_t *RBS_NONNULL allocator, rbs_location_range location, rbs_location_range prefix_location, rbs_location_range keyword_location, rbs_location_range colon_location, rbs_type_name_t *RBS_NONNULL name, rbs_node_list_t *RBS_NONNULL args, rbs_location_range open_bracket_location, rbs_location_range close_bracket_location, rbs_location_range_list_t *RBS_NONNULL args_comma_locations, rbs_location_range comment_location);
1008
1008
  rbs_ast_ruby_annotations_node_type_assertion_t *RBS_NONNULL rbs_ast_ruby_annotations_node_type_assertion_new(rbs_allocator_t *RBS_NONNULL allocator, rbs_location_range location, rbs_location_range prefix_location, rbs_node_t *RBS_NONNULL type);
1009
1009
  rbs_ast_ruby_annotations_param_type_annotation_t *RBS_NONNULL rbs_ast_ruby_annotations_param_type_annotation_new(rbs_allocator_t *RBS_NONNULL allocator, rbs_location_range location, rbs_location_range prefix_location, rbs_location_range name_location, rbs_location_range colon_location, rbs_node_t *RBS_NONNULL param_type, rbs_location_range comment_location);
data/lib/rbs/version.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module RBS
4
- VERSION = "4.1.0"
4
+ VERSION = "4.1.2"
5
5
  end
data/src/ast.c CHANGED
@@ -913,7 +913,7 @@ rbs_ast_ruby_annotations_block_param_type_annotation_t *RBS_NONNULL rbs_ast_ruby
913
913
  return instance;
914
914
  }
915
915
  #line 140 "templates/src/ast.c.erb"
916
- rbs_ast_ruby_annotations_class_alias_annotation_t *RBS_NONNULL rbs_ast_ruby_annotations_class_alias_annotation_new(rbs_allocator_t *RBS_NONNULL allocator, rbs_location_range location, rbs_location_range prefix_location, rbs_location_range keyword_location, rbs_type_name_t *RBS_NONNULL type_name, rbs_location_range type_name_location) {
916
+ rbs_ast_ruby_annotations_class_alias_annotation_t *RBS_NONNULL rbs_ast_ruby_annotations_class_alias_annotation_new(rbs_allocator_t *RBS_NONNULL allocator, rbs_location_range location, rbs_location_range prefix_location, rbs_location_range keyword_location, rbs_type_name_t *RBS_NULLABLE type_name, rbs_location_range type_name_location) {
917
917
  rbs_ast_ruby_annotations_class_alias_annotation_t *instance = rbs_allocator_alloc(allocator, rbs_ast_ruby_annotations_class_alias_annotation_t);
918
918
 
919
919
  *instance = (rbs_ast_ruby_annotations_class_alias_annotation_t) {
@@ -1001,7 +1001,7 @@ rbs_ast_ruby_annotations_method_types_annotation_t *RBS_NONNULL rbs_ast_ruby_ann
1001
1001
  return instance;
1002
1002
  }
1003
1003
  #line 140 "templates/src/ast.c.erb"
1004
- rbs_ast_ruby_annotations_module_alias_annotation_t *RBS_NONNULL rbs_ast_ruby_annotations_module_alias_annotation_new(rbs_allocator_t *RBS_NONNULL allocator, rbs_location_range location, rbs_location_range prefix_location, rbs_location_range keyword_location, rbs_type_name_t *RBS_NONNULL type_name, rbs_location_range type_name_location) {
1004
+ rbs_ast_ruby_annotations_module_alias_annotation_t *RBS_NONNULL rbs_ast_ruby_annotations_module_alias_annotation_new(rbs_allocator_t *RBS_NONNULL allocator, rbs_location_range location, rbs_location_range prefix_location, rbs_location_range keyword_location, rbs_type_name_t *RBS_NULLABLE type_name, rbs_location_range type_name_location) {
1005
1005
  rbs_ast_ruby_annotations_module_alias_annotation_t *instance = rbs_allocator_alloc(allocator, rbs_ast_ruby_annotations_module_alias_annotation_t);
1006
1006
 
1007
1007
  *instance = (rbs_ast_ruby_annotations_module_alias_annotation_t) {
data/src/parser.c CHANGED
@@ -405,18 +405,21 @@ NODISCARD
405
405
  static bool parse_keyword_key(rbs_parser_t *parser, rbs_ast_symbol_t **key) {
406
406
  rbs_parser_advance(parser);
407
407
 
408
- rbs_location_range symbol_range = rbs_location_range_current_token(parser);
408
+ rbs_range_t symbol_range = parser->current_token.range;
409
409
 
410
410
  if (parser->next_token.type == pQUESTION) {
411
+ // The `?` is part of the key, so it is part of the location too.
412
+ symbol_range.end = parser->next_token.range.end;
413
+
411
414
  *key = rbs_ast_symbol_new(
412
415
  ALLOCATOR(),
413
- symbol_range,
416
+ RBS_RANGE_LEX2AST(symbol_range),
414
417
  &parser->constant_pool,
415
418
  intern_token_start_end(parser, parser->current_token, parser->next_token)
416
419
  );
417
420
  rbs_parser_advance(parser);
418
421
  } else {
419
- *key = rbs_ast_symbol_new(ALLOCATOR(), symbol_range, &parser->constant_pool, INTERN_TOKEN(parser, parser->current_token));
422
+ *key = rbs_ast_symbol_new(ALLOCATOR(), RBS_RANGE_LEX2AST(symbol_range), &parser->constant_pool, INTERN_TOKEN(parser, parser->current_token));
420
423
  }
421
424
 
422
425
  return true;
data/wasm/README.md CHANGED
@@ -27,6 +27,39 @@ $ rake wasm:install_jars # download the Chicory/ASM jars into ~/.m2 (run on JRub
27
27
 
28
28
  The compiled `rbs_parser.wasm` is a build artifact and is not checked in.
29
29
 
30
+ The WASI SDK is needed for the *build*, not for running the result — the host clang already
31
+ knows the `wasm32` target, but there is no wasm32 libc on a normal machine, so it picks up the
32
+ host headers and fails on the first `#include`. That is what the SDK supplies, along with the
33
+ builtins the link step needs.
34
+
35
+ ## Running the suite on JRuby
36
+
37
+ [`Dockerfile.jruby`](../Dockerfile.jruby) builds an image that has everything this needs, so no
38
+ JRuby, JDK or WASI SDK has to be installed to work on the JRuby side:
39
+
40
+ ```console
41
+ $ docker build -f Dockerfile.jruby -t rbs-jruby .
42
+ $ docker run --rm rbs-jruby # run the test suite
43
+ $ docker run --rm -e RBS_PLATFORM=java rbs-jruby \
44
+ gem build rbs.gemspec # build the -java gem
45
+ ```
46
+
47
+ Two things in it are not obvious:
48
+
49
+ - `build-essential` is for prism, which builds `libprism.so` and loads it through FFI on JRuby
50
+ rather than as an MRI C extension. It needs `cc` and `make`.
51
+ - Bundler is skipped. The development `Gemfile` pulls in CRuby-only C extensions (bigdecimal,
52
+ stackprof, …) that cannot build on JRuby, so the few gems the suite needs are installed
53
+ directly, in the same set as [`jruby.yml`](../.github/workflows/jruby.yml).
54
+
55
+ The image compiles `rbs_parser.wasm` itself, which is why it carries the WASI SDK. That is not
56
+ the only arrangement: the build needs the SDK but not JRuby, and running the suite needs JRuby
57
+ but not the SDK, so `jruby.yml` splits them instead — it compiles the module on CRuby and then
58
+ switches engines to test against the result.
59
+
60
+ `rake wasm:install_jars` is the step that has to be on JRuby either way: it resolves the `jar`
61
+ requirements from `rbs.gemspec` through the JVM.
62
+
30
63
  ## Exported functions
31
64
 
32
65
  The module is built as a "reactor": it has no `main`, and the host calls
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rbs
3
3
  version: !ruby/object:Gem::Version
4
- version: 4.1.0
4
+ version: 4.1.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Soutaro Matsumoto
@@ -70,7 +70,7 @@ files:
70
70
  - ".github/workflows/comments.yml"
71
71
  - ".github/workflows/dependabot.yml"
72
72
  - ".github/workflows/jruby.yml"
73
- - ".github/workflows/milestone.yml"
73
+ - ".github/workflows/release-gems.yml"
74
74
  - ".github/workflows/ruby.yml"
75
75
  - ".github/workflows/rust.yml"
76
76
  - ".github/workflows/truffleruby.yml"
@@ -649,7 +649,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
649
649
  - !ruby/object:Gem::Version
650
650
  version: '0'
651
651
  requirements: []
652
- rubygems_version: 4.0.3
652
+ rubygems_version: 4.0.17
653
653
  specification_version: 4
654
654
  summary: Type signature for Ruby.
655
655
  test_files: []
@@ -1,91 +0,0 @@
1
- name: Check milestone
2
-
3
- on:
4
- pull_request:
5
- types: [opened, edited, labeled, unlabeled, milestoned, demilestoned, synchronize]
6
- merge_group: {}
7
-
8
- permissions:
9
- contents: read
10
-
11
- jobs:
12
- check:
13
- runs-on: ubuntu-latest
14
-
15
- steps:
16
- # The milestone is a property of the pull request, so there is nothing to
17
- # check once it enters the merge queue. This job still has to run there
18
- # because `check` is a required status check -- it just reports success
19
- # without doing anything.
20
- - uses: actions/checkout@v7
21
- if: github.event_name == 'pull_request'
22
-
23
- - name: Extract RBS::Version
24
- id: version
25
- if: github.event_name == 'pull_request'
26
- run: |
27
- # Extract version string from lib/rbs/version.rb
28
- version=$(ruby -e 'load "lib/rbs/version.rb"; print RBS::VERSION')
29
- echo "version=$version" >> "$GITHUB_OUTPUT"
30
-
31
- # Parse major.minor.patch
32
- IFS='.' read -r major minor patch _rest <<< "$version"
33
- echo "major=$major" >> "$GITHUB_OUTPUT"
34
- echo "minor=$minor" >> "$GITHUB_OUTPUT"
35
- echo "patch=$patch" >> "$GITHUB_OUTPUT"
36
-
37
- echo "RBS::VERSION = $version (major=$major, minor=$minor, patch=$patch)"
38
-
39
- - name: Check milestone
40
- if: github.event_name == 'pull_request'
41
- uses: actions/github-script@v9
42
- with:
43
- script: |
44
- const pr = context.payload.pull_request;
45
- const milestone = pr.milestone;
46
- const labels = pr.labels.map(l => l.name);
47
-
48
- const version = '${{ steps.version.outputs.version }}';
49
- const major = '${{ steps.version.outputs.major }}';
50
- const minor = '${{ steps.version.outputs.minor }}';
51
- const patch = parseInt('${{ steps.version.outputs.patch }}', 10);
52
-
53
- if (!milestone) {
54
- if (labels.includes('no-milestone')) {
55
- core.info('No milestone set, but no-milestone label is present — OK');
56
- return;
57
- }
58
- core.setFailed(
59
- 'No milestone set. Add a milestone or add the "no-milestone" label.'
60
- );
61
- return;
62
- }
63
-
64
- if (labels.includes('no-milestone')) {
65
- core.setFailed(
66
- 'Milestone is set but "no-milestone" label is present. Remove the label or the milestone.'
67
- );
68
- return;
69
- }
70
-
71
- const milestoneName = milestone.title;
72
- core.info(`Milestone: "${milestoneName}", RBS::VERSION: ${version}`);
73
-
74
- // Expected milestone based on version:
75
- // patch == 0 → "RBS major.minor" (e.g. "RBS 4.0")
76
- // patch >= 1 → "RBS major.minor.x" (e.g. "RBS 4.0.x")
77
- let expectedMilestone;
78
- if (patch === 0) {
79
- expectedMilestone = `RBS ${major}.${minor}`;
80
- } else {
81
- expectedMilestone = `RBS ${major}.${minor}.x`;
82
- }
83
-
84
- if (milestoneName !== expectedMilestone) {
85
- core.setFailed(
86
- `Milestone "${milestoneName}" does not match RBS::VERSION ${version}. ` +
87
- `Expected milestone: "${expectedMilestone}"`
88
- );
89
- } else {
90
- core.info(`Milestone "${milestoneName}" matches RBS::VERSION ${version}`);
91
- }