steep 1.5.0.pre.5 → 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 +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
|