mirror of
https://github.com/hajimehoshi/ebiten.git
synced 2024-11-10 04:57:26 +01:00
internal/shader: stricter const type check
This commit is contained in:
parent
685a6acb05
commit
5d8216def3
@ -731,7 +731,7 @@ func (cs *compileState) parseExpr(block *block, fname string, expr ast.Expr, mar
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if !canAssign(&args[i], &p, &argts[i]) {
|
if !canAssign(&p, &argts[i], args[i].Const) {
|
||||||
cs.addError(e.Pos(), fmt.Sprintf("cannot use type %s as type %s in argument", argts[i].String(), p.String()))
|
cs.addError(e.Pos(), fmt.Sprintf("cannot use type %s as type %s in argument", argts[i].String(), p.String()))
|
||||||
return nil, nil, nil, false
|
return nil, nil, nil, false
|
||||||
}
|
}
|
||||||
|
@ -507,7 +507,7 @@ func (s *compileState) parseVariable(block *block, fname string, vs *ast.ValueSp
|
|||||||
}
|
}
|
||||||
|
|
||||||
for i, rt := range rts {
|
for i, rt := range rts {
|
||||||
if !canAssign(&es[i], &t, &rt) {
|
if !canAssign(&t, &rt, es[i].Const) {
|
||||||
s.addError(vs.Pos(), fmt.Sprintf("cannot use type %s as type %s in variable declaration", rt.String(), t.String()))
|
s.addError(vs.Pos(), fmt.Sprintf("cannot use type %s as type %s in variable declaration", rt.String(), t.String()))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -545,7 +545,7 @@ func (s *compileState) parseVariable(block *block, fname string, vs *ast.ValueSp
|
|||||||
t = inittypes[i]
|
t = inittypes[i]
|
||||||
}
|
}
|
||||||
|
|
||||||
if !canAssign(&initexprs[i], &t, &inittypes[i]) {
|
if !canAssign(&t, &inittypes[i], initexprs[i].Const) {
|
||||||
s.addError(vs.Pos(), fmt.Sprintf("cannot use type %s as type %s in variable declaration", inittypes[i].String(), t.String()))
|
s.addError(vs.Pos(), fmt.Sprintf("cannot use type %s as type %s in variable declaration", inittypes[i].String(), t.String()))
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -617,10 +617,26 @@ func (s *compileState) parseConstant(block *block, fname string, vs *ast.ValueSp
|
|||||||
s.addError(vs.Pos(), fmt.Sprintf("constant expression must be a number but not: %s", n))
|
s.addError(vs.Pos(), fmt.Sprintf("constant expression must be a number but not: %s", n))
|
||||||
return nil, false
|
return nil, false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if !t.Equal(&shaderir.Type{}) && !canAssign(&t, &ts[0], es[0].Const) {
|
||||||
|
s.addError(vs.Pos(), fmt.Sprintf("cannot use %v as %s value in constant declaration", es[0].Const, t.String()))
|
||||||
|
return nil, false
|
||||||
|
}
|
||||||
|
|
||||||
|
constType := es[0].ConstType
|
||||||
|
switch t.Main {
|
||||||
|
case shaderir.Bool:
|
||||||
|
constType = shaderir.ConstTypeBool
|
||||||
|
case shaderir.Int:
|
||||||
|
constType = shaderir.ConstTypeInt
|
||||||
|
case shaderir.Float:
|
||||||
|
constType = shaderir.ConstTypeFloat
|
||||||
|
}
|
||||||
|
|
||||||
cs = append(cs, constant{
|
cs = append(cs, constant{
|
||||||
name: name,
|
name: name,
|
||||||
typ: t,
|
typ: t,
|
||||||
ctyp: es[0].ConstType,
|
ctyp: constType,
|
||||||
value: es[0].Const,
|
value: es[0].Const,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -667,7 +667,7 @@ func (cs *compileState) assign(block *block, fname string, pos token.Pos, lhs, r
|
|||||||
}
|
}
|
||||||
|
|
||||||
for i := range lts {
|
for i := range lts {
|
||||||
if !canAssign(&r[i], <s[i], &rts[i]) {
|
if !canAssign(<s[i], &rts[i], r[i].Const) {
|
||||||
cs.addError(pos, fmt.Sprintf("cannot use type %s as type %s in variable declaration", rts[i].String(), lts[i].String()))
|
cs.addError(pos, fmt.Sprintf("cannot use type %s as type %s in variable declaration", rts[i].String(), lts[i].String()))
|
||||||
return nil, false
|
return nil, false
|
||||||
}
|
}
|
||||||
@ -755,7 +755,7 @@ func (cs *compileState) assign(block *block, fname string, pos token.Pos, lhs, r
|
|||||||
allblank = false
|
allblank = false
|
||||||
|
|
||||||
for i, lt := range lts {
|
for i, lt := range lts {
|
||||||
if !canAssign(&rhsExprs[i], <, &rhsTypes[i]) {
|
if !canAssign(<, &rhsTypes[i], rhsExprs[i].Const) {
|
||||||
cs.addError(pos, fmt.Sprintf("cannot use type %s as type %s in variable declaration", rhsTypes[i].String(), lt.String()))
|
cs.addError(pos, fmt.Sprintf("cannot use type %s as type %s in variable declaration", rhsTypes[i].String(), lt.String()))
|
||||||
return nil, false
|
return nil, false
|
||||||
}
|
}
|
||||||
@ -789,19 +789,23 @@ func toDefaultType(v gconstant.Value) shaderir.Type {
|
|||||||
return shaderir.Type{}
|
return shaderir.Type{}
|
||||||
}
|
}
|
||||||
|
|
||||||
func canAssign(re *shaderir.Expr, lt *shaderir.Type, rt *shaderir.Type) bool {
|
func canAssign(lt *shaderir.Type, rt *shaderir.Type, rc gconstant.Value) bool {
|
||||||
if lt.Equal(rt) {
|
if lt.Equal(rt) {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
if re.Const != nil {
|
|
||||||
switch lt.Main {
|
if rc == nil {
|
||||||
case shaderir.Bool:
|
return false
|
||||||
return re.Const.Kind() == gconstant.Bool
|
}
|
||||||
case shaderir.Int:
|
|
||||||
return canTruncateToInteger(re.Const)
|
switch lt.Main {
|
||||||
case shaderir.Float:
|
case shaderir.Bool:
|
||||||
return gconstant.ToFloat(re.Const).Kind() != gconstant.Unknown
|
return rc.Kind() == gconstant.Bool
|
||||||
}
|
case shaderir.Int:
|
||||||
}
|
return canTruncateToInteger(rc)
|
||||||
|
case shaderir.Float:
|
||||||
|
return gconstant.ToFloat(rc).Kind() != gconstant.Unknown
|
||||||
|
}
|
||||||
|
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
@ -1127,6 +1127,10 @@ func TestSyntaxOperatorMultiplyAssign(t *testing.T) {
|
|||||||
{stmt: "a := 1.0; a *= 2.0", err: false},
|
{stmt: "a := 1.0; a *= 2.0", err: false},
|
||||||
{stmt: "const c = 2; a := 1.0; a *= c", err: false},
|
{stmt: "const c = 2; a := 1.0; a *= c", err: false},
|
||||||
{stmt: "const c = 2.0; a := 1.0; a *= c", err: false},
|
{stmt: "const c = 2.0; a := 1.0; a *= c", err: false},
|
||||||
|
{stmt: "const c int = 2; a := 1.0; a *= c", err: true},
|
||||||
|
{stmt: "const c int = 2.0; a := 1.0; a *= c", err: true},
|
||||||
|
{stmt: "const c float = 2; a := 1.0; a *= c", err: false},
|
||||||
|
{stmt: "const c float = 2.0; a := 1.0; a *= c", err: false},
|
||||||
{stmt: "a := 1.0; a *= int(2)", err: true},
|
{stmt: "a := 1.0; a *= int(2)", err: true},
|
||||||
{stmt: "a := 1.0; a *= vec2(2)", err: true},
|
{stmt: "a := 1.0; a *= vec2(2)", err: true},
|
||||||
{stmt: "a := 1.0; a *= vec3(2)", err: true},
|
{stmt: "a := 1.0; a *= vec3(2)", err: true},
|
||||||
@ -1134,10 +1138,15 @@ func TestSyntaxOperatorMultiplyAssign(t *testing.T) {
|
|||||||
{stmt: "a := 1.0; a *= mat2(2)", err: true},
|
{stmt: "a := 1.0; a *= mat2(2)", err: true},
|
||||||
{stmt: "a := 1.0; a *= mat3(2)", err: true},
|
{stmt: "a := 1.0; a *= mat3(2)", err: true},
|
||||||
{stmt: "a := 1.0; a *= mat4(2)", err: true},
|
{stmt: "a := 1.0; a *= mat4(2)", err: true},
|
||||||
|
|
||||||
{stmt: "a := vec2(1); a *= 2", err: false},
|
{stmt: "a := vec2(1); a *= 2", err: false},
|
||||||
{stmt: "a := vec2(1); a *= 2.0", err: false},
|
{stmt: "a := vec2(1); a *= 2.0", err: false},
|
||||||
{stmt: "const c = 2; a := vec2(1); a *= c", err: false},
|
{stmt: "const c = 2; a := vec2(1); a *= c", err: false},
|
||||||
{stmt: "const c = 2.0; a := vec2(1); a *= c", err: false},
|
{stmt: "const c = 2.0; a := vec2(1); a *= c", err: false},
|
||||||
|
{stmt: "const c int = 2; a := vec2(1); a *= c", err: true},
|
||||||
|
{stmt: "const c int = 2.0; a := vec2(1); a *= c", err: true},
|
||||||
|
{stmt: "const c float = 2; a := vec2(1); a *= c", err: false},
|
||||||
|
{stmt: "const c float = 2.0; a := vec2(1); a *= c", err: false},
|
||||||
{stmt: "a := vec2(1); a /= 2.0", err: false},
|
{stmt: "a := vec2(1); a /= 2.0", err: false},
|
||||||
{stmt: "a := vec2(1); a += 2.0", err: false},
|
{stmt: "a := vec2(1); a += 2.0", err: false},
|
||||||
{stmt: "a := vec2(1); a *= int(2)", err: true},
|
{stmt: "a := vec2(1); a *= int(2)", err: true},
|
||||||
@ -1152,10 +1161,15 @@ func TestSyntaxOperatorMultiplyAssign(t *testing.T) {
|
|||||||
{stmt: "a := vec2(1); a /= mat2(2)", err: true},
|
{stmt: "a := vec2(1); a /= mat2(2)", err: true},
|
||||||
{stmt: "a := vec2(1); a *= mat3(2)", err: true},
|
{stmt: "a := vec2(1); a *= mat3(2)", err: true},
|
||||||
{stmt: "a := vec2(1); a *= mat4(2)", err: true},
|
{stmt: "a := vec2(1); a *= mat4(2)", err: true},
|
||||||
|
|
||||||
{stmt: "a := mat2(1); a *= 2", err: false},
|
{stmt: "a := mat2(1); a *= 2", err: false},
|
||||||
{stmt: "a := mat2(1); a *= 2.0", err: false},
|
{stmt: "a := mat2(1); a *= 2.0", err: false},
|
||||||
{stmt: "const c = 2; a := mat2(1); a *= c", err: false},
|
{stmt: "const c = 2; a := mat2(1); a *= c", err: false},
|
||||||
{stmt: "const c = 2.0; a := mat2(1); a *= c", err: false},
|
{stmt: "const c = 2.0; a := mat2(1); a *= c", err: false},
|
||||||
|
{stmt: "const c int = 2; a := mat2(1); a *= c", err: true},
|
||||||
|
{stmt: "const c int = 2.0; a := mat2(1); a *= c", err: true},
|
||||||
|
{stmt: "const c float = 2; a := mat2(1); a *= c", err: false},
|
||||||
|
{stmt: "const c float = 2.0; a := mat2(1); a *= c", err: false},
|
||||||
{stmt: "a := mat2(1); a /= 2.0", err: false},
|
{stmt: "a := mat2(1); a /= 2.0", err: false},
|
||||||
{stmt: "a := mat2(1); a += 2.0", err: true},
|
{stmt: "a := mat2(1); a += 2.0", err: true},
|
||||||
{stmt: "a := mat2(1); a *= int(2)", err: true},
|
{stmt: "a := mat2(1); a *= int(2)", err: true},
|
||||||
@ -2465,3 +2479,56 @@ func Fragment(position vec4, texCoord vec2, color vec4) vec4 {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestConstType(t *testing.T) {
|
||||||
|
cases := []struct {
|
||||||
|
stmt string
|
||||||
|
err bool
|
||||||
|
}{
|
||||||
|
{stmt: "const a = false", err: false},
|
||||||
|
{stmt: "const a bool = false", err: false},
|
||||||
|
{stmt: "const a int = false", err: true},
|
||||||
|
{stmt: "const a float = false", err: true},
|
||||||
|
{stmt: "const a vec2 = false", err: true},
|
||||||
|
|
||||||
|
{stmt: "const a = 1", err: false},
|
||||||
|
{stmt: "const a bool = 1", err: true},
|
||||||
|
{stmt: "const a int = 1", err: false},
|
||||||
|
{stmt: "const a float = 1", err: false},
|
||||||
|
{stmt: "const a vec2 = 1", err: true},
|
||||||
|
|
||||||
|
{stmt: "const a = 1.0", err: false},
|
||||||
|
{stmt: "const a bool = 1.0", err: true},
|
||||||
|
{stmt: "const a int = 1.0", err: false},
|
||||||
|
{stmt: "const a float = 1.0", err: false},
|
||||||
|
{stmt: "const a vec2 = 1.0", err: true},
|
||||||
|
|
||||||
|
{stmt: "const a = 1.1", err: false},
|
||||||
|
{stmt: "const a bool = 1.1", err: true},
|
||||||
|
{stmt: "const a int = 1.1", err: true},
|
||||||
|
{stmt: "const a float = 1.1", err: false},
|
||||||
|
{stmt: "const a vec2 = 1.1", err: true},
|
||||||
|
|
||||||
|
{stmt: "const a = vec2(0)", err: true},
|
||||||
|
{stmt: "const a bool = vec2(0)", err: true},
|
||||||
|
{stmt: "const a int = vec2(0)", err: true},
|
||||||
|
{stmt: "const a float = vec2(0)", err: true},
|
||||||
|
{stmt: "const a vec2 = vec2(0)", 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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user