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
@@ -42,10 +42,35 @@ module RBS
42
42
 
43
43
  def self_types
44
44
  each_decl.flat_map do |decl|
45
- decl.self_types
45
+ self_types = decl.self_types
46
+ subst = align_params(decl)
47
+
48
+ if self_types.empty? || subst.nil?
49
+ self_types
50
+ else
51
+ self_types.map do |self_type|
52
+ AST::Declarations::Module::Self.new(
53
+ name: self_type.name,
54
+ args: self_type.args.map {|type| type.sub(subst) },
55
+ location: self_type.location
56
+ )
57
+ end
58
+ end
46
59
  end.uniq
47
60
  end
48
61
 
62
+ def align_params(decl)
63
+ entry_params = type_params
64
+ decl_param_names = decl.type_params.map(&:name)
65
+
66
+ return nil if decl_param_names == entry_params.map(&:name)
67
+
68
+ Substitution.build(
69
+ decl_param_names,
70
+ entry_params.map {|param| Types::Variable.new(name: param.name, location: param.location) }
71
+ )
72
+ end
73
+
49
74
  def validate_type_params
50
75
  unless context_decls.empty?
51
76
  first_decl, *rest_decls = each_decl.to_a
@@ -14,7 +14,7 @@ module RBS
14
14
  def self.parse_method_type(source, range: nil, byte_range: 0..., variables: [], require_eof: false)
15
15
  buf = buffer(source)
16
16
  byte_range = byte_range(range, buf.content) if range
17
- _parse_method_type(buf, byte_range.begin || 0, byte_range.end || buf.content.bytesize, variables, require_eof)
17
+ _parse_method_type(buf, byte_range.begin || 0, byte_range.end || buf.content.bytesize, variables, require_eof, false)
18
18
  end
19
19
 
20
20
  def self.parse_signature(source)
@@ -28,7 +28,7 @@ module RBS
28
28
  0
29
29
  end
30
30
  content = buf.content
31
- dirs, decls = _parse_signature(buf, start_pos, content.bytesize)
31
+ dirs, decls = _parse_signature(buf, start_pos, content.bytesize, false)
32
32
 
33
33
  if resolved
34
34
  dirs = dirs.dup if dirs.frozen?
data/lib/rbs/types.rb CHANGED
@@ -959,6 +959,33 @@ module RBS
959
959
  end
960
960
  end
961
961
 
962
+ class ForwardingParam
963
+ attr_reader :location
964
+
965
+ def initialize(location:)
966
+ @location = location
967
+ end
968
+
969
+ def ==(other)
970
+ other.is_a?(ForwardingParam)
971
+ end
972
+
973
+ alias eql? ==
974
+
975
+ def hash
976
+ self.class.hash
977
+ end
978
+
979
+ def to_json(state = nil)
980
+ json = {} #: Hash[Symbol, untyped]
981
+ json.to_json(state)
982
+ end
983
+
984
+ def to_s
985
+ "..."
986
+ end
987
+ end
988
+
962
989
  attr_reader :required_positionals
963
990
  attr_reader :optional_positionals
964
991
  attr_reader :rest_positionals
@@ -966,9 +993,10 @@ module RBS
966
993
  attr_reader :required_keywords
967
994
  attr_reader :optional_keywords
968
995
  attr_reader :rest_keywords
996
+ attr_reader :forwarding
969
997
  attr_reader :return_type
970
998
 
971
- def initialize(required_positionals:, optional_positionals:, rest_positionals:, trailing_positionals:, required_keywords:, optional_keywords:, rest_keywords:, return_type:)
999
+ def initialize(required_positionals:, optional_positionals:, rest_positionals:, trailing_positionals:, required_keywords:, optional_keywords:, rest_keywords:, return_type:, forwarding: nil)
972
1000
  @return_type = return_type
973
1001
  @required_positionals = required_positionals
974
1002
  @optional_positionals = optional_positionals
@@ -977,6 +1005,7 @@ module RBS
977
1005
  @required_keywords = required_keywords
978
1006
  @optional_keywords = optional_keywords
979
1007
  @rest_keywords = rest_keywords
1008
+ @forwarding = forwarding
980
1009
  end
981
1010
 
982
1011
  def ==(other)
@@ -988,6 +1017,7 @@ module RBS
988
1017
  other.required_keywords == required_keywords &&
989
1018
  other.optional_keywords == optional_keywords &&
990
1019
  other.rest_keywords == rest_keywords &&
1020
+ other.forwarding == forwarding &&
991
1021
  other.return_type == return_type
992
1022
  end
993
1023
 
@@ -1002,6 +1032,7 @@ module RBS
1002
1032
  required_keywords.hash ^
1003
1033
  optional_keywords.hash ^
1004
1034
  rest_keywords.hash ^
1035
+ forwarding.hash ^
1005
1036
  return_type.hash
1006
1037
  end
1007
1038
 
@@ -1043,6 +1074,7 @@ module RBS
1043
1074
  required_keywords: hmapv(required_keywords) {|param| param.map_type(&block) },
1044
1075
  optional_keywords: hmapv(optional_keywords) {|param| param.map_type(&block) },
1045
1076
  rest_keywords: rest_keywords&.yield_self {|param| param.map_type(&block) },
1077
+ forwarding: forwarding,
1046
1078
  return_type: yield(return_type)
1047
1079
  )
1048
1080
  else
@@ -1110,6 +1142,7 @@ module RBS
1110
1142
  required_keywords: required_keywords,
1111
1143
  optional_keywords: optional_keywords,
1112
1144
  rest_keywords: rest_keywords,
1145
+ forwarding: forwarding,
1113
1146
  return_type: return_type
1114
1147
  }.to_json(state)
1115
1148
  end
@@ -1129,6 +1162,7 @@ module RBS
1129
1162
  required_keywords: {},
1130
1163
  optional_keywords: {},
1131
1164
  rest_keywords: nil,
1165
+ forwarding: nil,
1132
1166
  return_type: return_type
1133
1167
  )
1134
1168
  end
@@ -1142,12 +1176,13 @@ module RBS
1142
1176
  required_keywords: required_keywords,
1143
1177
  optional_keywords: optional_keywords,
1144
1178
  rest_keywords: rest_keywords,
1179
+ forwarding: forwarding,
1145
1180
  return_type: type
1146
1181
  )
1147
1182
  end
1148
1183
 
1149
1184
  def update(required_positionals: self.required_positionals, optional_positionals: self.optional_positionals, rest_positionals: self.rest_positionals, trailing_positionals: self.trailing_positionals,
1150
- required_keywords: self.required_keywords, optional_keywords: self.optional_keywords, rest_keywords: self.rest_keywords, return_type: self.return_type)
1185
+ required_keywords: self.required_keywords, optional_keywords: self.optional_keywords, rest_keywords: self.rest_keywords, forwarding: self.forwarding, return_type: self.return_type)
1151
1186
  Function.new(
1152
1187
  required_positionals: required_positionals,
1153
1188
  optional_positionals: optional_positionals,
@@ -1156,6 +1191,7 @@ module RBS
1156
1191
  required_keywords: required_keywords,
1157
1192
  optional_keywords: optional_keywords,
1158
1193
  rest_keywords: rest_keywords,
1194
+ forwarding: forwarding,
1159
1195
  return_type: return_type
1160
1196
  )
1161
1197
  end
@@ -1167,6 +1203,7 @@ module RBS
1167
1203
  trailing_positionals.empty? &&
1168
1204
  required_keywords.empty? &&
1169
1205
  optional_keywords.empty? &&
1206
+ !forwarding? &&
1170
1207
  !rest_keywords
1171
1208
  end
1172
1209
 
@@ -1175,6 +1212,7 @@ module RBS
1175
1212
  params = []
1176
1213
 
1177
1214
  params.push(*required_positionals.map(&:to_s))
1215
+ params.push(forwarding.to_s) if forwarding
1178
1216
  params.push(*optional_positionals.map {|p| "?#{p}"})
1179
1217
  params.push("*#{rest_positionals}") if rest_positionals
1180
1218
  params.push(*trailing_positionals.map(&:to_s))
@@ -1185,6 +1223,10 @@ module RBS
1185
1223
  params.join(", ")
1186
1224
  end
1187
1225
 
1226
+ def forwarding?
1227
+ !forwarding.nil?
1228
+ end
1229
+
1188
1230
  def return_to_s
1189
1231
  return_type.to_s(1)
1190
1232
  end
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.3"
4
+ VERSION = "4.2.0.pre.1"
5
5
  end
@@ -12,83 +12,102 @@ module RBS
12
12
  # RBS::Parser API on top, exactly as it does for the C extension.
13
13
  class Parser
14
14
  class << self
15
- def _parse_signature(buffer, start_pos, end_pos)
16
- validate_position_range(start_pos, end_pos)
15
+ def _parse_signature(buffer, start_pos, end_pos, enable_forwarding_params)
16
+ validate_position_range(buffer, start_pos, end_pos)
17
+ validate_parser_options(enable_forwarding_params)
17
18
  encoding = buffer.content.encoding.name
18
- success, bytes = WASM::Runtime.instance.parse_signature(buffer.content, encoding, start_pos, end_pos)
19
- raise_parsing_error(buffer, bytes) unless success
19
+ status, bytes = WASM::Runtime.instance.parse_signature(buffer.content, encoding, start_pos, end_pos)
20
+ raise_parse_failure(buffer, status, bytes, start_pos, end_pos) unless status == WASM::Runtime::OK
20
21
 
21
22
  WASM::Deserializer.deserialize(bytes, buffer)
22
23
  end
23
24
 
24
25
  def _parse_type(buffer, start_pos, end_pos, variables, require_eof, void_allowed, self_allowed, classish_allowed)
25
- validate_position_range(start_pos, end_pos)
26
+ validate_position_range(buffer, start_pos, end_pos)
26
27
  validate_variables(variables)
27
28
  encoding = buffer.content.encoding.name
28
- success, bytes = WASM::Runtime.instance.parse_type(buffer.content, encoding, start_pos, end_pos, variables, require_eof, void_allowed, self_allowed, classish_allowed)
29
- raise_parsing_error(buffer, bytes) unless success
29
+ status, bytes = WASM::Runtime.instance.parse_type(buffer.content, encoding, start_pos, end_pos, variables, require_eof, void_allowed, self_allowed, classish_allowed)
30
+ raise_parse_failure(buffer, status, bytes, start_pos, end_pos) unless status == WASM::Runtime::OK
30
31
 
31
32
  deserialize_or_nil(bytes, buffer)
32
33
  end
33
34
 
34
- def _parse_method_type(buffer, start_pos, end_pos, variables, require_eof)
35
- validate_position_range(start_pos, end_pos)
35
+ def _parse_method_type(buffer, start_pos, end_pos, variables, require_eof, enable_forwarding_params)
36
+ validate_position_range(buffer, start_pos, end_pos)
36
37
  validate_variables(variables)
38
+ validate_parser_options(enable_forwarding_params)
37
39
  encoding = buffer.content.encoding.name
38
- success, bytes = WASM::Runtime.instance.parse_method_type(buffer.content, encoding, start_pos, end_pos, variables, require_eof)
39
- raise_parsing_error(buffer, bytes) unless success
40
+ status, bytes = WASM::Runtime.instance.parse_method_type(buffer.content, encoding, start_pos, end_pos, variables, require_eof)
41
+ raise_parse_failure(buffer, status, bytes, start_pos, end_pos) unless status == WASM::Runtime::OK
40
42
 
41
43
  deserialize_or_nil(bytes, buffer)
42
44
  end
43
45
 
44
46
  def _parse_type_params(buffer, start_pos, end_pos, module_type_params)
45
- validate_position_range(start_pos, end_pos)
47
+ validate_position_range(buffer, start_pos, end_pos)
46
48
  encoding = buffer.content.encoding.name
47
- success, bytes = WASM::Runtime.instance.parse_type_params(buffer.content, encoding, start_pos, end_pos, module_type_params)
48
- raise_parsing_error(buffer, bytes) unless success
49
+ status, bytes = WASM::Runtime.instance.parse_type_params(buffer.content, encoding, start_pos, end_pos, module_type_params)
50
+ raise_parse_failure(buffer, status, bytes, start_pos, end_pos) unless status == WASM::Runtime::OK
49
51
 
50
52
  bytes.empty? ? nil : WASM::Deserializer.deserialize_node_list(bytes, buffer)
51
53
  end
52
54
 
53
55
  def _lex(buffer, end_pos)
54
56
  encoding = buffer.content.encoding.name
55
- _success, bytes = WASM::Runtime.instance.lex(buffer.content, encoding, end_pos)
57
+ _status, bytes = WASM::Runtime.instance.lex(buffer.content, encoding, end_pos)
56
58
 
57
59
  WASM::Deserializer.deserialize_tokens(bytes, buffer)
58
60
  end
59
61
 
60
62
  def _parse_inline_leading_annotation(buffer, start_pos, end_pos, variables)
61
- validate_position_range(start_pos, end_pos)
63
+ validate_position_range(buffer, start_pos, end_pos)
62
64
  validate_variables(variables)
63
65
  encoding = buffer.content.encoding.name
64
- success, bytes = WASM::Runtime.instance.parse_inline_leading_annotation(buffer.content, encoding, start_pos, end_pos, variables)
65
- raise_parsing_error(buffer, bytes) unless success
66
+ status, bytes = WASM::Runtime.instance.parse_inline_leading_annotation(buffer.content, encoding, start_pos, end_pos, variables)
67
+ raise_parse_failure(buffer, status, bytes, start_pos, end_pos) unless status == WASM::Runtime::OK
66
68
 
67
69
  deserialize_or_nil(bytes, buffer)
68
70
  end
69
71
 
70
72
  def _parse_inline_trailing_annotation(buffer, start_pos, end_pos, variables)
71
- validate_position_range(start_pos, end_pos)
73
+ validate_position_range(buffer, start_pos, end_pos)
72
74
  validate_variables(variables)
73
75
  encoding = buffer.content.encoding.name
74
- success, bytes = WASM::Runtime.instance.parse_inline_trailing_annotation(buffer.content, encoding, start_pos, end_pos, variables)
75
- raise_parsing_error(buffer, bytes) unless success
76
+ status, bytes = WASM::Runtime.instance.parse_inline_trailing_annotation(buffer.content, encoding, start_pos, end_pos, variables)
77
+ raise_parse_failure(buffer, status, bytes, start_pos, end_pos) unless status == WASM::Runtime::OK
76
78
 
77
79
  deserialize_or_nil(bytes, buffer)
78
80
  end
79
81
 
80
82
  private
81
83
 
82
- # Reject negative or reversed ranges before handing them to the parser,
83
- # matching validate_position_range in the C extension (main.c). A reversed
84
- # range would otherwise make the lexer loop forever inside WebAssembly.
85
- def validate_position_range(start_pos, end_pos)
84
+ # Reject the position ranges the parser cannot take, matching
85
+ # validate_position_range in the C extension (main.c).
86
+ #
87
+ # `end_pos` past the end of the buffer is fine: clamping with a large
88
+ # number instead of measuring the buffer is ordinary, and the lexer stops
89
+ # at the end of the input on its own.
90
+ def validate_position_range(buffer, start_pos, end_pos)
86
91
  if start_pos < 0 || end_pos < 0
87
92
  raise ArgumentError, "negative position range: #{start_pos}...#{end_pos}"
88
93
  end
89
94
  if start_pos > end_pos
90
95
  raise ArgumentError, "invalid position range: #{start_pos}...#{end_pos}"
91
96
  end
97
+
98
+ size = buffer.content.bytesize
99
+ if start_pos > size
100
+ raise ArgumentError, "position range starts past the end of the buffer: #{start_pos}...#{end_pos}, buffer is #{size} bytes"
101
+ end
102
+ end
103
+
104
+ # The WebAssembly entry points (rbs_wasm.c) build their parsers with the
105
+ # default options, so the optional syntax the C extension can enable is
106
+ # not reachable here. The public RBS::Parser API never enables it.
107
+ def validate_parser_options(enable_forwarding_params)
108
+ if enable_forwarding_params
109
+ raise NotImplementedError, "forwarding parameter syntax is not supported by the WebAssembly parser"
110
+ end
92
111
  end
93
112
 
94
113
  # Reject anything that is not nil or an Array of Symbols, matching
@@ -112,6 +131,24 @@ module RBS
112
131
  bytes.empty? ? nil : WASM::Deserializer.deserialize(bytes, buffer)
113
132
  end
114
133
 
134
+ # Raise for a status other than OK (see rbs_wasm.c).
135
+ #
136
+ # A negative status is about the range rather than the source text, so it
137
+ # comes with an empty result and an ArgumentError, as in the C extension
138
+ # (main.c). Starting past the end of the buffer is plain from the
139
+ # buffer's size and rejected above, so a start position that comes back
140
+ # rejected can only be one inside a character.
141
+ def raise_parse_failure(buffer, status, bytes, start_pos, end_pos)
142
+ case status
143
+ when WASM::Runtime::INVALID_START_POS
144
+ raise ArgumentError, "position range starts inside a character: #{start_pos}...#{end_pos}"
145
+ when WASM::Runtime::INVALID_RANGE
146
+ raise ArgumentError, "invalid position range: #{start_pos}...#{end_pos}"
147
+ else
148
+ raise_parsing_error(buffer, bytes)
149
+ end
150
+ end
151
+
115
152
  # Decodes the error blob written by set_error_result (rbs_wasm.c) and raises
116
153
  # the same error the C extension would (see raise_error in main.c).
117
154
  def raise_parsing_error(buffer, blob)
Binary file
@@ -16,6 +16,14 @@ module RBS
16
16
  class Runtime
17
17
  include MonitorMixin
18
18
 
19
+ # Statuses the parse entry points return (see rbs_wasm.c). A negative one
20
+ # is about the range the caller asked for rather than the source text,
21
+ # and comes with an empty result.
22
+ INVALID_START_POS = -2
23
+ INVALID_RANGE = -1
24
+ PARSE_ERROR = 0
25
+ OK = 1
26
+
19
27
  class << self
20
28
  def instance
21
29
  @instance ||= new
@@ -48,9 +56,9 @@ module RBS
48
56
  end
49
57
 
50
58
  # `content` is the whole buffer; `start_pos`/`end_pos` are the character
51
- # range within it to parse. Each method returns [success, bytes]: on success
52
- # `bytes` is the serialized AST, otherwise it is the error blob (see
53
- # set_error_result in rbs_wasm.c).
59
+ # range within it to parse. Each method returns [status, bytes]: with OK
60
+ # `bytes` is the serialized AST, with PARSE_ERROR it is the error blob (see
61
+ # set_error_result in rbs_wasm.c), and with a negative status it is empty.
54
62
 
55
63
  def parse_signature(content, encoding, start_pos, end_pos)
56
64
  run(content, encoding) { |ptr, len, enc_ptr, enc_len| @parse_signature.apply(ptr, len, enc_ptr, enc_len, start_pos, end_pos)[0] }
@@ -118,7 +126,7 @@ module RBS
118
126
  @memory.write(source_ptr, bytes.to_java_bytes)
119
127
  @memory.write(name_ptr, name.to_java_bytes) unless name_length.zero?
120
128
  status = yield(source_ptr, length, name_ptr, name_length)
121
- [status == 1, read_result]
129
+ [i32(status), read_result]
122
130
  ensure
123
131
  @free.apply(source_ptr)
124
132
  @free.apply(name_ptr)
@@ -156,6 +164,13 @@ module RBS
156
164
  end
157
165
  end
158
166
 
167
+ # A WebAssembly i32 comes back in a JVM long, so read the low 32 bits as
168
+ # signed: the negative statuses have to stay negative on this side.
169
+ def i32(value)
170
+ value &= 0xFFFF_FFFF
171
+ value >= 0x8000_0000 ? value - 0x1_0000_0000 : value
172
+ end
173
+
159
174
  def bool(value)
160
175
  value ? 1 : 0
161
176
  end
@@ -23,7 +23,7 @@ module RBS
23
23
  # :bool, :location_range, :location_range_list, :attr_ivar_name, or
24
24
  # [:enum, [value_or_nil, ...]].
25
25
  module SerializationSchema
26
- SYMBOL_TAG = 78
26
+ SYMBOL_TAG = 79
27
27
 
28
28
  SCHEMA = [
29
29
  nil, # tag 0 is reserved for NULL
@@ -91,7 +91,8 @@ module RBS
91
91
  [:node, "RBS::Types::Block", true, nil, [[:type, :node], [:required, :bool], [:self_type, :node]], false],
92
92
  [:node, "RBS::Types::ClassInstance", true, [[:name, true], [:args, false]], [[:name, :node], [:args, :node_list]], false],
93
93
  [:node, "RBS::Types::ClassSingleton", true, [[:name, true], [:args, false]], [[:name, :node], [:args, :node_list]], false],
94
- [:node, "RBS::Types::Function", false, nil, [[:required_positionals, :node_list], [:optional_positionals, :node_list], [:rest_positionals, :node], [:trailing_positionals, :node_list], [:required_keywords, :hash], [:optional_keywords, :hash], [:rest_keywords, :node], [:return_type, :node]], false],
94
+ [:node, "RBS::Types::Function", false, nil, [[:required_positionals, :node_list], [:optional_positionals, :node_list], [:rest_positionals, :node], [:trailing_positionals, :node_list], [:required_keywords, :hash], [:optional_keywords, :hash], [:rest_keywords, :node], [:forwarding, :node], [:return_type, :node]], false],
95
+ [:node, "RBS::Types::Function::ForwardingParam", true, nil, nil, false],
95
96
  [:node, "RBS::Types::Function::Param", true, [[:name, false]], [[:type, :node], [:name, :node]], false],
96
97
  [:node, "RBS::Types::Interface", true, [[:name, true], [:args, false]], [[:name, :node], [:args, :node_list]], false],
97
98
  [:node, "RBS::Types::Intersection", true, nil, [[:types, :node_list]], false],
data/schema/function.json CHANGED
@@ -78,10 +78,21 @@
78
78
  }
79
79
  ]
80
80
  },
81
+ "forwarding": {
82
+ "title": "Forwarding parameter",
83
+ "oneOf": [
84
+ {
85
+ "type": "object"
86
+ },
87
+ {
88
+ "type": "null"
89
+ }
90
+ ]
91
+ },
81
92
  "return_type": {
82
93
  "title": "Return type of a function",
83
94
  "$ref": "types.json"
84
95
  }
85
96
  },
86
- "required": ["required_positionals", "optional_positionals", "rest_positionals", "trailing_positionals", "required_keywords", "optional_keywords", "rest_keywords", "return_type"]
97
+ "required": ["required_positionals", "optional_positionals", "rest_positionals", "trailing_positionals", "required_keywords", "optional_keywords", "rest_keywords", "forwarding", "return_type"]
87
98
  }
@@ -45,6 +45,12 @@ module RBS
45
45
  # * Raises `GenericParameterMismatchError` if incompatible declaration is detected.
46
46
  #
47
47
  def validate_type_params: () -> void
48
+
49
+ # Returns a substitution that renames the type parameters of the declaration to the entry's type parameters (`#type_params`)
50
+ #
51
+ # Returns `nil` if the declaration uses the same type parameter names as `#type_params`.
52
+ #
53
+ def align_params: (declaration | ModuleEntry::declaration) -> Substitution?
48
54
  end
49
55
  end
50
56
  end
@@ -44,7 +44,22 @@ module RBS
44
44
  #
45
45
  def validate_type_params: () -> void
46
46
 
47
+ # Returns the self types of the declarations
48
+ #
49
+ # The type variables in the self types are aligned to `#type_params`,
50
+ # so that the self types from declarations with different type parameter
51
+ # names can be compared and used with `#type_params`.
52
+ #
53
+ # Note that the returned objects may be different from the ones in the
54
+ # declarations, but `#location` points to the original declaration.
55
+ #
47
56
  def self_types: () -> Array[AST::Declarations::Module::Self]
57
+
58
+ # Returns a substitution that renames the type parameters of the declaration to the entry's type parameters (`#type_params`)
59
+ #
60
+ # Returns `nil` if the declaration uses the same type parameter names as `#type_params`.
61
+ #
62
+ def align_params: (declaration | ClassEntry::declaration) -> Substitution?
48
63
  end
49
64
  end
50
65
  end
data/sig/parser.rbs CHANGED
@@ -136,9 +136,9 @@ module RBS
136
136
 
137
137
  def self._parse_type: (Buffer, Integer start_pos, Integer end_pos, Array[Symbol] variables, bool require_eof, bool void_allowed, bool self_allowed, bool classish_allowed) -> Types::t?
138
138
 
139
- def self._parse_method_type: (Buffer, Integer start_pos, Integer end_pos, Array[Symbol] variables, bool require_eof) -> MethodType?
139
+ def self._parse_method_type: (Buffer, Integer start_pos, Integer end_pos, Array[Symbol] variables, bool require_eof, bool enable_forwarding_params) -> MethodType?
140
140
 
141
- def self._parse_signature: (Buffer, Integer start_pos, Integer end_pos) -> [Array[AST::Directives::t], Array[AST::Declarations::t]]
141
+ def self._parse_signature: (Buffer, Integer start_pos, Integer end_pos, bool enable_forwarding_params) -> [Array[AST::Directives::t], Array[AST::Declarations::t]]
142
142
 
143
143
  # Parse and serialize the result to the binary format consumed by
144
144
  # RBS::WASM::Deserializer (see ext/rbs_extension/main.c and
@@ -146,9 +146,9 @@ module RBS
146
146
  # round-trip can be exercised on CRuby.
147
147
  def self._parse_type_to_bytes: (Buffer, Integer start_pos, Integer end_pos, Array[Symbol] variables, bool require_eof, bool void_allowed, bool self_allowed, bool classish_allowed) -> String?
148
148
 
149
- def self._parse_method_type_to_bytes: (Buffer, Integer start_pos, Integer end_pos, Array[Symbol] variables, bool require_eof) -> String?
149
+ def self._parse_method_type_to_bytes: (Buffer, Integer start_pos, Integer end_pos, Array[Symbol] variables, bool require_eof, bool enable_forwarding_params) -> String?
150
150
 
151
- def self._parse_signature_to_bytes: (Buffer, Integer start_pos, Integer end_pos) -> String
151
+ def self._parse_signature_to_bytes: (Buffer, Integer start_pos, Integer end_pos, bool enable_forwarding_params) -> String
152
152
 
153
153
  def self._parse_type_params: (Buffer, Integer start_pos, Integer end_pos, bool module_type_params) -> Array[AST::TypeParam]
154
154
 
data/sig/types.rbs CHANGED
@@ -385,6 +385,12 @@ module RBS
385
385
  | -> Enumerator[t, Param]
386
386
  end
387
387
 
388
+ class ForwardingParam
389
+ attr_reader location: Location?
390
+
391
+ def initialize: (location: Location) -> void
392
+ end
393
+
388
394
  attr_reader required_positionals: Array[Param]
389
395
  attr_reader optional_positionals: Array[Param]
390
396
  attr_reader rest_positionals: Param?
@@ -392,6 +398,7 @@ module RBS
392
398
  attr_reader required_keywords: Hash[Symbol, Param]
393
399
  attr_reader optional_keywords: Hash[Symbol, Param]
394
400
  attr_reader rest_keywords: Param?
401
+ attr_reader forwarding: ForwardingParam?
395
402
  attr_reader return_type: t
396
403
 
397
404
  def initialize: (required_positionals: Array[Param],
@@ -401,7 +408,8 @@ module RBS
401
408
  required_keywords: Hash[Symbol, Param],
402
409
  optional_keywords: Hash[Symbol, Param],
403
410
  rest_keywords: Param?,
404
- return_type: t) -> void
411
+ return_type: t,
412
+ ?forwarding: ForwardingParam?) -> void
405
413
 
406
414
  def free_variables: (?Set[Symbol]) -> Set[Symbol]
407
415
 
@@ -431,9 +439,11 @@ module RBS
431
439
  ?required_keywords: Hash[Symbol, Param],
432
440
  ?optional_keywords: Hash[Symbol, Param],
433
441
  ?rest_keywords: Param?,
442
+ ?forwarding: ForwardingParam?,
434
443
  ?return_type: t) -> Function
435
444
 
436
445
  def empty?: () -> bool
446
+ def forwarding?: () -> bool
437
447
 
438
448
  def param_to_s: () -> String
439
449
  def return_to_s: () -> String
data/src/ast.c CHANGED
@@ -143,6 +143,8 @@ const char *RBS_NONNULL rbs_node_type_name(rbs_node_t *RBS_NONNULL node) {
143
143
  return "RBS::Types::ClassSingleton";
144
144
  case RBS_TYPES_FUNCTION:
145
145
  return "RBS::Types::Function";
146
+ case RBS_TYPES_FUNCTION_FORWARDING_PARAM:
147
+ return "RBS::Types::Function::ForwardingParam";
146
148
  case RBS_TYPES_FUNCTION_PARAM:
147
149
  return "RBS::Types::Function::Param";
148
150
  case RBS_TYPES_INTERFACE:
@@ -1430,7 +1432,7 @@ rbs_types_class_singleton_t *RBS_NONNULL rbs_types_class_singleton_new(rbs_alloc
1430
1432
  return instance;
1431
1433
  }
1432
1434
  #line 140 "templates/src/ast.c.erb"
1433
- 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) {
1435
+ 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) {
1434
1436
  rbs_types_function_t *instance = rbs_allocator_alloc(allocator, rbs_types_function_t);
1435
1437
 
1436
1438
  *instance = (rbs_types_function_t) {
@@ -1445,12 +1447,26 @@ rbs_types_function_t *RBS_NONNULL rbs_types_function_new(rbs_allocator_t *RBS_NO
1445
1447
  .required_keywords = required_keywords,
1446
1448
  .optional_keywords = optional_keywords,
1447
1449
  .rest_keywords = rest_keywords,
1450
+ .forwarding = forwarding,
1448
1451
  .return_type = return_type,
1449
1452
  };
1450
1453
 
1451
1454
  return instance;
1452
1455
  }
1453
1456
  #line 140 "templates/src/ast.c.erb"
1457
+ rbs_types_function_forwarding_param_t *RBS_NONNULL rbs_types_function_forwarding_param_new(rbs_allocator_t *RBS_NONNULL allocator, rbs_location_range location) {
1458
+ rbs_types_function_forwarding_param_t *instance = rbs_allocator_alloc(allocator, rbs_types_function_forwarding_param_t);
1459
+
1460
+ *instance = (rbs_types_function_forwarding_param_t) {
1461
+ .base = (rbs_node_t) {
1462
+ .type = RBS_TYPES_FUNCTION_FORWARDING_PARAM,
1463
+ .location = location,
1464
+ },
1465
+ };
1466
+
1467
+ return instance;
1468
+ }
1469
+ #line 140 "templates/src/ast.c.erb"
1454
1470
  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) {
1455
1471
  rbs_types_function_param_t *instance = rbs_allocator_alloc(allocator, rbs_types_function_param_t);
1456
1472