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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: ed79428764aa83fbd2e7f3c5a8e52ff863b4e65bef05aae43ba9ca4b7c9d2f4e
4
- data.tar.gz: be79772ce19f152e3048ae565802640cae96f1bfca98adf60eab47a28ab3ccad
3
+ metadata.gz: d00242c259b7c8d2a4a0f7022874ac5bb5f08491ab3edade6165ff1a9fbe89a7
4
+ data.tar.gz: e02d896359c4eb88c730601320bb9137342c19b9ad1956d4ac417ffa5926d74a
5
5
  SHA512:
6
- metadata.gz: aa071be8eaf425a2a36ffed4c8d0a97446997f9cbf85c9dc4190b5bf26c9bf5f66c7106ab27b96378d05e246a6327689ef491dedbd16ad7cb9eb8d8079b3818d
7
- data.tar.gz: d7f842d51c84a2f48bdfd79a07de3e6265dd746497aa9661871f12b062832c2a24f46b37ce1ddb614ac5ba1c65f4c408e9e1eafec27fd69d7158514fe77e0fec
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
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- steep (1.5.0.pre.5)
4
+ steep (1.5.0.pre.6)
5
5
  activesupport (>= 5.1)
6
6
  concurrent-ruby (>= 1.1.10)
7
7
  csv (>= 3.0.9)
@@ -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.validate_type(ty)
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.validate_type(ty)
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
@@ -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
@@ -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
@@ -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, *_parents = source.find_nodes(line: position.line, column: position.column)
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.children[0]
59
+ send_node = parent
44
60
  else
45
61
  send_node = node
46
62
  end
47
63
 
48
- return signature_help_for(send_node, typing)
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 signature_help_for(node, typing)
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
- items << Item.new(subtyping.factory.method_type_1(method_type), defn&.comment)
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
- if type = as_type.type?(module_context.nesting, checker, [])
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
- diagnostics << Diagnostic::Ruby::UnexpectedPositionalArgument.new(node: error.node, params: params)
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
@@ -1,3 +1,3 @@
1
1
  module Steep
2
- VERSION = "1.5.0.pre.5"
2
+ VERSION = "1.5.0.pre.6"
3
3
  end
@@ -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
@@ -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
- def initialize: (RBS::MethodType, RBS::AST::Comment?) -> void
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 signature_help_for: (Parser::AST::Node, Typing) -> [Array[Item], Integer?]?
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`) -> untyped
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.5
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-07 00:00:00.000000000 Z
11
+ date: 2023-07-11 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: parser