blob: 31e49dfd35f95a252a20d14dfcd3cca19472a69b [file] [log] [blame]
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);
});