steep 1.5.0.pre.5 → 1.5.0.pre.6
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +18 -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 +7 -0
- data/lib/steep/diagnostic/ruby.rb +13 -0
- 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 +39 -11
- data/lib/steep/type_inference/send_args.rb +9 -1
- data/lib/steep/version.rb +1 -1
- 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 +9 -1
- 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
- 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,24 @@
|
|
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
|
+
|
5
23
|
## 1.5.0.pre.5 (2023-07-07)
|
6
24
|
|
7
25
|
### 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
|
@@ -964,6 +964,19 @@ module Steep
|
|
964
964
|
end
|
965
965
|
end
|
966
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
|
+
|
967
980
|
ALL = ObjectSpace.each_object(Class).with_object([]) do |klass, array|
|
968
981
|
if klass < Base
|
969
982
|
array << klass
|
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
|
@@ -1950,10 +1950,6 @@ module Steep
|
|
1950
1950
|
branch_results = [] #: Array[Pair]
|
1951
1951
|
|
1952
1952
|
cond_type, constr = constr.synthesize(cond)
|
1953
|
-
_, cond_vars = interpreter.decompose_value(cond)
|
1954
|
-
SPECIAL_LVAR_NAMES.each do |name|
|
1955
|
-
cond_vars.delete(name)
|
1956
|
-
end
|
1957
1953
|
|
1958
1954
|
var_name = :"_a[#{SecureRandom.alphanumeric(4)}]"
|
1959
1955
|
var_cond, value_node = transform_condition_node(cond, var_name)
|
@@ -2621,7 +2617,26 @@ module Steep
|
|
2621
2617
|
# @type var as_type: AST::Node::TypeAssertion
|
2622
2618
|
asserted_node, as_type = node.children
|
2623
2619
|
|
2624
|
-
|
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
|
2625
2640
|
actual_type, constr = synthesize(asserted_node, hint: type)
|
2626
2641
|
|
2627
2642
|
if no_subtyping?(sub_type: type, super_type: actual_type) && no_subtyping?(sub_type: actual_type, super_type: type)
|
@@ -2635,22 +2650,34 @@ module Steep
|
|
2635
2650
|
end
|
2636
2651
|
|
2637
2652
|
constr.add_typing(node, type: type)
|
2638
|
-
else
|
2639
|
-
synthesize(asserted_node, hint: hint)
|
2640
2653
|
end
|
2641
2654
|
end
|
2642
2655
|
|
2643
|
-
when :block, :numblock, :send, :csend
|
2644
|
-
synthesize_sendish(node, hint: hint, tapp: nil)
|
2645
|
-
|
2646
2656
|
when :tapp
|
2647
2657
|
yield_self do
|
2658
|
+
# @type var tapp: AST::Node::TypeApplication
|
2648
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
|
+
|
2649
2673
|
type, constr = synthesize_sendish(sendish, hint: hint, tapp: tapp)
|
2650
2674
|
|
2651
2675
|
constr.add_typing(node, type: type)
|
2652
2676
|
end
|
2653
2677
|
|
2678
|
+
when :block, :numblock, :send, :csend
|
2679
|
+
synthesize_sendish(node, hint: hint, tapp: nil)
|
2680
|
+
|
2654
2681
|
when :forwarded_args, :forward_arg
|
2655
2682
|
add_typing(node, type: AST::Builtin.any_type)
|
2656
2683
|
|
@@ -3077,7 +3104,8 @@ module Steep
|
|
3077
3104
|
type_hint = deep_expand_alias(type_hint) || type_hint
|
3078
3105
|
|
3079
3106
|
procs = flatten_union(type_hint).select do |type|
|
3080
|
-
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)
|
3081
3109
|
end
|
3082
3110
|
|
3083
3111
|
proc_instances, proc_types = procs.partition {|type| AST::Builtin::Proc.instance_type?(type) }
|
@@ -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
@@ -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
|
|
@@ -495,7 +495,7 @@ module Steep
|
|
495
495
|
# ```
|
496
496
|
#
|
497
497
|
# This diagnostic allows writing `raise` or `return`, by checking the type of the branch body is `bot` or not.
|
498
|
-
#
|
498
|
+
#
|
499
499
|
class UnreachableValueBranch < Base
|
500
500
|
attr_reader type: AST::Types::t
|
501
501
|
|
@@ -622,6 +622,14 @@ module Steep
|
|
622
622
|
def initialize: (hint_type: AST::Types::t, node: Parser::AST::Node) -> void
|
623
623
|
end
|
624
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
|
+
|
625
633
|
# Argument forwarding `...` cannot be done safely, because of
|
626
634
|
#
|
627
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
|
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
|