2021-05-13 17:21:43 +00:00
|
|
|
//! Tests for the WGSL front end.
|
|
|
|
#![cfg(feature = "wgsl-in")]
|
|
|
|
|
2021-04-14 18:20:48 +00:00
|
|
|
fn check(input: &str, snapshot: &str) {
|
|
|
|
let output = naga::front::wgsl::parse_str(input)
|
|
|
|
.expect_err("expected parser error")
|
2021-05-02 04:49:02 +00:00
|
|
|
.emit_to_string(input);
|
2021-04-14 18:20:48 +00:00
|
|
|
if output != snapshot {
|
|
|
|
for diff in diff::lines(&output, snapshot) {
|
|
|
|
match diff {
|
|
|
|
diff::Result::Left(l) => println!("-{}", l),
|
|
|
|
diff::Result::Both(l, _) => println!(" {}", l),
|
|
|
|
diff::Result::Right(r) => println!("+{}", r),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
panic!("Error snapshot failed");
|
|
|
|
}
|
2021-02-13 20:54:31 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn function_without_identifier() {
|
2021-04-14 18:20:48 +00:00
|
|
|
check(
|
2021-02-13 20:54:31 +00:00
|
|
|
"fn () {}",
|
2021-04-14 23:22:40 +00:00
|
|
|
r###"error: expected identifier, found '('
|
2021-04-14 18:20:48 +00:00
|
|
|
┌─ wgsl:1:4
|
|
|
|
│
|
|
|
|
1 │ fn () {}
|
|
|
|
│ ^ expected identifier
|
2021-02-28 04:22:34 +00:00
|
|
|
|
2021-04-14 18:20:48 +00:00
|
|
|
"###,
|
2021-02-13 20:54:31 +00:00
|
|
|
);
|
|
|
|
}
|
2021-03-04 03:28:54 +00:00
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn invalid_integer() {
|
2021-04-14 18:20:48 +00:00
|
|
|
check(
|
2021-03-07 05:03:05 +00:00
|
|
|
"fn foo([location(1.)] x: i32) {}",
|
2021-04-14 23:22:40 +00:00
|
|
|
r###"error: expected identifier, found '['
|
2021-04-14 18:20:48 +00:00
|
|
|
┌─ wgsl:1:8
|
|
|
|
│
|
|
|
|
1 │ fn foo([location(1.)] x: i32) {}
|
|
|
|
│ ^ expected identifier
|
2021-03-04 03:28:54 +00:00
|
|
|
|
2021-04-14 18:20:48 +00:00
|
|
|
"###,
|
2021-03-04 03:28:54 +00:00
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn invalid_float() {
|
2021-04-14 18:20:48 +00:00
|
|
|
check(
|
2021-04-11 04:35:03 +00:00
|
|
|
"let scale: f32 = 1.1.;",
|
2021-04-14 23:22:40 +00:00
|
|
|
r###"error: expected floating-point literal, found `1.1.`
|
2021-04-14 18:20:48 +00:00
|
|
|
┌─ wgsl:1:18
|
|
|
|
│
|
|
|
|
1 │ let scale: f32 = 1.1.;
|
|
|
|
│ ^^^^ expected floating-point literal
|
Improve wgsl lexer error messages.
Better errors for Unexpected, BadInteger, BadFloat, BadTexture, BadTypeCast, UnknownScalarType, UnknownStorageClass, UnknownAttribute, UnknownBuiltin, UnknownShaderStage, UnknownStorageFormat and UnknownConservativeDepth, ZeroStride, ZeroSizeOrAlign and UnknownType.
Also adds lexer::capture_span.
Also fixes some validation for texture sample types and and issue that cauld cause e.g. the type `f33` to be parsed as `f32`.
2021-05-25 14:58:17 +00:00
|
|
|
│
|
|
|
|
= note: invalid float literal
|
2021-03-04 03:28:54 +00:00
|
|
|
|
2021-04-14 18:20:48 +00:00
|
|
|
"###,
|
2021-03-04 03:28:54 +00:00
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn invalid_scalar_width() {
|
2021-04-14 18:20:48 +00:00
|
|
|
check(
|
2021-04-11 04:35:03 +00:00
|
|
|
"let scale: f32 = 1.1f1000;",
|
2021-04-14 23:22:40 +00:00
|
|
|
r###"error: invalid width of `1000` for literal
|
2021-04-14 18:20:48 +00:00
|
|
|
┌─ wgsl:1:18
|
|
|
|
│
|
|
|
|
1 │ let scale: f32 = 1.1f1000;
|
|
|
|
│ ^^^^^^^^ invalid width
|
|
|
|
│
|
Improve wgsl lexer error messages.
Better errors for Unexpected, BadInteger, BadFloat, BadTexture, BadTypeCast, UnknownScalarType, UnknownStorageClass, UnknownAttribute, UnknownBuiltin, UnknownShaderStage, UnknownStorageFormat and UnknownConservativeDepth, ZeroStride, ZeroSizeOrAlign and UnknownType.
Also adds lexer::capture_span.
Also fixes some validation for texture sample types and and issue that cauld cause e.g. the type `f33` to be parsed as `f32`.
2021-05-25 14:58:17 +00:00
|
|
|
= note: valid widths are 8, 16, 32, 64
|
|
|
|
|
|
|
|
"###,
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn invalid_texture_sample_type() {
|
|
|
|
check(
|
|
|
|
"let x: texture_2d<f16>;",
|
|
|
|
r###"error: texture sample type must be one of f32, i32 or u32, but found f16
|
|
|
|
┌─ wgsl:1:19
|
|
|
|
│
|
|
|
|
1 │ let x: texture_2d<f16>;
|
|
|
|
│ ^^^ must be one of f32, i32 or u32
|
2021-03-04 03:28:54 +00:00
|
|
|
|
2021-04-14 18:20:48 +00:00
|
|
|
"###,
|
2021-03-04 03:28:54 +00:00
|
|
|
);
|
|
|
|
}
|
2021-05-13 17:29:03 +00:00
|
|
|
|
2021-05-17 23:19:33 +00:00
|
|
|
#[test]
|
|
|
|
fn unknown_identifier() {
|
|
|
|
check(
|
|
|
|
r###"
|
|
|
|
fn f(x: f32) -> f32 {
|
|
|
|
return x * schmoo;
|
|
|
|
}
|
|
|
|
"###,
|
2021-05-18 18:20:25 +00:00
|
|
|
r###"error: no definition in scope for identifier: 'schmoo'
|
2021-05-17 23:19:33 +00:00
|
|
|
┌─ wgsl:3:30
|
|
|
|
│
|
|
|
|
3 │ return x * schmoo;
|
|
|
|
│ ^^^^^^ unknown identifier
|
|
|
|
|
|
|
|
"###,
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2021-05-27 22:02:38 +00:00
|
|
|
#[test]
|
|
|
|
fn negative_index() {
|
|
|
|
check(
|
|
|
|
r#"
|
|
|
|
fn main() -> f32 {
|
|
|
|
let a = array<f32, 3>(0., 1., 2.);
|
|
|
|
return a[-1];
|
|
|
|
}
|
|
|
|
"#,
|
|
|
|
r#"error: expected non-negative integer constant expression, found `-1`
|
|
|
|
┌─ wgsl:4:26
|
|
|
|
│
|
|
|
|
4 │ return a[-1];
|
|
|
|
│ ^^ expected non-negative integer
|
|
|
|
|
|
|
|
"#,
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2021-07-04 03:12:22 +00:00
|
|
|
#[test]
|
|
|
|
fn bad_texture() {
|
|
|
|
check(
|
|
|
|
r#"
|
|
|
|
[[group(0), binding(0)]] var sampler : sampler;
|
|
|
|
|
|
|
|
[[stage(fragment)]]
|
|
|
|
fn main() -> [[location(0)]] vec4<f32> {
|
|
|
|
let a = 3;
|
|
|
|
return textureSample(a, sampler, vec2<f32>(0.0));
|
|
|
|
}
|
|
|
|
"#,
|
|
|
|
r#"error: expected an image, but found 'a' which is not an image
|
|
|
|
┌─ wgsl:7:38
|
|
|
|
│
|
|
|
|
7 │ return textureSample(a, sampler, vec2<f32>(0.0));
|
|
|
|
│ ^ not an image
|
|
|
|
|
|
|
|
"#
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn bad_type_cast() {
|
|
|
|
check(
|
|
|
|
r#"
|
|
|
|
fn x() -> i32 {
|
|
|
|
return i32(vec2<f32>(0.0));
|
|
|
|
}
|
|
|
|
"#,
|
|
|
|
r#"error: cannot cast a vec2<f32> to a i32
|
|
|
|
┌─ wgsl:3:27
|
|
|
|
│
|
|
|
|
3 │ return i32(vec2<f32>(0.0));
|
|
|
|
│ ^^^^^^^^^^^^^^^^ cannot cast a vec2<f32> to a i32
|
|
|
|
|
|
|
|
"#,
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn bad_texture_sample_type() {
|
|
|
|
check(
|
|
|
|
r#"
|
|
|
|
[[group(0), binding(0)]] var sampler : sampler;
|
|
|
|
[[group(0), binding(1)]] var texture : texture_2d<bool>;
|
|
|
|
|
|
|
|
[[stage(fragment)]]
|
|
|
|
fn main() -> [[location(0)]] vec4<f32> {
|
|
|
|
return textureSample(texture, sampler, vec2<f32>(0.0));
|
|
|
|
}
|
|
|
|
"#,
|
|
|
|
r#"error: texture sample type must be one of f32, i32 or u32, but found bool
|
|
|
|
┌─ wgsl:3:63
|
|
|
|
│
|
|
|
|
3 │ [[group(0), binding(1)]] var texture : texture_2d<bool>;
|
|
|
|
│ ^^^^ must be one of f32, i32 or u32
|
|
|
|
|
|
|
|
"#
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn bad_for_initializer() {
|
|
|
|
check(
|
|
|
|
r#"
|
|
|
|
fn x() {
|
|
|
|
for ({};;) {}
|
|
|
|
}
|
|
|
|
"#,
|
|
|
|
r#"error: for(;;) initializer is not an assignment or a function call: '{}'
|
|
|
|
┌─ wgsl:3:22
|
|
|
|
│
|
|
|
|
3 │ for ({};;) {}
|
|
|
|
│ ^^ not an assignment or function call
|
|
|
|
|
|
|
|
"#,
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn unknown_storage_class() {
|
|
|
|
check(
|
|
|
|
r#"
|
|
|
|
[[group(0), binding(0)]] var<bad> texture: texture_2d<f32>;
|
|
|
|
"#,
|
|
|
|
r#"error: unknown storage class: 'bad'
|
|
|
|
┌─ wgsl:2:42
|
|
|
|
│
|
|
|
|
2 │ [[group(0), binding(0)]] var<bad> texture: texture_2d<f32>;
|
|
|
|
│ ^^^ unknown storage class
|
|
|
|
|
|
|
|
"#,
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn unknown_attribute() {
|
|
|
|
check(
|
|
|
|
r#"
|
|
|
|
[[a]]
|
|
|
|
fn x() {}
|
|
|
|
"#,
|
|
|
|
r#"error: unknown attribute: 'a'
|
|
|
|
┌─ wgsl:2:15
|
|
|
|
│
|
|
|
|
2 │ [[a]]
|
|
|
|
│ ^ unknown attribute
|
|
|
|
|
|
|
|
"#
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2021-05-13 17:29:03 +00:00
|
|
|
macro_rules! check_validation_error {
|
2021-05-26 16:11:18 +00:00
|
|
|
// We want to support an optional guard expression after the pattern, so
|
|
|
|
// that we can check values we can't match against, like strings.
|
|
|
|
// Unfortunately, we can't simply include `$( if $guard:expr )?` in the
|
|
|
|
// pattern, because Rust treats `?` as a repetition operator, and its count
|
|
|
|
// (0 or 1) will not necessarily match `$source`.
|
2021-05-13 17:29:03 +00:00
|
|
|
( $( $source:literal ),* : $pattern:pat ) => {
|
2021-05-26 16:11:18 +00:00
|
|
|
check_validation_error!( @full $( $source ),* : $pattern if true ; "");
|
|
|
|
};
|
|
|
|
|
|
|
|
( $( $source:literal ),* : $pattern:pat if $guard:expr ) => {
|
|
|
|
check_validation_error!( @full $( $source ),* : $pattern if $guard ; stringify!( $guard ) );
|
|
|
|
};
|
|
|
|
|
|
|
|
( @full $( $source:literal ),* : $pattern:pat if $guard:expr ; $guard_string:expr ) => {
|
2021-05-13 17:29:03 +00:00
|
|
|
$(
|
|
|
|
let error = validation_error($source);
|
2021-05-26 16:11:18 +00:00
|
|
|
if ! matches!(&error, $pattern if $guard) {
|
2021-05-13 17:29:03 +00:00
|
|
|
eprintln!("validation error does not match pattern:\n\
|
2021-05-27 21:01:40 +00:00
|
|
|
source code: {}\n\
|
|
|
|
\n\
|
|
|
|
actual result:\n\
|
2021-05-26 16:11:18 +00:00
|
|
|
{:#?}\n\
|
|
|
|
\n\
|
|
|
|
expected match for pattern:\n\
|
|
|
|
{}{}",
|
2021-05-27 21:01:40 +00:00
|
|
|
stringify!($source),
|
2021-05-26 16:11:18 +00:00
|
|
|
error,
|
|
|
|
stringify!($pattern),
|
|
|
|
$guard_string);
|
2021-05-13 17:29:03 +00:00
|
|
|
panic!("validation error does not match pattern");
|
|
|
|
}
|
|
|
|
)*
|
2021-05-26 16:11:18 +00:00
|
|
|
};
|
2021-05-13 17:29:03 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
fn validation_error(source: &str) -> Result<naga::valid::ModuleInfo, naga::valid::ValidationError> {
|
2021-05-27 22:02:38 +00:00
|
|
|
let module = match naga::front::wgsl::parse_str(source) {
|
|
|
|
Ok(module) => module,
|
|
|
|
Err(err) => {
|
|
|
|
eprintln!("WGSL parse failed:");
|
|
|
|
panic!("{}", err.emit_to_string(source));
|
|
|
|
}
|
|
|
|
};
|
2021-05-13 17:29:03 +00:00
|
|
|
naga::valid::Validator::new(
|
|
|
|
naga::valid::ValidationFlags::all(),
|
|
|
|
naga::valid::Capabilities::empty(),
|
|
|
|
)
|
|
|
|
.validate(&module)
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn invalid_arrays() {
|
|
|
|
check_validation_error! {
|
|
|
|
"type Bad = array<array<f32>, 4>;",
|
|
|
|
"type Bad = array<sampler, 4>;",
|
|
|
|
"type Bad = array<texture_2d<f32>, 4>;":
|
|
|
|
Err(naga::valid::ValidationError::Type {
|
|
|
|
error: naga::valid::TypeError::InvalidArrayBaseType(_),
|
|
|
|
..
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
check_validation_error! {
|
|
|
|
r#"
|
|
|
|
[[block]] struct Block { value: f32; };
|
|
|
|
type Bad = array<Block, 4>;
|
|
|
|
"#:
|
|
|
|
Err(naga::valid::ValidationError::Type {
|
2021-05-16 04:46:46 +00:00
|
|
|
error: naga::valid::TypeError::NestedTopLevel,
|
2021-05-13 17:29:03 +00:00
|
|
|
..
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
check_validation_error! {
|
|
|
|
r#"
|
|
|
|
type Bad = [[stride(2)]] array<f32, 4>;
|
|
|
|
"#:
|
|
|
|
Err(naga::valid::ValidationError::Type {
|
|
|
|
error: naga::valid::TypeError::InsufficientArrayStride { stride: 2, base_size: 4 },
|
|
|
|
..
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
check_validation_error! {
|
|
|
|
"type Bad = array<f32, true>;",
|
|
|
|
r#"
|
|
|
|
let length: f32 = 2.718;
|
|
|
|
type Bad = array<f32, length>;
|
|
|
|
"#:
|
|
|
|
Err(naga::valid::ValidationError::Type {
|
|
|
|
error: naga::valid::TypeError::InvalidArraySizeConstant(_),
|
|
|
|
..
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn invalid_structs() {
|
|
|
|
check_validation_error! {
|
|
|
|
"struct Bad { data: sampler; };",
|
|
|
|
"struct Bad { data: texture_2d<f32>; };":
|
|
|
|
Err(naga::valid::ValidationError::Type {
|
|
|
|
error: naga::valid::TypeError::InvalidData(_),
|
|
|
|
..
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
check_validation_error! {
|
|
|
|
"[[block]] struct Bad { data: ptr<storage, f32>; };":
|
|
|
|
Err(naga::valid::ValidationError::Type {
|
|
|
|
error: naga::valid::TypeError::InvalidBlockType(_),
|
|
|
|
..
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
check_validation_error! {
|
|
|
|
"struct Bad { data: array<f32>; other: f32; };":
|
|
|
|
Err(naga::valid::ValidationError::Type {
|
|
|
|
error: naga::valid::TypeError::InvalidDynamicArray(_, _),
|
|
|
|
..
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
2021-05-21 20:11:35 +00:00
|
|
|
|
2021-05-26 16:11:18 +00:00
|
|
|
#[test]
|
|
|
|
fn invalid_functions() {
|
|
|
|
check_validation_error! {
|
2021-05-27 21:01:40 +00:00
|
|
|
"fn unacceptable_unsized(arg: array<f32>) { }",
|
|
|
|
"fn unacceptable_unsized(arg: ptr<storage, array<f32>>) { }",
|
|
|
|
"
|
|
|
|
struct Unsized { data: array<f32>; };
|
|
|
|
fn unacceptable_unsized(arg: Unsized) { }
|
|
|
|
":
|
2021-05-26 16:11:18 +00:00
|
|
|
Err(naga::valid::ValidationError::Function {
|
|
|
|
name: function_name,
|
|
|
|
error: naga::valid::FunctionError::InvalidArgumentType {
|
|
|
|
index: 0,
|
|
|
|
name: argument_name,
|
|
|
|
},
|
|
|
|
..
|
|
|
|
})
|
2021-05-27 21:01:40 +00:00
|
|
|
if function_name == "unacceptable_unsized" && argument_name == "arg"
|
|
|
|
}
|
|
|
|
|
|
|
|
// A *valid* way to pass an unsized value.
|
|
|
|
check_validation_error! {
|
|
|
|
"
|
|
|
|
struct Unsized { data: array<f32>; };
|
|
|
|
fn acceptable_ptr_to_unsized(okay: ptr<storage, Unsized>) { }
|
|
|
|
":
|
|
|
|
Ok(_)
|
2021-05-26 16:11:18 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-05-21 20:11:35 +00:00
|
|
|
#[test]
|
|
|
|
fn missing_bindings() {
|
|
|
|
check_validation_error! {
|
|
|
|
"
|
|
|
|
[[stage(vertex)]]
|
|
|
|
fn vertex(input: vec4<f32>) -> [[location(0)]] vec4<f32> {
|
|
|
|
return input;
|
|
|
|
}
|
|
|
|
":
|
|
|
|
Err(naga::valid::ValidationError::EntryPoint {
|
|
|
|
stage: naga::ShaderStage::Vertex,
|
|
|
|
error: naga::valid::EntryPointError::Argument(
|
|
|
|
0,
|
|
|
|
naga::valid::VaryingError::MissingBinding,
|
|
|
|
),
|
|
|
|
..
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
check_validation_error! {
|
|
|
|
"
|
|
|
|
[[stage(vertex)]]
|
|
|
|
fn vertex([[location(0)]] input: vec4<f32>, more_input: f32) -> [[location(0)]] vec4<f32> {
|
|
|
|
return input + more_input;
|
|
|
|
}
|
|
|
|
":
|
|
|
|
Err(naga::valid::ValidationError::EntryPoint {
|
|
|
|
stage: naga::ShaderStage::Vertex,
|
|
|
|
error: naga::valid::EntryPointError::Argument(
|
|
|
|
1,
|
|
|
|
naga::valid::VaryingError::MissingBinding,
|
|
|
|
),
|
|
|
|
..
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
check_validation_error! {
|
|
|
|
"
|
|
|
|
[[stage(vertex)]]
|
|
|
|
fn vertex([[location(0)]] input: vec4<f32>) -> vec4<f32> {
|
|
|
|
return input;
|
|
|
|
}
|
|
|
|
":
|
|
|
|
Err(naga::valid::ValidationError::EntryPoint {
|
|
|
|
stage: naga::ShaderStage::Vertex,
|
|
|
|
error: naga::valid::EntryPointError::Result(
|
|
|
|
naga::valid::VaryingError::MissingBinding,
|
|
|
|
),
|
|
|
|
..
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
check_validation_error! {
|
|
|
|
"
|
|
|
|
struct VertexIn {
|
|
|
|
[[location(0)]] pos: vec4<f32>;
|
|
|
|
uv: vec2<f32>;
|
|
|
|
};
|
|
|
|
|
|
|
|
[[stage(vertex)]]
|
|
|
|
fn vertex(input: VertexIn) -> [[location(0)]] vec4<f32> {
|
|
|
|
return input.pos;
|
|
|
|
}
|
|
|
|
":
|
|
|
|
Err(naga::valid::ValidationError::EntryPoint {
|
|
|
|
stage: naga::ShaderStage::Vertex,
|
|
|
|
error: naga::valid::EntryPointError::Argument(
|
|
|
|
0,
|
|
|
|
naga::valid::VaryingError::MemberMissingBinding(1),
|
|
|
|
),
|
|
|
|
..
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
2021-06-04 16:57:20 +00:00
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn invalid_access() {
|
|
|
|
check_validation_error! {
|
|
|
|
"
|
|
|
|
fn array_by_value(a: array<i32, 5>, i: i32) -> i32 {
|
|
|
|
return a[i];
|
|
|
|
}
|
|
|
|
",
|
|
|
|
"
|
|
|
|
fn matrix_by_value(m: mat4x4<f32>, i: i32) -> vec4<f32> {
|
|
|
|
return m[i];
|
|
|
|
}
|
|
|
|
":
|
|
|
|
Err(naga::valid::ValidationError::Function {
|
|
|
|
error: naga::valid::FunctionError::Expression {
|
|
|
|
error: naga::valid::ExpressionError::IndexMustBeConstant(_),
|
|
|
|
..
|
|
|
|
},
|
|
|
|
..
|
|
|
|
})
|
|
|
|
}
|
2021-05-27 22:02:38 +00:00
|
|
|
|
|
|
|
check_validation_error! {
|
|
|
|
r#"
|
|
|
|
fn main() -> f32 {
|
|
|
|
let a = array<f32, 3>(0., 1., 2.);
|
|
|
|
return a[3];
|
|
|
|
}
|
|
|
|
"#:
|
|
|
|
Err(naga::valid::ValidationError::Function {
|
|
|
|
error: naga::valid::FunctionError::Expression {
|
|
|
|
error: naga::valid::ExpressionError::IndexOutOfBounds(_, _),
|
|
|
|
..
|
|
|
|
},
|
|
|
|
..
|
|
|
|
})
|
|
|
|
}
|
2021-06-04 16:57:20 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn valid_access() {
|
|
|
|
check_validation_error! {
|
|
|
|
"
|
|
|
|
fn vector_by_value(v: vec4<i32>, i: i32) -> i32 {
|
|
|
|
return v[i];
|
|
|
|
}
|
|
|
|
",
|
|
|
|
"
|
|
|
|
fn matrix_dynamic(m: mat4x4<f32>, i: i32, j: i32) -> f32 {
|
|
|
|
var temp: mat4x4<f32> = m;
|
|
|
|
// Dynamically indexing the column vector applies
|
|
|
|
// `Access` to a `ValuePointer`.
|
|
|
|
return temp[i][j];
|
|
|
|
}
|
|
|
|
":
|
|
|
|
Ok(_)
|
|
|
|
}
|
|
|
|
}
|
2021-05-27 21:01:40 +00:00
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn invalid_local_vars() {
|
|
|
|
check_validation_error! {
|
|
|
|
"
|
|
|
|
struct Unsized { data: array<f32>; };
|
|
|
|
fn local_ptr_dynamic_array(okay: ptr<storage, Unsized>) {
|
|
|
|
var not_okay: ptr<storage, array<f32>> = okay.data;
|
|
|
|
}
|
|
|
|
":
|
|
|
|
Err(naga::valid::ValidationError::Function {
|
|
|
|
error: naga::valid::FunctionError::LocalVariable {
|
|
|
|
name: local_var_name,
|
|
|
|
error: naga::valid::LocalVariableError::InvalidType(_),
|
|
|
|
..
|
|
|
|
},
|
|
|
|
..
|
|
|
|
})
|
|
|
|
if local_var_name == "not_okay"
|
|
|
|
}
|
|
|
|
}
|