Skip to content

Commit

Permalink
fix: handle untyped constant expressions in append() (#1177)
Browse files Browse the repository at this point in the history
This is a particular case of Go append builtin where the array type is
inferred from the first argument. We detect an untyped const passed as
argument, then we convert it to the array type prior to proceed further.
It fixes further consistency checks and value generation.

Fixes #1136, fixes #1149, fixes #1341.

<!-- please provide a detailed description of the changes made in this
pull request. -->

<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
- [ ] Provided any useful hints for running manual tests
- [ ] 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>

---------

Co-authored-by: Morgan <[email protected]>
Co-authored-by: Morgan <[email protected]>
  • Loading branch information
3 people authored Jan 10, 2024
1 parent 568a087 commit 2a2dcdc
Show file tree
Hide file tree
Showing 9 changed files with 72 additions and 7 deletions.
4 changes: 2 additions & 2 deletions examples/gno.land/r/gnoland/faucet/z2_filetest.gno
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,11 @@ func main() {
)
std.TestSetOrigCaller(adminaddr)
err := faucet.AdminAddController(controlleraddr1)
if err != nil {
if err != "" {
panic(err)
}
err = faucet.AdminAddController(controlleraddr2)
if err != nil {
if err != "" {
panic(err)
}
println(faucet.Render(""))
Expand Down
8 changes: 4 additions & 4 deletions examples/gno.land/r/gnoland/faucet/z3_filetest.gno
Original file line number Diff line number Diff line change
Expand Up @@ -18,21 +18,21 @@ func main() {
)
std.TestSetOrigCaller(adminaddr)
err := faucet.AdminAddController(controlleraddr1)
if err != nil {
if err != "" {
panic(err)
}
err = faucet.AdminAddController(controlleraddr2)
if err != nil {
if err != "" {
panic(err)
}
std.TestSetOrigCaller(controlleraddr1)
err = faucet.Transfer(testaddr1, 1000000)
if err != nil {
if err != "" {
panic(err)
}
std.TestSetOrigCaller(controlleraddr2)
err = faucet.Transfer(testaddr1, 2000000)
if err != nil {
if err != "" {
panic(err)
}
println(faucet.Render(""))
Expand Down
23 changes: 23 additions & 0 deletions gnovm/pkg/gnolang/preprocess.go
Original file line number Diff line number Diff line change
Expand Up @@ -1012,6 +1012,29 @@ func Preprocess(store Store, ctx BlockNode, n Node) Node {
args1 = Preprocess(nil, last, args1).(Expr)
n.Args[1] = args1
}
} else {
var tx *constTypeExpr // array type expr, lazily initialized
// Another special case for append: adding untyped constants.
// They must be converted to the array type for consistency.
for i, arg := range n.Args[1:] {
if _, ok := arg.(*ConstExpr); !ok {
// Consider only constant expressions.
continue
}
if t1 := evalStaticTypeOf(store, last, arg); t1 != nil && !isUntyped(t1) {
// Consider only untyped values (including nil).
continue
}

if tx == nil {
// Get the array type from the first argument.
s0 := evalStaticTypeOf(store, last, n.Args[0])
tx = constType(arg, s0.Elem())
}
// Convert to the array type.
arg1 := Call(tx, arg)
n.Args[i+1] = Preprocess(nil, last, arg1).(Expr)
}
}
} else if fv.PkgPath == uversePkgPath && fv.Name == "copy" {
if len(n.Args) == 2 {
Expand Down
4 changes: 4 additions & 0 deletions gnovm/pkg/gnolang/values_conversions.go
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,10 @@ GNO_CASE:
}
// special case for undefined/nil source
if tv.IsUndefined() {
switch t.Kind() {
case BoolKind, StringKind, IntKind, Int8Kind, Int16Kind, Int32Kind, Int64Kind, UintKind, Uint8Kind, Uint16Kind, Uint32Kind, Uint64Kind, Float32Kind, Float64Kind, BigintKind, BigdecKind:
panic(fmt.Sprintf("cannot convert %v to %v", tv, t))
}
tv.T = t
return
}
Expand Down
2 changes: 1 addition & 1 deletion gnovm/tests/files/append5.gno
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,4 @@ func main() {
}

// Output:
// X
// X
12 changes: 12 additions & 0 deletions gnovm/tests/files/append6.gno
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package main

func main() {
const x = 118999
y := 11
p := []int{}
p = append(p, x, y)
println(p[0] + p[1])
}

// Output:
// 119010
10 changes: 10 additions & 0 deletions gnovm/tests/files/append7.gno
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package main

func main() {
var errors []error
errors = append(errors, nil, nil)
println(len(errors))
}

// Output:
// 2
7 changes: 7 additions & 0 deletions gnovm/tests/files/convert4.gno
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package main

func main() {
println(int(nil))
}

// error: cannot convert (undefined) to int
9 changes: 9 additions & 0 deletions gnovm/tests/files/convert5.gno
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package main

func main() {
var ints []int
ints = append(ints, nil, nil)
println(ints)
}

// error: cannot convert (undefined) to int

0 comments on commit 2a2dcdc

Please sign in to comment.