steep 0.43.0 → 0.45.0

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.
Files changed (59) hide show
  1. checksums.yaml +4 -4
  2. data/.github/dependabot.yml +8 -0
  3. data/.github/workflows/ruby.yml +3 -2
  4. data/.gitignore +0 -1
  5. data/CHANGELOG.md +30 -0
  6. data/Gemfile +0 -1
  7. data/Gemfile.lock +77 -0
  8. data/bin/output_test.rb +8 -2
  9. data/lib/steep.rb +4 -1
  10. data/lib/steep/ast/builtin.rb +7 -1
  11. data/lib/steep/ast/types/factory.rb +19 -25
  12. data/lib/steep/diagnostic/ruby.rb +137 -60
  13. data/lib/steep/diagnostic/signature.rb +34 -0
  14. data/lib/steep/equatable.rb +21 -0
  15. data/lib/steep/index/source_index.rb +55 -5
  16. data/lib/steep/interface/block.rb +4 -0
  17. data/lib/steep/interface/function.rb +798 -579
  18. data/lib/steep/server/interaction_worker.rb +239 -20
  19. data/lib/steep/server/master.rb +40 -19
  20. data/lib/steep/server/type_check_worker.rb +68 -0
  21. data/lib/steep/services/file_loader.rb +26 -19
  22. data/lib/steep/services/goto_service.rb +322 -0
  23. data/lib/steep/services/hover_content.rb +131 -79
  24. data/lib/steep/services/type_check_service.rb +25 -0
  25. data/lib/steep/source.rb +7 -10
  26. data/lib/steep/type_construction.rb +496 -518
  27. data/lib/steep/type_inference/block_params.rb +2 -5
  28. data/lib/steep/type_inference/method_params.rb +483 -0
  29. data/lib/steep/type_inference/send_args.rb +610 -128
  30. data/lib/steep/typing.rb +46 -21
  31. data/lib/steep/version.rb +1 -1
  32. data/sig/steep/type_inference/send_args.rbs +42 -0
  33. data/smoke/array/test_expectations.yml +3 -3
  34. data/smoke/block/c.rb +0 -1
  35. data/smoke/class/test_expectations.yml +12 -15
  36. data/smoke/const/test_expectations.yml +0 -10
  37. data/smoke/diagnostics-rbs/mixin-class-error.rbs +6 -0
  38. data/smoke/diagnostics-rbs/test_expectations.yml +12 -0
  39. data/smoke/diagnostics-ruby-unsat/Steepfile +5 -0
  40. data/smoke/diagnostics-ruby-unsat/a.rbs +3 -0
  41. data/smoke/diagnostics-ruby-unsat/test_expectations.yml +27 -0
  42. data/smoke/{diagnostics → diagnostics-ruby-unsat}/unsatisfiable_constraint.rb +0 -1
  43. data/smoke/diagnostics/a.rbs +0 -4
  44. data/smoke/diagnostics/different_method_parameter_kind.rb +9 -0
  45. data/smoke/diagnostics/method_arity_mismatch.rb +2 -2
  46. data/smoke/diagnostics/method_parameter_mismatch.rb +10 -0
  47. data/smoke/diagnostics/test_expectations.yml +108 -57
  48. data/smoke/ensure/test_expectations.yml +3 -3
  49. data/smoke/enumerator/test_expectations.yml +1 -1
  50. data/smoke/literal/test_expectations.yml +2 -2
  51. data/smoke/method/test_expectations.yml +11 -10
  52. data/smoke/regression/issue_372.rb +8 -0
  53. data/smoke/regression/issue_372.rbs +4 -0
  54. data/smoke/regression/test_expectations.yml +0 -12
  55. data/smoke/rescue/test_expectations.yml +3 -3
  56. data/smoke/toplevel/test_expectations.yml +3 -3
  57. data/smoke/tsort/test_expectations.yml +2 -2
  58. data/steep.gemspec +2 -2
  59. metadata +24 -10
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: '0568c96d6a39d5c6db14e2259b5cdf3cd39bfaf5f2a4368ce060de4c803c0c96'
4
- data.tar.gz: d820c5f0c0d6394893a907999d4fdbd0f3a90b4821380c20598e9251d29852e6
3
+ metadata.gz: '080cf1692f90640baacc712908524e2daf36039ea992eb3424de7094c49f6778'
4
+ data.tar.gz: dd9f8837ec50e625ce9a0814fcbef03191bf484debd33034f9d00819115fef81
5
5
  SHA512:
6
- metadata.gz: 8f4f17d938d9f7f462f3db8aff1e48f8bf4118ab66bf40b35abd9b38ea3585014a0d8d372277e5589e9697043946b0e646193e4d7413c55fcf490d6065494203
7
- data.tar.gz: d7ece354f2e50faa86b65ed4a62c14f97dc74550fb81326142b8932f8c58deb2da40679a34e1869183e15ab4a90e939fb0041c44c63a5149b8234c82058481b0
6
+ metadata.gz: 67d26f6197f5b4fe53195c2202cdbbf556e2496fda4498151646c6d93a8455de0b75af66c35b16f32375fc239574600e33cc5f8caf92cc8f96a659ca0588b4da
7
+ data.tar.gz: 718c99448377245e8e0871af93c445d037aef4dbc727185bfd658f49672c08a11e8acc3807c7cb2a55814ffd32fb87642c9b37fc9f17143d4474a2810e2e4f3e
@@ -0,0 +1,8 @@
1
+ version: 2
2
+ updates:
3
+ - package-ecosystem: bundler
4
+ directory: "/"
5
+ schedule:
6
+ interval: daily
7
+ time: "20:00"
8
+ open-pull-requests-limit: 10
@@ -12,8 +12,9 @@ jobs:
12
12
  strategy:
13
13
  matrix:
14
14
  container_tag:
15
- - 2.6.5-bionic
16
- - 2.7.0-bionic
15
+ - "2.6"
16
+ - "2.7"
17
+ - "3.0"
17
18
  task:
18
19
  - test
19
20
  - test:output
data/.gitignore CHANGED
@@ -1,6 +1,5 @@
1
1
  /.bundle/
2
2
  /.yardoc
3
- /Gemfile.lock
4
3
  /_yardoc/
5
4
  /coverage/
6
5
  /doc/
data/CHANGELOG.md CHANGED
@@ -2,6 +2,36 @@
2
2
 
3
3
  ## master
4
4
 
5
+ ## 0.45.0 (2021-08-22)
6
+
7
+ * Fix error reporting on `RBS::MixinClassError` ([\#411](https://github.com/soutaro/steep/pull/411))
8
+ * Compact error reporting for method body type mismatch ([\#414](https://github.com/soutaro/steep/pull/414))
9
+ * Fix NoMethodError with csend/numblock ([\#412](https://github.com/soutaro/steep/pull/412))
10
+ * LSP completion for RBS files ([\#404](https://github.com/soutaro/steep/pull/404))
11
+ * Allow break without value from bot methods ([\#398](https://github.com/soutaro/steep/pull/398))
12
+ * Type check on lvar assignments ([\#390](https://github.com/soutaro/steep/pull/390))
13
+ * Assign different error code to break without value ([\#387](https://github.com/soutaro/steep/pull/387))
14
+ * Support Ruby3 Keyword Arguments ([\#386](https://github.com/soutaro/steep/pull/386))
15
+ * LSP hover for RBS files ([\#385](https://github.com/soutaro/steep/pull/385), [\#397](https://github.com/soutaro/steep/pull/397))
16
+ * Fix FileLoader to skip files not matching to the given pattern ([\#382](https://github.com/soutaro/steep/pull/382))
17
+ * Ruby3 support for numbered block parameters and end-less def ([\#381](https://github.com/soutaro/steep/pull/381))
18
+
19
+ ## 0.44.1 (2021-04-23)
20
+
21
+ * Disable goto declaration and goto type declaration (because they are not implemented) ([#377](https://github.com/soutaro/steep/pull/377))
22
+ * Fix goto from block calls ([#378](https://github.com/soutaro/steep/pull/378))
23
+
24
+ ## 0.44.0 (2021-04-22)
25
+
26
+ * Implement LSP go to definition/implementation ([#371](https://github.com/soutaro/steep/pull/371), [#375](https://github.com/soutaro/steep/pull/375))
27
+ * Fix typing on passing optional block ([#373](https://github.com/soutaro/steep/pull/373))
28
+ * Do not crash when completion request `context` is missing ([#370](https://github.com/soutaro/steep/pull/370))
29
+ * Update RBS ([#376](https://github.com/soutaro/steep/pull/376))
30
+
31
+ ## 0.43.1 (2021-04-01)
32
+
33
+ * Fix LSP `textDocument/didSave` notification handling ([#368](https://github.com/soutaro/steep/issues/368))
34
+
5
35
  ## 0.43.0 (2021-03-30)
6
36
 
7
37
  * LSP responsiveness improvements ([\#352](https://github.com/soutaro/steep/issues/352))
data/Gemfile CHANGED
@@ -9,6 +9,5 @@ gem "without_steep_types", path: "test/gems/without_steep_types"
9
9
  gem "rake"
10
10
  gem "minitest", "~> 5.0"
11
11
  gem "racc", "~> 1.4"
12
- gem "minitest-reporters"
13
12
  gem "minitest-hooks"
14
13
  gem "stackprof"
data/Gemfile.lock ADDED
@@ -0,0 +1,77 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ steep (0.45.0)
5
+ activesupport (>= 5.1)
6
+ language_server-protocol (>= 3.15, < 4.0)
7
+ listen (~> 3.0)
8
+ parallel (>= 1.0.0)
9
+ parser (>= 3.0)
10
+ rainbow (>= 2.2.2, < 4.0)
11
+ rbs (>= 1.2.0)
12
+ terminal-table (>= 2, < 4)
13
+
14
+ PATH
15
+ remote: test/gems/with_steep_types
16
+ specs:
17
+ with_steep_types (1.0.0)
18
+
19
+ PATH
20
+ remote: test/gems/without_steep_types
21
+ specs:
22
+ without_steep_types (1.0.0)
23
+
24
+ GEM
25
+ remote: https://rubygems.org/
26
+ specs:
27
+ activesupport (6.1.4.1)
28
+ concurrent-ruby (~> 1.0, >= 1.0.2)
29
+ i18n (>= 1.6, < 2)
30
+ minitest (>= 5.1)
31
+ tzinfo (~> 2.0)
32
+ zeitwerk (~> 2.3)
33
+ ast (2.4.2)
34
+ concurrent-ruby (1.1.9)
35
+ ffi (1.15.3)
36
+ i18n (1.8.10)
37
+ concurrent-ruby (~> 1.0)
38
+ language_server-protocol (3.16.0.1)
39
+ listen (3.7.0)
40
+ rb-fsevent (~> 0.10, >= 0.10.3)
41
+ rb-inotify (~> 0.9, >= 0.9.10)
42
+ minitest (5.14.4)
43
+ minitest-hooks (1.5.0)
44
+ minitest (> 5.3)
45
+ parallel (1.20.1)
46
+ parser (3.0.2.0)
47
+ ast (~> 2.4.1)
48
+ racc (1.5.2)
49
+ rainbow (3.0.0)
50
+ rake (13.0.6)
51
+ rb-fsevent (0.11.0)
52
+ rb-inotify (0.10.1)
53
+ ffi (~> 1.0)
54
+ rbs (1.5.1)
55
+ stackprof (0.2.17)
56
+ terminal-table (3.0.1)
57
+ unicode-display_width (>= 1.1.1, < 3)
58
+ tzinfo (2.0.4)
59
+ concurrent-ruby (~> 1.0)
60
+ unicode-display_width (2.0.0)
61
+ zeitwerk (2.4.2)
62
+
63
+ PLATFORMS
64
+ ruby
65
+
66
+ DEPENDENCIES
67
+ minitest (~> 5.0)
68
+ minitest-hooks
69
+ racc (~> 1.4)
70
+ rake
71
+ stackprof
72
+ steep!
73
+ with_steep_types!
74
+ without_steep_types!
75
+
76
+ BUNDLED WITH
77
+ 2.2.22
data/bin/output_test.rb CHANGED
@@ -16,6 +16,8 @@ end
16
16
 
17
17
  failed_tests = []
18
18
 
19
+ ALLOW_FAILURE = ["diagnostics-ruby-unsat"]
20
+
19
21
  test_dirs.each do |dir|
20
22
  puts "Running test #{dir}..."
21
23
 
@@ -30,8 +32,12 @@ test_dirs.each do |dir|
30
32
  output, status = Open3.capture2(*command, chdir: dir.to_s)
31
33
 
32
34
  unless status.success?
33
- failed_tests << dir.basename
34
- puts " Failed! 🤕"
35
+ unless ALLOW_FAILURE.include?(dir.basename.to_s)
36
+ failed_tests << dir.basename
37
+ puts " Failed! 🤕"
38
+ else
39
+ puts " Failed! 🤕 (ALLOW_FAILURE)"
40
+ end
35
41
  else
36
42
  puts " Succeed! 👍"
37
43
  end
data/lib/steep.rb CHANGED
@@ -1,7 +1,7 @@
1
1
  require "steep/version"
2
2
 
3
3
  require "pathname"
4
- require "parser/ruby27"
4
+ require "parser/ruby30"
5
5
  require "active_support/core_ext/object/try"
6
6
  require "active_support/core_ext/string/inflections"
7
7
  require "logger"
@@ -21,6 +21,7 @@ require "terminal-table"
21
21
 
22
22
  require "rbs"
23
23
 
24
+ require "steep/equatable"
24
25
  require "steep/method_name"
25
26
  require "steep/ast/types/helper"
26
27
  require "steep/ast/types/any"
@@ -77,6 +78,7 @@ require "steep/type_inference/context"
77
78
  require "steep/type_inference/context_array"
78
79
  require "steep/type_inference/send_args"
79
80
  require "steep/type_inference/block_params"
81
+ require "steep/type_inference/method_params"
80
82
  require "steep/type_inference/constant_env"
81
83
  require "steep/type_inference/type_env"
82
84
  require "steep/type_inference/local_variable_type_env"
@@ -104,6 +106,7 @@ require "steep/services/hover_content"
104
106
  require "steep/services/completion_provider"
105
107
  require "steep/services/stats_calculator"
106
108
  require "steep/services/file_loader"
109
+ require "steep/services/goto_service"
107
110
 
108
111
  require "steep/project"
109
112
  require "steep/project/pattern"
@@ -10,8 +10,14 @@ module Steep
10
10
  @arity = arity
11
11
  end
12
12
 
13
- def instance_type(*args)
13
+ def instance_type(*args, fill_untyped: false)
14
+ if fill_untyped
15
+ (arity - args.size).times do
16
+ args << Builtin.any_type
17
+ end
18
+ end
14
19
  arity == args.size or raise "Mulformed instance type: name=#{module_name}, args=#{args}"
20
+
15
21
  Types::Name::Instance.new(name: module_name, args: args)
16
22
  end
17
23
 
@@ -194,7 +194,7 @@ module Steep
194
194
  end
195
195
 
196
196
  def params(type)
197
- Interface::Function::Params.new(
197
+ Interface::Function::Params.build(
198
198
  required: type.required_positionals.map {|param| type(param.type) },
199
199
  optional: type.optional_positionals.map {|param| type(param.type) },
200
200
  rest: type.rest_positionals&.yield_self {|param| type(param.type) },
@@ -621,12 +621,7 @@ module Steep
621
621
  Interface::MethodType.new(
622
622
  type_params: [],
623
623
  type: Interface::Function.new(
624
- params: Interface::Function::Params.new(required: [AST::Types::Literal.new(value: index)],
625
- optional: [],
626
- rest: nil,
627
- required_keywords: {},
628
- optional_keywords: {},
629
- rest_keywords: nil),
624
+ params: Interface::Function::Params.build(required: [AST::Types::Literal.new(value: index)]),
630
625
  return_type: elem_type,
631
626
  location: nil
632
627
  ),
@@ -643,12 +638,7 @@ module Steep
643
638
  Interface::MethodType.new(
644
639
  type_params: [],
645
640
  type: Interface::Function.new(
646
- params: Interface::Function::Params.new(required: [AST::Types::Literal.new(value: index), elem_type],
647
- optional: [],
648
- rest: nil,
649
- required_keywords: {},
650
- optional_keywords: {},
651
- rest_keywords: nil),
641
+ params: Interface::Function::Params.build(required: [AST::Types::Literal.new(value: index), elem_type]),
652
642
  return_type: elem_type,
653
643
  location: nil
654
644
  ),
@@ -712,12 +702,14 @@ module Steep
712
702
  Interface::MethodType.new(
713
703
  type_params: [],
714
704
  type: Interface::Function.new(
715
- params: Interface::Function::Params.new(required: [key_type],
716
- optional: [],
717
- rest: nil,
718
- required_keywords: {},
719
- optional_keywords: {},
720
- rest_keywords: nil),
705
+ params: Interface::Function::Params.build(
706
+ required: [key_type],
707
+ optional: [],
708
+ rest: nil,
709
+ required_keywords: {},
710
+ optional_keywords: {},
711
+ rest_keywords: nil
712
+ ),
721
713
  return_type: value_type,
722
714
  location: nil
723
715
  ),
@@ -735,12 +727,14 @@ module Steep
735
727
  Interface::MethodType.new(
736
728
  type_params: [],
737
729
  type: Interface::Function.new(
738
- params: Interface::Function::Params.new(required: [key_type, value_type],
739
- optional: [],
740
- rest: nil,
741
- required_keywords: {},
742
- optional_keywords: {},
743
- rest_keywords: nil),
730
+ params: Interface::Function::Params.build(
731
+ required: [key_type, value_type],
732
+ optional: [],
733
+ rest: nil,
734
+ required_keywords: {},
735
+ optional_keywords: {},
736
+ rest_keywords: nil
737
+ ),
744
738
  return_type: value_type,
745
739
  location: nil),
746
740
  block: nil,
@@ -71,46 +71,104 @@ module Steep
71
71
  end
72
72
  end
73
73
 
74
- class IncompatibleArguments < Base
74
+ class UnexpectedPositionalArgument < Base
75
75
  attr_reader :node
76
+ attr_reader :method_type
76
77
  attr_reader :method_name
77
- attr_reader :receiver_type
78
- attr_reader :method_types
79
78
 
80
- def initialize(node:, method_name:, receiver_type:, method_types:)
81
- location = case node.type
82
- when :send
83
- node.loc.selector
84
- when :block
85
- node.children[0].yield_self do |node|
86
- node.loc.selector
87
- end
88
- when :super
89
- node.loc.expression
90
- else
91
- Steep.logger.error { "Unexpected node given: #{node.type} (IncompatibleArguments#initialize)"}
92
- node.loc.expression
93
- end
94
- super(node: node, location: location)
95
- @receiver_type = receiver_type
96
- @method_types = method_types
79
+ def initialize(node:, method_name:, method_type:)
80
+ super(node: node)
97
81
  @method_name = method_name
82
+ @method_type = method_type
98
83
  end
99
84
 
100
85
  def header_line
101
- "Cannot find method `#{method_name}` of type `#{receiver_type}` with compatible arity"
86
+ "Unexpected positional argument"
102
87
  end
88
+ end
103
89
 
104
- def detail_lines
105
- StringIO.new.tap do |io|
106
- io.puts "Method types:"
107
- first_type, *rest_types = method_types
108
- defn = " def #{method_name}"
109
- io.puts "#{defn}: #{first_type}"
110
- rest_types.each do |method_type|
111
- io.puts "#{" " * defn.size}| #{method_type}"
112
- end
113
- end.string.chomp
90
+ class InsufficientPositionalArguments < Base
91
+ attr_reader :node
92
+ attr_reader :method_name
93
+ attr_reader :method_type
94
+
95
+ def initialize(node:, method_name:, method_type:)
96
+ send = case node.type
97
+ when :send, :csend
98
+ node
99
+ when :block, :numblock
100
+ node.children[0]
101
+ end
102
+
103
+ loc = if send
104
+ send.loc.selector.with(end_pos: send.loc.expression.end_pos)
105
+ else
106
+ node.loc.expression
107
+ end
108
+
109
+ super(node: node, location: loc)
110
+ @method_name = method_name
111
+ @method_type = method_type
112
+ end
113
+
114
+ def header_line
115
+ "More positional arguments are required"
116
+ end
117
+ end
118
+
119
+ class UnexpectedKeywordArgument < Base
120
+ attr_reader :node
121
+ attr_reader :method_name
122
+ attr_reader :method_type
123
+
124
+ def initialize(node:, method_name:, method_type:)
125
+ loc = case node.type
126
+ when :pair
127
+ node.children[0].location.expression
128
+ when :kwsplat
129
+ node.location.expression
130
+ else
131
+ raise
132
+ end
133
+ super(node: node, location: loc)
134
+ @method_name = method_name
135
+ @method_type = method_type
136
+ end
137
+
138
+ def header_line
139
+ "Unexpected keyword argument"
140
+ end
141
+ end
142
+
143
+ class InsufficientKeywordArguments < Base
144
+ attr_reader :node
145
+ attr_reader :method_name
146
+ attr_reader :method_type
147
+ attr_reader :missing_keywords
148
+
149
+ def initialize(node:, method_name:, method_type:, missing_keywords:)
150
+ send = case node.type
151
+ when :send, :csend
152
+ node
153
+ when :block, :numblock
154
+ node.children[0]
155
+ end
156
+
157
+ loc = if send
158
+ send.loc.selector.with(end_pos: send.loc.expression.end_pos)
159
+ else
160
+ node.loc.expression
161
+ end
162
+
163
+ super(node: node, location: loc)
164
+
165
+ @method_name = method_name
166
+ @method_type = method_type
167
+ @missing_keywords = missing_keywords
168
+ end
169
+
170
+ def header_line
171
+ "More keyword arguments are required: #{missing_keywords.join(", ")}"
114
172
  end
115
173
  end
116
174
 
@@ -292,6 +350,23 @@ module Steep
292
350
  end
293
351
  end
294
352
 
353
+ class ImplicitBreakValueMismatch < Base
354
+ attr_reader :jump_type
355
+ attr_reader :result
356
+
357
+ include ResultPrinter
358
+
359
+ def initialize(node:, jump_type:, result:)
360
+ super(node: node)
361
+ @jump_type = jump_type
362
+ @result = result
363
+ end
364
+
365
+ def header_line
366
+ "Breaking without a value may result an error because a value of type `#{jump_type}` is expected"
367
+ end
368
+ end
369
+
295
370
  class UnexpectedJump < Base
296
371
  def header_line
297
372
  "Cannot jump from here"
@@ -323,6 +398,36 @@ module Steep
323
398
  end
324
399
  end
325
400
 
401
+ class MethodParameterMismatch < Base
402
+ attr_reader :method_param
403
+ attr_reader :method_type
404
+
405
+ def initialize(method_param:, method_type:)
406
+ super(node: method_param.node)
407
+ @method_param = method_param
408
+ @method_type = method_type
409
+ end
410
+
411
+ def header_line
412
+ "The method parameter is incompatible with the declaration `#{method_type}`"
413
+ end
414
+ end
415
+
416
+ class DifferentMethodParameterKind < Base
417
+ attr_reader :method_param
418
+ attr_reader :method_type
419
+
420
+ def initialize(method_param:, method_type:)
421
+ super(node: method_param.node)
422
+ @method_param = method_param
423
+ @method_type = method_type
424
+ end
425
+
426
+ def header_line
427
+ "The method parameter has different kind from the declaration `#{method_type}`"
428
+ end
429
+ end
430
+
326
431
  class IncompatibleMethodTypeAnnotation < Base
327
432
  attr_reader :interface_method
328
433
  attr_reader :annotation_method
@@ -366,7 +471,7 @@ module Steep
366
471
  include ResultPrinter
367
472
 
368
473
  def initialize(node:, expected:, actual:, result:)
369
- super(node: node)
474
+ super(node: node, location: node.loc.name)
370
475
  @expected = expected
371
476
  @actual = actual
372
477
  @result = result
@@ -552,34 +657,6 @@ module Steep
552
657
  end
553
658
  end
554
659
 
555
- class UnexpectedKeyword < Base
556
- attr_reader :unexpected_keywords
557
-
558
- def initialize(node:, unexpected_keywords:)
559
- super(node: node)
560
- @unexpected_keywords = unexpected_keywords
561
- end
562
-
563
- def header_line
564
- keywords = unexpected_keywords.sort.map {|x| "`#{x}`" }
565
- "Cannot specify unexpected keyword arguments: #{keywords.join(", ")}"
566
- end
567
- end
568
-
569
- class MissingKeyword < Base
570
- attr_reader :missing_keywords
571
-
572
- def initialize(node:, missing_keywords:)
573
- super(node: node)
574
- @missing_keywords = missing_keywords
575
- end
576
-
577
- def header_line
578
- keywords = missing_keywords.sort.map {|x| "`#{x}`" }
579
- "Cannot omit required keywords: #{keywords.join(", ")}"
580
- end
581
- end
582
-
583
660
  class UnsupportedSyntax < Base
584
661
  attr_reader :message
585
662