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

feat(gnovm): align Gno constant handling with Go specifications #2828

Merged
merged 45 commits into from
Jan 14, 2025
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
Show all changes
45 commits
Select commit Hold shift + click to select a range
3d5030a
feat(gnovm): align Gno constant handling with Go specifications
omarsy Sep 21, 2024
2543294
Merge branch 'master' into fix/2628
omarsy Oct 18, 2024
bb2d9fd
feat: correct test
omarsy Oct 18, 2024
c7643eb
Merge branch 'master' into fix/2628
omarsy Oct 22, 2024
b80a890
feat: add a todo for native type conversion
omarsy Oct 23, 2024
ff74523
feat: uncomment package branch
omarsy Oct 23, 2024
761ef1a
feat: use println
omarsy Oct 23, 2024
5fa41e9
feat: add test
omarsy Oct 23, 2024
90c8c5b
fix: use evalStaticType only for type
omarsy Oct 23, 2024
e74e6e9
feat: add more test
omarsy Oct 23, 2024
3a52e14
feat: add missing init expr
omarsy Oct 24, 2024
f53a19f
feat: add real and imag on todo
omarsy Nov 7, 2024
194883a
Merge remote-tracking branch 'upstream/master' into fix/2628
omarsy Nov 26, 2024
13136c5
fix: test
omarsy Nov 26, 2024
27e69b4
feat: correct merge
omarsy Nov 27, 2024
5dc615a
feat: add test
omarsy Nov 27, 2024
6fb3cf7
Merge branch 'master' into fix/2628
omarsy Nov 27, 2024
743962c
fix: test
omarsy Nov 27, 2024
35d6ae1
Merge branch 'master' into fix/2628
omarsy Dec 3, 2024
459f0da
Merge branch 'master' into fix/2628
omarsy Dec 7, 2024
1ba4872
refactor: replace checkConstantExpr with assertValidConstExpr for imp…
omarsy Dec 7, 2024
54878f0
refactor: rename assertValidConstantExprRecursively to assertValidCon…
omarsy Dec 9, 2024
72b8910
Merge branch 'master' into fix/2628
omarsy Dec 9, 2024
88dae32
Merge branch 'master' into fix/2628
omarsy Dec 10, 2024
59a7d85
Merge branch 'master' into fix/2628
omarsy Dec 11, 2024
9001059
fix(gnovm): check type
omarsy Dec 26, 2024
c45f63e
fix(gnovm): enhance constant evaluation for array and map types
omarsy Dec 26, 2024
7083830
refactore(gnovm): some refactor
omarsy Dec 26, 2024
4da7934
fix(gnovm): remove unnecessary panic for non-constant array type expr…
omarsy Dec 26, 2024
6ef45d4
Merge branch 'master' into fix/2628
omarsy Dec 27, 2024
29b6ab0
feat(gnolang): add comment
omarsy Jan 1, 2025
524b995
Merge branch 'master' into fix/2628
omarsy Jan 1, 2025
72e949e
Merge branch 'master' into fix/2628
omarsy Jan 7, 2025
700c1da
refactor: simplify constant expression validation logic and update er…
omarsy Jan 9, 2025
bdf71d3
Merge branch 'master' into fix/2628
omarsy Jan 9, 2025
ba22f83
Merge branch 'master' into fix/2628
omarsy Jan 9, 2025
0cbd6f0
feat(gnolang): enhance constant value validation in type checking
omarsy Jan 10, 2025
6d8129a
Merge branch 'master' into fix/2628
omarsy Jan 10, 2025
f812805
fix(gnolang): add support for unary expressions in constant value val…
omarsy Jan 12, 2025
09e32a0
fix(gnolang): correct test
omarsy Jan 12, 2025
a068cd1
fix(gnolang): simplify variable declaration in const50.gno
omarsy Jan 12, 2025
e63f16d
fix(gnolang): update error message location in const50.gno
omarsy Jan 13, 2025
5eee6bc
Merge branch 'master' into fix/2628
omarsy Jan 13, 2025
81ed3c9
fix(gnolang): remove unused case for BasicLitExpr in type_check
omarsy Jan 13, 2025
e0499db
Merge branch 'master' into fix/2628
omarsy Jan 13, 2025
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
2 changes: 1 addition & 1 deletion examples/gno.land/r/demo/keystore/keystore_test.gno
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import (
)

func TestRender(t *testing.T) {
const (
var (
author1 std.Address = testutils.TestAddress("author1")
author2 std.Address = testutils.TestAddress("author2")
)
Expand Down
2 changes: 1 addition & 1 deletion examples/gno.land/r/demo/microblog/microblog_test.gno
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import (
)

func TestMicroblog(t *testing.T) {
const (
var (
author1 std.Address = testutils.TestAddress("author1")
author2 std.Address = testutils.TestAddress("author2")
)
Expand Down
18 changes: 18 additions & 0 deletions gnovm/pkg/gnolang/preprocess.go
Original file line number Diff line number Diff line change
Expand Up @@ -2264,6 +2264,7 @@
// NOTE: may or may not be a *ConstExpr,
// but if not, make one now.
for i, vx := range n.Values {
checkConstantExpr(store, last, vx)
n.Values[i] = evalConst(store, last, vx)
}
} else {
Expand Down Expand Up @@ -2344,6 +2345,16 @@
if n.Type != nil {
// only a single type can be specified.
nt := evalStaticType(store, last, n.Type)
if n.Const {
if xnt, ok := nt.(*NativeType); ok {
nt = go2GnoBaseType(xnt.Type)
}

Check warning on line 2351 in gnovm/pkg/gnolang/preprocess.go

View check run for this annotation

Codecov / codecov/patch

gnovm/pkg/gnolang/preprocess.go#L2350-L2351

Added lines #L2350 - L2351 were not covered by tests

if _, ok := baseOf(nt).(PrimitiveType); !ok {
panic(fmt.Sprintf("invalid constant type %s", nt.String()))

Check warning on line 2354 in gnovm/pkg/gnolang/preprocess.go

View check run for this annotation

Codecov / codecov/patch

gnovm/pkg/gnolang/preprocess.go#L2354

Added line #L2354 was not covered by tests
}
}

for i := 0; i < numNames; i++ {
sts[i] = nt
}
Expand All @@ -2355,6 +2366,13 @@
// derive static type from values.
for i, vx := range n.Values {
vt := evalStaticTypeOf(store, last, vx)
if xnt, ok := vt.(*NativeType); ok {
vt = go2GnoBaseType(xnt.Type)
}

if _, ok := baseOf(vt).(PrimitiveType); !ok {
panic(fmt.Sprintf("invalid constant type %s", vt.String()))

Check warning on line 2374 in gnovm/pkg/gnolang/preprocess.go

View check run for this annotation

Codecov / codecov/patch

gnovm/pkg/gnolang/preprocess.go#L2374

Added line #L2374 was not covered by tests
}
sts[i] = vt
}
} else { // T is nil, n not const
Expand Down
109 changes: 109 additions & 0 deletions gnovm/pkg/gnolang/type_check.go
Original file line number Diff line number Diff line change
Expand Up @@ -215,6 +215,115 @@
}
}

func checkConstantExpr(store Store, last BlockNode, vx Expr) {
Main:
switch vx := vx.(type) {
case *NameExpr:
t := evalStaticTypeOf(store, last, vx)
if _, ok := t.(*ArrayType); ok {
thehowl marked this conversation as resolved.
Show resolved Hide resolved
break Main
ltzmaxwell marked this conversation as resolved.
Show resolved Hide resolved
}
panic(fmt.Sprintf("%s (variable of type %s) is not constant", vx.Name, t))
case *TypeAssertExpr:
panic(fmt.Sprintf("%s (comma, ok expression of type %s) is not constant", vx.String(), vx.Type))
case *IndexExpr:
panic(fmt.Sprintf("%s (variable of type %s) is not constant", vx.String(), vx.X))
case *CallExpr:
ift := evalStaticTypeOf(store, last, vx.Func)
switch baseOf(ift).(type) {
case *FuncType:
tup := evalStaticTypeOfRaw(store, last, vx).(*tupleType)

// check for built-in functions
petar-dambovaliev marked this conversation as resolved.
Show resolved Hide resolved
if cx, ok := vx.Func.(*ConstExpr); ok {
if fv, ok := cx.V.(*FuncValue); ok {
if fv.PkgPath == uversePkgPath {
// TODO: should support min, max
switch {
case fv.Name == "len":
checkConstantExpr(store, last, vx.Args[0])
break Main
case fv.Name == "cap":
checkConstantExpr(store, last, vx.Args[0])
break Main
}
}
}
}

switch {
case len(tup.Elts) == 0:
panic(fmt.Sprintf("%s (no value) used as value", vx.String()))
case len(tup.Elts) == 1:
panic(fmt.Sprintf("%s (value of type %s) is not constant", vx.String(), tup.Elts[0]))
default:
panic(fmt.Sprintf("multiple-value %s (value of type %s) in single-value context", vx.String(), tup.Elts))
ltzmaxwell marked this conversation as resolved.
Show resolved Hide resolved
}
case *TypeType:
for _, arg := range vx.Args {
checkConstantExpr(store, last, arg)
}
ltzmaxwell marked this conversation as resolved.
Show resolved Hide resolved
case *NativeType:
ltzmaxwell marked this conversation as resolved.
Show resolved Hide resolved
panic("NativeType\n")
default:
panic(fmt.Sprintf(
"unexpected func type %v (%v)",
ift, reflect.TypeOf(ift)))

Check warning on line 271 in gnovm/pkg/gnolang/type_check.go

View check run for this annotation

Codecov / codecov/patch

gnovm/pkg/gnolang/type_check.go#L266-L271

Added lines #L266 - L271 were not covered by tests
}
case *BinaryExpr:
checkConstantExpr(store, last, vx.Left)
checkConstantExpr(store, last, vx.Right)
ltzmaxwell marked this conversation as resolved.
Show resolved Hide resolved
case *SelectorExpr:
xt := evalStaticTypeOf(store, last, vx.X)
switch xt := xt.(type) {
case *PackageType:
// Todo: check if the package is const after the fix of https://github.com/gnolang/gno/issues/2836
// var pv *PackageValue
// if cx, ok := vx.X.(*ConstExpr); ok {
// // NOTE: *Machine.TestMemPackage() needs this
// // to pass in an imported package as *ConstEzpr.
// pv = cx.V.(*PackageValue)
// } else {
// // otherwise, packages can only be referred to by
// // *NameExprs, and cannot be copied.
// pvc := evalConst(store, last, vx.X)
// pv_, ok := pvc.V.(*PackageValue)
// if !ok {
// panic(fmt.Sprintf(
// "missing package in selector expr %s",
// vx.String()))
// }
// pv = pv_
// }
// if pv.GetBlock(store).Source.GetIsConst(store, vx.Sel) {
// break Main
// }
// panic(fmt.Sprintf("%s (variable of type %s) is not constant", vx.String(), xt))
omarsy marked this conversation as resolved.
Show resolved Hide resolved
case *PointerType, *DeclaredType, *StructType, *InterfaceType:
ltzmaxwell marked this conversation as resolved.
Show resolved Hide resolved
ltzmaxwell marked this conversation as resolved.
Show resolved Hide resolved
ty := evalStaticTypeOf(store, last, vx.X)
panic(fmt.Sprintf("%s (variable of type %s) is not constant", vx.String(), ty))
case *TypeType:
ty := evalStaticType(store, last, vx.X)
panic(fmt.Sprintf("%s (variable of type %s) is not constant", vx.String(), ty))
case *NativeType:
panic(fmt.Sprintf("%s (variable of type %s) is not constant", vx.String(), xt))
default:
panic(fmt.Sprintf(
"unexpected selector expression type %v",
reflect.TypeOf(xt)))

Check warning on line 313 in gnovm/pkg/gnolang/type_check.go

View check run for this annotation

Codecov / codecov/patch

gnovm/pkg/gnolang/type_check.go#L302-L313

Added lines #L302 - L313 were not covered by tests
}

case *ArrayTypeExpr:

Check warning on line 316 in gnovm/pkg/gnolang/type_check.go

View check run for this annotation

Codecov / codecov/patch

gnovm/pkg/gnolang/type_check.go#L316

Added line #L316 was not covered by tests
case *ConstExpr:
case *BasicLitExpr:

Check warning on line 318 in gnovm/pkg/gnolang/type_check.go

View check run for this annotation

Codecov / codecov/patch

gnovm/pkg/gnolang/type_check.go#L318

Added line #L318 was not covered by tests
case *CompositeLitExpr:
ltzmaxwell marked this conversation as resolved.
Show resolved Hide resolved
checkConstantExpr(store, last, vx.Type)
default:
ift := evalStaticType(store, last, vx)
panic(fmt.Sprintf("%s (variable of type %s) is not constant", vx.String(), ift))
}
}

// checkValDefineMismatch checks for mismatch between the number of variables and values in a ValueDecl or AssignStmt.
func checkValDefineMismatch(n Node) {
var (
Expand Down
11 changes: 11 additions & 0 deletions gnovm/tests/files/const23.gno
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package main

import "fmt"

func main() {
const t []string = []string{}
fmt.Println(t)
}

// Error:
// main/files/const23.gno:6:8: [](const-type string) (variable of type []string) is not constant
76 changes: 76 additions & 0 deletions gnovm/tests/files/const24.gno
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
package main

import (
"fmt"
"time"
)

func main() {
const a int = 1_000_000
const b byte = byte(1)
const c float64 = 1_000_000.000
const d string = "Hello, World!"
const e rune = 'a'
const g bool = true
const h uint = 1_000
const i int8 = 1
const j int16 = 1
const k int32 = 1
const l int64 = 1
const m uint8 = 1
const n uint16 = 1
const o uint32 = 1
const p uint64 = 1
const r float32 = 1_000_000.000
const s = r
const t = len("s")
const u = 1 + len("s") + 3
ars := [10]string{}
const v = len(ars)
const w = cap(ars)

fmt.Println(a)
fmt.Println(b)
fmt.Println(c)
fmt.Println(d)
fmt.Println(e)
fmt.Println(g)
fmt.Println(h)
fmt.Println(i)
fmt.Println(j)
fmt.Println(k)
fmt.Println(l)
fmt.Println(m)
fmt.Println(n)
fmt.Println(o)
fmt.Println(p)
fmt.Println(r)
fmt.Println(s)
fmt.Println(t)
fmt.Println(u)
fmt.Println(v)
fmt.Println(w)
}

// Output:
// 1000000
// 1
// 1e+06
// Hello, World!
// 97
// true
// 1000
// 1
// 1
// 1
// 1
// 1
// 1
// 1
// 1
// 1e+06
// 1e+06
// 1
// 5
// 10
// 10
11 changes: 11 additions & 0 deletions gnovm/tests/files/const25.gno
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package main

import "fmt"

func main() {
const t = []string{"1"}
fmt.Println(t)
}

// Error:
// main/files/const25.gno:6:8: [](const-type string) (variable of type []string) is not constant
15 changes: 15 additions & 0 deletions gnovm/tests/files/const26.gno
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package main

import "fmt"

func v() string {
return ""
}

func main() {
const t = v()
fmt.Println(t)
}

// Error:
// main/files/const26.gno:10:8: v<VPBlock(3,0)>() (value of type string) is not constant
16 changes: 16 additions & 0 deletions gnovm/tests/files/const27.gno
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package main

import "fmt"

func v() string {
return ""
}

func main() {
var i interface{} = 1
const t, ok = i.(int)
fmt.Println(t, ok)
}

// Error:
// main/files/const27.gno:11:8: i<VPBlock(1,0)>.((const-type int)) (comma, ok expression of type (const-type int)) is not constant
12 changes: 12 additions & 0 deletions gnovm/tests/files/const28.gno
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package main

import "fmt"

func main() {
var s []string = []string{"1"}
const t, ok = s[0]
fmt.Println(t, ok)
}

// Error:
// main/files/const28.gno:7:8: s<VPBlock(1,0)>[(const (0 int))] (variable of type s<VPBlock(1,0)>) is not constant
12 changes: 12 additions & 0 deletions gnovm/tests/files/const29.gno
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package main

import "fmt"

func main() {
s := "1"
const t = s
fmt.Println(t)
}

// Error:
// main/files/const29.gno:7:8: s (variable of type string) is not constant
15 changes: 15 additions & 0 deletions gnovm/tests/files/const30.gno
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package main

import "fmt"

func v() {
return
}

func main() {
const t = v()
fmt.Println(t)
}

// Error:
// main/files/const30.gno:10:8: v<VPBlock(3,0)>() (no value) used as value
15 changes: 15 additions & 0 deletions gnovm/tests/files/const31.gno
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package main

import "fmt"

func v() (string, string) {
return "", ""
}

func main() {
const t, v = v()
fmt.Println(t)
}

// Error:
// main/files/const31.gno:10:8: multiple-value (const (v func()( string, string)))() (value of type [string string]) in single-value context
11 changes: 11 additions & 0 deletions gnovm/tests/files/const32.gno
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package main

import "fmt"

func main() {
const t = 1 + 2 + len([]string{})
fmt.Println(t)
}

thehowl marked this conversation as resolved.
Show resolved Hide resolved
// Error:
// main/files/const32.gno:6:8: [](const-type string) (variable of type []string) is not constant
Loading