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
@@ -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
+ ```