steep 1.5.0.pre.4 → 1.5.0.pre.6
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 +25 -0
- data/Gemfile.lock +1 -1
- data/lib/steep/ast/node/type_application.rb +5 -3
- data/lib/steep/ast/node/type_assertion.rb +7 -3
- data/lib/steep/ast/types/factory.rb +8 -1
- data/lib/steep/diagnostic/ruby.rb +30 -1
- data/lib/steep/node_helper.rb +23 -0
- data/lib/steep/server/interaction_worker.rb +13 -0
- data/lib/steep/server/lsp_formatter.rb +13 -0
- data/lib/steep/services/completion_provider.rb +85 -3
- data/lib/steep/services/hover_provider/ruby.rb +1 -1
- data/lib/steep/services/signature_help_provider.rb +100 -5
- data/lib/steep/type_construction.rb +117 -36
- data/lib/steep/type_inference/context.rb +3 -1
- data/lib/steep/type_inference/send_args.rb +9 -1
- data/lib/steep/version.rb +1 -1
- data/sig/shims/parser/nodes.rbs +5 -0
- data/sig/steep/ast/node/type_application.rbs +1 -1
- data/sig/steep/ast/node/type_assertion.rbs +1 -1
- data/sig/steep/diagnostic/ruby.rbs +33 -0
- data/sig/steep/node_helper.rbs +9 -0
- data/sig/steep/services/completion_provider.rbs +15 -1
- data/sig/steep/services/signature_help_provider.rbs +12 -2
- data/sig/steep/signature/validator.rbs +2 -2
- data/smoke/diagnostics/test_expectations.yml +0 -12
- data/smoke/type_case/test_expectations.yml +6 -6
- metadata +2 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: d00242c259b7c8d2a4a0f7022874ac5bb5f08491ab3edade6165ff1a9fbe89a7
|
|
4
|
+
data.tar.gz: e02d896359c4eb88c730601320bb9137342c19b9ad1956d4ac417ffa5926d74a
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 5be83d84d984d215342c030e9ea590c419a1e12963361266f4bc57e2b2ceec110a3f08313754b2f46a274fc8b0d2acca497c71f2eff24c3fd4505cb1ff2ac5a7
|
|
7
|
+
data.tar.gz: 7a30b064aa7ec6e27e3811e93b1ddf7ff4824cdeb5dfe70075f34311f7e22016bf4f3a2b107307a5247c54532451a25155fc2ba277842fec85f71aa23fdaced1
|
data/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,31 @@
|
|
|
2
2
|
|
|
3
3
|
## master
|
|
4
4
|
|
|
5
|
+
## 1.5.0.pre.6 (2023-07-11)
|
|
6
|
+
|
|
7
|
+
### Type checker core
|
|
8
|
+
|
|
9
|
+
* Report RBS validation errors in Ruby code ([#859](https://github.com/soutaro/steep/pull/859))
|
|
10
|
+
* Fix proc type assignment ([#858](https://github.com/soutaro/steep/pull/858))
|
|
11
|
+
* Report `UnexpectedKeywordArgument` even if no keyword param is accepted ([#856](https://github.com/soutaro/steep/pull/856))
|
|
12
|
+
* Unfold type alias on unwrap optional ([#855](https://github.com/soutaro/steep/pull/855))
|
|
13
|
+
|
|
14
|
+
### Language server
|
|
15
|
+
|
|
16
|
+
* Keyword completion in block call ([#865](https://github.com/soutaro/steep/pull/865))
|
|
17
|
+
* Indicate the current or next argument on signature help ([#850](https://github.com/soutaro/steep/pull/850))
|
|
18
|
+
* Support completion for keyword arguments ([#851](https://github.com/soutaro/steep/pull/851))
|
|
19
|
+
* Let hover show the type of method call node ([#864](https://github.com/soutaro/steep/pull/864))
|
|
20
|
+
* Fix UnknownNodeError in SignatureHelp ([#863](https://github.com/soutaro/steep/pull/863))
|
|
21
|
+
* hover: Fix NoMethodError on generating hover for not supported files ([#853](https://github.com/soutaro/steep/pull/853))
|
|
22
|
+
|
|
23
|
+
## 1.5.0.pre.5 (2023-07-07)
|
|
24
|
+
|
|
25
|
+
### Type checker core
|
|
26
|
+
|
|
27
|
+
* Unreachability improvements ([#845](https://github.com/soutaro/steep/pull/845))
|
|
28
|
+
* Fix type inference problem ([#843](https://github.com/soutaro/steep/pull/843))
|
|
29
|
+
|
|
5
30
|
## 1.5.0.pre.4 (2023-07-06)
|
|
6
31
|
|
|
7
32
|
### Type checker core
|
data/Gemfile.lock
CHANGED
|
@@ -37,10 +37,12 @@ module Steep
|
|
|
37
37
|
ty = ty.map_type_name {|name| resolver.resolve(name, context: context) || name.absolute! }
|
|
38
38
|
|
|
39
39
|
validator = Signature::Validator.new(checker: subtyping)
|
|
40
|
-
validator.
|
|
40
|
+
validator.rescue_validation_errors do
|
|
41
|
+
validator.validate_type(ty)
|
|
42
|
+
end
|
|
41
43
|
|
|
42
44
|
if validator.has_error?
|
|
43
|
-
return
|
|
45
|
+
return validator.each_error
|
|
44
46
|
end
|
|
45
47
|
|
|
46
48
|
ty = subtyping.factory.type(ty)
|
|
@@ -58,7 +60,7 @@ module Steep
|
|
|
58
60
|
|
|
59
61
|
def types?(context, subtyping, type_vars)
|
|
60
62
|
case types = types(context, subtyping, type_vars)
|
|
61
|
-
when RBS::ParsingError
|
|
63
|
+
when RBS::ParsingError, Enumerator
|
|
62
64
|
nil
|
|
63
65
|
else
|
|
64
66
|
types
|
|
@@ -22,10 +22,14 @@ module Steep
|
|
|
22
22
|
ty = ty.map_type_name {|name| resolver.resolve(name, context: context) || name.absolute! }
|
|
23
23
|
|
|
24
24
|
validator = Signature::Validator.new(checker: subtyping)
|
|
25
|
-
validator.
|
|
25
|
+
validator.rescue_validation_errors do
|
|
26
|
+
validator.validate_type(ty)
|
|
27
|
+
end
|
|
26
28
|
|
|
27
29
|
unless validator.has_error?
|
|
28
30
|
subtyping.factory.type(ty)
|
|
31
|
+
else
|
|
32
|
+
validator.each_error.to_a
|
|
29
33
|
end
|
|
30
34
|
else
|
|
31
35
|
nil
|
|
@@ -37,7 +41,7 @@ module Steep
|
|
|
37
41
|
def type_syntax?
|
|
38
42
|
RBS::Parser.parse_type(type_location.buffer, range: type_location.range, variables: [], require_eof: true)
|
|
39
43
|
true
|
|
40
|
-
rescue::RBS::ParsingError
|
|
44
|
+
rescue ::RBS::ParsingError
|
|
41
45
|
false
|
|
42
46
|
end
|
|
43
47
|
|
|
@@ -45,7 +49,7 @@ module Steep
|
|
|
45
49
|
type = type(context, subtyping, type_vars)
|
|
46
50
|
|
|
47
51
|
case type
|
|
48
|
-
when RBS::ParsingError, nil
|
|
52
|
+
when RBS::ParsingError, nil, Array
|
|
49
53
|
nil
|
|
50
54
|
else
|
|
51
55
|
type
|
|
@@ -204,7 +204,7 @@ module Steep
|
|
|
204
204
|
when Logic::Base
|
|
205
205
|
RBS::Types::Bases::Bool.new(location: type.location)
|
|
206
206
|
else
|
|
207
|
-
|
|
207
|
+
raise "Unexpected type given: #{type} (#{type.class})"
|
|
208
208
|
end
|
|
209
209
|
end
|
|
210
210
|
|
|
@@ -401,6 +401,13 @@ module Steep
|
|
|
401
401
|
end
|
|
402
402
|
when AST::Types::Nil
|
|
403
403
|
nil
|
|
404
|
+
when AST::Types::Name::Alias
|
|
405
|
+
type_ = expand_alias(type)
|
|
406
|
+
if type_ == type
|
|
407
|
+
type_
|
|
408
|
+
else
|
|
409
|
+
unwrap_optional(type_)
|
|
410
|
+
end
|
|
404
411
|
else
|
|
405
412
|
type
|
|
406
413
|
end
|
|
@@ -767,6 +767,19 @@ module Steep
|
|
|
767
767
|
end
|
|
768
768
|
end
|
|
769
769
|
|
|
770
|
+
class UnreachableValueBranch < Base
|
|
771
|
+
attr_reader :type
|
|
772
|
+
|
|
773
|
+
def initialize(node:, type:, location: node.location.expression)
|
|
774
|
+
super(node: node, location: location)
|
|
775
|
+
@type = type
|
|
776
|
+
end
|
|
777
|
+
|
|
778
|
+
def header_line
|
|
779
|
+
"The branch may evaluate to a value of `#{type}` but unreachable"
|
|
780
|
+
end
|
|
781
|
+
end
|
|
782
|
+
|
|
770
783
|
class UnexpectedSplat < Base
|
|
771
784
|
attr_reader :type
|
|
772
785
|
|
|
@@ -951,6 +964,19 @@ module Steep
|
|
|
951
964
|
end
|
|
952
965
|
end
|
|
953
966
|
|
|
967
|
+
class RBSError < Base
|
|
968
|
+
attr_reader :error
|
|
969
|
+
|
|
970
|
+
def initialize(error:, node:, location:)
|
|
971
|
+
@error = error
|
|
972
|
+
super(node: node, location: location)
|
|
973
|
+
end
|
|
974
|
+
|
|
975
|
+
def header_line
|
|
976
|
+
error.header_line
|
|
977
|
+
end
|
|
978
|
+
end
|
|
979
|
+
|
|
954
980
|
ALL = ObjectSpace.each_object(Class).with_object([]) do |klass, array|
|
|
955
981
|
if klass < Base
|
|
956
982
|
array << klass
|
|
@@ -968,7 +994,8 @@ module Steep
|
|
|
968
994
|
{
|
|
969
995
|
ImplicitBreakValueMismatch => :warning,
|
|
970
996
|
FallbackAny => :information,
|
|
971
|
-
|
|
997
|
+
UnreachableValueBranch => :warning,
|
|
998
|
+
UnreachableBranch => :information,
|
|
972
999
|
UnknownConstant => :warning,
|
|
973
1000
|
MethodDefinitionMissing => :information,
|
|
974
1001
|
FalseAssertion => :information,
|
|
@@ -989,6 +1016,7 @@ module Steep
|
|
|
989
1016
|
NoMethod => nil,
|
|
990
1017
|
ImplicitBreakValueMismatch => nil,
|
|
991
1018
|
FallbackAny => nil,
|
|
1019
|
+
UnreachableValueBranch => nil,
|
|
992
1020
|
UnreachableBranch => nil,
|
|
993
1021
|
UnknownConstant => nil,
|
|
994
1022
|
MethodDefinitionMissing => nil,
|
|
@@ -1006,6 +1034,7 @@ module Steep
|
|
|
1006
1034
|
NoMethod => nil,
|
|
1007
1035
|
ImplicitBreakValueMismatch => nil,
|
|
1008
1036
|
FallbackAny => nil,
|
|
1037
|
+
UnreachableValueBranch => nil,
|
|
1009
1038
|
UnreachableBranch => nil,
|
|
1010
1039
|
UnknownConstant => nil,
|
|
1011
1040
|
MethodDefinitionMissing => nil,
|
data/lib/steep/node_helper.rb
CHANGED
|
@@ -217,5 +217,28 @@ module Steep
|
|
|
217
217
|
false
|
|
218
218
|
end
|
|
219
219
|
end
|
|
220
|
+
|
|
221
|
+
def deconstruct_sendish_and_block_nodes(*nodes)
|
|
222
|
+
send_node, block_node = nodes.take(2)
|
|
223
|
+
|
|
224
|
+
if send_node
|
|
225
|
+
case send_node.type
|
|
226
|
+
when :send, :csend, :super
|
|
227
|
+
if block_node
|
|
228
|
+
case block_node.type
|
|
229
|
+
when :block, :numblock
|
|
230
|
+
if send_node.equal?(block_node.children[0])
|
|
231
|
+
return [send_node, block_node]
|
|
232
|
+
end
|
|
233
|
+
end
|
|
234
|
+
end
|
|
235
|
+
|
|
236
|
+
[send_node, nil]
|
|
237
|
+
when :zsuper
|
|
238
|
+
# zsuper doesn't receive block
|
|
239
|
+
[send_node, nil]
|
|
240
|
+
end
|
|
241
|
+
end
|
|
242
|
+
end
|
|
220
243
|
end
|
|
221
244
|
end
|
|
@@ -361,6 +361,17 @@ module Steep
|
|
|
361
361
|
new_text: item.identifier.to_s
|
|
362
362
|
)
|
|
363
363
|
)
|
|
364
|
+
when Services::CompletionProvider::KeywordArgumentItem
|
|
365
|
+
LSP::Interface::CompletionItem.new(
|
|
366
|
+
label: item.identifier.to_s,
|
|
367
|
+
kind: LSP::Constant::CompletionItemKind::FIELD,
|
|
368
|
+
label_details: LSP::Interface::CompletionItemLabelDetails.new(description: 'Keyword argument'),
|
|
369
|
+
documentation: LSPFormatter.markup_content { LSPFormatter.format_completion_docs(item) },
|
|
370
|
+
text_edit: LSP::Interface::TextEdit.new(
|
|
371
|
+
range: range,
|
|
372
|
+
new_text: item.identifier.to_s
|
|
373
|
+
)
|
|
374
|
+
)
|
|
364
375
|
when Services::CompletionProvider::TypeNameItem
|
|
365
376
|
kind =
|
|
366
377
|
case
|
|
@@ -397,6 +408,8 @@ module Steep
|
|
|
397
408
|
signatures = items.map do |item|
|
|
398
409
|
LSP::Interface::SignatureInformation.new(
|
|
399
410
|
label: "(#{item.method_type.type.param_to_s})",
|
|
411
|
+
parameters: item.parameters.map { |param| LSP::Interface::ParameterInformation.new(label: param)},
|
|
412
|
+
active_parameter: item.active_parameter,
|
|
400
413
|
documentation: item.comment&.yield_self do |comment|
|
|
401
414
|
LSP::Interface::MarkupContent.new(
|
|
402
415
|
kind: LSP::Constant::MarkupKind::MARKDOWN,
|
|
@@ -28,7 +28,16 @@ module Steep
|
|
|
28
28
|
|
|
29
29
|
case call
|
|
30
30
|
when TypeInference::MethodCall::Typed
|
|
31
|
+
io.puts <<~MD
|
|
32
|
+
```rbs
|
|
33
|
+
#{call.actual_method_type.type.return_type}
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
----
|
|
37
|
+
MD
|
|
38
|
+
|
|
31
39
|
method_types = call.method_decls.map(&:method_type)
|
|
40
|
+
|
|
32
41
|
if call.is_a?(TypeInference::MethodCall::Special)
|
|
33
42
|
method_types = [
|
|
34
43
|
call.actual_method_type.with(
|
|
@@ -250,6 +259,10 @@ module Steep
|
|
|
250
259
|
end
|
|
251
260
|
|
|
252
261
|
io.string
|
|
262
|
+
when Services::CompletionProvider::KeywordArgumentItem
|
|
263
|
+
<<~MD
|
|
264
|
+
**Keyword argument**: `#{item.identifier}`
|
|
265
|
+
MD
|
|
253
266
|
end
|
|
254
267
|
end
|
|
255
268
|
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
module Steep
|
|
2
2
|
module Services
|
|
3
3
|
class CompletionProvider
|
|
4
|
+
include NodeHelper
|
|
5
|
+
|
|
4
6
|
Position = _ = Struct.new(:line, :column, keyword_init: true) do
|
|
5
7
|
# @implements Position
|
|
6
8
|
def -(size)
|
|
@@ -11,6 +13,7 @@ module Steep
|
|
|
11
13
|
Range = _ = Struct.new(:start, :end, keyword_init: true)
|
|
12
14
|
|
|
13
15
|
InstanceVariableItem = _ = Struct.new(:identifier, :range, :type, keyword_init: true)
|
|
16
|
+
KeywordArgumentItem = _ = Struct.new(:identifier, :range, keyword_init: true)
|
|
14
17
|
LocalVariableItem = _ = Struct.new(:identifier, :range, :type, keyword_init: true)
|
|
15
18
|
ConstantItem = _ = Struct.new(:env, :identifier, :range, :type, :full_name, keyword_init: true) do
|
|
16
19
|
# @implements ConstantItem
|
|
@@ -267,7 +270,9 @@ module Steep
|
|
|
267
270
|
[]
|
|
268
271
|
end
|
|
269
272
|
else
|
|
270
|
-
[]
|
|
273
|
+
items = [] #: Array[item]
|
|
274
|
+
items_for_following_keyword_arguments(source_text, index: index, line: line, column: column, items: items)
|
|
275
|
+
items
|
|
271
276
|
end
|
|
272
277
|
end
|
|
273
278
|
end
|
|
@@ -302,10 +307,10 @@ module Steep
|
|
|
302
307
|
end
|
|
303
308
|
|
|
304
309
|
def items_for_trigger(position:)
|
|
305
|
-
node, *
|
|
310
|
+
node, *parents = source.find_nodes(line: position.line, column: position.column)
|
|
306
311
|
node ||= source.node
|
|
307
312
|
|
|
308
|
-
return [] unless node
|
|
313
|
+
return [] unless node && parents
|
|
309
314
|
|
|
310
315
|
items = [] #: Array[item]
|
|
311
316
|
|
|
@@ -319,6 +324,16 @@ module Steep
|
|
|
319
324
|
method_items_for_receiver_type(context.self_type, include_private: true, prefix: prefix, position: position, items: items)
|
|
320
325
|
local_variable_items_for_context(context, position: position, prefix: prefix, items: items)
|
|
321
326
|
|
|
327
|
+
if (send_node, block_node = deconstruct_sendish_and_block_nodes(*parents))
|
|
328
|
+
keyword_argument_items_for_method(
|
|
329
|
+
call_node: block_node || send_node,
|
|
330
|
+
send_node: send_node,
|
|
331
|
+
position: position,
|
|
332
|
+
prefix: prefix,
|
|
333
|
+
items: items
|
|
334
|
+
)
|
|
335
|
+
end
|
|
336
|
+
|
|
322
337
|
when node.type == :lvar && at_end?(position, of: node.loc)
|
|
323
338
|
# foo ← (lvar)
|
|
324
339
|
local_variable_items_for_context(context, position: position, prefix: node.children[0].to_s, items: items)
|
|
@@ -527,6 +542,37 @@ module Steep
|
|
|
527
542
|
items
|
|
528
543
|
end
|
|
529
544
|
|
|
545
|
+
def items_for_following_keyword_arguments(text, index:, line:, column:, items:)
|
|
546
|
+
return if text[index - 1] !~ /[a-zA-Z0-9]/
|
|
547
|
+
|
|
548
|
+
text = text.dup
|
|
549
|
+
argname = [] #: Array[String]
|
|
550
|
+
while text[index - 1] =~ /[a-zA-Z0-9]/
|
|
551
|
+
argname.unshift(text[index - 1] || '')
|
|
552
|
+
source_text[index - 1] = " "
|
|
553
|
+
index -= 1
|
|
554
|
+
end
|
|
555
|
+
|
|
556
|
+
begin
|
|
557
|
+
type_check!(source_text, line: line, column: column)
|
|
558
|
+
rescue Parser::SyntaxError
|
|
559
|
+
return
|
|
560
|
+
end
|
|
561
|
+
|
|
562
|
+
if nodes = source.find_nodes(line: line, column: column)
|
|
563
|
+
if (send_node, block_node = deconstruct_sendish_and_block_nodes(*nodes))
|
|
564
|
+
position = Position.new(line: line, column: column)
|
|
565
|
+
keyword_argument_items_for_method(
|
|
566
|
+
call_node: block_node || send_node,
|
|
567
|
+
send_node: send_node,
|
|
568
|
+
position: position,
|
|
569
|
+
prefix: argname.join,
|
|
570
|
+
items: items
|
|
571
|
+
)
|
|
572
|
+
end
|
|
573
|
+
end
|
|
574
|
+
end
|
|
575
|
+
|
|
530
576
|
def method_items_for_receiver_type(type, include_private:, prefix:, position:, items:)
|
|
531
577
|
range = range_for(position, prefix: prefix)
|
|
532
578
|
context = typing.context_at(line: position.line, column: position.column)
|
|
@@ -641,6 +687,42 @@ module Steep
|
|
|
641
687
|
end
|
|
642
688
|
end
|
|
643
689
|
|
|
690
|
+
def keyword_argument_items_for_method(call_node:, send_node:, position:, prefix:, items:)
|
|
691
|
+
receiver_node, method_name, argument_nodes = deconstruct_send_node!(send_node)
|
|
692
|
+
|
|
693
|
+
call = typing.call_of(node: call_node)
|
|
694
|
+
|
|
695
|
+
case call
|
|
696
|
+
when TypeInference::MethodCall::Typed, TypeInference::MethodCall::Error
|
|
697
|
+
type = call.receiver_type
|
|
698
|
+
shape = subtyping.builder.shape(
|
|
699
|
+
type,
|
|
700
|
+
public_only: !!receiver_node,
|
|
701
|
+
config: Interface::Builder::Config.new(self_type: type, class_type: nil, instance_type: nil, variable_bounds: {})
|
|
702
|
+
)
|
|
703
|
+
if shape
|
|
704
|
+
if method = shape.methods[call.method_name]
|
|
705
|
+
method.method_types.each.with_index do |method_type, i|
|
|
706
|
+
defn = method_type.method_decls.to_a[0]&.method_def
|
|
707
|
+
if defn
|
|
708
|
+
range = range_for(position, prefix: prefix)
|
|
709
|
+
kwargs = argument_nodes.find { |arg| arg.type == :kwargs }&.children || []
|
|
710
|
+
used_kwargs = kwargs.filter_map { |arg| arg.type == :pair && arg.children.first.children.first }
|
|
711
|
+
|
|
712
|
+
kwargs = defn.type.type.required_keywords.keys + defn.type.type.optional_keywords.keys
|
|
713
|
+
kwargs.each do |name|
|
|
714
|
+
if name.to_s.start_with?(prefix) && !used_kwargs.include?(name)
|
|
715
|
+
items << KeywordArgumentItem.new(identifier: "#{name}:", range: range)
|
|
716
|
+
end
|
|
717
|
+
end
|
|
718
|
+
end
|
|
719
|
+
end
|
|
720
|
+
end
|
|
721
|
+
end
|
|
722
|
+
end
|
|
723
|
+
end
|
|
724
|
+
|
|
725
|
+
|
|
644
726
|
def index_for(string, line:, column:)
|
|
645
727
|
index = 0
|
|
646
728
|
|
|
@@ -110,7 +110,7 @@ module Steep
|
|
|
110
110
|
end
|
|
111
111
|
|
|
112
112
|
def content_for(target:, path:, line:, column:)
|
|
113
|
-
file = service.source_files[path]
|
|
113
|
+
file = service.source_files[path] or return
|
|
114
114
|
typing = typecheck(target, path: path, content: file.content, line: line, column: column) or return
|
|
115
115
|
node, *parents = typing.source.find_nodes(line: line, column: column)
|
|
116
116
|
|
|
@@ -3,7 +3,21 @@ module Steep
|
|
|
3
3
|
class SignatureHelpProvider
|
|
4
4
|
MethodCall = TypeInference::MethodCall
|
|
5
5
|
|
|
6
|
-
Item = _ = Struct.new(:method_type, :comment)
|
|
6
|
+
Item = _ = Struct.new(:method_type, :comment, :active_parameter) do
|
|
7
|
+
# @implements Item
|
|
8
|
+
|
|
9
|
+
def parameters
|
|
10
|
+
arguments = [] #: Array[String]
|
|
11
|
+
arguments.push(*method_type.type.required_positionals.map(&:to_s))
|
|
12
|
+
arguments.push(*method_type.type.optional_positionals.map {|p| "?#{p}"})
|
|
13
|
+
arguments.push("*#{self.method_type.type.rest_positionals}") if method_type.type.rest_positionals
|
|
14
|
+
arguments.push(*method_type.type.trailing_positionals.map(&:to_s))
|
|
15
|
+
arguments.push(*method_type.type.required_keywords.map {|name, param| "#{name}: #{param}" })
|
|
16
|
+
arguments.push(*method_type.type.optional_keywords.map {|name, param| "?#{name}: #{param}" })
|
|
17
|
+
arguments.push("**#{method_type.type.rest_keywords}") if method_type.type.rest_keywords
|
|
18
|
+
arguments
|
|
19
|
+
end
|
|
20
|
+
end
|
|
7
21
|
|
|
8
22
|
attr_reader :source, :path, :subtyping, :typing, :buffer
|
|
9
23
|
|
|
@@ -23,12 +37,14 @@ module Steep
|
|
|
23
37
|
return unless nodes
|
|
24
38
|
|
|
25
39
|
typing = type_check!(line: line, column: column)
|
|
40
|
+
argument_nodes = [] #: Array[Parser::AST::Node]
|
|
26
41
|
|
|
27
42
|
while true
|
|
28
43
|
node = nodes.shift()
|
|
29
44
|
parent = nodes.first
|
|
30
45
|
|
|
31
46
|
node or return
|
|
47
|
+
argument_nodes << node
|
|
32
48
|
|
|
33
49
|
if node.type == :send || node.type == :csend
|
|
34
50
|
pos = buffer.loc_to_pos([line, column])
|
|
@@ -40,12 +56,13 @@ module Steep
|
|
|
40
56
|
# Given position is between open/close parens of args of send node
|
|
41
57
|
|
|
42
58
|
if parent && (parent.type == :block || parent.type == :numblock)
|
|
43
|
-
send_node = parent
|
|
59
|
+
send_node = parent
|
|
44
60
|
else
|
|
45
61
|
send_node = node
|
|
46
62
|
end
|
|
47
63
|
|
|
48
|
-
|
|
64
|
+
last_argument_nodes = last_argument_nodes_for(argument_nodes: argument_nodes, line: line, column: column)
|
|
65
|
+
return signature_help_for(send_node, argument_nodes, last_argument_nodes, typing)
|
|
49
66
|
end
|
|
50
67
|
end
|
|
51
68
|
end
|
|
@@ -58,7 +75,24 @@ module Steep
|
|
|
58
75
|
TypeCheckService.type_check(source: source, subtyping: subtyping, constant_resolver: resolver)
|
|
59
76
|
end
|
|
60
77
|
|
|
61
|
-
def
|
|
78
|
+
def last_argument_nodes_for(argument_nodes:, line:, column:)
|
|
79
|
+
return unless argument_nodes.last.children[2] # No arguments
|
|
80
|
+
return argument_nodes if argument_nodes.size > 1 # Cursor is on the last argument
|
|
81
|
+
|
|
82
|
+
pos = buffer.loc_to_pos([line, column])
|
|
83
|
+
|
|
84
|
+
while true
|
|
85
|
+
pos -= 1
|
|
86
|
+
line, column = buffer.pos_to_loc(pos)
|
|
87
|
+
nodes = source.find_nodes(line: line, column: column)
|
|
88
|
+
return unless nodes
|
|
89
|
+
|
|
90
|
+
index = nodes.index { |n| n.type == :send || n.type == :csend }
|
|
91
|
+
return nodes[..index] if index.to_i > 0
|
|
92
|
+
end
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
def signature_help_for(node, argument, last_argument, typing)
|
|
62
96
|
call = typing.call_of(node: node)
|
|
63
97
|
context = typing.context_at(line: node.loc.expression.line, column: node.loc.expression.column)
|
|
64
98
|
|
|
@@ -82,7 +116,8 @@ module Steep
|
|
|
82
116
|
method.method_types.each.with_index do |method_type, i|
|
|
83
117
|
defn = method_type.method_decls.to_a[0]&.method_def
|
|
84
118
|
|
|
85
|
-
|
|
119
|
+
active_parameter = active_parameter_for(defn&.type, argument, last_argument, node)
|
|
120
|
+
items << Item.new(subtyping.factory.method_type_1(method_type), defn&.comment, active_parameter)
|
|
86
121
|
|
|
87
122
|
if call.is_a?(MethodCall::Typed)
|
|
88
123
|
if method_type.method_decls.intersect?(call.method_decls)
|
|
@@ -98,6 +133,66 @@ module Steep
|
|
|
98
133
|
|
|
99
134
|
[items, index]
|
|
100
135
|
end
|
|
136
|
+
|
|
137
|
+
def active_parameter_for(method_type, argument_nodes, last_argument_nodes, node)
|
|
138
|
+
return unless method_type
|
|
139
|
+
|
|
140
|
+
positionals = method_type.type.required_positionals.size + method_type.type.optional_positionals.size + (method_type.type.rest_positionals ? 1 : 0) + method_type.type.trailing_positionals.size
|
|
141
|
+
|
|
142
|
+
if argument_nodes.size == 1
|
|
143
|
+
# Cursor is not on the argument (maybe on comma after argument)
|
|
144
|
+
return 0 if last_argument_nodes.nil? # No arguments
|
|
145
|
+
|
|
146
|
+
case last_argument_nodes[-2].type
|
|
147
|
+
when :splat
|
|
148
|
+
method_type.type.required_positionals.size + method_type.type.optional_positionals.size + 1 if method_type.type.rest_positionals
|
|
149
|
+
when :kwargs
|
|
150
|
+
case last_argument_nodes[-3].type
|
|
151
|
+
when :pair
|
|
152
|
+
argname = last_argument_nodes[-3].children.first.children.first
|
|
153
|
+
if method_type.type.required_keywords[argname]
|
|
154
|
+
positionals + method_type.type.required_keywords.keys.index(argname).to_i + 1
|
|
155
|
+
elsif method_type.type.optional_keywords[argname]
|
|
156
|
+
positionals + method_type.type.required_keywords.size + method_type.type.optional_keywords.keys.index(argname).to_i + 1
|
|
157
|
+
elsif method_type.type.rest_keywords
|
|
158
|
+
positionals + method_type.type.required_keywords.size + method_type.type.optional_keywords.size
|
|
159
|
+
end
|
|
160
|
+
when :kwsplat
|
|
161
|
+
positionals + method_type.type.required_keywords.size + method_type.type.optional_keywords.size if method_type.type.rest_keywords
|
|
162
|
+
end
|
|
163
|
+
else
|
|
164
|
+
pos = node.children[2...].index { |c| c.location == last_argument_nodes[-2].location }.to_i
|
|
165
|
+
if method_type.type.rest_positionals
|
|
166
|
+
[pos + 1, positionals - 1].min
|
|
167
|
+
else
|
|
168
|
+
[pos + 1, positionals].min
|
|
169
|
+
end
|
|
170
|
+
end
|
|
171
|
+
else
|
|
172
|
+
# Cursor is on the argument
|
|
173
|
+
case argument_nodes[-2].type
|
|
174
|
+
when :splat
|
|
175
|
+
method_type.type.required_positionals.size + method_type.type.optional_positionals.size if method_type.type.rest_positionals
|
|
176
|
+
when :kwargs
|
|
177
|
+
case argument_nodes[-3].type
|
|
178
|
+
when :pair
|
|
179
|
+
argname = argument_nodes[-3].children.first.children.first
|
|
180
|
+
if method_type.type.required_keywords[argname]
|
|
181
|
+
positionals + method_type.type.required_keywords.keys.index(argname).to_i
|
|
182
|
+
elsif method_type.type.optional_keywords[argname]
|
|
183
|
+
positionals + method_type.type.required_keywords.size + method_type.type.optional_keywords.keys.index(argname).to_i
|
|
184
|
+
elsif method_type.type.rest_keywords
|
|
185
|
+
positionals + method_type.type.required_keywords.size + method_type.type.optional_keywords.size
|
|
186
|
+
end
|
|
187
|
+
when :kwsplat
|
|
188
|
+
positionals + method_type.type.required_keywords.size + method_type.type.optional_keywords.size if method_type.type.rest_keywords
|
|
189
|
+
end
|
|
190
|
+
else
|
|
191
|
+
pos = node.children[2...].index { |c| c.location == argument_nodes[-2].location }.to_i
|
|
192
|
+
[pos, positionals - 1].min
|
|
193
|
+
end
|
|
194
|
+
end
|
|
195
|
+
end
|
|
101
196
|
end
|
|
102
197
|
end
|
|
103
198
|
end
|
|
@@ -1883,9 +1883,25 @@ module Steep
|
|
|
1883
1883
|
|
|
1884
1884
|
if truthy.unreachable
|
|
1885
1885
|
if true_clause
|
|
1886
|
+
_, _, _, loc = deconstruct_if_node!(node)
|
|
1887
|
+
|
|
1888
|
+
if loc.respond_to?(:keyword)
|
|
1889
|
+
condition_loc = loc #: NodeHelper::condition_loc
|
|
1890
|
+
case condition_loc.keyword.source
|
|
1891
|
+
when "if"
|
|
1892
|
+
location = condition_loc.begin || condition_loc.keyword
|
|
1893
|
+
when "unless"
|
|
1894
|
+
# `else` token always exists
|
|
1895
|
+
location = condition_loc.else || raise
|
|
1896
|
+
end
|
|
1897
|
+
else
|
|
1898
|
+
location = true_clause.loc.expression
|
|
1899
|
+
end
|
|
1900
|
+
|
|
1886
1901
|
typing.add_error(
|
|
1887
1902
|
Diagnostic::Ruby::UnreachableBranch.new(
|
|
1888
|
-
node: true_clause
|
|
1903
|
+
node: true_clause,
|
|
1904
|
+
location: location || raise
|
|
1889
1905
|
)
|
|
1890
1906
|
)
|
|
1891
1907
|
end
|
|
@@ -1893,9 +1909,25 @@ module Steep
|
|
|
1893
1909
|
|
|
1894
1910
|
if falsy.unreachable
|
|
1895
1911
|
if false_clause
|
|
1912
|
+
_, _, _, loc = deconstruct_if_node!(node)
|
|
1913
|
+
|
|
1914
|
+
if loc.respond_to?(:keyword)
|
|
1915
|
+
condition_loc = loc #: NodeHelper::condition_loc
|
|
1916
|
+
case condition_loc.keyword.source
|
|
1917
|
+
when "if"
|
|
1918
|
+
# `else` token always exists
|
|
1919
|
+
location = condition_loc.else || raise
|
|
1920
|
+
when "unless"
|
|
1921
|
+
location = condition_loc.begin || condition_loc.keyword
|
|
1922
|
+
end
|
|
1923
|
+
else
|
|
1924
|
+
location = false_clause.loc.expression
|
|
1925
|
+
end
|
|
1926
|
+
|
|
1896
1927
|
typing.add_error(
|
|
1897
1928
|
Diagnostic::Ruby::UnreachableBranch.new(
|
|
1898
|
-
node: false_clause
|
|
1929
|
+
node: false_clause,
|
|
1930
|
+
location: location || raise
|
|
1899
1931
|
)
|
|
1900
1932
|
)
|
|
1901
1933
|
end
|
|
@@ -1918,10 +1950,6 @@ module Steep
|
|
|
1918
1950
|
branch_results = [] #: Array[Pair]
|
|
1919
1951
|
|
|
1920
1952
|
cond_type, constr = constr.synthesize(cond)
|
|
1921
|
-
_, cond_vars = interpreter.decompose_value(cond)
|
|
1922
|
-
SPECIAL_LVAR_NAMES.each do |name|
|
|
1923
|
-
cond_vars.delete(name)
|
|
1924
|
-
end
|
|
1925
1953
|
|
|
1926
1954
|
var_name = :"_a[#{SecureRandom.alphanumeric(4)}]"
|
|
1927
1955
|
var_cond, value_node = transform_condition_node(cond, var_name)
|
|
@@ -1961,19 +1989,25 @@ module Steep
|
|
|
1961
1989
|
next_branch_reachable &&= false_branch_reachable
|
|
1962
1990
|
body_constr = when_constr.update_type_env {|env| env.join(*test_envs) }
|
|
1963
1991
|
|
|
1964
|
-
|
|
1965
|
-
|
|
1992
|
+
branch_result =
|
|
1993
|
+
if body
|
|
1966
1994
|
body_constr
|
|
1967
1995
|
.for_branch(body)
|
|
1968
1996
|
.tap {|constr| typing.add_context_for_node(body, context: constr.context) }
|
|
1969
1997
|
.synthesize(body, hint: hint)
|
|
1970
|
-
|
|
1971
|
-
|
|
1972
|
-
|
|
1998
|
+
else
|
|
1999
|
+
Pair.new(type: AST::Builtin.nil_type, constr: body_constr)
|
|
2000
|
+
end
|
|
1973
2001
|
|
|
1974
|
-
|
|
2002
|
+
branch_results << branch_result
|
|
2003
|
+
|
|
2004
|
+
if !branch_reachable && !branch_result.type.is_a?(AST::Types::Bot)
|
|
1975
2005
|
typing.add_error(
|
|
1976
|
-
Diagnostic::Ruby::
|
|
2006
|
+
Diagnostic::Ruby::UnreachableValueBranch.new(
|
|
2007
|
+
node: clause,
|
|
2008
|
+
type: branch_result.type,
|
|
2009
|
+
location: clause.location.keyword
|
|
2010
|
+
)
|
|
1977
2011
|
)
|
|
1978
2012
|
end
|
|
1979
2013
|
|
|
@@ -2004,9 +2038,14 @@ module Steep
|
|
|
2004
2038
|
# `else` may present even if it's empty
|
|
2005
2039
|
if loc.else
|
|
2006
2040
|
if els
|
|
2007
|
-
|
|
2008
|
-
|
|
2009
|
-
|
|
2041
|
+
else_result or raise
|
|
2042
|
+
unless else_result.type.is_a?(AST::Types::Bot)
|
|
2043
|
+
typing.add_error Diagnostic::Ruby::UnreachableValueBranch.new(
|
|
2044
|
+
node: els,
|
|
2045
|
+
type: else_result.type,
|
|
2046
|
+
location: node.loc.else || raise
|
|
2047
|
+
)
|
|
2048
|
+
end
|
|
2010
2049
|
end
|
|
2011
2050
|
end
|
|
2012
2051
|
else
|
|
@@ -2042,21 +2081,29 @@ module Steep
|
|
|
2042
2081
|
branch_reachable ||= !truthy.unreachable
|
|
2043
2082
|
end
|
|
2044
2083
|
|
|
2045
|
-
|
|
2046
|
-
|
|
2084
|
+
branch_result =
|
|
2085
|
+
if body
|
|
2047
2086
|
when_clause_constr
|
|
2048
2087
|
.for_branch(body)
|
|
2049
2088
|
.update_type_env {|env| env.join(*body_envs) }
|
|
2050
2089
|
.tap {|constr| typing.add_context_for_node(body, context: constr.context) }
|
|
2051
2090
|
.synthesize(body, hint: hint)
|
|
2052
|
-
|
|
2053
|
-
|
|
2054
|
-
|
|
2091
|
+
else
|
|
2092
|
+
Pair.new(type: AST::Builtin.nil_type, constr: when_clause_constr)
|
|
2093
|
+
end
|
|
2094
|
+
|
|
2095
|
+
branch_results << branch_result
|
|
2055
2096
|
|
|
2056
2097
|
unless branch_reachable
|
|
2057
|
-
|
|
2058
|
-
|
|
2059
|
-
|
|
2098
|
+
unless branch_result.type.is_a?(AST::Types::Bot)
|
|
2099
|
+
typing.add_error(
|
|
2100
|
+
Diagnostic::Ruby::UnreachableValueBranch.new(
|
|
2101
|
+
node: when_clause,
|
|
2102
|
+
type: branch_result.type,
|
|
2103
|
+
location: when_clause.location.keyword || raise
|
|
2104
|
+
)
|
|
2105
|
+
)
|
|
2106
|
+
end
|
|
2060
2107
|
end
|
|
2061
2108
|
end
|
|
2062
2109
|
|
|
@@ -2570,7 +2617,26 @@ module Steep
|
|
|
2570
2617
|
# @type var as_type: AST::Node::TypeAssertion
|
|
2571
2618
|
asserted_node, as_type = node.children
|
|
2572
2619
|
|
|
2573
|
-
|
|
2620
|
+
type = as_type.type(module_context.nesting, checker, [])
|
|
2621
|
+
|
|
2622
|
+
case type
|
|
2623
|
+
when Array
|
|
2624
|
+
type.each do |error|
|
|
2625
|
+
typing.add_error(
|
|
2626
|
+
Diagnostic::Ruby::RBSError.new(
|
|
2627
|
+
error: error,
|
|
2628
|
+
node: node,
|
|
2629
|
+
location: error.location || raise
|
|
2630
|
+
)
|
|
2631
|
+
)
|
|
2632
|
+
end
|
|
2633
|
+
|
|
2634
|
+
synthesize(asserted_node, hint: hint)
|
|
2635
|
+
|
|
2636
|
+
when nil, RBS::ParsingError
|
|
2637
|
+
synthesize(asserted_node, hint: hint)
|
|
2638
|
+
|
|
2639
|
+
else
|
|
2574
2640
|
actual_type, constr = synthesize(asserted_node, hint: type)
|
|
2575
2641
|
|
|
2576
2642
|
if no_subtyping?(sub_type: type, super_type: actual_type) && no_subtyping?(sub_type: actual_type, super_type: type)
|
|
@@ -2584,22 +2650,34 @@ module Steep
|
|
|
2584
2650
|
end
|
|
2585
2651
|
|
|
2586
2652
|
constr.add_typing(node, type: type)
|
|
2587
|
-
else
|
|
2588
|
-
synthesize(asserted_node, hint: hint)
|
|
2589
2653
|
end
|
|
2590
2654
|
end
|
|
2591
2655
|
|
|
2592
|
-
when :block, :numblock, :send, :csend
|
|
2593
|
-
synthesize_sendish(node, hint: hint, tapp: nil)
|
|
2594
|
-
|
|
2595
2656
|
when :tapp
|
|
2596
2657
|
yield_self do
|
|
2658
|
+
# @type var tapp: AST::Node::TypeApplication
|
|
2597
2659
|
sendish, tapp = node.children
|
|
2660
|
+
|
|
2661
|
+
if (array = tapp.types(module_context.nesting, checker, [])).is_a?(Enumerator)
|
|
2662
|
+
array.each do |error|
|
|
2663
|
+
typing.add_error(
|
|
2664
|
+
Diagnostic::Ruby::RBSError.new(
|
|
2665
|
+
error: error,
|
|
2666
|
+
node: node,
|
|
2667
|
+
location: error.location || raise
|
|
2668
|
+
)
|
|
2669
|
+
)
|
|
2670
|
+
end
|
|
2671
|
+
end
|
|
2672
|
+
|
|
2598
2673
|
type, constr = synthesize_sendish(sendish, hint: hint, tapp: tapp)
|
|
2599
2674
|
|
|
2600
2675
|
constr.add_typing(node, type: type)
|
|
2601
2676
|
end
|
|
2602
2677
|
|
|
2678
|
+
when :block, :numblock, :send, :csend
|
|
2679
|
+
synthesize_sendish(node, hint: hint, tapp: nil)
|
|
2680
|
+
|
|
2603
2681
|
when :forwarded_args, :forward_arg
|
|
2604
2682
|
add_typing(node, type: AST::Builtin.any_type)
|
|
2605
2683
|
|
|
@@ -3026,7 +3104,8 @@ module Steep
|
|
|
3026
3104
|
type_hint = deep_expand_alias(type_hint) || type_hint
|
|
3027
3105
|
|
|
3028
3106
|
procs = flatten_union(type_hint).select do |type|
|
|
3029
|
-
check_relation(sub_type: type, super_type: AST::Builtin::Proc.instance_type).success?
|
|
3107
|
+
check_relation(sub_type: type, super_type: AST::Builtin::Proc.instance_type).success? &&
|
|
3108
|
+
!type.is_a?(AST::Types::Any)
|
|
3030
3109
|
end
|
|
3031
3110
|
|
|
3032
3111
|
proc_instances, proc_types = procs.partition {|type| AST::Builtin::Proc.instance_type?(type) }
|
|
@@ -3913,13 +3992,15 @@ module Steep
|
|
|
3913
3992
|
end
|
|
3914
3993
|
|
|
3915
3994
|
if hint && !fvs.empty?
|
|
3916
|
-
if
|
|
3917
|
-
|
|
3918
|
-
|
|
3995
|
+
if hint.free_variables.subset?(self_type.free_variables)
|
|
3996
|
+
if check_relation(sub_type: method_type.type.return_type, super_type: hint, constraints: constraints).success?
|
|
3997
|
+
method_type, solved, s = apply_solution(errors, node: node, method_type: method_type) do
|
|
3998
|
+
constraints.solution(checker, variables: fvs, context: ccontext)
|
|
3999
|
+
end
|
|
3919
4000
|
end
|
|
3920
|
-
end
|
|
3921
4001
|
|
|
3922
|
-
|
|
4002
|
+
method_type.block or raise
|
|
4003
|
+
end
|
|
3923
4004
|
end
|
|
3924
4005
|
|
|
3925
4006
|
# Method accepts block
|
|
@@ -126,7 +126,9 @@ module Steep
|
|
|
126
126
|
|
|
127
127
|
def upper_bounds
|
|
128
128
|
table.each_value.with_object({}) do |type_param, bounds|
|
|
129
|
-
|
|
129
|
+
if type_param.upper_bound
|
|
130
|
+
bounds[type_param.name] = type_param.upper_bound
|
|
131
|
+
end
|
|
130
132
|
end
|
|
131
133
|
end
|
|
132
134
|
|
|
@@ -681,7 +681,15 @@ module Steep
|
|
|
681
681
|
when KeywordArgs::MissingKeyword
|
|
682
682
|
missing_keywords.push(*error.keywords.to_a)
|
|
683
683
|
when PositionalArgs::UnexpectedArg
|
|
684
|
-
|
|
684
|
+
if error.node.type == :kwargs
|
|
685
|
+
error.node.children.each do |kwarg|
|
|
686
|
+
if kwarg.type == :pair
|
|
687
|
+
diagnostics << Diagnostic::Ruby::UnexpectedKeywordArgument.new(node: kwarg, params: params)
|
|
688
|
+
end
|
|
689
|
+
end
|
|
690
|
+
else
|
|
691
|
+
diagnostics << Diagnostic::Ruby::UnexpectedPositionalArgument.new(node: error.node, params: params)
|
|
692
|
+
end
|
|
685
693
|
when PositionalArgs::MissingArg
|
|
686
694
|
diagnostics << Diagnostic::Ruby::InsufficientPositionalArguments.new(node: node, params: params)
|
|
687
695
|
end
|
data/lib/steep/version.rb
CHANGED
data/sig/shims/parser/nodes.rbs
CHANGED
|
@@ -12,7 +12,7 @@ module Steep
|
|
|
12
12
|
|
|
13
13
|
def initialize: (RBS::Location[untyped, untyped]) -> void
|
|
14
14
|
|
|
15
|
-
def types: (RBS::Resolver::context, Subtyping::Check, Array[Symbol] type_vars) -> (Array[Types::t] | RBS::ParsingError | nil)
|
|
15
|
+
def types: (RBS::Resolver::context, Subtyping::Check, Array[Symbol] type_vars) -> (Array[Types::t] | RBS::ParsingError | Enumerator[Diagnostic::Signature::Base, void] | nil)
|
|
16
16
|
|
|
17
17
|
def types?: (RBS::Resolver::context, Subtyping::Check, Array[Symbol] type_vars) -> Array[Types::t]?
|
|
18
18
|
|
|
@@ -10,7 +10,7 @@ module Steep
|
|
|
10
10
|
|
|
11
11
|
def initialize: (RBS::Location[untyped, untyped]) -> void
|
|
12
12
|
|
|
13
|
-
def type: (RBS::Resolver::context, Subtyping::Check, Array[Symbol] type_vars) -> (Types::t | RBS::ParsingError | nil)
|
|
13
|
+
def type: (RBS::Resolver::context, Subtyping::Check, Array[Symbol] type_vars) -> (Types::t | RBS::ParsingError | Array[Diagnostic::Signature::Base] | nil)
|
|
14
14
|
|
|
15
15
|
def type?: (RBS::Resolver::context, Subtyping::Check, Array[Symbol] type_vars) -> Types::t?
|
|
16
16
|
|
|
@@ -479,6 +479,31 @@ module Steep
|
|
|
479
479
|
def header_line: () -> String
|
|
480
480
|
end
|
|
481
481
|
|
|
482
|
+
# The branch is unreachable, but not `bot` type
|
|
483
|
+
#
|
|
484
|
+
# We often have `else` branch to make the code more defensive:
|
|
485
|
+
#
|
|
486
|
+
# ```ruby
|
|
487
|
+
# case value
|
|
488
|
+
# when Integer
|
|
489
|
+
# # ...
|
|
490
|
+
# when String
|
|
491
|
+
# # ...
|
|
492
|
+
# else
|
|
493
|
+
# raise "Cannot happen!"
|
|
494
|
+
# end
|
|
495
|
+
# ```
|
|
496
|
+
#
|
|
497
|
+
# This diagnostic allows writing `raise` or `return`, by checking the type of the branch body is `bot` or not.
|
|
498
|
+
#
|
|
499
|
+
class UnreachableValueBranch < Base
|
|
500
|
+
attr_reader type: AST::Types::t
|
|
501
|
+
|
|
502
|
+
def initialize: (node: Parser::AST::Node, type: AST::Types::t, ?location: location) -> void
|
|
503
|
+
|
|
504
|
+
def header_line: () -> String
|
|
505
|
+
end
|
|
506
|
+
|
|
482
507
|
class UnexpectedSplat < Base
|
|
483
508
|
attr_reader type: untyped
|
|
484
509
|
|
|
@@ -597,6 +622,14 @@ module Steep
|
|
|
597
622
|
def initialize: (hint_type: AST::Types::t, node: Parser::AST::Node) -> void
|
|
598
623
|
end
|
|
599
624
|
|
|
625
|
+
# RBS embedded in the Ruby code has validation error
|
|
626
|
+
#
|
|
627
|
+
class RBSError < Base
|
|
628
|
+
attr_reader error: Signature::Base
|
|
629
|
+
|
|
630
|
+
def initialize: (error: Signature::Base, node: Parser::AST::Node, location: location) -> void
|
|
631
|
+
end
|
|
632
|
+
|
|
600
633
|
# Argument forwarding `...` cannot be done safely, because of
|
|
601
634
|
#
|
|
602
635
|
# 1. The arguments are incompatible, or
|
data/sig/steep/node_helper.rbs
CHANGED
|
@@ -65,5 +65,14 @@ module Steep
|
|
|
65
65
|
def deconstruct_send_node!: (Node) -> [Node?, Symbol, Array[Node], send_loc]
|
|
66
66
|
|
|
67
67
|
def test_send_node: (Node) { (Node?, Symbol, Array[Node], send_loc) -> bool } -> bool
|
|
68
|
+
|
|
69
|
+
# Deconstruct sendish node and it's associated block node
|
|
70
|
+
#
|
|
71
|
+
# Receives a sequence of node tree where the leaf node comes first.
|
|
72
|
+
# If the first node is `send`, `csend`, `super`, or `zsuper`, it is the sendish node.
|
|
73
|
+
#
|
|
74
|
+
# If the next node is a `block` or `numblock` that is associated to the *sendish node*, it is the block node.
|
|
75
|
+
#
|
|
76
|
+
def deconstruct_sendish_and_block_nodes: (*Parser::AST::Node) -> [Parser::AST::Node, Parser::AST::Node?]?
|
|
68
77
|
end
|
|
69
78
|
end
|
|
@@ -4,6 +4,8 @@ use Steep::TypeInference::MethodCall
|
|
|
4
4
|
module Steep
|
|
5
5
|
module Services
|
|
6
6
|
class CompletionProvider
|
|
7
|
+
include NodeHelper
|
|
8
|
+
|
|
7
9
|
# Cursor position
|
|
8
10
|
class Position
|
|
9
11
|
attr_reader line: Integer
|
|
@@ -33,6 +35,14 @@ module Steep
|
|
|
33
35
|
def initialize: (identifier: Symbol, range: Range, type: AST::Types::t) -> void
|
|
34
36
|
end
|
|
35
37
|
|
|
38
|
+
class KeywordArgumentItem
|
|
39
|
+
attr_reader identifier: String
|
|
40
|
+
|
|
41
|
+
attr_reader range: Range
|
|
42
|
+
|
|
43
|
+
def initialize: (identifier: String, range: Range) -> void
|
|
44
|
+
end
|
|
45
|
+
|
|
36
46
|
class LocalVariableItem
|
|
37
47
|
attr_reader identifier: Symbol
|
|
38
48
|
|
|
@@ -169,6 +179,7 @@ module Steep
|
|
|
169
179
|
end
|
|
170
180
|
|
|
171
181
|
type item = InstanceVariableItem
|
|
182
|
+
| KeywordArgumentItem
|
|
172
183
|
| LocalVariableItem
|
|
173
184
|
| ConstantItem
|
|
174
185
|
| SimpleMethodNameItem
|
|
@@ -216,6 +227,8 @@ module Steep
|
|
|
216
227
|
|
|
217
228
|
def items_for_rbs: (position: Position, buffer: RBS::Buffer) -> Array[item]
|
|
218
229
|
|
|
230
|
+
def items_for_following_keyword_arguments: (String text, index: Integer, line: Integer, column: Integer, items: Array[item]) -> void
|
|
231
|
+
|
|
219
232
|
def method_items_for_receiver_type: (AST::Types::t, include_private: bool, prefix: String, position: Position, items: Array[item]) -> void
|
|
220
233
|
|
|
221
234
|
def word_name?: (String name) -> bool
|
|
@@ -226,12 +239,13 @@ module Steep
|
|
|
226
239
|
|
|
227
240
|
def instance_variable_items_for_context: (TypeInference::Context context, position: Position, prefix: String, items: Array[item]) -> void
|
|
228
241
|
|
|
242
|
+
def keyword_argument_items_for_method: (call_node: Parser::AST::Node, send_node: Parser::AST::Node, position: Position, prefix: String, items: Array[item]) -> void
|
|
243
|
+
|
|
229
244
|
def index_for: (String, line: Integer, column: Integer) -> Integer
|
|
230
245
|
|
|
231
246
|
def disallowed_method?: (Symbol name) -> bool
|
|
232
247
|
|
|
233
248
|
def unwrap_optional: (AST::Types::t) -> AST::Types::t
|
|
234
|
-
|
|
235
249
|
end
|
|
236
250
|
end
|
|
237
251
|
end
|
|
@@ -10,7 +10,11 @@ module Steep
|
|
|
10
10
|
|
|
11
11
|
attr_reader comment: RBS::AST::Comment?
|
|
12
12
|
|
|
13
|
-
|
|
13
|
+
attr_reader active_parameter: Integer?
|
|
14
|
+
|
|
15
|
+
def initialize: (RBS::MethodType, RBS::AST::Comment?, Integer?) -> void
|
|
16
|
+
|
|
17
|
+
def parameters: () -> Array[String]
|
|
14
18
|
end
|
|
15
19
|
|
|
16
20
|
attr_reader source: Source
|
|
@@ -31,7 +35,13 @@ module Steep
|
|
|
31
35
|
|
|
32
36
|
private
|
|
33
37
|
|
|
34
|
-
def
|
|
38
|
+
def active_parameter_for: (RBS::MethodType?, Array[Parser::AST::Node], Array[Parser::AST::Node]?, Parser::AST::Node) -> Integer?
|
|
39
|
+
|
|
40
|
+
def arguments_for: (RBS::MethodType) -> Array[String]
|
|
41
|
+
|
|
42
|
+
def last_argument_nodes_for: (argument_nodes: Array[Parser::AST::Node], line: Integer, column: Integer) -> Array[Parser::AST::Node]?
|
|
43
|
+
|
|
44
|
+
def signature_help_for: (Parser::AST::Node, Array[Parser::AST::Node], Array[Parser::AST::Node]?, Typing) -> [Array[Item], Integer?]?
|
|
35
45
|
|
|
36
46
|
def type_check!: (line: Integer, column: Integer) -> Typing
|
|
37
47
|
end
|
|
@@ -38,7 +38,7 @@ module Steep
|
|
|
38
38
|
|
|
39
39
|
def validate_type_application: (RBS::Types::t) -> void
|
|
40
40
|
|
|
41
|
-
def validate_type: (RBS::Types::t `type`) ->
|
|
41
|
+
def validate_type: (RBS::Types::t `type`) -> void
|
|
42
42
|
|
|
43
43
|
def ancestor_to_type: (RBS::Definition::Ancestor::t ancestor) -> (AST::Types::Name::Interface | AST::Types::Name::Instance)
|
|
44
44
|
|
|
@@ -69,7 +69,7 @@ module Steep
|
|
|
69
69
|
def validate_one_alias: (RBS::TypeName name, ?RBS::Environment::TypeAliasEntry entry) -> void
|
|
70
70
|
|
|
71
71
|
def validate_one_class_decl: (RBS::TypeName) -> void
|
|
72
|
-
|
|
72
|
+
|
|
73
73
|
def validate_one_class_alias: (RBS::TypeName, RBS::Environment::ClassAliasEntry | RBS::Environment::ModuleAliasEntry) -> void
|
|
74
74
|
|
|
75
75
|
def validate_alias: () -> void
|
|
@@ -120,18 +120,6 @@
|
|
|
120
120
|
message: 'The method parameter has different kind from the declaration `(name:
|
|
121
121
|
::String, size: ::Integer) -> void`'
|
|
122
122
|
code: Ruby::DifferentMethodParameterKind
|
|
123
|
-
- file: else_on_exhaustive_case.rb
|
|
124
|
-
diagnostics:
|
|
125
|
-
- range:
|
|
126
|
-
start:
|
|
127
|
-
line: 11
|
|
128
|
-
character: 2
|
|
129
|
-
end:
|
|
130
|
-
line: 11
|
|
131
|
-
character: 26
|
|
132
|
-
severity: ERROR
|
|
133
|
-
message: The branch is unreachable
|
|
134
|
-
code: Ruby::UnreachableBranch
|
|
135
123
|
- file: incompatible_annotation.rb
|
|
136
124
|
diagnostics:
|
|
137
125
|
- range:
|
|
@@ -13,14 +13,14 @@
|
|
|
13
13
|
code: Ruby::NoMethod
|
|
14
14
|
- range:
|
|
15
15
|
start:
|
|
16
|
-
line:
|
|
17
|
-
character:
|
|
16
|
+
line: 11
|
|
17
|
+
character: 0
|
|
18
18
|
end:
|
|
19
|
-
line:
|
|
20
|
-
character:
|
|
19
|
+
line: 11
|
|
20
|
+
character: 4
|
|
21
21
|
severity: ERROR
|
|
22
|
-
message: The branch
|
|
23
|
-
code: Ruby::
|
|
22
|
+
message: The branch may evaluate to a value of `untyped` but unreachable
|
|
23
|
+
code: Ruby::UnreachableValueBranch
|
|
24
24
|
- range:
|
|
25
25
|
start:
|
|
26
26
|
line: 12
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: steep
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 1.5.0.pre.
|
|
4
|
+
version: 1.5.0.pre.6
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Soutaro Matsumoto
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: exe
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2023-07-
|
|
11
|
+
date: 2023-07-11 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: parser
|