Class: Rigor::TypeNode::Generic

Inherits:
Object
  • Object
show all
Defined in:
lib/rigor/type_node/generic.rb

Overview

A parameterised named-type reference (Pick<T, K>, non-empty-array[Integer], pick_of[T, "name" | "email"], …) in an RBS::Extended payload. The head is the parser- observed name (no bracket type); args is the ordered sequence of type-argument nodes already produced by the parser at one level of depth.

Args are themselves Identifier or Generic. Nested generics ride the same shape: Pick<Address, "name" | "surname"> reaches the resolver as Generic("Pick", [Identifier("Address"), Union([...])]).

The carrier is intentionally permissive about args.size. The grammar-level rule "no brackets ⇒ Identifier; brackets ⇒ Generic" lives on the parser side; nothing here forbids a zero-arg Generic so plugins can synthesise nodes for diagnostic or testing purposes without the parser fighting back.

Instance Method Summary collapse

Constructor Details

#initialize(head:, args:) ⇒ Generic

Returns a new instance of Generic.



20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
# File 'lib/rigor/type_node/generic.rb', line 20

def initialize(head:, args:)
  unless head.is_a?(String) && !head.empty?
    raise ArgumentError,
          "TypeNode::Generic head must be a non-empty String, " \
          "got #{head.inspect}"
  end

  unless args.is_a?(Array) && args.all? { |a| valid_arg?(a) }
    raise ArgumentError,
          "TypeNode::Generic args must be an Array of " \
          "TypeNode::Identifier / TypeNode::Generic / " \
          "TypeNode::IntegerLiteral, got #{args.inspect}"
  end

  # Freeze the String head + Array args so the Data object is `Ractor.shareable?`. Each `a` is
  # already a shareable TypeNode value object (checked above), so freezing the wrapping Array
  # is sufficient.
  frozen_head = head.frozen? ? head : head.dup.freeze
  frozen_args = args.frozen? ? args : args.dup.freeze
  super(head: frozen_head, args: frozen_args)
end