rbs 1.8.0 → 2.0.0

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 (67) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +82 -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 +18 -7
  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 +49 -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 +62 -11
  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 +11 -2
  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 +8 -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/generic.rbs +34 -34
  63. data/stdlib/uri/0/mailto.rbs +5 -0
  64. data/stdlib/uri/0/ws.rbs +10 -0
  65. data/stdlib/uri/0/wss.rbs +7 -0
  66. data/stdlib/yaml/0/manifest.yaml +3 -0
  67. metadata +17 -2
@@ -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
@@ -104,9 +113,9 @@ module RBS
104
113
  else
105
114
  begin
106
115
  # git v2.27.0 or greater
107
- git 'clone', '--filter=blob:none', remote, git_dir.to_s
116
+ git 'clone', '--filter=blob:none', remote, git_dir.to_s, chdir: nil
108
117
  rescue CommandError
109
- git 'clone', remote, git_dir.to_s
118
+ git 'clone', remote, git_dir.to_s, chdir: nil
110
119
  end
111
120
  end
112
121
 
@@ -131,7 +140,8 @@ module RBS
131
140
  private def git_dir
132
141
  @git_dir ||= (
133
142
  base = Pathname(ENV['XDG_CACHE_HOME'] || File.expand_path("~/.cache"))
134
- dir = base.join('rbs', Digest::SHA256.hexdigest(remote))
143
+ cache_key = remote.start_with?('.') ? "#{remote}\0#{Dir.pwd}" : remote
144
+ dir = base.join('rbs', Digest::SHA256.hexdigest(cache_key))
135
145
  dir.mkpath
136
146
  dir
137
147
  )
@@ -149,13 +159,14 @@ module RBS
149
159
  git('rev-parse', 'HEAD').chomp
150
160
  end
151
161
 
152
- private def git(*cmd)
153
- sh! 'git', *cmd
162
+ private def git(*cmd, **opt)
163
+ sh! 'git', *cmd, **opt
154
164
  end
155
165
 
156
- private def sh!(*cmd)
166
+ private def sh!(*cmd, **opt)
157
167
  RBS.logger.debug "$ #{cmd.join(' ')}"
158
- (__skip__ = Open3.capture3(*cmd, chdir: git_dir)).then do |out, err, status|
168
+ opt = { chdir: git_dir }.merge(opt).compact
169
+ (__skip__ = Open3.capture3(*cmd, **opt)).then do |out, err, status|
159
170
  raise CommandError, "Unexpected status #{status.exitstatus}\n\n#{err}" unless status.success?
160
171
 
161
172
  out
@@ -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,
@@ -291,6 +291,10 @@ module RBS
291
291
  end
292
292
 
293
293
  one_ancestors.each_extended_module do |mod|
294
+ mod.args.each do |arg|
295
+ validate_type_presence(arg)
296
+ end
297
+
294
298
  mod_defn = build_instance(mod.name, no_self_types: true)
295
299
  merge_definition(src: mod_defn,
296
300
  dest: definition,
@@ -299,6 +303,10 @@ module RBS
299
303
 
300
304
  interface_methods = {}
301
305
  one_ancestors.each_extended_interface do |mod|
306
+ mod.args.each do |arg|
307
+ validate_type_presence(arg)
308
+ end
309
+
302
310
  mod_defn = build_interface(mod.name)
303
311
  subst = Substitution.build(mod_defn.type_params, mod.args)
304
312
 
@@ -377,7 +385,7 @@ module RBS
377
385
  initialize = instance.methods[:initialize]
378
386
 
379
387
  if initialize
380
- class_params = entry.type_params.each.map(&:name)
388
+ class_params = entry.type_params
381
389
 
382
390
  # Inject a virtual _typed new_.
383
391
  initialize_defs = initialize.defs
@@ -386,28 +394,34 @@ module RBS
386
394
  defs: initialize_defs.map do |initialize_def|
387
395
  method_type = initialize_def.type
388
396
 
389
- class_type_param_vars = Set.new(class_params)
390
- 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))
391
399
 
392
400
  if class_type_param_vars.intersect?(method_type_param_vars)
393
- renamed_method_params = method_type.type_params.map do |name|
394
- if class_type_param_vars.include?(name)
395
- 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
396
404
  else
397
- name
405
+ method_param.name
398
406
  end
399
407
  end
400
- method_params = class_params + renamed_method_params
401
408
 
402
- 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)
403
419
  else
404
- method_params = class_params + method_type.type_params
405
- sub = Substitution.build([], [])
420
+ method_type = method_type
421
+ .update(type_params: class_params + method_type.type_params)
406
422
  end
407
423
 
408
- method_type = method_type.map_type {|ty| ty.sub(sub) }
409
424
  method_type = method_type.update(
410
- type_params: method_params,
411
425
  type: method_type.type.with_return_type(
412
426
  Types::ClassInstance.new(
413
427
  name: type_name,
@@ -438,7 +452,7 @@ module RBS
438
452
 
439
453
  def validate_params_with(type_params, result:)
440
454
  type_params.each do |param|
441
- unless param.skip_validation
455
+ unless param.unchecked?
442
456
  unless result.compatible?(param.name, with_annotation: param.variance)
443
457
  yield param
444
458
  end
@@ -831,5 +845,26 @@ module RBS
831
845
  end
832
846
  end
833
847
  end
848
+
849
+ def validate_type_presence(type)
850
+ case type
851
+ when Types::ClassInstance, Types::ClassSingleton, Types::Interface, Types::Alias
852
+ validate_type_name(type.name, type.location)
853
+ end
854
+
855
+ type.each_type do |type|
856
+ validate_type_presence(type)
857
+ end
858
+ end
859
+
860
+ def validate_type_name(name, location)
861
+ name = name.absolute!
862
+
863
+ return if name.class? && env.class_decls.key?(name)
864
+ return if name.interface? && env.interface_decls.key?(name)
865
+ return if name.alias? && env.alias_decls.key?(name)
866
+
867
+ raise NoTypeFoundError.new(type_name: name, location: location)
868
+ end
834
869
  end
835
870
  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