rbs 3.2.0 → 3.3.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (136) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/comments.yml +1 -1
  3. data/.github/workflows/ruby.yml +7 -2
  4. data/.rubocop.yml +1 -1
  5. data/CHANGELOG.md +134 -0
  6. data/Gemfile +3 -0
  7. data/Gemfile.lock +21 -15
  8. data/README.md +11 -2
  9. data/Rakefile +10 -7
  10. data/Steepfile +7 -7
  11. data/core/basic_object.rbs +7 -7
  12. data/core/binding.rbs +3 -3
  13. data/core/builtin.rbs +171 -5
  14. data/core/constants.rbs +17 -17
  15. data/core/dir.rbs +3 -3
  16. data/core/encoding.rbs +434 -628
  17. data/core/enumerator.rbs +37 -0
  18. data/core/exception.rbs +11 -11
  19. data/core/false_class.rbs +5 -11
  20. data/core/fiber.rbs +5 -5
  21. data/core/file_test.rbs +28 -26
  22. data/core/kernel.rbs +900 -21
  23. data/core/marshal.rbs +24 -14
  24. data/core/match_data.rbs +8 -8
  25. data/core/math.rbs +57 -53
  26. data/core/method.rbs +3 -1
  27. data/core/module.rbs +38 -36
  28. data/core/nil_class.rbs +7 -13
  29. data/core/object.rbs +3 -966
  30. data/core/process.rbs +3 -3
  31. data/core/ractor.rbs +2 -2
  32. data/core/rb_config.rbs +64 -43
  33. data/core/regexp.rbs +3 -3
  34. data/core/set.rbs +3 -2
  35. data/core/signal.rbs +10 -4
  36. data/core/struct.rbs +1 -1
  37. data/core/thread.rbs +7 -7
  38. data/core/thread_group.rbs +9 -9
  39. data/core/true_class.rbs +5 -11
  40. data/core/unbound_method.rbs +56 -7
  41. data/core/warning.rbs +33 -0
  42. data/docs/collection.md +56 -6
  43. data/docs/data_and_struct.md +57 -0
  44. data/docs/stdlib.md +61 -2
  45. data/docs/syntax.md +123 -2
  46. data/ext/rbs_extension/constants.c +73 -72
  47. data/ext/rbs_extension/lexer.c +624 -569
  48. data/ext/rbs_extension/lexer.h +1 -0
  49. data/ext/rbs_extension/lexer.re +1 -0
  50. data/ext/rbs_extension/lexstate.c +1 -0
  51. data/ext/rbs_extension/parser.c +6 -0
  52. data/goodcheck.yml +2 -2
  53. data/lib/rbs/annotate/formatter.rb +13 -3
  54. data/lib/rbs/annotate/rdoc_source.rb +10 -1
  55. data/lib/rbs/cli/colored_io.rb +48 -0
  56. data/lib/rbs/cli/diff.rb +80 -0
  57. data/lib/rbs/cli.rb +169 -17
  58. data/lib/rbs/collection/config/lockfile.rb +0 -25
  59. data/lib/rbs/collection/config/lockfile_generator.rb +0 -6
  60. data/lib/rbs/collection/installer.rb +1 -1
  61. data/lib/rbs/collection/sources/git.rb +6 -4
  62. data/lib/rbs/collection/sources/local.rb +7 -5
  63. data/lib/rbs/diff.rb +121 -0
  64. data/lib/rbs/environment.rb +7 -4
  65. data/lib/rbs/method_type.rb +23 -0
  66. data/lib/rbs/prototype/rb.rb +2 -9
  67. data/lib/rbs/prototype/rbi.rb +1 -1
  68. data/lib/rbs/prototype/runtime/helpers.rb +59 -0
  69. data/lib/rbs/prototype/runtime/reflection.rb +19 -0
  70. data/lib/rbs/prototype/runtime/value_object_generator.rb +275 -0
  71. data/lib/rbs/prototype/runtime.rb +233 -153
  72. data/lib/rbs/resolver/constant_resolver.rb +1 -1
  73. data/lib/rbs/sorter.rb +144 -117
  74. data/lib/rbs/test/guaranteed.rb +31 -0
  75. data/lib/rbs/test/type_check.rb +4 -4
  76. data/lib/rbs/test.rb +3 -0
  77. data/lib/rbs/types.rb +184 -3
  78. data/lib/rbs/version.rb +1 -1
  79. data/lib/rbs/writer.rb +4 -4
  80. data/lib/rbs.rb +1 -0
  81. data/rbs.gemspec +1 -0
  82. data/sig/annotate/formatter.rbs +2 -2
  83. data/sig/annotate/rdoc_annotater.rbs +1 -1
  84. data/sig/cli/colored_io.rbs +15 -0
  85. data/sig/cli/diff.rbs +21 -0
  86. data/sig/cli.rbs +2 -0
  87. data/sig/collection/config/lockfile.rbs +0 -6
  88. data/sig/diff.rbs +23 -0
  89. data/sig/errors.rbs +1 -5
  90. data/sig/method_types.rbs +6 -0
  91. data/sig/prototype/runtime.rbs +166 -0
  92. data/sig/rdoc/rbs.rbs +4 -0
  93. data/sig/shims/bundler.rbs +5 -0
  94. data/sig/sorter.rbs +23 -5
  95. data/sig/types.rbs +29 -0
  96. data/stdlib/benchmark/0/benchmark.rbs +1 -1
  97. data/stdlib/cgi/0/core.rbs +2 -2
  98. data/stdlib/did_you_mean/0/did_you_mean.rbs +2 -2
  99. data/stdlib/digest/0/digest.rbs +1 -1
  100. data/stdlib/fileutils/0/fileutils.rbs +1 -1
  101. data/stdlib/forwardable/0/forwardable.rbs +4 -4
  102. data/stdlib/io-console/0/io-console.rbs +1 -1
  103. data/stdlib/json/0/json.rbs +37 -0
  104. data/stdlib/logger/0/logger.rbs +2 -2
  105. data/stdlib/net-http/0/manifest.yaml +1 -1
  106. data/stdlib/net-http/0/net-http.rbs +16 -63
  107. data/stdlib/net-protocol/0/manifest.yaml +2 -0
  108. data/stdlib/net-protocol/0/net-protocol.rbs +56 -0
  109. data/stdlib/net-smtp/0/manifest.yaml +2 -0
  110. data/stdlib/net-smtp/0/net-smtp.rbs +55 -0
  111. data/stdlib/open-uri/0/manifest.yaml +3 -0
  112. data/stdlib/open-uri/0/open-uri.rbs +341 -0
  113. data/stdlib/openssl/0/openssl.rbs +1 -1
  114. data/stdlib/pp/0/manifest.yaml +2 -0
  115. data/stdlib/pp/0/pp.rbs +301 -0
  116. data/stdlib/{yaml → psych}/0/dbm.rbs +3 -3
  117. data/stdlib/psych/0/manifest.yaml +3 -0
  118. data/stdlib/psych/0/psych.rbs +391 -0
  119. data/stdlib/{yaml → psych}/0/store.rbs +2 -2
  120. data/stdlib/rdoc/0/code_object.rbs +55 -0
  121. data/stdlib/rdoc/0/comment.rbs +60 -0
  122. data/stdlib/rdoc/0/context.rbs +153 -0
  123. data/stdlib/rdoc/0/markup.rbs +119 -0
  124. data/stdlib/rdoc/0/parser.rbs +56 -0
  125. data/stdlib/rdoc/0/rdoc.rbs +0 -372
  126. data/stdlib/rdoc/0/ri.rbs +17 -0
  127. data/stdlib/rdoc/0/store.rbs +48 -0
  128. data/stdlib/rdoc/0/top_level.rbs +97 -0
  129. data/stdlib/socket/0/basic_socket.rbs +1 -1
  130. data/stdlib/socket/0/socket.rbs +1 -1
  131. data/stdlib/uri/0/common.rbs +1 -1
  132. data/stdlib/yaml/0/manifest.yaml +1 -2
  133. data/stdlib/yaml/0/yaml.rbs +1 -199
  134. metadata +49 -7
  135. data/sig/shims/pp.rbs +0 -3
  136. data/sig/shims.rbs +0 -47
@@ -7,7 +7,7 @@ module RBS
7
7
  include Base
8
8
 
9
9
  attr_reader :path, :full_path
10
-
10
+
11
11
  def initialize(path:, base_directory:)
12
12
  # TODO: resolve relative path from dir of rbs_collection.yaml
13
13
  @path = Pathname(path)
@@ -33,22 +33,24 @@ module RBS
33
33
  from = @full_path.join(name, version)
34
34
  gem_dir = dest.join(name, version)
35
35
 
36
+ colored_io = CLI::ColoredIO.new(stdout: stdout)
37
+
36
38
  case
37
39
  when gem_dir.symlink? && gem_dir.readlink == from
38
- stdout.puts "Using #{name}:#{version} (#{from})"
40
+ colored_io.puts "Using #{name}:#{version} (#{from})"
39
41
  when gem_dir.symlink?
40
42
  prev = gem_dir.readlink
41
43
  gem_dir.unlink
42
44
  _install(from, dest.join(name, version))
43
- stdout.puts "Updating #{name}:#{version} to #{from} from #{prev}"
45
+ colored_io.puts_green("Updating #{name}:#{version} to #{from} from #{prev}")
44
46
  when gem_dir.directory?
45
47
  # TODO: Show version of git source
46
48
  FileUtils.remove_entry_secure(gem_dir.to_s)
47
49
  _install(from, dest.join(name, version))
48
- stdout.puts "Updating #{name}:#{version} from git source"
50
+ colored_io.puts_green("Updating #{name}:#{version} from git source")
49
51
  when !gem_dir.exist?
50
52
  _install(from, dest.join(name, version))
51
- stdout.puts "Installing #{name}:#{version} (#{from})"
53
+ colored_io.puts_green("Installing #{name}:#{version} (#{from})")
52
54
  else
53
55
  raise
54
56
  end
data/lib/rbs/diff.rb ADDED
@@ -0,0 +1,121 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RBS
4
+ class Diff
5
+ def initialize(type_name:, library_options:, after_path: [], before_path: [])
6
+ @type_name = type_name
7
+ @library_options = library_options
8
+ @after_path = after_path
9
+ @before_path = before_path
10
+ end
11
+
12
+ def each_diff(&block)
13
+ return to_enum(:each_diff) unless block
14
+
15
+ before_instance_methods, before_singleton_methods, before_constant_children = build_methods(@before_path)
16
+ after_instance_methods, after_singleton_methods, after_constant_children = build_methods(@after_path)
17
+
18
+ each_diff_methods(:instance, before_instance_methods, after_instance_methods, &block)
19
+ each_diff_methods(:singleton, before_singleton_methods, after_singleton_methods, &block)
20
+
21
+ each_diff_constants(before_constant_children, after_constant_children, &block)
22
+ end
23
+
24
+ private
25
+
26
+ def each_diff_methods(kind, before_methods, after_methods)
27
+ all_keys = before_methods.keys.to_set + after_methods.keys.to_set
28
+ all_keys.each do |key|
29
+ before = definition_method_to_s(key, kind, before_methods[key]) or next
30
+ after = definition_method_to_s(key, kind, after_methods[key]) or next
31
+ next if before == after
32
+
33
+ yield before, after
34
+ end
35
+ end
36
+
37
+ def each_diff_constants(before_constant_children, after_constant_children)
38
+ all_keys = before_constant_children.keys.to_set + after_constant_children.keys.to_set
39
+ all_keys.each do |key|
40
+ before = constant_to_s(before_constant_children[key]) or next
41
+ after = constant_to_s(after_constant_children[key]) or next
42
+ next if before == after
43
+
44
+ yield before, after
45
+ end
46
+ end
47
+
48
+ def build_methods(path)
49
+ env = build_env(path)
50
+ builder = build_builder(env)
51
+
52
+ instance_methods = begin
53
+ builder.build_instance(@type_name).methods
54
+ rescue => e
55
+ RBS.logger.warn("#{path}: (#{e.class}) #{e.message}")
56
+ {}
57
+ end
58
+ singleton_methods = begin
59
+ builder.build_singleton(@type_name).methods
60
+ rescue => e
61
+ RBS.logger.warn("#{path}: (#{e.class}) #{e.message}")
62
+ {}
63
+ end
64
+
65
+ constant_children = begin
66
+ constant_resolver = RBS::Resolver::ConstantResolver.new(builder: builder)
67
+ constant_resolver.children(@type_name)
68
+ rescue => e
69
+ RBS.logger.warn("#{path}: (#{e.class}) #{e.message}")
70
+ {}
71
+ end
72
+
73
+ [ instance_methods, singleton_methods, constant_children ]
74
+ end
75
+
76
+ def build_env(path)
77
+ loader = @library_options.loader()
78
+ path&.each do |dir|
79
+ dir_pathname = Pathname(dir)
80
+ loader.add(path: dir_pathname)
81
+
82
+ manifest_pathname = dir_pathname / 'manifest.yaml'
83
+ if manifest_pathname.exist?
84
+ manifest = YAML.safe_load(manifest_pathname.read)
85
+ if manifest['dependencies']
86
+ manifest['dependencies'].each do |dependency|
87
+ loader.add(library: dependency['name'], version: nil)
88
+ end
89
+ end
90
+ end
91
+ end
92
+ Environment.from_loader(loader)
93
+ end
94
+
95
+ def build_builder(env)
96
+ DefinitionBuilder.new(env: env.resolve_type_names)
97
+ end
98
+
99
+ def definition_method_to_s(key, kind, definition_method)
100
+ if definition_method
101
+ prefix = kind == :instance ? "" : "self."
102
+
103
+ if definition_method.alias_of
104
+ "alias #{prefix}#{key} #{prefix}#{definition_method.alias_of.defs.first.member.name}"
105
+ else
106
+ "def #{prefix}#{key}: #{definition_method.method_types.join(" | ")}"
107
+ end
108
+ else
109
+ +"-"
110
+ end
111
+ end
112
+
113
+ def constant_to_s(constant)
114
+ if constant
115
+ "#{constant.name.name}: #{constant.type}"
116
+ else
117
+ +"-"
118
+ end
119
+ end
120
+ end
121
+ end
@@ -276,9 +276,9 @@ module RBS
276
276
  end
277
277
 
278
278
  def normalize_type_name?(name)
279
- if name.class?
280
- normalize_module_name?(name)
281
- else
279
+ return normalize_module_name?(name) if name.class?
280
+
281
+ type_name =
282
282
  unless name.namespace.empty?
283
283
  parent = name.namespace.to_type_name
284
284
  parent = normalize_module_name?(parent)
@@ -288,6 +288,9 @@ module RBS
288
288
  else
289
289
  name
290
290
  end
291
+
292
+ if type_name?(type_name)
293
+ type_name
291
294
  end
292
295
  end
293
296
 
@@ -438,7 +441,7 @@ module RBS
438
441
 
439
442
  when AST::Declarations::Global
440
443
  if entry = global_decls[decl.name]
441
- raise DuplicatedDeclarationError.new(name, decl, entry.decl)
444
+ raise DuplicatedDeclarationError.new(decl.name, decl, entry.decl)
442
445
  end
443
446
 
444
447
  global_decls[decl.name] = GlobalEntry.new(name: decl.name, decl: decl, outer: outer)
@@ -86,6 +86,9 @@ module RBS
86
86
  type.each_type(&block)
87
87
  self.block&.yield_self do |b|
88
88
  b.type.each_type(&block)
89
+ if b.self_type
90
+ yield b.self_type
91
+ end
89
92
  end
90
93
  else
91
94
  enum_for :each_type
@@ -114,5 +117,25 @@ module RBS
114
117
  def type_param_names
115
118
  type_params.map(&:name)
116
119
  end
120
+
121
+ def has_self_type?
122
+ each_type.any? {|type| type.has_self_type? }
123
+ end
124
+
125
+ def has_classish_type?
126
+ each_type.any? {|type| type.has_classish_type? }
127
+ end
128
+
129
+ def with_nonreturn_void?
130
+ if type.with_nonreturn_void?
131
+ true
132
+ else
133
+ if block = block()
134
+ block.type.with_nonreturn_void? || block.self_type&.with_nonreturn_void? || false
135
+ else
136
+ false
137
+ end
138
+ end
139
+ end
117
140
  end
118
141
  end
@@ -89,8 +89,7 @@ module RBS
89
89
  body = "\n" if body.empty?
90
90
 
91
91
  comment = AST::Comment.new(string: body, location: nil)
92
- if (prev_comment = hash[line - 1])
93
- hash[line - 1] = nil
92
+ if prev_comment = hash.delete(line - 1)
94
93
  hash[line] = AST::Comment.new(string: prev_comment.string + comment.string,
95
94
  location: nil)
96
95
  else
@@ -362,13 +361,7 @@ module RBS
362
361
  end
363
362
 
364
363
  when :ITER
365
- method_name = node.children.first.children.first
366
- case method_name
367
- when :refine
368
- # ignore
369
- else
370
- process_children(node, decls: decls, comments: comments, context: context)
371
- end
364
+ # ignore
372
365
 
373
366
  when :CDECL
374
367
  const_name = case
@@ -246,7 +246,7 @@ module RBS
246
246
  end
247
247
  end
248
248
  value_node = node.children.last
249
- type = if value_node.type == :CALL && value_node.children[1] == :let
249
+ type = if value_node && value_node.type == :CALL && value_node.children[1] == :let
250
250
  type_node = each_arg(value_node.children[2]).to_a[1]
251
251
  type_of type_node, variables: current_module&.type_params || []
252
252
  else
@@ -0,0 +1,59 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RBS
4
+ module Prototype
5
+ class Runtime
6
+ module Helpers
7
+ private
8
+
9
+ # Returns the exact name & not compactly declared name
10
+ def only_name(mod)
11
+ # No nil check because this method is invoked after checking if the module exists
12
+ const_name!(mod).split(/::/).last or raise # (A::B::C) => C
13
+ end
14
+
15
+ def const_name!(const)
16
+ const_name(const) or raise
17
+ end
18
+
19
+ def const_name(const)
20
+ @module_name_method ||= Module.instance_method(:name)
21
+ name = @module_name_method.bind(const).call
22
+ return nil unless name
23
+
24
+ begin
25
+ deprecated, Warning[:deprecated] = Warning[:deprecated], false
26
+ Object.const_get(name)
27
+ rescue NameError
28
+ # Should generate const name if anonymous or internal module (e.g. NameError::message)
29
+ nil
30
+ else
31
+ name
32
+ ensure
33
+ Warning[:deprecated] = deprecated
34
+ end
35
+ end
36
+
37
+ def to_type_name(name, full_name: false)
38
+ *prefix, last = name.split(/::/)
39
+
40
+ last or raise
41
+
42
+ if full_name
43
+ if prefix.empty?
44
+ TypeName.new(name: last.to_sym, namespace: Namespace.empty)
45
+ else
46
+ TypeName.new(name: last.to_sym, namespace: Namespace.parse(prefix.join("::")))
47
+ end
48
+ else
49
+ TypeName.new(name: last.to_sym, namespace: Namespace.empty)
50
+ end
51
+ end
52
+
53
+ def untyped
54
+ @untyped ||= Types::Bases::Any.new(location: nil)
55
+ end
56
+ end
57
+ end
58
+ end
59
+ end
@@ -0,0 +1,19 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RBS
4
+ module Prototype
5
+ class Runtime
6
+ module Reflection
7
+ def self.object_class(value)
8
+ @object_class ||= Object.instance_method(:class)
9
+ @object_class.bind_call(value)
10
+ end
11
+
12
+ def self.constants_of(mod, inherit = true)
13
+ @constants_of ||= Module.instance_method(:constants)
14
+ @constants_of.bind_call(mod, inherit)
15
+ end
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,275 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'helpers'
4
+
5
+ module RBS
6
+ module Prototype
7
+ class Runtime
8
+ class ValueObjectBase
9
+ include Helpers
10
+
11
+ def initialize(target_class)
12
+ @target_class = target_class
13
+ end
14
+
15
+ def build_decl
16
+ decl = AST::Declarations::Class.new(
17
+ name: to_type_name(only_name(@target_class)),
18
+ type_params: [],
19
+ super_class: build_super_class,
20
+ members: [],
21
+ annotations: [],
22
+ location: nil,
23
+ comment: nil
24
+ )
25
+
26
+ add_decl_members(decl)
27
+
28
+ decl
29
+ end
30
+
31
+ private
32
+
33
+ # def self.members: () -> [ :foo, :bar ]
34
+ # def members: () -> [ :foo, :bar ]
35
+ def build_s_members
36
+ [:singleton, :instance].map do |kind|
37
+ AST::Members::MethodDefinition.new(
38
+ name: :members,
39
+ overloads: [
40
+ AST::Members::MethodDefinition::Overload.new(
41
+ annotations: [],
42
+ method_type: MethodType.new(
43
+ type: Types::Function.empty(
44
+ Types::Tuple.new(
45
+ types: @target_class.members.map do |member|
46
+ if member.to_s.ascii_only?
47
+ Types::Literal.new(literal: member, location: nil)
48
+ else
49
+ BuiltinNames::Symbol.instance_type
50
+ end
51
+ end,
52
+ location: nil
53
+ )
54
+ ),
55
+ type_params: [],
56
+ block: nil,
57
+ location: nil,
58
+ )
59
+ )
60
+ ],
61
+ kind: kind,
62
+ location: nil,
63
+ comment: nil,
64
+ annotations: [],
65
+ overloading: false,
66
+ visibility: nil
67
+ )
68
+ end
69
+ end
70
+
71
+ # attr_accessor foo: untyped
72
+ def build_member_accessors(ast_members_class)
73
+ @target_class.members.map do |member|
74
+ ast_members_class.new(
75
+ name: member,
76
+ ivar_name: nil,
77
+ type: untyped,
78
+ kind: :instance,
79
+ location: nil,
80
+ comment: nil,
81
+ annotations: []
82
+ )
83
+ end
84
+ end
85
+ end
86
+
87
+ class StructGenerator < ValueObjectBase
88
+ def self.generatable?(target)
89
+ return false unless target < Struct
90
+ # Avoid direct inherited class like `class Option < Struct`
91
+ return false unless target.respond_to?(:members)
92
+
93
+ true
94
+ end
95
+
96
+ private
97
+
98
+ CAN_CALL_KEYWORD_INIT_P = Struct.new(:tmp).respond_to?(:keyword_init?)
99
+
100
+ def build_super_class
101
+ AST::Declarations::Class::Super.new(name: TypeName("::Struct"), args: [untyped], location: nil)
102
+ end
103
+
104
+ def add_decl_members(decl)
105
+ decl.members.concat build_s_new
106
+ decl.members.concat build_s_keyword_init_p
107
+ decl.members.concat build_s_members
108
+ decl.members.concat build_member_accessors(AST::Members::AttrAccessor)
109
+ end
110
+
111
+ # def self.new: (?untyped foo, ?untyped bar) -> instance
112
+ # | (?foo: untyped, ?bar: untyped) -> instance
113
+ def build_s_new
114
+ [:new, :[]].map do |name|
115
+ new_overloads = []
116
+
117
+ if CAN_CALL_KEYWORD_INIT_P
118
+ case @target_class.keyword_init?
119
+ when false
120
+ new_overloads << build_overload_for_positional_arguments
121
+ when true
122
+ new_overloads << build_overload_for_keyword_arguments
123
+ when nil
124
+ new_overloads << build_overload_for_positional_arguments
125
+ new_overloads << build_overload_for_keyword_arguments
126
+ else
127
+ raise
128
+ end
129
+ else
130
+ new_overloads << build_overload_for_positional_arguments
131
+ new_overloads << build_overload_for_keyword_arguments
132
+ end
133
+
134
+ AST::Members::MethodDefinition.new(
135
+ name: name,
136
+ overloads: new_overloads,
137
+ kind: :singleton,
138
+ location: nil,
139
+ comment: nil,
140
+ annotations: [],
141
+ overloading: false,
142
+ visibility: nil
143
+ )
144
+ end
145
+ end
146
+
147
+ def build_overload_for_positional_arguments
148
+ AST::Members::MethodDefinition::Overload.new(
149
+ annotations: [],
150
+ method_type: MethodType.new(
151
+ type: Types::Function.empty(Types::Bases::Instance.new(location: nil)).update(
152
+ optional_positionals: @target_class.members.map { |m| Types::Function::Param.new(name: m, type: untyped) },
153
+ ),
154
+ type_params: [],
155
+ block: nil,
156
+ location: nil,
157
+ )
158
+ )
159
+ end
160
+
161
+ def build_overload_for_keyword_arguments
162
+ AST::Members::MethodDefinition::Overload.new(
163
+ annotations: [],
164
+ method_type: MethodType.new(
165
+ type: Types::Function.empty(Types::Bases::Instance.new(location: nil)).update(
166
+ optional_keywords: @target_class.members.to_h { |m| [m, Types::Function::Param.new(name: nil, type: untyped)] },
167
+ ),
168
+ type_params: [],
169
+ block: nil,
170
+ location: nil,
171
+ )
172
+ )
173
+ end
174
+
175
+ # def self.keyword_init?: () -> bool?
176
+ def build_s_keyword_init_p
177
+ return [] unless CAN_CALL_KEYWORD_INIT_P
178
+
179
+ return_type = @target_class.keyword_init?.nil? \
180
+ ? Types::Bases::Nil.new(location: nil)
181
+ : Types::Literal.new(literal: @target_class.keyword_init?, location: nil)
182
+ type = Types::Function.empty(return_type)
183
+
184
+ [
185
+ AST::Members::MethodDefinition.new(
186
+ name: :keyword_init?,
187
+ overloads: [
188
+ AST::Members::MethodDefinition::Overload.new(
189
+ annotations: [],
190
+ method_type: MethodType.new(
191
+ type: type,
192
+ type_params: [],
193
+ block: nil,
194
+ location: nil,
195
+ )
196
+ )
197
+ ],
198
+ kind: :singleton,
199
+ location: nil,
200
+ comment: nil,
201
+ annotations: [],
202
+ overloading: false,
203
+ visibility: nil
204
+ )
205
+ ]
206
+ end
207
+ end
208
+
209
+ class DataGenerator < ValueObjectBase
210
+ def self.generatable?(target)
211
+ return false unless RUBY_VERSION >= '3.2'
212
+ return false unless target < Data
213
+ # Avoid direct inherited class like `class Option < Data`
214
+ return false unless target.respond_to?(:members)
215
+
216
+ true
217
+ end
218
+
219
+ private
220
+
221
+ def build_super_class
222
+ AST::Declarations::Class::Super.new(name: TypeName("::Data"), args: [], location: nil)
223
+ end
224
+
225
+ def add_decl_members(decl)
226
+ decl.members.concat build_s_new
227
+ decl.members.concat build_s_members
228
+ decl.members.concat build_member_accessors(AST::Members::AttrReader)
229
+ end
230
+
231
+ # def self.new: (untyped foo, untyped bar) -> instance
232
+ # | (foo: untyped, bar: untyped) -> instance
233
+ def build_s_new
234
+ [:new, :[]].map do |name|
235
+ new_overloads = []
236
+
237
+ new_overloads << AST::Members::MethodDefinition::Overload.new(
238
+ annotations: [],
239
+ method_type: MethodType.new(
240
+ type: Types::Function.empty(Types::Bases::Instance.new(location: nil)).update(
241
+ required_positionals: @target_class.members.map { |m| Types::Function::Param.new(name: m, type: untyped) },
242
+ ),
243
+ type_params: [],
244
+ block: nil,
245
+ location: nil,
246
+ )
247
+ )
248
+ new_overloads << AST::Members::MethodDefinition::Overload.new(
249
+ annotations: [],
250
+ method_type: MethodType.new(
251
+ type: Types::Function.empty(Types::Bases::Instance.new(location: nil)).update(
252
+ required_keywords: @target_class.members.to_h { |m| [m, Types::Function::Param.new(name: nil, type: untyped)] },
253
+ ),
254
+ type_params: [],
255
+ block: nil,
256
+ location: nil,
257
+ )
258
+ )
259
+
260
+ AST::Members::MethodDefinition.new(
261
+ name: name,
262
+ overloads: new_overloads,
263
+ kind: :singleton,
264
+ location: nil,
265
+ comment: nil,
266
+ annotations: [],
267
+ overloading: false,
268
+ visibility: nil
269
+ )
270
+ end
271
+ end
272
+ end
273
+ end
274
+ end
275
+ end