Skip to content

Commit

Permalink
fix(gnovm): handle non call expression valuedecl values (gnolang#2647)
Browse files Browse the repository at this point in the history
Closes gnolang#2636.

With a value declaration like `var a, b = ...`, we currently only
support a call expression on the RHS. This PR supports type assertion
and index expressions as well.

<details><summary>Contributors' checklist...</summary>

- [x] Added new tests, or not needed, or not feasible
- [x] Provided an example (e.g. screenshot) to aid review or the PR is
self-explanatory
- [x] Updated the official documentation or not needed
- [x] No breaking changes were made, or a `BREAKING CHANGE: xxx` message
was included in the description
- [x] Added references to related issues and PRs
- [x] Provided any useful hints for running manual tests
- [x] Added new benchmarks to [generated
graphs](https://gnoland.github.io/benchmarks), if any. More info
[here](https://github.com/gnolang/gno/blob/master/.benchmarks/README.md).
</details>
  • Loading branch information
deelawn authored Aug 19, 2024
1 parent 8bd07c9 commit 6214fe9
Show file tree
Hide file tree
Showing 3 changed files with 59 additions and 7 deletions.
41 changes: 35 additions & 6 deletions gnovm/pkg/gnolang/preprocess.go
Original file line number Diff line number Diff line change
Expand Up @@ -2170,13 +2170,42 @@ func Preprocess(store Store, ctx BlockNode, n Node) Node {
numNames := len(n.NameExprs)
sts := make([]Type, numNames) // static types
tvs := make([]TypedValue, numNames)

if numNames > 1 && len(n.Values) == 1 {
// special case if `var a, b, c T? = f()` form.
cx := n.Values[0].(*CallExpr)
tt := evalStaticTypeOfRaw(store, last, cx).(*tupleType)
if rLen := len(tt.Elts); rLen != numNames {
panic(fmt.Sprintf("assignment mismatch: %d variable(s) but %s returns %d value(s)", numNames, cx.Func.String(), rLen))
// Special cases if one of the following:
// - `var a, b, c T = f()`
// - `var a, b = n.(T)`
// - `var a, b = n[i], where n is a map`

var tuple *tupleType
valueExpr := n.Values[0]
valueType := evalStaticTypeOfRaw(store, last, valueExpr)

switch expr := valueExpr.(type) {
case *CallExpr:
tuple = valueType.(*tupleType)
case *TypeAssertExpr, *IndexExpr:
tuple = &tupleType{Elts: []Type{valueType, BoolType}}
if ex, ok := expr.(*TypeAssertExpr); ok {
ex.HasOK = true
break
}
expr.(*IndexExpr).HasOK = true
default:
panic(fmt.Sprintf("unexpected ValueDecl value expression type %T", expr))
}

if rLen := len(tuple.Elts); rLen != numNames {
panic(
fmt.Sprintf(
"assignment mismatch: %d variable(s) but %s returns %d value(s)",
numNames,
valueExpr.String(),
rLen,
),
)
}

if n.Type != nil {
// only a single type can be specified.
nt := evalStaticType(store, last, n.Type)
Expand All @@ -2188,7 +2217,7 @@ func Preprocess(store Store, ctx BlockNode, n Node) Node {
} else {
// set types as return types.
for i := 0; i < numNames; i++ {
et := tt.Elts[i]
et := tuple.Elts[i]
sts[i] = et
tvs[i] = anyValue(et)
}
Expand Down
2 changes: 1 addition & 1 deletion gnovm/tests/files/var20.gno
Original file line number Diff line number Diff line change
Expand Up @@ -9,4 +9,4 @@ func main() {
}

// Error:
// main/files/var20.gno:8:6: assignment mismatch: 3 variable(s) but r<VPBlock(3,0)> returns 1 value(s)
// main/files/var20.gno:8:6: assignment mismatch: 3 variable(s) but r<VPBlock(3,0)>() returns 1 value(s)
23 changes: 23 additions & 0 deletions gnovm/tests/files/vardecl.gno
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package main

func main() {
var i interface{} = 1
var a, ok = i.(int)
println(a, ok)

var b, c = doSomething()
println(b, c)

m := map[string]int{"a": 1, "b": 2}
var d, okk = m["d"]
println(d, okk)
}

func doSomething() (int, string) {
return 4, "hi"
}

// Output:
// 1 true
// 4 hi
// 0 false

0 comments on commit 6214fe9

Please sign in to comment.