rbs 4.0.0.dev.5 → 4.0.1.dev.1

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 (194) hide show
  1. checksums.yaml +4 -4
  2. data/.clang-format +1 -0
  3. data/.github/workflows/c-check.yml +8 -4
  4. data/.github/workflows/comments.yml +3 -1
  5. data/.github/workflows/dependabot.yml +1 -1
  6. data/.github/workflows/ruby.yml +10 -0
  7. data/.github/workflows/rust.yml +95 -0
  8. data/CHANGELOG.md +323 -0
  9. data/Rakefile +12 -29
  10. data/Steepfile +1 -0
  11. data/config.yml +393 -37
  12. data/core/array.rbs +218 -188
  13. data/core/basic_object.rbs +9 -8
  14. data/core/class.rbs +6 -5
  15. data/core/comparable.rbs +45 -31
  16. data/core/complex.rbs +52 -40
  17. data/core/dir.rbs +57 -45
  18. data/core/encoding.rbs +5 -5
  19. data/core/enumerable.rbs +96 -91
  20. data/core/enumerator.rbs +4 -3
  21. data/core/errno.rbs +3 -2
  22. data/core/errors.rbs +31 -29
  23. data/core/exception.rbs +12 -12
  24. data/core/fiber.rbs +36 -36
  25. data/core/file.rbs +186 -113
  26. data/core/file_test.rbs +2 -2
  27. data/core/float.rbs +41 -32
  28. data/core/gc.rbs +78 -70
  29. data/core/hash.rbs +70 -60
  30. data/core/integer.rbs +32 -28
  31. data/core/io/buffer.rbs +36 -36
  32. data/core/io/wait.rbs +7 -7
  33. data/core/io.rbs +120 -135
  34. data/core/kernel.rbs +189 -139
  35. data/core/marshal.rbs +3 -3
  36. data/core/match_data.rbs +14 -12
  37. data/core/math.rbs +69 -67
  38. data/core/method.rbs +6 -6
  39. data/core/module.rbs +146 -85
  40. data/core/nil_class.rbs +4 -3
  41. data/core/numeric.rbs +35 -32
  42. data/core/object.rbs +6 -8
  43. data/core/object_space.rbs +11 -10
  44. data/core/pathname.rbs +131 -81
  45. data/core/proc.rbs +65 -33
  46. data/core/process.rbs +219 -201
  47. data/core/ractor.rbs +15 -11
  48. data/core/random.rbs +4 -3
  49. data/core/range.rbs +52 -47
  50. data/core/rational.rbs +5 -5
  51. data/core/rbs/unnamed/argf.rbs +58 -51
  52. data/core/rbs/unnamed/env_class.rbs +18 -13
  53. data/core/rbs/unnamed/main_class.rbs +123 -0
  54. data/core/rbs/unnamed/random.rbs +7 -5
  55. data/core/regexp.rbs +236 -197
  56. data/core/ruby.rbs +1 -1
  57. data/core/ruby_vm.rbs +32 -30
  58. data/core/rubygems/config_file.rbs +5 -5
  59. data/core/rubygems/errors.rbs +1 -1
  60. data/core/rubygems/requirement.rbs +5 -5
  61. data/core/rubygems/rubygems.rbs +5 -3
  62. data/core/set.rbs +17 -16
  63. data/core/signal.rbs +2 -2
  64. data/core/string.rbs +311 -292
  65. data/core/struct.rbs +26 -25
  66. data/core/symbol.rbs +25 -24
  67. data/core/thread.rbs +40 -34
  68. data/core/time.rbs +47 -42
  69. data/core/trace_point.rbs +34 -31
  70. data/core/true_class.rbs +2 -2
  71. data/core/unbound_method.rbs +10 -10
  72. data/core/warning.rbs +7 -7
  73. data/docs/collection.md +1 -1
  74. data/docs/config.md +171 -0
  75. data/docs/inline.md +110 -4
  76. data/docs/syntax.md +13 -12
  77. data/ext/rbs_extension/ast_translation.c +489 -135
  78. data/ext/rbs_extension/class_constants.c +8 -0
  79. data/ext/rbs_extension/class_constants.h +4 -0
  80. data/ext/rbs_extension/legacy_location.c +28 -51
  81. data/ext/rbs_extension/legacy_location.h +37 -0
  82. data/ext/rbs_extension/main.c +12 -20
  83. data/include/rbs/ast.h +423 -195
  84. data/include/rbs/lexer.h +2 -2
  85. data/include/rbs/location.h +25 -44
  86. data/include/rbs/parser.h +2 -2
  87. data/include/rbs/util/rbs_constant_pool.h +0 -3
  88. data/include/rbs.h +8 -0
  89. data/lib/rbs/ast/ruby/annotations.rb +157 -4
  90. data/lib/rbs/ast/ruby/members.rb +374 -22
  91. data/lib/rbs/cli/validate.rb +5 -60
  92. data/lib/rbs/collection/config/lockfile_generator.rb +6 -2
  93. data/lib/rbs/definition_builder.rb +60 -27
  94. data/lib/rbs/errors.rb +0 -11
  95. data/lib/rbs/inline_parser.rb +1 -1
  96. data/lib/rbs/parser_aux.rb +20 -7
  97. data/lib/rbs/prototype/helpers.rb +57 -0
  98. data/lib/rbs/prototype/rb.rb +1 -26
  99. data/lib/rbs/prototype/rbi.rb +1 -20
  100. data/lib/rbs/test/type_check.rb +3 -0
  101. data/lib/rbs/types.rb +62 -52
  102. data/lib/rbs/unit_test/type_assertions.rb +35 -8
  103. data/lib/rbs/version.rb +1 -1
  104. data/lib/rbs.rb +0 -1
  105. data/rbs.gemspec +1 -1
  106. data/rust/.gitignore +1 -0
  107. data/rust/Cargo.lock +378 -0
  108. data/rust/Cargo.toml +7 -0
  109. data/rust/ruby-rbs/Cargo.toml +22 -0
  110. data/rust/ruby-rbs/build.rs +764 -0
  111. data/rust/ruby-rbs/examples/locations.rs +60 -0
  112. data/rust/ruby-rbs/src/lib.rs +1 -0
  113. data/rust/ruby-rbs/src/node/mod.rs +742 -0
  114. data/rust/ruby-rbs/tests/sanity.rs +47 -0
  115. data/rust/ruby-rbs/vendor/rbs/config.yml +1 -0
  116. data/rust/ruby-rbs-sys/Cargo.toml +23 -0
  117. data/rust/ruby-rbs-sys/build.rs +204 -0
  118. data/rust/ruby-rbs-sys/src/lib.rs +50 -0
  119. data/rust/ruby-rbs-sys/vendor/rbs/include +1 -0
  120. data/rust/ruby-rbs-sys/vendor/rbs/src +1 -0
  121. data/rust/ruby-rbs-sys/wrapper.h +1 -0
  122. data/sig/ast/ruby/annotations.rbs +191 -4
  123. data/sig/ast/ruby/members.rbs +21 -1
  124. data/sig/cli/validate.rbs +1 -6
  125. data/sig/definition_builder.rbs +2 -0
  126. data/sig/errors.rbs +0 -8
  127. data/sig/method_types.rbs +1 -1
  128. data/sig/parser.rbs +17 -13
  129. data/sig/prototype/helpers.rbs +2 -0
  130. data/sig/types.rbs +10 -11
  131. data/sig/unit_test/spy.rbs +0 -8
  132. data/sig/unit_test/type_assertions.rbs +11 -0
  133. data/src/ast.c +339 -161
  134. data/src/lexstate.c +1 -1
  135. data/src/location.c +7 -47
  136. data/src/parser.c +674 -480
  137. data/src/util/rbs_constant_pool.c +0 -4
  138. data/stdlib/bigdecimal/0/big_decimal.rbs +16 -16
  139. data/stdlib/cgi-escape/0/escape.rbs +4 -4
  140. data/stdlib/coverage/0/coverage.rbs +4 -3
  141. data/stdlib/date/0/date.rbs +33 -28
  142. data/stdlib/date/0/date_time.rbs +24 -23
  143. data/stdlib/did_you_mean/0/did_you_mean.rbs +17 -16
  144. data/stdlib/erb/0/erb.rbs +64 -53
  145. data/stdlib/etc/0/etc.rbs +55 -50
  146. data/stdlib/fileutils/0/fileutils.rbs +138 -125
  147. data/stdlib/forwardable/0/forwardable.rbs +10 -10
  148. data/stdlib/io-console/0/io-console.rbs +2 -2
  149. data/stdlib/json/0/json.rbs +135 -108
  150. data/stdlib/monitor/0/monitor.rbs +3 -3
  151. data/stdlib/net-http/0/net-http.rbs +159 -134
  152. data/stdlib/objspace/0/objspace.rbs +8 -7
  153. data/stdlib/open-uri/0/open-uri.rbs +8 -8
  154. data/stdlib/open3/0/open3.rbs +36 -35
  155. data/stdlib/openssl/0/openssl.rbs +144 -129
  156. data/stdlib/optparse/0/optparse.rbs +18 -14
  157. data/stdlib/pathname/0/pathname.rbs +2 -2
  158. data/stdlib/pp/0/pp.rbs +9 -8
  159. data/stdlib/prettyprint/0/prettyprint.rbs +7 -7
  160. data/stdlib/pstore/0/pstore.rbs +35 -30
  161. data/stdlib/psych/0/psych.rbs +61 -8
  162. data/stdlib/psych/0/store.rbs +2 -4
  163. data/stdlib/pty/0/pty.rbs +9 -6
  164. data/stdlib/random-formatter/0/random-formatter.rbs +2 -2
  165. data/stdlib/ripper/0/ripper.rbs +20 -17
  166. data/stdlib/securerandom/0/securerandom.rbs +1 -1
  167. data/stdlib/shellwords/0/shellwords.rbs +2 -2
  168. data/stdlib/socket/0/addrinfo.rbs +7 -7
  169. data/stdlib/socket/0/basic_socket.rbs +3 -3
  170. data/stdlib/socket/0/ip_socket.rbs +10 -8
  171. data/stdlib/socket/0/socket.rbs +10 -9
  172. data/stdlib/socket/0/tcp_server.rbs +1 -1
  173. data/stdlib/socket/0/tcp_socket.rbs +1 -1
  174. data/stdlib/socket/0/udp_socket.rbs +1 -1
  175. data/stdlib/socket/0/unix_server.rbs +1 -1
  176. data/stdlib/stringio/0/stringio.rbs +55 -54
  177. data/stdlib/strscan/0/string_scanner.rbs +46 -44
  178. data/stdlib/tempfile/0/tempfile.rbs +24 -20
  179. data/stdlib/time/0/time.rbs +7 -5
  180. data/stdlib/tsort/0/tsort.rbs +7 -6
  181. data/stdlib/uri/0/common.rbs +26 -18
  182. data/stdlib/uri/0/file.rbs +2 -2
  183. data/stdlib/uri/0/generic.rbs +2 -2
  184. data/stdlib/uri/0/http.rbs +2 -2
  185. data/stdlib/uri/0/ldap.rbs +2 -2
  186. data/stdlib/uri/0/mailto.rbs +3 -3
  187. data/stdlib/uri/0/rfc2396_parser.rbs +6 -5
  188. data/stdlib/zlib/0/deflate.rbs +4 -3
  189. data/stdlib/zlib/0/gzip_reader.rbs +4 -4
  190. data/stdlib/zlib/0/gzip_writer.rbs +14 -12
  191. data/stdlib/zlib/0/inflate.rbs +1 -1
  192. data/stdlib/zlib/0/need_dict.rbs +1 -1
  193. metadata +23 -5
  194. data/.github/workflows/valgrind.yml +0 -42
@@ -398,6 +398,19 @@ module RBS
398
398
  .update(type_params: class_params + method_type.type_params)
399
399
  end
400
400
 
401
+ method_type = method_type.map_type do |type|
402
+ case type
403
+ when Types::Bases::Self
404
+ Types::ClassInstance.new(
405
+ name: type_name,
406
+ args: entry.type_params.map {|param| Types::Variable.new(name: param.name, location: param.location) },
407
+ location: nil
408
+ )
409
+ else
410
+ type
411
+ end
412
+ end
413
+
401
414
  method_type = method_type.update(
402
415
  type: method_type.type.with_return_type(
403
416
  Types::ClassInstance.new(
@@ -695,12 +708,14 @@ module RBS
695
708
  )
696
709
  end
697
710
 
711
+ accessibility = special_accessibility(original.instance?, original.new_name) || original_method.accessibility
712
+
698
713
  method_definition = Definition::Method.new(
699
714
  super_method: existing_method,
700
715
  defs: original_method.defs.map do |defn|
701
716
  defn.update(defined_in: defined_in, implemented_in: implemented_in)
702
717
  end,
703
- accessibility: original_method.accessibility,
718
+ accessibility: accessibility,
704
719
  alias_of: original_method,
705
720
  alias_member: original
706
721
  )
@@ -727,13 +742,9 @@ module RBS
727
742
  end
728
743
  end
729
744
 
730
- # @type var accessibility: RBS::Definition::accessibility
731
- accessibility =
732
- if original.instance? && [:initialize, :initialize_copy, :initialize_clone, :initialize_dup, :respond_to_missing?].include?(method.name)
733
- :private
734
- else
735
- method.accessibility
736
- end
745
+ # Respect the visibility of the original method definition.
746
+ accessibility = original.visibility || special_accessibility(original.instance?, method.name) || method.accessibility
747
+
737
748
  # Skip setting up `super_method` if `implemented_in` is `nil`, that means the type doesn't have implementation.
738
749
  # This typically happens if the type is an interface.
739
750
  if implemented_in
@@ -786,6 +797,9 @@ module RBS
786
797
  super_method = existing_method
787
798
  end
788
799
 
800
+ # Respect the visibility of the original method definition.
801
+ accessibility = original.visibility || special_accessibility(original.kind == :instance, method.name) || method.accessibility
802
+
789
803
  method_definition = Definition::Method.new(
790
804
  super_method: super_method,
791
805
  defs: [
@@ -796,7 +810,7 @@ module RBS
796
810
  implemented_in: implemented_in
797
811
  )
798
812
  ],
799
- accessibility: method.accessibility,
813
+ accessibility: accessibility,
800
814
  alias_of: nil,
801
815
  alias_member: nil
802
816
  )
@@ -864,27 +878,40 @@ module RBS
864
878
  )
865
879
  end
866
880
 
867
- defs = original.overloads.map do |overload|
868
- Definition::Method::TypeDef.new(
869
- type: subst.empty? ? overload.method_type : overload.method_type.sub(subst),
870
- member: original,
871
- defined_in: defined_in,
872
- implemented_in: implemented_in
873
- ).tap do |type_def|
874
- # Keep the original annotations given to overloads.
875
- type_def.overload_annotations.replace(overload.annotations)
881
+ if original.method_type.empty? && existing_method
882
+ # Unannotated method with a parent definition → inherit from the parent, like @rbs ...
883
+ method_definition = Definition::Method.new(
884
+ super_method: existing_method,
885
+ defs: existing_method.defs.map { |defn| defn.update(implemented_in: implemented_in) },
886
+ accessibility: :public,
887
+ alias_of: existing_method.alias_of,
888
+ alias_member: nil
889
+ )
890
+
891
+ method_definition.annotations.replace(existing_method.annotations)
892
+ else
893
+ defs = original.overloads.map do |overload|
894
+ Definition::Method::TypeDef.new(
895
+ type: subst.empty? ? overload.method_type : overload.method_type.sub(subst),
896
+ member: original,
897
+ defined_in: defined_in,
898
+ implemented_in: implemented_in
899
+ ).tap do |type_def|
900
+ # Keep the original annotations given to overloads.
901
+ type_def.overload_annotations.replace(overload.annotations)
902
+ end
876
903
  end
877
- end
878
904
 
879
- method_definition = Definition::Method.new(
880
- super_method: existing_method,
881
- defs: defs,
882
- accessibility: :public,
883
- alias_of: nil,
884
- alias_member: nil
885
- )
905
+ method_definition = Definition::Method.new(
906
+ super_method: existing_method,
907
+ defs: defs,
908
+ accessibility: :public,
909
+ alias_of: nil,
910
+ alias_member: nil
911
+ )
886
912
 
887
- method_definition.annotations.replace([])
913
+ method_definition.annotations.replace([])
914
+ end
888
915
 
889
916
  when nil
890
917
  # Overloading method definition only
@@ -943,6 +970,12 @@ module RBS
943
970
  methods[method.name] = method_definition
944
971
  end
945
972
 
973
+ def special_accessibility(is_instance, method_name)
974
+ if is_instance && [:initialize, :initialize_copy, :initialize_clone, :initialize_dup, :respond_to_missing?].include?(method_name)
975
+ :private
976
+ end
977
+ end
978
+
946
979
  def try_cache(type_name, cache:)
947
980
  cache[type_name] ||= yield
948
981
  end
data/lib/rbs/errors.rb CHANGED
@@ -611,17 +611,6 @@ module RBS
611
611
  end
612
612
  end
613
613
 
614
- class WillSyntaxError < DefinitionError
615
- include DetailedMessageable
616
-
617
- attr_reader :location
618
-
619
- def initialize(message, location:)
620
- super "#{Location.to_string(location)}: #{message}"
621
- @location = location
622
- end
623
- end
624
-
625
614
  class TypeParamDefaultReferenceError < DefinitionError
626
615
  include DetailedMessageable
627
616
 
@@ -196,7 +196,7 @@ module RBS
196
196
  trailing_block = comments.trailing_block!(end_loc)
197
197
  end
198
198
 
199
- method_type, leading_unuseds, trailing_unused = AST::Ruby::Members::MethodTypeAnnotation.build(leading_block, trailing_block, [])
199
+ method_type, leading_unuseds, trailing_unused = AST::Ruby::Members::MethodTypeAnnotation.build(leading_block, trailing_block, [], node)
200
200
  report_unused_annotation(trailing_unused, *leading_unuseds)
201
201
 
202
202
  defn = AST::Ruby::Members::DefMember.new(buffer, node.name, node, method_type, leading_block)
@@ -5,14 +5,16 @@ require_relative "parser/token"
5
5
 
6
6
  module RBS
7
7
  class Parser
8
- def self.parse_type(source, range: 0..., variables: [], require_eof: false, void_allowed: true, self_allowed: true)
8
+ def self.parse_type(source, range: nil, byte_range: 0..., variables: [], require_eof: false, void_allowed: true, self_allowed: true, classish_allowed: true)
9
9
  buf = buffer(source)
10
- _parse_type(buf, range.begin || 0, range.end || buf.last_position, variables, require_eof, void_allowed, self_allowed)
10
+ byte_range = byte_range(range, buf.content) if range
11
+ _parse_type(buf, byte_range.begin || 0, byte_range.end || buf.content.bytesize, variables, require_eof, void_allowed, self_allowed, classish_allowed)
11
12
  end
12
13
 
13
- def self.parse_method_type(source, range: 0..., variables: [], require_eof: false)
14
+ def self.parse_method_type(source, range: nil, byte_range: 0..., variables: [], require_eof: false)
14
15
  buf = buffer(source)
15
- _parse_method_type(buf, range.begin || 0, range.end || buf.last_position, variables, require_eof)
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)
16
18
  end
17
19
 
18
20
  def self.parse_signature(source)
@@ -25,7 +27,8 @@ module RBS
25
27
  else
26
28
  0
27
29
  end
28
- dirs, decls = _parse_signature(buf, start_pos, buf.last_position)
30
+ content = buf.content
31
+ dirs, decls = _parse_signature(buf, start_pos, content.bytesize)
29
32
 
30
33
  if resolved
31
34
  dirs = dirs.dup if dirs.frozen?
@@ -37,7 +40,7 @@ module RBS
37
40
 
38
41
  def self.parse_type_params(source, module_type_params: true)
39
42
  buf = buffer(source)
40
- _parse_type_params(buf, 0, buf.last_position, module_type_params)
43
+ _parse_type_params(buf, 0, buf.content.bytesize, module_type_params)
41
44
  end
42
45
 
43
46
  def self.magic_comment(buf)
@@ -66,7 +69,7 @@ module RBS
66
69
 
67
70
  def self.lex(source)
68
71
  buf = buffer(source)
69
- list = _lex(buf, buf.last_position)
72
+ list = _lex(buf, buf.content.bytesize)
70
73
  value = list.map do |type, location|
71
74
  Token.new(type: type, location: location)
72
75
  end
@@ -125,5 +128,15 @@ module RBS
125
128
  buf = buffer(source)
126
129
  _parse_inline_trailing_annotation(buf, range.begin || 0, range.end || buf.last_position, variables)
127
130
  end
131
+
132
+ def self.byte_range(char_range, content)
133
+ start_offset = char_range.begin
134
+ end_offset = char_range.end
135
+
136
+ start_prefix = content[0, start_offset] or raise if start_offset
137
+ end_prefix = content[0, end_offset] or raise if end_offset
138
+
139
+ start_prefix&.bytesize...end_prefix&.bytesize
140
+ end
128
141
  end
129
142
  end
@@ -5,6 +5,63 @@ module RBS
5
5
  module Helpers
6
6
  private
7
7
 
8
+ # Prism can't parse Ruby 3.2 code
9
+ if RUBY_VERSION >= "3.3"
10
+ def parse_comments(string, include_trailing:)
11
+ Prism.parse_comments(string, version: "current").yield_self do |prism_comments| # steep:ignore UnexpectedKeywordArgument
12
+ prism_comments.each_with_object({}) do |comment, hash| #$ Hash[Integer, AST::Comment]
13
+ # Skip EmbDoc comments
14
+ next unless comment.is_a?(Prism::InlineComment)
15
+ # skip like `module Foo # :nodoc:`
16
+ next if comment.trailing? && !include_trailing
17
+
18
+ line = comment.location.start_line
19
+ body = "#{comment.location.slice}\n"
20
+ body = body[2..-1] or raise
21
+ body = "\n" if body.empty?
22
+
23
+ comment = AST::Comment.new(string: body, location: nil)
24
+ if prev_comment = hash.delete(line - 1)
25
+ hash[line] = AST::Comment.new(string: prev_comment.string + comment.string,
26
+ location: nil)
27
+ else
28
+ hash[line] = comment
29
+ end
30
+ end
31
+ end
32
+ end
33
+ else
34
+ require "ripper"
35
+ def parse_comments(string, include_trailing:)
36
+ Ripper.lex(string).yield_self do |tokens|
37
+ code_lines = {} #: Hash[Integer, bool]
38
+ tokens.each.with_object({}) do |token, hash| #$ Hash[Integer, AST::Comment]
39
+ case token[1]
40
+ when :on_sp, :on_ignored_nl
41
+ # skip
42
+ when :on_comment
43
+ line = token[0][0]
44
+ # skip like `module Foo # :nodoc:`
45
+ next if code_lines[line] && !include_trailing
46
+ body = token[2][2..-1] or raise
47
+
48
+ body = "\n" if body.empty?
49
+
50
+ comment = AST::Comment.new(string: body, location: nil)
51
+ if prev_comment = hash.delete(line - 1)
52
+ hash[line] = AST::Comment.new(string: prev_comment.string + comment.string,
53
+ location: nil)
54
+ else
55
+ hash[line] = comment
56
+ end
57
+ else
58
+ code_lines[token[0][0]] = true
59
+ end
60
+ end
61
+ end
62
+ end
63
+ end
64
+
8
65
  def block_from_body(node)
9
66
  _, args_node, body_node = node.children
10
67
  _pre_num, _pre_init, _opt, _first_post, _post_num, _post_init, _rest, _kw, _kwrest, block_var = args_from_node(args_node)
@@ -74,32 +74,7 @@ module RBS
74
74
 
75
75
  def parse(string)
76
76
  # @type var comments: Hash[Integer, AST::Comment]
77
- comments = Ripper.lex(string).yield_self do |tokens|
78
- code_lines = {} #: Hash[Integer, bool]
79
- tokens.each.with_object({}) do |token, hash| #$ Hash[Integer, AST::Comment]
80
- case token[1]
81
- when :on_sp, :on_ignored_nl
82
- # skip
83
- when :on_comment
84
- line = token[0][0]
85
- # skip like `module Foo # :nodoc:`
86
- next if code_lines[line]
87
- body = token[2][2..-1] or raise
88
-
89
- body = "\n" if body.empty?
90
-
91
- comment = AST::Comment.new(string: body, location: nil)
92
- if prev_comment = hash.delete(line - 1)
93
- hash[line] = AST::Comment.new(string: prev_comment.string + comment.string,
94
- location: nil)
95
- else
96
- hash[line] = comment
97
- end
98
- else
99
- code_lines[token[0][0]] = true
100
- end
101
- end
102
- end
77
+ comments = parse_comments(string, include_trailing: false)
103
78
 
104
79
  process RubyVM::AbstractSyntaxTree.parse(string), decls: source_decls, comments: comments, context: Context.initial
105
80
  end
@@ -16,26 +16,7 @@ module RBS
16
16
  end
17
17
 
18
18
  def parse(string)
19
- comments = Ripper.lex(string).yield_self do |tokens|
20
- tokens.each.with_object({}) do |token, hash| #$ Hash[Integer, AST::Comment]
21
- if token[1] == :on_comment
22
- line = token[0][0]
23
- body = token[2][2..-1] or raise
24
-
25
- body = "\n" if body.empty?
26
-
27
- comment = AST::Comment.new(string: body, location: nil)
28
- if (prev_comment = hash.delete(line - 1))
29
- hash[line] = AST::Comment.new(
30
- string: prev_comment.string + comment.string,
31
- location: nil
32
- )
33
- else
34
- hash[line] = comment
35
- end
36
- end
37
- end
38
- end
19
+ comments = parse_comments(string, include_trailing: true)
39
20
  process RubyVM::AbstractSyntaxTree.parse(string), comments: comments
40
21
  end
41
22
 
@@ -264,6 +264,9 @@ module RBS
264
264
  klass = get_class(type.name) or return false
265
265
  if params = builder.env.normalized_module_class_entry(type.name.absolute!)&.type_params
266
266
  args = AST::TypeParam.normalize_args(params, type.args)
267
+ if args.size != params.size
268
+ return false
269
+ end
267
270
  unless args == type.args
268
271
  type = Types::ClassInstance.new(name: type.name, args: args, location: type.location)
269
272
  end
data/lib/rbs/types.rb CHANGED
@@ -199,58 +199,6 @@ module RBS
199
199
  end
200
200
  end
201
201
 
202
- class ClassSingleton
203
- attr_reader :name
204
- attr_reader :location
205
-
206
- def initialize(name:, location:)
207
- @name = name
208
- @location = location
209
- end
210
-
211
- def ==(other)
212
- other.is_a?(ClassSingleton) && other.name == name
213
- end
214
-
215
- alias eql? ==
216
-
217
- def hash
218
- self.class.hash ^ name.hash
219
- end
220
-
221
- include NoFreeVariables
222
- include NoSubst
223
-
224
- def to_json(state = nil)
225
- { class: :class_singleton, name: name, location: location }.to_json(state)
226
- end
227
-
228
- def to_s(level = 0)
229
- "singleton(#{name})"
230
- end
231
-
232
- include EmptyEachType
233
-
234
- def map_type_name(&)
235
- ClassSingleton.new(
236
- name: yield(name, location, self),
237
- location: location
238
- )
239
- end
240
-
241
- def has_self_type?
242
- false
243
- end
244
-
245
- def has_classish_type?
246
- false
247
- end
248
-
249
- def with_nonreturn_void?
250
- false
251
- end
252
- end
253
-
254
202
  module Application
255
203
  attr_reader :name
256
204
  attr_reader :args
@@ -309,6 +257,68 @@ module RBS
309
257
  end
310
258
  end
311
259
 
260
+ class ClassSingleton
261
+ attr_reader :location
262
+
263
+ include Application
264
+
265
+ def initialize(name:, location:, args: [])
266
+ @name = name
267
+ @location = location
268
+ @args = args
269
+ end
270
+
271
+ def ==(other)
272
+ other.is_a?(ClassSingleton) && other.name == name && other.args == args
273
+ end
274
+
275
+ alias eql? ==
276
+
277
+ def hash
278
+ self.class.hash ^ name.hash ^ args.hash
279
+ end
280
+
281
+ def sub(s)
282
+ return self if s.empty?
283
+
284
+ self.class.new(name: name,
285
+ args: args.map {|ty| ty.sub(s) },
286
+ location: location)
287
+ end
288
+
289
+ def to_json(state = _ = nil)
290
+ { class: :class_singleton, name: name, args: args, location: location }.to_json(state)
291
+ end
292
+
293
+ def to_s(level = 0)
294
+ if args.empty?
295
+ "singleton(#{name})"
296
+ else
297
+ "singleton(#{name})[#{args.join(", ")}]"
298
+ end
299
+ end
300
+
301
+ def map_type_name(&block)
302
+ ClassSingleton.new(
303
+ name: yield(name, location, self),
304
+ args: args.map {|type| type.map_type_name(&block) },
305
+ location: location
306
+ )
307
+ end
308
+
309
+ def map_type(&block)
310
+ if block
311
+ ClassSingleton.new(
312
+ name: name,
313
+ args: args.map {|type| yield type },
314
+ location: location
315
+ )
316
+ else
317
+ enum_for :map_type
318
+ end
319
+ end
320
+ end
321
+
312
322
  class Interface
313
323
  attr_reader :location
314
324
 
@@ -192,6 +192,31 @@ module RBS
192
192
  end
193
193
  end
194
194
 
195
+ ruby2_keywords def assert_send_type_error(method_type, error_type, receiver, method, *args, &block)
196
+ send_setup(method_type, receiver, method, args, block) do |method_type, trace, result, exception|
197
+ typecheck = RBS::Test::TypeCheck.new(
198
+ self_class: receiver.class,
199
+ builder: builder,
200
+ sample_size: 100,
201
+ unchecked_classes: [],
202
+ instance_class: instance_class,
203
+ class_class: class_class
204
+ )
205
+ errors = typecheck.method_call(method, method_type, trace, errors: [])
206
+
207
+ assert_empty errors.map {|x| RBS::Test::Errors.to_string(x) }, "Call trace does not match with given method type: #{trace.inspect}"
208
+
209
+ method_defs = method_defs(method)
210
+ all_errors = method_defs.map {|t| typecheck.method_call(method, t.type, trace, errors: [], annotations: t.each_annotation.to_a) }
211
+ assert all_errors.any? {|es| es.empty? }, "Call trace does not match one of method definitions:\n #{trace.inspect}\n #{method_defs.map(&:type).join(" | ")}"
212
+
213
+ # Use `instnace_of?` instead of `is_a?` as we want to check for _the exact exception class_.
214
+ assert exception.instance_of? error_type
215
+
216
+ result
217
+ end
218
+ end
219
+
195
220
  ruby2_keywords def refute_send_type(method_type, receiver, method, *args, &block)
196
221
  send_setup(method_type, receiver, method, args, block) do |method_type, trace, result, exception|
197
222
  method_type = method_type.update(
@@ -231,15 +256,17 @@ module RBS
231
256
  type, definition = target
232
257
 
233
258
  case type
234
- when Types::ClassInstance
235
- subst = RBS::Substitution.build(definition.type_params, type.args)
236
- definition.methods[method].defs.map do |type_def|
237
- type_def.update(
238
- type: type_def.type.sub(subst)
239
- )
259
+ when Types::ClassInstance, Types::ClassSingleton
260
+ if type.is_a?(Types::ClassSingleton) && type.args.empty?
261
+ definition.methods[method].defs
262
+ else
263
+ subst = RBS::Substitution.build(definition.type_params, type.args)
264
+ definition.methods[method].defs.map do |type_def|
265
+ type_def.update(
266
+ type: type_def.type.sub(subst)
267
+ )
268
+ end
240
269
  end
241
- when Types::ClassSingleton
242
- definition.methods[method].defs
243
270
  else
244
271
  raise
245
272
  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.0.0.dev.5"
4
+ VERSION = "4.0.1.dev.1"
5
5
  end
data/lib/rbs.rb CHANGED
@@ -6,7 +6,6 @@ require "set"
6
6
  require "json"
7
7
  require "pathname" unless defined?(Pathname)
8
8
  require "pp"
9
- require "ripper"
10
9
  require "logger"
11
10
  require "tsort"
12
11
  require "strscan"
data/rbs.gemspec CHANGED
@@ -46,6 +46,6 @@ Gem::Specification.new do |spec|
46
46
  spec.require_paths = ["lib"]
47
47
  spec.required_ruby_version = ">= 3.2"
48
48
  spec.add_dependency "logger"
49
- spec.add_dependency "prism", ">= 1.3.0"
49
+ spec.add_dependency "prism", ">= 1.6.0"
50
50
  spec.add_dependency "tsort"
51
51
  end
data/rust/.gitignore ADDED
@@ -0,0 +1 @@
1
+ /target/