steep 1.9.0.dev.2 → 1.9.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (48) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +76 -0
  3. data/README.md +9 -4
  4. data/Rakefile +1 -0
  5. data/Steepfile +11 -0
  6. data/bin/generate-diagnostics-docs.rb +112 -0
  7. data/lib/steep/ast/builtin.rb +1 -0
  8. data/lib/steep/ast/ignore.rb +1 -1
  9. data/lib/steep/ast/types/factory.rb +2 -0
  10. data/lib/steep/cli.rb +9 -2
  11. data/lib/steep/diagnostic/lsp_formatter.rb +8 -1
  12. data/lib/steep/diagnostic/ruby.rb +65 -3
  13. data/lib/steep/diagnostic/signature.rb +4 -4
  14. data/lib/steep/drivers/check.rb +3 -3
  15. data/lib/steep/drivers/diagnostic_printer.rb +1 -1
  16. data/lib/steep/drivers/init.rb +6 -3
  17. data/lib/steep/expectations.rb +1 -1
  18. data/lib/steep/interface/builder.rb +2 -3
  19. data/lib/steep/interface/function.rb +13 -0
  20. data/lib/steep/interface/method_type.rb +5 -0
  21. data/lib/steep/interface/shape.rb +1 -1
  22. data/lib/steep/project/dsl.rb +2 -0
  23. data/lib/steep/server/change_buffer.rb +1 -1
  24. data/lib/steep/server/interaction_worker.rb +5 -5
  25. data/lib/steep/server/master.rb +2 -17
  26. data/lib/steep/server/type_check_controller.rb +2 -2
  27. data/lib/steep/server/type_check_worker.rb +1 -1
  28. data/lib/steep/services/completion_provider.rb +4 -4
  29. data/lib/steep/services/goto_service.rb +3 -3
  30. data/lib/steep/services/hover_provider/rbs.rb +1 -1
  31. data/lib/steep/services/hover_provider/ruby.rb +6 -6
  32. data/lib/steep/services/signature_help_provider.rb +8 -8
  33. data/lib/steep/services/type_check_service.rb +8 -8
  34. data/lib/steep/signature/validator.rb +3 -3
  35. data/lib/steep/source.rb +4 -4
  36. data/lib/steep/subtyping/check.rb +3 -3
  37. data/lib/steep/subtyping/constraints.rb +4 -4
  38. data/lib/steep/type_construction.rb +84 -45
  39. data/lib/steep/type_inference/block_params.rb +3 -3
  40. data/lib/steep/type_inference/context.rb +1 -1
  41. data/lib/steep/type_inference/method_params.rb +1 -1
  42. data/lib/steep/type_inference/type_env.rb +3 -3
  43. data/lib/steep/version.rb +1 -1
  44. data/manual/annotations.md +37 -0
  45. data/manual/ignore.md +20 -0
  46. data/manual/ruby-diagnostics.md +1812 -0
  47. data/steep.gemspec +1 -1
  48. metadata +8 -5
@@ -164,6 +164,7 @@ module Steep
164
164
  end
165
165
 
166
166
  def group(name, &block)
167
+ name = name.to_str.to_sym unless Symbol === name
167
168
  group = GroupDSL.new(name, self)
168
169
 
169
170
  Steep.logger.tagged "group=#{name}" do
@@ -230,6 +231,7 @@ module Steep
230
231
  end
231
232
 
232
233
  def target(name, &block)
234
+ name = name.to_str.to_sym unless Symbol === name
233
235
  dsl = TargetDSL.new(name, project: project)
234
236
 
235
237
  Steep.logger.tagged "target=#{name}" do
@@ -46,7 +46,7 @@ module Steep
46
46
 
47
47
  changes[path] ||= []
48
48
  request[:params][:contentChanges].each do |change|
49
- changes[path] << Services::ContentChange.new(
49
+ changes.fetch(path) << Services::ContentChange.new(
50
50
  range: change[:range]&.yield_self {|range|
51
51
  [
52
52
  range[:start].yield_self {|pos| Services::ContentChange::Position.new(line: pos[:line] + 1, column: pos[:character]) },
@@ -156,7 +156,7 @@ module Steep
156
156
  case
157
157
  when target = project.target_for_source_path(job.path)
158
158
  file = service.source_files[job.path] or return
159
- subtyping = service.signature_services[target.name].current_subtyping or return
159
+ subtyping = service.signature_services.fetch(target.name).current_subtyping or return
160
160
 
161
161
  provider = Services::CompletionProvider.new(source_text: file.content, path: job.path, subtyping: subtyping)
162
162
  items = begin
@@ -184,12 +184,12 @@ module Steep
184
184
  case sig_service.status
185
185
  when Services::SignatureService::SyntaxErrorStatus, Services::SignatureService::AncestorErrorStatus
186
186
  if buffer = sig_service.latest_env.buffers.find {|buf| Pathname(buf.name) == Pathname(relative_path) }
187
- dirs = sig_service.latest_env.signatures[buffer][0]
187
+ dirs = sig_service.latest_env.signatures.fetch(buffer)[0]
188
188
  else
189
189
  dirs = [] #: Array[RBS::AST::Directives::t]
190
190
  end
191
191
  else
192
- signature = sig_service.files[relative_path].signature
192
+ signature = sig_service.files.fetch(relative_path).signature
193
193
  signature.is_a?(Array) or raise
194
194
  buffer, dirs, decls = signature
195
195
 
@@ -210,7 +210,7 @@ module Steep
210
210
  end
211
211
  end
212
212
 
213
- buffer = RBS::Buffer.new(name: relative_path, content: sig_service.files[relative_path].content)
213
+ buffer = RBS::Buffer.new(name: relative_path, content: sig_service.files.fetch(relative_path).content)
214
214
  prefix = Services::TypeNameCompletion::Prefix.parse(buffer, line: job.line, column: job.column)
215
215
 
216
216
  completion = Services::TypeNameCompletion.new(env: sig_service.latest_env, context: context, dirs: dirs)
@@ -451,7 +451,7 @@ module Steep
451
451
  Steep.logger.tagged("##{__method__}") do
452
452
  if target = project.target_for_source_path(job.path)
453
453
  file = service.source_files[job.path] or return
454
- subtyping = service.signature_services[target.name].current_subtyping or return
454
+ subtyping = service.signature_services.fetch(target.name).current_subtyping or return
455
455
  source =
456
456
  Source.parse(file.content, path: file.path, factory: subtyping.factory)
457
457
  .without_unrelated_defs(line: job.line, column: job.column)
@@ -178,7 +178,6 @@ module Steep
178
178
  attr_reader :job_queue, :write_queue
179
179
 
180
180
  attr_reader :current_type_check_request
181
- attr_reader :current_diagnostics
182
181
  attr_reader :controller
183
182
  attr_reader :result_controller
184
183
 
@@ -197,7 +196,6 @@ module Steep
197
196
  @commandline_args = []
198
197
  @job_queue = queue
199
198
  @write_queue = SizedQueue.new(100)
200
- @current_diagnostics = {}
201
199
 
202
200
  @controller = TypeCheckController.new(project: project)
203
201
  @result_controller = ResultController.new()
@@ -802,15 +800,7 @@ module Steep
802
800
  Steep.logger.info "Starting new progress..."
803
801
 
804
802
  @current_type_check_request = request
805
- if last_request
806
- checking_paths = request.each_path.to_set
807
- current_diagnostics.keep_if do |path, _|
808
- checking_paths.include?(path)
809
- end
810
- else
811
- current_diagnostics.clear
812
- end
813
-
803
+
814
804
  if progress
815
805
  # If `request:` keyword arg is not given
816
806
  request.work_done_progress.begin("Type checking", request_id: fresh_request_id)
@@ -909,15 +899,10 @@ module Steep
909
899
 
910
900
  def push_diagnostics(path, diagnostics)
911
901
  if diagnostics
912
- ds = (current_diagnostics[path] ||= [])
913
-
914
- ds.concat(diagnostics)
915
- ds.uniq!
916
-
917
902
  write_queue.push SendMessageJob.to_client(
918
903
  message: {
919
904
  method: :"textDocument/publishDiagnostics",
920
- params: { uri: Steep::PathHelper.to_uri(path).to_s, diagnostics: ds }
905
+ params: { uri: Steep::PathHelper.to_uri(path).to_s, diagnostics: diagnostics }
921
906
  }
922
907
  )
923
908
  end
@@ -266,7 +266,7 @@ module Steep
266
266
  request.code_paths << [target_group.name, path]
267
267
  end
268
268
  else
269
- group_set = groups.map do |group_name|
269
+ group_set = groups.filter_map do |group_name|
270
270
  target_name, group_name = group_name.split(".", 2)
271
271
  target_name or raise
272
272
 
@@ -280,7 +280,7 @@ module Steep
280
280
  else
281
281
  project.targets.find {|target| target.name == target_name }
282
282
  end
283
- end.compact.to_set
283
+ end.to_set
284
284
 
285
285
  files.signature_paths.each do |path, target_group|
286
286
  if group_set.include?(target_group)
@@ -223,7 +223,7 @@ module Steep
223
223
  Steep.measure "Generating workspace symbol list for query=`#{query}`" do
224
224
  provider = Index::SignatureSymbolProvider.new(project: project, assignment: assignment)
225
225
  project.targets.each do |target|
226
- index = service.signature_services[target.name].latest_rbs_index
226
+ index = service.signature_services.fetch(target.name).latest_rbs_index
227
227
  provider.indexes[target] = index
228
228
  end
229
229
 
@@ -105,9 +105,9 @@ module Steep
105
105
  def decl
106
106
  case
107
107
  when absolute_type_name.interface?
108
- env.interface_decls[absolute_type_name].decl
108
+ env.interface_decls.fetch(absolute_type_name).decl
109
109
  when absolute_type_name.alias?
110
- env.type_alias_decls[absolute_type_name].decl
110
+ env.type_alias_decls.fetch(absolute_type_name).decl
111
111
  when absolute_type_name.class?
112
112
  case entry = env.module_class_entry(absolute_type_name)
113
113
  when RBS::Environment::ClassEntry, RBS::Environment::ModuleEntry
@@ -127,11 +127,11 @@ module Steep
127
127
 
128
128
  case
129
129
  when absolute_type_name.interface?
130
- if comment = env.interface_decls[absolute_type_name].decl.comment
130
+ if comment = env.interface_decls.fetch(absolute_type_name).decl.comment
131
131
  comments << comment
132
132
  end
133
133
  when absolute_type_name.alias?
134
- if comment = env.type_alias_decls[absolute_type_name].decl.comment
134
+ if comment = env.type_alias_decls.fetch(absolute_type_name).decl.comment
135
135
  comments << comment
136
136
  end
137
137
  when absolute_type_name.class?
@@ -97,7 +97,7 @@ module Steep
97
97
  relative_path = project.relative_path(path)
98
98
 
99
99
  target = type_check.project.target_for_path(relative_path) or return []
100
- source = type_check.source_files[relative_path]
100
+ source = type_check.source_files.fetch(relative_path)
101
101
  typing, signature = type_check_path(target: target, path: relative_path, content: source.content, line: line, column: column)
102
102
 
103
103
  typing or return []
@@ -163,7 +163,7 @@ module Steep
163
163
 
164
164
  case
165
165
  when target = type_check.project.target_for_source_path(relative_path)
166
- source = type_check.source_files[relative_path] or return []
166
+ source = type_check.source_files.fetch(relative_path, nil) or return []
167
167
  typing, _signature = type_check_path(target: target, path: relative_path, content: source.content, line: line, column: column)
168
168
  if typing
169
169
  node, *parents = typing.source.find_nodes(line: line, column: column)
@@ -284,7 +284,7 @@ module Steep
284
284
  end
285
285
 
286
286
  def type_check_path(target:, path:, content:, line:, column:)
287
- signature_service = type_check.signature_services[target.name]
287
+ signature_service = type_check.signature_services.fetch(target.name)
288
288
  subtyping = signature_service.current_subtyping or return
289
289
  source = Source.parse(content, path: path, factory: subtyping.factory)
290
290
  source = source.without_unrelated_defs(line: line, column: column)
@@ -17,7 +17,7 @@ module Steep
17
17
  end
18
18
 
19
19
  def content_for(target:, path:, line:, column:)
20
- service = self.service.signature_services[target.name]
20
+ service = self.service.signature_services.fetch(target.name)
21
21
 
22
22
  env = service.latest_env
23
23
  buffer = env.buffers.find {|buf| buf.name.to_s == path.to_s } or return
@@ -65,14 +65,14 @@ module Steep
65
65
  def method_definition_for(factory, type_name, singleton_method: nil, instance_method: nil)
66
66
  case
67
67
  when instance_method
68
- factory.definition_builder.build_instance(type_name).methods[instance_method]
68
+ factory.definition_builder.build_instance(type_name).methods.fetch(instance_method)
69
69
  when singleton_method
70
70
  methods = factory.definition_builder.build_singleton(type_name).methods
71
71
 
72
72
  if singleton_method == :new
73
- methods[:new] || methods[:initialize]
73
+ methods[:new] || methods.fetch(:initialize)
74
74
  else
75
- methods[singleton_method]
75
+ methods.fetch(singleton_method)
76
76
  end
77
77
  else
78
78
  raise "One of the instance_method or singleton_method is required"
@@ -80,7 +80,7 @@ module Steep
80
80
  end
81
81
 
82
82
  def typecheck(target, path:, content:, line:, column:)
83
- subtyping = service.signature_services[target.name].current_subtyping or return
83
+ subtyping = service.signature_services.fetch(target.name).current_subtyping or return
84
84
  source = Source.parse(content, path: path, factory: subtyping.factory)
85
85
  source = source.without_unrelated_defs(line: line, column: column)
86
86
  resolver = ::RBS::Resolver::ConstantResolver.new(builder: subtyping.factory.definition_builder)
@@ -145,8 +145,8 @@ module Steep
145
145
  result_node =
146
146
  case parents[0]&.type
147
147
  when :block, :numblock
148
- if node == parents[0].children[0]
149
- parents[0]
148
+ if node == parents.fetch(0).children[0]
149
+ parents.fetch(0)
150
150
  else
151
151
  node
152
152
  end
@@ -145,13 +145,13 @@ module Steep
145
145
  # Cursor is not on the argument (maybe on comma after argument)
146
146
  return 0 if last_argument_nodes.nil? # No arguments
147
147
 
148
- case last_argument_nodes[-2].type
148
+ case last_argument_nodes.fetch(-2).type
149
149
  when :splat
150
150
  method_type.type.required_positionals.size + method_type.type.optional_positionals.size + 1 if method_type.type.rest_positionals
151
151
  when :kwargs
152
- case last_argument_nodes[-3].type
152
+ case last_argument_nodes.fetch(-3).type
153
153
  when :pair
154
- argname = last_argument_nodes[-3].children.first.children.first
154
+ argname = last_argument_nodes.fetch(-3).children.first.children.first
155
155
  if method_type.type.required_keywords.key?(argname)
156
156
  positionals + method_type.type.required_keywords.keys.index(argname).to_i + 1
157
157
  elsif method_type.type.optional_keywords.key?(argname)
@@ -163,7 +163,7 @@ module Steep
163
163
  positionals + method_type.type.required_keywords.size + method_type.type.optional_keywords.size if method_type.type.rest_keywords
164
164
  end
165
165
  else
166
- pos = (node.children[2...] || raise).index { |c| c.location == last_argument_nodes[-2].location }.to_i
166
+ pos = (node.children[2...] || raise).index { |c| c.location == last_argument_nodes.fetch(-2).location }.to_i
167
167
  if method_type.type.rest_positionals
168
168
  [pos + 1, positionals - 1].min
169
169
  else
@@ -172,14 +172,14 @@ module Steep
172
172
  end
173
173
  else
174
174
  # Cursor is on the argument
175
- case argument_nodes[-2].type
175
+ case argument_nodes.fetch(-2).type
176
176
  when :splat
177
177
  method_type.type.required_positionals.size + method_type.type.optional_positionals.size if method_type.type.rest_positionals
178
178
  when :kwargs
179
179
  if argument_nodes[-3]
180
- case argument_nodes[-3].type
180
+ case argument_nodes.fetch(-3).type
181
181
  when :pair
182
- argname = argument_nodes[-3].children.first.children.first
182
+ argname = argument_nodes.fetch(-3).children.first.children.first
183
183
  if method_type.type.required_keywords.key?(argname)
184
184
  positionals + method_type.type.required_keywords.keys.index(argname).to_i
185
185
  elsif method_type.type.optional_keywords.key?(argname)
@@ -192,7 +192,7 @@ module Steep
192
192
  end
193
193
  end
194
194
  else
195
- pos = (node.children[2...] || raise).index { |c| c.location == argument_nodes[-2].location }.to_i
195
+ pos = (node.children[2...] || raise).index { |c| c.location == argument_nodes.fetch(-2).location }.to_i
196
196
  [pos, positionals - 1].min
197
197
  end
198
198
  end
@@ -94,7 +94,7 @@ module Steep
94
94
  signature_diagnostics = {}
95
95
 
96
96
  project.targets.each do |target|
97
- service = signature_services[target.name]
97
+ service = signature_services.fetch(target.name)
98
98
 
99
99
  service.each_rbs_path do |path|
100
100
  signature_diagnostics[path] ||= []
@@ -105,13 +105,13 @@ module Steep
105
105
  service.status.diagnostics.group_by {|diag| diag.location&.buffer&.name&.to_s }.each do |path_string, diagnostics|
106
106
  if path_string
107
107
  path = Pathname(path_string)
108
- signature_diagnostics[path].push(*diagnostics)
108
+ signature_diagnostics.fetch(path).push(*diagnostics)
109
109
  end
110
110
  end
111
111
  when SignatureService::LoadedStatus
112
112
  validation_diagnostics = signature_validation_diagnostics[target.name] || {}
113
113
  validation_diagnostics.each do |path, diagnostics|
114
- signature_diagnostics[path].push(*diagnostics)
114
+ signature_diagnostics.fetch(path).push(*diagnostics)
115
115
  end
116
116
  end
117
117
  end
@@ -154,7 +154,7 @@ module Steep
154
154
  def validate_signature(path:, target:)
155
155
  Steep.logger.tagged "#validate_signature(path=#{path})" do
156
156
  Steep.measure "validation" do
157
- service = signature_services[target.name]
157
+ service = signature_services.fetch(target.name)
158
158
 
159
159
  raise "#{path} is not library nor signature of #{target.name}" unless target.possible_signature_file?(path) || service.env_rbs_paths.include?(path)
160
160
 
@@ -221,7 +221,7 @@ module Steep
221
221
  end
222
222
  end
223
223
 
224
- signature_validation_diagnostics[target.name][path] = diagnostics
224
+ signature_validation_diagnostics.fetch(target.name)[path] = diagnostics
225
225
  end
226
226
  end
227
227
  end
@@ -231,11 +231,11 @@ module Steep
231
231
 
232
232
  Steep.logger.tagged "#typecheck_source(path=#{path})" do
233
233
  Steep.measure "typecheck" do
234
- signature_service = signature_services[target.name]
234
+ signature_service = signature_services.fetch(target.name)
235
235
  subtyping = signature_service.current_subtyping
236
236
 
237
237
  if subtyping
238
- text = source_files[path].content
238
+ text = source_files.fetch(path).content
239
239
  file = type_check_file(target: target, subtyping: subtyping, path: path, text: text) { signature_service.latest_constant_resolver }
240
240
  source_files[path] = file
241
241
 
@@ -287,7 +287,7 @@ module Steep
287
287
  SourceFile.with_typing(path: path, content: text, node: source.node, typing: typing, ignores: ignores)
288
288
  end
289
289
  rescue AnnotationParser::SyntaxError => exn
290
- error = Diagnostic::Ruby::SyntaxError.new(message: exn.message, location: exn.location)
290
+ error = Diagnostic::Ruby::AnnotationSyntaxError.new(message: exn.message, location: exn.location)
291
291
  SourceFile.with_syntax_error(path: path, content: text, error: error)
292
292
  rescue ::Parser::SyntaxError => exn
293
293
  error = Diagnostic::Ruby::SyntaxError.new(message: exn.message, location: (_ = exn).diagnostic.location)
@@ -130,7 +130,7 @@ module Steep
130
130
  ]
131
131
  when RBS::Types::Alias
132
132
  type_name = env.normalize_type_name?(type.name) or return
133
- entry = env.type_alias_decls[type_name]
133
+ entry = env.type_alias_decls.fetch(type_name)
134
134
 
135
135
  [
136
136
  type_name,
@@ -485,7 +485,7 @@ module Steep
485
485
  location =
486
486
  case ancestor.source
487
487
  when :super
488
- primary_decl = env.class_decls[name].primary.decl
488
+ primary_decl = env.class_decls.fetch(name).primary.decl
489
489
  primary_decl.is_a?(RBS::AST::Declarations::Class) or raise
490
490
  if super_class = primary_decl.super_class
491
491
  super_class.location
@@ -594,7 +594,7 @@ module Steep
594
594
  end
595
595
  end
596
596
 
597
- def validate_one_alias(name, entry = env.type_alias_decls[name])
597
+ def validate_one_alias(name, entry = env.type_alias_decls.fetch(name))
598
598
  *, inner_most_outer_module = entry.outer
599
599
  if inner_most_outer_module
600
600
  class_type = AST::Types::Name::Singleton.new(name: inner_most_outer_module.name)
data/lib/steep/source.rb CHANGED
@@ -88,7 +88,7 @@ module Steep
88
88
 
89
89
  annotations.each do |annot|
90
90
  map[node] ||= []
91
- map[node] << annot
91
+ map.fetch(node) << annot
92
92
  end
93
93
 
94
94
  ignores = comments.filter_map do |comment|
@@ -269,7 +269,7 @@ module Steep
269
269
 
270
270
  associated_annotations.each do |annot|
271
271
  mapping[node] ||= []
272
- mapping[node] << annot
272
+ mapping.fetch(node) << annot
273
273
  end
274
274
 
275
275
  annotations.replace(other_annotations)
@@ -379,7 +379,7 @@ module Steep
379
379
  position = buffer.loc_to_pos([line, column])
380
380
 
381
381
  if heredoc_nodes = find_heredoc_nodes(line, column, position)
382
- Source.each_child_node(heredoc_nodes[0]) do |child|
382
+ Source.each_child_node(heredoc_nodes.fetch(0)) do |child|
383
383
  if nodes = find_nodes_loc(child, position, heredoc_nodes)
384
384
  return nodes
385
385
  end
@@ -442,7 +442,7 @@ module Steep
442
442
 
443
443
  annotations.each do |annot|
444
444
  mapping[node_] ||= []
445
- mapping[node_] << annot
445
+ mapping.fetch(node_) << annot
446
446
  end
447
447
 
448
448
  Source.new(buffer: buffer, path: path, node: node_, mapping: mapping, comments: comments, ignores: ignores)
@@ -515,7 +515,7 @@ module Steep
515
515
  types: relation.sub_type.types
516
516
  )
517
517
 
518
- check_type(Relation.new(sub_type: tuple_element_type, super_type: super_type.args[0]))
518
+ check_type(Relation.new(sub_type: tuple_element_type, super_type: super_type.args.fetch(0)))
519
519
  end
520
520
 
521
521
  when relation.sub_type.is_a?(AST::Types::Tuple)
@@ -1057,10 +1057,10 @@ module Steep
1057
1057
 
1058
1058
  sup_flat_kws.each do |name, _|
1059
1059
  if sub_flat_kws.key?(name)
1060
- pairs << [sub_flat_kws[name], sup_flat_kws[name]]
1060
+ pairs << [sub_flat_kws.fetch(name), sup_flat_kws.fetch(name)]
1061
1061
  else
1062
1062
  if sub_params.rest_keywords
1063
- pairs << [sub_params.rest_keywords, sup_flat_kws[name]]
1063
+ pairs << [sub_params.rest_keywords, sup_flat_kws.fetch(name)]
1064
1064
  else
1065
1065
  return failure
1066
1066
  end
@@ -102,7 +102,7 @@ module Steep
102
102
  end
103
103
 
104
104
  def add(var, sub_type: nil, super_type: nil, skip: false)
105
- subs, supers, skips = dictionary[var]
105
+ subs, supers, skips = dictionary.fetch(var)
106
106
 
107
107
  if sub_type.is_a?(AST::Types::Logic::Base)
108
108
  sub_type = AST::Builtin.bool_type
@@ -204,7 +204,7 @@ module Steep
204
204
  if skip
205
205
  upper_bound = upper_bound_types(var)
206
206
  else
207
- _, upper_bound, _ = dictionary[var]
207
+ _, upper_bound, _ = dictionary.fetch(var)
208
208
  end
209
209
 
210
210
  case upper_bound.size
@@ -320,12 +320,12 @@ module Steep
320
320
  end
321
321
 
322
322
  def lower_bound_types(var_name)
323
- lower, _, _ = dictionary[var_name]
323
+ lower, _, _ = dictionary.fetch(var_name)
324
324
  lower
325
325
  end
326
326
 
327
327
  def upper_bound_types(var_name)
328
- _, upper, skips = dictionary[var_name]
328
+ _, upper, skips = dictionary.fetch(var_name)
329
329
 
330
330
  case
331
331
  when upper.empty?