rbs 4.0.3 → 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 (125) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/c-check.yml +3 -0
  3. data/.github/workflows/dependabot.yml +1 -1
  4. data/.github/workflows/jruby.yml +67 -0
  5. data/.github/workflows/milestone.yml +4 -1
  6. data/.github/workflows/ruby.yml +40 -0
  7. data/.github/workflows/rust.yml +3 -2
  8. data/.github/workflows/truffleruby.yml +54 -0
  9. data/.github/workflows/typecheck.yml +3 -0
  10. data/.github/workflows/wasm.yml +53 -0
  11. data/.github/workflows/windows.yml +3 -0
  12. data/.gitignore +7 -0
  13. data/CHANGELOG.md +0 -8
  14. data/README.md +3 -3
  15. data/Rakefile +118 -3
  16. data/Steepfile +7 -0
  17. data/config.yml +24 -0
  18. data/core/array.rbs +144 -144
  19. data/core/builtin.rbs +7 -6
  20. data/core/class.rbs +5 -3
  21. data/core/enumerable.rbs +109 -109
  22. data/core/enumerator/product.rbs +5 -5
  23. data/core/enumerator.rbs +28 -28
  24. data/core/file.rbs +24 -1018
  25. data/core/file_constants.rbs +463 -0
  26. data/core/file_stat.rbs +534 -0
  27. data/core/hash.rbs +117 -101
  28. data/core/integer.rbs +21 -58
  29. data/core/io.rbs +25 -7
  30. data/core/kernel.rbs +26 -11
  31. data/core/module.rbs +88 -74
  32. data/core/numeric.rbs +3 -0
  33. data/core/object_space/weak_key_map.rbs +7 -7
  34. data/core/range.rbs +23 -23
  35. data/core/rbs/ops.rbs +154 -0
  36. data/core/rbs/unnamed/argf.rbs +3 -3
  37. data/core/ruby_vm.rbs +40 -0
  38. data/core/set.rbs +3 -3
  39. data/core/struct.rbs +16 -16
  40. data/core/thread.rbs +6 -6
  41. data/docs/CONTRIBUTING.md +2 -1
  42. data/docs/inline.md +65 -7
  43. data/docs/rbs_by_example.md +20 -20
  44. data/docs/syntax.md +2 -2
  45. data/docs/wasm_serialization.md +80 -0
  46. data/ext/rbs_extension/ast_translation.c +1298 -956
  47. data/ext/rbs_extension/ast_translation.h +4 -0
  48. data/ext/rbs_extension/class_constants.c +2 -0
  49. data/ext/rbs_extension/class_constants.h +1 -0
  50. data/ext/rbs_extension/extconf.rb +1 -0
  51. data/ext/rbs_extension/main.c +139 -4
  52. data/include/rbs/ast.h +323 -298
  53. data/include/rbs/defines.h +13 -0
  54. data/include/rbs/lexer.h +1 -0
  55. data/include/rbs/serialize.h +39 -0
  56. data/lib/rbs/annotate/rdoc_annotator.rb +27 -31
  57. data/lib/rbs/ast/ruby/annotations.rb +42 -0
  58. data/lib/rbs/ast/ruby/comment_block.rb +6 -4
  59. data/lib/rbs/ast/ruby/declarations.rb +11 -1
  60. data/lib/rbs/ast/ruby/helpers/location_helper.rb +1 -1
  61. data/lib/rbs/ast/ruby/members.rb +40 -1
  62. data/lib/rbs/buffer.rb +48 -11
  63. data/lib/rbs/cli.rb +3 -5
  64. data/lib/rbs/collection/config/lockfile_generator.rb +14 -1
  65. data/lib/rbs/collection/sources/git.rb +6 -0
  66. data/lib/rbs/definition_builder/method_builder.rb +12 -6
  67. data/lib/rbs/environment.rb +10 -3
  68. data/lib/rbs/inline_parser.rb +54 -28
  69. data/lib/rbs/namespace.rb +47 -11
  70. data/lib/rbs/prototype/runtime.rb +2 -0
  71. data/lib/rbs/resolver/type_name_resolver.rb +12 -14
  72. data/lib/rbs/rewriter.rb +70 -0
  73. data/lib/rbs/test/type_check.rb +6 -1
  74. data/lib/rbs/type_name.rb +33 -13
  75. data/lib/rbs/unit_test/type_assertions.rb +9 -0
  76. data/lib/rbs/version.rb +1 -1
  77. data/lib/rbs/wasm/deserializer.rb +213 -0
  78. data/lib/rbs/wasm/location.rb +61 -0
  79. data/lib/rbs/wasm/parser.rb +137 -0
  80. data/lib/rbs/wasm/runtime.rb +217 -0
  81. data/lib/rbs/wasm/serialization_schema.rb +110 -0
  82. data/lib/rbs.rb +14 -2
  83. data/rbs.gemspec +19 -2
  84. data/sig/annotate/rdoc_annotater.rbs +12 -9
  85. data/sig/ast/ruby/annotations.rbs +49 -0
  86. data/sig/ast/ruby/members.rbs +21 -1
  87. data/sig/buffer.rbs +19 -1
  88. data/sig/collection/config/lockfile_generator.rbs +2 -0
  89. data/sig/inline_parser.rbs +2 -0
  90. data/sig/manifest.yaml +0 -1
  91. data/sig/namespace.rbs +20 -0
  92. data/sig/parser.rbs +10 -0
  93. data/sig/resolver/type_name_resolver.rbs +2 -4
  94. data/sig/rewriter.rbs +45 -0
  95. data/sig/typename.rbs +15 -0
  96. data/sig/unit_test/type_assertions.rbs +4 -0
  97. data/sig/wasm/deserializer.rbs +66 -0
  98. data/sig/wasm/serialization_schema.rbs +13 -0
  99. data/src/ast.c +186 -162
  100. data/src/lexer.c +137 -114
  101. data/src/lexer.re +1 -0
  102. data/src/lexstate.c +6 -1
  103. data/src/parser.c +55 -5
  104. data/src/serialize.c +958 -0
  105. data/src/util/rbs_allocator.c +1 -4
  106. data/stdlib/abbrev/0/array.rbs +1 -1
  107. data/stdlib/csv/0/csv.rbs +5 -5
  108. data/stdlib/digest/0/digest.rbs +1 -1
  109. data/stdlib/etc/0/etc.rbs +18 -4
  110. data/stdlib/fileutils/0/fileutils.rbs +21 -21
  111. data/stdlib/json/0/json.rbs +6 -6
  112. data/stdlib/openssl/0/openssl.rbs +7 -7
  113. data/stdlib/resolv/0/resolv.rbs +1 -1
  114. data/stdlib/shellwords/0/shellwords.rbs +1 -1
  115. data/stdlib/stringio/0/stringio.rbs +32 -10
  116. data/stdlib/strscan/0/string_scanner.rbs +74 -55
  117. data/stdlib/tsort/0/cyclic.rbs +1 -1
  118. data/stdlib/tsort/0/interfaces.rbs +8 -8
  119. data/stdlib/tsort/0/tsort.rbs +9 -9
  120. data/stdlib/zlib/0/gzip_reader.rbs +2 -2
  121. data/wasm/README.md +59 -0
  122. data/wasm/rbs_wasm.c +411 -0
  123. metadata +23 -5
  124. data/.vscode/extensions.json +0 -5
  125. data/.vscode/settings.json +0 -19
@@ -119,7 +119,53 @@ module RBS
119
119
 
120
120
  class_decl = AST::Ruby::Declarations::ClassDecl.new(buffer, class_name, node, super_class)
121
121
  insert_declaration(class_decl)
122
- push_module_nesting(class_decl) do
122
+ visit_class_or_module_body(class_decl, node)
123
+ end
124
+
125
+ def visit_module_node(node)
126
+ return if skip_node?(node)
127
+
128
+ unless module_name = constant_as_type_name(node.constant_path)
129
+ diagnostics << Diagnostic::NonConstantModuleName.new(
130
+ rbs_location(node.constant_path.location),
131
+ "Module name must be a constant"
132
+ )
133
+ return
134
+ end
135
+
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
+
163
+ insert_declaration(module_decl)
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
123
169
  visit_child_nodes(node)
124
170
 
125
171
  node.child_nodes.each do |child_node|
@@ -137,7 +183,7 @@ module RBS
137
183
  block.each_paragraph([]) do |paragraph|
138
184
  case paragraph
139
185
  when AST::Ruby::Annotations::InstanceVariableAnnotation
140
- class_decl.members << AST::Ruby::Members::InstanceVariableMember.new(buffer, paragraph)
186
+ decl.members << AST::Ruby::Members::InstanceVariableMember.new(buffer, paragraph)
141
187
  when Location
142
188
  # Skip
143
189
  when AST::Ruby::CommentBlock::AnnotationSyntaxError
@@ -150,42 +196,22 @@ module RBS
150
196
  report_unused_annotation(*unused_annotations)
151
197
  end
152
198
 
153
- class_decl.members.sort_by! { _1.location.start_line }
154
- end
155
-
156
- def visit_module_node(node)
157
- return if skip_node?(node)
158
-
159
- unless module_name = constant_as_type_name(node.constant_path)
160
- diagnostics << Diagnostic::NonConstantModuleName.new(
161
- rbs_location(node.constant_path.location),
162
- "Module name must be a constant"
163
- )
164
- return
165
- end
166
-
167
- module_decl = AST::Ruby::Declarations::ModuleDecl.new(buffer, module_name, node)
168
- insert_declaration(module_decl)
169
- push_module_nesting(module_decl) do
170
- visit_child_nodes(node)
171
- end
172
-
173
- comments.each_enclosed_block(node) do |block|
174
- report_unused_block(block)
175
- end
199
+ decl.members.sort_by! { _1.location.start_line }
176
200
  end
177
201
 
178
202
  def visit_def_node(node)
179
203
  return if skip_node?(node)
180
204
 
181
- if node.receiver
205
+ if node.receiver && !node.receiver.is_a?(Prism::SelfNode)
182
206
  diagnostics << Diagnostic::NotImplementedYet.new(
183
207
  rbs_location(node.receiver.location),
184
- "Singleton method definition is not supported yet"
208
+ "Method definition with non-self receiver is not supported"
185
209
  )
186
210
  return
187
211
  end
188
212
 
213
+ kind = node.receiver ? :singleton : :instance #: :singleton | :instance
214
+
189
215
  case current = current_module
190
216
  when AST::Ruby::Declarations::ClassDecl, AST::Ruby::Declarations::ModuleDecl
191
217
  leading_block = comments.leading_block!(node)
@@ -199,7 +225,7 @@ module RBS
199
225
  method_type, leading_unuseds, trailing_unused = AST::Ruby::Members::MethodTypeAnnotation.build(leading_block, trailing_block, [], node)
200
226
  report_unused_annotation(trailing_unused, *leading_unuseds)
201
227
 
202
- defn = AST::Ruby::Members::DefMember.new(buffer, node.name, node, method_type, leading_block)
228
+ defn = AST::Ruby::Members::DefMember.new(buffer, node.name, node, method_type, leading_block, kind: kind)
203
229
  current.members << defn
204
230
 
205
231
  # Skip other comments in `def` node
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
 
@@ -77,6 +77,8 @@ module RBS
77
77
  attr_accessor :outline
78
78
 
79
79
  def initialize(patterns:, env:, merge:, todo: false, owners_included: [])
80
+ Kernel.warn("RBS::Prototype::Runtime is deprecated. See https://github.com/ruby/rbs/issues/2841")
81
+
80
82
  @patterns = patterns
81
83
  @decls = nil
82
84
  @modules = {}
@@ -29,11 +29,9 @@ module RBS
29
29
  new(all_names, aliases)
30
30
  end
31
31
 
32
- def try_cache(query)
33
- cache.fetch(query) do
34
- result = yield
35
- cache[query] = result
36
- end
32
+ def try_cache(type_name, context)
33
+ inner = cache[context] ||= {}
34
+ inner.fetch(type_name) { inner[type_name] = yield }
37
35
  end
38
36
 
39
37
  def resolve(type_name, context:)
@@ -41,7 +39,7 @@ module RBS
41
39
  return type_name
42
40
  end
43
41
 
44
- try_cache([type_name, context]) do
42
+ try_cache(type_name, context) do
45
43
  if type_name.class?
46
44
  resolve_namespace0(type_name, context, Set.new) || nil
47
45
  else
@@ -51,7 +49,7 @@ module RBS
51
49
  resolve_type_name(type_name.name, context)
52
50
  else
53
51
  if namespace = resolve_namespace0(namespace.to_type_name, context, Set.new)
54
- type_name = TypeName.new(name: type_name.name, namespace: namespace.to_namespace)
52
+ type_name = TypeName[namespace.to_namespace, type_name.name]
55
53
  has_type_name?(type_name)
56
54
  end
57
55
  end
@@ -68,7 +66,7 @@ module RBS
68
66
  raise "Type name must be a class name: #{type_name}"
69
67
  end
70
68
 
71
- try_cache([type_name, context]) do
69
+ try_cache(type_name, context) do
72
70
  ns = resolve_namespace0(type_name, context, Set.new) or return ns
73
71
  end
74
72
  end
@@ -93,10 +91,10 @@ module RBS
93
91
  resolve_type_name(type_name, outer)
94
92
  else
95
93
  has_type_name?(inner) or raise "Context must be normalized: #{inner.inspect}"
96
- has_type_name?(TypeName.new(name: type_name, namespace: inner.to_namespace)) || resolve_type_name(type_name, outer)
94
+ has_type_name?(TypeName[inner.to_namespace, type_name]) || resolve_type_name(type_name, outer)
97
95
  end
98
96
  else
99
- type_name = TypeName.new(name: type_name, namespace: Namespace.root)
97
+ type_name = TypeName[Namespace.root, type_name]
100
98
  has_type_name?(type_name)
101
99
  end
102
100
  end
@@ -109,11 +107,11 @@ module RBS
109
107
  resolve_head_namespace(head, outer)
110
108
  when TypeName
111
109
  has_type_name?(inner) or raise "Context must be normalized: #{inner.inspect}"
112
- type_name = TypeName.new(name: head, namespace: inner.to_namespace)
110
+ type_name = TypeName[inner.to_namespace, head]
113
111
  has_type_name?(type_name) || aliased_name?(type_name) || resolve_head_namespace(head, outer)
114
112
  end
115
113
  else
116
- type_name = TypeName.new(name: head, namespace: Namespace.root)
114
+ type_name = TypeName[Namespace.root, head]
117
115
  has_type_name?(type_name) || aliased_name?(type_name)
118
116
  end
119
117
  end
@@ -140,7 +138,7 @@ module RBS
140
138
 
141
139
  head =
142
140
  if type_name.absolute?
143
- root_name = TypeName.new(name: head, namespace: Namespace.root)
141
+ root_name = TypeName[Namespace.root, head]
144
142
  has_type_name?(root_name) || aliased_name?(root_name)
145
143
  else
146
144
  resolve_head_namespace(head, context)
@@ -152,7 +150,7 @@ module RBS
152
150
  end
153
151
 
154
152
  tail.inject(head) do |namespace, name|
155
- type_name = TypeName.new(name: name, namespace: namespace.to_namespace)
153
+ type_name = TypeName[namespace.to_namespace, name]
156
154
  case
157
155
  when has_type_name?(type_name)
158
156
  type_name
@@ -0,0 +1,70 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RBS
4
+ class Rewriter
5
+ attr_reader :buffer
6
+
7
+ def initialize(buffer)
8
+ raise "Rewriter only supports toplevel buffers" if buffer.parent
9
+
10
+ @buffer = buffer
11
+ @rewrites = []
12
+ end
13
+
14
+ def rewrite(location, string)
15
+ @rewrites.each do |existing_location, _|
16
+ if location.start_pos < existing_location.end_pos && existing_location.start_pos < location.end_pos
17
+ raise "Overlapping rewrites: #{existing_location} and #{location}"
18
+ end
19
+ end
20
+
21
+ @rewrites << [location, string]
22
+ self
23
+ end
24
+
25
+ def add_comment(*locations, content:)
26
+ earliest = locations.min_by(&:start_pos) or raise "At least one location is required"
27
+ insert_pos = earliest.start_pos
28
+ indent = " " * earliest.start_column
29
+
30
+ formatted = format_comment(content, indent)
31
+
32
+ loc = Location.new(buffer, insert_pos, insert_pos)
33
+ rewrite(loc, "#{formatted}\n#{indent}")
34
+ end
35
+
36
+ def replace_comment(comment, content:)
37
+ location = comment.location or raise "Comment must have a location"
38
+ indent = " " * location.start_column
39
+
40
+ rewrite(location, format_comment(content, indent))
41
+ end
42
+
43
+ def delete_comment(comment)
44
+ location = comment.location or raise "Comment must have a location"
45
+ line_start = location.start_pos - location.start_column
46
+ line_end = location.end_pos + 1
47
+ loc = Location.new(buffer, line_start, line_end)
48
+ rewrite(loc, "")
49
+ end
50
+
51
+ def string
52
+ result = buffer.content.dup
53
+
54
+ @rewrites.sort_by { |location, _| location.start_pos }.reverse_each do |location, replacement|
55
+ result[location.start_pos...location.end_pos] = replacement
56
+ end
57
+
58
+ result
59
+ end
60
+
61
+ private
62
+
63
+ def format_comment(content, indent)
64
+ content.lines.map do |line|
65
+ line = line.chomp
66
+ line.empty? ? "#" : "# #{line}"
67
+ end.join("\n#{indent}")
68
+ end
69
+ end
70
+ end
@@ -356,7 +356,12 @@ module RBS
356
356
  when Types::Variable
357
357
  true
358
358
  when Types::Literal
359
- type.literal == val
359
+ begin
360
+ type.literal == val
361
+ rescue NoMethodError
362
+ raise if defined?(val.==)
363
+ false
364
+ end
360
365
  when Types::Union
361
366
  type.types.any? {|type| value(val, type) }
362
367
  when Types::Intersection
data/lib/rbs/type_name.rb CHANGED
@@ -22,14 +22,40 @@ module RBS
22
22
  end
23
23
  end
24
24
 
25
+ # Process-wide flyweight cache. Two-level Hash keyed by canonical
26
+ # Namespace identity (outer uses `compare_by_identity`) and name
27
+ # Symbol.
28
+ @intern_mutex = Mutex.new
29
+ @intern_cache = {} #: Hash[Namespace, Hash[Symbol, TypeName]]
30
+ @intern_cache.compare_by_identity
31
+
32
+ # Returns a canonical `TypeName` instance for the given `namespace` /
33
+ # `name` pair. The namespace is canonicalized through `Namespace.[]`
34
+ # so identity-based lookup works regardless of the caller passing a
35
+ # fresh `Namespace.new` or an already-interned instance.
36
+ def self.[](namespace, name)
37
+ ns = Namespace[namespace.path, namespace.absolute?]
38
+
39
+ inner = @intern_cache[ns]
40
+ if inner && (cached = inner[name])
41
+ return cached
42
+ end
43
+
44
+ @intern_mutex.synchronize do
45
+ inner = (@intern_cache[ns] ||= {})
46
+ inner[name] ||= new(namespace: ns, name: name)
47
+ end
48
+ end
49
+
25
50
  def ==(other)
51
+ return true if equal?(other)
26
52
  other.is_a?(self.class) && other.namespace == namespace && other.name == name
27
53
  end
28
54
 
29
55
  alias eql? ==
30
56
 
31
57
  def hash
32
- namespace.hash ^ name.hash
58
+ @hash ||= namespace.hash ^ name.hash
33
59
  end
34
60
 
35
61
  def to_s
@@ -53,7 +79,7 @@ module RBS
53
79
  end
54
80
 
55
81
  def absolute!
56
- self.class.new(namespace: namespace.absolute!, name: name)
82
+ TypeName[namespace.absolute!, name]
57
83
  end
58
84
 
59
85
  def absolute?
@@ -61,7 +87,7 @@ module RBS
61
87
  end
62
88
 
63
89
  def relative!
64
- self.class.new(namespace: namespace.relative!, name: name)
90
+ TypeName[namespace.relative!, name]
65
91
  end
66
92
 
67
93
  def interface?
@@ -69,7 +95,7 @@ module RBS
69
95
  end
70
96
 
71
97
  def with_prefix(namespace)
72
- self.class.new(namespace: namespace + self.namespace, name: name)
98
+ TypeName[namespace + self.namespace, name]
73
99
  end
74
100
 
75
101
  def split
@@ -80,23 +106,17 @@ module RBS
80
106
  if other.absolute?
81
107
  other
82
108
  else
83
- TypeName.new(
84
- namespace: self.to_namespace + other.namespace,
85
- name: other.name
86
- )
109
+ TypeName[self.to_namespace + other.namespace, other.name]
87
110
  end
88
111
  end
89
-
112
+
90
113
  def self.parse(string)
91
114
  absolute = string.start_with?("::")
92
115
 
93
116
  *path, name = string.delete_prefix("::").split("::").map(&:to_sym)
94
117
  raise unless name
95
118
 
96
- TypeName.new(
97
- name: name,
98
- namespace: RBS::Namespace.new(path: path, absolute: absolute)
99
- )
119
+ TypeName[Namespace[path, absolute], name]
100
120
  end
101
121
  end
102
122
  end
@@ -323,6 +323,15 @@ module RBS
323
323
  assert typecheck.value(constant, definition_type), "`#{constant_name}` (#{constant.inspect}) must be compatible with RBS type definition `#{definition_type}`"
324
324
  end
325
325
 
326
+ def assert_visibility(visibility, method)
327
+ _, definition = target
328
+ method_entry = definition.methods[method]
329
+
330
+ assert method_entry, "Method `#{method}` not found in RBS definition"
331
+ assert visibility == method_entry.accessibility,
332
+ "Expected `#{method}` to be #{visibility}, but was #{method_entry.accessibility}"
333
+ end
334
+
326
335
  def assert_type(type, value)
327
336
  typecheck = RBS::Test::TypeCheck.new(
328
337
  self_class: value.class,
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.0.3"
4
+ VERSION = "4.1.0.pre.2"
5
5
  end