steep 1.5.3 → 1.6.0.pre.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (53) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/ruby-windows.yml +1 -2
  3. data/.github/workflows/ruby.yml +1 -2
  4. data/CHANGELOG.md +46 -0
  5. data/Gemfile +3 -1
  6. data/Gemfile.lock +37 -10
  7. data/gemfile_steep/Gemfile.lock +3 -3
  8. data/lib/steep/ast/types/logic.rb +6 -0
  9. data/lib/steep/cli.rb +39 -19
  10. data/lib/steep/diagnostic/ruby.rb +4 -4
  11. data/lib/steep/interface/builder.rb +9 -0
  12. data/lib/steep/path_helper.rb +2 -0
  13. data/lib/steep/project/pattern.rb +1 -1
  14. data/lib/steep/server/change_buffer.rb +9 -0
  15. data/lib/steep/server/delay_queue.rb +41 -0
  16. data/lib/steep/server/interaction_worker.rb +4 -2
  17. data/lib/steep/server/master.rb +106 -10
  18. data/lib/steep/server/type_check_worker.rb +10 -3
  19. data/lib/steep/services/completion_provider.rb +2 -2
  20. data/lib/steep/services/stats_calculator.rb +2 -2
  21. data/lib/steep/services/type_name_completion.rb +86 -15
  22. data/lib/steep/signature/validator.rb +9 -2
  23. data/lib/steep/subtyping/check.rb +24 -18
  24. data/lib/steep/type_construction.rb +61 -17
  25. data/lib/steep/type_inference/logic_type_interpreter.rb +26 -0
  26. data/lib/steep/type_inference/method_params.rb +1 -1
  27. data/lib/steep/version.rb +1 -1
  28. data/lib/steep.rb +1 -3
  29. data/sig/shims/language-server_protocol.rbs +12 -0
  30. data/sig/steep/ast/types/logic.rbs +5 -0
  31. data/sig/steep/ast/types.rbs +1 -1
  32. data/sig/steep/cli.rbs +2 -0
  33. data/sig/steep/diagnostic/ruby.rbs +7 -7
  34. data/sig/steep/project/pattern.rbs +22 -0
  35. data/sig/steep/server/change_buffer.rbs +4 -0
  36. data/sig/steep/server/delay_queue.rbs +37 -0
  37. data/sig/steep/server/master.rbs +4 -0
  38. data/sig/steep/services/stats_calculator.rbs +30 -6
  39. data/sig/steep/services/type_name_completion.rbs +13 -0
  40. data/sig/steep/signature/validator.rbs +5 -0
  41. data/sig/steep/subtyping/check.rbs +1 -1
  42. data/sig/steep/subtyping/relation.rbs +11 -1
  43. data/sig/steep/subtyping/result.rbs +1 -1
  44. data/sig/steep/type_construction.rbs +1 -1
  45. data/smoke/block/test_expectations.yml +10 -14
  46. data/smoke/enumerator/test_expectations.yml +10 -10
  47. data/smoke/integer/test_expectations.yml +5 -16
  48. data/smoke/regression/hello world.rb +1 -0
  49. data/smoke/regression/test_expectations.yml +12 -0
  50. data/steep.gemspec +1 -1
  51. metadata +8 -7
  52. data/lib/steep/shims/filter_map.rb +0 -30
  53. data/lib/steep/shims/symbol_start_with.rb +0 -18
@@ -402,6 +402,7 @@ module Steep
402
402
 
403
403
  attr_reader :initialize_params
404
404
  attr_accessor :typecheck_automatically
405
+ attr_reader :start_type_checking_queue
405
406
 
406
407
  def initialize(project:, reader:, writer:, interaction_worker:, typecheck_workers:, queue: Queue.new)
407
408
  @project = project
@@ -416,6 +417,7 @@ module Steep
416
417
 
417
418
  @controller = TypeCheckController.new(project: project)
418
419
  @result_controller = ResultController.new()
420
+ @start_type_checking_queue = DelayQueue.new(delay: 0.1)
419
421
  end
420
422
 
421
423
  def start
@@ -488,6 +490,8 @@ module Steep
488
490
  Steep.logger.info { "Processing SendMessageJob: dest=#{job.dest.name}, method=#{job.message[:method] || "-"}, id=#{job.message[:id] || "-"}" }
489
491
  job.dest << job.message
490
492
  end
493
+ when Proc
494
+ job.call()
491
495
  end
492
496
  end
493
497
  end
@@ -529,6 +533,10 @@ module Steep
529
533
  initialize_params&.dig(:capabilities, :window, :workDoneProgress) ? true : false
530
534
  end
531
535
 
536
+ def file_system_watcher_supported?
537
+ initialize_params&.dig(:capabilities, :workspace, :didChangeWatchedFiles, :dynamicRegistration) || false
538
+ end
539
+
532
540
  def process_message_from_client(message)
533
541
  Steep.logger.info "Processing message from client: method=#{message[:method]}, id=#{message[:id]}"
534
542
  id = message[:id]
@@ -551,7 +559,6 @@ module Steep
551
559
  capabilities: LSP::Interface::ServerCapabilities.new(
552
560
  text_document_sync: LSP::Interface::TextDocumentSyncOptions.new(
553
561
  change: LSP::Constant::TextDocumentSyncKind::INCREMENTAL,
554
- save: LSP::Interface::SaveOptions.new(include_text: false),
555
562
  open_close: true
556
563
  ),
557
564
  hover_provider: {
@@ -575,6 +582,52 @@ module Steep
575
582
  )
576
583
  }
577
584
  )
585
+
586
+ if file_system_watcher_supported?
587
+ patterns = [] #: Array[String]
588
+ project.targets.each do |target|
589
+ target.source_pattern.patterns.each do |pat|
590
+ path = project.base_dir + pat
591
+ patterns << path.to_s unless path.directory?
592
+ end
593
+ target.source_pattern.prefixes.each do |pat|
594
+ path = project.base_dir + pat
595
+ patterns << (path + "**/*.rb").to_s unless path.file?
596
+ end
597
+ target.signature_pattern.patterns.each do |pat|
598
+ path = project.base_dir + pat
599
+ patterns << path.to_s unless path.directory?
600
+ end
601
+ target.signature_pattern.prefixes.each do |pat|
602
+ path = project.base_dir + pat
603
+ patterns << (path + "**/*.rbs").to_s unless path.file?
604
+ end
605
+ end
606
+ patterns.sort!
607
+ patterns.uniq!
608
+
609
+ Steep.logger.info { "Setting up didChangeWatchedFiles with pattern: #{patterns.inspect}" }
610
+
611
+ job_queue << SendMessageJob.to_client(
612
+ message: {
613
+ id: SecureRandom.uuid,
614
+ method: "client/registerCapability",
615
+ params: {
616
+ registrations: [
617
+ {
618
+ id: SecureRandom.uuid,
619
+ method: "workspace/didChangeWatchedFiles",
620
+ registerOptions: {
621
+ watchers: patterns.map do |pattern|
622
+ { globPattern: pattern }
623
+ end
624
+ }
625
+ }
626
+ ]
627
+ }
628
+ }
629
+ )
630
+ end
578
631
  end
579
632
  end
580
633
 
@@ -585,28 +638,71 @@ module Steep
585
638
  end
586
639
  end
587
640
 
641
+ when "workspace/didChangeWatchedFiles"
642
+ message[:params][:changes].each do |change|
643
+ uri = change[:uri]
644
+ type = change[:type]
645
+
646
+ path = PathHelper.to_pathname(uri) or next
647
+
648
+ controller.push_changes(path)
649
+
650
+ case type
651
+ when 1, 2
652
+ content = path.read
653
+ when 4
654
+ # Deleted
655
+ content = ""
656
+ end
657
+
658
+ broadcast_notification({
659
+ method: "$/file/reset",
660
+ params: { uri: uri, content: content }
661
+ })
662
+ end
663
+
664
+ if typecheck_automatically
665
+ start_type_checking_queue.execute do
666
+ job_queue.push(
667
+ -> do
668
+ last_request = current_type_check_request
669
+ if request = controller.make_request(last_request: last_request)
670
+ start_type_check(request, last_request: last_request, start_progress: request.total > 10)
671
+ end
672
+ end
673
+ )
674
+ end
675
+ end
676
+
588
677
  when "textDocument/didChange"
589
678
  if path = pathname(message[:params][:textDocument][:uri])
590
679
  broadcast_notification(message)
591
680
  controller.push_changes(path)
592
- end
593
681
 
594
- when "textDocument/didSave"
595
- if path = pathname(message[:params][:textDocument][:uri])
596
682
  if typecheck_automatically
597
- if request = controller.make_request(last_request: current_type_check_request)
598
- start_type_check(
599
- request,
600
- last_request: current_type_check_request,
601
- start_progress: request.total > 10
683
+ start_type_checking_queue.execute do
684
+ job_queue.push(
685
+ -> do
686
+ last_request = current_type_check_request
687
+ if request = controller.make_request(last_request: last_request)
688
+ start_type_check(request, last_request: last_request, start_progress: request.total > 10)
689
+ end
690
+ end
602
691
  )
603
692
  end
604
693
  end
605
694
  end
606
695
 
607
696
  when "textDocument/didOpen"
608
- if path = pathname(message[:params][:textDocument][:uri])
697
+ uri = message[:params][:textDocument][:uri]
698
+ text = message[:params][:textDocument][:text]
699
+
700
+ if path = pathname(uri)
609
701
  controller.update_priority(open: path)
702
+ broadcast_notification({
703
+ method: "$/file/reset",
704
+ params: { uri: uri, content: text }
705
+ })
610
706
  end
611
707
 
612
708
  when "textDocument/didClose"
@@ -70,8 +70,15 @@ module Steep
70
70
  when "initialize"
71
71
  load_files(project: project, commandline_args: commandline_args)
72
72
  writer.write({ id: request[:id], result: nil})
73
+
73
74
  when "textDocument/didChange"
74
75
  collect_changes(request)
76
+
77
+ when "$/file/reset"
78
+ uri = request[:params][:uri]
79
+ text = request[:params][:content]
80
+ reset_change(uri: uri, text: text)
81
+
75
82
  when "workspace/symbol"
76
83
  query = request[:params][:query]
77
84
  queue << WorkspaceSymbolJob.new(id: request[:id], query: query)
@@ -165,7 +172,7 @@ module Steep
165
172
  writer.write(
166
173
  method: :"textDocument/publishDiagnostics",
167
174
  params: LSP::Interface::PublishDiagnosticsParams.new(
168
- uri: Steep::PathHelper.to_uri(job.path),
175
+ uri: Steep::PathHelper.to_uri(job.path).to_s,
169
176
  diagnostics: diagnostics.map {|diagnostic| formatter.format(diagnostic) }.uniq
170
177
  )
171
178
  )
@@ -183,7 +190,7 @@ module Steep
183
190
  writer.write(
184
191
  method: :"textDocument/publishDiagnostics",
185
192
  params: LSP::Interface::PublishDiagnosticsParams.new(
186
- uri: Steep::PathHelper.to_uri(job.path),
193
+ uri: Steep::PathHelper.to_uri(job.path).to_s,
187
194
  diagnostics: diagnostics.map {|diagnostic| formatter.format(diagnostic) }.uniq.compact
188
195
  )
189
196
  )
@@ -202,7 +209,7 @@ module Steep
202
209
  writer.write(
203
210
  method: :"textDocument/publishDiagnostics",
204
211
  params: LSP::Interface::PublishDiagnosticsParams.new(
205
- uri: Steep::PathHelper.to_uri(job.path),
212
+ uri: Steep::PathHelper.to_uri(job.path).to_s,
206
213
  diagnostics: diagnostics.map {|diagnostic| formatter.format(diagnostic) }.uniq.compact
207
214
  )
208
215
  )
@@ -115,7 +115,7 @@ module Steep
115
115
  when RBS::Environment::ClassAliasEntry, RBS::Environment::ModuleAliasEntry
116
116
  entry.decl
117
117
  else
118
- raise
118
+ raise "absolute_type_name=#{absolute_type_name}, relative_type_name=#{relative_type_name}"
119
119
  end
120
120
  else
121
121
  raise
@@ -663,7 +663,7 @@ module Steep
663
663
  if parent
664
664
  case parent.type
665
665
  when :const
666
- const_name = typing.source_index.reference(constant_node: parent)
666
+ const_name = typing.source_index.reference(constant_node: parent) or raise "Unknown node in source_index: #{parent}"
667
667
  consts = context.type_env.constant_env.children(const_name)
668
668
  end
669
669
  else
@@ -1,7 +1,7 @@
1
1
  module Steep
2
2
  module Services
3
3
  class StatsCalculator
4
- SuccessStats = Struct.new(:target, :path, :typed_calls_count, :untyped_calls_count, :error_calls_count, keyword_init: true) do
4
+ class SuccessStats < Struct.new(:target, :path, :typed_calls_count, :untyped_calls_count, :error_calls_count, keyword_init: true)
5
5
  def as_json
6
6
  {
7
7
  type: "success",
@@ -14,7 +14,7 @@ module Steep
14
14
  }
15
15
  end
16
16
  end
17
- ErrorStats = Struct.new(:target, :path, keyword_init: true) do
17
+ class ErrorStats < Struct.new(:target, :path, keyword_init: true)
18
18
  def as_json
19
19
  {
20
20
  type: "error",
@@ -31,15 +31,20 @@ module Steep
31
31
 
32
32
  case prefix
33
33
  when /\A((::\w+[A-Z])+(::)?)/
34
- NamespacePrefix.new(RBS::Namespace.parse($1.reverse), $1.size)
34
+ namespace = $1 or raise
35
+ NamespacePrefix.new(RBS::Namespace.parse(namespace.reverse), namespace.size)
35
36
  when /\A::/
36
37
  NamespacePrefix.new(RBS::Namespace.root, 2)
37
38
  when /\A(\w*[A-Za-z_])((::\w+[A-Z])+(::)?)/
38
- NamespacedIdentPrefix.new(RBS::Namespace.parse($2.reverse), $1.reverse, $1.size + $2.size)
39
+ namespace = $1 or raise
40
+ identifier = $2 or raise
41
+ NamespacedIdentPrefix.new(RBS::Namespace.parse(identifier.reverse), namespace.reverse, namespace.size + identifier.size)
39
42
  when /\A(\w*[A-Za-z_])::/
40
- NamespacedIdentPrefix.new(RBS::Namespace.root, $1.reverse, $1.size + 2)
43
+ namespace = $1 or raise
44
+ NamespacedIdentPrefix.new(RBS::Namespace.root, namespace.reverse, namespace.size + 2)
41
45
  when /\A(\w*[A-Za-z_])/
42
- RawIdentPrefix.new($1.reverse)
46
+ identifier = $1 or raise
47
+ RawIdentPrefix.new(identifier.reverse)
43
48
  end
44
49
  end
45
50
  end
@@ -92,36 +97,97 @@ module Steep
92
97
  if block
93
98
  env = self.env
94
99
 
100
+ table = {} #: Hash[RBS::Namespace, Array[RBS::TypeName]]
101
+ env.class_decls.each_key do |type_name|
102
+ yield(type_name)
103
+ (table[type_name.namespace] ||= []) << type_name
104
+ end
105
+ env.type_alias_decls.each_key do |type_name|
106
+ yield(type_name)
107
+ (table[type_name.namespace] ||= []) << type_name
108
+ end
109
+ env.interface_decls.each_key do |type_name|
110
+ yield(type_name)
111
+ (table[type_name.namespace] ||= []) << type_name
112
+ end
113
+ env.class_alias_decls.each_key do |type_name|
114
+ yield(type_name)
115
+ (table[type_name.namespace] ||= []) << type_name
116
+ end
117
+
118
+ env.class_alias_decls.each_key do |alias_name|
119
+ normalized_name = env.normalize_module_name?(alias_name) or next
120
+ each_type_name_under(alias_name, normalized_name, table: table, &block)
121
+ end
122
+
123
+ resolve_pairs = [] #: Array[[RBS::TypeName, RBS::TypeName]]
124
+
95
125
  map.instance_eval do
96
126
  @map.each_key do |name|
97
127
  relative_name = RBS::TypeName.new(name: name, namespace: RBS::Namespace.empty)
98
128
  if absolute_name = resolve?(relative_name)
99
129
  if env.type_name?(absolute_name)
100
130
  # Yields only if the relative type name resolves to existing absolute type name
101
- yield relative_name
131
+ resolve_pairs << [relative_name, absolute_name]
102
132
  end
103
133
  end
104
134
  end
105
135
  end
106
- env.class_decls.each_key(&block)
107
- env.class_alias_decls.each_key(&block)
108
- env.type_alias_decls.each_key(&block)
109
- env.interface_decls.each_key(&block)
136
+
137
+ resolve_pairs.each do |use_name, absolute_name|
138
+ yield use_name
139
+ each_type_name_under(use_name, absolute_name, table: table, &block)
140
+ end
110
141
  else
111
142
  enum_for :each_type_name
112
143
  end
113
144
  end
114
145
 
146
+ def each_type_name_under(module_name, normalized_name, table:, &block)
147
+ if children = table.fetch(normalized_name.to_namespace, nil)
148
+ module_namespace = module_name.to_namespace
149
+
150
+ children.each do |normalized_child_name|
151
+ child_name = RBS::TypeName.new(namespace: module_namespace, name: normalized_child_name.name)
152
+
153
+ yield child_name
154
+
155
+ if normalized_child_name.class?
156
+ each_type_name_under(child_name, env.normalize_module_name(normalized_child_name), table: table, &block)
157
+ end
158
+ end
159
+ end
160
+ end
161
+
162
+ def resolve_used_name(name)
163
+ return nil if name.absolute?
164
+
165
+ case
166
+ when resolved = map.resolve?(name)
167
+ resolved
168
+ when name.namespace.empty?
169
+ nil
170
+ else
171
+ if resolved_parent = resolve_used_name(name.namespace.to_type_name)
172
+ resolved_name = RBS::TypeName.new(namespace: resolved_parent.to_namespace, name: name.name)
173
+ if env.normalize_type_name?(resolved_name)
174
+ resolved_name
175
+ end
176
+ end
177
+ end
178
+ end
179
+
115
180
  def resolve_name_in_context(name)
116
- if resolved_name = map.resolve?(name)
181
+ if resolved_name = resolve_used_name(name)
117
182
  return [resolved_name, name]
118
183
  end
119
184
 
120
185
  name.absolute? or raise
186
+ normalized_name = env.normalize_type_name?(name) or raise "Cannot normalize given type name `#{name}`"
121
187
 
122
188
  name.namespace.path.reverse_each.inject(RBS::TypeName.new(namespace: RBS::Namespace.empty, name: name.name)) do |relative_name, component|
123
189
  if type_name_resolver.resolve(relative_name, context: context) == name
124
- return [name, relative_name]
190
+ return [normalized_name, relative_name]
125
191
  end
126
192
 
127
193
  RBS::TypeName.new(
@@ -130,10 +196,10 @@ module Steep
130
196
  )
131
197
  end
132
198
 
133
- if type_name_resolver.resolve(name.relative!, context: context) == name && !map.resolve?(name.relative!)
134
- [name, name.relative!]
199
+ if type_name_resolver.resolve(name.relative!, context: context) == name && !resolve_used_name(name.relative!)
200
+ [normalized_name, name.relative!]
135
201
  else
136
- [name, name]
202
+ [normalized_name, name]
137
203
  end
138
204
  end
139
205
 
@@ -144,7 +210,12 @@ module Steep
144
210
  type_name.split.any? {|sym| sym.to_s.downcase.include?(prefix.ident.downcase) }
145
211
  end
146
212
  when Prefix::NamespacedIdentPrefix
147
- absolute_namespace = type_name_resolver.resolve(prefix.namespace.to_type_name, context: context)&.to_namespace || prefix.namespace
213
+ absolute_namespace =
214
+ if prefix.namespace.empty?
215
+ RBS::Namespace.root
216
+ else
217
+ type_name_resolver.resolve(prefix.namespace.to_type_name, context: context)&.to_namespace || prefix.namespace
218
+ end
148
219
 
149
220
  each_type_name.filter do|name|
150
221
  name.namespace == absolute_namespace &&
@@ -112,10 +112,11 @@ module Steep
112
112
  type.args
113
113
  ]
114
114
  when RBS::Types::Alias
115
- entry = env.type_alias_decls[type.name]
115
+ type_name = env.normalize_type_name?(type.name) or return
116
+ entry = env.type_alias_decls[type_name]
116
117
 
117
118
  [
118
- type.name,
119
+ type_name,
119
120
  entry.decl.type_params,
120
121
  type.args
121
122
  ]
@@ -520,6 +521,12 @@ module Steep
520
521
  def validate_one_alias(name, entry = env.type_alias_decls[name])
521
522
  rescue_validation_errors(name) do
522
523
  Steep.logger.debug "Validating alias `#{name}`..."
524
+
525
+ unless name.namespace.empty?
526
+ outer = name.namespace.to_type_name
527
+ builder.validate_type_name(outer, entry.decl.location&.aref(:name))
528
+ end
529
+
523
530
  upper_bounds = entry.decl.type_params.each.with_object({}) do |param, bounds|
524
531
  bounds[param.name] = factory.type_opt(param.upper_bound)
525
532
  end
@@ -79,11 +79,11 @@ module Steep
79
79
  end
80
80
 
81
81
  def instance_type
82
- @instance_type
82
+ @instance_type || AST::Types::Instance.instance
83
83
  end
84
84
 
85
85
  def class_type
86
- @class_type
86
+ @class_type || AST::Types::Class.instance
87
87
  end
88
88
 
89
89
  def constraints
@@ -193,7 +193,7 @@ module Steep
193
193
  bounds = cache_bounds(relation)
194
194
  fvs = relation.sub_type.free_variables + relation.super_type.free_variables
195
195
  cached = cache[relation, @self_type, @instance_type, @class_type, bounds]
196
- if cached && fvs.none? {|var| constraints.unknown?(var) }
196
+ if cached && fvs.none? {|var| var.is_a?(Symbol) && constraints.unknown?(var) }
197
197
  cached
198
198
  else
199
199
  if assumptions.member?(relation)
@@ -212,7 +212,8 @@ module Steep
212
212
 
213
213
  def cache_bounds(relation)
214
214
  vars = relation.sub_type.free_variables + relation.super_type.free_variables
215
- vars.each.with_object({}) do |var, hash|
215
+ vars.each.with_object({}) do |var, hash| #$ Hash[Symbol, AST::Types::t]
216
+ next unless var.is_a?(Symbol)
216
217
  if upper_bound = variable_upper_bound(var)
217
218
  hash[var] = upper_bound
218
219
  end
@@ -232,7 +233,7 @@ module Steep
232
233
  when AST::Types::Literal
233
234
  type.value == true
234
235
  else
235
- AST::Builtin::TrueClass.instance_type?(type)
236
+ AST::Builtin::TrueClass.instance_type?(type) ? true : false
236
237
  end
237
238
  end
238
239
 
@@ -241,7 +242,7 @@ module Steep
241
242
  when AST::Types::Literal
242
243
  type.value == false
243
244
  else
244
- AST::Builtin::FalseClass.instance_type?(type)
245
+ AST::Builtin::FalseClass.instance_type?(type) ? true : false
245
246
  end
246
247
  end
247
248
 
@@ -410,7 +411,7 @@ module Steep
410
411
  class_type: class_type,
411
412
  variable_bounds: variable_upper_bounds
412
413
  )
413
- ) or raise
414
+ ) or return Failure(relation, Result::Failure::UnknownPairError.new(relation: relation))
414
415
  }
415
416
  )
416
417
  end
@@ -492,7 +493,7 @@ module Steep
492
493
  Failure(relation, Result::Failure::UnknownPairError.new(relation: relation))
493
494
  end
494
495
 
495
- when relation.sub_type.is_a?(AST::Types::Tuple) && AST::Builtin::Array.instance_type?(relation.super_type)
496
+ when relation.sub_type.is_a?(AST::Types::Tuple) && (super_type = AST::Builtin::Array.instance_type?(relation.super_type))
496
497
  Expand(relation) do
497
498
  tuple_element_type =
498
499
  AST::Types::Union.build(
@@ -500,7 +501,7 @@ module Steep
500
501
  location: relation.sub_type.location
501
502
  )
502
503
 
503
- check_type(Relation.new(sub_type: tuple_element_type, super_type: relation.super_type.args[0]))
504
+ check_type(Relation.new(sub_type: tuple_element_type, super_type: super_type.args[0]))
504
505
  end
505
506
 
506
507
  when relation.sub_type.is_a?(AST::Types::Record) && relation.super_type.is_a?(AST::Types::Record)
@@ -549,9 +550,7 @@ module Steep
549
550
  end
550
551
 
551
552
  when relation.super_type.is_a?(AST::Types::Nil) && AST::Builtin::NilClass.instance_type?(relation.sub_type)
552
- Success(relation)
553
-
554
- when relation.sub_type.is_a?(AST::Types::Nil) && AST::Builtin::NilClass.instance_type?(relation.super_type)
553
+ # NilClass <: nil
555
554
  Success(relation)
556
555
 
557
556
  when relation.sub_type.is_a?(AST::Types::Literal)
@@ -742,10 +741,17 @@ module Steep
742
741
  args = sub_type.type_params.map {|type_param| AST::Types::Var.fresh(type_param.name) }
743
742
  args.each {|arg| constraints.unknown!(arg.name) }
744
743
 
745
- upper_bounds = {}
746
- relations = [] #: Array[Relation]
744
+ upper_bounds = {} #: Hash[Symbol, AST::Types::t]
745
+ relations = [] #: Array[Relation[AST::Types::t]]
747
746
 
748
747
  args.zip(sub_type.type_params, super_type.type_params).each do |arg, sub_param, sup_param|
748
+ # @type var arg: AST::Types::Var
749
+ # @type var sub_param: Interface::TypeParam?
750
+ # @type var super_param: Interface::TypeParam?
751
+
752
+ sub_param or raise
753
+ sup_param or raise
754
+
749
755
  sub_ub = sub_param.upper_bound
750
756
  sup_ub = sup_param.upper_bound
751
757
 
@@ -927,7 +933,7 @@ module Steep
927
933
 
928
934
  sub_params, super_params = relation
929
935
 
930
- pairs = []
936
+ pairs = [] #: Array[[AST::Types::t, AST::Types::t]]
931
937
 
932
938
  sub_flat = sub_params.flat_unnamed_params
933
939
  sup_flat = super_params.flat_unnamed_params
@@ -939,7 +945,7 @@ module Steep
939
945
  return failure unless sub_params.rest
940
946
 
941
947
  while sub_flat.size > 0
942
- sub_type = sub_flat.shift
948
+ sub_type = sub_flat.shift or raise
943
949
  sup_type = sup_flat.shift
944
950
 
945
951
  if sup_type
@@ -955,7 +961,7 @@ module Steep
955
961
 
956
962
  when sub_params.rest
957
963
  while sub_flat.size > 0
958
- sub_type = sub_flat.shift
964
+ sub_type = sub_flat.shift or raise
959
965
  sup_type = sup_flat.shift
960
966
 
961
967
  if sup_type
@@ -972,7 +978,7 @@ module Steep
972
978
  end
973
979
  when sub_params.required.size + sub_params.optional.size >= super_params.required.size + super_params.optional.size
974
980
  while sub_flat.size > 0
975
- sub_type = sub_flat.shift
981
+ sub_type = sub_flat.shift or raise
976
982
  sup_type = sup_flat.shift
977
983
 
978
984
  if sup_type