steep 0.37.0 → 0.42.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (221) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/ruby.yml +1 -1
  3. data/CHANGELOG.md +34 -0
  4. data/Rakefile +5 -2
  5. data/bin/output_rebaseline.rb +34 -0
  6. data/bin/output_test.rb +53 -0
  7. data/lib/steep.rb +95 -14
  8. data/lib/steep/ast/types/bot.rb +1 -1
  9. data/lib/steep/ast/types/class.rb +4 -0
  10. data/lib/steep/ast/types/factory.rb +10 -0
  11. data/lib/steep/ast/types/logic.rb +16 -3
  12. data/lib/steep/ast/types/top.rb +1 -1
  13. data/lib/steep/cli.rb +31 -7
  14. data/lib/steep/diagnostic/helper.rb +17 -0
  15. data/lib/steep/diagnostic/lsp_formatter.rb +16 -0
  16. data/lib/steep/diagnostic/ruby.rb +619 -0
  17. data/lib/steep/diagnostic/signature.rb +357 -0
  18. data/lib/steep/drivers/annotations.rb +19 -28
  19. data/lib/steep/drivers/check.rb +182 -60
  20. data/lib/steep/drivers/diagnostic_printer.rb +99 -0
  21. data/lib/steep/drivers/langserver.rb +3 -8
  22. data/lib/steep/drivers/print_project.rb +10 -9
  23. data/lib/steep/drivers/stats.rb +124 -32
  24. data/lib/steep/drivers/trace_printer.rb +5 -1
  25. data/lib/steep/drivers/utils/jobs_count.rb +9 -0
  26. data/lib/steep/drivers/validate.rb +31 -13
  27. data/lib/steep/drivers/watch.rb +69 -48
  28. data/lib/steep/drivers/worker.rb +16 -8
  29. data/lib/steep/expectations.rb +159 -0
  30. data/lib/steep/index/rbs_index.rb +334 -0
  31. data/lib/steep/index/signature_symbol_provider.rb +162 -0
  32. data/lib/steep/index/source_index.rb +100 -0
  33. data/lib/steep/project.rb +0 -30
  34. data/lib/steep/project/dsl.rb +5 -3
  35. data/lib/steep/project/options.rb +4 -4
  36. data/lib/steep/project/pattern.rb +56 -0
  37. data/lib/steep/project/target.rb +9 -214
  38. data/lib/steep/range_extension.rb +29 -0
  39. data/lib/steep/server/base_worker.rb +43 -7
  40. data/lib/steep/server/change_buffer.rb +63 -0
  41. data/lib/steep/server/interaction_worker.rb +73 -56
  42. data/lib/steep/server/master.rb +245 -109
  43. data/lib/steep/server/type_check_worker.rb +122 -0
  44. data/lib/steep/server/worker_process.rb +17 -15
  45. data/lib/steep/{project → services}/completion_provider.rb +3 -3
  46. data/lib/steep/services/content_change.rb +61 -0
  47. data/lib/steep/services/file_loader.rb +48 -0
  48. data/lib/steep/{project → services}/hover_content.rb +14 -16
  49. data/lib/steep/services/path_assignment.rb +29 -0
  50. data/lib/steep/services/signature_service.rb +369 -0
  51. data/lib/steep/services/stats_calculator.rb +69 -0
  52. data/lib/steep/services/type_check_service.rb +342 -0
  53. data/lib/steep/signature/validator.rb +174 -32
  54. data/lib/steep/subtyping/check.rb +248 -47
  55. data/lib/steep/subtyping/constraints.rb +2 -2
  56. data/lib/steep/type_construction.rb +565 -295
  57. data/lib/steep/type_inference/constant_env.rb +5 -1
  58. data/lib/steep/type_inference/local_variable_type_env.rb +26 -12
  59. data/lib/steep/type_inference/logic_type_interpreter.rb +99 -26
  60. data/lib/steep/type_inference/type_env.rb +43 -17
  61. data/lib/steep/typing.rb +8 -2
  62. data/lib/steep/version.rb +1 -1
  63. data/smoke/alias/a.rb +0 -3
  64. data/smoke/alias/b.rb +0 -1
  65. data/smoke/alias/c.rb +0 -2
  66. data/smoke/alias/test_expectations.yml +96 -0
  67. data/smoke/and/a.rb +0 -3
  68. data/smoke/and/test_expectations.yml +31 -0
  69. data/smoke/array/a.rb +0 -3
  70. data/smoke/array/b.rb +0 -2
  71. data/smoke/array/c.rb +0 -1
  72. data/smoke/array/test_expectations.yml +103 -0
  73. data/smoke/block/a.rb +0 -2
  74. data/smoke/block/b.rb +0 -2
  75. data/smoke/block/d.rb +0 -4
  76. data/smoke/block/test_expectations.yml +125 -0
  77. data/smoke/case/a.rb +0 -3
  78. data/smoke/case/test_expectations.yml +47 -0
  79. data/smoke/class/a.rb +0 -3
  80. data/smoke/class/c.rb +0 -1
  81. data/smoke/class/f.rb +0 -1
  82. data/smoke/class/g.rb +0 -2
  83. data/smoke/class/i.rb +0 -2
  84. data/smoke/class/test_expectations.yml +120 -0
  85. data/smoke/const/a.rb +0 -3
  86. data/smoke/const/b.rb +7 -0
  87. data/smoke/const/b.rbs +5 -0
  88. data/smoke/const/test_expectations.yml +139 -0
  89. data/smoke/diagnostics-rbs-duplicated/Steepfile +5 -0
  90. data/smoke/diagnostics-rbs-duplicated/a.rbs +5 -0
  91. data/smoke/diagnostics-rbs-duplicated/test_expectations.yml +13 -0
  92. data/smoke/diagnostics-rbs/Steepfile +8 -0
  93. data/smoke/diagnostics-rbs/duplicated-method-definition.rbs +20 -0
  94. data/smoke/diagnostics-rbs/generic-parameter-mismatch.rbs +7 -0
  95. data/smoke/diagnostics-rbs/invalid-method-overload.rbs +3 -0
  96. data/smoke/diagnostics-rbs/invalid-type-application.rbs +7 -0
  97. data/smoke/diagnostics-rbs/invalid_variance_annotation.rbs +3 -0
  98. data/smoke/diagnostics-rbs/recursive-alias.rbs +5 -0
  99. data/smoke/diagnostics-rbs/recursive-class.rbs +8 -0
  100. data/smoke/diagnostics-rbs/superclass-mismatch.rbs +7 -0
  101. data/smoke/diagnostics-rbs/test_expectations.yml +231 -0
  102. data/smoke/diagnostics-rbs/unknown-method-alias.rbs +3 -0
  103. data/smoke/diagnostics-rbs/unknown-type-name-2.rbs +5 -0
  104. data/smoke/diagnostics-rbs/unknown-type-name.rbs +13 -0
  105. data/smoke/diagnostics/Steepfile +5 -0
  106. data/smoke/diagnostics/a.rbs +26 -0
  107. data/smoke/diagnostics/argument_type_mismatch.rb +1 -0
  108. data/smoke/diagnostics/block_body_type_mismatch.rb +1 -0
  109. data/smoke/diagnostics/block_type_mismatch.rb +3 -0
  110. data/smoke/diagnostics/break_type_mismatch.rb +1 -0
  111. data/smoke/diagnostics/else_on_exhaustive_case.rb +12 -0
  112. data/smoke/diagnostics/incompatible_annotation.rb +6 -0
  113. data/smoke/diagnostics/incompatible_argument.rb +1 -0
  114. data/smoke/diagnostics/incompatible_assignment.rb +8 -0
  115. data/smoke/diagnostics/method_arity_mismatch.rb +11 -0
  116. data/smoke/diagnostics/method_body_type_mismatch.rb +6 -0
  117. data/smoke/diagnostics/method_definition_missing.rb +2 -0
  118. data/smoke/diagnostics/method_return_type_annotation_mismatch.rb +7 -0
  119. data/smoke/diagnostics/missing_keyword.rb +1 -0
  120. data/smoke/diagnostics/no_method.rb +1 -0
  121. data/smoke/diagnostics/required_block_missing.rb +1 -0
  122. data/smoke/diagnostics/return_type_mismatch.rb +6 -0
  123. data/smoke/diagnostics/test_expectations.yml +477 -0
  124. data/smoke/diagnostics/unexpected_block_given.rb +1 -0
  125. data/smoke/diagnostics/unexpected_dynamic_method.rb +3 -0
  126. data/smoke/diagnostics/unexpected_jump.rb +4 -0
  127. data/smoke/diagnostics/unexpected_jump_value.rb +3 -0
  128. data/smoke/diagnostics/unexpected_keyword.rb +1 -0
  129. data/smoke/diagnostics/unexpected_splat.rb +1 -0
  130. data/smoke/diagnostics/unexpected_yield.rb +6 -0
  131. data/smoke/diagnostics/unknown_constant_assigned.rb +7 -0
  132. data/smoke/diagnostics/unresolved_overloading.rb +1 -0
  133. data/smoke/diagnostics/unsatisfiable_constraint.rb +7 -0
  134. data/smoke/diagnostics/unsupported_syntax.rb +2 -0
  135. data/smoke/dstr/a.rb +0 -1
  136. data/smoke/dstr/test_expectations.yml +13 -0
  137. data/smoke/ensure/a.rb +0 -4
  138. data/smoke/ensure/test_expectations.yml +62 -0
  139. data/smoke/enumerator/a.rb +0 -6
  140. data/smoke/enumerator/b.rb +0 -3
  141. data/smoke/enumerator/test_expectations.yml +135 -0
  142. data/smoke/extension/a.rb +0 -1
  143. data/smoke/extension/b.rb +0 -2
  144. data/smoke/extension/c.rb +0 -1
  145. data/smoke/extension/f.rb +2 -0
  146. data/smoke/extension/f.rbs +3 -0
  147. data/smoke/extension/test_expectations.yml +73 -0
  148. data/smoke/hash/b.rb +0 -1
  149. data/smoke/hash/c.rb +0 -3
  150. data/smoke/hash/d.rb +0 -1
  151. data/smoke/hash/e.rb +0 -1
  152. data/smoke/hash/test_expectations.yml +81 -0
  153. data/smoke/hello/hello.rb +0 -2
  154. data/smoke/hello/test_expectations.yml +25 -0
  155. data/smoke/if/a.rb +0 -2
  156. data/smoke/if/test_expectations.yml +34 -0
  157. data/smoke/implements/a.rb +0 -2
  158. data/smoke/implements/test_expectations.yml +23 -0
  159. data/smoke/initialize/test_expectations.yml +1 -0
  160. data/smoke/integer/a.rb +0 -7
  161. data/smoke/integer/test_expectations.yml +101 -0
  162. data/smoke/interface/a.rb +0 -2
  163. data/smoke/interface/test_expectations.yml +23 -0
  164. data/smoke/kwbegin/a.rb +0 -1
  165. data/smoke/kwbegin/test_expectations.yml +17 -0
  166. data/smoke/lambda/a.rb +1 -4
  167. data/smoke/lambda/test_expectations.yml +39 -0
  168. data/smoke/literal/a.rb +0 -5
  169. data/smoke/literal/b.rb +0 -2
  170. data/smoke/literal/test_expectations.yml +106 -0
  171. data/smoke/map/test_expectations.yml +1 -0
  172. data/smoke/method/a.rb +0 -5
  173. data/smoke/method/b.rb +0 -1
  174. data/smoke/method/test_expectations.yml +90 -0
  175. data/smoke/module/a.rb +0 -2
  176. data/smoke/module/b.rb +0 -2
  177. data/smoke/module/c.rb +0 -1
  178. data/smoke/module/d.rb +0 -1
  179. data/smoke/module/f.rb +0 -2
  180. data/smoke/module/test_expectations.yml +75 -0
  181. data/smoke/regexp/a.rb +0 -38
  182. data/smoke/regexp/b.rb +0 -26
  183. data/smoke/regexp/test_expectations.yml +615 -0
  184. data/smoke/regression/set_divide.rb +0 -4
  185. data/smoke/regression/test_expectations.yml +43 -0
  186. data/smoke/rescue/a.rb +0 -5
  187. data/smoke/rescue/test_expectations.yml +79 -0
  188. data/smoke/self/a.rb +0 -2
  189. data/smoke/self/test_expectations.yml +23 -0
  190. data/smoke/skip/skip.rb +0 -2
  191. data/smoke/skip/test_expectations.yml +23 -0
  192. data/smoke/stdout/test_expectations.yml +1 -0
  193. data/smoke/super/a.rb +0 -4
  194. data/smoke/super/test_expectations.yml +79 -0
  195. data/smoke/toplevel/a.rb +0 -1
  196. data/smoke/toplevel/test_expectations.yml +15 -0
  197. data/smoke/tsort/Steepfile +2 -0
  198. data/smoke/tsort/a.rb +0 -3
  199. data/smoke/tsort/test_expectations.yml +63 -0
  200. data/smoke/type_case/a.rb +0 -4
  201. data/smoke/type_case/test_expectations.yml +48 -0
  202. data/smoke/unexpected/Steepfile +5 -0
  203. data/smoke/unexpected/test_expectations.yml +25 -0
  204. data/smoke/unexpected/unexpected.rb +1 -0
  205. data/smoke/unexpected/unexpected.rbs +3 -0
  206. data/smoke/yield/a.rb +0 -3
  207. data/smoke/yield/b.rb +6 -0
  208. data/smoke/yield/test_expectations.yml +68 -0
  209. data/steep.gemspec +4 -3
  210. metadata +144 -29
  211. data/bin/smoke_runner.rb +0 -139
  212. data/lib/steep/drivers/signature_error_printer.rb +0 -25
  213. data/lib/steep/errors.rb +0 -565
  214. data/lib/steep/project/file_loader.rb +0 -68
  215. data/lib/steep/project/signature_file.rb +0 -33
  216. data/lib/steep/project/source_file.rb +0 -129
  217. data/lib/steep/server/code_worker.rb +0 -137
  218. data/lib/steep/server/signature_worker.rb +0 -152
  219. data/lib/steep/server/utils.rb +0 -69
  220. data/lib/steep/signature/errors.rb +0 -82
  221. data/lib/steep/type_assignability.rb +0 -367
data/lib/steep/cli.rb CHANGED
@@ -8,6 +8,8 @@ module Steep
8
8
  attr_reader :stderr
9
9
  attr_reader :command
10
10
 
11
+ include Parallel::ProcessorCount
12
+
11
13
  def initialize(stdout:, stdin:, stderr:, argv:)
12
14
  @stdout = stdout
13
15
  @stdin = stdin
@@ -51,19 +53,27 @@ module Steep
51
53
  end
52
54
 
53
55
  def handle_logging_options(opts)
54
- opts.on("--log-level=[debug,info,warn,error,fatal]") do |level|
56
+ opts.on("--log-level=LEVEL", "Specify log level: debug, info, warn, error, fatal") do |level|
55
57
  Steep.logger.level = level
56
58
  end
57
59
 
58
- opts.on("--log-output=[PATH]") do |file|
60
+ opts.on("--log-output=PATH", "Print logs to given path") do |file|
59
61
  Steep.log_output = file
60
62
  end
61
63
 
62
- opts.on("--verbose") do
64
+ opts.on("--verbose", "Set log level to debug") do
63
65
  Steep.logger.level = Logger::DEBUG
64
66
  end
65
67
  end
66
68
 
69
+ def handle_jobs_option(command, opts, modifier = 0)
70
+ default = physical_processor_count + modifier
71
+ command.jobs_count = default
72
+ opts.on("-j N", "--jobs=N", "Specify the number of type check workers (defaults: #{default})") do |count|
73
+ command.jobs_count = Integer(count)
74
+ end
75
+ end
76
+
67
77
  def process_init
68
78
  Drivers::Init.new(stdout: stdout, stderr: stderr).tap do |command|
69
79
  OptionParser.new do |opts|
@@ -83,7 +93,13 @@ module Steep
83
93
  opts.banner = "Usage: steep check [options] [sources]"
84
94
 
85
95
  opts.on("--steepfile=PATH") {|path| check.steepfile = Pathname(path) }
86
- opts.on("--dump-all-types") { check.dump_all_types = true }
96
+ opts.on("--with-expectations[=PATH]", "Type check with expectations saved in PATH (or steep_expectations.yml)") do |path|
97
+ check.with_expectations_path = Pathname(path || "steep_expectations.yml")
98
+ end
99
+ opts.on("--save-expectations[=PATH]", "Save expectations with current type check result to PATH (or steep_expectations.yml)") do |path|
100
+ check.save_expectations_path = Pathname(path || "steep_expectations.yml")
101
+ end
102
+ handle_jobs_option check, opts
87
103
  handle_logging_options opts
88
104
  end.parse!(argv)
89
105
 
@@ -97,6 +113,7 @@ module Steep
97
113
  opts.banner = "Usage: steep stats [options] [sources]"
98
114
 
99
115
  opts.on("--steepfile=PATH") {|path| check.steepfile = Pathname(path) }
116
+ handle_jobs_option check, opts
100
117
  handle_logging_options opts
101
118
  end.parse!(argv)
102
119
 
@@ -137,10 +154,12 @@ module Steep
137
154
  Drivers::Watch.new(stdout: stdout, stderr: stderr).tap do |command|
138
155
  OptionParser.new do |opts|
139
156
  opts.banner = "Usage: steep watch [options] [dirs]"
157
+ handle_jobs_option command, opts
140
158
  handle_logging_options opts
141
159
  end.parse!(argv)
142
160
 
143
- command.dirs.push *argv
161
+ dirs = argv.map {|dir| Pathname(dir) }
162
+ command.dirs.push(*dirs)
144
163
  end.run
145
164
  end
146
165
 
@@ -148,6 +167,7 @@ module Steep
148
167
  Drivers::Langserver.new(stdout: stdout, stderr: stderr, stdin: stdin).tap do |command|
149
168
  OptionParser.new do |opts|
150
169
  opts.on("--steepfile=PATH") {|path| command.steepfile = Pathname(path) }
170
+ handle_jobs_option command, opts, -1
151
171
  handle_logging_options opts
152
172
  end.parse!(argv)
153
173
  end.run
@@ -180,11 +200,15 @@ module Steep
180
200
  handle_logging_options opts
181
201
 
182
202
  opts.on("--interaction") { command.worker_type = :interaction }
183
- opts.on("--code") { command.worker_type = :code }
184
- opts.on("--signature") { command.worker_type = :signature }
203
+ opts.on("--typecheck") { command.worker_type = :typecheck }
185
204
  opts.on("--steepfile=PATH") {|path| command.steepfile = Pathname(path) }
186
205
  opts.on("--name=NAME") {|name| command.worker_name = name }
206
+ opts.on("--delay-shutdown") { command.delay_shutdown = true }
207
+ opts.on("--max-index=COUNT") {|count| command.max_index = Integer(count) }
208
+ opts.on("--index=INDEX") {|index| command.index = Integer(index) }
187
209
  end.parse!(argv)
210
+
211
+ command.commandline_args.push(*argv)
188
212
  end.run
189
213
  end
190
214
  end
@@ -0,0 +1,17 @@
1
+ module Steep
2
+ module Diagnostic
3
+ module Helper
4
+ def error_name
5
+ self.class.name.split(/::/).last
6
+ end
7
+
8
+ def full_message
9
+ if detail = detail_lines
10
+ "#{header_line}\n#{detail}"
11
+ else
12
+ "#{header_line}"
13
+ end
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,16 @@
1
+ module Steep
2
+ module Diagnostic
3
+ class LSPFormatter
4
+ LSP = LanguageServer::Protocol
5
+
6
+ def format(diagnostic)
7
+ LSP::Interface::Diagnostic.new(
8
+ message: diagnostic.full_message,
9
+ code: diagnostic.diagnostic_code,
10
+ severity: LSP::Constant::DiagnosticSeverity::ERROR,
11
+ range: diagnostic.location.as_lsp_range
12
+ ).to_hash
13
+ end
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,619 @@
1
+ module Steep
2
+ module Diagnostic
3
+ module Ruby
4
+ class Base
5
+ include Helper
6
+
7
+ attr_reader :node
8
+ attr_reader :location
9
+
10
+ def initialize(node:, location: node.location.expression)
11
+ @node = node
12
+ @location = location
13
+ end
14
+
15
+ def header_line
16
+ error_name
17
+ end
18
+
19
+ def detail_lines
20
+ nil
21
+ end
22
+
23
+ def diagnostic_code
24
+ "Ruby::#{error_name}"
25
+ end
26
+ end
27
+
28
+ module ResultPrinter
29
+ def print_result_to(io, level: 1)
30
+ printer = Drivers::TracePrinter.new(io)
31
+ printer.print result.trace, level: level
32
+ end
33
+
34
+ def trace_lines
35
+ StringIO.new.tap do |io|
36
+ print_result_to(io)
37
+ end.string.chomp
38
+ end
39
+
40
+ def detail_lines
41
+ StringIO.new.tap do |io|
42
+ print_result_to(io)
43
+ end.string.chomp
44
+ end
45
+ end
46
+
47
+ class IncompatibleAssignment < Base
48
+ attr_reader :lhs_type
49
+ attr_reader :rhs_type
50
+ attr_reader :result
51
+
52
+ include ResultPrinter
53
+
54
+ def initialize(node:, lhs_type:, rhs_type:, result:)
55
+ super(node: node)
56
+ @lhs_type = lhs_type
57
+ @rhs_type = rhs_type
58
+ @result = result
59
+ end
60
+
61
+ def header_line
62
+ element = case node.type
63
+ when :ivasgn, :lvasgn, :gvasgn, :cvasgn
64
+ "a variable"
65
+ when :casgn
66
+ "a constant"
67
+ else
68
+ "an expression"
69
+ end
70
+ "Cannot assign a value of type `#{rhs_type}` to #{element} of type `#{lhs_type}`"
71
+ end
72
+ end
73
+
74
+ class IncompatibleArguments < Base
75
+ attr_reader :node
76
+ attr_reader :method_name
77
+ attr_reader :receiver_type
78
+ attr_reader :method_types
79
+
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
97
+ @method_name = method_name
98
+ end
99
+
100
+ def header_line
101
+ "Cannot find method `#{method_name}` of type `#{receiver_type}` with compatible arity"
102
+ end
103
+
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
114
+ end
115
+ end
116
+
117
+ class UnresolvedOverloading < Base
118
+ attr_reader :node
119
+ attr_reader :receiver_type
120
+ attr_reader :method_name
121
+ attr_reader :method_types
122
+
123
+ def initialize(node:, receiver_type:, method_name:, method_types:)
124
+ super node: node
125
+ @receiver_type = receiver_type
126
+ @method_name = method_name
127
+ @method_types = method_types
128
+ end
129
+
130
+ def header_line
131
+ "Cannot find compatible overloading of method `#{method_name}` of type `#{receiver_type}`"
132
+ end
133
+
134
+ def detail_lines
135
+ StringIO.new.tap do |io|
136
+ io.puts "Method types:"
137
+ first_type, *rest_types = method_types
138
+ defn = " def #{method_name}"
139
+ io.puts "#{defn}: #{first_type}"
140
+ rest_types.each do |method_type|
141
+ io.puts "#{" " * defn.size}| #{method_type}"
142
+ end
143
+ end.string.chomp
144
+ end
145
+ end
146
+
147
+ class ArgumentTypeMismatch < Base
148
+ attr_reader :node
149
+ attr_reader :expected
150
+ attr_reader :actual
151
+ attr_reader :receiver_type
152
+ attr_reader :result
153
+
154
+ include ResultPrinter
155
+
156
+ def initialize(node:, receiver_type:, expected:, actual:, result:)
157
+ super(node: node)
158
+ @receiver_type = receiver_type
159
+ @expected = expected
160
+ @actual = actual
161
+ @result = result
162
+ end
163
+
164
+ def header_line
165
+ "Cannot pass a value of type `#{actual}` as an argument of type `#{expected}`"
166
+ end
167
+ end
168
+
169
+ class NoMethod < Base
170
+ attr_reader :type
171
+ attr_reader :method
172
+
173
+ def initialize(node:, type:, method:)
174
+ loc = case node.type
175
+ when :send
176
+ node.loc.selector
177
+ when :block
178
+ node.children[0].loc.selector
179
+ else
180
+ node.loc.expression
181
+ end
182
+ super(node: node, location: loc)
183
+ @type = type
184
+ @method = method
185
+ end
186
+
187
+ def header_line
188
+ "Type `#{type}` does not have method `#{method}`"
189
+ end
190
+ end
191
+
192
+ class ReturnTypeMismatch < Base
193
+ attr_reader :expected
194
+ attr_reader :actual
195
+ attr_reader :result
196
+
197
+ include ResultPrinter
198
+
199
+ def initialize(node:, expected:, actual:, result:)
200
+ super(node: node)
201
+ @expected = expected
202
+ @actual = actual
203
+ @result = result
204
+ end
205
+
206
+ def header_line
207
+ "The method cannot return a value of type `#{actual}` because declared as type `#{expected}`"
208
+ end
209
+ end
210
+
211
+ class UnexpectedBlockGiven < Base
212
+ attr_reader :method_type
213
+
214
+ def initialize(node:, method_type:)
215
+ loc = node.loc.begin.join(node.loc.end)
216
+ super(node: node, location: loc)
217
+ @method_type = method_type
218
+ end
219
+
220
+ def header_line
221
+ "The method cannot be called with a block"
222
+ end
223
+
224
+ def to_s
225
+ format_message "method_type=#{method_type}"
226
+ end
227
+ end
228
+
229
+ class RequiredBlockMissing < Base
230
+ attr_reader :method_type
231
+
232
+ def initialize(node:, method_type:)
233
+ super(node: node, location: node.loc.selector)
234
+ @method_type = method_type
235
+ end
236
+
237
+ def header_line
238
+ "The method cannot be called without a block"
239
+ end
240
+ end
241
+
242
+ class BlockTypeMismatch < Base
243
+ attr_reader :expected
244
+ attr_reader :actual
245
+ attr_reader :result
246
+
247
+ include ResultPrinter
248
+
249
+ def initialize(node:, expected:, actual:, result:)
250
+ super(node: node)
251
+ @expected = expected
252
+ @actual = actual
253
+ @result = result
254
+ end
255
+
256
+ def header_line
257
+ "Cannot pass a value of type `#{actual}` as a block-pass-argument of type `#{expected}`"
258
+ end
259
+ end
260
+
261
+ class BlockBodyTypeMismatch < Base
262
+ attr_reader :expected
263
+ attr_reader :actual
264
+ attr_reader :result
265
+
266
+ include ResultPrinter
267
+
268
+ def initialize(node:, expected:, actual:, result:)
269
+ super(node: node, location: node.loc.begin.join(node.loc.end))
270
+ @expected = expected
271
+ @actual = actual
272
+ @result = result
273
+ end
274
+
275
+ def header_line
276
+ "Cannot allow block body have type `#{actual}` because declared as type `#{expected}`"
277
+ end
278
+ end
279
+
280
+ class BreakTypeMismatch < Base
281
+ attr_reader :expected
282
+ attr_reader :actual
283
+ attr_reader :result
284
+
285
+ include ResultPrinter
286
+
287
+ def initialize(node:, expected:, actual:, result:)
288
+ super(node: node)
289
+ @expected = expected
290
+ @actual = actual
291
+ @result = result
292
+ end
293
+
294
+ def header_line
295
+ "Cannot break with a value of type `#{actual}` because type `#{expected}` is assumed"
296
+ end
297
+ end
298
+
299
+ class UnexpectedJump < Base
300
+ def header_line
301
+ "Cannot jump from here"
302
+ end
303
+ end
304
+
305
+ class UnexpectedJumpValue < Base
306
+ def header_line
307
+ "The value given to #{node.type} will be ignored"
308
+ end
309
+ end
310
+
311
+ class MethodArityMismatch < Base
312
+ attr_reader :method_type
313
+
314
+ def initialize(node:, method_type:)
315
+ args = case node.type
316
+ when :def
317
+ node.children[1]
318
+ when :defs
319
+ node.children[2]
320
+ end
321
+ super(node: node, location: args&.loc&.expression || node.loc.name)
322
+ @method_type = method_type
323
+ end
324
+
325
+ def header_line
326
+ "Method parameters are incompatible with declaration `#{method_type}`"
327
+ end
328
+ end
329
+
330
+ class IncompatibleMethodTypeAnnotation < Base
331
+ attr_reader :interface_method
332
+ attr_reader :annotation_method
333
+ attr_reader :result
334
+
335
+ include ResultPrinter
336
+
337
+ def initialize(node:, interface_method:, annotation_method:, result:)
338
+ raise
339
+ super(node: node)
340
+ @interface_method = interface_method
341
+ @annotation_method = annotation_method
342
+ @result = result
343
+ end
344
+ end
345
+
346
+ class MethodReturnTypeAnnotationMismatch < Base
347
+ attr_reader :method_type
348
+ attr_reader :annotation_type
349
+ attr_reader :result
350
+
351
+ include ResultPrinter
352
+
353
+ def initialize(node:, method_type:, annotation_type:, result:)
354
+ super(node: node)
355
+ @method_type = method_type
356
+ @annotation_type = annotation_type
357
+ @result = result
358
+ end
359
+
360
+ def header_line
361
+ "Annotation `@type return` specifies type `#{annotation_type}` where declared as type `#{method_type}`"
362
+ end
363
+ end
364
+
365
+ class MethodBodyTypeMismatch < Base
366
+ attr_reader :expected
367
+ attr_reader :actual
368
+ attr_reader :result
369
+
370
+ include ResultPrinter
371
+
372
+ def initialize(node:, expected:, actual:, result:)
373
+ super(node: node)
374
+ @expected = expected
375
+ @actual = actual
376
+ @result = result
377
+ end
378
+
379
+ def header_line
380
+ "Cannot allow method body have type `#{actual}` because declared as type `#{expected}`"
381
+ end
382
+ end
383
+
384
+ class UnexpectedYield < Base
385
+ def header_line
386
+ "No block given for `yield`"
387
+ end
388
+ end
389
+
390
+ class UnexpectedSuper < Base
391
+ attr_reader :method
392
+
393
+ def initialize(node:, method:)
394
+ super(node: node)
395
+ @method = method
396
+ end
397
+
398
+ def to_s
399
+ format_message "method=#{method}"
400
+ end
401
+ end
402
+
403
+ class MethodDefinitionMissing < Base
404
+ attr_reader :module_name
405
+ attr_reader :kind
406
+ attr_reader :missing_method
407
+
408
+ def initialize(node:, module_name:, kind:, missing_method:)
409
+ super(node: node, location: node.children[0].loc.expression)
410
+ @module_name = module_name
411
+ @kind = kind
412
+ @missing_method = missing_method
413
+ end
414
+
415
+ def header_line
416
+ method_name = case kind
417
+ when :module
418
+ ".#{missing_method}"
419
+ when :instance
420
+ "##{missing_method}"
421
+ end
422
+ "Cannot find implementation of method `#{module_name}#{method_name}`"
423
+ end
424
+ end
425
+
426
+ class UnexpectedDynamicMethod < Base
427
+ attr_reader :module_name
428
+ attr_reader :method_name
429
+
430
+ def initialize(node:, module_name:, method_name:)
431
+ super(node: node, location: node.children[0].loc.expression)
432
+ @module_name = module_name
433
+ @method_name = method_name
434
+ end
435
+
436
+ def header_line
437
+ "@dynamic annotation contains unknown method name `#{method_name}`"
438
+ end
439
+ end
440
+
441
+ class UnknownConstantAssigned < Base
442
+ attr_reader :context
443
+ attr_reader :name
444
+
445
+ def initialize(node:, context:, name:)
446
+ const = node.children[0]
447
+ loc = if const
448
+ const.loc.expression.join(node.loc.name)
449
+ else
450
+ node.loc.name
451
+ end
452
+ super(node: node, location: loc)
453
+ @context = context
454
+ @name = name
455
+ end
456
+
457
+ def header_line
458
+ "Cannot find the declaration of constant `#{name}`"
459
+ end
460
+ end
461
+
462
+ class FallbackAny < Base
463
+ def initialize(node:)
464
+ super(node: node)
465
+ end
466
+
467
+ def header_line
468
+ "Cannot detect the type of the expression"
469
+ end
470
+ end
471
+
472
+ class UnsatisfiableConstraint < Base
473
+ attr_reader :method_type
474
+ attr_reader :var
475
+ attr_reader :sub_type
476
+ attr_reader :super_type
477
+ attr_reader :result
478
+
479
+ def initialize(node:, method_type:, var:, sub_type:, super_type:, result:)
480
+ super(node: node)
481
+ @method_type = method_type
482
+ @var = var
483
+ @sub_type = sub_type
484
+ @super_type = super_type
485
+ @result = result
486
+ end
487
+
488
+ include ResultPrinter
489
+
490
+ def header_line
491
+ "Unsatisfiable constraint `#{sub_type} <: #{var} <: #{super_type}` is generated through #{method_type}"
492
+ end
493
+ end
494
+
495
+ class IncompatibleAnnotation < Base
496
+ attr_reader :var_name
497
+ attr_reader :result
498
+ attr_reader :relation
499
+
500
+ def initialize(node:, var_name:, result:, relation:)
501
+ super(node: node)
502
+ @var_name = var_name
503
+ @result = result
504
+ @relation = relation
505
+ end
506
+
507
+ include ResultPrinter
508
+
509
+ def header_line
510
+ "Type annotation about `#{var_name}` is incompatible since #{relation} doesn't hold"
511
+ end
512
+ end
513
+
514
+ class IncompatibleTypeCase < Base
515
+ attr_reader :var_name
516
+ attr_reader :result
517
+ attr_reader :relation
518
+
519
+ def initialize(node:, var_name:, result:, relation:)
520
+ super(node: node)
521
+ @var_name = var_name
522
+ @result = result
523
+ @relation = relation
524
+ end
525
+
526
+ include ResultPrinter
527
+
528
+ def header_line
529
+ "Type annotation for branch about `#{var_name}` is incompatible since #{relation} doesn't hold"
530
+ end
531
+ end
532
+
533
+ class ElseOnExhaustiveCase < Base
534
+ attr_reader :type
535
+
536
+ def initialize(node:, type:)
537
+ super(node: node)
538
+ @type = type
539
+ end
540
+
541
+ def header_line
542
+ "The branch is unreachable because the condition is exhaustive"
543
+ end
544
+ end
545
+
546
+ class UnexpectedSplat < Base
547
+ attr_reader :type
548
+
549
+ def initialize(node:, type:)
550
+ super(node: node)
551
+ @type = type
552
+ end
553
+
554
+ def header_line
555
+ "Hash splat is given with object other than `Hash[X, Y]`"
556
+ end
557
+ end
558
+
559
+ class UnexpectedKeyword < Base
560
+ attr_reader :unexpected_keywords
561
+
562
+ def initialize(node:, unexpected_keywords:)
563
+ super(node: node)
564
+ @unexpected_keywords = unexpected_keywords
565
+ end
566
+
567
+ def header_line
568
+ keywords = unexpected_keywords.sort.map {|x| "`#{x}`" }
569
+ "Cannot specify unexpected keyword arguments: #{keywords.join(", ")}"
570
+ end
571
+ end
572
+
573
+ class MissingKeyword < Base
574
+ attr_reader :missing_keywords
575
+
576
+ def initialize(node:, missing_keywords:)
577
+ super(node: node)
578
+ @missing_keywords = missing_keywords
579
+ end
580
+
581
+ def header_line
582
+ keywords = missing_keywords.sort.map {|x| "`#{x}`" }
583
+ "Cannot omit required keywords: #{keywords.join(", ")}"
584
+ end
585
+ end
586
+
587
+ class UnsupportedSyntax < Base
588
+ attr_reader :message
589
+
590
+ def initialize(node:, message: nil)
591
+ super(node: node)
592
+ @message = message
593
+ end
594
+
595
+ def header_line
596
+ if message
597
+ message
598
+ else
599
+ "Syntax `#{node.type}` is not supported in Steep"
600
+ end
601
+ end
602
+ end
603
+
604
+ class UnexpectedError < Base
605
+ attr_reader :message
606
+ attr_reader :error
607
+
608
+ def initialize(node:, error:)
609
+ super(node: node)
610
+ @error = error
611
+ end
612
+
613
+ def header_line
614
+ "UnexpectedError: #{error.message}"
615
+ end
616
+ end
617
+ end
618
+ end
619
+ end