rbs 1.8.1 → 2.0.0.pre1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (66) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +51 -4
  3. data/docs/collection.md +23 -1
  4. data/docs/syntax.md +94 -41
  5. data/ext/rbs_extension/constants.c +2 -6
  6. data/ext/rbs_extension/constants.h +1 -2
  7. data/ext/rbs_extension/parser.c +212 -178
  8. data/ext/rbs_extension/parserstate.c +6 -2
  9. data/ext/rbs_extension/parserstate.h +10 -0
  10. data/ext/rbs_extension/ruby_objs.c +9 -11
  11. data/ext/rbs_extension/ruby_objs.h +1 -2
  12. data/lib/rbs/ast/declarations.rb +0 -97
  13. data/lib/rbs/ast/type_param.rb +134 -0
  14. data/lib/rbs/cli.rb +32 -4
  15. data/lib/rbs/collection/config/lockfile_generator.rb +26 -18
  16. data/lib/rbs/collection/sources/git.rb +9 -0
  17. data/lib/rbs/collection/sources/rubygems.rb +7 -0
  18. data/lib/rbs/collection/sources/stdlib.rb +6 -0
  19. data/lib/rbs/definition.rb +9 -0
  20. data/lib/rbs/definition_builder.rb +20 -14
  21. data/lib/rbs/environment.rb +32 -9
  22. data/lib/rbs/environment_loader.rb +0 -2
  23. data/lib/rbs/errors.rb +20 -7
  24. data/lib/rbs/location_aux.rb +2 -0
  25. data/lib/rbs/method_type.rb +29 -6
  26. data/lib/rbs/prototype/rb.rb +3 -3
  27. data/lib/rbs/prototype/rbi.rb +8 -6
  28. data/lib/rbs/prototype/runtime.rb +4 -4
  29. data/lib/rbs/types.rb +89 -0
  30. data/lib/rbs/validator.rb +56 -1
  31. data/lib/rbs/variance_calculator.rb +9 -8
  32. data/lib/rbs/version.rb +1 -1
  33. data/lib/rbs/writer.rb +1 -13
  34. data/lib/rbs.rb +1 -0
  35. data/schema/decls.json +16 -55
  36. data/schema/methodType.json +1 -1
  37. data/schema/typeParam.json +36 -0
  38. data/sig/collection/collections.rbs +9 -0
  39. data/sig/collection/config.rbs +2 -2
  40. data/sig/declarations.rbs +8 -58
  41. data/sig/definition.rbs +11 -1
  42. data/sig/definition_builder.rbs +1 -1
  43. data/sig/environment.rbs +7 -1
  44. data/sig/errors.rbs +19 -4
  45. data/sig/location.rbs +3 -1
  46. data/sig/locator.rbs +1 -1
  47. data/sig/method_types.rbs +25 -4
  48. data/sig/type_param.rbs +74 -0
  49. data/sig/types.rbs +27 -1
  50. data/sig/validator.rbs +31 -2
  51. data/sig/variance_calculator.rbs +1 -1
  52. data/sig/writer.rbs +1 -1
  53. data/stdlib/bigdecimal-math/0/manifest.yaml +2 -0
  54. data/stdlib/csv/0/manifest.yaml +2 -0
  55. data/stdlib/logger/0/manifest.yaml +2 -0
  56. data/stdlib/net-http/0/manifest.yaml +2 -0
  57. data/stdlib/openssl/0/manifest.yaml +2 -0
  58. data/stdlib/prime/0/manifest.yaml +2 -0
  59. data/stdlib/resolv/0/manifest.yaml +3 -0
  60. data/stdlib/uri/0/common.rbs +10 -5
  61. data/stdlib/uri/0/ftp.rbs +10 -0
  62. data/stdlib/uri/0/mailto.rbs +5 -0
  63. data/stdlib/uri/0/ws.rbs +10 -0
  64. data/stdlib/uri/0/wss.rbs +7 -0
  65. data/stdlib/yaml/0/manifest.yaml +3 -0
  66. metadata +19 -4
@@ -0,0 +1,134 @@
1
+ module RBS
2
+ module AST
3
+ class TypeParam
4
+ attr_reader :name, :variance, :location, :upper_bound
5
+
6
+ def initialize(name:, variance:, upper_bound:, location:)
7
+ @name = name
8
+ @variance = variance
9
+ @upper_bound = upper_bound
10
+ @location = location
11
+ @unchecked = false
12
+ end
13
+
14
+ def unchecked!(value = true)
15
+ @unchecked = value ? true : false
16
+ self
17
+ end
18
+
19
+ def unchecked?
20
+ @unchecked
21
+ end
22
+
23
+ def ==(other)
24
+ other.is_a?(TypeParam) &&
25
+ other.name == name &&
26
+ other.variance == variance &&
27
+ other.upper_bound == upper_bound &&
28
+ other.unchecked? == unchecked?
29
+ end
30
+
31
+ alias eql? ==
32
+
33
+ def hash
34
+ self.class.hash ^ name.hash ^ variance.hash ^ upper_bound.hash ^ unchecked?.hash
35
+ end
36
+
37
+ def to_json(state = JSON::State.new)
38
+ {
39
+ name: name,
40
+ variance: variance,
41
+ unchecked: unchecked?,
42
+ location: location,
43
+ upper_bound: upper_bound
44
+ }.to_json(state)
45
+ end
46
+
47
+ def rename(name)
48
+ TypeParam.new(
49
+ name: name,
50
+ variance: variance,
51
+ upper_bound: upper_bound,
52
+ location: location
53
+ ).unchecked!(unchecked?)
54
+ end
55
+
56
+ def map_type(&block)
57
+ if b = upper_bound
58
+ _upper_bound = yield(b)
59
+ end
60
+
61
+ TypeParam.new(
62
+ name: name,
63
+ variance: variance,
64
+ upper_bound: _upper_bound,
65
+ location: location
66
+ ).unchecked!(unchecked?)
67
+ end
68
+
69
+ def self.resolve_variables(params)
70
+ return if params.empty?
71
+
72
+ vars = Set.new(params.map(&:name))
73
+
74
+ params.map! do |param|
75
+ param.map_type {|bound| _ = subst_var(vars, bound) }
76
+ end
77
+ end
78
+
79
+ def self.subst_var(vars, type)
80
+ case type
81
+ when Types::ClassInstance
82
+ namespace = type.name.namespace
83
+ if namespace.relative? && namespace.empty? && vars.member?(type.name.name)
84
+ return Types::Variable.new(name: type.name.name, location: type.location)
85
+ end
86
+ end
87
+
88
+ type.map_type {|t| subst_var(vars, t) }
89
+ end
90
+
91
+ def self.rename(params, new_names:)
92
+ raise unless params.size == new_names.size
93
+
94
+ subst = Substitution.build(new_names, Types::Variable.build(new_names))
95
+
96
+ params.map.with_index do |param, index|
97
+ new_name = new_names[index]
98
+
99
+ TypeParam.new(
100
+ name: new_name,
101
+ variance: param.variance,
102
+ upper_bound: param.upper_bound&.map_type {|type| type.sub(subst) },
103
+ location: param.location
104
+ ).unchecked!(param.unchecked?)
105
+ end
106
+ end
107
+
108
+ def to_s
109
+ s = ""
110
+
111
+ if unchecked?
112
+ s << "unchecked "
113
+ end
114
+
115
+ case variance
116
+ when :invariant
117
+ # nop
118
+ when :covariant
119
+ s << "out "
120
+ when :contravariant
121
+ s << "in "
122
+ end
123
+
124
+ s << name.to_s
125
+
126
+ if type = upper_bound
127
+ s << " < #{type}"
128
+ end
129
+
130
+ s
131
+ end
132
+ end
133
+ end
134
+ end
data/lib/rbs/cli.rb CHANGED
@@ -430,7 +430,7 @@ EOU
430
430
  builder = DefinitionBuilder.new(env: env)
431
431
  validator = Validator.new(env: env, resolver: TypeNameResolver.from_env(env))
432
432
 
433
- env.class_decls.each_key do |name|
433
+ env.class_decls.each do |name, decl|
434
434
  stdout.puts "Validating class/module definition: `#{name}`..."
435
435
  builder.build_instance(name).each_type do |type|
436
436
  validator.validate_type type, context: [Namespace.root]
@@ -438,13 +438,43 @@ EOU
438
438
  builder.build_singleton(name).each_type do |type|
439
439
  validator.validate_type type, context: [Namespace.root]
440
440
  end
441
+
442
+ d = decl.primary.decl
443
+
444
+ validator.validate_type_params(
445
+ d.type_params,
446
+ type_name: name,
447
+ location: d.location&.aref(:type_params)
448
+ )
449
+
450
+ decl.decls.each do |d|
451
+ d.decl.each_member do |member|
452
+ case member
453
+ when AST::Members::MethodDefinition
454
+ validator.validate_method_definition(member, type_name: name)
455
+ end
456
+ end
457
+ end
441
458
  end
442
459
 
443
- env.interface_decls.each_key do |name|
460
+ env.interface_decls.each do |name, decl|
444
461
  stdout.puts "Validating interface: `#{name}`..."
445
462
  builder.build_interface(name).each_type do |type|
446
463
  validator.validate_type type, context: [Namespace.root]
447
464
  end
465
+
466
+ validator.validate_type_params(
467
+ decl.decl.type_params,
468
+ type_name: name,
469
+ location: decl.decl.location&.aref(:type_params)
470
+ )
471
+
472
+ decl.decl.members.each do |member|
473
+ case member
474
+ when AST::Members::MethodDefinition
475
+ validator.validate_method_definition(member, type_name: name)
476
+ end
477
+ end
448
478
  end
449
479
 
450
480
  env.constant_decls.each do |name, const|
@@ -836,8 +866,6 @@ EOB
836
866
  end
837
867
 
838
868
  def run_collection(args, options)
839
- warn "warning: rbs collection is experimental, and the behavior may change until RBS v2.0"
840
-
841
869
  opts = collection_options(args)
842
870
  params = {}
843
871
  opts.order args.drop(1), into: params
@@ -15,15 +15,20 @@ module RBS
15
15
  @lock_path = Config.to_lockfile_path(config_path)
16
16
  @lock = Config.from_path(lock_path) if lock_path.exist? && with_lockfile
17
17
  @gemfile_lock = Bundler::LockfileParser.new(gemfile_lock_path.read)
18
+ @gem_queue = []
18
19
  end
19
20
 
20
21
  def generate
21
22
  config.gems.each do |gem|
22
- assign_gem(gem_name: gem['name'], version: gem['version'])
23
+ @gem_queue.push({ name: gem['name'], version: gem['version'] })
23
24
  end
24
25
 
25
26
  gemfile_lock_gems do |spec|
26
- assign_gem(gem_name: spec.name, version: spec.version)
27
+ @gem_queue.push({ name: spec.name, version: spec.version })
28
+ end
29
+
30
+ while gem = @gem_queue.shift
31
+ assign_gem(**gem)
27
32
  end
28
33
  remove_ignored_gems!
29
34
 
@@ -31,30 +36,33 @@ module RBS
31
36
  config
32
37
  end
33
38
 
34
- private def assign_gem(gem_name:, version:)
35
- locked = lock&.gem(gem_name)
36
- specified = config.gem(gem_name)
39
+ private def assign_gem(name:, version:)
40
+ locked = lock&.gem(name)
41
+ specified = config.gem(name)
37
42
 
38
43
  return if specified&.dig('ignore')
39
44
  return if specified&.dig('source') # skip if the source is already filled
40
45
 
41
- if locked
42
- # If rbs_collection.lock.yaml contain the gem, use it.
43
- upsert_gem specified, locked
44
- else
45
- # Find the gem from gem_collection.
46
- source = find_source(gem_name: gem_name)
46
+ # If rbs_collection.lock.yaml contain the gem, use it.
47
+ # Else find the gem from gem_collection.
48
+ unless locked
49
+ source = find_source(name: name)
47
50
  return unless source
48
51
 
49
52
  installed_version = version
50
- best_version = find_best_version(version: installed_version, versions: source.versions({ 'name' => gem_name }))
51
- # @type var new_content: RBS::Collection::Config::gem_entry
52
- new_content = {
53
- 'name' => gem_name,
53
+ best_version = find_best_version(version: installed_version, versions: source.versions({ 'name' => name }))
54
+ locked = {
55
+ 'name' => name,
54
56
  'version' => best_version.to_s,
55
57
  'source' => source.to_lockfile,
56
58
  }
57
- upsert_gem specified, new_content
59
+ end
60
+
61
+ upsert_gem specified, locked
62
+ source = Sources.from_config_entry(locked['source'])
63
+ manifest = source.manifest_of(locked) or return
64
+ manifest['dependencies']&.each do |dep|
65
+ @gem_queue.push({ name: dep['name'], version: nil} )
58
66
  end
59
67
  end
60
68
 
@@ -76,10 +84,10 @@ module RBS
76
84
  end
77
85
  end
78
86
 
79
- private def find_source(gem_name:)
87
+ private def find_source(name:)
80
88
  sources = config.sources
81
89
 
82
- sources.find { |c| c.has?({ 'name' => gem_name, 'revision' => nil } ) }
90
+ sources.find { |c| c.has?({ 'name' => name, 'revision' => nil } ) }
83
91
  end
84
92
 
85
93
  private def find_best_version(version:, versions:)
@@ -50,6 +50,15 @@ module RBS
50
50
  end
51
51
  end
52
52
 
53
+ def manifest_of(config_entry)
54
+ gem_name = config_entry['name']
55
+ version = config_entry['version'] or raise
56
+ gem_dir = gem_repo_dir.join(gem_name, version)
57
+
58
+ manifest_path = gem_dir.join('manifest.yaml')
59
+ YAML.safe_load(manifest_path.read) if manifest_path.exist?
60
+ end
61
+
53
62
  private def _install(dest:, config_entry:)
54
63
  gem_name = config_entry['name']
55
64
  version = config_entry['version'] or raise
@@ -25,6 +25,13 @@ module RBS
25
25
  stdout.puts "Using #{name}:#{version} (#{from})"
26
26
  end
27
27
 
28
+ def manifest_of(config_entry)
29
+ _, sig_path = gem_sig_path(config_entry)
30
+ sig_path or raise
31
+ manifest_path = sig_path.join('manifest.yaml')
32
+ YAML.safe_load(manifest_path.read) if manifest_path.exist?
33
+ end
34
+
28
35
  def to_lockfile
29
36
  {
30
37
  'type' => 'rubygems',
@@ -23,6 +23,12 @@ module RBS
23
23
  stdout.puts "Using #{name}:#{version} (#{from})"
24
24
  end
25
25
 
26
+ def manifest_of(config_entry)
27
+ version = config_entry['version'] or raise
28
+ manifest_path = gem_dir(config_entry).join(version, 'manifest.yaml')
29
+ YAML.safe_load(manifest_path.read) if manifest_path.exist?
30
+ end
31
+
26
32
  def to_lockfile
27
33
  {
28
34
  'type' => 'stdlib',
@@ -155,6 +155,15 @@ module RBS
155
155
  )
156
156
  end
157
157
 
158
+ def map_type_bound(&block)
159
+ self.class.new(
160
+ super_method: super_method&.map_type_bound(&block),
161
+ defs: defs.map {|defn| defn.update(type: defn.type.map_type_bound(&block)) },
162
+ accessibility: @accessibility,
163
+ alias_of: alias_of
164
+ )
165
+ end
166
+
158
167
  def map_method_type(&block)
159
168
  self.class.new(
160
169
  super_method: super_method,
@@ -385,7 +385,7 @@ module RBS
385
385
  initialize = instance.methods[:initialize]
386
386
 
387
387
  if initialize
388
- class_params = entry.type_params.each.map(&:name)
388
+ class_params = entry.type_params
389
389
 
390
390
  # Inject a virtual _typed new_.
391
391
  initialize_defs = initialize.defs
@@ -394,28 +394,34 @@ module RBS
394
394
  defs: initialize_defs.map do |initialize_def|
395
395
  method_type = initialize_def.type
396
396
 
397
- class_type_param_vars = Set.new(class_params)
398
- method_type_param_vars = Set.new(method_type.type_params)
397
+ class_type_param_vars = Set.new(class_params.map(&:name))
398
+ method_type_param_vars = Set.new(method_type.type_params.map(&:name))
399
399
 
400
400
  if class_type_param_vars.intersect?(method_type_param_vars)
401
- renamed_method_params = method_type.type_params.map do |name|
402
- if class_type_param_vars.include?(name)
403
- Types::Variable.fresh(name).name
401
+ new_method_param_names = method_type.type_params.map do |method_param|
402
+ if class_type_param_vars.include?(method_param.name)
403
+ Types::Variable.fresh(method_param.name).name
404
404
  else
405
- name
405
+ method_param.name
406
406
  end
407
407
  end
408
- method_params = class_params + renamed_method_params
409
408
 
410
- sub = Substitution.build(method_type.type_params, Types::Variable.build(renamed_method_params))
409
+ sub = Substitution.build(
410
+ method_type.type_params.map(&:name),
411
+ Types::Variable.build(new_method_param_names)
412
+ )
413
+
414
+ method_params = class_params + AST::TypeParam.rename(method_type.type_params, new_names: new_method_param_names)
415
+ method_type = method_type
416
+ .update(type_params: [])
417
+ .sub(sub)
418
+ .update(type_params: method_params)
411
419
  else
412
- method_params = class_params + method_type.type_params
413
- sub = Substitution.build([], [])
420
+ method_type = method_type
421
+ .update(type_params: class_params + method_type.type_params)
414
422
  end
415
423
 
416
- method_type = method_type.map_type {|ty| ty.sub(sub) }
417
424
  method_type = method_type.update(
418
- type_params: method_params,
419
425
  type: method_type.type.with_return_type(
420
426
  Types::ClassInstance.new(
421
427
  name: type_name,
@@ -446,7 +452,7 @@ module RBS
446
452
 
447
453
  def validate_params_with(type_params, result:)
448
454
  type_params.each do |param|
449
- unless param.skip_validation
455
+ unless param.unchecked?
450
456
  unless result.compatible?(param.name, with_annotation: param.variance)
451
457
  yield param
452
458
  end
@@ -39,22 +39,29 @@ module RBS
39
39
 
40
40
  def validate_type_params
41
41
  unless decls.empty?
42
+ # @type var hd_decl: MultiEntry::D[module_decl]
43
+ # @type var tl_decls: Array[MultiEntry::D[module_decl]]
42
44
  hd_decl, *tl_decls = decls
43
45
  raise unless hd_decl
44
46
 
45
47
  hd_params = hd_decl.decl.type_params
46
- hd_names = hd_params.params.map(&:name)
47
48
 
48
49
  tl_decls.each do |tl_decl|
49
50
  tl_params = tl_decl.decl.type_params
50
51
 
51
- unless hd_params.size == tl_params.size && hd_params == tl_params.rename_to(hd_names)
52
+ unless compatible_params?(hd_params, tl_params)
52
53
  raise GenericParameterMismatchError.new(name: name, decl: tl_decl.decl)
53
54
  end
54
55
  end
55
56
  end
56
57
  end
57
58
 
59
+ def compatible_params?(ps1, ps2)
60
+ if ps1.size == ps2.size
61
+ ps1 == AST::TypeParam.rename(ps2, new_names: ps1.map(&:name))
62
+ end
63
+ end
64
+
58
65
  def type_params
59
66
  primary.decl.type_params
60
67
  end
@@ -240,17 +247,19 @@ module RBS
240
247
  array.unshift(head + decl.name.to_namespace)
241
248
  end
242
249
 
250
+ outer_context = context.drop(1)
251
+
243
252
  case decl
244
253
  when AST::Declarations::Class
245
254
  outer_ = outer + [decl]
246
255
  prefix_ = prefix + decl.name.to_namespace
247
256
  AST::Declarations::Class.new(
248
257
  name: decl.name.with_prefix(prefix),
249
- type_params: decl.type_params,
258
+ type_params: resolve_type_params(resolver, decl.type_params, context: context),
250
259
  super_class: decl.super_class&.yield_self do |super_class|
251
260
  AST::Declarations::Class::Super.new(
252
- name: absolute_type_name(resolver, super_class.name, context: context),
253
- args: super_class.args.map {|type| absolute_type(resolver, type, context: context) },
261
+ name: absolute_type_name(resolver, super_class.name, context: outer_context),
262
+ args: super_class.args.map {|type| absolute_type(resolver, type, context: outer_context) },
254
263
  location: super_class.location
255
264
  )
256
265
  end,
@@ -278,7 +287,7 @@ module RBS
278
287
  prefix_ = prefix + decl.name.to_namespace
279
288
  AST::Declarations::Module.new(
280
289
  name: decl.name.with_prefix(prefix),
281
- type_params: decl.type_params,
290
+ type_params: resolve_type_params(resolver, decl.type_params, context: context),
282
291
  self_types: decl.self_types.map do |module_self|
283
292
  AST::Declarations::Module::Self.new(
284
293
  name: absolute_type_name(resolver, module_self.name, context: context),
@@ -308,7 +317,7 @@ module RBS
308
317
  when AST::Declarations::Interface
309
318
  AST::Declarations::Interface.new(
310
319
  name: decl.name.with_prefix(prefix),
311
- type_params: decl.type_params,
320
+ type_params: resolve_type_params(resolver, decl.type_params, context: context),
312
321
  members: decl.members.map do |member|
313
322
  resolve_member(resolver, member, context: context)
314
323
  end,
@@ -319,7 +328,7 @@ module RBS
319
328
  when AST::Declarations::Alias
320
329
  AST::Declarations::Alias.new(
321
330
  name: decl.name.with_prefix(prefix),
322
- type_params: decl.type_params,
331
+ type_params: resolve_type_params(resolver, decl.type_params, context: context),
323
332
  type: absolute_type(resolver, decl.type, context: context),
324
333
  location: decl.location,
325
334
  annotations: decl.annotations,
@@ -343,7 +352,7 @@ module RBS
343
352
  name: member.name,
344
353
  kind: member.kind,
345
354
  types: member.types.map do |type|
346
- type.map_type {|ty| absolute_type(resolver, ty, context: context) }
355
+ resolve_method_type(resolver, type, context: context)
347
356
  end,
348
357
  comment: member.comment,
349
358
  overload: member.overload?,
@@ -430,6 +439,20 @@ module RBS
430
439
  end
431
440
  end
432
441
 
442
+ def resolve_method_type(resolver, type, context:)
443
+ type.map_type do |ty|
444
+ absolute_type(resolver, ty, context: context)
445
+ end.map_type_bound do |bound|
446
+ _ = absolute_type(resolver, bound, context: context)
447
+ end
448
+ end
449
+
450
+ def resolve_type_params(resolver, params, context:)
451
+ params.map do |param|
452
+ param.map_type {|type| _ = absolute_type(resolver, type, context: context) }
453
+ end
454
+ end
455
+
433
456
  def absolute_type_name(resolver, type_name, context:)
434
457
  resolver.resolve(type_name, context: context) || type_name
435
458
  end
@@ -48,8 +48,6 @@ module RBS
48
48
  end
49
49
 
50
50
  def add_collection(collection_config)
51
- warn "warning: rbs collection is experimental, and the behavior may change until RBS v2.0"
52
-
53
51
  collection_config.check_rbs_availability!
54
52
 
55
53
  repository.add(collection_config.repo_path)
data/lib/rbs/errors.rb CHANGED
@@ -14,11 +14,11 @@ module RBS
14
14
  end
15
15
  end
16
16
 
17
- class ErrorBase < StandardError; end
18
- class LoadingError < ErrorBase; end
19
- class DefinitionError < ErrorBase; end
17
+ class BaseError < StandardError; end
18
+ class LoadingError < BaseError; end
19
+ class DefinitionError < BaseError; end
20
20
 
21
- class ParsingError < ErrorBase
21
+ class ParsingError < BaseError
22
22
  attr_reader :location
23
23
  attr_reader :error_message
24
24
  attr_reader :token_type
@@ -105,7 +105,7 @@ module RBS
105
105
  end
106
106
  end
107
107
 
108
- class NoTypeFoundError < ErrorBase
108
+ class NoTypeFoundError < BaseError
109
109
  attr_reader :type_name
110
110
  attr_reader :location
111
111
 
@@ -416,7 +416,7 @@ module RBS
416
416
  end
417
417
  end
418
418
 
419
- class RecursiveTypeAliasError < LoadingError
419
+ class RecursiveTypeAliasError < BaseError
420
420
  attr_reader :alias_names
421
421
  attr_reader :location
422
422
 
@@ -432,7 +432,7 @@ module RBS
432
432
  end
433
433
  end
434
434
 
435
- class NonregularTypeAliasError < LoadingError
435
+ class NonregularTypeAliasError < BaseError
436
436
  attr_reader :diagnostic
437
437
  attr_reader :location
438
438
 
@@ -443,4 +443,17 @@ module RBS
443
443
  super "#{Location.to_string location}: Nonregular generic type alias is prohibited: #{diagnostic.type_name}, #{diagnostic.nonregular_type}"
444
444
  end
445
445
  end
446
+
447
+ class CyclicTypeParameterBound < BaseError
448
+ attr_reader :params, :type_name, :method_name, :location
449
+
450
+ def initialize(type_name:, method_name:, params:, location:)
451
+ @type_name = type_name
452
+ @method_name = method_name
453
+ @params = params
454
+ @location = location
455
+
456
+ super "#{Location.to_string(location)}: Cyclic type parameter bound is prohibited"
457
+ end
458
+ end
446
459
  end
@@ -17,6 +17,8 @@ module RBS
17
17
  end
18
18
  end
19
19
 
20
+ alias aref []
21
+
20
22
  WithChildren = self
21
23
 
22
24
  def name
@@ -29,11 +29,18 @@ module RBS
29
29
  end
30
30
 
31
31
  def sub(s)
32
- s.without(*type_params).yield_self do |sub|
33
- map_type do |ty|
34
- ty.sub(sub)
35
- end
36
- end
32
+ sub = s.without(*type_param_names)
33
+
34
+ self.class.new(
35
+ type_params: type_params.map do |param|
36
+ param.map_type do |bound|
37
+ bound.map_type {|ty| ty.sub(sub) }
38
+ end
39
+ end,
40
+ type: type.sub(sub),
41
+ block: block&.sub(sub),
42
+ location: location
43
+ )
37
44
  end
38
45
 
39
46
  def update(type_params: self.type_params, type: self.type, block: self.block, location: self.location)
@@ -48,7 +55,7 @@ module RBS
48
55
  def free_variables(set = Set.new)
49
56
  type.free_variables(set)
50
57
  block&.type&.free_variables(set)
51
- set.subtract(type_params)
58
+ set.subtract(type_param_names)
52
59
  end
53
60
 
54
61
  def map_type(&block)
@@ -62,6 +69,18 @@ module RBS
62
69
  )
63
70
  end
64
71
 
72
+ def map_type_bound(&block)
73
+ if type_params.empty?
74
+ self
75
+ else
76
+ self.update(
77
+ type_params: type_params.map {|param|
78
+ param.map_type(&block)
79
+ }
80
+ )
81
+ end
82
+ end
83
+
65
84
  def each_type(&block)
66
85
  if block
67
86
  type.each_type(&block)
@@ -89,5 +108,9 @@ module RBS
89
108
  "[#{type_params.join(", ")}] #{s}"
90
109
  end
91
110
  end
111
+
112
+ def type_param_names
113
+ type_params.map(&:name)
114
+ end
92
115
  end
93
116
  end
@@ -49,7 +49,7 @@ module RBS
49
49
  annotations: [],
50
50
  comment: nil,
51
51
  location: nil,
52
- type_params: AST::Declarations::ModuleTypeParams.empty
52
+ type_params: []
53
53
  )
54
54
  decls << top
55
55
  end
@@ -88,7 +88,7 @@ module RBS
88
88
  kls = AST::Declarations::Class.new(
89
89
  name: const_to_name(class_name),
90
90
  super_class: super_class && AST::Declarations::Class::Super.new(name: const_to_name(super_class), args: [], location: nil),
91
- type_params: AST::Declarations::ModuleTypeParams.empty,
91
+ type_params: [],
92
92
  members: [],
93
93
  annotations: [],
94
94
  location: nil,
@@ -108,7 +108,7 @@ module RBS
108
108
 
109
109
  mod = AST::Declarations::Module.new(
110
110
  name: const_to_name(module_name),
111
- type_params: AST::Declarations::ModuleTypeParams.empty,
111
+ type_params: [],
112
112
  self_types: [],
113
113
  members: [],
114
114
  annotations: [],