From 85d54515cdcf960d7e1cf48eaac8b2e32249bf59 Mon Sep 17 00:00:00 2001 From: Hajime Hoshi Date: Fri, 19 Aug 2022 17:34:03 +0900 Subject: [PATCH] internal/shader: check types for && and || correctly Updates #2256 --- internal/shader/expr.go | 25 ++++++++++++++++---- internal/shader/syntax_test.go | 42 ++++++++++++++++++++++++++++++++++ 2 files changed, 62 insertions(+), 5 deletions(-) diff --git a/internal/shader/expr.go b/internal/shader/expr.go index 4ce9b3b67..60fbcb2c4 100644 --- a/internal/shader/expr.go +++ b/internal/shader/expr.go @@ -53,7 +53,11 @@ func isModAvailableForConsts(lhs, rhs *shaderir.Expr) bool { return false } -func canCompare(lhs, rhs *shaderir.Expr, lhst, rhst shaderir.Type) bool { +func canApplyBinaryOp(lhs, rhs *shaderir.Expr, lhst, rhst shaderir.Type, op shaderir.Op) bool { + if op == shaderir.AndAnd || op == shaderir.OrOr { + return lhst.Main == shaderir.Bool && rhst.Main == shaderir.Bool + } + switch { case lhs.Const != nil && rhs.Const != nil: switch { @@ -202,12 +206,23 @@ func (cs *compileState) parseExpr(block *block, fname string, expr ast.Expr, mar var v gconstant.Value var t shaderir.Type switch op { - case token.EQL, token.NEQ, token.LSS, token.LEQ, token.GTR, token.GEQ: - if !canCompare(&lhs[0], &rhs[0], lhst, rhst) { + case token.EQL, token.NEQ, token.LSS, token.LEQ, token.GTR, token.GEQ, token.LAND, token.LOR: + op2, ok := shaderir.OpFromToken(op, lhst, rhst) + if !ok { + cs.addError(e.Pos(), fmt.Sprintf("unexpected operator: %s", op)) + return nil, nil, nil, false + } + if !canApplyBinaryOp(&lhs[0], &rhs[0], lhst, rhst, op2) { cs.addError(e.Pos(), fmt.Sprintf("types don't match: %s %s %s", lhst.String(), op, rhst.String())) return nil, nil, nil, false } - v = gconstant.MakeBool(gconstant.Compare(lhs[0].Const, op, rhs[0].Const)) + switch op { + case token.LAND, token.LOR: + b := gconstant.BoolVal(gconstant.BinaryOp(lhs[0].Const, op, rhs[0].Const)) + v = gconstant.MakeBool(b) + default: + v = gconstant.MakeBool(gconstant.Compare(lhs[0].Const, op, rhs[0].Const)) + } t = shaderir.Type{Main: shaderir.Bool} default: if op == token.REM { @@ -253,7 +268,7 @@ func (cs *compileState) parseExpr(block *block, fname string, expr ast.Expr, mar var t shaderir.Type switch { case op == shaderir.LessThanOp || op == shaderir.LessThanEqualOp || op == shaderir.GreaterThanOp || op == shaderir.GreaterThanEqualOp || op == shaderir.EqualOp || op == shaderir.NotEqualOp || op == shaderir.VectorEqualOp || op == shaderir.VectorNotEqualOp || op == shaderir.AndAnd || op == shaderir.OrOr: - if !canCompare(&lhs[0], &rhs[0], lhst, rhst) { + if !canApplyBinaryOp(&lhs[0], &rhs[0], lhst, rhst, op) { cs.addError(e.Pos(), fmt.Sprintf("types don't match: %s %s %s", lhst.String(), e.Op, rhst.String())) return nil, nil, nil, false } diff --git a/internal/shader/syntax_test.go b/internal/shader/syntax_test.go index 76c49f480..b7870b7ae 100644 --- a/internal/shader/syntax_test.go +++ b/internal/shader/syntax_test.go @@ -2321,6 +2321,48 @@ func TestSyntaxEqual(t *testing.T) { {stmt: "a, b := mat2(1), vec2(1); _ = a != b", err: true}, {stmt: "a, b := mat2(1), mat2(1); _ = a == b", err: true}, // Comparing matrices are not allowed. {stmt: "a, b := mat2(1), mat2(1); _ = a != b", err: true}, // Comparing matrices are not allowed. + + {stmt: "_ = false && true", err: false}, + {stmt: "_ = false || true", err: false}, + {stmt: "_ = false && 1", err: true}, + {stmt: "_ = false || 1", err: true}, + {stmt: "_ = false && 1.0", err: true}, + {stmt: "_ = false || 1.0", err: true}, + {stmt: "_ = false && 1.1", err: true}, + {stmt: "_ = false || 1.1", err: true}, + {stmt: "a, b := false, true; _ = a && b", err: false}, + {stmt: "a, b := false, true; _ = a || b", err: false}, + {stmt: "a, b := false, 1; _ = a && b", err: true}, + {stmt: "a, b := false, 1; _ = a || b", err: true}, + {stmt: "a, b := false, 1.0; _ = a && b", err: true}, + {stmt: "a, b := false, 1.0; _ = a || b", err: true}, + {stmt: "a, b := false, 1.1; _ = a && b", err: true}, + {stmt: "a, b := false, 1.1; _ = a || b", err: true}, + {stmt: "a, b := false, vec2(1); _ = a && b", err: true}, + {stmt: "a, b := false, vec2(1); _ = a || b", err: true}, + {stmt: "a, b := false, mat2(1); _ = a && b", err: true}, + {stmt: "a, b := false, mat2(1); _ = a || b", err: true}, + + {stmt: "_ = 1.0 && true", err: true}, + {stmt: "_ = 1.0 || true", err: true}, + {stmt: "_ = 1.0 && 1", err: true}, + {stmt: "_ = 1.0 || 1", err: true}, + {stmt: "_ = 1.0 && 1.0", err: true}, + {stmt: "_ = 1.0 || 1.0", err: true}, + {stmt: "_ = 1.0 && 1.1", err: true}, + {stmt: "_ = 1.0 || 1.1", err: true}, + {stmt: "a, b := 1.0, true; _ = a && b", err: true}, + {stmt: "a, b := 1.0, true; _ = a || b", err: true}, + {stmt: "a, b := 1.0, 1; _ = a && b", err: true}, + {stmt: "a, b := 1.0, 1; _ = a || b", err: true}, + {stmt: "a, b := 1.0, 1.0; _ = a && b", err: true}, + {stmt: "a, b := 1.0, 1.0; _ = a || b", err: true}, + {stmt: "a, b := 1.0, 1.1; _ = a && b", err: true}, + {stmt: "a, b := 1.0, 1.1; _ = a || b", err: true}, + {stmt: "a, b := 1.0, vec2(1); _ = a && b", err: true}, + {stmt: "a, b := 1.0, vec2(1); _ = a || b", err: true}, + {stmt: "a, b := 1.0, mat2(1); _ = a && b", err: true}, + {stmt: "a, b := 1.0, mat2(1); _ = a || b", err: true}, } for _, c := range cases {