steep 0.46.0 → 0.48.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (49) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/ruby.yml +0 -1
  3. data/CHANGELOG.md +23 -0
  4. data/Gemfile +1 -2
  5. data/Gemfile.lock +18 -22
  6. data/README.md +2 -1
  7. data/lib/steep/annotation_parser.rb +1 -1
  8. data/lib/steep/ast/types/factory.rb +161 -137
  9. data/lib/steep/ast/types/var.rb +14 -3
  10. data/lib/steep/diagnostic/ruby.rb +23 -11
  11. data/lib/steep/diagnostic/signature.rb +60 -15
  12. data/lib/steep/interface/method_type.rb +14 -26
  13. data/lib/steep/interface/type_param.rb +103 -0
  14. data/lib/steep/project/dsl.rb +32 -5
  15. data/lib/steep/project/options.rb +1 -0
  16. data/lib/steep/project/target.rb +1 -0
  17. data/lib/steep/server/base_worker.rb +1 -0
  18. data/lib/steep/server/interaction_worker.rb +9 -9
  19. data/lib/steep/server/type_check_worker.rb +2 -2
  20. data/lib/steep/services/hover_content.rb +3 -0
  21. data/lib/steep/services/signature_service.rb +2 -2
  22. data/lib/steep/services/type_check_service.rb +2 -1
  23. data/lib/steep/signature/validator.rb +221 -49
  24. data/lib/steep/source.rb +5 -1
  25. data/lib/steep/subtyping/cache.rb +30 -0
  26. data/lib/steep/subtyping/check.rb +582 -708
  27. data/lib/steep/subtyping/constraints.rb +66 -30
  28. data/lib/steep/subtyping/relation.rb +60 -0
  29. data/lib/steep/subtyping/result.rb +190 -16
  30. data/lib/steep/type_construction.rb +493 -372
  31. data/lib/steep/type_inference/block_params.rb +1 -1
  32. data/lib/steep/type_inference/context.rb +37 -3
  33. data/lib/steep/type_inference/send_args.rb +1 -12
  34. data/lib/steep/version.rb +1 -1
  35. data/lib/steep.rb +5 -5
  36. data/sample/lib/length.rb +35 -0
  37. data/sample/sig/length.rbs +34 -0
  38. data/smoke/diagnostics/test_expectations.yml +4 -4
  39. data/smoke/diagnostics-rbs/nonregular-type-alias.rbs +3 -0
  40. data/smoke/diagnostics-rbs/recursive-type-alias.rbs +3 -0
  41. data/smoke/diagnostics-rbs/test_expectations.yml +57 -12
  42. data/smoke/extension/e.rbs +1 -1
  43. data/steep.gemspec +1 -1
  44. metadata +11 -10
  45. data/lib/steep/drivers/trace_printer.rb +0 -29
  46. data/lib/steep/interface/method.rb +0 -78
  47. data/lib/steep/subtyping/trace.rb +0 -71
  48. data/sig/project.rbi +0 -109
  49. data/sig/steep/type_inference/send_args.rbs +0 -42
@@ -63,6 +63,10 @@ module Steep
63
63
  context.type_env
64
64
  end
65
65
 
66
+ def variable_context
67
+ context.variable_context
68
+ end
69
+
66
70
  def initialize(checker:, source:, annotations:, typing:, context:)
67
71
  @checker = checker
68
72
  @source = source
@@ -114,13 +118,15 @@ module Steep
114
118
  def check_relation(sub_type:, super_type:, constraints: Subtyping::Constraints.empty)
115
119
  Steep.logger.debug { "check_relation: self:#{self_type}, instance:#{module_context.instance_type}, class:#{module_context.module_type} |- #{sub_type} <: #{super_type}" }
116
120
  relation = Subtyping::Relation.new(sub_type: sub_type, super_type: super_type)
117
- checker.check(
118
- relation,
119
- self_type: self_type,
120
- instance_type: module_context.instance_type,
121
- class_type: module_context.module_type,
122
- constraints: constraints
123
- )
121
+ checker.push_variable_bounds(variable_context.upper_bounds) do
122
+ checker.check(
123
+ relation,
124
+ self_type: self_type,
125
+ instance_type: module_context.instance_type,
126
+ class_type: module_context.module_type,
127
+ constraints: constraints
128
+ )
129
+ end
124
130
  end
125
131
 
126
132
  def for_new_method(method_name, node, args:, self_type:, definition:)
@@ -169,6 +175,12 @@ module Steep
169
175
  end
170
176
  end
171
177
 
178
+ if definition && method_type
179
+ variable_context = TypeInference::Context::TypeVariableContext.new(method_type.type_params, parent_context: self.variable_context)
180
+ else
181
+ variable_context = self.variable_context
182
+ end
183
+
172
184
  method_context = TypeInference::Context::MethodContext.new(
173
185
  name: method_name,
174
186
  method: definition && definition.methods[method_name],
@@ -245,12 +257,20 @@ module Steep
245
257
  self_type: annots.self_type || self_type,
246
258
  type_env: type_env,
247
259
  lvar_env: lvar_env,
248
- call_context: call_context
260
+ call_context: call_context,
261
+ variable_context: variable_context
249
262
  ),
250
263
  typing: typing,
251
264
  )
252
265
  end
253
266
 
267
+ def with_method_constr(method_name, node, args:, self_type:, definition:)
268
+ constr = for_new_method(method_name, node, args: args, self_type: self_type, definition: definition)
269
+ constr.checker.push_variable_bounds(constr.variable_context.upper_bounds) do
270
+ yield constr
271
+ end
272
+ end
273
+
254
274
  def implement_module(module_name:, super_name: nil, annotations:)
255
275
  if (annotation = annotations.implement_module_annotation)
256
276
  absolute_name(annotation.name.name).yield_self do |absolute_name|
@@ -332,7 +352,10 @@ module Steep
332
352
  module_context = default_module_context(implement_module_name, const_env: module_const_env, current_namespace: new_namespace)
333
353
 
334
354
  unless implement_module_name
335
- module_context = module_context.update(module_type: AST::Builtin::Module.instance_type)
355
+ module_context = module_context.update(
356
+ module_type: AST::Builtin::Module.instance_type,
357
+ instance_type: AST::Builtin::BasicObject.instance_type
358
+ )
336
359
  end
337
360
 
338
361
  if implement_module_name
@@ -389,6 +412,21 @@ module Steep
389
412
  class_type: module_context.module_type
390
413
  ).annotate(annots)
391
414
 
415
+ if implement_module_name
416
+ definition = checker.factory.definition_builder.build_instance(implement_module_name.name)
417
+ type_params = definition.type_params_decl.map do |param|
418
+ Interface::TypeParam.new(
419
+ name: param.name,
420
+ upper_bound: checker.factory.type_opt(param.upper_bound),
421
+ variance: param.variance,
422
+ unchecked: param.unchecked?
423
+ )
424
+ end
425
+ variable_context = TypeInference::Context::TypeVariableContext.new(type_params)
426
+ else
427
+ variable_context = TypeInference::Context::TypeVariableContext.empty
428
+ end
429
+
392
430
  self.class.new(
393
431
  checker: checker,
394
432
  source: source,
@@ -402,11 +440,19 @@ module Steep
402
440
  self_type: module_context.module_type,
403
441
  type_env: module_type_env,
404
442
  lvar_env: lvar_env,
405
- call_context: TypeInference::MethodCall::ModuleContext.new(type_name: module_context.class_name)
443
+ call_context: TypeInference::MethodCall::ModuleContext.new(type_name: module_context.class_name),
444
+ variable_context: variable_context
406
445
  )
407
446
  )
408
447
  end
409
448
 
449
+ def with_module_constr(node)
450
+ constr = for_module(node)
451
+ constr.checker.push_variable_bounds(constr.variable_context.upper_bounds) do
452
+ yield constr
453
+ end
454
+ end
455
+
410
456
  def for_class(node)
411
457
  new_class_name = module_name_from_node(node.children.first) or raise "Unexpected class name: #{node.children.first}"
412
458
  super_class_name = node.children[1] && module_name_from_node(node.children[1])
@@ -422,10 +468,7 @@ module Steep
422
468
 
423
469
  if implement_module_name
424
470
  if super_class_name && implement_module_name.name == absolute_name(super_class_name)
425
- module_context = module_context.update(
426
- instance_definition: nil,
427
- module_definition: nil
428
- )
471
+ module_context = module_context.update(instance_definition: nil, module_definition: nil)
429
472
  end
430
473
  else
431
474
  module_context = module_context.update(
@@ -446,6 +489,18 @@ module Steep
446
489
  module_context = module_context.update(module_type: annots.self_type)
447
490
  end
448
491
 
492
+ definition = checker.factory.definition_builder.build_instance(module_context.class_name)
493
+ type_params = definition.type_params_decl.map do |type_param|
494
+ Interface::TypeParam.new(
495
+ name: type_param.name,
496
+ upper_bound: type_param.upper_bound&.yield_self {|t| checker.factory.type(t) },
497
+ variance: type_param.variance,
498
+ unchecked: type_param.unchecked?,
499
+ location: type_param.location
500
+ )
501
+ end
502
+ variable_context = TypeInference::Context::TypeVariableContext.new(type_params)
503
+
449
504
  class_type_env = TypeInference::TypeEnv.build(annotations: annots,
450
505
  subtyping: checker,
451
506
  const_env: class_const_env,
@@ -466,7 +521,8 @@ module Steep
466
521
  self_type: module_context.module_type,
467
522
  type_env: class_type_env,
468
523
  lvar_env: lvar_env,
469
- call_context: TypeInference::MethodCall::ModuleContext.new(type_name: module_context.class_name)
524
+ call_context: TypeInference::MethodCall::ModuleContext.new(type_name: module_context.class_name),
525
+ variable_context: variable_context
470
526
  )
471
527
 
472
528
  self.class.new(
@@ -478,6 +534,24 @@ module Steep
478
534
  )
479
535
  end
480
536
 
537
+ def with_class_constr(node)
538
+ constr = for_class(node)
539
+
540
+ constr.checker.push_variable_bounds(constr.variable_context.upper_bounds) do
541
+ yield constr
542
+ end
543
+ end
544
+
545
+ def with_sclass_constr(node, type)
546
+ if constr = for_sclass(node, type)
547
+ constr.checker.push_variable_bounds(constr.variable_context.upper_bounds) do
548
+ yield constr
549
+ end
550
+ else
551
+ yield nil
552
+ end
553
+ end
554
+
481
555
  def for_sclass(node, type)
482
556
  annots = source.annotations(block: node, factory: checker.factory, current_module: current_namespace)
483
557
 
@@ -554,7 +628,8 @@ module Steep
554
628
  self_type: module_context.module_type,
555
629
  type_env: type_env,
556
630
  lvar_env: lvar_env,
557
- call_context: TypeInference::MethodCall::ModuleContext.new(type_name: module_context.class_name)
631
+ call_context: TypeInference::MethodCall::ModuleContext.new(type_name: module_context.class_name),
632
+ variable_context: TypeInference::Context::TypeVariableContext.empty # Assuming `::Class` and `::Module` don't have type params
558
633
  )
559
634
 
560
635
  self.class.new(
@@ -959,75 +1034,76 @@ module Steep
959
1034
  yield_self do
960
1035
  name, args_node, body_node = node.children
961
1036
 
962
- new = for_new_method(
1037
+ with_method_constr(
963
1038
  name,
964
1039
  node,
965
1040
  args: args_node.children,
966
1041
  self_type: module_context&.instance_type,
967
1042
  definition: module_context&.instance_definition
968
- )
969
- new.typing.add_context_for_node(node, context: new.context)
970
- new.typing.add_context_for_body(node, context: new.context)
971
-
972
- new.method_context.tap do |method_context|
973
- if method_context.method
974
- method_name = InstanceMethodName.new(type_name: method_context.method.implemented_in, method_name: name)
975
- new.typing.source_index.add_definition(method: method_name, definition: node)
1043
+ ) do |new|
1044
+ new.typing.add_context_for_node(node, context: new.context)
1045
+ new.typing.add_context_for_body(node, context: new.context)
1046
+
1047
+ new.method_context.tap do |method_context|
1048
+ if method_context.method
1049
+ method_name = InstanceMethodName.new(type_name: method_context.method.implemented_in, method_name: name)
1050
+ new.typing.source_index.add_definition(method: method_name, definition: node)
1051
+ end
976
1052
  end
977
- end
978
-
979
- new = new.synthesize_children(args_node)
980
1053
 
981
- body_pair = if body_node
982
- return_type = expand_alias(new.method_context&.return_type)
983
- if return_type && !return_type.is_a?(AST::Types::Void)
984
- new.check(body_node, return_type) do |_, actual_type, result|
985
- typing.add_error(
986
- Diagnostic::Ruby::MethodBodyTypeMismatch.new(
987
- node: node,
988
- expected: new.method_context&.return_type,
989
- actual: actual_type,
990
- result: result
1054
+ new = new.synthesize_children(args_node)
1055
+
1056
+ body_pair = if body_node
1057
+ return_type = expand_alias(new.method_context&.return_type)
1058
+ if return_type && !return_type.is_a?(AST::Types::Void)
1059
+ new.check(body_node, return_type) do |_, actual_type, result|
1060
+ typing.add_error(
1061
+ Diagnostic::Ruby::MethodBodyTypeMismatch.new(
1062
+ node: node,
1063
+ expected: new.method_context&.return_type,
1064
+ actual: actual_type,
1065
+ result: result
1066
+ )
991
1067
  )
992
- )
1068
+ end
1069
+ else
1070
+ new.synthesize(body_node)
993
1071
  end
994
1072
  else
995
- new.synthesize(body_node)
996
- end
997
- else
998
- return_type = expand_alias(new.method_context&.return_type)
999
- if return_type && !return_type.is_a?(AST::Types::Void)
1000
- result = check_relation(sub_type: AST::Builtin.nil_type, super_type: return_type)
1001
- if result.failure?
1002
- typing.add_error(
1003
- Diagnostic::Ruby::MethodBodyTypeMismatch.new(
1004
- node: node,
1005
- expected: new.method_context&.return_type,
1006
- actual: AST::Builtin.nil_type,
1007
- result: result
1073
+ return_type = expand_alias(new.method_context&.return_type)
1074
+ if return_type && !return_type.is_a?(AST::Types::Void)
1075
+ result = check_relation(sub_type: AST::Builtin.nil_type, super_type: return_type)
1076
+ if result.failure?
1077
+ typing.add_error(
1078
+ Diagnostic::Ruby::MethodBodyTypeMismatch.new(
1079
+ node: node,
1080
+ expected: new.method_context&.return_type,
1081
+ actual: AST::Builtin.nil_type,
1082
+ result: result
1083
+ )
1008
1084
  )
1009
- )
1085
+ end
1010
1086
  end
1087
+
1088
+ Pair.new(type: AST::Builtin.nil_type, constr: new)
1011
1089
  end
1012
1090
 
1013
- Pair.new(type: AST::Builtin.nil_type, constr: new)
1014
- end
1091
+ if body_node
1092
+ # Add context to ranges from the end of the method body to the beginning of the `end` keyword
1093
+ if node.loc.end
1094
+ # Skip end-less def
1095
+ begin_pos = body_node.loc.expression.end_pos
1096
+ end_pos = node.loc.end.begin_pos
1097
+ typing.add_context(begin_pos..end_pos, context: body_pair.context)
1098
+ end
1099
+ end
1015
1100
 
1016
- if body_node
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)
1101
+ if module_context
1102
+ module_context.defined_instance_methods << node.children[0]
1023
1103
  end
1024
- end
1025
1104
 
1026
- if module_context
1027
- module_context.defined_instance_methods << node.children[0]
1105
+ add_typing(node, type: AST::Builtin::Symbol.instance_type)
1028
1106
  end
1029
-
1030
- add_typing(node, type: AST::Builtin::Symbol.instance_type)
1031
1107
  end
1032
1108
 
1033
1109
  when :defs
@@ -1109,12 +1185,14 @@ module Steep
1109
1185
  method_return_type = expand_alias(method_context&.return_type)
1110
1186
 
1111
1187
  return_types = node.children.map do |value|
1112
- synthesize(value,
1113
- hint: if method_return_type.is_a?(AST::Types::Void)
1114
- nil
1115
- else
1116
- method_return_type
1117
- end).type
1188
+ synthesize(
1189
+ value,
1190
+ hint: if method_return_type.is_a?(AST::Types::Void)
1191
+ nil
1192
+ else
1193
+ method_return_type
1194
+ end
1195
+ ).type
1118
1196
  end
1119
1197
 
1120
1198
  value_type = if return_types.size == 1
@@ -1427,7 +1505,7 @@ module Steep
1427
1505
  end
1428
1506
  _, constr = constr.synthesize(sup) if sup
1429
1507
 
1430
- constr.for_class(node).tap do |constructor|
1508
+ with_class_constr(node) do |constructor|
1431
1509
  if module_type = constructor.module_context&.module_type
1432
1510
  _, constructor = constructor.add_typing(name, type: module_type)
1433
1511
  else
@@ -1467,7 +1545,7 @@ module Steep
1467
1545
  _, constr = constr.synthesize(name)
1468
1546
  end
1469
1547
 
1470
- for_module(node).yield_self do |constructor|
1548
+ with_module_constr(node) do |constructor|
1471
1549
  if module_type = constructor.module_context&.module_type
1472
1550
  _, constructor = constructor.add_typing(name, type: module_type)
1473
1551
  else
@@ -1495,27 +1573,28 @@ module Steep
1495
1573
  when :sclass
1496
1574
  yield_self do
1497
1575
  type, constr = synthesize(node.children[0])
1498
- constructor = constr.for_sclass(node, type)
1499
1576
 
1500
- unless constructor
1501
- typing.add_error(
1502
- Diagnostic::Ruby::UnsupportedSyntax.new(
1503
- node: node,
1504
- message: "sclass receiver must be instance type or singleton type, but type given `#{type}`"
1577
+ with_sclass_constr(node, type) do |constructor|
1578
+ unless constructor
1579
+ typing.add_error(
1580
+ Diagnostic::Ruby::UnsupportedSyntax.new(
1581
+ node: node,
1582
+ message: "sclass receiver must be instance type or singleton type, but type given `#{type}`"
1583
+ )
1505
1584
  )
1506
- )
1507
- constr.add_typing(node, type: AST::Builtin.nil_type)
1508
- return
1509
- end
1585
+ constr.add_typing(node, type: AST::Builtin.nil_type)
1586
+ return
1587
+ end
1510
1588
 
1511
- constructor.typing.add_context_for_node(node, context: constructor.context)
1512
- constructor.typing.add_context_for_body(node, context: constructor.context)
1589
+ constructor.typing.add_context_for_node(node, context: constructor.context)
1590
+ constructor.typing.add_context_for_body(node, context: constructor.context)
1513
1591
 
1514
- constructor.synthesize(node.children[1]) if node.children[1]
1592
+ constructor.synthesize(node.children[1]) if node.children[1]
1515
1593
 
1516
- if constructor.module_context.instance_definition && module_context.module_definition
1517
- if constructor.module_context.instance_definition.type_name == module_context.module_definition.type_name
1518
- module_context.defined_module_methods.merge(constructor.module_context.defined_instance_methods)
1594
+ if constructor.module_context.instance_definition && module_context.module_definition
1595
+ if constructor.module_context.instance_definition.type_name == module_context.module_definition.type_name
1596
+ module_context.defined_module_methods.merge(constructor.module_context.defined_instance_methods)
1597
+ end
1519
1598
  end
1520
1599
  end
1521
1600
 
@@ -1573,8 +1652,7 @@ module Steep
1573
1652
  instance_type: module_context.instance_type,
1574
1653
  class_type: module_context.module_type
1575
1654
  ) do |error|
1576
- case error
1577
- when Subtyping::Result::Failure
1655
+ if error
1578
1656
  const_type = type_env.get(const: const_name)
1579
1657
  typing.add_error(
1580
1658
  Diagnostic::Ruby::IncompatibleAssignment.new(
@@ -1584,7 +1662,7 @@ module Steep
1584
1662
  result: error
1585
1663
  )
1586
1664
  )
1587
- when nil
1665
+ else
1588
1666
  typing.add_error(
1589
1667
  Diagnostic::Ruby::UnknownConstantAssigned.new(
1590
1668
  node: node,
@@ -2385,7 +2463,7 @@ module Steep
2385
2463
  raise "#synthesize should return an instance of Pair: #{pair.class}, node=#{node.inspect}"
2386
2464
  end
2387
2465
  end
2388
- rescue RBS::ErrorBase => exn
2466
+ rescue RBS::BaseError => exn
2389
2467
  Steep.logger.warn { "Unexpected RBS error: #{exn.message}" }
2390
2468
  exn.backtrace.each {|loc| Steep.logger.warn " #{loc}" }
2391
2469
  typing.add_error(Diagnostic::Ruby::UnexpectedError.new(node: node, error: exn))
@@ -2411,6 +2489,7 @@ module Steep
2411
2489
 
2412
2490
  def type_ivasgn(name, rhs, node)
2413
2491
  rhs_type = synthesize(rhs, hint: type_env.get(ivar: name) { fallback_to_any(node) }).type
2492
+
2414
2493
  ivar_type = type_env.assign(
2415
2494
  ivar: name,
2416
2495
  type: rhs_type,
@@ -2418,8 +2497,7 @@ module Steep
2418
2497
  instance_type: module_context.instance_type,
2419
2498
  class_type: module_context.module_type
2420
2499
  ) do |error|
2421
- case error
2422
- when Subtyping::Result::Failure
2500
+ if error
2423
2501
  type = type_env.get(ivar: name)
2424
2502
  typing.add_error(
2425
2503
  Diagnostic::Ruby::IncompatibleAssignment.new(
@@ -2429,7 +2507,7 @@ module Steep
2429
2507
  result: error
2430
2508
  )
2431
2509
  )
2432
- when nil
2510
+ else
2433
2511
  fallback_to_any node
2434
2512
  end
2435
2513
  end
@@ -2473,8 +2551,7 @@ module Steep
2473
2551
  instance_type: module_context.instance_type,
2474
2552
  class_type: module_context.module_type
2475
2553
  ) do |error|
2476
- case error
2477
- when Subtyping::Result::Failure
2554
+ if error
2478
2555
  var_type = type_env.get(ivar: ivar)
2479
2556
  typing.add_error(
2480
2557
  Diagnostic::Ruby::IncompatibleAssignment.new(
@@ -2484,7 +2561,7 @@ module Steep
2484
2561
  result: error
2485
2562
  )
2486
2563
  )
2487
- when nil
2564
+ else
2488
2565
  fallback_to_any node
2489
2566
  end
2490
2567
  end
@@ -2830,6 +2907,32 @@ module Steep
2830
2907
  )
2831
2908
  )
2832
2909
 
2910
+ when AST::Types::Var
2911
+ if upper_bound = variable_context[receiver_type.name]
2912
+ interface = calculate_interface(upper_bound, private: false)
2913
+
2914
+ constr.type_send_interface(
2915
+ node,
2916
+ interface: interface,
2917
+ receiver: receiver,
2918
+ receiver_type: receiver_type,
2919
+ method_name: method_name,
2920
+ arguments: arguments,
2921
+ block_params: block_params,
2922
+ block_body: block_body
2923
+ )
2924
+ else
2925
+ constr = constr.synthesize_children(node, skips: [receiver])
2926
+ constr.add_call(
2927
+ TypeInference::MethodCall::NoMethodError.new(
2928
+ node: node,
2929
+ context: context.method_context,
2930
+ method_name: method_name,
2931
+ receiver_type: receiver_type,
2932
+ error: Diagnostic::Ruby::NoMethod.new(node: node, method: method_name, type: receiver_type)
2933
+ )
2934
+ )
2935
+ end
2833
2936
  when AST::Types::Void, AST::Types::Bot, AST::Types::Top, AST::Types::Var
2834
2937
  constr = constr.synthesize_children(node, skips: [receiver])
2835
2938
  constr.add_call(
@@ -2872,6 +2975,7 @@ module Steep
2872
2975
  block_params: block_params,
2873
2976
  block_body: block_body)
2874
2977
  end
2978
+
2875
2979
  else
2876
2980
  interface = calculate_interface(receiver_type, private: private, self_type: receiver_type)
2877
2981
 
@@ -2991,115 +3095,161 @@ module Steep
2991
3095
  end
2992
3096
  end
2993
3097
 
3098
+ def apply_solution(errors, node:, method_type:)
3099
+ subst = yield
3100
+
3101
+ [
3102
+ method_type.subst(subst),
3103
+ true,
3104
+ subst
3105
+ ]
3106
+
3107
+ rescue Subtyping::Constraints::UnsatisfiableConstraint => exn
3108
+ errors << Diagnostic::Ruby::UnsatisfiableConstraint.new(
3109
+ node: node,
3110
+ method_type: method_type,
3111
+ var: exn.var,
3112
+ sub_type: exn.sub_type,
3113
+ super_type: exn.super_type,
3114
+ result: exn.result
3115
+ )
3116
+ [method_type, false, Interface::Substitution.empty]
3117
+ end
3118
+
3119
+ def eliminate_vars(type, variables, to: AST::Builtin.any_type)
3120
+ if variables.empty?
3121
+ type
3122
+ else
3123
+ subst = Interface::Substitution.build(variables, Array.new(variables.size, to))
3124
+ type.subst(subst)
3125
+ end
3126
+ end
3127
+
2994
3128
  def try_method_type(node, receiver_type:, method_name:, method_type:, arguments:, block_params:, block_body:, topdown_hint:)
2995
- fresh_types = method_type.type_params.map {|x| AST::Types::Var.fresh(x)}
2996
- fresh_vars = Set.new(fresh_types.map(&:name))
2997
- instantiation = Interface::Substitution.build(method_type.type_params, fresh_types)
3129
+ type_params, instantiation = Interface::TypeParam.rename(method_type.type_params)
3130
+ type_param_names = type_params.map(&:name)
2998
3131
 
2999
3132
  constr = self
3000
3133
 
3001
3134
  method_type = method_type.instantiate(instantiation)
3002
3135
 
3003
- constraints = Subtyping::Constraints.new(unknowns: fresh_types.map(&:name))
3004
3136
  variance = Subtyping::VariableVariance.from_method_type(method_type)
3005
3137
  occurence = Subtyping::VariableOccurence.from_method_type(method_type)
3138
+ constraints = Subtyping::Constraints.new(unknowns: type_params.map(&:name))
3139
+ ccontext = Subtyping::Constraints::Context.new(
3140
+ self_type: self_type,
3141
+ instance_type: module_context.instance_type,
3142
+ class_type: module_context.module_type,
3143
+ variance: variance
3144
+ )
3006
3145
 
3007
- errors = []
3146
+ upper_bounds = {}
3008
3147
 
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
- )
3148
+ type_params.each do |param|
3149
+ if ub = param.upper_bound
3150
+ constraints.add(param.name, super_type: ub, skip: true)
3151
+ upper_bounds[param.name] = ub
3152
+ end
3153
+ end
3020
3154
 
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,
3155
+ checker.push_variable_bounds(upper_bounds) do
3156
+ errors = []
3157
+
3158
+ args = TypeInference::SendArgs.new(node: node, arguments: arguments, method_name: method_name, method_type: method_type)
3159
+ es = args.each do |arg|
3160
+ case arg
3161
+ when TypeInference::SendArgs::PositionalArgs::NodeParamPair
3162
+ _, constr = constr.type_check_argument(
3163
+ arg.node,
3164
+ type: arg.param.type,
3026
3165
  receiver_type: receiver_type,
3027
3166
  constraints: constraints,
3028
- report_node: arg.node,
3029
3167
  errors: errors
3030
3168
  )
3031
- end
3032
3169
 
3033
- when TypeInference::SendArgs::PositionalArgs::UnexpectedArg
3034
- _, constr = bypass_splat(arg.node) do |n|
3035
- constr.synthesize(n)
3036
- end
3037
-
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|
3170
+ when TypeInference::SendArgs::PositionalArgs::NodeTypePair
3171
+ _, constr = bypass_splat(arg.node) do |n|
3050
3172
  constr.type_check_argument(
3051
- node,
3052
- type: type,
3173
+ n,
3174
+ type: arg.node_type,
3053
3175
  receiver_type: receiver_type,
3054
3176
  constraints: constraints,
3177
+ report_node: arg.node,
3055
3178
  errors: errors
3056
3179
  )
3057
3180
  end
3058
- end
3059
3181
 
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
3182
+ when TypeInference::SendArgs::PositionalArgs::UnexpectedArg
3066
3183
  _, constr = bypass_splat(arg.node) do |n|
3067
3184
  constr.synthesize(n)
3068
3185
  end
3069
- end
3070
3186
 
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
3187
+ when TypeInference::SendArgs::PositionalArgs::SplatArg
3188
+ arg_type, _ = constr
3189
+ .with_child_typing(range: arg.node.loc.expression.begin_pos ... arg.node.loc.expression.end_pos)
3190
+ .try_tuple_type!(arg.node.children[0])
3191
+ arg.type = arg_type
3192
+
3193
+ when TypeInference::SendArgs::PositionalArgs::MissingArg
3194
+ # ignore
3195
+
3196
+ when TypeInference::SendArgs::KeywordArgs::ArgTypePairs
3197
+ arg.pairs.each do |node, type|
3198
+ _, constr = bypass_splat(node) do |node|
3199
+ constr.type_check_argument(
3200
+ node,
3201
+ type: type,
3202
+ receiver_type: receiver_type,
3203
+ constraints: constraints,
3204
+ errors: errors
3205
+ )
3206
+ end
3075
3207
  end
3076
3208
 
3077
- constr.synthesize(sp_node)
3078
- end
3209
+ when TypeInference::SendArgs::KeywordArgs::UnexpectedKeyword
3210
+ if arg.node.type == :pair
3211
+ arg.node.children.each do |nn|
3212
+ _, constr = constr.synthesize(nn)
3213
+ end
3214
+ else
3215
+ _, constr = bypass_splat(arg.node) do |n|
3216
+ constr.synthesize(n)
3217
+ end
3218
+ end
3079
3219
 
3080
- arg.type = type
3220
+ when TypeInference::SendArgs::KeywordArgs::SplatArg
3221
+ type, _ = bypass_splat(arg.node) do |sp_node|
3222
+ if sp_node.type == :hash
3223
+ pair = constr.type_hash_record(sp_node, nil) and break pair
3224
+ end
3081
3225
 
3082
- when TypeInference::SendArgs::KeywordArgs::MissingKeyword
3083
- # ignore
3084
- else
3085
- raise arg.inspect
3086
- end
3226
+ constr.synthesize(sp_node)
3227
+ end
3087
3228
 
3088
- constr
3089
- end
3229
+ arg.type = type
3230
+
3231
+ when TypeInference::SendArgs::KeywordArgs::MissingKeyword
3232
+ # ignore
3233
+ else
3234
+ raise arg.inspect
3235
+ end
3236
+
3237
+ constr
3238
+ end
3090
3239
 
3091
- errors.push(*es)
3240
+ errors.push(*es)
3092
3241
 
3093
- if block_params
3094
- # block is given
3095
- block_annotations = source.annotations(block: node, factory: checker.factory, current_module: current_namespace)
3096
- block_params_ = TypeInference::BlockParams.from_node(block_params, annotations: block_annotations)
3242
+ if block_params
3243
+ # block is given
3244
+ block_annotations = source.annotations(block: node, factory: checker.factory, current_module: current_namespace)
3245
+ block_params_ = TypeInference::BlockParams.from_node(block_params, annotations: block_annotations)
3097
3246
 
3098
- if method_type.block
3099
- pairs = method_type.block && block_params_&.zip(method_type.block.type.params)
3247
+ if method_type.block
3248
+ # Method accepts block
3249
+ pairs = method_type.block && block_params_&.zip(method_type.block.type.params)
3100
3250
 
3101
- if pairs
3102
- begin
3251
+ if pairs
3252
+ # Block parameters are compatible with the block type
3103
3253
  block_constr = constr.for_block(
3104
3254
  block_params: block_params_,
3105
3255
  block_param_hint: method_type.block.type.params,
@@ -3131,236 +3281,206 @@ module Steep
3131
3281
  end
3132
3282
  end
3133
3283
 
3134
- s = constraints.solution(
3135
- checker,
3136
- self_type: self_type,
3137
- instance_type: module_context.instance_type,
3138
- class_type: module_context.module_type,
3139
- variance: variance,
3140
- variables: method_type.type.params.free_variables + method_type.block.type.params.free_variables
3141
- )
3142
- method_type = method_type.subst(s)
3143
- block_constr = block_constr.update_lvar_env {|env| env.subst(s) }
3144
- if block_body
3145
- block_body_type = block_constr.synthesize_block(
3146
- node: node,
3147
- block_body: block_body,
3148
- block_type_hint: method_type.block.type.return_type
3284
+ method_type, solved, s = apply_solution(errors, node: node, method_type: method_type) {
3285
+ constraints.solution(
3286
+ checker,
3287
+ variables: method_type.type.params.free_variables + method_type.block.type.params.free_variables,
3288
+ context: ccontext
3149
3289
  )
3150
- else
3151
- block_body_type = AST::Builtin.nil_type
3152
- end
3290
+ }
3291
+
3292
+ if solved
3293
+ # Ready for type check the body of the block
3294
+ block_constr = block_constr.update_lvar_env {|env| env.subst(s) }
3295
+ if block_body
3296
+ block_body_type = block_constr.synthesize_block(
3297
+ node: node,
3298
+ block_body: block_body,
3299
+ block_type_hint: method_type.block.type.return_type
3300
+ )
3301
+ else
3302
+ block_body_type = AST::Builtin.nil_type
3303
+ end
3153
3304
 
3154
- result = check_relation(sub_type: block_body_type,
3155
- super_type: method_type.block.type.return_type,
3156
- constraints: constraints)
3305
+ result = check_relation(sub_type: block_body_type,
3306
+ super_type: method_type.block.type.return_type,
3307
+ constraints: constraints)
3157
3308
 
3158
- case result
3159
- when Subtyping::Result::Success
3160
- s = constraints.solution(
3161
- checker,
3162
- self_type: self_type,
3163
- instance_type: module_context.instance_type,
3164
- class_type: module_context.module_type,
3165
- variance: variance,
3166
- variables: fresh_vars
3167
- )
3168
- method_type = method_type.subst(s)
3309
+ if result.success?
3310
+ # Successfully type checked the body
3311
+ method_type, solved, _ = apply_solution(errors, node: node, method_type: method_type) do
3312
+ constraints.solution(checker, variables: type_param_names, context: ccontext)
3313
+ end
3314
+ method_type = eliminate_vars(method_type, type_param_names) unless solved
3169
3315
 
3170
- return_type = method_type.type.return_type
3171
- if break_type = block_annotations.break_type
3172
- return_type = union_type(break_type, return_type)
3316
+ return_type = method_type.type.return_type
3317
+ if break_type = block_annotations.break_type
3318
+ return_type = union_type(break_type, return_type)
3319
+ end
3320
+ else
3321
+ # The block body has incompatible type
3322
+ errors << Diagnostic::Ruby::BlockBodyTypeMismatch.new(
3323
+ node: node,
3324
+ expected: method_type.block.type.return_type,
3325
+ actual: block_body_type,
3326
+ result: result
3327
+ )
3328
+
3329
+ method_type = eliminate_vars(method_type, type_param_names)
3330
+ return_type = method_type.type.return_type
3173
3331
  end
3174
3332
 
3175
- when Subtyping::Result::Failure
3176
- errors << Diagnostic::Ruby::BlockBodyTypeMismatch.new(
3177
- node: node,
3178
- expected: method_type.block.type.return_type,
3179
- actual: block_body_type,
3180
- result: result
3181
- )
3333
+ block_constr.typing.save!
3334
+ else
3335
+ # Failed to infer the type of block parameters
3336
+ constr.type_block_without_hint(node: node, block_annotations: block_annotations, block_params: block_params_, block_body: block_body) do |error|
3337
+ errors << error
3338
+ end
3182
3339
 
3340
+ method_type = eliminate_vars(method_type, type_param_names)
3183
3341
  return_type = method_type.type.return_type
3184
3342
  end
3185
-
3186
- block_constr.typing.save!
3187
-
3188
- rescue Subtyping::Constraints::UnsatisfiableConstraint => exn
3189
- errors << Diagnostic::Ruby::UnsatisfiableConstraint.new(
3190
- node: node,
3191
- method_type: method_type,
3192
- var: exn.var,
3193
- sub_type: exn.sub_type,
3194
- super_type: exn.super_type,
3195
- result: exn.result
3343
+ else
3344
+ # Block parameters are unsupported syntax
3345
+ errors << Diagnostic::Ruby::UnsupportedSyntax.new(
3346
+ node: block_params,
3347
+ message: "Unsupported block params pattern, probably masgn?"
3196
3348
  )
3197
3349
 
3198
- constr.type_block_without_hint(node: node, block_annotations: block_annotations, block_params: block_params_, block_body: block_body) do |error|
3199
- errors << error
3200
- end
3350
+ method_type, solved, _ = apply_solution(errors, node: node, method_type: method_type) {
3351
+ constraints.solution(checker, variables: type_param_names, context: ccontext)
3352
+ }
3353
+ method_type = eliminate_vars(method_type, type_param_names) unless solved
3201
3354
 
3202
- s = Interface::Substitution.build(method_type.free_variables,
3203
- Array.new(method_type.free_variables.size, AST::Builtin.any_type))
3204
- method_type = method_type.subst(s)
3355
+ return_type = method_type.type.return_type
3205
3356
  end
3206
3357
  else
3207
- errors << Diagnostic::Ruby::UnsupportedSyntax.new(
3208
- node: block_params,
3209
- message: "Unsupported block params pattern, probably masgn?"
3210
- )
3358
+ # Block is given but method doesn't accept
3359
+ #
3360
+ constr.type_block_without_hint(node: node, block_annotations: block_annotations, block_params: block_params_, block_body: block_body) do |error|
3361
+ errors << error
3362
+ end
3211
3363
 
3212
- s = constraints.solution(
3213
- checker,
3214
- variance: variance,
3215
- variables: fresh_vars,
3216
- self_type: self_type,
3217
- instance_type: module_context.instance_type,
3218
- class_type: module_context.module_type
3364
+ errors << Diagnostic::Ruby::UnexpectedBlockGiven.new(
3365
+ node: node,
3366
+ method_type: method_type
3219
3367
  )
3220
- method_type = method_type.subst(s)
3368
+
3369
+ method_type = eliminate_vars(method_type, type_param_names)
3370
+ return_type = method_type.type.return_type
3221
3371
  end
3222
3372
  else
3223
- # Block is given but method doesn't accept
3224
- #
3225
- constr.type_block_without_hint(node: node, block_annotations: block_annotations, block_params: block_params_, block_body: block_body) do |error|
3226
- errors << error
3227
- end
3373
+ # Block syntax is not given
3374
+ arg = args.block_pass_arg
3375
+
3376
+ case
3377
+ when arg.compatible?
3378
+ if arg.node
3379
+ # Block pass (&block) is given
3380
+ node_type, constr = constr.synthesize(arg.node, hint: arg.node_type)
3381
+
3382
+ nil_given =
3383
+ constr.check_relation(sub_type: node_type, super_type: AST::Builtin.nil_type).success? &&
3384
+ !node_type.is_a?(AST::Types::Any)
3385
+
3386
+ if nil_given
3387
+ # nil is given ==> no block arg node is given
3388
+ method_type, solved, _ = apply_solution(errors, node: node, method_type: method_type) {
3389
+ constraints.solution(checker, variables: method_type.free_variables, context: ccontext)
3390
+ }
3391
+ method_type = eliminate_vars(method_type, type_param_names) unless solved
3228
3392
 
3229
- errors << Diagnostic::Ruby::UnexpectedBlockGiven.new(
3230
- node: node,
3231
- method_type: method_type
3232
- )
3233
- end
3234
- else
3235
- arg = args.block_pass_arg
3393
+ # Passing no block
3394
+ errors << Diagnostic::Ruby::RequiredBlockMissing.new(
3395
+ node: node,
3396
+ method_type: method_type
3397
+ )
3398
+ else
3399
+ # non-nil value is given
3400
+ constr.check_relation(sub_type: node_type, super_type: arg.node_type, constraints: constraints).else do |result|
3401
+ errors << Diagnostic::Ruby::BlockTypeMismatch.new(
3402
+ node: arg.node,
3403
+ expected: arg.node_type,
3404
+ actual: node_type,
3405
+ result: result
3406
+ )
3407
+ end
3236
3408
 
3237
- case
3238
- when arg.compatible?
3239
- if arg.node
3240
- subst = constraints.solution(
3241
- checker,
3242
- self_type: self_type,
3243
- instance_type: module_context.instance_type,
3244
- class_type: module_context.module_type,
3245
- variance: variance,
3246
- variables: occurence.params
3247
- )
3409
+ method_type, solved, _ = apply_solution(errors, node: node, method_type: method_type) {
3410
+ constraints.solution(checker, variables: method_type.free_variables, context: ccontext)
3411
+ }
3412
+ method_type = eliminate_vars(method_type, type_param_names) unless solved
3413
+ end
3414
+ else
3415
+ # Block is not given
3416
+ method_type, solved, _ = apply_solution(errors, node: node, method_type: method_type) {
3417
+ constraints.solution(checker, variables: method_type.free_variables, context: ccontext)
3418
+ }
3419
+ method_type = eliminate_vars(method_type, type_param_names) unless solved
3420
+ end
3248
3421
 
3249
- block_type = arg.node_type.subst(subst)
3422
+ return_type = method_type.type.return_type
3250
3423
 
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)
3424
+ when arg.block_missing?
3425
+ # Block is required but not given
3426
+ method_type, solved, _ = apply_solution(errors, node: node, method_type: method_type) {
3427
+ constraints.solution(checker, variables: method_type.free_variables, context: ccontext)
3428
+ }
3255
3429
 
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
3430
+ method_type = eliminate_vars(method_type, type_param_names) unless solved
3431
+ return_type = method_type.type.return_type
3266
3432
 
3267
- subst = constraints.solution(
3268
- checker,
3269
- self_type: self_type,
3270
- instance_type: module_context.instance_type,
3271
- class_type: module_context.module_type,
3272
- variance: variance,
3273
- variables: method_type.free_variables
3433
+ errors << Diagnostic::Ruby::RequiredBlockMissing.new(
3434
+ node: node,
3435
+ method_type: method_type
3274
3436
  )
3275
3437
 
3276
- method_type = method_type.subst(subst)
3438
+ when arg.unexpected_block?
3439
+ # Unexpected block is given
3440
+ method_type, solved, _ = apply_solution(errors, node: node, method_type: method_type) {
3441
+ constraints.solution(checker, variables: method_type.free_variables, context: ccontext)
3442
+ }
3443
+ method_type = eliminate_vars(method_type, type_param_names) unless solved
3444
+ return_type = method_type.type.return_type
3277
3445
 
3278
- if nil_block && arg.block.required?
3279
- # Passing no block
3280
- errors << Diagnostic::Ruby::RequiredBlockMissing.new(
3446
+ node_type, constr = constr.synthesize(arg.node)
3447
+
3448
+ unless constr.check_relation(sub_type: node_type, super_type: AST::Builtin.nil_type).success?
3449
+ errors << Diagnostic::Ruby::UnexpectedBlockGiven.new(
3281
3450
  node: node,
3282
3451
  method_type: method_type
3283
3452
  )
3284
3453
  end
3285
- else
3286
- subst = constraints.solution(
3287
- checker,
3288
- self_type: self_type,
3289
- instance_type: module_context.instance_type,
3290
- class_type: module_context.module_type,
3291
- variance: variance,
3292
- variables: method_type.free_variables
3293
- )
3294
-
3295
- method_type = method_type.subst(subst)
3296
- end
3297
-
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
- )
3334
3454
  end
3335
3455
  end
3336
- end
3337
3456
 
3338
- call = if errors.empty?
3339
- TypeInference::MethodCall::Typed.new(
3340
- node: node,
3341
- context: context.method_context,
3342
- receiver_type: receiver_type,
3343
- method_name: method_name,
3344
- actual_method_type: method_type,
3345
- return_type: return_type || method_type.type.return_type,
3346
- method_decls: method_type.method_decls
3347
- )
3348
- else
3349
- TypeInference::MethodCall::Error.new(
3350
- node: node,
3351
- context: context.method_context,
3352
- receiver_type: receiver_type,
3353
- method_name: method_name,
3354
- return_type: return_type || method_type.type.return_type,
3355
- method_decls: method_type.method_decls,
3356
- errors: errors
3357
- )
3358
- end
3359
-
3360
- [
3361
- call,
3362
- constr
3363
- ]
3457
+ call = if errors.empty?
3458
+ TypeInference::MethodCall::Typed.new(
3459
+ node: node,
3460
+ context: context.method_context,
3461
+ receiver_type: receiver_type,
3462
+ method_name: method_name,
3463
+ actual_method_type: method_type,
3464
+ return_type: return_type || method_type.type.return_type,
3465
+ method_decls: method_type.method_decls
3466
+ )
3467
+ else
3468
+ TypeInference::MethodCall::Error.new(
3469
+ node: node,
3470
+ context: context.method_context,
3471
+ receiver_type: receiver_type,
3472
+ method_name: method_name,
3473
+ return_type: return_type || method_type.type.return_type,
3474
+ method_decls: method_type.method_decls,
3475
+ errors: errors
3476
+ )
3477
+ end
3478
+
3479
+ [
3480
+ call,
3481
+ constr
3482
+ ]
3483
+ end
3364
3484
  end
3365
3485
 
3366
3486
  def type_check_argument(node, receiver_type:, type:, constraints:, report_node: node, errors:)
@@ -3485,7 +3605,8 @@ module Steep
3485
3605
  self_type: self_type,
3486
3606
  type_env: type_env.dup,
3487
3607
  lvar_env: lvar_env,
3488
- call_context: self.context.call_context
3608
+ call_context: self.context.call_context,
3609
+ variable_context: variable_context
3489
3610
  )
3490
3611
  )
3491
3612
  end
@@ -3798,7 +3919,7 @@ module Steep
3798
3919
  # `record_type` can be nil when the keys are not specified.
3799
3920
  #
3800
3921
  def type_hash_record(hash_node, record_type)
3801
- raise unless hash_node.type == :hash
3922
+ raise unless hash_node.type == :hash || hash_node.type == :kwargs
3802
3923
 
3803
3924
  constr = self
3804
3925