steep 0.44.1 → 0.45.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/.github/dependabot.yml +8 -0
- data/.github/workflows/ruby.yml +3 -2
- data/.gitignore +0 -1
- data/CHANGELOG.md +14 -0
- data/Gemfile +0 -2
- data/Gemfile.lock +77 -0
- data/lib/steep.rb +3 -1
- data/lib/steep/ast/builtin.rb +7 -1
- data/lib/steep/ast/types/factory.rb +19 -25
- data/lib/steep/diagnostic/ruby.rb +137 -60
- data/lib/steep/diagnostic/signature.rb +34 -0
- data/lib/steep/equatable.rb +21 -0
- data/lib/steep/interface/function.rb +798 -579
- data/lib/steep/server/interaction_worker.rb +238 -19
- data/lib/steep/services/file_loader.rb +26 -19
- data/lib/steep/services/hover_content.rb +131 -79
- data/lib/steep/source.rb +7 -10
- data/lib/steep/type_construction.rb +435 -502
- data/lib/steep/type_inference/block_params.rb +2 -5
- data/lib/steep/type_inference/method_params.rb +483 -0
- data/lib/steep/type_inference/send_args.rb +610 -128
- data/lib/steep/typing.rb +46 -21
- data/lib/steep/version.rb +1 -1
- data/sig/steep/type_inference/send_args.rbs +42 -0
- data/smoke/array/test_expectations.yml +3 -3
- data/smoke/block/c.rb +0 -1
- data/smoke/class/test_expectations.yml +12 -15
- data/smoke/diagnostics-rbs/mixin-class-error.rbs +6 -0
- data/smoke/diagnostics-rbs/test_expectations.yml +12 -0
- 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/ensure/test_expectations.yml +3 -3
- data/smoke/enumerator/test_expectations.yml +1 -1
- data/smoke/literal/test_expectations.yml +2 -2
- data/smoke/method/test_expectations.yml +11 -10
- data/smoke/rescue/test_expectations.yml +3 -3
- data/smoke/toplevel/test_expectations.yml +3 -3
- data/smoke/tsort/test_expectations.yml +2 -2
- data/steep.gemspec +1 -1
- metadata +13 -5
data/lib/steep/source.rb
CHANGED
@@ -35,28 +35,25 @@ module Steep
|
|
35
35
|
|
36
36
|
self.emit_lambda = true
|
37
37
|
self.emit_procarg0 = true
|
38
|
+
self.emit_kwargs = true
|
38
39
|
end
|
39
40
|
|
40
|
-
def self.
|
41
|
-
::Parser::
|
41
|
+
def self.new_parser
|
42
|
+
::Parser::Ruby30.new(Builder.new).tap do |parser|
|
42
43
|
parser.diagnostics.all_errors_are_fatal = true
|
43
44
|
parser.diagnostics.ignore_warnings = true
|
44
45
|
end
|
45
46
|
end
|
46
47
|
|
47
48
|
def self.parse(source_code, path:, factory:)
|
48
|
-
buffer = ::Parser::Source::Buffer.new(path.to_s, 1)
|
49
|
-
|
50
|
-
node = parser.parse(buffer)
|
49
|
+
buffer = ::Parser::Source::Buffer.new(path.to_s, 1, source: source_code)
|
50
|
+
node = new_parser().parse(buffer)
|
51
51
|
|
52
52
|
annotations = []
|
53
53
|
|
54
54
|
_, comments, _ = yield_self do
|
55
|
-
buffer = ::Parser::Source::Buffer.new(path.to_s)
|
56
|
-
buffer
|
57
|
-
parser = ::Parser::Ruby27.new
|
58
|
-
|
59
|
-
parser.tokenize(buffer)
|
55
|
+
buffer = ::Parser::Source::Buffer.new(path.to_s, 1, source: source_code)
|
56
|
+
new_parser().tokenize(buffer)
|
60
57
|
end
|
61
58
|
|
62
59
|
buffer = RBS::Buffer.new(name: path, content: source_code)
|
@@ -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
|
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
|