rbs 4.0.0.dev.4 → 4.1.0.pre.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.
Files changed (306) hide show
  1. checksums.yaml +4 -4
  2. data/.clang-format +1 -0
  3. data/.github/dependabot.yml +16 -14
  4. data/.github/workflows/bundle-update.yml +63 -0
  5. data/.github/workflows/c-check.yml +21 -11
  6. data/.github/workflows/comments.yml +5 -3
  7. data/.github/workflows/dependabot.yml +2 -2
  8. data/.github/workflows/jruby.yml +67 -0
  9. data/.github/workflows/milestone.yml +83 -0
  10. data/.github/workflows/ruby.yml +63 -24
  11. data/.github/workflows/rust.yml +184 -0
  12. data/.github/workflows/truffleruby.yml +54 -0
  13. data/.github/workflows/typecheck.yml +5 -2
  14. data/.github/workflows/wasm.yml +53 -0
  15. data/.github/workflows/windows.yml +8 -2
  16. data/.gitignore +11 -0
  17. data/.rubocop.yml +1 -1
  18. data/CHANGELOG.md +357 -0
  19. data/README.md +4 -4
  20. data/Rakefile +365 -33
  21. data/Steepfile +8 -0
  22. data/config.yml +450 -24
  23. data/core/array.rbs +443 -363
  24. data/core/basic_object.rbs +9 -8
  25. data/core/binding.rbs +0 -2
  26. data/core/builtin.rbs +9 -8
  27. data/core/class.rbs +11 -8
  28. data/core/comparable.rbs +55 -34
  29. data/core/complex.rbs +104 -78
  30. data/core/dir.rbs +61 -49
  31. data/core/encoding.rbs +12 -15
  32. data/core/enumerable.rbs +288 -196
  33. data/core/enumerator/arithmetic_sequence.rbs +70 -0
  34. data/core/enumerator/product.rbs +5 -5
  35. data/core/enumerator.rbs +91 -28
  36. data/core/errno.rbs +11 -2
  37. data/core/errors.rbs +58 -29
  38. data/core/exception.rbs +13 -13
  39. data/core/fiber.rbs +74 -54
  40. data/core/file.rbs +260 -1151
  41. data/core/file_constants.rbs +463 -0
  42. data/core/file_stat.rbs +534 -0
  43. data/core/file_test.rbs +3 -3
  44. data/core/float.rbs +257 -92
  45. data/core/gc.rbs +425 -281
  46. data/core/hash.rbs +1151 -829
  47. data/core/integer.rbs +156 -195
  48. data/core/io/buffer.rbs +53 -42
  49. data/core/io/wait.rbs +13 -35
  50. data/core/io.rbs +216 -150
  51. data/core/kernel.rbs +239 -163
  52. data/core/marshal.rbs +4 -4
  53. data/core/match_data.rbs +15 -13
  54. data/core/math.rbs +107 -66
  55. data/core/method.rbs +69 -33
  56. data/core/module.rbs +302 -150
  57. data/core/nil_class.rbs +7 -6
  58. data/core/numeric.rbs +77 -63
  59. data/core/object.rbs +9 -11
  60. data/core/object_space/weak_key_map.rbs +7 -7
  61. data/core/object_space.rbs +30 -23
  62. data/core/pathname.rbs +1322 -0
  63. data/core/proc.rbs +95 -58
  64. data/core/process.rbs +222 -202
  65. data/core/ractor.rbs +371 -515
  66. data/core/random.rbs +21 -3
  67. data/core/range.rbs +181 -79
  68. data/core/rational.rbs +60 -89
  69. data/core/rbs/ops.rbs +154 -0
  70. data/core/rbs/unnamed/argf.rbs +63 -56
  71. data/core/rbs/unnamed/env_class.rbs +19 -14
  72. data/core/rbs/unnamed/main_class.rbs +123 -0
  73. data/core/rbs/unnamed/random.rbs +11 -118
  74. data/core/regexp.rbs +258 -214
  75. data/core/ruby.rbs +53 -0
  76. data/core/ruby_vm.rbs +78 -34
  77. data/core/rubygems/config_file.rbs +5 -5
  78. data/core/rubygems/errors.rbs +4 -71
  79. data/core/rubygems/requirement.rbs +5 -5
  80. data/core/rubygems/rubygems.rbs +16 -82
  81. data/core/rubygems/version.rbs +2 -3
  82. data/core/set.rbs +493 -363
  83. data/core/signal.rbs +26 -16
  84. data/core/string.rbs +3234 -1285
  85. data/core/struct.rbs +43 -42
  86. data/core/symbol.rbs +41 -34
  87. data/core/thread.rbs +141 -73
  88. data/core/time.rbs +81 -50
  89. data/core/trace_point.rbs +41 -35
  90. data/core/true_class.rbs +2 -2
  91. data/core/unbound_method.rbs +24 -16
  92. data/core/warning.rbs +7 -7
  93. data/docs/CONTRIBUTING.md +2 -1
  94. data/docs/aliases.md +79 -0
  95. data/docs/collection.md +3 -3
  96. data/docs/config.md +171 -0
  97. data/docs/encoding.md +56 -0
  98. data/docs/gem.md +0 -1
  99. data/docs/inline.md +634 -0
  100. data/docs/rbs_by_example.md +20 -20
  101. data/docs/rust.md +96 -0
  102. data/docs/sigs.md +3 -3
  103. data/docs/syntax.md +48 -18
  104. data/docs/type_fingerprint.md +21 -0
  105. data/docs/wasm_serialization.md +80 -0
  106. data/exe/rbs +1 -1
  107. data/ext/rbs_extension/ast_translation.c +1441 -671
  108. data/ext/rbs_extension/ast_translation.h +7 -0
  109. data/ext/rbs_extension/class_constants.c +18 -2
  110. data/ext/rbs_extension/class_constants.h +9 -0
  111. data/ext/rbs_extension/extconf.rb +6 -1
  112. data/ext/rbs_extension/legacy_location.c +33 -56
  113. data/ext/rbs_extension/legacy_location.h +37 -0
  114. data/ext/rbs_extension/main.c +183 -39
  115. data/include/rbs/ast.h +597 -297
  116. data/include/rbs/defines.h +40 -0
  117. data/include/rbs/lexer.h +31 -11
  118. data/include/rbs/location.h +25 -44
  119. data/include/rbs/parser.h +6 -6
  120. data/include/rbs/serialize.h +39 -0
  121. data/include/rbs/string.h +0 -2
  122. data/include/rbs/util/rbs_allocator.h +34 -13
  123. data/include/rbs/util/rbs_assert.h +12 -1
  124. data/include/rbs/util/rbs_constant_pool.h +0 -3
  125. data/include/rbs/util/rbs_encoding.h +2 -0
  126. data/include/rbs/util/rbs_unescape.h +2 -1
  127. data/include/rbs.h +8 -0
  128. data/lib/rbs/annotate/rdoc_annotator.rb +27 -31
  129. data/lib/rbs/ast/annotation.rb +1 -1
  130. data/lib/rbs/ast/comment.rb +1 -1
  131. data/lib/rbs/ast/declarations.rb +10 -10
  132. data/lib/rbs/ast/members.rb +14 -14
  133. data/lib/rbs/ast/ruby/annotations.rb +335 -3
  134. data/lib/rbs/ast/ruby/comment_block.rb +30 -4
  135. data/lib/rbs/ast/ruby/declarations.rb +209 -4
  136. data/lib/rbs/ast/ruby/helpers/constant_helper.rb +4 -0
  137. data/lib/rbs/ast/ruby/helpers/location_helper.rb +1 -1
  138. data/lib/rbs/ast/ruby/members.rb +571 -22
  139. data/lib/rbs/ast/type_param.rb +24 -4
  140. data/lib/rbs/buffer.rb +66 -24
  141. data/lib/rbs/cli/diff.rb +16 -15
  142. data/lib/rbs/cli/validate.rb +38 -106
  143. data/lib/rbs/cli.rb +55 -24
  144. data/lib/rbs/collection/config/lockfile_generator.rb +28 -3
  145. data/lib/rbs/collection/sources/git.rb +7 -0
  146. data/lib/rbs/definition.rb +1 -1
  147. data/lib/rbs/definition_builder/ancestor_builder.rb +62 -9
  148. data/lib/rbs/definition_builder/method_builder.rb +32 -6
  149. data/lib/rbs/definition_builder.rb +147 -25
  150. data/lib/rbs/diff.rb +7 -1
  151. data/lib/rbs/environment.rb +235 -75
  152. data/lib/rbs/environment_loader.rb +0 -6
  153. data/lib/rbs/errors.rb +27 -18
  154. data/lib/rbs/inline_parser.rb +377 -15
  155. data/lib/rbs/location_aux.rb +1 -1
  156. data/lib/rbs/locator.rb +5 -1
  157. data/lib/rbs/method_type.rb +5 -3
  158. data/lib/rbs/namespace.rb +47 -11
  159. data/lib/rbs/parser_aux.rb +20 -7
  160. data/lib/rbs/prototype/helpers.rb +57 -0
  161. data/lib/rbs/prototype/rb.rb +3 -28
  162. data/lib/rbs/prototype/rbi.rb +3 -20
  163. data/lib/rbs/prototype/runtime.rb +10 -0
  164. data/lib/rbs/resolver/constant_resolver.rb +2 -2
  165. data/lib/rbs/resolver/type_name_resolver.rb +120 -44
  166. data/lib/rbs/rewriter.rb +70 -0
  167. data/lib/rbs/subtractor.rb +3 -1
  168. data/lib/rbs/test/type_check.rb +25 -3
  169. data/lib/rbs/type_name.rb +34 -14
  170. data/lib/rbs/types.rb +88 -78
  171. data/lib/rbs/unit_test/type_assertions.rb +44 -8
  172. data/lib/rbs/validator.rb +2 -2
  173. data/lib/rbs/version.rb +1 -1
  174. data/lib/rbs/wasm/deserializer.rb +213 -0
  175. data/lib/rbs/wasm/location.rb +61 -0
  176. data/lib/rbs/wasm/parser.rb +137 -0
  177. data/lib/rbs/wasm/runtime.rb +217 -0
  178. data/lib/rbs/wasm/serialization_schema.rb +110 -0
  179. data/lib/rbs.rb +13 -2
  180. data/lib/rdoc/discover.rb +1 -1
  181. data/lib/rdoc_plugin/parser.rb +1 -1
  182. data/rbs.gemspec +24 -6
  183. data/schema/typeParam.json +17 -1
  184. data/sig/annotate/rdoc_annotater.rbs +12 -9
  185. data/sig/ast/ruby/annotations.rbs +364 -4
  186. data/sig/ast/ruby/comment_block.rbs +8 -0
  187. data/sig/ast/ruby/declarations.rbs +102 -4
  188. data/sig/ast/ruby/members.rbs +128 -2
  189. data/sig/buffer.rbs +19 -1
  190. data/sig/cli/diff.rbs +5 -11
  191. data/sig/cli/validate.rbs +12 -8
  192. data/sig/cli.rbs +18 -18
  193. data/sig/collection/config/lockfile_generator.rbs +2 -0
  194. data/sig/definition.rbs +6 -1
  195. data/sig/definition_builder.rbs +2 -0
  196. data/sig/environment.rbs +70 -12
  197. data/sig/errors.rbs +13 -14
  198. data/sig/inline_parser.rbs +41 -2
  199. data/sig/locator.rbs +0 -2
  200. data/sig/manifest.yaml +0 -2
  201. data/sig/method_builder.rbs +3 -1
  202. data/sig/namespace.rbs +20 -0
  203. data/sig/parser.rbs +41 -13
  204. data/sig/prototype/helpers.rbs +2 -0
  205. data/sig/resolver/type_name_resolver.rbs +36 -10
  206. data/sig/rewriter.rbs +45 -0
  207. data/sig/source.rbs +3 -3
  208. data/sig/type_param.rbs +13 -8
  209. data/sig/typename.rbs +15 -0
  210. data/sig/types.rbs +6 -7
  211. data/sig/unit_test/spy.rbs +0 -8
  212. data/sig/unit_test/type_assertions.rbs +15 -0
  213. data/sig/wasm/deserializer.rbs +66 -0
  214. data/sig/wasm/serialization_schema.rbs +13 -0
  215. data/src/ast.c +443 -162
  216. data/src/lexer.c +1415 -1313
  217. data/src/lexer.re +4 -0
  218. data/src/lexstate.c +63 -37
  219. data/src/location.c +7 -47
  220. data/src/parser.c +1032 -521
  221. data/src/serialize.c +958 -0
  222. data/src/string.c +0 -48
  223. data/src/util/rbs_allocator.c +89 -74
  224. data/src/util/rbs_assert.c +1 -1
  225. data/src/util/rbs_buffer.c +2 -2
  226. data/src/util/rbs_constant_pool.c +10 -14
  227. data/src/util/rbs_encoding.c +4 -8
  228. data/src/util/rbs_unescape.c +56 -20
  229. data/stdlib/abbrev/0/array.rbs +1 -1
  230. data/stdlib/bigdecimal/0/big_decimal.rbs +116 -98
  231. data/stdlib/bigdecimal-math/0/big_math.rbs +169 -8
  232. data/stdlib/cgi/0/core.rbs +9 -393
  233. data/stdlib/cgi/0/manifest.yaml +1 -0
  234. data/stdlib/cgi-escape/0/escape.rbs +171 -0
  235. data/stdlib/coverage/0/coverage.rbs +7 -4
  236. data/stdlib/csv/0/csv.rbs +5 -5
  237. data/stdlib/date/0/date.rbs +92 -79
  238. data/stdlib/date/0/date_time.rbs +25 -24
  239. data/stdlib/delegate/0/delegator.rbs +10 -7
  240. data/stdlib/did_you_mean/0/did_you_mean.rbs +17 -16
  241. data/stdlib/digest/0/digest.rbs +111 -1
  242. data/stdlib/erb/0/erb.rbs +748 -347
  243. data/stdlib/etc/0/etc.rbs +73 -54
  244. data/stdlib/fileutils/0/fileutils.rbs +179 -160
  245. data/stdlib/forwardable/0/forwardable.rbs +13 -10
  246. data/stdlib/io-console/0/io-console.rbs +2 -2
  247. data/stdlib/json/0/json.rbs +223 -142
  248. data/stdlib/monitor/0/monitor.rbs +3 -3
  249. data/stdlib/net-http/0/net-http.rbs +162 -134
  250. data/stdlib/objspace/0/objspace.rbs +17 -34
  251. data/stdlib/open-uri/0/open-uri.rbs +48 -8
  252. data/stdlib/open3/0/open3.rbs +469 -10
  253. data/stdlib/openssl/0/openssl.rbs +482 -364
  254. data/stdlib/optparse/0/optparse.rbs +26 -17
  255. data/stdlib/pathname/0/pathname.rbs +11 -1381
  256. data/stdlib/pp/0/pp.rbs +9 -8
  257. data/stdlib/prettyprint/0/prettyprint.rbs +7 -7
  258. data/stdlib/pstore/0/pstore.rbs +35 -30
  259. data/stdlib/psych/0/psych.rbs +65 -12
  260. data/stdlib/psych/0/store.rbs +2 -4
  261. data/stdlib/pty/0/pty.rbs +9 -6
  262. data/stdlib/random-formatter/0/random-formatter.rbs +277 -0
  263. data/stdlib/rdoc/0/code_object.rbs +2 -1
  264. data/stdlib/rdoc/0/parser.rbs +1 -1
  265. data/stdlib/rdoc/0/rdoc.rbs +1 -1
  266. data/stdlib/rdoc/0/store.rbs +1 -1
  267. data/stdlib/resolv/0/resolv.rbs +26 -69
  268. data/stdlib/ripper/0/ripper.rbs +22 -19
  269. data/stdlib/securerandom/0/manifest.yaml +2 -0
  270. data/stdlib/securerandom/0/securerandom.rbs +7 -20
  271. data/stdlib/shellwords/0/shellwords.rbs +3 -3
  272. data/stdlib/singleton/0/singleton.rbs +3 -0
  273. data/stdlib/socket/0/addrinfo.rbs +7 -7
  274. data/stdlib/socket/0/basic_socket.rbs +3 -3
  275. data/stdlib/socket/0/ip_socket.rbs +10 -8
  276. data/stdlib/socket/0/socket.rbs +23 -10
  277. data/stdlib/socket/0/tcp_server.rbs +1 -1
  278. data/stdlib/socket/0/tcp_socket.rbs +11 -3
  279. data/stdlib/socket/0/udp_socket.rbs +1 -1
  280. data/stdlib/socket/0/unix_server.rbs +1 -1
  281. data/stdlib/stringio/0/stringio.rbs +1209 -95
  282. data/stdlib/strscan/0/string_scanner.rbs +101 -80
  283. data/stdlib/tempfile/0/tempfile.rbs +25 -21
  284. data/stdlib/time/0/time.rbs +8 -6
  285. data/stdlib/timeout/0/timeout.rbs +63 -7
  286. data/stdlib/tsort/0/cyclic.rbs +4 -1
  287. data/stdlib/tsort/0/interfaces.rbs +8 -8
  288. data/stdlib/tsort/0/tsort.rbs +16 -15
  289. data/stdlib/uri/0/common.rbs +42 -20
  290. data/stdlib/uri/0/file.rbs +3 -3
  291. data/stdlib/uri/0/generic.rbs +26 -18
  292. data/stdlib/uri/0/http.rbs +2 -2
  293. data/stdlib/uri/0/ldap.rbs +2 -2
  294. data/stdlib/uri/0/mailto.rbs +3 -3
  295. data/stdlib/uri/0/rfc2396_parser.rbs +12 -12
  296. data/stdlib/zlib/0/deflate.rbs +4 -3
  297. data/stdlib/zlib/0/gzip_reader.rbs +8 -8
  298. data/stdlib/zlib/0/gzip_writer.rbs +14 -12
  299. data/stdlib/zlib/0/inflate.rbs +1 -1
  300. data/stdlib/zlib/0/need_dict.rbs +1 -1
  301. data/stdlib/zlib/0/zstream.rbs +1 -0
  302. data/wasm/README.md +59 -0
  303. data/wasm/rbs_wasm.c +411 -0
  304. metadata +56 -8
  305. data/.vscode/extensions.json +0 -5
  306. data/.vscode/settings.json +0 -19
@@ -11,6 +11,10 @@ module RBS
11
11
  @declarations = []
12
12
  @diagnostics = []
13
13
  end
14
+
15
+ def type_fingerprint
16
+ declarations.map(&:type_fingerprint)
17
+ end
14
18
  end
15
19
 
16
20
  module Diagnostic
@@ -26,15 +30,26 @@ module RBS
26
30
  NotImplementedYet = _ = Class.new(Base)
27
31
  NonConstantClassName = _ = Class.new(Base)
28
32
  NonConstantModuleName = _ = Class.new(Base)
33
+ NonConstantSuperClassName = _ = Class.new(Base)
29
34
  TopLevelMethodDefinition = _ = Class.new(Base)
35
+ TopLevelAttributeDefinition = _ = Class.new(Base)
36
+ NonConstantConstantDeclaration = _ = Class.new(Base)
30
37
  UnusedInlineAnnotation = _ = Class.new(Base)
31
38
  AnnotationSyntaxError = _ = Class.new(Base)
39
+ MixinMultipleArguments = _ = Class.new(Base)
40
+ MixinNonConstantModule = _ = Class.new(Base)
41
+ AttributeNonSymbolName = _ = Class.new(Base)
42
+ ClassModuleAliasDeclarationMissingTypeName = _ = Class.new(Base)
32
43
  end
33
44
 
34
45
  def self.parse(buffer, prism)
35
46
  result = Result.new(buffer, prism)
36
47
 
37
- Parser.new(result).visit(prism.value)
48
+ parser = Parser.new(result)
49
+ parser.visit(prism.value)
50
+ parser.comments.each_unassociated_block do |block|
51
+ parser.report_unused_block(block)
52
+ end
38
53
 
39
54
  result
40
55
  end
@@ -96,15 +111,15 @@ module RBS
96
111
  return
97
112
  end
98
113
 
99
- class_decl = AST::Ruby::Declarations::ClassDecl.new(buffer, class_name, node)
100
- insert_declaration(class_decl)
101
- push_module_nesting(class_decl) do
102
- visit_child_nodes(node)
114
+ # Parse super class if present
115
+ super_class = if node.superclass
116
+ node.inheritance_operator_loc or raise
117
+ parse_super_class(node.superclass, node.inheritance_operator_loc)
103
118
  end
104
119
 
105
- comments.each_enclosed_block(node) do |block|
106
- report_unused_block(block)
107
- end
120
+ class_decl = AST::Ruby::Declarations::ClassDecl.new(buffer, class_name, node, super_class)
121
+ insert_declaration(class_decl)
122
+ visit_class_or_module_body(class_decl, node)
108
123
  end
109
124
 
110
125
  def visit_module_node(node)
@@ -119,27 +134,84 @@ module RBS
119
134
  end
120
135
 
121
136
  module_decl = AST::Ruby::Declarations::ModuleDecl.new(buffer, module_name, node)
137
+
138
+ if leading_ref = comments.leading_block(node)
139
+ unused_annotations = [] #: Array[AST::Ruby::CommentBlock::AnnotationSyntaxError | AST::Ruby::Annotations::leading_annotation]
140
+
141
+ leading_ref.block.each_paragraph([]) do |paragraph|
142
+ case paragraph
143
+ when AST::Ruby::Annotations::ModuleSelfAnnotation
144
+ module_decl.members << AST::Ruby::Members::ModuleSelfMember.new(buffer, paragraph)
145
+ when Location
146
+ # Skip
147
+ when AST::Ruby::CommentBlock::AnnotationSyntaxError
148
+ unused_annotations << paragraph
149
+ when AST::Ruby::Annotations::SkipAnnotation
150
+ # Already handled by skip_node?
151
+ else
152
+ unused_annotations << paragraph
153
+ end
154
+ end
155
+
156
+ unless unused_annotations.empty?
157
+ report_unused_annotation(*unused_annotations)
158
+ end
159
+
160
+ leading_ref.associate!
161
+ end
162
+
122
163
  insert_declaration(module_decl)
123
- push_module_nesting(module_decl) do
164
+ visit_class_or_module_body(module_decl, node)
165
+ end
166
+
167
+ def visit_class_or_module_body(decl, node)
168
+ push_module_nesting(decl) do
124
169
  visit_child_nodes(node)
170
+
171
+ node.child_nodes.each do |child_node|
172
+ if child_node
173
+ comments.each_enclosed_block(child_node) do |block|
174
+ report_unused_block(block)
175
+ end
176
+ end
177
+ end
125
178
  end
126
179
 
127
180
  comments.each_enclosed_block(node) do |block|
128
- report_unused_block(block)
181
+ unused_annotations = [] #: Array[AST::Ruby::CommentBlock::AnnotationSyntaxError | AST::Ruby::Annotations::leading_annotation]
182
+
183
+ block.each_paragraph([]) do |paragraph|
184
+ case paragraph
185
+ when AST::Ruby::Annotations::InstanceVariableAnnotation
186
+ decl.members << AST::Ruby::Members::InstanceVariableMember.new(buffer, paragraph)
187
+ when Location
188
+ # Skip
189
+ when AST::Ruby::CommentBlock::AnnotationSyntaxError
190
+ unused_annotations << paragraph
191
+ else
192
+ unused_annotations << paragraph
193
+ end
194
+ end
195
+
196
+ report_unused_annotation(*unused_annotations)
129
197
  end
198
+
199
+ decl.members.sort_by! { _1.location.start_line }
130
200
  end
131
201
 
132
202
  def visit_def_node(node)
133
203
  return if skip_node?(node)
134
204
 
135
- if node.receiver
205
+ if node.receiver && !node.receiver.is_a?(Prism::SelfNode)
136
206
  diagnostics << Diagnostic::NotImplementedYet.new(
137
207
  rbs_location(node.receiver.location),
138
- "Singleton method definition is not supported yet"
208
+ "Method definition with non-self receiver is not supported"
139
209
  )
140
210
  return
141
211
  end
142
212
 
213
+ kind = node.receiver ? :singleton : :instance #: :singleton | :instance
214
+
143
215
  case current = current_module
144
216
  when AST::Ruby::Declarations::ClassDecl, AST::Ruby::Declarations::ModuleDecl
145
217
  leading_block = comments.leading_block!(node)
@@ -150,15 +222,15 @@ module RBS
150
222
  trailing_block = comments.trailing_block!(end_loc)
151
223
  end
152
224
 
153
- method_type, leading_unuseds, trailing_unused = AST::Ruby::Members::MethodTypeAnnotation.build(leading_block, trailing_block, [])
225
+ method_type, leading_unuseds, trailing_unused = AST::Ruby::Members::MethodTypeAnnotation.build(leading_block, trailing_block, [], node)
154
226
  report_unused_annotation(trailing_unused, *leading_unuseds)
155
227
 
156
- defn = AST::Ruby::Members::DefMember.new(buffer, node.name, node, method_type)
228
+ defn = AST::Ruby::Members::DefMember.new(buffer, node.name, node, method_type, leading_block, kind: kind)
157
229
  current.members << defn
158
230
 
159
231
  # Skip other comments in `def` node
160
232
  comments.each_enclosed_block(node) do |block|
161
- comments.associated_blocks << block
233
+ report_unused_block(block)
162
234
  end
163
235
  else
164
236
  diagnostics << Diagnostic::TopLevelMethodDefinition.new(
@@ -168,6 +240,261 @@ module RBS
168
240
  end
169
241
  end
170
242
 
243
+ def visit_call_node(node)
244
+ return unless node.receiver.nil? # Only handle top-level calls like include, extend, prepend, attr_*
245
+
246
+ case node.name
247
+ when :include, :extend, :prepend
248
+ return if skip_node?(node)
249
+
250
+ case current = current_module
251
+ when AST::Ruby::Declarations::ClassDecl, AST::Ruby::Declarations::ModuleDecl
252
+ parse_mixin_call(node)
253
+ end
254
+ when :attr_reader, :attr_writer, :attr_accessor
255
+ return if skip_node?(node)
256
+
257
+ case current = current_module
258
+ when AST::Ruby::Declarations::ClassDecl, AST::Ruby::Declarations::ModuleDecl
259
+ parse_attribute_call(node)
260
+ when nil
261
+ # Top-level attribute definition
262
+ diagnostics << Diagnostic::TopLevelAttributeDefinition.new(
263
+ rbs_location(node.message_loc || node.location),
264
+ "Top-level attribute definition is not supported"
265
+ )
266
+ end
267
+ else
268
+ visit_child_nodes(node)
269
+ end
270
+ end
271
+
272
+ def visit_constant_write_node(node)
273
+ return if skip_node?(node)
274
+
275
+ # Parse constant declaration (both top-level and in classes/modules)
276
+ parse_constant_declaration(node)
277
+ end
278
+
279
+ def visit_constant_path_write_node(node)
280
+ return if skip_node?(node)
281
+
282
+ parse_constant_declaration(node)
283
+ end
284
+
285
+ def parse_mixin_call(node)
286
+ # Check for multiple arguments
287
+ if node.arguments && node.arguments.arguments.length > 1
288
+ diagnostics << Diagnostic::MixinMultipleArguments.new(
289
+ rbs_location(node.location),
290
+ "Mixing multiple modules with one call is not supported"
291
+ )
292
+ return
293
+ end
294
+
295
+ # Check for missing arguments
296
+ unless node.arguments && node.arguments.arguments.length == 1
297
+ # This shouldn't happen in valid Ruby code, but handle it gracefully
298
+ return
299
+ end
300
+
301
+ first_arg = node.arguments.arguments.first
302
+
303
+ # Check if the argument is a constant
304
+ unless module_name = constant_as_type_name(first_arg)
305
+ diagnostics << Diagnostic::MixinNonConstantModule.new(
306
+ rbs_location(first_arg.location),
307
+ "Module name must be a constant"
308
+ )
309
+ return
310
+ end
311
+
312
+ # Look for type application annotation in trailing comments
313
+ # For single-line calls like "include Bar #[String]", the annotation is trailing
314
+ trailing_block = comments.trailing_block!(node.location)
315
+ annotation = nil
316
+
317
+ if trailing_block
318
+ case trailing_annotation = trailing_block.trailing_annotation([])
319
+ when AST::Ruby::Annotations::TypeApplicationAnnotation
320
+ annotation = trailing_annotation
321
+ else
322
+ report_unused_annotation(trailing_annotation)
323
+ end
324
+ end
325
+
326
+ # Create the appropriate member based on the method name
327
+ member = case node.name
328
+ when :include
329
+ AST::Ruby::Members::IncludeMember.new(buffer, node, module_name, annotation)
330
+ when :extend
331
+ AST::Ruby::Members::ExtendMember.new(buffer, node, module_name, annotation)
332
+ when :prepend
333
+ AST::Ruby::Members::PrependMember.new(buffer, node, module_name, annotation)
334
+ else
335
+ raise "Unexpected mixin method: #{node.name}"
336
+ end
337
+
338
+ current_module!.members << member
339
+ end
340
+
341
+ def parse_attribute_call(node)
342
+ # Get the name nodes (arguments to attr_*)
343
+ unless node.arguments && !node.arguments.arguments.empty?
344
+ return # No arguments, nothing to do
345
+ end
346
+
347
+ name_nodes = [] #: Array[Prism::SymbolNode]
348
+ node.arguments.arguments.each do |arg|
349
+ case arg
350
+ when Prism::SymbolNode
351
+ name_nodes << arg
352
+ else
353
+ # Non-symbol argument, report error
354
+ diagnostics << Diagnostic::AttributeNonSymbolName.new(
355
+ rbs_location(arg.location),
356
+ "Attribute name must be a symbol"
357
+ )
358
+ end
359
+ end
360
+
361
+ return if name_nodes.empty?
362
+
363
+ # Look for leading comment block
364
+ leading_block = comments.leading_block!(node)
365
+
366
+ # Look for trailing type annotation (#: Type)
367
+ trailing_block = comments.trailing_block!(node.location)
368
+ type_annotation = nil
369
+
370
+ if trailing_block
371
+ case annotation = trailing_block.trailing_annotation([])
372
+ when AST::Ruby::Annotations::NodeTypeAssertion
373
+ type_annotation = annotation
374
+ when AST::Ruby::CommentBlock::AnnotationSyntaxError
375
+ diagnostics << Diagnostic::AnnotationSyntaxError.new(
376
+ annotation.location, "Syntax error: " + annotation.error.error_message
377
+ )
378
+ end
379
+ end
380
+
381
+ # Report unused leading annotations since @rbs annotations are not used for attributes
382
+ if leading_block
383
+ report_unused_block(leading_block)
384
+ end
385
+
386
+ # Create the appropriate member type
387
+ member = case node.name
388
+ when :attr_reader
389
+ AST::Ruby::Members::AttrReaderMember.new(buffer, node, name_nodes, leading_block, type_annotation)
390
+ when :attr_writer
391
+ AST::Ruby::Members::AttrWriterMember.new(buffer, node, name_nodes, leading_block, type_annotation)
392
+ when :attr_accessor
393
+ AST::Ruby::Members::AttrAccessorMember.new(buffer, node, name_nodes, leading_block, type_annotation)
394
+ else
395
+ raise "Unexpected attribute method: #{node.name}"
396
+ end
397
+
398
+ current_module!.members << member
399
+ end
400
+
401
+ def parse_constant_declaration(node)
402
+ # Create TypeName for the constant
403
+ unless constant_name = constant_as_type_name(node)
404
+ location =
405
+ case node
406
+ when Prism::ConstantWriteNode
407
+ node.name_loc
408
+ when Prism::ConstantPathWriteNode
409
+ node.target.location
410
+ end
411
+
412
+ diagnostics << Diagnostic::NonConstantConstantDeclaration.new(
413
+ rbs_location(location),
414
+ "Constant name must be a constant"
415
+ )
416
+ return
417
+ end
418
+
419
+ # Look for leading comment block
420
+ leading_block = comments.leading_block!(node)
421
+ report_unused_block(leading_block) if leading_block
422
+
423
+ # Look for trailing type annotation (#: Type)
424
+ trailing_block = comments.trailing_block!(node.location)
425
+ type_annotation = nil
426
+ alias_annotation = nil
427
+
428
+ if trailing_block
429
+ case annotation = trailing_block.trailing_annotation([])
430
+ when AST::Ruby::Annotations::NodeTypeAssertion
431
+ type_annotation = annotation
432
+ when AST::Ruby::Annotations::ClassAliasAnnotation, AST::Ruby::Annotations::ModuleAliasAnnotation
433
+ alias_annotation = annotation
434
+ when AST::Ruby::CommentBlock::AnnotationSyntaxError
435
+ diagnostics << Diagnostic::AnnotationSyntaxError.new(
436
+ annotation.location, "Syntax error: " + annotation.error.error_message
437
+ )
438
+ end
439
+ end
440
+
441
+ # Handle class/module alias declarations
442
+ if alias_annotation
443
+ # Try to infer the old name from the right-hand side
444
+ infered_old_name = constant_as_type_name(node.value)
445
+
446
+ # Check if we have either an explicit type name or can infer one
447
+ if alias_annotation.type_name.nil? && infered_old_name.nil?
448
+ message =
449
+ if alias_annotation.is_a?(AST::Ruby::Annotations::ClassAliasAnnotation)
450
+ "Class name is missing in class alias declaration"
451
+ else
452
+ "Module name is missing in module alias declaration"
453
+ end
454
+
455
+ diagnostics << Diagnostic::ClassModuleAliasDeclarationMissingTypeName.new(
456
+ alias_annotation.location,
457
+ message
458
+ )
459
+ return
460
+ end
461
+
462
+ # Create class/module alias declaration
463
+ alias_decl = AST::Ruby::Declarations::ClassModuleAliasDecl.new(
464
+ buffer,
465
+ node,
466
+ constant_name,
467
+ infered_old_name,
468
+ leading_block,
469
+ alias_annotation
470
+ )
471
+
472
+ # Insert the alias declaration appropriately
473
+
474
+ if current_module
475
+ current_module.members << alias_decl
476
+ else
477
+ result.declarations << alias_decl
478
+ end
479
+ else
480
+ # Create regular constant declaration
481
+ constant_decl = AST::Ruby::Declarations::ConstantDecl.new(
482
+ buffer,
483
+ constant_name,
484
+ node,
485
+ leading_block,
486
+ type_annotation
487
+ )
488
+
489
+ # Insert the constant declaration appropriately
490
+ if current_module
491
+ current_module.members << constant_decl
492
+ else
493
+ result.declarations << constant_decl
494
+ end
495
+ end
496
+ end
497
+
171
498
  def insert_declaration(decl)
172
499
  if current_module
173
500
  current_module.members << decl
@@ -192,6 +519,8 @@ module RBS
192
519
  end
193
520
 
194
521
  def report_unused_block(block)
522
+ return unless block.leading?
523
+
195
524
  block.each_paragraph([]) do |paragraph|
196
525
  case paragraph
197
526
  when Location
@@ -201,6 +530,39 @@ module RBS
201
530
  end
202
531
  end
203
532
  end
533
+
534
+ def parse_super_class(super_class_expr, inheritance_operator_loc)
535
+ # Check if the superclass is a constant
536
+ unless super_class_name = constant_as_type_name(super_class_expr)
537
+ diagnostics << Diagnostic::NonConstantSuperClassName.new(
538
+ rbs_location(super_class_expr.location),
539
+ "Super class name must be a constant"
540
+ )
541
+ return nil
542
+ end
543
+
544
+ # Look for type application annotation in trailing comments
545
+ # For example: class StringArray < Array #[String]
546
+ trailing_block = comments.trailing_block!(super_class_expr.location)
547
+ type_annotation = nil
548
+
549
+ if trailing_block
550
+ case annotation = trailing_block.trailing_annotation([])
551
+ when AST::Ruby::Annotations::TypeApplicationAnnotation
552
+ type_annotation = annotation
553
+ else
554
+ report_unused_annotation(annotation)
555
+ end
556
+ end
557
+
558
+ # Create SuperClass object
559
+ AST::Ruby::Declarations::ClassDecl::SuperClass.new(
560
+ rbs_location(super_class_expr.location),
561
+ rbs_location(inheritance_operator_loc),
562
+ super_class_name,
563
+ type_annotation
564
+ )
565
+ end
204
566
  end
205
567
  end
206
568
  end
@@ -83,7 +83,7 @@ module RBS
83
83
  other.end_pos == end_pos
84
84
  end
85
85
 
86
- def to_json(state = _ = nil)
86
+ def to_json(state = nil)
87
87
  {
88
88
  start: {
89
89
  line: start_line,
data/lib/rbs/locator.rb CHANGED
@@ -177,6 +177,10 @@ module RBS
177
177
  find_in_type(pos, type: upper_bound, array: array) and return true
178
178
  end
179
179
 
180
+ if lower_bound = type_param.lower_bound_type
181
+ find_in_type(pos, type: lower_bound, array: array) and return true
182
+ end
183
+
180
184
  if default_type = type_param.default_type
181
185
  find_in_type(pos, type: default_type, array: array) and return true
182
186
  end
@@ -234,7 +238,7 @@ module RBS
234
238
 
235
239
  def test_loc(pos, location:)
236
240
  if location
237
- location.range === pos
241
+ location.start_pos <= pos && pos <= location.end_pos
238
242
  else
239
243
  false
240
244
  end
@@ -21,7 +21,7 @@ module RBS
21
21
  other.block == block
22
22
  end
23
23
 
24
- def to_json(state = _ = nil)
24
+ def to_json(state = nil)
25
25
  {
26
26
  type_params: type_params,
27
27
  type: type,
@@ -129,11 +129,13 @@ module RBS
129
129
  end
130
130
 
131
131
  def with_nonreturn_void?
132
- if type.with_nonreturn_void?
132
+ if type.with_nonreturn_void? # steep:ignore DeprecatedReference
133
133
  true
134
134
  else
135
135
  if block = block()
136
- block.type.with_nonreturn_void? || block.self_type&.with_nonreturn_void? || false
136
+ block.type.with_nonreturn_void? || # steep:ignore DeprecatedReference
137
+ block.self_type&.with_nonreturn_void? || # steep:ignore DeprecatedReference
138
+ false
137
139
  else
138
140
  false
139
141
  end
data/lib/rbs/namespace.rb CHANGED
@@ -9,30 +9,65 @@ module RBS
9
9
  @absolute = absolute ? true : false
10
10
  end
11
11
 
12
+ # Process-wide flyweight cache. Two tries (one per `absolute` flag)
13
+ # keyed on path Symbols, with the cached Namespace stored under the
14
+ # `INTERN_LEAF` sentinel at each path's terminal node.
15
+ @intern_mutex = Mutex.new
16
+ @intern_trie_absolute = {}
17
+ @intern_trie_relative = {}
18
+ INTERN_LEAF = Module.new
19
+
20
+ # Returns a canonical `Namespace` instance for the given `path` /
21
+ # `absolute` pair. Repeated calls with structurally equal arguments
22
+ # return the same object, so callers can rely on `equal?` for fast
23
+ # equality. The path Array is duplicated and frozen on insert.
24
+ def self.[](path, absolute)
25
+ absolute = absolute ? true : false
26
+
27
+ # Lock-free fast path.
28
+ node = absolute ? @intern_trie_absolute : @intern_trie_relative
29
+ path.each do |sym|
30
+ node = node[sym]
31
+ break unless node
32
+ end
33
+ if node && (cached = node[INTERN_LEAF])
34
+ return cached
35
+ end
36
+
37
+ @intern_mutex.synchronize do
38
+ node = absolute ? @intern_trie_absolute : @intern_trie_relative
39
+ path.each { |sym| node = (node[sym] ||= {}) }
40
+ node[INTERN_LEAF] ||= begin
41
+ frozen_path = path.frozen? ? path : path.dup.freeze
42
+ new(path: frozen_path, absolute: absolute)
43
+ end
44
+ end
45
+ end
46
+
12
47
  def self.empty
13
- @empty ||= new(path: [], absolute: false)
48
+ @empty ||= self[[], false]
14
49
  end
15
50
 
16
51
  def self.root
17
- @root ||= new(path: [], absolute: true)
52
+ @root ||= self[[], true]
18
53
  end
19
54
 
20
55
  def +(other)
21
56
  if other.absolute?
22
57
  other
23
58
  else
24
- self.class.new(path: path + other.path, absolute: absolute?)
59
+ Namespace[path + other.path, absolute?]
25
60
  end
26
61
  end
27
62
 
28
63
  def append(component)
29
- self.class.new(path: path + [component], absolute: absolute?)
64
+ Namespace[path + [component], absolute?]
30
65
  end
31
66
 
32
67
  def parent
33
68
  @parent ||= begin
34
69
  raise "Parent with empty namespace" if empty?
35
- self.class.new(path: path.take(path.size - 1), absolute: absolute?)
70
+ Namespace[path.take(path.size - 1), absolute?]
36
71
  end
37
72
  end
38
73
 
@@ -45,11 +80,11 @@ module RBS
45
80
  end
46
81
 
47
82
  def absolute!
48
- self.class.new(path: path, absolute: true)
83
+ Namespace[path, true]
49
84
  end
50
85
 
51
86
  def relative!
52
- self.class.new(path: path, absolute: false)
87
+ Namespace[path, false]
53
88
  end
54
89
 
55
90
  def empty?
@@ -57,13 +92,14 @@ module RBS
57
92
  end
58
93
 
59
94
  def ==(other)
95
+ return true if equal?(other)
60
96
  other.is_a?(Namespace) && other.path == path && other.absolute? == absolute?
61
97
  end
62
98
 
63
99
  alias eql? ==
64
100
 
65
101
  def hash
66
- path.hash ^ absolute?.hash
102
+ @hash ||= path.hash ^ absolute?.hash
67
103
  end
68
104
 
69
105
  def split
@@ -87,14 +123,14 @@ module RBS
87
123
  raise unless name
88
124
  raise unless parent
89
125
 
90
- TypeName.new(name: name, namespace: parent)
126
+ TypeName[parent, name]
91
127
  end
92
128
 
93
129
  def self.parse(string)
94
130
  if string.start_with?("::")
95
- new(path: string.split("::").drop(1).map(&:to_sym), absolute: true)
131
+ self[string.split("::").drop(1).map(&:to_sym), true]
96
132
  else
97
- new(path: string.split("::").map(&:to_sym), absolute: false)
133
+ self[string.split("::").map(&:to_sym), false]
98
134
  end
99
135
  end
100
136