================================================================================
constants
:language(crystal)
================================================================================
A
A1
(A_A____)

::B
::B💎::C
::B_::C4

# now valid in Crystal 1.15!
Á𖹀𐓓::ＢB
ǅdz::ǈlljj
ᾈ
𝐈𝘼
𝙕𝘼𝘼𝙕
--------------------------------------------------------------------------------

(expressions
  (constant)
  (constant)
  (expressions
    (constant))
  (constant)
  (constant)
  (constant)
  (comment)
  (constant)
  (constant)
  (constant)
  (constant)
  (constant))

================================================================================
unions
:language(crystal)
================================================================================
alias AOrB = A | B

alias AOrBCOrD = A|B::C|D

alias NestedUnion = (A)|( B::C|D )

alias NestedUnion2 = A | ( B | (C | D ) | E) | ((F) | G | H)
--------------------------------------------------------------------------------

(expressions
  (alias
    name: (constant)
    type: (union_type
      (constant)
      (constant)))
  (alias
    name: (constant)
    type: (union_type
      (constant)
      (constant)
      (constant)))
  (alias
    name: (constant)
    type: (union_type
      (constant)
      (union_type
        (constant)
        (constant))))
  (alias
    name: (constant)
    type: (union_type
      (constant)
      (union_type
        (constant)
        (union_type
          (constant)
          (constant))
        (constant))
      (union_type
        (constant)
        (constant)
        (constant)))))

================================================================================
proc types
:language(crystal)
================================================================================
[] of ->
{} of -> => ->

[] of -> Int32 | String
[] of Proc(Int32 | String)

[ [] of Int32, Int32 -> String ]
[ [] of Proc(Int32, Int32, String) ]


[ {} of Int32 => Int32, Int32 -> String]
[ {} of Int32 => Proc(Int32, Int32, String)]

{ {} of Int32 => Int32, Int32 }

{ {} of Int32 => Int32, Int32 ->}
{ {} of Int32 => Proc(Int32, Int32, Nil)}

[] of Proc(Int32, Int32 -> Int32)

[] of (A -> B) -> C

def x(y : A, b); end

def x(y : A, B ->); end

alias Foo = A | B -> C | D

alias DoubleProc = -> ->
--------------------------------------------------------------------------------

(expressions
  (array
    of: (proc_type))
  (hash
    of_key: (proc_type)
    of_value: (proc_type))
  (array
    of: (proc_type
      return: (union_type
        (constant)
        (constant))))
  (array
    of: (generic_instance_type
      (constant)
      params: (param_list
        (union_type
          (constant)
          (constant)))))
  (array
    (array
      of: (proc_type
        (constant)
        (constant)
        return: (constant))))
  (array
    (array
      of: (generic_instance_type
        (constant)
        params: (param_list
          (constant)
          (constant)
          (constant)))))
  (array
    (hash
      of_key: (constant)
      of_value: (proc_type
        (constant)
        (constant)
        return: (constant))))
  (array
    (hash
      of_key: (constant)
      of_value: (generic_instance_type
        (constant)
        params: (param_list
          (constant)
          (constant)
          (constant)))))
  (tuple
    (hash
      of_key: (constant)
      of_value: (constant))
    (constant))
  (tuple
    (hash
      of_key: (constant)
      of_value: (proc_type
        (constant)
        (constant))))
  (tuple
    (hash
      of_key: (constant)
      of_value: (generic_instance_type
        (constant)
        params: (param_list
          (constant)
          (constant)
          (constant)))))
  (array
    of: (generic_instance_type
      (constant)
      params: (param_list
        (proc_type
          (constant)
          (constant)
          return: (constant)))))
  (array
    of: (proc_type
      (proc_type
        (constant)
        return: (constant))
      return: (constant)))
  (method_def
    name: (identifier)
    params: (param_list
      (param
        name: (identifier)
        type: (constant))
      (param
        name: (identifier))))
  (method_def
    name: (identifier)
    params: (param_list
      (param
        name: (identifier)
        type: (proc_type
          (constant)
          (constant)))))
  (alias
    name: (constant)
    type: (proc_type
      (union_type
        (constant)
        (constant))
      return: (union_type
        (constant)
        (constant))))
  (alias
    name: (constant)
    type: (proc_type
      return: (proc_type))))

================================================================================
proc types, continued
:language(crystal)
================================================================================
alias P2 = -> Tuple(Int8) ->
--------------------------------------------------------------------------------

(expressions
  (alias
    name: (constant)
    type: (proc_type
      (proc_type
        return: (generic_instance_type
          (constant)
          params: (param_list
            (constant)))))))

================================================================================
proc ambiguity resolution
:language(crystal)
================================================================================
def p1 : ->{1=>1}; end
def p2 : ->{Int32}; end
def p2 : ->{Int32,}; end

def p3 : ->(Int32.to_s); end
def p4 : ->(Int32.class); end

def p3 : ->{Int32 . class_thinyg}; end
def p4 : ->{Int32 . class}; end

def p1 : ->{_}; end
def p2 : ->{_a};end

def p1 : ->(_); end
def p2 : ->(_a);end

def p1 : ->{(A🦝->B🐼)}; end
def p2 : ->{(A🦝-B🐼)}; end

def p1 : ->(Int8 -> Char); end
def p2 : ->(Int8 - Char); end

def p1 : ->{A**,B*}; end
def p2 : ->{A*B}; end

def p1 : ->(A**); end
def p2 : ->(A*B); end

def p1 : ->{A?,}; end
def p2 : ->{A ?1:2}; end

def p1 : ->(A?); end
def p2 : ->(A ?1:2); end
--------------------------------------------------------------------------------

(expressions
  (method_def
    name: (identifier)
    type: (proc_type)
    body: (expressions
      (hash
        (hash_entry
          (integer)
          (integer)))))
  (method_def
    name: (identifier)
    type: (proc_type)
    body: (expressions
      (tuple
        (constant))))
  (method_def
    name: (identifier)
    type: (proc_type
      return: (tuple_type
        (constant))))
  (method_def
    name: (identifier)
    type: (proc_type)
    body: (expressions
      (expressions
        (call
          receiver: (constant)
          method: (identifier)))))
  (method_def
    name: (identifier)
    type: (proc_type
      return: (class_type
        (constant))))
  (method_def
    name: (identifier)
    type: (proc_type)
    body: (expressions
      (tuple
        (call
          receiver: (constant)
          method: (identifier)))))
  (method_def
    name: (identifier)
    type: (proc_type
      return: (tuple_type
        (class_type
          (constant)))))
  (method_def
    name: (identifier)
    type: (proc_type
      return: (tuple_type
        (underscore))))
  (method_def
    name: (identifier)
    type: (proc_type)
    body: (expressions
      (tuple
        (identifier))))
  (method_def
    name: (identifier)
    type: (proc_type
      return: (underscore)))
  (method_def
    name: (identifier)
    type: (proc_type)
    body: (expressions
      (expressions
        (identifier))))
  (method_def
    name: (identifier)
    type: (proc_type
      return: (tuple_type
        (proc_type
          (constant)
          return: (constant)))))
  (method_def
    name: (identifier)
    type: (proc_type)
    body: (expressions
      (tuple
        (expressions
          (call
            receiver: (constant)
            method: (operator)
            arguments: (argument_list
              (constant)))))))
  (method_def
    name: (identifier)
    type: (proc_type
      return: (proc_type
        (constant)
        return: (constant))))
  (method_def
    name: (identifier)
    type: (proc_type)
    body: (expressions
      (expressions
        (call
          receiver: (constant)
          method: (operator)
          arguments: (argument_list
            (constant))))))
  (method_def
    name: (identifier)
    type: (proc_type
      return: (tuple_type
        (pointer_type
          (pointer_type
            (constant)))
        (pointer_type
          (constant)))))
  (method_def
    name: (identifier)
    type: (proc_type)
    body: (expressions
      (tuple
        (call
          receiver: (constant)
          method: (operator)
          arguments: (argument_list
            (constant))))))
  (method_def
    name: (identifier)
    type: (proc_type
      return: (pointer_type
        (pointer_type
          (constant)))))
  (method_def
    name: (identifier)
    type: (proc_type)
    body: (expressions
      (expressions
        (call
          receiver: (constant)
          method: (operator)
          arguments: (argument_list
            (constant))))))
  (method_def
    name: (identifier)
    type: (proc_type
      return: (tuple_type
        (nilable_type
          (constant)))))
  (method_def
    name: (identifier)
    type: (proc_type)
    body: (expressions
      (tuple
        (conditional
          cond: (constant)
          then: (integer)
          else: (integer)))))
  (method_def
    name: (identifier)
    type: (proc_type
      return: (nilable_type
        (constant))))
  (method_def
    name: (identifier)
    type: (proc_type)
    body: (expressions
      (expressions
        (conditional
          cond: (constant)
          then: (integer)
          else: (integer))))))

================================================================================
proc ambiguity resolution, continued
:language(crystal)
================================================================================
def p1 : ->{self,}; end
def p1 : ->{self?,}; end
def p2 : ->{self2,}; end
def p2 : ->{selfa,}; end
def p2 : ->{self!,}; end
def p2 : ->{self: self}; end

def p1 : ->(self); end
def p1 : ->(self?); end
def p2 : ->(self2); end
def p2 : ->(selfa); end
def p2 : ->(self!); end

def p1 : ->{typeof(7)}; end
def p1 : ->{typeof ( "A" )}; end
def p2 : ->{typeof!}; end
def p2 : ->{typeof🆎}; end
def p2 : ->{typeof: "t"}; end

def p1 : ->(typeof(7)); end
def p1 : ->(typeof ( "A" )); end
def p2 : ->(typeof!); end
def p2 : ->(typeof🆎); end

def p1 : -> { A::B, }; end
def p2 : -> { A: :B, }; end

f = -> : -> { a: String; ->{} }
--------------------------------------------------------------------------------

(expressions
  (method_def
    name: (identifier)
    type: (proc_type
      return: (tuple_type
        (self))))
  (method_def
    name: (identifier)
    type: (proc_type
      return: (tuple_type
        (nilable_type
          (self)))))
  (method_def
    name: (identifier)
    type: (proc_type)
    body: (expressions
      (tuple
        (identifier))))
  (method_def
    name: (identifier)
    type: (proc_type)
    body: (expressions
      (tuple
        (identifier))))
  (method_def
    name: (identifier)
    type: (proc_type)
    body: (expressions
      (tuple
        (call
          method: (identifier)))))
  (method_def
    name: (identifier)
    type: (proc_type)
    body: (expressions
      (named_tuple
        (named_expr
          name: (identifier)
          (self)))))
  (method_def
    name: (identifier)
    type: (proc_type
      return: (self)))
  (method_def
    name: (identifier)
    type: (proc_type
      return: (nilable_type
        (self))))
  (method_def
    name: (identifier)
    type: (proc_type)
    body: (expressions
      (expressions
        (identifier))))
  (method_def
    name: (identifier)
    type: (proc_type)
    body: (expressions
      (expressions
        (identifier))))
  (method_def
    name: (identifier)
    type: (proc_type)
    body: (expressions
      (expressions
        (call
          method: (identifier)))))
  (method_def
    name: (identifier)
    type: (proc_type
      return: (tuple_type
        (typeof
          (integer)))))
  (method_def
    name: (identifier)
    type: (proc_type
      return: (tuple_type
        (typeof
          (string
            (literal_content))))))
  (method_def
    name: (identifier)
    type: (proc_type)
    body: (expressions
      (tuple
        (call
          method: (identifier)))))
  (method_def
    name: (identifier)
    type: (proc_type)
    body: (expressions
      (tuple
        (identifier))))
  (method_def
    name: (identifier)
    type: (proc_type)
    body: (expressions
      (named_tuple
        (named_expr
          name: (identifier)
          (string
            (literal_content))))))
  (method_def
    name: (identifier)
    type: (proc_type
      return: (typeof
        (integer))))
  (method_def
    name: (identifier)
    type: (proc_type
      return: (typeof
        (string
          (literal_content)))))
  (method_def
    name: (identifier)
    type: (proc_type)
    body: (expressions
      (expressions
        (call
          method: (identifier)))))
  (method_def
    name: (identifier)
    type: (proc_type)
    body: (expressions
      (expressions
        (identifier))))
  (method_def
    name: (identifier)
    type: (proc_type
      return: (tuple_type
        (constant))))
  (method_def
    name: (identifier)
    type: (proc_type)
    body: (expressions
      (named_tuple
        (named_expr
          name: (identifier)
          (symbol
            (literal_content))))))
  (assign
    lhs: (identifier)
    rhs: (proc
      type: (proc_type)
      block: (block
        body: (expressions
          (type_declaration
            var: (identifier)
            type: (constant))
          (proc
            block: (block)))))))

================================================================================
proc ambiguity resolution, pt 3
================================================================================
# Not tagged with :language(crystal) because the Crystal parser doesn't represent
# these keys as strings
def p1 : ->{"a": "b"}; end
def p1 : ->{ %(a()): "b"}; end
def p1 : ->{ %q|a|: "b"}; end
def p1 : ->{ %Q<<>a>: "b"}; end
def p1 : ->{ %[[a]]: "b"}; end
def p1 : ->{ %{a{}a}: "b"}; end
--------------------------------------------------------------------------------
(expressions
  (comment)
  (comment)
  (method_def
    name: (identifier)
    type: (proc_type)
    body: (expressions
      (named_tuple
        (named_expr
          name: (string
            (literal_content))
          (string
            (literal_content))))))
  (method_def
    name: (identifier)
    type: (proc_type)
    body: (expressions
      (named_tuple
        (named_expr
          name: (string
            (literal_content))
          (string
            (literal_content))))))
  (method_def
    name: (identifier)
    type: (proc_type)
    body: (expressions
      (named_tuple
        (named_expr
          name: (string
            (literal_content))
          (string
            (literal_content))))))
  (method_def
    name: (identifier)
    type: (proc_type)
    body: (expressions
      (named_tuple
        (named_expr
          name: (string
            (literal_content))
          (string
            (literal_content))))))
  (method_def
    name: (identifier)
    type: (proc_type)
    body: (expressions
      (named_tuple
        (named_expr
          name: (string
            (literal_content))
          (string
            (literal_content))))))
  (method_def
    name: (identifier)
    type: (proc_type)
    body: (expressions
      (named_tuple
        (named_expr
          name: (string
            (literal_content))
          (string
            (literal_content)))))))

================================================================================
tuple types
:language(crystal)
================================================================================
alias Foo1 = {Int32}
alias Foo2 = {Int32, Int32}

-> : {Int32, Proc(Int32)} { {1, -> {1}} }

-> : Int32, Int32 -> { ->, ->} do  end
--------------------------------------------------------------------------------

(expressions
  (alias
    name: (constant)
    type: (tuple_type
      (constant)))
  (alias
    name: (constant)
    type: (tuple_type
      (constant)
      (constant)))
  (proc
    type: (tuple_type
      (constant)
      (generic_instance_type
        (constant)
        params: (param_list
          (constant))))
    block: (block
      body: (expressions
        (tuple
          (integer)
          (proc
            block: (block
              body: (expressions
                (integer))))))))
  (proc
    type: (proc_type
      (constant)
      (constant)
      return: (tuple_type
        (proc_type)
        (proc_type)))
    block: (block)))

================================================================================
named tuple types
:language(crystal)
================================================================================
alias NamedTuple1 = {x: Int32, y: String, Z: Char, w?: String}

alias NamedTuple1 = NamedTuple(x: Int32, y: String, Z: Char, w?: String)
--------------------------------------------------------------------------------

(expressions
  (alias
    name: (constant)
    type: (named_tuple_type
      (named_type
        name: (identifier)
        (constant))
      (named_type
        name: (identifier)
        (constant))
      (named_type
        name: (identifier)
        (constant))
      (named_type
        name: (identifier)
        (constant))))
  (alias
    name: (constant)
    type: (generic_instance_type
      (constant)
      params: (param_list
        (named_type
          name: (identifier)
          (constant))
        (named_type
          name: (identifier)
          (constant))
        (named_type
          name: (identifier)
          (constant))
        (named_type
          name: (identifier)
          (constant))))))

================================================================================
named tuple types with string keys
================================================================================
# Not tagged with :language(crystal) because the Crystal parser doesn't represent
# these keys as strings

alias NamedTupleWithStrings = {"x": Int32, %<.>: String, %q(hi): Int8}

alias NamedTupleWithStrings = NamedTuple("x": Int32, %q(hi again): Int8)
--------------------------------------------------------------------------------

(expressions
  (comment)
  (comment)
  (alias
    name: (constant)
    type: (named_tuple_type
      (named_type
        name: (string
          (literal_content))
        (constant))
      (named_type
        name: (string
          (literal_content))
        (constant))
      (named_type
        name: (string
          (literal_content))
        (constant))))
  (alias
    name: (constant)
    type: (generic_instance_type
      (constant)
      params: (param_list
        (named_type
          name: (string
            (literal_content))
          (constant))
        (named_type
          name: (string
            (literal_content))
          (constant))))))

================================================================================
generic types
:language(crystal)
================================================================================
class Gen(*U)
end

alias Foo = Gen()
alias Foo2 = Gen(Int32)
alias Foo3 = Gen(Int32,)
alias Foo4 = Gen(Int32,String)
alias Foo5 = Gen(Int32,String|Char)
--------------------------------------------------------------------------------

(expressions
  (class_def
    name: (generic_type
      (constant)
      params: (param_list
        (splat
          (constant)))))
  (alias
    name: (constant)
    type: (generic_instance_type
      (constant)))
  (alias
    name: (constant)
    type: (generic_instance_type
      (constant)
      params: (param_list
        (constant))))
  (alias
    name: (constant)
    type: (generic_instance_type
      (constant)
      params: (param_list
        (constant))))
  (alias
    name: (constant)
    type: (generic_instance_type
      (constant)
      params: (param_list
        (constant)
        (constant))))
  (alias
    name: (constant)
    type: (generic_instance_type
      (constant)
      params: (param_list
        (constant)
        (union_type
          (constant)
          (constant))))))

================================================================================
generic classes, etc.
:language(crystal)
================================================================================
class Foo(*T)
  getter content

  def initialize(*content : *T)
    @content = content
  end
end
--------------------------------------------------------------------------------

(expressions
  (class_def
    name: (generic_type
      (constant)
      params: (param_list
        (splat
          (constant))))
    body: (expressions
      (call
        method: (identifier)
        arguments: (argument_list
          (identifier)))
      (method_def
        name: (identifier)
        params: (param_list
          (splat_param
            name: (identifier)
            type: (splat_type
              (constant))))
        body: (expressions
          (assign
            lhs: (instance_var)
            rhs: (identifier)))))))

================================================================================
splat types
:language(crystal)
================================================================================
def foo : {*{Int32 | Int8}}
end

alias Foo = {*{Int32 | Int8, Int8}}

alias Bar = {Char, *Foo, String}

c : *Char -> = ->(c : Char){}
--------------------------------------------------------------------------------

(expressions
  (method_def
    name: (identifier)
    type: (tuple_type
      (splat_type
        (tuple_type
          (union_type
            (constant)
            (constant))))))
  (alias
    name: (constant)
    type: (tuple_type
      (splat_type
        (tuple_type
          (union_type
            (constant)
            (constant))
          (constant)))))
  (alias
    name: (constant)
    type: (tuple_type
      (constant)
      (splat_type
        (constant))
      (constant)))
  (type_declaration
    var: (identifier)
    type: (proc_type
      (splat_type
        (constant)))
    value: (proc
      params: (param_list
        (param
          name: (identifier)
          type: (constant)))
      block: (block))))

================================================================================
underscore type
:language(crystal)
================================================================================
def foo(x : _, y : _, _ -> String)
  _ = 7
  a, _, b = expand_foo
end
--------------------------------------------------------------------------------

(expressions
  (method_def
    name: (identifier)
    params: (param_list
      (param
        name: (identifier)
        type: (underscore))
      (param
        name: (identifier)
        type: (proc_type
          (underscore)
          (underscore)
          return: (constant))))
    body: (expressions
      (assign
        lhs: (underscore)
        rhs: (integer))
      (assign
        lhs: (identifier)
        lhs: (underscore)
        lhs: (identifier)
        rhs: (identifier)))))

================================================================================
pointer type
:language(crystal)
================================================================================
alias ProcP = -> C *
alias SP = String*
alias SPP = String**
alias SPNP = String*?*
alias SPPPPPP = String** * ** *

int_ptr : UInt8* = Pointer(UInt8).null

alias Foo = {*{Char, String}*} # compiler blocks this type of splat
--------------------------------------------------------------------------------

(expressions
  (alias
    name: (constant)
    type: (proc_type
      return: (pointer_type
        (constant))))
  (alias
    name: (constant)
    type: (pointer_type
      (constant)))
  (alias
    name: (constant)
    type: (pointer_type
      (pointer_type
        (constant))))
  (alias
    name: (constant)
    type: (pointer_type
      (nilable_type
        (pointer_type
          (constant)))))
  (alias
    name: (constant)
    type: (pointer_type
      (pointer_type
        (pointer_type
          (pointer_type
            (pointer_type
              (pointer_type
                (constant))))))))
  (type_declaration
    var: (identifier)
    type: (pointer_type
      (constant))
    value: (call
      receiver: (generic_instance_type
        (constant)
        params: (param_list
          (constant)))
      method: (identifier)))
  (alias
    name: (constant)
    type: (tuple_type
      (splat_type
        (pointer_type
          (tuple_type
            (constant)
            (constant))))))
  (comment))

================================================================================
nilable type
:language(crystal)
================================================================================
alias S = String*?
alias I = Foo(Bar?)?????

a = [] of (String ?) ?
b = ([] of (String?)?) ? 1 : 2
--------------------------------------------------------------------------------

(expressions
  (alias
    name: (constant)
    type: (nilable_type
      (pointer_type
        (constant))))
  (alias
    name: (constant)
    type: (nilable_type
      (nilable_type
        (nilable_type
          (nilable_type
            (nilable_type
              (generic_instance_type
                (constant)
                params: (param_list
                  (nilable_type
                    (constant))))))))))
  (assign
    lhs: (identifier)
    rhs: (array
      of: (nilable_type
        (nilable_type
          (constant)))))
  (assign
    lhs: (identifier)
    rhs: (conditional
      cond: (expressions
        (array
          of: (nilable_type
            (nilable_type
              (constant)))))
      then: (integer)
      else: (integer))))

================================================================================
typeof
:language(crystal)
================================================================================
alias Foo = {Char, typeof(1 + w)}

def p2 : ->{asdf: typeof(FOO)}; end
--------------------------------------------------------------------------------

(expressions
  (alias
    name: (constant)
    type: (tuple_type
      (constant)
      (typeof
        (call
          receiver: (integer)
          method: (operator)
          arguments: (argument_list
            (identifier))))))
  (method_def
    name: (identifier)
    type: (proc_type)
    body: (expressions
      (named_tuple
        (named_expr
          name: (identifier)
          (typeof
            (constant)))))))

================================================================================
static array types
:language(crystal)
================================================================================
alias A = Int8[+1_0i32]
alias B = ->Int8[0xa]
alias C = (->Int8)[42]
alias D = UInt8[CONST]
alias E = UInt8[sizeof(Int64)]
alias F = UInt8[instance_sizeof(Foo(Bar))]
alias G = LibC::Char[offsetof(String -> Int32, @a)]
alias H = StaticArray(Int32, 8)
alias I = StaticArray(Char*, 2.0)
alias J = Foo(Bar,)
alias K = Foo(Bar, Baz -> Qux)
alias L = Foo(Bar, Baz)

g : Int64[8]
--------------------------------------------------------------------------------

(expressions
  (alias
    name: (constant)
    type: (static_array_type
      (constant)
      (integer)))
  (alias
    name: (constant)
    type: (proc_type
      return: (static_array_type
        (constant)
        (integer))))
  (alias
    name: (constant)
    type: (static_array_type
      (proc_type
        return: (constant))
      (integer)))
  (alias
    name: (constant)
    type: (static_array_type
      (constant)
      (constant)))
  (alias
    name: (constant)
    type: (static_array_type
      (constant)
      (sizeof
        (constant))))
  (alias
    name: (constant)
    type: (static_array_type
      (constant)
      (instance_sizeof
        (generic_instance_type
          (constant)
          params: (param_list
            (constant))))))
  (alias
    name: (constant)
    type: (static_array_type
      (constant)
      (offsetof
        (proc_type
          (constant)
          return: (constant))
        (instance_var))))
  (alias
    name: (constant)
    type: (generic_instance_type
      (constant)
      params: (param_list
        (constant)
        (integer))))
  (alias
    name: (constant)
    type: (generic_instance_type
      (constant)
      params: (param_list
        (pointer_type
          (constant))
        (float))))
  (alias
    name: (constant)
    type: (generic_instance_type
      (constant)
      params: (param_list
        (constant))))
  (alias
    name: (constant)
    type: (generic_instance_type
      (constant)
      params: (param_list
        (proc_type
          (constant)
          (constant)
          return: (constant)))))
  (alias
    name: (constant)
    type: (generic_instance_type
      (constant)
      params: (param_list
        (constant)
        (constant))))
  (type_declaration
    var: (identifier)
    type: (static_array_type
      (constant)
      (integer))))

=================
double splat type
:language(crystal)
=================

class MyClass(T)
  def self.new(**options : **T)
  end
end
---

(expressions
  (class_def
    name: (generic_type
      (constant)
      params: (param_list
        (constant)))
    body: (expressions
      (method_def
        class: (self)
        name: (identifier)
        params: (param_list
          (double_splat_param
            name: (identifier)
            type: (double_splat_type
              (constant))))))))

=====================
union type precedence
:language(crystal)
=====================
foo : Int32 | Int64.class
bar : (Int32 | Int64).class

foo : Int32 | LibXML::Node*
bar : (Int32 | LibXML::Node)*

foo : Int32 | Int64[8]
bar : (Int32 | Int64)[8]

foo : A | B? | C* | {d: D} | {E} | _ -> F | self | G.class = typeof(A | B? | C)
---

(expressions
  (type_declaration
    var: (identifier)
    type: (union_type
      (constant)
      (class_type
        (constant))))
  (type_declaration
    var: (identifier)
    type: (class_type
      (union_type
        (constant)
        (constant))))
  (type_declaration
    var: (identifier)
    type: (union_type
      (constant)
      (pointer_type
        (constant))))
  (type_declaration
    var: (identifier)
    type: (pointer_type
      (union_type
        (constant)
        (constant))))
  (type_declaration
    var: (identifier)
    type: (union_type
      (constant)
      (static_array_type
        (constant)
        (integer))))
  (type_declaration
    var: (identifier)
    type: (static_array_type
      (union_type
        (constant)
        (constant))
      (integer)))
  (type_declaration
    var: (identifier)
    type: (proc_type
      (union_type
        (constant)
        (nilable_type
          (constant))
        (pointer_type
          (constant))
        (named_tuple_type
          (named_type
            name: (identifier)
            (constant)))
        (tuple_type
          (constant))
        (underscore))
      return: (union_type
        (constant)
        (self)
        (class_type
          (constant))))
    value: (typeof
      (call
        receiver: (call
          receiver: (constant)
          method: (operator)
          arguments: (argument_list
            (nilable_constant
              (constant))))
        method: (operator)
        arguments: (argument_list
          (constant))))))
