///|
fn WgslIrValidator::missing_function_expression_type(
self : WgslIrValidator,
function : Function,
handle : Handle,
) -> WgslIrValidationError {
ignore(self)
let expression = match function.expressions.items.get(handle.index()) {
Some(value) => @debug.to_string(value)
None => ""
}
MissingExpressionType(handle.index(), expression)
}
///|
fn WgslIrValidator::missing_global_expression_type(
self : WgslIrValidator,
handle : Handle,
) -> WgslIrValidationError {
let expression = match
self.shader_module.global_expressions.items.get(handle.index()) {
Some(value) => @debug.to_string(value)
None => ""
}
MissingExpressionType(handle.index(), expression)
}
///|
fn WgslIrValidator::invalid_condition_type(
self : WgslIrValidator,
function : Function,
handle : Handle,
ty : Handle,
) -> WgslIrValidationError {
let expression = match function.expressions.items.get(handle.index()) {
Some(value) => @debug.to_string(value)
None => ""
}
let ty_text = match self.shader_module.types.items.get(ty.index()) {
Some(value) => @debug.to_string(value)
None => ""
}
InvalidConditionType(
self.function_display_name(function),
handle.index(),
expression,
ty_text,
)
}
///|
fn WgslIrValidator::require_bool_condition(
self : WgslIrValidator,
function : Function,
handle : Handle,
) -> Unit raise WgslIrValidationError {
guard self.function_expression_type(function, handle) is Some(ty) else {
raise self.missing_function_expression_type(function, handle)
}
guard self.type_is_bool_scalar(ty) else {
raise self.invalid_condition_type(function, handle, ty)
}
}
///|
fn WgslIrValidator::require_integer_selector(
self : WgslIrValidator,
function : Function,
handle : Handle,
) -> Unit raise WgslIrValidationError {
guard self.function_expression_type(function, handle) is Some(ty) else {
raise self.missing_function_expression_type(function, handle)
}
guard self.type_is_integer_scalar(ty) else {
raise self.invalid_condition_type(function, handle, ty)
}
}
///|
fn WgslIrValidator::require_return_value(
self : WgslIrValidator,
function : Function,
handle : Handle,
) -> Unit raise WgslIrValidationError {
guard function.result is Some(result) else {
raise InvalidReturnValue(self.function_display_name(function))
}
match self.function_expression_type(function, handle) {
Some(actual) =>
if !self.type_assignable(result.ty, actual) {
raise InvalidReturnValue(self.function_display_name(function))
}
None => ()
}
}
///|
fn WgslIrValidator::require_void_return(
self : WgslIrValidator,
function : Function,
) -> Unit raise WgslIrValidationError {
if function.result != None {
raise InvalidReturnValue(self.function_display_name(function))
}
}
///|
fn WgslIrValidator::require_store(
self : WgslIrValidator,
function : Function,
pointer : Handle,
value : Handle,
) -> Unit raise WgslIrValidationError {
guard self.store_target_value_type(function, pointer) is Some(value_ty) else {
raise InvalidStoreTarget(pointer.index())
}
match self.function_expression_type(function, value) {
Some(actual) => {
// The Naga IR allows storing a scalar into an `atomic` target
// (naga src/valid/function.rs, `S::Store`); the relaxation is scoped
// to stores and does not extend to general type compatibility.
let assignable = match self.atomic_scalar_type(value_ty) {
Some(scalar) =>
match self.shader_module.types.get(actual) {
Some(actual_ty) =>
self.type_inner_assignable(Scalar(scalar), actual_ty.inner)
None => false
}
None => self.type_assignable(value_ty, actual)
}
if !assignable {
raise InvalidStoreTarget(pointer.index())
}
}
None => ()
}
}
///|
fn WgslIrValidator::require_function_compose_signature(
self : WgslIrValidator,
function : Function,
ty : Handle,
components : Array[Handle],
) -> Unit raise WgslIrValidationError {
match self.shader_module.types.get(ty) {
Some(type_) =>
match type_.inner {
Scalar(_) =>
if components.length() != 0 && components.length() != 1 {
raise InvalidExpression(
"scalar constructor component count mismatch",
ty.index(),
)
}
Vector(size, _) =>
self.require_composite_component_capacity(
function,
components,
size.width(),
ty.index(),
)
Matrix(columns, rows, _) =>
self.require_composite_component_capacity(
function,
components,
columns.width() * rows.width(),
ty.index(),
)
Struct(members, _) | PredeclaredStruct(members, _) =>
if components.length() != 0 && components.length() != members.length() {
raise InvalidExpression(
"struct constructor component count mismatch",
ty.index(),
)
}
Array(_, Constant(count), _) | BindingArray(_, Constant(count)) =>
if components.length() != 0 && components.length() != count {
raise InvalidExpression(
"array constructor component count mismatch",
ty.index(),
)
}
Array(_, Dynamic, _) | BindingArray(_, Dynamic) =>
raise InvalidExpression(
"runtime array constructor is not valid",
ty.index(),
)
_ => ()
}
None => ()
}
}
///|
fn WgslIrValidator::require_global_compose_signature(
self : WgslIrValidator,
ty : Handle,
components : Array[Handle],
) -> Unit raise WgslIrValidationError {
match self.shader_module.types.get(ty) {
Some(type_) =>
match type_.inner {
Scalar(_) =>
if components.length() != 0 && components.length() != 1 {
raise InvalidExpression(
"scalar constructor component count mismatch",
ty.index(),
)
}
Vector(size, _) =>
self.require_global_composite_component_capacity(
components,
size.width(),
ty.index(),
)
Matrix(columns, rows, _) =>
self.require_global_composite_component_capacity(
components,
columns.width() * rows.width(),
ty.index(),
)
Struct(members, _) | PredeclaredStruct(members, _) =>
if components.length() != 0 && components.length() != members.length() {
raise InvalidExpression(
"struct constructor component count mismatch",
ty.index(),
)
}
Array(_, Constant(count), _) | BindingArray(_, Constant(count)) =>
if components.length() != 0 && components.length() != count {
raise InvalidExpression(
"array constructor component count mismatch",
ty.index(),
)
}
Array(_, Dynamic, _) | BindingArray(_, Dynamic) =>
raise InvalidExpression(
"runtime array constructor is not valid",
ty.index(),
)
_ => ()
}
None => ()
}
}
///|
fn WgslIrValidator::require_composite_component_capacity(
self : WgslIrValidator,
function : Function,
components : Array[Handle],
expected_lanes : Int32,
expression_index : Int32,
) -> Unit raise WgslIrValidationError {
if components.length() == 0 {
return
}
let mut lanes = 0
for component in components {
match self.function_expression_lane_count(function, component) {
Some(count) => lanes += count
None => raise self.missing_function_expression_type(function, component)
}
}
if lanes != expected_lanes && !(components.length() == 1 && lanes == 1) {
raise InvalidExpression(
"vector constructor lane count mismatch", expression_index,
)
}
}
///|
fn WgslIrValidator::function_expression_lane_count(
self : WgslIrValidator,
function : Function,
handle : Handle,
) -> Int32? {
match function.expressions.items.get(handle.index()) {
Some(expression) =>
match expression {
Swizzle(size, _, _) | Splat(size, _) => Some(size.width())
Compose(ty, _) | ZeroValue(ty) =>
match self.shader_module.types.get(ty) {
Some(_) => Some(self.type_lane_count(ty))
None => None
}
Literal(_) => Some(1)
_ =>
match self.function_expression_type(function, handle) {
Some(ty) => Some(self.type_lane_count(ty))
None => None
}
}
None => None
}
}
///|
fn WgslIrValidator::global_expression_lane_count(
self : WgslIrValidator,
handle : Handle,
) -> Int32? {
match self.shader_module.global_expressions.items.get(handle.index()) {
Some(expression) =>
match expression {
Swizzle(size, _, _) | Splat(size, _) => Some(size.width())
Compose(ty, _) | ZeroValue(ty) =>
match self.shader_module.types.get(ty) {
Some(_) => Some(self.type_lane_count(ty))
None => None
}
Literal(_) => Some(1)
_ =>
match self.global_expression_type(handle) {
Some(ty) => Some(self.type_lane_count(ty))
None => None
}
}
None => None
}
}
///|
fn WgslIrValidator::require_global_composite_component_capacity(
self : WgslIrValidator,
components : Array[Handle],
expected_lanes : Int32,
expression_index : Int32,
) -> Unit raise WgslIrValidationError {
if components.length() == 0 {
return
}
let mut lanes = 0
for component in components {
match self.global_expression_lane_count(component) {
Some(count) => lanes += count
None => {
guard self.global_expression_type(component) is Some(_) else {
raise self.missing_global_expression_type(component)
}
}
}
}
if lanes != expected_lanes && !(components.length() == 1 && lanes == 1) {
raise InvalidExpression(
"vector constructor lane count mismatch", expression_index,
)
}
}
///|
fn WgslIrValidator::require_function_access_signature(
self : WgslIrValidator,
function : Function,
base : Handle,
index : Handle,
) -> Unit raise WgslIrValidationError {
guard self.function_expression_type(function, base) is Some(base_ty) else {
raise self.missing_function_expression_type(function, base)
}
guard self.dynamic_indexed_type(base_ty) is Some(_) else {
raise InvalidExpression(
"dynamic access base is not indexable",
base.index(),
)
}
guard self.function_expression_type(function, index) is Some(index_ty) else {
raise self.missing_function_expression_type(function, index)
}
if !self.type_is_integer_scalar(index_ty) {
raise InvalidExpression(
"dynamic access index is not an integer scalar",
index.index(),
)
}
}
///|
fn WgslIrValidator::require_global_access_signature(
self : WgslIrValidator,
base : Handle,
index : Handle,
) -> Unit raise WgslIrValidationError {
guard self.global_expression_type(base) is Some(base_ty) else {
raise self.missing_global_expression_type(base)
}
guard self.dynamic_indexed_type(base_ty) is Some(_) else {
raise InvalidExpression(
"dynamic access base is not indexable",
base.index(),
)
}
guard self.global_expression_type(index) is Some(index_ty) else {
raise self.missing_global_expression_type(index)
}
if !self.type_is_integer_scalar(index_ty) {
raise InvalidExpression(
"dynamic access index is not an integer scalar",
index.index(),
)
}
}
///|
fn WgslIrValidator::require_function_access_index_signature(
self : WgslIrValidator,
function : Function,
base : Handle,
index : Int32,
) -> Unit raise WgslIrValidationError {
guard self.function_expression_type(function, base) is Some(base_ty) else {
raise self.missing_function_expression_type(function, base)
}
guard self.indexed_type(base_ty, Some(index)) is Some(_) else {
raise InvalidExpression(
"constant access index is out of range or not indexable",
base.index(),
)
}
}
///|
fn WgslIrValidator::require_global_access_index_signature(
self : WgslIrValidator,
base : Handle,
index : Int32,
) -> Unit raise WgslIrValidationError {
guard self.global_expression_type(base) is Some(base_ty) else {
raise self.missing_global_expression_type(base)
}
guard self.indexed_type(base_ty, Some(index)) is Some(_) else {
raise InvalidExpression(
"constant access index is out of range or not indexable",
base.index(),
)
}
}
///|
fn WgslIrValidator::require_function_address_of_signature(
self : WgslIrValidator,
function : Function,
ty : Handle,
target : Handle,
) -> Unit raise WgslIrValidationError {
guard self.expression_is_addressable(function, target) else {
raise InvalidExpression(
"address-of target is not addressable",
target.index(),
)
}
guard self.pointer_pointee_type(ty) is Some(pointee) else {
raise InvalidExpression(
"address-of result type is not pointer-like",
target.index(),
)
}
guard self.function_expression_value_type(function, target) is Some(target_ty) else {
raise InvalidExpression(
"address-of target has no value type",
target.index(),
)
}
if !self.type_assignable(pointee, target_ty) {
raise InvalidExpression(
"address-of result pointee type does not match target",
target.index(),
)
}
}
///|
fn WgslIrValidator::require_global_address_of_signature(
self : WgslIrValidator,
ty : Handle,
target : Handle,
) -> Unit raise WgslIrValidationError {
guard self.global_expression_is_addressable(target) else {
raise InvalidExpression(
"address-of target is not addressable",
target.index(),
)
}
guard self.pointer_pointee_type(ty) is Some(pointee) else {
raise InvalidExpression(
"address-of result type is not pointer-like",
target.index(),
)
}
guard self.global_expression_value_type(target) is Some(target_ty) else {
raise InvalidExpression(
"address-of target has no value type",
target.index(),
)
}
if !self.type_assignable(pointee, target_ty) {
raise InvalidExpression(
"address-of result pointee type does not match target",
target.index(),
)
}
}
///|
fn WgslIrValidator::require_as_width(
self : WgslIrValidator,
kind : ScalarKind,
width : Int32?,
) -> Unit raise WgslIrValidationError {
ignore(self)
match width {
Some(value) =>
if !wgsl_ir_validation_scalar_width_is_valid(kind, value) {
raise InvalidType("invalid scalar cast width")
}
None => ()
}
}
///|
fn WgslIrValidator::require_call_signature(
self : WgslIrValidator,
function : Function,
callee : Handle,
arguments : Array[Handle],
result : Handle?,
) -> Unit raise WgslIrValidationError {
let callee_function = match
self.shader_module.functions.items.get(callee.index()) {
Some(value) => value
None => return
}
let name = self.function_display_name(callee_function)
if arguments.length() != callee_function.arguments.length() {
raise InvalidFunctionArgumentCount(
name,
callee_function.arguments.length(),
arguments.length(),
)
}
for index in 0..
match self.function_expression_type(function, actual_handle) {
Some(actual) =>
if !self.type_assignable(expected.ty, actual) {
raise InvalidFunctionResult(name)
}
None => ()
}
(None, None) => ()
(Some(_), None) => ()
(None, Some(_)) => raise InvalidFunctionResult(name)
}
}
///|
fn WgslIrValidator::function_call_argument_matches_parameter(
self : WgslIrValidator,
function : Function,
expected : Handle,
argument : Handle,
) -> Bool {
let expected_pointee = self.pointer_pointee_type(expected)
match self.function_expression_type(function, argument) {
Some(actual) => if self.type_assignable(expected, actual) { return true }
None => if expected_pointee == None { return true }
}
match expected_pointee {
Some(pointee) => {
if !self.expression_is_addressable(function, argument) {
return false
}
match self.function_expression_value_type(function, argument) {
Some(actual) => self.type_assignable(pointee, actual)
None => false
}
}
None => false
}
}
///|
fn WgslIrValidator::require_global_call_signature(
self : WgslIrValidator,
callee : Handle,
arguments : Array[Handle],
) -> Unit raise WgslIrValidationError {
let callee_function = match
self.shader_module.functions.items.get(callee.index()) {
Some(value) => value
None => return
}
let name = self.function_display_name(callee_function)
if arguments.length() != callee_function.arguments.length() {
raise InvalidFunctionArgumentCount(
name,
callee_function.arguments.length(),
arguments.length(),
)
}
for index in 0.. Bool {
let expected_pointee = self.pointer_pointee_type(expected)
match self.global_expression_type(argument) {
Some(actual) => if self.type_assignable(expected, actual) { return true }
None => if expected_pointee == None { return true }
}
match expected_pointee {
Some(pointee) => {
if !self.global_expression_is_addressable(argument) {
return false
}
match self.global_expression_value_type(argument) {
Some(actual) => self.type_assignable(pointee, actual)
None => false
}
}
None => false
}
}
///|
fn WgslIrValidator::require_select_signature(
self : WgslIrValidator,
function : Function,
condition : Handle,
accept : Handle,
reject : Handle,
) -> Unit raise WgslIrValidationError {
guard self.function_expression_type(function, condition) is Some(cond_ty) else {
raise self.missing_function_expression_type(function, condition)
}
guard self.function_expression_type(function, accept) is Some(accept_ty) else {
raise self.missing_function_expression_type(function, accept)
}
guard self.function_expression_type(function, reject) is Some(reject_ty) else {
raise self.missing_function_expression_type(function, reject)
}
guard self.types_are_select_compatible(accept_ty, reject_ty) else {
raise InvalidFunctionArgumentType("select", 1)
}
guard self.select_condition_type_matches_result(cond_ty, accept_ty) else {
raise self.invalid_condition_type(function, condition, cond_ty)
}
}
///|
fn WgslIrValidator::require_global_select_signature(
self : WgslIrValidator,
condition : Handle,
accept : Handle,
reject : Handle,
) -> Unit raise WgslIrValidationError {
guard self.global_expression_type(condition) is Some(cond_ty) else {
raise self.missing_global_expression_type(condition)
}
guard self.global_expression_type(accept) is Some(accept_ty) else {
raise self.missing_global_expression_type(accept)
}
guard self.global_expression_type(reject) is Some(reject_ty) else {
raise self.missing_global_expression_type(reject)
}
guard self.types_are_select_compatible(accept_ty, reject_ty) else {
raise InvalidFunctionArgumentType("select", 1)
}
guard self.select_condition_type_matches_result(cond_ty, accept_ty) else {
let expression = match
self.shader_module.global_expressions.items.get(condition.index()) {
Some(value) => @debug.to_string(value)
None => ""
}
let ty_text = match self.shader_module.types.items.get(cond_ty.index()) {
Some(value) => @debug.to_string(value)
None => ""
}
raise InvalidConditionType(
"",
condition.index(),
expression,
ty_text,
)
}
}
///|
fn WgslIrValidator::require_image_store_signature(
self : WgslIrValidator,
function : Function,
image : Handle,
value : Handle,
) -> Unit raise WgslIrValidationError {
guard self.function_expression_type(function, image) is Some(image_ty) else {
raise self.missing_function_expression_type(function, image)
}
let scalar = match self.shader_module.types.get(image_ty) {
Some(type_) =>
match type_.inner {
Image(_, _, Storage(format, access)) =>
if access.contains(StorageAccess::store()) ||
access.contains(StorageAccess::atomic_access()) {
Some(wgsl_ir_validation_storage_format_scalar(format))
} else {
None
}
_ => None
}
None => None
}
guard scalar is Some(value_scalar) else {
raise InvalidStatement(
"imageStore target is not a writable storage texture",
)
}
guard self.function_expression_type(function, value) is Some(actual) else {
raise self.missing_function_expression_type(function, value)
}
guard self.vector_type(Quad, value_scalar) is Some(expected) else {
raise InvalidStatement("imageStore value has unsupported storage format")
}
if !self.type_assignable(expected, actual) {
raise InvalidStatement(
"imageStore value type does not match storage texture format",
)
}
}
///|
fn WgslIrValidator::require_image_atomic_signature(
self : WgslIrValidator,
function : Function,
image : Handle,
atomic_function : AtomicFunction,
value : Handle,
) -> Unit raise WgslIrValidationError {
ignore(atomic_function)
guard self.function_expression_type(function, image) is Some(image_ty) else {
raise self.missing_function_expression_type(function, image)
}
let scalar = match self.shader_module.types.get(image_ty) {
Some(type_) =>
match type_.inner {
Image(_, _, Storage(format, access)) =>
if access.contains(StorageAccess::atomic_access()) {
Some(wgsl_ir_validation_storage_format_scalar(format))
} else {
None
}
_ => None
}
None => None
}
guard scalar is Some(expected_scalar) else {
raise InvalidStatement(
"image atomic target is not an atomic storage texture",
)
}
guard self.function_expression_type(function, value) is Some(actual) else {
raise self.missing_function_expression_type(function, value)
}
guard self.find_scalar_type(expected_scalar) is Some(expected) else {
raise InvalidStatement("image atomic value has unsupported storage format")
}
if !self.type_assignable(expected, actual) {
raise InvalidStatement(
"image atomic value type does not match storage texture format",
)
}
}
///|
fn WgslIrValidator::require_atomic_statement_signature(
self : WgslIrValidator,
function : Function,
pointer : Handle,
atomic_function : AtomicFunction,
value : Handle,
compare : Handle?,
result : Handle?,
) -> Unit raise WgslIrValidationError {
guard self.function_expression_type(function, pointer) is Some(pointer_ty) else {
raise self.missing_function_expression_type(function, pointer)
}
guard self.atomic_scalar_type(pointer_ty) is Some(scalar) else {
raise InvalidStatement("atomic statement target is not atomic")
}
guard self.find_scalar_type(scalar) is Some(expected) else {
raise InvalidStatement("atomic statement scalar type is unavailable")
}
guard self.function_expression_type(function, value) is Some(actual) else {
raise self.missing_function_expression_type(function, value)
}
if !self.type_assignable(expected, actual) {
raise InvalidStatement("atomic statement value type mismatch")
}
match (atomic_function, compare) {
(CompareExchangeWeak, Some(compare_handle)) => {
guard self.function_expression_type(function, compare_handle)
is Some(compare_ty) else {
raise self.missing_function_expression_type(function, compare_handle)
}
if !self.type_assignable(expected, compare_ty) {
raise InvalidStatement("atomic compare value type mismatch")
}
}
(CompareExchangeWeak, None) =>
raise InvalidStatement("atomic compare-exchange requires compare value")
(_, Some(_)) =>
raise InvalidStatement(
"atomic compare value is only valid for compare-exchange",
)
_ => ()
}
match result {
Some(result_handle) =>
match function.expressions.items.get(result_handle.index()) {
Some(AtomicResult(result_ty, comparison)) =>
match (atomic_function, comparison) {
(CompareExchangeWeak, true) => {
let expected_result_ty = match
self.predeclared_type_handle(
AtomicCompareExchangeWeakResult(scalar),
) {
Some(ty) => ty
None =>
raise InvalidStatement(
"atomic compare-exchange result type is unavailable",
)
}
if !self.type_assignable(expected_result_ty, result_ty) {
raise InvalidStatement(
"atomic compare-exchange result type mismatch",
)
}
}
(CompareExchangeWeak, false) =>
raise InvalidStatement(
"compare-exchange atomic result must be a comparison result",
)
(_, true) =>
raise InvalidStatement(
"comparison atomic result is only valid for compare-exchange",
)
_ =>
if !self.type_assignable(expected, result_ty) {
raise InvalidStatement("atomic result type mismatch")
}
}
_ =>
raise InvalidStatement("atomic statement result must be AtomicResult")
}
None => ()
}
}
///|
fn WgslIrValidator::require_atomic_call_signature(
self : WgslIrValidator,
function : Function,
atomic_function : AtomicFunction,
arguments : Array[Handle],
) -> Unit raise WgslIrValidationError {
let expected_count = match atomic_function {
Load => 1
Store => 2
CompareExchangeWeak => 3
_ => 2
}
if arguments.length() != expected_count {
raise InvalidFunctionArgumentCount(
"atomic",
expected_count,
arguments.length(),
)
}
guard arguments.get(0) is Some(pointer) else { return }
guard self.function_expression_type(function, pointer) is Some(pointer_ty) else {
raise self.missing_function_expression_type(function, pointer)
}
guard self.atomic_scalar_type(pointer_ty) is Some(scalar) else {
raise InvalidFunctionArgumentType("atomic", 0)
}
guard self.find_scalar_type(scalar) is Some(expected) else { return }
for index in 1.. Unit raise WgslIrValidationError {
guard self.function_expression_type(function, pointer) is Some(pointer_ty) else {
raise self.missing_function_expression_type(function, pointer)
}
if self.pointer_address_space(pointer_ty) != Some(WorkGroup) {
raise InvalidStatement(
"workgroupUniformLoad pointer is not in workgroup address space",
)
}
guard self.deref_type(pointer_ty) is Some(expected) else {
raise InvalidStatement("workgroupUniformLoad pointer has no value type")
}
guard self.function_expression_type(function, result) is Some(actual) else {
raise self.missing_function_expression_type(function, result)
}
if !self.type_assignable(expected, actual) {
raise InvalidStatement("workgroupUniformLoad result type mismatch")
}
}
///|
fn WgslIrValidator::require_subgroup_ballot_signature(
self : WgslIrValidator,
function : Function,
value : Handle,
result : Handle?,
) -> Unit raise WgslIrValidationError {
guard self.function_expression_type(function, value) is Some(value_ty) else {
raise self.missing_function_expression_type(function, value)
}
if !self.type_is_bool_scalar(value_ty) {
raise InvalidStatement("subgroupBallot value is not bool")
}
match result {
Some(handle) => {
guard self.function_expression_type(function, handle) is Some(actual) else {
raise self.missing_function_expression_type(function, handle)
}
guard self.vector_type(Quad, Scalar(Uint, 4)) is Some(expected) else {
return
}
if !self.type_assignable(expected, actual) {
raise InvalidStatement("subgroupBallot result type mismatch")
}
}
None => ()
}
}
///|
fn WgslIrValidator::require_matching_statement_result(
self : WgslIrValidator,
function : Function,
value : Handle,
result : Handle,
) -> Unit raise WgslIrValidationError {
guard self.function_expression_type(function, value) is Some(expected) else {
raise self.missing_function_expression_type(function, value)
}
guard self.function_expression_type(function, result) is Some(actual) else {
raise self.missing_function_expression_type(function, result)
}
if !self.type_assignable(expected, actual) {
raise InvalidStatement("statement result type mismatch")
}
}
///|
fn WgslIrValidator::require_array_length_argument(
self : WgslIrValidator,
function : Function,
handle : Handle,
) -> Unit raise WgslIrValidationError {
guard self.function_expression_type(function, handle) is Some(ty) else {
raise self.missing_function_expression_type(function, handle)
}
if !self.pointer_targets_runtime_array(ty) &&
!self.type_or_struct_tail_is_runtime_array(ty) {
raise InvalidExpression(
"arrayLength argument does not point at a runtime array",
handle.index(),
)
}
}
///|
fn WgslIrValidator::require_swizzle_signature(
self : WgslIrValidator,
function : Function,
size : VectorSize,
expr : Handle,
components : Array[SwizzleComponent],
) -> Unit raise WgslIrValidationError {
if components.length() != size.width() {
raise InvalidExpression(
"swizzle component count does not match result size",
expr.index(),
)
}
guard self.function_expression_type(function, expr) is Some(ty) else {
return
}
guard self.vector_size(ty) is Some(base_size) else {
raise InvalidExpression("swizzle base is not a vector", expr.index())
}
for component in components {
if wgsl_ir_validation_swizzle_index(component) >= base_size.width() {
raise InvalidExpression("swizzle component is out of range", expr.index())
}
}
}