steep 0.44.0 → 0.47.0
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 +8 -0
- data/.github/workflows/ruby.yml +3 -2
- data/.gitignore +0 -1
- data/CHANGELOG.md +42 -0
- data/Gemfile +0 -3
- data/Gemfile.lock +75 -0
- data/README.md +2 -1
- data/lib/steep/annotation_parser.rb +1 -1
- data/lib/steep/ast/builtin.rb +7 -1
- data/lib/steep/ast/types/factory.rb +19 -25
- data/lib/steep/cli.rb +7 -1
- data/lib/steep/diagnostic/lsp_formatter.rb +59 -6
- data/lib/steep/diagnostic/ruby.rb +188 -60
- data/lib/steep/diagnostic/signature.rb +38 -15
- data/lib/steep/drivers/check.rb +3 -0
- data/lib/steep/drivers/init.rb +10 -3
- data/lib/steep/drivers/utils/driver_helper.rb +15 -0
- data/lib/steep/drivers/validate.rb +1 -1
- data/lib/steep/drivers/watch.rb +3 -0
- data/lib/steep/equatable.rb +21 -0
- data/lib/steep/interface/function.rb +798 -579
- data/lib/steep/project/dsl.rb +135 -36
- data/lib/steep/project/options.rb +13 -53
- data/lib/steep/project/target.rb +22 -8
- data/lib/steep/server/interaction_worker.rb +245 -26
- data/lib/steep/server/master.rb +2 -2
- data/lib/steep/server/type_check_worker.rb +6 -9
- data/lib/steep/services/file_loader.rb +26 -19
- data/lib/steep/services/goto_service.rb +1 -0
- data/lib/steep/services/hover_content.rb +135 -80
- data/lib/steep/source.rb +12 -11
- data/lib/steep/type_construction.rb +435 -502
- data/lib/steep/type_inference/block_params.rb +3 -6
- data/lib/steep/type_inference/method_params.rb +483 -0
- data/lib/steep/type_inference/send_args.rb +599 -128
- data/lib/steep/typing.rb +46 -21
- data/lib/steep/version.rb +1 -1
- data/lib/steep.rb +4 -2
- data/sample/Steepfile +10 -3
- data/smoke/alias/Steepfile +2 -1
- data/smoke/and/Steepfile +2 -1
- data/smoke/array/Steepfile +2 -1
- data/smoke/array/test_expectations.yml +3 -3
- data/smoke/block/Steepfile +2 -2
- data/smoke/block/c.rb +0 -1
- data/smoke/case/Steepfile +2 -1
- data/smoke/class/Steepfile +2 -1
- data/smoke/class/test_expectations.yml +12 -15
- data/smoke/const/Steepfile +2 -1
- data/smoke/diagnostics/Steepfile +2 -1
- data/smoke/diagnostics/different_method_parameter_kind.rb +9 -0
- data/smoke/diagnostics/method_arity_mismatch.rb +2 -2
- data/smoke/diagnostics/method_parameter_mismatch.rb +10 -0
- data/smoke/diagnostics/test_expectations.yml +108 -31
- data/smoke/diagnostics-rbs/Steepfile +1 -1
- data/smoke/diagnostics-rbs/mixin-class-error.rbs +6 -0
- data/smoke/diagnostics-rbs/test_expectations.yml +12 -0
- data/smoke/diagnostics-rbs-duplicated/Steepfile +2 -1
- data/smoke/diagnostics-ruby-unsat/Steepfile +2 -1
- data/smoke/dstr/Steepfile +2 -1
- data/smoke/ensure/Steepfile +2 -1
- data/smoke/ensure/test_expectations.yml +3 -3
- data/smoke/enumerator/Steepfile +2 -1
- data/smoke/enumerator/test_expectations.yml +1 -1
- data/smoke/extension/Steepfile +2 -1
- data/smoke/extension/e.rbs +1 -1
- data/smoke/hash/Steepfile +2 -1
- data/smoke/hello/Steepfile +2 -1
- data/smoke/if/Steepfile +2 -1
- data/smoke/implements/Steepfile +2 -1
- data/smoke/initialize/Steepfile +2 -1
- data/smoke/integer/Steepfile +2 -1
- data/smoke/interface/Steepfile +2 -1
- data/smoke/kwbegin/Steepfile +2 -1
- data/smoke/lambda/Steepfile +2 -1
- data/smoke/literal/Steepfile +2 -1
- data/smoke/literal/test_expectations.yml +2 -2
- data/smoke/map/Steepfile +2 -1
- data/smoke/method/Steepfile +2 -1
- data/smoke/method/test_expectations.yml +11 -10
- data/smoke/module/Steepfile +2 -1
- data/smoke/regexp/Steepfile +2 -1
- data/smoke/regression/Steepfile +2 -1
- data/smoke/rescue/Steepfile +2 -1
- data/smoke/rescue/test_expectations.yml +3 -3
- data/smoke/self/Steepfile +2 -1
- data/smoke/skip/Steepfile +2 -1
- data/smoke/stdout/Steepfile +2 -1
- data/smoke/super/Steepfile +2 -1
- data/smoke/toplevel/Steepfile +2 -1
- data/smoke/toplevel/test_expectations.yml +3 -3
- data/smoke/tsort/Steepfile +4 -5
- data/smoke/tsort/test_expectations.yml +2 -2
- data/smoke/type_case/Steepfile +2 -1
- data/smoke/unexpected/Steepfile +2 -1
- data/smoke/yield/Steepfile +2 -1
- data/steep.gemspec +2 -2
- metadata +16 -10
- data/sig/project.rbi +0 -109
@@ -10,10 +10,7 @@ module Steep
|
|
10
10
|
end
|
11
11
|
|
12
12
|
def with(type: self.type, constr: self.constr)
|
13
|
-
self.class.new(
|
14
|
-
type: type,
|
15
|
-
constr: constr
|
16
|
-
)
|
13
|
+
self.class.new(type: type, constr: constr)
|
17
14
|
end
|
18
15
|
|
19
16
|
def +(other)
|
@@ -162,23 +159,6 @@ module Steep
|
|
162
159
|
|
163
160
|
# constructor_method = method&.attributes&.include?(:constructor)
|
164
161
|
|
165
|
-
if method_type
|
166
|
-
var_types = TypeConstruction.parameter_types(args, method_type.type)
|
167
|
-
unless TypeConstruction.valid_parameter_env?(var_types, args.reject {|arg| arg.type == :blockarg}, method_type.type.params)
|
168
|
-
typing.add_error Diagnostic::Ruby::MethodArityMismatch.new(node: node, method_type: method_type)
|
169
|
-
end
|
170
|
-
end
|
171
|
-
|
172
|
-
if (block_arg = args.find {|arg| arg.type == :blockarg})
|
173
|
-
if method_type&.block
|
174
|
-
block_type = AST::Types::Proc.new(type: method_type.block.type, block: nil)
|
175
|
-
if method_type.block.optional?
|
176
|
-
block_type = AST::Types::Union.build(types: [block_type, AST::Builtin.nil_type])
|
177
|
-
end
|
178
|
-
var_types[block_arg.children[0]] = block_type
|
179
|
-
end
|
180
|
-
end
|
181
|
-
|
182
162
|
super_method = if definition
|
183
163
|
if (this_method = definition.methods[method_name])
|
184
164
|
if module_context&.class_name == this_method.defined_in
|
@@ -219,13 +199,21 @@ module Steep
|
|
219
199
|
class_type: module_context.module_type
|
220
200
|
)
|
221
201
|
|
222
|
-
|
223
|
-
|
224
|
-
|
225
|
-
|
226
|
-
|
227
|
-
|
228
|
-
|
202
|
+
method_params =
|
203
|
+
if method_type
|
204
|
+
TypeInference::MethodParams.build(node: node, method_type: method_type)
|
205
|
+
else
|
206
|
+
TypeInference::MethodParams.empty(node: node)
|
207
|
+
end
|
208
|
+
|
209
|
+
method_params.each_param do |param|
|
210
|
+
lvar_env = lvar_env.assign(param.name, type: param.var_type, node: param.node) {
|
211
|
+
raise "Unexpected assignment error: #{param.name}"
|
212
|
+
}
|
213
|
+
end
|
214
|
+
|
215
|
+
method_params.errors.each do |error|
|
216
|
+
typing.add_error error
|
229
217
|
end
|
230
218
|
|
231
219
|
lvar_env = lvar_env.annotate(annots)
|
@@ -692,7 +680,7 @@ module Steep
|
|
692
680
|
end
|
693
681
|
|
694
682
|
def synthesize(node, hint: nil, condition: false)
|
695
|
-
Steep.logger.tagged "synthesize:(#{node.location.expression.to_s.split(/:/, 2).last})" do
|
683
|
+
Steep.logger.tagged "synthesize:(#{node.location&.yield_self {|loc| loc.expression.to_s.split(/:/, 2).last } || "-"})" do
|
696
684
|
Steep.logger.debug node.type
|
697
685
|
case node.type
|
698
686
|
when :begin, :kwbegin
|
@@ -732,8 +720,17 @@ module Steep
|
|
732
720
|
when :__skip__
|
733
721
|
add_typing(node, type: AST::Builtin.any_type)
|
734
722
|
else
|
735
|
-
if
|
736
|
-
hint
|
723
|
+
if declared_type = context.lvar_env.declared_types[name]&.type
|
724
|
+
case hint
|
725
|
+
when nil
|
726
|
+
hint = declared_type
|
727
|
+
else
|
728
|
+
if check_relation(sub_type: declared_type, super_type: hint).success?
|
729
|
+
# declared_type is compatible with hint and more specific to hint.
|
730
|
+
# This typically happens when hint is untyped, top, or void.
|
731
|
+
hint = declared_type
|
732
|
+
end
|
733
|
+
end
|
737
734
|
end
|
738
735
|
|
739
736
|
rhs_result = synthesize(rhs, hint: hint)
|
@@ -751,7 +748,7 @@ module Steep
|
|
751
748
|
end
|
752
749
|
end
|
753
750
|
|
754
|
-
add_typing(node, type: rhs_result.type
|
751
|
+
constr.add_typing(node, type: rhs_result.type)
|
755
752
|
end
|
756
753
|
end
|
757
754
|
|
@@ -888,13 +885,12 @@ module Steep
|
|
888
885
|
checker.factory.method_type(method_type, self_type: self_type, method_decls: Set[decl])
|
889
886
|
}
|
890
887
|
)
|
891
|
-
args = TypeInference::SendArgs.from_nodes(node.children.dup)
|
892
888
|
|
893
889
|
call, constr = type_method_call(node,
|
894
890
|
receiver_type: self_type,
|
895
891
|
method_name: method_context.name,
|
896
892
|
method: super_method,
|
897
|
-
|
893
|
+
arguments: node.children,
|
898
894
|
block_params: nil,
|
899
895
|
block_body: nil,
|
900
896
|
topdown_hint: true)
|
@@ -940,6 +936,25 @@ module Steep
|
|
940
936
|
end
|
941
937
|
end
|
942
938
|
|
939
|
+
when :numblock
|
940
|
+
yield_self do
|
941
|
+
send_node, max_num, body = node.children
|
942
|
+
|
943
|
+
if max_num == 1
|
944
|
+
arg_nodes = [Parser::AST::Node.new(:procarg0, [:_1])]
|
945
|
+
else
|
946
|
+
arg_nodes = max_num.times.map {|i| Parser::AST::Node.new(:arg, [:"_#{i+1}"]) }
|
947
|
+
end
|
948
|
+
|
949
|
+
params = Parser::AST::Node.new(:args, arg_nodes)
|
950
|
+
|
951
|
+
if send_node.type == :lambda
|
952
|
+
type_lambda(node, block_params: params, block_body: body, type_hint: hint)
|
953
|
+
else
|
954
|
+
type_send(node, send_node: send_node, block_params: params, block_body: body, unwrap: send_node.type == :csend)
|
955
|
+
end
|
956
|
+
end
|
957
|
+
|
943
958
|
when :def
|
944
959
|
yield_self do
|
945
960
|
name, args_node, body_node = node.children
|
@@ -999,10 +1014,13 @@ module Steep
|
|
999
1014
|
end
|
1000
1015
|
|
1001
1016
|
if body_node
|
1002
|
-
|
1003
|
-
|
1004
|
-
|
1005
|
-
|
1017
|
+
# Add context to ranges from the end of the method body to the beginning of the `end` keyword
|
1018
|
+
if node.loc.end
|
1019
|
+
# Skip end-less def
|
1020
|
+
begin_pos = body_node.loc.expression.end_pos
|
1021
|
+
end_pos = node.loc.end.begin_pos
|
1022
|
+
typing.add_context(begin_pos..end_pos, context: body_pair.context)
|
1023
|
+
end
|
1006
1024
|
end
|
1007
1025
|
|
1008
1026
|
if module_context
|
@@ -1143,15 +1161,16 @@ module Steep
|
|
1143
1161
|
)
|
1144
1162
|
end
|
1145
1163
|
else
|
1146
|
-
|
1147
|
-
|
1148
|
-
|
1149
|
-
|
1150
|
-
|
1151
|
-
|
1152
|
-
|
1164
|
+
unless break_type.is_a?(AST::Types::Bot)
|
1165
|
+
check_relation(sub_type: AST::Builtin.nil_type, super_type: break_type).else do |result|
|
1166
|
+
typing.add_error(
|
1167
|
+
Diagnostic::Ruby::ImplicitBreakValueMismatch.new(
|
1168
|
+
node: node,
|
1169
|
+
jump_type: break_type,
|
1170
|
+
result: result
|
1171
|
+
)
|
1153
1172
|
)
|
1154
|
-
|
1173
|
+
end
|
1155
1174
|
end
|
1156
1175
|
end
|
1157
1176
|
else
|
@@ -1363,52 +1382,20 @@ module Steep
|
|
1363
1382
|
add_typing(node, type: AST::Types::Boolean.new)
|
1364
1383
|
end
|
1365
1384
|
|
1366
|
-
when :hash
|
1367
|
-
|
1368
|
-
|
1369
|
-
|
1370
|
-
if AST::Builtin::Hash.instance_type
|
1371
|
-
|
1372
|
-
|
1373
|
-
|
1374
|
-
|
1375
|
-
|
1376
|
-
value_types = []
|
1377
|
-
|
1378
|
-
each_child_node(node) do |child|
|
1379
|
-
case child.type
|
1380
|
-
when :pair
|
1381
|
-
key, value = child.children
|
1382
|
-
key_types << synthesize(key, hint: key_hint).type.yield_self do |type|
|
1383
|
-
select_super_type(type, key_hint)
|
1384
|
-
end
|
1385
|
-
value_types << synthesize(value, hint: value_hint).type.yield_self do |type|
|
1386
|
-
select_super_type(type, value_hint)
|
1387
|
-
end
|
1388
|
-
when :kwsplat
|
1389
|
-
expand_alias(synthesize(child.children[0]).type) do |splat_type, original_type|
|
1390
|
-
if AST::Builtin::Hash.instance_type?(splat_type)
|
1391
|
-
key_types << splat_type.args[0]
|
1392
|
-
value_types << splat_type.args[1]
|
1393
|
-
else
|
1394
|
-
typing.add_error Diagnostic::Ruby::UnexpectedSplat.new(node: child, type: original_type)
|
1395
|
-
key_types << AST::Builtin.any_type
|
1396
|
-
value_types << AST::Builtin.any_type
|
1397
|
-
end
|
1398
|
-
end
|
1385
|
+
when :hash, :kwargs
|
1386
|
+
# :kwargs happens for method calls with keyword argument, but the method doesn't have keyword params.
|
1387
|
+
# Conversion from kwargs to hash happens, and this when-clause is to support it.
|
1388
|
+
type_hash(node, hint: hint).tap do |pair|
|
1389
|
+
if pair.type == AST::Builtin::Hash.instance_type(fill_untyped: true)
|
1390
|
+
case hint
|
1391
|
+
when AST::Types::Any, AST::Types::Top, AST::Types::Void
|
1392
|
+
# ok
|
1393
|
+
when hint == pair.type
|
1394
|
+
# ok
|
1399
1395
|
else
|
1400
|
-
|
1396
|
+
pair.constr.typing.add_error Diagnostic::Ruby::FallbackAny.new(node: node)
|
1401
1397
|
end
|
1402
1398
|
end
|
1403
|
-
|
1404
|
-
key_type = key_types.empty? ? AST::Builtin.any_type : AST::Types::Union.build(types: key_types)
|
1405
|
-
value_type = value_types.empty? ? AST::Builtin.any_type : AST::Types::Union.build(types: value_types)
|
1406
|
-
|
1407
|
-
if key_types.empty? && value_types.empty? && !hint
|
1408
|
-
typing.add_error Diagnostic::Ruby::FallbackAny.new(node: node)
|
1409
|
-
end
|
1410
|
-
|
1411
|
-
add_typing(node, type: AST::Builtin::Hash.instance_type(key_type, value_type))
|
1412
1399
|
end
|
1413
1400
|
|
1414
1401
|
when :dstr, :xstr
|
@@ -1683,8 +1670,7 @@ module Steep
|
|
1683
1670
|
tuples.each do |tuple|
|
1684
1671
|
typing.new_child(node_range) do |child_typing|
|
1685
1672
|
if pair = with_new_typing(child_typing).try_tuple_type(node, tuple)
|
1686
|
-
|
1687
|
-
return pair.with(constr: pair.constr.with_new_typing(typing))
|
1673
|
+
return pair.with(constr: pair.constr.save_typing)
|
1688
1674
|
end
|
1689
1675
|
end
|
1690
1676
|
end
|
@@ -1695,8 +1681,7 @@ module Steep
|
|
1695
1681
|
typing.new_child(node_range) do |child_typing|
|
1696
1682
|
pair = with_new_typing(child_typing).try_array_type(node, array)
|
1697
1683
|
if pair.constr.check_relation(sub_type: pair.type, super_type: hint).success?
|
1698
|
-
|
1699
|
-
return pair.with(constr: pair.constr.with_new_typing(typing))
|
1684
|
+
return pair.with(constr: pair.constr.save_typing)
|
1700
1685
|
end
|
1701
1686
|
end
|
1702
1687
|
end
|
@@ -2291,7 +2276,9 @@ module Steep
|
|
2291
2276
|
unless return_types.empty?
|
2292
2277
|
type = AST::Types::Proc.new(
|
2293
2278
|
type: Interface::Function.new(
|
2294
|
-
params: Interface::Function::Params.empty.
|
2279
|
+
params: Interface::Function::Params.empty.with_first_param(
|
2280
|
+
Interface::Function::Params::PositionalParams::Required.new(param_type)
|
2281
|
+
),
|
2295
2282
|
return_type: AST::Types::Union.build(types: return_types),
|
2296
2283
|
location: nil
|
2297
2284
|
),
|
@@ -2389,6 +2376,7 @@ module Steep
|
|
2389
2376
|
|
2390
2377
|
else
|
2391
2378
|
typing.add_error(Diagnostic::Ruby::UnsupportedSyntax.new(node: node))
|
2379
|
+
add_typing(node, type: AST::Builtin.any_type)
|
2392
2380
|
|
2393
2381
|
end.tap do |pair|
|
2394
2382
|
unless pair.is_a?(Pair) && !pair.type.is_a?(Pair)
|
@@ -2738,11 +2726,10 @@ module Steep
|
|
2738
2726
|
method = interface.methods[method_name]
|
2739
2727
|
|
2740
2728
|
if method
|
2741
|
-
args = TypeInference::SendArgs.from_nodes(arguments)
|
2742
2729
|
call, constr = type_method_call(node,
|
2743
2730
|
method: method,
|
2744
2731
|
method_name: method_name,
|
2745
|
-
|
2732
|
+
arguments: arguments,
|
2746
2733
|
block_params: block_params,
|
2747
2734
|
block_body: block_body,
|
2748
2735
|
receiver_type: receiver_type,
|
@@ -2922,27 +2909,22 @@ module Steep
|
|
2922
2909
|
end
|
2923
2910
|
end
|
2924
2911
|
|
2925
|
-
def type_method_call(node, method_name:, receiver_type:, method:,
|
2912
|
+
def type_method_call(node, method_name:, receiver_type:, method:, arguments:, block_params:, block_body:, topdown_hint:)
|
2926
2913
|
node_range = node.loc.expression.yield_self {|l| l.begin_pos..l.end_pos }
|
2927
2914
|
|
2928
|
-
results = method.method_types.
|
2915
|
+
results = method.method_types.map do |method_type|
|
2929
2916
|
Steep.logger.tagged method_type.to_s do
|
2930
|
-
|
2931
|
-
|
2932
|
-
|
2933
|
-
|
2934
|
-
|
2935
|
-
|
2936
|
-
|
2937
|
-
|
2938
|
-
|
2939
|
-
|
2940
|
-
|
2941
|
-
block_params: block_params,
|
2942
|
-
block_body: block_body,
|
2943
|
-
topdown_hint: topdown_hint
|
2944
|
-
)
|
2945
|
-
end
|
2917
|
+
typing.new_child(node_range) do |child_typing|
|
2918
|
+
self.with_new_typing(child_typing).try_method_type(
|
2919
|
+
node,
|
2920
|
+
receiver_type: receiver_type,
|
2921
|
+
method_name: method_name,
|
2922
|
+
method_type: method_type,
|
2923
|
+
arguments: arguments,
|
2924
|
+
block_params: block_params,
|
2925
|
+
block_body: block_body,
|
2926
|
+
topdown_hint: topdown_hint
|
2927
|
+
)
|
2946
2928
|
end
|
2947
2929
|
end
|
2948
2930
|
end
|
@@ -2982,138 +2964,34 @@ module Steep
|
|
2982
2964
|
]
|
2983
2965
|
end
|
2984
2966
|
|
2985
|
-
def
|
2986
|
-
|
2987
|
-
|
2988
|
-
case node.type
|
2989
|
-
when :hash
|
2990
|
-
keyword_hash_type = AST::Builtin::Hash.instance_type(AST::Builtin::Symbol.instance_type,
|
2991
|
-
AST::Builtin.any_type)
|
2992
|
-
add_typing node, type: keyword_hash_type
|
2993
|
-
|
2994
|
-
given_keys = Set.new()
|
2995
|
-
|
2996
|
-
node.children.each do |element|
|
2997
|
-
case element.type
|
2998
|
-
when :pair
|
2999
|
-
key_node, value_node = element.children
|
3000
|
-
|
3001
|
-
case key_node.type
|
3002
|
-
when :sym
|
3003
|
-
key_symbol = key_node.children[0]
|
3004
|
-
keyword_type = case
|
3005
|
-
when params.required_keywords.key?(key_symbol)
|
3006
|
-
params.required_keywords[key_symbol]
|
3007
|
-
when params.optional_keywords.key?(key_symbol)
|
3008
|
-
AST::Types::Union.build(
|
3009
|
-
types: [params.optional_keywords[key_symbol],
|
3010
|
-
AST::Builtin.nil_type]
|
3011
|
-
)
|
3012
|
-
when params.rest_keywords
|
3013
|
-
params.rest_keywords
|
3014
|
-
end
|
3015
|
-
|
3016
|
-
add_typing key_node, type: AST::Builtin::Symbol.instance_type
|
3017
|
-
|
3018
|
-
given_keys << key_symbol
|
3019
|
-
|
3020
|
-
if keyword_type
|
3021
|
-
check(value_node, keyword_type, constraints: constraints) do |expected, actual, result|
|
3022
|
-
return Diagnostic::Ruby::IncompatibleAssignment.new(
|
3023
|
-
node: value_node,
|
3024
|
-
lhs_type: expected,
|
3025
|
-
rhs_type: actual,
|
3026
|
-
result: result
|
3027
|
-
)
|
3028
|
-
end
|
3029
|
-
else
|
3030
|
-
synthesize(value_node)
|
3031
|
-
end
|
3032
|
-
|
3033
|
-
else
|
3034
|
-
check(key_node, AST::Builtin::Symbol.instance_type, constraints: constraints) do |expected, actual, result|
|
3035
|
-
return Diagnostic::Ruby::IncompatibleAssignment.new(
|
3036
|
-
node: key_node,
|
3037
|
-
lhs_type: expected,
|
3038
|
-
rhs_type: actual,
|
3039
|
-
result: result
|
3040
|
-
)
|
3041
|
-
end
|
3042
|
-
end
|
3043
|
-
|
3044
|
-
when :kwsplat
|
3045
|
-
Steep.logger.warn("Keyword arg with kwsplat(**) node are not supported.")
|
3046
|
-
|
3047
|
-
check(element.children[0], keyword_hash_type, constraints: constraints) do |expected, actual, result|
|
3048
|
-
return Diagnostic::Ruby::IncompatibleAssignment.new(
|
3049
|
-
node: node,
|
3050
|
-
lhs_type: expected,
|
3051
|
-
rhs_type: actual,
|
3052
|
-
result: result
|
3053
|
-
)
|
3054
|
-
end
|
2967
|
+
def inspect
|
2968
|
+
"#<#{self.class}>"
|
2969
|
+
end
|
3055
2970
|
|
3056
|
-
|
3057
|
-
|
3058
|
-
end
|
2971
|
+
def with_child_typing(range:)
|
2972
|
+
constr = with_new_typing(typing.new_child(range: range))
|
3059
2973
|
|
3060
|
-
|
3061
|
-
|
3062
|
-
missing_keywords = Set.new(params.required_keywords.keys) - given_keys
|
3063
|
-
unless missing_keywords.empty?
|
3064
|
-
return Diagnostic::Ruby::MissingKeyword.new(
|
3065
|
-
node: node,
|
3066
|
-
missing_keywords: missing_keywords
|
3067
|
-
)
|
3068
|
-
end
|
3069
|
-
|
3070
|
-
extra_keywords = given_keys - Set.new(params.required_keywords.keys) - Set.new(params.optional_keywords.keys)
|
3071
|
-
if extra_keywords.any? && !params.rest_keywords
|
3072
|
-
return Diagnostic::Ruby::UnexpectedKeyword.new(
|
3073
|
-
node: node,
|
3074
|
-
unexpected_keywords: extra_keywords
|
3075
|
-
)
|
3076
|
-
end
|
3077
|
-
end
|
2974
|
+
if block_given?
|
2975
|
+
yield constr
|
3078
2976
|
else
|
3079
|
-
|
3080
|
-
|
3081
|
-
|
3082
|
-
value_types = params.required_keywords.values +
|
3083
|
-
params.optional_keywords.values.map {|type| AST::Types::Union.build(types: [type, AST::Builtin.nil_type])} +
|
3084
|
-
[params.rest_keywords]
|
3085
|
-
|
3086
|
-
hash_type = AST::Builtin::Hash.instance_type(
|
3087
|
-
AST::Builtin::Symbol.instance_type,
|
3088
|
-
AST::Types::Union.build(types: value_types)
|
3089
|
-
)
|
3090
|
-
else
|
3091
|
-
hash_elements = params.required_keywords.merge(
|
3092
|
-
params.optional_keywords.transform_values do |type|
|
3093
|
-
AST::Types::Union.build(types: [type, AST::Builtin.nil_type])
|
3094
|
-
end
|
3095
|
-
)
|
3096
|
-
|
3097
|
-
hash_type = AST::Types::Record.new(elements: hash_elements)
|
3098
|
-
end
|
2977
|
+
constr
|
2978
|
+
end
|
2979
|
+
end
|
3099
2980
|
|
3100
|
-
|
2981
|
+
# Bypass :splat and :kwsplat
|
2982
|
+
def bypass_splat(node)
|
2983
|
+
splat = node.type == :splat || node.type == :kwsplat
|
3101
2984
|
|
3102
|
-
|
3103
|
-
|
3104
|
-
|
3105
|
-
|
3106
|
-
|
3107
|
-
|
3108
|
-
result: result
|
3109
|
-
)
|
3110
|
-
end
|
2985
|
+
if splat
|
2986
|
+
pair = yield(node.children[0])
|
2987
|
+
pair.constr.add_typing(node, type: pair.type)
|
2988
|
+
pair
|
2989
|
+
else
|
2990
|
+
yield node
|
3111
2991
|
end
|
3112
|
-
|
3113
|
-
nil
|
3114
2992
|
end
|
3115
2993
|
|
3116
|
-
def try_method_type(node, receiver_type:, method_name:, method_type:,
|
2994
|
+
def try_method_type(node, receiver_type:, method_name:, method_type:, arguments:, block_params:, block_body:, topdown_hint:)
|
3117
2995
|
fresh_types = method_type.type_params.map {|x| AST::Types::Var.fresh(x)}
|
3118
2996
|
fresh_vars = Set.new(fresh_types.map(&:name))
|
3119
2997
|
instantiation = Interface::Substitution.build(method_type.type_params, fresh_types)
|
@@ -3128,38 +3006,90 @@ module Steep
|
|
3128
3006
|
|
3129
3007
|
errors = []
|
3130
3008
|
|
3131
|
-
|
3132
|
-
|
3133
|
-
|
3134
|
-
|
3135
|
-
|
3009
|
+
args = TypeInference::SendArgs.new(node: node, arguments: arguments, method_name: method_name, method_type: method_type)
|
3010
|
+
es = args.each do |arg|
|
3011
|
+
case arg
|
3012
|
+
when TypeInference::SendArgs::PositionalArgs::NodeParamPair
|
3013
|
+
_, constr = constr.type_check_argument(
|
3014
|
+
arg.node,
|
3015
|
+
type: arg.param.type,
|
3016
|
+
receiver_type: receiver_type,
|
3017
|
+
constraints: constraints,
|
3018
|
+
errors: errors
|
3019
|
+
)
|
3136
3020
|
|
3137
|
-
|
3138
|
-
|
3139
|
-
|
3140
|
-
|
3141
|
-
|
3021
|
+
when TypeInference::SendArgs::PositionalArgs::NodeTypePair
|
3022
|
+
_, constr = bypass_splat(arg.node) do |n|
|
3023
|
+
constr.type_check_argument(
|
3024
|
+
n,
|
3025
|
+
type: arg.node_type,
|
3026
|
+
receiver_type: receiver_type,
|
3027
|
+
constraints: constraints,
|
3028
|
+
report_node: arg.node,
|
3029
|
+
errors: errors
|
3030
|
+
)
|
3031
|
+
end
|
3142
3032
|
|
3143
|
-
|
3144
|
-
|
3145
|
-
|
3146
|
-
expected: param_type,
|
3147
|
-
actual: arg_type,
|
3148
|
-
result: result)
|
3033
|
+
when TypeInference::SendArgs::PositionalArgs::UnexpectedArg
|
3034
|
+
_, constr = bypass_splat(arg.node) do |n|
|
3035
|
+
constr.synthesize(n)
|
3149
3036
|
end
|
3150
|
-
else
|
3151
|
-
# keyword
|
3152
|
-
result = constr.check_keyword_arg(receiver_type: receiver_type,
|
3153
|
-
node: pair,
|
3154
|
-
method_type: method_type,
|
3155
|
-
constraints: constraints)
|
3156
3037
|
|
3157
|
-
|
3158
|
-
|
3038
|
+
when TypeInference::SendArgs::PositionalArgs::SplatArg
|
3039
|
+
arg_type, _ = constr
|
3040
|
+
.with_child_typing(range: arg.node.loc.expression.begin_pos ... arg.node.loc.expression.end_pos)
|
3041
|
+
.try_tuple_type!(arg.node.children[0])
|
3042
|
+
arg.type = arg_type
|
3043
|
+
|
3044
|
+
when TypeInference::SendArgs::PositionalArgs::MissingArg
|
3045
|
+
# ignore
|
3046
|
+
|
3047
|
+
when TypeInference::SendArgs::KeywordArgs::ArgTypePairs
|
3048
|
+
arg.pairs.each do |node, type|
|
3049
|
+
_, constr = bypass_splat(node) do |node|
|
3050
|
+
constr.type_check_argument(
|
3051
|
+
node,
|
3052
|
+
type: type,
|
3053
|
+
receiver_type: receiver_type,
|
3054
|
+
constraints: constraints,
|
3055
|
+
errors: errors
|
3056
|
+
)
|
3057
|
+
end
|
3159
3058
|
end
|
3059
|
+
|
3060
|
+
when TypeInference::SendArgs::KeywordArgs::UnexpectedKeyword
|
3061
|
+
if arg.node.type == :pair
|
3062
|
+
arg.node.children.each do |nn|
|
3063
|
+
_, constr = constr.synthesize(nn)
|
3064
|
+
end
|
3065
|
+
else
|
3066
|
+
_, constr = bypass_splat(arg.node) do |n|
|
3067
|
+
constr.synthesize(n)
|
3068
|
+
end
|
3069
|
+
end
|
3070
|
+
|
3071
|
+
when TypeInference::SendArgs::KeywordArgs::SplatArg
|
3072
|
+
type, _ = bypass_splat(arg.node) do |sp_node|
|
3073
|
+
if sp_node.type == :hash
|
3074
|
+
pair = constr.type_hash_record(sp_node, nil) and break pair
|
3075
|
+
end
|
3076
|
+
|
3077
|
+
constr.synthesize(sp_node)
|
3078
|
+
end
|
3079
|
+
|
3080
|
+
arg.type = type
|
3081
|
+
|
3082
|
+
when TypeInference::SendArgs::KeywordArgs::MissingKeyword
|
3083
|
+
# ignore
|
3084
|
+
else
|
3085
|
+
raise arg.inspect
|
3160
3086
|
end
|
3087
|
+
|
3088
|
+
constr
|
3161
3089
|
end
|
3162
3090
|
|
3091
|
+
errors.push(*es)
|
3092
|
+
|
3163
3093
|
if block_params
|
3164
3094
|
# block is given
|
3165
3095
|
block_annotations = source.annotations(block: node, factory: checker.factory, current_module: current_namespace)
|
@@ -3302,108 +3232,105 @@ module Steep
|
|
3302
3232
|
)
|
3303
3233
|
end
|
3304
3234
|
else
|
3305
|
-
|
3306
|
-
|
3307
|
-
|
3308
|
-
|
3309
|
-
|
3310
|
-
|
3235
|
+
arg = args.block_pass_arg
|
3236
|
+
|
3237
|
+
case
|
3238
|
+
when arg.compatible?
|
3239
|
+
if arg.node
|
3240
|
+
subst = constraints.solution(
|
3311
3241
|
checker,
|
3312
|
-
variance: variance,
|
3313
|
-
variables: fresh_vars,
|
3314
3242
|
self_type: self_type,
|
3315
3243
|
instance_type: module_context.instance_type,
|
3316
|
-
class_type: module_context.module_type
|
3244
|
+
class_type: module_context.module_type,
|
3245
|
+
variance: variance,
|
3246
|
+
variables: occurence.params
|
3317
3247
|
)
|
3318
|
-
|
3319
|
-
|
3320
|
-
|
3321
|
-
|
3248
|
+
|
3249
|
+
block_type = arg.node_type.subst(subst)
|
3250
|
+
|
3251
|
+
node_type, constr = constr.synthesize(arg.node, hint: block_type)
|
3252
|
+
nil_block =
|
3253
|
+
constr.check_relation(sub_type: node_type, super_type: AST::Builtin.nil_type).success? &&
|
3254
|
+
!node_type.is_a?(AST::Types::Any)
|
3255
|
+
|
3256
|
+
unless nil_block
|
3257
|
+
constr.check_relation(sub_type: node_type, super_type: block_type, constraints: constraints).else do |result|
|
3258
|
+
errors << Diagnostic::Ruby::BlockTypeMismatch.new(
|
3259
|
+
node: arg.node,
|
3260
|
+
expected: block_type,
|
3261
|
+
actual: node_type,
|
3262
|
+
result: result
|
3263
|
+
)
|
3264
|
+
end
|
3265
|
+
end
|
3266
|
+
|
3267
|
+
subst = constraints.solution(
|
3322
3268
|
checker,
|
3323
|
-
variance: variance,
|
3324
|
-
variables: fresh_vars,
|
3325
3269
|
self_type: self_type,
|
3326
3270
|
instance_type: module_context.instance_type,
|
3327
|
-
class_type: module_context.module_type
|
3271
|
+
class_type: module_context.module_type,
|
3272
|
+
variance: variance,
|
3273
|
+
variables: method_type.free_variables
|
3328
3274
|
)
|
3329
|
-
method_type = method_type.subst(s)
|
3330
3275
|
|
3331
|
-
|
3332
|
-
|
3333
|
-
|
3334
|
-
|
3335
|
-
node: node,
|
3336
|
-
method_type: method_type
|
3337
|
-
)
|
3338
|
-
end
|
3339
|
-
end
|
3340
|
-
else
|
3341
|
-
# Method accepts block
|
3342
|
-
if !args.block_pass_arg
|
3343
|
-
# Block pass is not given
|
3344
|
-
if method_type.block.required?
|
3345
|
-
# Required block is missing
|
3276
|
+
method_type = method_type.subst(subst)
|
3277
|
+
|
3278
|
+
if nil_block && arg.block.required?
|
3279
|
+
# Passing no block
|
3346
3280
|
errors << Diagnostic::Ruby::RequiredBlockMissing.new(
|
3347
3281
|
node: node,
|
3348
3282
|
method_type: method_type
|
3349
3283
|
)
|
3350
3284
|
end
|
3351
|
-
|
3352
|
-
|
3285
|
+
else
|
3286
|
+
subst = constraints.solution(
|
3353
3287
|
checker,
|
3354
|
-
variance: variance,
|
3355
|
-
variables: fresh_vars,
|
3356
3288
|
self_type: self_type,
|
3357
3289
|
instance_type: module_context.instance_type,
|
3358
|
-
class_type: module_context.module_type
|
3290
|
+
class_type: module_context.module_type,
|
3291
|
+
variance: variance,
|
3292
|
+
variables: method_type.free_variables
|
3359
3293
|
)
|
3360
|
-
method_type = method_type.subst(s)
|
3361
|
-
else
|
3362
|
-
begin
|
3363
|
-
method_type = method_type.subst(
|
3364
|
-
constraints.solution(
|
3365
|
-
checker,
|
3366
|
-
self_type: self_type,
|
3367
|
-
instance_type: module_context.instance_type,
|
3368
|
-
class_type: module_context.module_type,
|
3369
|
-
variance: variance,
|
3370
|
-
variables: occurence.params
|
3371
|
-
)
|
3372
|
-
)
|
3373
|
-
hint_type = if topdown_hint
|
3374
|
-
AST::Types::Proc.new(type: method_type.block.type, block: nil)
|
3375
|
-
end
|
3376
|
-
given_block_type, constr = constr.synthesize(args.block_pass_arg, hint: hint_type)
|
3377
|
-
method_block_type = method_type.block.yield_self {|expected_block|
|
3378
|
-
proc_type = AST::Types::Proc.new(type: expected_block.type, block: nil)
|
3379
|
-
if expected_block.optional?
|
3380
|
-
AST::Builtin.optional(proc_type)
|
3381
|
-
else
|
3382
|
-
proc_type
|
3383
|
-
end
|
3384
|
-
}
|
3385
3294
|
|
3386
|
-
|
3387
|
-
|
3388
|
-
errors << Diagnostic::Ruby::BlockTypeMismatch.new(
|
3389
|
-
node: args.block_pass_arg,
|
3390
|
-
expected: method_block_type,
|
3391
|
-
actual: given_block_type,
|
3392
|
-
result: result
|
3393
|
-
)
|
3394
|
-
end
|
3295
|
+
method_type = method_type.subst(subst)
|
3296
|
+
end
|
3395
3297
|
|
3396
|
-
|
3397
|
-
|
3398
|
-
|
3399
|
-
|
3400
|
-
|
3401
|
-
|
3402
|
-
|
3403
|
-
|
3404
|
-
|
3405
|
-
|
3406
|
-
|
3298
|
+
when arg.block_missing?
|
3299
|
+
subst = constraints.solution(
|
3300
|
+
checker,
|
3301
|
+
self_type: self_type,
|
3302
|
+
instance_type: module_context.instance_type,
|
3303
|
+
class_type: module_context.module_type,
|
3304
|
+
variance: variance,
|
3305
|
+
variables: method_type.free_variables
|
3306
|
+
)
|
3307
|
+
|
3308
|
+
method_type = method_type.subst(subst)
|
3309
|
+
|
3310
|
+
errors << Diagnostic::Ruby::RequiredBlockMissing.new(
|
3311
|
+
node: node,
|
3312
|
+
method_type: method_type
|
3313
|
+
)
|
3314
|
+
|
3315
|
+
when arg.unexpected_block?
|
3316
|
+
subst = constraints.solution(
|
3317
|
+
checker,
|
3318
|
+
self_type: self_type,
|
3319
|
+
instance_type: module_context.instance_type,
|
3320
|
+
class_type: module_context.module_type,
|
3321
|
+
variance: variance,
|
3322
|
+
variables: method_type.free_variables
|
3323
|
+
)
|
3324
|
+
|
3325
|
+
method_type = method_type.subst(subst)
|
3326
|
+
|
3327
|
+
node_type, constr = constr.synthesize(arg.node)
|
3328
|
+
|
3329
|
+
unless constr.check_relation(sub_type: node_type, super_type: AST::Builtin.nil_type).success?
|
3330
|
+
errors << Diagnostic::Ruby::UnexpectedBlockGiven.new(
|
3331
|
+
node: node,
|
3332
|
+
method_type: method_type
|
3333
|
+
)
|
3407
3334
|
end
|
3408
3335
|
end
|
3409
3336
|
end
|
@@ -3436,6 +3363,18 @@ module Steep
|
|
3436
3363
|
]
|
3437
3364
|
end
|
3438
3365
|
|
3366
|
+
def type_check_argument(node, receiver_type:, type:, constraints:, report_node: node, errors:)
|
3367
|
+
check(node, type, constraints: constraints) do |expected, actual, result|
|
3368
|
+
errors << Diagnostic::Ruby::ArgumentTypeMismatch.new(
|
3369
|
+
node: report_node,
|
3370
|
+
receiver_type: receiver_type,
|
3371
|
+
expected: expected,
|
3372
|
+
actual: actual,
|
3373
|
+
result: result
|
3374
|
+
)
|
3375
|
+
end
|
3376
|
+
end
|
3377
|
+
|
3439
3378
|
def type_block_without_hint(node:, block_annotations:, block_params:, block_body:, &block)
|
3440
3379
|
unless block_params
|
3441
3380
|
typing.add_error(
|
@@ -3576,68 +3515,6 @@ module Steep
|
|
3576
3515
|
end
|
3577
3516
|
end
|
3578
3517
|
|
3579
|
-
def self.parameter_types(nodes, type)
|
3580
|
-
nodes = nodes.dup
|
3581
|
-
|
3582
|
-
env = {}
|
3583
|
-
|
3584
|
-
type.params.required.each do |type|
|
3585
|
-
a = nodes.first
|
3586
|
-
if a&.type == :arg
|
3587
|
-
env[a.children.first] = type
|
3588
|
-
nodes.shift
|
3589
|
-
else
|
3590
|
-
break
|
3591
|
-
end
|
3592
|
-
end
|
3593
|
-
|
3594
|
-
type.params.optional.each do |type|
|
3595
|
-
a = nodes.first
|
3596
|
-
|
3597
|
-
if a&.type == :optarg
|
3598
|
-
env[a.children.first] = type
|
3599
|
-
nodes.shift
|
3600
|
-
else
|
3601
|
-
break
|
3602
|
-
end
|
3603
|
-
end
|
3604
|
-
|
3605
|
-
if type.params.rest
|
3606
|
-
a = nodes.first
|
3607
|
-
if a&.type == :restarg
|
3608
|
-
env[a.children.first] = AST::Builtin::Array.instance_type(type.params.rest)
|
3609
|
-
nodes.shift
|
3610
|
-
end
|
3611
|
-
end
|
3612
|
-
|
3613
|
-
nodes.each do |node|
|
3614
|
-
if node.type == :kwarg
|
3615
|
-
name = node.children[0]
|
3616
|
-
ty = type.params.required_keywords[name]
|
3617
|
-
env[name] = ty if ty
|
3618
|
-
end
|
3619
|
-
|
3620
|
-
if node.type == :kwoptarg
|
3621
|
-
name = node.children[0]
|
3622
|
-
ty = type.params.optional_keywords[name]
|
3623
|
-
env[name] = ty if ty
|
3624
|
-
end
|
3625
|
-
|
3626
|
-
if node.type == :kwrestarg
|
3627
|
-
ty = type.params.rest_keywords
|
3628
|
-
if ty
|
3629
|
-
env[node.children[0]] = AST::Builtin::Hash.instance_type(AST::Builtin::Symbol.instance_type, ty)
|
3630
|
-
end
|
3631
|
-
end
|
3632
|
-
end
|
3633
|
-
|
3634
|
-
env
|
3635
|
-
end
|
3636
|
-
|
3637
|
-
def self.valid_parameter_env?(env, nodes, params)
|
3638
|
-
env.size == nodes.size && env.size == params.size
|
3639
|
-
end
|
3640
|
-
|
3641
3518
|
def current_namespace
|
3642
3519
|
module_context&.current_namespace || AST::Namespace.root
|
3643
3520
|
end
|
@@ -3745,25 +3622,6 @@ module Steep
|
|
3745
3622
|
end
|
3746
3623
|
end
|
3747
3624
|
|
3748
|
-
def flatten_const_name(node)
|
3749
|
-
path = []
|
3750
|
-
|
3751
|
-
while node
|
3752
|
-
case node.type
|
3753
|
-
when :const, :casgn
|
3754
|
-
path.unshift(node.children[1])
|
3755
|
-
node = node.children[0]
|
3756
|
-
when :cbase
|
3757
|
-
path.unshift("")
|
3758
|
-
break
|
3759
|
-
else
|
3760
|
-
return nil
|
3761
|
-
end
|
3762
|
-
end
|
3763
|
-
|
3764
|
-
path.join("::").to_sym
|
3765
|
-
end
|
3766
|
-
|
3767
3625
|
def fallback_to_any(node)
|
3768
3626
|
if block_given?
|
3769
3627
|
typing.add_error yield
|
@@ -3805,16 +3663,6 @@ module Steep
|
|
3805
3663
|
Pair.new(type: AST::Builtin.any_type, constr: self)
|
3806
3664
|
end
|
3807
3665
|
|
3808
|
-
def fallback_any_rec(node)
|
3809
|
-
fallback_to_any(node) unless typing.has_type?(node)
|
3810
|
-
|
3811
|
-
each_child_node(node) do |child|
|
3812
|
-
fallback_any_rec(child)
|
3813
|
-
end
|
3814
|
-
|
3815
|
-
typing.type_of(node: node)
|
3816
|
-
end
|
3817
|
-
|
3818
3666
|
def unwrap(type)
|
3819
3667
|
expand_alias(type) do |expanded|
|
3820
3668
|
case
|
@@ -3827,19 +3675,6 @@ module Steep
|
|
3827
3675
|
end
|
3828
3676
|
end
|
3829
3677
|
|
3830
|
-
def self.value_variables(node)
|
3831
|
-
case node&.type
|
3832
|
-
when :lvar
|
3833
|
-
Set.new([node.children.first])
|
3834
|
-
when :lvasgn
|
3835
|
-
Set.new([node.children.first]) + value_variables(node.children[1])
|
3836
|
-
when :begin
|
3837
|
-
value_variables(node.children.last)
|
3838
|
-
else
|
3839
|
-
Set.new
|
3840
|
-
end
|
3841
|
-
end
|
3842
|
-
|
3843
3678
|
def deep_expand_alias(type, &block)
|
3844
3679
|
checker.factory.deep_expand_alias(type, &block)
|
3845
3680
|
end
|
@@ -3886,24 +3721,6 @@ module Steep
|
|
3886
3721
|
end
|
3887
3722
|
end
|
3888
3723
|
|
3889
|
-
def select_super_type(sub_type, super_type)
|
3890
|
-
if super_type
|
3891
|
-
result = check_relation(sub_type: sub_type, super_type: super_type)
|
3892
|
-
|
3893
|
-
if result.success?
|
3894
|
-
super_type
|
3895
|
-
else
|
3896
|
-
if block_given?
|
3897
|
-
yield result
|
3898
|
-
else
|
3899
|
-
sub_type
|
3900
|
-
end
|
3901
|
-
end
|
3902
|
-
else
|
3903
|
-
sub_type
|
3904
|
-
end
|
3905
|
-
end
|
3906
|
-
|
3907
3724
|
def to_instance_type(type, args: nil)
|
3908
3725
|
args = args || case type
|
3909
3726
|
when AST::Types::Name::Singleton
|
@@ -3915,16 +3732,35 @@ module Steep
|
|
3915
3732
|
AST::Types::Name::Instance.new(name: type.name, args: args)
|
3916
3733
|
end
|
3917
3734
|
|
3735
|
+
def try_tuple_type!(node, hint: nil)
|
3736
|
+
if node.type == :array && (hint.nil? || hint.is_a?(AST::Types::Tuple))
|
3737
|
+
node_range = node.loc.expression.yield_self {|l| l.begin_pos..l.end_pos }
|
3738
|
+
|
3739
|
+
typing.new_child(node_range) do |child_typing|
|
3740
|
+
if pair = with_new_typing(child_typing).try_tuple_type(node, hint)
|
3741
|
+
return pair.with(constr: pair.constr.save_typing)
|
3742
|
+
end
|
3743
|
+
end
|
3744
|
+
end
|
3745
|
+
|
3746
|
+
synthesize(node, hint: hint)
|
3747
|
+
end
|
3748
|
+
|
3918
3749
|
def try_tuple_type(node, hint)
|
3919
|
-
if
|
3920
|
-
|
3750
|
+
if hint
|
3751
|
+
if node.children.size != hint.types.size
|
3752
|
+
return
|
3753
|
+
end
|
3921
3754
|
end
|
3922
3755
|
|
3923
3756
|
constr = self
|
3924
3757
|
element_types = []
|
3925
3758
|
|
3926
3759
|
each_child_node(node).with_index do |child, index|
|
3927
|
-
|
3760
|
+
child_hint = if hint
|
3761
|
+
hint.types[index]
|
3762
|
+
end
|
3763
|
+
type, constr = constr.synthesize(child, hint: child_hint)
|
3928
3764
|
element_types << type
|
3929
3765
|
end
|
3930
3766
|
|
@@ -3956,55 +3792,152 @@ module Steep
|
|
3956
3792
|
constr.add_typing(node, type: AST::Builtin::Array.instance_type(element_type))
|
3957
3793
|
end
|
3958
3794
|
|
3959
|
-
|
3960
|
-
|
3795
|
+
# Try to give record type to hash_node.
|
3796
|
+
#
|
3797
|
+
# Returns nil when it cannot have a record type.
|
3798
|
+
# `record_type` can be nil when the keys are not specified.
|
3799
|
+
#
|
3800
|
+
def type_hash_record(hash_node, record_type)
|
3801
|
+
raise unless hash_node.type == :hash || hash_node.type == :kwargs
|
3802
|
+
|
3803
|
+
constr = self
|
3804
|
+
|
3805
|
+
if record_type
|
3806
|
+
elements = record_type.elements.dup
|
3807
|
+
else
|
3808
|
+
elements = {}
|
3809
|
+
end
|
3810
|
+
|
3811
|
+
elems = {}
|
3812
|
+
|
3813
|
+
each_child_node(hash_node) do |child|
|
3814
|
+
if child.type == :pair
|
3815
|
+
case child.children[0].type
|
3816
|
+
when :sym, :str, :int
|
3817
|
+
key_node = child.children[0]
|
3818
|
+
value_node = child.children[1]
|
3819
|
+
|
3820
|
+
key = key_node.children[0]
|
3821
|
+
|
3822
|
+
_, constr = constr.synthesize(key_node, hint: AST::Types::Literal.new(value: key))
|
3823
|
+
value_type, constr = constr.synthesize(value_node, hint: elements[key])
|
3824
|
+
|
3825
|
+
elems[key] = value_type
|
3826
|
+
else
|
3827
|
+
return
|
3828
|
+
end
|
3829
|
+
else
|
3830
|
+
return
|
3831
|
+
end
|
3832
|
+
end
|
3833
|
+
|
3834
|
+
type = AST::Types::Record.new(elements: elems)
|
3835
|
+
constr.add_typing(hash_node, type: type)
|
3836
|
+
end
|
3837
|
+
|
3838
|
+
# Give hash_node a type based on hint.
|
3839
|
+
#
|
3840
|
+
# * When hint is Record type, it may have record type.
|
3841
|
+
# * When hint is union type, it tries recursively with the union cases.
|
3842
|
+
# * Otherwise, it tries to be a hash instance.
|
3843
|
+
#
|
3844
|
+
def type_hash(hash_node, hint:)
|
3845
|
+
hint = deep_expand_alias(hint)
|
3846
|
+
range = hash_node.loc.expression.yield_self {|l| l.begin_pos..l.end_pos }
|
3961
3847
|
|
3962
3848
|
case hint
|
3963
3849
|
when AST::Types::Record
|
3964
|
-
|
3965
|
-
|
3966
|
-
|
3850
|
+
with_child_typing(range: range) do |constr|
|
3851
|
+
pair = constr.type_hash_record(hash_node, hint)
|
3852
|
+
if pair
|
3853
|
+
return pair.with(constr: pair.constr.save_typing)
|
3854
|
+
end
|
3855
|
+
end
|
3856
|
+
when AST::Types::Union
|
3857
|
+
pair = pick_one_of(hint.types, range: range) do |type, constr|
|
3858
|
+
constr.type_hash(hash_node, hint: type)
|
3859
|
+
end
|
3967
3860
|
|
3968
|
-
|
3969
|
-
|
3970
|
-
|
3971
|
-
|
3861
|
+
if pair
|
3862
|
+
return pair
|
3863
|
+
end
|
3864
|
+
end
|
3972
3865
|
|
3973
|
-
|
3974
|
-
|
3975
|
-
key.children[0]
|
3976
|
-
else
|
3977
|
-
return nil
|
3978
|
-
end
|
3866
|
+
key_types = []
|
3867
|
+
value_types = []
|
3979
3868
|
|
3980
|
-
|
3981
|
-
|
3869
|
+
if AST::Builtin::Hash.instance_type?(hint)
|
3870
|
+
key_hint, value_hint = hint.args
|
3871
|
+
end
|
3982
3872
|
|
3983
|
-
|
3984
|
-
|
3985
|
-
|
3986
|
-
|
3873
|
+
hint_hash = AST::Builtin::Hash.instance_type(
|
3874
|
+
key_hint || AST::Builtin.any_type,
|
3875
|
+
value_hint || AST::Builtin.any_type
|
3876
|
+
)
|
3877
|
+
|
3878
|
+
constr = self
|
3879
|
+
|
3880
|
+
if hash_node.children.empty?
|
3881
|
+
key_types << key_hint if key_hint
|
3882
|
+
value_types << value_hint if value_hint
|
3883
|
+
else
|
3884
|
+
hash_node.children.each do |elem|
|
3885
|
+
case elem.type
|
3886
|
+
when :pair
|
3887
|
+
key_node, value_node = elem.children
|
3888
|
+
key_type, constr = constr.synthesize(key_node, hint: key_hint)
|
3889
|
+
value_type, constr = constr.synthesize(value_node, hint: value_hint)
|
3890
|
+
|
3891
|
+
key_types << key_type
|
3892
|
+
value_types << value_type
|
3893
|
+
when :kwsplat
|
3894
|
+
bypass_splat(elem) do |elem_|
|
3895
|
+
pair = constr.synthesize(elem_, hint: hint_hash)
|
3896
|
+
|
3897
|
+
if AST::Builtin::Hash.instance_type?(pair.type)
|
3898
|
+
key_types << pair.type.args[0]
|
3899
|
+
value_types << pair.type.args[1]
|
3987
3900
|
end
|
3988
3901
|
|
3989
|
-
|
3990
|
-
else
|
3991
|
-
return nil
|
3902
|
+
pair
|
3992
3903
|
end
|
3904
|
+
else
|
3905
|
+
raise
|
3993
3906
|
end
|
3907
|
+
end
|
3908
|
+
end
|
3994
3909
|
|
3995
|
-
|
3910
|
+
key_types.reject! {|ty| ty.is_a?(AST::Types::Any) }
|
3911
|
+
value_types.reject! {|ty| ty.is_a?(AST::Types::Any) }
|
3996
3912
|
|
3997
|
-
|
3998
|
-
|
3999
|
-
|
4000
|
-
|
4001
|
-
|
4002
|
-
|
4003
|
-
|
3913
|
+
key_types << AST::Builtin.any_type if key_types.empty?
|
3914
|
+
value_types << AST::Builtin.any_type if value_types.empty?
|
3915
|
+
|
3916
|
+
hash_type = AST::Builtin::Hash.instance_type(
|
3917
|
+
AST::Types::Union.build(types: key_types),
|
3918
|
+
AST::Types::Union.build(types: value_types)
|
3919
|
+
)
|
3920
|
+
constr.add_typing(hash_node, type: hash_type)
|
3921
|
+
end
|
3922
|
+
|
3923
|
+
def pick_one_of(types, range:)
|
3924
|
+
types.each do |type|
|
3925
|
+
with_child_typing(range: range) do |constr|
|
3926
|
+
type_, constr = yield type, constr
|
3927
|
+
|
3928
|
+
constr.check_relation(sub_type: type_, super_type: type).then do
|
3929
|
+
constr = constr.save_typing
|
3930
|
+
return Pair.new(type: type, constr: constr)
|
4004
3931
|
end
|
4005
3932
|
end
|
4006
|
-
nil
|
4007
3933
|
end
|
3934
|
+
|
3935
|
+
nil
|
3936
|
+
end
|
3937
|
+
|
3938
|
+
def save_typing
|
3939
|
+
typing.save!
|
3940
|
+
with_new_typing(typing.parent)
|
4008
3941
|
end
|
4009
3942
|
end
|
4010
3943
|
end
|