steep 1.9.0.dev.2 → 1.9.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 (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
@@ -357,35 +357,40 @@ module Steep
357
357
  end
358
358
 
359
359
  if implement_module_name
360
- module_entry = checker.factory.definition_builder.env.normalized_module_entry(implement_module_name.name) or raise
361
-
362
- module_context = module_context.update(
363
- instance_type: AST::Types::Intersection.build(
364
- types: [
365
- AST::Builtin::Object.instance_type,
366
- *module_entry.self_types.map {|module_self|
367
- type = case
368
- when module_self.name.interface?
369
- RBS::Types::Interface.new(
370
- name: module_self.name,
371
- args: module_self.args,
372
- location: module_self.location
373
- )
374
- when module_self.name.class?
375
- RBS::Types::ClassInstance.new(
376
- name: module_self.name,
377
- args: module_self.args,
378
- location: module_self.location
379
- )
380
- else
381
- raise
382
- end
383
- checker.factory.type(type)
384
- },
385
- module_context.instance_type
386
- ].compact
360
+ module_entry = checker.factory.definition_builder.env.normalized_module_entry(implement_module_name.name)
361
+ if module_entry
362
+ module_context = module_context.update(
363
+ instance_type: AST::Types::Intersection.build(
364
+ types: [
365
+ AST::Builtin::Object.instance_type,
366
+ *module_entry.self_types.map {|module_self|
367
+ type = case
368
+ when module_self.name.interface?
369
+ RBS::Types::Interface.new(
370
+ name: module_self.name,
371
+ args: module_self.args,
372
+ location: module_self.location
373
+ )
374
+ when module_self.name.class?
375
+ RBS::Types::ClassInstance.new(
376
+ name: module_self.name,
377
+ args: module_self.args,
378
+ location: module_self.location
379
+ )
380
+ else
381
+ raise
382
+ end
383
+ checker.factory.type(type)
384
+ },
385
+ module_context.instance_type
386
+ ].compact
387
+ )
387
388
  )
388
- )
389
+ elsif checker.factory.definition_builder.env.normalized_class_entry(implement_module_name.name)
390
+ typing.add_error(
391
+ Diagnostic::Ruby::ClassModuleMismatch.new(node: node, name: new_module_name)
392
+ )
393
+ end
389
394
  end
390
395
 
391
396
  if annots.instance_type
@@ -472,6 +477,13 @@ module Steep
472
477
  if super_class_name && implement_module_name.name == absolute_name(super_class_name)
473
478
  module_context = module_context.update(instance_definition: nil, module_definition: nil)
474
479
  end
480
+
481
+ if !checker.factory.definition_builder.env.normalized_class_entry(implement_module_name.name) &&
482
+ checker.factory.definition_builder.env.normalized_module_entry(implement_module_name.name)
483
+ typing.add_error(
484
+ Diagnostic::Ruby::ClassModuleMismatch.new(node: node, name: new_class_name)
485
+ )
486
+ end
475
487
  else
476
488
  module_context = module_context.update(
477
489
  instance_type: AST::Builtin::Object.instance_type,
@@ -2401,11 +2413,26 @@ module Steep
2401
2413
  if value_node
2402
2414
  type, constr = synthesize(value_node, hint: hint)
2403
2415
 
2404
- if hint.is_a?(AST::Types::Proc) && value_node.type == :sym
2416
+ if hint.is_a?(AST::Types::Proc) && value_node.type == :send && value_node.children[1] == :method && AST::Builtin::Method.instance_type?(type)
2417
+ receiver_node = value_node.children[0] #: Parser::AST::Node?
2418
+ receiver_type = receiver_node ? typing.type_of(node: receiver_node) : self_type
2419
+ method_name = value_node.children[2].children[0] #: Symbol
2420
+ if method = calculate_interface(receiver_type, private: true)&.methods&.[](method_name)
2421
+ if method_type = method.method_types.find {|method_type| method_type.accept_one_arg? }
2422
+ if method_type.type_params.empty?
2423
+ type = AST::Types::Proc.new(
2424
+ type: method_type.type,
2425
+ block: method_type.block,
2426
+ self_type: nil
2427
+ )
2428
+ end
2429
+ end
2430
+ end
2431
+ elsif hint.is_a?(AST::Types::Proc) && value_node.type == :sym
2405
2432
  if hint.one_arg?
2406
2433
  if hint.type.params
2407
2434
  # Assumes Symbol#to_proc implementation
2408
- param_type = hint.type.params.required[0]
2435
+ param_type = hint.type.params.required.fetch(0)
2409
2436
  case param_type
2410
2437
  when AST::Types::Any
2411
2438
  type = AST::Types::Any.instance
@@ -2423,7 +2450,7 @@ module Steep
2423
2450
  params: Interface::Function::Params.empty.with_first_param(
2424
2451
  Interface::Function::Params::PositionalParams::Required.new(param_type)
2425
2452
  ),
2426
- return_type: return_types[0],
2453
+ return_type: return_types.fetch(0),
2427
2454
  location: nil
2428
2455
  ),
2429
2456
  block: nil,
@@ -3479,13 +3506,13 @@ module Steep
3479
3506
  decls = method_overload.method_decls(method_name).to_set
3480
3507
 
3481
3508
  case
3482
- when decl = decls.find {|decl| SPECIAL_METHOD_NAMES[:array_compact].include?(decl.method_name) }
3509
+ when decl = decls.find {|decl| SPECIAL_METHOD_NAMES.fetch(:array_compact).include?(decl.method_name) }
3483
3510
  if arguments.empty? && !block_params
3484
3511
  # compact
3485
3512
  return_type = method_type.type.return_type
3486
3513
  if AST::Builtin::Array.instance_type?(return_type)
3487
3514
  # @type var return_type: AST::Types::Name::Instance
3488
- elem = return_type.args[0]
3515
+ elem = return_type.args.fetch(0)
3489
3516
  type = AST::Builtin::Array.instance_type(unwrap(elem))
3490
3517
 
3491
3518
  _, constr = add_typing(node, type: type)
@@ -3502,14 +3529,14 @@ module Steep
3502
3529
  return [call, constr]
3503
3530
  end
3504
3531
  end
3505
- when decl = decls.find {|decl| SPECIAL_METHOD_NAMES[:hash_compact].include?(decl.method_name) }
3532
+ when decl = decls.find {|decl| SPECIAL_METHOD_NAMES.fetch(:hash_compact).include?(decl.method_name) }
3506
3533
  if arguments.empty? && !block_params
3507
3534
  # compact
3508
3535
  return_type = method_type.type.return_type
3509
3536
  if AST::Builtin::Hash.instance_type?(return_type)
3510
3537
  # @type var return_type: AST::Types::Name::Instance
3511
- key = return_type.args[0]
3512
- value = return_type.args[1]
3538
+ key = return_type.args.fetch(0)
3539
+ value = return_type.args.fetch(1)
3513
3540
  type = AST::Builtin::Hash.instance_type(key, unwrap(value))
3514
3541
 
3515
3542
  _, constr = add_typing(node, type: type)
@@ -3526,7 +3553,7 @@ module Steep
3526
3553
  return [call, constr]
3527
3554
  end
3528
3555
  end
3529
- when decl = decls.find {|decl| SPECIAL_METHOD_NAMES[:lambda].include?(decl.method_name) }
3556
+ when decl = decls.find {|decl| SPECIAL_METHOD_NAMES.fetch(:lambda).include?(decl.method_name) }
3530
3557
  if block_params
3531
3558
  # @type var node: Parser::AST::Node & Parser::AST::_BlockNode
3532
3559
  type, constr = type_lambda(node, params_node: block_params, body_node: block_body, type_hint: hint)
@@ -3609,7 +3636,7 @@ module Steep
3609
3636
  end
3610
3637
 
3611
3638
  if fails.one?
3612
- call, constr = fails[0]
3639
+ call, constr = fails.fetch(0)
3613
3640
 
3614
3641
  constr.typing.save!
3615
3642
 
@@ -3824,7 +3851,7 @@ module Steep
3824
3851
  args_ = []
3825
3852
 
3826
3853
  type_args.each_with_index do |type, index|
3827
- param = method_type.type_params[index]
3854
+ param = method_type.type_params.fetch(index)
3828
3855
 
3829
3856
  if upper_bound = param.upper_bound
3830
3857
  if result = no_subtyping?(sub_type: type.value, super_type: upper_bound)
@@ -4912,7 +4939,7 @@ module Steep
4912
4939
  case
4913
4940
  when AST::Builtin::Array.instance_type?(type)
4914
4941
  type.is_a?(AST::Types::Name::Instance) or raise
4915
- element_types << type.args[0]
4942
+ element_types << type.args.fetch(0)
4916
4943
  when type.is_a?(AST::Types::Tuple)
4917
4944
  element_types.push(*type.types)
4918
4945
  else
@@ -4948,20 +4975,32 @@ module Steep
4948
4975
  key_node = child.children[0] #: Parser::AST::Node
4949
4976
  value_node = child.children[1] #: Parser::AST::Node
4950
4977
 
4951
- key = key_node.children[0] #: AST::Types::Record::key
4978
+ key =
4979
+ case key_node.type
4980
+ when :sym, :int, :str
4981
+ key_node.children[0]
4982
+ when :true
4983
+ true
4984
+ when :false
4985
+ false
4986
+ end #: AST::Types::Record::key
4952
4987
 
4953
4988
  _, constr = constr.synthesize(key_node, hint: AST::Types::Literal.new(value: key))
4954
4989
 
4955
4990
  value_type, constr = constr.synthesize(value_node, hint: hints[key])
4956
4991
 
4957
4992
  if hints.key?(key)
4958
- hint_type = hints[key]
4993
+ hint_type = hints.fetch(key)
4959
4994
  case
4960
4995
  when value_type.is_a?(AST::Types::Any)
4961
- value_type = hints[key]
4996
+ value_type = hints.fetch(key)
4962
4997
  when hint_type.is_a?(AST::Types::Var)
4963
4998
  value_type = value_type
4964
4999
  end
5000
+ else
5001
+ typing.add_error(
5002
+ Diagnostic::Ruby::UnknownRecordKey.new(key: key, node: key_node)
5003
+ )
4965
5004
  end
4966
5005
 
4967
5006
  elems[key] = value_type
@@ -5033,8 +5072,8 @@ module Steep
5033
5072
  constr.synthesize(elem_, hint: hint_hash).tap do |(type, _)|
5034
5073
  if AST::Builtin::Hash.instance_type?(type)
5035
5074
  # @type var type: AST::Types::Name::Instance
5036
- key_types << type.args[0]
5037
- value_types << type.args[1]
5075
+ key_types << type.args.fetch(0)
5076
+ value_types << type.args.fetch(1)
5038
5077
  end
5039
5078
  end
5040
5079
  end
@@ -266,7 +266,7 @@ module Steep
266
266
  when AST::Builtin::Array.instance_type?(type)
267
267
  type.is_a?(AST::Types::Name::Instance) or raise
268
268
 
269
- type_arg = type.args[0]
269
+ type_arg = type.args.fetch(0)
270
270
  params.each do |param|
271
271
  unless param == rest_param
272
272
  zip << [param, AST::Types::Union.build(types: [type_arg, AST::Builtin.nil_type])]
@@ -359,7 +359,7 @@ module Steep
359
359
  true
360
360
  when (leading_params.any? || trailing_params.any?) && rest_param
361
361
  true
362
- when params.size == 1 && params[0].node.type == :arg
362
+ when params.size == 1 && params.fetch(0).node.type == :arg
363
363
  true
364
364
  else
365
365
  false
@@ -409,7 +409,7 @@ module Steep
409
409
 
410
410
  def untyped_args?(params)
411
411
  flat = params.flat_unnamed_params
412
- flat.size == 1 && flat[0][1].is_a?(AST::Types::Any)
412
+ flat.size == 1 && flat.dig(0, 1)&.is_a?(AST::Types::Any)
413
413
  end
414
414
  end
415
415
  end
@@ -121,7 +121,7 @@ module Steep
121
121
  end
122
122
 
123
123
  def [](name)
124
- table[name].upper_bound
124
+ table.fetch(name).upper_bound
125
125
  end
126
126
 
127
127
  def upper_bounds
@@ -469,7 +469,7 @@ module Steep
469
469
  has_error = false
470
470
 
471
471
  keywords.each do |keyword|
472
- rest_types << (keyword_params.requireds[keyword] || keyword_params.optionals[keyword])
472
+ rest_types << (keyword_params.requireds[keyword] || keyword_params.optionals.fetch(keyword))
473
473
  has_error = true
474
474
  end
475
475
  keywords.clear
@@ -231,7 +231,7 @@ module Steep
231
231
 
232
232
  envs.each do |env|
233
233
  all_lvar_types.each_key do |name|
234
- all_lvar_types[name] << (env[name] || AST::Builtin.nil_type)
234
+ all_lvar_types.fetch(name) << (env[name] || AST::Builtin.nil_type)
235
235
  end
236
236
  end
237
237
 
@@ -245,11 +245,11 @@ module Steep
245
245
  .inject {|s1, s2| s1.intersection(s2) } || Set[]
246
246
 
247
247
  pure_call_updates = common_pure_nodes.each_with_object({}) do |node, hash| #$ Hash[Parser::AST::Node, [MethodCall::Typed, AST::Types::t]]
248
- pairs = envs.map {|env| env.pure_method_calls[node] }
248
+ pairs = envs.map {|env| env.pure_method_calls.fetch(node) }
249
249
  refined_type = AST::Types::Union.build(types: pairs.map {|call, type| type || call.return_type })
250
250
 
251
251
  # Any *pure_method_call* can be used because it's *pure*
252
- (call, _ = envs[0].pure_method_calls[node]) or raise
252
+ (call, _ = envs.fetch(0).pure_method_calls[node]) or raise
253
253
 
254
254
  hash[node] = [call, refined_type]
255
255
  end
data/lib/steep/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Steep
2
- VERSION = "1.9.0.dev.2"
2
+ VERSION = "1.9.0"
3
3
  end
@@ -142,3 +142,40 @@ This annotation tells instance variable of instance.
142
142
 
143
143
  * `@type` `instance` `ivar` *ivar* `:` *type*
144
144
  * `@type` `module` `ivar` *ivar* `:` *type*
145
+
146
+ ## Type assertion
147
+
148
+ Type assertion allows declaring type of an expression inline, without introducing new local variable with variable type annotation.
149
+
150
+ ### Example
151
+
152
+ ```
153
+ array = [] #: Array[String]
154
+
155
+ path = nil #: Pathname?
156
+ ```
157
+
158
+ ##### Syntax
159
+
160
+ * `#:` *type*
161
+
162
+ ## Type application
163
+
164
+ Type application is for generic method calls.
165
+
166
+ ### Example
167
+
168
+ ```
169
+ table = accounts.each_with_object({}) do |account, table| #$ Hash[String, Account]
170
+ table[account.email] = account
171
+ end
172
+ ```
173
+
174
+ The `each_with_object` method has `[T] (T) { (Account, T) -> void } -> T`,
175
+ and the type application syntax directly specifies the type of `T`.
176
+
177
+ So the resulting type is `(Hash[String, Account]) { (Account, Hash[String, Account]) -> void } -> Hash[String, Account]`.
178
+
179
+ #### Syntax
180
+
181
+ * `#$` *type*
data/manual/ignore.md ADDED
@@ -0,0 +1,20 @@
1
+ # Ignore diagnostics
2
+
3
+ Steep allows you to ignore diagnostics by adding comments to your code.
4
+
5
+ ```ruby
6
+ # Ignoring a range of lines
7
+
8
+ # steep:ignore:start
9
+
10
+ foo() # NoMethod is detected, but ignored
11
+
12
+ # steep:ignore:end
13
+ ```
14
+
15
+ ```ruby
16
+ # Ignoring a specific line
17
+
18
+ foo() # steep:ignore
19
+ foo() # steep:ignore NoMethod
20
+ ```