mirror of
https://github.com/gfx-rs/wgpu.git
synced 2026-04-22 03:02:01 -04:00
[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:
649
src/front/wgsl/construction.rs
Normal file
649
src/front/wgsl/construction.rs
Normal 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)))
|
||||
}
|
||||
@@ -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));
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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() {
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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(
|
||||
|
||||
@@ -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
|
||||
@@ -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() {
|
||||
|
||||
@@ -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
|
||||
|
||||
"#,
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user