Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions gnovm/pkg/gnolang/nodes.go
Original file line number Diff line number Diff line change
Expand Up @@ -2299,6 +2299,11 @@ func (sb *StaticBlock) GetFuncNodeForExpr(store Store, fne Expr) (FuncNode, erro
// could go further and store preprocessed constant results here too. See
// "anyValue()" and "asValue()" for usage.
func (sb *StaticBlock) Define(n Name, tv TypedValue) {
if tv.T == nil {
panic(fmt.Sprintf(
"StaticBlock.Define(%s) requires non-nil tv.T; use Reserve() for placeholder slots",
n))
}
sb.Define2(false, n, tv.T, tv, NameSource{})
}

Expand Down
5 changes: 3 additions & 2 deletions gnovm/pkg/gnolang/preprocess.go
Original file line number Diff line number Diff line change
Expand Up @@ -1042,15 +1042,16 @@ func preprocess1(store Store, ctx BlockNode, n Node) Node {
n.Cases[i] = toConstTypeExpr(last, cx, ct)
// maybe type-switch def.
if ss.VarName != "" {
if len(n.Cases) == 1 {
if len(n.Cases) == 1 && ct != nil {
// If there is only 1 case, the
// define applies with type.
// (re-definition).
last.Define(
ss.VarName, anyValue(ct))
} else {
// If there are 2 or more
// cases, the type is the tag type.
// cases, or the sole case is nil,
// the type is the tag type.
tt := evalStaticTypeOf(store, last, ss.X)
last.Define(
ss.VarName, anyValue(tt))
Expand Down
87 changes: 87 additions & 0 deletions gnovm/tests/files/typeswitch1.gno
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
// Test simple type switches on basic types, including `case nil:` as
// the sole case (the regression that motivated this filetest — Gno
// preprocess previously panicked "name xx not declared" because the
// single-case branch registered the type-switch var with a nil static
// type when ct was nil).

package main

import "fmt"

const (
a = iota
b
c
d
e
)

var x = []int{1, 2, 3}

func f(x int, len *byte) {
*len = byte(x)
}

func whatis(x interface{}) string {
switch xx := x.(type) {
default:
return fmt.Sprint("default ", xx)
case int, int8, int16, int32:
return fmt.Sprint("signed ", xx)
case int64:
return fmt.Sprint("signed64 ", int64(xx))
case uint, uint8, uint16, uint32:
return fmt.Sprint("unsigned ", xx)
case uint64:
return fmt.Sprint("unsigned64 ", uint64(xx))
case nil:
return fmt.Sprint("nil ", xx)
}
panic("not reached")
}

func whatis1(x interface{}) string {
xx := x
switch xx.(type) {
default:
return fmt.Sprint("default ", xx)
case int, int8, int16, int32:
return fmt.Sprint("signed ", xx)
case int64:
return fmt.Sprint("signed64 ", xx.(int64))
case uint, uint8, uint16, uint32:
return fmt.Sprint("unsigned ", xx)
case uint64:
return fmt.Sprint("unsigned64 ", xx.(uint64))
case nil:
return fmt.Sprint("nil ", xx)
}
panic("not reached")
}

func check(x interface{}, s string) {
w := whatis(x)
if w != s {
fmt.Println("whatis", x, "=>", w, "!=", s)
panic("fail")
}

w = whatis1(x)
if w != s {
fmt.Println("whatis1", x, "=>", w, "!=", s)
panic("fail")
}
}

func main() {
check(1, "signed 1")
check(uint(1), "unsigned 1")
check(int64(1), "signed64 1")
check(uint64(1), "unsigned64 1")
check(1.5, "default 1.5")
check(nil, "nil <nil>")
fmt.Println("ok")
}

// Output:
// ok
Loading