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