export const description = `Validation tests for 'switch' statements'`; import { makeTestGroup } from '../../../../common/framework/test_group.js'; import { keysOf } from '../../../../common/util/data_tables.js'; import { Type } from '../../../util/conversion.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 'switch' condition must be of an integer 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 { switch ${type.value} { case 1: { return true; } default: { return false; } } } `; const pass = t.params.type === 'i32' || t.params.type === 'u32' || t.params.type === 'abstract-int'; t.expectCompileResult(pass, code); }); g.test('condition_type_match_case_type') .desc(`Tests that a 'switch' condition must have a common type with its case values`) .params(u => u .combine('cond_type', ['i32', 'u32', 'abstract-int'] as const) .combine('case_type', ['i32', 'u32', 'abstract-int'] as const) ) .fn(t => { const code = ` fn f() -> bool { switch ${Type[t.params.cond_type].create(1).wgsl()} { case ${Type[t.params.case_type].create(2).wgsl()}: { return true; } default: { return false; } } } `; const pass = t.params.cond_type === t.params.case_type || t.params.cond_type === 'abstract-int' || t.params.case_type === 'abstract-int'; t.expectCompileResult(pass, code); }); g.test('case_types_match') .desc(`Tests that switch case types must have a common type`) .params(u => u .combine('case_a_type', ['i32', 'u32', 'abstract-int'] as const) .combine('case_b_type', ['i32', 'u32', 'abstract-int'] as const) ) .fn(t => { const code = ` fn f() -> bool { switch 1 { case ${Type[t.params.case_a_type].create(1).wgsl()}: { return true; } case ${Type[t.params.case_b_type].create(2).wgsl()}: { return true; } default: { return false; } } } `; const pass = t.params.case_a_type === t.params.case_b_type || t.params.case_a_type === 'abstract-int' || t.params.case_b_type === 'abstract-int'; t.expectCompileResult(pass, code); }); const kTests = { L_default: { wgsl: `switch L { default {} }`, pass: true }, L_paren_default: { wgsl: `switch (L) { default {} }`, pass: true }, L_case_1_2_default: { wgsl: `switch L { case 1, 2 {} default {} }`, pass: true }, L_case_1_case_2_default: { wgsl: `switch L { case 1 {} case 2 {} default {} }`, pass: true }, L_case_1_colon_case_2_colon_default_colon: { wgsl: `switch L { case 1: {} case 2: {} default: {} }`, pass: true, }, L_case_1_colon_default_colon: { wgsl: `switch L { case 1: {} default: {} }`, pass: true }, L_case_1_colon_default: { wgsl: `switch L { case 1: {} default {} }`, pass: true }, L_case_1_default_2: { wgsl: `switch L { case 1, default, 2 {} }`, pass: true }, L_case_1_default_case_2: { wgsl: `switch L { case 1 {} default {} case 2 {} }`, pass: true }, L_case_1_default_colon: { wgsl: `switch L { case 1 {} default: {} }`, pass: true }, L_case_1_default: { wgsl: `switch L { case 1 {} default {} }`, pass: true }, L_case_2_1_default: { wgsl: `switch L { case 2, 1 {} default {} }`, pass: true }, L_case_2_case_1_default: { wgsl: `switch L { case 2 {} case 1 {} default {} }`, pass: true }, L_case_2_default_case_1: { wgsl: `switch L { case 2 {} default {} case 1 {} }`, pass: true }, L_case_builtin_default: { wgsl: `switch L { case max(1,2) {} default {} }`, pass: true }, L_case_C1_case_C2_default: { wgsl: `switch L { case C1 {} case C2 {} default {} }`, pass: true }, L_case_C1_default: { wgsl: `switch L { case C1 {} default {} }`, pass: true }, L_case_default_1: { wgsl: `switch L { case default, 1 {} }`, pass: true }, L_case_default_2_1: { wgsl: `switch L { case default, 2, 1 {} }`, pass: true }, L_case_default_2_case_1: { wgsl: `switch L { case default, 2 {} case 1 {} }`, pass: true }, L_case_default: { wgsl: `switch L { case default {} }`, pass: true }, L_case_expr_default: { wgsl: `switch L { case 1+1 {} default {} }`, pass: true }, L_default_break: { wgsl: `switch L { default { break; } }`, pass: true }, L_default_case_1_2: { wgsl: `switch L { default {} case 1, 2 {} }`, pass: true }, L_default_case_1_break: { wgsl: `switch L { default {} case 1 { break; } }`, pass: true }, L_default_case_1_case_2: { wgsl: `switch L { default {} case 1 {} case 2 {} }`, pass: true }, L_default_case_1_colon_break: { wgsl: `switch L { default {} case 1: { break; } }`, pass: true }, L_default_case_2_case_1: { wgsl: `switch L { default {} case 2 {} case 1 {} }`, pass: true }, L_default_colon_break: { wgsl: `switch L { default: { break; } }`, pass: true }, L_default_colon: { wgsl: `switch L { default: {} }`, pass: true }, L_no_block: { wgsl: `switch L`, pass: false }, L_empty_block: { wgsl: `switch L {}`, pass: false }, L_no_default: { wgsl: `switch L { case 1 {} }`, pass: false }, L_default_default: { wgsl: `switch L { default, default {} }`, pass: false }, L_default_block_default_block: { wgsl: `switch L { default {} default {} }`, pass: false }, L_case_1_case_1_default: { wgsl: `switch L { case 1 {} case 1 {} default {} }`, pass: false }, L_case_C1_case_C1_default: { wgsl: `switch L { case C1 {} case C1 {} default {} }`, pass: false }, L_case_C2_case_expr_default: { wgsl: `switch L { case C2 {} case 1+1 {} default {} }`, pass: false, }, L_default_1: { wgsl: `switch L { default, 1 {} }`, pass: false }, L_default_2_case_1: { wgsl: `switch L { default, 2 {} case 1 {} }`, pass: false }, no_cond: { wgsl: `switch { default{} }`, pass: false }, no_cond_no_block: { wgsl: `switch;`, pass: false }, lparen_L: { wgsl: `switch (L { default {}}`, pass: false }, L_lparen: { wgsl: `switch L) { default {}}`, pass: false }, lparen_L_lparen: { wgsl: `switch )L) { default {}}`, pass: false }, rparen_L_rparen: { wgsl: `switch (L( { default {}}`, pass: false }, }; g.test('parse') .desc(`Test that 'switch' statements are parsed correctly.`) .params(u => u.combine('test', keysOf(kTests))) .fn(t => { const code = ` fn f() { let L = 1; const C1 = 1; const C2 = 2; ${kTests[t.params.test].wgsl} }`; t.expectCompileResult(kTests[t.params.test].pass, code); });