///|
fn WgslIrLowerer::infer_local_type_from_initializer(
self : WgslIrLowerer,
name : String,
initializer : @ast.WgslExprRef?,
) -> Handle raise WgslIrLowerError {
guard initializer is Some(expr_ref) else { raise MissingType(name) }
match expr_ref.root() {
Some(root) => self.infer_expression_type(root, name)
None => raise MissingType(name)
}
}
///|
fn WgslIrLowerer::infer_constant_declaration_type(
self : WgslIrLowerer,
constant : @ast.WgslConst,
) -> Handle raise WgslIrLowerError {
let name = constant.name().name()
match self.constant_type_cache.get(name) {
Some(ty) => return ty
None => ()
}
if self.constant_type_inference_stack.contains(name) {
raise MissingType(name)
}
self.constant_type_inference_stack.add(name)
let ty = match constant.ty_ref() {
Some(ty_ref) => self.lower_type_ref(ty_ref)
None =>
self.infer_local_type_from_initializer(name, constant.initializer_ref())
}
self.constant_type_cache.set(name, ty)
ignore(self.constant_type_inference_stack.remove(name))
ty
}
///|
fn WgslIrLowerer::infer_expression_type(
self : WgslIrLowerer,
node : @ast.WgslExprNode,
name : String,
) -> Handle raise WgslIrLowerError {
match node.kind() {
Literal(token) =>
match token.kind() {
BoolLiteral(_) => self.lower_builtin_type_name("bool")
NumericLiteral(literal) =>
self.lower_builtin_type_name(
wgsl_ir_numeric_literal_default_type_name(literal),
)
_ => raise MissingType(name)
}
Identifier(identifier) =>
self.infer_named_expression_type(identifier.name(), name)
Group(inner) => self.infer_expression_type(inner, name)
Unary(op, inner) =>
match op {
Not => self.lower_builtin_type_name("bool")
Subtract | Complement => self.infer_expression_type(inner, name)
_ => raise MissingType(name)
}
Member(base, member_ident) =>
match self.infer_member_expression_type(base, member_ident.name(), name) {
Some(ty) => ty
None => raise MissingType(name)
}
Index(base, _) =>
match self.infer_index_expression_type(base, name) {
Some(ty) => ty
None => raise MissingType(name)
}
Binary(op, left, right) =>
match self.infer_expression_type(left, name) {
left_ty =>
match self.infer_expression_type(right, name) {
right_ty =>
self.binary_expression_result_type(
wgsl_ir_binary_operator(op),
left_ty,
right_ty,
)
}
}
Call(callee, arguments) => {
let arguments = wgsl_ir_call_arguments(arguments)
match self.lower_bitcast_callee_type(callee) {
Some(ty) => ty
None =>
match self.lower_templated_callee_type(callee) {
Some(ty) => ty
None =>
match callee.kind() {
Identifier(ident) =>
if ident.name() == "select" {
self.infer_select_expression_type(arguments, name)
} else if ident.name() == "array" {
self.infer_array_constructor_type_from_ast(arguments, name)
} else if wgsl_ir_barrier_builtin_from_name(ident.name())
is Some(_) {
raise wgsl_ir_barrier_value_error(ident.name())
} else {
match self.function_names.get(ident.name()) {
Some(handle) =>
match
self.shader_module.functions.items.get(handle.index()) {
Some(function) =>
match function.result {
Some(result) => result.ty
None => raise MissingType(name)
}
None => raise MissingType(name)
}
None =>
match
wgsl_ir_relational_function_from_name(ident.name()) {
Some(relational_function) =>
self.infer_relational_expression_type(
relational_function, arguments, name,
)
None =>
match
wgsl_ir_math_function_from_name(ident.name()) {
Some(math_function) =>
self.infer_math_expression_type(
math_function, arguments, name,
)
None =>
self.lower_untemplated_constructor_type_from_ast(
ident.name(),
arguments,
name,
)
}
}
}
}
_ => raise MissingType(name)
}
}
}
}
_ => raise MissingType(name)
}
}
///|
fn WgslIrLowerer::infer_expression_type_in_function_scope(
self : WgslIrLowerer,
node : @ast.WgslExprNode,
name : String,
function : Function,
scope : WgslIrFunctionScope,
) -> Handle raise WgslIrLowerError {
match node.kind() {
Identifier(identifier) =>
self.infer_scoped_named_expression_type(
identifier.name(),
name,
function,
scope,
)
Group(inner) =>
self.infer_expression_type_in_function_scope(inner, name, function, scope)
Unary(op, inner) =>
match op {
Not => self.lower_builtin_type_name("bool")
Subtract | Complement =>
self.infer_expression_type_in_function_scope(
inner, name, function, scope,
)
_ => raise MissingType(name)
}
Member(base, member_ident) =>
match
self.infer_scoped_member_expression_type(
base,
member_ident.name(),
name,
function,
scope,
) {
Some(ty) => ty
None => raise MissingType(name)
}
Index(base, _) =>
match
self.infer_scoped_index_expression_type(base, name, function, scope) {
Some(ty) => ty
None => raise MissingType(name)
}
Binary(op, left, right) => {
let left_ty = self.infer_expression_type_in_function_scope(
left, name, function, scope,
)
let right_ty = self.infer_expression_type_in_function_scope(
right, name, function, scope,
)
self.binary_expression_result_type(
wgsl_ir_binary_operator(op),
left_ty,
right_ty,
)
}
Call(callee, arguments) =>
self.infer_scoped_call_expression_type(
callee,
wgsl_ir_call_arguments(arguments),
name,
function,
scope,
)
_ => self.infer_expression_type(node, name)
}
}
///|
fn WgslIrLowerer::infer_scoped_named_expression_type(
self : WgslIrLowerer,
referenced_name : String,
diagnostic_name : String,
function : Function,
scope : WgslIrFunctionScope,
) -> Handle raise WgslIrLowerError {
match scope.arguments.get(referenced_name) {
Some(index) =>
match function.arguments.get(index) {
Some(argument) => return argument.ty
None => raise MissingType(diagnostic_name)
}
None => ()
}
match scope.locals.get(referenced_name) {
Some(handle) =>
match function.local_variables.items.get(handle.index()) {
Some(local_variable) => return local_variable.ty
None => raise MissingType(diagnostic_name)
}
None => ()
}
match scope.local_constants.get(referenced_name) {
Some({ value: ExpressionAlias(handle, _), .. }) =>
match self.function_expression_type(function, handle) {
Some(ty) => return ty
None => raise MissingType(diagnostic_name)
}
Some({ value: LazyConstant(local_constant), .. }) =>
match local_constant.explicit_ty {
Some(ty) => return ty
None =>
match local_constant.expr_ref.root() {
Some(root) =>
return self.infer_expression_type_in_function_scope(
root, diagnostic_name, function, scope,
)
None => raise MissingType(diagnostic_name)
}
}
None => ()
}
self.infer_named_expression_type(referenced_name, diagnostic_name)
}
///|
fn WgslIrLowerer::infer_scoped_member_expression_type(
self : WgslIrLowerer,
base : @ast.WgslExprNode,
member_name : String,
diagnostic_name : String,
function : Function,
scope : WgslIrFunctionScope,
) -> Handle? raise WgslIrLowerError {
let base_ty = self.infer_expression_type_in_function_scope(
base, diagnostic_name, function, scope,
)
self.member_type_from_base_type(base_ty, member_name)
}
///|
fn WgslIrLowerer::infer_scoped_index_expression_type(
self : WgslIrLowerer,
base : @ast.WgslExprNode,
diagnostic_name : String,
function : Function,
scope : WgslIrFunctionScope,
) -> Handle? raise WgslIrLowerError {
let base_ty = self.infer_expression_type_in_function_scope(
base, diagnostic_name, function, scope,
)
self.indexed_type_from_type_handle(base_ty, None)
}
///|
fn WgslIrLowerer::infer_scoped_call_expression_type(
self : WgslIrLowerer,
callee : @ast.WgslExprNode,
arguments : Array[@ast.WgslExprNode],
name : String,
function : Function,
scope : WgslIrFunctionScope,
) -> Handle raise WgslIrLowerError {
match self.lower_bitcast_callee_type(callee) {
Some(ty) => ty
None =>
match self.lower_templated_callee_type(callee) {
Some(ty) => ty
None =>
match callee.kind() {
Identifier(ident) =>
if ident.name() == "select" {
match wgsl_ir_flatten_expression_arguments(arguments) {
[reject, _, _] =>
self.infer_expression_type_in_function_scope(
reject, name, function, scope,
)
_ => raise MissingType(name)
}
} else if ident.name() == "array" {
self.infer_scoped_array_constructor_type_from_ast(
arguments, name, function, scope,
)
} else {
match self.function_names.get(ident.name()) {
Some(handle) =>
match
self.shader_module.functions.items.get(handle.index()) {
Some(function) =>
match function.result {
Some(result) => result.ty
None => raise MissingType(name)
}
None => raise MissingType(name)
}
None =>
match wgsl_ir_relational_function_from_name(ident.name()) {
Some(relational_function) =>
self.infer_scoped_relational_expression_type(
relational_function, arguments, name, function, scope,
)
None =>
match wgsl_ir_math_function_from_name(ident.name()) {
Some(math_function) =>
self.infer_scoped_math_expression_type(
math_function, arguments, name, function, scope,
)
None =>
self.lower_scoped_untemplated_constructor_type_from_ast(
ident.name(),
arguments,
name,
function,
scope,
)
}
}
}
}
_ => raise MissingType(name)
}
}
}
}
///|
fn WgslIrLowerer::lower_scoped_untemplated_constructor_type_from_ast(
self : WgslIrLowerer,
name : String,
arguments : Array[@ast.WgslExprNode],
diagnostic_name : String,
function : Function,
scope : WgslIrFunctionScope,
) -> Handle raise WgslIrLowerError {
match self.type_cache.get(name) {
Some(handle) => handle
None =>
match wgsl_ir_builtin_vector_alias(name) {
Some(inner) => self.intern_type(name, inner)
None =>
match wgsl_ir_builtin_matrix_alias(name) {
Some(inner) => self.intern_type(name, inner)
None =>
match wgsl_ir_builtin_scalar_alias(name) {
Some(inner) => self.intern_type(name, inner)
None =>
self.lower_scoped_generic_constructor_type_from_ast(
name, arguments, diagnostic_name, function, scope,
)
}
}
}
}
}
///|
fn WgslIrLowerer::lower_scoped_generic_constructor_type_from_ast(
self : WgslIrLowerer,
name : String,
arguments : Array[@ast.WgslExprNode],
diagnostic_name : String,
function : Function,
scope : WgslIrFunctionScope,
) -> Handle raise WgslIrLowerError {
match name {
"vec2" | "vec3" | "vec4" => {
let scalar = self.scoped_constructor_scalar_from_ast_arguments(
arguments, diagnostic_name, function, scope,
)
self.intern_type(
"\{name}<\{wgsl_ir_scalar_name(scalar.kind, scalar.width)}>",
Vector(wgsl_ir_vector_size_from_name(name), scalar),
)
}
"mat2x2"
| "mat2x3"
| "mat2x4"
| "mat3x2"
| "mat3x3"
| "mat3x4"
| "mat4x2"
| "mat4x3"
| "mat4x4" => {
let scalar = self.scoped_constructor_scalar_from_ast_arguments(
arguments, diagnostic_name, function, scope,
)
let (columns, rows) = wgsl_ir_matrix_size_from_name(name)
self.intern_type(
"\{name}<\{wgsl_ir_scalar_name(scalar.kind, scalar.width)}>",
Matrix(columns, rows, scalar),
)
}
_ => raise UnsupportedType(name)
}
}
///|
fn WgslIrLowerer::infer_scoped_array_constructor_type_from_ast(
self : WgslIrLowerer,
arguments : Array[@ast.WgslExprNode],
diagnostic_name : String,
function : Function,
scope : WgslIrFunctionScope,
) -> Handle raise WgslIrLowerError {
let flattened = wgsl_ir_flatten_expression_arguments(arguments)
guard flattened is [first, ..] else { raise MissingType(diagnostic_name) }
let element_ty = self.infer_expression_type_in_function_scope(
first, diagnostic_name, function, scope,
)
self.intern_inferred_array_type(element_ty, flattened.length())
}
///|
fn WgslIrLowerer::scoped_constructor_scalar_from_ast_arguments(
self : WgslIrLowerer,
arguments : Array[@ast.WgslExprNode],
diagnostic_name : String,
function : Function,
scope : WgslIrFunctionScope,
) -> Scalar raise WgslIrLowerError {
let arguments = wgsl_ir_flatten_expression_arguments(arguments)
guard arguments is [first, .. rest] else {
raise MissingType(diagnostic_name)
}
let first_ty = self.infer_expression_type_in_function_scope(
first, diagnostic_name, function, scope,
)
let mut scalar = self.scalar_from_type_handle(first_ty, diagnostic_name)
for argument in rest {
let ty = self.infer_expression_type_in_function_scope(
argument, diagnostic_name, function, scope,
)
let next = self.scalar_from_type_handle(ty, diagnostic_name)
scalar = self.merge_constructor_scalar(scalar, next, diagnostic_name)
}
scalar
}
///|
fn WgslIrLowerer::infer_scoped_math_expression_type(
self : WgslIrLowerer,
math_function : MathFunction,
arguments : Array[@ast.WgslExprNode],
name : String,
function : Function,
scope : WgslIrFunctionScope,
) -> Handle raise WgslIrLowerError {
guard arguments is [first, .. rest] else { raise MissingType(name) }
match math_function {
Dot | Distance | Length | Determinant =>
match
self.infer_expression_type_in_function_scope(
first, name, function, scope,
) {
ty => self.scalar_type_from_composite_type(ty)
}
Modf | Frexp =>
self.infer_expression_type_in_function_scope(first, name, function, scope)
_ =>
match rest {
_ =>
self.infer_expression_type_in_function_scope(
first, name, function, scope,
)
}
}
}
///|
fn WgslIrLowerer::infer_scoped_relational_expression_type(
self : WgslIrLowerer,
relational_function : RelationalFunction,
arguments : Array[@ast.WgslExprNode],
name : String,
function : Function,
scope : WgslIrFunctionScope,
) -> Handle raise WgslIrLowerError {
guard arguments is [first, ..] else { raise MissingType(name) }
match relational_function {
All | Any => self.scalar_type_handle(Scalar(Bool, 1))
IsNan | IsInf =>
match
self.infer_expression_type_in_function_scope(
first, name, function, scope,
) {
ty => self.boolean_result_type(ty, ty)
}
}
}
///|
fn WgslIrLowerer::infer_member_expression_type(
self : WgslIrLowerer,
base : @ast.WgslExprNode,
member_name : String,
diagnostic_name : String,
) -> Handle? raise WgslIrLowerError {
let base_ty = self.infer_expression_type(base, diagnostic_name)
self.member_type_from_base_type(base_ty, member_name)
}
///|
fn WgslIrLowerer::member_type_from_base_type(
self : WgslIrLowerer,
base_ty : Handle,
member_name : String,
) -> Handle? {
let deref_ty = self.deref_pointer_type_handle(base_ty)
match self.shader_module.types.get(deref_ty) {
Some(ty) =>
match ty.inner {
Struct(members, _) | PredeclaredStruct(members, _) =>
match wgsl_ir_struct_member_index(members, member_name) {
Some(index) =>
self.indexed_type_from_type_handle(deref_ty, Some(index))
None => None
}
Vector(_, scalar) =>
match wgsl_ir_swizzle_components(member_name) {
Some(components) =>
match components.length() {
1 => Some(self.scalar_type_handle(scalar))
count =>
Some(
self.vector_type_handle(
wgsl_ir_vector_size_from_component_count(count),
scalar,
),
)
}
None => None
}
_ => None
}
None => None
}
}
///|
fn WgslIrLowerer::infer_index_expression_type(
self : WgslIrLowerer,
base : @ast.WgslExprNode,
diagnostic_name : String,
) -> Handle? raise WgslIrLowerError {
let base_ty = self.infer_expression_type(base, diagnostic_name)
self.indexed_type_from_type_handle(base_ty, None)
}
///|
fn WgslIrLowerer::lower_bitcast_callee_type(
self : WgslIrLowerer,
callee : @ast.WgslExprNode,
) -> Handle? raise WgslIrLowerError {
match callee.kind() {
Template(base, template_arguments) =>
match base.kind() {
Identifier(name) if name.name() == "bitcast" =>
match template_arguments {
[Type(ty_ref)] => Some(self.lower_type_ref(ty_ref))
_ =>
raise UnsupportedExpression(
"bitcast expects exactly one type template argument",
)
}
_ => None
}
_ => None
}
}
///|
fn WgslIrLowerer::infer_select_expression_type(
self : WgslIrLowerer,
arguments : Array[@ast.WgslExprNode],
name : String,
) -> Handle raise WgslIrLowerError {
let arguments = wgsl_ir_flatten_expression_arguments(arguments)
match arguments {
[reject, _, _] => self.infer_expression_type(reject, name)
_ => raise MissingType(name)
}
}
///|
fn WgslIrLowerer::infer_math_expression_type(
self : WgslIrLowerer,
math_function : MathFunction,
arguments : Array[@ast.WgslExprNode],
name : String,
) -> Handle raise WgslIrLowerError {
let arguments = wgsl_ir_flatten_expression_arguments(arguments)
guard arguments is [first, .. rest] else { raise MissingType(name) }
match math_function {
Dot | Distance | Length | Determinant =>
match self.infer_expression_type(first, name) {
ty => self.scalar_type_from_composite_type(ty)
}
Modf | Frexp => self.infer_expression_type(first, name)
_ =>
match rest {
_ => self.infer_expression_type(first, name)
}
}
}
///|
fn WgslIrLowerer::infer_relational_expression_type(
self : WgslIrLowerer,
relational_function : RelationalFunction,
arguments : Array[@ast.WgslExprNode],
name : String,
) -> Handle raise WgslIrLowerError {
let arguments = wgsl_ir_flatten_expression_arguments(arguments)
guard arguments is [first, ..] else { raise MissingType(name) }
match relational_function {
All | Any => self.scalar_type_handle(Scalar(Bool, 1))
IsNan | IsInf =>
match self.infer_expression_type(first, name) {
ty => self.boolean_result_type(ty, ty)
}
}
}
///|
fn WgslIrLowerer::scalar_type_from_composite_type(
self : WgslIrLowerer,
ty_handle : Handle,
) -> Handle {
match self.shader_module.types.get(ty_handle) {
Some(ty) =>
match ty.inner {
Vector(_, scalar) => self.scalar_type_handle(scalar)
Matrix(_, _, scalar) => self.scalar_type_handle(scalar)
_ => ty_handle
}
None => ty_handle
}
}
///|
fn WgslIrLowerer::infer_named_expression_type(
self : WgslIrLowerer,
referenced_name : String,
diagnostic_name : String,
) -> Handle raise WgslIrLowerError {
match wgsl_ir_predeclared_u32_constant_literal(referenced_name) {
Some(_) => self.lower_builtin_type_name("u32")
None =>
match self.constant_names.get(referenced_name) {
Some(handle) =>
match self.shader_module.constants.items.get(handle.index()) {
Some(constant) => constant.ty
None => raise MissingType(diagnostic_name)
}
None =>
match self.constant_declarations.get(referenced_name) {
Some(constant) => self.infer_constant_declaration_type(constant)
None =>
self.infer_non_constant_named_expression_type(
referenced_name, diagnostic_name,
)
}
}
}
}
///|
fn wgsl_ir_predeclared_u32_constant_literal(name : String) -> Literal? {
match name {
"RAY_FLAG_NONE" => Some(U32(0))
"RAY_FLAG_FORCE_OPAQUE" => Some(U32(0x1))
"RAY_FLAG_FORCE_NO_OPAQUE" => Some(U32(0x2))
"RAY_FLAG_TERMINATE_ON_FIRST_HIT" => Some(U32(0x4))
"RAY_FLAG_SKIP_CLOSEST_HIT_SHADER" => Some(U32(0x8))
"RAY_FLAG_CULL_BACK_FACING" => Some(U32(0x10))
"RAY_FLAG_CULL_FRONT_FACING" => Some(U32(0x20))
"RAY_FLAG_CULL_OPAQUE" => Some(U32(0x40))
"RAY_FLAG_CULL_NO_OPAQUE" => Some(U32(0x80))
"RAY_FLAG_SKIP_TRIANGLES" => Some(U32(0x100))
"RAY_FLAG_SKIP_AABBS" => Some(U32(0x200))
"RAY_QUERY_INTERSECTION_NONE" => Some(U32(0))
"RAY_QUERY_INTERSECTION_TRIANGLE" => Some(U32(1))
"RAY_QUERY_INTERSECTION_GENERATED" => Some(U32(2))
"RAY_QUERY_INTERSECTION_AABB" => Some(U32(3))
_ => None
}
}
///|
fn WgslIrLowerer::global_identifier_expression(
self : WgslIrLowerer,
name : @ast.WgslIdent,
) -> Expression raise WgslIrLowerError {
match self.ensure_constant_declaration_lowered(name.name()) {
Some(handle) => Constant(handle)
None =>
match self.ensure_override_declaration_predeclared(name.name()) {
Some(handle) => Override(handle)
None =>
match self.global_names.get(name.name()) {
Some(handle) => GlobalVariable(handle)
None =>
match wgsl_ir_predeclared_u32_constant_literal(name.name()) {
Some(literal) => Literal(literal)
None => raise UnknownIdentifier(name.name())
}
}
}
}
}
///|
fn WgslIrLowerer::infer_non_constant_named_expression_type(
self : WgslIrLowerer,
referenced_name : String,
diagnostic_name : String,
) -> Handle raise WgslIrLowerError {
match self.override_names.get(referenced_name) {
Some(handle) =>
match self.shader_module.overrides.items.get(handle.index()) {
Some(override_) => override_.ty
None => raise MissingType(diagnostic_name)
}
None =>
match self.override_declarations.get(referenced_name) {
Some(override_decl) => {
self.predeclare_override_declaration(override_decl)
match self.override_names.get(referenced_name) {
Some(handle) =>
match self.shader_module.overrides.items.get(handle.index()) {
Some(override_) => override_.ty
None => raise MissingType(diagnostic_name)
}
None => raise MissingType(diagnostic_name)
}
}
None =>
match self.global_names.get(referenced_name) {
Some(handle) =>
match
self.shader_module.global_variables.items.get(handle.index()) {
Some(global) => global.ty
None => raise MissingType(diagnostic_name)
}
None => raise MissingType(diagnostic_name)
}
}
}
}
///|
fn WgslIrLowerer::lower_builtin_type_name(
self : WgslIrLowerer,
name : String,
) -> Handle raise WgslIrLowerError {
match self.type_cache.get(name) {
Some(handle) => handle
None => raise MissingType(name)
}
}