| export const description = `Validation tests for 'for' statements'`; |
| |
| import { makeTestGroup } from '../../../../common/framework/test_group.js'; |
| import { keysOf } from '../../../../common/util/data_tables.js'; |
| import { ShaderValidationTest } from '../shader_validation_test.js'; |
| |
| import { kTestTypes } from './test_types.js'; |
| |
| export const g = makeTestGroup(ShaderValidationTest); |
| |
| g.test('condition_type') |
| .desc(`Tests that a 'for' condition must be a bool type`) |
| .params(u => u.combine('type', keysOf(kTestTypes))) |
| .fn(t => { |
| const type = kTestTypes[t.params.type]; |
| const code = ` |
| ${type.requires ? `enable ${type.requires};` : ''} |
| |
| ${type.header ?? ''} |
| |
| fn f() -> bool { |
| for (; ${type.value};) { |
| return true; |
| } |
| return false; |
| } |
| `; |
| |
| const pass = t.params.type === 'bool'; |
| t.expectCompileResult(pass, code); |
| }); |
| |
| const kTests = { |
| break: { wgsl: `for (;;) { break; }`, pass: true }, |
| |
| init_var: { wgsl: `for (var i = 1;;) { break; }`, pass: true }, |
| init_var_type: { wgsl: `for (var i : i32 = 1;;) { break; }`, pass: true }, |
| init_var_function: { wgsl: `for (var<function> i = 1;;) { break; }`, pass: true }, |
| init_var_function_type: { wgsl: `for (var<function> i : i32 = 1;;) { break; }`, pass: true }, |
| init_let: { wgsl: `for (let i = 1;;) { break; }`, pass: true }, |
| init_let_type: { wgsl: `for (let i : u32 = 1;;) { break; }`, pass: true }, |
| init_const: { wgsl: `for (const i = 1;;) { break; }`, pass: true }, |
| init_const_type: { wgsl: `for (const i : f32 = 1;;) { break; }`, pass: true }, |
| init_call: { wgsl: `for (x();;) { break; }`, pass: true }, |
| init_phony: { wgsl: `for (_ = v;;) { break; }`, pass: true }, |
| init_increment: { wgsl: `for (v++;;) { break; }`, pass: true }, |
| init_compound_assign: { wgsl: `for (v += 3;;) { break; }`, pass: true }, |
| |
| cond_true: { wgsl: `for (;true;) { break; }`, pass: true }, |
| |
| cont_call: { wgsl: `for (;;x()) { break; }`, pass: true }, |
| cont_phony: { wgsl: `for (;;_ = v) { break; }`, pass: true }, |
| cont_increment: { wgsl: `for (;;v++) { break; }`, pass: true }, |
| cont_compound_assign: { wgsl: `for (;;v += 3) { break; }`, pass: true }, |
| |
| init_cond: { wgsl: `for (var i = 1; i < 5;) {}`, pass: true }, |
| cond_cont: { wgsl: `for (;v < 5; v++) {}`, pass: true }, |
| init_cond_cont: { wgsl: `for (var i = 0; i < 5; i++) {}`, pass: true }, |
| init_shadow: { wgsl: `for (var f = 0; f < 5; f++) {}`, pass: true }, |
| |
| no_semicolon: { wgsl: `for () { break; }`, pass: false }, |
| one_semicolon: { wgsl: `for (;) { break; }`, pass: false }, |
| no_paren: { wgsl: `for ;; { break; }`, pass: false }, |
| empty: { wgsl: `for (;;) {}`, pass: false }, // note: fails due to behavior-analysis |
| init_expr: { wgsl: `for (true;;) { break; }`, pass: false }, |
| cond_stmt: { wgsl: `for (;var i = 0;) { break; }`, pass: false }, |
| cont_expr: { wgsl: `for (;;true) { break; }`, pass: false }, |
| cont_var: { wgsl: `for (;;var i = 1) { break; }`, pass: false }, |
| cont_var_type: { wgsl: `for (;;var i : i32 = 1) { break; }`, pass: false }, |
| cont_var_function: { wgsl: `for (;;var<function> i = 1) { break; }`, pass: false }, |
| cont_var_function_type: { wgsl: `for (;;var<function> i : i32 = 1) { break; }`, pass: false }, |
| cont_let: { wgsl: `for (;;let i = 1) { break; }`, pass: false }, |
| cont_let_type: { wgsl: `for (;;let i : u32 = 1) { break; }`, pass: false }, |
| }; |
| |
| g.test('parse') |
| .desc(`Test that 'for' statements are parsed correctly.`) |
| .params(u => u.combine('test', keysOf(kTests))) |
| .fn(t => { |
| const code = ` |
| fn f() { |
| var v = 1; |
| ${kTests[t.params.test].wgsl} |
| } |
| |
| fn x() {} |
| `; |
| t.expectCompileResult(kTests[t.params.test].pass, code); |
| }); |