diff --git a/internal/shader/expr.go b/internal/shader/expr.go index f28fb9fe4..1451b17d9 100644 --- a/internal/shader/expr.go +++ b/internal/shader/expr.go @@ -430,9 +430,6 @@ func (cs *compileState) parseExpr(block *block, fname string, expr ast.Expr, mar return nil, nil, nil, false } t = shaderir.Type{Main: shaderir.Mat4} - case shaderir.Step: - // TODO: Check arg types. - t = argts[1] case shaderir.Smoothstep: // TODO: Check arg types. t = argts[2] @@ -478,7 +475,7 @@ func (cs *compileState) parseExpr(block *block, fname string, expr ast.Expr, mar t = argts[0] - case shaderir.Atan2, shaderir.Mod, shaderir.Min, shaderir.Max, shaderir.Distance, shaderir.Dot, shaderir.Cross, shaderir.Reflect: + case shaderir.Atan2, shaderir.Mod, shaderir.Min, shaderir.Max, shaderir.Step, shaderir.Distance, shaderir.Dot, shaderir.Cross, shaderir.Reflect: // 2 arguments if len(args) != 2 { cs.addError(e.Pos(), fmt.Sprintf("number of %s's arguments must be 2 but %d", callee.BuiltinFunc, len(args))) @@ -503,6 +500,11 @@ func (cs *compileState) parseExpr(block *block, fname string, expr ast.Expr, mar cs.addError(e.Pos(), fmt.Sprintf("the second argument for %s must equal to the first argument %s or float but %s", callee.BuiltinFunc, argts[0].String(), argts[1].String())) return nil, nil, nil, false } + case shaderir.Step: + if !argts[0].Equal(&argts[1]) && argts[0].Main != shaderir.Float { + cs.addError(e.Pos(), fmt.Sprintf("the first argument for %s must equal to the second argument %s or float but %s", callee.BuiltinFunc, argts[1].String(), argts[0].String())) + return nil, nil, nil, false + } case shaderir.Cross: for i := range argts { if argts[i].Main != shaderir.Vec3 { @@ -516,9 +518,12 @@ func (cs *compileState) parseExpr(block *block, fname string, expr ast.Expr, mar return nil, nil, nil, false } } - if callee.BuiltinFunc == shaderir.Distance || callee.BuiltinFunc == shaderir.Dot { + switch callee.BuiltinFunc { + case shaderir.Distance, shaderir.Dot: t = shaderir.Type{Main: shaderir.Float} - } else { + case shaderir.Step: + t = argts[1] + default: t = argts[0] } diff --git a/internal/shader/syntax_test.go b/internal/shader/syntax_test.go index b3593483f..40e516e80 100644 --- a/internal/shader/syntax_test.go +++ b/internal/shader/syntax_test.go @@ -1793,6 +1793,55 @@ func Fragment(position vec4, texCoord vec2, color vec4) vec4 { } } +// Issue #2184 +func TestSyntaxBuiltinFuncStepType(t *testing.T) { + cases := []struct { + stmt string + err bool + }{ + {stmt: "a := step(); _ = a", err: true}, + {stmt: "a := step(1); _ = a", err: true}, + {stmt: "a := step(false, false); _ = a", err: true}, + {stmt: "a := step(1, 1); _ = a", err: false}, + {stmt: "a := step(1.0, 1); _ = a", err: false}, + {stmt: "a := step(1, 1.0); _ = a", err: false}, + {stmt: "a := step(int(1), int(1)); _ = a", err: true}, + {stmt: "a := step(1, vec2(1)); _ = a", err: false}, // The first argument can be a scalar. + {stmt: "a := step(1, vec3(1)); _ = a", err: false}, // The first argument can be a scalar. + {stmt: "a := step(1, vec4(1)); _ = a", err: false}, // The first argument can be a scalar. + {stmt: "a := step(vec2(1), 1); _ = a", err: true}, + {stmt: "a := step(vec2(1), vec2(1)); _ = a", err: false}, + {stmt: "a := step(vec2(1), vec3(1)); _ = a", err: true}, + {stmt: "a := step(vec2(1), vec4(1)); _ = a", err: true}, + {stmt: "a := step(vec3(1), 1); _ = a", err: true}, + {stmt: "a := step(vec3(1), vec2(1)); _ = a", err: true}, + {stmt: "a := step(vec3(1), vec3(1)); _ = a", err: false}, + {stmt: "a := step(vec3(1), vec4(1)); _ = a", err: true}, + {stmt: "a := step(vec4(1), 1); _ = a", err: true}, + {stmt: "a := step(vec4(1), vec2(1)); _ = a", err: true}, + {stmt: "a := step(vec4(1), vec3(1)); _ = a", err: true}, + {stmt: "a := step(vec4(1), vec4(1)); _ = a", err: false}, + {stmt: "a := step(mat2(1), mat2(1)); _ = a", err: true}, + {stmt: "a := step(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 TestSyntaxBuiltinFuncClampType(t *testing.T) { cases := []struct {