///|
fn WgslIrValidator::type_layout(
  self : WgslIrValidator,
  ty : Handle,
) -> WgslIrValidationLayout raise WgslIrValidationError {
  match self.shader_module.types.get(ty) {
    Some(type_) => self.type_inner_layout(type_.inner)
    None => raise InvalidTypeHandle(ty.index())
  }
}

///|
fn WgslIrValidator::type_inner_layout(
  self : WgslIrValidator,
  inner : TypeInner,
) -> WgslIrValidationLayout raise WgslIrValidationError {
  match inner {
    Scalar(scalar) | Atomic(scalar) =>
      { align: scalar.width, size: scalar.width, }
    Vector(size, scalar) => {
      let lanes = size.width()
      let raw_size = lanes * scalar.width
      {
        align: if lanes == 3 {
          4 * scalar.width
        } else {
          raw_size
        },
        size: raw_size,
      }
    }
    Matrix(columns, rows, scalar) => {
      let row_lanes = rows.width()
      let column_align = if row_lanes == 3 {
        4 * scalar.width
      } else {
        row_lanes * scalar.width
      }
      let column_size = wgsl_ir_validation_align_to(
        row_lanes * scalar.width,
        column_align,
      )
      { align: column_align, size: column_size * columns.width(), }
    }
    Array(base, size, stride) => {
      let count = match size {
        Constant(value) => value
        Dynamic | Pending(_) => 1
      }
      { align: self.type_layout(base).align, size: count * stride, }
    }
    Struct(members, span) | PredeclaredStruct(members, span) => {
      let mut align = 1
      for struct_member in members {
        let member_layout = self.type_layout(struct_member.ty)
        let member_align = match struct_member.align {
          Some(value) => value
          None => member_layout.align
        }
        if member_align > align {
          align = member_align
        }
      }
      { align, size: span, }
    }
    Pointer(_, _) | ValuePointer(_, _, _) => { align: 1, size: 4, }
    Image(_, _, _)
    | Sampler(_)
    | AccelerationStructure(_)
    | RayQuery(_)
    | BindingArray(_, _) => { align: 1, size: 0, }
    CooperativeMatrix(columns, rows, scalar, _) =>
      {
        align: scalar.width,
        size: wgsl_ir_validation_cooperative_size_width(columns) *
        wgsl_ir_validation_cooperative_size_width(rows) *
        scalar.width,
      }
  }
}

///|
fn WgslIrValidator::find_type_by_name(
  self : WgslIrValidator,
  name : String,
) -> Handle? {
  for index in 0.. Handle? {
  self.find_type_inner(Scalar(scalar))
}

///|
fn WgslIrValidator::vector_type(
  self : WgslIrValidator,
  size : VectorSize,
  scalar : Scalar,
) -> Handle? {
  self.find_type_inner(Vector(size, scalar))
}

///|
fn WgslIrValidator::matrix_type(
  self : WgslIrValidator,
  columns : VectorSize,
  rows : VectorSize,
  scalar : Scalar,
) -> Handle? {
  self.find_type_inner(Matrix(columns, rows, scalar))
}

///|
fn WgslIrValidator::cooperative_matrix_type(
  self : WgslIrValidator,
  columns : CooperativeSize,
  rows : CooperativeSize,
  scalar : Scalar,
  role : CooperativeRole,
) -> Handle? {
  self.find_type_inner(CooperativeMatrix(columns, rows, scalar, role))
}

///|
fn WgslIrValidator::find_type_inner(
  self : WgslIrValidator,
  inner : TypeInner,
) -> Handle? {
  for index in 0.. String {
  ignore(self)
  match function.name {
    Some(name) => name
    None => ""
  }
}

///|
fn wgsl_ir_validation_binary_operator_is_comparison(
  op : BinaryOperator,
) -> Bool {
  match op {
    Equal | NotEqual | Less | LessEqual | Greater | GreaterEqual => true
    _ => false
  }
}

///|
fn wgsl_ir_validation_scalar_assignable(
  expected : Scalar,
  actual : Scalar,
) -> Bool {
  if expected == actual {
    return true
  }
  match (expected.kind, actual.kind) {
    (Sint, AbstractInt) | (Uint, AbstractInt) | (Float, AbstractFloat) => true
    (Float, AbstractInt) => true
    (AbstractFloat, AbstractInt) | (AbstractInt, AbstractFloat) => true
    _ => false
  }
}

///|
fn wgsl_ir_validation_storage_format_scalar(format : StorageFormat) -> Scalar {
  match format {
    R64Uint => Scalar(Uint, 8)
    R8Uint
    | R16Uint
    | Rg8Uint
    | R32Uint
    | Rg16Uint
    | Rgba8Uint
    | Rgb10a2Uint
    | Rg32Uint
    | Rgba16Uint
    | Rgba32Uint => Scalar(Uint, 4)
    R8Sint | R16Sint | Rg8Sint | R32Sint | Rg16Sint | Rgba8Sint | Rgba32Sint =>
      Scalar(Sint, 4)
    _ => Scalar(Float, 4)
  }
}

///|
fn wgsl_ir_validation_scalar_width_is_valid(
  kind : ScalarKind,
  width : Int32,
) -> Bool {
  match kind {
    Bool => width == 1
    Sint | Uint | Float => width == 2 || width == 4 || width == 8
    AbstractInt | AbstractFloat => width == 8
  }
}

///|
fn wgsl_ir_validation_swizzle_index(component : SwizzleComponent) -> Int32 {
  match component {
    X => 0
    Y => 1
    Z => 2
    W => 3
  }
}

///|
fn wgsl_ir_validation_is_power_of_two(value : Int32) -> Bool {
  value > 0 && (value & (value - 1)) == 0
}

///|
fn wgsl_ir_validation_align_to(value : Int32, align : Int32) -> Int32 {
  if align <= 1 {
    value
  } else {
    (value + align - 1) / align * align
  }
}

///|
fn wgsl_ir_validation_cooperative_size_width(size : CooperativeSize) -> Int32 {
  match size {
    Eight => 8
    Sixteen => 16
  }
}