steep 1.6.0.pre.4 → 1.7.0.dev.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.github/dependabot.yml +6 -0
- data/.github/workflows/ruby-windows.yml +2 -1
- data/.github/workflows/ruby.yml +9 -10
- data/.gitignore +0 -1
- data/CHANGELOG.md +4 -0
- data/Gemfile +1 -1
- data/Gemfile.lock +31 -29
- data/bin/output_test.rb +1 -0
- data/doc/narrowing.md +195 -0
- data/gemfile_steep/Gemfile.lock +30 -15
- data/guides/src/getting-started/getting-started.md +10 -11
- data/lib/steep/ast/ignore.rb +148 -0
- data/lib/steep/cli.rb +6 -1
- data/lib/steep/diagnostic/ruby.rb +16 -0
- data/lib/steep/drivers/utils/driver_helper.rb +22 -11
- data/lib/steep/node_helper.rb +12 -0
- data/lib/steep/project/dsl.rb +18 -21
- data/lib/steep/project/options.rb +39 -2
- data/lib/steep/project.rb +11 -7
- data/lib/steep/server/change_buffer.rb +2 -2
- data/lib/steep/server/interaction_worker.rb +61 -11
- data/lib/steep/server/worker_process.rb +3 -1
- data/lib/steep/services/completion_provider.rb +39 -8
- data/lib/steep/services/file_loader.rb +3 -2
- data/lib/steep/services/signature_help_provider.rb +9 -8
- data/lib/steep/services/type_check_service.rb +36 -8
- data/lib/steep/source/ignore_ranges.rb +69 -0
- data/lib/steep/source.rb +10 -4
- data/lib/steep/type_construction.rb +6 -147
- data/lib/steep/type_inference/case_when.rb +301 -0
- data/lib/steep/version.rb +1 -1
- data/lib/steep.rb +14 -1
- data/rbs_collection.steep.lock.yaml +8 -6
- data/sig/shims/parser.rbs +10 -0
- data/sig/shims/yaml.rbs +4 -0
- data/sig/steep/ast/ignore.rbs +66 -0
- data/sig/steep/diagnostic/ruby.rbs +8 -0
- data/sig/steep/node_helper.rbs +2 -0
- data/sig/steep/project/dsl.rbs +8 -4
- data/sig/steep/project/options.rbs +21 -1
- data/sig/steep/project.rbs +3 -3
- data/sig/steep/server/change_buffer.rbs +6 -4
- data/sig/steep/server/interaction_worker.rbs +10 -0
- data/sig/steep/server/worker_process.rbs +4 -4
- data/sig/steep/services/completion_provider.rbs +14 -1
- data/sig/steep/services/type_check_service.rbs +6 -1
- data/sig/steep/source/ignore_ranges.rbs +38 -0
- data/sig/steep/source.rbs +5 -2
- data/sig/steep/subtyping/check.rbs +2 -2
- data/sig/steep/type_construction.rbs +1 -26
- data/sig/steep/type_inference/branch.rbs +15 -0
- data/sig/steep/type_inference/case_when.rbs +130 -0
- data/sig/steep.rbs +9 -0
- data/steep.gemspec +1 -1
- metadata +14 -260
- data/smoke/alias/Steepfile +0 -6
- data/smoke/alias/a.rb +0 -16
- data/smoke/alias/a.rbs +0 -10
- data/smoke/alias/b.rb +0 -6
- data/smoke/alias/c.rb +0 -8
- data/smoke/alias/test_expectations.yml +0 -96
- data/smoke/and/Steepfile +0 -6
- data/smoke/and/a.rb +0 -8
- data/smoke/and/test_expectations.yml +0 -29
- data/smoke/array/Steepfile +0 -6
- data/smoke/array/a.rb +0 -18
- data/smoke/array/b.rb +0 -12
- data/smoke/array/c.rb +0 -6
- data/smoke/array/test_expectations.yml +0 -103
- data/smoke/block/Steepfile +0 -6
- data/smoke/block/a.rb +0 -10
- data/smoke/block/a.rbs +0 -6
- data/smoke/block/b.rb +0 -13
- data/smoke/block/c.rb +0 -9
- data/smoke/block/c.rbs +0 -3
- data/smoke/block/d.rb +0 -11
- data/smoke/block/e.rb +0 -12
- data/smoke/block/e.rbs +0 -4
- data/smoke/block/test_expectations.yml +0 -133
- data/smoke/case/Steepfile +0 -6
- data/smoke/case/a.rb +0 -18
- data/smoke/case/test_expectations.yml +0 -47
- data/smoke/class/Steepfile +0 -6
- data/smoke/class/a.rb +0 -25
- data/smoke/class/a.rbs +0 -23
- data/smoke/class/b.rb +0 -5
- data/smoke/class/c.rb +0 -9
- data/smoke/class/f.rb +0 -10
- data/smoke/class/g.rb +0 -6
- data/smoke/class/h.rb +0 -19
- data/smoke/class/h.rbs +0 -6
- data/smoke/class/i.rb +0 -14
- data/smoke/class/i.rbs +0 -9
- data/smoke/class/test_expectations.yml +0 -117
- data/smoke/compact/Steepfile +0 -6
- data/smoke/compact/a.rb +0 -2
- data/smoke/compact/a.rbs +0 -5
- data/smoke/compact/b.rb +0 -2
- data/smoke/compact/test_expectations.yml +0 -18
- data/smoke/const/Steepfile +0 -6
- data/smoke/const/a.rb +0 -27
- data/smoke/const/b.rb +0 -7
- data/smoke/const/b.rbs +0 -5
- data/smoke/const/test_expectations.yml +0 -134
- data/smoke/diagnostics/Steepfile +0 -6
- data/smoke/diagnostics/a.rbs +0 -22
- data/smoke/diagnostics/argument_type_mismatch.rb +0 -1
- data/smoke/diagnostics/block_body_type_mismatch.rb +0 -1
- data/smoke/diagnostics/block_type_mismatch.rb +0 -3
- data/smoke/diagnostics/break_type_mismatch.rb +0 -1
- data/smoke/diagnostics/different_method_parameter_kind.rb +0 -9
- data/smoke/diagnostics/else_on_exhaustive_case.rb +0 -12
- data/smoke/diagnostics/incompatible_annotation.rb +0 -6
- data/smoke/diagnostics/incompatible_argument.rb +0 -1
- data/smoke/diagnostics/incompatible_assignment.rb +0 -8
- data/smoke/diagnostics/method_arity_mismatch.rb +0 -11
- data/smoke/diagnostics/method_body_type_mismatch.rb +0 -6
- data/smoke/diagnostics/method_definition_missing.rb +0 -2
- data/smoke/diagnostics/method_parameter_mismatch.rb +0 -10
- data/smoke/diagnostics/method_return_type_annotation_mismatch.rb +0 -7
- data/smoke/diagnostics/missing_keyword.rb +0 -1
- data/smoke/diagnostics/no_method.rb +0 -1
- data/smoke/diagnostics/proc_type_expected.rb +0 -3
- data/smoke/diagnostics/required_block_missing.rb +0 -1
- data/smoke/diagnostics/return_type_mismatch.rb +0 -6
- data/smoke/diagnostics/test_expectations.yml +0 -591
- data/smoke/diagnostics/unexpected_block_given.rb +0 -1
- data/smoke/diagnostics/unexpected_dynamic_method.rb +0 -3
- data/smoke/diagnostics/unexpected_jump.rb +0 -4
- data/smoke/diagnostics/unexpected_jump_value.rb +0 -3
- data/smoke/diagnostics/unexpected_keyword.rb +0 -1
- data/smoke/diagnostics/unexpected_splat.rb +0 -1
- data/smoke/diagnostics/unexpected_yield.rb +0 -6
- data/smoke/diagnostics/unknown_constant_assigned.rb +0 -7
- data/smoke/diagnostics/unresolved_overloading.rb +0 -1
- data/smoke/diagnostics/unsupported_syntax.rb +0 -2
- data/smoke/diagnostics-rbs/Steepfile +0 -8
- data/smoke/diagnostics-rbs/duplicated-method-definition.rbs +0 -20
- data/smoke/diagnostics-rbs/generic-parameter-mismatch.rbs +0 -7
- data/smoke/diagnostics-rbs/inherit-module.rbs +0 -2
- data/smoke/diagnostics-rbs/invalid-method-overload.rbs +0 -3
- data/smoke/diagnostics-rbs/invalid-type-application.rbs +0 -7
- data/smoke/diagnostics-rbs/invalid_variance_annotation.rbs +0 -3
- data/smoke/diagnostics-rbs/mixin-class-error.rbs +0 -6
- data/smoke/diagnostics-rbs/nonregular-type-alias.rbs +0 -3
- data/smoke/diagnostics-rbs/recursive-alias.rbs +0 -5
- data/smoke/diagnostics-rbs/recursive-class.rbs +0 -8
- data/smoke/diagnostics-rbs/recursive-type-alias.rbs +0 -3
- data/smoke/diagnostics-rbs/superclass-mismatch.rbs +0 -7
- data/smoke/diagnostics-rbs/test_expectations.yml +0 -300
- data/smoke/diagnostics-rbs/unknown-method-alias.rbs +0 -3
- data/smoke/diagnostics-rbs/unknown-type-name-2.rbs +0 -5
- data/smoke/diagnostics-rbs/unknown-type-name.rbs +0 -13
- data/smoke/diagnostics-rbs-duplicated/Steepfile +0 -6
- data/smoke/diagnostics-rbs-duplicated/a.rbs +0 -5
- data/smoke/diagnostics-rbs-duplicated/test_expectations.yml +0 -13
- data/smoke/diagnostics-ruby-unsat/Steepfile +0 -6
- data/smoke/diagnostics-ruby-unsat/a.rbs +0 -3
- data/smoke/diagnostics-ruby-unsat/test_expectations.yml +0 -27
- data/smoke/diagnostics-ruby-unsat/unsatisfiable_constraint.rb +0 -6
- data/smoke/dstr/Steepfile +0 -6
- data/smoke/dstr/a.rb +0 -5
- data/smoke/dstr/test_expectations.yml +0 -13
- data/smoke/ensure/Steepfile +0 -6
- data/smoke/ensure/a.rb +0 -18
- data/smoke/ensure/test_expectations.yml +0 -62
- data/smoke/enumerator/Steepfile +0 -6
- data/smoke/enumerator/a.rb +0 -6
- data/smoke/enumerator/b.rb +0 -17
- data/smoke/enumerator/test_expectations.yml +0 -47
- data/smoke/extension/Steepfile +0 -6
- data/smoke/extension/a.rb +0 -10
- data/smoke/extension/a.rbs +0 -13
- data/smoke/extension/b.rb +0 -10
- data/smoke/extension/c.rb +0 -9
- data/smoke/extension/d.rb +0 -2
- data/smoke/extension/e.rb +0 -2
- data/smoke/extension/e.rbs +0 -7
- data/smoke/extension/f.rb +0 -2
- data/smoke/extension/f.rbs +0 -3
- data/smoke/extension/test_expectations.yml +0 -73
- data/smoke/hash/Steepfile +0 -6
- data/smoke/hash/a.rb +0 -17
- data/smoke/hash/a.rbs +0 -8
- data/smoke/hash/b.rb +0 -6
- data/smoke/hash/c.rb +0 -15
- data/smoke/hash/d.rb +0 -5
- data/smoke/hash/e.rb +0 -1
- data/smoke/hash/e.rbs +0 -3
- data/smoke/hash/f.rb +0 -11
- data/smoke/hash/test_expectations.yml +0 -81
- data/smoke/hello/Steepfile +0 -6
- data/smoke/hello/hello.rb +0 -11
- data/smoke/hello/hello.rbs +0 -7
- data/smoke/hello/test_expectations.yml +0 -25
- data/smoke/if/Steepfile +0 -6
- data/smoke/if/a.rb +0 -20
- data/smoke/if/test_expectations.yml +0 -34
- data/smoke/implements/Steepfile +0 -6
- data/smoke/implements/a.rb +0 -12
- data/smoke/implements/a.rbs +0 -6
- data/smoke/implements/b.rb +0 -13
- data/smoke/implements/b.rbs +0 -12
- data/smoke/implements/test_expectations.yml +0 -23
- data/smoke/initialize/Steepfile +0 -6
- data/smoke/initialize/a.rb +0 -12
- data/smoke/initialize/a.rbs +0 -3
- data/smoke/initialize/test_expectations.yml +0 -1
- data/smoke/integer/Steepfile +0 -6
- data/smoke/integer/a.rb +0 -26
- data/smoke/integer/test_expectations.yml +0 -110
- data/smoke/interface/Steepfile +0 -6
- data/smoke/interface/a.rb +0 -12
- data/smoke/interface/a.rbs +0 -12
- data/smoke/interface/test_expectations.yml +0 -23
- data/smoke/kwbegin/Steepfile +0 -6
- data/smoke/kwbegin/a.rb +0 -7
- data/smoke/kwbegin/test_expectations.yml +0 -17
- data/smoke/lambda/Steepfile +0 -6
- data/smoke/lambda/a.rb +0 -10
- data/smoke/lambda/test_expectations.yml +0 -17
- data/smoke/literal/Steepfile +0 -6
- data/smoke/literal/a.rb +0 -11
- data/smoke/literal/b.rb +0 -7
- data/smoke/literal/literal_methods.rbs +0 -4
- data/smoke/literal/test_expectations.yml +0 -106
- data/smoke/map/Steepfile +0 -6
- data/smoke/map/a.rb +0 -5
- data/smoke/map/test_expectations.yml +0 -1
- data/smoke/method/Steepfile +0 -6
- data/smoke/method/a.rb +0 -21
- data/smoke/method/a.rbs +0 -4
- data/smoke/method/b.rb +0 -25
- data/smoke/method/c.rb +0 -5
- data/smoke/method/d.rb +0 -1
- data/smoke/method/d.rbs +0 -3
- data/smoke/method/test_expectations.yml +0 -121
- data/smoke/module/Steepfile +0 -6
- data/smoke/module/a.rb +0 -19
- data/smoke/module/a.rbs +0 -16
- data/smoke/module/b.rb +0 -6
- data/smoke/module/c.rb +0 -22
- data/smoke/module/d.rb +0 -4
- data/smoke/module/e.rb +0 -13
- data/smoke/module/f.rb +0 -11
- data/smoke/module/test_expectations.yml +0 -75
- data/smoke/regexp/Steepfile +0 -6
- data/smoke/regexp/a.rb +0 -109
- data/smoke/regexp/b.rb +0 -79
- data/smoke/regexp/test_expectations.yml +0 -615
- data/smoke/regression/Steepfile +0 -6
- data/smoke/regression/array.rb +0 -7
- data/smoke/regression/block_param_split.rb +0 -7
- data/smoke/regression/block_param_split.rbs +0 -3
- data/smoke/regression/empty_yield.rb +0 -5
- data/smoke/regression/empty_yield.rbs +0 -3
- data/smoke/regression/enumerator_product.rb +0 -1
- data/smoke/regression/fun.rb +0 -8
- data/smoke/regression/fun.rbs +0 -4
- data/smoke/regression/hash.rb +0 -7
- data/smoke/regression/hello world.rb +0 -1
- data/smoke/regression/issue_328.rb +0 -1
- data/smoke/regression/issue_328.rbs +0 -0
- data/smoke/regression/issue_332.rb +0 -11
- data/smoke/regression/issue_332.rbs +0 -19
- data/smoke/regression/issue_372.rb +0 -8
- data/smoke/regression/issue_372.rbs +0 -4
- data/smoke/regression/lambda.rb +0 -3
- data/smoke/regression/masgn.rb +0 -4
- data/smoke/regression/poly_new.rb +0 -2
- data/smoke/regression/poly_new.rbs +0 -4
- data/smoke/regression/range.rb +0 -5
- data/smoke/regression/set_divide.rb +0 -12
- data/smoke/regression/test_expectations.yml +0 -120
- data/smoke/regression/thread.rb +0 -7
- data/smoke/rescue/Steepfile +0 -6
- data/smoke/rescue/a.rb +0 -48
- data/smoke/rescue/test_expectations.yml +0 -79
- data/smoke/self/Steepfile +0 -6
- data/smoke/self/a.rb +0 -21
- data/smoke/self/a.rbs +0 -4
- data/smoke/self/test_expectations.yml +0 -23
- data/smoke/skip/Steepfile +0 -6
- data/smoke/skip/skip.rb +0 -13
- data/smoke/skip/test_expectations.yml +0 -23
- data/smoke/stdout/Steepfile +0 -6
- data/smoke/stdout/a.rb +0 -8
- data/smoke/stdout/a.rbs +0 -7
- data/smoke/stdout/test_expectations.yml +0 -1
- data/smoke/super/Steepfile +0 -6
- data/smoke/super/a.rb +0 -30
- data/smoke/super/a.rbs +0 -10
- data/smoke/super/test_expectations.yml +0 -69
- data/smoke/toplevel/Steepfile +0 -6
- data/smoke/toplevel/a.rb +0 -3
- data/smoke/toplevel/a.rbs +0 -3
- data/smoke/toplevel/test_expectations.yml +0 -15
- data/smoke/tsort/Steepfile +0 -7
- data/smoke/tsort/a.rb +0 -12
- data/smoke/tsort/test_expectations.yml +0 -1
- data/smoke/type_case/Steepfile +0 -6
- data/smoke/type_case/a.rb +0 -24
- data/smoke/type_case/test_expectations.yml +0 -58
- data/smoke/unexpected/Steepfile +0 -6
- data/smoke/unexpected/test_expectations.yml +0 -13
- data/smoke/unexpected/unexpected.rbs +0 -3
- data/smoke/yield/Steepfile +0 -6
- data/smoke/yield/a.rb +0 -15
- data/smoke/yield/b.rb +0 -6
- data/smoke/yield/test_expectations.yml +0 -88
@@ -157,6 +157,9 @@ module Steep
|
|
157
157
|
end
|
158
158
|
end
|
159
159
|
|
160
|
+
class TextItem < Struct.new(:text, :help_text, :range, :label, keyword_init: true)
|
161
|
+
end
|
162
|
+
|
160
163
|
attr_reader :source_text
|
161
164
|
attr_reader :path
|
162
165
|
attr_reader :subtyping
|
@@ -205,7 +208,7 @@ module Steep
|
|
205
208
|
end
|
206
209
|
end
|
207
210
|
|
208
|
-
if at_comment?(position)
|
211
|
+
if comment = at_comment?(position)
|
209
212
|
node, *parents = source.find_nodes(line: position.line, column: position.column)
|
210
213
|
|
211
214
|
case
|
@@ -232,9 +235,41 @@ module Steep
|
|
232
235
|
if annotation
|
233
236
|
annotation.location or raise
|
234
237
|
return items_for_rbs(position: position, buffer: annotation.location.buffer)
|
235
|
-
else
|
236
|
-
return []
|
237
238
|
end
|
239
|
+
|
240
|
+
comment_content = comment.text[1..] || ""
|
241
|
+
comment_content.strip!
|
242
|
+
|
243
|
+
range = Range.new(
|
244
|
+
start: Position.new(line: line, column: column),
|
245
|
+
end: Position.new(line: line, column: column)
|
246
|
+
)
|
247
|
+
|
248
|
+
items = [
|
249
|
+
TextItem.new(label: "steep:ignore:start", text: "steep:ignore:start", help_text: "Open ignore block", range: range),
|
250
|
+
TextItem.new(label: "steep:ignore:end", text: "steep:ignore:end", help_text: "Close ignore block", range: range),
|
251
|
+
TextItem.new(label: "steep:ignore", text: "steep:ignore ${1:optional diagnostics}", help_text: "Ignore line", range: range),
|
252
|
+
TextItem.new(label: "@type var x: T", text: "@type var ${1:variable}: ${2:var type}", help_text: "Type of local variable", range: range),
|
253
|
+
TextItem.new(label: "@type self: T", text: "@type self: ${1:self type}", help_text: "Type of `self`", range: range),
|
254
|
+
TextItem.new(label: "@type block: T", text: "@type block: ${1:block type}", help_text: "Type of `block`", range: range),
|
255
|
+
TextItem.new(label: "@type break: T", text: "@type break: ${1:break type}", help_text: "Type of `block`", range: range),
|
256
|
+
]
|
257
|
+
|
258
|
+
items = items.filter_map do |item|
|
259
|
+
if item.text.start_with?(comment_content)
|
260
|
+
TextItem.new(
|
261
|
+
label: item.label,
|
262
|
+
text: item.text,
|
263
|
+
help_text: item.help_text,
|
264
|
+
range: Range.new(
|
265
|
+
start: Position.new(line: item.range.start.line, column: item.range.start.column - comment_content.size),
|
266
|
+
end: item.range.end
|
267
|
+
)
|
268
|
+
)
|
269
|
+
end
|
270
|
+
end
|
271
|
+
|
272
|
+
return items
|
238
273
|
end
|
239
274
|
end
|
240
275
|
|
@@ -294,11 +329,7 @@ module Steep
|
|
294
329
|
end
|
295
330
|
|
296
331
|
def at_comment?(position)
|
297
|
-
|
298
|
-
true
|
299
|
-
else
|
300
|
-
false
|
301
|
-
end
|
332
|
+
source.find_comment(line: position.line, column: position.column)
|
302
333
|
end
|
303
334
|
|
304
335
|
def range_for(position, prefix: "")
|
@@ -15,8 +15,9 @@ module Steep
|
|
15
15
|
absolute_path = base_dir + path
|
16
16
|
|
17
17
|
if absolute_path.file?
|
18
|
-
|
19
|
-
|
18
|
+
relative_path = absolute_path.relative_path_from(base_dir)
|
19
|
+
if pattern =~ relative_path
|
20
|
+
yield relative_path
|
20
21
|
end
|
21
22
|
else
|
22
23
|
files = if absolute_path.directory?
|
@@ -55,7 +55,7 @@ module Steep
|
|
55
55
|
if begin_loc.end_pos <= pos && pos <= end_loc.begin_pos
|
56
56
|
# Given position is between open/close parens of args of send node
|
57
57
|
|
58
|
-
if parent && (parent.type == :block || parent.type == :numblock)
|
58
|
+
if parent && (parent.type == :block || parent.type == :numblock) && node.equal?(parent.children[0])
|
59
59
|
send_node = parent
|
60
60
|
else
|
61
61
|
send_node = node
|
@@ -76,7 +76,8 @@ module Steep
|
|
76
76
|
end
|
77
77
|
|
78
78
|
def last_argument_nodes_for(argument_nodes:, line:, column:)
|
79
|
-
|
79
|
+
last = argument_nodes.last or raise
|
80
|
+
return unless last.children[2] # No arguments
|
80
81
|
return argument_nodes if argument_nodes.size > 1 # Cursor is on the last argument
|
81
82
|
|
82
83
|
pos = buffer.loc_to_pos([line, column])
|
@@ -150,9 +151,9 @@ module Steep
|
|
150
151
|
case last_argument_nodes[-3].type
|
151
152
|
when :pair
|
152
153
|
argname = last_argument_nodes[-3].children.first.children.first
|
153
|
-
if method_type.type.required_keywords
|
154
|
+
if method_type.type.required_keywords.key?(argname)
|
154
155
|
positionals + method_type.type.required_keywords.keys.index(argname).to_i + 1
|
155
|
-
elsif method_type.type.optional_keywords
|
156
|
+
elsif method_type.type.optional_keywords.key?(argname)
|
156
157
|
positionals + method_type.type.required_keywords.size + method_type.type.optional_keywords.keys.index(argname).to_i + 1
|
157
158
|
elsif method_type.type.rest_keywords
|
158
159
|
positionals + method_type.type.required_keywords.size + method_type.type.optional_keywords.size
|
@@ -161,7 +162,7 @@ module Steep
|
|
161
162
|
positionals + method_type.type.required_keywords.size + method_type.type.optional_keywords.size if method_type.type.rest_keywords
|
162
163
|
end
|
163
164
|
else
|
164
|
-
pos = node.children[2...].index { |c| c.location == last_argument_nodes[-2].location }.to_i
|
165
|
+
pos = (node.children[2...] || raise).index { |c| c.location == last_argument_nodes[-2].location }.to_i
|
165
166
|
if method_type.type.rest_positionals
|
166
167
|
[pos + 1, positionals - 1].min
|
167
168
|
else
|
@@ -177,9 +178,9 @@ module Steep
|
|
177
178
|
case argument_nodes[-3].type
|
178
179
|
when :pair
|
179
180
|
argname = argument_nodes[-3].children.first.children.first
|
180
|
-
if method_type.type.required_keywords
|
181
|
+
if method_type.type.required_keywords.key?(argname)
|
181
182
|
positionals + method_type.type.required_keywords.keys.index(argname).to_i
|
182
|
-
elsif method_type.type.optional_keywords
|
183
|
+
elsif method_type.type.optional_keywords.key?(argname)
|
183
184
|
positionals + method_type.type.required_keywords.size + method_type.type.optional_keywords.keys.index(argname).to_i
|
184
185
|
elsif method_type.type.rest_keywords
|
185
186
|
positionals + method_type.type.required_keywords.size + method_type.type.optional_keywords.size
|
@@ -188,7 +189,7 @@ module Steep
|
|
188
189
|
positionals + method_type.type.required_keywords.size + method_type.type.optional_keywords.size if method_type.type.rest_keywords
|
189
190
|
end
|
190
191
|
else
|
191
|
-
pos = node.children[2...].index { |c| c.location == argument_nodes[-2].location }.to_i
|
192
|
+
pos = (node.children[2...] || raise).index { |c| c.location == argument_nodes[-2].location }.to_i
|
192
193
|
[pos, positionals - 1].min
|
193
194
|
end
|
194
195
|
end
|
@@ -13,25 +13,27 @@ module Steep
|
|
13
13
|
attr_reader :node
|
14
14
|
attr_reader :typing
|
15
15
|
attr_reader :errors
|
16
|
+
attr_reader :ignores
|
16
17
|
|
17
|
-
def initialize(path:, node:, content:, typing:, errors:)
|
18
|
+
def initialize(path:, node:, content:, typing:, ignores:, errors:)
|
18
19
|
@path = path
|
19
20
|
@node = node
|
20
21
|
@content = content
|
21
22
|
@typing = typing
|
23
|
+
@ignores = ignores
|
22
24
|
@errors = errors
|
23
25
|
end
|
24
26
|
|
25
27
|
def self.with_syntax_error(path:, content:, error:)
|
26
|
-
new(path: path, node: false, content: content, errors: [error], typing: nil)
|
28
|
+
new(path: path, node: false, content: content, errors: [error], typing: nil, ignores: nil)
|
27
29
|
end
|
28
30
|
|
29
|
-
def self.with_typing(path:, content:, typing:, node:)
|
30
|
-
new(path: path, node: node, content: content, errors: nil, typing: typing)
|
31
|
+
def self.with_typing(path:, content:, typing:, node:, ignores:)
|
32
|
+
new(path: path, node: node, content: content, errors: nil, typing: typing, ignores: ignores)
|
31
33
|
end
|
32
34
|
|
33
35
|
def self.no_data(path:, content:)
|
34
|
-
new(path: path, content: content, node: false, errors: nil, typing: nil)
|
36
|
+
new(path: path, content: content, node: false, errors: nil, typing: nil, ignores: nil)
|
35
37
|
end
|
36
38
|
|
37
39
|
def update_content(content)
|
@@ -40,12 +42,37 @@ module Steep
|
|
40
42
|
content: content,
|
41
43
|
node: node,
|
42
44
|
errors: errors,
|
43
|
-
typing: typing
|
45
|
+
typing: typing,
|
46
|
+
ignores: ignores
|
44
47
|
)
|
45
48
|
end
|
46
49
|
|
47
50
|
def diagnostics
|
48
|
-
|
51
|
+
case
|
52
|
+
when errors
|
53
|
+
errors
|
54
|
+
when typing && ignores
|
55
|
+
errors = [] #: Array[Diagnostic::Ruby::Base]
|
56
|
+
|
57
|
+
errors.concat(
|
58
|
+
typing.errors.delete_if do |diagnostic|
|
59
|
+
case diagnostic.location
|
60
|
+
when ::Parser::Source::Range
|
61
|
+
ignores.ignore?(diagnostic.location.first_line, diagnostic.location.last_line, diagnostic.diagnostic_code)
|
62
|
+
when RBS::Location
|
63
|
+
ignores.ignore?(diagnostic.location.start_line, diagnostic.location.end_line, diagnostic.diagnostic_code)
|
64
|
+
end
|
65
|
+
end
|
66
|
+
)
|
67
|
+
|
68
|
+
ignores.error_ignores.each do |ignore|
|
69
|
+
errors << Diagnostic::Ruby::InvalidIgnoreComment.new(comment: ignore.comment)
|
70
|
+
end
|
71
|
+
|
72
|
+
errors
|
73
|
+
else
|
74
|
+
[]
|
75
|
+
end
|
49
76
|
end
|
50
77
|
end
|
51
78
|
|
@@ -327,7 +354,8 @@ module Steep
|
|
327
354
|
Steep.logger.tagged "#type_check_file(#{path}@#{target.name})" do
|
328
355
|
source = Source.parse(text, path: path, factory: subtyping.factory)
|
329
356
|
typing = TypeCheckService.type_check(source: source, subtyping: subtyping, constant_resolver: yield)
|
330
|
-
|
357
|
+
ignores = Source::IgnoreRanges.new(ignores: source.ignores)
|
358
|
+
SourceFile.with_typing(path: path, content: text, node: source.node, typing: typing, ignores: ignores)
|
331
359
|
end
|
332
360
|
rescue AnnotationParser::SyntaxError => exn
|
333
361
|
error = Diagnostic::Ruby::SyntaxError.new(message: exn.message, location: exn.location)
|
@@ -0,0 +1,69 @@
|
|
1
|
+
module Steep
|
2
|
+
class Source
|
3
|
+
class IgnoreRanges
|
4
|
+
attr_reader :all_ignores, :error_ignores, :ignored_ranges, :ignored_lines
|
5
|
+
|
6
|
+
def initialize(ignores:)
|
7
|
+
@all_ignores = ignores.sort_by(&:line)
|
8
|
+
@error_ignores = []
|
9
|
+
|
10
|
+
@ignored_lines = {}
|
11
|
+
@ignored_ranges = []
|
12
|
+
|
13
|
+
last_start = nil #: AST::Ignore::IgnoreStart?
|
14
|
+
|
15
|
+
all_ignores.each do |ignore|
|
16
|
+
case ignore
|
17
|
+
when AST::Ignore::IgnoreStart
|
18
|
+
if last_start
|
19
|
+
error_ignores << last_start
|
20
|
+
end
|
21
|
+
last_start = ignore
|
22
|
+
when AST::Ignore::IgnoreEnd
|
23
|
+
if last_start
|
24
|
+
ignored_ranges << (last_start.line..ignore.line)
|
25
|
+
last_start = nil
|
26
|
+
else
|
27
|
+
error_ignores << ignore
|
28
|
+
end
|
29
|
+
when AST::Ignore::IgnoreLine
|
30
|
+
if last_start
|
31
|
+
error_ignores << ignore
|
32
|
+
else
|
33
|
+
ignored_lines[ignore.line] = ignore
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
if last_start
|
39
|
+
error_ignores << last_start
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
def ignore?(start_line, end_line, code)
|
44
|
+
if ignore = ignored_lines.fetch(start_line, nil)
|
45
|
+
ignore_code?(ignore, code) and return true
|
46
|
+
end
|
47
|
+
|
48
|
+
if start_line != end_line
|
49
|
+
if ignore = ignored_lines.fetch(end_line, nil)
|
50
|
+
ignore_code?(ignore, code) and return true
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
ignored_ranges.any? do |range|
|
55
|
+
range.cover?(start_line) && range.cover?(end_line)
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
def ignore_code?(line, code)
|
60
|
+
case diags = line.ignored_diagnostics
|
61
|
+
when Symbol
|
62
|
+
true
|
63
|
+
else
|
64
|
+
diags.any? {|d| code == "Ruby::#{d}" }
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
data/lib/steep/source.rb
CHANGED
@@ -5,15 +5,17 @@ module Steep
|
|
5
5
|
attr_reader :node
|
6
6
|
attr_reader :mapping
|
7
7
|
attr_reader :comments
|
8
|
+
attr_reader :ignores
|
8
9
|
|
9
10
|
extend NodeHelper
|
10
11
|
|
11
|
-
def initialize(buffer:, path:, node:, mapping:, comments:)
|
12
|
+
def initialize(buffer:, path:, node:, mapping:, comments:, ignores:)
|
12
13
|
@buffer = buffer
|
13
14
|
@path = path
|
14
15
|
@node = node
|
15
16
|
@mapping = mapping
|
16
17
|
@comments = comments
|
18
|
+
@ignores = ignores
|
17
19
|
end
|
18
20
|
|
19
21
|
class Builder < ::Parser::Builders::Default
|
@@ -28,7 +30,7 @@ module Steep
|
|
28
30
|
end
|
29
31
|
|
30
32
|
def self.new_parser
|
31
|
-
::Parser::
|
33
|
+
::Parser::Ruby33.new(Builder.new).tap do |parser|
|
32
34
|
parser.diagnostics.all_errors_are_fatal = true
|
33
35
|
parser.diagnostics.ignore_warnings = true
|
34
36
|
end
|
@@ -88,7 +90,11 @@ module Steep
|
|
88
90
|
map[node] << annot
|
89
91
|
end
|
90
92
|
|
91
|
-
|
93
|
+
ignores = comments.filter_map do |comment|
|
94
|
+
AST::Ignore.parse(comment, buffer)
|
95
|
+
end
|
96
|
+
|
97
|
+
new(buffer: buffer, path: path, node: node, mapping: map, comments: comments, ignores: ignores)
|
92
98
|
end
|
93
99
|
|
94
100
|
def self.construct_mapping(node:, annotations:, mapping:, line_range: nil)
|
@@ -432,7 +438,7 @@ module Steep
|
|
432
438
|
mapping[node_] << annot
|
433
439
|
end
|
434
440
|
|
435
|
-
Source.new(buffer: buffer, path: path, node: node_, mapping: mapping, comments: comments)
|
441
|
+
Source.new(buffer: buffer, path: path, node: node_, mapping: mapping, comments: comments, ignores: ignores)
|
436
442
|
else
|
437
443
|
self
|
438
444
|
end
|
@@ -1966,113 +1966,7 @@ module Steep
|
|
1966
1966
|
interpreter = TypeInference::LogicTypeInterpreter.new(subtyping: checker, typing: typing, config: builder_config)
|
1967
1967
|
|
1968
1968
|
if cond
|
1969
|
-
|
1970
|
-
|
1971
|
-
cond_type, constr = constr.synthesize(cond)
|
1972
|
-
|
1973
|
-
var_name = :"_a[#{SecureRandom.alphanumeric(4)}]"
|
1974
|
-
var_cond, value_node = transform_condition_node(cond, var_name)
|
1975
|
-
constr = constr.update_type_env {|env| env.assign_local_variable(var_name, cond_type, nil) }
|
1976
|
-
|
1977
|
-
next_branch_reachable = true
|
1978
|
-
|
1979
|
-
when_constr = constr
|
1980
|
-
whens.each do |clause|
|
1981
|
-
# @type var tests: Array[Parser::AST::Node]
|
1982
|
-
# @type var body: Parser::AST::Node?
|
1983
|
-
*tests, body = clause.children
|
1984
|
-
|
1985
|
-
test_constr = when_constr
|
1986
|
-
# @type var test_envs: Array[TypeInference::TypeEnv]
|
1987
|
-
test_envs = []
|
1988
|
-
|
1989
|
-
branch_reachable = false
|
1990
|
-
false_branch_reachable = false
|
1991
|
-
|
1992
|
-
tests.each do |test|
|
1993
|
-
test_node = test.updated(:send, [test, :===, var_cond])
|
1994
|
-
test_type, test_constr = test_constr.synthesize(test_node, condition: true).to_ary
|
1995
|
-
truthy, falsy = interpreter.eval(node: test_node, env: test_constr.context.type_env)
|
1996
|
-
|
1997
|
-
truthy_env = propagate_type_env(var_name, value_node, truthy.env)
|
1998
|
-
falsy_env = propagate_type_env(var_name, value_node, falsy.env)
|
1999
|
-
|
2000
|
-
test_envs << truthy_env
|
2001
|
-
|
2002
|
-
test_constr = test_constr.update_type_env { falsy_env }
|
2003
|
-
|
2004
|
-
branch_reachable ||= next_branch_reachable && !truthy.unreachable
|
2005
|
-
false_branch_reachable = !falsy.unreachable
|
2006
|
-
end
|
2007
|
-
|
2008
|
-
next_branch_reachable &&= false_branch_reachable
|
2009
|
-
body_constr = when_constr.update_type_env {|env| env.join(*test_envs) }
|
2010
|
-
|
2011
|
-
branch_result =
|
2012
|
-
if body
|
2013
|
-
body_constr
|
2014
|
-
.for_branch(body)
|
2015
|
-
.tap {|constr| typing.add_context_for_node(body, context: constr.context) }
|
2016
|
-
.synthesize(body, hint: hint)
|
2017
|
-
else
|
2018
|
-
Pair.new(type: AST::Builtin.nil_type, constr: body_constr)
|
2019
|
-
end
|
2020
|
-
|
2021
|
-
branch_results << branch_result
|
2022
|
-
|
2023
|
-
if !branch_reachable && !branch_result.type.is_a?(AST::Types::Bot)
|
2024
|
-
typing.add_error(
|
2025
|
-
Diagnostic::Ruby::UnreachableValueBranch.new(
|
2026
|
-
node: clause,
|
2027
|
-
type: branch_result.type,
|
2028
|
-
location: clause.location.keyword
|
2029
|
-
)
|
2030
|
-
)
|
2031
|
-
end
|
2032
|
-
|
2033
|
-
when_constr = test_constr
|
2034
|
-
end
|
2035
|
-
|
2036
|
-
if els
|
2037
|
-
node.loc.else or raise
|
2038
|
-
|
2039
|
-
begin_pos = node.loc.else.end_pos
|
2040
|
-
end_pos = node.loc.end.begin_pos
|
2041
|
-
typing.add_context(begin_pos..end_pos, context: when_constr.context)
|
2042
|
-
|
2043
|
-
else_result = when_constr.synthesize(els, hint: hint)
|
2044
|
-
|
2045
|
-
if next_branch_reachable
|
2046
|
-
branch_results << else_result
|
2047
|
-
end
|
2048
|
-
end
|
2049
|
-
|
2050
|
-
types = branch_results.map(&:type)
|
2051
|
-
constrs = branch_results.map(&:constr)
|
2052
|
-
|
2053
|
-
if !next_branch_reachable
|
2054
|
-
# Exhaustive
|
2055
|
-
_, _, _, loc = deconstruct_case_node!(node)
|
2056
|
-
|
2057
|
-
# `else` may present even if it's empty
|
2058
|
-
if loc.else
|
2059
|
-
if els
|
2060
|
-
else_result or raise
|
2061
|
-
unless else_result.type.is_a?(AST::Types::Bot)
|
2062
|
-
typing.add_error Diagnostic::Ruby::UnreachableValueBranch.new(
|
2063
|
-
node: els,
|
2064
|
-
type: else_result.type,
|
2065
|
-
location: node.loc.else || raise
|
2066
|
-
)
|
2067
|
-
end
|
2068
|
-
end
|
2069
|
-
end
|
2070
|
-
else
|
2071
|
-
unless els
|
2072
|
-
constrs << when_constr
|
2073
|
-
types << AST::Builtin.nil_type
|
2074
|
-
end
|
2075
|
-
end
|
1969
|
+
types, envs = TypeInference::CaseWhen.type_check(constr, node, interpreter, hint: hint, condition: condition)
|
2076
1970
|
else
|
2077
1971
|
branch_results = [] #: Array[Pair]
|
2078
1972
|
|
@@ -2131,7 +2025,7 @@ module Steep
|
|
2131
2025
|
end
|
2132
2026
|
|
2133
2027
|
types = branch_results.map(&:type)
|
2134
|
-
|
2028
|
+
envs = branch_results.map {|result| result.constr.context.type_env }
|
2135
2029
|
|
2136
2030
|
unless els
|
2137
2031
|
types << AST::Builtin.nil_type
|
@@ -2139,7 +2033,6 @@ module Steep
|
|
2139
2033
|
end
|
2140
2034
|
|
2141
2035
|
constr = constr.update_type_env do |env|
|
2142
|
-
envs = constrs.map {|c| c.context.type_env }
|
2143
2036
|
env.join(*envs)
|
2144
2037
|
end
|
2145
2038
|
|
@@ -2455,11 +2348,8 @@ module Steep
|
|
2455
2348
|
end
|
2456
2349
|
|
2457
2350
|
when :defined?
|
2458
|
-
|
2459
|
-
|
2460
|
-
end
|
2461
|
-
|
2462
|
-
add_typing(node, type: AST::Builtin.any_type)
|
2351
|
+
type_any_rec(node, only_children: true)
|
2352
|
+
add_typing(node, type: AST::Builtin.optional(AST::Builtin::String.instance_type))
|
2463
2353
|
|
2464
2354
|
when :gvasgn
|
2465
2355
|
yield_self do
|
@@ -4774,8 +4664,8 @@ module Steep
|
|
4774
4664
|
!nodes.empty? && nodes.all? {|child| child.type == :class || child.type == :module}
|
4775
4665
|
end
|
4776
4666
|
|
4777
|
-
def type_any_rec(node)
|
4778
|
-
add_typing node, type: AST::Builtin.any_type
|
4667
|
+
def type_any_rec(node, only_children: false)
|
4668
|
+
add_typing node, type: AST::Builtin.any_type unless only_children
|
4779
4669
|
|
4780
4670
|
each_child_node(node) do |child|
|
4781
4671
|
type_any_rec(child)
|
@@ -5162,22 +5052,6 @@ module Steep
|
|
5162
5052
|
with_new_typing(typing.parent || raise)
|
5163
5053
|
end
|
5164
5054
|
|
5165
|
-
def transform_condition_node(node, var_name)
|
5166
|
-
case node.type
|
5167
|
-
when :lvasgn
|
5168
|
-
name, rhs = node.children
|
5169
|
-
rhs, value_node = transform_condition_node(rhs, var_name)
|
5170
|
-
[node.updated(nil, [name, rhs]), value_node]
|
5171
|
-
when :begin
|
5172
|
-
*children, last = node.children
|
5173
|
-
last, value_node = transform_condition_node(last, var_name)
|
5174
|
-
[node.updated(nil, children.push(last)), value_node]
|
5175
|
-
else
|
5176
|
-
var_node = node.updated(:lvar, [var_name])
|
5177
|
-
[var_node, node]
|
5178
|
-
end
|
5179
|
-
end
|
5180
|
-
|
5181
5055
|
def type_name(type)
|
5182
5056
|
case type
|
5183
5057
|
when AST::Types::Name::Instance, AST::Types::Name::Singleton
|
@@ -5228,20 +5102,5 @@ module Steep
|
|
5228
5102
|
end
|
5229
5103
|
end
|
5230
5104
|
end
|
5231
|
-
|
5232
|
-
def propagate_type_env(source, dest, env)
|
5233
|
-
source_type = env[source] or raise
|
5234
|
-
|
5235
|
-
if dest.type == :lvar
|
5236
|
-
var_name = dest.children[0] #: Symbol
|
5237
|
-
env.assign_local_variable(var_name, source_type, nil)
|
5238
|
-
else
|
5239
|
-
if env[dest]
|
5240
|
-
env.replace_pure_call_type(dest, source_type)
|
5241
|
-
else
|
5242
|
-
env
|
5243
|
-
end
|
5244
|
-
end
|
5245
|
-
end
|
5246
5105
|
end
|
5247
5106
|
end
|