internal/shader: add type checks for the builtin function mix

Updates #2184
This commit is contained in:
Hajime Hoshi 2022-08-19 01:16:11 +09:00
parent ec851a85f5
commit f3ea274d20
2 changed files with 68 additions and 4 deletions

View File

@ -450,7 +450,7 @@ func (cs *compileState) parseExpr(block *block, fname string, expr ast.Expr, mar
}) })
return nil, nil, stmts, true return nil, nil, stmts, true
case shaderir.Clamp: case shaderir.Clamp, shaderir.Mix:
// 3 arguments // 3 arguments
if len(args) != 3 { if len(args) != 3 {
cs.addError(e.Pos(), fmt.Sprintf("number of %s's arguments must be 3 but %d", callee.BuiltinFunc, len(args))) cs.addError(e.Pos(), fmt.Sprintf("number of %s's arguments must be 3 but %d", callee.BuiltinFunc, len(args)))
@ -468,10 +468,22 @@ func (cs *compileState) parseExpr(block *block, fname string, expr ast.Expr, mar
return nil, nil, nil, false return nil, nil, nil, false
} }
} }
switch callee.BuiltinFunc {
case shaderir.Clamp:
if (!argts[0].Equal(&argts[1]) || !argts[0].Equal(&argts[2])) && (argts[1].Main != shaderir.Float || argts[2].Main != shaderir.Float) { if (!argts[0].Equal(&argts[1]) || !argts[0].Equal(&argts[2])) && (argts[1].Main != shaderir.Float || argts[2].Main != shaderir.Float) {
cs.addError(e.Pos(), fmt.Sprintf("the second and the third arguments for %s must equal to the first argument %s or float but %s and %s", callee.BuiltinFunc, argts[0].String(), argts[1].String(), argts[2].String())) cs.addError(e.Pos(), fmt.Sprintf("the second and the third arguments for %s must equal to the first argument %s or float but %s and %s", callee.BuiltinFunc, argts[0].String(), argts[1].String(), argts[2].String()))
return nil, nil, nil, false return nil, nil, nil, false
} }
case shaderir.Mix:
if !argts[0].Equal(&argts[1]) {
cs.addError(e.Pos(), fmt.Sprintf("%s and %s don't match in argument to %s", argts[0].String(), argts[1].String(), callee.BuiltinFunc))
return nil, nil, nil, false
}
if !argts[0].Equal(&argts[2]) && argts[2].Main != shaderir.Float {
cs.addError(e.Pos(), fmt.Sprintf("the third arguments for %s must equal to the first/second argument %s or float but %s", callee.BuiltinFunc, argts[0].String(), argts[2].String()))
return nil, nil, nil, false
}
}
t = argts[0] t = argts[0]

View File

@ -1873,6 +1873,58 @@ func TestSyntaxBuiltinFuncClampType(t *testing.T) {
{stmt: "a := clamp(vec4(1), 1, vec4(1)); _ = a", err: true}, {stmt: "a := clamp(vec4(1), 1, vec4(1)); _ = a", err: true},
{stmt: "a := clamp(vec4(1), vec4(1), 1); _ = a", err: true}, {stmt: "a := clamp(vec4(1), vec4(1), 1); _ = a", err: true},
{stmt: "a := clamp(vec4(1), vec4(1), vec4(1)); _ = a", err: false}, {stmt: "a := clamp(vec4(1), vec4(1), vec4(1)); _ = a", err: false},
{stmt: "a := clamp(1, 1, 1, 1); _ = a", err: true},
}
for _, c := range cases {
stmt := c.stmt
src := fmt.Sprintf(`package main
func Fragment(position vec4, texCoord vec2, color vec4) vec4 {
%s
return position
}`, stmt)
_, err := compileToIR([]byte(src))
if err == nil && c.err {
t.Errorf("%s must return an error but does not", stmt)
} else if err != nil && !c.err {
t.Errorf("%s must not return nil but returned %v", stmt, err)
}
}
}
// Issue #2184
func TestSyntaxBuiltinFuncMixType(t *testing.T) {
cases := []struct {
stmt string
err bool
}{
{stmt: "a := mix(); _ = a", err: true},
{stmt: "a := mix(1); _ = a", err: true},
{stmt: "a := mix(false, false); _ = a", err: true},
{stmt: "a := mix(1, 1); _ = a", err: true},
{stmt: "a := mix(false, false, false); _ = a", err: true},
{stmt: "a := mix(1, 1, 1); _ = a", err: false},
{stmt: "a := mix(1.0, 1, 1); _ = a", err: false},
{stmt: "a := mix(1, 1.0, 1); _ = a", err: false},
{stmt: "a := mix(1, 1, 1.0); _ = a", err: false},
{stmt: "a := mix(1, vec2(1), 1); _ = a", err: true},
{stmt: "a := mix(1, 1, vec2(1)); _ = a", err: true},
{stmt: "a := mix(1, vec2(1), vec2(1)); _ = a", err: true},
{stmt: "a := mix(vec2(1), 1, 1); _ = a", err: true},
{stmt: "a := mix(vec2(1), 1, vec2(1)); _ = a", err: true},
{stmt: "a := mix(vec2(1), vec2(1), 1); _ = a", err: false}, // The thrid argument can be a float.
{stmt: "a := mix(vec2(1), vec2(1), vec2(1)); _ = a", err: false},
{stmt: "a := mix(vec2(1), vec2(1), vec3(1)); _ = a", err: true},
{stmt: "a := mix(vec3(1), 1, 1); _ = a", err: true},
{stmt: "a := mix(vec3(1), 1, vec3(1)); _ = a", err: true},
{stmt: "a := mix(vec3(1), vec3(1), 1); _ = a", err: false}, // The thrid argument can be a float.
{stmt: "a := mix(vec3(1), vec3(1), vec3(1)); _ = a", err: false},
{stmt: "a := mix(vec4(1), 1, 1); _ = a", err: true},
{stmt: "a := mix(vec4(1), 1, vec4(1)); _ = a", err: true},
{stmt: "a := mix(vec4(1), vec4(1), 1); _ = a", err: false}, // The thrid argument can be a float.
{stmt: "a := mix(vec4(1), vec4(1), vec4(1)); _ = a", err: false},
{stmt: "a := mix(1, 1, 1, 1); _ = a", err: true},
} }
for _, c := range cases { for _, c := range cases {