[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
This commit is contained in:
Teodor Tanasoaia
2022-03-30 07:51:54 +02:00
committed by GitHub
parent 012f2a6b2e
commit cfcf625019
9 changed files with 1174 additions and 357 deletions

View File

@@ -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<Type>,
size: ArraySize,
stride: u32,
},
Struct(Handle<Type>),
}
impl ConstructorType {
fn to_type_resolution(&self) -> Option<TypeResolution> {
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<Type>, constants: &Arena<Constant>) -> 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<Type>,
const_arena: &mut Arena<Constant>,
) -> Result<Option<ConstructorType>, 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<Option<Handle<Expression>>, 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<Expression>,
span: Span,
ty: &'a TypeInner,
},
Many {
components: Vec<Handle<Expression>>,
spans: Vec<Span>,
first_component_ty: &'a TypeInner,
},
}
impl<'a> Components<'a> {
fn into_components_vec(self) -> Vec<Handle<Expression>> {
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)))
}

View File

@@ -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<crate::Type>,
) -> Option<Handle<crate::Constant>> {
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::<Option<_>>()?,
}
}
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::<Option<_>>()?,
}
}
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::<Option<_>>()?,
}
}
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::<Option<_>>()?,
}
}
_ => 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<Option<Handle<crate::Expression>>, 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));

View File

@@ -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<u32>();
var _ = mat2x2<f32>();
var _ = array<Foo, 3>();
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;
}

View File

@@ -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() {

View File

@@ -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()

View File

@@ -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(

View File

@@ -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

View File

@@ -40,12 +40,26 @@ fn bool_cast(x: vec3<f32>) -> vec3<f32> {
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<u32> = vec2<u32>(0u, 0u);
var unnamed_5: mat2x2<f32> = mat2x2<f32>(vec2<f32>(0.0, 0.0), vec2<f32>(0.0, 0.0));
var unnamed_6: array<Foo,3> = array<Foo,3>(Foo(vec4<f32>(0.0, 0.0, 0.0, 0.0), 0), Foo(vec4<f32>(0.0, 0.0, 0.0, 0.0), 0), Foo(vec4<f32>(0.0, 0.0, 0.0, 0.0), 0));
var unnamed_7: Foo = Foo(vec4<f32>(0.0, 0.0, 0.0, 0.0), 0);
var unnamed_8: vec2<u32>;
var unnamed_9: mat2x2<f32>;
var unnamed_10: array<i32,4u>;
foo = Foo(vec4<f32>(1.0), 1);
let mat2comp = mat2x2<f32>(vec2<f32>(1.0, 0.0), vec2<f32>(0.0, 1.0));
let mat4comp = mat4x4<f32>(vec4<f32>(1.0, 0.0, 0.0, 0.0), vec4<f32>(0.0, 1.0, 0.0, 0.0), vec4<f32>(0.0, 0.0, 1.0, 0.0), vec4<f32>(0.0, 0.0, 0.0, 1.0));
let _e39 = foo.a.x;
return _e39;
unnamed_8 = vec2<u32>(0u);
unnamed_9 = mat2x2<f32>(vec2<f32>(0.0), vec2<f32>(0.0));
unnamed_10 = array<i32,4u>(0, 1, 2, 3);
let _e70 = foo.a.x;
return _e70;
}
fn modulo() {

View File

@@ -157,10 +157,82 @@ fn bad_type_cast() {
}
"#,
r#"error: cannot cast a vec2<f32> to a i32
┌─ wgsl:3:27
┌─ wgsl:3:28
3 │ return i32(vec2<f32>(0.0));
^^^^^^^^^^^^^^^^ cannot cast a vec2<f32> to a i32
^^^^^^^^^^^^^^ cannot cast a vec2<f32> to a i32
"#,
);
}
#[test]
fn type_not_constructible() {
check(
r#"
fn x() {
var _ = atomic<i32>(0);
}
"#,
r#"error: type `atomic` is not constructible
┌─ wgsl:3:25
3 │ var _ = atomic<i32>(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<f32>(array(0, 1), vec2(2, 3));
}
"#,
r#"error: invalid type for constructor component at index [0]
┌─ wgsl:3:37
3 │ var _ = mat2x2<f32>(array(0, 1), vec2(2, 3));
│ ^^^^^^^^^^^ invalid component type
"#,
);