steep 1.10.0 → 2.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +84 -1
- data/CLAUDE.md +114 -0
- data/README.md +1 -1
- data/Rakefile +15 -3
- data/Steepfile +13 -13
- 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 +50 -8
- 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/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 +123 -64
- data/lib/steep/services/hover_provider/singleton_methods.rb +4 -0
- 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 +16 -2
- data/lib/steep/tagged_logging.rb +39 -0
- data/lib/steep/type_construction.rb +94 -21
- 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 +21 -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 +0 -2
- 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 +26 -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::Parser33.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
|
|
@@ -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
|
|
@@ -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,
|
|
@@ -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))
|
|
@@ -3225,6 +3251,8 @@ module Steep
|
|
|
3225
3251
|
MethodName("::Hash#[]")
|
|
3226
3252
|
]
|
|
3227
3253
|
|
|
3254
|
+
KERNEL_BLOCK_GIVEN = MethodName("::Kernel#block_given?")
|
|
3255
|
+
|
|
3228
3256
|
def pure_send?(call, receiver, arguments)
|
|
3229
3257
|
return false unless call.node.type == :send || call.node.type == :csend
|
|
3230
3258
|
return false unless call.pure? || KNOWN_PURE_METHODS.superset?(Set.new(call.method_decls.map(&:method_name)))
|
|
@@ -3364,6 +3392,34 @@ module Steep
|
|
|
3364
3392
|
)
|
|
3365
3393
|
end
|
|
3366
3394
|
|
|
3395
|
+
# Handle block_given? type narrowing
|
|
3396
|
+
if method_name == :block_given? && call.is_a?(TypeInference::MethodCall::Typed)
|
|
3397
|
+
if call.method_decls.all? { _1.method_name == KERNEL_BLOCK_GIVEN }
|
|
3398
|
+
if (block_var = constr.method_context&.block_param_name)
|
|
3399
|
+
if (var_type = constr.context.type_env[block_var])
|
|
3400
|
+
unwrapped = constr.checker.factory.unwrap_optional(var_type)
|
|
3401
|
+
|
|
3402
|
+
if unwrapped
|
|
3403
|
+
truthy_env = constr.context.type_env.refine_types(
|
|
3404
|
+
local_variable_types: { block_var => unwrapped }
|
|
3405
|
+
)
|
|
3406
|
+
falsy_env = constr.context.type_env.refine_types(
|
|
3407
|
+
local_variable_types: { block_var => AST::Builtin.nil_type }
|
|
3408
|
+
)
|
|
3409
|
+
|
|
3410
|
+
env_type = AST::Types::Logic::Env.new(
|
|
3411
|
+
truthy: truthy_env,
|
|
3412
|
+
falsy: falsy_env,
|
|
3413
|
+
type: call.return_type
|
|
3414
|
+
)
|
|
3415
|
+
|
|
3416
|
+
call = call.with_return_type(env_type)
|
|
3417
|
+
end
|
|
3418
|
+
end
|
|
3419
|
+
end
|
|
3420
|
+
end
|
|
3421
|
+
end
|
|
3422
|
+
|
|
3367
3423
|
constr.add_call(call)
|
|
3368
3424
|
else
|
|
3369
3425
|
skips = [] #: Array[Parser::AST::Node?]
|
|
@@ -4710,8 +4766,15 @@ module Steep
|
|
|
4710
4766
|
|
|
4711
4767
|
def validate_method_definitions(node, module_name)
|
|
4712
4768
|
module_name_1 = module_name.name
|
|
4713
|
-
module_entry = checker.factory.env.
|
|
4714
|
-
member_decl_count = module_entry.
|
|
4769
|
+
module_entry = checker.factory.env.module_class_entry(module_name_1, normalized: true) or raise
|
|
4770
|
+
member_decl_count = module_entry.each_decl.count do |decl|
|
|
4771
|
+
case decl
|
|
4772
|
+
when RBS::AST::Declarations::Base
|
|
4773
|
+
decl.each_member.count > 0
|
|
4774
|
+
else
|
|
4775
|
+
false
|
|
4776
|
+
end
|
|
4777
|
+
end
|
|
4715
4778
|
|
|
4716
4779
|
return unless member_decl_count == 1
|
|
4717
4780
|
|
|
@@ -4878,7 +4941,7 @@ module Steep
|
|
|
4878
4941
|
else
|
|
4879
4942
|
literal_type = AST::Types::Literal.new(value: literal)
|
|
4880
4943
|
if check_relation(sub_type: literal_type, super_type: hint).success?
|
|
4881
|
-
hint
|
|
4944
|
+
unwrap(hint)
|
|
4882
4945
|
end
|
|
4883
4946
|
end
|
|
4884
4947
|
end
|
|
@@ -4887,7 +4950,7 @@ module Steep
|
|
|
4887
4950
|
def to_instance_type(type, args: nil)
|
|
4888
4951
|
args = args || case type
|
|
4889
4952
|
when AST::Types::Name::Singleton
|
|
4890
|
-
decl = checker.factory.env.
|
|
4953
|
+
decl = checker.factory.env.module_class_entry(type.name, normalized: true) or raise
|
|
4891
4954
|
decl.type_params.each.map { AST::Builtin.any_type }
|
|
4892
4955
|
else
|
|
4893
4956
|
raise "unexpected type to to_instance_type: #{type}"
|
|
@@ -5295,9 +5358,19 @@ module Steep
|
|
|
5295
5358
|
annotations =
|
|
5296
5359
|
case entry
|
|
5297
5360
|
when RBS::Environment::ModuleEntry, RBS::Environment::ClassEntry
|
|
5298
|
-
entry.
|
|
5361
|
+
entry.each_decl.flat_map do |decl|
|
|
5362
|
+
if decl.is_a?(RBS::AST::Declarations::Base)
|
|
5363
|
+
decl.annotations
|
|
5364
|
+
else
|
|
5365
|
+
[]
|
|
5366
|
+
end
|
|
5367
|
+
end
|
|
5299
5368
|
when RBS::Environment::ConstantEntry, RBS::Environment::ClassAliasEntry, RBS::Environment::ModuleAliasEntry
|
|
5300
|
-
entry.decl.
|
|
5369
|
+
if entry.decl.is_a?(RBS::AST::Declarations::Base)
|
|
5370
|
+
entry.decl.annotations
|
|
5371
|
+
else
|
|
5372
|
+
[] #: Array[RBS::AST::Annotation]
|
|
5373
|
+
end
|
|
5301
5374
|
end
|
|
5302
5375
|
|
|
5303
5376
|
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,9 @@ module Steep
|
|
|
548
564
|
false_types << type
|
|
549
565
|
end
|
|
550
566
|
else
|
|
551
|
-
|
|
567
|
+
# For === (for_receiver: false), non-literal types can match the literal in truthy branch
|
|
568
|
+
# For == (for_receiver: true), non-literal types only go to falsy branch
|
|
569
|
+
true_types << AST::Types::Literal.new(value: value_node.children[0]) unless for_receiver
|
|
552
570
|
false_types << type
|
|
553
571
|
end
|
|
554
572
|
end
|
|
@@ -42,6 +42,8 @@ module Steep
|
|
|
42
42
|
end
|
|
43
43
|
|
|
44
44
|
TopLevelContext = _ = Class.new() do
|
|
45
|
+
# @implements TopLevelContext
|
|
46
|
+
|
|
45
47
|
def to_s
|
|
46
48
|
"@<main>"
|
|
47
49
|
end
|
|
@@ -58,6 +60,8 @@ module Steep
|
|
|
58
60
|
end
|
|
59
61
|
|
|
60
62
|
UnknownContext = _ = Class.new() do
|
|
63
|
+
# @implements UnknownContext
|
|
64
|
+
|
|
61
65
|
def to_s
|
|
62
66
|
"@<unknown>"
|
|
63
67
|
end
|
|
@@ -150,7 +150,7 @@ module Steep
|
|
|
150
150
|
pure_call_updates = pure_node_invalidation(invalidated_nodes)
|
|
151
151
|
|
|
152
152
|
pure_call_types.each do |node, type|
|
|
153
|
-
call, _ = pure_call_updates
|
|
153
|
+
call, _ = pure_call_updates.fetch(node)
|
|
154
154
|
pure_call_updates[node] = [call, type]
|
|
155
155
|
end
|
|
156
156
|
|
data/lib/steep/typing.rb
CHANGED
data/lib/steep/version.rb
CHANGED