rbs 0.18.0 → 1.0.0.pre

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 (55) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +31 -0
  3. data/Rakefile +4 -0
  4. data/core/builtin.rbs +4 -0
  5. data/core/file.rbs +0 -4
  6. data/core/hash.rbs +1 -3
  7. data/core/io.rbs +159 -6
  8. data/core/kernel.rbs +1 -1
  9. data/core/time.rbs +0 -12
  10. data/goodcheck.yml +20 -0
  11. data/lib/rbs.rb +2 -0
  12. data/lib/rbs/ast/declarations.rb +7 -2
  13. data/lib/rbs/ast/members.rb +10 -4
  14. data/lib/rbs/cli.rb +10 -10
  15. data/lib/rbs/definition.rb +70 -3
  16. data/lib/rbs/definition_builder.rb +544 -989
  17. data/lib/rbs/definition_builder/ancestor_builder.rb +476 -0
  18. data/lib/rbs/definition_builder/method_builder.rb +217 -0
  19. data/lib/rbs/environment.rb +5 -1
  20. data/lib/rbs/environment_loader.rb +1 -1
  21. data/lib/rbs/environment_walker.rb +16 -10
  22. data/lib/rbs/errors.rb +71 -66
  23. data/lib/rbs/method_type.rb +1 -31
  24. data/lib/rbs/parser.rb +1000 -894
  25. data/lib/rbs/parser.y +108 -57
  26. data/lib/rbs/prototype/rb.rb +14 -3
  27. data/lib/rbs/prototype/rbi.rb +6 -6
  28. data/lib/rbs/prototype/runtime.rb +53 -33
  29. data/lib/rbs/substitution.rb +4 -0
  30. data/lib/rbs/test.rb +3 -1
  31. data/lib/rbs/test/hook.rb +24 -7
  32. data/lib/rbs/types.rb +63 -6
  33. data/lib/rbs/validator.rb +4 -2
  34. data/lib/rbs/variance_calculator.rb +5 -1
  35. data/lib/rbs/version.rb +1 -1
  36. data/lib/rbs/writer.rb +9 -1
  37. data/schema/members.json +5 -1
  38. data/sig/definition.rbs +6 -1
  39. data/sig/definition_builder.rbs +3 -0
  40. data/sig/errors.rbs +20 -0
  41. data/sig/members.rbs +4 -1
  42. data/sig/method_types.rbs +3 -16
  43. data/sig/type_name_resolver.rbs +4 -2
  44. data/sig/types.rbs +17 -1
  45. data/sig/validator.rbs +12 -0
  46. data/stdlib/dbm/0/dbm.rbs +0 -2
  47. data/stdlib/logger/0/log_device.rbs +1 -2
  48. data/stdlib/monitor/0/monitor.rbs +119 -0
  49. data/stdlib/time/0/time.rbs +327 -0
  50. data/stdlib/tsort/0/tsort.rbs +8 -0
  51. data/stdlib/uri/0/common.rbs +401 -0
  52. data/stdlib/uri/0/rfc2396_parser.rbs +9 -0
  53. data/stdlib/uri/0/rfc3986_parser.rbs +2 -0
  54. data/steep/Gemfile.lock +13 -14
  55. metadata +14 -5
@@ -20,7 +20,7 @@ class RBS::Parser
20
20
  nonassoc kARROW
21
21
  preclow
22
22
 
23
- expect 2
23
+ expect 5
24
24
 
25
25
  rule
26
26
 
@@ -99,11 +99,13 @@ rule
99
99
  { result = nil }
100
100
  | kLT class_name {
101
101
  result = Declarations::Class::Super.new(name: val[1].value,
102
- args: [])
102
+ args: [],
103
+ location: val[1].location)
103
104
  }
104
105
  | kLT class_name kLBRACKET type_list kRBRACKET {
105
106
  result = Declarations::Class::Super.new(name: val[1].value,
106
- args: val[3])
107
+ args: val[3],
108
+ location: val[1].location + val[4].location)
107
109
  }
108
110
 
109
111
  module_decl:
@@ -202,57 +204,67 @@ rule
202
204
  | alias_member
203
205
  | signature
204
206
 
207
+ attribute_kind:
208
+ { result = :instance }
209
+ | kSELF kDOT { result = :singleton }
210
+
205
211
  attribute_member:
206
- annotations kATTRREADER keyword type {
207
- location = val[1].location + val[3].location
208
- result = Members::AttrReader.new(name: val[2].value,
212
+ annotations kATTRREADER attribute_kind keyword type {
213
+ location = val[1].location + val[4].location
214
+ result = Members::AttrReader.new(name: val[3].value,
209
215
  ivar_name: nil,
210
- type: val[3],
216
+ type: val[4],
217
+ kind: val[2],
211
218
  annotations: val[0],
212
219
  location: location,
213
220
  comment: leading_comment(val[0].first&.location || location))
214
221
  }
215
- | annotations kATTRREADER method_name attr_var_opt kCOLON type {
216
- location = val[1].location + val[5].location
217
- result = Members::AttrReader.new(name: val[2].value.to_sym,
218
- ivar_name: val[3],
219
- type: val[5],
222
+ | annotations kATTRREADER attribute_kind method_name attr_var_opt kCOLON type {
223
+ location = val[1].location + val[6].location
224
+ result = Members::AttrReader.new(name: val[3].value.to_sym,
225
+ ivar_name: val[4],
226
+ type: val[6],
227
+ kind: val[2],
220
228
  annotations: val[0],
221
229
  location: location,
222
230
  comment: leading_comment(val[0].first&.location || location))
223
231
  }
224
- | annotations kATTRWRITER keyword type {
225
- location = val[1].location + val[3].location
226
- result = Members::AttrWriter.new(name: val[2].value,
232
+ | annotations kATTRWRITER attribute_kind keyword type {
233
+ location = val[1].location + val[4].location
234
+ result = Members::AttrWriter.new(name: val[3].value,
227
235
  ivar_name: nil,
228
- type: val[3],
236
+ kind: val[2],
237
+ type: val[4],
229
238
  annotations: val[0],
230
239
  location: location,
231
240
  comment: leading_comment(val[0].first&.location || location))
232
241
  }
233
- | annotations kATTRWRITER method_name attr_var_opt kCOLON type {
234
- location = val[1].location + val[5].location
235
- result = Members::AttrWriter.new(name: val[2].value.to_sym,
236
- ivar_name: val[3],
237
- type: val[5],
242
+ | annotations kATTRWRITER attribute_kind method_name attr_var_opt kCOLON type {
243
+ location = val[1].location + val[6].location
244
+ result = Members::AttrWriter.new(name: val[3].value.to_sym,
245
+ ivar_name: val[4],
246
+ kind: val[2],
247
+ type: val[6],
238
248
  annotations: val[0],
239
249
  location: location,
240
250
  comment: leading_comment(val[0].first&.location || location))
241
251
  }
242
- | annotations kATTRACCESSOR keyword type {
243
- location = val[1].location + val[3].location
244
- result = Members::AttrAccessor.new(name: val[2].value,
252
+ | annotations kATTRACCESSOR attribute_kind keyword type {
253
+ location = val[1].location + val[4].location
254
+ result = Members::AttrAccessor.new(name: val[3].value,
245
255
  ivar_name: nil,
246
- type: val[3],
256
+ kind: val[2],
257
+ type: val[4],
247
258
  annotations: val[0],
248
259
  location: location,
249
260
  comment: leading_comment(val[0].first&.location || location))
250
261
  }
251
- | annotations kATTRACCESSOR method_name attr_var_opt kCOLON type {
252
- location = val[1].location + val[5].location
253
- result = Members::AttrAccessor.new(name: val[2].value.to_sym,
254
- ivar_name: val[3],
255
- type: val[5],
262
+ | annotations kATTRACCESSOR attribute_kind method_name attr_var_opt kCOLON type {
263
+ location = val[1].location + val[6].location
264
+ result = Members::AttrAccessor.new(name: val[3].value.to_sym,
265
+ ivar_name: val[4],
266
+ kind: val[2],
267
+ type: val[6],
256
268
  annotations: val[0],
257
269
  location: location,
258
270
  comment: leading_comment(val[0].first&.location || location))
@@ -474,26 +486,13 @@ rule
474
486
  }
475
487
 
476
488
  method_type:
477
- start_merged_scope type_params params_opt block_opt kARROW simple_type {
489
+ start_merged_scope type_params proc_type {
478
490
  reset_variable_scope
479
491
 
480
- location = (val[1] || val[2] || val[3] || val[4]).location + val[5].location
492
+ location = (val[1] || val[2]).location + val[2].location
481
493
  type_params = val[1]&.value || []
482
494
 
483
- params = val[2]&.value || empty_params_result
484
-
485
- type = Types::Function.new(
486
- required_positionals: params[0],
487
- optional_positionals: params[1],
488
- rest_positionals: params[2],
489
- trailing_positionals: params[3],
490
- required_keywords: params[4],
491
- optional_keywords: params[5],
492
- rest_keywords: params[6],
493
- return_type: val[5]
494
- )
495
-
496
- block = val[3]&.value
495
+ type, block = val[2].value
497
496
 
498
497
  result = MethodType.new(type_params: type_params,
499
498
  type: type,
@@ -507,14 +506,13 @@ rule
507
506
  result = LocatedValue.new(value: val[1], location: val[0].location + val[2].location)
508
507
  }
509
508
 
510
- block_opt:
511
- { result = nil }
512
- | kLBRACE function_type kRBRACE {
513
- block = MethodType::Block.new(type: val[1].value, required: true)
509
+ block:
510
+ kLBRACE simple_function_type kRBRACE {
511
+ block = Types::Block.new(type: val[1].value, required: true)
514
512
  result = LocatedValue.new(value: block, location: val[0].location + val[2].location)
515
513
  }
516
- | kQUESTION kLBRACE function_type kRBRACE {
517
- block = MethodType::Block.new(type: val[2].value, required: false)
514
+ | kQUESTION kLBRACE simple_function_type kRBRACE {
515
+ block = Types::Block.new(type: val[2].value, required: false)
518
516
  result = LocatedValue.new(value: block, location: val[0].location + val[3].location)
519
517
  }
520
518
 
@@ -797,8 +795,9 @@ rule
797
795
  result = Types::ClassSingleton.new(name: val[2].value,
798
796
  location: val[0].location + val[3].location)
799
797
  }
800
- | kHAT function_type {
801
- result = Types::Proc.new(type: val[1].value, location: val[0].location + val[1].location)
798
+ | kHAT proc_type {
799
+ type, block = val[1].value
800
+ result = Types::Proc.new(type: type, block: block, location: val[0].location + val[1].location)
802
801
  }
803
802
  | simple_type kQUESTION {
804
803
  result = Types::Optional.new(type: val[0], location: val[0].location + val[1].location)
@@ -842,6 +841,15 @@ rule
842
841
  | keyword type {
843
842
  result = { val[0].value => val[1] }
844
843
  }
844
+ | identifier_keywords kCOLON type {
845
+ result = { val[0].value => val[2] }
846
+ }
847
+ | tQUOTEDIDENT kCOLON type {
848
+ result = { val[0].value => val[2] }
849
+ }
850
+ | tQUOTEDMETHOD kCOLON type {
851
+ result = { val[0].value => val[2] }
852
+ }
845
853
 
846
854
  keyword_name:
847
855
  keyword
@@ -851,7 +859,32 @@ rule
851
859
 
852
860
  keyword: tLKEYWORD | tUKEYWORD | tLKEYWORD_Q_E | tUKEYWORD_Q_E
853
861
 
854
- function_type:
862
+ proc_type:
863
+ params_opt block kARROW simple_type {
864
+ location = (val[0] || val[1] || val[2]).location + val[3].location
865
+
866
+ params = val[0]&.value || [[], [], nil, [], {}, {}, nil]
867
+
868
+ type = Types::Function.new(
869
+ required_positionals: params[0],
870
+ optional_positionals: params[1],
871
+ rest_positionals: params[2],
872
+ trailing_positionals: params[3],
873
+ required_keywords: params[4],
874
+ optional_keywords: params[5],
875
+ rest_keywords: params[6],
876
+ return_type: val[3]
877
+ )
878
+
879
+ block = val[1].value
880
+
881
+ result = LocatedValue.new(value: [type, block], location: location)
882
+ }
883
+ | simple_function_type {
884
+ result = LocatedValue.new(value: [val[0].value, nil], location: val[0].location)
885
+ }
886
+
887
+ simple_function_type:
855
888
  kLPAREN params kRPAREN kARROW simple_type {
856
889
  location = val[0].location + val[4].location
857
890
  type = Types::Function.new(
@@ -883,7 +916,7 @@ rule
883
916
  result = LocatedValue.new(value: type, location: location)
884
917
  }
885
918
 
886
- params:
919
+ params:
887
920
  required_positional kCOMMA params {
888
921
  result = val[2]
889
922
  result[0].unshift(val[0])
@@ -1294,6 +1327,10 @@ ANNOTATION_RE = Regexp.union(/%a\{.*?\}/,
1294
1327
  /%a\(.*?\)/,
1295
1328
  /%a\<.*?\>/,
1296
1329
  /%a\|.*?\|/)
1330
+
1331
+ escape_sequences = %w[a b e f n r s t v "].map { |l| "\\\\#{l}" }
1332
+ DBL_QUOTE_STR_ESCAPE_SEQUENCES_RE = /(#{escape_sequences.join("|")})/
1333
+
1297
1334
  def next_token
1298
1335
  if @type
1299
1336
  type = @type
@@ -1373,7 +1410,21 @@ def next_token
1373
1410
  when input.scan(/[a-z_]\w*\b/)
1374
1411
  new_token(:tLIDENT)
1375
1412
  when input.scan(/"(\\"|[^"])*"/)
1376
- s = input.matched.yield_self {|s| s[1, s.length - 2] }.gsub(/\\"/, '"')
1413
+ s = input.matched.yield_self {|s| s[1, s.length - 2] }
1414
+ .gsub(DBL_QUOTE_STR_ESCAPE_SEQUENCES_RE) do |match|
1415
+ case match
1416
+ when '\\a' then "\a"
1417
+ when '\\b' then "\b"
1418
+ when '\\e' then "\e"
1419
+ when '\\f' then "\f"
1420
+ when '\\n' then "\n"
1421
+ when '\\r' then "\r"
1422
+ when '\\s' then "\s"
1423
+ when '\\t' then "\t"
1424
+ when '\\v' then "\v"
1425
+ when '\\"' then '"'
1426
+ end
1427
+ end
1377
1428
  new_token(:tSTRING, s)
1378
1429
  when input.scan(/'(\\'|[^'])*'/)
1379
1430
  s = input.matched.yield_self {|s| s[1, s.length - 2] }.gsub(/\\'/, "'")
@@ -15,6 +15,14 @@ module RBS
15
15
  :instance
16
16
  end
17
17
  end
18
+
19
+ def attribute_kind
20
+ if singleton
21
+ :singleton
22
+ else
23
+ :instance
24
+ end
25
+ end
18
26
  end
19
27
 
20
28
  attr_reader :source_decls
@@ -77,7 +85,7 @@ module RBS
77
85
  class_name, super_class, *class_body = node.children
78
86
  kls = AST::Declarations::Class.new(
79
87
  name: const_to_name(class_name),
80
- super_class: super_class && AST::Declarations::Class::Super.new(name: const_to_name(super_class), args: []),
88
+ super_class: super_class && AST::Declarations::Class::Super.new(name: const_to_name(super_class), args: [], location: nil),
81
89
  type_params: AST::Declarations::ModuleTypeParams.empty,
82
90
  members: [],
83
91
  annotations: [],
@@ -202,6 +210,7 @@ module RBS
202
210
  name: name,
203
211
  ivar_name: nil,
204
212
  type: Types::Bases::Any.new(location: nil),
213
+ kind: context.attribute_kind,
205
214
  location: nil,
206
215
  comment: comments[node.first_lineno - 1],
207
216
  annotations: []
@@ -215,6 +224,7 @@ module RBS
215
224
  name: name,
216
225
  ivar_name: nil,
217
226
  type: Types::Bases::Any.new(location: nil),
227
+ kind: context.attribute_kind,
218
228
  location: nil,
219
229
  comment: comments[node.first_lineno - 1],
220
230
  annotations: []
@@ -228,6 +238,7 @@ module RBS
228
238
  name: name,
229
239
  ivar_name: nil,
230
240
  type: Types::Bases::Any.new(location: nil),
241
+ kind: context.attribute_kind,
231
242
  location: nil,
232
243
  comment: comments[node.first_lineno - 1],
233
244
  annotations: []
@@ -549,7 +560,7 @@ module RBS
549
560
  method_block = nil
550
561
 
551
562
  if block
552
- method_block = MethodType::Block.new(
563
+ method_block = Types::Block.new(
553
564
  required: true,
554
565
  type: Types::Function.empty(untyped)
555
566
  )
@@ -557,7 +568,7 @@ module RBS
557
568
 
558
569
  if body_node
559
570
  if (yields = any_node?(body_node) {|n| n.type == :YIELD })
560
- method_block = MethodType::Block.new(
571
+ method_block = Types::Block.new(
561
572
  required: true,
562
573
  type: Types::Function.empty(untyped)
563
574
  )
@@ -47,7 +47,7 @@ module RBS
47
47
  def push_class(name, super_class, comment:)
48
48
  modules.push AST::Declarations::Class.new(
49
49
  name: nested_name(name),
50
- super_class: super_class && AST::Declarations::Class::Super.new(name: const_to_name(super_class), args: []),
50
+ super_class: super_class && AST::Declarations::Class::Super.new(name: const_to_name(super_class), args: [], location: nil),
51
51
  type_params: AST::Declarations::ModuleTypeParams.empty,
52
52
  members: [],
53
53
  annotations: [],
@@ -387,19 +387,19 @@ module RBS
387
387
  if block
388
388
  if (type = vars[block])
389
389
  if type.is_a?(Types::Proc)
390
- method_block = MethodType::Block.new(required: true, type: type.type)
390
+ method_block = Types::Block.new(required: true, type: type.type)
391
391
  elsif type.is_a?(Types::Bases::Any)
392
- method_block = MethodType::Block.new(
392
+ method_block = Types::Block.new(
393
393
  required: true,
394
394
  type: Types::Function.empty(Types::Bases::Any.new(location: nil))
395
395
  )
396
396
  # Handle an optional block like `T.nilable(T.proc.void)`.
397
397
  elsif type.is_a?(Types::Optional) && type.type.is_a?(Types::Proc)
398
- method_block = MethodType::Block.new(required: false, type: type.type.type)
398
+ method_block = Types::Block.new(required: false, type: type.type.type)
399
399
  else
400
400
  STDERR.puts "Unexpected block type: #{type}"
401
401
  PP.pp args_node, STDERR
402
- method_block = MethodType::Block.new(
402
+ method_block = Types::Block.new(
403
403
  required: true,
404
404
  type: Types::Function.empty(Types::Bases::Any.new(location: nil))
405
405
  )
@@ -485,7 +485,7 @@ module RBS
485
485
  Types::Tuple.new(types: types, location: nil)
486
486
  else
487
487
  if proc_type?(type_node)
488
- Types::Proc.new(type: method_type(nil, type_node, variables: variables).type, location: nil)
488
+ Types::Proc.new(type: method_type(nil, type_node, variables: variables).type, block: nil, location: nil)
489
489
  else
490
490
  STDERR.puts "Unexpected type_node:"
491
491
  PP.pp type_node, STDERR
@@ -61,11 +61,32 @@ module RBS
61
61
  end
62
62
  end
63
63
 
64
- def each_mixin(mixins, *super_mixes)
65
- supers = Set.new(super_mixes)
66
- mixins.each do |mix|
64
+ def each_included_module(type_name, mod)
65
+ supers = Set[]
66
+
67
+ mod.included_modules.each do |mix|
68
+ supers.merge(mix.included_modules)
69
+ end
70
+
71
+ if mod.is_a?(Class)
72
+ mod.superclass.included_modules.each do |mix|
73
+ supers << mix
74
+ supers.merge(mix.included_modules)
75
+ end
76
+ end
77
+
78
+ mod.included_modules.each do |mix|
67
79
  unless supers.include?(mix)
68
- yield mix
80
+ unless const_name(mix)
81
+ RBS.logger.warn("Skipping anonymous module #{mix} included in #{mod}")
82
+ else
83
+ module_name = to_type_name(const_name(mix))
84
+ if module_name.namespace == type_name.namespace
85
+ module_name = TypeName.new(name: module_name.name, namespace: Namespace.empty)
86
+ end
87
+
88
+ yield module_name, mix
89
+ end
69
90
  end
70
91
  end
71
92
  end
@@ -103,7 +124,7 @@ module RBS
103
124
  when :keyrest
104
125
  rest_keywords = Types::Function::Param.new(name: nil, type: untyped)
105
126
  when :block
106
- block = MethodType::Block.new(
127
+ block = Types::Block.new(
107
128
  type: Types::Function.empty(untyped).update(rest_positionals: Types::Function::Param.new(name: nil, type: untyped)),
108
129
  required: true
109
130
  )
@@ -298,11 +319,11 @@ module RBS
298
319
  location: nil
299
320
  )
300
321
  else
301
- Types::ClassInstance.new(name: to_type_name(value.class.to_s), args: [], location: nil)
322
+ Types::ClassInstance.new(name: to_type_name(const_name(value.class)), args: [], location: nil)
302
323
  end
303
324
 
304
325
  @decls << AST::Declarations::Constant.new(
305
- name: "#{mod.to_s}::#{name}",
326
+ name: "#{const_name(mod)}::#{name}",
306
327
  type: type,
307
328
  location: nil,
308
329
  comment: nil
@@ -311,14 +332,14 @@ module RBS
311
332
  end
312
333
 
313
334
  def generate_class(mod)
314
- type_name = to_type_name(mod.name)
335
+ type_name = to_type_name(const_name(mod))
315
336
  super_class = if mod.superclass == ::Object
316
337
  nil
317
- elsif mod.superclass.name.nil?
338
+ elsif const_name(mod.superclass).nil?
318
339
  RBS.logger.warn("Skipping anonymous superclass #{mod.superclass} of #{mod}")
319
340
  nil
320
341
  else
321
- AST::Declarations::Class::Super.new(name: to_type_name(mod.superclass.name), args: [])
342
+ AST::Declarations::Class::Super.new(name: to_type_name(const_name(mod.superclass)), args: [], location: nil)
322
343
  end
323
344
 
324
345
  decl = AST::Declarations::Class.new(
@@ -331,17 +352,7 @@ module RBS
331
352
  comment: nil
332
353
  )
333
354
 
334
- each_mixin(mod.included_modules, *mod.superclass.included_modules, *mod.included_modules.flat_map(&:included_modules)) do |included_module|
335
- unless included_module.name
336
- RBS.logger.warn("Skipping anonymous module #{included_module} included in #{mod}")
337
- next
338
- end
339
-
340
- module_name = to_type_name(included_module.name)
341
- if module_name.namespace == type_name.namespace
342
- module_name = TypeName.new(name: module_name.name, namespace: Namespace.empty)
343
- end
344
-
355
+ each_included_module(type_name, mod) do |module_name, _|
345
356
  decl.members << AST::Members::Include.new(
346
357
  name: module_name,
347
358
  args: [],
@@ -351,6 +362,16 @@ module RBS
351
362
  )
352
363
  end
353
364
 
365
+ each_included_module(type_name, mod.singleton_class) do |module_name, _|
366
+ decl.members << AST::Members::Extend.new(
367
+ name: module_name,
368
+ args: [],
369
+ location: nil,
370
+ comment: nil,
371
+ annotations: []
372
+ )
373
+ end
374
+
354
375
  generate_methods(mod, type_name, decl.members)
355
376
 
356
377
  @decls << decl
@@ -378,18 +399,7 @@ module RBS
378
399
  comment: nil
379
400
  )
380
401
 
381
- each_mixin(mod.included_modules, *mod.included_modules.flat_map(&:included_modules), namespace: type_name.namespace) do |included_module|
382
- included_module_name = const_name(included_module)
383
- unless included_module_name
384
- RBS.logger.warn("Skipping anonymous module #{included_module} included in #{mod}")
385
- next
386
- end
387
-
388
- module_name = to_type_name(included_module_name)
389
- if module_name.namespace == type_name.namespace
390
- module_name = TypeName.new(name: module_name.name, namespace: Namespace.empty)
391
- end
392
-
402
+ each_included_module(type_name, mod) do |module_name, _|
393
403
  decl.members << AST::Members::Include.new(
394
404
  name: module_name,
395
405
  args: [],
@@ -399,6 +409,16 @@ module RBS
399
409
  )
400
410
  end
401
411
 
412
+ each_included_module(type_name, mod.singleton_class) do |module_name, _|
413
+ decl.members << AST::Members::Extend.new(
414
+ name: module_name,
415
+ args: [],
416
+ location: nil,
417
+ comment: nil,
418
+ annotations: []
419
+ )
420
+ end
421
+
402
422
  generate_methods(mod, type_name, decl.members)
403
423
 
404
424
  @decls << decl