From cfcf625019188f88431d7abc44d5505eead8f4b5 Mon Sep 17 00:00:00 2001 From: Teodor Tanasoaia <28601907+teoxoy@users.noreply.github.com> Date: Wed, 30 Mar 2022 07:51:54 +0200 Subject: [PATCH] [wgsl-in] Constructor improvements (#1790) * add support for zero value constructors and constructors that infer their type from their parameters * address comments * extract constructor machinery into new module * fix doc link --- src/front/wgsl/construction.rs | 649 +++++++++++++++++++++ src/front/wgsl/mod.rs | 277 ++++----- tests/in/operators.wgsl | 15 + tests/out/glsl/operators.main.Compute.glsl | 18 +- tests/out/hlsl/operators.hlsl | 21 +- tests/out/msl/operators.msl | 30 +- tests/out/spv/operators.spvasm | 427 ++++++++------ tests/out/wgsl/operators.wgsl | 18 +- tests/wgsl-errors.rs | 76 ++- 9 files changed, 1174 insertions(+), 357 deletions(-) create mode 100644 src/front/wgsl/construction.rs diff --git a/src/front/wgsl/construction.rs b/src/front/wgsl/construction.rs new file mode 100644 index 0000000000..7916caa620 --- /dev/null +++ b/src/front/wgsl/construction.rs @@ -0,0 +1,649 @@ +use crate::{ + proc::TypeResolution, Arena, ArraySize, Bytes, Constant, ConstantInner, Expression, Handle, + ScalarKind, ScalarValue, Span as NagaSpan, Type, TypeInner, UniqueArena, VectorSize, +}; + +use super::{Error, ExpressionContext, Lexer, Parser, Scope, Span, Token}; + +/// Represents the type of the constructor +/// +/// Vectors, Matrices and Arrays can have partial type information +/// which later gets inferred from the constructor parameters +enum ConstructorType { + Scalar { + kind: ScalarKind, + width: Bytes, + }, + PartialVector { + size: VectorSize, + }, + Vector { + size: VectorSize, + kind: ScalarKind, + width: Bytes, + }, + PartialMatrix { + columns: VectorSize, + rows: VectorSize, + }, + Matrix { + columns: VectorSize, + rows: VectorSize, + width: Bytes, + }, + PartialArray, + Array { + base: Handle, + size: ArraySize, + stride: u32, + }, + Struct(Handle), +} + +impl ConstructorType { + fn to_type_resolution(&self) -> Option { + Some(match *self { + ConstructorType::Scalar { kind, width } => { + TypeResolution::Value(TypeInner::Scalar { kind, width }) + } + ConstructorType::Vector { size, kind, width } => { + TypeResolution::Value(TypeInner::Vector { size, kind, width }) + } + ConstructorType::Matrix { + columns, + rows, + width, + } => TypeResolution::Value(TypeInner::Matrix { + columns, + rows, + width, + }), + ConstructorType::Array { base, size, stride } => { + TypeResolution::Value(TypeInner::Array { base, size, stride }) + } + ConstructorType::Struct(handle) => TypeResolution::Handle(handle), + _ => return None, + }) + } +} + +impl ConstructorType { + fn to_error_string(&self, types: &UniqueArena, constants: &Arena) -> String { + match *self { + ConstructorType::Scalar { kind, width } => kind.to_wgsl(width), + ConstructorType::PartialVector { size } => { + format!("vec{}", size as u32,) + } + ConstructorType::Vector { size, kind, width } => { + format!("vec{}<{}>", size as u32, kind.to_wgsl(width)) + } + ConstructorType::PartialMatrix { columns, rows } => { + format!("mat{}x{}", columns as u32, rows as u32,) + } + ConstructorType::Matrix { + columns, + rows, + width, + } => { + format!( + "mat{}x{}<{}>", + columns as u32, + rows as u32, + ScalarKind::Float.to_wgsl(width) + ) + } + ConstructorType::PartialArray => "array".to_string(), + ConstructorType::Array { base, size, .. } => { + format!( + "array<{}, {}>", + types[base].name.as_deref().unwrap_or("?"), + match size { + ArraySize::Constant(size) => { + constants[size] + .to_array_length() + .map(|len| len.to_string()) + .unwrap_or_else(|| "?".to_string()) + } + _ => unreachable!(), + } + ) + } + ConstructorType::Struct(handle) => types[handle] + .name + .clone() + .unwrap_or_else(|| "?".to_string()), + } + } +} + +fn parse_constructor_type<'a>( + parser: &mut Parser, + lexer: &mut Lexer<'a>, + word: &'a str, + type_arena: &mut UniqueArena, + const_arena: &mut Arena, +) -> Result, Error<'a>> { + if let Some((kind, width)) = super::conv::get_scalar_type(word) { + return Ok(Some(ConstructorType::Scalar { kind, width })); + } + + let partial = match word { + "vec2" => ConstructorType::PartialVector { + size: VectorSize::Bi, + }, + "vec3" => ConstructorType::PartialVector { + size: VectorSize::Tri, + }, + "vec4" => ConstructorType::PartialVector { + size: VectorSize::Quad, + }, + "mat2x2" => ConstructorType::PartialMatrix { + columns: VectorSize::Bi, + rows: VectorSize::Bi, + }, + "mat2x3" => ConstructorType::PartialMatrix { + columns: VectorSize::Bi, + rows: VectorSize::Tri, + }, + "mat2x4" => ConstructorType::PartialMatrix { + columns: VectorSize::Bi, + rows: VectorSize::Quad, + }, + "mat3x2" => ConstructorType::PartialMatrix { + columns: VectorSize::Tri, + rows: VectorSize::Bi, + }, + "mat3x3" => ConstructorType::PartialMatrix { + columns: VectorSize::Tri, + rows: VectorSize::Tri, + }, + "mat3x4" => ConstructorType::PartialMatrix { + columns: VectorSize::Tri, + rows: VectorSize::Quad, + }, + "mat4x2" => ConstructorType::PartialMatrix { + columns: VectorSize::Quad, + rows: VectorSize::Bi, + }, + "mat4x3" => ConstructorType::PartialMatrix { + columns: VectorSize::Quad, + rows: VectorSize::Tri, + }, + "mat4x4" => ConstructorType::PartialMatrix { + columns: VectorSize::Quad, + rows: VectorSize::Quad, + }, + "array" => ConstructorType::PartialArray, + _ => return Ok(None), + }; + + // parse component type if present + match (lexer.peek().0, partial) { + (Token::Paren('<'), ConstructorType::PartialVector { size }) => { + let (kind, width) = lexer.next_scalar_generic()?; + Ok(Some(ConstructorType::Vector { size, kind, width })) + } + (Token::Paren('<'), ConstructorType::PartialMatrix { columns, rows }) => { + let (_, width) = lexer.next_scalar_generic()?; + Ok(Some(ConstructorType::Matrix { + columns, + rows, + width, + })) + } + (Token::Paren('<'), ConstructorType::PartialArray) => { + lexer.expect_generic_paren('<')?; + let base = parser + .parse_type_decl(lexer, None, type_arena, const_arena)? + .0; + let size = if lexer.skip(Token::Separator(',')) { + let const_handle = parser.parse_const_expression(lexer, type_arena, const_arena)?; + ArraySize::Constant(const_handle) + } else { + ArraySize::Dynamic + }; + lexer.expect_generic_paren('>')?; + + let stride = { + parser.layouter.update(type_arena, const_arena).unwrap(); + parser.layouter[base].to_stride() + }; + + Ok(Some(ConstructorType::Array { base, size, stride })) + } + (_, partial) => Ok(Some(partial)), + } +} + +/// Expects [`Scope::PrimaryExpr`] scope on top; if returning Some(_), pops it. +pub(super) fn parse_construction<'a>( + parser: &mut Parser, + lexer: &mut Lexer<'a>, + type_name: &'a str, + type_span: Span, + mut ctx: ExpressionContext<'a, '_, '_>, +) -> Result>, Error<'a>> { + assert_eq!( + parser.scopes.last().map(|&(ref scope, _)| scope.clone()), + Some(Scope::PrimaryExpr) + ); + let dst_ty = match parser.lookup_type.get(type_name) { + Some(&handle) => ConstructorType::Struct(handle), + None => match parse_constructor_type(parser, lexer, type_name, ctx.types, ctx.constants)? { + Some(inner) => inner, + None => { + match parser.parse_type_decl_impl( + lexer, + super::TypeAttributes::default(), + type_name, + ctx.types, + ctx.constants, + )? { + Some(_) => { + return Err(Error::TypeNotConstructible(type_span)); + } + None => return Ok(None), + } + } + }, + }; + + lexer.open_arguments()?; + + let mut components = Vec::new(); + let mut spans = Vec::new(); + + if lexer.peek().0 == Token::Paren(')') { + let _ = lexer.next(); + } else { + while components.is_empty() || lexer.next_argument()? { + let (component, span) = lexer + .capture_span(|lexer| parser.parse_general_expression(lexer, ctx.reborrow()))?; + components.push(component); + spans.push(span); + } + } + + enum Components<'a> { + None, + One { + component: Handle, + span: Span, + ty: &'a TypeInner, + }, + Many { + components: Vec>, + spans: Vec, + first_component_ty: &'a TypeInner, + }, + } + + impl<'a> Components<'a> { + fn into_components_vec(self) -> Vec> { + match self { + Components::None => vec![], + Components::One { component, .. } => vec![component], + Components::Many { components, .. } => components, + } + } + } + + let components = match *components.as_slice() { + [] => Components::None, + [component] => { + ctx.resolve_type(component)?; + Components::One { + component, + span: spans[0].clone(), + ty: ctx.typifier.get(component, ctx.types), + } + } + [component, ..] => { + ctx.resolve_type(component)?; + Components::Many { + components, + spans, + first_component_ty: ctx.typifier.get(component, ctx.types), + } + } + }; + + let expr = match (components, dst_ty) { + // Empty constructor + (Components::None, dst_ty) => { + let ty = match dst_ty.to_type_resolution() { + Some(TypeResolution::Handle(handle)) => handle, + Some(TypeResolution::Value(inner)) => ctx + .types + .insert(Type { name: None, inner }, Default::default()), + None => return Err(Error::TypeNotInferrable(type_span)), + }; + + return match ctx.create_zero_value_constant(ty) { + Some(constant) => { + let span = parser.pop_scope(lexer); + Ok(Some(ctx.interrupt_emitter( + Expression::Constant(constant), + span.into(), + ))) + } + None => Err(Error::TypeNotConstructible(type_span)), + }; + } + + // Scalar constructor & conversion (scalar -> scalar) + ( + Components::One { + component, + ty: &TypeInner::Scalar { .. }, + .. + }, + ConstructorType::Scalar { kind, width }, + ) => Expression::As { + expr: component, + kind, + convert: Some(width), + }, + + // Vector conversion (vector -> vector) + ( + Components::One { + component, + ty: &TypeInner::Vector { size: src_size, .. }, + .. + }, + ConstructorType::Vector { + size: dst_size, + kind: dst_kind, + width: dst_width, + }, + ) if dst_size == src_size => Expression::As { + expr: component, + kind: dst_kind, + convert: Some(dst_width), + }, + + // Matrix conversion (matrix -> matrix) + ( + Components::One { + component, + ty: + &TypeInner::Matrix { + columns: src_columns, + rows: src_rows, + .. + }, + .. + }, + ConstructorType::Matrix { + columns: dst_columns, + rows: dst_rows, + width: dst_width, + }, + ) if dst_columns == src_columns && dst_rows == src_rows => Expression::As { + expr: component, + kind: ScalarKind::Float, + convert: Some(dst_width), + }, + + // Vector constructor (splat) - infer type + ( + Components::One { + component, + ty: &TypeInner::Scalar { .. }, + .. + }, + ConstructorType::PartialVector { size }, + ) => Expression::Splat { + size, + value: component, + }, + + // Vector constructor (splat) + ( + Components::One { + component, + ty: + &TypeInner::Scalar { + kind: src_kind, + width: src_width, + .. + }, + .. + }, + ConstructorType::Vector { + size, + kind: dst_kind, + width: dst_width, + }, + ) if dst_kind == src_kind || dst_width == src_width => Expression::Splat { + size, + value: component, + }, + + // Vector constructor (by elements) + ( + Components::Many { + components, + first_component_ty: &TypeInner::Scalar { kind, width }, + .. + }, + ConstructorType::PartialVector { size }, + ) + | ( + Components::Many { + components, + first_component_ty: &TypeInner::Vector { kind, width, .. }, + .. + }, + ConstructorType::PartialVector { size }, + ) + | ( + Components::Many { + components, + first_component_ty: &TypeInner::Scalar { .. }, + .. + }, + ConstructorType::Vector { size, width, kind }, + ) + | ( + Components::Many { + components, + first_component_ty: &TypeInner::Vector { .. }, + .. + }, + ConstructorType::Vector { size, width, kind }, + ) => { + let ty = ctx.types.insert( + Type { + name: None, + inner: TypeInner::Vector { size, kind, width }, + }, + Default::default(), + ); + Expression::Compose { ty, components } + } + + // Matrix constructor (by elements) + ( + Components::Many { + components, + first_component_ty: &TypeInner::Scalar { width, .. }, + .. + }, + ConstructorType::PartialMatrix { columns, rows }, + ) + | ( + Components::Many { + components, + first_component_ty: &TypeInner::Scalar { .. }, + .. + }, + ConstructorType::Matrix { + columns, + rows, + width, + }, + ) => { + let vec_ty = ctx.types.insert( + Type { + name: None, + inner: TypeInner::Vector { + width, + kind: ScalarKind::Float, + size: rows, + }, + }, + Default::default(), + ); + + let components = components + .chunks(rows as usize) + .map(|vec_components| { + ctx.expressions.append( + Expression::Compose { + ty: vec_ty, + components: Vec::from(vec_components), + }, + Default::default(), + ) + }) + .collect(); + + let ty = ctx.types.insert( + Type { + name: None, + inner: TypeInner::Matrix { + columns, + rows, + width, + }, + }, + Default::default(), + ); + Expression::Compose { ty, components } + } + + // Matrix constructor (by columns) + ( + Components::Many { + components, + first_component_ty: &TypeInner::Vector { width, .. }, + .. + }, + ConstructorType::PartialMatrix { columns, rows }, + ) + | ( + Components::Many { + components, + first_component_ty: &TypeInner::Vector { .. }, + .. + }, + ConstructorType::Matrix { + columns, + rows, + width, + }, + ) => { + let ty = ctx.types.insert( + Type { + name: None, + inner: TypeInner::Matrix { + columns, + rows, + width, + }, + }, + Default::default(), + ); + Expression::Compose { ty, components } + } + + // Array constructor - infer type + (components, ConstructorType::PartialArray) => { + let components = components.into_components_vec(); + + let base = match ctx.typifier[components[0]].clone() { + TypeResolution::Handle(ty) => ty, + TypeResolution::Value(inner) => ctx + .types + .insert(Type { name: None, inner }, Default::default()), + }; + + let size = Constant { + name: None, + specialization: None, + inner: ConstantInner::Scalar { + width: 4, + value: ScalarValue::Uint(components.len() as u64), + }, + }; + + let inner = TypeInner::Array { + base, + size: ArraySize::Constant(ctx.constants.append(size, Default::default())), + stride: { + parser.layouter.update(ctx.types, ctx.constants).unwrap(); + parser.layouter[base].to_stride() + }, + }; + + let ty = ctx + .types + .insert(Type { name: None, inner }, Default::default()); + + Expression::Compose { ty, components } + } + + // Array constructor + (components, ConstructorType::Array { base, size, stride }) => { + let components = components.into_components_vec(); + let inner = TypeInner::Array { base, size, stride }; + let ty = ctx + .types + .insert(Type { name: None, inner }, Default::default()); + Expression::Compose { ty, components } + } + + // Struct constructor + (components, ConstructorType::Struct(ty)) => Expression::Compose { + ty, + components: components.into_components_vec(), + }, + + // ERRORS + + // Bad conversion (type cast) + ( + Components::One { + span, ty: src_ty, .. + }, + dst_ty, + ) => { + return Err(Error::BadTypeCast { + span, + from_type: src_ty.to_wgsl(ctx.types, ctx.constants), + to_type: dst_ty.to_error_string(ctx.types, ctx.constants), + }); + } + + // Too many parameters for scalar constructor + (Components::Many { spans, .. }, ConstructorType::Scalar { .. }) => { + return Err(Error::UnexpectedComponents(Span { + start: spans[1].start, + end: spans.last().unwrap().end, + })); + } + + // Parameters are of the wrong type for vector or matrix constructor + (Components::Many { spans, .. }, ConstructorType::Vector { .. }) + | (Components::Many { spans, .. }, ConstructorType::Matrix { .. }) + | (Components::Many { spans, .. }, ConstructorType::PartialVector { .. }) + | (Components::Many { spans, .. }, ConstructorType::PartialMatrix { .. }) => { + return Err(Error::InvalidConstructorComponentType(spans[0].clone(), 0)); + } + }; + + let span = NagaSpan::from(parser.pop_scope(lexer)); + Ok(Some(ctx.expressions.append(expr, span))) +} diff --git a/src/front/wgsl/mod.rs b/src/front/wgsl/mod.rs index f0b4b32c88..cd1f445c97 100644 --- a/src/front/wgsl/mod.rs +++ b/src/front/wgsl/mod.rs @@ -4,6 +4,7 @@ Frontend for [WGSL][wgsl] (WebGPU Shading Language). [wgsl]: https://gpuweb.github.io/gpuweb/wgsl.html */ +mod construction; mod conv; mod lexer; mod number_literals; @@ -124,6 +125,7 @@ pub enum BadFloatError { #[derive(Clone, Debug)] pub enum Error<'a> { Unexpected(TokenSpan<'a>, ExpectedToken<'a>), + UnexpectedComponents(Span), BadU32(Span, BadIntError), BadI32(Span, BadIntError), /// A negative signed integer literal where both signed and unsigned, @@ -148,6 +150,7 @@ pub enum Error<'a> { InvalidResolve(ResolveError), InvalidForInitializer(Span), InvalidGatherComponent(Span, i32), + InvalidConstructorComponentType(Span, i32), ReservedIdentifierPrefix(Span), UnknownAddressSpace(Span), UnknownAttribute(Span), @@ -162,6 +165,8 @@ pub enum Error<'a> { ZeroSizeOrAlign(Span), InconsistentBinding(Span), UnknownLocalFunction(Span), + TypeNotConstructible(Span), + TypeNotInferrable(Span), InitializationTypeMismatch(Span, String), MissingType(Span), MissingAttribute(&'static str, Span), @@ -253,6 +258,11 @@ impl<'a> Error<'a> { notes: vec![], } }, + Error::UnexpectedComponents(ref bad_span) => ParseError { + message: "unexpected components".to_string(), + labels: vec![(bad_span.clone(), "unexpected components".into())], + notes: vec![], + }, Error::BadU32(ref bad_span, ref err) => ParseError { message: format!( "expected unsigned integer literal, found `{}`", @@ -355,6 +365,11 @@ impl<'a> Error<'a> { labels: vec![(bad_span.clone(), "invalid component".into())], notes: vec![], }, + Error::InvalidConstructorComponentType(ref bad_span, component) => ParseError { + message: format!("invalid type for constructor component at index [{}]", component), + labels: vec![(bad_span.clone(), "invalid component type".into())], + notes: vec![], + }, Error::ReservedIdentifierPrefix(ref bad_span) => ParseError { message: format!("Identifier starts with a reserved prefix: '{}'", &source[bad_span.clone()]), labels: vec![(bad_span.clone(), "invalid identifier".into())], @@ -415,6 +430,16 @@ impl<'a> Error<'a> { labels: vec![(span.clone(), "unknown local function".into())], notes: vec![], }, + Error::TypeNotConstructible(ref span) => ParseError { + message: format!("type `{}` is not constructible", &source[span.clone()]), + labels: vec![(span.clone(), "type is not constructible".into())], + notes: vec![], + }, + Error::TypeNotInferrable(ref span) => ParseError { + message: "type can't be inferred".to_string(), + labels: vec![(span.clone(), "type can't be inferred".into())], + notes: vec![], + }, Error::InitializationTypeMismatch(ref name_span, ref expected_ty) => ParseError { message: format!("the type of `{}` is expected to be `{}`", &source[name_span.clone()], expected_ty), labels: vec![(name_span.clone(), format!("definition of `{}`", &source[name_span.clone()]).into())], @@ -969,6 +994,98 @@ impl<'a> ExpressionContext<'a, '_, '_> { expr.handle } } + + /// Creates a zero value constant of type `ty` + /// + /// Returns `None` if the given `ty` is not a constructible type + fn create_zero_value_constant( + &mut self, + ty: Handle, + ) -> Option> { + let inner = match self.types[ty].inner { + crate::TypeInner::Scalar { kind, width } => { + let value = match kind { + crate::ScalarKind::Sint => crate::ScalarValue::Sint(0), + crate::ScalarKind::Uint => crate::ScalarValue::Uint(0), + crate::ScalarKind::Float => crate::ScalarValue::Float(0.), + crate::ScalarKind::Bool => crate::ScalarValue::Bool(false), + }; + crate::ConstantInner::Scalar { width, value } + } + crate::TypeInner::Vector { size, kind, width } => { + let scalar_ty = self.types.insert( + crate::Type { + name: None, + inner: crate::TypeInner::Scalar { width, kind }, + }, + Default::default(), + ); + let component = self.create_zero_value_constant(scalar_ty); + crate::ConstantInner::Composite { + ty, + components: (0..size as u8).map(|_| component).collect::>()?, + } + } + crate::TypeInner::Matrix { + columns, + rows, + width, + } => { + let vec_ty = self.types.insert( + crate::Type { + name: None, + inner: crate::TypeInner::Vector { + width, + kind: crate::ScalarKind::Float, + size: rows, + }, + }, + Default::default(), + ); + let component = self.create_zero_value_constant(vec_ty); + crate::ConstantInner::Composite { + ty, + components: (0..columns as u8) + .map(|_| component) + .collect::>()?, + } + } + crate::TypeInner::Array { + base, + size: crate::ArraySize::Constant(size), + .. + } => { + let component = self.create_zero_value_constant(base); + crate::ConstantInner::Composite { + ty, + components: (0..self.constants[size].to_array_length().unwrap()) + .map(|_| component) + .collect::>()?, + } + } + crate::TypeInner::Struct { ref members, .. } => { + let members = members.clone(); + crate::ConstantInner::Composite { + ty, + components: members + .iter() + .map(|member| self.create_zero_value_constant(member.ty)) + .collect::>()?, + } + } + _ => return None, + }; + + let constant = self.constants.fetch_or_append( + crate::Constant { + name: None, + specialization: None, + inner, + }, + crate::Span::default(), + ); + Some(constant) + } } /// A Naga [`Expression`] handle, with WGSL type information. @@ -2044,158 +2161,6 @@ impl Parser { })) } - /// Expects [`Scope::PrimaryExpr`] scope on top; if returning Some(_), pops it. - fn parse_construction<'a>( - &mut self, - lexer: &mut Lexer<'a>, - type_name: &'a str, - mut ctx: ExpressionContext<'a, '_, '_>, - ) -> Result>, Error<'a>> { - assert_eq!( - self.scopes.last().map(|&(ref scope, _)| scope.clone()), - Some(Scope::PrimaryExpr) - ); - let ty_resolution = match self.lookup_type.get(type_name) { - Some(&handle) => TypeResolution::Handle(handle), - None => match self.parse_type_decl_impl( - lexer, - TypeAttributes::default(), - type_name, - ctx.types, - ctx.constants, - )? { - Some(inner) => TypeResolution::Value(inner), - None => return Ok(None), - }, - }; - - let mut components = Vec::new(); - let (last_component, arguments_span) = lexer.capture_span(|lexer| { - lexer.open_arguments()?; - let mut last_component = self.parse_general_expression(lexer, ctx.reborrow())?; - - while lexer.next_argument()? { - components.push(last_component); - last_component = self.parse_general_expression(lexer, ctx.reborrow())?; - } - - Ok(last_component) - })?; - - // We can't use the `TypeInner` returned by this because - // `resolve_type` borrows context mutably. - // Use it to insert into the right maps, - // and then grab it again immutably. - ctx.resolve_type(last_component)?; - - let expr = if components.is_empty() - && ty_resolution.inner_with(ctx.types).scalar_kind().is_some() - { - match ( - ty_resolution.inner_with(ctx.types), - ctx.typifier.get(last_component, ctx.types), - ) { - ( - &crate::TypeInner::Vector { - size, kind, width, .. - }, - &crate::TypeInner::Scalar { - kind: arg_kind, - width: arg_width, - .. - }, - ) if arg_kind == kind && arg_width == width => crate::Expression::Splat { - size, - value: last_component, - }, - ( - &crate::TypeInner::Scalar { kind, width, .. }, - &crate::TypeInner::Scalar { .. }, - ) - | ( - &crate::TypeInner::Vector { kind, width, .. }, - &crate::TypeInner::Vector { .. }, - ) => crate::Expression::As { - expr: last_component, - kind, - convert: Some(width), - }, - (&crate::TypeInner::Matrix { width, .. }, &crate::TypeInner::Matrix { .. }) => { - crate::Expression::As { - expr: last_component, - kind: crate::ScalarKind::Float, - convert: Some(width), - } - } - (to_type, from_type) => { - return Err(Error::BadTypeCast { - span: arguments_span, - from_type: from_type.to_wgsl(ctx.types, ctx.constants), - to_type: to_type.to_wgsl(ctx.types, ctx.constants), - }); - } - } - } else { - components.push(last_component); - let mut compose_components = Vec::new(); - - if let ( - &crate::TypeInner::Matrix { - rows, - width, - columns, - }, - &crate::TypeInner::Scalar { - kind: crate::ScalarKind::Float, - .. - }, - ) = ( - ty_resolution.inner_with(ctx.types), - ctx.typifier.get(last_component, ctx.types), - ) { - let vec_ty = ctx.types.insert( - crate::Type { - name: None, - inner: crate::TypeInner::Vector { - width, - kind: crate::ScalarKind::Float, - size: rows, - }, - }, - Default::default(), - ); - - compose_components.reserve(columns as usize); - for vec_components in components.chunks(rows as usize) { - let handle = ctx.expressions.append( - crate::Expression::Compose { - ty: vec_ty, - components: Vec::from(vec_components), - }, - crate::Span::default(), - ); - compose_components.push(handle); - } - } else { - compose_components = components; - } - - let ty = match ty_resolution { - TypeResolution::Handle(handle) => handle, - TypeResolution::Value(inner) => ctx - .types - .insert(crate::Type { name: None, inner }, Default::default()), - }; - crate::Expression::Compose { - ty, - components: compose_components, - } - }; - - let span = NagaSpan::from(self.pop_scope(lexer)); - Ok(Some(ctx.expressions.append(expr, span))) - } - fn parse_const_expression_impl<'a>( &mut self, first_token_span: TokenSpan<'a>, @@ -2325,7 +2290,13 @@ impl Parser { TypedExpression::non_reference(expr) } else { let _ = lexer.next(); - if let Some(expr) = self.parse_construction(lexer, word, ctx.reborrow())? { + if let Some(expr) = construction::parse_construction( + self, + lexer, + word, + span.clone(), + ctx.reborrow(), + )? { TypedExpression::non_reference(expr) } else { return Err(Error::UnknownIdent(span, word)); diff --git a/tests/in/operators.wgsl b/tests/in/operators.wgsl index 996f528d4a..5ad2a2a2b5 100644 --- a/tests/in/operators.wgsl +++ b/tests/in/operators.wgsl @@ -58,6 +58,21 @@ fn constructors() -> f32 { 0.0, 0.0, 0.0, 1.0, ); + // zero value constructors + var _ = bool(); + var _ = i32(); + var _ = u32(); + var _ = f32(); + var _ = vec2(); + var _ = mat2x2(); + var _ = array(); + var _ = Foo(); + + // constructors that infer their type from their parameters + var _ = vec2(0u); + var _ = mat2x2(vec2(0.), vec2(0.)); + var _ = array(0, 1, 2, 3); + return foo.a.x; } diff --git a/tests/out/glsl/operators.main.Compute.glsl b/tests/out/glsl/operators.main.Compute.glsl index f8a24579b7..76486c837c 100644 --- a/tests/out/glsl/operators.main.Compute.glsl +++ b/tests/out/glsl/operators.main.Compute.glsl @@ -43,11 +43,25 @@ vec3 bool_cast(vec3 x) { float constructors() { Foo foo = Foo(vec4(0.0), 0); + bool unnamed = false; + int unnamed_1 = 0; + uint unnamed_2 = 0u; + float unnamed_3 = 0.0; + uvec2 unnamed_4 = uvec2(0u, 0u); + mat2x2 unnamed_5 = mat2x2(vec2(0.0, 0.0), vec2(0.0, 0.0)); + Foo unnamed_6[3] = Foo[3](Foo(vec4(0.0, 0.0, 0.0, 0.0), 0), Foo(vec4(0.0, 0.0, 0.0, 0.0), 0), Foo(vec4(0.0, 0.0, 0.0, 0.0), 0)); + Foo unnamed_7 = Foo(vec4(0.0, 0.0, 0.0, 0.0), 0); + uvec2 unnamed_8 = uvec2(0u); + mat2x2 unnamed_9 = mat2x2(0.0); + int unnamed_10[4] = int[4](0, 0, 0, 0); foo = Foo(vec4(1.0), 1); mat2x2 mat2comp = mat2x2(vec2(1.0, 0.0), vec2(0.0, 1.0)); mat4x4 mat4comp = mat4x4(vec4(1.0, 0.0, 0.0, 0.0), vec4(0.0, 1.0, 0.0, 0.0), vec4(0.0, 0.0, 1.0, 0.0), vec4(0.0, 0.0, 0.0, 1.0)); - float _e39 = foo.a.x; - return _e39; + unnamed_8 = uvec2(0u); + unnamed_9 = mat2x2(vec2(0.0), vec2(0.0)); + unnamed_10 = int[4](0, 1, 2, 3); + float _e70 = foo.a.x; + return _e70; } void modulo() { diff --git a/tests/out/hlsl/operators.hlsl b/tests/out/hlsl/operators.hlsl index 327269054f..08aed4f934 100644 --- a/tests/out/hlsl/operators.hlsl +++ b/tests/out/hlsl/operators.hlsl @@ -53,12 +53,29 @@ Foo ConstructFoo(float4 arg0, int arg1) { float constructors() { Foo foo = (Foo)0; + bool unnamed = false; + int unnamed_1 = 0; + uint unnamed_2 = 0u; + float unnamed_3 = 0.0; + uint2 unnamed_4 = uint2(0u, 0u); + float2x2 unnamed_5 = float2x2(float2(0.0, 0.0), float2(0.0, 0.0)); + Foo unnamed_6[3] = { { float4(0.0, 0.0, 0.0, 0.0), 0 }, { float4(0.0, 0.0, 0.0, 0.0), 0 }, { float4(0.0, 0.0, 0.0, 0.0), 0 } }; + Foo unnamed_7 = { float4(0.0, 0.0, 0.0, 0.0), 0 }; + uint2 unnamed_8 = (uint2)0; + float2x2 unnamed_9 = (float2x2)0; + int unnamed_10[4] = {(int)0,(int)0,(int)0,(int)0}; foo = ConstructFoo(float4(1.0.xxxx), 1); float2x2 mat2comp = float2x2(float2(1.0, 0.0), float2(0.0, 1.0)); float4x4 mat4comp = float4x4(float4(1.0, 0.0, 0.0, 0.0), float4(0.0, 1.0, 0.0, 0.0), float4(0.0, 0.0, 1.0, 0.0), float4(0.0, 0.0, 0.0, 1.0)); - float _expr39 = foo.a.x; - return _expr39; + unnamed_8 = uint2(0u.xx); + unnamed_9 = float2x2(float2(0.0.xx), float2(0.0.xx)); + { + int _result[4]={ 0, 1, 2, 3 }; + for(int _i=0; _i<4; ++_i) unnamed_10[_i] = _result[_i]; + } + float _expr70 = foo.a.x; + return _expr70; } void modulo() diff --git a/tests/out/msl/operators.msl b/tests/out/msl/operators.msl index 0170f43ea2..65a5f61c4e 100644 --- a/tests/out/msl/operators.msl +++ b/tests/out/msl/operators.msl @@ -8,10 +8,22 @@ struct Foo { metal::float4 a; int b; }; +struct type_12 { + Foo inner[3]; +}; +struct type_13 { + int inner[4u]; +}; constant metal::float4 v_f32_one = {1.0, 1.0, 1.0, 1.0}; constant metal::float4 v_f32_zero = {0.0, 0.0, 0.0, 0.0}; constant metal::float4 v_f32_half = {0.5, 0.5, 0.5, 0.5}; constant metal::int4 v_i32_one = {1, 1, 1, 1}; +constant metal::uint2 const_type_11_ = {0u, 0u}; +constant metal::float2 const_type_6_ = {0.0, 0.0}; +constant metal::float2x2 const_type_7_ = {const_type_6_, const_type_6_}; +constant metal::float4 const_type = {0.0, 0.0, 0.0, 0.0}; +constant Foo const_Foo = {const_type, 0}; +constant type_12 const_type_12_ = {const_Foo, const_Foo, const_Foo}; metal::float4 builtins( ) { @@ -52,11 +64,25 @@ metal::float3 bool_cast( float constructors( ) { Foo foo; + bool unnamed = false; + int unnamed_1 = 0; + uint unnamed_2 = 0u; + float unnamed_3 = 0.0; + metal::uint2 unnamed_4 = const_type_11_; + metal::float2x2 unnamed_5 = const_type_7_; + type_12 unnamed_6 = const_type_12_; + Foo unnamed_7 = const_Foo; + metal::uint2 unnamed_8; + metal::float2x2 unnamed_9; + type_13 unnamed_10; foo = Foo {metal::float4(1.0), 1}; metal::float2x2 mat2comp = metal::float2x2(metal::float2(1.0, 0.0), metal::float2(0.0, 1.0)); metal::float4x4 mat4comp = metal::float4x4(metal::float4(1.0, 0.0, 0.0, 0.0), metal::float4(0.0, 1.0, 0.0, 0.0), metal::float4(0.0, 0.0, 1.0, 0.0), metal::float4(0.0, 0.0, 0.0, 1.0)); - float _e39 = foo.a.x; - return _e39; + unnamed_8 = metal::uint2(0u); + unnamed_9 = metal::float2x2(metal::float2(0.0), metal::float2(0.0)); + for(int _i=0; _i<4; ++_i) unnamed_10.inner[_i] = type_13 {0, 1, 2, 3}.inner[_i]; + float _e70 = foo.a.x; + return _e70; } void modulo( diff --git a/tests/out/spv/operators.spvasm b/tests/out/spv/operators.spvasm index 22376a350b..be03133c90 100644 --- a/tests/out/spv/operators.spvasm +++ b/tests/out/spv/operators.spvasm @@ -1,14 +1,16 @@ ; SPIR-V ; Version: 1.1 ; Generator: rspirv -; Bound: 180 +; Bound: 214 OpCapability Shader %1 = OpExtInstImport "GLSL.std.450" OpMemoryModel Logical GLSL450 -OpEntryPoint GLCompute %168 "main" -OpExecutionMode %168 LocalSize 1 1 1 -OpMemberDecorate %23 0 Offset 0 -OpMemberDecorate %23 1 Offset 16 +OpEntryPoint GLCompute %202 "main" +OpExecutionMode %202 LocalSize 1 1 1 +OpMemberDecorate %27 0 Offset 0 +OpMemberDecorate %27 1 Offset 16 +OpDecorate %32 ArrayStride 32 +OpDecorate %33 ArrayStride 4 %2 = OpTypeVoid %4 = OpTypeFloat 32 %3 = OpConstant %4 1.0 @@ -26,208 +28,245 @@ OpMemberDecorate %23 1 Offset 16 %16 = OpConstant %4 4.0 %17 = OpConstant %8 5 %18 = OpConstant %8 2 -%19 = OpTypeVector %4 4 -%20 = OpTypeVector %8 4 -%21 = OpTypeVector %10 4 -%22 = OpTypeVector %4 3 -%23 = OpTypeStruct %19 %8 -%24 = OpTypeVector %4 2 -%25 = OpTypeMatrix %24 2 -%26 = OpTypeMatrix %19 4 -%27 = OpConstantComposite %19 %3 %3 %3 %3 -%28 = OpConstantComposite %19 %5 %5 %5 %5 -%29 = OpConstantComposite %19 %6 %6 %6 %6 -%30 = OpConstantComposite %20 %7 %7 %7 %7 -%33 = OpTypeFunction %19 -%74 = OpTypeFunction %8 -%81 = OpConstantNull %8 -%85 = OpTypeFunction %22 %22 -%87 = OpTypeVector %10 3 -%94 = OpTypePointer Function %23 -%97 = OpTypeFunction %4 -%109 = OpTypePointer Function %19 -%110 = OpTypePointer Function %4 -%112 = OpTypeInt 32 0 -%111 = OpConstant %112 0 -%117 = OpTypeFunction %2 -%121 = OpTypeVector %8 3 -%143 = OpTypePointer Function %8 -%32 = OpFunction %19 None %33 -%31 = OpLabel -OpBranch %34 -%34 = OpLabel -%35 = OpSelect %8 %9 %7 %11 -%37 = OpCompositeConstruct %21 %9 %9 %9 %9 -%36 = OpSelect %19 %37 %27 %28 -%38 = OpCompositeConstruct %21 %12 %12 %12 %12 -%39 = OpSelect %19 %38 %28 %27 -%40 = OpExtInst %19 %1 FMix %28 %27 %29 -%42 = OpCompositeConstruct %19 %13 %13 %13 %13 -%41 = OpExtInst %19 %1 FMix %28 %27 %42 -%43 = OpCompositeExtract %8 %30 0 -%44 = OpBitcast %4 %43 -%45 = OpBitcast %19 %30 -%46 = OpConvertFToS %20 %28 -%47 = OpCompositeConstruct %20 %35 %35 %35 %35 -%48 = OpIAdd %20 %47 %46 -%49 = OpConvertSToF %19 %48 -%50 = OpFAdd %19 %49 %36 -%51 = OpFAdd %19 %50 %40 -%52 = OpFAdd %19 %51 %41 -%53 = OpCompositeConstruct %19 %44 %44 %44 %44 -%54 = OpFAdd %19 %52 %53 -%55 = OpFAdd %19 %54 %45 -OpReturnValue %55 +%20 = OpTypeInt 32 0 +%19 = OpConstant %20 0 +%21 = OpConstant %8 3 +%22 = OpConstant %20 4 +%23 = OpTypeVector %4 4 +%24 = OpTypeVector %8 4 +%25 = OpTypeVector %10 4 +%26 = OpTypeVector %4 3 +%27 = OpTypeStruct %23 %8 +%28 = OpTypeVector %4 2 +%29 = OpTypeMatrix %28 2 +%30 = OpTypeMatrix %23 4 +%31 = OpTypeVector %20 2 +%32 = OpTypeArray %27 %21 +%33 = OpTypeArray %8 %22 +%34 = OpConstantComposite %23 %3 %3 %3 %3 +%35 = OpConstantComposite %23 %5 %5 %5 %5 +%36 = OpConstantComposite %23 %6 %6 %6 %6 +%37 = OpConstantComposite %24 %7 %7 %7 %7 +%38 = OpConstantComposite %31 %19 %19 +%39 = OpConstantComposite %28 %5 %5 +%40 = OpConstantComposite %29 %39 %39 +%41 = OpConstantComposite %23 %5 %5 %5 %5 +%42 = OpConstantComposite %27 %41 %11 +%43 = OpConstantComposite %32 %42 %42 %42 +%46 = OpTypeFunction %23 +%87 = OpTypeFunction %8 +%94 = OpConstantNull %8 +%98 = OpTypeFunction %26 %26 +%100 = OpTypeVector %10 3 +%107 = OpTypePointer Function %27 +%109 = OpTypePointer Function %10 +%111 = OpTypePointer Function %8 +%113 = OpTypePointer Function %20 +%115 = OpTypePointer Function %4 +%117 = OpTypePointer Function %31 +%119 = OpTypePointer Function %29 +%121 = OpTypePointer Function %32 +%126 = OpTypePointer Function %33 +%129 = OpTypeFunction %4 +%146 = OpTypePointer Function %23 +%147 = OpTypePointer Function %4 +%152 = OpTypeFunction %2 +%156 = OpTypeVector %8 3 +%45 = OpFunction %23 None %46 +%44 = OpLabel +OpBranch %47 +%47 = OpLabel +%48 = OpSelect %8 %9 %7 %11 +%50 = OpCompositeConstruct %25 %9 %9 %9 %9 +%49 = OpSelect %23 %50 %34 %35 +%51 = OpCompositeConstruct %25 %12 %12 %12 %12 +%52 = OpSelect %23 %51 %35 %34 +%53 = OpExtInst %23 %1 FMix %35 %34 %36 +%55 = OpCompositeConstruct %23 %13 %13 %13 %13 +%54 = OpExtInst %23 %1 FMix %35 %34 %55 +%56 = OpCompositeExtract %8 %37 0 +%57 = OpBitcast %4 %56 +%58 = OpBitcast %23 %37 +%59 = OpConvertFToS %24 %35 +%60 = OpCompositeConstruct %24 %48 %48 %48 %48 +%61 = OpIAdd %24 %60 %59 +%62 = OpConvertSToF %23 %61 +%63 = OpFAdd %23 %62 %49 +%64 = OpFAdd %23 %63 %53 +%65 = OpFAdd %23 %64 %54 +%66 = OpCompositeConstruct %23 %57 %57 %57 %57 +%67 = OpFAdd %23 %65 %66 +%68 = OpFAdd %23 %67 %58 +OpReturnValue %68 OpFunctionEnd -%57 = OpFunction %19 None %33 -%56 = OpLabel -OpBranch %58 -%58 = OpLabel -%59 = OpCompositeConstruct %24 %14 %14 -%60 = OpCompositeConstruct %24 %3 %3 -%61 = OpFAdd %24 %60 %59 -%62 = OpCompositeConstruct %24 %15 %15 -%63 = OpFSub %24 %61 %62 -%64 = OpCompositeConstruct %24 %16 %16 -%65 = OpFDiv %24 %63 %64 -%66 = OpCompositeConstruct %20 %17 %17 %17 %17 -%67 = OpCompositeConstruct %20 %18 %18 %18 %18 -%68 = OpSMod %20 %66 %67 -%69 = OpVectorShuffle %19 %65 %65 0 1 0 1 -%70 = OpConvertSToF %19 %68 -%71 = OpFAdd %19 %69 %70 -OpReturnValue %71 +%70 = OpFunction %23 None %46 +%69 = OpLabel +OpBranch %71 +%71 = OpLabel +%72 = OpCompositeConstruct %28 %14 %14 +%73 = OpCompositeConstruct %28 %3 %3 +%74 = OpFAdd %28 %73 %72 +%75 = OpCompositeConstruct %28 %15 %15 +%76 = OpFSub %28 %74 %75 +%77 = OpCompositeConstruct %28 %16 %16 +%78 = OpFDiv %28 %76 %77 +%79 = OpCompositeConstruct %24 %17 %17 %17 %17 +%80 = OpCompositeConstruct %24 %18 %18 %18 %18 +%81 = OpSMod %24 %79 %80 +%82 = OpVectorShuffle %23 %78 %78 0 1 0 1 +%83 = OpConvertSToF %23 %81 +%84 = OpFAdd %23 %82 %83 +OpReturnValue %84 OpFunctionEnd -%73 = OpFunction %8 None %74 -%72 = OpLabel -OpBranch %75 -%75 = OpLabel -%76 = OpLogicalNot %10 %9 -OpSelectionMerge %77 None -OpBranchConditional %76 %78 %79 -%78 = OpLabel +%86 = OpFunction %8 None %87 +%85 = OpLabel +OpBranch %88 +%88 = OpLabel +%89 = OpLogicalNot %10 %9 +OpSelectionMerge %90 None +OpBranchConditional %89 %91 %92 +%91 = OpLabel OpReturnValue %7 -%79 = OpLabel -%80 = OpNot %8 %7 -OpReturnValue %80 -%77 = OpLabel -OpReturnValue %81 +%92 = OpLabel +%93 = OpNot %8 %7 +OpReturnValue %93 +%90 = OpLabel +OpReturnValue %94 OpFunctionEnd -%84 = OpFunction %22 None %85 -%83 = OpFunctionParameter %22 -%82 = OpLabel -OpBranch %86 -%86 = OpLabel -%88 = OpCompositeConstruct %22 %5 %5 %5 -%89 = OpFUnordNotEqual %87 %83 %88 -%90 = OpCompositeConstruct %22 %5 %5 %5 -%91 = OpCompositeConstruct %22 %3 %3 %3 -%92 = OpSelect %22 %89 %91 %90 -OpReturnValue %92 -OpFunctionEnd -%96 = OpFunction %4 None %97 +%97 = OpFunction %26 None %98 +%96 = OpFunctionParameter %26 %95 = OpLabel -%93 = OpVariable %94 Function -OpBranch %98 -%98 = OpLabel -%99 = OpCompositeConstruct %19 %3 %3 %3 %3 -%100 = OpCompositeConstruct %23 %99 %7 -OpStore %93 %100 -%101 = OpCompositeConstruct %24 %3 %5 -%102 = OpCompositeConstruct %24 %5 %3 -%103 = OpCompositeConstruct %25 %101 %102 -%104 = OpCompositeConstruct %19 %3 %5 %5 %5 -%105 = OpCompositeConstruct %19 %5 %3 %5 %5 -%106 = OpCompositeConstruct %19 %5 %5 %3 %5 -%107 = OpCompositeConstruct %19 %5 %5 %5 %3 -%108 = OpCompositeConstruct %26 %104 %105 %106 %107 -%113 = OpAccessChain %110 %93 %111 %111 -%114 = OpLoad %4 %113 -OpReturnValue %114 +OpBranch %99 +%99 = OpLabel +%101 = OpCompositeConstruct %26 %5 %5 %5 +%102 = OpFUnordNotEqual %100 %96 %101 +%103 = OpCompositeConstruct %26 %5 %5 %5 +%104 = OpCompositeConstruct %26 %3 %3 %3 +%105 = OpSelect %26 %102 %104 %103 +OpReturnValue %105 OpFunctionEnd -%116 = OpFunction %2 None %117 -%115 = OpLabel -OpBranch %118 -%118 = OpLabel -%119 = OpSMod %8 %7 %7 -%120 = OpFRem %4 %3 %3 -%122 = OpCompositeConstruct %121 %7 %7 %7 -%123 = OpCompositeConstruct %121 %7 %7 %7 -%124 = OpSMod %121 %122 %123 -%125 = OpCompositeConstruct %22 %3 %3 %3 -%126 = OpCompositeConstruct %22 %3 %3 %3 -%127 = OpFRem %22 %125 %126 -OpReturn -OpFunctionEnd -%129 = OpFunction %2 None %117 -%128 = OpLabel +%128 = OpFunction %4 None %129 +%127 = OpLabel +%123 = OpVariable %117 Function +%118 = OpVariable %119 Function %40 +%112 = OpVariable %113 Function %19 +%106 = OpVariable %107 Function +%124 = OpVariable %119 Function +%120 = OpVariable %121 Function %43 +%114 = OpVariable %115 Function %5 +%108 = OpVariable %109 Function %12 +%125 = OpVariable %126 Function +%122 = OpVariable %107 Function %42 +%116 = OpVariable %117 Function %38 +%110 = OpVariable %111 Function %11 OpBranch %130 %130 = OpLabel -%131 = OpCompositeConstruct %19 %3 %5 %5 %5 -%132 = OpCompositeConstruct %19 %5 %3 %5 %5 -%133 = OpCompositeConstruct %19 %5 %5 %3 %5 -%134 = OpCompositeConstruct %19 %5 %5 %5 %3 -%135 = OpCompositeConstruct %26 %131 %132 %133 %134 -%136 = OpMatrixTimesScalar %26 %135 %14 +%131 = OpCompositeConstruct %23 %3 %3 %3 %3 +%132 = OpCompositeConstruct %27 %131 %7 +OpStore %106 %132 +%133 = OpCompositeConstruct %28 %3 %5 +%134 = OpCompositeConstruct %28 %5 %3 +%135 = OpCompositeConstruct %29 %133 %134 +%136 = OpCompositeConstruct %23 %3 %5 %5 %5 +%137 = OpCompositeConstruct %23 %5 %3 %5 %5 +%138 = OpCompositeConstruct %23 %5 %5 %3 %5 +%139 = OpCompositeConstruct %23 %5 %5 %5 %3 +%140 = OpCompositeConstruct %30 %136 %137 %138 %139 +%141 = OpCompositeConstruct %31 %19 %19 +OpStore %123 %141 +%142 = OpCompositeConstruct %28 %5 %5 +%143 = OpCompositeConstruct %28 %5 %5 +%144 = OpCompositeConstruct %29 %142 %143 +OpStore %124 %144 +%145 = OpCompositeConstruct %33 %11 %7 %18 %21 +OpStore %125 %145 +%148 = OpAccessChain %147 %106 %19 %19 +%149 = OpLoad %4 %148 +OpReturnValue %149 +OpFunctionEnd +%151 = OpFunction %2 None %152 +%150 = OpLabel +OpBranch %153 +%153 = OpLabel +%154 = OpSMod %8 %7 %7 +%155 = OpFRem %4 %3 %3 +%157 = OpCompositeConstruct %156 %7 %7 %7 +%158 = OpCompositeConstruct %156 %7 %7 %7 +%159 = OpSMod %156 %157 %158 +%160 = OpCompositeConstruct %26 %3 %3 %3 +%161 = OpCompositeConstruct %26 %3 %3 %3 +%162 = OpFRem %26 %160 %161 OpReturn OpFunctionEnd -%138 = OpFunction %2 None %117 -%137 = OpLabel -OpBranch %139 -%139 = OpLabel -%140 = OpLogicalOr %10 %9 %12 -%141 = OpLogicalAnd %10 %9 %12 +%164 = OpFunction %2 None %152 +%163 = OpLabel +OpBranch %165 +%165 = OpLabel +%166 = OpCompositeConstruct %23 %3 %5 %5 %5 +%167 = OpCompositeConstruct %23 %5 %3 %5 %5 +%168 = OpCompositeConstruct %23 %5 %5 %3 %5 +%169 = OpCompositeConstruct %23 %5 %5 %5 %3 +%170 = OpCompositeConstruct %30 %166 %167 %168 %169 +%171 = OpMatrixTimesScalar %30 %170 %14 OpReturn OpFunctionEnd -%145 = OpFunction %2 None %117 -%144 = OpLabel -%142 = OpVariable %143 Function %7 -OpBranch %146 -%146 = OpLabel -%147 = OpLoad %8 %142 -%148 = OpIAdd %8 %147 %7 -OpStore %142 %148 -%149 = OpLoad %8 %142 -%150 = OpISub %8 %149 %7 -OpStore %142 %150 -%151 = OpLoad %8 %142 -%152 = OpLoad %8 %142 -%153 = OpIMul %8 %151 %152 -OpStore %142 %153 -%154 = OpLoad %8 %142 -%155 = OpLoad %8 %142 -%156 = OpSDiv %8 %154 %155 -OpStore %142 %156 -%157 = OpLoad %8 %142 -%158 = OpSMod %8 %157 %7 -OpStore %142 %158 -%159 = OpLoad %8 %142 -%160 = OpBitwiseXor %8 %159 %11 -OpStore %142 %160 -%161 = OpLoad %8 %142 -%162 = OpBitwiseAnd %8 %161 %11 -OpStore %142 %162 -%163 = OpLoad %8 %142 -%164 = OpIAdd %8 %163 %7 -OpStore %142 %164 -%165 = OpLoad %8 %142 -%166 = OpISub %8 %165 %7 -OpStore %142 %166 +%173 = OpFunction %2 None %152 +%172 = OpLabel +OpBranch %174 +%174 = OpLabel +%175 = OpLogicalOr %10 %9 %12 +%176 = OpLogicalAnd %10 %9 %12 OpReturn OpFunctionEnd -%168 = OpFunction %2 None %117 -%167 = OpLabel -OpBranch %169 -%169 = OpLabel -%170 = OpFunctionCall %19 %32 -%171 = OpFunctionCall %19 %57 -%172 = OpFunctionCall %8 %73 -%173 = OpVectorShuffle %22 %27 %27 0 1 2 -%174 = OpFunctionCall %22 %84 %173 -%175 = OpFunctionCall %4 %96 -%176 = OpFunctionCall %2 %116 -%177 = OpFunctionCall %2 %129 -%178 = OpFunctionCall %2 %138 -%179 = OpFunctionCall %2 %145 +%179 = OpFunction %2 None %152 +%178 = OpLabel +%177 = OpVariable %111 Function %7 +OpBranch %180 +%180 = OpLabel +%181 = OpLoad %8 %177 +%182 = OpIAdd %8 %181 %7 +OpStore %177 %182 +%183 = OpLoad %8 %177 +%184 = OpISub %8 %183 %7 +OpStore %177 %184 +%185 = OpLoad %8 %177 +%186 = OpLoad %8 %177 +%187 = OpIMul %8 %185 %186 +OpStore %177 %187 +%188 = OpLoad %8 %177 +%189 = OpLoad %8 %177 +%190 = OpSDiv %8 %188 %189 +OpStore %177 %190 +%191 = OpLoad %8 %177 +%192 = OpSMod %8 %191 %7 +OpStore %177 %192 +%193 = OpLoad %8 %177 +%194 = OpBitwiseXor %8 %193 %11 +OpStore %177 %194 +%195 = OpLoad %8 %177 +%196 = OpBitwiseAnd %8 %195 %11 +OpStore %177 %196 +%197 = OpLoad %8 %177 +%198 = OpIAdd %8 %197 %7 +OpStore %177 %198 +%199 = OpLoad %8 %177 +%200 = OpISub %8 %199 %7 +OpStore %177 %200 +OpReturn +OpFunctionEnd +%202 = OpFunction %2 None %152 +%201 = OpLabel +OpBranch %203 +%203 = OpLabel +%204 = OpFunctionCall %23 %45 +%205 = OpFunctionCall %23 %70 +%206 = OpFunctionCall %8 %86 +%207 = OpVectorShuffle %26 %34 %34 0 1 2 +%208 = OpFunctionCall %26 %97 %207 +%209 = OpFunctionCall %4 %128 +%210 = OpFunctionCall %2 %151 +%211 = OpFunctionCall %2 %164 +%212 = OpFunctionCall %2 %173 +%213 = OpFunctionCall %2 %179 OpReturn OpFunctionEnd \ No newline at end of file diff --git a/tests/out/wgsl/operators.wgsl b/tests/out/wgsl/operators.wgsl index 33e0ab1984..d2ce238570 100644 --- a/tests/out/wgsl/operators.wgsl +++ b/tests/out/wgsl/operators.wgsl @@ -40,12 +40,26 @@ fn bool_cast(x: vec3) -> vec3 { fn constructors() -> f32 { var foo: Foo; + var unnamed: bool = false; + var unnamed_1: i32 = 0; + var unnamed_2: u32 = 0u; + var unnamed_3: f32 = 0.0; + var unnamed_4: vec2 = vec2(0u, 0u); + var unnamed_5: mat2x2 = mat2x2(vec2(0.0, 0.0), vec2(0.0, 0.0)); + var unnamed_6: array = array(Foo(vec4(0.0, 0.0, 0.0, 0.0), 0), Foo(vec4(0.0, 0.0, 0.0, 0.0), 0), Foo(vec4(0.0, 0.0, 0.0, 0.0), 0)); + var unnamed_7: Foo = Foo(vec4(0.0, 0.0, 0.0, 0.0), 0); + var unnamed_8: vec2; + var unnamed_9: mat2x2; + var unnamed_10: array; foo = Foo(vec4(1.0), 1); let mat2comp = mat2x2(vec2(1.0, 0.0), vec2(0.0, 1.0)); let mat4comp = mat4x4(vec4(1.0, 0.0, 0.0, 0.0), vec4(0.0, 1.0, 0.0, 0.0), vec4(0.0, 0.0, 1.0, 0.0), vec4(0.0, 0.0, 0.0, 1.0)); - let _e39 = foo.a.x; - return _e39; + unnamed_8 = vec2(0u); + unnamed_9 = mat2x2(vec2(0.0), vec2(0.0)); + unnamed_10 = array(0, 1, 2, 3); + let _e70 = foo.a.x; + return _e70; } fn modulo() { diff --git a/tests/wgsl-errors.rs b/tests/wgsl-errors.rs index 7e6b3578ec..71ed5ac91a 100644 --- a/tests/wgsl-errors.rs +++ b/tests/wgsl-errors.rs @@ -157,10 +157,82 @@ fn bad_type_cast() { } "#, r#"error: cannot cast a vec2 to a i32 - ┌─ wgsl:3:27 + ┌─ wgsl:3:28 │ 3 │ return i32(vec2(0.0)); - │ ^^^^^^^^^^^^^^^^ cannot cast a vec2 to a i32 + │ ^^^^^^^^^^^^^^ cannot cast a vec2 to a i32 + +"#, + ); +} + +#[test] +fn type_not_constructible() { + check( + r#" + fn x() { + var _ = atomic(0); + } + "#, + r#"error: type `atomic` is not constructible + ┌─ wgsl:3:25 + │ +3 │ var _ = atomic(0); + │ ^^^^^^ type is not constructible + +"#, + ); +} + +#[test] +fn type_not_inferrable() { + check( + r#" + fn x() { + var _ = vec2(); + } + "#, + r#"error: type can't be inferred + ┌─ wgsl:3:25 + │ +3 │ var _ = vec2(); + │ ^^^^ type can't be inferred + +"#, + ); +} + +#[test] +fn unexpected_constructor_parameters() { + check( + r#" + fn x() { + var _ = i32(0, 1); + } + "#, + r#"error: unexpected components + ┌─ wgsl:3:31 + │ +3 │ var _ = i32(0, 1); + │ ^^ unexpected components + +"#, + ); +} + +#[test] +fn constructor_parameter_type_mismatch() { + check( + r#" + fn x() { + var _ = mat2x2(array(0, 1), vec2(2, 3)); + } + "#, + r#"error: invalid type for constructor component at index [0] + ┌─ wgsl:3:37 + │ +3 │ var _ = mat2x2(array(0, 1), vec2(2, 3)); + │ ^^^^^^^^^^^ invalid component type "#, );