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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +76 -0
- data/README.md +9 -4
- data/Rakefile +1 -0
- data/Steepfile +11 -0
- data/bin/generate-diagnostics-docs.rb +112 -0
- data/lib/steep/ast/builtin.rb +1 -0
- data/lib/steep/ast/ignore.rb +1 -1
- data/lib/steep/ast/types/factory.rb +2 -0
- data/lib/steep/cli.rb +9 -2
- data/lib/steep/diagnostic/lsp_formatter.rb +8 -1
- data/lib/steep/diagnostic/ruby.rb +65 -3
- data/lib/steep/diagnostic/signature.rb +4 -4
- data/lib/steep/drivers/check.rb +3 -3
- data/lib/steep/drivers/diagnostic_printer.rb +1 -1
- data/lib/steep/drivers/init.rb +6 -3
- data/lib/steep/expectations.rb +1 -1
- data/lib/steep/interface/builder.rb +2 -3
- data/lib/steep/interface/function.rb +13 -0
- data/lib/steep/interface/method_type.rb +5 -0
- data/lib/steep/interface/shape.rb +1 -1
- data/lib/steep/project/dsl.rb +2 -0
- data/lib/steep/server/change_buffer.rb +1 -1
- data/lib/steep/server/interaction_worker.rb +5 -5
- data/lib/steep/server/master.rb +2 -17
- data/lib/steep/server/type_check_controller.rb +2 -2
- data/lib/steep/server/type_check_worker.rb +1 -1
- data/lib/steep/services/completion_provider.rb +4 -4
- data/lib/steep/services/goto_service.rb +3 -3
- data/lib/steep/services/hover_provider/rbs.rb +1 -1
- data/lib/steep/services/hover_provider/ruby.rb +6 -6
- data/lib/steep/services/signature_help_provider.rb +8 -8
- data/lib/steep/services/type_check_service.rb +8 -8
- data/lib/steep/signature/validator.rb +3 -3
- data/lib/steep/source.rb +4 -4
- data/lib/steep/subtyping/check.rb +3 -3
- data/lib/steep/subtyping/constraints.rb +4 -4
- data/lib/steep/type_construction.rb +84 -45
- data/lib/steep/type_inference/block_params.rb +3 -3
- data/lib/steep/type_inference/context.rb +1 -1
- data/lib/steep/type_inference/method_params.rb +1 -1
- data/lib/steep/type_inference/type_env.rb +3 -3
- data/lib/steep/version.rb +1 -1
- data/manual/annotations.md +37 -0
- data/manual/ignore.md +20 -0
- data/manual/ruby-diagnostics.md +1812 -0
- data/steep.gemspec +1 -1
- 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)
|
361
|
-
|
362
|
-
|
363
|
-
|
364
|
-
|
365
|
-
|
366
|
-
|
367
|
-
|
368
|
-
|
369
|
-
|
370
|
-
|
371
|
-
|
372
|
-
|
373
|
-
|
374
|
-
|
375
|
-
|
376
|
-
|
377
|
-
|
378
|
-
|
379
|
-
|
380
|
-
|
381
|
-
|
382
|
-
|
383
|
-
|
384
|
-
|
385
|
-
|
386
|
-
|
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 == :
|
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
|
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
|
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
|
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
|
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
|
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
|
3512
|
-
value = return_type.args
|
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
|
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
|
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
|
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
|
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 =
|
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
|
4993
|
+
hint_type = hints.fetch(key)
|
4959
4994
|
case
|
4960
4995
|
when value_type.is_a?(AST::Types::Any)
|
4961
|
-
value_type = hints
|
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
|
5037
|
-
value_types << type.args
|
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
|
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
|
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
|
412
|
+
flat.size == 1 && flat.dig(0, 1)&.is_a?(AST::Types::Any)
|
413
413
|
end
|
414
414
|
end
|
415
415
|
end
|
@@ -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
|
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
|
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
|
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
|
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
data/manual/annotations.md
CHANGED
@@ -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
|
+
```
|