diff --git a/internal/shader/expr.go b/internal/shader/expr.go index 1451b17d9..c9461e03c 100644 --- a/internal/shader/expr.go +++ b/internal/shader/expr.go @@ -450,7 +450,7 @@ func (cs *compileState) parseExpr(block *block, fname string, expr ast.Expr, mar }) return nil, nil, stmts, true - case shaderir.Clamp: + case shaderir.Clamp, shaderir.Mix: // 3 arguments if len(args) != 3 { cs.addError(e.Pos(), fmt.Sprintf("number of %s's arguments must be 3 but %d", callee.BuiltinFunc, len(args))) @@ -468,9 +468,21 @@ func (cs *compileState) parseExpr(block *block, fname string, expr ast.Expr, mar return nil, nil, nil, false } } - 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())) - 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) { + 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 + } + 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] diff --git a/internal/shader/syntax_test.go b/internal/shader/syntax_test.go index 40e516e80..64f7989fe 100644 --- a/internal/shader/syntax_test.go +++ b/internal/shader/syntax_test.go @@ -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), vec4(1), 1); _ = a", err: true}, {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 {