diff --git a/internal/shader/expr.go b/internal/shader/expr.go index 1d06be676..b3dac6a40 100644 --- a/internal/shader/expr.go +++ b/internal/shader/expr.go @@ -124,8 +124,11 @@ func (cs *compileState) parseExpr(block *block, fname string, expr ast.Expr, mar // If left is untyped const if lhst.Main == shaderir.None && lhs[0].Const != nil { - lhst = shaderir.Type{Main: shaderir.Int} - // Left should be implicitly converted to the type it would assume if the shift expression were replaced by its left operand alone. + if rhs[0].Const != nil { + lhst = shaderir.Type{Main: shaderir.Int} + } else { + lhst = shaderir.Type{Main: shaderir.DeducedInt} + } } } } else { diff --git a/internal/shader/stmt.go b/internal/shader/stmt.go index 6c07057da..b3d8e1732 100644 --- a/internal/shader/stmt.go +++ b/internal/shader/stmt.go @@ -514,6 +514,9 @@ func (cs *compileState) assign(block *block, fname string, pos token.Pos, lhs, r return nil, false } t := ts[0] + if t.Main == shaderir.DeducedInt { + cs.addError(pos, "invalid operation: shifted operand 1 (type float) must be integer") + } if t.Main == shaderir.None { t = toDefaultType(r[0].Const) } @@ -705,6 +708,9 @@ func canAssign(lt *shaderir.Type, rt *shaderir.Type, rc gconstant.Value) bool { if lt.Equal(rt) { return true } + if lt.Main == shaderir.Int && rt.Main == shaderir.DeducedInt { + return true + } if rc == nil { return false diff --git a/internal/shader/syntax_test.go b/internal/shader/syntax_test.go index 1c2920cc4..df2c1c84d 100644 --- a/internal/shader/syntax_test.go +++ b/internal/shader/syntax_test.go @@ -1324,16 +1324,16 @@ func TestSyntaxOperatorShift(t *testing.T) { // {stmt: "s := 1; var a float = float(1.0 << s); _ = a", err: true}, // {stmt: "s := 1; var a int = int(1 << s); _ = a", err: false}, // {stmt: "s := 1; var a int = int(1.0 << s); _ = a", err: false}, - // {stmt: "s := 1; a := 1 << s; _ = a", err: false}, - // {stmt: "s := 1; a := 1.0 << s; _ = a", err: true}, - // {stmt: "s := 1; a := int(1.0 << s); _ = a", err: false}, - // {stmt: "s := 1; var a float = float(1.0 << s); _ = a", err: true}, - // {stmt: "s := 1; var a float = 1.0 << s; _ = a", err: true}, - // {stmt: "s := 1; var a float = 1 << s; _ = a", err: true}, - // {stmt: "s := 1; var a int = 1.0 << s; _ = a", err: false}, - // {stmt: "s := 1; var a int = 1 << s; _ = a", err: false}, + {stmt: "s := 1; a := 1 << s; _ = a", err: false}, + {stmt: "s := 1; a := 1.0 << s; _ = a", err: true}, + {stmt: "s := 1; a := int(1.0 << s); _ = a", err: false}, {stmt: "var a float = 1.0 << 2.0; _ = a", err: false}, + {stmt: "s := 1; var a float = float(1.0 << s); _ = a", err: true}, + {stmt: "s := 1; var a float = 1.0 << s; _ = a", err: true}, + {stmt: "s := 1; var a float = 1 << s; _ = a", err: true}, + {stmt: "s := 1; var a int = 1.0 << s; _ = a", err: false}, + {stmt: "s := 1; var a int = 1 << s; _ = a", err: false}, {stmt: "var a int = 1.0 << 2; _ = a", err: false}, {stmt: "var a float = 1.0 << 2; _ = a", err: false}, {stmt: "var a = 1.0 << 2; _ = a", err: false}, @@ -1363,7 +1363,12 @@ func TestSyntaxOperatorShift(t *testing.T) { {stmt: "a := vec3(1) << ivec2(2); _ = a", err: true}, {stmt: "a := ivec2(1) << vec3(2); _ = a", err: true}, - {stmt: "var a float = 1.0 >> 2.0; _ = a", err: false}, + {stmt: "s := 1; var a float = float(1.0 >> s); _ = a", err: true}, + {stmt: "s := 1; var a int = int(1.0 >> s); _ = a", err: false}, + {stmt: "s := 1; var a float = 1.0 >> s; _ = a", err: true}, + {stmt: "s := 1; var a float = 1 >> s; _ = a", err: true}, + {stmt: "s := 1; var a int = 1.0 >> s; _ = a", err: false}, + {stmt: "s := 1; var a int = 1 >> s; _ = a", err: false}, {stmt: "var a int = 1.0 >> 2; _ = a", err: false}, {stmt: "var a float = 1.0 >> 2; _ = a", err: false}, {stmt: "var a = 1.0 >> 2; _ = a", err: false}, diff --git a/internal/shader/type.go b/internal/shader/type.go index 546407556..5c8aade39 100644 --- a/internal/shader/type.go +++ b/internal/shader/type.go @@ -165,7 +165,7 @@ func checkArgsForIntBuiltinFunc(args []shaderir.Expr, argts []shaderir.Type) err if len(args) != 1 { return fmt.Errorf("number of int's arguments must be 1 but %d", len(args)) } - if argts[0].Main == shaderir.Int || argts[0].Main == shaderir.Float { + if argts[0].Main == shaderir.Int || argts[0].Main == shaderir.Float || argts[0].Main == shaderir.DeducedInt { return nil } if args[0].Const != nil && gconstant.ToInt(args[0].Const).Kind() != gconstant.Unknown { diff --git a/internal/shaderir/check.go b/internal/shaderir/check.go index 57bacc749..e518726b1 100644 --- a/internal/shaderir/check.go +++ b/internal/shaderir/check.go @@ -145,7 +145,7 @@ func TypeFromBinaryOp(op Op, lhst, rhst Type, lhsConst, rhsConst constant.Value) } if op == LeftShift || op == RightShift { - if lhst.Main == Int && rhst.Main == Int { + if (lhst.Main == Int || lhst.Main == DeducedInt) && rhst.Main == Int { return Type{Main: lhst.Main}, true } if lhst.IsIntVector() && rhst.Main == Int { diff --git a/internal/shaderir/type.go b/internal/shaderir/type.go index ede2c91e2..885d579c4 100644 --- a/internal/shaderir/type.go +++ b/internal/shaderir/type.go @@ -180,6 +180,7 @@ const ( Texture Array Struct + DeducedInt ) func descendantLocalVars(block, target *Block) ([]Type, bool) {