Class: RBI::Type

Inherits:
Object
  • Object
show all
Extended by:
T::Helpers, T::Sig
Defined in:
lib/rbi/type.rb,
lib/rbi/rbs_printer.rb,
lib/rbi/type_parser.rb,
lib/rbi/type_visitor.rb

Overview

The base class for all RBI types.

Defined Under Namespace

Classes: All, Any, Anything, AttachedClass, Boolean, Class, ClassOf, Composite, Error, Generic, Nilable, NoReturn, Proc, SelfType, Shape, Simple, Tuple, TypeParameter, Untyped, Visitor, Void

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initializeType

Returns a new instance of Type.



699
700
701
# File 'lib/rbi/type.rb', line 699

def initialize
  @nilable = T.let(false, T::Boolean)
end

Class Method Details

.all(type1, type2, *types) ⇒ Object



563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
# File 'lib/rbi/type.rb', line 563

def all(type1, type2, *types)
  types = [type1, type2, *types]

  # TODO: should we move this logic to a `flatten!`, `normalize!` or `simplify!` method?
  flattened = types.flatten.flat_map do |type|
    case type
    when All
      type.types
    else
      type
    end
  end.uniq

  if flattened.size == 1
    T.must(flattened.first)
  else
    raise ArgumentError, "RBI::Type.all should have at least 2 types supplied" if flattened.size < 2

    All.new(flattened)
  end
end

.any(type1, type2, *types) ⇒ Object



590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
# File 'lib/rbi/type.rb', line 590

def any(type1, type2, *types)
  types = [type1, type2, *types]

  # TODO: should we move this logic to a `flatten!`, `normalize!` or `simplify!` method?
  flattened = types.flatten.flat_map do |type|
    case type
    when Any
      type.types
    else
      type
    end
  end

  is_nilable = T.let(false, T::Boolean)

  types = flattened.filter_map do |type|
    case type
    when Simple
      if type.name == "NilClass"
        is_nilable = true
        nil
      else
        type
      end
    when Nilable
      is_nilable = true
      type.type
    else
      type
    end
  end.uniq

  has_true_class = types.any? { |type| type.is_a?(Simple) && type.name == "TrueClass" }
  has_false_class = types.any? { |type| type.is_a?(Simple) && type.name == "FalseClass" }

  if has_true_class && has_false_class
    types = types.reject { |type| type.is_a?(Simple) && (type.name == "TrueClass" || type.name == "FalseClass") }
    types << boolean
  end

  type = case types.size
  when 0
    if is_nilable
      is_nilable = false
      simple("NilClass")
    else
      raise ArgumentError, "RBI::Type.any should have at least 2 types supplied"
    end
  when 1
    T.must(types.first)
  else
    Any.new(types)
  end

  if is_nilable
    nilable(type)
  else
    type
  end
end

.anythingObject



488
489
490
# File 'lib/rbi/type.rb', line 488

def anything
  Anything.new
end

.attached_classObject



494
495
496
# File 'lib/rbi/type.rb', line 494

def attached_class
  AttachedClass.new
end

.booleanObject



500
501
502
# File 'lib/rbi/type.rb', line 500

def boolean
  Boolean.new
end

.class_of(type, type_parameter = nil) ⇒ Object



538
539
540
# File 'lib/rbi/type.rb', line 538

def class_of(type, type_parameter = nil)
  ClassOf.new(type, type_parameter)
end

.generic(name, *params) ⇒ Object



655
656
657
# File 'lib/rbi/type.rb', line 655

def generic(name, *params)
  T.unsafe(Generic).new(name, *params.flatten)
end

.nilable(type) ⇒ Object



547
548
549
550
551
552
553
554
555
556
# File 'lib/rbi/type.rb', line 547

def nilable(type)
  # TODO: should we move this logic to a `flatten!`, `normalize!` or `simplify!` method?
  return type if type.is_a?(Untyped)

  if type.nilable?
    type
  else
    Nilable.new(type)
  end
end

.noreturnObject



506
507
508
# File 'lib/rbi/type.rb', line 506

def noreturn
  NoReturn.new
end

.parse_node(node) ⇒ Object



26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
# File 'lib/rbi/type_parser.rb', line 26

def parse_node(node)
  case node
  when Prism::ConstantReadNode, Prism::ConstantPathNode
    parse_constant(node)
  when Prism::CallNode
    parse_call(node)
  when Prism::ArrayNode
    parse_tuple(node)
  when Prism::HashNode, Prism::KeywordHashNode
    parse_shape(node)
  when Prism::ParenthesesNode
    body = node.body
    raise Error, "Expected exactly 1 child, got 0" unless body.is_a?(Prism::StatementsNode)

    children = body.body
    raise Error, "Expected exactly 1 child, got #{children.size}" unless children.size == 1

    parse_node(T.must(children.first))
  else
    raise Error, "Unexpected node `#{node}`"
  end
end

.parse_string(string) ⇒ Object

Raises:



10
11
12
13
14
15
16
17
18
19
20
21
22
23
# File 'lib/rbi/type_parser.rb', line 10

def parse_string(string)
  result = Prism.parse(string)
  unless result.success?
    raise Error, result.errors.map { |e| "#{e.message}." }.join(" ")
  end

  node = result.value
  raise Error, "Expected a type expression, got `#{node.class}`" unless node.is_a?(Prism::ProgramNode)
  raise Error, "Expected a type expression, got nothing" if node.statements.body.empty?
  raise Error, "Expected a single type expression, got `#{node.slice}`" if node.statements.body.size > 1

  node = T.must(node.statements.body.first)
  parse_node(node)
end

.procObject



683
684
685
# File 'lib/rbi/type.rb', line 683

def proc
  Proc.new
end

.self_typeObject



512
513
514
# File 'lib/rbi/type.rb', line 512

def self_type
  SelfType.new
end

.shape(types = {}) ⇒ Object



675
676
677
# File 'lib/rbi/type.rb', line 675

def shape(types = {})
  Shape.new(types)
end

.simple(name) ⇒ Object

Raises:

  • (NameError)


477
478
479
480
481
482
# File 'lib/rbi/type.rb', line 477

def simple(name)
  # TODO: should we allow creating the instance anyway and move this to a `validate!` method?
  raise NameError, "Invalid type name: `#{name}`" unless valid_identifier?(name)

  Simple.new(name)
end

.t_class(type) ⇒ Object



532
533
534
# File 'lib/rbi/type.rb', line 532

def t_class(type)
  Class.new(type)
end

.tuple(*types) ⇒ Object



669
670
671
# File 'lib/rbi/type.rb', line 669

def tuple(*types)
  Tuple.new(types.flatten)
end

.type_parameter(name) ⇒ Object



661
662
663
# File 'lib/rbi/type.rb', line 661

def type_parameter(name)
  TypeParameter.new(name)
end

.untypedObject



518
519
520
# File 'lib/rbi/type.rb', line 518

def untyped
  Untyped.new
end

.voidObject



524
525
526
# File 'lib/rbi/type.rb', line 524

def void
  Void.new
end

Instance Method Details

#==(other) ⇒ Object



745
# File 'lib/rbi/type.rb', line 745

def ==(other); end

#eql?(other) ⇒ Boolean

Returns:



748
749
750
# File 'lib/rbi/type.rb', line 748

def eql?(other)
  self == other
end

#hashObject



753
754
755
# File 'lib/rbi/type.rb', line 753

def hash
  to_rbi.hash
end

#nilableObject



713
714
715
# File 'lib/rbi/type.rb', line 713

def nilable
  Type.nilable(self)
end

#nilable?Boolean

Returns:



740
741
742
# File 'lib/rbi/type.rb', line 740

def nilable?
  is_a?(Nilable)
end

#non_nilableObject



728
729
730
731
732
733
734
735
736
# File 'lib/rbi/type.rb', line 728

def non_nilable
  # TODO: Should this logic be moved into a builder method?
  case self
  when Nilable
    type
  else
    self
  end
end

#rbs_stringObject



1023
1024
1025
1026
1027
# File 'lib/rbi/rbs_printer.rb', line 1023

def rbs_string
  p = TypePrinter.new
  p.visit(self)
  p.string
end

#to_rbiObject



758
# File 'lib/rbi/type.rb', line 758

def to_rbi; end

#to_sObject



761
762
763
# File 'lib/rbi/type.rb', line 761

def to_s
  to_rbi
end