Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: custom boolean types in conditional statements #2147

Merged
merged 12 commits into from
Jun 19, 2024
83 changes: 83 additions & 0 deletions gnovm/pkg/gnolang/gno_test.go
nettijoe96 marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
Expand Up @@ -724,3 +724,86 @@ func TestCallFieldLHS(t *testing.T) {
assert.Equal(t, 2, x.X)
assert.Equal(t, 3, y)
}

// check nameExpr in if cond
func TestNameExprIfCond(t *testing.T) {
t.Parallel()

m := NewMachine("test", nil)
c := `package test
func main() {
v := T
if v {
println("X")
}
}

type C bool

const (
F C = false
T C = true
)`
n := MustParseFile("main.go", c)
m.RunFiles(n)
m.RunMain()
}

// check nameExpr in for cond
func TestNameExprForCond(t *testing.T) {
t.Parallel()

m := NewMachine("test", nil)
c := `package test
func main() {
v := T
i := 0
for v {
println("X")
if i > 3 {
break
}
i++
}
}

type C bool

const (
F C = false
T C = true
)`
n := MustParseFile("main.go", c)
m.RunFiles(n)
m.RunMain()
}

func TestInvalidAssignment(t *testing.T) {
t.Parallel()

defer func() {
if r := recover(); r != nil {
assert.Error(t, r.(error), "cannot use bool as test.C without explicit conversion")
}
}()

m := NewMachine("test", nil)
c := `package test
func main() {
b := true
var v C = b
fmt.Println(v)
}

type C bool

const (
F C = false
T C = true
)
`
n := MustParseFile("main.go", c)
m.RunFiles(n)
m.RunMain()
assert.True(t, false) // Should not be reached because should panic
}
28 changes: 24 additions & 4 deletions gnovm/pkg/gnolang/preprocess.go
Original file line number Diff line number Diff line change
Expand Up @@ -1701,13 +1701,23 @@ func Preprocess(store Store, ctx BlockNode, n Node) Node {

// TRANS_LEAVE -----------------------
case *ForStmt:
// Cond consts become bool *ConstExprs.
checkOrConvertType(store, last, &n.Cond, BoolType, false)
if nx, ok := (n.Cond).(*NameExpr); ok {
// Cond is named type, check if bool
checkNameExprType(store, last, nx, BoolType)
} else {
// Cond consts become bool *ConstExprs.
checkOrConvertType(store, last, &n.Cond, BoolType, false)
}

// TRANS_LEAVE -----------------------
case *IfStmt:
// Cond consts become bool *ConstExprs.
checkOrConvertType(store, last, &n.Cond, BoolType, false)
if nx, ok := (n.Cond).(*NameExpr); ok {
// Cond is named type, check if bool
checkNameExprType(store, last, nx, BoolType)
} else {
// Cond consts become bool *ConstExprs.
checkOrConvertType(store, last, &n.Cond, BoolType, false)
}
nettijoe96 marked this conversation as resolved.
Show resolved Hide resolved

// TRANS_LEAVE -----------------------
case *RangeStmt:
Expand Down Expand Up @@ -2713,6 +2723,16 @@ func checkType(xt Type, dt Type, autoNative bool) {
dt.String()))
}

// Checks type of NameExpr
func checkNameExprType(store Store, last BlockNode, nx *NameExpr, t Type) {
nettijoe96 marked this conversation as resolved.
Show resolved Hide resolved
xt := evalStaticTypeOf(store, last, Expr(nx))
if dxt, ok := xt.(*DeclaredType); ok {
checkType(dxt.Base, t, false)
} else {
panic("cannot assign named type to primitive, or primitive to named type without conversion")
}
}

// Returns any names not yet defined nor predefined in expr. These happen
// upon transcribe:enter from the top, so value paths cannot be used. If no
// names are un and x is TypeExpr, evalStaticType(store,last, x) must not
Expand Down
Loading