steep 1.10.0 → 2.1.0.dev.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +84 -1
- data/CLAUDE.md +114 -0
- data/README.md +2 -2
- data/Rakefile +365 -150
- data/Steepfile +13 -13
- data/doc/release.md +264 -0
- data/lib/steep/annotation_parser.rb +5 -1
- data/lib/steep/annotations_helper.rb +12 -2
- data/lib/steep/ast/node/type_application.rb +22 -16
- data/lib/steep/ast/node/type_assertion.rb +7 -4
- data/lib/steep/ast/types/factory.rb +3 -2
- data/lib/steep/cli.rb +246 -2
- data/lib/steep/daemon/configuration.rb +19 -0
- data/lib/steep/daemon/server.rb +476 -0
- data/lib/steep/daemon.rb +201 -0
- data/lib/steep/diagnostic/ruby.rb +54 -12
- data/lib/steep/diagnostic/signature.rb +31 -8
- data/lib/steep/drivers/check.rb +301 -140
- data/lib/steep/drivers/print_project.rb +9 -10
- data/lib/steep/drivers/query.rb +102 -0
- data/lib/steep/drivers/start_server.rb +19 -0
- data/lib/steep/drivers/stop_server.rb +20 -0
- data/lib/steep/drivers/watch.rb +2 -2
- data/lib/steep/index/rbs_index.rb +38 -13
- data/lib/steep/index/signature_symbol_provider.rb +24 -3
- data/lib/steep/interface/builder.rb +48 -15
- data/lib/steep/interface/shape.rb +13 -5
- data/lib/steep/locator.rb +377 -0
- data/lib/steep/node_helper.rb +2 -2
- data/lib/steep/project/dsl.rb +26 -5
- data/lib/steep/project/group.rb +8 -2
- data/lib/steep/project/target.rb +16 -2
- data/lib/steep/project.rb +21 -2
- data/lib/steep/server/base_worker.rb +2 -2
- data/lib/steep/server/change_buffer.rb +2 -1
- data/lib/steep/server/custom_methods.rb +12 -0
- data/lib/steep/server/inline_source_change_detector.rb +94 -0
- data/lib/steep/server/interaction_worker.rb +51 -74
- data/lib/steep/server/lsp_formatter.rb +48 -12
- data/lib/steep/server/master.rb +100 -18
- data/lib/steep/server/target_group_files.rb +124 -151
- data/lib/steep/server/type_check_controller.rb +276 -123
- data/lib/steep/server/type_check_worker.rb +104 -3
- data/lib/steep/services/completion_provider/rbs.rb +74 -0
- data/lib/steep/services/completion_provider/ruby.rb +652 -0
- data/lib/steep/services/completion_provider/type_name.rb +243 -0
- data/lib/steep/services/completion_provider.rb +39 -662
- data/lib/steep/services/content_change.rb +14 -1
- data/lib/steep/services/file_loader.rb +4 -2
- data/lib/steep/services/goto_service.rb +271 -68
- data/lib/steep/services/hover_provider/content.rb +67 -0
- data/lib/steep/services/hover_provider/rbs.rb +8 -9
- data/lib/steep/services/hover_provider/ruby.rb +124 -65
- data/lib/steep/services/hover_provider/singleton_methods.rb +4 -0
- data/lib/steep/services/signature_help_provider.rb +1 -1
- data/lib/steep/services/signature_service.rb +129 -54
- data/lib/steep/services/type_check_service.rb +72 -27
- data/lib/steep/signature/validator.rb +30 -18
- data/lib/steep/source/ignore_ranges.rb +14 -4
- data/lib/steep/source.rb +21 -7
- data/lib/steep/tagged_logging.rb +39 -0
- data/lib/steep/type_construction.rb +111 -24
- data/lib/steep/type_inference/block_params.rb +7 -7
- data/lib/steep/type_inference/context.rb +4 -2
- data/lib/steep/type_inference/logic_type_interpreter.rb +24 -3
- data/lib/steep/type_inference/method_call.rb +4 -0
- data/lib/steep/type_inference/type_env.rb +1 -1
- data/lib/steep/typing.rb +3 -5
- data/lib/steep/version.rb +1 -1
- data/lib/steep.rb +42 -32
- data/manual/ruby-diagnostics.md +67 -0
- data/sample/Steepfile +1 -0
- data/sample/lib/conference.rb +1 -0
- data/sample/lib/deprecated.rb +6 -0
- data/sample/lib/inline.rb +43 -0
- data/sample/sig/generics.rbs +3 -0
- data/steep.gemspec +4 -5
- metadata +27 -26
- data/lib/steep/services/type_name_completion.rb +0 -236
|
@@ -49,7 +49,7 @@ module Steep
|
|
|
49
49
|
end
|
|
50
50
|
|
|
51
51
|
def type_name_resolver
|
|
52
|
-
@type_name_resolver ||= RBS::Resolver::TypeNameResolver.
|
|
52
|
+
@type_name_resolver ||= RBS::Resolver::TypeNameResolver.build(env)
|
|
53
53
|
end
|
|
54
54
|
|
|
55
55
|
def validator
|
|
@@ -321,12 +321,12 @@ module Steep
|
|
|
321
321
|
args: entry.type_params.map { AST::Types::Any.instance() }
|
|
322
322
|
)
|
|
323
323
|
|
|
324
|
-
entry.
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
324
|
+
entry.each_decl do |decl|
|
|
325
|
+
if decl.is_a?(RBS::AST::Declarations::Base)
|
|
326
|
+
unless AnnotationsHelper.deprecated_annotation?(decl.annotations)
|
|
327
|
+
if location = decl.location
|
|
328
|
+
validate_type_name_deprecation(name, location[:name])
|
|
329
|
+
end
|
|
330
330
|
end
|
|
331
331
|
end
|
|
332
332
|
end
|
|
@@ -391,7 +391,7 @@ module Steep
|
|
|
391
391
|
location =
|
|
392
392
|
case ancestor.source
|
|
393
393
|
when :super
|
|
394
|
-
if (primary_decl = entry.
|
|
394
|
+
if (primary_decl = entry.primary_decl).is_a?(RBS::AST::Declarations::Class)
|
|
395
395
|
primary_decl.super_class&.location
|
|
396
396
|
end
|
|
397
397
|
when nil
|
|
@@ -455,7 +455,13 @@ module Steep
|
|
|
455
455
|
definition.class_variables.each do |name, var|
|
|
456
456
|
if var.declared_in == definition.type_name
|
|
457
457
|
if (parent = var.parent_variable) && var.declared_in != parent.declared_in
|
|
458
|
-
|
|
458
|
+
members = entry.each_decl.flat_map do |decl|
|
|
459
|
+
case decl
|
|
460
|
+
when RBS::AST::Declarations::Class, RBS::AST::Declarations::Module
|
|
461
|
+
decl.members
|
|
462
|
+
end
|
|
463
|
+
end
|
|
464
|
+
class_var = members.find do |member|
|
|
459
465
|
member.is_a?(RBS::AST::Members::ClassVariable) && member.name == name
|
|
460
466
|
end
|
|
461
467
|
|
|
@@ -534,8 +540,10 @@ module Steep
|
|
|
534
540
|
location =
|
|
535
541
|
case ancestor.source
|
|
536
542
|
when :super
|
|
537
|
-
primary_decl = env.class_decls.fetch(name).
|
|
538
|
-
primary_decl.is_a?(RBS::AST::Declarations::Class)
|
|
543
|
+
primary_decl = env.class_decls.fetch(name).primary_decl
|
|
544
|
+
unless primary_decl.is_a?(RBS::AST::Declarations::Class) || primary_decl.is_a?(RBS::AST::Ruby::Declarations::ClassDecl)
|
|
545
|
+
raise
|
|
546
|
+
end
|
|
539
547
|
if super_class = primary_decl.super_class
|
|
540
548
|
super_class.location
|
|
541
549
|
else
|
|
@@ -644,13 +652,17 @@ module Steep
|
|
|
644
652
|
end
|
|
645
653
|
|
|
646
654
|
def validate_one_alias(name, entry = env.type_alias_decls.fetch(name))
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
655
|
+
inner_most_outer_module_name = entry.context&.last
|
|
656
|
+
|
|
657
|
+
if inner_most_outer_module_name
|
|
658
|
+
inner_most_outer_module = env.module_class_entry(inner_most_outer_module_name, normalized: true)
|
|
659
|
+
if inner_most_outer_module
|
|
660
|
+
class_type = AST::Types::Name::Singleton.new(name: inner_most_outer_module.name)
|
|
661
|
+
instance_type = AST::Types::Name::Instance.new(
|
|
662
|
+
name: inner_most_outer_module.name,
|
|
663
|
+
args: inner_most_outer_module.type_params.map { AST::Types::Any.instance() },
|
|
664
|
+
)
|
|
665
|
+
end
|
|
654
666
|
end
|
|
655
667
|
|
|
656
668
|
push_context(class_type: class_type, instance_type: instance_type, self_type: nil) do
|
|
@@ -21,7 +21,7 @@ module Steep
|
|
|
21
21
|
last_start = ignore
|
|
22
22
|
when AST::Ignore::IgnoreEnd
|
|
23
23
|
if last_start
|
|
24
|
-
ignored_ranges <<
|
|
24
|
+
ignored_ranges << [last_start, ignore]
|
|
25
25
|
last_start = nil
|
|
26
26
|
else
|
|
27
27
|
error_ignores << ignore
|
|
@@ -40,18 +40,28 @@ module Steep
|
|
|
40
40
|
end
|
|
41
41
|
end
|
|
42
42
|
|
|
43
|
+
def each_ignore(&block)
|
|
44
|
+
if block
|
|
45
|
+
ignored_ranges.each(&block)
|
|
46
|
+
ignored_lines.each_value(&block)
|
|
47
|
+
else
|
|
48
|
+
enum_for(:each_ignore)
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
|
|
43
52
|
def ignore?(start_line, end_line, code)
|
|
44
53
|
if ignore = ignored_lines.fetch(start_line, nil)
|
|
45
|
-
ignore_code?(ignore, code) and return
|
|
54
|
+
ignore_code?(ignore, code) and return ignore
|
|
46
55
|
end
|
|
47
56
|
|
|
48
57
|
if start_line != end_line
|
|
49
58
|
if ignore = ignored_lines.fetch(end_line, nil)
|
|
50
|
-
ignore_code?(ignore, code) and return
|
|
59
|
+
ignore_code?(ignore, code) and return ignore
|
|
51
60
|
end
|
|
52
61
|
end
|
|
53
62
|
|
|
54
|
-
ignored_ranges.
|
|
63
|
+
ignored_ranges.find do |ignore_start, ignore_end|
|
|
64
|
+
range = ignore_start.line..ignore_end.line
|
|
55
65
|
range.cover?(start_line) && range.cover?(end_line)
|
|
56
66
|
end
|
|
57
67
|
end
|
data/lib/steep/source.rb
CHANGED
|
@@ -19,7 +19,7 @@ module Steep
|
|
|
19
19
|
@ignores = ignores
|
|
20
20
|
end
|
|
21
21
|
|
|
22
|
-
class Builder < ::Parser::
|
|
22
|
+
class Builder < Prism::Translation::Parser::Builder
|
|
23
23
|
def string_value(token)
|
|
24
24
|
value(token)
|
|
25
25
|
end
|
|
@@ -31,7 +31,7 @@ module Steep
|
|
|
31
31
|
end
|
|
32
32
|
|
|
33
33
|
def self.new_parser
|
|
34
|
-
::
|
|
34
|
+
Prism::Translation::Parser34.new(Builder.new).tap do |parser|
|
|
35
35
|
parser.diagnostics.all_errors_are_fatal = true
|
|
36
36
|
parser.diagnostics.ignore_warnings = true
|
|
37
37
|
end
|
|
@@ -257,7 +257,7 @@ module Steep
|
|
|
257
257
|
annot.line or next
|
|
258
258
|
|
|
259
259
|
case node.type
|
|
260
|
-
when :def, :module, :class, :block, :numblock, :ensure, :defs, :resbody
|
|
260
|
+
when :def, :module, :class, :block, :numblock, :itblock, :ensure, :defs, :resbody
|
|
261
261
|
location = node.loc
|
|
262
262
|
location.line <= annot.line && annot.line < location.last_line
|
|
263
263
|
else
|
|
@@ -319,6 +319,20 @@ module Steep
|
|
|
319
319
|
end
|
|
320
320
|
end
|
|
321
321
|
|
|
322
|
+
def each_block_annotation(node, &block)
|
|
323
|
+
if block
|
|
324
|
+
if annots = mapping.fetch(node, nil)
|
|
325
|
+
annots.each(&block)
|
|
326
|
+
end
|
|
327
|
+
else
|
|
328
|
+
enum_for :each_block_annotation, node
|
|
329
|
+
end
|
|
330
|
+
end
|
|
331
|
+
|
|
332
|
+
def find_block_node(nodes)
|
|
333
|
+
nodes.find { mapping.key?(_1) }
|
|
334
|
+
end
|
|
335
|
+
|
|
322
336
|
def each_heredoc_node(node = self.node, parents = [], &block)
|
|
323
337
|
if block
|
|
324
338
|
return unless node
|
|
@@ -551,13 +565,13 @@ module Steep
|
|
|
551
565
|
end
|
|
552
566
|
]
|
|
553
567
|
)
|
|
554
|
-
when :numblock
|
|
555
|
-
send,
|
|
568
|
+
when :numblock, :itblock
|
|
569
|
+
send, arg, body = node.children
|
|
556
570
|
node = node.updated(
|
|
557
571
|
nil,
|
|
558
572
|
[
|
|
559
573
|
map_child_node(send) {|child| insert_type_node(child, child_assertions) },
|
|
560
|
-
|
|
574
|
+
arg,
|
|
561
575
|
insert_type_node(body, child_assertions)
|
|
562
576
|
]
|
|
563
577
|
)
|
|
@@ -634,7 +648,7 @@ module Steep
|
|
|
634
648
|
case node.type
|
|
635
649
|
when :send, :csend
|
|
636
650
|
node
|
|
637
|
-
when :block, :numblock
|
|
651
|
+
when :block, :numblock, :itblock
|
|
638
652
|
send = node.children[0]
|
|
639
653
|
case send.type
|
|
640
654
|
when :send, :csend
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
module Steep
|
|
2
|
+
# A basic implementation of ActiveSupport::TaggedLogging.
|
|
3
|
+
# Might be able to be replaced by plain logger in the future.
|
|
4
|
+
# https://github.com/ruby/logger/pull/132
|
|
5
|
+
class TaggedLogging < Logger
|
|
6
|
+
def initialize(...)
|
|
7
|
+
super
|
|
8
|
+
self.formatter = proc do |severity, datetime, progname, msg|
|
|
9
|
+
# @type var severity: String
|
|
10
|
+
# @type var datetime: Time
|
|
11
|
+
# @type var progname: untyped
|
|
12
|
+
# @type var msg: untyped
|
|
13
|
+
# @type block: String
|
|
14
|
+
"#{datetime.strftime('%Y-%m-%d %H:%M:%S.%L')}: #{severity}: #{formatted_tags} #{msg}\n"
|
|
15
|
+
end
|
|
16
|
+
@thread_key = "steep_tagged_logging_tags:#{object_id}"
|
|
17
|
+
current_tags << "Steep #{VERSION}"
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def tagged(tag)
|
|
21
|
+
current_tags << tag
|
|
22
|
+
yield
|
|
23
|
+
ensure
|
|
24
|
+
current_tags.pop
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def current_tags
|
|
28
|
+
Thread.current[@thread_key] ||= []
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def push_tags(*tags)
|
|
32
|
+
current_tags.concat(tags)
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def formatted_tags
|
|
36
|
+
current_tags.map { |tag| "[#{tag}]" }.join(" ")
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
end
|
|
@@ -39,6 +39,10 @@ module Steep
|
|
|
39
39
|
|
|
40
40
|
SPECIAL_LVAR_NAMES = Set[:_, :__any__, :__skip__]
|
|
41
41
|
|
|
42
|
+
# a synthetic variable name for anonymous block params (can't conflict with
|
|
43
|
+
# user variables since Ruby doesn't allow * in local variable names).
|
|
44
|
+
ANONYMOUS_BLOCK_PASSABLE_LVAR = :"*block"
|
|
45
|
+
|
|
42
46
|
include ModuleHelper
|
|
43
47
|
|
|
44
48
|
attr_reader :checker
|
|
@@ -212,13 +216,21 @@ module Steep
|
|
|
212
216
|
TypeInference::MethodParams.empty(node: node)
|
|
213
217
|
end
|
|
214
218
|
|
|
219
|
+
block_param_name = nil #: Symbol?
|
|
220
|
+
method_params.each_param do |param|
|
|
221
|
+
if param.is_a?(TypeInference::MethodParams::BlockParameter)
|
|
222
|
+
block_param_name = param.name || ANONYMOUS_BLOCK_PASSABLE_LVAR
|
|
223
|
+
end
|
|
224
|
+
end
|
|
225
|
+
|
|
215
226
|
method_context = TypeInference::Context::MethodContext.new(
|
|
216
227
|
name: method_name,
|
|
217
228
|
method: definition && definition.methods[method_name],
|
|
218
229
|
method_type: method_type,
|
|
219
230
|
return_type: annots.return_type || method_type&.type&.return_type || AST::Builtin.any_type,
|
|
220
231
|
super_method: super_method,
|
|
221
|
-
forward_arg_type: method_params.forward_arg_type
|
|
232
|
+
forward_arg_type: method_params.forward_arg_type,
|
|
233
|
+
block_param_name: block_param_name
|
|
222
234
|
)
|
|
223
235
|
|
|
224
236
|
local_variable_types = method_params.each_param.with_object({}) do |param, hash| #$ Hash[Symbol, AST::Types::t]
|
|
@@ -226,6 +238,8 @@ module Steep
|
|
|
226
238
|
unless SPECIAL_LVAR_NAMES.include?(param.name)
|
|
227
239
|
hash[param.name] = param.var_type
|
|
228
240
|
end
|
|
241
|
+
elsif param.is_a?(TypeInference::MethodParams::BlockParameter)
|
|
242
|
+
hash[ANONYMOUS_BLOCK_PASSABLE_LVAR] = param.var_type
|
|
229
243
|
end
|
|
230
244
|
end
|
|
231
245
|
type_env = context.type_env.assign_local_variables(local_variable_types)
|
|
@@ -368,7 +382,7 @@ module Steep
|
|
|
368
382
|
end
|
|
369
383
|
|
|
370
384
|
if implement_module_name
|
|
371
|
-
module_entry = checker.factory.definition_builder.env.
|
|
385
|
+
module_entry = checker.factory.definition_builder.env.module_entry(implement_module_name.name, normalized: true)
|
|
372
386
|
if module_entry
|
|
373
387
|
module_context = module_context.update(
|
|
374
388
|
instance_type: AST::Types::Intersection.build(
|
|
@@ -397,7 +411,7 @@ module Steep
|
|
|
397
411
|
].compact
|
|
398
412
|
)
|
|
399
413
|
)
|
|
400
|
-
elsif checker.factory.definition_builder.env.
|
|
414
|
+
elsif checker.factory.definition_builder.env.class_entry(implement_module_name.name, normalized:true)
|
|
401
415
|
typing.add_error(
|
|
402
416
|
Diagnostic::Ruby::ClassModuleMismatch.new(node: node, name: new_module_name)
|
|
403
417
|
)
|
|
@@ -489,8 +503,8 @@ module Steep
|
|
|
489
503
|
module_context = module_context.update(instance_definition: nil, module_definition: nil)
|
|
490
504
|
end
|
|
491
505
|
|
|
492
|
-
if !checker.factory.definition_builder.env.
|
|
493
|
-
checker.factory.definition_builder.env.
|
|
506
|
+
if !checker.factory.definition_builder.env.class_entry(implement_module_name.name, normalized: true) &&
|
|
507
|
+
checker.factory.definition_builder.env.module_entry(implement_module_name.name, normalized: true)
|
|
494
508
|
typing.add_error(
|
|
495
509
|
Diagnostic::Ruby::ClassModuleMismatch.new(node: node, name: new_class_name)
|
|
496
510
|
)
|
|
@@ -1355,7 +1369,7 @@ module Steep
|
|
|
1355
1369
|
yield_self do
|
|
1356
1370
|
var = node.children[0]
|
|
1357
1371
|
|
|
1358
|
-
if SPECIAL_LVAR_NAMES.include?(var)
|
|
1372
|
+
if !var || SPECIAL_LVAR_NAMES.include?(var)
|
|
1359
1373
|
return add_typing(node, type: AST::Builtin.any_type)
|
|
1360
1374
|
end
|
|
1361
1375
|
|
|
@@ -1376,7 +1390,7 @@ module Steep
|
|
|
1376
1390
|
yield_self do
|
|
1377
1391
|
var = node.children[0]
|
|
1378
1392
|
|
|
1379
|
-
if SPECIAL_LVAR_NAMES.include?(var)
|
|
1393
|
+
if !var || SPECIAL_LVAR_NAMES.include?(var)
|
|
1380
1394
|
return add_typing(node, type: AST::Builtin.any_type)
|
|
1381
1395
|
end
|
|
1382
1396
|
|
|
@@ -1442,7 +1456,7 @@ module Steep
|
|
|
1442
1456
|
|
|
1443
1457
|
case
|
|
1444
1458
|
when hint && check_relation(sub_type: ty, super_type: hint).success? && !hint.is_a?(AST::Types::Any) && !hint.is_a?(AST::Types::Top)
|
|
1445
|
-
add_typing(node, type: hint)
|
|
1459
|
+
add_typing(node, type: unwrap(hint))
|
|
1446
1460
|
when condition
|
|
1447
1461
|
add_typing(node, type: ty)
|
|
1448
1462
|
else
|
|
@@ -1670,7 +1684,7 @@ module Steep
|
|
|
1670
1684
|
end
|
|
1671
1685
|
|
|
1672
1686
|
when :yield
|
|
1673
|
-
if method_context && method_context.method_type
|
|
1687
|
+
if method_context && (method_type = method_context.method_type)
|
|
1674
1688
|
if block_type = method_context.block_type
|
|
1675
1689
|
if block_type.type.params
|
|
1676
1690
|
type = AST::Types::Proc.new(
|
|
@@ -1701,9 +1715,12 @@ module Steep
|
|
|
1701
1715
|
end
|
|
1702
1716
|
|
|
1703
1717
|
add_typing(node, type: block_type.type.return_type)
|
|
1704
|
-
|
|
1718
|
+
elsif method_type.type.params
|
|
1705
1719
|
typing.add_error(Diagnostic::Ruby::UnexpectedYield.new(node: node))
|
|
1706
1720
|
fallback_to_any node
|
|
1721
|
+
else
|
|
1722
|
+
constr = type_check_untyped_args(node.children)
|
|
1723
|
+
add_typing(node, type: AST::Builtin.any_type)
|
|
1707
1724
|
end
|
|
1708
1725
|
else
|
|
1709
1726
|
fallback_to_any node
|
|
@@ -1733,7 +1750,7 @@ module Steep
|
|
|
1733
1750
|
if hint
|
|
1734
1751
|
array = AST::Builtin::Array.instance_type(AST::Builtin.any_type)
|
|
1735
1752
|
if check_relation(sub_type: array, super_type: hint).success?
|
|
1736
|
-
add_typing node, type: hint
|
|
1753
|
+
add_typing node, type: unwrap(hint)
|
|
1737
1754
|
else
|
|
1738
1755
|
add_typing node, type: array
|
|
1739
1756
|
end
|
|
@@ -1745,13 +1762,18 @@ module Steep
|
|
|
1745
1762
|
if hint
|
|
1746
1763
|
tuples = select_flatten_types(hint) {|type| type.is_a?(AST::Types::Tuple) } #: Array[AST::Types::Tuple]
|
|
1747
1764
|
unless tuples.empty?
|
|
1765
|
+
fallback_pair = nil #: Pair?
|
|
1748
1766
|
tuples.each do |tuple|
|
|
1749
1767
|
typing.new_child() do |child_typing|
|
|
1750
1768
|
if pair = with_new_typing(child_typing).try_tuple_type(node, tuple)
|
|
1751
|
-
|
|
1769
|
+
if pair.constr.check_relation(sub_type: pair.type, super_type: tuple).success?
|
|
1770
|
+
return pair.with(constr: pair.constr.save_typing)
|
|
1771
|
+
end
|
|
1772
|
+
fallback_pair ||= pair.with(constr: pair.constr.save_typing)
|
|
1752
1773
|
end
|
|
1753
1774
|
end
|
|
1754
1775
|
end
|
|
1776
|
+
return fallback_pair if fallback_pair
|
|
1755
1777
|
end
|
|
1756
1778
|
end
|
|
1757
1779
|
|
|
@@ -2192,7 +2214,10 @@ module Steep
|
|
|
2192
2214
|
yield_self do
|
|
2193
2215
|
body, ensure_body = node.children
|
|
2194
2216
|
body_type = synthesize(body).type if body
|
|
2195
|
-
|
|
2217
|
+
if ensure_body
|
|
2218
|
+
ensure_constr = for_branch(node)
|
|
2219
|
+
ensure_constr.synthesize(ensure_body)
|
|
2220
|
+
end
|
|
2196
2221
|
if body_type
|
|
2197
2222
|
add_typing(node, type: body_type)
|
|
2198
2223
|
else
|
|
@@ -2505,7 +2530,9 @@ module Steep
|
|
|
2505
2530
|
end
|
|
2506
2531
|
else
|
|
2507
2532
|
# Anonymous block_pass only happens inside method definition
|
|
2508
|
-
if
|
|
2533
|
+
if (type = context.type_env[ANONYMOUS_BLOCK_PASSABLE_LVAR])
|
|
2534
|
+
# Use type from type_env (may have been narrowed by block_given?)
|
|
2535
|
+
elsif block_type = method_context!.block_type
|
|
2509
2536
|
type = AST::Types::Proc.new(
|
|
2510
2537
|
type: block_type.type,
|
|
2511
2538
|
block: nil,
|
|
@@ -2669,7 +2696,7 @@ module Steep
|
|
|
2669
2696
|
constr.add_typing(node, type: type)
|
|
2670
2697
|
end
|
|
2671
2698
|
|
|
2672
|
-
when :block, :numblock, :send, :csend
|
|
2699
|
+
when :block, :numblock, :itblock, :send, :csend
|
|
2673
2700
|
synthesize_sendish(node, hint: hint, tapp: nil)
|
|
2674
2701
|
|
|
2675
2702
|
when :forwarded_args, :forward_arg
|
|
@@ -2687,7 +2714,6 @@ module Steep
|
|
|
2687
2714
|
end
|
|
2688
2715
|
end
|
|
2689
2716
|
rescue RBS::BaseError => exn
|
|
2690
|
-
Steep.logger.warn("hello")
|
|
2691
2717
|
Steep.logger.warn { "Unexpected RBS error: #{exn.message}" }
|
|
2692
2718
|
exn.backtrace&.each {|loc| Steep.logger.warn " #{loc}" }
|
|
2693
2719
|
typing.add_error(Diagnostic::Ruby::UnexpectedError.new(node: node, error: exn))
|
|
@@ -2746,6 +2772,20 @@ module Steep
|
|
|
2746
2772
|
|
|
2747
2773
|
params = Parser::AST::Node.new(:args, arg_nodes)
|
|
2748
2774
|
|
|
2775
|
+
if send_node.type == :lambda
|
|
2776
|
+
# @type var node: Parser::AST::Node & Parser::AST::_BlockNode
|
|
2777
|
+
type_lambda(node, params_node: params, body_node: body, type_hint: hint)
|
|
2778
|
+
else
|
|
2779
|
+
type_send(node, send_node: send_node, block_params: params, block_body: body, unwrap: send_node.type == :csend, tapp: tapp, hint: hint)
|
|
2780
|
+
end
|
|
2781
|
+
end
|
|
2782
|
+
when :itblock
|
|
2783
|
+
yield_self do
|
|
2784
|
+
send_node, _name, body = node.children
|
|
2785
|
+
|
|
2786
|
+
arg_nodes = [Parser::AST::Node.new(:procarg0, [:it])]
|
|
2787
|
+
params = Parser::AST::Node.new(:args, arg_nodes)
|
|
2788
|
+
|
|
2749
2789
|
if send_node.type == :lambda
|
|
2750
2790
|
# @type var node: Parser::AST::Node & Parser::AST::_BlockNode
|
|
2751
2791
|
type_lambda(node, params_node: params, body_node: body, type_hint: hint)
|
|
@@ -3225,6 +3265,8 @@ module Steep
|
|
|
3225
3265
|
MethodName("::Hash#[]")
|
|
3226
3266
|
]
|
|
3227
3267
|
|
|
3268
|
+
KERNEL_BLOCK_GIVEN = MethodName("::Kernel#block_given?")
|
|
3269
|
+
|
|
3228
3270
|
def pure_send?(call, receiver, arguments)
|
|
3229
3271
|
return false unless call.node.type == :send || call.node.type == :csend
|
|
3230
3272
|
return false unless call.pure? || KNOWN_PURE_METHODS.superset?(Set.new(call.method_decls.map(&:method_name)))
|
|
@@ -3318,7 +3360,7 @@ module Steep
|
|
|
3318
3360
|
end
|
|
3319
3361
|
end
|
|
3320
3362
|
|
|
3321
|
-
if node.type == :csend || ((node.type == :block || node.type == :numblock) && node.children[0].type == :csend)
|
|
3363
|
+
if node.type == :csend || ((node.type == :block || node.type == :numblock || node.type == :itblock) && node.children[0].type == :csend)
|
|
3322
3364
|
optional_type = AST::Types::Union.build(types: [call.return_type, AST::Builtin.nil_type])
|
|
3323
3365
|
call = call.with_return_type(optional_type)
|
|
3324
3366
|
end
|
|
@@ -3364,6 +3406,34 @@ module Steep
|
|
|
3364
3406
|
)
|
|
3365
3407
|
end
|
|
3366
3408
|
|
|
3409
|
+
# Handle block_given? type narrowing
|
|
3410
|
+
if method_name == :block_given? && call.is_a?(TypeInference::MethodCall::Typed)
|
|
3411
|
+
if call.method_decls.all? { _1.method_name == KERNEL_BLOCK_GIVEN }
|
|
3412
|
+
if (block_var = constr.method_context&.block_param_name)
|
|
3413
|
+
if (var_type = constr.context.type_env[block_var])
|
|
3414
|
+
unwrapped = constr.checker.factory.unwrap_optional(var_type)
|
|
3415
|
+
|
|
3416
|
+
if unwrapped
|
|
3417
|
+
truthy_env = constr.context.type_env.refine_types(
|
|
3418
|
+
local_variable_types: { block_var => unwrapped }
|
|
3419
|
+
)
|
|
3420
|
+
falsy_env = constr.context.type_env.refine_types(
|
|
3421
|
+
local_variable_types: { block_var => AST::Builtin.nil_type }
|
|
3422
|
+
)
|
|
3423
|
+
|
|
3424
|
+
env_type = AST::Types::Logic::Env.new(
|
|
3425
|
+
truthy: truthy_env,
|
|
3426
|
+
falsy: falsy_env,
|
|
3427
|
+
type: call.return_type
|
|
3428
|
+
)
|
|
3429
|
+
|
|
3430
|
+
call = call.with_return_type(env_type)
|
|
3431
|
+
end
|
|
3432
|
+
end
|
|
3433
|
+
end
|
|
3434
|
+
end
|
|
3435
|
+
end
|
|
3436
|
+
|
|
3367
3437
|
constr.add_call(call)
|
|
3368
3438
|
else
|
|
3369
3439
|
skips = [] #: Array[Parser::AST::Node?]
|
|
@@ -3453,7 +3523,7 @@ module Steep
|
|
|
3453
3523
|
|
|
3454
3524
|
when AST::Types::Any
|
|
3455
3525
|
case node.type
|
|
3456
|
-
when :block, :numblock
|
|
3526
|
+
when :block, :numblock, :itblock
|
|
3457
3527
|
# @type var node: Parser::AST::Node & Parser::AST::_BlockNode
|
|
3458
3528
|
block_annotations = source.annotations(block: node, factory: checker.factory, context: nesting)
|
|
3459
3529
|
block_params or raise
|
|
@@ -4710,8 +4780,15 @@ module Steep
|
|
|
4710
4780
|
|
|
4711
4781
|
def validate_method_definitions(node, module_name)
|
|
4712
4782
|
module_name_1 = module_name.name
|
|
4713
|
-
module_entry = checker.factory.env.
|
|
4714
|
-
member_decl_count = module_entry.
|
|
4783
|
+
module_entry = checker.factory.env.module_class_entry(module_name_1, normalized: true) or raise
|
|
4784
|
+
member_decl_count = module_entry.each_decl.count do |decl|
|
|
4785
|
+
case decl
|
|
4786
|
+
when RBS::AST::Declarations::Base
|
|
4787
|
+
decl.each_member.count > 0
|
|
4788
|
+
else
|
|
4789
|
+
false
|
|
4790
|
+
end
|
|
4791
|
+
end
|
|
4715
4792
|
|
|
4716
4793
|
return unless member_decl_count == 1
|
|
4717
4794
|
|
|
@@ -4878,7 +4955,7 @@ module Steep
|
|
|
4878
4955
|
else
|
|
4879
4956
|
literal_type = AST::Types::Literal.new(value: literal)
|
|
4880
4957
|
if check_relation(sub_type: literal_type, super_type: hint).success?
|
|
4881
|
-
hint
|
|
4958
|
+
unwrap(hint)
|
|
4882
4959
|
end
|
|
4883
4960
|
end
|
|
4884
4961
|
end
|
|
@@ -4887,7 +4964,7 @@ module Steep
|
|
|
4887
4964
|
def to_instance_type(type, args: nil)
|
|
4888
4965
|
args = args || case type
|
|
4889
4966
|
when AST::Types::Name::Singleton
|
|
4890
|
-
decl = checker.factory.env.
|
|
4967
|
+
decl = checker.factory.env.module_class_entry(type.name, normalized: true) or raise
|
|
4891
4968
|
decl.type_params.each.map { AST::Builtin.any_type }
|
|
4892
4969
|
else
|
|
4893
4970
|
raise "unexpected type to to_instance_type: #{type}"
|
|
@@ -5295,9 +5372,19 @@ module Steep
|
|
|
5295
5372
|
annotations =
|
|
5296
5373
|
case entry
|
|
5297
5374
|
when RBS::Environment::ModuleEntry, RBS::Environment::ClassEntry
|
|
5298
|
-
entry.
|
|
5375
|
+
entry.each_decl.flat_map do |decl|
|
|
5376
|
+
if decl.is_a?(RBS::AST::Declarations::Base)
|
|
5377
|
+
decl.annotations
|
|
5378
|
+
else
|
|
5379
|
+
[]
|
|
5380
|
+
end
|
|
5381
|
+
end
|
|
5299
5382
|
when RBS::Environment::ConstantEntry, RBS::Environment::ClassAliasEntry, RBS::Environment::ModuleAliasEntry
|
|
5300
|
-
entry.decl.
|
|
5383
|
+
if entry.decl.is_a?(RBS::AST::Declarations::Base)
|
|
5384
|
+
entry.decl.annotations
|
|
5385
|
+
else
|
|
5386
|
+
[] #: Array[RBS::AST::Annotation]
|
|
5387
|
+
end
|
|
5301
5388
|
end
|
|
5302
5389
|
|
|
5303
5390
|
if annotations
|
|
@@ -101,13 +101,13 @@ module Steep
|
|
|
101
101
|
end
|
|
102
102
|
|
|
103
103
|
def params
|
|
104
|
-
[]
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
104
|
+
params = [] #: Array[Param | MultipleParam]
|
|
105
|
+
params.push(*leading_params)
|
|
106
|
+
params.push(*optional_params)
|
|
107
|
+
params.push rest_param if rest_param
|
|
108
|
+
params.push(*trailing_params)
|
|
109
|
+
params.push(block_param) if block_param
|
|
110
|
+
params
|
|
111
111
|
end
|
|
112
112
|
|
|
113
113
|
def self.from_node(node, annotations:)
|
|
@@ -8,14 +8,16 @@ module Steep
|
|
|
8
8
|
attr_reader :return_type
|
|
9
9
|
attr_reader :super_method
|
|
10
10
|
attr_reader :forward_arg_type
|
|
11
|
+
attr_reader :block_param_name
|
|
11
12
|
|
|
12
|
-
def initialize(name:, method:, method_type:, return_type:, super_method:, forward_arg_type:)
|
|
13
|
+
def initialize(name:, method:, method_type:, return_type:, super_method:, forward_arg_type:, block_param_name: nil)
|
|
13
14
|
@name = name
|
|
14
15
|
@method = method
|
|
15
16
|
@return_type = return_type
|
|
16
17
|
@method_type = method_type
|
|
17
18
|
@super_method = super_method
|
|
18
19
|
@forward_arg_type = forward_arg_type
|
|
20
|
+
@block_param_name = block_param_name
|
|
19
21
|
end
|
|
20
22
|
|
|
21
23
|
def block_type
|
|
@@ -174,7 +176,7 @@ module Steep
|
|
|
174
176
|
block_context: block_context,
|
|
175
177
|
break_context: break_context,
|
|
176
178
|
module_context: module_context,
|
|
177
|
-
self_type: self_type,
|
|
179
|
+
self_type: self_type, # steep:ignore ArgumentTypeMismatch
|
|
178
180
|
type_env: type_env,
|
|
179
181
|
call_context: call_context,
|
|
180
182
|
variable_context: variable_context
|
|
@@ -344,6 +344,22 @@ module Steep
|
|
|
344
344
|
falsy_result = Result.new(type: FALSE, env: falsy_env, unreachable: false)
|
|
345
345
|
falsy_result.unreachable! unless falsy_type
|
|
346
346
|
|
|
347
|
+
[truthy_result, falsy_result]
|
|
348
|
+
elsif (truthy_types, falsy_types = literal_var_type_case_select(arg, receiver_type, for_receiver: true))
|
|
349
|
+
# Handle literal equality: receiver == literal_value
|
|
350
|
+
truthy_env, falsy_env = refine_node_type(
|
|
351
|
+
env: env,
|
|
352
|
+
node: receiver,
|
|
353
|
+
truthy_type: truthy_types.empty? ? BOT : AST::Types::Union.build(types: truthy_types),
|
|
354
|
+
falsy_type: falsy_types.empty? ? BOT : AST::Types::Union.build(types: falsy_types)
|
|
355
|
+
)
|
|
356
|
+
|
|
357
|
+
truthy_result = Result.new(type: TRUE, env: truthy_env, unreachable: false)
|
|
358
|
+
truthy_result.unreachable! if truthy_types.empty?
|
|
359
|
+
|
|
360
|
+
falsy_result = Result.new(type: FALSE, env: falsy_env, unreachable: false)
|
|
361
|
+
falsy_result.unreachable! if falsy_types.empty?
|
|
362
|
+
|
|
347
363
|
[truthy_result, falsy_result]
|
|
348
364
|
end
|
|
349
365
|
end
|
|
@@ -493,7 +509,7 @@ module Steep
|
|
|
493
509
|
end
|
|
494
510
|
end
|
|
495
511
|
|
|
496
|
-
def literal_var_type_case_select(value_node, arg_type)
|
|
512
|
+
def literal_var_type_case_select(value_node, arg_type, for_receiver: false)
|
|
497
513
|
case arg_type
|
|
498
514
|
when AST::Types::Union
|
|
499
515
|
# @type var truthy_types: Array[AST::Types::t]
|
|
@@ -502,7 +518,7 @@ module Steep
|
|
|
502
518
|
falsy_types = []
|
|
503
519
|
|
|
504
520
|
arg_type.types.each do |type|
|
|
505
|
-
if (ts, fs = literal_var_type_case_select(value_node, type))
|
|
521
|
+
if (ts, fs = literal_var_type_case_select(value_node, type, for_receiver: for_receiver))
|
|
506
522
|
truthy_types.push(*ts)
|
|
507
523
|
falsy_types.push(*fs)
|
|
508
524
|
else
|
|
@@ -548,7 +564,12 @@ module Steep
|
|
|
548
564
|
false_types << type
|
|
549
565
|
end
|
|
550
566
|
else
|
|
551
|
-
|
|
567
|
+
# For `==`, narrow only when the literal can be a value of `type`.
|
|
568
|
+
# e.g. `Symbol == :fatal` can be true, but `SomeClass == :fatal` cannot.
|
|
569
|
+
literal_type = AST::Types::Literal.new(value: value_node.children[0])
|
|
570
|
+
if !for_receiver || subtyping?(sub_type: literal_type, super_type: type)
|
|
571
|
+
true_types << literal_type
|
|
572
|
+
end
|
|
552
573
|
false_types << type
|
|
553
574
|
end
|
|
554
575
|
end
|