solargraph 0.59.2 → 0.60.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 (38) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/rspec.yml +4 -1
  3. data/.rubocop.yml +1 -0
  4. data/.rubocop_todo.yml +1 -1
  5. data/CHANGELOG.md +11 -0
  6. data/Gemfile +3 -0
  7. data/lib/solargraph/api_map/index.rb +13 -2
  8. data/lib/solargraph/api_map/store.rb +21 -6
  9. data/lib/solargraph/api_map.rb +34 -2
  10. data/lib/solargraph/complex_type/unique_type.rb +4 -0
  11. data/lib/solargraph/complex_type.rb +4 -0
  12. data/lib/solargraph/doc_map.rb +1 -0
  13. data/lib/solargraph/parser/parser_gem/node_methods.rb +42 -0
  14. data/lib/solargraph/parser/parser_gem/node_processors/namespace_node.rb +29 -5
  15. data/lib/solargraph/pin/base.rb +31 -3
  16. data/lib/solargraph/pin/callable.rb +2 -2
  17. data/lib/solargraph/pin/common.rb +12 -0
  18. data/lib/solargraph/pin/method.rb +56 -16
  19. data/lib/solargraph/rbs_map/conversions.rb +96 -145
  20. data/lib/solargraph/rbs_translator.rb +206 -0
  21. data/lib/solargraph/shell.rb +130 -63
  22. data/lib/solargraph/source/chain/call.rb +8 -76
  23. data/lib/solargraph/source_map/mapper.rb +5 -135
  24. data/lib/solargraph/source_map.rb +14 -0
  25. data/lib/solargraph/version.rb +19 -1
  26. data/lib/solargraph/yard_map/directives/attribute_directive.rb +65 -0
  27. data/lib/solargraph/yard_map/directives/domain_directive.rb +30 -0
  28. data/lib/solargraph/yard_map/directives/method_directive.rb +51 -0
  29. data/lib/solargraph/yard_map/directives/override_directive.rb +30 -0
  30. data/lib/solargraph/yard_map/directives/parse_directive.rb +53 -0
  31. data/lib/solargraph/yard_map/directives/visibility_directive.rb +70 -0
  32. data/lib/solargraph/yard_map/directives.rb +35 -0
  33. data/lib/solargraph/yard_map/macro.rb +113 -0
  34. data/lib/solargraph/yard_map/mapper.rb +19 -1
  35. data/lib/solargraph/yard_map.rb +2 -0
  36. data/lib/solargraph.rb +1 -0
  37. data/solargraph.gemspec +1 -0
  38. metadata +24 -1
@@ -67,7 +67,6 @@ module Solargraph
67
67
  unless closure.name == '' || decl.name.absolute?
68
68
  Solargraph.assert_or_log(:rbs_closure, "Ignoring closure #{closure.inspect} on interface #{decl.inspect}")
69
69
  end
70
- # STDERR.puts "Skipping interface #{decl.name.relative!}"
71
70
  interface_decl_to_pin decl
72
71
  when RBS::AST::Declarations::TypeAlias
73
72
  # @sg-ignore flow sensitive typing should support case/when
@@ -80,7 +79,7 @@ module Solargraph
80
79
  # @sg-ignore Wrong argument type for Solargraph::Pin::Reference::TypeAlias.new: return_type expected Solargraph::ComplexType, received Solargraph::ComplexType::UniqueType, Solargraph::ComplexType
81
80
  Solargraph::Pin::Reference::TypeAlias.new(
82
81
  # @sg-ignore Unresolved calls to name, type, type_location; return_type type mismatch
83
- name: ComplexType.try_parse(decl.name.to_s).to_s, return_type: other_type_to_type(decl.type).force_rooted, closure: closure, source: :rbs, type_location: location_decl_to_pin_location(decl.location)
82
+ name: ComplexType.try_parse(decl.name.to_s).to_s, return_type: RbsTranslator.to_complex_type(decl.type).force_rooted, closure: closure, source: :rbs, type_location: location_decl_to_pin_location(decl.location)
84
83
  )
85
84
  )
86
85
  when RBS::AST::Declarations::Module
@@ -169,7 +168,8 @@ module Solargraph
169
168
  rbs_name = type_name.relative!.to_s
170
169
  base = RBS_TO_CLASS.fetch(rbs_name, rbs_name)
171
170
 
172
- params = type_args.map { |a| other_type_to_type(a) }
171
+ params = type_args.map { |a| RbsTranslator.to_complex_type(a) }
172
+ # @todo Tuples are in flux
173
173
  # tuples have their own class and are handled in other_type_to_type
174
174
  if base == 'Hash' && params.length == 2
175
175
  ComplexType::UniqueType.new(base, [params.first], [params.last], rooted: type_name.absolute?,
@@ -185,9 +185,9 @@ module Solargraph
185
185
  # @return [void]
186
186
  def convert_self_type_to_pins decl, closure
187
187
  type = build_type(decl.name, decl.args)
188
- generic_values = type.all_params.map(&:rooted_tags)
188
+ generic_values = type.all_params.map(&:to_s)
189
189
  include_pin = Solargraph::Pin::Reference::Include.new(
190
- name: type.name,
190
+ name: decl.name.relative!.to_s,
191
191
  type_location: location_decl_to_pin_location(decl.location),
192
192
  generic_values: generic_values,
193
193
  closure: closure,
@@ -274,7 +274,10 @@ module Solargraph
274
274
  # @type [Hash{String => ComplexType, ComplexType::UniqueType}]
275
275
  generic_defaults = {}
276
276
  decl.type_params.each do |param|
277
- generic_defaults[param.name.to_s] = other_type_to_type param.default_type if param.default_type
277
+ if param.default_type
278
+ complex_type = RbsTranslator.to_complex_type(param.default_type).force_rooted
279
+ generic_defaults[param.name.to_s] = complex_type
280
+ end
278
281
  end
279
282
 
280
283
  class_name = fqns(decl.name)
@@ -297,7 +300,8 @@ module Solargraph
297
300
  pins.push class_pin
298
301
  if decl.super_class
299
302
  type = build_type(decl.super_class.name, decl.super_class.args)
300
- generic_values = type.all_params.map(&:rooted_tags)
303
+ generic_values = type.all_params.map(&:to_s)
304
+ superclass_name = decl.super_class.name.to_s
301
305
  pins.push Solargraph::Pin::Reference::Superclass.new(
302
306
  type_location: location_decl_to_pin_location(decl.super_class.location),
303
307
  closure: class_pin,
@@ -316,7 +320,7 @@ module Solargraph
316
320
  class_pin = Solargraph::Pin::Namespace.new(
317
321
  type: :module,
318
322
  type_location: location_decl_to_pin_location(decl.location),
319
- name: fqns(decl.name),
323
+ name: decl.name.relative!.to_s,
320
324
  closure: Solargraph::Pin::ROOT_PIN,
321
325
  comments: decl.comment&.string,
322
326
  generics: type_parameter_names(decl),
@@ -335,7 +339,7 @@ module Solargraph
335
339
  def module_decl_to_pin decl
336
340
  module_pin = Solargraph::Pin::Namespace.new(
337
341
  type: :module,
338
- name: fqns(decl.name),
342
+ name: decl.name.relative!.to_s,
339
343
  type_location: location_decl_to_pin_location(decl.location),
340
344
  closure: Solargraph::Pin::ROOT_PIN,
341
345
  comments: decl.comment&.string,
@@ -380,6 +384,9 @@ module Solargraph
380
384
  )
381
385
  rooted_tag = type.rooted_tags
382
386
  rooted_tag = "#{base}<#{rooted_tag}>" if base
387
+ # @todo alt version
388
+ # tag = "#{base}<#{tag}>" if base
389
+ # rooted_tag = ComplexType.parse(tag).force_rooted.rooted_tags
383
390
  constant_pin.docstring.add_tag(YARD::Tags::Tag.new(:return, '', rooted_tag))
384
391
  constant_pin
385
392
  end
@@ -406,9 +413,8 @@ module Solargraph
406
413
  # @param decl [RBS::AST::Declarations::Constant]
407
414
  # @return [void]
408
415
  def constant_decl_to_pin decl
409
- target_type = other_type_to_type(decl.type)
410
- constant_name = fqns(decl.name)
411
- pins.push create_constant(constant_name, target_type, decl.comment&.string, decl)
416
+ tag = RbsTranslator.to_complex_type(decl.type)
417
+ pins.push create_constant(decl.name.relative!.to_s, tag, decl.comment&.string, decl)
412
418
  end
413
419
 
414
420
  # @param decl [RBS::AST::Declarations::Global]
@@ -423,7 +429,7 @@ module Solargraph
423
429
  type_location: location_decl_to_pin_location(decl.location),
424
430
  source: :rbs
425
431
  )
426
- rooted_tag = other_type_to_type(decl.type).rooted_tags
432
+ rooted_tag = RbsTranslator.to_complex_type(decl.type).force_rooted.rooted_tags
427
433
  pin.docstring.add_tag(YARD::Tags::Tag.new(:type, '', rooted_tag))
428
434
  pins.push pin
429
435
  end
@@ -529,23 +535,24 @@ module Solargraph
529
535
  pin.instance_variable_set(:@return_type, ComplexType::VOID)
530
536
  end
531
537
  end
532
- return unless decl.singleton?
533
- final_scope = :class
534
- name = decl.name.to_s
535
- visibility = calculate_method_visibility(decl, context, closure, final_scope, name)
536
- pin = Solargraph::Pin::Method.new(
537
- name: name,
538
- closure: closure,
539
- comments: decl.comment&.string,
540
- type_location: location_decl_to_pin_location(decl.location),
541
- visibility: visibility,
542
- scope: final_scope,
543
- signatures: [],
544
- generics: generics,
545
- source: :rbs
546
- )
547
- pin.signatures.concat method_def_to_sigs(decl, pin)
548
- pins.push pin
538
+ if decl.singleton?
539
+ final_scope = :class
540
+ name = decl.name.to_s
541
+ visibility = calculate_method_visibility(decl, context, closure, final_scope, name)
542
+ pin = Solargraph::Pin::Method.new(
543
+ name: name,
544
+ closure: closure,
545
+ comments: decl.comment&.string,
546
+ type_location: location_decl_to_pin_location(decl.location),
547
+ visibility: visibility,
548
+ scope: final_scope,
549
+ signatures: [],
550
+ generics: generics,
551
+ source: :rbs
552
+ )
553
+ pin.signatures.concat method_def_to_sigs(decl, pin)
554
+ pins.push pin
555
+ end
549
556
  end
550
557
 
551
558
  # @param decl [RBS::AST::Members::MethodDefinition]
@@ -554,38 +561,29 @@ module Solargraph
554
561
  def method_def_to_sigs decl, pin
555
562
  # rubocop:disable Style/SafeNavigationChainLength
556
563
  implicit_nil = decl.overloads.first&.annotations&.map(&:string)&.include?('implicitly-returns-nil') || false
557
- # rubocop:enable Style/SafeNavigationChainLength
558
- # @param overload [RBS::AST::Members::MethodDefinition::Overload]
564
+ # rubocop:enable Style/SafeNavigationChainLength # @param overload [RBS::AST::Members::MethodDefinition::Overload]
559
565
  decl.overloads.map do |overload|
560
- # @sg-ignore Wrong argument type for Solargraph::RbsMap::Conversions#location_decl_to_pin_location:
561
- # location expected RBS::Location, nil, received RBS::Location<:type, :type_params>, RBS::AST::Members::Attribute::loc, nil
562
566
  type_location = location_decl_to_pin_location(overload.method_type.location)
563
- generics = type_parameter_names(overload.method_type)
567
+ generics = overload.method_type.type_params.map(&:name).map(&:to_s)
564
568
  signature_parameters, signature_return_type = parts_of_function(overload.method_type, pin, implicit_nil)
565
- rbs_block = overload.method_type.block
566
- block = if rbs_block
567
- block_parameters, block_return_type = parts_of_function(rbs_block, pin, implicit_nil)
568
- Pin::Signature.new(generics: generics, parameters: block_parameters,
569
- return_type: block_return_type, source: :rbs,
569
+ block = if overload.method_type.block
570
+ block_parameters, block_return_type = parts_of_function(overload.method_type.block, pin, implicit_nil)
571
+ Pin::Signature.new(generics: generics, parameters: block_parameters, return_type: block_return_type, source: :rbs,
570
572
  type_location: type_location, closure: pin)
571
573
  end
572
- Pin::Signature.new(generics: generics, parameters: signature_parameters,
573
- return_type: signature_return_type, block: block, source: :rbs,
574
+ Pin::Signature.new(generics: generics, parameters: signature_parameters, return_type: signature_return_type, block: block, source: :rbs,
574
575
  type_location: type_location, closure: pin)
575
576
  end
576
577
  end
577
578
 
578
579
  # @param location [RBS::Location, nil]
579
580
  # @return [Solargraph::Location, nil]
580
- def location_decl_to_pin_location location
581
+ def location_decl_to_pin_location(location)
581
582
  return nil if location&.name.nil?
582
583
 
583
- # @sg-ignore flow sensitive typing should handle return nil if location&.name.nil?
584
584
  start_pos = Position.new(location.start_line - 1, location.start_column)
585
- # @sg-ignore flow sensitive typing should handle return nil if location&.name.nil?
586
585
  end_pos = Position.new(location.end_line - 1, location.end_column)
587
586
  range = Range.new(start_pos, end_pos)
588
- # @sg-ignore flow sensitve typing should handle return nil if location&.name.nil?
589
587
  Location.new(location.name.to_s, range)
590
588
  end
591
589
 
@@ -667,6 +665,17 @@ module Solargraph
667
665
  [parameters, return_type]
668
666
  end
669
667
 
668
+ # @param type [RBS::MethodType,RBS::Types::Block]
669
+ # @param pin [Pin::Method]
670
+ # @param implicit_nil [Boolean]
671
+ # @return [Array(Array<Pin::Parameter>, ComplexType)]
672
+ def parts_of_function type, pin, implicit_nil
673
+ [
674
+ RbsTranslator.to_parameter_pins(type, pin, pin.parameter_names),
675
+ extract_method_type_return_type(type, implicit_nil).force_rooted
676
+ ]
677
+ end
678
+
670
679
  # @param decl [RBS::AST::Members::AttrReader,RBS::AST::Members::AttrAccessor]
671
680
  # @param closure [Pin::Namespace]
672
681
  # @param context [Context]
@@ -685,7 +694,7 @@ module Solargraph
685
694
  visibility: visibility,
686
695
  source: :rbs
687
696
  )
688
- rooted_tag = other_type_to_type(decl.type).rooted_tags
697
+ rooted_tag = RbsTranslator.to_complex_type(decl.type).force_rooted.rooted_tags
689
698
  pin.docstring.add_tag(YARD::Tags::Tag.new(:return, '', rooted_tag))
690
699
  logger.debug do
691
700
  "Conversions#attr_reader_to_pin(name=#{name.inspect}, visibility=#{visibility.inspect}) => #{pin.inspect}"
@@ -716,13 +725,13 @@ module Solargraph
716
725
  pin.parameters <<
717
726
  Solargraph::Pin::Parameter.new(
718
727
  name: 'value',
719
- return_type: other_type_to_type(decl.type),
728
+ return_type: RbsTranslator.to_complex_type(decl.type).force_rooted,
720
729
  source: :rbs,
721
730
  closure: pin,
722
731
  type_location: type_location
723
732
  )
724
- rooted_tags = other_type_to_type(decl.type).rooted_tags
725
- pin.docstring.add_tag(YARD::Tags::Tag.new(:return, '', rooted_tags))
733
+ rooted_tag = RbsTranslator.to_complex_type(decl.type).force_rooted.rooted_tags
734
+ pin.docstring.add_tag(YARD::Tags::Tag.new(:return, '', rooted_tag))
726
735
  pins.push pin
727
736
  end
728
737
 
@@ -746,7 +755,7 @@ module Solargraph
746
755
  comments: decl.comment&.string,
747
756
  source: :rbs
748
757
  )
749
- rooted_tag = other_type_to_type(decl.type).rooted_tags
758
+ rooted_tag = RbsTranslator.to_complex_type(decl.type).force_rooted.rooted_tags
750
759
  pin.docstring.add_tag(YARD::Tags::Tag.new(:type, '', rooted_tag))
751
760
  pins.push pin
752
761
  end
@@ -763,7 +772,7 @@ module Solargraph
763
772
  type_location: location_decl_to_pin_location(decl.location),
764
773
  source: :rbs
765
774
  )
766
- rooted_tag = other_type_to_type(decl.type).rooted_tags
775
+ rooted_tag = RbsTranslator.to_complex_type(decl.type).force_rooted.rooted_tags
767
776
  pin.docstring.add_tag(YARD::Tags::Tag.new(:type, '', rooted_tag))
768
777
  pins.push pin
769
778
  end
@@ -780,7 +789,7 @@ module Solargraph
780
789
  type_location: location_decl_to_pin_location(decl.location),
781
790
  source: :rbs
782
791
  )
783
- rooted_tag = other_type_to_type(decl.type).rooted_tags
792
+ rooted_tag = RbsTranslator.to_complex_type(decl.type).force_rooted.rooted_tags
784
793
  pin.docstring.add_tag(YARD::Tags::Tag.new(:type, '', rooted_tag))
785
794
  pins.push pin
786
795
  end
@@ -790,9 +799,9 @@ module Solargraph
790
799
  # @return [void]
791
800
  def include_to_pin decl, closure
792
801
  type = build_type(decl.name, decl.args)
793
- generic_values = type.all_params.map(&:rooted_tags)
802
+ generic_values = type.all_params.map(&:to_s)
794
803
  pins.push Solargraph::Pin::Reference::Include.new(
795
- name: type.rooted_name, # reference pins use rooted names
804
+ name: decl.name.relative!.to_s,
796
805
  type_location: location_decl_to_pin_location(decl.location),
797
806
  generic_values: generic_values,
798
807
  closure: closure,
@@ -807,9 +816,8 @@ module Solargraph
807
816
  type = build_type(decl.name, decl.args)
808
817
  generic_values = type.all_params.map(&:rooted_tags)
809
818
  pins.push Solargraph::Pin::Reference::Prepend.new(
810
- name: type.rooted_name, # reference pins use rooted names
819
+ name: decl.name.relative!.to_s,
811
820
  type_location: location_decl_to_pin_location(decl.location),
812
- generic_values: generic_values,
813
821
  closure: closure,
814
822
  source: :rbs
815
823
  )
@@ -822,9 +830,8 @@ module Solargraph
822
830
  type = build_type(decl.name, decl.args)
823
831
  generic_values = type.all_params.map(&:rooted_tags)
824
832
  pins.push Solargraph::Pin::Reference::Extend.new(
825
- name: type.rooted_name, # reference pins use rooted names
833
+ name: decl.name.relative!.to_s,
826
834
  type_location: location_decl_to_pin_location(decl.location),
827
- generic_values: generic_values,
828
835
  closure: closure,
829
836
  source: :rbs
830
837
  )
@@ -845,93 +852,37 @@ module Solargraph
845
852
  )
846
853
  end
847
854
 
848
- # @param type [RBS::MethodType, RBS::Types::Block]
849
- # @param implicit_nil [Boolean]
850
- # @return [ComplexType, ComplexType::UniqueType]
851
- def method_type_to_type type, implicit_nil
852
- tag = other_type_to_type type.type.return_type
853
- return ComplexType.parse("#{tag}, nil") if tag && implicit_nil
854
- tag
855
- end
855
+ RBS_TO_YARD_TYPE = {
856
+ 'bool' => 'Boolean',
857
+ 'string' => 'String',
858
+ 'int' => 'Integer',
859
+ 'untyped' => '',
860
+ 'NilClass' => 'nil'
861
+ }
862
+ private_constant :RBS_TO_YARD_TYPE
856
863
 
857
- # @param type [RBS::Types::Bases::Base,Object] RBS type object.
858
- # Note: Generally these extend from RBS::Types::Bases::Base,
859
- # but not all.
864
+ # Extract a ComplexType from a MethodType's return type.
860
865
  #
861
- # @return [ComplexType, ComplexType::UniqueType]
862
- def other_type_to_type type
863
- case type
864
- when RBS::Types::Optional
865
- # @sg-ignore flow based typing needs to understand case when class pattern
866
- ComplexType.new([other_type_to_type(type.type),
867
- ComplexType::UniqueType::NIL])
868
- when RBS::Types::Bases::Any
869
- ComplexType::UNDEFINED
870
- when RBS::Types::Bases::Bool
871
- ComplexType::BOOLEAN
872
- when RBS::Types::Tuple
873
- # @sg-ignore flow based typing needs to understand case when class pattern
874
- tuple_types = type.types.map { |t| other_type_to_type(t) }
875
- ComplexType::UniqueType.new('Array', [], tuple_types, rooted: true, parameters_type: :fixed)
876
- when RBS::Types::Literal
877
- # @sg-ignore flow based typing needs to understand case when class pattern
878
- ComplexType.try_parse(type.literal.inspect).force_rooted
879
- when RBS::Types::Union
880
- # @sg-ignore flow based typing needs to understand case when class pattern
881
- ComplexType.new(type.types.map { |t| other_type_to_type(t) })
882
- when RBS::Types::Record
883
- # @todo Better record support
884
- ComplexType::UniqueType.new('Hash', rooted: true)
885
- when RBS::Types::Bases::Nil
886
- ComplexType::NIL
887
- when RBS::Types::Bases::Self
888
- ComplexType::SELF
889
- when RBS::Types::Bases::Void
890
- ComplexType::VOID
891
- when RBS::Types::Variable
892
- # @sg-ignore flow based typing needs to understand case when class pattern
893
- ComplexType.parse("generic<#{type.name}>").force_rooted
894
- when RBS::Types::ClassInstance # && !type.args.empty?
895
- # @sg-ignore flow based typing needs to understand case when class pattern
896
- build_type(type.name, type.args)
897
- when RBS::Types::Bases::Instance
898
- ComplexType::SELF
899
- when RBS::Types::Bases::Top
900
- # top is the most super superclass
901
- ComplexType::UniqueType.new('BasicObject', rooted: true)
902
- when RBS::Types::Bases::Bottom
903
- # bottom is used in contexts where nothing will ever return
904
- # - e.g., it could be the return type of 'exit()' or 'raise'
905
- #
906
- # @todo define a specific bottom type and use it to
907
- # determine dead code
908
- ComplexType::UNDEFINED
909
- when RBS::Types::Intersection
910
- # @sg-ignore flow based typing needs to understand case when class pattern
911
- ComplexType.new(type.types.map { |member| other_type_to_type(member) })
912
- when RBS::Types::Proc
913
- ComplexType::UniqueType.new('Proc', rooted: true)
914
- when RBS::Types::Alias
915
- # type-level alias use - e.g., 'bool' in "type bool = true | false"
916
- # @todo ensure these get resolved after processing all aliases
917
- # @todo handle recursive aliases
918
- # @sg-ignore flow based typing needs to understand case when class pattern
919
- build_type(type.name, type.args)
920
- when RBS::Types::Interface
921
- # represents a mix-in module which can be considered a
922
- # subtype of a consumer of it
923
- # @sg-ignore flow based typing needs to understand case when class pattern
924
- build_type(type.name, type.args)
925
- when RBS::Types::ClassSingleton
926
- # e.g., singleton(String)
927
- # @sg-ignore flow based typing needs to understand case when class pattern
928
- build_type(type.name)
866
+ # This method will convert type aliases to concrete types.
867
+ #
868
+ # @param type [RBS::MethodType]
869
+ # @return [ComplexType]
870
+ def extract_method_type_return_type type, implicit_nil
871
+ tag = RbsTranslator.to_complex_type(type.type.return_type)
872
+ return ComplexType.parse("#{tag}, nil") if tag && implicit_nil
873
+ tag
874
+ end
875
+
876
+ # @param type_name [RBS::TypeName]
877
+ # @param type_args [Enumerable<RBS::Types::Bases::Base>]
878
+ # @return [ComplexType::UniqueType]
879
+ def build_type(type_name, type_args = [])
880
+ base = RBS_TO_YARD_TYPE[type_name.relative!.to_s] || type_name.relative!.to_s
881
+ params = type_args.map { |arg| RbsTranslator.to_complex_type(arg).force_rooted }
882
+ if base == 'Hash' && params.length == 2
883
+ ComplexType::UniqueType.new(base, [params.first], [params.last], rooted: true, parameters_type: :hash)
929
884
  else
930
- # RBS doesn't provide a common base class for its type AST nodes
931
- #
932
- # @sg-ignore all types should include location
933
- Solargraph.logger.warn "Unrecognized RBS type: #{type.class} at #{type.location}"
934
- ComplexType::UNDEFINED
885
+ ComplexType::UniqueType.new(base, [], params.reject(&:undefined?), rooted: true, parameters_type: :list)
935
886
  end
936
887
  end
937
888
 
@@ -944,9 +895,9 @@ module Solargraph
944
895
  # @todo are we handling prepend correctly?
945
896
  klass = mixin.is_a?(RBS::AST::Members::Include) ? Pin::Reference::Include : Pin::Reference::Extend
946
897
  type = build_type(mixin.name, mixin.args)
947
- generic_values = type.all_params.map(&:rooted_tags)
898
+ generic_values = type.all_params.map(&:to_s)
948
899
  pins.push klass.new(
949
- name: type.rooted_name, # reference pins use rooted names
900
+ name: mixin.name.relative!.to_s,
950
901
  type_location: location_decl_to_pin_location(mixin.location),
951
902
  generic_values: generic_values,
952
903
  closure: namespace,
@@ -0,0 +1,206 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Solargraph
4
+ # Convert RBS types to complex types and pins.
5
+ #
6
+ module RbsTranslator
7
+ RBS_TO_YARD_TYPE = {
8
+ 'bool' => 'Boolean',
9
+ 'string' => 'String',
10
+ 'int' => 'Integer',
11
+ 'untyped' => '',
12
+ 'NilClass' => 'nil'
13
+ }
14
+
15
+ # @param type [RBS::Types::Bases::Base]
16
+ # @return [ComplexType]
17
+ def self.to_complex_type(type)
18
+ tag = type_to_tag(type)
19
+ ComplexType.try_parse(tag).force_rooted
20
+ end
21
+
22
+ # @param param_type [RBS::Types::Function::Param]
23
+ # @param name [String]
24
+ # @param decl [Symbol]
25
+ # @param closure [Pin::Closure]
26
+ # @return [Pin::Parameter]
27
+ def self.to_parameter_pin(param_type, name, decl, closure)
28
+ return_type = if decl == :restarg
29
+ ComplexType.parse('Array')
30
+ elsif decl == :kwrestarg
31
+ ComplexType.parse('Hash{Symbol => Object}')
32
+ else
33
+ RbsTranslator.to_complex_type(param_type.type)
34
+ end
35
+ Solargraph::Pin::Parameter.new(decl: decl, name: name, closure: closure, return_type: return_type, source: :rbs, type_location: to_sg_location(param_type.location) || closure.type_location)
36
+ end
37
+
38
+ # @param method_type [RBS::MethodType]
39
+ # @param closure [Pin::Closure]
40
+ # @param parameter_names [Array<String>]
41
+ # @return [Array<Pin::Parameter>]
42
+ def self.to_parameter_pins method_type, closure, parameter_names = []
43
+ if defined?(RBS::Types::UntypedFunction) && method_type.type.is_a?(RBS::Types::UntypedFunction)
44
+ return [
45
+ Solargraph::Pin::Parameter.new(decl: :restarg, name: 'arg', closure: closure, source: :rbs)
46
+ ]
47
+ end
48
+
49
+ arg_num = 0
50
+ params = []
51
+ method_type.type.required_positionals.each do |param|
52
+ params.push RbsTranslator.to_parameter_pin(param, param.name&.to_s || parameter_names[arg_num] || "arg_#{arg_num}", :arg, closure)
53
+ arg_num += 1
54
+ end
55
+ method_type.type.optional_positionals.each do |param|
56
+ params.push RbsTranslator.to_parameter_pin(param, param.name&.to_s || parameter_names[arg_num] || "arg_#{arg_num}", :optarg, closure)
57
+ arg_num += 1
58
+ end
59
+ if method_type.type.rest_positionals
60
+ params.push RbsTranslator.to_parameter_pin(method_type.type.rest_positionals, method_type.type.rest_positionals.name&.to_s || parameter_names[arg_num] || "arg_#{arg_num}", :restarg, closure)
61
+ arg_num += 1
62
+ end
63
+ method_type.type.required_keywords.each do |param|
64
+ params.push RbsTranslator.to_parameter_pin(param.last, param.first.to_s, :kwarg, closure)
65
+ arg_num += 1
66
+ end
67
+ method_type.type.optional_keywords.each do |param|
68
+ params.push RbsTranslator.to_parameter_pin(param.last, param.first.to_s, :kwoptarg, closure)
69
+ arg_num += 1
70
+ end
71
+ if method_type.type.rest_keywords
72
+ params.push RbsTranslator.to_parameter_pin(method_type.type.rest_keywords, method_type.type.rest_keywords.name&.to_s || parameter_names[arg_num] || "arg_#{arg_num}", :kwrestarg, closure)
73
+ end
74
+ params
75
+ end
76
+
77
+ # @param method_type [RBS::MethodType]
78
+ # @param closure [Pin::Closure]
79
+ # @param parameter_names [Array<String>]
80
+ # @return [Pin::Signature]
81
+ def self.to_signature method_type, closure, parameter_names = []
82
+ # There may be edge cases here around different signatures
83
+ # having different type params / orders - we may need to match
84
+ # this data model and have generics live in signatures to
85
+ # handle those correctly
86
+ generics = method_type.type_params.map(&:name).map(&:to_s).uniq
87
+ parameters = to_parameter_pins(method_type, closure, parameter_names)
88
+ return_type = to_complex_type(method_type.type.return_type)
89
+ block = if method_type.block
90
+ block_parameters = to_parameter_pins(method_type.block, closure)
91
+ block_return_type = to_complex_type(method_type.block.type.return_type)
92
+ Pin::Signature.new(generics: generics, parameters: block_parameters, return_type: block_return_type, source: :rbs, type_location: closure.location, closure: closure)
93
+ end
94
+ Pin::Signature.new(generics: generics, parameters: parameters, return_type: return_type, block: block, source: :rbs, type_location: closure.location, closure: closure)
95
+ end
96
+
97
+ # @param type_name [RBS::TypeName]
98
+ # @param type_args [Enumerable<RBS::Types::Bases::Base>]
99
+ # @return [ComplexType::UniqueType]
100
+ def self.build_unique_type(type_name, type_args = [])
101
+ base = RBS_TO_YARD_TYPE[type_name.relative!.to_s] || type_name.relative!.to_s
102
+ params = type_args.map do |a|
103
+ RbsTranslator.to_complex_type(a)
104
+ end
105
+ if base == 'Hash' && params.length == 2
106
+ ComplexType::UniqueType.new(base, [params.first], [params.last], rooted: true, parameters_type: :hash)
107
+ else
108
+ ComplexType::UniqueType.new(base, [], params.reject(&:undefined?), rooted: true, parameters_type: :list)
109
+ end
110
+ end
111
+
112
+ # @param location [RBS::Location, nil]
113
+ # @return [Solargraph::Location, nil]
114
+ def self.to_sg_location(location)
115
+ return nil if location&.name.nil?
116
+
117
+ start_pos = Position.new(location.start_line - 1, location.start_column)
118
+ end_pos = Position.new(location.end_line - 1, location.end_column)
119
+ range = Range.new(start_pos, end_pos)
120
+ Location.new(location.name.to_s, range)
121
+ end
122
+
123
+ class << self
124
+ private
125
+
126
+ # @param type [RBS::Types::Bases::Base]
127
+ # @return [String]
128
+ def type_to_tag type
129
+ case type
130
+ when RBS::Types::Optional
131
+ "#{type_to_tag(type.type)}, nil"
132
+ when RBS::Types::Bases::Bool
133
+ 'Boolean'
134
+ when RBS::Types::Tuple
135
+ "Array(#{type.types.map { |t| type_to_tag(t) }.join(', ')})"
136
+ when RBS::Types::Literal
137
+ type.literal.inspect
138
+ when RBS::Types::Union
139
+ type.types.map { |t| type_to_tag(t) }.join(', ')
140
+ when RBS::Types::Record
141
+ # @todo Better record support
142
+ 'Hash'
143
+ when RBS::Types::Bases::Nil
144
+ 'nil'
145
+ when RBS::Types::Bases::Void
146
+ 'void'
147
+ when RBS::Types::Variable
148
+ "#{Solargraph::ComplexType::GENERIC_TAG_NAME}<#{type.name}>"
149
+ when RBS::Types::Bases::Self, RBS::Types::Bases::Instance
150
+ 'self'
151
+ when RBS::Types::Bases::Top
152
+ # `Top` is the most super superclass
153
+ 'BasicObject'
154
+ when RBS::Types::Intersection
155
+ type.types.map { |member| type_to_tag(member) }.join(', ')
156
+ when RBS::Types::Proc
157
+ 'Proc'
158
+ when RBS::Types::ClassInstance, RBS::Types::Alias, RBS::Types::Interface
159
+ # `Alias` is a top-level type alias, e.g., 'bool' in "type bool = true | false"
160
+ # @todo ensure these get resolved after processing all aliases
161
+ # @todo handle recursive aliases
162
+ #
163
+ # `Interface represents a mix-in module which can be considered a
164
+ # subtype of a consumer of it
165
+ #
166
+ type_tag(type.name, type.args)
167
+ when RBS::Types::ClassSingleton
168
+ # e.g., singleton(String)
169
+ type_tag(type.name)
170
+ when RBS::Types::Bases::Any, RBS::Types::Bases::Bottom
171
+ # `Bottom`` is used in contexts where nothing will ever return
172
+ # - e.g., it could be the return type of 'exit()' or 'raise'
173
+ # @todo define a specific bottom type and use it to
174
+ # determine dead code
175
+ #
176
+ 'undefined'
177
+ else
178
+ Solargraph.logger.warn "Unrecognized RBS type: #{type.class} at #{type.location}"
179
+ 'undefined'
180
+ end
181
+ end
182
+
183
+ # @param type_name [RBS::TypeName]
184
+ # @param type_args [Enumerable<RBS::Types::Bases::Base>]
185
+ # @return [String]
186
+ def type_tag(type_name, type_args = [])
187
+ build_type(type_name, type_args).tags
188
+ end
189
+
190
+ # @param type_name [RBS::TypeName]
191
+ # @param type_args [Enumerable<RBS::Types::Bases::Base>]
192
+ # @return [ComplexType::UniqueType]
193
+ def build_type(type_name, type_args = [])
194
+ base = RBS_TO_YARD_TYPE[type_name.relative!.to_s] || type_name.relative!.to_s
195
+ params = type_args.map { |a| type_to_tag(a) }.map do |t|
196
+ ComplexType.try_parse(t)
197
+ end
198
+ if base == 'Hash' && params.length == 2
199
+ ComplexType::UniqueType.new(base, [params.first], [params.last], rooted: true, parameters_type: :hash)
200
+ else
201
+ ComplexType::UniqueType.new(base, [], params.reject(&:undefined?), rooted: true, parameters_type: :list)
202
+ end
203
+ end
204
+ end
205
+ end
206
+ end