steep 0.47.1 → 0.48.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.
@@ -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