steep 0.49.1 → 0.52.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.
Files changed (40) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +22 -0
  3. data/Gemfile +4 -1
  4. data/Gemfile.lock +8 -5
  5. data/lib/steep/ast/annotation/collection.rb +10 -8
  6. data/lib/steep/ast/types/factory.rb +5 -5
  7. data/lib/steep/cli.rb +83 -1
  8. data/lib/steep/diagnostic/deprecated/unknown_constant_assigned.rb +28 -0
  9. data/lib/steep/diagnostic/ruby.rb +21 -15
  10. data/lib/steep/drivers/check.rb +1 -0
  11. data/lib/steep/drivers/langserver.rb +2 -2
  12. data/lib/steep/drivers/stats.rb +1 -0
  13. data/lib/steep/drivers/utils/jobs_count.rb +1 -1
  14. data/lib/steep/drivers/watch.rb +1 -1
  15. data/lib/steep/index/source_index.rb +18 -1
  16. data/lib/steep/interface/function.rb +5 -0
  17. data/lib/steep/module_helper.rb +4 -7
  18. data/lib/steep/project.rb +15 -1
  19. data/lib/steep/server/interaction_worker.rb +47 -4
  20. data/lib/steep/server/master.rb +10 -5
  21. data/lib/steep/server/type_check_worker.rb +19 -4
  22. data/lib/steep/server/worker_process.rb +15 -6
  23. data/lib/steep/services/completion_provider.rb +109 -1
  24. data/lib/steep/services/goto_service.rb +23 -10
  25. data/lib/steep/services/hover_content.rb +52 -4
  26. data/lib/steep/services/type_check_service.rb +6 -3
  27. data/lib/steep/source.rb +71 -18
  28. data/lib/steep/type_construction.rb +209 -162
  29. data/lib/steep/type_inference/constant_env.rb +33 -15
  30. data/lib/steep/type_inference/context.rb +6 -7
  31. data/lib/steep/type_inference/type_env.rb +16 -54
  32. data/lib/steep/version.rb +1 -1
  33. data/smoke/const/test_expectations.yml +24 -19
  34. data/smoke/diagnostics/test_expectations.yml +77 -17
  35. data/smoke/integer/test_expectations.yml +24 -4
  36. data/smoke/method/test_expectations.yml +30 -0
  37. data/smoke/regression/test_expectations.yml +24 -0
  38. data/smoke/yield/test_expectations.yml +20 -0
  39. data/steep.gemspec +1 -1
  40. metadata +5 -4
@@ -130,9 +130,8 @@ module Steep
130
130
  end
131
131
 
132
132
  def for_new_method(method_name, node, args:, self_type:, definition:)
133
- annots = source.annotations(block: node, factory: checker.factory, current_module: current_namespace)
134
- type_env = TypeInference::TypeEnv.new(subtyping: checker,
135
- const_env: module_context&.const_env || self.type_env.const_env)
133
+ annots = source.annotations(block: node, factory: checker.factory, context: nesting)
134
+ type_env = TypeInference::TypeEnv.new(subtyping: checker, const_env: module_context&.const_env || self.type_env.const_env)
136
135
 
137
136
  self.type_env.const_types.each do |name, type|
138
137
  type_env.set(const: name, type: type)
@@ -285,17 +284,9 @@ module Steep
285
284
  end
286
285
  end
287
286
  else
288
- name = nil
289
- name ||= absolute_name(module_name).yield_self do |absolute_name|
290
- absolute_name if checker.factory.class_name?(absolute_name) || checker.factory.module_name?(absolute_name)
291
- end
292
- name ||= super_name && absolute_name(super_name).yield_self do |absolute_name|
293
- absolute_name if checker.factory.class_name?(absolute_name) || checker.factory.module_name?(absolute_name)
294
- end
287
+ name = module_name || super_name
295
288
 
296
- if name
297
- absolute_name_ = name
298
- entry = checker.factory.env.class_decls[absolute_name_]
289
+ if name && entry = checker.factory.env.class_decls[name]
299
290
  AST::Annotation::Implements::Module.new(
300
291
  name: name,
301
292
  args: entry.type_params.each.map(&:name)
@@ -304,9 +295,9 @@ module Steep
304
295
  end
305
296
  end
306
297
 
307
- def default_module_context(implement_module_name, const_env:, current_namespace:)
298
+ def default_module_context(implement_module_name, const_env:)
308
299
  if implement_module_name
309
- module_name = checker.factory.absolute_type_name(implement_module_name.name, namespace: current_namespace)
300
+ module_name = checker.factory.absolute_type_name(implement_module_name.name, context: const_env.context)
310
301
  module_args = implement_module_name.args.map {|name| AST::Types::Var.new(name: name) }
311
302
 
312
303
  instance_def = checker.factory.definition_builder.build_instance(module_name)
@@ -319,7 +310,6 @@ module Steep
319
310
  instance_type: instance_type,
320
311
  module_type: module_type,
321
312
  implement_name: implement_module_name,
322
- current_namespace: current_namespace,
323
313
  const_env: const_env,
324
314
  class_name: module_name,
325
315
  instance_definition: instance_def,
@@ -330,7 +320,6 @@ module Steep
330
320
  instance_type: nil,
331
321
  module_type: nil,
332
322
  implement_name: nil,
333
- current_namespace: current_namespace,
334
323
  const_env: self.module_context.const_env,
335
324
  class_name: self.module_context.class_name,
336
325
  module_definition: nil,
@@ -339,17 +328,19 @@ module Steep
339
328
  end
340
329
  end
341
330
 
342
- def for_module(node)
343
- new_module_name = module_name_from_node(node.children.first) or raise "Unexpected module name: #{node.children.first}"
344
- new_namespace = nested_namespace_for_module(new_module_name)
331
+ def for_module(node, new_module_name)
332
+ new_nesting = [nesting, new_module_name || false]
345
333
 
346
- const_context = [new_namespace] + self.module_context.const_env.context
347
- module_const_env = TypeInference::ConstantEnv.new(factory: checker.factory, context: const_context)
334
+ module_const_env = TypeInference::ConstantEnv.new(
335
+ factory: checker.factory,
336
+ context: new_nesting,
337
+ resolver: self.module_context.const_env.resolver
338
+ )
348
339
 
349
- annots = source.annotations(block: node, factory: checker.factory, current_module: new_namespace)
340
+ annots = source.annotations(block: node, factory: checker.factory, context: new_nesting)
350
341
 
351
342
  implement_module_name = implement_module(module_name: new_module_name, annotations: annots)
352
- module_context = default_module_context(implement_module_name, const_env: module_const_env, current_namespace: new_namespace)
343
+ module_context = default_module_context(implement_module_name, const_env: module_const_env)
353
344
 
354
345
  unless implement_module_name
355
346
  module_context = module_context.update(
@@ -446,25 +437,25 @@ module Steep
446
437
  )
447
438
  end
448
439
 
449
- def with_module_constr(node)
450
- constr = for_module(node)
440
+ def with_module_constr(node, module_name)
441
+ constr = for_module(node, module_name)
451
442
  constr.checker.push_variable_bounds(constr.variable_context.upper_bounds) do
452
443
  yield constr
453
444
  end
454
445
  end
455
446
 
456
- def for_class(node)
457
- new_class_name = module_name_from_node(node.children.first) or raise "Unexpected class name: #{node.children.first}"
458
- super_class_name = node.children[1] && module_name_from_node(node.children[1])
459
- new_namespace = nested_namespace_for_module(new_class_name)
460
-
461
- annots = source.annotations(block: node, factory: checker.factory, current_module: new_namespace)
447
+ def for_class(node, new_class_name, super_class_name)
448
+ new_nesting = [nesting, new_class_name || false]
449
+ annots = source.annotations(block: node, factory: checker.factory, context: new_nesting)
462
450
 
463
- const_context = [new_namespace] + self.module_context.const_env.context
464
- class_const_env = TypeInference::ConstantEnv.new(factory: checker.factory, context: const_context)
451
+ class_const_env = TypeInference::ConstantEnv.new(
452
+ factory: checker.factory,
453
+ context: new_nesting,
454
+ resolver: self.module_context.const_env.resolver
455
+ )
465
456
 
466
457
  implement_module_name = implement_module(module_name: new_class_name, super_name: super_class_name, annotations: annots)
467
- module_context = default_module_context(implement_module_name, const_env: class_const_env, current_namespace: new_namespace)
458
+ module_context = default_module_context(implement_module_name, const_env: class_const_env)
468
459
 
469
460
  if implement_module_name
470
461
  if super_class_name && implement_module_name.name == absolute_name(super_class_name)
@@ -534,8 +525,8 @@ module Steep
534
525
  )
535
526
  end
536
527
 
537
- def with_class_constr(node)
538
- constr = for_class(node)
528
+ def with_class_constr(node, new_class_name, super_class_name)
529
+ constr = for_class(node, new_class_name, super_class_name)
539
530
 
540
531
  constr.checker.push_variable_bounds(constr.variable_context.upper_bounds) do
541
532
  yield constr
@@ -553,7 +544,7 @@ module Steep
553
544
  end
554
545
 
555
546
  def for_sclass(node, type)
556
- annots = source.annotations(block: node, factory: checker.factory, current_module: current_namespace)
547
+ annots = source.annotations(block: node, factory: checker.factory, context: nesting)
557
548
 
558
549
  instance_type = if type.is_a?(AST::Types::Self)
559
550
  context.self_type
@@ -601,7 +592,6 @@ module Steep
601
592
  instance_type: annots.instance_type || instance_type,
602
593
  module_type: annots.self_type || annots.module_type || module_type,
603
594
  implement_name: nil,
604
- current_namespace: current_namespace,
605
595
  const_env: self.module_context.const_env,
606
596
  class_name: self.module_context.class_name,
607
597
  module_definition: module_definition,
@@ -642,7 +632,7 @@ module Steep
642
632
  end
643
633
 
644
634
  def for_branch(node, truthy_vars: Set.new, type_case_override: nil, break_context: context.break_context)
645
- annots = source.annotations(block: node, factory: checker.factory, current_module: current_namespace)
635
+ annots = source.annotations(block: node, factory: checker.factory, context: nesting)
646
636
 
647
637
  lvar_env = context.lvar_env
648
638
 
@@ -1497,33 +1487,37 @@ module Steep
1497
1487
  yield_self do
1498
1488
  constr = self
1499
1489
 
1500
- name, sup, _ = node.children
1501
- if name.type == :const
1502
- # skip the last constant reference
1503
- if const_parent = name.children[0]
1504
- _, constr = constr.synthesize(const_parent)
1490
+ name_node, super_node, _ = node.children
1491
+ _, constr, class_name = synthesize_constant(name_node, name_node.children[0], name_node.children[1]) do
1492
+ typing.add_error(
1493
+ Diagnostic::Ruby::UnknownConstant.new(node: name_node, name: name_node.children[1]).class!
1494
+ )
1495
+ end
1496
+ if class_name
1497
+ typing.source_index.add_definition(constant: class_name, definition: name_node)
1498
+ end
1499
+
1500
+ if super_node
1501
+ _, constr, super_name = constr.synthesize_constant(super_node, super_node.children[0], super_node.children[1]) do
1502
+ typing.add_error(
1503
+ Diagnostic::Ruby::UnknownConstant.new(node: super_node, name: super_node.children[1]).class!
1504
+ )
1505
+ end
1506
+ if super_name
1507
+ typing.source_index.add_reference(constant: super_name, ref: super_node)
1505
1508
  end
1506
- else
1507
- _, constr = constr.synthesize(name)
1508
1509
  end
1509
- _, constr = constr.synthesize(sup) if sup
1510
1510
 
1511
- with_class_constr(node) do |constructor|
1511
+ with_class_constr(node, class_name, super_name) do |constructor|
1512
1512
  if module_type = constructor.module_context&.module_type
1513
1513
  _, constructor = constructor.add_typing(name, type: module_type)
1514
1514
  else
1515
1515
  _, constructor = constructor.fallback_to_any(name)
1516
1516
  end
1517
1517
 
1518
- constructor.typing.source_index.add_definition(
1519
- constant: constructor.module_context.class_name,
1520
- definition: node
1521
- )
1522
-
1523
1518
  constructor.typing.add_context_for_node(node, context: constructor.context)
1524
1519
  constructor.typing.add_context_for_body(node, context: constructor.context)
1525
1520
 
1526
- constructor.synthesize(node.children[1]) if node.children[1]
1527
1521
  constructor.synthesize(node.children[2]) if node.children[2]
1528
1522
 
1529
1523
  if constructor.module_context&.implement_name && !namespace_module?(node)
@@ -1538,28 +1532,22 @@ module Steep
1538
1532
  yield_self do
1539
1533
  constr = self
1540
1534
 
1541
- name, _ = node.children
1542
- if name.type == :const
1543
- # skip the last constant reference
1544
- if const_parent = name.children[0]
1545
- _, constr = constr.synthesize(const_parent)
1546
- end
1547
- else
1548
- _, constr = constr.synthesize(name)
1535
+ name_node, _ = node.children
1536
+ _, constr, module_name = synthesize_constant(name_node, name_node.children[0], name_node.children[1]) do
1537
+ typing.add_error Diagnostic::Ruby::UnknownConstant.new(node: name_node, name: name_node.children[1]).module!
1538
+ end
1539
+
1540
+ if module_name
1541
+ constr.typing.source_index.add_definition(constant: module_name, definition: name_node)
1549
1542
  end
1550
1543
 
1551
- with_module_constr(node) do |constructor|
1544
+ with_module_constr(node, module_name) do |constructor|
1552
1545
  if module_type = constructor.module_context&.module_type
1553
1546
  _, constructor = constructor.add_typing(name, type: module_type)
1554
1547
  else
1555
1548
  _, constructor = constructor.fallback_to_any(name)
1556
1549
  end
1557
1550
 
1558
- constructor.typing.source_index.add_definition(
1559
- constant: constructor.module_context.class_name,
1560
- definition: node
1561
- )
1562
-
1563
1551
  constructor.typing.add_context_for_node(node, context: constructor.context)
1564
1552
  constructor.typing.add_context_for_body(node, context: constructor.context)
1565
1553
 
@@ -1611,75 +1599,47 @@ module Steep
1611
1599
  add_typing node, type: AST::Types::Void.new
1612
1600
 
1613
1601
  when :const
1614
- parent = node.children[0]
1615
- if parent
1616
- _, constr = synthesize(parent)
1617
- else
1618
- constr = self
1619
- end
1620
-
1621
- const_name = constr.module_name_from_node(node)
1602
+ yield_self do
1603
+ type, constr, name = synthesize_constant(node, node.children[0], node.children[1])
1622
1604
 
1623
- if const_name
1624
- if constant = module_context.const_env.lookup_constant(const_name)
1625
- typing.source_index.add_reference(constant: constant.name, ref: node)
1605
+ if name
1606
+ typing.source_index.add_reference(constant: name, ref: node)
1626
1607
  end
1627
1608
 
1628
- type = type_env.get(const: const_name) do
1629
- constr.fallback_to_any(node)
1630
- end
1631
- constr.add_typing(node, type: type)
1632
- else
1633
- constr.fallback_to_any(node)
1609
+ Pair.new(type: type, constr: constr)
1634
1610
  end
1635
1611
 
1636
1612
  when :casgn
1637
1613
  yield_self do
1638
- constr = self
1614
+ constant_type, constr, constant_name = synthesize_constant(nil, node.children[0], node.children[1]) do
1615
+ typing.add_error(
1616
+ Diagnostic::Ruby::UnknownConstant.new(
1617
+ node: node,
1618
+ name: node.children[1]
1619
+ )
1620
+ )
1621
+ end
1639
1622
 
1640
- parent = node.children[0]
1641
- _, constr = constr.synthesize(parent) if parent
1642
- const_name = constr.module_name_from_node(node)
1623
+ if constant_name
1624
+ typing.source_index.add_definition(constant: constant_name, definition: node)
1625
+ end
1643
1626
 
1644
- if const_name
1645
- if constant = module_context.const_env.lookup_constant(const_name)
1646
- typing.source_index.add_definition(constant: constant.name, definition: node)
1647
- end
1627
+ value_type, constr = constr.synthesize(node.children.last, hint: constant_type)
1648
1628
 
1649
- const_type = type_env.get(const: const_name) {}
1650
- value_type, constr = constr.synthesize(node.children.last, hint: const_type)
1651
- type = type_env.assign(
1652
- const: const_name,
1653
- type: value_type,
1654
- self_type: self_type,
1655
- instance_type: module_context.instance_type,
1656
- class_type: module_context.module_type
1657
- ) do |error|
1658
- if error
1659
- const_type = type_env.get(const: const_name)
1660
- typing.add_error(
1661
- Diagnostic::Ruby::IncompatibleAssignment.new(
1662
- node: node,
1663
- lhs_type: const_type,
1664
- rhs_type: value_type,
1665
- result: error
1666
- )
1667
- )
1668
- else
1669
- typing.add_error(
1670
- Diagnostic::Ruby::UnknownConstantAssigned.new(
1671
- node: node,
1672
- name: const_name,
1673
- context: module_context
1674
- )
1675
- )
1676
- end
1677
- end
1629
+ result = check_relation(sub_type: value_type, super_type: constant_type)
1630
+ if result.failure?
1631
+ typing.add_error(
1632
+ Diagnostic::Ruby::IncompatibleAssignment.new(
1633
+ node: node,
1634
+ lhs_type: constant_type,
1635
+ rhs_type: value_type,
1636
+ result: result
1637
+ )
1638
+ )
1678
1639
 
1679
- constr.add_typing(node, type: type)
1640
+ constr.add_typing(node, type: constant_type)
1680
1641
  else
1681
- _, constr = constr.synthesize(node.children.last)
1682
- constr.fallback_to_any(node)
1642
+ constr.add_typing(node, type: value_type)
1683
1643
  end
1684
1644
  end
1685
1645
 
@@ -2275,13 +2235,10 @@ module Steep
2275
2235
  type, constr = synthesize(rhs, hint: hint)
2276
2236
  constr.ivasgn(asgn, type)
2277
2237
  when :send
2278
- rhs_ = node.updated(:send,
2279
- [
2280
- asgn.children[0],
2281
- :"#{asgn.children[1]}=",
2282
- asgn.children[2],
2283
- rhs
2284
- ])
2238
+ children = asgn.children.dup
2239
+ children[1] = :"#{children[1]}="
2240
+ send_arg_nodes = [*children, rhs]
2241
+ rhs_ = node.updated(:send, send_arg_nodes)
2285
2242
  node_type = case node.type
2286
2243
  when :or_asgn
2287
2244
  :or
@@ -2348,11 +2305,11 @@ module Steep
2348
2305
  interface = calculate_interface(param_type, private: true)
2349
2306
  method = interface.methods[value.children[0]]
2350
2307
  if method
2351
- return_types = method.method_types.select {|method_type|
2352
- method_type.type.params.empty?
2353
- }.map {|method_type|
2354
- method_type.type.return_type
2355
- }
2308
+ return_types = method.method_types.filter_map do |method_type|
2309
+ if method_type.type.params.optional?
2310
+ method_type.type.return_type
2311
+ end
2312
+ end
2356
2313
 
2357
2314
  unless return_types.empty?
2358
2315
  type = AST::Types::Proc.new(
@@ -2360,7 +2317,7 @@ module Steep
2360
2317
  params: Interface::Function::Params.empty.with_first_param(
2361
2318
  Interface::Function::Params::PositionalParams::Required.new(param_type)
2362
2319
  ),
2363
- return_type: AST::Types::Union.build(types: return_types),
2320
+ return_type: return_types[0],
2364
2321
  location: nil
2365
2322
  ),
2366
2323
  block: nil
@@ -2727,6 +2684,82 @@ module Steep
2727
2684
  end
2728
2685
  end
2729
2686
 
2687
+ def synthesize_constant(node, parent_node, constant_name)
2688
+ const_name = module_name_from_node(parent_node, constant_name)
2689
+
2690
+ if const_name && type = type_env.get(const: const_name) { break }
2691
+ # const-type annotation wins
2692
+ if node
2693
+ constr = synthesize_children(node)
2694
+ type, constr = constr.add_typing(node, type: type)
2695
+ [type, constr, nil]
2696
+ else
2697
+ [type, self, nil]
2698
+ end
2699
+ else
2700
+ case
2701
+ when !parent_node
2702
+ constr = self
2703
+
2704
+ if (type, name = module_context.const_env.resolve(constant_name))
2705
+ if node
2706
+ _, constr = add_typing(node, type: type)
2707
+ end
2708
+
2709
+ return [type, constr, name]
2710
+ end
2711
+ when parent_node.type == :cbase
2712
+ _, constr = add_typing(parent_node, type: AST::Builtin.nil_type)
2713
+
2714
+ if (type, name = constr.module_context.const_env.toplevel(constant_name))
2715
+ if node
2716
+ _, constr = constr.add_typing(node, type: type)
2717
+ end
2718
+
2719
+ return [type, constr, name]
2720
+ end
2721
+ else
2722
+ parent_type, constr = synthesize(parent_node)
2723
+ parent_type = deep_expand_alias(parent_type)
2724
+
2725
+ case parent_type
2726
+ when AST::Types::Name::Singleton
2727
+ if (type, name = module_context.const_env.resolve_child(parent_type.name, constant_name))
2728
+ if node
2729
+ _, constr = add_typing(node, type: type)
2730
+ end
2731
+
2732
+ return [type, constr, name]
2733
+ end
2734
+ when AST::Types::Any
2735
+ # Couldn't detect the type of the parent constant
2736
+ # Skip reporting error for this node.
2737
+ if node
2738
+ _, constr = add_typing(node, type: parent_type)
2739
+ end
2740
+
2741
+ return [parent_type, constr, nil]
2742
+ end
2743
+ end
2744
+
2745
+ if block_given?
2746
+ yield
2747
+ else
2748
+ if node
2749
+ constr.typing.add_error(
2750
+ Diagnostic::Ruby::UnknownConstant.new(node: node, name: constant_name)
2751
+ )
2752
+ end
2753
+ end
2754
+
2755
+ if node
2756
+ _, constr = add_typing(node, type: AST::Builtin.any_type)
2757
+ end
2758
+
2759
+ [AST::Builtin.any_type, constr, nil]
2760
+ end
2761
+ end
2762
+
2730
2763
  def optional_proc?(type)
2731
2764
  if type.is_a?(AST::Types::Union)
2732
2765
  if type.types.size == 2
@@ -2740,7 +2773,7 @@ module Steep
2740
2773
  end
2741
2774
 
2742
2775
  def type_lambda(node, params_node:, body_node:, type_hint:)
2743
- block_annotations = source.annotations(block: node, factory: checker.factory, current_module: current_namespace)
2776
+ block_annotations = source.annotations(block: node, factory: checker.factory, context: nesting)
2744
2777
  params = TypeInference::BlockParams.from_node(params_node, annotations: block_annotations)
2745
2778
 
2746
2779
  type_hint = deep_expand_alias(type_hint) if type_hint
@@ -2897,7 +2930,7 @@ module Steep
2897
2930
 
2898
2931
  constr = synthesize_children(node, skips: skips)
2899
2932
  if block_params
2900
- block_annotations = source.annotations(block: node, factory: checker.factory, current_module: current_namespace)
2933
+ block_annotations = source.annotations(block: node, factory: checker.factory, context: nesting)
2901
2934
 
2902
2935
  constr.type_block_without_hint(
2903
2936
  node: node,
@@ -2918,7 +2951,7 @@ module Steep
2918
2951
 
2919
2952
  constr = synthesize_children(node, skips: skips)
2920
2953
  if block_params
2921
- block_annotations = source.annotations(block: node, factory: checker.factory, current_module: current_namespace)
2954
+ block_annotations = source.annotations(block: node, factory: checker.factory, context: nesting)
2922
2955
 
2923
2956
  constr.type_block_without_hint(
2924
2957
  node: node,
@@ -3299,7 +3332,7 @@ module Steep
3299
3332
 
3300
3333
  if block_params
3301
3334
  # block is given
3302
- block_annotations = source.annotations(block: node, factory: checker.factory, current_module: current_namespace)
3335
+ block_annotations = source.annotations(block: node, factory: checker.factory, context: nesting)
3303
3336
  block_params_ = TypeInference::BlockParams.from_node(block_params, annotations: block_annotations)
3304
3337
 
3305
3338
  if method_type.block
@@ -3641,8 +3674,7 @@ module Steep
3641
3674
  if implements = block_annotations.implement_module_annotation
3642
3675
  module_context = default_module_context(
3643
3676
  implements.name,
3644
- const_env: self.module_context.const_env,
3645
- current_namespace: current_namespace
3677
+ const_env: self.module_context.const_env
3646
3678
  )
3647
3679
 
3648
3680
  self_type = module_context.module_type
@@ -3696,30 +3728,25 @@ module Steep
3696
3728
  end
3697
3729
  end
3698
3730
 
3699
- def current_namespace
3700
- module_context&.current_namespace || AST::Namespace.root
3731
+ def nesting
3732
+ module_context&.nesting
3701
3733
  end
3702
3734
 
3703
- def nested_namespace_for_module(module_name)
3704
- if module_name.namespace.relative?
3705
- (current_namespace + module_name.namespace).append(module_name.name)
3706
- else
3707
- module_name.to_namespace
3735
+ def absolute_nested_module_name(module_name)
3736
+ n = nesting
3737
+ while n && !n[1]
3738
+ n = n[0]
3708
3739
  end
3709
- end
3710
3740
 
3711
- def absolute_name(module_name)
3712
- if current_namespace
3713
- module_name.with_prefix(current_namespace)
3714
- else
3741
+ if n
3715
3742
  module_name.absolute!
3743
+ else
3744
+ n + module_name
3716
3745
  end
3717
3746
  end
3718
3747
 
3719
- def absolute_type(type)
3720
- if type
3721
- checker.builder.absolute_type(type, current: current_namespace)
3722
- end
3748
+ def absolute_name(name)
3749
+ checker.factory.absolute_type_name(name, context: nesting)
3723
3750
  end
3724
3751
 
3725
3752
  def union_type(*types)
@@ -3948,6 +3975,20 @@ module Steep
3948
3975
  constr.add_typing(node, type: AST::Types::Tuple.new(types: element_types))
3949
3976
  end
3950
3977
 
3978
+ def try_convert(type, method)
3979
+ interface = checker.factory.interface(type, private: false)
3980
+ if entry = interface.methods[method]
3981
+ method_type = entry.method_types.find do |method_type|
3982
+ method_type.type.params.optional?
3983
+ end
3984
+
3985
+ method_type.type.return_type
3986
+ end
3987
+ rescue => exn
3988
+ Steep.log_error(exn, message: "Unexpected error when converting #{type.to_s} with #{method}")
3989
+ nil
3990
+ end
3991
+
3951
3992
  def try_array_type(node, hint)
3952
3993
  element_hint = hint ? hint.args[0] : nil
3953
3994
 
@@ -3958,8 +3999,14 @@ module Steep
3958
3999
  case child.type
3959
4000
  when :splat
3960
4001
  type, constr = constr.synthesize(child.children[0], hint: hint)
3961
- if AST::Builtin::Array.instance_type?(type)
4002
+
4003
+ type = try_convert(type, :to_a) || type
4004
+
4005
+ case
4006
+ when AST::Builtin::Array.instance_type?(type)
3962
4007
  element_types << type.args[0]
4008
+ when type.is_a?(AST::Types::Tuple)
4009
+ element_types.push(*type.types)
3963
4010
  else
3964
4011
  element_types.push(*flatten_array_elements(type))
3965
4012
  end
@@ -2,33 +2,51 @@ module Steep
2
2
  module TypeInference
3
3
  class ConstantEnv
4
4
  attr_reader :context
5
- attr_reader :cache
6
5
  attr_reader :factory
7
- attr_reader :table
6
+ attr_reader :resolver
8
7
 
9
8
  # ConstantEnv receives an TypeName as a context, not a Namespace, because this is a simulation of Ruby.
10
9
  # Any namespace is a module or class.
11
- def initialize(factory:, context:)
10
+ def initialize(factory:, context:, resolver:)
12
11
  @cache = {}
13
12
  @factory = factory
14
13
  @context = context
15
- @table = RBS::ConstantTable.new(builder: factory.definition_builder)
14
+ @resolver = resolver
16
15
  end
17
16
 
18
- def lookup_constant(name)
19
- table.resolve_constant_reference(name, context: context)
17
+ def resolve(name)
18
+ decompose_constant(
19
+ resolver.resolve(name, context: context)
20
+ )
20
21
  end
21
22
 
22
- def lookup(name)
23
- cache[name] ||= begin
24
- constant = lookup_constant(name)
23
+ def toplevel(name)
24
+ decompose_constant(
25
+ resolver.table.toplevel[name]
26
+ )
27
+ end
28
+
29
+ def constants
30
+ resolver.constants(context).transform_values {|c| decompose_constant(c) }
31
+ end
32
+
33
+ def resolve_child(module_name, constant_name)
34
+ decompose_constant(
35
+ resolver.resolve_child(module_name, constant_name)
36
+ )
37
+ end
38
+
39
+ def children(module_name)
40
+ resolver.children(module_name).transform_values {|c| decompose_constant(c) }
41
+ end
25
42
 
26
- if constant
27
- factory.type(constant.type)
28
- end
29
- rescue => exn
30
- Steep.logger.debug "Looking up a constant failed: name=#{name}, context=[#{context.join(", ")}], error=#{exn.inspect}"
31
- nil
43
+ def decompose_constant(constant)
44
+ if constant
45
+ [
46
+ factory.type(constant.type),
47
+ constant.name,
48
+ constant.entry
49
+ ]
32
50
  end
33
51
  end
34
52
  end