From a22ce24d4def408b79566b00db1327b604789f07 Mon Sep 17 00:00:00 2001 From: Blake <104744707+r3v4s@users.noreply.github.com> Date: Fri, 14 Jun 2024 01:26:10 +0900 Subject: [PATCH 01/26] feat(std): support timestamp skipping in test cases (#569) # Description support timestamp skipping in test cases # How has this been tested? test case run by gnodev --- docs/reference/stdlibs/std/testing.md | 2 ++ .../gno.land/p/demo/rand/rand0_filetest.gno | 10 +++---- .../r/x/skip_height_to_skip_time/skiptime.gno | 1 + .../skiptime_test.gno | 27 +++++++++++++++++++ gnovm/tests/stdlibs/std/std.go | 1 + 5 files changed, 36 insertions(+), 5 deletions(-) create mode 100644 examples/gno.land/r/x/skip_height_to_skip_time/skiptime.gno create mode 100644 examples/gno.land/r/x/skip_height_to_skip_time/skiptime_test.gno diff --git a/docs/reference/stdlibs/std/testing.md b/docs/reference/stdlibs/std/testing.md index 102b9ed6d70..9efb98e351d 100644 --- a/docs/reference/stdlibs/std/testing.md +++ b/docs/reference/stdlibs/std/testing.md @@ -20,6 +20,8 @@ func TestSkipHeights(count int64) ``` Modifies the block height variable by skipping **count** blocks. +It also increases block timestamp by 5 seconds for every single count + #### Usage ```go std.TestSkipHeights(100) diff --git a/examples/gno.land/p/demo/rand/rand0_filetest.gno b/examples/gno.land/p/demo/rand/rand0_filetest.gno index c5c138924fc..446e04b696d 100644 --- a/examples/gno.land/p/demo/rand/rand0_filetest.gno +++ b/examples/gno.land/p/demo/rand/rand0_filetest.gno @@ -49,8 +49,8 @@ func main() { // 177 // 802 // --- -// 450 -// 78 -// 777 -// 15 -// 339 +// 269 +// 233 +// 591 +// 936 +// 908 diff --git a/examples/gno.land/r/x/skip_height_to_skip_time/skiptime.gno b/examples/gno.land/r/x/skip_height_to_skip_time/skiptime.gno new file mode 100644 index 00000000000..524e6f58ad9 --- /dev/null +++ b/examples/gno.land/r/x/skip_height_to_skip_time/skiptime.gno @@ -0,0 +1 @@ +package skiptime diff --git a/examples/gno.land/r/x/skip_height_to_skip_time/skiptime_test.gno b/examples/gno.land/r/x/skip_height_to_skip_time/skiptime_test.gno new file mode 100644 index 00000000000..52670a5626b --- /dev/null +++ b/examples/gno.land/r/x/skip_height_to_skip_time/skiptime_test.gno @@ -0,0 +1,27 @@ +package skiptime + +import ( + "std" + "testing" + "time" +) + +func TestSkipHeights(t *testing.T) { + oldHeight := std.GetHeight() + shouldEQ(t, oldHeight, 123) + + oldNow := time.Now().Unix() + shouldEQ(t, oldNow, 1234567890) + + // skip 3 blocks == 15 seconds + std.TestSkipHeights(3) + + shouldEQ(t, std.GetHeight()-oldHeight, 3) + shouldEQ(t, time.Now().Unix()-oldNow, 15) +} + +func shouldEQ(t *testing.T, got, expected int64) { + if got != expected { + t.Fatalf("expected %d, got %d.", expected, got) + } +} diff --git a/gnovm/tests/stdlibs/std/std.go b/gnovm/tests/stdlibs/std/std.go index ee17ccb2c15..0421f359932 100644 --- a/gnovm/tests/stdlibs/std/std.go +++ b/gnovm/tests/stdlibs/std/std.go @@ -57,6 +57,7 @@ func IsOriginCall(m *gno.Machine) bool { func TestSkipHeights(m *gno.Machine, count int64) { ctx := m.Context.(*TestExecContext) ctx.Height += count + ctx.Timestamp += (count * 5) m.Context = ctx } From b89a9c934cd9419345390eb205b42e17ce385226 Mon Sep 17 00:00:00 2001 From: Manfred Touron <94029+moul@users.noreply.github.com> Date: Thu, 13 Jun 2024 18:45:35 +0200 Subject: [PATCH 02/26] feat: improve p/ownable API (#2330) Improve the `p/ownable` API based on my needs encountered recently. - switch from origcaller to prevrealm - add AssertXXX helper - add a new constructor taking an arbitrary address - improve coding style in tests - identified a new bug with `std.TestSetRealm` (cc @thehowl) Part of #2150 --------- Signed-off-by: moul <94029+moul@users.noreply.github.com> Co-authored-by: Leon Hudak <33522493+leohhhn@users.noreply.github.com> --- examples/gno.land/p/demo/ownable/ownable.gno | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/examples/gno.land/p/demo/ownable/ownable.gno b/examples/gno.land/p/demo/ownable/ownable.gno index 22c0c33acc6..75ebcde0a28 100644 --- a/examples/gno.land/p/demo/ownable/ownable.gno +++ b/examples/gno.land/p/demo/ownable/ownable.gno @@ -4,6 +4,8 @@ import ( "std" ) +const OwnershipTransferEvent = "OwnershipTransfer" + // Ownable is meant to be used as a top-level object to make your contract ownable OR // being embedded in a Gno object to manage per-object ownership. type Ownable struct { @@ -31,7 +33,13 @@ func (o *Ownable) TransferOwnership(newOwner std.Address) error { return ErrInvalidAddress } + prevOwner := o.owner o.owner = newOwner + std.Emit( + OwnershipTransferEvent, + "from", string(prevOwner), + "to", string(newOwner), + ) return nil } @@ -44,7 +52,15 @@ func (o *Ownable) DropOwnership() error { return err } + prevOwner := o.owner o.owner = "" + + std.Emit( + OwnershipTransferEvent, + "from", string(prevOwner), + "to", "", + ) + return nil } From cbd0725c4d738fded0137febfadac52907a4df8e Mon Sep 17 00:00:00 2001 From: Alex Gherasie <68433935+agherasie@users.noreply.github.com> Date: Thu, 13 Jun 2024 21:03:18 +0200 Subject: [PATCH 03/26] fix(docs): missing 'false' return in Iterate() methods (#2356) Fixes https://github.com/gnolang/gno/issues/2310 The example code provided in https://docs.gno.land/how-to-guides/write-simple-dapp/ was missing a `return false` inside the `Iterate()` method, resulting in a `missing return` error when attempting to deploy. This PR adds the missing return to the example code Before: ![image](https://github.com/gnolang/gno/assets/68433935/63c57440-4e1f-41e4-8b05-5772142cb5c6) After: ![image](https://github.com/gnolang/gno/assets/68433935/e880527c-d9f1-4b13-8a94-74771f44e7d9)
Contributors' checklist... - [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).
--------- Co-authored-by: Leon Hudak <33522493+leohhhn@users.noreply.github.com> --- docs/assets/how-to-guides/write-simple-dapp/poll-1.gno | 2 ++ docs/how-to-guides/write-simple-dapp.md | 2 ++ 2 files changed, 4 insertions(+) diff --git a/docs/assets/how-to-guides/write-simple-dapp/poll-1.gno b/docs/assets/how-to-guides/write-simple-dapp/poll-1.gno index bf2a64743d0..98b0ae4ed7a 100644 --- a/docs/assets/how-to-guides/write-simple-dapp/poll-1.gno +++ b/docs/assets/how-to-guides/write-simple-dapp/poll-1.gno @@ -64,6 +64,8 @@ func (p Poll) VoteCount() (int, int) { if vote == true { yay = yay + 1 } + + return false }) return yay, p.Voters().Size() - yay } diff --git a/docs/how-to-guides/write-simple-dapp.md b/docs/how-to-guides/write-simple-dapp.md index a46d6688fa9..851320b2a61 100644 --- a/docs/how-to-guides/write-simple-dapp.md +++ b/docs/how-to-guides/write-simple-dapp.md @@ -94,6 +94,8 @@ func (p Poll) VoteCount() (int, int) { if vote == true { yay = yay + 1 } + + return false }) return yay, p.Voters().Size() - yay } From 6ec4bb80ee053d1a20c4109a2742e8cfc7a5eac4 Mon Sep 17 00:00:00 2001 From: Morgan Date: Thu, 13 Jun 2024 23:24:46 +0200 Subject: [PATCH 04/26] chore(gnodev): fix typo (#2341) --- contribs/gnodev/pkg/dev/node.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contribs/gnodev/pkg/dev/node.go b/contribs/gnodev/pkg/dev/node.go index d839091d328..cede02d0ebc 100644 --- a/contribs/gnodev/pkg/dev/node.go +++ b/contribs/gnodev/pkg/dev/node.go @@ -237,7 +237,7 @@ func (n *Node) updatePackages(paths ...string) error { pkgsUpdated += len(pkgslist) } - n.logger.Info(fmt.Sprintf("updated %d pacakges", pkgsUpdated)) + n.logger.Info(fmt.Sprintf("updated %d packages", pkgsUpdated)) return nil } From b42d0f06fb7c1e54cfdb4580fcd8684cd6e54d05 Mon Sep 17 00:00:00 2001 From: ltzmaxwell Date: Fri, 14 Jun 2024 16:38:05 +0800 Subject: [PATCH 05/26] fix(gnovm): Correct file test issue in zream12 (#2340) This file(zrealm12.gno) causes a panic that isn't caught(as it's missing import), making the test invalid. This PR addresses the issue. --- gnovm/tests/files/zrealm12.gno | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/gnovm/tests/files/zrealm12.gno b/gnovm/tests/files/zrealm12.gno index ee9e85d827b..d201ecc1470 100644 --- a/gnovm/tests/files/zrealm12.gno +++ b/gnovm/tests/files/zrealm12.gno @@ -2,6 +2,7 @@ package test import ( + "gno.land/r/demo/tests" "std" ) @@ -23,3 +24,6 @@ func main() { panic("should not happen") } } + +// Output: +// second's child From e7e47d2589ceece37b0502d0df8d54ded582d501 Mon Sep 17 00:00:00 2001 From: deelawn Date: Fri, 14 Jun 2024 10:08:02 +0100 Subject: [PATCH 06/26] fix: default untyped to uint when necessary (#2024) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Closes #2004. This change allows for passing a value to `defaultTypeOf`. In the case where we are looking for the default value of an untyped int, it can use the value, if it exists, in order to determine whether the default type should be a signed or unsigned int.
Contributors' checklist... - [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).
--------- Co-authored-by: Miloš Živković --- gnovm/pkg/gnolang/preprocess.go | 2 +- gnovm/pkg/gnolang/types.go | 19 ++++++++++++++----- gnovm/pkg/gnolang/values.go | 2 +- gnovm/pkg/gnolang/values_conversions.go | 2 +- gnovm/tests/files/bigint1.gno | 14 ++++++++++++++ 5 files changed, 31 insertions(+), 8 deletions(-) create mode 100644 gnovm/tests/files/bigint1.gno diff --git a/gnovm/pkg/gnolang/preprocess.go b/gnovm/pkg/gnolang/preprocess.go index 459910505b9..88c5c2f1da4 100644 --- a/gnovm/pkg/gnolang/preprocess.go +++ b/gnovm/pkg/gnolang/preprocess.go @@ -2477,7 +2477,7 @@ func checkOrConvertType(store Store, last BlockNode, x *Expr, t Type, autoNative // convert type if isUntyped(xt) { // convert if x is untyped literal if t == nil { - t = defaultTypeOf(xt) + t = defaultTypeOf(xt, nil) } // Push type into expr if qualifying binary expr. if bx, ok := (*x).(*BinaryExpr); ok { diff --git a/gnovm/pkg/gnolang/types.go b/gnovm/pkg/gnolang/types.go index fcfcd7d9d37..86b3d588eda 100644 --- a/gnovm/pkg/gnolang/types.go +++ b/gnovm/pkg/gnolang/types.go @@ -1203,8 +1203,8 @@ func (ft *FuncType) Specify(store Store, argTVs []TypedValue, isVarg bool) *Func continue } else if vargt == nil { vargt = varg.T - } else if isUntyped(varg.T) && vargt.TypeID() == defaultTypeOf(varg.T).TypeID() { - vargt = defaultTypeOf(varg.T) + } else if isUntyped(varg.T) && vargt.TypeID() == defaultTypeOf(varg.T, varg.V).TypeID() { + vargt = defaultTypeOf(varg.T, varg.V) } else if vargt.TypeID() != varg.T.TypeID() { panic(fmt.Sprintf( "incompatible varg types: expected %v, got %s", @@ -2281,14 +2281,23 @@ func isDataByte(t Type) bool { // TODO move untyped const stuff to preprocess.go. // TODO associate with ConvertTo() in documentation. -func defaultTypeOf(t Type) Type { +func defaultTypeOf(t Type, v Value) Type { switch t { case UntypedBoolType: return BoolType case UntypedRuneType: return Int32Type case UntypedBigintType: - return IntType + typeVal := IntType + if bigintValue, ok := v.(BigintValue); ok { + if bigintValue.V != nil && bigintValue.V.Sign() == 1 && !bigintValue.V.IsInt64() { + // Use an unsigned type if the value is positive and we know + // it won't fit in an int64. + typeVal = Uint64Type + } + } + + return typeVal case UntypedBigdecType: return Float64Type case UntypedStringType: @@ -2514,7 +2523,7 @@ func specifyType(store Store, lookup map[Name]Type, tmpl Type, spec Type, specTy return // ok } else { if isUntyped(spec) { - spec = defaultTypeOf(spec) + spec = defaultTypeOf(spec, nil) } lookup[ct.Generic] = spec return // ok diff --git a/gnovm/pkg/gnolang/values.go b/gnovm/pkg/gnolang/values.go index b0996b98b6f..d8d4bc58bc3 100644 --- a/gnovm/pkg/gnolang/values.go +++ b/gnovm/pkg/gnolang/values.go @@ -1594,7 +1594,7 @@ func (tv *TypedValue) Assign(alloc *Allocator, tv2 TypedValue, cu bool) { } *tv = tv2.Copy(alloc) if cu && isUntyped(tv.T) { - ConvertUntypedTo(tv, defaultTypeOf(tv.T)) + ConvertUntypedTo(tv, defaultTypeOf(tv.T, tv.V)) } } diff --git a/gnovm/pkg/gnolang/values_conversions.go b/gnovm/pkg/gnolang/values_conversions.go index b4888878c7a..edaa8883819 100644 --- a/gnovm/pkg/gnolang/values_conversions.go +++ b/gnovm/pkg/gnolang/values_conversions.go @@ -926,7 +926,7 @@ func ConvertUntypedTo(tv *TypedValue, t Type) { } // general case if t == nil { - t = defaultTypeOf(tv.T) + t = defaultTypeOf(tv.T, tv.V) } switch tv.T { case UntypedBoolType: diff --git a/gnovm/tests/files/bigint1.gno b/gnovm/tests/files/bigint1.gno new file mode 100644 index 00000000000..01032e27b3f --- /dev/null +++ b/gnovm/tests/files/bigint1.gno @@ -0,0 +1,14 @@ +package main + +import ( + "math" +) + +func main() { + println(float64(math.MaxUint32)) + println(float64(math.MaxUint64)) +} + +// Output: +// 4.294967295e+09 +// 1.8446744073709552e+19 From c5b999f22bd165524ec0534bc3d2c0969a16a674 Mon Sep 17 00:00:00 2001 From: Manfred Touron <94029+moul@users.noreply.github.com> Date: Mon, 17 Jun 2024 12:13:19 +0200 Subject: [PATCH 07/26] feat: govdao mvp improvement (#2344) Continues #1945 --------- Signed-off-by: moul <94029+moul@users.noreply.github.com> --- examples/gno.land/p/gov/proposal/proposal.gno | 24 +++- examples/gno.land/p/gov/proposal/types.gno | 12 +- examples/gno.land/r/gov/dao/dao.gno | 124 ++++++++++++++---- examples/gno.land/r/gov/dao/gno.mod | 5 +- examples/gno.land/r/gov/dao/types.gno | 10 ++ examples/gno.land/r/gov/integration/gno.mod | 3 + .../r/gov/integration/integration.gno | 4 + .../gno.land/r/gov/integration/z_filetest.gno | 45 +++++++ .../gno.land/r/gov/proposals/prop1/prop1.gno | 9 +- .../gno.land/r/sys/validators/validators.gno | 4 +- 10 files changed, 203 insertions(+), 37 deletions(-) create mode 100644 examples/gno.land/r/gov/dao/types.gno create mode 100644 examples/gno.land/r/gov/integration/gno.mod create mode 100644 examples/gno.land/r/gov/integration/integration.gno create mode 100644 examples/gno.land/r/gov/integration/z_filetest.gno diff --git a/examples/gno.land/p/gov/proposal/proposal.gno b/examples/gno.land/p/gov/proposal/proposal.gno index f01d3661a5e..d4f151f935a 100644 --- a/examples/gno.land/p/gov/proposal/proposal.gno +++ b/examples/gno.land/p/gov/proposal/proposal.gno @@ -1,6 +1,10 @@ // Package proposal provides a structure for executing proposals. package proposal +import "std" + +const daoPkgPath = "gno.land/r/gov/dao" // XXX: make it configurable with r/sys/vars? + // NewExecutor creates a new executor with the provided callback function. func NewExecutor(callback func() error) Executor { return &executorImpl{ @@ -21,7 +25,7 @@ func (exec *executorImpl) Execute() error { if exec.done { return ErrAlreadyDone } - // XXX: assertCalledByGovdao + assertCalledByGovdao() err := exec.callback() exec.done = true exec.success = err == nil @@ -37,3 +41,21 @@ func (exec *executorImpl) Done() bool { func (exec *executorImpl) Success() bool { return exec.success } + +func (exec executorImpl) Status() Status { + switch { + case exec.success: + return Success + case exec.done: + return Failed + default: + return NotExecuted + } +} + +func assertCalledByGovdao() { + caller := std.CurrentRealm().PkgPath() + if caller != daoPkgPath { + panic("only gov/dao can execute proposals") + } +} diff --git a/examples/gno.land/p/gov/proposal/types.gno b/examples/gno.land/p/gov/proposal/types.gno index a2ebad6f585..d84d1bfd21f 100644 --- a/examples/gno.land/p/gov/proposal/types.gno +++ b/examples/gno.land/p/gov/proposal/types.gno @@ -8,9 +8,19 @@ import "errors" type Executor interface { Execute() error Done() bool - Success() bool // Done() && !err + Success() bool // Done() && !err + Status() Status // human-readable execution status } // ErrAlreadyDone is the error returned when trying to execute an already // executed proposal. var ErrAlreadyDone = errors.New("already executed") + +// Status enum. +type Status string + +var ( + NotExecuted Status = "not_executed" + Success Status = "success" + Failed Status = "failed" +) diff --git a/examples/gno.land/r/gov/dao/dao.gno b/examples/gno.land/r/gov/dao/dao.gno index 37caca9fa19..68f188eb0a4 100644 --- a/examples/gno.land/r/gov/dao/dao.gno +++ b/examples/gno.land/r/gov/dao/dao.gno @@ -2,60 +2,88 @@ package govdao import ( "std" + "strconv" - "gno.land/p/gov/proposal" + "gno.land/p/demo/ufmt" + pproposal "gno.land/p/gov/proposal" ) -var proposals = make([]Proposal, 0) +var proposals = make([]*proposal, 0) // XXX var members ... -// Proposal represents a proposal in the governance system. -type Proposal struct { - author std.Address +type proposal struct { idx int - Comment string - Executor proposal.Executor + author std.Address + comment string + executor pproposal.Executor + // XXX: make "accepted" and "finished" managed by an interface that can have various voting implementations + accepted bool + finished bool +} + +func (p proposal) Status() Status { + if p.executor.Done() { + return Status(p.executor.Status()) + } + if p.accepted { + return Accepted + } + // XXX: timeout + // XXX: not_accepted + return Active } // Propose is designed to be called by another contract or with // `maketx run`, not by a `maketx call`. -func Propose(proposal Proposal) int { +func Propose(comment string, executor pproposal.Executor) int { // XXX: require payment? - // XXX: sanitize proposal + if executor == nil { + panic("missing proposal executor") + } caller := std.PrevRealm().Addr() AssertIsMember(caller) - proposal.author = caller - proposal.idx = len(proposals) - proposals = append(proposals, proposal) - return proposal.idx + + prop := &proposal{ + comment: comment, + executor: executor, + author: caller, + idx: len(proposals), + } + + proposals = append(proposals, prop) + return prop.idx } func VoteOnProposal(idx int, option string) { + assertProposalExists(idx) caller := std.PrevRealm().Addr() AssertIsMember(caller) - panic("not implemented") - // XXX: implement the voting (woudl be cool to have a generic p/) + + prop := getProposal(idx) + if prop.finished { + panic("prop is not active anymore, cannot vote.") + } + // XXX: implement the real voting (would be cool to have a generic p/) + prop.accepted = option == "YES" + prop.finished = true } func ExecuteProposal(idx int) { assertProposalExists(idx) - // XXX: assert voting is finished - // XXX: assert voting result is YES - // XXX: proposal was not already executed - proposal := proposals[idx] - proposal.Executor.Execute() -} - -func assertProposalExists(idx int) { - if idx < 0 || idx >= len(proposals) { - panic("invalid proposal id") + prop := getProposal(idx) + if !prop.finished { + panic("prop is still active, cannot execute.") } + if !prop.accepted { + panic("prop is not accepted, cannot execute.") + } + prop.executor.Execute() } func IsMember(addr std.Address) bool { // XXX: implement - return true + return true // in the meantime, everyone is a DAO member } func AssertIsMember(addr std.Address) { @@ -63,3 +91,47 @@ func AssertIsMember(addr std.Address) { panic("caller is not member of govdao") } } + +func Render(path string) string { + if path == "" { + output := "" + for idx, prop := range proposals { + output += ufmt.Sprintf("- [/r/gov/dao:%d](%d) - %s (by %s)", idx, idx, prop.comment, prop.author) + } + return output + } + + // else display the proposal + idx, err := strconv.Atoi(path) + if err != nil { + return "404" + } + + if !proposalExists(idx) { + return "404" + } + prop := getProposal(idx) + output := "" + output += ufmt.Sprintf("# Prop#%d", prop.idx) + "\n" + output += "\n" + output += prop.comment + output += "\n" + output += ufmt.Sprintf("Status: %s", string(prop.Status())) + output += "\n" + output += ufmt.Sprintf("Author: %s", string(prop.author)) + return output +} + +func getProposal(idx int) *proposal { + return proposals[idx-1] +} + +func proposalExists(idx int) bool { + return idx > 0 && idx <= len(proposals) +} + +func assertProposalExists(idx int) { + if !proposalExists(idx) { + panic("invalid proposal id") + } +} diff --git a/examples/gno.land/r/gov/dao/gno.mod b/examples/gno.land/r/gov/dao/gno.mod index ae296cf121c..0127e84a8e2 100644 --- a/examples/gno.land/r/gov/dao/gno.mod +++ b/examples/gno.land/r/gov/dao/gno.mod @@ -1,3 +1,6 @@ module gno.land/r/gov/dao -require gno.land/p/gov/proposal v0.0.0-latest +require ( + gno.land/p/demo/ufmt v0.0.0-latest + gno.land/p/gov/proposal v0.0.0-latest +) diff --git a/examples/gno.land/r/gov/dao/types.gno b/examples/gno.land/r/gov/dao/types.gno new file mode 100644 index 00000000000..9e4ca0718c9 --- /dev/null +++ b/examples/gno.land/r/gov/dao/types.gno @@ -0,0 +1,10 @@ +package govdao + +// Status enum. +type Status string + +var ( + Accepted Status = "accepted" + Active Status = "active" + // Timeout, NotAccepted +) diff --git a/examples/gno.land/r/gov/integration/gno.mod b/examples/gno.land/r/gov/integration/gno.mod new file mode 100644 index 00000000000..f584f375133 --- /dev/null +++ b/examples/gno.land/r/gov/integration/gno.mod @@ -0,0 +1,3 @@ +// Draft + +module integration diff --git a/examples/gno.land/r/gov/integration/integration.gno b/examples/gno.land/r/gov/integration/integration.gno new file mode 100644 index 00000000000..5b47b3dec83 --- /dev/null +++ b/examples/gno.land/r/gov/integration/integration.gno @@ -0,0 +1,4 @@ +// Package integration tests the govdao ecosystem from an external perspective. +// It aims to confirm that the system can remain static while supporting +// additional DAO use cases over time. +package integration diff --git a/examples/gno.land/r/gov/integration/z_filetest.gno b/examples/gno.land/r/gov/integration/z_filetest.gno new file mode 100644 index 00000000000..a85588e4f11 --- /dev/null +++ b/examples/gno.land/r/gov/integration/z_filetest.gno @@ -0,0 +1,45 @@ +package main + +import ( + govdao "gno.land/r/gov/dao" + _ "gno.land/r/gov/proposals/prop1" +) + +func main() { + println("--") + println(govdao.Render("")) + println("--") + println(govdao.Render("1")) + println("--") + govdao.VoteOnProposal(1, "YES") + println("--") + println(govdao.Render("1")) + println("--") + govdao.ExecuteProposal(1) + println("--") + println(govdao.Render("1")) +} + +// Output: +// -- +// - [/r/gov/dao:0](0) - manual valset changes proposal example (by g1tk0fscr3p5g8hnhxq6v93jxcpm5g3cstlxfxa3) +// -- +// # Prop#0 +// +// manual valset changes proposal example +// Status: active +// Author: g1tk0fscr3p5g8hnhxq6v93jxcpm5g3cstlxfxa3 +// -- +// -- +// # Prop#0 +// +// manual valset changes proposal example +// Status: accepted +// Author: g1tk0fscr3p5g8hnhxq6v93jxcpm5g3cstlxfxa3 +// -- +// -- +// # Prop#0 +// +// manual valset changes proposal example +// Status: success +// Author: g1tk0fscr3p5g8hnhxq6v93jxcpm5g3cstlxfxa3 diff --git a/examples/gno.land/r/gov/proposals/prop1/prop1.gno b/examples/gno.land/r/gov/proposals/prop1/prop1.gno index 6e5edb0c97b..68cd9d60bfa 100644 --- a/examples/gno.land/r/gov/proposals/prop1/prop1.gno +++ b/examples/gno.land/r/gov/proposals/prop1/prop1.gno @@ -27,13 +27,10 @@ func init() { // Wraps changesFn to emit a certified event only if executed from a // complete governance proposal process. - executor := validators.NewProposalExecutor(changesFn) + executor := validators.NewPropExecutor(changesFn) // Create a proposal. // XXX: payment - proposal := govdao.Proposal{ - Comment: "manual valset changes proposal example", - Executor: executor, - } - govdao.Propose(proposal) + comment := "manual valset changes proposal example" + govdao.Propose(comment, executor) } diff --git a/examples/gno.land/r/sys/validators/validators.gno b/examples/gno.land/r/sys/validators/validators.gno index 0e6e132f6e9..5fb08ebbfc7 100644 --- a/examples/gno.land/r/sys/validators/validators.gno +++ b/examples/gno.land/r/sys/validators/validators.gno @@ -15,10 +15,10 @@ type Change struct { Power int } -// NewProposalExecutor creates a new executor that wraps a changes closure +// NewPropExecutor creates a new executor that wraps a changes closure // proposal. It emits a typed object (subscribed by tm2) only if it passes // through a complete p/gov/proposal process. -func NewProposalExecutor(changesFn func() []Change) proposal.Executor { +func NewPropExecutor(changesFn func() []Change) proposal.Executor { if changesFn == nil { panic("changesFn should not be nil") } From fcbc61e3ebb02a6cc2f6cfe58e93ac75da88d109 Mon Sep 17 00:00:00 2001 From: Morgan Date: Mon, 17 Jun 2024 16:11:23 +0200 Subject: [PATCH 08/26] chore(docs): bump minimum version to go 1.21 (#2328) @leohhhn this should be kept in sync with the go version in go.mod if we want to have something which we don't need to update, we can say simply that "we support the latest 2 Go [major versions](https://go.dev/doc/devel/release)" --- docs/getting-started/local-setup/installation.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/getting-started/local-setup/installation.md b/docs/getting-started/local-setup/installation.md index fe96998e239..8700ff9a2b2 100644 --- a/docs/getting-started/local-setup/installation.md +++ b/docs/getting-started/local-setup/installation.md @@ -13,7 +13,7 @@ to run on your machine. ## Prerequisites - **Git** - **`make` (for running Makefiles)** -- **Go 1.19+** +- **Go 1.21+** - **Go Environment Setup**: - Make sure `$GOPATH` is well-defined, and `$GOPATH/bin` is added to your `$PATH` variable. - To do this, you can add the following line to your `.bashrc`, `.zshrc` or other config file: From 5fdbce0e1fe533165c0c2009e93695ece677b2bd Mon Sep 17 00:00:00 2001 From: Morgan Date: Mon, 17 Jun 2024 16:14:03 +0200 Subject: [PATCH 09/26] fix(contribs): revert back to `make .` syntax instead of the opposite (#2353) Please, can we take a bit of care when modifying the syntaxes of our makefile commands? They may not break code, but they break documentation and user flows. We can add a CI check as well; I see this for another PR as this is a hotfix. (Currently, running `make install` / `make install.gnodev` in the top-level directory doesn't work; because @moul inverted these in #1945). This is still not a substitute for a bit of good ol' attention in recognising when something is user-facing and thus should be changed with a bit more care and reason. Note, I'm NOT saying that we should not change things, as we are before any 1.0 so we should change anything that makes sense; but it is a good practice that when changing a flag, command, etc., to do a global search for the old syntax to see examples where old documentation or untested code is broken. --- contribs/Makefile | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/contribs/Makefile b/contribs/Makefile index 04b607cb32d..5a2a00fc2ef 100644 --- a/contribs/Makefile +++ b/contribs/Makefile @@ -31,27 +31,27 @@ install: @echo 'To install a tool, go to the subdirectory, then run `make install`.' @echo 'To do a full installation, run `make install_all`.' -install_all: $(addsuffix .install,$(programs)) -%.install: - @echo "[+] make -C $(basename $@) install" - $(MAKE) --no-print-directory -C $(basename $@) install +install_all: $(addprefix install.,$(programs)) +install.%: + @echo "[+] make -C $(subst install.,,$@) install" + $(MAKE) --no-print-directory -C $(subst install.,,$@) install .PHONY: install_all ######################################## # Test suite -test: $(addsuffix .test,$(programs)) -%.test: - @echo "[+] make -C $(basename $@) install" - $(MAKE) --no-print-directory -C $(basename $@) test -.PHONY: test +test: $(addprefix test.,$(programs)) +test.%: + @echo "[+] make -C $(subst test.,,$@) install" + $(MAKE) --no-print-directory -C $(subst test.,,$@) test +.PHONY: test ######################################## # Lint .PHONY: lint -lint: $(addsuffix .lint,$(programs)) -%.lint: - @echo "[+] make -C $(basename $@) install" - $(MAKE) --no-print-directory -C $(basename $@) lint +lint: $(addprefix lint.,$(programs)) +lint.%: + @echo "[+] make -C $(subst lint.,,$@) install" + $(MAKE) --no-print-directory -C $(subst lint.,,$@) lint ######################################## # Dev tools From aa9c64a110e1aec33388e6d2688d7a5f0528823f Mon Sep 17 00:00:00 2001 From: Leon Hudak <33522493+leohhhn@users.noreply.github.com> Date: Tue, 18 Jun 2024 09:49:02 +0200 Subject: [PATCH 10/26] docs: add `TestSetRealm` reference docs (#2369) ## Description This PR adds `TestSetRealm` docs, as well as related docs. It also fixes up a few minor details. Closes: #2273
Contributors' checklist... - [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).
--------- Co-authored-by: Morgan --- docs/reference/stdlibs/std/testing.md | 77 +++++++++++++++++++++++++-- gnovm/tests/stdlibs/std/std.gno | 2 +- 2 files changed, 74 insertions(+), 5 deletions(-) diff --git a/docs/reference/stdlibs/std/testing.md b/docs/reference/stdlibs/std/testing.md index 9efb98e351d..7a383478ef5 100644 --- a/docs/reference/stdlibs/std/testing.md +++ b/docs/reference/stdlibs/std/testing.md @@ -10,11 +10,15 @@ func TestSetOrigCaller(addr Address) func TestSetOrigPkgAddr(addr Address) func TestSetOrigSend(sent, spent Coins) func TestIssueCoins(addr Address, coins Coins) +func TestSetRealm(realm Realm) +func NewUserRealm(address Address) +func NewCodeRealm(pkgPath string) ``` --- ## TestSkipHeights + ```go func TestSkipHeights(count int64) ``` @@ -29,6 +33,7 @@ std.TestSkipHeights(100) --- ## TestSetOrigCaller + ```go func TestSetOrigCaller(addr Address) ``` @@ -36,23 +41,26 @@ Sets the current caller of the transaction to **addr**. #### Usage ```go -std.TestSetOrigCaller("g1jg8mtutu9khhfwc4nxmuhcpftf0pajdhfvsqf5") +std.TestSetOrigCaller(std.Address("g1jg8mtutu9khhfwc4nxmuhcpftf0pajdhfvsqf5")) ``` --- ## TestSetOrigPkgAddr + ```go func TestSetOrigPkgAddr(addr Address) ``` -Sets the current realm/package address to **addr**. +Sets the call entry realm address to **addr**. #### Usage ```go -std.TestSetOrigPkgAddr("g1ecely4gjy0yl6s9kt409ll330q9hk2lj9ls3ec") +std.TestSetOrigPkgAddr(std.Address("g1ecely4gjy0yl6s9kt409ll330q9hk2lj9ls3ec")) ``` + --- ## TestSetOrigSend + ```go func TestSetOrigSend(sent, spent Coins) ``` @@ -65,17 +73,78 @@ std.TestSetOrigSend(sent, spent Coins) --- ## TestIssueCoins + ```go func TestIssueCoins(addr Address, coins Coins) ``` + Issues testing context **coins** to **addr**. + #### Usage + ```go issue := std.Coins{{"coin1", 100}, {"coin2", 200}} -addr := "g1ecely4gjy0yl6s9kt409ll330q9hk2lj9ls3ec" +addr := std.Address("g1ecely4gjy0yl6s9kt409ll330q9hk2lj9ls3ec") std.TestIssueCoins(addr, issue) ``` +--- + +## TestSetRealm + +```go +func TestSetRealm(rlm Realm) +``` + +Sets the realm for the current frame. After calling `TestSetRealm()`, calling +[`CurrentRealm()`](chain.md#currentrealm) in the same test function will yield the value of `rlm`, and +any `PrevRealm()` called from a function used after TestSetRealm will yield `rlm`. + +Should be used in combination with [`NewUserRealm`](#newuserrealm) & +[`NewCodeRealm`](#newcoderealm). + +#### Usage +```go +addr := std.Address("g1ecely4gjy0yl6s9kt409ll330q9hk2lj9ls3ec") +std.TestSetRealm(std.NewUserRealm("")) +// or +std.TestSetRealm(std.NewCodeRealm("gno.land/r/demo/users")) +``` + +--- + +## NewUserRealm + +```go +func NewUserRealm(address Address) Realm +``` + +Creates a new user realm for testing purposes. + +#### Usage +```go +addr := std.Address("g1ecely4gjy0yl6s9kt409ll330q9hk2lj9ls3ec") +userRealm := std.NewUserRealm(addr) +``` + +--- + +## NewCodeRealm + +```go +func NewCodeRealm(pkgPath string) +``` + +Creates a new code realm for testing purposes. + +#### Usage +```go +path := "gno.land/r/demo/boards" +codeRealm := std.NewCodeRealm(path) +``` + + + diff --git a/gnovm/tests/stdlibs/std/std.gno b/gnovm/tests/stdlibs/std/std.gno index e96be939eb5..f583342ae04 100644 --- a/gnovm/tests/stdlibs/std/std.gno +++ b/gnovm/tests/stdlibs/std/std.gno @@ -9,7 +9,7 @@ func TestSetOrigCaller(addr Address) { testSetOrigCaller(string(addr)) } func TestSetOrigPkgAddr(addr Address) { testSetOrigPkgAddr(string(addr)) } // TestSetRealm sets the realm for the current frame. -// After calling TestSetRealm, calling CurrentRealm() will yield the value of +// After calling TestSetRealm, calling CurrentRealm() in the test function will yield the value of // rlm, while if a realm function is called, using PrevRealm() will yield rlm. func TestSetRealm(rlm Realm) { testSetRealm(string(rlm.addr), rlm.pkgPath) From 628466935468c15a167e9f570e67c5e5d6d14508 Mon Sep 17 00:00:00 2001 From: Morgan Date: Tue, 18 Jun 2024 18:40:41 +0200 Subject: [PATCH 11/26] ci: test gno.land when changing gnovm and tm2 (#2215) --- .github/workflows/gnoland.yml | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/.github/workflows/gnoland.yml b/.github/workflows/gnoland.yml index 97df3f13a2a..d84e9f62bd6 100644 --- a/.github/workflows/gnoland.yml +++ b/.github/workflows/gnoland.yml @@ -5,9 +5,11 @@ on: branches: - master workflow_dispatch: - pull_request: + pull_request: paths: - "gno.land/**" + - "tm2/**.go" + - "gnovm/**.go" - ".github/**" jobs: @@ -17,4 +19,4 @@ jobs: with: modulepath: "gno.land" secrets: - codecov-token: ${{ secrets.CODECOV_TOKEN }} \ No newline at end of file + codecov-token: ${{ secrets.CODECOV_TOKEN }} From ea969b3a68ae8d6c968b189a936ca10dd3fc384d Mon Sep 17 00:00:00 2001 From: jaekwon Date: Tue, 18 Jun 2024 21:00:10 -0700 Subject: [PATCH 12/26] Revert "fix: default untyped to uint when necessary (#2024)" This reverts commit e7e47d2589ceece37b0502d0df8d54ded582d501. --- gnovm/pkg/gnolang/preprocess.go | 2 +- gnovm/pkg/gnolang/types.go | 19 +++++-------------- gnovm/pkg/gnolang/values.go | 2 +- gnovm/pkg/gnolang/values_conversions.go | 2 +- gnovm/tests/files/bigint1.gno | 14 -------------- 5 files changed, 8 insertions(+), 31 deletions(-) delete mode 100644 gnovm/tests/files/bigint1.gno diff --git a/gnovm/pkg/gnolang/preprocess.go b/gnovm/pkg/gnolang/preprocess.go index 88c5c2f1da4..459910505b9 100644 --- a/gnovm/pkg/gnolang/preprocess.go +++ b/gnovm/pkg/gnolang/preprocess.go @@ -2477,7 +2477,7 @@ func checkOrConvertType(store Store, last BlockNode, x *Expr, t Type, autoNative // convert type if isUntyped(xt) { // convert if x is untyped literal if t == nil { - t = defaultTypeOf(xt, nil) + t = defaultTypeOf(xt) } // Push type into expr if qualifying binary expr. if bx, ok := (*x).(*BinaryExpr); ok { diff --git a/gnovm/pkg/gnolang/types.go b/gnovm/pkg/gnolang/types.go index 86b3d588eda..fcfcd7d9d37 100644 --- a/gnovm/pkg/gnolang/types.go +++ b/gnovm/pkg/gnolang/types.go @@ -1203,8 +1203,8 @@ func (ft *FuncType) Specify(store Store, argTVs []TypedValue, isVarg bool) *Func continue } else if vargt == nil { vargt = varg.T - } else if isUntyped(varg.T) && vargt.TypeID() == defaultTypeOf(varg.T, varg.V).TypeID() { - vargt = defaultTypeOf(varg.T, varg.V) + } else if isUntyped(varg.T) && vargt.TypeID() == defaultTypeOf(varg.T).TypeID() { + vargt = defaultTypeOf(varg.T) } else if vargt.TypeID() != varg.T.TypeID() { panic(fmt.Sprintf( "incompatible varg types: expected %v, got %s", @@ -2281,23 +2281,14 @@ func isDataByte(t Type) bool { // TODO move untyped const stuff to preprocess.go. // TODO associate with ConvertTo() in documentation. -func defaultTypeOf(t Type, v Value) Type { +func defaultTypeOf(t Type) Type { switch t { case UntypedBoolType: return BoolType case UntypedRuneType: return Int32Type case UntypedBigintType: - typeVal := IntType - if bigintValue, ok := v.(BigintValue); ok { - if bigintValue.V != nil && bigintValue.V.Sign() == 1 && !bigintValue.V.IsInt64() { - // Use an unsigned type if the value is positive and we know - // it won't fit in an int64. - typeVal = Uint64Type - } - } - - return typeVal + return IntType case UntypedBigdecType: return Float64Type case UntypedStringType: @@ -2523,7 +2514,7 @@ func specifyType(store Store, lookup map[Name]Type, tmpl Type, spec Type, specTy return // ok } else { if isUntyped(spec) { - spec = defaultTypeOf(spec, nil) + spec = defaultTypeOf(spec) } lookup[ct.Generic] = spec return // ok diff --git a/gnovm/pkg/gnolang/values.go b/gnovm/pkg/gnolang/values.go index d8d4bc58bc3..b0996b98b6f 100644 --- a/gnovm/pkg/gnolang/values.go +++ b/gnovm/pkg/gnolang/values.go @@ -1594,7 +1594,7 @@ func (tv *TypedValue) Assign(alloc *Allocator, tv2 TypedValue, cu bool) { } *tv = tv2.Copy(alloc) if cu && isUntyped(tv.T) { - ConvertUntypedTo(tv, defaultTypeOf(tv.T, tv.V)) + ConvertUntypedTo(tv, defaultTypeOf(tv.T)) } } diff --git a/gnovm/pkg/gnolang/values_conversions.go b/gnovm/pkg/gnolang/values_conversions.go index edaa8883819..b4888878c7a 100644 --- a/gnovm/pkg/gnolang/values_conversions.go +++ b/gnovm/pkg/gnolang/values_conversions.go @@ -926,7 +926,7 @@ func ConvertUntypedTo(tv *TypedValue, t Type) { } // general case if t == nil { - t = defaultTypeOf(tv.T, tv.V) + t = defaultTypeOf(tv.T) } switch tv.T { case UntypedBoolType: diff --git a/gnovm/tests/files/bigint1.gno b/gnovm/tests/files/bigint1.gno deleted file mode 100644 index 01032e27b3f..00000000000 --- a/gnovm/tests/files/bigint1.gno +++ /dev/null @@ -1,14 +0,0 @@ -package main - -import ( - "math" -) - -func main() { - println(float64(math.MaxUint32)) - println(float64(math.MaxUint64)) -} - -// Output: -// 4.294967295e+09 -// 1.8446744073709552e+19 From 0ba53aca29f947a11e6ca3e30fdbb1336bcec7a7 Mon Sep 17 00:00:00 2001 From: ltzmaxwell Date: Wed, 19 Jun 2024 12:42:41 +0800 Subject: [PATCH 13/26] feat: gno type check (#1426) **Pinned Update:** The original https://github.com/gnolang/gno/pull/1426 is now divided into 4 parts, with the dependency relationship being: https://github.com/gnolang/gno/pull/1426 < https://github.com/gnolang/gno/pull/1775, https://github.com/gnolang/gno/pull/1426 <- https://github.com/gnolang/gno/pull/1890<- https://github.com/gnolang/gno/pull/1891. Among these, the main part, https://github.com/gnolang/gno/pull/1426, has been supplemented and optimized for the missing parts in the type checks of the original implementation, specifically as follows: - A new layer for type check is added(type_check.go). during the preprocess stage, the compatibility of operators and operands in expressions is checked, such as 1 - "a". This part used to be implemented as a runtime error, but now it is checked in type_check.go; - Modifications have been made to checkOrConvertType to add conversion checks for constants, such as int(1) + int64(1), which previously would not trigger a compile-time error; - Refined and improved several aspects of the handling logic for BinaryExpr during the preprocessing stage. - The existing checkType has been renamed to assertAssignableTo. ==========================update complete======================= ### Problem Definition Please proceed to #1424. ======update: fix #1462 , tests located in `gnovm/tests/files/type2`. this issue is fixed since they share the same contexts of type check and conversion. briefly for #1462, type of shift expression (or any composed expression involved shift expression) will be determined in the context they are used if they are untyped, also can be mutated by explicitly conversion with a `type call`. ========================================================================================== ### Overview of Solution #### checkOperandWithOp function: **Purpose**: Newly introduced to evaluate operand compatibility before deep type analysis. **Functionality**: Employs predefined rules to quickly identify incompatible patterns (e.g., "a" << 1 is flagged as incompatible). **Advantage**: Prevents unnecessary processing by checkOrConvertType for clear mismatches. #### checkOrConvertType function: **Role**: Engages after checkOperandWithOp's clearance. It's the hub for core type checking and conversion. **Key Improvement**: Enhanced handling of const conversions by limiting it within a certain range. **Example**: In cases like int(1) + int(8), the issue of unregulated const conversion is addressed. **Constraints**: Mandatory const conversion is now limited to specific scenarios (e.g., explicit conversion, operand in array/slice index, RHS of a shift expression). ### Specific Problems Solved 1. **assignable and sameType check:** This code should output "something else". the root cause for this is Error(0) is assignable to errCmp since it satisfies the interface of error, and result in inequality since the have different concrete type in runtime. Thanks @jaekwon for pointing out my mistake and give an improved version of this. ```go package main import ( "errors" "strconv" ) type Error int64 func (e Error) Error() string { return "error: " + strconv.Itoa(int(e)) } var errCmp = errors.New("XXXX") func main() { if Error(0) == errCmp { println("what the firetruck?") } else { println("something else") } } ``` 2. **Early Incompatibility Detection:** Conducted during preprocessing, not runtime. **Example**: ```go package main func main() { println(1 / "a") // Detects incompatibility early. } ``` ```go func main() { println(int(1) == int8(1)) // this is checked before checkOrConvertType if LHS and RHS are both typed. } ``` ~~3. **Implicit Conversion:**~~(this is split out) ~~Focus: Ensuring accurate conversions, particularly unnamed to named types.~~ ~~Example:~~ ~~```go~~ ~~package main~~ ~~type word uint~~ ~~type nat []word~~ ~~func (n nat) add() bool {~~ ~~ return true~~ ~~} ~~func Gen() nat {~~ ~~n := []word{0}~~ ~~return n~~ ~~}~~ ~~func main() {~~ ~~r := Gen()~~ ~~switch r.(type) {~~ ~~ case nat:~~ ~~println("nat")~~ ~~println(r.add())~~ ~~default:~~ ~~println("should not happen")~~ ~~ }~~ ~~}~~ ~~```~~ ~~4. **Type of Shift Expressions:**~~ ~~**Context**: Determines the type based on usage context and explicit conversions.~~ ~~**Implementation**: Additional checks in assignStmt, callExpr for potential untyped shift expressions (or else expressions with untyped shift expression embedded)~~~~appear, e.g. uint64(1 << x). This will trigger a potentially recursive check&convert until the shift expr got its final type.~~ ### Conclusion: This PR enhances the type check workflow and addresses previously overlooked aspects, resolving a variety of type-related issues. --------- Co-authored-by: Morgan Co-authored-by: jaekwon --- .../p/demo/memeland/memeland_test.gno | 5 +- gno.land/pkg/sdk/vm/vm.proto | 10 + gnovm/Makefile | 3 + gnovm/pkg/gnolang/debugger_test.go | 9 +- gnovm/pkg/gnolang/gnolang.proto | 2 + gnovm/pkg/gnolang/gonative.go | 2 +- gnovm/pkg/gnolang/op_assign.go | 18 +- gnovm/pkg/gnolang/op_binary.go | 34 +- gnovm/pkg/gnolang/op_exec.go | 2 +- gnovm/pkg/gnolang/preprocess.go | 670 +++++-------- gnovm/pkg/gnolang/preprocess_test.go | 4 +- gnovm/pkg/gnolang/type_check.go | 926 ++++++++++++++++++ gnovm/pkg/gnolang/types.go | 17 +- gnovm/pkg/gnolang/values.go | 82 ++ gnovm/pkg/gnolang/values_conversions.go | 5 + gnovm/tests/file.go | 26 +- .../{access0.gno => access0_stdlibs.gno} | 0 .../{access1.gno => access1_stdlibs.gno} | 2 +- .../{access2.gno => access2_stdlibs.gno} | 0 .../{access3.gno => access3_stdlibs.gno} | 0 .../{access4.gno => access4_stdlibs.gno} | 2 +- .../{access5.gno => access5_stdlibs.gno} | 0 .../{access6.gno => access6_stdlibs.gno} | 2 +- .../{access7.gno => access7_stdlibs.gno} | 2 +- .../method/declaredType6_filetest.gno | 2 +- .../method/declaredType6b_filetest.gno | 2 +- ...s_realm_compositelit_filetest_stdlibs.gno} | 0 .../unnamedtype0b_filetest.gno | 2 +- gnovm/tests/files/bool6.gno | 2 +- gnovm/tests/files/comp4.gno | 32 + gnovm/tests/files/comp5.gno | 23 + gnovm/tests/files/fun24.gno | 2 +- ...{issue_558b.gno => issue_558b_stdlibs.gno} | 0 gnovm/tests/files/math_native.gno | 14 + gnovm/tests/files/op7.gno | 2 +- .../files/{std0.gno => std0_stdlibs.gno} | 0 .../files/{std10.gno => std10_stdlibs.gno} | 0 .../files/{std11.gno => std11_stdlibs.gno} | 0 .../files/{std2.gno => std2_stdlibs.gno} | 0 .../files/{std3.gno => std3_stdlibs.gno} | 0 .../files/{std4.gno => std4_stdlibs.gno} | 0 .../files/{std5.gno => std5_stdlibs.gno} | 0 .../files/{std6.gno => std6_stdlibs.gno} | 0 .../files/{std7.gno => std7_stdlibs.gno} | 0 .../files/{std8.gno => std8_stdlibs.gno} | 0 .../files/{std9.gno => std9_stdlibs.gno} | 0 gnovm/tests/files/time16_native.gno | 2 +- gnovm/tests/files/type31.gno | 2 +- gnovm/tests/files/type32.gno | 2 +- gnovm/tests/files/types/add_a0.gno | 9 + gnovm/tests/files/types/add_a1.gno | 25 + gnovm/tests/files/types/add_assign_a0.gno | 9 + gnovm/tests/files/types/add_assign_a1.gno | 25 + gnovm/tests/files/types/add_assign_a_01.gno | 12 + gnovm/tests/files/types/add_assign_b0.gno | 13 + gnovm/tests/files/types/add_assign_b1.gno | 13 + gnovm/tests/files/types/add_assign_b2.gno | 10 + gnovm/tests/files/types/add_assign_d0.gno | 12 + gnovm/tests/files/types/add_assign_e.gno | 21 + gnovm/tests/files/types/add_assign_e0.gno | 28 + gnovm/tests/files/types/add_assign_e1.gno | 20 + .../files/types/add_assign_f0_stdlibs.gno | 25 + .../files/types/add_assign_f1_stdlibs.gno | 28 + .../files/types/add_assign_f2_stdlibs.gno | 25 + gnovm/tests/files/types/add_assign_f3.gno | 32 + gnovm/tests/files/types/add_assign_f4.gno | 10 + gnovm/tests/files/types/add_b0.gno | 13 + gnovm/tests/files/types/add_b1.gno | 21 + gnovm/tests/files/types/add_b2.gno | 9 + gnovm/tests/files/types/add_b3.gno | 9 + gnovm/tests/files/types/add_d0.gno | 13 + gnovm/tests/files/types/add_d1.gno | 10 + gnovm/tests/files/types/add_d2.gno | 13 + gnovm/tests/files/types/add_d3.gno | 15 + gnovm/tests/files/types/add_d4.gno | 11 + gnovm/tests/files/types/add_e0.gno | 27 + gnovm/tests/files/types/add_f0_stdlibs.gno | 23 + gnovm/tests/files/types/add_f1_stdlibs.gno | 23 + gnovm/tests/files/types/add_f2.gno | 31 + gnovm/tests/files/types/and_a0.gno | 9 + gnovm/tests/files/types/and_a1.gno | 25 + gnovm/tests/files/types/and_b0.gno | 13 + gnovm/tests/files/types/and_b1.gno | 21 + gnovm/tests/files/types/and_b2.gno | 9 + gnovm/tests/files/types/and_b3.gno | 9 + gnovm/tests/files/types/and_b4.gno | 9 + gnovm/tests/files/types/and_d0.gno | 10 + gnovm/tests/files/types/and_d1.gno | 10 + gnovm/tests/files/types/and_d2.gno | 13 + gnovm/tests/files/types/and_d3.gno | 15 + gnovm/tests/files/types/and_d4.gno | 10 + gnovm/tests/files/types/and_e0.gno | 27 + gnovm/tests/files/types/and_f0_stdlibs.gno | 23 + gnovm/tests/files/types/and_f1_stdlibs.gno | 23 + gnovm/tests/files/types/and_f2.gno | 31 + gnovm/tests/files/types/assign_call.gno | 14 + gnovm/tests/files/types/assign_index.gno | 14 + gnovm/tests/files/types/assign_index_a.gno | 12 + gnovm/tests/files/types/assign_index_b.gno | 14 + gnovm/tests/files/types/assign_index_c.gno | 12 + gnovm/tests/files/types/assign_literal.gno | 8 + gnovm/tests/files/types/assign_literal10.gno | 21 + gnovm/tests/files/types/assign_literal10a.gno | 20 + gnovm/tests/files/types/assign_literal11.gno | 11 + gnovm/tests/files/types/assign_literal2.gno | 9 + gnovm/tests/files/types/assign_literal2_a.gno | 9 + gnovm/tests/files/types/assign_literal3.gno | 8 + gnovm/tests/files/types/assign_literal4.gno | 8 + gnovm/tests/files/types/assign_literal4_a.gno | 8 + gnovm/tests/files/types/assign_literal5.gno | 8 + gnovm/tests/files/types/assign_literal6.gno | 8 + gnovm/tests/files/types/assign_literal7.gno | 10 + gnovm/tests/files/types/assign_literal7a.gno | 10 + gnovm/tests/files/types/assign_literal7b.gno | 10 + gnovm/tests/files/types/assign_literal7c.gno | 13 + gnovm/tests/files/types/assign_literal7d.gno | 14 + gnovm/tests/files/types/assign_literal8.gno | 11 + gnovm/tests/files/types/assign_literal9.gno | 14 + gnovm/tests/files/types/assign_literal_a.gno | 8 + gnovm/tests/files/types/assign_nil.gno | 11 + gnovm/tests/files/types/assign_nil2.gno | 11 + gnovm/tests/files/types/assign_range.gno | 42 + gnovm/tests/files/types/assign_range_a.gno | 22 + gnovm/tests/files/types/assign_range_a1.gno | 22 + gnovm/tests/files/types/assign_range_b.gno | 20 + gnovm/tests/files/types/assign_range_b1.gno | 20 + gnovm/tests/files/types/assign_range_b2.gno | 28 + gnovm/tests/files/types/assign_range_c.gno | 20 + gnovm/tests/files/types/assign_range_d.gno | 14 + gnovm/tests/files/types/assign_range_e.gno | 15 + gnovm/tests/files/types/assign_rune.gno | 18 + gnovm/tests/files/types/assign_rune_a.gno | 12 + .../files/types/assign_type_assertion.gno | 22 + .../files/types/assign_type_assertion_a.gno | 33 + .../files/types/assign_type_assertion_b.gno | 32 + .../files/types/assign_type_assertion_c.gno | 33 + .../files/types/assign_type_assertion_d.gno | 25 + .../files/types/assign_type_assertion_e.gno | 27 + .../files/types/assign_type_assertion_f.gno | 25 + .../files/types/assign_type_assertion_g.gno | 27 + gnovm/tests/files/types/bigdec.gno | 11 + gnovm/tests/files/types/bigdec2.gno | 11 + gnovm/tests/files/types/bigdec3.gno | 11 + gnovm/tests/files/types/bigdec4.gno | 11 + gnovm/tests/files/types/bigdec5.gno | 11 + gnovm/tests/files/types/bigdec_6.gno | 8 + gnovm/tests/files/types/cmp_array.gno | 16 + gnovm/tests/files/types/cmp_array_a.gno | 21 + gnovm/tests/files/types/cmp_array_b.gno | 15 + gnovm/tests/files/types/cmp_array_c.gno | 15 + gnovm/tests/files/types/cmp_array_d.gno | 13 + gnovm/tests/files/types/cmp_poiner.gno | 23 + gnovm/tests/files/types/cmp_poiner2.gno | 10 + gnovm/tests/files/types/cmp_struct.gno | 23 + gnovm/tests/files/types/cmp_struct_a.gno | 20 + gnovm/tests/files/types/cmp_struct_b.gno | 19 + gnovm/tests/files/types/cmp_struct_c.gno | 19 + gnovm/tests/files/types/cmp_struct_c1.gno | 19 + gnovm/tests/files/types/cmp_struct_d.gno | 19 + gnovm/tests/files/types/cmp_struct_e.gno | 15 + gnovm/tests/files/types/cmp_struct_f.gno | 43 + gnovm/tests/files/types/cmp_struct_g.gno | 21 + gnovm/tests/files/types/eql_0a0.gno | 9 + gnovm/tests/files/types/eql_0a01.gno | 8 + gnovm/tests/files/types/eql_0a02.gno | 11 + gnovm/tests/files/types/eql_0a03.gno | 12 + gnovm/tests/files/types/eql_0a1.gno | 9 + gnovm/tests/files/types/eql_0a1a.gno | 11 + gnovm/tests/files/types/eql_0a1a0.gno | 9 + gnovm/tests/files/types/eql_0a1a1.gno | 9 + gnovm/tests/files/types/eql_0a1b.gno | 20 + gnovm/tests/files/types/eql_0a1c.gno | 10 + gnovm/tests/files/types/eql_0a1d.gno | 14 + gnovm/tests/files/types/eql_0a1e.gno | 16 + gnovm/tests/files/types/eql_0a1f.gno | 10 + gnovm/tests/files/types/eql_0a1g.gno | 10 + gnovm/tests/files/types/eql_0a2.gno | 25 + gnovm/tests/files/types/eql_0a3.gno | 25 + gnovm/tests/files/types/eql_0a4.gno | 25 + gnovm/tests/files/types/eql_0b0.gno | 24 + gnovm/tests/files/types/eql_0b1.gno | 23 + gnovm/tests/files/types/eql_0b2.gno | 22 + gnovm/tests/files/types/eql_0b3.gno | 15 + gnovm/tests/files/types/eql_0b4_native.gno | 13 + gnovm/tests/files/types/eql_0b4_stdlibs.gno | 13 + gnovm/tests/files/types/eql_0c2.gno | 24 + gnovm/tests/files/types/eql_0d0.gno | 13 + gnovm/tests/files/types/eql_0e0.gno | 27 + gnovm/tests/files/types/eql_0e1.gno | 27 + gnovm/tests/files/types/eql_0f0_native.gno | 28 + gnovm/tests/files/types/eql_0f0_stdlibs.gno | 28 + gnovm/tests/files/types/eql_0f12.gno | 13 + gnovm/tests/files/types/eql_0f14.gno | 14 + gnovm/tests/files/types/eql_0f15.gno | 17 + gnovm/tests/files/types/eql_0f16.gno | 20 + gnovm/tests/files/types/eql_0f17.gno | 13 + gnovm/tests/files/types/eql_0f18.gno | 12 + gnovm/tests/files/types/eql_0f19.gno | 12 + gnovm/tests/files/types/eql_0f1_stdlibs.gno | 28 + gnovm/tests/files/types/eql_0f20.gno | 13 + gnovm/tests/files/types/eql_0f21.gno | 13 + gnovm/tests/files/types/eql_0f21a.gno | 13 + gnovm/tests/files/types/eql_0f22.gno | 11 + gnovm/tests/files/types/eql_0f23.gno | 13 + gnovm/tests/files/types/eql_0f24.gno | 13 + gnovm/tests/files/types/eql_0f25.gno | 19 + gnovm/tests/files/types/eql_0f27_stdlibs.gno | 21 + gnovm/tests/files/types/eql_0f28.gno | 31 + gnovm/tests/files/types/eql_0f29.gno | 24 + gnovm/tests/files/types/eql_0f2b_native.gno | 28 + gnovm/tests/files/types/eql_0f2b_stdlibs.gno | 28 + gnovm/tests/files/types/eql_0f2c_native.gno | 28 + gnovm/tests/files/types/eql_0f2c_stdlibs.gno | 28 + gnovm/tests/files/types/eql_0f2d.gno | 32 + gnovm/tests/files/types/eql_0f2e.gno | 32 + gnovm/tests/files/types/eql_0f30.gno | 9 + gnovm/tests/files/types/eql_0f30a.gno | 8 + gnovm/tests/files/types/eql_0f30b.gno | 13 + gnovm/tests/files/types/eql_0f30c.gno | 10 + gnovm/tests/files/types/eql_0f30d.gno | 8 + gnovm/tests/files/types/eql_0f30e.gno | 8 + gnovm/tests/files/types/eql_0f30f.gno | 11 + gnovm/tests/files/types/eql_0f30g.gno | 11 + gnovm/tests/files/types/eql_0f31.gno | 13 + gnovm/tests/files/types/eql_0f32.gno | 8 + gnovm/tests/files/types/eql_0f33.gno | 49 + gnovm/tests/files/types/eql_0f34.gno | 49 + gnovm/tests/files/types/eql_0f35.gno | 34 + gnovm/tests/files/types/eql_0f37.gno | 39 + gnovm/tests/files/types/eql_0f40_stdlibs.gno | 41 + gnovm/tests/files/types/eql_0f41_stdlibs.gno | 35 + gnovm/tests/files/types/eql_0f42.gno | 10 + gnovm/tests/files/types/eql_0f43_hasNil.gno | 15 + gnovm/tests/files/types/eql_0f44.gno | 16 + gnovm/tests/files/types/eql_0f45.gno | 14 + gnovm/tests/files/types/eql_0f46.gno | 18 + gnovm/tests/files/types/eql_0f46a.gno | 18 + gnovm/tests/files/types/eql_0f48.gno | 22 + gnovm/tests/files/types/eql_0f8_stdlibs.gno | 27 + gnovm/tests/files/types/eql_iface.gno | 13 + gnovm/tests/files/types/incdec_a0.gno | 10 + gnovm/tests/files/types/incdec_a1.gno | 10 + gnovm/tests/files/types/incdec_a2.gno | 29 + gnovm/tests/files/types/incdec_a3.gno | 19 + gnovm/tests/files/types/incdec_a4.gno | 18 + gnovm/tests/files/types/nil.gno | 9 + gnovm/tests/files/types/or_a0.gno | 9 + gnovm/tests/files/types/or_a1.gno | 25 + gnovm/tests/files/types/or_b0.gno | 13 + gnovm/tests/files/types/or_b1.gno | 21 + gnovm/tests/files/types/or_b2.gno | 9 + gnovm/tests/files/types/or_b3.gno | 9 + gnovm/tests/files/types/or_b4.gno | 9 + gnovm/tests/files/types/or_d0.gno | 10 + gnovm/tests/files/types/or_d1.gno | 10 + gnovm/tests/files/types/or_d2.gno | 13 + gnovm/tests/files/types/or_d3.gno | 15 + gnovm/tests/files/types/or_d4.gno | 10 + gnovm/tests/files/types/or_e0.gno | 27 + gnovm/tests/files/types/or_f0_stdlibs.gno | 23 + gnovm/tests/files/types/or_f1_stdlibs.gno | 23 + gnovm/tests/files/types/or_f2.gno | 31 + gnovm/tests/files/types/overflow_a0.gno | 11 + gnovm/tests/files/types/overflow_a1.gno | 9 + gnovm/tests/files/types/rem_a0.gno | 9 + gnovm/tests/files/types/rem_a1.gno | 25 + gnovm/tests/files/types/rem_a2.gno | 8 + gnovm/tests/files/types/rem_b0.gno | 13 + gnovm/tests/files/types/rem_f3.gno | 9 + gnovm/tests/files/types/runtime_a0.gno | 9 + gnovm/tests/files/types/runtime_a0a.gno | 8 + gnovm/tests/files/types/runtime_a2.gno | 15 + gnovm/tests/files/types/runtime_a3.gno | 12 + gnovm/tests/files/types/shift_a0.gno | 11 + gnovm/tests/files/types/shift_a1.gno | 11 + gnovm/tests/files/types/shift_a10.gno | 10 + gnovm/tests/files/types/shift_a11.gno | 10 + gnovm/tests/files/types/shift_a12.gno | 14 + gnovm/tests/files/types/shift_a13.gno | 13 + gnovm/tests/files/types/shift_a14.gno | 10 + gnovm/tests/files/types/shift_a15.gno | 10 + gnovm/tests/files/types/shift_a16.gno | 9 + gnovm/tests/files/types/shift_a2.gno | 11 + gnovm/tests/files/types/shift_a3.gno | 10 + gnovm/tests/files/types/shift_a4.gno | 11 + gnovm/tests/files/types/shift_a5.gno | 10 + gnovm/tests/files/types/shift_a6.gno | 14 + gnovm/tests/files/types/shift_a7.gno | 9 + gnovm/tests/files/types/shift_a8.gno | 10 + gnovm/tests/files/types/shift_a9.gno | 10 + gnovm/tests/files/types/time_native.gno | 13 + gnovm/tests/files/types/unary_a0.gno | 12 + gnovm/tests/files/types/unary_a0a.gno | 12 + gnovm/tests/files/types/unary_a0b.gno | 12 + gnovm/tests/files/types/unary_a0c.gno | 12 + gnovm/tests/files/types/unary_a1.gno | 13 + gnovm/tests/files/types/unary_a2.gno | 13 + gnovm/tests/files/types/unary_a2a.gno | 13 + gnovm/tests/files/types/unary_a3.gno | 12 + gnovm/tests/files/types/unary_a4.gno | 10 + gnovm/tests/files/types/unary_a5.gno | 12 + gnovm/tests/files/types/unary_a6.gno | 12 + gnovm/tests/files/var18.gno | 2 +- .../{zrealm12.gno => zrealm12_stdlibs.gno} | 0 ...alm_const.gno => zrealm_const_stdlibs.gno} | 0 ...lm0.gno => zrealm_crossrealm0_stdlibs.gno} | 0 ...10.gno => zrealm_crossrealm10_stdlibs.gno} | 0 ...11.gno => zrealm_crossrealm11_stdlibs.gno} | 5 +- ...12.gno => zrealm_crossrealm12_stdlibs.gno} | 12 +- ...13.gno => zrealm_crossrealm13_stdlibs.gno} | 0 ...a.gno => zrealm_crossrealm13a_stdlibs.gno} | 0 ...lm1.gno => zrealm_crossrealm1_stdlibs.gno} | 0 ...lm2.gno => zrealm_crossrealm2_stdlibs.gno} | 0 ...lm3.gno => zrealm_crossrealm3_stdlibs.gno} | 0 ...lm4.gno => zrealm_crossrealm4_stdlibs.gno} | 0 ...lm5.gno => zrealm_crossrealm5_stdlibs.gno} | 0 ...lm6.gno => zrealm_crossrealm6_stdlibs.gno} | 0 ...lm7.gno => zrealm_crossrealm7_stdlibs.gno} | 0 ...lm8.gno => zrealm_crossrealm8_stdlibs.gno} | 0 ...lm9.gno => zrealm_crossrealm9_stdlibs.gno} | 0 ...initctx.gno => zrealm_initctx_stdlibs.gno} | 0 ...tbind0.gno => zrealm_natbind0_stdlibs.gno} | 0 ...realm_std0.gno => zrealm_std0_stdlibs.gno} | 0 ...realm_std1.gno => zrealm_std1_stdlibs.gno} | 0 ...realm_std2.gno => zrealm_std2_stdlibs.gno} | 0 ...realm_std3.gno => zrealm_std3_stdlibs.gno} | 0 ...realm_std4.gno => zrealm_std4_stdlibs.gno} | 0 ...realm_std5.gno => zrealm_std5_stdlibs.gno} | 0 ...realm_std6.gno => zrealm_std6_stdlibs.gno} | 6 +- ...m_tests0.gno => zrealm_tests0_stdlibs.gno} | 0 ...ils0.gno => zrealm_testutils0_stdlibs.gno} | 0 gnovm/tests/package_test.go | 2 +- tm2/pkg/errors/errors.go | 3 + tm2/pkg/sdk/sdk.proto | 2 +- 334 files changed, 5606 insertions(+), 529 deletions(-) create mode 100644 gnovm/pkg/gnolang/type_check.go rename gnovm/tests/files/{access0.gno => access0_stdlibs.gno} (100%) rename gnovm/tests/files/{access1.gno => access1_stdlibs.gno} (53%) rename gnovm/tests/files/{access2.gno => access2_stdlibs.gno} (100%) rename gnovm/tests/files/{access3.gno => access3_stdlibs.gno} (100%) rename gnovm/tests/files/{access4.gno => access4_stdlibs.gno} (57%) rename gnovm/tests/files/{access5.gno => access5_stdlibs.gno} (100%) rename gnovm/tests/files/{access6.gno => access6_stdlibs.gno} (67%) rename gnovm/tests/files/{access7.gno => access7_stdlibs.gno} (72%) rename gnovm/tests/files/assign_unnamed_type/more/{cross_realm_compositelit_filetest.gno => cross_realm_compositelit_filetest_stdlibs.gno} (100%) create mode 100644 gnovm/tests/files/comp4.gno create mode 100644 gnovm/tests/files/comp5.gno rename gnovm/tests/files/{issue_558b.gno => issue_558b_stdlibs.gno} (100%) create mode 100644 gnovm/tests/files/math_native.gno rename gnovm/tests/files/{std0.gno => std0_stdlibs.gno} (100%) rename gnovm/tests/files/{std10.gno => std10_stdlibs.gno} (100%) rename gnovm/tests/files/{std11.gno => std11_stdlibs.gno} (100%) rename gnovm/tests/files/{std2.gno => std2_stdlibs.gno} (100%) rename gnovm/tests/files/{std3.gno => std3_stdlibs.gno} (100%) rename gnovm/tests/files/{std4.gno => std4_stdlibs.gno} (100%) rename gnovm/tests/files/{std5.gno => std5_stdlibs.gno} (100%) rename gnovm/tests/files/{std6.gno => std6_stdlibs.gno} (100%) rename gnovm/tests/files/{std7.gno => std7_stdlibs.gno} (100%) rename gnovm/tests/files/{std8.gno => std8_stdlibs.gno} (100%) rename gnovm/tests/files/{std9.gno => std9_stdlibs.gno} (100%) create mode 100644 gnovm/tests/files/types/add_a0.gno create mode 100644 gnovm/tests/files/types/add_a1.gno create mode 100644 gnovm/tests/files/types/add_assign_a0.gno create mode 100644 gnovm/tests/files/types/add_assign_a1.gno create mode 100644 gnovm/tests/files/types/add_assign_a_01.gno create mode 100644 gnovm/tests/files/types/add_assign_b0.gno create mode 100644 gnovm/tests/files/types/add_assign_b1.gno create mode 100644 gnovm/tests/files/types/add_assign_b2.gno create mode 100644 gnovm/tests/files/types/add_assign_d0.gno create mode 100644 gnovm/tests/files/types/add_assign_e.gno create mode 100644 gnovm/tests/files/types/add_assign_e0.gno create mode 100644 gnovm/tests/files/types/add_assign_e1.gno create mode 100644 gnovm/tests/files/types/add_assign_f0_stdlibs.gno create mode 100644 gnovm/tests/files/types/add_assign_f1_stdlibs.gno create mode 100644 gnovm/tests/files/types/add_assign_f2_stdlibs.gno create mode 100644 gnovm/tests/files/types/add_assign_f3.gno create mode 100644 gnovm/tests/files/types/add_assign_f4.gno create mode 100644 gnovm/tests/files/types/add_b0.gno create mode 100644 gnovm/tests/files/types/add_b1.gno create mode 100644 gnovm/tests/files/types/add_b2.gno create mode 100644 gnovm/tests/files/types/add_b3.gno create mode 100644 gnovm/tests/files/types/add_d0.gno create mode 100644 gnovm/tests/files/types/add_d1.gno create mode 100644 gnovm/tests/files/types/add_d2.gno create mode 100644 gnovm/tests/files/types/add_d3.gno create mode 100644 gnovm/tests/files/types/add_d4.gno create mode 100644 gnovm/tests/files/types/add_e0.gno create mode 100644 gnovm/tests/files/types/add_f0_stdlibs.gno create mode 100644 gnovm/tests/files/types/add_f1_stdlibs.gno create mode 100644 gnovm/tests/files/types/add_f2.gno create mode 100644 gnovm/tests/files/types/and_a0.gno create mode 100644 gnovm/tests/files/types/and_a1.gno create mode 100644 gnovm/tests/files/types/and_b0.gno create mode 100644 gnovm/tests/files/types/and_b1.gno create mode 100644 gnovm/tests/files/types/and_b2.gno create mode 100644 gnovm/tests/files/types/and_b3.gno create mode 100644 gnovm/tests/files/types/and_b4.gno create mode 100644 gnovm/tests/files/types/and_d0.gno create mode 100644 gnovm/tests/files/types/and_d1.gno create mode 100644 gnovm/tests/files/types/and_d2.gno create mode 100644 gnovm/tests/files/types/and_d3.gno create mode 100644 gnovm/tests/files/types/and_d4.gno create mode 100644 gnovm/tests/files/types/and_e0.gno create mode 100644 gnovm/tests/files/types/and_f0_stdlibs.gno create mode 100644 gnovm/tests/files/types/and_f1_stdlibs.gno create mode 100644 gnovm/tests/files/types/and_f2.gno create mode 100644 gnovm/tests/files/types/assign_call.gno create mode 100644 gnovm/tests/files/types/assign_index.gno create mode 100644 gnovm/tests/files/types/assign_index_a.gno create mode 100644 gnovm/tests/files/types/assign_index_b.gno create mode 100644 gnovm/tests/files/types/assign_index_c.gno create mode 100644 gnovm/tests/files/types/assign_literal.gno create mode 100644 gnovm/tests/files/types/assign_literal10.gno create mode 100644 gnovm/tests/files/types/assign_literal10a.gno create mode 100644 gnovm/tests/files/types/assign_literal11.gno create mode 100644 gnovm/tests/files/types/assign_literal2.gno create mode 100644 gnovm/tests/files/types/assign_literal2_a.gno create mode 100644 gnovm/tests/files/types/assign_literal3.gno create mode 100644 gnovm/tests/files/types/assign_literal4.gno create mode 100644 gnovm/tests/files/types/assign_literal4_a.gno create mode 100644 gnovm/tests/files/types/assign_literal5.gno create mode 100644 gnovm/tests/files/types/assign_literal6.gno create mode 100644 gnovm/tests/files/types/assign_literal7.gno create mode 100644 gnovm/tests/files/types/assign_literal7a.gno create mode 100644 gnovm/tests/files/types/assign_literal7b.gno create mode 100644 gnovm/tests/files/types/assign_literal7c.gno create mode 100644 gnovm/tests/files/types/assign_literal7d.gno create mode 100644 gnovm/tests/files/types/assign_literal8.gno create mode 100644 gnovm/tests/files/types/assign_literal9.gno create mode 100644 gnovm/tests/files/types/assign_literal_a.gno create mode 100644 gnovm/tests/files/types/assign_nil.gno create mode 100644 gnovm/tests/files/types/assign_nil2.gno create mode 100644 gnovm/tests/files/types/assign_range.gno create mode 100644 gnovm/tests/files/types/assign_range_a.gno create mode 100644 gnovm/tests/files/types/assign_range_a1.gno create mode 100644 gnovm/tests/files/types/assign_range_b.gno create mode 100644 gnovm/tests/files/types/assign_range_b1.gno create mode 100644 gnovm/tests/files/types/assign_range_b2.gno create mode 100644 gnovm/tests/files/types/assign_range_c.gno create mode 100644 gnovm/tests/files/types/assign_range_d.gno create mode 100644 gnovm/tests/files/types/assign_range_e.gno create mode 100644 gnovm/tests/files/types/assign_rune.gno create mode 100644 gnovm/tests/files/types/assign_rune_a.gno create mode 100644 gnovm/tests/files/types/assign_type_assertion.gno create mode 100644 gnovm/tests/files/types/assign_type_assertion_a.gno create mode 100644 gnovm/tests/files/types/assign_type_assertion_b.gno create mode 100644 gnovm/tests/files/types/assign_type_assertion_c.gno create mode 100644 gnovm/tests/files/types/assign_type_assertion_d.gno create mode 100644 gnovm/tests/files/types/assign_type_assertion_e.gno create mode 100644 gnovm/tests/files/types/assign_type_assertion_f.gno create mode 100644 gnovm/tests/files/types/assign_type_assertion_g.gno create mode 100644 gnovm/tests/files/types/bigdec.gno create mode 100644 gnovm/tests/files/types/bigdec2.gno create mode 100644 gnovm/tests/files/types/bigdec3.gno create mode 100644 gnovm/tests/files/types/bigdec4.gno create mode 100644 gnovm/tests/files/types/bigdec5.gno create mode 100644 gnovm/tests/files/types/bigdec_6.gno create mode 100644 gnovm/tests/files/types/cmp_array.gno create mode 100644 gnovm/tests/files/types/cmp_array_a.gno create mode 100644 gnovm/tests/files/types/cmp_array_b.gno create mode 100644 gnovm/tests/files/types/cmp_array_c.gno create mode 100644 gnovm/tests/files/types/cmp_array_d.gno create mode 100644 gnovm/tests/files/types/cmp_poiner.gno create mode 100644 gnovm/tests/files/types/cmp_poiner2.gno create mode 100644 gnovm/tests/files/types/cmp_struct.gno create mode 100644 gnovm/tests/files/types/cmp_struct_a.gno create mode 100644 gnovm/tests/files/types/cmp_struct_b.gno create mode 100644 gnovm/tests/files/types/cmp_struct_c.gno create mode 100644 gnovm/tests/files/types/cmp_struct_c1.gno create mode 100644 gnovm/tests/files/types/cmp_struct_d.gno create mode 100644 gnovm/tests/files/types/cmp_struct_e.gno create mode 100644 gnovm/tests/files/types/cmp_struct_f.gno create mode 100644 gnovm/tests/files/types/cmp_struct_g.gno create mode 100644 gnovm/tests/files/types/eql_0a0.gno create mode 100644 gnovm/tests/files/types/eql_0a01.gno create mode 100644 gnovm/tests/files/types/eql_0a02.gno create mode 100644 gnovm/tests/files/types/eql_0a03.gno create mode 100644 gnovm/tests/files/types/eql_0a1.gno create mode 100644 gnovm/tests/files/types/eql_0a1a.gno create mode 100644 gnovm/tests/files/types/eql_0a1a0.gno create mode 100644 gnovm/tests/files/types/eql_0a1a1.gno create mode 100644 gnovm/tests/files/types/eql_0a1b.gno create mode 100644 gnovm/tests/files/types/eql_0a1c.gno create mode 100644 gnovm/tests/files/types/eql_0a1d.gno create mode 100644 gnovm/tests/files/types/eql_0a1e.gno create mode 100644 gnovm/tests/files/types/eql_0a1f.gno create mode 100644 gnovm/tests/files/types/eql_0a1g.gno create mode 100644 gnovm/tests/files/types/eql_0a2.gno create mode 100644 gnovm/tests/files/types/eql_0a3.gno create mode 100644 gnovm/tests/files/types/eql_0a4.gno create mode 100644 gnovm/tests/files/types/eql_0b0.gno create mode 100644 gnovm/tests/files/types/eql_0b1.gno create mode 100644 gnovm/tests/files/types/eql_0b2.gno create mode 100644 gnovm/tests/files/types/eql_0b3.gno create mode 100644 gnovm/tests/files/types/eql_0b4_native.gno create mode 100644 gnovm/tests/files/types/eql_0b4_stdlibs.gno create mode 100644 gnovm/tests/files/types/eql_0c2.gno create mode 100644 gnovm/tests/files/types/eql_0d0.gno create mode 100644 gnovm/tests/files/types/eql_0e0.gno create mode 100644 gnovm/tests/files/types/eql_0e1.gno create mode 100644 gnovm/tests/files/types/eql_0f0_native.gno create mode 100644 gnovm/tests/files/types/eql_0f0_stdlibs.gno create mode 100644 gnovm/tests/files/types/eql_0f12.gno create mode 100644 gnovm/tests/files/types/eql_0f14.gno create mode 100644 gnovm/tests/files/types/eql_0f15.gno create mode 100644 gnovm/tests/files/types/eql_0f16.gno create mode 100644 gnovm/tests/files/types/eql_0f17.gno create mode 100644 gnovm/tests/files/types/eql_0f18.gno create mode 100644 gnovm/tests/files/types/eql_0f19.gno create mode 100644 gnovm/tests/files/types/eql_0f1_stdlibs.gno create mode 100644 gnovm/tests/files/types/eql_0f20.gno create mode 100644 gnovm/tests/files/types/eql_0f21.gno create mode 100644 gnovm/tests/files/types/eql_0f21a.gno create mode 100644 gnovm/tests/files/types/eql_0f22.gno create mode 100644 gnovm/tests/files/types/eql_0f23.gno create mode 100644 gnovm/tests/files/types/eql_0f24.gno create mode 100644 gnovm/tests/files/types/eql_0f25.gno create mode 100644 gnovm/tests/files/types/eql_0f27_stdlibs.gno create mode 100644 gnovm/tests/files/types/eql_0f28.gno create mode 100644 gnovm/tests/files/types/eql_0f29.gno create mode 100644 gnovm/tests/files/types/eql_0f2b_native.gno create mode 100644 gnovm/tests/files/types/eql_0f2b_stdlibs.gno create mode 100644 gnovm/tests/files/types/eql_0f2c_native.gno create mode 100644 gnovm/tests/files/types/eql_0f2c_stdlibs.gno create mode 100644 gnovm/tests/files/types/eql_0f2d.gno create mode 100644 gnovm/tests/files/types/eql_0f2e.gno create mode 100644 gnovm/tests/files/types/eql_0f30.gno create mode 100644 gnovm/tests/files/types/eql_0f30a.gno create mode 100644 gnovm/tests/files/types/eql_0f30b.gno create mode 100644 gnovm/tests/files/types/eql_0f30c.gno create mode 100644 gnovm/tests/files/types/eql_0f30d.gno create mode 100644 gnovm/tests/files/types/eql_0f30e.gno create mode 100644 gnovm/tests/files/types/eql_0f30f.gno create mode 100644 gnovm/tests/files/types/eql_0f30g.gno create mode 100644 gnovm/tests/files/types/eql_0f31.gno create mode 100644 gnovm/tests/files/types/eql_0f32.gno create mode 100644 gnovm/tests/files/types/eql_0f33.gno create mode 100644 gnovm/tests/files/types/eql_0f34.gno create mode 100644 gnovm/tests/files/types/eql_0f35.gno create mode 100644 gnovm/tests/files/types/eql_0f37.gno create mode 100644 gnovm/tests/files/types/eql_0f40_stdlibs.gno create mode 100644 gnovm/tests/files/types/eql_0f41_stdlibs.gno create mode 100644 gnovm/tests/files/types/eql_0f42.gno create mode 100644 gnovm/tests/files/types/eql_0f43_hasNil.gno create mode 100644 gnovm/tests/files/types/eql_0f44.gno create mode 100644 gnovm/tests/files/types/eql_0f45.gno create mode 100644 gnovm/tests/files/types/eql_0f46.gno create mode 100644 gnovm/tests/files/types/eql_0f46a.gno create mode 100644 gnovm/tests/files/types/eql_0f48.gno create mode 100644 gnovm/tests/files/types/eql_0f8_stdlibs.gno create mode 100644 gnovm/tests/files/types/eql_iface.gno create mode 100644 gnovm/tests/files/types/incdec_a0.gno create mode 100644 gnovm/tests/files/types/incdec_a1.gno create mode 100644 gnovm/tests/files/types/incdec_a2.gno create mode 100644 gnovm/tests/files/types/incdec_a3.gno create mode 100644 gnovm/tests/files/types/incdec_a4.gno create mode 100644 gnovm/tests/files/types/nil.gno create mode 100644 gnovm/tests/files/types/or_a0.gno create mode 100644 gnovm/tests/files/types/or_a1.gno create mode 100644 gnovm/tests/files/types/or_b0.gno create mode 100644 gnovm/tests/files/types/or_b1.gno create mode 100644 gnovm/tests/files/types/or_b2.gno create mode 100644 gnovm/tests/files/types/or_b3.gno create mode 100644 gnovm/tests/files/types/or_b4.gno create mode 100644 gnovm/tests/files/types/or_d0.gno create mode 100644 gnovm/tests/files/types/or_d1.gno create mode 100644 gnovm/tests/files/types/or_d2.gno create mode 100644 gnovm/tests/files/types/or_d3.gno create mode 100644 gnovm/tests/files/types/or_d4.gno create mode 100644 gnovm/tests/files/types/or_e0.gno create mode 100644 gnovm/tests/files/types/or_f0_stdlibs.gno create mode 100644 gnovm/tests/files/types/or_f1_stdlibs.gno create mode 100644 gnovm/tests/files/types/or_f2.gno create mode 100644 gnovm/tests/files/types/overflow_a0.gno create mode 100644 gnovm/tests/files/types/overflow_a1.gno create mode 100644 gnovm/tests/files/types/rem_a0.gno create mode 100644 gnovm/tests/files/types/rem_a1.gno create mode 100644 gnovm/tests/files/types/rem_a2.gno create mode 100644 gnovm/tests/files/types/rem_b0.gno create mode 100644 gnovm/tests/files/types/rem_f3.gno create mode 100644 gnovm/tests/files/types/runtime_a0.gno create mode 100644 gnovm/tests/files/types/runtime_a0a.gno create mode 100644 gnovm/tests/files/types/runtime_a2.gno create mode 100644 gnovm/tests/files/types/runtime_a3.gno create mode 100644 gnovm/tests/files/types/shift_a0.gno create mode 100644 gnovm/tests/files/types/shift_a1.gno create mode 100644 gnovm/tests/files/types/shift_a10.gno create mode 100644 gnovm/tests/files/types/shift_a11.gno create mode 100644 gnovm/tests/files/types/shift_a12.gno create mode 100644 gnovm/tests/files/types/shift_a13.gno create mode 100644 gnovm/tests/files/types/shift_a14.gno create mode 100644 gnovm/tests/files/types/shift_a15.gno create mode 100644 gnovm/tests/files/types/shift_a16.gno create mode 100644 gnovm/tests/files/types/shift_a2.gno create mode 100644 gnovm/tests/files/types/shift_a3.gno create mode 100644 gnovm/tests/files/types/shift_a4.gno create mode 100644 gnovm/tests/files/types/shift_a5.gno create mode 100644 gnovm/tests/files/types/shift_a6.gno create mode 100644 gnovm/tests/files/types/shift_a7.gno create mode 100644 gnovm/tests/files/types/shift_a8.gno create mode 100644 gnovm/tests/files/types/shift_a9.gno create mode 100644 gnovm/tests/files/types/time_native.gno create mode 100644 gnovm/tests/files/types/unary_a0.gno create mode 100644 gnovm/tests/files/types/unary_a0a.gno create mode 100644 gnovm/tests/files/types/unary_a0b.gno create mode 100644 gnovm/tests/files/types/unary_a0c.gno create mode 100644 gnovm/tests/files/types/unary_a1.gno create mode 100644 gnovm/tests/files/types/unary_a2.gno create mode 100644 gnovm/tests/files/types/unary_a2a.gno create mode 100644 gnovm/tests/files/types/unary_a3.gno create mode 100644 gnovm/tests/files/types/unary_a4.gno create mode 100644 gnovm/tests/files/types/unary_a5.gno create mode 100644 gnovm/tests/files/types/unary_a6.gno rename gnovm/tests/files/{zrealm12.gno => zrealm12_stdlibs.gno} (100%) rename gnovm/tests/files/{zrealm_const.gno => zrealm_const_stdlibs.gno} (100%) rename gnovm/tests/files/{zrealm_crossrealm0.gno => zrealm_crossrealm0_stdlibs.gno} (100%) rename gnovm/tests/files/{zrealm_crossrealm10.gno => zrealm_crossrealm10_stdlibs.gno} (100%) rename gnovm/tests/files/{zrealm_crossrealm11.gno => zrealm_crossrealm11_stdlibs.gno} (99%) rename gnovm/tests/files/{zrealm_crossrealm12.gno => zrealm_crossrealm12_stdlibs.gno} (86%) rename gnovm/tests/files/{zrealm_crossrealm13.gno => zrealm_crossrealm13_stdlibs.gno} (100%) rename gnovm/tests/files/{zrealm_crossrealm13a.gno => zrealm_crossrealm13a_stdlibs.gno} (100%) rename gnovm/tests/files/{zrealm_crossrealm1.gno => zrealm_crossrealm1_stdlibs.gno} (100%) rename gnovm/tests/files/{zrealm_crossrealm2.gno => zrealm_crossrealm2_stdlibs.gno} (100%) rename gnovm/tests/files/{zrealm_crossrealm3.gno => zrealm_crossrealm3_stdlibs.gno} (100%) rename gnovm/tests/files/{zrealm_crossrealm4.gno => zrealm_crossrealm4_stdlibs.gno} (100%) rename gnovm/tests/files/{zrealm_crossrealm5.gno => zrealm_crossrealm5_stdlibs.gno} (100%) rename gnovm/tests/files/{zrealm_crossrealm6.gno => zrealm_crossrealm6_stdlibs.gno} (100%) rename gnovm/tests/files/{zrealm_crossrealm7.gno => zrealm_crossrealm7_stdlibs.gno} (100%) rename gnovm/tests/files/{zrealm_crossrealm8.gno => zrealm_crossrealm8_stdlibs.gno} (100%) rename gnovm/tests/files/{zrealm_crossrealm9.gno => zrealm_crossrealm9_stdlibs.gno} (100%) rename gnovm/tests/files/{zrealm_initctx.gno => zrealm_initctx_stdlibs.gno} (100%) rename gnovm/tests/files/{zrealm_natbind0.gno => zrealm_natbind0_stdlibs.gno} (100%) rename gnovm/tests/files/{zrealm_std0.gno => zrealm_std0_stdlibs.gno} (100%) rename gnovm/tests/files/{zrealm_std1.gno => zrealm_std1_stdlibs.gno} (100%) rename gnovm/tests/files/{zrealm_std2.gno => zrealm_std2_stdlibs.gno} (100%) rename gnovm/tests/files/{zrealm_std3.gno => zrealm_std3_stdlibs.gno} (100%) rename gnovm/tests/files/{zrealm_std4.gno => zrealm_std4_stdlibs.gno} (100%) rename gnovm/tests/files/{zrealm_std5.gno => zrealm_std5_stdlibs.gno} (100%) rename gnovm/tests/files/{zrealm_std6.gno => zrealm_std6_stdlibs.gno} (56%) rename gnovm/tests/files/{zrealm_tests0.gno => zrealm_tests0_stdlibs.gno} (100%) rename gnovm/tests/files/{zrealm_testutils0.gno => zrealm_testutils0_stdlibs.gno} (100%) diff --git a/examples/gno.land/p/demo/memeland/memeland_test.gno b/examples/gno.land/p/demo/memeland/memeland_test.gno index 76c44327993..fbfcfec8ae3 100644 --- a/examples/gno.land/p/demo/memeland/memeland_test.gno +++ b/examples/gno.land/p/demo/memeland/memeland_test.gno @@ -6,6 +6,7 @@ import ( "testing" "time" + "gno.land/p/demo/seqid" "gno.land/p/demo/testutils" "gno.land/p/demo/ufmt" ) @@ -97,7 +98,7 @@ func TestGetPostsInRangeByTimestamp(t *testing.T) { // Count the number of posts returned in the JSON string as a rudimentary check for correct pagination/filtering postCount := strings.Count(jsonStr, `"id":"`) - if postCount != m.MemeCounter { + if seqid.ID(postCount) != m.MemeCounter { t.Errorf("Expected %d posts in the JSON string, but found %d", m.MemeCounter, postCount) } @@ -157,7 +158,7 @@ func TestGetPostsInRangeByUpvote(t *testing.T) { // Count the number of posts returned in the JSON string as a rudimentary check for correct pagination/filtering postCount := strings.Count(jsonStr, `"id":"`) - if postCount != m.MemeCounter { + if seqid.ID(postCount) != m.MemeCounter { t.Errorf("Expected %d posts in the JSON string, but found %d", m.MemeCounter, postCount) } diff --git a/gno.land/pkg/sdk/vm/vm.proto b/gno.land/pkg/sdk/vm/vm.proto index b99be0a85ff..aa0be4f6e14 100644 --- a/gno.land/pkg/sdk/vm/vm.proto +++ b/gno.land/pkg/sdk/vm/vm.proto @@ -15,6 +15,12 @@ message m_call { repeated string args = 5; } +message m_run { + string caller = 1; + string send = 2; + std.MemPackage package = 3; +} + message m_addpkg { string creator = 1; std.MemPackage package = 2; @@ -28,4 +34,8 @@ message InvalidStmtError { } message InvalidExprError { +} + +message TypeCheckError { + repeated string errors = 1 [json_name = "Errors"]; } \ No newline at end of file diff --git a/gnovm/Makefile b/gnovm/Makefile index ff3f07158c5..452b2dcc81a 100644 --- a/gnovm/Makefile +++ b/gnovm/Makefile @@ -81,6 +81,9 @@ _test.gnolang.native:; go test tests/*.go -test.short -run "TestFilesNativ _test.gnolang.stdlibs:; go test tests/*.go -test.short -run 'TestFiles$$/' $(GOTEST_FLAGS) _test.gnolang.native.sync:; go test tests/*.go -test.short -run "TestFilesNative/" --update-golden-tests $(GOTEST_FLAGS) _test.gnolang.stdlibs.sync:; go test tests/*.go -test.short -run 'TestFiles$$/' --update-golden-tests $(GOTEST_FLAGS) +# NOTE: challenges are current GnoVM bugs which are supposed to fail. +# If any of these tests pass, it should be moved to a normal test. +_test.gnolang.challenges:; go test tests/*.go -test.short -run 'TestChallenges$$/' $(GOTEST_FLAGS) ######################################## # Code gen diff --git a/gnovm/pkg/gnolang/debugger_test.go b/gnovm/pkg/gnolang/debugger_test.go index 1b5a72a183a..3f2f58b9709 100644 --- a/gnovm/pkg/gnolang/debugger_test.go +++ b/gnovm/pkg/gnolang/debugger_test.go @@ -31,9 +31,9 @@ func evalTest(debugAddr, in, file string) (out, err string) { stdout := writeNopCloser{bout} stderr := writeNopCloser{berr} debug := in != "" || debugAddr != "" - mode := tests.ImportModeNativePreferred - if strings.HasSuffix(file, "_stdlibs.gno") { - mode = tests.ImportModeStdlibsPreferred + mode := tests.ImportModeStdlibsPreferred + if strings.HasSuffix(file, "_native.gno") { + mode = tests.ImportModeNativePreferred } defer func() { @@ -196,7 +196,8 @@ func TestRemoteDebug(t *testing.T) { func TestRemoteError(t *testing.T) { _, err := evalTest(":xxx", "", debugTarget) t.Log("err:", err) - if !strings.Contains(err, "tcp/xxx: unknown port") { + if !strings.Contains(err, "tcp/xxx: unknown port") && + !strings.Contains(err, "tcp/xxx: nodename nor servname provided, or not known") { t.Error(err) } } diff --git a/gnovm/pkg/gnolang/gnolang.proto b/gnovm/pkg/gnolang/gnolang.proto index f7eaa907ec5..9904e26078f 100644 --- a/gnovm/pkg/gnolang/gnolang.proto +++ b/gnovm/pkg/gnolang/gnolang.proto @@ -58,6 +58,8 @@ message FuncValue { google.protobuf.Any closure = 5 [json_name = "Closure"]; string file_name = 6 [json_name = "FileName"]; string pkg_path = 7 [json_name = "PkgPath"]; + string native_pkg = 8 [json_name = "NativePkg"]; + string native_name = 9 [json_name = "NativeName"]; } message MapValue { diff --git a/gnovm/pkg/gnolang/gonative.go b/gnovm/pkg/gnolang/gonative.go index f73a5c58962..6127fa42b07 100644 --- a/gnovm/pkg/gnolang/gonative.go +++ b/gnovm/pkg/gnolang/gonative.go @@ -890,7 +890,7 @@ func gno2GoType(t Type) reflect.Type { // If gno2GoTypeMatches(t, rt) is true, a t value can // be converted to an rt native value using gno2GoValue(v, rv). -// This is called when autoNative is true in checkType(). +// This is called when autoNative is true in assertAssignableTo(). // This is used for all native function calls, and also // for testing whether a native value implements a gno interface. func gno2GoTypeMatches(t Type, rt reflect.Type) (result bool) { diff --git a/gnovm/pkg/gnolang/op_assign.go b/gnovm/pkg/gnolang/op_assign.go index 0cc30861355..eb67ffcc351 100644 --- a/gnovm/pkg/gnolang/op_assign.go +++ b/gnovm/pkg/gnolang/op_assign.go @@ -50,7 +50,7 @@ func (m *Machine) doOpAddAssign() { rv := m.PopValue() // only one. lv := m.PopAsPointer(s.Lhs[0]) if debug { - assertSameTypes(lv.TV.T, rv.T) + debugAssertSameTypes(lv.TV.T, rv.T) } // XXX HACK (until value persistence impl'd) @@ -73,7 +73,7 @@ func (m *Machine) doOpSubAssign() { rv := m.PopValue() // only one. lv := m.PopAsPointer(s.Lhs[0]) if debug { - assertSameTypes(lv.TV.T, rv.T) + debugAssertSameTypes(lv.TV.T, rv.T) } // XXX HACK (until value persistence impl'd) @@ -96,7 +96,7 @@ func (m *Machine) doOpMulAssign() { rv := m.PopValue() // only one. lv := m.PopAsPointer(s.Lhs[0]) if debug { - assertSameTypes(lv.TV.T, rv.T) + debugAssertSameTypes(lv.TV.T, rv.T) } // XXX HACK (until value persistence impl'd) @@ -119,7 +119,7 @@ func (m *Machine) doOpQuoAssign() { rv := m.PopValue() // only one. lv := m.PopAsPointer(s.Lhs[0]) if debug { - assertSameTypes(lv.TV.T, rv.T) + debugAssertSameTypes(lv.TV.T, rv.T) } // XXX HACK (until value persistence impl'd) @@ -142,7 +142,7 @@ func (m *Machine) doOpRemAssign() { rv := m.PopValue() // only one. lv := m.PopAsPointer(s.Lhs[0]) if debug { - assertSameTypes(lv.TV.T, rv.T) + debugAssertSameTypes(lv.TV.T, rv.T) } // XXX HACK (until value persistence impl'd) @@ -165,7 +165,7 @@ func (m *Machine) doOpBandAssign() { rv := m.PopValue() // only one. lv := m.PopAsPointer(s.Lhs[0]) if debug { - assertSameTypes(lv.TV.T, rv.T) + debugAssertSameTypes(lv.TV.T, rv.T) } // XXX HACK (until value persistence impl'd) @@ -188,7 +188,7 @@ func (m *Machine) doOpBandnAssign() { rv := m.PopValue() // only one. lv := m.PopAsPointer(s.Lhs[0]) if debug { - assertSameTypes(lv.TV.T, rv.T) + debugAssertSameTypes(lv.TV.T, rv.T) } // XXX HACK (until value persistence impl'd) @@ -211,7 +211,7 @@ func (m *Machine) doOpBorAssign() { rv := m.PopValue() // only one. lv := m.PopAsPointer(s.Lhs[0]) if debug { - assertSameTypes(lv.TV.T, rv.T) + debugAssertSameTypes(lv.TV.T, rv.T) } // XXX HACK (until value persistence impl'd) @@ -234,7 +234,7 @@ func (m *Machine) doOpXorAssign() { rv := m.PopValue() // only one. lv := m.PopAsPointer(s.Lhs[0]) if debug { - assertSameTypes(lv.TV.T, rv.T) + debugAssertSameTypes(lv.TV.T, rv.T) } // XXX HACK (until value persistence impl'd) diff --git a/gnovm/pkg/gnolang/op_binary.go b/gnovm/pkg/gnolang/op_binary.go index 99b56c18a06..a1861ed3aaa 100644 --- a/gnovm/pkg/gnolang/op_binary.go +++ b/gnovm/pkg/gnolang/op_binary.go @@ -45,7 +45,7 @@ func (m *Machine) doOpLor() { rv := m.PopValue() lv := m.PeekValue(1) // also the result if debug { - assertSameTypes(lv.T, rv.T) + debugAssertSameTypes(lv.T, rv.T) } // set result in lv. @@ -60,7 +60,7 @@ func (m *Machine) doOpLand() { rv := m.PopValue() lv := m.PeekValue(1) // also the result if debug { - assertSameTypes(lv.T, rv.T) + debugAssertSameTypes(lv.T, rv.T) } // set result in lv. @@ -77,7 +77,7 @@ func (m *Machine) doOpEql() { rv := m.PopValue() lv := m.PeekValue(1) // also the result if debug { - assertEqualityTypes(lv.T, rv.T) + debugAssertEqualityTypes(lv.T, rv.T) } // set result in lv. @@ -94,7 +94,7 @@ func (m *Machine) doOpNeq() { rv := m.PopValue() lv := m.PeekValue(1) // also the result if debug { - assertEqualityTypes(lv.T, rv.T) + debugAssertEqualityTypes(lv.T, rv.T) } // set result in lv. @@ -111,7 +111,7 @@ func (m *Machine) doOpLss() { rv := m.PopValue() lv := m.PeekValue(1) // also the result if debug { - assertSameTypes(lv.T, rv.T) + debugAssertSameTypes(lv.T, rv.T) } // set the result in lv. @@ -128,7 +128,7 @@ func (m *Machine) doOpLeq() { rv := m.PopValue() lv := m.PeekValue(1) // also the result if debug { - assertSameTypes(lv.T, rv.T) + debugAssertSameTypes(lv.T, rv.T) } // set the result in lv. @@ -145,7 +145,7 @@ func (m *Machine) doOpGtr() { rv := m.PopValue() lv := m.PeekValue(1) // also the result if debug { - assertSameTypes(lv.T, rv.T) + debugAssertSameTypes(lv.T, rv.T) } // set the result in lv. @@ -162,7 +162,7 @@ func (m *Machine) doOpGeq() { rv := m.PopValue() lv := m.PeekValue(1) // also the result if debug { - assertSameTypes(lv.T, rv.T) + debugAssertSameTypes(lv.T, rv.T) } // set the result in lv. @@ -179,7 +179,7 @@ func (m *Machine) doOpAdd() { rv := m.PopValue() lv := m.PeekValue(1) // also result if debug { - assertSameTypes(lv.T, rv.T) + debugAssertSameTypes(lv.T, rv.T) } // add rv to lv. @@ -193,7 +193,7 @@ func (m *Machine) doOpSub() { rv := m.PopValue() lv := m.PeekValue(1) // also result if debug { - assertSameTypes(lv.T, rv.T) + debugAssertSameTypes(lv.T, rv.T) } // sub rv from lv. @@ -207,7 +207,7 @@ func (m *Machine) doOpBor() { rv := m.PopValue() lv := m.PeekValue(1) // also result if debug { - assertSameTypes(lv.T, rv.T) + debugAssertSameTypes(lv.T, rv.T) } // lv | rv @@ -221,7 +221,7 @@ func (m *Machine) doOpXor() { rv := m.PopValue() lv := m.PeekValue(1) // also result if debug { - assertSameTypes(lv.T, rv.T) + debugAssertSameTypes(lv.T, rv.T) } // lv ^ rv @@ -235,7 +235,7 @@ func (m *Machine) doOpMul() { rv := m.PopValue() lv := m.PeekValue(1) // also result if debug { - assertSameTypes(lv.T, rv.T) + debugAssertSameTypes(lv.T, rv.T) } // lv * rv @@ -249,7 +249,7 @@ func (m *Machine) doOpQuo() { rv := m.PopValue() lv := m.PeekValue(1) // also result if debug { - assertSameTypes(lv.T, rv.T) + debugAssertSameTypes(lv.T, rv.T) } // lv / rv @@ -263,7 +263,7 @@ func (m *Machine) doOpRem() { rv := m.PopValue() lv := m.PeekValue(1) // also result if debug { - assertSameTypes(lv.T, rv.T) + debugAssertSameTypes(lv.T, rv.T) } // lv % rv @@ -309,7 +309,7 @@ func (m *Machine) doOpBand() { rv := m.PopValue() lv := m.PeekValue(1) // also result if debug { - assertSameTypes(lv.T, rv.T) + debugAssertSameTypes(lv.T, rv.T) } // lv & rv @@ -323,7 +323,7 @@ func (m *Machine) doOpBandn() { rv := m.PopValue() lv := m.PeekValue(1) // also result if debug { - assertSameTypes(lv.T, rv.T) + debugAssertSameTypes(lv.T, rv.T) } // lv &^ rv diff --git a/gnovm/pkg/gnolang/op_exec.go b/gnovm/pkg/gnolang/op_exec.go index 12e0f9e26e3..c7e8ffd600c 100644 --- a/gnovm/pkg/gnolang/op_exec.go +++ b/gnovm/pkg/gnolang/op_exec.go @@ -957,7 +957,7 @@ func (m *Machine) doOpSwitchClauseCase() { // eval whether cv == tv. if debug { - assertEqualityTypes(cv.T, tv.T) + debugAssertEqualityTypes(cv.T, tv.T) } match := isEql(m.Store, cv, tv) if match { diff --git a/gnovm/pkg/gnolang/preprocess.go b/gnovm/pkg/gnolang/preprocess.go index 459910505b9..8aca0058dcd 100644 --- a/gnovm/pkg/gnolang/preprocess.go +++ b/gnovm/pkg/gnolang/preprocess.go @@ -753,66 +753,75 @@ func Preprocess(store Store, ctx BlockNode, n Node) Node { case *BinaryExpr: lt := evalStaticTypeOf(store, last, n.Left) rt := evalStaticTypeOf(store, last, n.Right) - // Special (recursive) case if shift and right isn't uint. - isShift := n.Op == SHL || n.Op == SHR - if isShift && baseOf(rt) != UintType { - // convert n.Right to (gno) uint type, - rn := Expr(Call("uint", n.Right)) - // reset/create n2 to preprocess right child. - n2 := &BinaryExpr{ - Left: n.Left, - Op: n.Op, - Right: rn, - } - resn := Preprocess(store, last, n2) - return resn, TRANS_CONTINUE + + lcx, lic := n.Left.(*ConstExpr) + rcx, ric := n.Right.(*ConstExpr) + + if debug { + debug.Printf("Trans_leave, BinaryExpr, OP: %v, lx: %v, rx: %v, lt: %v, rt: %v, isLeftConstExpr: %v, isRightConstExpr %v, isLeftUntyped: %v, isRightUntyped: %v \n", n.Op, n.Left, n.Right, lt, rt, lic, ric, isUntyped(lt), isUntyped(rt)) } - // Left and right hand expressions must evaluate to a boolean typed value if - // the operation is a logical AND or OR. - if (n.Op == LAND || n.Op == LOR) && (lt.Kind() != BoolKind || rt.Kind() != BoolKind) { - panic("operands of boolean operators must evaluate to boolean typed values") + // Special (recursive) case if shift and right isn't uint. + isShift := n.Op == SHL || n.Op == SHR + if isShift { + // check LHS type compatibility + n.checkShiftLhs(lt) + // checkOrConvert RHS + if baseOf(rt) != UintType { + // convert n.Right to (gno) uint type, + rn := Expr(Call("uint", n.Right)) + // reset/create n2 to preprocess right child. + n2 := &BinaryExpr{ + Left: n.Left, + Op: n.Op, + Right: rn, + } + resn := Preprocess(store, last, n2) + return resn, TRANS_CONTINUE + } + // Then, evaluate the expression. + if lic && ric { + cx := evalConst(store, last, n) + return cx, TRANS_CONTINUE + } + return n, TRANS_CONTINUE } + // general cases + n.AssertCompatible(lt, rt) // check compatibility against binaryExprs other than shift expr // General case. - lcx, lic := n.Left.(*ConstExpr) - rcx, ric := n.Right.(*ConstExpr) if lic { if ric { // Left const, Right const ---------------------- // Replace with *ConstExpr if const operands. // First, convert untyped as necessary. - if !isShift { - cmp := cmpSpecificity(lcx.T, rcx.T) - if cmp < 0 { - // convert n.Left to right type. - checkOrConvertType(store, last, &n.Left, rcx.T, false) - } else if cmp == 0 { - // NOTE: the following doesn't work. - // TODO: make it work. - // convert n.Left to right type, - // or check for compatibility. - // (the other way around would work too) - // checkOrConvertType(store, last, n.Left, rcx.T, false) - } else { - // convert n.Right to left type. - checkOrConvertType(store, last, &n.Right, lcx.T, false) - } + if !shouldSwapOnSpecificity(lcx.T, rcx.T) { + // convert n.Left to right type. + checkOrConvertType(store, last, &n.Left, rcx.T, false) + } else { + // convert n.Right to left type. + checkOrConvertType(store, last, &n.Right, lcx.T, false) } // Then, evaluate the expression. cx := evalConst(store, last, n) return cx, TRANS_CONTINUE } else if isUntyped(lcx.T) { // Left untyped const, Right not ---------------- - if rnt, ok := rt.(*NativeType); ok { - if isShift { + if rnt, ok := rt.(*NativeType); ok { // untyped -> gno(native), e.g. 1*time.Second + if isShift { // RHS of shift should not be native panic("should not happen") } // get concrete native base type. - pt := go2GnoBaseType(rnt.Type).(PrimitiveType) + pt, ok := go2GnoBaseType(rnt.Type).(PrimitiveType) + if !ok { + panic(fmt.Sprintf( + "unexpected type pair: cannot use %s as %s", + lt.String(), + rnt.String())) + } // convert n.Left to pt type, checkOrConvertType(store, last, &n.Left, pt, false) - // convert n.Right to (gno) pt type, + // if check pass, convert n.Right to (gno) pt type, rn := Expr(Call(pt.String(), n.Right)) // and convert result back. tx := constType(n, rnt) @@ -822,100 +831,127 @@ func Preprocess(store Store, ctx BlockNode, n Node) Node { Op: n.Op, Right: rn, } - resn := Node(Call(tx, n2)) + resn := Node(Call(tx, n2)) // this make current node to gonative{xxx} resn = Preprocess(store, last, resn) return resn, TRANS_CONTINUE // NOTE: binary operations are always computed in // gno, never with reflect. } else { - if isShift { - // nothing to do, right type is (already) uint type. - // we don't yet know what this type should be, - // but another checkOrConvertType() later does. - // (e.g. from AssignStmt or other). - } else { - // convert n.Left to right type. - checkOrConvertType(store, last, &n.Left, rt, false) - } + // convert n.Left to right type. + checkOrConvertType(store, last, &n.Left, rt, false) } - } else if lcx.T == nil { + } else if lcx.T == nil { // LHS is nil. // convert n.Left to typed-nil type. checkOrConvertType(store, last, &n.Left, rt, false) } - } else if ric { + } else if ric { // right is const, left is not if isUntyped(rcx.T) { // Left not, Right untyped const ---------------- - if isShift { - if baseOf(rt) != UintType { - // convert n.Right to (gno) uint type. - checkOrConvertType(store, last, &n.Right, UintType, false) - } else { - // leave n.Left as is and baseOf(n.Right) as UintType. + if lnt, ok := lt.(*NativeType); ok { + // get concrete native base type. + pt, ok := go2GnoBaseType(lnt.Type).(PrimitiveType) + if !ok { + panic(fmt.Sprintf( + "unexpected type pair: cannot use %s as %s", + rt.String(), + lnt.String())) } - } else { - if lnt, ok := lt.(*NativeType); ok { - // get concrete native base type. - pt := go2GnoBaseType(lnt.Type).(PrimitiveType) - // convert n.Left to (gno) pt type, - ln := Expr(Call(pt.String(), n.Left)) - // convert n.Right to pt type, - checkOrConvertType(store, last, &n.Right, pt, false) - // and convert result back. - tx := constType(n, lnt) - // reset/create n2 to preprocess left child. - n2 := &BinaryExpr{ - Left: ln, - Op: n.Op, - Right: n.Right, - } - resn := Node(Call(tx, n2)) - resn = Preprocess(store, last, resn) - return resn, TRANS_CONTINUE - // NOTE: binary operations are always computed in - // gno, never with reflect. - } else { - // convert n.Right to left type. - checkOrConvertType(store, last, &n.Right, lt, false) + // convert n.Left to (gno) pt type, + ln := Expr(Call(pt.String(), n.Left)) + // convert n.Right to pt type, + checkOrConvertType(store, last, &n.Right, pt, false) + // and convert result back. + tx := constType(n, lnt) + // reset/create n2 to preprocess left child. + n2 := &BinaryExpr{ + Left: ln, + Op: n.Op, + Right: n.Right, } + resn := Node(Call(tx, n2)) + resn = Preprocess(store, last, resn) + return resn, TRANS_CONTINUE + // NOTE: binary operations are always computed in + // gno, never with reflect. + } else { + // convert n.Right to left type. + checkOrConvertType(store, last, &n.Right, lt, false) } - } else if rcx.T == nil { - // convert n.Right to typed-nil type. + } else if rcx.T == nil { // RHS is nil + // refer to tests/files/types/eql_0f20.gno checkOrConvertType(store, last, &n.Right, lt, false) } } else { // Left not const, Right not const ------------------ - if n.Op == EQL || n.Op == NEQ { - // If == or !=, no conversions. - } else if lnt, ok := lt.(*NativeType); ok && isNative(rt) { - if debug { - if !isShift { - assertSameTypes(lt, rt) - } - } - // If left and right are native type, and same type + if lnt, ok := lt.(*NativeType); ok { + // If left and right are native type, // convert left and right to gno, then // convert result back to native. - // - // get concrete native base type. - if lt.TypeID() != rt.TypeID() { + // get native base type. + lpt, ok := go2GnoBaseType(lnt.Type).(PrimitiveType) + if !ok { + panic(fmt.Sprintf( + "unexpected type pair: cannot use %s as %s", + rt.String(), + lnt.String())) + } + // convert n.Left to (gno) pt type, + ln := Expr(Call(lpt.String(), n.Left)) + + rn := n.Right + // e.g. native: time.Second + time.Second, convert both(or it will be converted recursively) + // see tests/files/types/time_native.gno + if rnt, ok := rt.(*NativeType); ok { + rpt, ok := go2GnoBaseType(rnt.Type).(PrimitiveType) + if !ok { + panic(fmt.Sprintf( + "unexpected type pair: cannot use %s as %s", + lt.String(), + rnt.String())) + } + // check assignable, if pass, convert right to gno first + assertAssignableTo(lpt, rpt, false) // both primitive types + rn = Expr(Call(rpt.String(), n.Right)) + } else { // rt not native panic(fmt.Sprintf( - "incompatible types in binary expression: %v %v %v", + "incompatible operands in binary expression: %s %s %s", lt.TypeID(), n.Op, rt.TypeID())) } - pt := go2GnoBaseType(lnt.Type).(PrimitiveType) + + // and convert result back. + tx := constType(n, lnt) + // reset/create n2 to preprocess + // children. + n2 := &BinaryExpr{ + Left: ln, + Op: n.Op, + Right: rn, + } + resn := Node(Call(tx, n2)) + resn = Preprocess(store, last, resn) + return resn, TRANS_CONTINUE + // NOTE: binary operations are always + // computed in gno, never with + // reflect. + } else if rnt, ok := rt.(*NativeType); ok { // e.g. a * time.Second + pt, ok := go2GnoBaseType(rnt.Type).(PrimitiveType) + if !ok { + panic(fmt.Sprintf( + "unexpected type pair: cannot use %s as %s", + lt.String(), + rnt.String())) + } // convert n.Left to (gno) pt type, - ln := Expr(Call(pt.String(), n.Left)) + rn := Expr(Call(pt.String(), n.Right)) // convert n.Right to pt or uint type, - rn := n.Right + ln := n.Left if isShift { - if baseOf(rt) != UintType { - rn = Expr(Call("uint", n.Right)) - } + panic("should not happen") } else { - rn = Expr(Call(pt.String(), n.Right)) + checkOrConvertType(store, last, &n.Left, pt, false) } // and convert result back. - tx := constType(n, lnt) + tx := constType(n, rnt) // reset/create n2 to preprocess // children. n2 := &BinaryExpr{ @@ -929,8 +965,6 @@ func Preprocess(store Store, ctx BlockNode, n Node) Node { // NOTE: binary operations are always // computed in gno, never with // reflect. - } else if n.Op == SHL || n.Op == SHR { - // shift operator, nothing yet to do. } else { // non-shift non-const binary operator. liu, riu := isUntyped(lt), isUntyped(rt) @@ -941,24 +975,20 @@ func Preprocess(store Store, ctx BlockNode, n Node) Node { "incompatible types in binary expression: %v %v %v", lt.TypeID(), n.Op, rt.TypeID())) } - } else { + } else { // left untyped, right typed checkOrConvertType(store, last, &n.Left, rt, false) } - } else { - if riu { - checkOrConvertType(store, last, &n.Right, lt, false) + } else if riu { // left typed, right untyped + checkOrConvertType(store, last, &n.Right, lt, false) + } else { // both typed, refer to 0a1g.gno + if !shouldSwapOnSpecificity(lt, rt) { + checkOrConvertType(store, last, &n.Left, rt, false) } else { - // left is untyped, right is not. - if lt.TypeID() != rt.TypeID() { - panic(fmt.Sprintf( - "incompatible types in binary expression: %v %v %v", - lt.TypeID(), n.Op, rt.TypeID())) - } + checkOrConvertType(store, last, &n.Right, lt, false) } } } } - // TRANS_LEAVE ----------------------- case *CallExpr: // Func type evaluation. @@ -1177,12 +1207,12 @@ func Preprocess(store Store, ctx BlockNode, n Node) Node { for i, tv := range argTVs { if hasVarg { if (len(spts) - 1) <= i { - checkType(tv.T, spts[len(spts)-1].Type.Elem(), true) + assertAssignableTo(tv.T, spts[len(spts)-1].Type.Elem(), true) } else { - checkType(tv.T, spts[i].Type, true) + assertAssignableTo(tv.T, spts[i].Type, true) } } else { - checkType(tv.T, spts[i].Type, true) + assertAssignableTo(tv.T, spts[i].Type, true) } } } else { @@ -1278,6 +1308,7 @@ func Preprocess(store Store, ctx BlockNode, n Node) Node { // TRANS_LEAVE ----------------------- case *UnaryExpr: xt := evalStaticTypeOf(store, last, n.X) + n.AssertCompatible(xt) if xnt, ok := xt.(*NativeType); ok { // get concrete native base type. pt := go2GnoBaseType(xnt.Type).(PrimitiveType) @@ -1325,12 +1356,12 @@ func Preprocess(store Store, ctx BlockNode, n Node) Node { } case *ArrayType: for i := 0; i < len(n.Elts); i++ { - checkOrConvertType(store, last, &n.Elts[i].Key, IntType, false) + convertType(store, last, &n.Elts[i].Key, IntType) checkOrConvertType(store, last, &n.Elts[i].Value, cclt.Elt, false) } case *SliceType: for i := 0; i < len(n.Elts); i++ { - checkOrConvertType(store, last, &n.Elts[i].Key, IntType, false) + convertType(store, last, &n.Elts[i].Key, IntType) checkOrConvertType(store, last, &n.Elts[i].Value, cclt.Elt, false) } case *MapType: @@ -1571,6 +1602,7 @@ func Preprocess(store Store, ctx BlockNode, n Node) Node { // TRANS_LEAVE ----------------------- case *AssignStmt: + n.AssertCompatible(store, last) // NOTE: keep DEFINE and ASSIGN in sync. if n.Op == DEFINE { // Rhs consts become default *ConstExprs. @@ -1578,22 +1610,13 @@ func Preprocess(store Store, ctx BlockNode, n Node) Node { // NOTE: does nothing if rx is "nil". convertIfConst(store, last, rx) } + if len(n.Lhs) > len(n.Rhs) { - // Unpack n.Rhs[0] to n.Lhs[:] - if len(n.Rhs) != 1 { - panic("should not happen") - } switch cx := n.Rhs[0].(type) { case *CallExpr: // Call case: a, b := x(...) ift := evalStaticTypeOf(store, last, cx.Func) cft := getGnoFuncTypeOf(store, ift) - if len(n.Lhs) != len(cft.Results) { - panic(fmt.Sprintf( - "assignment mismatch: "+ - "%d variables but %s returns %d values", - len(n.Lhs), cx.Func.String(), len(cft.Results))) - } for i, lx := range n.Lhs { ln := lx.(*NameExpr).Name rf := cft.Results[i] @@ -1601,11 +1624,6 @@ func Preprocess(store Store, ctx BlockNode, n Node) Node { last.Define(ln, anyValue(rf.Type)) } case *TypeAssertExpr: - // Type-assert case: a, ok := x.(type) - if len(n.Lhs) != 2 { - panic("should not happen") - } - cx.HasOK = true lhs0 := n.Lhs[0].(*NameExpr).Name lhs1 := n.Lhs[1].(*NameExpr).Name tt := evalStaticType(store, last, cx.Type) @@ -1613,11 +1631,6 @@ func Preprocess(store Store, ctx BlockNode, n Node) Node { last.Define(lhs0, anyValue(tt)) last.Define(lhs1, anyValue(BoolType)) case *IndexExpr: - // Index case: v, ok := x[k], x is map. - if len(n.Lhs) != 2 { - panic("should not happen") - } - cx.HasOK = true lhs0 := n.Lhs[0].(*NameExpr).Name lhs1 := n.Lhs[1].(*NameExpr).Name @@ -1649,56 +1662,27 @@ func Preprocess(store Store, ctx BlockNode, n Node) Node { } } } else { // ASSIGN, or assignment operation (+=, -=, <<=, etc.) - // If this is an assignment operation, ensure there's only 1 - // expr on lhs/rhs. - if n.Op != ASSIGN && - (len(n.Lhs) != 1 || len(n.Rhs) != 1) { - panic("assignment operator " + n.Op.TokenString() + - " requires only one expression on lhs and rhs") - } - // NOTE: Keep in sync with DEFINE above. - if n.Op == SHL_ASSIGN || n.Op == SHR_ASSIGN { - // Special case if shift assign <<= or >>=. - checkOrConvertType(store, last, &n.Rhs[0], UintType, false) - } else if len(n.Lhs) > len(n.Rhs) { - // TODO dry code w/ above. - // Unpack n.Rhs[0] to n.Lhs[:] - if len(n.Rhs) != 1 { - panic("should not happen") - } - switch cx := n.Rhs[0].(type) { - case *CallExpr: - // Call case: a, b = x(...) - ift := evalStaticTypeOf(store, last, cx.Func) - cft := getGnoFuncTypeOf(store, ift) - if len(n.Lhs) != len(cft.Results) { - panic(fmt.Sprintf( - "assignment mismatch: "+ - "%d variables but %s returns %d values", - len(n.Lhs), cx.Func.String(), len(cft.Results))) - } - case *TypeAssertExpr: - // Type-assert case: a, ok := x.(type) - if len(n.Lhs) != 2 { + if len(n.Lhs) > len(n.Rhs) { + // check is done in assertCompatible + } else { // len(Lhs) == len(Rhs) + if n.Op == SHL_ASSIGN || n.Op == SHR_ASSIGN { + if len(n.Lhs) != 1 || len(n.Rhs) != 1 { panic("should not happen") } - cx.HasOK = true - case *IndexExpr: - // Index case: v, ok := x[k], x is map. - if len(n.Lhs) != 2 { - panic("should not happen") + // Special case if shift assign <<= or >>=. + convertType(store, last, &n.Rhs[0], UintType) + } else if n.Op == ADD_ASSIGN || n.Op == SUB_ASSIGN || n.Op == MUL_ASSIGN || n.Op == QUO_ASSIGN || n.Op == REM_ASSIGN { + // e.g. a += b, single value for lhs and rhs, + lt := evalStaticTypeOf(store, last, n.Lhs[0]) + checkOrConvertType(store, last, &n.Rhs[0], lt, true) + } else { // all else, like BAND_ASSIGN, etc + // General case: a, b = x, y. + for i, lx := range n.Lhs { + lt := evalStaticTypeOf(store, last, lx) + // if lt is interface, nothing will happen + checkOrConvertType(store, last, &n.Rhs[i], lt, true) } - cx.HasOK = true - default: - panic("should not happen") - } - } else { - // General case: a, b = x, y. - for i, lx := range n.Lhs { - lt := evalStaticTypeOf(store, last, lx) - // converts if rx is "nil". - checkOrConvertType(store, last, &n.Rhs[i], lt, false) } } } @@ -1737,6 +1721,10 @@ func Preprocess(store Store, ctx BlockNode, n Node) Node { panic("should not happen") } + case *IncDecStmt: + xt := evalStaticTypeOf(store, last, n.X) + n.AssertCompatible(xt) + // TRANS_LEAVE ----------------------- case *ForStmt: // Cond consts become bool *ConstExprs. @@ -1750,6 +1738,7 @@ func Preprocess(store Store, ctx BlockNode, n Node) Node { // TRANS_LEAVE ----------------------- case *RangeStmt: // NOTE: k,v already defined @ TRANS_BLOCK. + n.AssertCompatible(store, last) // TRANS_LEAVE ----------------------- case *ReturnStmt: @@ -2438,47 +2427,25 @@ func isConstType(x Expr) bool { return ok } -func cmpSpecificity(t1, t2 Type) int { - t1s, t2s := 0, 0 - if t1p, ok := t1.(PrimitiveType); ok { - t1s = t1p.Specificity() - } - if t2p, ok := t2.(PrimitiveType); ok { - t2s = t2p.Specificity() - } - if t1s < t2s { - // NOTE: higher specificity has lower value, so backwards. - return 1 - } else if t1s == t2s { - return 0 - } else { - return -1 - } -} - -// 1. convert x to t if x is *ConstExpr. -// 2. otherwise, assert that x can be coerced to t. -// autoNative is usually false, but set to true -// for native function calls, where gno values are -// automatically converted to native go types. -// NOTE: also see checkOrConvertIntegerType() +// check before convert type func checkOrConvertType(store Store, last BlockNode, x *Expr, t Type, autoNative bool) { + if debug { + debug.Printf("checkOrConvertType, *x: %v:, t:%v \n", *x, t) + } if cx, ok := (*x).(*ConstExpr); ok { - convertConst(store, last, cx, t) + if _, ok := t.(*NativeType); !ok { // not native type, refer to time4_native.gno. + // e.g. int(1) == int8(1) + assertAssignableTo(cx.T, t, autoNative) + } } else if bx, ok := (*x).(*BinaryExpr); ok && (bx.Op == SHL || bx.Op == SHR) { - // "push" expected type into shift binary's left operand. + // "push" expected type into shift binary's left operand. recursively. checkOrConvertType(store, last, &bx.Left, t, autoNative) } else if *x != nil { // XXX if x != nil && t != nil { - // check type xt := evalStaticTypeOf(store, last, *x) if t != nil { - checkType(xt, t, autoNative) + assertAssignableTo(xt, t, autoNative) } - // convert type - if isUntyped(xt) { // convert if x is untyped literal - if t == nil { - t = defaultTypeOf(xt) - } + if isUntyped(xt) { // Push type into expr if qualifying binary expr. if bx, ok := (*x).(*BinaryExpr); ok { switch bx.Op { @@ -2496,20 +2463,47 @@ func checkOrConvertType(store Store, last BlockNode, x *Expr, t Type, autoNative // default: } } + } + } + // convert recursively + convertType(store, last, x, t) +} + +// 1. convert x to t if x is *ConstExpr. +// 2. otherwise, assert that x can be coerced to t. +// autoNative is usually false, but set to true +// for native function calls, where gno values are +// automatically converted to native go types. +// NOTE: also see checkOrConvertIntegerType() +func convertType(store Store, last BlockNode, x *Expr, t Type) { + if debug { + debug.Printf("convertType, *x: %v:, t:%v \n", *x, t) + } + if cx, ok := (*x).(*ConstExpr); ok { + convertConst(store, last, cx, t) + } else if *x != nil { + xt := evalStaticTypeOf(store, last, *x) + if isUntyped(xt) { + if t == nil { + t = defaultTypeOf(xt) + } + if debug { + debug.Printf("default type of t: %v \n", t) + } // convert x to destination type t - convertType(store, last, x, t) + doConvertType(store, last, x, t) } else { // if one side is declared name type and the other side is unnamed type if isNamedConversion(xt, t) { // covert right (xt) to the type of the left (t) - convertType(store, last, x, t) + doConvertType(store, last, x, t) } } } } // convert x to destination type t -func convertType(store Store, last BlockNode, x *Expr, t Type) { +func doConvertType(store Store, last BlockNode, x *Expr, t Type) { cx := Expr(Call(constType(nil, t), *x)) cx = Preprocess(store, last, cx).(Expr) *x = cx @@ -2563,7 +2557,7 @@ func convertIfConst(store Store, last BlockNode, x Expr) { func convertConst(store Store, last BlockNode, cx *ConstExpr, t Type) { if t != nil && t.Kind() == InterfaceKind { if cx.T != nil { - checkType(cx.T, t, false) + assertAssignableTo(cx.T, t, false) } t = nil // signifies to convert to default type. } @@ -2577,232 +2571,6 @@ func convertConst(store Store, last BlockNode, cx *ConstExpr, t Type) { } } -// Assert that xt can be assigned as dt (dest type). -// If autoNative is true, a broad range of xt can match against -// a target native dt type, if and only if dt is a native type. -func checkType(xt Type, dt Type, autoNative bool) { - // Special case if dt is interface kind: - if dt.Kind() == InterfaceKind { - if idt, ok := baseOf(dt).(*InterfaceType); ok { - if idt.IsEmptyInterface() { - // if dt is an empty Gno interface, any x ok. - return // ok - } else if idt.IsImplementedBy(xt) { - // if dt implements idt, ok. - return // ok - } else { - panic(fmt.Sprintf( - "%s does not implement %s", - xt.String(), - dt.String())) - } - } else if ndt, ok := baseOf(dt).(*NativeType); ok { - nidt := ndt.Type - if nidt.NumMethod() == 0 { - // if dt is an empty Go native interface, ditto. - return // ok - } else if nxt, ok := baseOf(xt).(*NativeType); ok { - // if xt has native base, do the naive native. - if nxt.Type.AssignableTo(nidt) { - return // ok - } else { - panic(fmt.Sprintf( - "cannot use %s as %s", - nxt.String(), - nidt.String())) - } - } else if pxt, ok := baseOf(xt).(*PointerType); ok { - nxt, ok := pxt.Elt.(*NativeType) - if !ok { - panic(fmt.Sprintf( - "pointer to non-native type cannot satisfy non-empty native interface; %s doesn't implement %s", - pxt.String(), - nidt.String())) - } - // if xt has native base, do the naive native. - if reflect.PointerTo(nxt.Type).AssignableTo(nidt) { - return // ok - } else { - panic(fmt.Sprintf( - "cannot use %s as %s", - pxt.String(), - nidt.String())) - } - } else { - panic(fmt.Sprintf( - "unexpected type pair: cannot use %s as %s", - xt.String(), - dt.String())) - } - } else { - panic("should not happen") - } - } - // Special case if xt or dt is *PointerType to *NativeType, - // convert to *NativeType of pointer kind. - if pxt, ok := xt.(*PointerType); ok { - // *gonative{x} is(to) gonative{*x} - //nolint:misspell - if enxt, ok := pxt.Elt.(*NativeType); ok { - xt = &NativeType{ - Type: reflect.PointerTo(enxt.Type), - } - } - } - if pdt, ok := dt.(*PointerType); ok { - // *gonative{x} is gonative{*x} - if endt, ok := pdt.Elt.(*NativeType); ok { - dt = &NativeType{ - Type: reflect.PointerTo(endt.Type), - } - } - } - // Special case of xt or dt is *DeclaredType, - // allow implicit conversion unless both are declared. - // TODO simplify with .IsNamedType(). - if dxt, ok := xt.(*DeclaredType); ok { - if ddt, ok := dt.(*DeclaredType); ok { - // types must match exactly. - if !dxt.sealed && !ddt.sealed && - dxt.PkgPath == ddt.PkgPath && - dxt.Name == ddt.Name { // not yet sealed - return // ok - } else if dxt.TypeID() == ddt.TypeID() { - return // ok - } else { - panic(fmt.Sprintf( - "cannot use %s as %s without explicit conversion", - dxt.String(), - ddt.String())) - } - } else { - // special case if implicitly named primitive type. - // TODO simplify with .IsNamedType(). - if _, ok := dt.(PrimitiveType); ok { - panic(fmt.Sprintf( - "cannot use %s as %s without explicit conversion", - dxt.String(), - dt.String())) - } else { - // carry on with baseOf(dxt) - xt = dxt.Base - } - } - } else if ddt, ok := dt.(*DeclaredType); ok { - // special case if implicitly named primitive type. - // TODO simplify with .IsNamedType(). - if _, ok := xt.(PrimitiveType); ok { - panic(fmt.Sprintf( - "cannot use %s as %s without explicit conversion", - xt.String(), - ddt.String())) - } else { - // carry on with baseOf(ddt) - dt = ddt.Base - } - } - // General cases. - switch cdt := dt.(type) { - case PrimitiveType: - // if xt is untyped, ensure dt is compatible. - switch xt { - case UntypedBoolType: - if dt.Kind() == BoolKind { - return // ok - } else { - panic(fmt.Sprintf( - "cannot use untyped bool as %s", - dt.Kind())) - } - case UntypedStringType: - if dt.Kind() == StringKind { - return // ok - } else { - panic(fmt.Sprintf( - "cannot use untyped string as %s", - dt.Kind())) - } - case UntypedRuneType, UntypedBigintType: - switch dt.Kind() { - case IntKind, Int8Kind, Int16Kind, Int32Kind, - Int64Kind, UintKind, Uint8Kind, Uint16Kind, - Uint32Kind, Uint64Kind: - return // ok - default: - panic(fmt.Sprintf( - "cannot use untyped rune as %s", - dt.Kind())) - } - default: - if isUntyped(xt) { - panic("unexpected untyped type") - } - if xt.TypeID() == cdt.TypeID() { - return // ok - } - } - case *PointerType: - if pt, ok := xt.(*PointerType); ok { - checkType(pt.Elt, cdt.Elt, false) - return // ok - } - case *ArrayType: - if at, ok := xt.(*ArrayType); ok { - checkType(at.Elt, cdt.Elt, false) - return // ok - } - case *SliceType: - if st, ok := xt.(*SliceType); ok { - checkType(st.Elt, cdt.Elt, false) - return // ok - } - case *MapType: - if mt, ok := xt.(*MapType); ok { - checkType(mt.Key, cdt.Key, false) - checkType(mt.Value, cdt.Value, false) - return // ok - } - case *FuncType: - if xt.TypeID() == cdt.TypeID() { - return // ok - } - case *InterfaceType: - panic("should not happen") - case *DeclaredType: - panic("should not happen") - case *StructType, *PackageType, *ChanType: - if xt.TypeID() == cdt.TypeID() { - return // ok - } - case *TypeType: - if xt.TypeID() == cdt.TypeID() { - return // ok - } - case *NativeType: - if !autoNative { - if xt.TypeID() == cdt.TypeID() { - return // ok - } - } else { - // autoNative, so check whether matches. - // xt: any type but a *DeclaredType; could be native. - // cdt: actual concrete native target type. - // ie, if cdt can match against xt. - if gno2GoTypeMatches(xt, cdt.Type) { - return // ok - } - } - default: - panic(fmt.Sprintf( - "unexpected type %s", - dt.String())) - } - panic(fmt.Sprintf( - "cannot use %s as %s", - xt.String(), - dt.String())) -} - // 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 diff --git a/gnovm/pkg/gnolang/preprocess_test.go b/gnovm/pkg/gnolang/preprocess_test.go index 2419a385e14..49e6d53fd3d 100644 --- a/gnovm/pkg/gnolang/preprocess_test.go +++ b/gnovm/pkg/gnolang/preprocess_test.go @@ -29,7 +29,7 @@ func main() { defer func() { err := recover() - assert.Contains(t, fmt.Sprint(err), "incompatible types in binary expression") + assert.Contains(t, fmt.Sprint(err), "incompatible operands in binary expression") }() Preprocess(store, pn, n) } @@ -54,7 +54,7 @@ func main() { defer func() { err := recover() - assert.Contains(t, fmt.Sprint(err), "incompatible types in binary expression") + assert.Contains(t, fmt.Sprint(err), "incompatible operands in binary expression") }() Preprocess(store, pn, n) } diff --git a/gnovm/pkg/gnolang/type_check.go b/gnovm/pkg/gnolang/type_check.go new file mode 100644 index 00000000000..870eb10b690 --- /dev/null +++ b/gnovm/pkg/gnolang/type_check.go @@ -0,0 +1,926 @@ +package gnolang + +import ( + "fmt" + "reflect" + + "github.com/gnolang/gno/tm2/pkg/errors" +) + +// here are a range of rules predefined for preprocessor to check the compatibility between operands and operators +// e,g. for binary expr x + y, x, y can only be numeric or string, 1+2, "a" + "b" +// this is used in assertCompatible()s. +var ( + binaryChecker = map[Word]func(t Type) bool{ + ADD: isNumericOrString, + SUB: isNumeric, + MUL: isNumeric, + QUO: isNumeric, + REM: isIntNum, + SHL: isIntNum, + SHR: isIntNum, + BAND: isIntNum, // bit ops + XOR: isIntNum, + BOR: isIntNum, + BAND_NOT: isIntNum, + LAND: isBoolean, // logic + LOR: isBoolean, + LSS: isOrdered, // compare + LEQ: isOrdered, + GTR: isOrdered, + GEQ: isOrdered, + } + // TODO: star, addressable + unaryChecker = map[Word]func(t Type) bool{ + ADD: isNumeric, + SUB: isNumeric, + XOR: isIntNum, + NOT: isBoolean, + } + IncDecStmtChecker = map[Word]func(t Type) bool{ + INC: isNumeric, + DEC: isNumeric, + } + AssignStmtChecker = map[Word]func(t Type) bool{ + ADD_ASSIGN: isNumericOrString, + SUB_ASSIGN: isNumeric, + MUL_ASSIGN: isNumeric, + QUO_ASSIGN: isNumeric, + REM_ASSIGN: isIntNum, + SHL_ASSIGN: isNumeric, + SHR_ASSIGN: isNumeric, + BAND_ASSIGN: isIntNum, + XOR_ASSIGN: isIntNum, + BOR_ASSIGN: isIntNum, + BAND_NOT_ASSIGN: isIntNum, + } +) + +type category int + +const ( + IsBoolean category = 1 << iota + IsInteger + IsFloat + IsString + IsBigInt + IsBigDec + + IsNumeric = IsInteger | IsFloat | IsBigInt | IsBigDec + IsOrdered = IsNumeric | IsString +) + +func (pt PrimitiveType) category() category { + switch pt.Kind() { + case BoolKind: + return IsBoolean + case StringKind: + return IsString + case IntKind, Int8Kind, Int16Kind, Int32Kind, Int64Kind, UintKind, Uint8Kind, Uint16Kind, Uint32Kind, Uint64Kind: + return IsInteger // UntypedRuneType is int32kind, DataByteType is uint8 kind + case Float32Kind, Float64Kind: + return IsFloat + case BigintKind: + return IsBigInt + case BigdecKind: + return IsBigDec + default: + panic(fmt.Sprintf("unexpected primitive type %v", pt)) + } +} + +func isOrdered(t Type) bool { + switch t := baseOf(t).(type) { + case PrimitiveType: + return t.category()&IsOrdered != 0 + default: + return false + } +} + +func isBoolean(t Type) bool { + switch t := baseOf(t).(type) { + case PrimitiveType: + return t.category()&IsBoolean != 0 + default: + return false + } +} + +// rune can be numeric and string +func isNumeric(t Type) bool { + switch t := baseOf(t).(type) { + case PrimitiveType: + return t.category()&IsNumeric != 0 + default: + return false + } +} + +func isIntNum(t Type) bool { + switch t := baseOf(t).(type) { + case PrimitiveType: + return t.category()&IsInteger != 0 || t.category()&IsBigInt != 0 + default: + return false + } +} + +func isNumericOrString(t Type) bool { + switch t := baseOf(t).(type) { + case PrimitiveType: + return t.category()&IsNumeric != 0 || t.category()&IsString != 0 + default: + return false + } +} + +// =========================================================== +func assertComparable(xt, dt Type) { + switch baseOf(dt).(type) { + case *SliceType, *FuncType, *MapType: + if xt != nil { + panic(fmt.Sprintf("%v can only be compared to nil", dt)) + } + } + assertComparable2(dt) +} + +// assert value with dt is comparable +func assertComparable2(dt Type) { + if debug { + debug.Printf("assertComparable2 dt: %v \n", dt) + } + switch cdt := baseOf(dt).(type) { + case PrimitiveType: + case *ArrayType: + switch baseOf(cdt.Elem()).(type) { + case PrimitiveType, *PointerType, *InterfaceType, *NativeType, *ArrayType, *StructType, *ChanType: + assertComparable2(cdt.Elem()) + default: + panic(fmt.Sprintf("%v is not comparable", dt)) + } + case *StructType: + for _, f := range cdt.Fields { + switch cft := baseOf(f.Type).(type) { + case PrimitiveType, *PointerType, *InterfaceType, *NativeType, *ArrayType, *StructType: + assertComparable2(cft) + default: + panic(fmt.Sprintf("%v is not comparable", dt)) + } + } + case *PointerType: // &a == &b + case *InterfaceType: + case *SliceType, *FuncType, *MapType: + case *NativeType: + if !cdt.Type.Comparable() { + panic(fmt.Sprintf("%v is not comparable", dt)) + } + default: + panic(fmt.Sprintf("%v is not comparable", dt)) + } +} + +func maybeNil(t Type) bool { + switch cxt := baseOf(t).(type) { + case *SliceType, *FuncType, *MapType, *InterfaceType, *PointerType, *ChanType: // we don't have unsafePointer + return true + case *NativeType: + switch nk := cxt.Type.Kind(); nk { + case reflect.Slice, reflect.Func, reflect.Map, reflect.Interface, reflect.Pointer: + return true + default: + return false + } + default: + return false + } +} + +func checkSame(at, bt Type, msg string) error { + if debug { + debug.Printf("checkSame, at: %v bt: %v \n", at, bt) + } + if at.TypeID() != bt.TypeID() { + return errors.New("incompatible types %v and %v %s", + at.TypeID(), bt.TypeID(), msg) + } + return nil +} + +func assertAssignableTo(xt, dt Type, autoNative bool) { + err := checkAssignableTo(xt, dt, autoNative) + if err != nil { + panic(err.Error()) + } +} + +// Assert that xt can be assigned as dt (dest type). +// If autoNative is true, a broad range of xt can match against +// a target native dt type, if and only if dt is a native type. +func checkAssignableTo(xt, dt Type, autoNative bool) error { + if debug { + debug.Printf("checkAssignableTo, xt: %v dt: %v \n", xt, dt) + } + // case0 + if xt == nil { // see test/files/types/eql_0f18 + if !maybeNil(dt) { + panic(fmt.Sprintf("invalid operation, nil can not be compared to %v", dt)) + } + return nil + } else if dt == nil { // _ = xxx, assign8.gno, 0f31. else cases? + return nil + } + // case3 + if dt.Kind() == InterfaceKind { // note native interface + if idt, ok := baseOf(dt).(*InterfaceType); ok { + if idt.IsEmptyInterface() { // XXX, can this be merged with IsImplementedBy? + // if dt is an empty Gno interface, any x ok. + return nil // ok + } else if idt.IsImplementedBy(xt) { + // if dt implements idt, ok. + return nil // ok + } else { + return errors.New( + "%s does not implement %s", + xt.String(), + dt.String()) + } + } else if ndt, ok := baseOf(dt).(*NativeType); ok { + nidt := ndt.Type + if nidt.NumMethod() == 0 { + // if dt is an empty Go native interface, ditto. + return nil // ok + } else if nxt, ok := baseOf(xt).(*NativeType); ok { + // if xt has native base, do the naive native. + if nxt.Type.AssignableTo(nidt) { + return nil // ok + } else { + return errors.New( + "cannot use %s as %s", + nxt.String(), + nidt.String()) + } + } else if pxt, ok := baseOf(xt).(*PointerType); ok { + nxt, ok := pxt.Elt.(*NativeType) + if !ok { + return errors.New( + "pointer to non-native type cannot satisfy non-empty native interface; %s doesn't implement %s", + pxt.String(), + nidt.String()) + } + // if xt has native base, do the naive native. + if reflect.PtrTo(nxt.Type).AssignableTo(nidt) { + return nil // ok + } else { + return errors.New( + "cannot use %s as %s", + pxt.String(), + nidt.String()) + } + } else if xdt, ok := xt.(*DeclaredType); ok { + if gno2GoTypeMatches(baseOf(xdt), ndt.Type) { + return nil + } // not check against native interface + } else { + return errors.New( + "unexpected type pair: cannot use %s as %s", + xt.String(), + dt.String()) + } + } else { + return errors.New("should not happen") + } + } + + // case2 + // Special case if xt or dt is *PointerType to *NativeType, + // convert to *NativeType of pointer kind. + if pxt, ok := xt.(*PointerType); ok { + // *gonative{x} is gonative{*x} + //nolint:misspell + if enxt, ok := pxt.Elt.(*NativeType); ok { + xt = &NativeType{ + Type: reflect.PtrTo(enxt.Type), + } + } + } + if pdt, ok := dt.(*PointerType); ok { + // *gonative{x} is gonative{*x} + if endt, ok := pdt.Elt.(*NativeType); ok { + dt = &NativeType{ + Type: reflect.PtrTo(endt.Type), + } + } + } + + // Special case of xt or dt is *DeclaredType, + // allow implicit conversion unless both are declared. + // TODO simplify with .IsNamedType(). + if dxt, ok := xt.(*DeclaredType); ok { + if ddt, ok := dt.(*DeclaredType); ok { + // types must match exactly. + if !dxt.sealed && !ddt.sealed && + dxt.PkgPath == ddt.PkgPath && + dxt.Name == ddt.Name { // not yet sealed + return nil // ok + } else if dxt.TypeID() == ddt.TypeID() { + return nil // ok + } else { + return errors.New( + "cannot use %s as %s without explicit conversion", + dxt.String(), + ddt.String()) + } + } else { + // special case if implicitly named primitive type. + // TODO simplify with .IsNamedType(). + if _, ok := dt.(PrimitiveType); ok { + return errors.New( + "cannot use %s as %s without explicit conversion", + dxt.String(), + dt.String()) + } else { + // carry on with baseOf(dxt) + xt = dxt.Base // set as base to do the rest check + } + } + } else if ddt, ok := dt.(*DeclaredType); ok { + // special case if implicitly named primitive type. + // TODO simplify with .IsNamedType(). + if _, ok := xt.(PrimitiveType); ok { // e.g. 1 == Int(1) + if debug { + debug.Printf("xt is primitiveType: %v, ddt: %v \n", xt, ddt) + } + // this is special when dt is the declared type of x + if !isUntyped(xt) { + return errors.New( + "cannot use %s as %s without explicit conversion", + xt.String(), + ddt.String()) + } else { // xt untyped, carry on with check below + dt = ddt.Base + } + } else { + dt = ddt.Base + } + } + + // General cases. + switch cdt := dt.(type) { + case PrimitiveType: // case 1 + // if xt is untyped, ensure dt is compatible. + switch xt { + case UntypedBoolType: + if dt.Kind() == BoolKind { + return nil // ok + } else { + return errors.New( + "cannot use untyped bool as %s", + dt.Kind()) + } + case UntypedStringType: + if dt.Kind() == StringKind { + return nil // ok + } else { + return errors.New( + "cannot use untyped string as %s", + dt.Kind()) + } + // XXX, this is a loose check, we don't have the context + // to check if it is an exact integer, e.g. 1.2 or 1.0(1.0 can be converted to int). + // this ensure expr like (a % 1.0) pass check, while + // expr like (a % 1.2) panic at ConvertUntypedTo, which is a delayed assertion after const evaluated. + // assignable does not guarantee convertible. + case UntypedBigdecType: + switch dt.Kind() { + case IntKind, Int8Kind, Int16Kind, Int32Kind, + Int64Kind, UintKind, Uint8Kind, Uint16Kind, + Uint32Kind, Uint64Kind, BigdecKind, Float32Kind, Float64Kind: + return nil // ok + default: + panic(fmt.Sprintf( + "cannot use untyped Bigdec as %s", + dt.Kind())) + } + case UntypedBigintType: + switch dt.Kind() { + case IntKind, Int8Kind, Int16Kind, Int32Kind, + Int64Kind, UintKind, Uint8Kind, Uint16Kind, + Uint32Kind, Uint64Kind, BigintKind, BigdecKind, Float32Kind, Float64Kind: // see 0d0 + return nil // ok + default: + return errors.New( + "cannot use untyped Bigint as %s", + dt.Kind()) + } + case UntypedRuneType: + switch dt.Kind() { + case IntKind, Int8Kind, Int16Kind, Int32Kind, + Int64Kind, UintKind, Uint8Kind, Uint16Kind, + Uint32Kind, Uint64Kind, BigintKind, BigdecKind, Float32Kind, Float64Kind: + return nil // ok + default: + return errors.New( + "cannot use untyped rune as %s", + dt.Kind()) + } + + default: + if isUntyped(xt) { + panic("unexpected untyped type") + } + if xt.TypeID() == cdt.TypeID() { + return nil // ok + } + } + case *PointerType: // case 4 from here on + if pt, ok := xt.(*PointerType); ok { + return checkAssignableTo(pt.Elt, cdt.Elt, false) + } + case *ArrayType: + if at, ok := xt.(*ArrayType); ok { + if at.Len != cdt.Len { + return errors.New( + "cannot use %s as %s", + at.String(), + cdt.String()) + } + err := checkSame(at.Elt, cdt.Elt, "") + if err != nil { + return errors.New( + "cannot use %s as %s", + at.String(), + cdt.String()) + } + return nil + } + case *SliceType: + if st, ok := xt.(*SliceType); ok { + if cdt.Vrd { + return checkAssignableTo(st.Elt, cdt.Elt, false) + } else { + err := checkSame(st.Elt, cdt.Elt, "") + if err != nil { + return errors.New( + "cannot use %s as %s", + st.String(), + cdt.String()) + } + return nil + } + } + case *MapType: + if mt, ok := xt.(*MapType); ok { + err := checkSame(mt.Key, cdt.Key, "") + if err != nil { + return errors.New( + "cannot use %s as %s", + mt.String(), + cdt.String()).Stacktrace() + } + return nil + } + case *InterfaceType: + return errors.New("should not happen") + case *DeclaredType: + panic("should not happen") + case *FuncType, *StructType, *PackageType, *ChanType, *TypeType: + if xt.TypeID() == cdt.TypeID() { + return nil // ok + } + case *NativeType: + if !autoNative { + if debug { + debug.Printf("native type, xt.TypeID: %v, cdt.TypeID: %v \n", xt.TypeID(), cdt.TypeID()) + } + if xt.TypeID() == cdt.TypeID() { + return nil // ok + } + } else { + // autoNative, so check whether matches. + // xt: any type but a *DeclaredType; could be native. + // cdt: actual concrete native target type. + // ie, if cdt can match against xt. + if gno2GoTypeMatches(xt, cdt.Type) { + return nil // ok + } + } + default: + return errors.New( + "unexpected type %s", + dt.String()) + } + return errors.New( + "cannot use %s as %s", + xt.String(), + dt.String()).Stacktrace() +} + +// =========================================================== +func (x *BinaryExpr) checkShiftLhs(dt Type) { + if checker, ok := binaryChecker[x.Op]; ok { + if !checker(dt) { + panic(fmt.Sprintf("operator %s not defined on: %v", x.Op.TokenString(), kindString(dt))) + } + } else { + panic(fmt.Sprintf("checker for %s does not exist", x.Op)) + } +} + +// AssertCompatible works as a pre-check prior to checkOrConvertType. +// It checks against expressions to ensure the compatibility between operands and operators. +// e.g. "a" << 1, the left hand operand is not compatible with <<, it will fail the check. +// Overall,it efficiently filters out incompatible expressions, stopping before the next +// checkOrConvertType() operation to optimize performance. +func (x *BinaryExpr) AssertCompatible(lt, rt Type) { + // native type will be converted to gno in latter logic, + // this check logic will be conduct again from trans_leave *BinaryExpr. + lnt, lin := lt.(*NativeType) + rnt, rin := rt.(*NativeType) + if lin && rin { + if lt.TypeID() != rt.TypeID() { + panic(fmt.Sprintf( + "incompatible operands in binary expression: %s %s %s", + lt.TypeID(), x.Op, rt.TypeID())) + } + } + if lin { + if _, ok := go2GnoBaseType(lnt.Type).(PrimitiveType); ok { + return + } + } + if rin { + if _, ok := go2GnoBaseType(rnt.Type).(PrimitiveType); ok { + return + } + } + + xt, dt := lt, rt + if shouldSwapOnSpecificity(lt, rt) { + xt, dt = dt, xt + } + + if isComparison(x.Op) { + switch x.Op { + case EQL, NEQ: + assertComparable(xt, dt) + if !isUntyped(xt) && !isUntyped(dt) { + assertAssignableTo(xt, dt, false) + } + case LSS, LEQ, GTR, GEQ: + if checker, ok := binaryChecker[x.Op]; ok { + x.checkCompatibility(xt, dt, checker, x.Op.TokenString()) + } else { + panic(fmt.Sprintf("checker for %s does not exist", x.Op)) + } + default: + panic("invalid comparison operator") + } + } else { + if checker, ok := binaryChecker[x.Op]; ok { + x.checkCompatibility(xt, dt, checker, x.Op.TokenString()) + } else { + panic(fmt.Sprintf("checker for %s does not exist", x.Op)) + } + + switch x.Op { + case QUO, REM: + // special case of zero divisor + if isQuoOrRem(x.Op) { + if rcx, ok := x.Right.(*ConstExpr); ok { + if rcx.TypedValue.isZero() { + panic("invalid operation: division by zero") + } + } + } + default: + // do nothing + } + } +} + +// Check compatibility of the destination type (dt) with the operator. +// If both source type (xt) and destination type (dt) are typed: +// Verify that xt is assignable to dt. +// If xt is untyped: +// The function checkOrConvertType will be invoked after this check. +// NOTE: dt is established based on a specificity check between xt and dt, +// confirming dt as the appropriate destination type for this context. +func (x *BinaryExpr) checkCompatibility(xt, dt Type, checker func(t Type) bool, OpStr string) { + if !checker(dt) { + panic(fmt.Sprintf("operator %s not defined on: %v", OpStr, kindString(dt))) + } + + // if both typed + if !isUntyped(xt) && !isUntyped(dt) { + err := checkAssignableTo(xt, dt, false) + if err != nil { + panic(fmt.Sprintf("invalid operation: mismatched types %v and %v", xt, dt)) + } + } +} + +func (x *UnaryExpr) AssertCompatible(t Type) { + if nt, ok := t.(*NativeType); ok { + if _, ok := go2GnoBaseType(nt.Type).(PrimitiveType); ok { + return + } + } + // check compatible + if checker, ok := unaryChecker[x.Op]; ok { + if !checker(t) { + panic(fmt.Sprintf("operator %s not defined on: %v", x.Op.TokenString(), kindString(t))) + } + } else { + panic(fmt.Sprintf("checker for %s does not exist", x.Op)) + } +} + +func (x *IncDecStmt) AssertCompatible(t Type) { + if nt, ok := t.(*NativeType); ok { + if _, ok := go2GnoBaseType(nt.Type).(PrimitiveType); ok { + return + } + } + // check compatible + if checker, ok := IncDecStmtChecker[x.Op]; ok { + if !checker(t) { + panic(fmt.Sprintf("operator %s not defined on: %v", x.Op.TokenString(), kindString(t))) + } + } else { + panic(fmt.Sprintf("checker for %s does not exist", x.Op)) + } +} + +func assertIndexTypeIsInt(kt Type) { + if kt.Kind() != IntKind { + panic(fmt.Sprintf("index type should be int, but got %v", kt)) + } +} + +func (x *RangeStmt) AssertCompatible(store Store, last BlockNode) { + if x.Op != ASSIGN { + return + } + if isBlankIdentifier(x.Key) && isBlankIdentifier(x.Value) { + // both "_" + return + } + assertValidAssignLhs(store, last, x.Key) + // if is valid left value + + kt := evalStaticTypeOf(store, last, x.Key) + var vt Type + if x.Value != nil { + vt = evalStaticTypeOf(store, last, x.Value) + } + + xt := evalStaticTypeOf(store, last, x.X) + switch cxt := xt.(type) { + case *MapType: + assertAssignableTo(cxt.Key, kt, false) + if vt != nil { + assertAssignableTo(cxt.Value, vt, false) + } + case *SliceType: + assertIndexTypeIsInt(kt) + if vt != nil { + assertAssignableTo(cxt.Elt, vt, false) + } + case *ArrayType: + assertIndexTypeIsInt(kt) + if vt != nil { + assertAssignableTo(cxt.Elt, vt, false) + } + case PrimitiveType: + if cxt.Kind() == StringKind { + if kt != nil && kt.Kind() != IntKind { + panic(fmt.Sprintf("index type should be int, but got %v", kt)) + } + if vt != nil { + if vt.Kind() != Int32Kind { // rune + panic(fmt.Sprintf("value type should be int32, but got %v", kt)) + } + } + } + } +} + +func (x *AssignStmt) AssertCompatible(store Store, last BlockNode) { + if x.Op == ASSIGN || x.Op == DEFINE { + if len(x.Lhs) > len(x.Rhs) { + if len(x.Rhs) != 1 { + panic(fmt.Sprintf("assignment mismatch: %d variables but %d values", len(x.Lhs), len(x.Rhs))) + } + switch cx := x.Rhs[0].(type) { + case *CallExpr: + // Call case: a, b = x(...) + ift := evalStaticTypeOf(store, last, cx.Func) + cft := getGnoFuncTypeOf(store, ift) + if len(x.Lhs) != len(cft.Results) { + panic(fmt.Sprintf( + "assignment mismatch: "+ + "%d variables but %s returns %d values", + len(x.Lhs), cx.Func.String(), len(cft.Results))) + } + if x.Op == ASSIGN { + // check assignable + for i, lx := range x.Lhs { + if !isBlankIdentifier(lx) { + assertValidAssignLhs(store, last, lx) + lxt := evalStaticTypeOf(store, last, lx) + assertAssignableTo(cft.Results[i].Type, lxt, false) + } + } + } + case *TypeAssertExpr: + // Type-assert case: a, ok := x.(type) + if len(x.Lhs) != 2 { + panic("should not happen") + } + if x.Op == ASSIGN { + // check assignable to first value + if !isBlankIdentifier(x.Lhs[0]) { // see composite3.gno + assertValidAssignLhs(store, last, x.Lhs[0]) + dt := evalStaticTypeOf(store, last, x.Lhs[0]) + ift := evalStaticTypeOf(store, last, cx) + assertAssignableTo(ift, dt, false) + } + if !isBlankIdentifier(x.Lhs[1]) { // see composite3.gno + assertValidAssignLhs(store, last, x.Lhs[1]) + dt := evalStaticTypeOf(store, last, x.Lhs[1]) + if dt.Kind() != BoolKind { // typed, not bool + panic(fmt.Sprintf("want bool type got %v", dt)) + } + } + } + cx.HasOK = true + case *IndexExpr: // must be with map type when len(Lhs) > len(Rhs) + if len(x.Lhs) != 2 { + panic("should not happen") + } + if x.Op == ASSIGN { + if !isBlankIdentifier(x.Lhs[0]) { + assertValidAssignLhs(store, last, x.Lhs[0]) + lt := evalStaticTypeOf(store, last, x.Lhs[0]) + if _, ok := cx.X.(*NameExpr); ok { + rt := evalStaticTypeOf(store, last, cx.X) + if mt, ok := rt.(*MapType); ok { + assertAssignableTo(mt.Value, lt, false) + } + } else if _, ok := cx.X.(*CompositeLitExpr); ok { + cpt := evalStaticTypeOf(store, last, cx.X) + if mt, ok := cpt.(*MapType); ok { + assertAssignableTo(mt.Value, lt, false) + } else { + panic("should not happen") + } + } + } + if !isBlankIdentifier(x.Lhs[1]) { + assertValidAssignLhs(store, last, x.Lhs[1]) + dt := evalStaticTypeOf(store, last, x.Lhs[1]) + if dt != nil && dt.Kind() != BoolKind { // typed, not bool + panic(fmt.Sprintf("want bool type got %v", dt)) + } + } + } + cx.HasOK = true + default: + panic(fmt.Sprintf("RHS should not be %v when len(Lhs) > len(Rhs)", cx)) + } + } else { // len(Lhs) == len(Rhs) + if x.Op == ASSIGN { + // assert valid left value + for _, lx := range x.Lhs { + assertValidAssignLhs(store, last, lx) + } + } + } + } else { // Ops other than assign and define + // If this is an assignment operation, ensure there's only 1 + // expr on lhs/rhs. + if len(x.Lhs) != 1 || len(x.Rhs) != 1 { + panic("assignment operator " + x.Op.TokenString() + + " requires only one expression on lhs and rhs") + } + for i, lx := range x.Lhs { + lt := evalStaticTypeOf(store, last, lx) + rt := evalStaticTypeOf(store, last, x.Rhs[i]) + + if checker, ok := AssignStmtChecker[x.Op]; ok { + if !checker(lt) { + panic(fmt.Sprintf("operator %s not defined on: %v", x.Op.TokenString(), kindString(lt))) + } + switch x.Op { + case ADD_ASSIGN, SUB_ASSIGN, MUL_ASSIGN, QUO_ASSIGN, REM_ASSIGN, BAND_ASSIGN, BOR_ASSIGN, BAND_NOT_ASSIGN, XOR_ASSIGN: + // check when both typed + if !isUntyped(lt) && !isUntyped(rt) { // in this stage, lt or rt maybe untyped, not converted yet + if lt != nil && rt != nil { + if lt.TypeID() != rt.TypeID() { + panic(fmt.Sprintf("invalid operation: mismatched types %v and %v", lt, rt)) + } + } + } + default: + // do nothing + } + } else { + panic(fmt.Sprintf("checker for %s does not exist", x.Op)) + } + } + } +} + +// misc +func assertValidAssignLhs(store Store, last BlockNode, lx Expr) { + shouldPanic := true + switch clx := lx.(type) { + case *NameExpr, *StarExpr, *SelectorExpr: + shouldPanic = false + case *IndexExpr: + xt := evalStaticTypeOf(store, last, clx.X) + shouldPanic = xt != nil && xt.Kind() == StringKind + default: + } + if shouldPanic { + panic(fmt.Sprintf("cannot assign to %v", lx)) + } +} + +func kindString(xt Type) string { + if xt != nil { + return xt.Kind().String() + } + return "nil" +} + +func isQuoOrRem(op Word) bool { + switch op { + case QUO, QUO_ASSIGN, REM, REM_ASSIGN: + return true + default: + return false + } +} + +func isComparison(op Word) bool { + switch op { + case EQL, NEQ, LSS, LEQ, GTR, GEQ: + return true + default: + return false + } +} + +// shouldSwapOnSpecificity determines the potential direction for +// checkOrConvertType. it checks whether a swap is needed between two types +// based on their specificity. If t2 has a lower specificity than t1, it returns +// false, indicating no swap is needed. If t1 has a lower specificity than t2, +// it returns true, indicating a swap is needed. +func shouldSwapOnSpecificity(t1, t2 Type) bool { + // check nil + if t1 == nil { // see test file 0f46 + return false // also with both nil + } else if t2 == nil { + return true + } + + // check interface + if it1, ok := baseOf(t1).(*InterfaceType); ok { + if it1.IsEmptyInterface() { + return true // left empty interface + } else { + if _, ok := baseOf(t2).(*InterfaceType); ok { + return false + } else { + return true // right not interface + } + } + } else if _, ok := t2.(*InterfaceType); ok { + return false // left not interface, right is interface + } + + // primitive types + t1s, t2s := 0, 0 + if t1p, ok := t1.(PrimitiveType); ok { + t1s = t1p.Specificity() + } + if t2p, ok := t2.(PrimitiveType); ok { + t2s = t2p.Specificity() + } + if t1s < t2s { + // NOTE: higher specificity has lower value, so backwards. + return true + } else { + return false + } +} + +func isBlankIdentifier(x Expr) bool { + if nx, ok := x.(*NameExpr); ok { + return nx.Name == "_" + } + return false +} diff --git a/gnovm/pkg/gnolang/types.go b/gnovm/pkg/gnolang/types.go index fcfcd7d9d37..ab8e9effdc8 100644 --- a/gnovm/pkg/gnolang/types.go +++ b/gnovm/pkg/gnolang/types.go @@ -2203,11 +2203,11 @@ func KindOf(t Type) Kind { // ---------------------------------------- // main type-assertion functions. -// TODO: document what class of problems its for. +// Only for runtime debugging. // One of them can be nil, and this lets uninitialized primitives // and others serve as empty values. See doOpAdd() -// usage: if debug { assertSameTypes() } -func assertSameTypes(lt, rt Type) { +// usage: if debug { debugAssertSameTypes() } +func debugAssertSameTypes(lt, rt Type) { if lt == nil && rt == nil { // both are nil. } else if lt == nil || rt == nil { @@ -2232,8 +2232,10 @@ func assertSameTypes(lt, rt Type) { } } -// Like assertSameTypes(), but more relaxed, for == and !=. -func assertEqualityTypes(lt, rt Type) { +// Only for runtime debugging. +// Like debugAssertSameTypes(), but more relaxed, for == and !=. +// usage: if debug { debugAssertEqualityTypes() } +func debugAssertEqualityTypes(lt, rt Type) { if lt == nil && rt == nil { // both are nil. } else if lt == nil || rt == nil { @@ -2362,6 +2364,7 @@ func fillEmbeddedName(ft *FieldType) { ft.Embedded = true } +// TODO: empty interface? refer to assertAssignableTo func IsImplementedBy(it Type, ot Type) bool { switch cbt := baseOf(it).(type) { case *InterfaceType: @@ -2496,7 +2499,7 @@ func specifyType(store Store, lookup map[Name]Type, tmpl Type, spec Type, specTy generic := ct.Generic[:len(ct.Generic)-len(".Elem()")] match, ok := lookup[generic] if ok { - checkType(spec, match.Elem(), false) + assertAssignableTo(spec, match.Elem(), false) return // ok } else { // Panic here, because we don't know whether T @@ -2510,7 +2513,7 @@ func specifyType(store Store, lookup map[Name]Type, tmpl Type, spec Type, specTy } else { match, ok := lookup[ct.Generic] if ok { - checkType(spec, match, false) + assertAssignableTo(spec, match, false) return // ok } else { if isUntyped(spec) { diff --git a/gnovm/pkg/gnolang/values.go b/gnovm/pkg/gnolang/values.go index b0996b98b6f..344977a849c 100644 --- a/gnovm/pkg/gnolang/values.go +++ b/gnovm/pkg/gnolang/values.go @@ -1494,6 +1494,88 @@ func (tv *TypedValue) GetBigDec() *apd.Decimal { return tv.V.(BigdecValue).V } +// returns true if tv is zero +func (tv *TypedValue) isZero() bool { + if tv.T == nil { + panic("type should not be nil") + } + switch tv.T.Kind() { + case IntKind: + v := tv.GetInt() + if v == 0 { + return true + } + case Int8Kind: + v := tv.GetInt8() + if v == 0 { + return true + } + case Int16Kind: + v := tv.GetInt16() + if v == 0 { + return true + } + case Int32Kind: + v := tv.GetInt32() + if v == 0 { + return true + } + case Int64Kind: + v := tv.GetInt64() + if v == 0 { + return true + } + case UintKind: + v := tv.GetUint() + if v == 0 { + return true + } + case Uint8Kind: + v := tv.GetUint8() + if v == 0 { + return true + } + case Uint16Kind: + v := tv.GetUint16() + if v == 0 { + return true + } + case Uint32Kind: + v := tv.GetUint32() + if v == 0 { + return true + } + case Uint64Kind: + v := tv.GetUint64() + if v == 0 { + return true + } + case Float32Kind: + v := tv.GetFloat32() + if v == 0 { + return true + } + case Float64Kind: + v := tv.GetFloat64() + if v == 0 { + return true + } + case BigintKind: + v := tv.GetBigInt() + if v.Sign() == 0 { + return true + } + case BigdecKind: + v := tv.GetBigDec() + if v.Sign() == 0 { + return true + } + default: + panic("not numeric") + } + return false +} + func (tv *TypedValue) ComputeMapKey(store Store, omitType bool) MapKey { // Special case when nil: has no separator. if tv.T == nil { diff --git a/gnovm/pkg/gnolang/values_conversions.go b/gnovm/pkg/gnolang/values_conversions.go index b4888878c7a..c5ddc232fcb 100644 --- a/gnovm/pkg/gnolang/values_conversions.go +++ b/gnovm/pkg/gnolang/values_conversions.go @@ -881,6 +881,11 @@ GNO_CASE: // Panics if conversion is illegal. // TODO: method on TypedValue? func ConvertUntypedTo(tv *TypedValue, t Type) { + if debug { + defer func() { + debug.Printf("ConvertUntypedTo done, tv: %v \n", tv) + }() + } if debug { if !isUntyped(tv.T) { panic(fmt.Sprintf( diff --git a/gnovm/tests/file.go b/gnovm/tests/file.go index 852bb74d198..8ab60145bd5 100644 --- a/gnovm/tests/file.go +++ b/gnovm/tests/file.go @@ -263,8 +263,18 @@ func RunFileTest(rootDir string, path string, opts ...RunFileTestOption) error { errstr = strings.TrimSpace(fmt.Sprintf("%v", pnc)) } + parts := strings.SplitN(errstr, ":\n--- preprocess stack ---", 2) + if len(parts) == 2 { + fmt.Println(parts[0]) + errstr = parts[0] + } if errstr != errWanted { - panic(fmt.Sprintf("fail on %s: got %q, want: %q", path, errstr, errWanted)) + if f.syncWanted { + // write error to file + replaceWantedInPlace(path, "Error", errstr) + } else { + panic(fmt.Sprintf("fail on %s: got %q, want: %q", path, errstr, errWanted)) + } } // NOTE: ignores any gno.GetDebugErrors(). @@ -279,12 +289,16 @@ func RunFileTest(rootDir string, path string, opts ...RunFileTestOption) error { } else { errstr = strings.TrimSpace(fmt.Sprintf("%v", pnc)) } + parts := strings.SplitN(errstr, ":\n--- preprocess stack ---", 2) + if len(parts) == 2 { + fmt.Println(parts[0]) + errstr = parts[0] + } // check tip line, write to file - ctl := fmt.Sprintf( - errstr + - "\n*** CHECK THE ERR MESSAGES ABOVE, MAKE SURE IT'S WHAT YOU EXPECTED, " + - "DELETE THIS LINE AND RUN TEST AGAIN ***", - ) + ctl := errstr + + "\n*** CHECK THE ERR MESSAGES ABOVE, MAKE SURE IT'S WHAT YOU EXPECTED, " + + "DELETE THIS LINE AND RUN TEST AGAIN ***" + // write error to file replaceWantedInPlace(path, "Error", ctl) panic(fmt.Sprintf("fail on %s: err recorded, check the message and run test again", path)) } diff --git a/gnovm/tests/files/access0.gno b/gnovm/tests/files/access0_stdlibs.gno similarity index 100% rename from gnovm/tests/files/access0.gno rename to gnovm/tests/files/access0_stdlibs.gno diff --git a/gnovm/tests/files/access1.gno b/gnovm/tests/files/access1_stdlibs.gno similarity index 53% rename from gnovm/tests/files/access1.gno rename to gnovm/tests/files/access1_stdlibs.gno index d9bb9f46203..7a2f2cf3817 100644 --- a/gnovm/tests/files/access1.gno +++ b/gnovm/tests/files/access1_stdlibs.gno @@ -9,4 +9,4 @@ func main() { } // Error: -// main/files/access1.gno:8: cannot access gno.land/p/demo/testutils.testVar2 from main +// main/files/access1_stdlibs.gno:8: cannot access gno.land/p/demo/testutils.testVar2 from main diff --git a/gnovm/tests/files/access2.gno b/gnovm/tests/files/access2_stdlibs.gno similarity index 100% rename from gnovm/tests/files/access2.gno rename to gnovm/tests/files/access2_stdlibs.gno diff --git a/gnovm/tests/files/access3.gno b/gnovm/tests/files/access3_stdlibs.gno similarity index 100% rename from gnovm/tests/files/access3.gno rename to gnovm/tests/files/access3_stdlibs.gno diff --git a/gnovm/tests/files/access4.gno b/gnovm/tests/files/access4_stdlibs.gno similarity index 57% rename from gnovm/tests/files/access4.gno rename to gnovm/tests/files/access4_stdlibs.gno index bb2dcc340f0..6f092efb61c 100644 --- a/gnovm/tests/files/access4.gno +++ b/gnovm/tests/files/access4_stdlibs.gno @@ -10,4 +10,4 @@ func main() { } // Error: -// main/files/access4.gno:9: cannot access gno.land/p/demo/testutils.TestAccessStruct.privateField from main +// main/files/access4_stdlibs.gno:9: cannot access gno.land/p/demo/testutils.TestAccessStruct.privateField from main diff --git a/gnovm/tests/files/access5.gno b/gnovm/tests/files/access5_stdlibs.gno similarity index 100% rename from gnovm/tests/files/access5.gno rename to gnovm/tests/files/access5_stdlibs.gno diff --git a/gnovm/tests/files/access6.gno b/gnovm/tests/files/access6_stdlibs.gno similarity index 67% rename from gnovm/tests/files/access6.gno rename to gnovm/tests/files/access6_stdlibs.gno index 991b4a5457a..b9e019525a7 100644 --- a/gnovm/tests/files/access6.gno +++ b/gnovm/tests/files/access6_stdlibs.gno @@ -16,4 +16,4 @@ func main() { } // Error: -// main/files/access6.gno:15: main.mystruct does not implement gno.land/p/demo/testutils.PrivateInterface +// main/files/access6_stdlibs.gno:15: main.mystruct does not implement gno.land/p/demo/testutils.PrivateInterface diff --git a/gnovm/tests/files/access7.gno b/gnovm/tests/files/access7_stdlibs.gno similarity index 72% rename from gnovm/tests/files/access7.gno rename to gnovm/tests/files/access7_stdlibs.gno index 2b4c32ab818..ab63b3b9639 100644 --- a/gnovm/tests/files/access7.gno +++ b/gnovm/tests/files/access7_stdlibs.gno @@ -20,4 +20,4 @@ func main() { } // Error: -// main/files/access7.gno:19: main.PrivateInterface2 does not implement gno.land/p/demo/testutils.PrivateInterface +// main/files/access7_stdlibs.gno:19: main.PrivateInterface2 does not implement gno.land/p/demo/testutils.PrivateInterface diff --git a/gnovm/tests/files/assign_unnamed_type/method/declaredType6_filetest.gno b/gnovm/tests/files/assign_unnamed_type/method/declaredType6_filetest.gno index 5d994352f35..ba40fb8caa3 100644 --- a/gnovm/tests/files/assign_unnamed_type/method/declaredType6_filetest.gno +++ b/gnovm/tests/files/assign_unnamed_type/method/declaredType6_filetest.gno @@ -17,4 +17,4 @@ func main() { } // Error: -// main/files/assign_unnamed_type/method/declaredType6_filetest.gno:15: cannot use main.c as main.word without explicit conversion +// main/files/assign_unnamed_type/method/declaredType6_filetest.gno:15: cannot use []main.c as []main.word diff --git a/gnovm/tests/files/assign_unnamed_type/method/declaredType6b_filetest.gno b/gnovm/tests/files/assign_unnamed_type/method/declaredType6b_filetest.gno index 88b3203a805..9e46c884252 100644 --- a/gnovm/tests/files/assign_unnamed_type/method/declaredType6b_filetest.gno +++ b/gnovm/tests/files/assign_unnamed_type/method/declaredType6b_filetest.gno @@ -17,4 +17,4 @@ func main() { } // Error: -// main/files/assign_unnamed_type/method/declaredType6b_filetest.gno:15: cannot use uint as main.word without explicit conversion +// main/files/assign_unnamed_type/method/declaredType6b_filetest.gno:15: cannot use []uint as []main.word diff --git a/gnovm/tests/files/assign_unnamed_type/more/cross_realm_compositelit_filetest.gno b/gnovm/tests/files/assign_unnamed_type/more/cross_realm_compositelit_filetest_stdlibs.gno similarity index 100% rename from gnovm/tests/files/assign_unnamed_type/more/cross_realm_compositelit_filetest.gno rename to gnovm/tests/files/assign_unnamed_type/more/cross_realm_compositelit_filetest_stdlibs.gno diff --git a/gnovm/tests/files/assign_unnamed_type/unnamedtype0b_filetest.gno b/gnovm/tests/files/assign_unnamed_type/unnamedtype0b_filetest.gno index cc1d54cfa2a..8f1eb5399b2 100644 --- a/gnovm/tests/files/assign_unnamed_type/unnamedtype0b_filetest.gno +++ b/gnovm/tests/files/assign_unnamed_type/unnamedtype0b_filetest.gno @@ -14,4 +14,4 @@ func main() { } // Error: -// main/files/assign_unnamed_type/unnamedtype0b_filetest.gno:11: cannot use main.word as int without explicit conversion +// main/files/assign_unnamed_type/unnamedtype0b_filetest.gno:11: cannot use []main.word as []int diff --git a/gnovm/tests/files/bool6.gno b/gnovm/tests/files/bool6.gno index ad4d832036c..3ad789dda32 100644 --- a/gnovm/tests/files/bool6.gno +++ b/gnovm/tests/files/bool6.gno @@ -9,4 +9,4 @@ func X() string { } // Error: -// main/files/bool6.gno:8: operands of boolean operators must evaluate to boolean typed values +// main/files/bool6.gno:8: operator || not defined on: StringKind diff --git a/gnovm/tests/files/comp4.gno b/gnovm/tests/files/comp4.gno new file mode 100644 index 00000000000..501cffeb871 --- /dev/null +++ b/gnovm/tests/files/comp4.gno @@ -0,0 +1,32 @@ +package main + +type S struct { +} + +func main() { + x := (*S)(nil) + println("x == x", x == x) + println("x == nil", x == nil) + println("nil == x", nil == x) + + var y interface{} = (*S)(nil) + println("y == y", y == y) + println("y == nil", y == nil) + println("nil == y", nil == y) + + y = nil + println("y == y", y == y) + println("y == nil", y == nil) + println("nil == y", nil == y) +} + +// Output: +// x == x true +// x == nil true +// nil == x true +// y == y true +// y == nil false +// nil == y false +// y == y true +// y == nil true +// nil == y true diff --git a/gnovm/tests/files/comp5.gno b/gnovm/tests/files/comp5.gno new file mode 100644 index 00000000000..827800f2a67 --- /dev/null +++ b/gnovm/tests/files/comp5.gno @@ -0,0 +1,23 @@ +package main + +type S struct { +} + +func main() { + x := (*S)(nil) + var y interface{} = (*S)(nil) + var znil interface{} = nil + + println("y == znil", y == znil) + println("znil == y", znil == y) + + y = nil + println("y == znil", y == znil) + println("znil == y", znil == y) +} + +// Output: +// y == znil false +// znil == y false +// y == znil true +// znil == y true diff --git a/gnovm/tests/files/fun24.gno b/gnovm/tests/files/fun24.gno index 42468ff087e..100d3c26ded 100644 --- a/gnovm/tests/files/fun24.gno +++ b/gnovm/tests/files/fun24.gno @@ -7,4 +7,4 @@ func main() { } // Error: -// main/files/fun24.gno:3: cannot convert StringKind to IntKind +// main/files/fun24.gno:3: cannot use untyped string as IntKind diff --git a/gnovm/tests/files/issue_558b.gno b/gnovm/tests/files/issue_558b_stdlibs.gno similarity index 100% rename from gnovm/tests/files/issue_558b.gno rename to gnovm/tests/files/issue_558b_stdlibs.gno diff --git a/gnovm/tests/files/math_native.gno b/gnovm/tests/files/math_native.gno new file mode 100644 index 00000000000..54bddcde1f3 --- /dev/null +++ b/gnovm/tests/files/math_native.gno @@ -0,0 +1,14 @@ +package main + +import ( + "fmt" + "math" +) + +func main() { + var a float64 = 2.0 + fmt.Println(math.Pi * a) +} + +// Output: +// 6.283185307179586 diff --git a/gnovm/tests/files/op7.gno b/gnovm/tests/files/op7.gno index 7167171035b..0c3f540600b 100644 --- a/gnovm/tests/files/op7.gno +++ b/gnovm/tests/files/op7.gno @@ -14,4 +14,4 @@ func main() { } // Error: -// main/files/op7.gno:11: incompatible types in binary expression: .uverse.error GTR main.T +// main/files/op7.gno:11: operator > not defined on: InterfaceKind diff --git a/gnovm/tests/files/std0.gno b/gnovm/tests/files/std0_stdlibs.gno similarity index 100% rename from gnovm/tests/files/std0.gno rename to gnovm/tests/files/std0_stdlibs.gno diff --git a/gnovm/tests/files/std10.gno b/gnovm/tests/files/std10_stdlibs.gno similarity index 100% rename from gnovm/tests/files/std10.gno rename to gnovm/tests/files/std10_stdlibs.gno diff --git a/gnovm/tests/files/std11.gno b/gnovm/tests/files/std11_stdlibs.gno similarity index 100% rename from gnovm/tests/files/std11.gno rename to gnovm/tests/files/std11_stdlibs.gno diff --git a/gnovm/tests/files/std2.gno b/gnovm/tests/files/std2_stdlibs.gno similarity index 100% rename from gnovm/tests/files/std2.gno rename to gnovm/tests/files/std2_stdlibs.gno diff --git a/gnovm/tests/files/std3.gno b/gnovm/tests/files/std3_stdlibs.gno similarity index 100% rename from gnovm/tests/files/std3.gno rename to gnovm/tests/files/std3_stdlibs.gno diff --git a/gnovm/tests/files/std4.gno b/gnovm/tests/files/std4_stdlibs.gno similarity index 100% rename from gnovm/tests/files/std4.gno rename to gnovm/tests/files/std4_stdlibs.gno diff --git a/gnovm/tests/files/std5.gno b/gnovm/tests/files/std5_stdlibs.gno similarity index 100% rename from gnovm/tests/files/std5.gno rename to gnovm/tests/files/std5_stdlibs.gno diff --git a/gnovm/tests/files/std6.gno b/gnovm/tests/files/std6_stdlibs.gno similarity index 100% rename from gnovm/tests/files/std6.gno rename to gnovm/tests/files/std6_stdlibs.gno diff --git a/gnovm/tests/files/std7.gno b/gnovm/tests/files/std7_stdlibs.gno similarity index 100% rename from gnovm/tests/files/std7.gno rename to gnovm/tests/files/std7_stdlibs.gno diff --git a/gnovm/tests/files/std8.gno b/gnovm/tests/files/std8_stdlibs.gno similarity index 100% rename from gnovm/tests/files/std8.gno rename to gnovm/tests/files/std8_stdlibs.gno diff --git a/gnovm/tests/files/std9.gno b/gnovm/tests/files/std9_stdlibs.gno similarity index 100% rename from gnovm/tests/files/std9.gno rename to gnovm/tests/files/std9_stdlibs.gno diff --git a/gnovm/tests/files/time16_native.gno b/gnovm/tests/files/time16_native.gno index 1789fcbef4f..03eca47172f 100644 --- a/gnovm/tests/files/time16_native.gno +++ b/gnovm/tests/files/time16_native.gno @@ -11,4 +11,4 @@ func main() { } // Error: -// main/files/time16_native.gno:10: incompatible types in binary expression: go:time.Duration MUL int64 +// main/files/time16_native.gno:10: incompatible operands in binary expression: go:time.Duration MUL int64 diff --git a/gnovm/tests/files/type31.gno b/gnovm/tests/files/type31.gno index a613c67525c..68c92e9a504 100644 --- a/gnovm/tests/files/type31.gno +++ b/gnovm/tests/files/type31.gno @@ -9,4 +9,4 @@ func main() { } // Error: -// main/files/type31.gno:8: incompatible types in binary expression: string ADD main.String +// main/files/type31.gno:8: invalid operation: mismatched types string and main.String diff --git a/gnovm/tests/files/type32.gno b/gnovm/tests/files/type32.gno index bc943d90186..9565cdba245 100644 --- a/gnovm/tests/files/type32.gno +++ b/gnovm/tests/files/type32.gno @@ -12,4 +12,4 @@ func main() { } // Error: -// main/files/type32.gno:9#1: incompatible types in binary expression: string ADD main.S +// main/files/type32.gno:9#1: invalid operation: mismatched types string and main.S diff --git a/gnovm/tests/files/types/add_a0.gno b/gnovm/tests/files/types/add_a0.gno new file mode 100644 index 00000000000..9b8e08718b7 --- /dev/null +++ b/gnovm/tests/files/types/add_a0.gno @@ -0,0 +1,9 @@ +package main + +// both typed(different) const +func main() { + println(int(1) + int8(1)) +} + +// Error: +// main/files/types/add_a0.gno:5: invalid operation: mismatched types int and int8 diff --git a/gnovm/tests/files/types/add_a1.gno b/gnovm/tests/files/types/add_a1.gno new file mode 100644 index 00000000000..f5bcec883b2 --- /dev/null +++ b/gnovm/tests/files/types/add_a1.gno @@ -0,0 +1,25 @@ +package main + +import ( + "strconv" +) + +type Error1 int64 + +func (e Error1) Error() string { + return "error: " + strconv.Itoa(int(e)) +} + +type Error2 int + +func (e Error2) Error() string { + return "error: " + strconv.Itoa(int(e)) +} + +// both typed(different) const +func main() { + println(Error1(0) + Error2(0)) +} + +// Error: +// main/files/types/add_a1.gno:21: invalid operation: mismatched types main.Error1 and main.Error2 diff --git a/gnovm/tests/files/types/add_assign_a0.gno b/gnovm/tests/files/types/add_assign_a0.gno new file mode 100644 index 00000000000..181941d1ea9 --- /dev/null +++ b/gnovm/tests/files/types/add_assign_a0.gno @@ -0,0 +1,9 @@ +package main + +// both typed(different) const +func main() { + int(0) += int8(1) +} + +// Error: +// main/files/types/add_assign_a0.gno:5: invalid operation: mismatched types int and int8 diff --git a/gnovm/tests/files/types/add_assign_a1.gno b/gnovm/tests/files/types/add_assign_a1.gno new file mode 100644 index 00000000000..f169e58d5b1 --- /dev/null +++ b/gnovm/tests/files/types/add_assign_a1.gno @@ -0,0 +1,25 @@ +package main + +import ( + "strconv" +) + +type Error1 int64 + +func (e Error1) Error() string { + return "error: " + strconv.Itoa(int(e)) +} + +type Error2 int + +func (e Error2) Error() string { + return "error: " + strconv.Itoa(int(e)) +} + +// both typed(different) const +func main() { + Error1(0) += Error2(0) +} + +// Error: +// main/files/types/add_assign_a1.gno:21: invalid operation: mismatched types main.Error1 and main.Error2 diff --git a/gnovm/tests/files/types/add_assign_a_01.gno b/gnovm/tests/files/types/add_assign_a_01.gno new file mode 100644 index 00000000000..f09c7ed7344 --- /dev/null +++ b/gnovm/tests/files/types/add_assign_a_01.gno @@ -0,0 +1,12 @@ +package main + +func main() { + a := 1 + b := 1 + a, b += 1, 1 + println(a) + println(b) +} + +// Error: +// main/files/types/add_assign_a_01.gno:6: assignment operator += requires only one expression on lhs and rhs diff --git a/gnovm/tests/files/types/add_assign_b0.gno b/gnovm/tests/files/types/add_assign_b0.gno new file mode 100644 index 00000000000..28b6af83d3a --- /dev/null +++ b/gnovm/tests/files/types/add_assign_b0.gno @@ -0,0 +1,13 @@ +package main + +type Error int8 + +// one untyped const, one typed const +func main() { + r := 1 + r += Error(1) + println(r) +} + +// Error: +// main/files/types/add_assign_b0.gno:8: invalid operation: mismatched types int and main.Error diff --git a/gnovm/tests/files/types/add_assign_b1.gno b/gnovm/tests/files/types/add_assign_b1.gno new file mode 100644 index 00000000000..2e702256f29 --- /dev/null +++ b/gnovm/tests/files/types/add_assign_b1.gno @@ -0,0 +1,13 @@ +package main + +type Error int8 + +// one untyped const, one typed const +func main() { + r := Error(1) + r += 1 + println(r) +} + +// Output: +// (2 main.Error) diff --git a/gnovm/tests/files/types/add_assign_b2.gno b/gnovm/tests/files/types/add_assign_b2.gno new file mode 100644 index 00000000000..87b09754046 --- /dev/null +++ b/gnovm/tests/files/types/add_assign_b2.gno @@ -0,0 +1,10 @@ +package main + +func main() { + r := 1 + r += 'a' + println(r) +} + +// Output: +// 98 diff --git a/gnovm/tests/files/types/add_assign_d0.gno b/gnovm/tests/files/types/add_assign_d0.gno new file mode 100644 index 00000000000..f3da2497a84 --- /dev/null +++ b/gnovm/tests/files/types/add_assign_d0.gno @@ -0,0 +1,12 @@ +package main + +// both untyped const +// TODO: dec value representation, and this should happen in process stage!!! +func main() { + r := 1.0 + r += 1 + println(r) +} + +// Output: +// 2 diff --git a/gnovm/tests/files/types/add_assign_e.gno b/gnovm/tests/files/types/add_assign_e.gno new file mode 100644 index 00000000000..3a72f9711be --- /dev/null +++ b/gnovm/tests/files/types/add_assign_e.gno @@ -0,0 +1,21 @@ +package main + +import ( + "strconv" +) + +type Error1 int64 + +func (e Error1) Error() string { + return "error: " + strconv.Itoa(int(e)) +} + +func main() { + var e1 Error1 = Error1(0) + var e2 int64 = 1 + e1 += Error1(e2) + println(e1) +} + +// Output: +// error: 1 diff --git a/gnovm/tests/files/types/add_assign_e0.gno b/gnovm/tests/files/types/add_assign_e0.gno new file mode 100644 index 00000000000..d71bedab118 --- /dev/null +++ b/gnovm/tests/files/types/add_assign_e0.gno @@ -0,0 +1,28 @@ +package main + +import ( + "strconv" +) + +type Error1 int64 + +func (e Error1) Error() string { + return "error: " + strconv.Itoa(int(e)) +} + +type Error2 int + +func (e Error2) Error() string { + return "error: " + strconv.Itoa(int(e)) +} + +// both not const, typed +func main() { + var e1 Error1 = Error1(0) + var e2 Error2 = Error2(0) + e1 += e2 + println(e1) +} + +// Error: +// main/files/types/add_assign_e0.gno:23: invalid operation: mismatched types main.Error1 and main.Error2 diff --git a/gnovm/tests/files/types/add_assign_e1.gno b/gnovm/tests/files/types/add_assign_e1.gno new file mode 100644 index 00000000000..3657cf2872d --- /dev/null +++ b/gnovm/tests/files/types/add_assign_e1.gno @@ -0,0 +1,20 @@ +package main + +import ( + "strconv" +) + +type Error1 int64 + +func (e Error1) Error() string { + return "error: " + strconv.Itoa(int(e)) +} + +func main() { + var e1 Error1 = Error1(0) + e1 += 1 + println(e1) +} + +// Output: +// error: 1 diff --git a/gnovm/tests/files/types/add_assign_f0_stdlibs.gno b/gnovm/tests/files/types/add_assign_f0_stdlibs.gno new file mode 100644 index 00000000000..b91fa58c30d --- /dev/null +++ b/gnovm/tests/files/types/add_assign_f0_stdlibs.gno @@ -0,0 +1,25 @@ +package main + +import ( + "errors" + "strconv" +) + +type Error int64 + +func (e Error) Error() string { + return "error: " + strconv.Itoa(int(e)) +} + +var errCmp = errors.New("XXXX") + +// specil case: +// one is interface +func main() { + r := 1 + r += errCmp + println(r) +} + +// Error: +// main/files/types/add_assign_f0_stdlibs.gno:20: invalid operation: mismatched types int and .uverse.error diff --git a/gnovm/tests/files/types/add_assign_f1_stdlibs.gno b/gnovm/tests/files/types/add_assign_f1_stdlibs.gno new file mode 100644 index 00000000000..090f8f51f89 --- /dev/null +++ b/gnovm/tests/files/types/add_assign_f1_stdlibs.gno @@ -0,0 +1,28 @@ +package main + +import ( + "errors" + "strconv" +) + +type Error int64 + +func (e Error) Error() string { + return "error: " + strconv.Itoa(int(e)) +} + +var errCmp = errors.New("XXXX") + +// special case: +// 1. base type of left is int64, op is legal; +// 2. while RHS is interface kind, and can be converted to left +func main() { + r := Error(0) + r += errCmp // in case of this, should panic mismatch on operand, except RHS is untyped + //println(r) + // println(Error(0) == errCmp) // Note: this is different with += + +} + +// Error: +// main/files/types/add_assign_f1_stdlibs.gno:21: invalid operation: mismatched types main.Error and .uverse.error diff --git a/gnovm/tests/files/types/add_assign_f2_stdlibs.gno b/gnovm/tests/files/types/add_assign_f2_stdlibs.gno new file mode 100644 index 00000000000..5cfd351f574 --- /dev/null +++ b/gnovm/tests/files/types/add_assign_f2_stdlibs.gno @@ -0,0 +1,25 @@ +package main + +import ( + "errors" + "strconv" +) + +type Error int64 + +func (e Error) Error() string { + return "error: " + strconv.Itoa(int(e)) +} + +var errCmp = errors.New("XXXX") + +// specil case: +// one is interface +func main() { + r := Error(0) + errCmp += r + println(errCmp) +} + +// Error: +// main/files/types/add_assign_f2_stdlibs.gno:20: operator += not defined on: InterfaceKind diff --git a/gnovm/tests/files/types/add_assign_f3.gno b/gnovm/tests/files/types/add_assign_f3.gno new file mode 100644 index 00000000000..7a48c584dff --- /dev/null +++ b/gnovm/tests/files/types/add_assign_f3.gno @@ -0,0 +1,32 @@ +package main + +import ( + "strconv" +) + +type E interface { + Error() string +} + +type Error1 int64 + +func (e Error1) Error() string { + return "error: " + strconv.Itoa(int(e)) +} + +type Error2 int + +func (e Error2) Error() string { + return "error: " + strconv.Itoa(int(e)) +} + +// both not const, and both interface +func main() { + var e1 E = Error1(0) + var e2 E = Error2(0) + e1 += e2 + println(e1) +} + +// Error: +// main/files/types/add_assign_f3.gno:27: operator += not defined on: InterfaceKind diff --git a/gnovm/tests/files/types/add_assign_f4.gno b/gnovm/tests/files/types/add_assign_f4.gno new file mode 100644 index 00000000000..bb4083e8935 --- /dev/null +++ b/gnovm/tests/files/types/add_assign_f4.gno @@ -0,0 +1,10 @@ +package main + +func main() { + a := 1 + a += int(1) + println(a) +} + +// Output: +// 2 diff --git a/gnovm/tests/files/types/add_b0.gno b/gnovm/tests/files/types/add_b0.gno new file mode 100644 index 00000000000..3790f9d7134 --- /dev/null +++ b/gnovm/tests/files/types/add_b0.gno @@ -0,0 +1,13 @@ +package main + +type Error int8 + +// one untyped const, one typed const +func main() { + println(1 + Error(1)) + println(Error(1) + 1) +} + +// Output: +// (2 main.Error) +// (2 main.Error) diff --git a/gnovm/tests/files/types/add_b1.gno b/gnovm/tests/files/types/add_b1.gno new file mode 100644 index 00000000000..854ecaa9770 --- /dev/null +++ b/gnovm/tests/files/types/add_b1.gno @@ -0,0 +1,21 @@ +package main + +import ( + "strconv" +) + +type Error int8 + +func (e Error) Error() string { + return "error: " + strconv.Itoa(int(e)) +} + +// one untyped const, one typed const +func main() { + println(1 + Error(1)) + println(Error(1) + 1) +} + +// Output: +// error: 2 +// error: 2 diff --git a/gnovm/tests/files/types/add_b2.gno b/gnovm/tests/files/types/add_b2.gno new file mode 100644 index 00000000000..b6463134da4 --- /dev/null +++ b/gnovm/tests/files/types/add_b2.gno @@ -0,0 +1,9 @@ +package main + +// one untyped const, one typed const +func main() { + println(1 + "a") +} + +// Error: +// main/files/types/add_b2.gno:5: cannot use untyped Bigint as StringKind diff --git a/gnovm/tests/files/types/add_b3.gno b/gnovm/tests/files/types/add_b3.gno new file mode 100644 index 00000000000..c8a94c5b6ab --- /dev/null +++ b/gnovm/tests/files/types/add_b3.gno @@ -0,0 +1,9 @@ +package main + +// one untyped const, one typed const +func main() { + println("b" + "a") +} + +// Output: +// ba diff --git a/gnovm/tests/files/types/add_d0.gno b/gnovm/tests/files/types/add_d0.gno new file mode 100644 index 00000000000..3f0d9548fff --- /dev/null +++ b/gnovm/tests/files/types/add_d0.gno @@ -0,0 +1,13 @@ +package main + +// both untyped const +// untyped bigint to untyped bigdec +// TODO: dec value representation +func main() { + println(1.0 + 1) + println(1.0 + 0) +} + +// Output: +// 2 +// 1 diff --git a/gnovm/tests/files/types/add_d1.gno b/gnovm/tests/files/types/add_d1.gno new file mode 100644 index 00000000000..7bf7c26565a --- /dev/null +++ b/gnovm/tests/files/types/add_d1.gno @@ -0,0 +1,10 @@ +package main + +// both untyped const +// TODO: dec value representation +func main() { + println('a' + 'b') +} + +// Output: +// 195 diff --git a/gnovm/tests/files/types/add_d2.gno b/gnovm/tests/files/types/add_d2.gno new file mode 100644 index 00000000000..7ea4924a594 --- /dev/null +++ b/gnovm/tests/files/types/add_d2.gno @@ -0,0 +1,13 @@ +package main + +// both untyped const +// TODO: dec value representation +var r rune + +func main() { + r = 'a' + println(r + 'b') +} + +// Output: +// 195 diff --git a/gnovm/tests/files/types/add_d3.gno b/gnovm/tests/files/types/add_d3.gno new file mode 100644 index 00000000000..b130fc98b66 --- /dev/null +++ b/gnovm/tests/files/types/add_d3.gno @@ -0,0 +1,15 @@ +package main + +// both untyped const +// TODO: dec value representation +var r1 rune +var r2 rune + +func main() { + r1 = 'a' + r2 = 'b' + println(r1 + r2) +} + +// Output: +// 195 diff --git a/gnovm/tests/files/types/add_d4.gno b/gnovm/tests/files/types/add_d4.gno new file mode 100644 index 00000000000..bdfca69ea88 --- /dev/null +++ b/gnovm/tests/files/types/add_d4.gno @@ -0,0 +1,11 @@ +package main + +var a int +var b interface{} + +func main() { + println(b + a) +} + +// Error: +// main/files/types/add_d4.gno:7: operator + not defined on: InterfaceKind diff --git a/gnovm/tests/files/types/add_e0.gno b/gnovm/tests/files/types/add_e0.gno new file mode 100644 index 00000000000..b7fc8e395be --- /dev/null +++ b/gnovm/tests/files/types/add_e0.gno @@ -0,0 +1,27 @@ +package main + +import ( + "strconv" +) + +type Error1 int64 + +func (e Error1) Error() string { + return "error: " + strconv.Itoa(int(e)) +} + +type Error2 int + +func (e Error2) Error() string { + return "error: " + strconv.Itoa(int(e)) +} + +// both not const, typed +func main() { + var e1 Error1 = Error1(0) + var e2 Error2 = Error2(0) + println(e1 + e2) +} + +// Error: +// main/files/types/add_e0.gno:23: invalid operation: mismatched types main.Error1 and main.Error2 diff --git a/gnovm/tests/files/types/add_f0_stdlibs.gno b/gnovm/tests/files/types/add_f0_stdlibs.gno new file mode 100644 index 00000000000..cf16d0ff084 --- /dev/null +++ b/gnovm/tests/files/types/add_f0_stdlibs.gno @@ -0,0 +1,23 @@ +package main + +import ( + "errors" + "strconv" +) + +type Error int64 + +func (e Error) Error() string { + return "error: " + strconv.Itoa(int(e)) +} + +var errCmp = errors.New("XXXX") + +// specil case: +// one is interface +func main() { + println(1 + errCmp) +} + +// Error: +// main/files/types/add_f0_stdlibs.gno:19: operator + not defined on: InterfaceKind diff --git a/gnovm/tests/files/types/add_f1_stdlibs.gno b/gnovm/tests/files/types/add_f1_stdlibs.gno new file mode 100644 index 00000000000..6bf1f814ac5 --- /dev/null +++ b/gnovm/tests/files/types/add_f1_stdlibs.gno @@ -0,0 +1,23 @@ +package main + +import ( + "errors" + "strconv" +) + +type Error int64 + +func (e Error) Error() string { + return "error: " + strconv.Itoa(int(e)) +} + +var errCmp = errors.New("XXXX") + +// specil case: +// one is interface +func main() { + println(Error(0) + errCmp) +} + +// Error: +// main/files/types/add_f1_stdlibs.gno:19: operator + not defined on: InterfaceKind diff --git a/gnovm/tests/files/types/add_f2.gno b/gnovm/tests/files/types/add_f2.gno new file mode 100644 index 00000000000..7adfcfdaca6 --- /dev/null +++ b/gnovm/tests/files/types/add_f2.gno @@ -0,0 +1,31 @@ +package main + +import ( + "strconv" +) + +type E interface { + Error() string +} + +type Error1 int64 + +func (e Error1) Error() string { + return "error: " + strconv.Itoa(int(e)) +} + +type Error2 int + +func (e Error2) Error() string { + return "error: " + strconv.Itoa(int(e)) +} + +// both not const, and both interface +func main() { + var e1 E = Error1(0) + var e2 E = Error2(0) + println(e1 + e2) +} + +// Error: +// main/files/types/add_f2.gno:27: operator + not defined on: InterfaceKind diff --git a/gnovm/tests/files/types/and_a0.gno b/gnovm/tests/files/types/and_a0.gno new file mode 100644 index 00000000000..b1d23b23c91 --- /dev/null +++ b/gnovm/tests/files/types/and_a0.gno @@ -0,0 +1,9 @@ +package main + +// both typed(different) const +func main() { + println(int(0) & int8(1)) +} + +// Error: +// main/files/types/and_a0.gno:5: invalid operation: mismatched types int and int8 diff --git a/gnovm/tests/files/types/and_a1.gno b/gnovm/tests/files/types/and_a1.gno new file mode 100644 index 00000000000..d2fceec80ef --- /dev/null +++ b/gnovm/tests/files/types/and_a1.gno @@ -0,0 +1,25 @@ +package main + +import ( + "strconv" +) + +type Error1 int64 + +func (e Error1) Error() string { + return "error: " + strconv.Itoa(int(e)) +} + +type Error2 int + +func (e Error2) Error() string { + return "error: " + strconv.Itoa(int(e)) +} + +// both typed(different) const +func main() { + println(Error1(0) & Error2(0)) +} + +// Error: +// main/files/types/and_a1.gno:21: invalid operation: mismatched types main.Error1 and main.Error2 diff --git a/gnovm/tests/files/types/and_b0.gno b/gnovm/tests/files/types/and_b0.gno new file mode 100644 index 00000000000..525796320e6 --- /dev/null +++ b/gnovm/tests/files/types/and_b0.gno @@ -0,0 +1,13 @@ +package main + +type Error int8 + +// one untyped const, one typed const +func main() { + println(1 & Error(1)) + println(Error(1) & 1) +} + +// Output: +// (1 main.Error) +// (1 main.Error) diff --git a/gnovm/tests/files/types/and_b1.gno b/gnovm/tests/files/types/and_b1.gno new file mode 100644 index 00000000000..dc21fc3956b --- /dev/null +++ b/gnovm/tests/files/types/and_b1.gno @@ -0,0 +1,21 @@ +package main + +import ( + "strconv" +) + +type Error int8 + +func (e Error) Error() string { + return "error: " + strconv.Itoa(int(e)) +} + +// one untyped const, one typed const +func main() { + println(1 & Error(1)) + println(Error(1) & 1) +} + +// Output: +// error: 1 +// error: 1 diff --git a/gnovm/tests/files/types/and_b2.gno b/gnovm/tests/files/types/and_b2.gno new file mode 100644 index 00000000000..8ff36aaa26b --- /dev/null +++ b/gnovm/tests/files/types/and_b2.gno @@ -0,0 +1,9 @@ +package main + +// one untyped const, one typed const +func main() { + println(1 & "a") +} + +// Error: +// main/files/types/and_b2.gno:5: operator & not defined on: StringKind diff --git a/gnovm/tests/files/types/and_b3.gno b/gnovm/tests/files/types/and_b3.gno new file mode 100644 index 00000000000..69be88d2dc9 --- /dev/null +++ b/gnovm/tests/files/types/and_b3.gno @@ -0,0 +1,9 @@ +package main + +// one untyped const, one typed const +func main() { + println("b" & "a") +} + +// Error: +// main/files/types/and_b3.gno:5: operator & not defined on: StringKind diff --git a/gnovm/tests/files/types/and_b4.gno b/gnovm/tests/files/types/and_b4.gno new file mode 100644 index 00000000000..725714eeafd --- /dev/null +++ b/gnovm/tests/files/types/and_b4.gno @@ -0,0 +1,9 @@ +package main + +// one untyped const, one typed const +func main() { + println(1 & 'a') +} + +// Output: +// 1 diff --git a/gnovm/tests/files/types/and_d0.gno b/gnovm/tests/files/types/and_d0.gno new file mode 100644 index 00000000000..90646e97bc9 --- /dev/null +++ b/gnovm/tests/files/types/and_d0.gno @@ -0,0 +1,10 @@ +package main + +// both untyped const +// TODO: dec value representation, and this should happen in process stage!!! +func main() { + println(1.0 & 1) +} + +// Error: +// main/files/types/and_d0.gno:6: operator & not defined on: BigdecKind diff --git a/gnovm/tests/files/types/and_d1.gno b/gnovm/tests/files/types/and_d1.gno new file mode 100644 index 00000000000..232fff4d385 --- /dev/null +++ b/gnovm/tests/files/types/and_d1.gno @@ -0,0 +1,10 @@ +package main + +// both untyped const +// TODO: dec value representation +func main() { + println('a' & 'b') +} + +// Output: +// 96 diff --git a/gnovm/tests/files/types/and_d2.gno b/gnovm/tests/files/types/and_d2.gno new file mode 100644 index 00000000000..f5c2660bafc --- /dev/null +++ b/gnovm/tests/files/types/and_d2.gno @@ -0,0 +1,13 @@ +package main + +// both untyped const +// TODO: dec value representation +var r rune + +func main() { + r = 'a' + println(r & 'b') +} + +// Output: +// 96 diff --git a/gnovm/tests/files/types/and_d3.gno b/gnovm/tests/files/types/and_d3.gno new file mode 100644 index 00000000000..f5cb8075f24 --- /dev/null +++ b/gnovm/tests/files/types/and_d3.gno @@ -0,0 +1,15 @@ +package main + +// both untyped const +// TODO: dec value representation +var r1 rune +var r2 rune + +func main() { + r1 = 'a' + r2 = 'b' + println(r1 & r2) +} + +// Output: +// 96 diff --git a/gnovm/tests/files/types/and_d4.gno b/gnovm/tests/files/types/and_d4.gno new file mode 100644 index 00000000000..b4f8a70ad3c --- /dev/null +++ b/gnovm/tests/files/types/and_d4.gno @@ -0,0 +1,10 @@ +package main + +// both untyped const +// TODO: dec value representation +func main() { + println(1.0 & 0) +} + +// Error: +// main/files/types/and_d4.gno:6: operator & not defined on: BigdecKind diff --git a/gnovm/tests/files/types/and_e0.gno b/gnovm/tests/files/types/and_e0.gno new file mode 100644 index 00000000000..28d58acf42b --- /dev/null +++ b/gnovm/tests/files/types/and_e0.gno @@ -0,0 +1,27 @@ +package main + +import ( + "strconv" +) + +type Error1 int64 + +func (e Error1) Error() string { + return "error: " + strconv.Itoa(int(e)) +} + +type Error2 int + +func (e Error2) Error() string { + return "error: " + strconv.Itoa(int(e)) +} + +// both not const, typed +func main() { + var e1 Error1 = Error1(0) + var e2 Error2 = Error2(0) + println(e1 & e2) +} + +// Error: +// main/files/types/and_e0.gno:23: invalid operation: mismatched types main.Error1 and main.Error2 diff --git a/gnovm/tests/files/types/and_f0_stdlibs.gno b/gnovm/tests/files/types/and_f0_stdlibs.gno new file mode 100644 index 00000000000..6b56a8e59c4 --- /dev/null +++ b/gnovm/tests/files/types/and_f0_stdlibs.gno @@ -0,0 +1,23 @@ +package main + +import ( + "errors" + "strconv" +) + +type Error int64 + +func (e Error) Error() string { + return "error: " + strconv.Itoa(int(e)) +} + +var errCmp = errors.New("XXXX") + +// specil case: +// one is interface +func main() { + println(1 & errCmp) +} + +// Error: +// main/files/types/and_f0_stdlibs.gno:19: operator & not defined on: InterfaceKind diff --git a/gnovm/tests/files/types/and_f1_stdlibs.gno b/gnovm/tests/files/types/and_f1_stdlibs.gno new file mode 100644 index 00000000000..f1d7589e2f6 --- /dev/null +++ b/gnovm/tests/files/types/and_f1_stdlibs.gno @@ -0,0 +1,23 @@ +package main + +import ( + "errors" + "strconv" +) + +type Error int64 + +func (e Error) Error() string { + return "error: " + strconv.Itoa(int(e)) +} + +var errCmp = errors.New("XXXX") + +// specil case: +// one is interface +func main() { + println(Error(0) & errCmp) +} + +// Error: +// main/files/types/and_f1_stdlibs.gno:19: operator & not defined on: InterfaceKind diff --git a/gnovm/tests/files/types/and_f2.gno b/gnovm/tests/files/types/and_f2.gno new file mode 100644 index 00000000000..24368256822 --- /dev/null +++ b/gnovm/tests/files/types/and_f2.gno @@ -0,0 +1,31 @@ +package main + +import ( + "strconv" +) + +type E interface { + Error() string +} + +type Error1 int64 + +func (e Error1) Error() string { + return "error: " + strconv.Itoa(int(e)) +} + +type Error2 int + +func (e Error2) Error() string { + return "error: " + strconv.Itoa(int(e)) +} + +// both not const, and both interface +func main() { + var e1 E = Error1(0) + var e2 E = Error2(0) + println(e1 & e2) +} + +// Error: +// main/files/types/and_f2.gno:27: operator & not defined on: InterfaceKind diff --git a/gnovm/tests/files/types/assign_call.gno b/gnovm/tests/files/types/assign_call.gno new file mode 100644 index 00000000000..a94b4a0b126 --- /dev/null +++ b/gnovm/tests/files/types/assign_call.gno @@ -0,0 +1,14 @@ +package main + +func foo() (int, float32) { + return 1, 1.0 +} + +func main() { + var s, s1 string + s, s1 = foo() + println(s) +} + +// Error: +// main/files/types/assign_call.gno:9: cannot use int as string diff --git a/gnovm/tests/files/types/assign_index.gno b/gnovm/tests/files/types/assign_index.gno new file mode 100644 index 00000000000..93f4cf0a3c1 --- /dev/null +++ b/gnovm/tests/files/types/assign_index.gno @@ -0,0 +1,14 @@ +package main + +func main() { + m := map[string]int{"a": 1, "b": 2, "c": 3} + + var s string + var ok bool + s, ok = m["a"] + println(s) + println(ok) +} + +// Error: +// main/files/types/assign_index.gno:8: cannot use int as string diff --git a/gnovm/tests/files/types/assign_index_a.gno b/gnovm/tests/files/types/assign_index_a.gno new file mode 100644 index 00000000000..dd92220b1fe --- /dev/null +++ b/gnovm/tests/files/types/assign_index_a.gno @@ -0,0 +1,12 @@ +package main + +func main() { + var s string + var ok bool + s, ok = map[string]int{"a": 1, "b": 2, "c": 3}["a"] + println(s) + println(ok) +} + +// Error: +// main/files/types/assign_index_a.gno:6: cannot use int as string diff --git a/gnovm/tests/files/types/assign_index_b.gno b/gnovm/tests/files/types/assign_index_b.gno new file mode 100644 index 00000000000..d8900759cb2 --- /dev/null +++ b/gnovm/tests/files/types/assign_index_b.gno @@ -0,0 +1,14 @@ +package main + +func main() { + m := map[string]int{"a": 1, "b": 2, "c": 3} + + var s int + var ok int + s, ok = m["a"] + println(s) + println(ok) +} + +// Error: +// main/files/types/assign_index_b.gno:8: want bool type got int diff --git a/gnovm/tests/files/types/assign_index_c.gno b/gnovm/tests/files/types/assign_index_c.gno new file mode 100644 index 00000000000..592191189a2 --- /dev/null +++ b/gnovm/tests/files/types/assign_index_c.gno @@ -0,0 +1,12 @@ +package main + +func main() { + s := []int{1, 2, 3} + + var s1 string + s1 = s[0] + println(s) +} + +// Error: +// main/files/types/assign_index_c.gno:7: cannot use int as string diff --git a/gnovm/tests/files/types/assign_literal.gno b/gnovm/tests/files/types/assign_literal.gno new file mode 100644 index 00000000000..61c128fbe1f --- /dev/null +++ b/gnovm/tests/files/types/assign_literal.gno @@ -0,0 +1,8 @@ +package main + +func main() { + 1 = 6 +} + +// Error: +// main/files/types/assign_literal.gno:4: cannot assign to (const (1 bigint)) diff --git a/gnovm/tests/files/types/assign_literal10.gno b/gnovm/tests/files/types/assign_literal10.gno new file mode 100644 index 00000000000..d7b29f91aec --- /dev/null +++ b/gnovm/tests/files/types/assign_literal10.gno @@ -0,0 +1,21 @@ +package main + +type foo struct { + a int +} + +var n int + +func (f foo) add() *int { return &n } + +func main() { + s := &foo{} + *(s.add()) = 1 + println((*s).a) + + println(n) +} + +// Output: +// 0 +// 1 diff --git a/gnovm/tests/files/types/assign_literal10a.gno b/gnovm/tests/files/types/assign_literal10a.gno new file mode 100644 index 00000000000..f6963d926ee --- /dev/null +++ b/gnovm/tests/files/types/assign_literal10a.gno @@ -0,0 +1,20 @@ +package main + +type foo struct { + a int +} + +var n int + +func (f foo) add() *int { return &n } + +func main() { + s := &foo{} + s.add() = 1 + println((*s).a) + + println(n) +} + +// Error: +// main/files/types/assign_literal10a.gno:13: cannot assign to s.add() diff --git a/gnovm/tests/files/types/assign_literal11.gno b/gnovm/tests/files/types/assign_literal11.gno new file mode 100644 index 00000000000..821f95422a0 --- /dev/null +++ b/gnovm/tests/files/types/assign_literal11.gno @@ -0,0 +1,11 @@ +package main + +const Pi = 3.14 + +func main() { + Pi = 3.14159 + println(Pi) +} + +// Error: +// main/files/types/assign_literal11.gno:6: cannot assign to (const (3.14 bigdec)) diff --git a/gnovm/tests/files/types/assign_literal2.gno b/gnovm/tests/files/types/assign_literal2.gno new file mode 100644 index 00000000000..2e495b6fb78 --- /dev/null +++ b/gnovm/tests/files/types/assign_literal2.gno @@ -0,0 +1,9 @@ +package main + +func main() { + var a int + a, 2 = 6, 6 +} + +// Error: +// main/files/types/assign_literal2.gno:5: cannot assign to (const (2 bigint)) diff --git a/gnovm/tests/files/types/assign_literal2_a.gno b/gnovm/tests/files/types/assign_literal2_a.gno new file mode 100644 index 00000000000..f66868ab842 --- /dev/null +++ b/gnovm/tests/files/types/assign_literal2_a.gno @@ -0,0 +1,9 @@ +package main + +func main() { + var a int + a, 2 := 6, 6 +} + +// Error: +// files/types/assign_literal2_a.gno:5:2: no new variables on left side of := \ No newline at end of file diff --git a/gnovm/tests/files/types/assign_literal3.gno b/gnovm/tests/files/types/assign_literal3.gno new file mode 100644 index 00000000000..67d4877cd5a --- /dev/null +++ b/gnovm/tests/files/types/assign_literal3.gno @@ -0,0 +1,8 @@ +package main + +func main() { + true = false +} + +// Error: +// main/files/types/assign_literal3.gno:4: cannot assign to (const (true bool)) diff --git a/gnovm/tests/files/types/assign_literal4.gno b/gnovm/tests/files/types/assign_literal4.gno new file mode 100644 index 00000000000..bdae4fa39a5 --- /dev/null +++ b/gnovm/tests/files/types/assign_literal4.gno @@ -0,0 +1,8 @@ +package main + +func main() { + []int{1, 2} = []int{3, 4} +} + +// Error: +// main/files/types/assign_literal4.gno:4: cannot assign to [](const-type int){(const (1 int)), (const (2 int))} diff --git a/gnovm/tests/files/types/assign_literal4_a.gno b/gnovm/tests/files/types/assign_literal4_a.gno new file mode 100644 index 00000000000..054ae227b32 --- /dev/null +++ b/gnovm/tests/files/types/assign_literal4_a.gno @@ -0,0 +1,8 @@ +package main + +func main() { + []int{1, 2} := []int{3, 4} +} + +// Error: +// files/types/assign_literal4_a.gno:4:2: no new variables on left side of := \ No newline at end of file diff --git a/gnovm/tests/files/types/assign_literal5.gno b/gnovm/tests/files/types/assign_literal5.gno new file mode 100644 index 00000000000..da382b8ac1c --- /dev/null +++ b/gnovm/tests/files/types/assign_literal5.gno @@ -0,0 +1,8 @@ +package main + +func main() { + map[string]int{"a": 1, "b": 2} = map[string]int{"a": 1, "b": 2} +} + +// Error: +// main/files/types/assign_literal5.gno:4: cannot assign to map[(const-type string)] (const-type int){(const ("a" string)): (const (1 int)), (const ("b" string)): (const (2 int))} diff --git a/gnovm/tests/files/types/assign_literal6.gno b/gnovm/tests/files/types/assign_literal6.gno new file mode 100644 index 00000000000..dfcf9cbb80a --- /dev/null +++ b/gnovm/tests/files/types/assign_literal6.gno @@ -0,0 +1,8 @@ +package main + +func main() { + 1 + 2 = 6 +} + +// Error: +// main/files/types/assign_literal6.gno:4: cannot assign to (const (3 bigint)) diff --git a/gnovm/tests/files/types/assign_literal7.gno b/gnovm/tests/files/types/assign_literal7.gno new file mode 100644 index 00000000000..56308cdbbfc --- /dev/null +++ b/gnovm/tests/files/types/assign_literal7.gno @@ -0,0 +1,10 @@ +package main + +func main() { + s := []int{1, 2, 3} + s[0] = 0 + println(s) +} + +// Output: +// slice[(0 int),(2 int),(3 int)] diff --git a/gnovm/tests/files/types/assign_literal7a.gno b/gnovm/tests/files/types/assign_literal7a.gno new file mode 100644 index 00000000000..8be126c49de --- /dev/null +++ b/gnovm/tests/files/types/assign_literal7a.gno @@ -0,0 +1,10 @@ +package main + +func main() { + m := map[string]int{"a": 1, "b": 2, "c": 3} + m["a"] = 0 + println(m) +} + +// Output: +// map{("a" string):(0 int),("b" string):(2 int),("c" string):(3 int)} diff --git a/gnovm/tests/files/types/assign_literal7b.gno b/gnovm/tests/files/types/assign_literal7b.gno new file mode 100644 index 00000000000..dc61467e07c --- /dev/null +++ b/gnovm/tests/files/types/assign_literal7b.gno @@ -0,0 +1,10 @@ +package main + +func main() { + s := [2]int{} + s[0] = 0 + println(s) +} + +// Output: +// array[(0 int),(0 int)] diff --git a/gnovm/tests/files/types/assign_literal7c.gno b/gnovm/tests/files/types/assign_literal7c.gno new file mode 100644 index 00000000000..989dcca6699 --- /dev/null +++ b/gnovm/tests/files/types/assign_literal7c.gno @@ -0,0 +1,13 @@ +package main + +import "fmt" + +func main() { + str := "hello" + str[0] = 'y' + fmt.Println(str[0]) + fmt.Printf("%c\n", str[0]) +} + +// Error: +// main/files/types/assign_literal7c.gno:7: cannot assign to str[(const (0 int))] diff --git a/gnovm/tests/files/types/assign_literal7d.gno b/gnovm/tests/files/types/assign_literal7d.gno new file mode 100644 index 00000000000..f56c304b3d3 --- /dev/null +++ b/gnovm/tests/files/types/assign_literal7d.gno @@ -0,0 +1,14 @@ +package main + +import "fmt" + +func main() { + bs := []byte("hello") + bs[0] = 'y' + fmt.Println(bs[0]) + fmt.Printf("%c\n", bs[0]) +} + +// Output: +// 121 +// y diff --git a/gnovm/tests/files/types/assign_literal8.gno b/gnovm/tests/files/types/assign_literal8.gno new file mode 100644 index 00000000000..d652efc0874 --- /dev/null +++ b/gnovm/tests/files/types/assign_literal8.gno @@ -0,0 +1,11 @@ +package main + +func main() { + var a int + p := &a + *p = 1 + println(*p) +} + +// Output: +// 1 diff --git a/gnovm/tests/files/types/assign_literal9.gno b/gnovm/tests/files/types/assign_literal9.gno new file mode 100644 index 00000000000..1d672ae46ce --- /dev/null +++ b/gnovm/tests/files/types/assign_literal9.gno @@ -0,0 +1,14 @@ +package main + +type foo struct { + a int +} + +func main() { + s := &foo{} + s.a = 1 + println(s.a) +} + +// Output: +// 1 diff --git a/gnovm/tests/files/types/assign_literal_a.gno b/gnovm/tests/files/types/assign_literal_a.gno new file mode 100644 index 00000000000..dd17e97c466 --- /dev/null +++ b/gnovm/tests/files/types/assign_literal_a.gno @@ -0,0 +1,8 @@ +package main + +func main() { + 1 := 6 +} + +// Error: +// files/types/assign_literal_a.gno:4:2: no new variables on left side of := \ No newline at end of file diff --git a/gnovm/tests/files/types/assign_nil.gno b/gnovm/tests/files/types/assign_nil.gno new file mode 100644 index 00000000000..e4012745d4f --- /dev/null +++ b/gnovm/tests/files/types/assign_nil.gno @@ -0,0 +1,11 @@ +package main + +func main() { + var i interface{} + i = 4 + var j int + j, nil = i.(int) +} + +// Error: +// main/files/types/assign_nil.gno:7: cannot assign to (const (undefined)) diff --git a/gnovm/tests/files/types/assign_nil2.gno b/gnovm/tests/files/types/assign_nil2.gno new file mode 100644 index 00000000000..8af61a1e496 --- /dev/null +++ b/gnovm/tests/files/types/assign_nil2.gno @@ -0,0 +1,11 @@ +package main + +func main() { + var i interface{} + i = 4 + var ok bool + nil, nil = i.(int) +} + +// Error: +// main/files/types/assign_nil2.gno:7: cannot assign to (const (undefined)) diff --git a/gnovm/tests/files/types/assign_range.gno b/gnovm/tests/files/types/assign_range.gno new file mode 100644 index 00000000000..5ee1c49a2e9 --- /dev/null +++ b/gnovm/tests/files/types/assign_range.gno @@ -0,0 +1,42 @@ +package main + +import "fmt" + +func main() { + // Creating a map where keys are strings and values are integers + scores := map[string]int{ + "Alice": 92, + "Bob": 89, + "Charlie": 95, + } + + // Using range to iterate over the map + // k is the key and v is the value for each pair in the map + for k, v := range scores { + fmt.Printf("%s has a score of %d\n", k, v) + } + + // Modifying values during iteration + for k := range scores { + scores[k] += 5 // Adding 5 to each score + } + fmt.Println("Updated scores:", scores) + + // Collecting keys and values into slices + var keys []string + var values []int + for k, v := range scores { + keys = append(keys, k) + values = append(values, v) + } + fmt.Println("Keys:", keys) + fmt.Println("Values:", values) +} + +// Output: +// Alice has a score of 92 +// Bob has a score of 89 +// Charlie has a score of 95 +// Updated scores: map[Alice:97 Bob:94 Charlie:100] +// Keys: [Alice Bob Charlie] +// Values: [97 94 100] diff --git a/gnovm/tests/files/types/assign_range_a.gno b/gnovm/tests/files/types/assign_range_a.gno new file mode 100644 index 00000000000..72115771e52 --- /dev/null +++ b/gnovm/tests/files/types/assign_range_a.gno @@ -0,0 +1,22 @@ +package main + +import "fmt" + +func main() { + // Creating a map where keys are strings and values are integers + scores := map[string]int{ + "Alice": 92, + "Bob": 89, + "Charlie": 95, + } + + // Using range to iterate over the map + // k is the key and v is the value for each pair in the map + var k, v int + for k, v = range scores { + fmt.Printf("%s has a score of %d\n", k, v) + } +} + +// Error: +// main/files/types/assign_range_a.gno:16: cannot use string as int diff --git a/gnovm/tests/files/types/assign_range_a1.gno b/gnovm/tests/files/types/assign_range_a1.gno new file mode 100644 index 00000000000..4e6ede4ffda --- /dev/null +++ b/gnovm/tests/files/types/assign_range_a1.gno @@ -0,0 +1,22 @@ +package main + +import "fmt" + +func main() { + // Creating a map where keys are strings and values are integers + scores := map[string]int{ + "Alice": 92, + "Bob": 89, + "Charlie": 95, + } + + // Using range to iterate over the map + // k is the key and v is the value for each pair in the map + var v int + for 6, v = range scores { + fmt.Printf("%s has a score of %d\n", "a", v) + } +} + +// Error: +// main/files/types/assign_range_a1.gno:16: cannot assign to (const (6 bigint)) diff --git a/gnovm/tests/files/types/assign_range_b.gno b/gnovm/tests/files/types/assign_range_b.gno new file mode 100644 index 00000000000..df7fbeb8158 --- /dev/null +++ b/gnovm/tests/files/types/assign_range_b.gno @@ -0,0 +1,20 @@ +package main + +import "fmt" + +func main() { + // Creating a map where keys are strings and values are integers + scores := []string{ + "a", "b", "c", + } + + // Using range to iterate over the map + // k is the key and v is the value for each pair in the map + var k, v int + for k, v = range scores { + fmt.Printf("%d has a score of %s\n", k, v) + } +} + +// Error: +// main/files/types/assign_range_b.gno:14: cannot use string as int diff --git a/gnovm/tests/files/types/assign_range_b1.gno b/gnovm/tests/files/types/assign_range_b1.gno new file mode 100644 index 00000000000..4632b79b6f0 --- /dev/null +++ b/gnovm/tests/files/types/assign_range_b1.gno @@ -0,0 +1,20 @@ +package main + +import "fmt" + +func main() { + // Creating a map where keys are strings and values are integers + scores := [3]string{ + "a", "b", "c", + } + + // Using range to iterate over the map + // k is the key and v is the value for each pair in the map + var k, v int + for k, v = range scores { + fmt.Printf("%d has a score of %s\n", k, v) + } +} + +// Error: +// main/files/types/assign_range_b1.gno:14: cannot use string as int diff --git a/gnovm/tests/files/types/assign_range_b2.gno b/gnovm/tests/files/types/assign_range_b2.gno new file mode 100644 index 00000000000..a96c3f91ace --- /dev/null +++ b/gnovm/tests/files/types/assign_range_b2.gno @@ -0,0 +1,28 @@ +package main + +func main() { + rangeMap() + rangeSlice() +} + +func rangeMap() { + m := map[int]string{999: "asdf"} + var v int + for v = range m { + println(v) + } +} + +func rangeSlice() { + m := []int{9, 4, 6} + var v int + for v = range m { + println(v) + } +} + +// Output: +// 999 +// 0 +// 1 +// 2 diff --git a/gnovm/tests/files/types/assign_range_c.gno b/gnovm/tests/files/types/assign_range_c.gno new file mode 100644 index 00000000000..783534bebb4 --- /dev/null +++ b/gnovm/tests/files/types/assign_range_c.gno @@ -0,0 +1,20 @@ +package main + +import "fmt" + +func main() { + // Creating a map where keys are strings and values are integers + scores := []string{ + "a", "b", "c", + } + + // Using range to iterate over the map + // k is the key and v is the value for each pair in the map + var k, v float32 + for k, v = range scores { + fmt.Printf("%d has a score of %s\n", k, v) + } +} + +// Error: +// main/files/types/assign_range_c.gno:14: index type should be int, but got float32 diff --git a/gnovm/tests/files/types/assign_range_d.gno b/gnovm/tests/files/types/assign_range_d.gno new file mode 100644 index 00000000000..6903cb0b7bc --- /dev/null +++ b/gnovm/tests/files/types/assign_range_d.gno @@ -0,0 +1,14 @@ +package main + +func main() { + s := "hello" + + var index float32 + var value rune + for index, value = range s { + println(index) + } +} + +// Error: +// main/files/types/assign_range_d.gno:8: index type should be int, but got float32 diff --git a/gnovm/tests/files/types/assign_range_e.gno b/gnovm/tests/files/types/assign_range_e.gno new file mode 100644 index 00000000000..7f7f15c5c23 --- /dev/null +++ b/gnovm/tests/files/types/assign_range_e.gno @@ -0,0 +1,15 @@ +package main + +func main() { + s := "hello" + + var index int + var value int + for index, value = range s { + println(index) + println(value) + } +} + +// Error: +// main/files/types/assign_range_e.gno:8: value type should be int32, but got int diff --git a/gnovm/tests/files/types/assign_rune.gno b/gnovm/tests/files/types/assign_rune.gno new file mode 100644 index 00000000000..7c1e8742fd4 --- /dev/null +++ b/gnovm/tests/files/types/assign_rune.gno @@ -0,0 +1,18 @@ +package main + +var r rune + +// TODO: print right dec, float +func main() { + r = 'a' + println(r) + println(float32(r)) + println(float64(r)) + println(string(r)) +} + +// Output: +// 97 +// 97 +// 97 +// a diff --git a/gnovm/tests/files/types/assign_rune_a.gno b/gnovm/tests/files/types/assign_rune_a.gno new file mode 100644 index 00000000000..13321fd8b08 --- /dev/null +++ b/gnovm/tests/files/types/assign_rune_a.gno @@ -0,0 +1,12 @@ +package main + +var r rune + +// assign +func main() { + r = "a" + println(r) +} + +// Error: +// main/files/types/assign_rune_a.gno:7: cannot use untyped string as Int32Kind diff --git a/gnovm/tests/files/types/assign_type_assertion.gno b/gnovm/tests/files/types/assign_type_assertion.gno new file mode 100644 index 00000000000..6bc2b4b26c8 --- /dev/null +++ b/gnovm/tests/files/types/assign_type_assertion.gno @@ -0,0 +1,22 @@ +package main + +import ( + "fmt" +) + +func main() { + var i interface{} = "Hello, world!" + + // Attempt to assert the type of i to string + var n int + var ok bool + n, ok = i.(string) + if ok { + fmt.Println("i contains a string:", n) + } else { + fmt.Println("i does not contain a string") + } +} + +// Error: +// main/files/types/assign_type_assertion.gno:13: cannot use string as int diff --git a/gnovm/tests/files/types/assign_type_assertion_a.gno b/gnovm/tests/files/types/assign_type_assertion_a.gno new file mode 100644 index 00000000000..1b28408d309 --- /dev/null +++ b/gnovm/tests/files/types/assign_type_assertion_a.gno @@ -0,0 +1,33 @@ +package main + +import "fmt" + +type MyError struct{} + +func (e MyError) Error() string { + return "my error" +} + +func (e MyError) IsSet() bool { + return true +} + +func main() { + var err error = MyError{} + + var assertedErr interface{ IsSet() bool } // Define a variable of the interface type + var ok bool + + // Perform the assertion and assign the result to assertedErr + assertedErr, ok = err.(interface{ IsSet() bool }) + if ok { + fmt.Println("Assertion succeeded:", ok) + fmt.Println("IsSet:", assertedErr.IsSet()) + } else { + fmt.Println("Assertion failed:", ok) + } +} + +// Output: +// Assertion succeeded: true +// IsSet: true diff --git a/gnovm/tests/files/types/assign_type_assertion_b.gno b/gnovm/tests/files/types/assign_type_assertion_b.gno new file mode 100644 index 00000000000..4f68751667d --- /dev/null +++ b/gnovm/tests/files/types/assign_type_assertion_b.gno @@ -0,0 +1,32 @@ +package main + +import "fmt" + +type MyError struct{} + +func (e MyError) Error() string { + return "my error" +} + +func (e MyError) IsSet() bool { + return true +} + +func main() { + var err error = MyError{} + + var assertedErr int // Define a variable of the interface type + var ok bool + + // Perform the assertion and assign the result to assertedErr + assertedErr, ok = err.(interface{ IsSet() bool }) + if ok { + fmt.Println("Assertion succeeded:", ok) + fmt.Println("IsSet:", assertedErr.IsSet()) + } else { + fmt.Println("Assertion failed:", ok) + } +} + +// Error: +// main/files/types/assign_type_assertion_b.gno:22: cannot use interface{IsSet func()(bool)} as int diff --git a/gnovm/tests/files/types/assign_type_assertion_c.gno b/gnovm/tests/files/types/assign_type_assertion_c.gno new file mode 100644 index 00000000000..044154dadfd --- /dev/null +++ b/gnovm/tests/files/types/assign_type_assertion_c.gno @@ -0,0 +1,33 @@ +package main + +import "fmt" + +type MyError struct{} + +func (e MyError) Error() string { + return "my error" +} + +func (e MyError) IsSet() bool { + return true +} + +func main() { + var err error = MyError{} + + var assertedErr interface{ IsNotSet() bool } // Define a variable of the interface type + + var ok bool + + // Perform the assertion and assign the result to assertedErr + assertedErr, ok = err.(interface{ IsSet() bool }) // not impl lhs + if ok { + fmt.Println("Assertion succeeded:", ok) + fmt.Println("IsSet:", assertedErr.IsSet()) + } else { + fmt.Println("Assertion failed:", ok) + } +} + +// Error: +// main/files/types/assign_type_assertion_c.gno:23: interface{IsSet func()(bool)} does not implement interface{IsNotSet func()(bool)} diff --git a/gnovm/tests/files/types/assign_type_assertion_d.gno b/gnovm/tests/files/types/assign_type_assertion_d.gno new file mode 100644 index 00000000000..4ab24f36aac --- /dev/null +++ b/gnovm/tests/files/types/assign_type_assertion_d.gno @@ -0,0 +1,25 @@ +package main + +type Animal interface { + eat() +} + +type Robot struct { +} + +type Dog struct{} + +func (Dog) eat() {} + +func main() { + var animal Animal = Dog{} + + var r Robot + + r = animal.(Dog) + + println(r) +} + +// Error: +// main/files/types/assign_type_assertion_d.gno:19: cannot use main.Dog as main.Robot without explicit conversion diff --git a/gnovm/tests/files/types/assign_type_assertion_e.gno b/gnovm/tests/files/types/assign_type_assertion_e.gno new file mode 100644 index 00000000000..fbe91031667 --- /dev/null +++ b/gnovm/tests/files/types/assign_type_assertion_e.gno @@ -0,0 +1,27 @@ +package main + +type Animal interface { + eat() +} + +type Robot struct { +} + +type Dog struct{} + +func (Dog) eat() {} + +func main() { + var animal Animal = Dog{} + + var r Robot + var ok bool + + r, ok = animal.(Dog) + + println(r) + println(ok) +} + +// Error: +// main/files/types/assign_type_assertion_e.gno:20: cannot use main.Dog as main.Robot without explicit conversion diff --git a/gnovm/tests/files/types/assign_type_assertion_f.gno b/gnovm/tests/files/types/assign_type_assertion_f.gno new file mode 100644 index 00000000000..bc2907eb8af --- /dev/null +++ b/gnovm/tests/files/types/assign_type_assertion_f.gno @@ -0,0 +1,25 @@ +package main + +type Animal interface { + eat() +} + +type Robot struct { +} + +type Dog struct{} + +func (Dog) eat() {} + +func main() { + var animal Animal = Dog{} + + var ok bool + + 1, ok = animal.(Dog) + + println(ok) +} + +// Error: +// main/files/types/assign_type_assertion_f.gno:19: cannot assign to (const (1 bigint)) diff --git a/gnovm/tests/files/types/assign_type_assertion_g.gno b/gnovm/tests/files/types/assign_type_assertion_g.gno new file mode 100644 index 00000000000..2d3d61c561d --- /dev/null +++ b/gnovm/tests/files/types/assign_type_assertion_g.gno @@ -0,0 +1,27 @@ +package main + +type Animal interface { + eat() +} + +type Robot struct { +} + +type Dog struct{} + +func (Dog) eat() {} + +func main() { + var animal Animal = Dog{} + + var a Animal + var ok int + + a, ok = animal.(Dog) + + println(a) + println(ok) +} + +// Error: +// main/files/types/assign_type_assertion_g.gno:20: want bool type got int diff --git a/gnovm/tests/files/types/bigdec.gno b/gnovm/tests/files/types/bigdec.gno new file mode 100644 index 00000000000..baa3d4d6309 --- /dev/null +++ b/gnovm/tests/files/types/bigdec.gno @@ -0,0 +1,11 @@ +package main + +var a uint64 + +func main() { + a = 1 + println(a % 1e9) +} + +// Output: +// 1 diff --git a/gnovm/tests/files/types/bigdec2.gno b/gnovm/tests/files/types/bigdec2.gno new file mode 100644 index 00000000000..60048151a31 --- /dev/null +++ b/gnovm/tests/files/types/bigdec2.gno @@ -0,0 +1,11 @@ +package main + +var a uint64 + +func main() { + a = 1 + println(a % 1.2) +} + +// Error: +// main/files/types/bigdec2.gno:7: cannot convert untyped bigdec to integer -- 1.2 not an exact integer diff --git a/gnovm/tests/files/types/bigdec3.gno b/gnovm/tests/files/types/bigdec3.gno new file mode 100644 index 00000000000..0e0effa7cbb --- /dev/null +++ b/gnovm/tests/files/types/bigdec3.gno @@ -0,0 +1,11 @@ +package main + +var a uint64 + +func main() { + a = 1 + println(1.0 % a) +} + +// Output: +// 0 diff --git a/gnovm/tests/files/types/bigdec4.gno b/gnovm/tests/files/types/bigdec4.gno new file mode 100644 index 00000000000..88cbe894020 --- /dev/null +++ b/gnovm/tests/files/types/bigdec4.gno @@ -0,0 +1,11 @@ +package main + +var a uint64 + +func main() { + a = 1.0 + println(a) +} + +// Output: +// 1 diff --git a/gnovm/tests/files/types/bigdec5.gno b/gnovm/tests/files/types/bigdec5.gno new file mode 100644 index 00000000000..e3f64e0a8ce --- /dev/null +++ b/gnovm/tests/files/types/bigdec5.gno @@ -0,0 +1,11 @@ +package main + +var a uint64 + +func main() { + a = 1.2 + println(a) +} + +// Error: +// main/files/types/bigdec5.gno:6: cannot convert untyped bigdec to integer -- 1.2 not an exact integer diff --git a/gnovm/tests/files/types/bigdec_6.gno b/gnovm/tests/files/types/bigdec_6.gno new file mode 100644 index 00000000000..5ef078619b5 --- /dev/null +++ b/gnovm/tests/files/types/bigdec_6.gno @@ -0,0 +1,8 @@ +package main + +func main() { + println(1 % 1e9) +} + +// Error: +// main/files/types/bigdec_6.gno:4: operator % not defined on: BigdecKind diff --git a/gnovm/tests/files/types/cmp_array.gno b/gnovm/tests/files/types/cmp_array.gno new file mode 100644 index 00000000000..52fea95b034 --- /dev/null +++ b/gnovm/tests/files/types/cmp_array.gno @@ -0,0 +1,16 @@ +package main + +import "fmt" + +func main() { + a := [2][2]int{{1, 2}, {3, 4}} + b := [2][2]int{{1, 2}, {3, 4}} + c := [2][2]int{{5, 6}, {7, 8}} + + fmt.Println("a == b:", a == b) // True because the elements match exactly + fmt.Println("a == c:", a == c) // False because the elements do not match +} + +// Output: +// a == b: true +// a == c: false diff --git a/gnovm/tests/files/types/cmp_array_a.gno b/gnovm/tests/files/types/cmp_array_a.gno new file mode 100644 index 00000000000..1d30f7c51eb --- /dev/null +++ b/gnovm/tests/files/types/cmp_array_a.gno @@ -0,0 +1,21 @@ +package main + +import "fmt" + +// Define a struct that embeds an array +type Matrix struct { + data [2]int +} + +func main() { + a := [2]Matrix{{data: [2]int{1, 2}}, {data: [2]int{3, 4}}} + b := [2]Matrix{{data: [2]int{1, 2}}, {data: [2]int{3, 4}}} + c := [2]Matrix{{data: [2]int{5, 6}}, {data: [2]int{7, 8}}} + + fmt.Println("a == b:", a == b) // True because the elements match exactly + fmt.Println("a == c:", a == c) // False because the elements do not match +} + +// Output: +// a == b: true +// a == c: false diff --git a/gnovm/tests/files/types/cmp_array_b.gno b/gnovm/tests/files/types/cmp_array_b.gno new file mode 100644 index 00000000000..490a3424965 --- /dev/null +++ b/gnovm/tests/files/types/cmp_array_b.gno @@ -0,0 +1,15 @@ +package main + +import "fmt" + +func main() { + a := [2][]int{{1, 2}, {3, 4}} + b := [2][]int{{1, 2}, {3, 4}} + c := [2][]int{{5, 6}, {7, 8}} + + fmt.Println("a == b:", a == b) // True because the elements match exactly + fmt.Println("a == c:", a == c) // False because the elements do not match +} + +// Error: +// main/files/types/cmp_array_b.gno:10: [2][]int is not comparable diff --git a/gnovm/tests/files/types/cmp_array_c.gno b/gnovm/tests/files/types/cmp_array_c.gno new file mode 100644 index 00000000000..f23ef6c9a78 --- /dev/null +++ b/gnovm/tests/files/types/cmp_array_c.gno @@ -0,0 +1,15 @@ +package main + +import "fmt" + +func main() { + a := [2][2][]int{{{1, 2}, {3, 4}}, {{5, 6}, {7, 8}}} + b := [2][2][]int{{{1, 2}, {3, 4}}, {{5, 6}, {7, 8}}} + c := [2][2][]int{{{5, 6}, {7, 8}}, {{1, 2}, {3, 4}}} + + fmt.Println("a == b:", a == b) + fmt.Println("a == c:", a == c) +} + +// Error: +// main/files/types/cmp_array_c.gno:10: [2][]int is not comparable diff --git a/gnovm/tests/files/types/cmp_array_d.gno b/gnovm/tests/files/types/cmp_array_d.gno new file mode 100644 index 00000000000..78f9527f819 --- /dev/null +++ b/gnovm/tests/files/types/cmp_array_d.gno @@ -0,0 +1,13 @@ +package main + +import "fmt" + +func main() { + a := [2]int{1, 2} + b := [2]int{1, 2} + + fmt.Println("a == b:", a == b) +} + +// Output: +// a == b: true diff --git a/gnovm/tests/files/types/cmp_poiner.gno b/gnovm/tests/files/types/cmp_poiner.gno new file mode 100644 index 00000000000..0d7625a878d --- /dev/null +++ b/gnovm/tests/files/types/cmp_poiner.gno @@ -0,0 +1,23 @@ +package main + +import "fmt" + +// Define a Person struct +type Person struct { + Name string + Age int +} + +type Worker string + +func main() { + // Create two pointers to Person instances + p1 := &Person{Name: "Alice", Age: 30} + p2 := Worker("a") + p2Ptr := &p2 + + fmt.Println("p1 == p2:", p1 == p2Ptr) +} + +// Error: +// main/files/types/cmp_poiner.gno:19: cannot use main.Person as main.Worker without explicit conversion diff --git a/gnovm/tests/files/types/cmp_poiner2.gno b/gnovm/tests/files/types/cmp_poiner2.gno new file mode 100644 index 00000000000..6899803075f --- /dev/null +++ b/gnovm/tests/files/types/cmp_poiner2.gno @@ -0,0 +1,10 @@ +package main + +func main() { + a := []int{1, 2} + b := []int{1, 2} + println(&a == &b) +} + +// Output: +// false diff --git a/gnovm/tests/files/types/cmp_struct.gno b/gnovm/tests/files/types/cmp_struct.gno new file mode 100644 index 00000000000..c3ead1510a4 --- /dev/null +++ b/gnovm/tests/files/types/cmp_struct.gno @@ -0,0 +1,23 @@ +package main + +import "fmt" + +// Define a struct that contains an array field +type Matrix struct { + data [2]int +} + +func main() { + // Create two instances of the struct + m1 := Matrix{data: [2]int{1, 2}} + m2 := Matrix{data: [2]int{1, 2}} + m3 := Matrix{data: [2]int{3, 4}} + + // Compare the instances + fmt.Println("m1 == m2:", m1 == m2) // True because the data fields are identical + fmt.Println("m1 == m3:", m1 == m3) // False because the data fields are different +} + +// Output: +// m1 == m2: true +// m1 == m3: false diff --git a/gnovm/tests/files/types/cmp_struct_a.gno b/gnovm/tests/files/types/cmp_struct_a.gno new file mode 100644 index 00000000000..5e8add9f1d6 --- /dev/null +++ b/gnovm/tests/files/types/cmp_struct_a.gno @@ -0,0 +1,20 @@ +package main + +import "fmt" + +// Define a struct that wraps the three-dimensional data structure +type Matrix struct { + data [2][2][]int +} + +func main() { + a := Matrix{data: [2][2][]int{{{1, 2}, {3, 4}}, {{5, 6}, {7, 8}}}} + b := Matrix{data: [2][2][]int{{{1, 2}, {3, 4}}, {{5, 6}, {7, 8}}}} + c := Matrix{data: [2][2][]int{{{5, 6}, {7, 8}}, {{1, 2}, {3, 4}}}} + + fmt.Println("a == b:", a == b) + fmt.Println("a == c:", a == c) +} + +// Error: +// main/files/types/cmp_struct_a.gno:15: [2][]int is not comparable diff --git a/gnovm/tests/files/types/cmp_struct_b.gno b/gnovm/tests/files/types/cmp_struct_b.gno new file mode 100644 index 00000000000..f767fec16d5 --- /dev/null +++ b/gnovm/tests/files/types/cmp_struct_b.gno @@ -0,0 +1,19 @@ +package main + +type foo struct { + a int +} + +type bar struct { + b int +} + +func main() { + fa := foo{} + bb := bar{} + + println(fa == bb) +} + +// Error: +// main/files/types/cmp_struct_b.gno:15: cannot use main.foo as main.bar without explicit conversion diff --git a/gnovm/tests/files/types/cmp_struct_c.gno b/gnovm/tests/files/types/cmp_struct_c.gno new file mode 100644 index 00000000000..4894e32d0e5 --- /dev/null +++ b/gnovm/tests/files/types/cmp_struct_c.gno @@ -0,0 +1,19 @@ +package main + +type foo struct { + a int +} + +type bar struct { + b []int +} + +func main() { + fa := foo{} + bb := bar{} + + println(fa == bb) +} + +// Error: +// main/files/types/cmp_struct_c.gno:15: main.bar is not comparable \ No newline at end of file diff --git a/gnovm/tests/files/types/cmp_struct_c1.gno b/gnovm/tests/files/types/cmp_struct_c1.gno new file mode 100644 index 00000000000..3cb4b835dcd --- /dev/null +++ b/gnovm/tests/files/types/cmp_struct_c1.gno @@ -0,0 +1,19 @@ +package main + +type foo struct { + a int +} + +type bar struct { + b []int +} + +func main() { + fa := foo{} + bb := bar{} + + println(bb == fa) +} + +// Error: +// main/files/types/cmp_struct_c1.gno:15: cannot use main.bar as main.foo without explicit conversion diff --git a/gnovm/tests/files/types/cmp_struct_d.gno b/gnovm/tests/files/types/cmp_struct_d.gno new file mode 100644 index 00000000000..4c2f6eb848f --- /dev/null +++ b/gnovm/tests/files/types/cmp_struct_d.gno @@ -0,0 +1,19 @@ +package main + +type foo struct { + a []int +} + +type bar struct { + b []int +} + +func main() { + fa := foo{} + bb := bar{} + + println(fa == bb) +} + +// Error: +// main/files/types/cmp_struct_d.gno:15: main.bar is not comparable diff --git a/gnovm/tests/files/types/cmp_struct_e.gno b/gnovm/tests/files/types/cmp_struct_e.gno new file mode 100644 index 00000000000..4640c0e4252 --- /dev/null +++ b/gnovm/tests/files/types/cmp_struct_e.gno @@ -0,0 +1,15 @@ +package main + +type foo struct { + a []int +} + +func main() { + fa := foo{} + fb := foo{} + + println(fa == fb) +} + +// Error: +// main/files/types/cmp_struct_e.gno:11: main.foo is not comparable diff --git a/gnovm/tests/files/types/cmp_struct_f.gno b/gnovm/tests/files/types/cmp_struct_f.gno new file mode 100644 index 00000000000..20366b625e9 --- /dev/null +++ b/gnovm/tests/files/types/cmp_struct_f.gno @@ -0,0 +1,43 @@ +package main + +import "fmt" + +// Define a Person struct +type Person struct { + Name string + Age int +} + +// Define an Employee struct that embeds Person +type Employee struct { + Person + Department string + ID int +} + +func main() { + emp1 := Employee{ + Person: Person{Name: "John Doe", Age: 30}, + Department: "Engineering", + ID: 12345, + } + + emp2 := Employee{ + Person: Person{Name: "John Doe", Age: 30}, + Department: "Engineering", + ID: 12345, + } + + emp3 := Employee{ + Person: Person{Name: "Jane Doe", Age: 29}, + Department: "Marketing", + ID: 67890, + } + + fmt.Println("emp1 == emp2:", emp1 == emp2) // True because all fields match + fmt.Println("emp1 == emp3:", emp1 == emp3) // False because some fields differ +} + +// Output: +// emp1 == emp2: true +// emp1 == emp3: false diff --git a/gnovm/tests/files/types/cmp_struct_g.gno b/gnovm/tests/files/types/cmp_struct_g.gno new file mode 100644 index 00000000000..05224000f05 --- /dev/null +++ b/gnovm/tests/files/types/cmp_struct_g.gno @@ -0,0 +1,21 @@ +package main + +import "fmt" + +type Person struct { + age int +} + +type Dog struct { + age int +} + +func main() { + a := Person{} + b := Dog{} + + fmt.Println("a == b:", a == b) +} + +// Error: +// main/files/types/cmp_struct_g.gno:17: cannot use main.Person as main.Dog without explicit conversion diff --git a/gnovm/tests/files/types/eql_0a0.gno b/gnovm/tests/files/types/eql_0a0.gno new file mode 100644 index 00000000000..32e5473b34f --- /dev/null +++ b/gnovm/tests/files/types/eql_0a0.gno @@ -0,0 +1,9 @@ +package main + +// both typed(different) const +func main() { + println(int(1) == int8(1)) +} + +// Error: +// main/files/types/eql_0a0.gno:5: cannot use int as int8 diff --git a/gnovm/tests/files/types/eql_0a01.gno b/gnovm/tests/files/types/eql_0a01.gno new file mode 100644 index 00000000000..e5cdeff4b63 --- /dev/null +++ b/gnovm/tests/files/types/eql_0a01.gno @@ -0,0 +1,8 @@ +package main + +func main() { + println(nil == nil) // xt: , dt: +} + +// Error: +// main/files/types/eql_0a01.gno:4: is not comparable diff --git a/gnovm/tests/files/types/eql_0a02.gno b/gnovm/tests/files/types/eql_0a02.gno new file mode 100644 index 00000000000..67116da6cc8 --- /dev/null +++ b/gnovm/tests/files/types/eql_0a02.gno @@ -0,0 +1,11 @@ +package main + +func main() { + intPtr := new(int) + *intPtr = 5 + s := "hello" + println(intPtr == s) +} + +// Error: +// main/files/types/eql_0a02.gno:7: cannot use *int as string diff --git a/gnovm/tests/files/types/eql_0a03.gno b/gnovm/tests/files/types/eql_0a03.gno new file mode 100644 index 00000000000..677493a9af6 --- /dev/null +++ b/gnovm/tests/files/types/eql_0a03.gno @@ -0,0 +1,12 @@ +package main + +func main() { + intPtr := new(int8) + *intPtr = 5 + + i := 0 + println(intPtr == &i) +} + +// Error: +// main/files/types/eql_0a03.gno:8: cannot use int8 as int diff --git a/gnovm/tests/files/types/eql_0a1.gno b/gnovm/tests/files/types/eql_0a1.gno new file mode 100644 index 00000000000..9641e67c90a --- /dev/null +++ b/gnovm/tests/files/types/eql_0a1.gno @@ -0,0 +1,9 @@ +package main + +// both typed(different) const +func main() { + println(int(1) != int8(1)) +} + +// Error: +// main/files/types/eql_0a1.gno:5: cannot use int as int8 diff --git a/gnovm/tests/files/types/eql_0a1a.gno b/gnovm/tests/files/types/eql_0a1a.gno new file mode 100644 index 00000000000..deb369511fd --- /dev/null +++ b/gnovm/tests/files/types/eql_0a1a.gno @@ -0,0 +1,11 @@ +package main + +// left typed, right untyped +func main() { + println(int(1) == 1) + println(int(1) != 1) +} + +// Output: +// true +// false diff --git a/gnovm/tests/files/types/eql_0a1a0.gno b/gnovm/tests/files/types/eql_0a1a0.gno new file mode 100644 index 00000000000..e251174adef --- /dev/null +++ b/gnovm/tests/files/types/eql_0a1a0.gno @@ -0,0 +1,9 @@ +package main + +func main() { + a := uint(1) + println(uint64(1) == a) +} + +// Error: +// main/files/types/eql_0a1a0.gno:5: cannot use uint64 as uint diff --git a/gnovm/tests/files/types/eql_0a1a1.gno b/gnovm/tests/files/types/eql_0a1a1.gno new file mode 100644 index 00000000000..0af8aa45943 --- /dev/null +++ b/gnovm/tests/files/types/eql_0a1a1.gno @@ -0,0 +1,9 @@ +package main + +func main() { + a := uint(1) + println(a == uint64(1)) +} + +// Error: +// main/files/types/eql_0a1a1.gno:5: cannot use uint as uint64 diff --git a/gnovm/tests/files/types/eql_0a1b.gno b/gnovm/tests/files/types/eql_0a1b.gno new file mode 100644 index 00000000000..1db537a4d8c --- /dev/null +++ b/gnovm/tests/files/types/eql_0a1b.gno @@ -0,0 +1,20 @@ +package main + +type S struct { + expected string +} + +// special case when RHS is result of slice operation, its type is determined in runtime +func main() { + s := S{ + expected: `hello`[:], // this is not converted + } + + a := "hello" + + println(a == s.expected) + +} + +// Output: +// true diff --git a/gnovm/tests/files/types/eql_0a1c.gno b/gnovm/tests/files/types/eql_0a1c.gno new file mode 100644 index 00000000000..76f2db8d7d8 --- /dev/null +++ b/gnovm/tests/files/types/eql_0a1c.gno @@ -0,0 +1,10 @@ +package main + +func main() { + expected := `hello`[:] + a := "hello" + println(a == expected) +} + +// Output: +// true diff --git a/gnovm/tests/files/types/eql_0a1d.gno b/gnovm/tests/files/types/eql_0a1d.gno new file mode 100644 index 00000000000..018d53fa81a --- /dev/null +++ b/gnovm/tests/files/types/eql_0a1d.gno @@ -0,0 +1,14 @@ +package main + +type S struct { + expected string +} + +func main() { + println("hello" == S{ + expected: `hello`[:], + }.expected) +} + +// Output: +// true diff --git a/gnovm/tests/files/types/eql_0a1e.gno b/gnovm/tests/files/types/eql_0a1e.gno new file mode 100644 index 00000000000..2795d618e91 --- /dev/null +++ b/gnovm/tests/files/types/eql_0a1e.gno @@ -0,0 +1,16 @@ +package main + +type S struct { + expected string +} + +func main() { + var s = S{ + expected: `hello`[:], + } + a := "hello" + println(a == s.expected) +} + +// Output: +// true diff --git a/gnovm/tests/files/types/eql_0a1f.gno b/gnovm/tests/files/types/eql_0a1f.gno new file mode 100644 index 00000000000..fda84dcdff8 --- /dev/null +++ b/gnovm/tests/files/types/eql_0a1f.gno @@ -0,0 +1,10 @@ +package main + +func main() { + expected := `hello`[:] + a := 1 + println(a == expected) // both typed +} + +// Error: +// main/files/types/eql_0a1f.gno:6: cannot use int as string diff --git a/gnovm/tests/files/types/eql_0a1g.gno b/gnovm/tests/files/types/eql_0a1g.gno new file mode 100644 index 00000000000..d80b6e0c9ac --- /dev/null +++ b/gnovm/tests/files/types/eql_0a1g.gno @@ -0,0 +1,10 @@ +package main + +func main() { + var a int = 1 + var b float32 = 1.0 + println(a == b) // both typed +} + +// Error: +// main/files/types/eql_0a1g.gno:6: cannot use int as float32 diff --git a/gnovm/tests/files/types/eql_0a2.gno b/gnovm/tests/files/types/eql_0a2.gno new file mode 100644 index 00000000000..281a61e50eb --- /dev/null +++ b/gnovm/tests/files/types/eql_0a2.gno @@ -0,0 +1,25 @@ +package main + +import ( + "strconv" +) + +type Error1 int64 + +func (e Error1) Error() string { + return "error: " + strconv.Itoa(int(e)) +} + +type Error2 int + +func (e Error2) Error() string { + return "error: " + strconv.Itoa(int(e)) +} + +// both typed(different) const +func main() { + println(Error1(0) == Error2(0)) +} + +// Error: +// main/files/types/eql_0a2.gno:21: cannot use main.Error1 as main.Error2 without explicit conversion diff --git a/gnovm/tests/files/types/eql_0a3.gno b/gnovm/tests/files/types/eql_0a3.gno new file mode 100644 index 00000000000..198a65b0827 --- /dev/null +++ b/gnovm/tests/files/types/eql_0a3.gno @@ -0,0 +1,25 @@ +package main + +import ( + "strconv" +) + +type Error1 int64 + +func (e Error1) Error() string { + return "error: " + strconv.Itoa(int(e)) +} + +type Error2 int + +func (e Error2) Error() string { + return "error: " + strconv.Itoa(int(e)) +} + +// both typed(different) const +func main() { + println(Error1(0) != Error2(0)) +} + +// Error: +// main/files/types/eql_0a3.gno:21: cannot use main.Error1 as main.Error2 without explicit conversion diff --git a/gnovm/tests/files/types/eql_0a4.gno b/gnovm/tests/files/types/eql_0a4.gno new file mode 100644 index 00000000000..d2c859edd09 --- /dev/null +++ b/gnovm/tests/files/types/eql_0a4.gno @@ -0,0 +1,25 @@ +package main + +import ( + "strconv" +) + +type Error1 int64 + +func (e Error1) Error() string { + return "error: " + strconv.Itoa(int(e)) +} + +type Error2 int + +func (e Error2) Error() string { + return "error: " + strconv.Itoa(int(e)) +} + +// both typed(different) const +func main() { + println(Error1(0) != Error2(0)) +} + +// Error: +// main/files/types/eql_0a4.gno:21: cannot use main.Error1 as main.Error2 without explicit conversion diff --git a/gnovm/tests/files/types/eql_0b0.gno b/gnovm/tests/files/types/eql_0b0.gno new file mode 100644 index 00000000000..2c968b5158f --- /dev/null +++ b/gnovm/tests/files/types/eql_0b0.gno @@ -0,0 +1,24 @@ +package main + +import ( + "strconv" +) + +type Error int8 + +func (e Error) Error() string { + return "error: " + strconv.Itoa(int(e)) +} + +// left is untyped const, right is typed const +// left is assignable to right +func main() { + if 1 == Error(1) { + println("what the firetruck?") + } else { + println("something else") + } +} + +// Output: +// what the firetruck? diff --git a/gnovm/tests/files/types/eql_0b1.gno b/gnovm/tests/files/types/eql_0b1.gno new file mode 100644 index 00000000000..a7bdf5275da --- /dev/null +++ b/gnovm/tests/files/types/eql_0b1.gno @@ -0,0 +1,23 @@ +package main + +import ( + "strconv" +) + +type Error int8 + +func (e Error) Error() string { + return "error: " + strconv.Itoa(int(e)) +} + +// left is untyped const, right is typed const +func main() { + if 1 != Error(1) { + println("what the firetruck?") + } else { + println("something else") + } +} + +// Output: +// something else diff --git a/gnovm/tests/files/types/eql_0b2.gno b/gnovm/tests/files/types/eql_0b2.gno new file mode 100644 index 00000000000..51981348a6e --- /dev/null +++ b/gnovm/tests/files/types/eql_0b2.gno @@ -0,0 +1,22 @@ +package main + +type Error string + +func (e Error) Error() string { + return "error: " + string(e) +} + +// left is untyped const, right is typed const +// left is not assignable to right +// a) it's (untyped) bigint +// b) base type of right is string +func main() { + if 1 == Error(1) { + println("what the firetruck?") + } else { + println("something else") + } +} + +// Error: +// main/files/types/eql_0b2.gno:14: cannot use untyped Bigint as StringKind diff --git a/gnovm/tests/files/types/eql_0b3.gno b/gnovm/tests/files/types/eql_0b3.gno new file mode 100644 index 00000000000..34c8a24cba2 --- /dev/null +++ b/gnovm/tests/files/types/eql_0b3.gno @@ -0,0 +1,15 @@ +package main + +var a int8 + +func main() { + a = 1 + if 1 == a { + println("what the firetruck?") + } else { + println("something else") + } +} + +// Output: +// what the firetruck? diff --git a/gnovm/tests/files/types/eql_0b4_native.gno b/gnovm/tests/files/types/eql_0b4_native.gno new file mode 100644 index 00000000000..b78d5f9be73 --- /dev/null +++ b/gnovm/tests/files/types/eql_0b4_native.gno @@ -0,0 +1,13 @@ +package main + +import ( + "errors" +) + +func main() { + errCmp := errors.New("xxx") + println(5 == errCmp) +} + +// Error: +// main/files/types/eql_0b4_native.gno:9: unexpected type pair: cannot use bigint as gonative{error} diff --git a/gnovm/tests/files/types/eql_0b4_stdlibs.gno b/gnovm/tests/files/types/eql_0b4_stdlibs.gno new file mode 100644 index 00000000000..de36f025f34 --- /dev/null +++ b/gnovm/tests/files/types/eql_0b4_stdlibs.gno @@ -0,0 +1,13 @@ +package main + +import ( + "errors" +) + +func main() { + errCmp := errors.New("xxx") + println(5 == errCmp) +} + +// Error: +// main/files/types/eql_0b4_stdlibs.gno:9: bigint does not implement .uverse.error diff --git a/gnovm/tests/files/types/eql_0c2.gno b/gnovm/tests/files/types/eql_0c2.gno new file mode 100644 index 00000000000..6ac4a2799ab --- /dev/null +++ b/gnovm/tests/files/types/eql_0c2.gno @@ -0,0 +1,24 @@ +package main + +import ( + "strconv" +) + +type Error int8 + +func (e Error) Error() string { + return "error: " + strconv.Itoa(int(e)) +} + +// left is typed const, right is untyped const +// NOTE: overflow +func main() { + if Error(1) == 128 { // note, this would overflow as expected + println("what the firetruck?") + } else { + println("something else") + } +} + +// Error: +// main/files/types/eql_0c2.gno:16: bigint overflows target kind diff --git a/gnovm/tests/files/types/eql_0d0.gno b/gnovm/tests/files/types/eql_0d0.gno new file mode 100644 index 00000000000..6890d450bab --- /dev/null +++ b/gnovm/tests/files/types/eql_0d0.gno @@ -0,0 +1,13 @@ +package main + +// both untyped const +func main() { + println(1.0 == 1) + println(1.0 == 0) + println(float32(1.0) == 0) +} + +// Output: +// true +// false +// false diff --git a/gnovm/tests/files/types/eql_0e0.gno b/gnovm/tests/files/types/eql_0e0.gno new file mode 100644 index 00000000000..a1ab28d1932 --- /dev/null +++ b/gnovm/tests/files/types/eql_0e0.gno @@ -0,0 +1,27 @@ +package main + +import ( + "strconv" +) + +type Error1 int64 + +func (e Error1) Error() string { + return "error: " + strconv.Itoa(int(e)) +} + +type Error2 int + +func (e Error2) Error() string { + return "error: " + strconv.Itoa(int(e)) +} + +// both not const, typed +func main() { + var e1 Error1 = Error1(0) + var e2 Error2 = Error2(0) + println(e1 == e2) +} + +// Error: +// main/files/types/eql_0e0.gno:23: cannot use main.Error1 as main.Error2 without explicit conversion diff --git a/gnovm/tests/files/types/eql_0e1.gno b/gnovm/tests/files/types/eql_0e1.gno new file mode 100644 index 00000000000..798d4f04777 --- /dev/null +++ b/gnovm/tests/files/types/eql_0e1.gno @@ -0,0 +1,27 @@ +package main + +import ( + "strconv" +) + +type Error1 int64 + +func (e Error1) Error() string { + return "error: " + strconv.Itoa(int(e)) +} + +type Error2 int + +func (e Error2) Error() string { + return "error: " + strconv.Itoa(int(e)) +} + +// both not const, typed +func main() { + var e1 Error1 = Error1(0) + var e2 Error2 = Error2(0) + println(e1 != e2) +} + +// Error: +// main/files/types/eql_0e1.gno:23: cannot use main.Error1 as main.Error2 without explicit conversion diff --git a/gnovm/tests/files/types/eql_0f0_native.gno b/gnovm/tests/files/types/eql_0f0_native.gno new file mode 100644 index 00000000000..7db72819774 --- /dev/null +++ b/gnovm/tests/files/types/eql_0f0_native.gno @@ -0,0 +1,28 @@ +package main + +import ( + "errors" + "strconv" +) + +type Error int64 + +func (e Error) Error() string { + return "error: " + strconv.Itoa(int(e)) +} + +var errCmp = errors.New("XXXX") + +// special case: +// one is interface +func main() { + if 1 == errCmp { + //if errCmp == 1 { + println("what the firetruck?") + } else { + println("something else") + } +} + +// Error: +// main/files/types/eql_0f0_native.gno:19: unexpected type pair: cannot use bigint as gonative{error} diff --git a/gnovm/tests/files/types/eql_0f0_stdlibs.gno b/gnovm/tests/files/types/eql_0f0_stdlibs.gno new file mode 100644 index 00000000000..39a7ac68490 --- /dev/null +++ b/gnovm/tests/files/types/eql_0f0_stdlibs.gno @@ -0,0 +1,28 @@ +package main + +import ( + "errors" + "strconv" +) + +type Error int64 + +func (e Error) Error() string { + return "error: " + strconv.Itoa(int(e)) +} + +var errCmp = errors.New("XXXX") + +// special case: +// one is interface +func main() { + if 1 == errCmp { + //if errCmp == 1 { + println("what the firetruck?") + } else { + println("something else") + } +} + +// Error: +// main/files/types/eql_0f0_stdlibs.gno:19: bigint does not implement .uverse.error diff --git a/gnovm/tests/files/types/eql_0f12.gno b/gnovm/tests/files/types/eql_0f12.gno new file mode 100644 index 00000000000..751852d0b70 --- /dev/null +++ b/gnovm/tests/files/types/eql_0f12.gno @@ -0,0 +1,13 @@ +package main + +var a [2]string +var b [2]string + +func main() { + a = [2]string{"hello", "world"} + b = [2]string{"hello", "world"} + println(a == b) +} + +// Output: +// true diff --git a/gnovm/tests/files/types/eql_0f14.gno b/gnovm/tests/files/types/eql_0f14.gno new file mode 100644 index 00000000000..500157d7303 --- /dev/null +++ b/gnovm/tests/files/types/eql_0f14.gno @@ -0,0 +1,14 @@ +package main + +var a [2]string +var c [2]int + +// TODO: should stop at comparable check +func main() { + a = [2]string{"hello", "world"} + c = [2]int{1, 2} + println(a == c) +} + +// Error: +// main/files/types/eql_0f14.gno:10: cannot use [2]string as [2]int diff --git a/gnovm/tests/files/types/eql_0f15.gno b/gnovm/tests/files/types/eql_0f15.gno new file mode 100644 index 00000000000..36077127332 --- /dev/null +++ b/gnovm/tests/files/types/eql_0f15.gno @@ -0,0 +1,17 @@ +package main + +var a [2]interface{} +var c [2]interface{} + +func gen() interface{} { + return 1 +} + +func main() { + a = [2]interface{}{gen(), gen()} + c = [2]interface{}{gen(), gen()} + println(a == c) +} + +// Output: +// true diff --git a/gnovm/tests/files/types/eql_0f16.gno b/gnovm/tests/files/types/eql_0f16.gno new file mode 100644 index 00000000000..ae0d8f45ab6 --- /dev/null +++ b/gnovm/tests/files/types/eql_0f16.gno @@ -0,0 +1,20 @@ +package main + +type word []int + +var a [2]word +var c [2]word + +func gen() word { + return []int{1} +} + +// TODO: consider log desc +func main() { + a = [2]word{gen(), gen()} + c = [2]word{gen(), gen()} + println(a == c) +} + +// Error: +// main/files/types/eql_0f16.gno:16: [2]main.word is not comparable diff --git a/gnovm/tests/files/types/eql_0f17.gno b/gnovm/tests/files/types/eql_0f17.gno new file mode 100644 index 00000000000..d60d474f668 --- /dev/null +++ b/gnovm/tests/files/types/eql_0f17.gno @@ -0,0 +1,13 @@ +package main + +type f func() bool + +var a f = func() bool { return true } +var b f = func() bool { return false } + +func main() { + println(a == b) +} + +// Error: +// main/files/types/eql_0f17.gno:9: main.f can only be compared to nil diff --git a/gnovm/tests/files/types/eql_0f18.gno b/gnovm/tests/files/types/eql_0f18.gno new file mode 100644 index 00000000000..ad534066fd1 --- /dev/null +++ b/gnovm/tests/files/types/eql_0f18.gno @@ -0,0 +1,12 @@ +package main + +type f func() bool + +var a f = func() bool { return true } + +func main() { + println(a == nil) +} + +// Output: +// false diff --git a/gnovm/tests/files/types/eql_0f19.gno b/gnovm/tests/files/types/eql_0f19.gno new file mode 100644 index 00000000000..8b08d616a06 --- /dev/null +++ b/gnovm/tests/files/types/eql_0f19.gno @@ -0,0 +1,12 @@ +package main + +type f func() bool + +var a f + +func main() { + println(a == nil) +} + +// Output: +// true diff --git a/gnovm/tests/files/types/eql_0f1_stdlibs.gno b/gnovm/tests/files/types/eql_0f1_stdlibs.gno new file mode 100644 index 00000000000..e0b8ec5c753 --- /dev/null +++ b/gnovm/tests/files/types/eql_0f1_stdlibs.gno @@ -0,0 +1,28 @@ +package main + +import ( + "errors" + "strconv" +) + +type Error int64 + +func (e Error) Error() string { + return "error: " + strconv.Itoa(int(e)) +} + +var errCmp = errors.New("XXXX") + +// specil case: +// one is interface +func main() { + if int64(1) == errCmp { + //if errCmp == 1 { + println("what the firetruck?") + } else { + println("something else") + } +} + +// Error: +// main/files/types/eql_0f1_stdlibs.gno:19: int64 does not implement .uverse.error diff --git a/gnovm/tests/files/types/eql_0f20.gno b/gnovm/tests/files/types/eql_0f20.gno new file mode 100644 index 00000000000..f0e2e93ffc9 --- /dev/null +++ b/gnovm/tests/files/types/eql_0f20.gno @@ -0,0 +1,13 @@ +package main + +type f func() bool + +// slice would be comparable +var a [2]f + +func main() { + println(a == nil) // rcx.T == nil +} + +// Error: +// main/files/types/eql_0f20.gno:9: [2]main.f is not comparable diff --git a/gnovm/tests/files/types/eql_0f21.gno b/gnovm/tests/files/types/eql_0f21.gno new file mode 100644 index 00000000000..20b52988a8d --- /dev/null +++ b/gnovm/tests/files/types/eql_0f21.gno @@ -0,0 +1,13 @@ +package main + +type f func() bool + +var a [2]f +var b [2]f + +func main() { + println(a == b) +} + +// Error: +// main/files/types/eql_0f21.gno:9: [2]main.f is not comparable diff --git a/gnovm/tests/files/types/eql_0f21a.gno b/gnovm/tests/files/types/eql_0f21a.gno new file mode 100644 index 00000000000..075149d264f --- /dev/null +++ b/gnovm/tests/files/types/eql_0f21a.gno @@ -0,0 +1,13 @@ +package main + +type f func() bool + +var a [2]*f +var b [2]*f + +func main() { + println(a == b) +} + +// Output: +// true diff --git a/gnovm/tests/files/types/eql_0f22.gno b/gnovm/tests/files/types/eql_0f22.gno new file mode 100644 index 00000000000..75891def307 --- /dev/null +++ b/gnovm/tests/files/types/eql_0f22.gno @@ -0,0 +1,11 @@ +package main + +var a int = 0 +var b int = 1 + +func main() { + println(&a == &b) +} + +// Output: +// false diff --git a/gnovm/tests/files/types/eql_0f23.gno b/gnovm/tests/files/types/eql_0f23.gno new file mode 100644 index 00000000000..55f2ab5189d --- /dev/null +++ b/gnovm/tests/files/types/eql_0f23.gno @@ -0,0 +1,13 @@ +package main + +var a int = 0 +var b int = 1 + +func main() { + c := &a + d := &b + println(*c == *d) +} + +// Output: +// false diff --git a/gnovm/tests/files/types/eql_0f24.gno b/gnovm/tests/files/types/eql_0f24.gno new file mode 100644 index 00000000000..d01a9d4a14a --- /dev/null +++ b/gnovm/tests/files/types/eql_0f24.gno @@ -0,0 +1,13 @@ +package main + +var a int = 0 +var b int = 0 + +func main() { + c := &a + d := &b + println(*c == *d) +} + +// Output: +// true diff --git a/gnovm/tests/files/types/eql_0f25.gno b/gnovm/tests/files/types/eql_0f25.gno new file mode 100644 index 00000000000..8a3343146b0 --- /dev/null +++ b/gnovm/tests/files/types/eql_0f25.gno @@ -0,0 +1,19 @@ +package main + +var a int = 0 +var b int = 0 + +func main() { + c := &a + d := &b + println(*c > *d) + println(*c >= *d) + println(*c < *d) + println(*c <= *d) +} + +// Output: +// false +// true +// false +// true diff --git a/gnovm/tests/files/types/eql_0f27_stdlibs.gno b/gnovm/tests/files/types/eql_0f27_stdlibs.gno new file mode 100644 index 00000000000..2bee791279a --- /dev/null +++ b/gnovm/tests/files/types/eql_0f27_stdlibs.gno @@ -0,0 +1,21 @@ +package main + +import ( + "errors" +) + +var errCmp1 = errors.New("XXXX") +var errCmp2 = errors.New("XXXX") + +// specil case: +// one is interface +func main() { + if errCmp1 > errCmp2 { + println("what the firetruck?") + } else { + println("something else") + } +} + +// Error: +// main/files/types/eql_0f27_stdlibs.gno:13: operator > not defined on: InterfaceKind diff --git a/gnovm/tests/files/types/eql_0f28.gno b/gnovm/tests/files/types/eql_0f28.gno new file mode 100644 index 00000000000..64f973cdde0 --- /dev/null +++ b/gnovm/tests/files/types/eql_0f28.gno @@ -0,0 +1,31 @@ +package main + +import ( + "strconv" +) + +type E interface { + Error() string +} + +type Error1 int64 + +func (e Error1) Error() string { + return "error: " + strconv.Itoa(int(e)) +} + +type Error2 int + +func (e Error2) Error() string { + return "error: " + strconv.Itoa(int(e)) +} + +// both not const, and both interface +func main() { + var e1 E = Error1(0) + var e2 E = Error2(0) + println(e1 > e2) +} + +// Error: +// main/files/types/eql_0f28.gno:27: operator > not defined on: InterfaceKind diff --git a/gnovm/tests/files/types/eql_0f29.gno b/gnovm/tests/files/types/eql_0f29.gno new file mode 100644 index 00000000000..b5d1e897b89 --- /dev/null +++ b/gnovm/tests/files/types/eql_0f29.gno @@ -0,0 +1,24 @@ +package main + +import ( + "strconv" +) + +type Error int64 + +func (e Error) Error() string { + return "error: " + strconv.Itoa(int(e)) +} + +// both not const, and both interface +func main() { + var l interface{} + if l > Error(0) { + println("what the firetruck?") + } else { + println("something else") + } +} + +// Error: +// main/files/types/eql_0f29.gno:16: operator > not defined on: InterfaceKind diff --git a/gnovm/tests/files/types/eql_0f2b_native.gno b/gnovm/tests/files/types/eql_0f2b_native.gno new file mode 100644 index 00000000000..fe961441328 --- /dev/null +++ b/gnovm/tests/files/types/eql_0f2b_native.gno @@ -0,0 +1,28 @@ +package main + +import ( + "errors" + "strconv" +) + +type Error int64 + +func (e Error) Error() string { + return "error: " + strconv.Itoa(int(e)) +} + +var errCmp = errors.New("XXXX") + +// special case: +// one is interface +func main() { + if Error(0) <= errCmp { + //if errCmp == 1 { + println("what the firetruck?") + } else { + println("something else") + } +} + +// Error: +// main/files/types/eql_0f2b_native.gno:19: operator <= not defined on: InterfaceKind diff --git a/gnovm/tests/files/types/eql_0f2b_stdlibs.gno b/gnovm/tests/files/types/eql_0f2b_stdlibs.gno new file mode 100644 index 00000000000..20de4b5b104 --- /dev/null +++ b/gnovm/tests/files/types/eql_0f2b_stdlibs.gno @@ -0,0 +1,28 @@ +package main + +import ( + "errors" + "strconv" +) + +type Error int64 + +func (e Error) Error() string { + return "error: " + strconv.Itoa(int(e)) +} + +var errCmp = errors.New("XXXX") + +// special case: +// one is interface +func main() { + if Error(0) <= errCmp { + //if errCmp == 1 { + println("what the firetruck?") + } else { + println("something else") + } +} + +// Error: +// main/files/types/eql_0f2b_stdlibs.gno:19: operator <= not defined on: InterfaceKind diff --git a/gnovm/tests/files/types/eql_0f2c_native.gno b/gnovm/tests/files/types/eql_0f2c_native.gno new file mode 100644 index 00000000000..c17c757b760 --- /dev/null +++ b/gnovm/tests/files/types/eql_0f2c_native.gno @@ -0,0 +1,28 @@ +package main + +import ( + "errors" + "strconv" +) + +type Error int64 + +func (e Error) Error() string { + return "error: " + strconv.Itoa(int(e)) +} + +var errCmp = errors.New("XXXX") + +// special case: +// one is interface +func main() { + if Error(0) < errCmp { + //if errCmp == 1 { + println("what the firetruck?") + } else { + println("something else") + } +} + +// Error: +// main/files/types/eql_0f2c_native.gno:19: operator < not defined on: InterfaceKind diff --git a/gnovm/tests/files/types/eql_0f2c_stdlibs.gno b/gnovm/tests/files/types/eql_0f2c_stdlibs.gno new file mode 100644 index 00000000000..f8da518f4a9 --- /dev/null +++ b/gnovm/tests/files/types/eql_0f2c_stdlibs.gno @@ -0,0 +1,28 @@ +package main + +import ( + "errors" + "strconv" +) + +type Error int64 + +func (e Error) Error() string { + return "error: " + strconv.Itoa(int(e)) +} + +var errCmp = errors.New("XXXX") + +// special case: +// one is interface +func main() { + if Error(0) < errCmp { + //if errCmp == 1 { + println("what the firetruck?") + } else { + println("something else") + } +} + +// Error: +// main/files/types/eql_0f2c_stdlibs.gno:19: operator < not defined on: InterfaceKind diff --git a/gnovm/tests/files/types/eql_0f2d.gno b/gnovm/tests/files/types/eql_0f2d.gno new file mode 100644 index 00000000000..5ad121f515b --- /dev/null +++ b/gnovm/tests/files/types/eql_0f2d.gno @@ -0,0 +1,32 @@ +package main + +import ( + "fmt" + "strconv" +) + +type E interface { + Error() string +} +type Error int64 + +func (e Error) Error() string { + return "error: " + strconv.Itoa(int(e)) +} + +// special case: +// one is interface +func main() { + var e0 E + e0 = Error(0) + fmt.Printf("%T \n", e0) + if e0 == Error(0) { + println("what the firetruck?") + } else { + println("something else") + } +} + +// Output: +// int64 +// what the firetruck? diff --git a/gnovm/tests/files/types/eql_0f2e.gno b/gnovm/tests/files/types/eql_0f2e.gno new file mode 100644 index 00000000000..ea03028f5e1 --- /dev/null +++ b/gnovm/tests/files/types/eql_0f2e.gno @@ -0,0 +1,32 @@ +package main + +import ( + "fmt" + "strconv" +) + +type E interface { + Error() string +} +type Error int64 + +func (e Error) Error() string { + return "error: " + strconv.Itoa(int(e)) +} + +// special case: +// one is interface +func main() { + var e0 E + e0 = Error(0) + fmt.Printf("%T \n", e0) + if Error(0) == e0 { + println("what the firetruck?") + } else { + println("something else") + } +} + +// Output: +// int64 +// what the firetruck? diff --git a/gnovm/tests/files/types/eql_0f30.gno b/gnovm/tests/files/types/eql_0f30.gno new file mode 100644 index 00000000000..0a9a61a96cf --- /dev/null +++ b/gnovm/tests/files/types/eql_0f30.gno @@ -0,0 +1,9 @@ +package main + +// both not const, and both interface +func main() { + println([]byte("a") == []byte("b")) +} + +// Error: +// main/files/types/eql_0f30.gno:5: []uint8 can only be compared to nil diff --git a/gnovm/tests/files/types/eql_0f30a.gno b/gnovm/tests/files/types/eql_0f30a.gno new file mode 100644 index 00000000000..2dadbd9d6d3 --- /dev/null +++ b/gnovm/tests/files/types/eql_0f30a.gno @@ -0,0 +1,8 @@ +package main + +func main() { + println(map[string]int{"a": 1} == map[string]int{"b": 2}) +} + +// Error: +// main/files/types/eql_0f30a.gno:4: map[string]int can only be compared to nil diff --git a/gnovm/tests/files/types/eql_0f30b.gno b/gnovm/tests/files/types/eql_0f30b.gno new file mode 100644 index 00000000000..2e7a463fddd --- /dev/null +++ b/gnovm/tests/files/types/eql_0f30b.gno @@ -0,0 +1,13 @@ +package main + +type f func() + +var f1 f +var f2 f + +func main() { + println(f1 == f2) +} + +// Error: +// main/files/types/eql_0f30b.gno:9: main.f can only be compared to nil diff --git a/gnovm/tests/files/types/eql_0f30c.gno b/gnovm/tests/files/types/eql_0f30c.gno new file mode 100644 index 00000000000..ffa8c7c96e7 --- /dev/null +++ b/gnovm/tests/files/types/eql_0f30c.gno @@ -0,0 +1,10 @@ +package main + +var f1 func() + +func main() { + println(f1 == nil) +} + +// Output: +// true diff --git a/gnovm/tests/files/types/eql_0f30d.gno b/gnovm/tests/files/types/eql_0f30d.gno new file mode 100644 index 00000000000..8b0612f011b --- /dev/null +++ b/gnovm/tests/files/types/eql_0f30d.gno @@ -0,0 +1,8 @@ +package main + +func main() { + println([]int{1} == []int{1}) +} + +// Error: +// main/files/types/eql_0f30d.gno:4: []int can only be compared to nil diff --git a/gnovm/tests/files/types/eql_0f30e.gno b/gnovm/tests/files/types/eql_0f30e.gno new file mode 100644 index 00000000000..002910072c3 --- /dev/null +++ b/gnovm/tests/files/types/eql_0f30e.gno @@ -0,0 +1,8 @@ +package main + +func main() { + println([]int{1} == nil) +} + +// Output: +// false diff --git a/gnovm/tests/files/types/eql_0f30f.gno b/gnovm/tests/files/types/eql_0f30f.gno new file mode 100644 index 00000000000..880b081b6cd --- /dev/null +++ b/gnovm/tests/files/types/eql_0f30f.gno @@ -0,0 +1,11 @@ +package main + +var a = [2]int{1, 1} +var b = [3]int{1, 1} + +func main() { + println(a == b) +} + +// Error: +// main/files/types/eql_0f30f.gno:7: cannot use [2]int as [3]int diff --git a/gnovm/tests/files/types/eql_0f30g.gno b/gnovm/tests/files/types/eql_0f30g.gno new file mode 100644 index 00000000000..66135a83b62 --- /dev/null +++ b/gnovm/tests/files/types/eql_0f30g.gno @@ -0,0 +1,11 @@ +package main + +var a = [2]int{1, 1} +var b = []int{1, 1} + +func main() { + println(a == b) +} + +// Error: +// main/files/types/eql_0f30g.gno:7: []int can only be compared to nil diff --git a/gnovm/tests/files/types/eql_0f31.gno b/gnovm/tests/files/types/eql_0f31.gno new file mode 100644 index 00000000000..bcb62dc76c3 --- /dev/null +++ b/gnovm/tests/files/types/eql_0f31.gno @@ -0,0 +1,13 @@ +package main + +import "bytes" + +// both not const, and both interface +func main() { + // lv.T: * uint8, rv.T: * uint8 + cmp := bytes.Compare([]byte("a"), []byte("b")) + println(cmp) +} + +// Output: +// -1 diff --git a/gnovm/tests/files/types/eql_0f32.gno b/gnovm/tests/files/types/eql_0f32.gno new file mode 100644 index 00000000000..321824566cb --- /dev/null +++ b/gnovm/tests/files/types/eql_0f32.gno @@ -0,0 +1,8 @@ +package main + +func main() { + println([]byte("a") == nil) // lx: (const (slice[0x61] []uint8)), rx: (const (undefined)), cmp = 0 +} + +// Output: +// false diff --git a/gnovm/tests/files/types/eql_0f33.gno b/gnovm/tests/files/types/eql_0f33.gno new file mode 100644 index 00000000000..e7aac0cf069 --- /dev/null +++ b/gnovm/tests/files/types/eql_0f33.gno @@ -0,0 +1,49 @@ +package main + +import "fmt" + +// var f func() +var a *struct{} +var b interface{} +var c map[string]int +var s []int + +func main() { + if a == nil { + fmt.Println("pointer == nil") + } else { + println("not nil!") + } + fmt.Println("----") + + if b == nil { + fmt.Println("interface == nil") + } else { + println("not nil!") + } + fmt.Println("----") + + if c == nil { + fmt.Println("map == nil") + } else { + println("not nil!") + } + fmt.Println("----") + + if s == nil { + fmt.Println("slice == nil") + } else { + println("not nil!") + } + fmt.Println("----") +} + +// Output: +// pointer == nil +// ---- +// interface == nil +// ---- +// map == nil +// ---- +// slice == nil +// ---- diff --git a/gnovm/tests/files/types/eql_0f34.gno b/gnovm/tests/files/types/eql_0f34.gno new file mode 100644 index 00000000000..8b5d3830091 --- /dev/null +++ b/gnovm/tests/files/types/eql_0f34.gno @@ -0,0 +1,49 @@ +package main + +import "fmt" + +// var f func() +var a *struct{} +var b interface{} +var c map[string]int +var s []int + +func main() { + if nil == a { + fmt.Println("pointer == nil") + } else { + println("not nil!") + } + fmt.Println("----") + + if nil == b { + fmt.Println("interface == nil") + } else { + println("not nil!") + } + fmt.Println("----") + + if nil == c { + fmt.Println("map == nil") + } else { + println("not nil!") + } + fmt.Println("----") + + if nil == s { + fmt.Println("slice == nil") + } else { + println("not nil!") + } + fmt.Println("----") +} + +// Output: +// pointer == nil +// ---- +// interface == nil +// ---- +// map == nil +// ---- +// slice == nil +// ---- diff --git a/gnovm/tests/files/types/eql_0f35.gno b/gnovm/tests/files/types/eql_0f35.gno new file mode 100644 index 00000000000..c57d3e9d375 --- /dev/null +++ b/gnovm/tests/files/types/eql_0f35.gno @@ -0,0 +1,34 @@ +package main + +import ( + "fmt" + "strconv" +) + +type Error0 int64 + +func (e Error0) Error() string { + return "error: " + strconv.Itoa(int(e)) +} + +type Error1 int64 + +func (e Error1) Error() string { + return "error: " + strconv.Itoa(int(e)) +} + +func main() { + defer func() { + if r := recover(); r != nil { + if r == Error1(0) { + fmt.Println("Recovered. Error:\n", r) + } + } + }() + + panic(Error1(0)) +} + +// Output: +// Recovered. Error: +// 0 diff --git a/gnovm/tests/files/types/eql_0f37.gno b/gnovm/tests/files/types/eql_0f37.gno new file mode 100644 index 00000000000..7fb051961ee --- /dev/null +++ b/gnovm/tests/files/types/eql_0f37.gno @@ -0,0 +1,39 @@ +package main + +import ( + "fmt" + "strconv" +) + +type Error0 int64 + +func (e Error0) Error() string { + return "error: " + strconv.Itoa(int(e)) +} + +type Error1 int64 + +func (e Error1) Error() string { + return "error: " + strconv.Itoa(int(e)) +} + +func get() interface{} { + return Error1(0) +} + +func main() { + defer func() { + if r := recover(); r != nil { + if r == get() { + fmt.Println("recover Error1") + } else { + fmt.Println("recover Error0") + } + } + }() + + panic(Error1(0)) +} + +// Output: +// recover Error1 diff --git a/gnovm/tests/files/types/eql_0f40_stdlibs.gno b/gnovm/tests/files/types/eql_0f40_stdlibs.gno new file mode 100644 index 00000000000..d826bdbd155 --- /dev/null +++ b/gnovm/tests/files/types/eql_0f40_stdlibs.gno @@ -0,0 +1,41 @@ +package main + +import ( + "errors" +) + +type animal interface { + eat() +} + +type dog struct { +} + +func (d *dog) eat() { + println("dog eating") +} + +func get() animal { + d := &dog{} + return d +} + +var errCmp = errors.New("errCmp") + +// no empty interface, different interface(with different methods) +func main() { + defer func() { + if r := recover(); r != nil { + if r == errCmp { + println("same error") + } else { + println("different error") + } + } + }() + + panic(get()) +} + +// Output: +// different error diff --git a/gnovm/tests/files/types/eql_0f41_stdlibs.gno b/gnovm/tests/files/types/eql_0f41_stdlibs.gno new file mode 100644 index 00000000000..679cb1f9295 --- /dev/null +++ b/gnovm/tests/files/types/eql_0f41_stdlibs.gno @@ -0,0 +1,35 @@ +package main + +import ( + "errors" +) + +type animal interface { + eat() +} + +type dog struct { +} + +func (d *dog) eat() { + println("dog eating") +} + +func get() animal { + d := &dog{} + return d +} + +var errCmp = errors.New("errCmp") + +// no empty interface, different interface(with different methods) +func main() { + if get() == errCmp { + println("same error") + } else { + println("different error") + } +} + +// Error: +// main/files/types/eql_0f41_stdlibs.gno:27: main.animal does not implement .uverse.error diff --git a/gnovm/tests/files/types/eql_0f42.gno b/gnovm/tests/files/types/eql_0f42.gno new file mode 100644 index 00000000000..efb63d40b97 --- /dev/null +++ b/gnovm/tests/files/types/eql_0f42.gno @@ -0,0 +1,10 @@ +package main + +var m map[string]int + +func main() { + println(m == nil) +} + +// Output: +// true diff --git a/gnovm/tests/files/types/eql_0f43_hasNil.gno b/gnovm/tests/files/types/eql_0f43_hasNil.gno new file mode 100644 index 00000000000..c336aa92ef6 --- /dev/null +++ b/gnovm/tests/files/types/eql_0f43_hasNil.gno @@ -0,0 +1,15 @@ +package main + +import "fmt" + +func main() { + var myPointer *int + if myPointer == nil { // rcx.T == nil, <-, after conversion lv: (nil *int), rv: (nil *int) + fmt.Println("Pointer is nil") + } else { + fmt.Println("Pointer is not nil") + } +} + +// Output: +// Pointer is nil diff --git a/gnovm/tests/files/types/eql_0f44.gno b/gnovm/tests/files/types/eql_0f44.gno new file mode 100644 index 00000000000..e23e6c07aba --- /dev/null +++ b/gnovm/tests/files/types/eql_0f44.gno @@ -0,0 +1,16 @@ +package main + +import "fmt" + +type f func() + +func main() { + if f(nil) == nil { // rcx.T == nil + fmt.Println("func is nil") + } else { + fmt.Println("func is not nil") + } +} + +// Output: +// func is nil diff --git a/gnovm/tests/files/types/eql_0f45.gno b/gnovm/tests/files/types/eql_0f45.gno new file mode 100644 index 00000000000..7707136b82e --- /dev/null +++ b/gnovm/tests/files/types/eql_0f45.gno @@ -0,0 +1,14 @@ +package main + +import "fmt" + +func main() { + if func() {} == nil { + fmt.Println("func is nil") + } else { + fmt.Println("func is not nil") + } +} + +// Output: +// func is not nil diff --git a/gnovm/tests/files/types/eql_0f46.gno b/gnovm/tests/files/types/eql_0f46.gno new file mode 100644 index 00000000000..3a65bd18b3b --- /dev/null +++ b/gnovm/tests/files/types/eql_0f46.gno @@ -0,0 +1,18 @@ +package main + +import "fmt" + +type m map[string]int + +func main() { + // m(nil) is a conversion from nil to m, whose underlying type is map[string]int + // lv: (nil main.m), rv: (undefined) + if m(nil) == nil { + fmt.Println("m is nil") + } else { + fmt.Println("m is not nil") + } +} + +// Output: +// m is nil diff --git a/gnovm/tests/files/types/eql_0f46a.gno b/gnovm/tests/files/types/eql_0f46a.gno new file mode 100644 index 00000000000..9476b1f22ef --- /dev/null +++ b/gnovm/tests/files/types/eql_0f46a.gno @@ -0,0 +1,18 @@ +package main + +import "fmt" + +type s []int + +func main() { + // s(nil) is a conversion from nil to s, whose underlying type is []int + // lv: (nil main.s), rv: (undefined) + if s(nil) == nil { + fmt.Println("s is nil") + } else { + fmt.Println("s is not nil") + } +} + +// Output: +// s is nil diff --git a/gnovm/tests/files/types/eql_0f48.gno b/gnovm/tests/files/types/eql_0f48.gno new file mode 100644 index 00000000000..fbf4f164c9d --- /dev/null +++ b/gnovm/tests/files/types/eql_0f48.gno @@ -0,0 +1,22 @@ +package main + +func testEql(want, got interface{}) { + if want != got { + println(false) + } else { + println(true) + } +} + +// return var of error nil +func gen() error { + return nil +} + +func main() { // about untyped nil to (interface{})typed-nil, no support for native for now. + r := gen() + testEql(r, error(nil)) +} + +// Output: +// true diff --git a/gnovm/tests/files/types/eql_0f8_stdlibs.gno b/gnovm/tests/files/types/eql_0f8_stdlibs.gno new file mode 100644 index 00000000000..400ce3c6d1e --- /dev/null +++ b/gnovm/tests/files/types/eql_0f8_stdlibs.gno @@ -0,0 +1,27 @@ +package main + +import ( + "errors" + "strconv" +) + +type Error int64 + +func (e Error) Error() string { + return "error: " + strconv.Itoa(int(e)) +} + +var errCmp = errors.New("XXXX") + +// special case: +// one is interface +func main() { + if errCmp == int64(1) { + println("what the firetruck?") + } else { + println("something else") + } +} + +// Error: +// main/files/types/eql_0f8_stdlibs.gno:19: int64 does not implement .uverse.error diff --git a/gnovm/tests/files/types/eql_iface.gno b/gnovm/tests/files/types/eql_iface.gno new file mode 100644 index 00000000000..d3d41348a62 --- /dev/null +++ b/gnovm/tests/files/types/eql_iface.gno @@ -0,0 +1,13 @@ +package main + +type Foo struct { + n int +} + +func main() { + var l interface{} = 1 + println(1 == l) +} + +// Output: +// true diff --git a/gnovm/tests/files/types/incdec_a0.gno b/gnovm/tests/files/types/incdec_a0.gno new file mode 100644 index 00000000000..8f3f97caaee --- /dev/null +++ b/gnovm/tests/files/types/incdec_a0.gno @@ -0,0 +1,10 @@ +package main + +func main() { + a := 1 + a++ + println(a) +} + +// Output: +// 2 diff --git a/gnovm/tests/files/types/incdec_a1.gno b/gnovm/tests/files/types/incdec_a1.gno new file mode 100644 index 00000000000..ee9d2b18c7e --- /dev/null +++ b/gnovm/tests/files/types/incdec_a1.gno @@ -0,0 +1,10 @@ +package main + +func main() { + a := "hello" + a++ + println(a) +} + +// Error: +// main/files/types/incdec_a1.gno:5: operator ++ not defined on: StringKind diff --git a/gnovm/tests/files/types/incdec_a2.gno b/gnovm/tests/files/types/incdec_a2.gno new file mode 100644 index 00000000000..a91080a0d95 --- /dev/null +++ b/gnovm/tests/files/types/incdec_a2.gno @@ -0,0 +1,29 @@ +package main + +func main() { + a := int(1) + a++ + println(a) + + // TODO: no support for now + //b := 1.0 + //b++ + //println(b) + // + //c := float32(1.0) + //c++ + //println(c) + + d := 'a' + d++ + println(d) + + e := uint(1) + e++ + println(e) +} + +// Output: +// 2 +// 98 +// 2 diff --git a/gnovm/tests/files/types/incdec_a3.gno b/gnovm/tests/files/types/incdec_a3.gno new file mode 100644 index 00000000000..f257b822f8e --- /dev/null +++ b/gnovm/tests/files/types/incdec_a3.gno @@ -0,0 +1,19 @@ +package main + +type Int int8 + +func (i Int) Inc() Int { + i++ + return i +} + +// right is typed const, can not use as its correspondence declared type +func main() { + var a Int + a = Int(int8(0)) + a = a.Inc() + println(a) +} + +// Output: +// (1 main.Int) diff --git a/gnovm/tests/files/types/incdec_a4.gno b/gnovm/tests/files/types/incdec_a4.gno new file mode 100644 index 00000000000..5f87eb5c09c --- /dev/null +++ b/gnovm/tests/files/types/incdec_a4.gno @@ -0,0 +1,18 @@ +package main + +type Int int8 + +func (i Int) Inc() { + i++ +} + +// right is typed const, can not use as its correspondence declared type +func main() { + var a Int + a = int8(0) + a.Inc() + println(a) +} + +// Error: +// main/files/types/incdec_a4.gno:12: cannot use int8 as main.Int without explicit conversion diff --git a/gnovm/tests/files/types/nil.gno b/gnovm/tests/files/types/nil.gno new file mode 100644 index 00000000000..a836d328dfe --- /dev/null +++ b/gnovm/tests/files/types/nil.gno @@ -0,0 +1,9 @@ +package main + +func main() { + + println(nil + nil) +} + +// Error: +// main/files/types/nil.gno:5: operator + not defined on: nil diff --git a/gnovm/tests/files/types/or_a0.gno b/gnovm/tests/files/types/or_a0.gno new file mode 100644 index 00000000000..b2f14c73785 --- /dev/null +++ b/gnovm/tests/files/types/or_a0.gno @@ -0,0 +1,9 @@ +package main + +// both typed(different) const +func main() { + println(int(0) | int8(1)) +} + +// Error: +// main/files/types/or_a0.gno:5: invalid operation: mismatched types int and int8 diff --git a/gnovm/tests/files/types/or_a1.gno b/gnovm/tests/files/types/or_a1.gno new file mode 100644 index 00000000000..c2e7bff0d5d --- /dev/null +++ b/gnovm/tests/files/types/or_a1.gno @@ -0,0 +1,25 @@ +package main + +import ( + "strconv" +) + +type Error1 int64 + +func (e Error1) Error() string { + return "error: " + strconv.Itoa(int(e)) +} + +type Error2 int + +func (e Error2) Error() string { + return "error: " + strconv.Itoa(int(e)) +} + +// both typed(different) const +func main() { + println(Error1(0) | Error2(0)) +} + +// Error: +// main/files/types/or_a1.gno:21: invalid operation: mismatched types main.Error1 and main.Error2 diff --git a/gnovm/tests/files/types/or_b0.gno b/gnovm/tests/files/types/or_b0.gno new file mode 100644 index 00000000000..655121ee2f2 --- /dev/null +++ b/gnovm/tests/files/types/or_b0.gno @@ -0,0 +1,13 @@ +package main + +type Error int8 + +// one untyped const, one typed const +func main() { + println(1 | Error(1)) + println(Error(1) | 1) +} + +// Output: +// (1 main.Error) +// (1 main.Error) diff --git a/gnovm/tests/files/types/or_b1.gno b/gnovm/tests/files/types/or_b1.gno new file mode 100644 index 00000000000..1616c4db687 --- /dev/null +++ b/gnovm/tests/files/types/or_b1.gno @@ -0,0 +1,21 @@ +package main + +import ( + "strconv" +) + +type Error int8 + +func (e Error) Error() string { + return "error: " + strconv.Itoa(int(e)) +} + +// one untyped const, one typed const +func main() { + println(1 | Error(1)) + println(Error(1) | 1) +} + +// Output: +// error: 1 +// error: 1 diff --git a/gnovm/tests/files/types/or_b2.gno b/gnovm/tests/files/types/or_b2.gno new file mode 100644 index 00000000000..0bdf3e0a73a --- /dev/null +++ b/gnovm/tests/files/types/or_b2.gno @@ -0,0 +1,9 @@ +package main + +// one untyped const, one typed const +func main() { + println(1 | "a") +} + +// Error: +// main/files/types/or_b2.gno:5: operator | not defined on: StringKind diff --git a/gnovm/tests/files/types/or_b3.gno b/gnovm/tests/files/types/or_b3.gno new file mode 100644 index 00000000000..4b6f20530cd --- /dev/null +++ b/gnovm/tests/files/types/or_b3.gno @@ -0,0 +1,9 @@ +package main + +// one untyped const, one typed const +func main() { + println("b" | "a") +} + +// Error: +// main/files/types/or_b3.gno:5: operator | not defined on: StringKind diff --git a/gnovm/tests/files/types/or_b4.gno b/gnovm/tests/files/types/or_b4.gno new file mode 100644 index 00000000000..54c50033ad1 --- /dev/null +++ b/gnovm/tests/files/types/or_b4.gno @@ -0,0 +1,9 @@ +package main + +// one untyped const, one typed const +func main() { + println(1 | 'a') +} + +// Output: +// 97 diff --git a/gnovm/tests/files/types/or_d0.gno b/gnovm/tests/files/types/or_d0.gno new file mode 100644 index 00000000000..827e29a8fba --- /dev/null +++ b/gnovm/tests/files/types/or_d0.gno @@ -0,0 +1,10 @@ +package main + +// both untyped const +// TODO: dec value representation, and this should happen in process stage!!! +func main() { + println(1.0 | 1) +} + +// Error: +// main/files/types/or_d0.gno:6: operator | not defined on: BigdecKind diff --git a/gnovm/tests/files/types/or_d1.gno b/gnovm/tests/files/types/or_d1.gno new file mode 100644 index 00000000000..ac2458a96a2 --- /dev/null +++ b/gnovm/tests/files/types/or_d1.gno @@ -0,0 +1,10 @@ +package main + +// both untyped const +// TODO: dec value representation +func main() { + println('a' | 'b') +} + +// Output: +// 99 diff --git a/gnovm/tests/files/types/or_d2.gno b/gnovm/tests/files/types/or_d2.gno new file mode 100644 index 00000000000..0812ff926e7 --- /dev/null +++ b/gnovm/tests/files/types/or_d2.gno @@ -0,0 +1,13 @@ +package main + +// both untyped const +// TODO: dec value representation +var r rune + +func main() { + r = 'a' + println(r | 'b') +} + +// Output: +// 99 diff --git a/gnovm/tests/files/types/or_d3.gno b/gnovm/tests/files/types/or_d3.gno new file mode 100644 index 00000000000..226c9423da5 --- /dev/null +++ b/gnovm/tests/files/types/or_d3.gno @@ -0,0 +1,15 @@ +package main + +// both untyped const +// TODO: dec value representation +var r1 rune +var r2 rune + +func main() { + r1 = 'a' + r2 = 'b' + println(r1 | r2) +} + +// Output: +// 99 diff --git a/gnovm/tests/files/types/or_d4.gno b/gnovm/tests/files/types/or_d4.gno new file mode 100644 index 00000000000..f1240f32c71 --- /dev/null +++ b/gnovm/tests/files/types/or_d4.gno @@ -0,0 +1,10 @@ +package main + +// both untyped const +// TODO: dec value representation +func main() { + println(1.0 | 0) +} + +// Error: +// main/files/types/or_d4.gno:6: operator | not defined on: BigdecKind diff --git a/gnovm/tests/files/types/or_e0.gno b/gnovm/tests/files/types/or_e0.gno new file mode 100644 index 00000000000..555ee5ad37b --- /dev/null +++ b/gnovm/tests/files/types/or_e0.gno @@ -0,0 +1,27 @@ +package main + +import ( + "strconv" +) + +type Error1 int64 + +func (e Error1) Error() string { + return "error: " + strconv.Itoa(int(e)) +} + +type Error2 int + +func (e Error2) Error() string { + return "error: " + strconv.Itoa(int(e)) +} + +// both not const, typed +func main() { + var e1 Error1 = Error1(0) + var e2 Error2 = Error2(0) + println(e1 | e2) +} + +// Error: +// main/files/types/or_e0.gno:23: invalid operation: mismatched types main.Error1 and main.Error2 diff --git a/gnovm/tests/files/types/or_f0_stdlibs.gno b/gnovm/tests/files/types/or_f0_stdlibs.gno new file mode 100644 index 00000000000..d2a080e0bab --- /dev/null +++ b/gnovm/tests/files/types/or_f0_stdlibs.gno @@ -0,0 +1,23 @@ +package main + +import ( + "errors" + "strconv" +) + +type Error int64 + +func (e Error) Error() string { + return "error: " + strconv.Itoa(int(e)) +} + +var errCmp = errors.New("XXXX") + +// specil case: +// one is interface +func main() { + println(1 | errCmp) +} + +// Error: +// main/files/types/or_f0_stdlibs.gno:19: operator | not defined on: InterfaceKind diff --git a/gnovm/tests/files/types/or_f1_stdlibs.gno b/gnovm/tests/files/types/or_f1_stdlibs.gno new file mode 100644 index 00000000000..9cc9eb5157b --- /dev/null +++ b/gnovm/tests/files/types/or_f1_stdlibs.gno @@ -0,0 +1,23 @@ +package main + +import ( + "errors" + "strconv" +) + +type Error int64 + +func (e Error) Error() string { + return "error: " + strconv.Itoa(int(e)) +} + +var errCmp = errors.New("XXXX") + +// specil case: +// one is interface +func main() { + println(Error(0) | errCmp) +} + +// Error: +// main/files/types/or_f1_stdlibs.gno:19: operator | not defined on: InterfaceKind diff --git a/gnovm/tests/files/types/or_f2.gno b/gnovm/tests/files/types/or_f2.gno new file mode 100644 index 00000000000..284078f41d4 --- /dev/null +++ b/gnovm/tests/files/types/or_f2.gno @@ -0,0 +1,31 @@ +package main + +import ( + "strconv" +) + +type E interface { + Error() string +} + +type Error1 int64 + +func (e Error1) Error() string { + return "error: " + strconv.Itoa(int(e)) +} + +type Error2 int + +func (e Error2) Error() string { + return "error: " + strconv.Itoa(int(e)) +} + +// both not const, and both interface +func main() { + var e1 E = Error1(0) + var e2 E = Error2(0) + println(e1 | e2) +} + +// Error: +// main/files/types/or_f2.gno:27: operator | not defined on: InterfaceKind diff --git a/gnovm/tests/files/types/overflow_a0.gno b/gnovm/tests/files/types/overflow_a0.gno new file mode 100644 index 00000000000..e3ecefd621f --- /dev/null +++ b/gnovm/tests/files/types/overflow_a0.gno @@ -0,0 +1,11 @@ +package main + +import "fmt" + +func main() { + const Huge = 1e1000 + fmt.Println(Huge / 1e999) +} + +// Output: +// 10 diff --git a/gnovm/tests/files/types/overflow_a1.gno b/gnovm/tests/files/types/overflow_a1.gno new file mode 100644 index 00000000000..bd893312cf2 --- /dev/null +++ b/gnovm/tests/files/types/overflow_a1.gno @@ -0,0 +1,9 @@ +package main + +func main() { + const Huge = 1e1000 + println(Huge) +} + +// Error: +// cannot convert untyped bigdec to float64: strconv.ParseFloat: parsing "1E+1000": value out of range diff --git a/gnovm/tests/files/types/rem_a0.gno b/gnovm/tests/files/types/rem_a0.gno new file mode 100644 index 00000000000..7ba0f66f533 --- /dev/null +++ b/gnovm/tests/files/types/rem_a0.gno @@ -0,0 +1,9 @@ +package main + +// both typed(different) const +func main() { + println(int(1) % int8(1)) +} + +// Error: +// main/files/types/rem_a0.gno:5: invalid operation: mismatched types int and int8 diff --git a/gnovm/tests/files/types/rem_a1.gno b/gnovm/tests/files/types/rem_a1.gno new file mode 100644 index 00000000000..edea73382ce --- /dev/null +++ b/gnovm/tests/files/types/rem_a1.gno @@ -0,0 +1,25 @@ +package main + +import ( + "strconv" +) + +type Error1 int64 + +func (e Error1) Error() string { + return "error: " + strconv.Itoa(int(e)) +} + +type Error2 int + +func (e Error2) Error() string { + return "error: " + strconv.Itoa(int(e)) +} + +// both typed(different) const +func main() { + println(Error1(0) % Error2(0)) +} + +// Error: +// main/files/types/rem_a1.gno:21: invalid operation: mismatched types main.Error1 and main.Error2 diff --git a/gnovm/tests/files/types/rem_a2.gno b/gnovm/tests/files/types/rem_a2.gno new file mode 100644 index 00000000000..3ebba194c0a --- /dev/null +++ b/gnovm/tests/files/types/rem_a2.gno @@ -0,0 +1,8 @@ +package main + +func main() { + println(1 % 0) +} + +// Error: +// main/files/types/rem_a2.gno:4: invalid operation: division by zero diff --git a/gnovm/tests/files/types/rem_b0.gno b/gnovm/tests/files/types/rem_b0.gno new file mode 100644 index 00000000000..9b5f82fb3b7 --- /dev/null +++ b/gnovm/tests/files/types/rem_b0.gno @@ -0,0 +1,13 @@ +package main + +type Error int8 + +// one untyped const, one typed const +func main() { + println(1 % Error(1)) + println(Error(1) % 1) +} + +// Output: +// (0 main.Error) +// (0 main.Error) diff --git a/gnovm/tests/files/types/rem_f3.gno b/gnovm/tests/files/types/rem_f3.gno new file mode 100644 index 00000000000..e34dfab9ae0 --- /dev/null +++ b/gnovm/tests/files/types/rem_f3.gno @@ -0,0 +1,9 @@ +package main + +func main() { + a := 1 + println(a % 0) +} + +// Error: +// main/files/types/rem_f3.gno:5: invalid operation: division by zero diff --git a/gnovm/tests/files/types/runtime_a0.gno b/gnovm/tests/files/types/runtime_a0.gno new file mode 100644 index 00000000000..7d6312e5b9c --- /dev/null +++ b/gnovm/tests/files/types/runtime_a0.gno @@ -0,0 +1,9 @@ +package main + +func main() { + m := map[string]bool{"foo": true} + m["foo"]++ +} + +// Error: +// main/files/types/runtime_a0.gno:5: operator ++ not defined on: BoolKind diff --git a/gnovm/tests/files/types/runtime_a0a.gno b/gnovm/tests/files/types/runtime_a0a.gno new file mode 100644 index 00000000000..fecce01817e --- /dev/null +++ b/gnovm/tests/files/types/runtime_a0a.gno @@ -0,0 +1,8 @@ +package main + +func main() { + println(map[string]bool{"foo": true}["foo"] == true) +} + +// Output: +// true diff --git a/gnovm/tests/files/types/runtime_a2.gno b/gnovm/tests/files/types/runtime_a2.gno new file mode 100644 index 00000000000..d53c9c4d970 --- /dev/null +++ b/gnovm/tests/files/types/runtime_a2.gno @@ -0,0 +1,15 @@ +package main + +import "fmt" + +func gen() interface{} { + return false +} + +func main() { + r := gen() + fmt.Printf("%T \n", r) +} + +// Output: +// bool diff --git a/gnovm/tests/files/types/runtime_a3.gno b/gnovm/tests/files/types/runtime_a3.gno new file mode 100644 index 00000000000..d46a83a1c35 --- /dev/null +++ b/gnovm/tests/files/types/runtime_a3.gno @@ -0,0 +1,12 @@ +package main + +func gen() interface{} { + return false +} + +func main() { + gen()++ +} + +// Error: +// main/files/types/runtime_a3.gno:8: operator ++ not defined on: InterfaceKind diff --git a/gnovm/tests/files/types/shift_a0.gno b/gnovm/tests/files/types/shift_a0.gno new file mode 100644 index 00000000000..a31e7bd8f82 --- /dev/null +++ b/gnovm/tests/files/types/shift_a0.gno @@ -0,0 +1,11 @@ +package main + +// both typed(different) const +func main() { + println(int(1) << int(1)) + println(int(1) >> int(1)) +} + +// Output: +// 2 +// 0 diff --git a/gnovm/tests/files/types/shift_a1.gno b/gnovm/tests/files/types/shift_a1.gno new file mode 100644 index 00000000000..ba92bf0f7d2 --- /dev/null +++ b/gnovm/tests/files/types/shift_a1.gno @@ -0,0 +1,11 @@ +package main + +// both typed(different) const +func main() { + println(int(1) << int8(1)) + println(int(1) >> int8(1)) +} + +// Output: +// 2 +// 0 diff --git a/gnovm/tests/files/types/shift_a10.gno b/gnovm/tests/files/types/shift_a10.gno new file mode 100644 index 00000000000..0eba81f4a9c --- /dev/null +++ b/gnovm/tests/files/types/shift_a10.gno @@ -0,0 +1,10 @@ +package main + +func main() { + a := 1 + r := a << 1.0 // NOTE: go vet would fail, but still process + println(r) +} + +// Output: +// 2 diff --git a/gnovm/tests/files/types/shift_a11.gno b/gnovm/tests/files/types/shift_a11.gno new file mode 100644 index 00000000000..2d3c935e97d --- /dev/null +++ b/gnovm/tests/files/types/shift_a11.gno @@ -0,0 +1,10 @@ +package main + +func main() { + a := 1 + r := a << "hello" // NOTE: go vet would fail, but still process + println(r) +} + +// Error: +// main/files/types/shift_a11.gno:3: cannot convert StringKind to UintKind diff --git a/gnovm/tests/files/types/shift_a12.gno b/gnovm/tests/files/types/shift_a12.gno new file mode 100644 index 00000000000..5735854d684 --- /dev/null +++ b/gnovm/tests/files/types/shift_a12.gno @@ -0,0 +1,14 @@ +package main + +import "fmt" + +func main() { + a := uint(1) + r := uint64(1) << a + println(r) + fmt.Printf("%T \n", r) +} + +// Output: +// 2 +// uint64 diff --git a/gnovm/tests/files/types/shift_a13.gno b/gnovm/tests/files/types/shift_a13.gno new file mode 100644 index 00000000000..7d70cc3589a --- /dev/null +++ b/gnovm/tests/files/types/shift_a13.gno @@ -0,0 +1,13 @@ +package main + +import "fmt" + +func main() { + var r uint64 = 1 << int8(1) + fmt.Printf("%T \n", r) + println(r) +} + +// Output: +// uint64 +// 2 diff --git a/gnovm/tests/files/types/shift_a14.gno b/gnovm/tests/files/types/shift_a14.gno new file mode 100644 index 00000000000..f879da5f3f9 --- /dev/null +++ b/gnovm/tests/files/types/shift_a14.gno @@ -0,0 +1,10 @@ +package main + +func main() { + a := "hello" + r := a << 1 + println(r) +} + +// Error: +// main/files/types/shift_a14.gno:5: operator << not defined on: StringKind diff --git a/gnovm/tests/files/types/shift_a15.gno b/gnovm/tests/files/types/shift_a15.gno new file mode 100644 index 00000000000..b86445f3e75 --- /dev/null +++ b/gnovm/tests/files/types/shift_a15.gno @@ -0,0 +1,10 @@ +package main + +// TODO: fix in assignment +func main() { + a := "hello" + a <<= 1 +} + +// Error: +// main/files/types/shift_a15.gno:6: operator <<= not defined on: StringKind diff --git a/gnovm/tests/files/types/shift_a16.gno b/gnovm/tests/files/types/shift_a16.gno new file mode 100644 index 00000000000..ed41f35f20d --- /dev/null +++ b/gnovm/tests/files/types/shift_a16.gno @@ -0,0 +1,9 @@ +package main + +func main() { + r := "hello" << 1 + println(r) +} + +// Error: +// main/files/types/shift_a16.gno:4: operator << not defined on: StringKind diff --git a/gnovm/tests/files/types/shift_a2.gno b/gnovm/tests/files/types/shift_a2.gno new file mode 100644 index 00000000000..91072929306 --- /dev/null +++ b/gnovm/tests/files/types/shift_a2.gno @@ -0,0 +1,11 @@ +package main + +// both typed(different) const +func main() { + println(1 << int(1)) + println(1 >> int(1)) +} + +// Output: +// 2 +// 0 diff --git a/gnovm/tests/files/types/shift_a3.gno b/gnovm/tests/files/types/shift_a3.gno new file mode 100644 index 00000000000..79d5c566f1d --- /dev/null +++ b/gnovm/tests/files/types/shift_a3.gno @@ -0,0 +1,10 @@ +package main + +// both typed(different) const +func main() { + println(1 << 'a') + println(1 >> 'a') +} + +// Error: +// main/files/types/shift_a3.gno:5: bigint overflows target kind diff --git a/gnovm/tests/files/types/shift_a4.gno b/gnovm/tests/files/types/shift_a4.gno new file mode 100644 index 00000000000..3561929b672 --- /dev/null +++ b/gnovm/tests/files/types/shift_a4.gno @@ -0,0 +1,11 @@ +package main + +// both typed(different) const +func main() { + println(1 << 1.0) + println(1 >> 1.0) +} + +// Output: +// 2 +// 0 diff --git a/gnovm/tests/files/types/shift_a5.gno b/gnovm/tests/files/types/shift_a5.gno new file mode 100644 index 00000000000..0394f8a2f3f --- /dev/null +++ b/gnovm/tests/files/types/shift_a5.gno @@ -0,0 +1,10 @@ +package main + +// TODO: support this? +func main() { + println(1.0 << 1) + println(1.0 >> 1) +} + +// Error: +// main/files/types/shift_a5.gno:5: operator << not defined on: BigdecKind diff --git a/gnovm/tests/files/types/shift_a6.gno b/gnovm/tests/files/types/shift_a6.gno new file mode 100644 index 00000000000..03ad4c0bcea --- /dev/null +++ b/gnovm/tests/files/types/shift_a6.gno @@ -0,0 +1,14 @@ +package main + +func main() { + r := int(1) + println(r << 5) + println(r) + r <<= 5 + println(r) +} + +// Output: +// 32 +// 1 +// 32 diff --git a/gnovm/tests/files/types/shift_a7.gno b/gnovm/tests/files/types/shift_a7.gno new file mode 100644 index 00000000000..5cad6897a21 --- /dev/null +++ b/gnovm/tests/files/types/shift_a7.gno @@ -0,0 +1,9 @@ +package main + +func main() { + r := int(1) + println(r << "a") +} + +// Error: +// main/files/types/shift_a7.gno:3: cannot convert StringKind to UintKind diff --git a/gnovm/tests/files/types/shift_a8.gno b/gnovm/tests/files/types/shift_a8.gno new file mode 100644 index 00000000000..a7a3e1f07d9 --- /dev/null +++ b/gnovm/tests/files/types/shift_a8.gno @@ -0,0 +1,10 @@ +package main + +func main() { + a := 1 + r := a << 1 + println(r) +} + +// Output: +// 2 diff --git a/gnovm/tests/files/types/shift_a9.gno b/gnovm/tests/files/types/shift_a9.gno new file mode 100644 index 00000000000..f998381ef1c --- /dev/null +++ b/gnovm/tests/files/types/shift_a9.gno @@ -0,0 +1,10 @@ +package main + +func main() { + a := 1 + a <<= 1 + println(a) +} + +// Output: +// 2 diff --git a/gnovm/tests/files/types/time_native.gno b/gnovm/tests/files/types/time_native.gno new file mode 100644 index 00000000000..ef1c3daaf44 --- /dev/null +++ b/gnovm/tests/files/types/time_native.gno @@ -0,0 +1,13 @@ +package main + +import ( + "fmt" + "time" +) + +func main() { + fmt.Println(time.Second + time.Second) +} + +// Output: +// 2s diff --git a/gnovm/tests/files/types/unary_a0.gno b/gnovm/tests/files/types/unary_a0.gno new file mode 100644 index 00000000000..2e5a1d289c9 --- /dev/null +++ b/gnovm/tests/files/types/unary_a0.gno @@ -0,0 +1,12 @@ +package main + +import "fmt" + +func main() { + x := 5 + y := +x + fmt.Println(y) // Output: 5 +} + +// Output: +// 5 diff --git a/gnovm/tests/files/types/unary_a0a.gno b/gnovm/tests/files/types/unary_a0a.gno new file mode 100644 index 00000000000..3556bcf2bf6 --- /dev/null +++ b/gnovm/tests/files/types/unary_a0a.gno @@ -0,0 +1,12 @@ +package main + +import "fmt" + +func main() { + x := 1.0 + y := +x + fmt.Println(y) +} + +// Output: +// 1 diff --git a/gnovm/tests/files/types/unary_a0b.gno b/gnovm/tests/files/types/unary_a0b.gno new file mode 100644 index 00000000000..ff4e863e10e --- /dev/null +++ b/gnovm/tests/files/types/unary_a0b.gno @@ -0,0 +1,12 @@ +package main + +import "fmt" + +func main() { + x := int(1) + y := +x + fmt.Println(y) +} + +// Output: +// 1 diff --git a/gnovm/tests/files/types/unary_a0c.gno b/gnovm/tests/files/types/unary_a0c.gno new file mode 100644 index 00000000000..9f1fa057357 --- /dev/null +++ b/gnovm/tests/files/types/unary_a0c.gno @@ -0,0 +1,12 @@ +package main + +import "fmt" + +func main() { + x := "hello" + y := +x + fmt.Println(y) +} + +// Error: +// main/files/types/unary_a0c.gno:7: operator + not defined on: StringKind diff --git a/gnovm/tests/files/types/unary_a1.gno b/gnovm/tests/files/types/unary_a1.gno new file mode 100644 index 00000000000..c3c96d6724e --- /dev/null +++ b/gnovm/tests/files/types/unary_a1.gno @@ -0,0 +1,13 @@ +package main + +import "fmt" + +func main() { + x := 5 + y := -x + fmt.Println(y) // Output: -5 + +} + +// Output: +// -5 diff --git a/gnovm/tests/files/types/unary_a2.gno b/gnovm/tests/files/types/unary_a2.gno new file mode 100644 index 00000000000..1b9edf1b712 --- /dev/null +++ b/gnovm/tests/files/types/unary_a2.gno @@ -0,0 +1,13 @@ +package main + +import "fmt" + +func main() { + a := true + b := !a + fmt.Println(b) // Output: false + +} + +// Output: +// false diff --git a/gnovm/tests/files/types/unary_a2a.gno b/gnovm/tests/files/types/unary_a2a.gno new file mode 100644 index 00000000000..9081ad64ebf --- /dev/null +++ b/gnovm/tests/files/types/unary_a2a.gno @@ -0,0 +1,13 @@ +package main + +import "fmt" + +func main() { + a := 1 + b := !a + fmt.Println(b) // Output: false + +} + +// Error: +// main/files/types/unary_a2a.gno:7: operator ! not defined on: IntKind diff --git a/gnovm/tests/files/types/unary_a3.gno b/gnovm/tests/files/types/unary_a3.gno new file mode 100644 index 00000000000..3f216ccb1c1 --- /dev/null +++ b/gnovm/tests/files/types/unary_a3.gno @@ -0,0 +1,12 @@ +package main + +import "fmt" + +func main() { + x := 10 + p := &x + fmt.Println(*p) // Output: 10 +} + +// Output: +// 10 diff --git a/gnovm/tests/files/types/unary_a4.gno b/gnovm/tests/files/types/unary_a4.gno new file mode 100644 index 00000000000..caaf1ed0438 --- /dev/null +++ b/gnovm/tests/files/types/unary_a4.gno @@ -0,0 +1,10 @@ +package main + +func main() { + v := 42 + p := &v + println(v == *p) +} + +// Output: +// true diff --git a/gnovm/tests/files/types/unary_a5.gno b/gnovm/tests/files/types/unary_a5.gno new file mode 100644 index 00000000000..bb956f85673 --- /dev/null +++ b/gnovm/tests/files/types/unary_a5.gno @@ -0,0 +1,12 @@ +package main + +import "fmt" + +func main() { + x := 1 + y := ^x + fmt.Println(y) // Output will be the bitwise complement of 1 +} + +// Output: +// -2 diff --git a/gnovm/tests/files/types/unary_a6.gno b/gnovm/tests/files/types/unary_a6.gno new file mode 100644 index 00000000000..99e87b66683 --- /dev/null +++ b/gnovm/tests/files/types/unary_a6.gno @@ -0,0 +1,12 @@ +package main + +import "fmt" + +func main() { + x := 1.0 + y := ^x + fmt.Println(y) // Output will be the bitwise complement of 1 +} + +// Error: +// main/files/types/unary_a6.gno:7: operator ^ not defined on: Float64Kind diff --git a/gnovm/tests/files/var18.gno b/gnovm/tests/files/var18.gno index 9fc0cba3053..f2f97f62b15 100644 --- a/gnovm/tests/files/var18.gno +++ b/gnovm/tests/files/var18.gno @@ -5,4 +5,4 @@ func main() { } // Error: -// main/files/var18.gno:4: should not happen +// main/files/var18.gno:4: assignment mismatch: 3 variables but 2 values diff --git a/gnovm/tests/files/zrealm12.gno b/gnovm/tests/files/zrealm12_stdlibs.gno similarity index 100% rename from gnovm/tests/files/zrealm12.gno rename to gnovm/tests/files/zrealm12_stdlibs.gno diff --git a/gnovm/tests/files/zrealm_const.gno b/gnovm/tests/files/zrealm_const_stdlibs.gno similarity index 100% rename from gnovm/tests/files/zrealm_const.gno rename to gnovm/tests/files/zrealm_const_stdlibs.gno diff --git a/gnovm/tests/files/zrealm_crossrealm0.gno b/gnovm/tests/files/zrealm_crossrealm0_stdlibs.gno similarity index 100% rename from gnovm/tests/files/zrealm_crossrealm0.gno rename to gnovm/tests/files/zrealm_crossrealm0_stdlibs.gno diff --git a/gnovm/tests/files/zrealm_crossrealm10.gno b/gnovm/tests/files/zrealm_crossrealm10_stdlibs.gno similarity index 100% rename from gnovm/tests/files/zrealm_crossrealm10.gno rename to gnovm/tests/files/zrealm_crossrealm10_stdlibs.gno diff --git a/gnovm/tests/files/zrealm_crossrealm11.gno b/gnovm/tests/files/zrealm_crossrealm11_stdlibs.gno similarity index 99% rename from gnovm/tests/files/zrealm_crossrealm11.gno rename to gnovm/tests/files/zrealm_crossrealm11_stdlibs.gno index b250b07bbac..e6f33c50654 100644 --- a/gnovm/tests/files/zrealm_crossrealm11.gno +++ b/gnovm/tests/files/zrealm_crossrealm11_stdlibs.gno @@ -2,13 +2,10 @@ package crossrealm_test import ( - "std" - "strings" - ptests "gno.land/p/demo/tests" "gno.land/p/demo/ufmt" rtests "gno.land/r/demo/tests" - testfoo "gno.land/r/demo/tests_foo" + "std" ) func getPrevRealm() std.Realm { diff --git a/gnovm/tests/files/zrealm_crossrealm12.gno b/gnovm/tests/files/zrealm_crossrealm12_stdlibs.gno similarity index 86% rename from gnovm/tests/files/zrealm_crossrealm12.gno rename to gnovm/tests/files/zrealm_crossrealm12_stdlibs.gno index ef8ea141ac5..f2f229cd5de 100644 --- a/gnovm/tests/files/zrealm_crossrealm12.gno +++ b/gnovm/tests/files/zrealm_crossrealm12_stdlibs.gno @@ -2,22 +2,22 @@ package crossrealm_test import ( - "std" "fmt" + "std" psubtests "gno.land/p/demo/tests/subtests" rsubtests "gno.land/r/demo/tests/subtests" ) func main() { - tests := []struct{ + tests := []struct { fn func() std.Realm }{ - { std.CurrentRealm }, - { psubtests.GetCurrentRealm }, - { rsubtests.GetCurrentRealm }, + {std.CurrentRealm}, + {psubtests.GetCurrentRealm}, + {rsubtests.GetCurrentRealm}, } - + for _, test := range tests { r := test.fn() diff --git a/gnovm/tests/files/zrealm_crossrealm13.gno b/gnovm/tests/files/zrealm_crossrealm13_stdlibs.gno similarity index 100% rename from gnovm/tests/files/zrealm_crossrealm13.gno rename to gnovm/tests/files/zrealm_crossrealm13_stdlibs.gno diff --git a/gnovm/tests/files/zrealm_crossrealm13a.gno b/gnovm/tests/files/zrealm_crossrealm13a_stdlibs.gno similarity index 100% rename from gnovm/tests/files/zrealm_crossrealm13a.gno rename to gnovm/tests/files/zrealm_crossrealm13a_stdlibs.gno diff --git a/gnovm/tests/files/zrealm_crossrealm1.gno b/gnovm/tests/files/zrealm_crossrealm1_stdlibs.gno similarity index 100% rename from gnovm/tests/files/zrealm_crossrealm1.gno rename to gnovm/tests/files/zrealm_crossrealm1_stdlibs.gno diff --git a/gnovm/tests/files/zrealm_crossrealm2.gno b/gnovm/tests/files/zrealm_crossrealm2_stdlibs.gno similarity index 100% rename from gnovm/tests/files/zrealm_crossrealm2.gno rename to gnovm/tests/files/zrealm_crossrealm2_stdlibs.gno diff --git a/gnovm/tests/files/zrealm_crossrealm3.gno b/gnovm/tests/files/zrealm_crossrealm3_stdlibs.gno similarity index 100% rename from gnovm/tests/files/zrealm_crossrealm3.gno rename to gnovm/tests/files/zrealm_crossrealm3_stdlibs.gno diff --git a/gnovm/tests/files/zrealm_crossrealm4.gno b/gnovm/tests/files/zrealm_crossrealm4_stdlibs.gno similarity index 100% rename from gnovm/tests/files/zrealm_crossrealm4.gno rename to gnovm/tests/files/zrealm_crossrealm4_stdlibs.gno diff --git a/gnovm/tests/files/zrealm_crossrealm5.gno b/gnovm/tests/files/zrealm_crossrealm5_stdlibs.gno similarity index 100% rename from gnovm/tests/files/zrealm_crossrealm5.gno rename to gnovm/tests/files/zrealm_crossrealm5_stdlibs.gno diff --git a/gnovm/tests/files/zrealm_crossrealm6.gno b/gnovm/tests/files/zrealm_crossrealm6_stdlibs.gno similarity index 100% rename from gnovm/tests/files/zrealm_crossrealm6.gno rename to gnovm/tests/files/zrealm_crossrealm6_stdlibs.gno diff --git a/gnovm/tests/files/zrealm_crossrealm7.gno b/gnovm/tests/files/zrealm_crossrealm7_stdlibs.gno similarity index 100% rename from gnovm/tests/files/zrealm_crossrealm7.gno rename to gnovm/tests/files/zrealm_crossrealm7_stdlibs.gno diff --git a/gnovm/tests/files/zrealm_crossrealm8.gno b/gnovm/tests/files/zrealm_crossrealm8_stdlibs.gno similarity index 100% rename from gnovm/tests/files/zrealm_crossrealm8.gno rename to gnovm/tests/files/zrealm_crossrealm8_stdlibs.gno diff --git a/gnovm/tests/files/zrealm_crossrealm9.gno b/gnovm/tests/files/zrealm_crossrealm9_stdlibs.gno similarity index 100% rename from gnovm/tests/files/zrealm_crossrealm9.gno rename to gnovm/tests/files/zrealm_crossrealm9_stdlibs.gno diff --git a/gnovm/tests/files/zrealm_initctx.gno b/gnovm/tests/files/zrealm_initctx_stdlibs.gno similarity index 100% rename from gnovm/tests/files/zrealm_initctx.gno rename to gnovm/tests/files/zrealm_initctx_stdlibs.gno diff --git a/gnovm/tests/files/zrealm_natbind0.gno b/gnovm/tests/files/zrealm_natbind0_stdlibs.gno similarity index 100% rename from gnovm/tests/files/zrealm_natbind0.gno rename to gnovm/tests/files/zrealm_natbind0_stdlibs.gno diff --git a/gnovm/tests/files/zrealm_std0.gno b/gnovm/tests/files/zrealm_std0_stdlibs.gno similarity index 100% rename from gnovm/tests/files/zrealm_std0.gno rename to gnovm/tests/files/zrealm_std0_stdlibs.gno diff --git a/gnovm/tests/files/zrealm_std1.gno b/gnovm/tests/files/zrealm_std1_stdlibs.gno similarity index 100% rename from gnovm/tests/files/zrealm_std1.gno rename to gnovm/tests/files/zrealm_std1_stdlibs.gno diff --git a/gnovm/tests/files/zrealm_std2.gno b/gnovm/tests/files/zrealm_std2_stdlibs.gno similarity index 100% rename from gnovm/tests/files/zrealm_std2.gno rename to gnovm/tests/files/zrealm_std2_stdlibs.gno diff --git a/gnovm/tests/files/zrealm_std3.gno b/gnovm/tests/files/zrealm_std3_stdlibs.gno similarity index 100% rename from gnovm/tests/files/zrealm_std3.gno rename to gnovm/tests/files/zrealm_std3_stdlibs.gno diff --git a/gnovm/tests/files/zrealm_std4.gno b/gnovm/tests/files/zrealm_std4_stdlibs.gno similarity index 100% rename from gnovm/tests/files/zrealm_std4.gno rename to gnovm/tests/files/zrealm_std4_stdlibs.gno diff --git a/gnovm/tests/files/zrealm_std5.gno b/gnovm/tests/files/zrealm_std5_stdlibs.gno similarity index 100% rename from gnovm/tests/files/zrealm_std5.gno rename to gnovm/tests/files/zrealm_std5_stdlibs.gno diff --git a/gnovm/tests/files/zrealm_std6.gno b/gnovm/tests/files/zrealm_std6_stdlibs.gno similarity index 56% rename from gnovm/tests/files/zrealm_std6.gno rename to gnovm/tests/files/zrealm_std6_stdlibs.gno index fb9e0f825a2..17a79c1d43b 100644 --- a/gnovm/tests/files/zrealm_std6.gno +++ b/gnovm/tests/files/zrealm_std6_stdlibs.gno @@ -1,5 +1,5 @@ -// PKGPATH: gno.land/r/test -package test +// PKGPATH: gno.land/r/std_test +package std_test import ( "std" @@ -14,4 +14,4 @@ func main() { } // Output: -// g148esskg7wzxxw6axwv4j5nkgjzdp6v4zmy3pwc +// g157y5v3k529jyzhjjz4fn49tzzhf4gess6v39xg diff --git a/gnovm/tests/files/zrealm_tests0.gno b/gnovm/tests/files/zrealm_tests0_stdlibs.gno similarity index 100% rename from gnovm/tests/files/zrealm_tests0.gno rename to gnovm/tests/files/zrealm_tests0_stdlibs.gno diff --git a/gnovm/tests/files/zrealm_testutils0.gno b/gnovm/tests/files/zrealm_testutils0_stdlibs.gno similarity index 100% rename from gnovm/tests/files/zrealm_testutils0.gno rename to gnovm/tests/files/zrealm_testutils0_stdlibs.gno diff --git a/gnovm/tests/package_test.go b/gnovm/tests/package_test.go index ded5bedce5f..8e497941c7f 100644 --- a/gnovm/tests/package_test.go +++ b/gnovm/tests/package_test.go @@ -18,7 +18,7 @@ import ( func TestStdlibs(t *testing.T) { // NOTE: this test only works using _test.gno files; // filetests are not meant to be used for testing standard libraries. - // The examples directory is tested directly using `gno test`. + // The examples directory is tested directly using `gno test`u // find all packages with *_test.gno files. rootDirs := []string{ diff --git a/tm2/pkg/errors/errors.go b/tm2/pkg/errors/errors.go index c07356f0b06..c72d9c64680 100644 --- a/tm2/pkg/errors/errors.go +++ b/tm2/pkg/errors/errors.go @@ -237,6 +237,9 @@ type FmtError struct { } func (fe FmtError) Error() string { + if len(fe.args) == 0 { + return fe.format + } return fmt.Sprintf(fe.format, fe.args...) } diff --git a/tm2/pkg/sdk/sdk.proto b/tm2/pkg/sdk/sdk.proto index 828b17950cf..62fbfc19758 100644 --- a/tm2/pkg/sdk/sdk.proto +++ b/tm2/pkg/sdk/sdk.proto @@ -12,4 +12,4 @@ message Result { abci.ResponseBase response_base = 1 [json_name = "ResponseBase"]; sint64 gas_wanted = 2 [json_name = "GasWanted"]; sint64 gas_used = 3 [json_name = "GasUsed"]; -} +} \ No newline at end of file From 71a298b21998a34705e2357c3754e711aa21959f Mon Sep 17 00:00:00 2001 From: Petar Dambovaliev Date: Wed, 19 Jun 2024 07:24:02 +0200 Subject: [PATCH 14/26] perf: for loop and if (#2140) solves [this](https://github.com/gnolang/gno/issues/2138) Benchmarks ``` Master BenchmarkIfStatement-10 238 4967960 ns/op BenchmarkForLoop-10 649 1771728 ns/op Current branch BenchmarkIfStatement-10 366 3316189 ns/op BenchmarkForLoop-10 1143 945930 ns/op ``` By avoiding the runtime type conversion, we can see that we almost doubled the performance of these statements. --------- Co-authored-by: jaekwon Co-authored-by: Jae Kwon <53785+jaekwon@users.noreply.github.com> --- gnovm/pkg/gnolang/gno_test.go | 32 ++++++++++++++++++++++ gnovm/pkg/gnolang/op_inc_dec.go | 4 +++ gnovm/pkg/gnolang/preprocess.go | 48 ++++++++++++++++++++++++--------- gnovm/tests/files/for7.gno | 2 +- gnovm/tests/files/if2.gno | 2 +- 5 files changed, 73 insertions(+), 15 deletions(-) diff --git a/gnovm/pkg/gnolang/gno_test.go b/gnovm/pkg/gnolang/gno_test.go index 24a92a81312..54d808faefc 100644 --- a/gnovm/pkg/gnolang/gno_test.go +++ b/gnovm/pkg/gnolang/gno_test.go @@ -159,6 +159,38 @@ func main() { m.RunMain() } +func BenchmarkPreprocessForLoop(b *testing.B) { + m := NewMachine("test", nil) + c := `package test +func main() { + for i:=0; i<10000; i++ {} +}` + n := MustParseFile("main.go", c) + m.RunFiles(n) + + for i := 0; i < b.N; i++ { + m.RunMain() + } +} + +func BenchmarkIfStatement(b *testing.B) { + m := NewMachine("test", nil) + c := `package test +func main() { + for i:=0; i<10000; i++ { + if i > 10 { + + } + } +}` + n := MustParseFile("main.go", c) + m.RunFiles(n) + + for i := 0; i < b.N; i++ { + m.RunMain() + } +} + func TestDoOpEvalBaseConversion(t *testing.T) { m := NewMachine("test", nil) diff --git a/gnovm/pkg/gnolang/op_inc_dec.go b/gnovm/pkg/gnolang/op_inc_dec.go index 84c39716eec..7a8a885bcf0 100644 --- a/gnovm/pkg/gnolang/op_inc_dec.go +++ b/gnovm/pkg/gnolang/op_inc_dec.go @@ -26,6 +26,10 @@ func (m *Machine) doOpInc() { panic("expected lv.V to be nil for primitive type for OpInc") } } + + // here we can't just switch on the value type + // because it could be a type alias + // type num int switch baseOf(lv.T) { case IntType: lv.SetInt(lv.GetInt() + 1) diff --git a/gnovm/pkg/gnolang/preprocess.go b/gnovm/pkg/gnolang/preprocess.go index 8aca0058dcd..8eb2b37fcc2 100644 --- a/gnovm/pkg/gnolang/preprocess.go +++ b/gnovm/pkg/gnolang/preprocess.go @@ -1253,7 +1253,7 @@ func Preprocess(store Store, ctx BlockNode, n Node) Node { case StringKind, ArrayKind, SliceKind: // Replace const index with int *ConstExpr, // or if not const, assert integer type.. - checkOrConvertIntegerType(store, last, n.Index) + checkOrConvertIntegerKind(store, last, n.Index) case MapKind: mt := baseOf(gnoTypeOf(store, dt)).(*MapType) checkOrConvertType(store, last, &n.Index, mt.Key, false) @@ -1267,9 +1267,9 @@ func Preprocess(store Store, ctx BlockNode, n Node) Node { case *SliceExpr: // Replace const L/H/M with int *ConstExpr, // or if not const, assert integer type.. - checkOrConvertIntegerType(store, last, n.Low) - checkOrConvertIntegerType(store, last, n.High) - checkOrConvertIntegerType(store, last, n.Max) + checkOrConvertIntegerKind(store, last, n.Low) + checkOrConvertIntegerKind(store, last, n.High) + checkOrConvertIntegerKind(store, last, n.Max) // TRANS_LEAVE ----------------------- case *TypeAssertExpr: @@ -1728,12 +1728,12 @@ 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) + checkOrConvertBoolKind(store, last, n.Cond) // TRANS_LEAVE ----------------------- case *IfStmt: // Cond consts become bool *ConstExprs. - checkOrConvertType(store, last, &n.Cond, BoolType, false) + checkOrConvertBoolKind(store, last, n.Cond) // TRANS_LEAVE ----------------------- case *RangeStmt: @@ -2474,7 +2474,7 @@ func checkOrConvertType(store Store, last BlockNode, x *Expr, t Type, autoNative // autoNative is usually false, but set to true // for native function calls, where gno values are // automatically converted to native go types. -// NOTE: also see checkOrConvertIntegerType() +// NOTE: also see checkOrConvertIntegerKind() func convertType(store Store, last BlockNode, x *Expr, t Type) { if debug { debug.Printf("convertType, *x: %v:, t:%v \n", *x, t) @@ -2783,18 +2783,40 @@ func findUndefined2(store Store, last BlockNode, x Expr, t Type) (un Name) { return } -// like checkOrConvertType() but for any integer type. -func checkOrConvertIntegerType(store Store, last BlockNode, x Expr) { +// like checkOrConvertType() but for any typed bool kind. +func checkOrConvertBoolKind(store Store, last BlockNode, x Expr) { + if cx, ok := x.(*ConstExpr); ok { + convertConst(store, last, cx, BoolType) + } else if x != nil { + xt := evalStaticTypeOf(store, last, x) + checkBoolKind(xt) + } +} + +// assert that xt is a typed bool kind. +func checkBoolKind(xt Type) { + switch xt.Kind() { + case BoolKind: + return // ok + default: + panic(fmt.Sprintf( + "expected typed bool kind, but got %v", + xt.Kind())) + } +} + +// like checkOrConvertType() but for any typed integer kind. +func checkOrConvertIntegerKind(store Store, last BlockNode, x Expr) { if cx, ok := x.(*ConstExpr); ok { convertConst(store, last, cx, IntType) } else if x != nil { xt := evalStaticTypeOf(store, last, x) - checkIntegerType(xt) + checkIntegerKind(xt) } } -// assert that xt can be assigned as an integer type. -func checkIntegerType(xt Type) { +// assert that xt is a typed integer kind. +func checkIntegerKind(xt Type) { switch xt.Kind() { case IntKind, Int8Kind, Int16Kind, Int32Kind, Int64Kind, UintKind, Uint8Kind, Uint16Kind, Uint32Kind, Uint64Kind, @@ -2802,7 +2824,7 @@ func checkIntegerType(xt Type) { return // ok default: panic(fmt.Sprintf( - "expected integer type, but got %v", + "expected typed integer kind, but got %v", xt.Kind())) } } diff --git a/gnovm/tests/files/for7.gno b/gnovm/tests/files/for7.gno index 92ad5f3ce34..0f471956314 100644 --- a/gnovm/tests/files/for7.gno +++ b/gnovm/tests/files/for7.gno @@ -6,4 +6,4 @@ func main() { } // Error: -// main/files/for7.gno:4: cannot use int as bool +// main/files/for7.gno:4: expected typed bool kind, but got IntKind diff --git a/gnovm/tests/files/if2.gno b/gnovm/tests/files/if2.gno index 88261c520c9..bc417a92fe7 100644 --- a/gnovm/tests/files/if2.gno +++ b/gnovm/tests/files/if2.gno @@ -10,4 +10,4 @@ func main() { } // Error: -// main/files/if2.gno:7: cannot use int as bool +// main/files/if2.gno:7: expected typed bool kind, but got IntKind From 3801d340cc6a30398c3864c23524ddca1eb66dd6 Mon Sep 17 00:00:00 2001 From: Joe Netti Date: Wed, 19 Jun 2024 01:44:16 -0400 Subject: [PATCH 15/26] fix: custom boolean types in conditional statements (#2147) Resolves https://github.com/gnolang/gno/issues/1087 Preprocess conditional expr with `checkOrConvertBoolType` Unit test for `if` and `for` condition and `integ` test for invalid assignment. The invalid assignment is a case that [fails](https://go.dev/play/p/P631q105QW3) to compile in Go, but succeeded in Gno before this change. Run tests: ``` go test -run ^TestRunApp$ github.com/gnolang/gno/gnovm/cmd/gno go test -run ^TestFiles$ github.com/gnolang/gno/gnovm/tests ```
Contributors' checklist... - [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 - [ ] 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).
--------- Co-authored-by: Jae Kwon <53785+jaekwon@users.noreply.github.com> --- gnovm/cmd/gno/run_test.go | 4 ++++ gnovm/tests/files/for19.gno | 25 +++++++++++++++++++++++ gnovm/tests/files/if8.gno | 18 ++++++++++++++++ gnovm/tests/integ/invalid_assign/main.gno | 16 +++++++++++++++ 4 files changed, 63 insertions(+) create mode 100644 gnovm/tests/files/for19.gno create mode 100644 gnovm/tests/files/if8.gno create mode 100644 gnovm/tests/integ/invalid_assign/main.gno diff --git a/gnovm/cmd/gno/run_test.go b/gnovm/cmd/gno/run_test.go index f78c15edb34..06f9a8dc3a5 100644 --- a/gnovm/cmd/gno/run_test.go +++ b/gnovm/cmd/gno/run_test.go @@ -75,6 +75,10 @@ func TestRunApp(t *testing.T) { args: []string{"run", "-debug-addr", "invalidhost:17538", "../../tests/integ/debugger/sample.gno"}, errShouldContain: "listen tcp: lookup invalidhost", }, + { + args: []string{"run", "../../tests/integ/invalid_assign/main.gno"}, + recoverShouldContain: "cannot use bool as main.C without explicit conversion", + }, // TODO: a test file // TODO: args // TODO: nativeLibs VS stdlibs diff --git a/gnovm/tests/files/for19.gno b/gnovm/tests/files/for19.gno new file mode 100644 index 00000000000..ce02c5fb655 --- /dev/null +++ b/gnovm/tests/files/for19.gno @@ -0,0 +1,25 @@ +package main + +func main() { + v := T + i := 0 + for v { + if i > 2 { + break + } + println(i) + i++ + } +} + +type C bool + +const ( + F C = false + T C = true +) + +// Output: +// 0 +// 1 +// 2 diff --git a/gnovm/tests/files/if8.gno b/gnovm/tests/files/if8.gno new file mode 100644 index 00000000000..c013896d9d3 --- /dev/null +++ b/gnovm/tests/files/if8.gno @@ -0,0 +1,18 @@ +package main + +func main() { + v := T + if v { + println("true") + } +} + +type C bool + +const ( + F C = false + T C = true +) + +// Output: +// true diff --git a/gnovm/tests/integ/invalid_assign/main.gno b/gnovm/tests/integ/invalid_assign/main.gno new file mode 100644 index 00000000000..9f98ef31213 --- /dev/null +++ b/gnovm/tests/integ/invalid_assign/main.gno @@ -0,0 +1,16 @@ +// This should result in a compilation error for assigning a bool to a custom bool type without conversion + +package main + +func main() { + b := true + var v C = b + fmt.Println(v) +} + +type C bool + +const ( + F C = false + T C = true +) From 6032b484d90e291c5ab8c6cff12ac1d3b8080978 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Milo=C5=A1=20=C5=BDivkovi=C4=87?= Date: Wed, 19 Jun 2024 11:11:53 +0200 Subject: [PATCH 16/26] feat: add support for displaying the P2P Address for node secrets info (#2361) ## Description Closes #1922 This PR introduces a new section to the `Node P2P Info` secrets output, that displays the P2P connection address. The secrets fetch command remains unchanged, and this info can be displayed by calling `gnoland secrets get NodeKey` It displays the following values: - if the config is not initialized yet, the default p2p listen address is used - if the config is initialized, the p2p listen address value is used Screenshot 2024-06-19 at 10 59 48 These values will be easily fetch-able when we introduce json output support for these outputs in #2301 cc @mazzy89
Contributors' checklist... - [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 - [ ] 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).
--- gno.land/cmd/gnoland/secrets.go | 2 +- gno.land/cmd/gnoland/secrets_common.go | 6 +- gno.land/cmd/gnoland/secrets_get.go | 53 +++++++++++++- gno.land/cmd/gnoland/secrets_get_test.go | 79 ++++++++++++++++++++- gno.land/cmd/gnoland/secrets_init.go | 2 +- gno.land/cmd/gnoland/secrets_init_test.go | 4 +- gno.land/cmd/gnoland/secrets_verify.go | 2 +- gno.land/cmd/gnoland/secrets_verify_test.go | 2 +- 8 files changed, 138 insertions(+), 12 deletions(-) diff --git a/gno.land/cmd/gnoland/secrets.go b/gno.land/cmd/gnoland/secrets.go index fda2a664c28..f45c751a463 100644 --- a/gno.land/cmd/gnoland/secrets.go +++ b/gno.land/cmd/gnoland/secrets.go @@ -21,7 +21,7 @@ const ( ) const ( - nodeKeyKey = "NodeKey" + nodeIDKey = "NodeID" validatorPrivateKeyKey = "ValidatorPrivateKey" validatorStateKey = "ValidatorState" ) diff --git a/gno.land/cmd/gnoland/secrets_common.go b/gno.land/cmd/gnoland/secrets_common.go index 588307b9b8e..d40e90f6b48 100644 --- a/gno.land/cmd/gnoland/secrets_common.go +++ b/gno.land/cmd/gnoland/secrets_common.go @@ -168,14 +168,14 @@ func verifySecretsKey(args []string) error { // Verify the set key key := args[0] - if key != nodeKeyKey && + if key != nodeIDKey && key != validatorPrivateKeyKey && key != validatorStateKey { return fmt.Errorf( "invalid secrets key value [%s, %s, %s]", validatorPrivateKeyKey, validatorStateKey, - nodeKeyKey, + nodeIDKey, ) } @@ -187,7 +187,7 @@ func getAvailableSecretsKeys() string { return fmt.Sprintf( "[%s, %s, %s]", validatorPrivateKeyKey, - nodeKeyKey, + nodeIDKey, validatorStateKey, ) } diff --git a/gno.land/cmd/gnoland/secrets_get.go b/gno.land/cmd/gnoland/secrets_get.go index 699450702b4..92648314bd1 100644 --- a/gno.land/cmd/gnoland/secrets_get.go +++ b/gno.land/cmd/gnoland/secrets_get.go @@ -5,10 +5,13 @@ import ( "flag" "fmt" "path/filepath" + "strings" "text/tabwriter" + "github.com/gnolang/gno/tm2/pkg/bft/config" "github.com/gnolang/gno/tm2/pkg/bft/privval" "github.com/gnolang/gno/tm2/pkg/commands" + osm "github.com/gnolang/gno/tm2/pkg/os" "github.com/gnolang/gno/tm2/pkg/p2p" ) @@ -75,7 +78,7 @@ func execSecretsGet(cfg *secretsGetCfg, args []string, io commands.IO) error { case validatorStateKey: // Show the validator's last sign state return readAndShowValidatorState(validatorStatePath, io) - case nodeKeyKey: + case nodeIDKey: // Show the node's p2p info return readAndShowNodeKey(nodeKeyPath, io) default: @@ -185,12 +188,30 @@ func readAndShowNodeKey(path string, io commands.IO) error { return fmt.Errorf("unable to read node key, %w", err) } + // Construct the config path + var ( + nodeDir = filepath.Join(filepath.Dir(path), "..") + configPath = constructConfigPath(nodeDir) + + cfg = config.DefaultConfig() + ) + + // Check if there is an existing config file + if osm.FileExists(configPath) { + // Attempt to grab the config from disk + cfg, err = config.LoadConfig(nodeDir) + if err != nil { + return fmt.Errorf("unable to load config file, %w", err) + } + } + w := tabwriter.NewWriter(io.Out(), 0, 0, 2, ' ', 0) if _, err := fmt.Fprintf(w, "[Node P2P Info]\n\n"); err != nil { return err } + // Print the ID info if _, err := fmt.Fprintf( w, "Node ID:\t%s\n", @@ -199,5 +220,35 @@ func readAndShowNodeKey(path string, io commands.IO) error { return err } + // Print the P2P address info + if _, err := fmt.Fprintf( + w, + "P2P Address:\t%s\n", + constructP2PAddress( + nodeKey.ID(), + cfg.P2P.ListenAddress, + ), + ); err != nil { + return err + } + return w.Flush() } + +// constructP2PAddress constructs the P2P address other nodes can use +// to connect directly +func constructP2PAddress(nodeID p2p.ID, listenAddress string) string { + var ( + address string + parts = strings.SplitN(listenAddress, "://", 2) + ) + + switch len(parts) { + case 2: + address = parts[1] + default: + address = listenAddress + } + + return fmt.Sprintf("%s@%s", nodeID, address) +} diff --git a/gno.land/cmd/gnoland/secrets_get_test.go b/gno.land/cmd/gnoland/secrets_get_test.go index 20f1eb2ef35..7d3951ded3e 100644 --- a/gno.land/cmd/gnoland/secrets_get_test.go +++ b/gno.land/cmd/gnoland/secrets_get_test.go @@ -4,10 +4,12 @@ import ( "bytes" "context" "fmt" + "os" "path/filepath" "strconv" "testing" + "github.com/gnolang/gno/tm2/pkg/bft/config" "github.com/gnolang/gno/tm2/pkg/bft/privval" "github.com/gnolang/gno/tm2/pkg/commands" "github.com/gnolang/gno/tm2/pkg/p2p" @@ -95,6 +97,13 @@ func TestSecrets_Get_All(t *testing.T) { nodeKey.ID().String(), ) + // Make sure the node p2p address is displayed + assert.Contains( + t, + output, + constructP2PAddress(nodeKey.ID(), config.DefaultConfig().P2P.ListenAddress), + ) + // Make sure the private key info is displayed assert.Contains( t, @@ -237,9 +246,11 @@ func TestSecrets_Get_Single(t *testing.T) { ) }) - t.Run("node key shown", func(t *testing.T) { + t.Run("node key shown, default config", func(t *testing.T) { t.Parallel() + cfg := config.DefaultConfig() + dirPath := t.TempDir() nodeKeyPath := filepath.Join(dirPath, defaultNodeKeyName) @@ -258,7 +269,7 @@ func TestSecrets_Get_Single(t *testing.T) { "get", "--data-dir", dirPath, - nodeKeyKey, + nodeIDKey, } // Run the command @@ -272,5 +283,69 @@ func TestSecrets_Get_Single(t *testing.T) { output, validNodeKey.ID().String(), ) + + // Make sure the default node p2p address is displayed + assert.Contains( + t, + output, + constructP2PAddress(validNodeKey.ID(), cfg.P2P.ListenAddress), + ) + }) + + t.Run("node key shown, existing config", func(t *testing.T) { + t.Parallel() + + var ( + dirPath = t.TempDir() + configPath = constructConfigPath(dirPath) + secretsPath = constructSecretsPath(dirPath) + nodeKeyPath = filepath.Join(secretsPath, defaultNodeKeyName) + ) + + // Ensure the sub-dirs exist + require.NoError(t, os.MkdirAll(filepath.Dir(configPath), 0o755)) + require.NoError(t, os.MkdirAll(secretsPath, 0o755)) + + // Set up the config + cfg := config.DefaultConfig() + cfg.P2P.ListenAddress = "tcp://127.0.0.1:2525" + + require.NoError(t, config.WriteConfigFile(configPath, cfg)) + + validNodeKey := generateNodeKey() + require.NoError(t, saveSecretData(validNodeKey, nodeKeyPath)) + + mockOutput := bytes.NewBufferString("") + io := commands.NewTestIO() + io.SetOut(commands.WriteNopCloser(mockOutput)) + + // Create the command + cmd := newRootCmd(io) + args := []string{ + "secrets", + "get", + "--data-dir", + secretsPath, + nodeIDKey, + } + + // Run the command + require.NoError(t, cmd.ParseAndRun(context.Background(), args)) + + output := mockOutput.String() + + // Make sure the node p2p key is displayed + assert.Contains( + t, + output, + validNodeKey.ID().String(), + ) + + // Make sure the custom node p2p address is displayed + assert.Contains( + t, + output, + constructP2PAddress(validNodeKey.ID(), cfg.P2P.ListenAddress), + ) }) } diff --git a/gno.land/cmd/gnoland/secrets_init.go b/gno.land/cmd/gnoland/secrets_init.go index 85181d4735c..58dd0783f66 100644 --- a/gno.land/cmd/gnoland/secrets_init.go +++ b/gno.land/cmd/gnoland/secrets_init.go @@ -93,7 +93,7 @@ func execSecretsInit(cfg *secretsInitCfg, args []string, io commands.IO) error { // Initialize and save the validator's private key return initAndSaveValidatorKey(validatorKeyPath, io) - case nodeKeyKey: + case nodeIDKey: if osm.FileExists(nodeKeyPath) && !cfg.forceOverwrite { return fmt.Errorf("unable to overwrite the node' p2p key, %w", errOverwriteNotEnabled) } diff --git a/gno.land/cmd/gnoland/secrets_init_test.go b/gno.land/cmd/gnoland/secrets_init_test.go index 4a707778cc6..20e061447f5 100644 --- a/gno.land/cmd/gnoland/secrets_init_test.go +++ b/gno.land/cmd/gnoland/secrets_init_test.go @@ -149,7 +149,7 @@ func TestSecrets_Init_Single(t *testing.T) { }, { "node p2p key initialized", - nodeKeyKey, + nodeIDKey, defaultNodeKeyName, verifyNodeKey, }, @@ -207,7 +207,7 @@ func TestSecrets_Init_Single_Overwrite(t *testing.T) { }, { "node p2p key not overwritten", - nodeKeyKey, + nodeIDKey, defaultNodeKeyName, }, } diff --git a/gno.land/cmd/gnoland/secrets_verify.go b/gno.land/cmd/gnoland/secrets_verify.go index 7e6c154d1ac..32e563c1c6f 100644 --- a/gno.land/cmd/gnoland/secrets_verify.go +++ b/gno.land/cmd/gnoland/secrets_verify.go @@ -87,7 +87,7 @@ func execSecretsVerify(cfg *secretsVerifyCfg, args []string, io commands.IO) err } return nil - case nodeKeyKey: + case nodeIDKey: return readAndVerifyNodeKey(nodeKeyPath, io) default: // Validate the validator's private key diff --git a/gno.land/cmd/gnoland/secrets_verify_test.go b/gno.land/cmd/gnoland/secrets_verify_test.go index 77ab8523d40..513d7c8b503 100644 --- a/gno.land/cmd/gnoland/secrets_verify_test.go +++ b/gno.land/cmd/gnoland/secrets_verify_test.go @@ -360,7 +360,7 @@ func TestSecrets_Verify_Single(t *testing.T) { "verify", "--data-dir", dirPath, - nodeKeyKey, + nodeIDKey, } // Run the command From 7b8a893ef1418d5ff9b5b3c8ac6fa0f285b1fb8d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Milo=C5=A1=20=C5=BDivkovi=C4=87?= Date: Wed, 19 Jun 2024 11:33:15 +0200 Subject: [PATCH 17/26] fix: Add default ports for `net.Dial` if missing in RPC URL (#2360) ## Description This PR fixes a bug with the `http.Client`, where the custom `DialContext` would fail if the specified RPC URL did not contain a port number (ex: `https://rpc.gno.land`). I've added the default catch values, and removed useless error returns. This additionally begs the question -- do we even want a custom dial context, given that we don't even use the features it provides?
Contributors' checklist... - [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 - [ ] 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).
--------- Co-authored-by: Manfred Touron <94029+moul@users.noreply.github.com> --- tm2/pkg/bft/rpc/lib/client/http/client.go | 42 +++++++++---------- .../bft/rpc/lib/client/http/client_test.go | 40 +++++++++++------- 2 files changed, 47 insertions(+), 35 deletions(-) diff --git a/tm2/pkg/bft/rpc/lib/client/http/client.go b/tm2/pkg/bft/rpc/lib/client/http/client.go index 34d301deba2..290310cea31 100644 --- a/tm2/pkg/bft/rpc/lib/client/http/client.go +++ b/tm2/pkg/bft/rpc/lib/client/http/client.go @@ -17,8 +17,6 @@ import ( const ( protoHTTP = "http" protoHTTPS = "https" - protoWSS = "wss" - protoWS = "ws" protoTCP = "tcp" ) @@ -173,12 +171,7 @@ func defaultHTTPClient(remoteAddr string) *http.Client { } func makeHTTPDialer(remoteAddr string) func(string, string) (net.Conn, error) { - protocol, address, err := parseRemoteAddr(remoteAddr) - if err != nil { - return func(_ string, _ string) (net.Conn, error) { - return nil, err - } - } + protocol, address := parseRemoteAddr(remoteAddr) // net.Dial doesn't understand http/https, so change it to TCP switch protocol { @@ -193,17 +186,14 @@ func makeHTTPDialer(remoteAddr string) func(string, string) (net.Conn, error) { // protocol - client's protocol (for example, "http", "https", "wss", "ws", "tcp") // trimmedS - rest of the address (for example, "192.0.2.1:25", "[2001:db8::1]:80") with "/" replaced with "." -func toClientAddrAndParse(remoteAddr string) (string, string, error) { - protocol, address, err := parseRemoteAddr(remoteAddr) - if err != nil { - return "", "", err - } +func toClientAddrAndParse(remoteAddr string) (string, string) { + protocol, address := parseRemoteAddr(remoteAddr) // protocol to use for http operations, to support both http and https var clientProtocol string // default to http for unknown protocols (ex. tcp) switch protocol { - case protoHTTP, protoHTTPS, protoWS, protoWSS: + case protoHTTP, protoHTTPS: clientProtocol = protocol default: clientProtocol = protoHTTP @@ -212,14 +202,11 @@ func toClientAddrAndParse(remoteAddr string) (string, string, error) { // replace / with . for http requests (kvstore domain) trimmedAddress := strings.Replace(address, "/", ".", -1) - return clientProtocol, trimmedAddress, nil + return clientProtocol, trimmedAddress } func toClientAddress(remoteAddr string) (string, error) { - clientProtocol, trimmedAddress, err := toClientAddrAndParse(remoteAddr) - if err != nil { - return "", err - } + clientProtocol, trimmedAddress := toClientAddrAndParse(remoteAddr) return clientProtocol + "://" + trimmedAddress, nil } @@ -227,8 +214,9 @@ func toClientAddress(remoteAddr string) (string, error) { // network - name of the network (for example, "tcp", "unix") // s - rest of the address (for example, "192.0.2.1:25", "[2001:db8::1]:80") // TODO: Deprecate support for IP:PORT or /path/to/socket -func parseRemoteAddr(remoteAddr string) (network string, s string, err error) { +func parseRemoteAddr(remoteAddr string) (string, string) { parts := strings.SplitN(remoteAddr, "://", 2) + var protocol, address string switch len(parts) { case 1: @@ -237,7 +225,19 @@ func parseRemoteAddr(remoteAddr string) (network string, s string, err error) { case 2: protocol, address = parts[0], parts[1] } - return protocol, address, nil + + // Append default ports if not specified + if !strings.Contains(address, ":") { + switch protocol { + case protoHTTPS: + address += ":443" + case protoHTTP, protoTCP: + address += ":80" + default: // noop + } + } + + return protocol, address } // isOKStatus returns a boolean indicating if the response diff --git a/tm2/pkg/bft/rpc/lib/client/http/client_test.go b/tm2/pkg/bft/rpc/lib/client/http/client_test.go index 7c4b1e52ac5..cfe69c3015c 100644 --- a/tm2/pkg/bft/rpc/lib/client/http/client_test.go +++ b/tm2/pkg/bft/rpc/lib/client/http/client_test.go @@ -17,24 +17,39 @@ func TestClient_parseRemoteAddr(t *testing.T) { t.Parallel() testTable := []struct { - remoteAddr string - network string - rest string + remoteAddr string + expectedNetwork string + expectedRest string }{ { "127.0.0.1", "tcp", - "127.0.0.1", + "127.0.0.1:80", + }, + { + "127.0.0.1:5000", + "tcp", + "127.0.0.1:5000", + }, + { + "http://example.com", + "http", + "example.com:80", }, { "https://example.com", "https", - "example.com", + "example.com:443", }, { - "wss://[::1]", - "wss", - "[::1]", + "http://example.com:5000", + "http", + "example.com:5000", + }, + { + "https://example.com:5000", + "https", + "example.com:5000", }, } @@ -44,11 +59,10 @@ func TestClient_parseRemoteAddr(t *testing.T) { t.Run(testCase.remoteAddr, func(t *testing.T) { t.Parallel() - n, r, err := parseRemoteAddr(testCase.remoteAddr) - require.NoError(t, err) + n, r := parseRemoteAddr(testCase.remoteAddr) - assert.Equal(t, n, testCase.network) - assert.Equal(t, r, testCase.rest) + assert.Equal(t, testCase.expectedNetwork, n) + assert.Equal(t, testCase.expectedRest, r) }) } } @@ -66,7 +80,6 @@ func TestClient_makeHTTPDialer(t *testing.T) { require.Error(t, err) assert.Contains(t, err.Error(), "dial tcp:", "should convert https to tcp") - assert.Contains(t, err.Error(), "address .:", "should have parsed the address (as incorrect)") }) t.Run("udp", func(t *testing.T) { @@ -76,7 +89,6 @@ func TestClient_makeHTTPDialer(t *testing.T) { require.Error(t, err) assert.Contains(t, err.Error(), "dial udp:", "udp protocol should remain the same") - assert.Contains(t, err.Error(), "address .:", "should have parsed the address (as incorrect)") }) } From feb3051b37d20a0cf2ee8309d0a468c0a4ba8657 Mon Sep 17 00:00:00 2001 From: ltzmaxwell Date: Wed, 19 Jun 2024 22:27:54 +0800 Subject: [PATCH 18/26] fix(examples): correct the version number in upgrade demo (#2390) Small fix to correct the version number in upgrade demo. --- .../r/x/manfred_upgrade_patterns/upgrade_c/v2/v2.gno | 2 +- .../r/x/manfred_upgrade_patterns/upgrade_d/v2/v2.gno | 2 +- .../upgrade_d/v2/z_filetest.gno | 12 +++++------- 3 files changed, 7 insertions(+), 9 deletions(-) diff --git a/examples/gno.land/r/x/manfred_upgrade_patterns/upgrade_c/v2/v2.gno b/examples/gno.land/r/x/manfred_upgrade_patterns/upgrade_c/v2/v2.gno index 7d07337a17d..03ffe876519 100644 --- a/examples/gno.land/r/x/manfred_upgrade_patterns/upgrade_c/v2/v2.gno +++ b/examples/gno.land/r/x/manfred_upgrade_patterns/upgrade_c/v2/v2.gno @@ -1,4 +1,4 @@ -package v1 +package v2 import "gno.land/r/x/manfred_upgrade_patterns/upgrade_c/root" diff --git a/examples/gno.land/r/x/manfred_upgrade_patterns/upgrade_d/v2/v2.gno b/examples/gno.land/r/x/manfred_upgrade_patterns/upgrade_d/v2/v2.gno index a31219cd4d0..22e43cf7bdd 100644 --- a/examples/gno.land/r/x/manfred_upgrade_patterns/upgrade_d/v2/v2.gno +++ b/examples/gno.land/r/x/manfred_upgrade_patterns/upgrade_d/v2/v2.gno @@ -1,4 +1,4 @@ -package v1 +package v2 import ( "gno.land/p/demo/avl" diff --git a/examples/gno.land/r/x/manfred_upgrade_patterns/upgrade_d/v2/z_filetest.gno b/examples/gno.land/r/x/manfred_upgrade_patterns/upgrade_d/v2/z_filetest.gno index 961c7a13208..f884b5278ab 100644 --- a/examples/gno.land/r/x/manfred_upgrade_patterns/upgrade_d/v2/z_filetest.gno +++ b/examples/gno.land/r/x/manfred_upgrade_patterns/upgrade_d/v2/z_filetest.gno @@ -1,17 +1,15 @@ package main import ( - "fmt" - "gno.land/r/x/manfred_upgrade_patterns/upgrade_d/v2" ) func main() { - println("a", v1.Get("a")) - println("b", v1.Get("b")) - println("c", v1.Get("c")) - println("d", v1.Get("d")) - println("e", v1.Get("e")) + println("a", v2.Get("a")) + println("b", v2.Get("b")) + println("c", v2.Get("c")) + println("d", v2.Get("d")) + println("e", v2.Get("e")) } // Output: From c4664edbbca0ab9cd21b175f36aea8680e6d768f Mon Sep 17 00:00:00 2001 From: Morgan Date: Wed, 19 Jun 2024 17:38:06 +0200 Subject: [PATCH 19/26] feat(transpiler): transpile gno standard libraries (#1695) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Merge order: 1. #1700 2. #1702 3. #1695 (this one!) -- review earlier ones first, if they're still open! This PR modifies the Gno transpiler (fka precompiler) to use Gno's standard libraries rather than Go's when performing transpilation. This creates the necessity to transpile Gno standard libraries, and as such support their native bindings. And it removes the necessity for a package like `stdshim`, and a mechanism like `stdlibWhitelist`. - Fixes #668. Fixes #1865. - Resolves #892. - Part of #814. - Makes #1475 / #1576 possible without using hacks like `stdshim`. cc/ @leohhhn @tbruyelle, as this relates to your work ## Why? - This PR enables us to perform Go type-checking across the board, and not use Go's standard libraries in transpiled code. This enables us to _properly support our own standard libraries_, such as `std` but any others we might want or need. - It also paves the way further to go full circle, and have Gno code be transpiled to Go, and then have "compilable" gno code ## Summary of changes - The transpiler has been thoroughly refactored. - The biggest change is described above: instead of maintaing the import paths like `"strconv"` and `"math"` the same (so using Gno's stdlibs in Gno, and Go's in Go), the import paths for standard libraries is now also updated to point to the Gno standard libraries. - Native functions are handled by removing their definitions when transpiling, and changing their call expressions where appropriate. This links the transpiled code directly to their native counterparts. - This removes the necessity for `stdlibWhitelist`. - As a consequence, `stdshim` is no longer needed and has been removed. - Test files are still not "strictly checked": they may reference stdlibs with no matching source, and will not be tested when running with `--gobuild`. This is because packages like `fmt` have no representation in Gno code; they only exist as injections in `tests/imports.go`. I'll fix this eventually :) - The CLI (`gno transpile`) has been changed to reflect the above changes. - Flag `--skip-fmt` has been removed (the result of transpile is always formatted, anyway), and `--gofmt-binary` too, obviously. `gno transpile` does not perform validation, but will gladly provide helpful validation with the `--gobuild` flag. - There is another PR that adds type checking in `gno lint`, without needing to run through the transpilation step first: https://github.com/gnolang/gno/pull/1730 - It now works by default by looking at "packages" rather than individual files. This is necessary so that when performing `transpile` on the `examples` directory, we can skip those where the gno.mod marks the module as draft. These modules make use of packages like "fmt", which because they don't have an underlying gno/go source, cannot be transpiled. - Running with `-gobuild` now handles more errors correctly; ie., all errors not previously captured by the `errorRe` which only matches those pertaining to a specific file/line. - `gnoFilesFromArgs` was unused and as such deleted - `gnomod`'s behaviour was slightly changed. - I am of the opinion that `gno mod download` should not precompile what it downloads; _especially_ to gather the dependencies it has. I've changed it so that it does a `OnlyImports` parse of the file it downloads to fetch additional dependencies Misc: - `Makefile` now contains a recipe to calculate the coverage for `gnovm/cmd/gno`, and also view it via the HTML interface. This is needed as it has a few extra steps (which @gfanton already previously added in the CI). - Realms r/demo/art/gnoface and r/x/manfred_outfmt have been marked as draft, as they depend on packages which are not actually present in the Gno standard libraries. - The transpiler now ignores draft packages by default. - `ReadMemPackage` now also considers Go files. This is meant to have on-chain the code for standard libraries like `std` which have native bindings. We still exclude Go code if it's not in a standard library. - `//go:build` constraints have been removed from standard libraries, as go files can only have one and we already add our own when transpiling ## Further improvements after this PR - Scope understanding in `transpiler` (so call expressions are not incorrectly rewritten) - Correctly transpile gno.mod --------- Co-authored-by: Antonio Navarro Perez Co-authored-by: Miloš Živković --- examples/gno.land/r/demo/art/gnoface/gno.mod | 2 + examples/gno.land/r/x/manfred_outfmt/gno.mod | 2 + gnovm/Makefile | 23 +- gnovm/cmd/gno/test.go | 3 +- .../gno_transpile/05_skip_fmt_flag.txtar | 36 -- .../gno_transpile/06_build_flag.txtar | 38 -- ...r.txtar => gobuild_flag_build_error.txtar} | 0 ...r.txtar => gobuild_flag_parse_error.txtar} | 0 ...elist_error.txtar => invalid_import.txtar} | 6 +- .../{01_no_args.txtar => no_args.txtar} | 0 ...es_parse_error.txtar => parse_error.txtar} | 0 ..._empty_dir.txtar => valid_empty_dir.txtar} | 0 .../gno_transpile/valid_gobuild_file.txtar | 31 ++ .../gno_transpile/valid_gobuild_flag.txtar | 72 ++++ .../gno_transpile/valid_output_flag.txtar | 41 ++ .../gno_transpile/valid_output_gobuild.txtar | 44 ++ .../gno_transpile/valid_transpile_file.txtar | 65 +++ ...es.txtar => valid_transpile_package.txtar} | 0 .../gno_transpile/valid_transpile_tree.txtar | 94 ++++ gnovm/cmd/gno/transpile.go | 272 +++++++++--- gnovm/cmd/gno/transpile_test.go | 80 ++++ gnovm/cmd/gno/util.go | 162 +++---- gnovm/cmd/gno/util_test.go | 47 ++ gnovm/pkg/gnolang/helpers.go | 28 ++ gnovm/pkg/gnolang/helpers_test.go | 55 +++ gnovm/pkg/gnolang/nodes.go | 12 +- gnovm/pkg/gnolang/realm.go | 15 - gnovm/pkg/gnomod/file.go | 9 +- gnovm/pkg/gnomod/gnomod.go | 41 +- gnovm/pkg/integration/gno.go | 2 + gnovm/pkg/transpiler/transpiler.go | 402 +++++++----------- gnovm/pkg/transpiler/transpiler_test.go | 232 +++++++--- gnovm/stdlibs/bytes/boundary_test.gno | 2 - .../crypto/chacha20/chacha/chacha_ref.gno | 2 - .../internal/bytealg/compare_generic.gno | 3 - .../internal/bytealg/count_generic.gno | 2 - .../internal/bytealg/index_generic.gno | 2 - .../internal/bytealg/indexbyte_generic.gno | 2 - gnovm/stdlibs/native.go | 58 ++- gnovm/stdlibs/stdlibs.go | 19 +- gnovm/stdlibs/stdshim/addr_set.gno | 47 -- gnovm/stdlibs/stdshim/banker.gno | 70 --- gnovm/stdlibs/stdshim/coins.gno | 174 -------- gnovm/stdlibs/stdshim/context.gno | 4 - gnovm/stdlibs/stdshim/crypto.gno | 17 - gnovm/stdlibs/stdshim/frame.gno | 18 - gnovm/stdlibs/time/time.gno | 3 - gnovm/tests/stdlibs/native.go | 36 +- misc/genstd/template.tmpl | 25 +- 49 files changed, 1327 insertions(+), 971 deletions(-) delete mode 100644 gnovm/cmd/gno/testdata/gno_transpile/05_skip_fmt_flag.txtar delete mode 100644 gnovm/cmd/gno/testdata/gno_transpile/06_build_flag.txtar rename gnovm/cmd/gno/testdata/gno_transpile/{07_build_flag_with_build_error.txtar => gobuild_flag_build_error.txtar} (100%) rename gnovm/cmd/gno/testdata/gno_transpile/{08_build_flag_with_parse_error.txtar => gobuild_flag_parse_error.txtar} (100%) rename gnovm/cmd/gno/testdata/gno_transpile/{09_gno_files_whitelist_error.txtar => invalid_import.txtar} (60%) rename gnovm/cmd/gno/testdata/gno_transpile/{01_no_args.txtar => no_args.txtar} (100%) rename gnovm/cmd/gno/testdata/gno_transpile/{03_gno_files_parse_error.txtar => parse_error.txtar} (100%) rename gnovm/cmd/gno/testdata/gno_transpile/{02_empty_dir.txtar => valid_empty_dir.txtar} (100%) create mode 100644 gnovm/cmd/gno/testdata/gno_transpile/valid_gobuild_file.txtar create mode 100644 gnovm/cmd/gno/testdata/gno_transpile/valid_gobuild_flag.txtar create mode 100644 gnovm/cmd/gno/testdata/gno_transpile/valid_output_flag.txtar create mode 100644 gnovm/cmd/gno/testdata/gno_transpile/valid_output_gobuild.txtar create mode 100644 gnovm/cmd/gno/testdata/gno_transpile/valid_transpile_file.txtar rename gnovm/cmd/gno/testdata/gno_transpile/{04_valid_gno_files.txtar => valid_transpile_package.txtar} (100%) create mode 100644 gnovm/cmd/gno/testdata/gno_transpile/valid_transpile_tree.txtar create mode 100644 gnovm/pkg/gnolang/helpers_test.go delete mode 100644 gnovm/stdlibs/stdshim/addr_set.gno delete mode 100644 gnovm/stdlibs/stdshim/banker.gno delete mode 100644 gnovm/stdlibs/stdshim/coins.gno delete mode 100644 gnovm/stdlibs/stdshim/context.gno delete mode 100644 gnovm/stdlibs/stdshim/crypto.gno delete mode 100644 gnovm/stdlibs/stdshim/frame.gno diff --git a/examples/gno.land/r/demo/art/gnoface/gno.mod b/examples/gno.land/r/demo/art/gnoface/gno.mod index bc17ee9df3b..6276629cba2 100644 --- a/examples/gno.land/r/demo/art/gnoface/gno.mod +++ b/examples/gno.land/r/demo/art/gnoface/gno.mod @@ -1,3 +1,5 @@ +// Draft + module gno.land/r/demo/art/gnoface require ( diff --git a/examples/gno.land/r/x/manfred_outfmt/gno.mod b/examples/gno.land/r/x/manfred_outfmt/gno.mod index e6f705c46b9..9804aecc7f1 100644 --- a/examples/gno.land/r/x/manfred_outfmt/gno.mod +++ b/examples/gno.land/r/x/manfred_outfmt/gno.mod @@ -1,3 +1,5 @@ +// Draft + module gno.land/r/x/manfred_outfmt require ( diff --git a/gnovm/Makefile b/gnovm/Makefile index 452b2dcc81a..aa80c61ac7d 100644 --- a/gnovm/Makefile +++ b/gnovm/Makefile @@ -27,6 +27,9 @@ GNOROOT_DIR ?= $(abspath $(lastword $(MAKEFILE_LIST))/../../) # We can't use '-trimpath' yet as amino use absolute path from call stack # to find some directory: see #1236 GOBUILD_FLAGS ?= -ldflags "-X github.com/gnolang/gno/gnovm/pkg/gnoenv._GNOROOT=$(GNOROOT_DIR)" +# file where to place cover profile; used for coverage commands which are +# more complex than adding -coverprofile, like test.cmd.coverage. +GOTEST_COVER_PROFILE ?= cmd-profile.out ######################################## # Dev tools @@ -66,6 +69,24 @@ test: _test.cmd _test.pkg _test.gnolang _test.cmd: go test ./cmd/... $(GOTEST_FLAGS) +# Run tests on ./cmd/, saving the result of the coverage in +# GOTEST_COVER_PROFILE. +.PHONY: test.cmd.coverage +test.cmd.coverage: + $(eval export TXTARCOVERDIR := $(shell mktemp -d --tmpdir gnovm-make.XXXXXXX)) + go test ./cmd/... -covermode atomic -test.gocoverdir='$(TXTARCOVERDIR)' $(GOTEST_FLAGS) + @echo "coverage results:" + go tool covdata percent -i="$(TXTARCOVERDIR)" + go tool covdata textfmt -v 1 -i="$(TXTARCOVERDIR)" -o '$(GOTEST_COVER_PROFILE)' + rm -rf "$(TXTARCOVERDIR)" + +# Run test.cmd.coverage, then view the result in the HTML browser render +# and delete the original file. +.PHONY: test.cmd.coverage_view +test.cmd.coverage_view: test.cmd.coverage + go tool cover -html='$(GOTEST_COVER_PROFILE)' + rm '$(GOTEST_COVER_PROFILE)' + .PHONY: _test.pkg _test.pkg: go test ./pkg/... $(GOTEST_FLAGS) @@ -74,7 +95,7 @@ _test.pkg: _test.gnolang: _test.gnolang.native _test.gnolang.stdlibs _test.gnolang.realm _test.gnolang.pkg0 _test.gnolang.pkg1 _test.gnolang.pkg2 _test.gnolang.other _test.gnolang.other:; go test tests/*.go -run "(TestFileStr|TestSelectors)" $(GOTEST_FLAGS) _test.gnolang.realm:; go test tests/*.go -run "TestFiles/^zrealm" $(GOTEST_FLAGS) -_test.gnolang.pkg0:; go test tests/*.go -run "TestStdlibs/(bufio|crypto|encoding|errors|internal|io|math|sort|std|stdshim|strconv|strings|testing|unicode)" $(GOTEST_FLAGS) +_test.gnolang.pkg0:; go test tests/*.go -run "TestStdlibs/(bufio|crypto|encoding|errors|internal|io|math|sort|std|strconv|strings|testing|unicode)" $(GOTEST_FLAGS) _test.gnolang.pkg1:; go test tests/*.go -run "TestStdlibs/regexp" $(GOTEST_FLAGS) _test.gnolang.pkg2:; go test tests/*.go -run "TestStdlibs/bytes" $(GOTEST_FLAGS) _test.gnolang.native:; go test tests/*.go -test.short -run "TestFilesNative/" $(GOTEST_FLAGS) diff --git a/gnovm/cmd/gno/test.go b/gnovm/cmd/gno/test.go index 2e966bd32a9..5884463a552 100644 --- a/gnovm/cmd/gno/test.go +++ b/gnovm/cmd/gno/test.go @@ -20,7 +20,6 @@ import ( "github.com/gnolang/gno/gnovm/pkg/gnoenv" gno "github.com/gnolang/gno/gnovm/pkg/gnolang" "github.com/gnolang/gno/gnovm/pkg/gnomod" - "github.com/gnolang/gno/gnovm/pkg/transpiler" "github.com/gnolang/gno/gnovm/tests" "github.com/gnolang/gno/tm2/pkg/commands" "github.com/gnolang/gno/tm2/pkg/errors" @@ -259,7 +258,7 @@ func gnoTestPkg( if gnoPkgPath == "" { // unable to read pkgPath from gno.mod, generate a random realm path io.ErrPrintfln("--- WARNING: unable to read package path from gno.mod or gno root directory; try creating a gno.mod file") - gnoPkgPath = transpiler.GnoRealmPkgsPrefixBefore + random.RandStr(8) + gnoPkgPath = gno.RealmPathPrefix + random.RandStr(8) } } memPkg := gno.ReadMemPackage(pkgPath, gnoPkgPath) diff --git a/gnovm/cmd/gno/testdata/gno_transpile/05_skip_fmt_flag.txtar b/gnovm/cmd/gno/testdata/gno_transpile/05_skip_fmt_flag.txtar deleted file mode 100644 index c07c670f721..00000000000 --- a/gnovm/cmd/gno/testdata/gno_transpile/05_skip_fmt_flag.txtar +++ /dev/null @@ -1,36 +0,0 @@ -# Run gno transpile with -skip-fmt flag -# NOTE(tb): this flag doesn't actually prevent the code format, because -# `gnolang.Transpile()` calls `format.Node()`. - -gno transpile -skip-fmt . - -! stdout .+ -! stderr .+ - -cmp main.gno.gen.go main.gno.gen.go.golden -cmp sub/sub.gno.gen.go sub/sub.gno.gen.go.golden - --- main.gno -- -package main - -func main(){} - --- sub/sub.gno -- -package sub - --- main.gno.gen.go.golden -- -// Code generated by github.com/gnolang/gno. DO NOT EDIT. - -//go:build gno - -//line main.gno:1:1 -package main - -func main() {} --- sub/sub.gno.gen.go.golden -- -// Code generated by github.com/gnolang/gno. DO NOT EDIT. - -//go:build gno - -//line sub.gno:1:1 -package sub diff --git a/gnovm/cmd/gno/testdata/gno_transpile/06_build_flag.txtar b/gnovm/cmd/gno/testdata/gno_transpile/06_build_flag.txtar deleted file mode 100644 index 110d04959c0..00000000000 --- a/gnovm/cmd/gno/testdata/gno_transpile/06_build_flag.txtar +++ /dev/null @@ -1,38 +0,0 @@ -# Run gno transpile with -gobuild flag - -gno transpile -gobuild . - -! stdout .+ -! stderr .+ - -cmp main.gno.gen.go main.gno.gen.go.golden -cmp sub/sub.gno.gen.go sub/sub.gno.gen.go.golden - --- main.gno -- -package main - -func main() { - var x = 1 - _=x -} --- sub/sub.gno -- -package sub --- main.gno.gen.go.golden -- -// Code generated by github.com/gnolang/gno. DO NOT EDIT. - -//go:build gno - -//line main.gno:1:1 -package main - -func main() { - var x = 1 - _ = x -} --- sub/sub.gno.gen.go.golden -- -// Code generated by github.com/gnolang/gno. DO NOT EDIT. - -//go:build gno - -//line sub.gno:1:1 -package sub diff --git a/gnovm/cmd/gno/testdata/gno_transpile/07_build_flag_with_build_error.txtar b/gnovm/cmd/gno/testdata/gno_transpile/gobuild_flag_build_error.txtar similarity index 100% rename from gnovm/cmd/gno/testdata/gno_transpile/07_build_flag_with_build_error.txtar rename to gnovm/cmd/gno/testdata/gno_transpile/gobuild_flag_build_error.txtar diff --git a/gnovm/cmd/gno/testdata/gno_transpile/08_build_flag_with_parse_error.txtar b/gnovm/cmd/gno/testdata/gno_transpile/gobuild_flag_parse_error.txtar similarity index 100% rename from gnovm/cmd/gno/testdata/gno_transpile/08_build_flag_with_parse_error.txtar rename to gnovm/cmd/gno/testdata/gno_transpile/gobuild_flag_parse_error.txtar diff --git a/gnovm/cmd/gno/testdata/gno_transpile/09_gno_files_whitelist_error.txtar b/gnovm/cmd/gno/testdata/gno_transpile/invalid_import.txtar similarity index 60% rename from gnovm/cmd/gno/testdata/gno_transpile/09_gno_files_whitelist_error.txtar rename to gnovm/cmd/gno/testdata/gno_transpile/invalid_import.txtar index 79d4d6a4a2c..0c51012feb7 100644 --- a/gnovm/cmd/gno/testdata/gno_transpile/09_gno_files_whitelist_error.txtar +++ b/gnovm/cmd/gno/testdata/gno_transpile/invalid_import.txtar @@ -1,10 +1,10 @@ -# Run gno transpile with gno files with whitelist errors +# Run gno transpile with gno files with an invalid import path ! gno transpile . ! stdout .+ -stderr '^main.gno:5:2: import "xxx" is not in the whitelist$' -stderr '^sub/sub.gno:3:8: import "xxx" is not in the whitelist$' +stderr '^main.gno:5:2: import "xxx" does not exist$' +stderr '^sub/sub.gno:3:8: import "xxx" does not exist$' stderr '^2 transpile error\(s\)$' # no *.gen.go files are created diff --git a/gnovm/cmd/gno/testdata/gno_transpile/01_no_args.txtar b/gnovm/cmd/gno/testdata/gno_transpile/no_args.txtar similarity index 100% rename from gnovm/cmd/gno/testdata/gno_transpile/01_no_args.txtar rename to gnovm/cmd/gno/testdata/gno_transpile/no_args.txtar diff --git a/gnovm/cmd/gno/testdata/gno_transpile/03_gno_files_parse_error.txtar b/gnovm/cmd/gno/testdata/gno_transpile/parse_error.txtar similarity index 100% rename from gnovm/cmd/gno/testdata/gno_transpile/03_gno_files_parse_error.txtar rename to gnovm/cmd/gno/testdata/gno_transpile/parse_error.txtar diff --git a/gnovm/cmd/gno/testdata/gno_transpile/02_empty_dir.txtar b/gnovm/cmd/gno/testdata/gno_transpile/valid_empty_dir.txtar similarity index 100% rename from gnovm/cmd/gno/testdata/gno_transpile/02_empty_dir.txtar rename to gnovm/cmd/gno/testdata/gno_transpile/valid_empty_dir.txtar diff --git a/gnovm/cmd/gno/testdata/gno_transpile/valid_gobuild_file.txtar b/gnovm/cmd/gno/testdata/gno_transpile/valid_gobuild_file.txtar new file mode 100644 index 00000000000..40bb1ecb98a --- /dev/null +++ b/gnovm/cmd/gno/testdata/gno_transpile/valid_gobuild_file.txtar @@ -0,0 +1,31 @@ +# Run gno transpile with -gobuild flag on an individual file + +gno transpile -gobuild -v main.gno + +! stdout .+ +cmp stderr stderr.golden + +cmp main.gno.gen.go main.gno.gen.go.golden + +-- stderr.golden -- +main.gno +main.gno [build] +-- main.gno -- +package main + +func main() { + var x = 1 + _=x +} +-- main.gno.gen.go.golden -- +// Code generated by github.com/gnolang/gno. DO NOT EDIT. + +//go:build gno + +//line main.gno:1:1 +package main + +func main() { + var x = 1 + _ = x +} diff --git a/gnovm/cmd/gno/testdata/gno_transpile/valid_gobuild_flag.txtar b/gnovm/cmd/gno/testdata/gno_transpile/valid_gobuild_flag.txtar new file mode 100644 index 00000000000..2eacfb9de60 --- /dev/null +++ b/gnovm/cmd/gno/testdata/gno_transpile/valid_gobuild_flag.txtar @@ -0,0 +1,72 @@ +# Run gno transpile with -gobuild flag + +gno transpile -gobuild -v . + +! stdout .+ +cmp stderr stderr.golden + +# The test file will be excluded from transpilation unless we pass it explicitly. +cmp main.gno.gen.go main.gno.gen.go.golden +! exists .main_test.gno.gen_test.go +cmp sub/sub.gno.gen.go sub/sub.gno.gen.go.golden +rm mai.gno.gen.gosub/sub.gno.gen.go + +# Re-try, but use an absolute path. +gno transpile -gobuild -v $WORK + +! stdout .+ +cmpenv stderr stderr2.golden + +cmp main.gno.gen.go main.gno.gen.go.golden +! exists .main_test.gno.gen_test.go +cmp sub/sub.gno.gen.go sub/sub.gno.gen.go.golden + +-- stderr.golden -- +. +sub +. [build] +sub [build] +-- stderr2.golden -- +$WORK +$WORK/sub +$WORK [build] +$WORK/sub [build] +-- main.gno -- +package main + +func main() { + var x = 1 + _=x +} +-- main.gno.gen.go.golden -- +// Code generated by github.com/gnolang/gno. DO NOT EDIT. + +//go:build gno + +//line main.gno:1:1 +package main + +func main() { + var x = 1 + _ = x +} +-- main_test.gno -- +package main + +import ( + "testing" + "badimport" +) + +func TestMain(t *testing.T) { + badimport.DoesNotExist() +} +-- sub/sub.gno -- +package sub +-- sub/sub.gno.gen.go.golden -- +// Code generated by github.com/gnolang/gno. DO NOT EDIT. + +//go:build gno + +//line sub.gno:1:1 +package sub diff --git a/gnovm/cmd/gno/testdata/gno_transpile/valid_output_flag.txtar b/gnovm/cmd/gno/testdata/gno_transpile/valid_output_flag.txtar new file mode 100644 index 00000000000..b1a63890f46 --- /dev/null +++ b/gnovm/cmd/gno/testdata/gno_transpile/valid_output_flag.txtar @@ -0,0 +1,41 @@ +# Run gno transpile with valid gno files, using the -output flag. + +gno transpile -v -output directory/hello/ . +! stdout .+ +cmp stderr stderr1.golden + +exists directory/hello/main.gno.gen.go +! exists main.gno.gen.go +rm directory + +# Try running using the absolute path to the directory. +gno transpile -v -output directory/hello $WORK +! stdout .+ +cmpenv stderr stderr2.golden + +exists directory/hello$WORK/main.gno.gen.go +! exists directory/hello/main.gno.gen.go +rm directory + +# Try running in subdirectory, using a "relative non-local path." (ie. has "../") +mkdir subdir +cd subdir +gno transpile -v -output hello .. +! stdout .+ +cmpenv stderr ../stderr3.golden + +exists hello$WORK/main.gno.gen.go +! exists main.gno.gen.go + +-- stderr1.golden -- +. +-- stderr2.golden -- +$WORK +-- stderr3.golden -- +.. +-- main.gno -- +package main + +func main() { + println("hello") +} diff --git a/gnovm/cmd/gno/testdata/gno_transpile/valid_output_gobuild.txtar b/gnovm/cmd/gno/testdata/gno_transpile/valid_output_gobuild.txtar new file mode 100644 index 00000000000..3540e865f3e --- /dev/null +++ b/gnovm/cmd/gno/testdata/gno_transpile/valid_output_gobuild.txtar @@ -0,0 +1,44 @@ +# Run gno transpile with valid gno files, using the -output and -gobuild flags together. + +gno transpile -v -output directory/hello/ -gobuild . +! stdout .+ +cmp stderr stderr1.golden + +exists directory/hello/main.gno.gen.go +! exists main.gno.gen.go +rm directory + +# Try running using the absolute path to the directory. +gno transpile -v -output directory/hello -gobuild $WORK +! stdout .+ +cmpenv stderr stderr2.golden + +exists directory/hello$WORK/main.gno.gen.go +! exists directory/hello/main.gno.gen.go +rm directory + +# Try running in subdirectory, using a "relative non-local path." (ie. has "../") +mkdir subdir +cd subdir +gno transpile -v -output hello -gobuild .. +! stdout .+ +cmpenv stderr ../stderr3.golden + +exists hello$WORK/main.gno.gen.go +! exists main.gno.gen.go + +-- stderr1.golden -- +. +directory/hello [build] +-- stderr2.golden -- +$WORK +directory/hello$WORK [build] +-- stderr3.golden -- +.. +hello$WORK [build] +-- main.gno -- +package main + +func main() { + println("hello") +} diff --git a/gnovm/cmd/gno/testdata/gno_transpile/valid_transpile_file.txtar b/gnovm/cmd/gno/testdata/gno_transpile/valid_transpile_file.txtar new file mode 100644 index 00000000000..86cc6f12f7a --- /dev/null +++ b/gnovm/cmd/gno/testdata/gno_transpile/valid_transpile_file.txtar @@ -0,0 +1,65 @@ +# Run gno transpile with an individual file. + +# Running transpile on the current directory should only precompile +# main.gno. +gno transpile -v . + +! stdout .+ +stderr ^\.$ + +exists main.gno.gen.go +! exists .hello_test.gno.gen_test.go +rm main.gno.gen.go + +# Running it using individual filenames should precompile hello_test.gno, as well. +gno transpile -v main.gno hello_test.gno + +! stdout .+ +cmp stderr transpile-files-stderr.golden + +cmp main.gno.gen.go main.gno.gen.go.golden +cmp .hello_test.gno.gen_test.go .hello_test.gno.gen_test.go.golden + +-- transpile-files-stderr.golden -- +main.gno +hello_test.gno +-- main.gno -- +package main + +func main() { + println("hello") +} + +-- hello_test.gno -- +package main + +import "std" + +func hello() { + std.AssertOriginCall() +} + +-- main.gno.gen.go.golden -- +// Code generated by github.com/gnolang/gno. DO NOT EDIT. + +//go:build gno + +//line main.gno:1:1 +package main + +func main() { + println("hello") +} +-- .hello_test.gno.gen_test.go.golden -- +// Code generated by github.com/gnolang/gno. DO NOT EDIT. + +//go:build gno && test + +//line hello_test.gno:1:1 +package main + +import "github.com/gnolang/gno/gnovm/stdlibs/std" + +func hello() { + std.AssertOriginCall(nil) +} diff --git a/gnovm/cmd/gno/testdata/gno_transpile/04_valid_gno_files.txtar b/gnovm/cmd/gno/testdata/gno_transpile/valid_transpile_package.txtar similarity index 100% rename from gnovm/cmd/gno/testdata/gno_transpile/04_valid_gno_files.txtar rename to gnovm/cmd/gno/testdata/gno_transpile/valid_transpile_package.txtar diff --git a/gnovm/cmd/gno/testdata/gno_transpile/valid_transpile_tree.txtar b/gnovm/cmd/gno/testdata/gno_transpile/valid_transpile_tree.txtar new file mode 100644 index 00000000000..a765ab5093b --- /dev/null +++ b/gnovm/cmd/gno/testdata/gno_transpile/valid_transpile_tree.txtar @@ -0,0 +1,94 @@ +# Run gno transpile with dependencies +env GNOROOT=$WORK + +gno transpile -v ./examples + +! stdout .+ +cmpenv stderr stderr.golden + +! exists examples/gno.land/r/question/question.gno.gen.go +cmp examples/gno.land/r/answer/answer.gno.gen.go examples/gno.land/r/answer/answer.gno.gen.go.golden +cmp examples/gno.land/r/answer/anti_answer.gno.gen.go examples/gno.land/r/answer/anti_answer.gno.gen.go.golden +cmp gnovm/stdlibs/math/math.gno.gen.go gnovm/stdlibs/math/math.gno.gen.go.golden + +-- stderr.golden -- +examples/gno.land/r/answer +$WORK/gnovm/stdlibs/math +examples/gno.land/r/question (skipped, gno.mod marks module as draft) +-- examples/gno.land/r/question/gno.mod -- +// Draft + +module gno.land/r/question + +-- examples/gno.land/r/question/question.gno -- +package question + +func Question() string { + return "What is the answer to Life, The Universe and Everything?" + invalid syntax +} + +-- examples/gno.land/r/answer/answer.gno -- +package answer + +import "math" + +func Answer() int { + return math.Sqrt(1764) +} + +-- examples/gno.land/r/answer/answer.gno.gen.go.golden -- +// Code generated by github.com/gnolang/gno. DO NOT EDIT. + +//go:build gno + +//line answer.gno:1:1 +package answer + +import "github.com/gnolang/gno/gnovm/stdlibs/math" + +func Answer() int { + return math.Sqrt(1764) +} +-- examples/gno.land/r/answer/anti_answer.gno -- +package answer + +import "math" + +func AntiAnswer() int { + return -math.Sqrt(1764) +} +-- examples/gno.land/r/answer/anti_answer.gno.gen.go.golden -- +// Code generated by github.com/gnolang/gno. DO NOT EDIT. + +//go:build gno + +//line anti_answer.gno:1:1 +package answer + +import "github.com/gnolang/gno/gnovm/stdlibs/math" + +func AntiAnswer() int { + return -math.Sqrt(1764) +} +-- examples/gno.land/r/answer/gno.mod -- +module gno.land/r/answer + +-- gnovm/stdlibs/math/math.gno -- +package math + +func Sqrt(i int) int { + return 42 +} + +-- gnovm/stdlibs/math/math.gno.gen.go.golden -- +// Code generated by github.com/gnolang/gno. DO NOT EDIT. + +//go:build gno + +//line math.gno:1:1 +package math + +func Sqrt(i int) int { + return 42 +} diff --git a/gnovm/cmd/gno/transpile.go b/gnovm/cmd/gno/transpile.go index 84744451f9d..2e12ee6f4b3 100644 --- a/gnovm/cmd/gno/transpile.go +++ b/gnovm/cmd/gno/transpile.go @@ -5,48 +5,61 @@ import ( "errors" "flag" "fmt" + "go/ast" "go/scanner" - "log" + "go/token" "os" + "os/exec" "path/filepath" + "regexp" + "slices" + "strconv" + "strings" + "github.com/gnolang/gno/gnovm/pkg/gnoenv" + "github.com/gnolang/gno/gnovm/pkg/gnomod" "github.com/gnolang/gno/gnovm/pkg/transpiler" "github.com/gnolang/gno/tm2/pkg/commands" ) -type importPath string - type transpileCfg struct { verbose bool - skipFmt bool + rootDir string skipImports bool gobuild bool goBinary string - gofmtBinary string output string } type transpileOptions struct { cfg *transpileCfg + // CLI output + io commands.IO // transpiled is the set of packages already // transpiled from .gno to .go. - transpiled map[importPath]struct{} + transpiled map[string]struct{} + // skipped packages (gno mod marks them as draft) + skipped []string } -func newTranspileOptions(cfg *transpileCfg) *transpileOptions { - return &transpileOptions{cfg, map[importPath]struct{}{}} +func newTranspileOptions(cfg *transpileCfg, io commands.IO) *transpileOptions { + return &transpileOptions{ + cfg: cfg, + io: io, + transpiled: map[string]struct{}{}, + } } func (p *transpileOptions) getFlags() *transpileCfg { return p.cfg } -func (p *transpileOptions) isTranspiled(pkg importPath) bool { +func (p *transpileOptions) isTranspiled(pkg string) bool { _, transpiled := p.transpiled[pkg] return transpiled } -func (p *transpileOptions) markAsTranspiled(pkg importPath) { +func (p *transpileOptions) markAsTranspiled(pkg string) { p.transpiled[pkg] = struct{}{} } @@ -74,11 +87,11 @@ func (c *transpileCfg) RegisterFlags(fs *flag.FlagSet) { "verbose output when running", ) - fs.BoolVar( - &c.skipFmt, - "skip-fmt", - false, - "do not check syntax of generated .go files", + fs.StringVar( + &c.rootDir, + "root-dir", + "", + "clone location of github.com/gnolang/gno (gno tries to guess it)", ) fs.BoolVar( @@ -102,13 +115,6 @@ func (c *transpileCfg) RegisterFlags(fs *flag.FlagSet) { "go binary to use for building", ) - fs.StringVar( - &c.gofmtBinary, - "go-fmt-binary", - "gofmt", - "gofmt binary to use for syntax checking", - ) - fs.StringVar( &c.output, "output", @@ -122,33 +128,54 @@ func execTranspile(cfg *transpileCfg, args []string, io commands.IO) error { return flag.ErrHelp } - // transpile .gno files. - paths, err := gnoFilesFromArgs(args) + // guess cfg.RootDir + if cfg.rootDir == "" { + cfg.rootDir = gnoenv.RootDir() + } + + // transpile .gno packages and files. + paths, err := gnoPackagesFromArgs(args) if err != nil { return fmt.Errorf("list paths: %w", err) } - opts := newTranspileOptions(cfg) + opts := newTranspileOptions(cfg, io) var errlist scanner.ErrorList - for _, filepath := range paths { - if err := transpileFile(filepath, opts); err != nil { + for _, path := range paths { + st, err := os.Stat(path) + if err != nil { + return err + } + if st.IsDir() { + err = transpilePkg(path, opts) + } else { + if opts.cfg.verbose { + io.ErrPrintln(filepath.Clean(path)) + } + + err = transpileFile(path, opts) + } + if err != nil { var fileErrlist scanner.ErrorList if !errors.As(err, &fileErrlist) { // Not an scanner.ErrorList: return immediately. - return fmt.Errorf("%s: transpile: %w", filepath, err) + return fmt.Errorf("%s: transpile: %w", path, err) } errlist = append(errlist, fileErrlist...) } } if errlist.Len() == 0 && cfg.gobuild { - paths, err := gnoPackagesFromArgs(args) - if err != nil { - return fmt.Errorf("list packages: %w", err) - } - for _, pkgPath := range paths { - err := goBuildFileOrPkg(pkgPath, cfg) + if slices.Contains(opts.skipped, pkgPath) { + continue + } + if cfg.output != "." { + if pkgPath, err = ResolvePath(cfg.output, pkgPath); err != nil { + return fmt.Errorf("resolve output path: %w", err) + } + } + err := goBuildFileOrPkg(io, pkgPath, cfg) if err != nil { var fileErrlist scanner.ErrorList if !errors.As(err, &fileErrlist) { @@ -169,19 +196,41 @@ func execTranspile(cfg *transpileCfg, args []string, io commands.IO) error { return nil } -func transpilePkg(pkgPath importPath, opts *transpileOptions) error { - if opts.isTranspiled(pkgPath) { +// transpilePkg transpiles all non-test files at the given location. +// Additionally, it checks the gno.mod in said location, and skips it if it is +// a draft module +func transpilePkg(dirPath string, opts *transpileOptions) error { + if opts.isTranspiled(dirPath) { + return nil + } + opts.markAsTranspiled(dirPath) + + gmod, err := gnomod.ParseAt(dirPath) + if err != nil && !errors.Is(err, gnomod.ErrGnoModNotFound) { + return err + } + if err == nil && gmod.Draft { + if opts.cfg.verbose { + opts.io.ErrPrintfln("%s (skipped, gno.mod marks module as draft)", filepath.Clean(dirPath)) + } + opts.skipped = append(opts.skipped, dirPath) return nil } - opts.markAsTranspiled(pkgPath) - files, err := filepath.Glob(filepath.Join(string(pkgPath), "*.gno")) + // XXX(morgan): Currently avoiding test files as they contain imports like "fmt". + // The transpiler doesn't currently support "test stdlibs", and even if it + // did all packages like "fmt" would have to exist as standard libraries to work. + // Easier to skip for now. + files, err := listNonTestFiles(dirPath) if err != nil { - log.Fatal(err) + return err } + if opts.cfg.verbose { + opts.io.ErrPrintln(filepath.Clean(dirPath)) + } for _, file := range files { - if err = transpileFile(file, opts); err != nil { + if err := transpileFile(file, opts); err != nil { return fmt.Errorf("%s: %w", file, err) } } @@ -191,14 +240,6 @@ func transpilePkg(pkgPath importPath, opts *transpileOptions) error { func transpileFile(srcPath string, opts *transpileOptions) error { flags := opts.getFlags() - gofmt := flags.gofmtBinary - if gofmt == "" { - gofmt = "gofmt" - } - - if flags.verbose { - fmt.Fprintf(os.Stderr, "%s\n", srcPath) - } // parse .gno. source, err := os.ReadFile(srcPath) @@ -207,7 +248,7 @@ func transpileFile(srcPath string, opts *transpileOptions) error { } // compute attributes based on filename. - targetFilename, tags := transpiler.GetTranspileFilenameAndTags(srcPath) + targetFilename, tags := transpiler.TranspiledFilenameAndTags(srcPath) // preprocess. transpileRes, err := transpiler.Transpile(string(source), tags, srcPath) @@ -218,7 +259,7 @@ func transpileFile(srcPath string, opts *transpileOptions) error { // resolve target path var targetPath string if flags.output != "." { - path, err := ResolvePath(flags.output, importPath(filepath.Dir(srcPath))) + path, err := ResolvePath(flags.output, filepath.Dir(srcPath)) if err != nil { return fmt.Errorf("resolve output path: %w", err) } @@ -233,18 +274,14 @@ func transpileFile(srcPath string, opts *transpileOptions) error { return fmt.Errorf("write .go file: %w", err) } - // check .go fmt, if `SkipFmt` sets to false. - if !flags.skipFmt { - err = transpiler.TranspileVerifyFile(targetPath, gofmt) + // transpile imported packages, if `SkipImports` sets to false + if !flags.skipImports && + !strings.HasSuffix(srcPath, "_filetest.gno") && !strings.HasSuffix(srcPath, "_test.gno") { + dirPaths, err := getPathsFromImportSpec(opts.cfg.rootDir, transpileRes.Imports) if err != nil { - return fmt.Errorf("check .go file: %w", err) + return err } - } - - // transpile imported packages, if `SkipImports` sets to false - if !flags.skipImports { - importPaths := getPathsFromImportSpec(transpileRes.Imports) - for _, path := range importPaths { + for _, path := range dirPaths { if err := transpilePkg(path, opts); err != nil { return err } @@ -254,13 +291,122 @@ func transpileFile(srcPath string, opts *transpileOptions) error { return nil } -func goBuildFileOrPkg(fileOrPkg string, cfg *transpileCfg) error { +func goBuildFileOrPkg(io commands.IO, fileOrPkg string, cfg *transpileCfg) error { verbose := cfg.verbose goBinary := cfg.goBinary if verbose { - fmt.Fprintf(os.Stderr, "%s\n", fileOrPkg) + io.ErrPrintfln("%s [build]", filepath.Clean(fileOrPkg)) + } + + return buildTranspiledPackage(fileOrPkg, goBinary) +} + +// getPathsFromImportSpec returns the directory paths where the code for each +// importSpec is stored (assuming they start with [transpiler.ImportPrefix]). +func getPathsFromImportSpec(rootDir string, importSpec []*ast.ImportSpec) (dirs []string, err error) { + for _, i := range importSpec { + path, err := strconv.Unquote(i.Path.Value) + if err != nil { + return nil, err + } + if strings.HasPrefix(path, transpiler.ImportPrefix) { + res := strings.TrimPrefix(path, transpiler.ImportPrefix) + + dirs = append(dirs, rootDir+filepath.FromSlash(res)) + } + } + return +} + +// buildTranspiledPackage tries to run `go build` against the transpiled .go files. +// +// This method is the most efficient to detect errors but requires that +// all the import are valid and available. +func buildTranspiledPackage(fileOrPkg, goBinary string) error { + // TODO: use cmd/compile instead of exec? + // TODO: find the nearest go.mod file, chdir in the same folder, trim prefix? + // TODO: temporarily create an in-memory go.mod or disable go modules for gno? + // TODO: ignore .go files that were not generated from gno? + + info, err := os.Stat(fileOrPkg) + if err != nil { + return fmt.Errorf("invalid file or package path %s: %w", fileOrPkg, err) + } + var ( + target string + chdir string + ) + if !info.IsDir() { + dstFilename, _ := transpiler.TranspiledFilenameAndTags(fileOrPkg) + // Makes clear to go compiler that this is a relative path, + // rather than a path to a package/module. + // can't use filepath.Join as it cleans its results. + target = filepath.Dir(fileOrPkg) + string(filepath.Separator) + dstFilename + } else { + // Go does not allow building packages using absolute paths, and requires + // relative paths to always be prefixed with `./` (because the argument + // go expects are import paths, not directories). + // To circumvent this, we use the -C flag to chdir into the right + // directory, then run `go build .` + chdir = fileOrPkg + target = "." + } + + // pre-alloc max 5 args + args := append(make([]string, 0, 5), "build") + if chdir != "" { + args = append(args, "-C", chdir) + } + args = append(args, "-tags=gno", target) + cmd := exec.Command(goBinary, args...) + out, err := cmd.CombinedOutput() + if errors.As(err, new(*exec.ExitError)) { + // there was a non-zero exit code; parse the go build errors + return parseGoBuildErrors(string(out)) + } + // other kinds of errors; return + return err +} + +var ( + reGoBuildError = regexp.MustCompile(`(?m)^(\S+):(\d+):(\d+): (.+)$`) + reGoBuildComment = regexp.MustCompile(`(?m)^#.*$`) +) + +// parseGoBuildErrors returns a scanner.ErrorList filled with all errors found +// in out, which is supposed to be the output of the `go build` command. +// +// TODO(tb): update when `go build -json` is released to replace regexp usage. +// See https://github.com/golang/go/issues/62067 +func parseGoBuildErrors(out string) error { + var errList scanner.ErrorList + matches := reGoBuildError.FindAllStringSubmatch(out, -1) + for _, match := range matches { + filename := match[1] + line, err := strconv.Atoi(match[2]) + if err != nil { + return fmt.Errorf("parse line go build error %s: %w", match, err) + } + + column, err := strconv.Atoi(match[3]) + if err != nil { + return fmt.Errorf("parse column go build error %s: %w", match, err) + } + msg := match[4] + errList.Add(token.Position{ + Filename: filename, + Line: line, + Column: column, + }, msg) + } + + replaced := reGoBuildError.ReplaceAllLiteralString(out, "") + replaced = reGoBuildComment.ReplaceAllString(replaced, "") + replaced = strings.TrimSpace(replaced) + if replaced != "" { + errList.Add(token.Position{}, "Additional go build errors:\n"+replaced) } - return transpiler.TranspileBuildPackage(fileOrPkg, goBinary) + return errList.Err() } diff --git a/gnovm/cmd/gno/transpile_test.go b/gnovm/cmd/gno/transpile_test.go index 2770026a01a..827c09e23f1 100644 --- a/gnovm/cmd/gno/transpile_test.go +++ b/gnovm/cmd/gno/transpile_test.go @@ -1,9 +1,13 @@ package main import ( + "go/scanner" + "go/token" + "strconv" "testing" "github.com/rogpeppe/go-internal/testscript" + "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "github.com/gnolang/gno/gnovm/pkg/integration" @@ -24,3 +28,79 @@ func Test_ScriptsTranspile(t *testing.T) { testscript.Run(t, p) } + +func Test_parseGoBuildErrors(t *testing.T) { + t.Parallel() + + tests := []struct { + name string + output string + expectedError error + expectedErrorIs error + }{ + { + name: "empty output", + output: "", + expectedError: nil, + }, + { + name: "random output", + output: "xxx", + expectedError: scanner.ErrorList{ + &scanner.Error{ + Msg: "Additional go build errors:\nxxx", + }, + }, + }, + { + name: "some errors", + output: `xxx +main.gno:6:2: nasty error +pkg/file.gno:60:20: ugly error`, + expectedError: scanner.ErrorList{ + &scanner.Error{ + Pos: token.Position{ + Filename: "main.gno", + Line: 6, + Column: 2, + }, + Msg: "nasty error", + }, + &scanner.Error{ + Pos: token.Position{ + Filename: "pkg/file.gno", + Line: 60, + Column: 20, + }, + Msg: "ugly error", + }, + &scanner.Error{ + Msg: "Additional go build errors:\nxxx", + }, + }, + }, + { + name: "line parse error", + output: `main.gno:9000000000000000000000000000000000000000000000000000:11: error`, + expectedErrorIs: strconv.ErrRange, + }, + { + name: "column parse error", + output: `main.gno:1:9000000000000000000000000000000000000000000000000000: error`, + expectedErrorIs: strconv.ErrRange, + }, + } + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + err := parseGoBuildErrors(tt.output) + if eis := tt.expectedErrorIs; eis != nil { + assert.ErrorIs(t, err, eis) + } else { + assert.Equal(t, tt.expectedError, err) + } + }) + } +} diff --git a/gnovm/cmd/gno/util.go b/gnovm/cmd/gno/util.go index d9ec775dfca..480161c2b7e 100644 --- a/gnovm/cmd/gno/util.go +++ b/gnovm/cmd/gno/util.go @@ -2,7 +2,6 @@ package main import ( "fmt" - "go/ast" "io" "io/fs" "os" @@ -10,9 +9,6 @@ import ( "regexp" "strings" "time" - - "github.com/gnolang/gno/gnovm/pkg/gnoenv" - "github.com/gnolang/gno/gnovm/pkg/transpiler" ) func isGnoFile(f fs.DirEntry) bool { @@ -25,84 +21,69 @@ func isFileExist(path string) bool { return err == nil } -func gnoFilesFromArgs(args []string) ([]string, error) { - paths := []string{} - for _, arg := range args { - info, err := os.Stat(arg) +func gnoPackagesFromArgs(args []string) ([]string, error) { + var paths []string + + for _, argPath := range args { + info, err := os.Stat(argPath) if err != nil { return nil, fmt.Errorf("invalid file or package path: %w", err) } + if !info.IsDir() { - curpath := arg - paths = append(paths, curpath) - } else { - err = filepath.WalkDir(arg, func(curpath string, f fs.DirEntry, err error) error { - if err != nil { - return fmt.Errorf("%s: walk dir: %w", arg, err) - } - - if !isGnoFile(f) { - return nil // skip - } - paths = append(paths, curpath) - return nil - }) - if err != nil { - return nil, err - } + paths = append(paths, ensurePathPrefix(argPath)) + + continue + } + + // Gather package paths from the directory + err = walkDirForGnoFiles(argPath, func(path string) { + paths = append(paths, ensurePathPrefix(path)) + }) + if err != nil { + return nil, fmt.Errorf("unable to walk dir: %w", err) } } + return paths, nil } -func gnoPackagesFromArgs(args []string) ([]string, error) { - paths := []string{} - for _, arg := range args { - info, err := os.Stat(arg) +func ensurePathPrefix(path string) string { + if filepath.IsAbs(path) { + return path + } + + // cannot use path.Join or filepath.Join, because we need + // to ensure that ./ is the prefix to pass to go build. + // if not absolute. + return "." + string(filepath.Separator) + path +} + +func walkDirForGnoFiles(root string, addPath func(path string)) error { + visited := make(map[string]struct{}) + + walkFn := func(currPath string, f fs.DirEntry, err error) error { if err != nil { - return nil, fmt.Errorf("invalid file or package path: %w", err) + return fmt.Errorf("%s: walk dir: %w", root, err) } - if !info.IsDir() { - paths = append(paths, arg) - } else { - // if the passed arg is a dir, then we'll recursively walk the dir - // and look for directories containing at least one .gno file. - - visited := map[string]bool{} // used to run the builder only once per folder. - err = filepath.WalkDir(arg, func(curpath string, f fs.DirEntry, err error) error { - if err != nil { - return fmt.Errorf("%s: walk dir: %w", arg, err) - } - if f.IsDir() { - return nil // skip - } - if !isGnoFile(f) { - return nil // skip - } - - parentDir := filepath.Dir(curpath) - if _, found := visited[parentDir]; found { - return nil - } - visited[parentDir] = true - - pkg := parentDir - if !filepath.IsAbs(parentDir) { - // cannot use path.Join or filepath.Join, because we need - // to ensure that ./ is the prefix to pass to go build. - // if not absolute. - pkg = "./" + parentDir - } - - paths = append(paths, pkg) - return nil - }) - if err != nil { - return nil, err - } + + if f.IsDir() || !isGnoFile(f) { + return nil } + + parentDir := filepath.Dir(currPath) + if _, found := visited[parentDir]; found { + return nil + } + + visited[parentDir] = struct{}{} + + addPath(parentDir) + + return nil } - return paths, nil + + return filepath.WalkDir(root, walkFn) } // targetsFromPatterns returns a list of target paths that match the patterns. @@ -192,36 +173,27 @@ func fmtDuration(d time.Duration) string { return fmt.Sprintf("%.2fs", d.Seconds()) } -// getPathsFromImportSpec derive and returns ImportPaths -// without ImportPrefix from *ast.ImportSpec -func getPathsFromImportSpec(importSpec []*ast.ImportSpec) (importPaths []importPath) { - for _, i := range importSpec { - path := i.Path.Value[1 : len(i.Path.Value)-1] // trim leading and trailing `"` - if strings.HasPrefix(path, transpiler.ImportPrefix) { - res := strings.TrimPrefix(path, transpiler.ImportPrefix) - importPaths = append(importPaths, importPath("."+res)) - } +// ResolvePath determines the path where to place output files. +// output is the output directory provided by the user. +// dstPath is the desired output path by the gno program. +// +// If dstPath is relative non-local path (ie. contains ../), the dstPath will +// be made absolute and joined with output. +// +// Otherwise, the result is simply filepath.Join(output, dstPath). +// +// See related test for examples. +func ResolvePath(output, dstPath string) (string, error) { + if filepath.IsAbs(dstPath) || + filepath.IsLocal(dstPath) { + return filepath.Join(output, dstPath), nil } - return -} - -// ResolvePath joins the output dir with relative pkg path -// e.g -// Output Dir: Temp/gno-transpile -// Pkg Path: ../example/gno.land/p/pkg -// Returns -> Temp/gno-transpile/example/gno.land/p/pkg -func ResolvePath(output string, path importPath) (string, error) { - absOutput, err := filepath.Abs(output) + // Make dstPath absolute and join it with output. + absDst, err := filepath.Abs(dstPath) if err != nil { return "", err } - absPkgPath, err := filepath.Abs(string(path)) - if err != nil { - return "", err - } - pkgPath := strings.TrimPrefix(absPkgPath, gnoenv.RootDir()) - - return filepath.Join(absOutput, pkgPath), nil + return filepath.Join(output, absDst), nil } // WriteDirFile write file to the path and also create diff --git a/gnovm/cmd/gno/util_test.go b/gnovm/cmd/gno/util_test.go index 9e9659bfe4f..a92c924e272 100644 --- a/gnovm/cmd/gno/util_test.go +++ b/gnovm/cmd/gno/util_test.go @@ -295,3 +295,50 @@ func createGnoPackages(t *testing.T, tmpDir string) { } } } + +func TestResolvePath(t *testing.T) { + t.Parallel() + + if os.PathSeparator != '/' { + t.Skip("ResolvePath test is only written of UNIX-like filesystems") + } + wd, err := os.Getwd() + require.NoError(t, err) + tt := []struct { + output string + dstPath string + result string + }{ + { + "transpile-result", + "./examples/test/test1.gno.gen.go", + "transpile-result/examples/test/test1.gno.gen.go", + }, + { + "/transpile-result", + "./examples/test/test1.gno.gen.go", + "/transpile-result/examples/test/test1.gno.gen.go", + }, + { + "/transpile-result", + "/home/gno/examples/test/test1.gno.gen.go", + "/transpile-result/home/gno/examples/test/test1.gno.gen.go", + }, + { + "result", + "../hello", + filepath.Join("result", filepath.Join(wd, "../hello")), + }, + } + + for _, tc := range tt { + res, err := ResolvePath(tc.output, tc.dstPath) + // ResolvePath should error only in case we can't get the abs path; + // so never in normal conditions. + require.NoError(t, err) + assert.Equal(t, + tc.result, res, + "unexpected result of ResolvePath(%q, %q)", tc.output, tc.dstPath, + ) + } +} diff --git a/gnovm/pkg/gnolang/helpers.go b/gnovm/pkg/gnolang/helpers.go index 564ac0622c2..c6f7e696ea4 100644 --- a/gnovm/pkg/gnolang/helpers.go +++ b/gnovm/pkg/gnolang/helpers.go @@ -7,6 +7,34 @@ import ( "strings" ) +// ---------------------------------------- +// Functions centralizing definitions + +// RealmPathPrefix is the prefix used to identify pkgpaths which are meant to +// be realms and as such to have their state persisted. This is used by [IsRealmPath]. +const RealmPathPrefix = "gno.land/r/" + +// ReGnoRunPath is the path used for realms executed in maketx run. +// These are not considered realms, as an exception to the RealmPathPrefix rule. +var ReGnoRunPath = regexp.MustCompile(`^gno\.land/r/g[a-z0-9]+/run$`) + +// IsRealmPath determines whether the given pkgpath is for a realm, and as such +// should persist the global state. +func IsRealmPath(pkgPath string) bool { + return strings.HasPrefix(pkgPath, RealmPathPrefix) && + // MsgRun pkgPath aren't realms + !ReGnoRunPath.MatchString(pkgPath) +} + +// IsStdlib determines whether s is a pkgpath for a standard library. +func IsStdlib(s string) bool { + // NOTE(morgan): this is likely to change in the future as we add support for + // IBC/ICS and we allow import paths to other chains. It might be good to + // (eventually) follow the same rule as Go, which is: does the first + // element of the import path contain a dot? + return !strings.HasPrefix(s, "gno.land/") +} + // ---------------------------------------- // AST Construction (Expr) // These are copied over from go-amino-x, but produces Gno ASTs. diff --git a/gnovm/pkg/gnolang/helpers_test.go b/gnovm/pkg/gnolang/helpers_test.go new file mode 100644 index 00000000000..af8fa64ac79 --- /dev/null +++ b/gnovm/pkg/gnolang/helpers_test.go @@ -0,0 +1,55 @@ +package gnolang + +import ( + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestIsRealmPath(t *testing.T) { + t.Parallel() + tt := []struct { + input string + result bool + }{ + {"gno.land/r/demo/users", true}, + {"gno.land/r/hello", true}, + {"gno.land/p/demo/users", false}, + {"gno.land/p/hello", false}, + {"gno.land/x", false}, + {"std", false}, + } + + for _, tc := range tt { + assert.Equal( + t, + tc.result, + IsRealmPath(tc.input), + "unexpected IsRealmPath(%q) result", tc.input, + ) + } +} + +func TestIsStdlib(t *testing.T) { + t.Parallel() + + tt := []struct { + s string + result bool + }{ + {"std", true}, + {"math", true}, + {"very/long/path/with_underscores", true}, + {"gno.land/r/demo/users", false}, + {"gno.land/hello", false}, + } + + for _, tc := range tt { + assert.Equal( + t, + tc.result, + IsStdlib(tc.s), + "IsStdlib(%q)", tc.s, + ) + } +} diff --git a/gnovm/pkg/gnolang/nodes.go b/gnovm/pkg/gnolang/nodes.go index 482f4850b6e..2897fdd5306 100644 --- a/gnovm/pkg/gnolang/nodes.go +++ b/gnovm/pkg/gnolang/nodes.go @@ -1115,11 +1115,21 @@ func ReadMemPackage(dir string, pkgPath string) *std.MemPackage { allowedFileExtensions := []string{ ".gno", } + // exceptions to allowedFileExtensions + var rejectedFileExtensions []string + + if IsStdlib(pkgPath) { + // Allows transpilation to work on stdlibs with native fns. + allowedFileExtensions = append(allowedFileExtensions, ".go") + rejectedFileExtensions = []string{".gen.go"} + } + list := make([]string, 0, len(files)) for _, file := range files { if file.IsDir() || strings.HasPrefix(file.Name(), ".") || - (!endsWith(file.Name(), allowedFileExtensions) && !contains(allowedFiles, file.Name())) { + (!endsWith(file.Name(), allowedFileExtensions) && !contains(allowedFiles, file.Name())) || + endsWith(file.Name(), rejectedFileExtensions) { continue } list = append(list, filepath.Join(dir, file.Name())) diff --git a/gnovm/pkg/gnolang/realm.go b/gnovm/pkg/gnolang/realm.go index 85f94d4fcbe..0036f9a54bf 100644 --- a/gnovm/pkg/gnolang/realm.go +++ b/gnovm/pkg/gnolang/realm.go @@ -5,7 +5,6 @@ import ( "encoding/json" "fmt" "reflect" - "regexp" "strings" ) @@ -1514,20 +1513,6 @@ func isUnsaved(oo Object) bool { return oo.GetIsNewReal() || oo.GetIsDirty() } -// realmPathPrefix is the prefix used to identify pkgpaths which are meant to -// be realms and as such to have their state persisted. This is used by [IsRealmPath]. -const realmPathPrefix = "gno.land/r/" - -var ReGnoRunPath = regexp.MustCompile(`^gno\.land/r/g[a-z0-9]+/run$`) - -// IsRealmPath determines whether the given pkgpath is for a realm, and as such -// should persist the global state. -func IsRealmPath(pkgPath string) bool { - return strings.HasPrefix(pkgPath, realmPathPrefix) && - // MsgRun pkgPath aren't realms - !ReGnoRunPath.MatchString(pkgPath) -} - func prettyJSON(jstr []byte) []byte { var c interface{} err := json.Unmarshal(jstr, &c) diff --git a/gnovm/pkg/gnomod/file.go b/gnovm/pkg/gnomod/file.go index fda9263914e..b6ee95acac8 100644 --- a/gnovm/pkg/gnomod/file.go +++ b/gnovm/pkg/gnomod/file.go @@ -17,7 +17,7 @@ import ( "path/filepath" "strings" - "github.com/gnolang/gno/gnovm/pkg/transpiler" + gno "github.com/gnolang/gno/gnovm/pkg/gnolang" "golang.org/x/mod/modfile" "golang.org/x/mod/module" ) @@ -183,13 +183,8 @@ func (f *File) FetchDeps(path string, remote string, verbose bool) error { if strings.HasSuffix(path, modFile.Module.Mod.Path) { continue } - // skip if `std`, special case. - if path == transpiler.GnoStdPkgAfter { - continue - } - if strings.HasPrefix(path, transpiler.ImportPrefix) { - path = strings.TrimPrefix(path, transpiler.ImportPrefix+"/examples/") + if !gno.IsStdlib(path) { modFile.AddNewRequire(path, "v0.0.0-latest", true) } } diff --git a/gnovm/pkg/gnomod/gnomod.go b/gnovm/pkg/gnomod/gnomod.go index 014873b8faa..0effa532107 100644 --- a/gnovm/pkg/gnomod/gnomod.go +++ b/gnovm/pkg/gnomod/gnomod.go @@ -3,6 +3,8 @@ package gnomod import ( "errors" "fmt" + "go/parser" + gotoken "go/token" "os" "path/filepath" "strings" @@ -63,23 +65,12 @@ func writePackage(remote, basePath, pkgPath string) (requirements []string, err } else { // Is File // Transpile and write generated go file - if strings.HasSuffix(fileName, ".gno") { - filePath := filepath.Join(basePath, pkgPath) - targetFilename, _ := transpiler.GetTranspileFilenameAndTags(filePath) - transpileRes, err := transpiler.Transpile(string(res.Data), "", fileName) - if err != nil { - return nil, fmt.Errorf("transpile: %w", err) - } - - for _, i := range transpileRes.Imports { - requirements = append(requirements, i.Path.Value) - } - - targetFileNameWithPath := filepath.Join(basePath, dirPath, targetFilename) - err = os.WriteFile(targetFileNameWithPath, []byte(transpileRes.Translated), 0o644) - if err != nil { - return nil, fmt.Errorf("writefile %q: %w", targetFileNameWithPath, err) - } + file, err := parser.ParseFile(gotoken.NewFileSet(), fileName, res.Data, parser.ImportsOnly) + if err != nil { + return nil, fmt.Errorf("parse gno file: %w", err) + } + for _, i := range file.Imports { + requirements = append(requirements, i.Path.Value) } // Write file @@ -96,11 +87,12 @@ func writePackage(remote, basePath, pkgPath string) (requirements []string, err // GnoToGoMod make necessary modifications in the gno.mod // and return go.mod file. func GnoToGoMod(f File) (*File, error) { + // TODO(morgan): good candidate to move to pkg/transpiler. + gnoModPath := GetGnoModPath() - if strings.HasPrefix(f.Module.Mod.Path, transpiler.GnoRealmPkgsPrefixBefore) || - strings.HasPrefix(f.Module.Mod.Path, transpiler.GnoPurePkgsPrefixBefore) { - f.AddModuleStmt(transpiler.ImportPrefix + "/examples/" + f.Module.Mod.Path) + if !gnolang.IsStdlib(f.Module.Mod.Path) { + f.AddModuleStmt(transpiler.TranspileImportPath(f.Module.Mod.Path)) } for i := range f.Require { @@ -111,14 +103,13 @@ func GnoToGoMod(f File) (*File, error) { } } path := f.Require[i].Mod.Path - if strings.HasPrefix(f.Require[i].Mod.Path, transpiler.GnoRealmPkgsPrefixBefore) || - strings.HasPrefix(f.Require[i].Mod.Path, transpiler.GnoPurePkgsPrefixBefore) { + if !gnolang.IsStdlib(path) { // Add dependency with a modified import path - f.AddRequire(transpiler.ImportPrefix+"/examples/"+f.Require[i].Mod.Path, f.Require[i].Mod.Version) + f.AddRequire(transpiler.TranspileImportPath(path), f.Require[i].Mod.Version) } - f.AddReplace(f.Require[i].Mod.Path, f.Require[i].Mod.Version, filepath.Join(gnoModPath, path), "") + f.AddReplace(path, f.Require[i].Mod.Version, filepath.Join(gnoModPath, path), "") // Remove the old require since the new dependency was added above - f.DropRequire(f.Require[i].Mod.Path) + f.DropRequire(path) } // Remove replacements that are not replaced by directories. diff --git a/gnovm/pkg/integration/gno.go b/gnovm/pkg/integration/gno.go index ee0216fa9e8..a389b6a9b24 100644 --- a/gnovm/pkg/integration/gno.go +++ b/gnovm/pkg/integration/gno.go @@ -68,6 +68,8 @@ func SetupGno(p *testscript.Params, buildDir string) error { return fmt.Errorf("unable to create temporary home directory: %w", err) } env.Setenv("HOME", home) + // Avoids go command printing errors relating to lack of go.mod. + env.Setenv("GO111MODULE", "off") // Cleanup home folder env.Defer(func() { os.RemoveAll(home) }) diff --git a/gnovm/pkg/transpiler/transpiler.go b/gnovm/pkg/transpiler/transpiler.go index 8a91ae4a486..bd4bb1b1bc9 100644 --- a/gnovm/pkg/transpiler/transpiler.go +++ b/gnovm/pkg/transpiler/transpiler.go @@ -1,3 +1,5 @@ +// Package transpiler implements a source-to-source compiler for translating Gno +// code into Go code. package transpiler import ( @@ -9,102 +11,52 @@ import ( goscanner "go/scanner" "go/token" "os" - "os/exec" + "path" "path/filepath" - "regexp" - "sort" "strconv" "strings" + "github.com/gnolang/gno/gnovm/pkg/gnoenv" + gno "github.com/gnolang/gno/gnovm/pkg/gnolang" + "github.com/gnolang/gno/gnovm/stdlibs" "golang.org/x/tools/go/ast/astutil" ) -const ( - GnoRealmPkgsPrefixBefore = "gno.land/r/" - GnoRealmPkgsPrefixAfter = "github.com/gnolang/gno/examples/gno.land/r/" - GnoPurePkgsPrefixBefore = "gno.land/p/" - GnoPurePkgsPrefixAfter = "github.com/gnolang/gno/examples/gno.land/p/" - GnoStdPkgBefore = "std" - GnoStdPkgAfter = "github.com/gnolang/gno/gnovm/stdlibs/stdshim" -) - -var stdlibWhitelist = []string{ - // go - "bufio", - "bytes", - "compress/gzip", - "context", - "crypto/md5", - "crypto/sha1", - "crypto/chacha20", - "crypto/cipher", - "crypto/sha256", - "encoding/base64", - "encoding/binary", - "encoding/hex", - "encoding/json", - "encoding/xml", - "errors", - "hash", - "hash/adler32", - "internal/bytealg", - "internal/os", - "flag", - "fmt", - "io", - "io/util", - "math", - "math/big", - "math/bits", - "math/rand", - "net/url", - "path", - "regexp", - "sort", - "strconv", - "strings", - "text/template", - "time", - "unicode", - "unicode/utf8", - "unicode/utf16", +// ImportPrefix is the import path to the root of the gno repository, which should +// be used to create go import paths. +const ImportPrefix = "github.com/gnolang/gno" - // gno - "std", +// TranspileImportPath takes an import path s, and converts it into the full +// import path relative to the Gno repository. +func TranspileImportPath(s string) string { + return ImportPrefix + "/" + PackageDirLocation(s) } -var importPrefixWhitelist = []string{ - "github.com/gnolang/gno/_test", +// PackageDirLocation provides the supposed directory of the package, relative to the root dir. +// +// TODO(morgan): move out, this should go in a "resolver" package. +func PackageDirLocation(s string) string { + switch { + case !gno.IsStdlib(s): + return "examples/" + s + default: + return "gnovm/stdlibs/" + s + } } -const ImportPrefix = "github.com/gnolang/gno" - -type transpileResult struct { +// Result is returned by Transpile, returning the file's imports and output +// out the transpilation. +type Result struct { Imports []*ast.ImportSpec Translated string + File *ast.File } // TODO: func TranspileFile: supports caching. // TODO: func TranspilePkg: supports directories. -func guessRootDir(fileOrPkg string, goBinary string) (string, error) { - abs, err := filepath.Abs(fileOrPkg) - if err != nil { - return "", err - } - args := []string{"list", "-m", "-mod=mod", "-f", "{{.Dir}}", ImportPrefix} - cmd := exec.Command(goBinary, args...) - cmd.Dir = abs - out, err := cmd.CombinedOutput() - if err != nil { - return "", fmt.Errorf("can't guess --root-dir") - } - rootDir := strings.TrimSpace(string(out)) - return rootDir, nil -} - -// GetTranspileFilenameAndTags returns the filename and tags for transpiled files. -func GetTranspileFilenameAndTags(gnoFilePath string) (targetFilename, tags string) { +// TranspiledFilenameAndTags returns the filename and tags for transpiled files. +func TranspiledFilenameAndTags(gnoFilePath string) (targetFilename, tags string) { nameNoExtension := strings.TrimSuffix(filepath.Base(gnoFilePath), ".gno") switch { case strings.HasSuffix(gnoFilePath, "_filetest.gno"): @@ -120,17 +72,43 @@ func GetTranspileFilenameAndTags(gnoFilePath string) (targetFilename, tags strin return } -func Transpile(source string, tags string, filename string) (*transpileResult, error) { +// Transpile performs transpilation on the given source code. tags can be used +// to specify build tags; and filename helps generate useful error messages and +// discriminate between test and normal source files. +func Transpile(source, tags, filename string) (*Result, error) { fset := token.NewFileSet() - f, err := parser.ParseFile(fset, filename, source, parser.ParseComments) + f, err := parser.ParseFile(fset, filename, source, + // SkipObjectResolution -- unused here. + // ParseComments -- so that they show up when re-building the AST. + parser.SkipObjectResolution|parser.ParseComments) if err != nil { return nil, fmt.Errorf("parse: %w", err) } isTestFile := strings.HasSuffix(filename, "_test.gno") || strings.HasSuffix(filename, "_filetest.gno") - shouldCheckWhitelist := !isTestFile + ctx := &transpileCtx{ + rootDir: gnoenv.RootDir(), + } + stdlibPrefix := filepath.Join(ctx.rootDir, "gnovm", "stdlibs") + if isTestFile { + // XXX(morgan): this disables checking that a package exists (in examples or stdlibs) + // when transpiling a test file. After all Gno functions, including those in + // tests/imports.go are converted to native bindings, support should + // be added for transpiling stdlibs only available in tests/stdlibs, and + // enable as such "package checking" also on test files. + ctx.rootDir = "" + } + if strings.HasPrefix(filename, stdlibPrefix) { + // this is a standard library. Mark it in the options so the native + // bindings resolve correctly. + path := strings.TrimPrefix(filename, stdlibPrefix) + path = filepath.ToSlash(filepath.Dir(path)) + path = strings.TrimLeft(path, "/") + + ctx.stdlibPath = path + } - transformed, err := transpileAST(fset, f, shouldCheckWhitelist) + transformed, err := ctx.transformFile(fset, f) if err != nil { return nil, fmt.Errorf("transpileAST: %w", err) } @@ -152,190 +130,64 @@ func Transpile(source string, tags string, filename string) (*transpileResult, e return nil, fmt.Errorf("format.Node: %w", err) } - res := &transpileResult{ + res := &Result{ Imports: f.Imports, Translated: out.String(), + File: transformed, } return res, nil } -// TranspileVerifyFile tries to run `go fmt` against a transpiled .go file. -// -// This is fast and won't look the imports. -func TranspileVerifyFile(path string, gofmtBinary string) error { - // TODO: use cmd/parser instead of exec? +type transpileCtx struct { + // If rootDir is given, we will check that the directory of the import path + // exists (using rootDir/packageDirLocation()). + rootDir string + // This should be set if we're working with a file from a standard library. + // This allows us to easily check if a function has a native binding, and as + // such modify its call expressions appropriately. + stdlibPath string - args := strings.Split(gofmtBinary, " ") - args = append(args, []string{"-l", "-e", path}...) - cmd := exec.Command(args[0], args[1:]...) - out, err := cmd.CombinedOutput() - if err != nil { - fmt.Fprintln(os.Stderr, string(out)) - return fmt.Errorf("%s: %w", gofmtBinary, err) - } - return nil -} - -// TranspileBuildPackage tries to run `go build` against the transpiled .go files. -// -// This method is the most efficient to detect errors but requires that -// all the import are valid and available. -func TranspileBuildPackage(fileOrPkg, goBinary string) error { - // TODO: use cmd/compile instead of exec? - // TODO: find the nearest go.mod file, chdir in the same folder, rim prefix? - // TODO: temporarily create an in-memory go.mod or disable go modules for gno? - // TODO: ignore .go files that were not generated from gno? - // TODO: automatically transpile if not yet done. - - files := []string{} - - info, err := os.Stat(fileOrPkg) - if err != nil { - return fmt.Errorf("invalid file or package path %s: %w", fileOrPkg, err) - } - if !info.IsDir() { - file := fileOrPkg - files = append(files, file) - } else { - pkgDir := fileOrPkg - goGlob := filepath.Join(pkgDir, "*.go") - goMatches, err := filepath.Glob(goGlob) - if err != nil { - return fmt.Errorf("glob %s: %w", goGlob, err) - } - for _, goMatch := range goMatches { - switch { - case strings.HasPrefix(goMatch, "."): // skip - case strings.HasSuffix(goMatch, "_filetest.go"): // skip - case strings.HasSuffix(goMatch, "_filetest.gno.gen.go"): // skip - case strings.HasSuffix(goMatch, "_test.go"): // skip - case strings.HasSuffix(goMatch, "_test.gno.gen.go"): // skip - default: - files = append(files, goMatch) - } - } - } - - sort.Strings(files) - args := append([]string{"build", "-v", "-tags=gno"}, files...) - cmd := exec.Command(goBinary, args...) - rootDir, err := guessRootDir(fileOrPkg, goBinary) - if err == nil { - cmd.Dir = rootDir - } - out, err := cmd.CombinedOutput() - if _, ok := err.(*exec.ExitError); ok { - // exit error - return parseGoBuildErrors(string(out)) - } - return err -} - -var reGoBuildError = regexp.MustCompile(`(?m)^(\S+):(\d+):(\d+): (.+)$`) - -// parseGoBuildErrors returns a scanner.ErrorList filled with all errors found -// in out, which is supposed to be the output of the `go build` command. -// -// TODO(tb): update when `go build -json` is released to replace regexp usage. -// See https://github.com/golang/go/issues/62067 -func parseGoBuildErrors(out string) error { - var errList goscanner.ErrorList - matches := reGoBuildError.FindAllStringSubmatch(out, -1) - for _, match := range matches { - filename := match[1] - line, err := strconv.Atoi(match[2]) - if err != nil { - return fmt.Errorf("parse line go build error %s: %w", match, err) - } - - column, err := strconv.Atoi(match[3]) - if err != nil { - return fmt.Errorf("parse column go build error %s: %w", match, err) - } - msg := match[4] - errList.Add(token.Position{ - Filename: filename, - Line: line, - Column: column, - }, msg) - } - return errList.Err() + stdlibImports map[string]string // symbol -> import path } -func transpileAST(fset *token.FileSet, f *ast.File, checkWhitelist bool) (ast.Node, error) { +func (ctx *transpileCtx) transformFile(fset *token.FileSet, f *ast.File) (*ast.File, error) { var errs goscanner.ErrorList imports := astutil.Imports(fset, f) + ctx.stdlibImports = make(map[string]string) - // import whitelist - if checkWhitelist { - for _, paragraph := range imports { - for _, importSpec := range paragraph { - importPath := strings.TrimPrefix(strings.TrimSuffix(importSpec.Path.Value, `"`), `"`) - - if strings.HasPrefix(importPath, GnoRealmPkgsPrefixBefore) { - continue - } - - if strings.HasPrefix(importPath, GnoPurePkgsPrefixBefore) { - continue - } - - valid := false - for _, whitelisted := range stdlibWhitelist { - if importPath == whitelisted { - valid = true - break - } - } - if valid { - continue - } - - for _, whitelisted := range importPrefixWhitelist { - if strings.HasPrefix(importPath, whitelisted) { - valid = true - break - } - } - if valid { - continue - } - - errs.Add(fset.Position(importSpec.Pos()), fmt.Sprintf("import %q is not in the whitelist", importPath)) - } - } - } - - // rewrite imports + // rewrite imports to point to stdlibs/ or examples/ for _, paragraph := range imports { for _, importSpec := range paragraph { - importPath := strings.TrimPrefix(strings.TrimSuffix(importSpec.Path.Value, `"`), `"`) - - // std package - if importPath == GnoStdPkgBefore { - if !astutil.RewriteImport(fset, f, GnoStdPkgBefore, GnoStdPkgAfter) { - errs.Add(fset.Position(importSpec.Pos()), fmt.Sprintf("failed to replace the %q package with %q", GnoStdPkgBefore, GnoStdPkgAfter)) - } + importPath, err := strconv.Unquote(importSpec.Path.Value) + if err != nil { + errs.Add(fset.Position(importSpec.Pos()), fmt.Sprintf("can't unquote import path %s: %v", importSpec.Path.Value, err)) + continue } - // p/pkg packages - if strings.HasPrefix(importPath, GnoPurePkgsPrefixBefore) { - target := GnoPurePkgsPrefixAfter + strings.TrimPrefix(importPath, GnoPurePkgsPrefixBefore) - - if !astutil.RewriteImport(fset, f, importPath, target) { - errs.Add(fset.Position(importSpec.Pos()), fmt.Sprintf("failed to replace the %q package with %q", importPath, target)) + if ctx.rootDir != "" { + dirPath := filepath.Join(ctx.rootDir, PackageDirLocation(importPath)) + if _, err := os.Stat(dirPath); err != nil { + if !os.IsNotExist(err) { + return nil, err + } + errs.Add(fset.Position(importSpec.Pos()), fmt.Sprintf("import %q does not exist", importPath)) + continue } } - // r/realm packages - if strings.HasPrefix(importPath, GnoRealmPkgsPrefixBefore) { - target := GnoRealmPkgsPrefixAfter + strings.TrimPrefix(importPath, GnoRealmPkgsPrefixBefore) - - if !astutil.RewriteImport(fset, f, importPath, target) { - errs.Add(fset.Position(importSpec.Pos()), fmt.Sprintf("failed to replace the %q package with %q", importPath, target)) + // Create mapping + if gno.IsStdlib(importPath) { + if importSpec.Name != nil { + ctx.stdlibImports[importSpec.Name.Name] = importPath + } else { + // XXX: imperfect, see comment on transformCallExpr + ctx.stdlibImports[path.Base(importPath)] = importPath } } + + transp := TranspileImportPath(importPath) + importSpec.Path.Value = strconv.Quote(transp) } } @@ -343,14 +195,72 @@ func transpileAST(fset *token.FileSet, f *ast.File, checkWhitelist bool) (ast.No node := astutil.Apply(f, // pre func(c *astutil.Cursor) bool { - // do things here + node := c.Node() + // is function declaration without body? + // -> delete (native binding) + if fd, ok := node.(*ast.FuncDecl); ok && fd.Body == nil { + c.Delete() + return false // don't attempt to traverse children + } + + // is function call to a native function? + // -> rename if unexported, apply `nil,` for the first arg if necessary + if ce, ok := node.(*ast.CallExpr); ok { + return ctx.transformCallExpr(c, ce) + } + return true }, + // post func(c *astutil.Cursor) bool { - // and here return true }, ) - return node, errs.Err() + return node.(*ast.File), errs.Err() +} + +func (ctx *transpileCtx) transformCallExpr(_ *astutil.Cursor, ce *ast.CallExpr) bool { + switch fe := ce.Fun.(type) { + case *ast.SelectorExpr: + // XXX: This is not correct in 100% of cases. If I shadow the `std` symbol, and + // its replacement is a type with the method AssertOriginCall, this system + // will incorrectly add a `nil` as the first argument. + // A full fix requires understanding scope; the Go standard library recommends + // using go/types, which for proper functioning requires an importer + // which can work with Gno. This is deferred for a future PR. + id, ok := fe.X.(*ast.Ident) + if !ok { + break + } + ip, ok := ctx.stdlibImports[id.Name] + if !ok { + break + } + nat := stdlibs.FindNative(ip, gno.Name(fe.Sel.Name)) + if nat != nil && nat.HasMachineParam() { + // Because it's an import, the symbol is always exported, so no need for the + // X_ prefix we add below. + ce.Args = append([]ast.Expr{ast.NewIdent("nil")}, ce.Args...) + } + + case *ast.Ident: + // Is this a native binding? + // Note: this is only useful within packages like `std` and `math`. + // The logic here is not robust to be generic. It does not account for locally + // defined scope. However, because native bindings have a narrowly defined and + // controlled scope (standard libraries) this will work for our usecase. + nat := stdlibs.FindNative(ctx.stdlibPath, gno.Name(fe.Name)) + if ctx.stdlibPath != "" && nat != nil { + if nat.HasMachineParam() { + ce.Args = append([]ast.Expr{ast.NewIdent("nil")}, ce.Args...) + } + if !fe.IsExported() { + // Prefix unexported names with X_, per native binding convention + // (to export the symbol within Go). + fe.Name = "X_" + fe.Name + } + } + } + return true } diff --git a/gnovm/pkg/transpiler/transpiler_test.go b/gnovm/pkg/transpiler/transpiler_test.go index b9e9b218675..2a0707f7f79 100644 --- a/gnovm/pkg/transpiler/transpiler_test.go +++ b/gnovm/pkg/transpiler/transpiler_test.go @@ -2,21 +2,69 @@ package transpiler import ( "go/ast" - goscanner "go/scanner" - "go/token" + "path/filepath" "strings" "testing" + "github.com/gnolang/gno/gnovm/pkg/gnoenv" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) +func TestTranspiledFilenameAndTags(t *testing.T) { + t.Parallel() + + tt := []struct { + name string + changed string + tags string + }{ + { + "hello.gno", + "hello.gno.gen.go", + "gno", + }, + { + "a/b/hello.gno", + "hello.gno.gen.go", + "gno", + }, + { + "hey_test.gno", + ".hey_test.gno.gen_test.go", + "gno && test", + }, + { + "hey_filetest.gno", + ".hey_filetest.gno.gen.go", + "gno && filetest", + }, + { + "badname.go", + "badname.go.gno.gen.go", + "gno", + }, + { + "badname_test.go", + "badname_test.go.gno.gen.go", + "gno", + }, + } + + for _, tc := range tt { + newName, tags := TranspiledFilenameAndTags(tc.name) + assert.Equal(t, tc.changed, newName, "name for %q", tc.name) + assert.Equal(t, tc.tags, tags, "tags for %q", tc.name) + } +} + func TestTranspile(t *testing.T) { t.Parallel() cases := []struct { name string tags string + filename string source string expectedOutput string expectedImports []*ast.ImportSpec @@ -75,7 +123,7 @@ func hello() string { //line foo.gno:1:1 package foo -import "github.com/gnolang/gno/gnovm/stdlibs/stdshim" +import "github.com/gnolang/gno/gnovm/stdlibs/std" func hello() string { _ = std.Foo @@ -87,9 +135,8 @@ func hello() string { Path: &ast.BasicLit{ ValuePos: 21, Kind: 9, - Value: `"github.com/gnolang/gno/gnovm/stdlibs/stdshim"`, + Value: `"github.com/gnolang/gno/gnovm/stdlibs/std"`, }, - EndPos: 26, }, }, }, @@ -119,7 +166,6 @@ func foo() { _ = users.Register } Kind: 9, Value: `"github.com/gnolang/gno/examples/gno.land/r/demo/users"`, }, - EndPos: 44, }, }, }, @@ -130,7 +176,7 @@ package foo import "gno.land/p/demo/avl" -func foo() { _ = avl.Tree } +func foo() { _ = avl.NewTree("hey", 1) } `, expectedOutput: ` // Code generated by github.com/gnolang/gno. DO NOT EDIT. @@ -140,7 +186,7 @@ package foo import "github.com/gnolang/gno/examples/gno.land/p/demo/avl" -func foo() { _ = avl.Tree } +func foo() { _ = avl.NewTree("hey", 1) } `, expectedImports: []*ast.ImportSpec{ { @@ -149,7 +195,6 @@ func foo() { _ = avl.Tree } Kind: 9, Value: `"github.com/gnolang/gno/examples/gno.land/p/demo/avl"`, }, - EndPos: 42, }, }, }, @@ -171,7 +216,7 @@ func hello() string { //line foo.gno:1:1 package foo -import bar "github.com/gnolang/gno/gnovm/stdlibs/stdshim" +import bar "github.com/gnolang/gno/gnovm/stdlibs/std" func hello() string { _ = bar.Foo @@ -187,14 +232,13 @@ func hello() string { Path: &ast.BasicLit{ ValuePos: 25, Kind: 9, - Value: `"github.com/gnolang/gno/gnovm/stdlibs/stdshim"`, + Value: `"github.com/gnolang/gno/gnovm/stdlibs/std"`, }, - EndPos: 30, }, }, }, { - name: "blacklisted-package", + name: "unknown-package", source: ` package foo @@ -202,7 +246,7 @@ import "reflect" func foo() { _ = reflect.ValueOf } `, - expectedError: `transpileAST: foo.gno:3:8: import "reflect" is not in the whitelist`, + expectedError: `transpileAST: foo.gno:3:8: import "reflect" does not exist`, }, { name: "syntax-error", @@ -226,6 +270,27 @@ import "gno.land/p/demo/unknownxyz" //line foo.gno:1:1 package foo +import "github.com/gnolang/gno/examples/gno.land/p/demo/unknownxyz" +`, + expectedError: `transpileAST: foo.gno:3:8: import "gno.land/p/demo/unknownxyz" does not exist`, + }, + { + // Test files should allow unknown imports while + // we still have "native" packages. + + name: "unknown-realm-test", + filename: "foo_test.gno", + source: ` +package foo + +import "gno.land/p/demo/unknownxyz" +`, + expectedOutput: ` +// Code generated by github.com/gnolang/gno. DO NOT EDIT. + +//line foo_test.gno:1:1 +package foo + import "github.com/gnolang/gno/examples/gno.land/p/demo/unknownxyz" `, expectedImports: []*ast.ImportSpec{ @@ -235,12 +300,11 @@ import "github.com/gnolang/gno/examples/gno.land/p/demo/unknownxyz" Kind: 9, Value: `"github.com/gnolang/gno/examples/gno.land/p/demo/unknownxyz"`, }, - EndPos: 49, }, }, }, { - name: "whitelisted-package", + name: "imported-package", source: ` package foo @@ -254,7 +318,7 @@ func foo() { _ = regexp.MatchString } //line foo.gno:1:1 package foo -import "regexp" +import "github.com/gnolang/gno/gnovm/stdlibs/regexp" func foo() { _ = regexp.MatchString } `, @@ -263,11 +327,87 @@ func foo() { _ = regexp.MatchString } Path: &ast.BasicLit{ ValuePos: 21, Kind: 9, - Value: `"regexp"`, + Value: `"github.com/gnolang/gno/gnovm/stdlibs/regexp"`, }, }, }, }, + { + name: "natbind-func", + filename: filepath.Join(gnoenv.RootDir(), "gnovm/stdlibs/math/math.gno"), + source: ` +package math + +import "std" + +func Float32bits(i float32) uint32 + +func testfunc() { + println(Float32bits(3.14159)) + std.AssertOriginCall() +} + +func otherFunc() { + std := 1 + // This is (incorrectly) changed for now. + std.AssertOriginCall() +} +`, + expectedOutput: ` +// Code generated by github.com/gnolang/gno. DO NOT EDIT. + +//line math.gno:1:1 +package math + +import "github.com/gnolang/gno/gnovm/stdlibs/std" + +func testfunc() { + println(Float32bits(3.14159)) + std.AssertOriginCall(nil) +} + +func otherFunc() { + std := 1 + // This is (incorrectly) changed for now. + std.AssertOriginCall(nil) +} +`, + expectedImports: []*ast.ImportSpec{ + { + Path: &ast.BasicLit{ + ValuePos: 22, + Kind: 9, + Value: `"github.com/gnolang/gno/gnovm/stdlibs/std"`, + }, + }, + }, + }, + { + name: "natbind-std", + filename: filepath.Join(gnoenv.RootDir(), "gnovm/stdlibs/std/std.gno"), + source: ` +package std + +func AssertOriginCall() +func origCaller() string + +func testfunc() { + AssertOriginCall() + println(origCaller()) +} +`, + expectedOutput: ` +// Code generated by github.com/gnolang/gno. DO NOT EDIT. + +//line std.gno:1:1 +package std + +func testfunc() { + AssertOriginCall(nil) + println(X_origCaller(nil)) +} +`, + }, } for _, c := range cases { c := c // scopelint @@ -276,7 +416,11 @@ func foo() { _ = regexp.MatchString } // "\n" is added for better test case readability, now trim it source := strings.TrimPrefix(c.source, "\n") - res, err := Transpile(source, c.tags, "foo.gno") + filename := c.filename + if filename == "" { + filename = "foo.gno" + } + res, err := Transpile(source, c.tags, filename) if c.expectedError != "" { require.EqualError(t, err, c.expectedError) @@ -289,53 +433,3 @@ func foo() { _ = regexp.MatchString } }) } } - -func TestParseGoBuildErrors(t *testing.T) { - tests := []struct { - name string - output string - expectedError error - }{ - { - name: "empty output", - output: "", - expectedError: nil, - }, - { - name: "random output", - output: "xxx", - expectedError: nil, - }, - { - name: "some errors", - output: `xxx -main.gno:6:2: nasty error -pkg/file.gno:60:20: ugly error`, - expectedError: goscanner.ErrorList{ - &goscanner.Error{ - Pos: token.Position{ - Filename: "main.gno", - Line: 6, - Column: 2, - }, - Msg: "nasty error", - }, - &goscanner.Error{ - Pos: token.Position{ - Filename: "pkg/file.gno", - Line: 60, - Column: 20, - }, - Msg: "ugly error", - }, - }, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - err := parseGoBuildErrors(tt.output) - - assert.Equal(t, tt.expectedError, err) - }) - } -} diff --git a/gnovm/stdlibs/bytes/boundary_test.gno b/gnovm/stdlibs/bytes/boundary_test.gno index 9873b1db987..5d77c576ff8 100644 --- a/gnovm/stdlibs/bytes/boundary_test.gno +++ b/gnovm/stdlibs/bytes/boundary_test.gno @@ -1,8 +1,6 @@ // Copyright 2017 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -// -//go:build linux package bytes_test diff --git a/gnovm/stdlibs/crypto/chacha20/chacha/chacha_ref.gno b/gnovm/stdlibs/crypto/chacha20/chacha/chacha_ref.gno index 903e2653572..91e5481fc42 100644 --- a/gnovm/stdlibs/crypto/chacha20/chacha/chacha_ref.gno +++ b/gnovm/stdlibs/crypto/chacha20/chacha/chacha_ref.gno @@ -2,8 +2,6 @@ // Use of this source code is governed by a license that can be // found in the LICENSE file. -//go:build (!amd64 && !386) || gccgo || appengine || nacl - package chacha import "encoding/binary" diff --git a/gnovm/stdlibs/internal/bytealg/compare_generic.gno b/gnovm/stdlibs/internal/bytealg/compare_generic.gno index e1795e47e9a..b56d0a67e02 100644 --- a/gnovm/stdlibs/internal/bytealg/compare_generic.gno +++ b/gnovm/stdlibs/internal/bytealg/compare_generic.gno @@ -2,8 +2,6 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -//go:build !386 && !amd64 && !s390x && !arm && !arm64 && !ppc64 && !ppc64le && !mips && !mipsle && !wasm && !mips64 && !mips64le - package bytealg // import _ "unsafe" // for go:linkname @@ -35,7 +33,6 @@ samebytes: return 0 } -//go:linkname runtime_cmpstring runtime.cmpstring func runtime_cmpstring(a, b string) int { l := len(a) if len(b) < l { diff --git a/gnovm/stdlibs/internal/bytealg/count_generic.gno b/gnovm/stdlibs/internal/bytealg/count_generic.gno index 932a7c584c1..de08418fcaa 100644 --- a/gnovm/stdlibs/internal/bytealg/count_generic.gno +++ b/gnovm/stdlibs/internal/bytealg/count_generic.gno @@ -2,8 +2,6 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -//go:build !amd64 && !arm && !arm64 && !ppc64le && !ppc64 && !riscv64 && !s390x - package bytealg func Count(b []byte, c byte) int { diff --git a/gnovm/stdlibs/internal/bytealg/index_generic.gno b/gnovm/stdlibs/internal/bytealg/index_generic.gno index a59e32938e7..d751b1bc940 100644 --- a/gnovm/stdlibs/internal/bytealg/index_generic.gno +++ b/gnovm/stdlibs/internal/bytealg/index_generic.gno @@ -2,8 +2,6 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -//go:build !amd64 && !arm64 && !s390x && !ppc64le && !ppc64 - package bytealg const MaxBruteForce = 0 diff --git a/gnovm/stdlibs/internal/bytealg/indexbyte_generic.gno b/gnovm/stdlibs/internal/bytealg/indexbyte_generic.gno index 0a45f903843..47aee225df9 100644 --- a/gnovm/stdlibs/internal/bytealg/indexbyte_generic.gno +++ b/gnovm/stdlibs/internal/bytealg/indexbyte_generic.gno @@ -2,8 +2,6 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -//go:build !386 && !amd64 && !s390x && !arm && !arm64 && !ppc64 && !ppc64le && !mips && !mipsle && !mips64 && !mips64le && !riscv64 && !wasm - package bytealg func IndexByte(b []byte, c byte) int { diff --git a/gnovm/stdlibs/native.go b/gnovm/stdlibs/native.go index 7319e393c35..3dd432c90c0 100644 --- a/gnovm/stdlibs/native.go +++ b/gnovm/stdlibs/native.go @@ -16,15 +16,25 @@ import ( libs_time "github.com/gnolang/gno/gnovm/stdlibs/time" ) -type nativeFunc struct { - gnoPkg string - gnoFunc gno.Name - params []gno.FieldTypeExpr - results []gno.FieldTypeExpr - f func(m *gno.Machine) +// NativeFunc represents a function in the standard library which has a native +// (go-based) implementation, commonly referred to as a "native binding". +type NativeFunc struct { + gnoPkg string + gnoFunc gno.Name + params []gno.FieldTypeExpr + results []gno.FieldTypeExpr + hasMachine bool + f func(m *gno.Machine) } -var nativeFuncs = [...]nativeFunc{ +// HasMachineParam returns whether the given native binding has a machine parameter. +// This means that the Go version of this function expects a *gno.Machine +// as its first parameter. +func (n *NativeFunc) HasMachineParam() bool { + return n.hasMachine +} + +var nativeFuncs = [...]NativeFunc{ { "crypto/ed25519", "verify", @@ -36,6 +46,7 @@ var nativeFuncs = [...]nativeFunc{ []gno.FieldTypeExpr{ {Name: gno.N("r0"), Type: gno.X("bool")}, }, + false, func(m *gno.Machine) { b := m.LastBlock() var ( @@ -69,6 +80,7 @@ var nativeFuncs = [...]nativeFunc{ []gno.FieldTypeExpr{ {Name: gno.N("r0"), Type: gno.X("[32]byte")}, }, + false, func(m *gno.Machine) { b := m.LastBlock() var ( @@ -96,6 +108,7 @@ var nativeFuncs = [...]nativeFunc{ []gno.FieldTypeExpr{ {Name: gno.N("r0"), Type: gno.X("uint32")}, }, + false, func(m *gno.Machine) { b := m.LastBlock() var ( @@ -123,6 +136,7 @@ var nativeFuncs = [...]nativeFunc{ []gno.FieldTypeExpr{ {Name: gno.N("r0"), Type: gno.X("float32")}, }, + false, func(m *gno.Machine) { b := m.LastBlock() var ( @@ -150,6 +164,7 @@ var nativeFuncs = [...]nativeFunc{ []gno.FieldTypeExpr{ {Name: gno.N("r0"), Type: gno.X("uint64")}, }, + false, func(m *gno.Machine) { b := m.LastBlock() var ( @@ -177,6 +192,7 @@ var nativeFuncs = [...]nativeFunc{ []gno.FieldTypeExpr{ {Name: gno.N("r0"), Type: gno.X("float64")}, }, + false, func(m *gno.Machine) { b := m.LastBlock() var ( @@ -206,6 +222,7 @@ var nativeFuncs = [...]nativeFunc{ {Name: gno.N("r0"), Type: gno.X("[]string")}, {Name: gno.N("r1"), Type: gno.X("[]int64")}, }, + true, func(m *gno.Machine) { b := m.LastBlock() var ( @@ -245,6 +262,7 @@ var nativeFuncs = [...]nativeFunc{ {Name: gno.N("p4"), Type: gno.X("[]int64")}, }, []gno.FieldTypeExpr{}, + true, func(m *gno.Machine) { b := m.LastBlock() var ( @@ -281,6 +299,7 @@ var nativeFuncs = [...]nativeFunc{ []gno.FieldTypeExpr{ {Name: gno.N("r0"), Type: gno.X("int64")}, }, + true, func(m *gno.Machine) { b := m.LastBlock() var ( @@ -314,6 +333,7 @@ var nativeFuncs = [...]nativeFunc{ {Name: gno.N("p3"), Type: gno.X("int64")}, }, []gno.FieldTypeExpr{}, + true, func(m *gno.Machine) { b := m.LastBlock() var ( @@ -347,6 +367,7 @@ var nativeFuncs = [...]nativeFunc{ {Name: gno.N("p3"), Type: gno.X("int64")}, }, []gno.FieldTypeExpr{}, + true, func(m *gno.Machine) { b := m.LastBlock() var ( @@ -378,6 +399,7 @@ var nativeFuncs = [...]nativeFunc{ {Name: gno.N("p1"), Type: gno.X("[]string")}, }, []gno.FieldTypeExpr{}, + true, func(m *gno.Machine) { b := m.LastBlock() var ( @@ -400,6 +422,7 @@ var nativeFuncs = [...]nativeFunc{ "AssertOriginCall", []gno.FieldTypeExpr{}, []gno.FieldTypeExpr{}, + true, func(m *gno.Machine) { libs_std.AssertOriginCall( m, @@ -413,6 +436,7 @@ var nativeFuncs = [...]nativeFunc{ []gno.FieldTypeExpr{ {Name: gno.N("r0"), Type: gno.X("bool")}, }, + true, func(m *gno.Machine) { r0 := libs_std.IsOriginCall( m, @@ -432,6 +456,7 @@ var nativeFuncs = [...]nativeFunc{ []gno.FieldTypeExpr{ {Name: gno.N("r0"), Type: gno.X("string")}, }, + true, func(m *gno.Machine) { r0 := libs_std.GetChainID( m, @@ -451,6 +476,7 @@ var nativeFuncs = [...]nativeFunc{ []gno.FieldTypeExpr{ {Name: gno.N("r0"), Type: gno.X("int64")}, }, + true, func(m *gno.Machine) { r0 := libs_std.GetHeight( m, @@ -471,6 +497,7 @@ var nativeFuncs = [...]nativeFunc{ {Name: gno.N("r0"), Type: gno.X("[]string")}, {Name: gno.N("r1"), Type: gno.X("[]int64")}, }, + true, func(m *gno.Machine) { r0, r1 := libs_std.X_origSend( m, @@ -495,6 +522,7 @@ var nativeFuncs = [...]nativeFunc{ []gno.FieldTypeExpr{ {Name: gno.N("r0"), Type: gno.X("string")}, }, + true, func(m *gno.Machine) { r0 := libs_std.X_origCaller( m, @@ -514,6 +542,7 @@ var nativeFuncs = [...]nativeFunc{ []gno.FieldTypeExpr{ {Name: gno.N("r0"), Type: gno.X("string")}, }, + true, func(m *gno.Machine) { r0 := libs_std.X_origPkgAddr( m, @@ -535,6 +564,7 @@ var nativeFuncs = [...]nativeFunc{ []gno.FieldTypeExpr{ {Name: gno.N("r0"), Type: gno.X("string")}, }, + true, func(m *gno.Machine) { b := m.LastBlock() var ( @@ -565,6 +595,7 @@ var nativeFuncs = [...]nativeFunc{ {Name: gno.N("r0"), Type: gno.X("string")}, {Name: gno.N("r1"), Type: gno.X("string")}, }, + true, func(m *gno.Machine) { b := m.LastBlock() var ( @@ -599,6 +630,7 @@ var nativeFuncs = [...]nativeFunc{ []gno.FieldTypeExpr{ {Name: gno.N("r0"), Type: gno.X("string")}, }, + false, func(m *gno.Machine) { b := m.LastBlock() var ( @@ -627,6 +659,7 @@ var nativeFuncs = [...]nativeFunc{ []gno.FieldTypeExpr{ {Name: gno.N("r0"), Type: gno.X("string")}, }, + false, func(m *gno.Machine) { b := m.LastBlock() var ( @@ -659,6 +692,7 @@ var nativeFuncs = [...]nativeFunc{ {Name: gno.N("r1"), Type: gno.X("[20]byte")}, {Name: gno.N("r2"), Type: gno.X("bool")}, }, + false, func(m *gno.Machine) { b := m.LastBlock() var ( @@ -696,6 +730,7 @@ var nativeFuncs = [...]nativeFunc{ []gno.FieldTypeExpr{ {Name: gno.N("r0"), Type: gno.X("string")}, }, + false, func(m *gno.Machine) { b := m.LastBlock() var ( @@ -725,6 +760,7 @@ var nativeFuncs = [...]nativeFunc{ []gno.FieldTypeExpr{ {Name: gno.N("r0"), Type: gno.X("[]byte")}, }, + false, func(m *gno.Machine) { b := m.LastBlock() var ( @@ -759,6 +795,7 @@ var nativeFuncs = [...]nativeFunc{ {Name: gno.N("r0"), Type: gno.X("int")}, {Name: gno.N("r1"), Type: gno.X("error")}, }, + false, func(m *gno.Machine) { b := m.LastBlock() var ( @@ -791,6 +828,7 @@ var nativeFuncs = [...]nativeFunc{ []gno.FieldTypeExpr{ {Name: gno.N("r0"), Type: gno.X("bool")}, }, + false, func(m *gno.Machine) { b := m.LastBlock() var ( @@ -819,6 +857,7 @@ var nativeFuncs = [...]nativeFunc{ []gno.FieldTypeExpr{ {Name: gno.N("r0"), Type: gno.X("string")}, }, + false, func(m *gno.Machine) { b := m.LastBlock() var ( @@ -850,6 +889,7 @@ var nativeFuncs = [...]nativeFunc{ []gno.FieldTypeExpr{ {Name: gno.N("r0"), Type: gno.X("string")}, }, + false, func(m *gno.Machine) { b := m.LastBlock() var ( @@ -880,6 +920,7 @@ var nativeFuncs = [...]nativeFunc{ []gno.FieldTypeExpr{ {Name: gno.N("r0"), Type: gno.X("string")}, }, + false, func(m *gno.Machine) { b := m.LastBlock() var ( @@ -907,6 +948,7 @@ var nativeFuncs = [...]nativeFunc{ []gno.FieldTypeExpr{ {Name: gno.N("r0"), Type: gno.X("string")}, }, + false, func(m *gno.Machine) { b := m.LastBlock() var ( @@ -932,6 +974,7 @@ var nativeFuncs = [...]nativeFunc{ []gno.FieldTypeExpr{ {Name: gno.N("r0"), Type: gno.X("int64")}, }, + false, func(m *gno.Machine) { r0 := libs_testing.X_unixNano() @@ -951,6 +994,7 @@ var nativeFuncs = [...]nativeFunc{ {Name: gno.N("r1"), Type: gno.X("int32")}, {Name: gno.N("r2"), Type: gno.X("int64")}, }, + true, func(m *gno.Machine) { r0, r1, r2 := libs_time.X_now( m, diff --git a/gnovm/stdlibs/stdlibs.go b/gnovm/stdlibs/stdlibs.go index 48e69f78253..c9b16815ab5 100644 --- a/gnovm/stdlibs/stdlibs.go +++ b/gnovm/stdlibs/stdlibs.go @@ -13,11 +13,24 @@ func GetContext(m *gno.Machine) ExecContext { return libsstd.GetContext(m) } -func NativeStore(pkgPath string, name gno.Name) func(*gno.Machine) { - for _, nf := range nativeFuncs { +// FindNative returns the NativeFunc associated with the given pkgPath+name +// combination. If there is none, FindNative returns nil. +func FindNative(pkgPath string, name gno.Name) *NativeFunc { + for i, nf := range nativeFuncs { if nf.gnoPkg == pkgPath && name == nf.gnoFunc { - return nf.f + return &nativeFuncs[i] } } return nil } + +// NativeStore is used by the GnoVM to determine if the given function, +// specified by its pkgPath and name, has a native implementation; and if so +// retrieve it. +func NativeStore(pkgPath string, name gno.Name) func(*gno.Machine) { + nt := FindNative(pkgPath, name) + if nt == nil { + return nil + } + return nt.f +} diff --git a/gnovm/stdlibs/stdshim/addr_set.gno b/gnovm/stdlibs/stdshim/addr_set.gno deleted file mode 100644 index 3f46f48b8b5..00000000000 --- a/gnovm/stdlibs/stdshim/addr_set.gno +++ /dev/null @@ -1,47 +0,0 @@ -package std - -import "errors" - -//---------------------------------------- -// AddressSet - -type AddressSet interface { - Size() int - AddAddress(Address) error - HasAddress(Address) bool -} - -//---------------------------------------- -// AddressList implements AddressSet. -// TODO implement AddressTree with avl. - -type AddressList []Address - -func NewAddressList() *AddressList { - return &AddressList{} -} - -func (alist *AddressList) Size() int { - return len(*alist) -} - -func (alist *AddressList) AddAddress(newAddr Address) error { - // TODO optimize with binary algorithm - for _, addr := range *alist { - if addr == newAddr { - return errors.New("address already exists") - } - } - *alist = append(*alist, newAddr) - return nil -} - -func (alist *AddressList) HasAddress(newAddr Address) bool { - // TODO optimize with binary algorithm - for _, addr := range *alist { - if addr == newAddr { - return true - } - } - return false -} diff --git a/gnovm/stdlibs/stdshim/banker.gno b/gnovm/stdlibs/stdshim/banker.gno deleted file mode 100644 index 44e611b780f..00000000000 --- a/gnovm/stdlibs/stdshim/banker.gno +++ /dev/null @@ -1,70 +0,0 @@ -package std - -// Realm functions can call std.GetBanker(options) to get -// a banker instance. Banker objects cannot be persisted, -// but can be passed onto other functions to be transacted -// on. A banker instance can be passed onto other realm -// functions; this allows other realms to spend coins on -// behalf of the first realm. -// -// Banker panics on errors instead of returning errors. -// This also helps simplify the interface and prevent -// hidden bugs (e.g. ignoring errors) -// -// NOTE: this Gno interface is satisfied by a native go -// type, and those can't return non-primitive objects -// (without confusion). -type Banker interface { - GetCoins(addr Address) (dst Coins) - SendCoins(from, to Address, amt Coins) - TotalCoin(denom string) int64 - IssueCoin(addr Address, denom string, amount int64) - RemoveCoin(addr Address, denom string, amount int64) -} - -// Also available natively in stdlibs/context.go -type BankerType uint8 - -// Also available natively in stdlibs/context.go -const ( - // Can only read state. - BankerTypeReadonly BankerType = iota - // Can only send from tx send. - BankerTypeOrigSend - // Can send from all realm coins. - BankerTypeRealmSend - // Can issue and remove realm coins. - BankerTypeRealmIssue -) - -//---------------------------------------- -// adapter for native banker - -type bankAdapter struct { - nativeBanker Banker -} - -func (ba bankAdapter) GetCoins(addr Address) (dst Coins) { - // convert native -> gno - coins := ba.nativeBanker.GetCoins(addr) - for _, coin := range coins { - dst = append(dst, (Coin)(coin)) - } - return dst -} - -func (ba bankAdapter) SendCoins(from, to Address, amt Coins) { - ba.nativeBanker.SendCoins(from, to, amt) -} - -func (ba bankAdapter) TotalCoin(denom string) int64 { - return ba.nativeBanker.TotalCoin(denom) -} - -func (ba bankAdapter) IssueCoin(addr Address, denom string, amount int64) { - ba.nativeBanker.IssueCoin(addr, denom, amount) -} - -func (ba bankAdapter) RemoveCoin(addr Address, denom string, amount int64) { - ba.nativeBanker.RemoveCoin(addr, denom, amount) -} diff --git a/gnovm/stdlibs/stdshim/coins.gno b/gnovm/stdlibs/stdshim/coins.gno deleted file mode 100644 index 4589113bff4..00000000000 --- a/gnovm/stdlibs/stdshim/coins.gno +++ /dev/null @@ -1,174 +0,0 @@ -package std - -import "strconv" - -// NOTE: this is selectively copied over from tm2/pkgs/std/coin.go - -// Coin hold some amount of one currency. -// A negative amount is invalid. -type Coin struct { - Denom string `json:"denom"` - Amount int64 `json:"amount"` -} - -// NewCoin returns a new coin with a denomination and amount -func NewCoin(denom string, amount int64) Coin { - return Coin{ - Denom: denom, - Amount: amount, - } -} - -// String provides a human-readable representation of a coin -func (c Coin) String() string { - return strconv.Itoa(int(c.Amount)) + c.Denom -} - -// IsGTE returns true if they are the same type and the receiver is -// an equal or greater value -func (c Coin) IsGTE(other Coin) bool { - mustMatchDenominations(c.Denom, other.Denom) - - return c.Amount >= other.Amount -} - -// IsLT returns true if they are the same type and the receiver is -// a smaller value -func (c Coin) IsLT(other Coin) bool { - mustMatchDenominations(c.Denom, other.Denom) - - return c.Amount < other.Amount -} - -// IsEqual returns true if the two sets of Coins have the same value -func (c Coin) IsEqual(other Coin) bool { - mustMatchDenominations(c.Denom, other.Denom) - - return c.Amount == other.Amount -} - -// Add adds amounts of two coins with same denom. -// If the coins differ in denom then it panics. -// An overflow or underflow panics. -// An invalid result panics. -func (c Coin) Add(coinB Coin) Coin { - mustMatchDenominations(c.Denom, coinB.Denom) - - sum := c.Amount + coinB.Amount - - c.Amount = sum - return c -} - -// Sub subtracts amounts of two coins with same denom. -// If the coins differ in denom then it panics. -// An overflow or underflow panics. -// An invalid result panics. -func (c Coin) Sub(coinB Coin) Coin { - mustMatchDenominations(c.Denom, coinB.Denom) - - dff := c.Amount - coinB.Amount - c.Amount = dff - - return c -} - -// IsPositive returns true if coin amount is positive. -func (c Coin) IsPositive() bool { - return c.Amount > 0 -} - -// IsNegative returns true if the coin amount is negative and false otherwise. -func (c Coin) IsNegative() bool { - return c.Amount < 0 -} - -// IsZero returns if this represents no money -func (c Coin) IsZero() bool { - return c.Amount == 0 -} - -func mustMatchDenominations(denomA, denomB string) { - if denomA != denomB { - panic("incompatible coin denominations: " + denomA + ", " + denomB) - } -} - -// Coins is a set of Coin, one per currency -type Coins []Coin - -// NewCoins returns a new set of Coins given one or more Coins -// Consolidates any denom duplicates into one, keeping the properties of a mathematical set -func NewCoins(coins ...Coin) Coins { - coinMap := make(map[string]int64) - - for _, coin := range coins { - coinMap[coin.Denom] = coin.Amount - } - - var setCoins Coins - for denom, amount := range coinMap { - setCoins = append(setCoins, NewCoin(denom, amount)) - } - - return setCoins -} - -// String returns the string representation of Coins -func (cz Coins) String() string { - if len(cz) == 0 { - return "" - } - - res := "" - for i, c := range cz { - if i > 0 { - res += "," - } - res += c.String() - } - - return res -} - -// AmountOf returns the amount of a specific coin from the Coins set -func (cz Coins) AmountOf(denom string) int64 { - for _, c := range cz { - if c.Denom == denom { - return c.Amount - } - } - - return 0 -} - -// Add adds a Coin to the Coins set -func (cz Coins) Add(b Coins) Coins { - c := Coins{} - for _, ac := range cz { - bc := b.AmountOf(ac.Denom) - ac.Amount += bc - c = append(c, ac) - } - - for _, bc := range b { - cc := c.AmountOf(bc.Denom) - if cc == 0 { - c = append(c, bc) - } - } - - return c -} - -// expandNative expands for usage within natively bound functions. -func (cz Coins) expandNative() (denoms []string, amounts []int64) { - denoms = make([]string, len(cz)) - amounts = make([]int64, len(cz)) - for i, coin := range cz { - denoms[i] = coin.Denom - amounts[i] = coin.Amount - } - - return denoms, amounts -} diff --git a/gnovm/stdlibs/stdshim/context.gno b/gnovm/stdlibs/stdshim/context.gno deleted file mode 100644 index 878c963b22b..00000000000 --- a/gnovm/stdlibs/stdshim/context.gno +++ /dev/null @@ -1,4 +0,0 @@ -package std - -// ExecContext is not exposed, -// use native injections std.GetChainID(), std.GetHeight() etc instead. diff --git a/gnovm/stdlibs/stdshim/crypto.gno b/gnovm/stdlibs/stdshim/crypto.gno deleted file mode 100644 index 402a6af3e22..00000000000 --- a/gnovm/stdlibs/stdshim/crypto.gno +++ /dev/null @@ -1,17 +0,0 @@ -package std - -type Address string // NOTE: bech32 - -func (a Address) String() string { - return string(a) -} - -// IsValid checks if the address is valid bech32 encoded string -func (a Address) IsValid() bool { - _, _, ok := DecodeBech32(a) - return ok -} - -const RawAddressSize = 20 - -type RawAddress [RawAddressSize]byte diff --git a/gnovm/stdlibs/stdshim/frame.gno b/gnovm/stdlibs/stdshim/frame.gno deleted file mode 100644 index bc3a000f5a0..00000000000 --- a/gnovm/stdlibs/stdshim/frame.gno +++ /dev/null @@ -1,18 +0,0 @@ -package std - -type Realm struct { - addr Address - pkgPath string -} - -func (r Realm) Addr() Address { - return r.addr -} - -func (r Realm) PkgPath() string { - return r.pkgPath -} - -func (r Realm) IsUser() bool { - return r.pkgPath == "" -} diff --git a/gnovm/stdlibs/time/time.gno b/gnovm/stdlibs/time/time.gno index 521679e48d5..f3395142d1d 100644 --- a/gnovm/stdlibs/time/time.gno +++ b/gnovm/stdlibs/time/time.gno @@ -80,7 +80,6 @@ package time import ( "errors" - // XXX _ "unsafe" // for go:linkname ) // A Time represents an instant in time with nanosecond precision. @@ -1072,8 +1071,6 @@ func daysSinceEpoch(year int) uint64 { func now() (sec int64, nsec int32, mono int64) // injected // runtimeNano returns the current value of the runtime clock in nanoseconds. -// -//go:linkname runtimeNano runtime.nanotime func runtimeNano() int64 { _, _, mono := now() return mono diff --git a/gnovm/tests/stdlibs/native.go b/gnovm/tests/stdlibs/native.go index 0f33548054b..d2964a7958c 100644 --- a/gnovm/tests/stdlibs/native.go +++ b/gnovm/tests/stdlibs/native.go @@ -11,20 +11,31 @@ import ( testlibs_testing "github.com/gnolang/gno/gnovm/tests/stdlibs/testing" ) -type nativeFunc struct { - gnoPkg string - gnoFunc gno.Name - params []gno.FieldTypeExpr - results []gno.FieldTypeExpr - f func(m *gno.Machine) +// NativeFunc represents a function in the standard library which has a native +// (go-based) implementation, commonly referred to as a "native binding". +type NativeFunc struct { + gnoPkg string + gnoFunc gno.Name + params []gno.FieldTypeExpr + results []gno.FieldTypeExpr + hasMachine bool + f func(m *gno.Machine) } -var nativeFuncs = [...]nativeFunc{ +// HasMachineParam returns whether the given native binding has a machine parameter. +// This means that the Go version of this function expects a *gno.Machine +// as its first parameter. +func (n *NativeFunc) HasMachineParam() bool { + return n.hasMachine +} + +var nativeFuncs = [...]NativeFunc{ { "std", "AssertOriginCall", []gno.FieldTypeExpr{}, []gno.FieldTypeExpr{}, + true, func(m *gno.Machine) { testlibs_std.AssertOriginCall( m, @@ -38,6 +49,7 @@ var nativeFuncs = [...]nativeFunc{ []gno.FieldTypeExpr{ {Name: gno.N("r0"), Type: gno.X("bool")}, }, + true, func(m *gno.Machine) { r0 := testlibs_std.IsOriginCall( m, @@ -57,6 +69,7 @@ var nativeFuncs = [...]nativeFunc{ {Name: gno.N("p0"), Type: gno.X("int64")}, }, []gno.FieldTypeExpr{}, + true, func(m *gno.Machine) { b := m.LastBlock() var ( @@ -76,6 +89,7 @@ var nativeFuncs = [...]nativeFunc{ "ClearStoreCache", []gno.FieldTypeExpr{}, []gno.FieldTypeExpr{}, + true, func(m *gno.Machine) { testlibs_std.ClearStoreCache( m, @@ -91,6 +105,7 @@ var nativeFuncs = [...]nativeFunc{ []gno.FieldTypeExpr{ {Name: gno.N("r0"), Type: gno.X("string")}, }, + true, func(m *gno.Machine) { b := m.LastBlock() var ( @@ -118,6 +133,7 @@ var nativeFuncs = [...]nativeFunc{ {Name: gno.N("p0"), Type: gno.X("string")}, }, []gno.FieldTypeExpr{}, + true, func(m *gno.Machine) { b := m.LastBlock() var ( @@ -139,6 +155,7 @@ var nativeFuncs = [...]nativeFunc{ {Name: gno.N("p0"), Type: gno.X("string")}, }, []gno.FieldTypeExpr{}, + true, func(m *gno.Machine) { b := m.LastBlock() var ( @@ -161,6 +178,7 @@ var nativeFuncs = [...]nativeFunc{ {Name: gno.N("p1"), Type: gno.X("string")}, }, []gno.FieldTypeExpr{}, + true, func(m *gno.Machine) { b := m.LastBlock() var ( @@ -188,6 +206,7 @@ var nativeFuncs = [...]nativeFunc{ {Name: gno.N("p3"), Type: gno.X("[]int64")}, }, []gno.FieldTypeExpr{}, + true, func(m *gno.Machine) { b := m.LastBlock() var ( @@ -220,6 +239,7 @@ var nativeFuncs = [...]nativeFunc{ {Name: gno.N("p2"), Type: gno.X("[]int64")}, }, []gno.FieldTypeExpr{}, + true, func(m *gno.Machine) { b := m.LastBlock() var ( @@ -250,6 +270,7 @@ var nativeFuncs = [...]nativeFunc{ {Name: gno.N("r0"), Type: gno.X("string")}, {Name: gno.N("r1"), Type: gno.X("string")}, }, + true, func(m *gno.Machine) { b := m.LastBlock() var ( @@ -282,6 +303,7 @@ var nativeFuncs = [...]nativeFunc{ []gno.FieldTypeExpr{ {Name: gno.N("r0"), Type: gno.X("int64")}, }, + false, func(m *gno.Machine) { r0 := testlibs_testing.X_unixNano() diff --git a/misc/genstd/template.tmpl b/misc/genstd/template.tmpl index f2cad0a851b..bfbe252a2d5 100644 --- a/misc/genstd/template.tmpl +++ b/misc/genstd/template.tmpl @@ -12,15 +12,25 @@ import ( {{- end }} ) -type nativeFunc struct { - gnoPkg string - gnoFunc gno.Name - params []gno.FieldTypeExpr - results []gno.FieldTypeExpr - f func(m *gno.Machine) +// NativeFunc represents a function in the standard library which has a native +// (go-based) implementation, commonly referred to as a "native binding". +type NativeFunc struct { + gnoPkg string + gnoFunc gno.Name + params []gno.FieldTypeExpr + results []gno.FieldTypeExpr + hasMachine bool + f func(m *gno.Machine) } -var nativeFuncs = [...]nativeFunc{ +// HasMachineParam returns whether the given native binding has a machine parameter. +// This means that the Go version of this function expects a *gno.Machine +// as its first parameter. +func (n *NativeFunc) HasMachineParam() bool { + return n.hasMachine +} + +var nativeFuncs = [...]NativeFunc{ {{- range $i, $m := .Mappings }} { {{ printf "%q" $m.GnoImportPath }}, @@ -36,6 +46,7 @@ var nativeFuncs = [...]nativeFunc{ {Name: gno.N("r{{ $i }}"), Type: gno.X({{ printf "%q" $r.GnoType }})}, {{- end }} }, + {{ if $m.MachineParam }}true{{ else }}false{{ end }}, func(m *gno.Machine) { {{ if $m.Params -}} b := m.LastBlock() From 813cb0f1f3093b77f4afaf13840c83b0941784c2 Mon Sep 17 00:00:00 2001 From: Manfred Touron <94029+moul@users.noreply.github.com> Date: Wed, 19 Jun 2024 17:39:46 +0200 Subject: [PATCH 20/26] chore: update CODEOWNERS (#2387) Co-authored-by: Morgan --- .github/CODEOWNERS | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index bcf4251abec..f13ce49ef45 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -31,7 +31,6 @@ /examples/gno.land/p/demo/seqid/ @thehowl /examples/gno.land/p/demo/ownable/ @leohhhn /examples/gno.land/p/demo/pausable/ @leohhhn -/examples/gno.land/p/demo/stack/ @harry-hov /examples/gno.land/p/demo/svg/ @moul /examples/gno.land/p/demo/tamagotchi/ @moul /examples/gno.land/p/demo/ui/ @moul @@ -64,11 +63,11 @@ /gnovm/ @jaekwon @moul @piux2 @thehowl /gnovm/stdlibs/ @thehowl /gnovm/tests/ @jaekwon @deelawn @thehowl @mvertes -/gnovm/cmd/gno/ @moul @thehowl @harry-hov +/gnovm/cmd/gno/ @moul @thehowl /gnovm/pkg/gnolang/ @jaekwon @moul @piux2 @deelawn /gnovm/pkg/doc/ @thehowl /gnovm/pkg/repl/ @mvertes @ajnavarro -/gnovm/pkg/gnomod/ @harry-hov +/gnovm/pkg/gnomod/ @thehowl /gnovm/pkg/gnoenv/ @gfanton /gnovm/pkg/transpiler/ @thehowl /gnovm/pkg/integration/ @gfanton @@ -91,5 +90,6 @@ /CONTRIBUTING.md @jaekwon @moul @gnolang/tech-staff /LICENSE.md @jaekwon /.github/ @moul @gnolang/tech-staff +/.github/workflows @ajnavarro @moul /.github/CODEOWNERS @jaekwon @moul /go.mod @gnolang/tech-staff # no unnecessary dependencies From 028a4edf1c8e7e60d68bb1eec316fc7473df402f Mon Sep 17 00:00:00 2001 From: Mohammed JBILOU <95973236+Molaryy@users.noreply.github.com> Date: Wed, 19 Jun 2024 17:51:46 +0200 Subject: [PATCH 21/26] chore(docs): fix example rpcclient.NewHTTPClient returning variables (#2352) In the [how to connect a Go app to Gno.land](https://docs.gno.land/how-to-guides/connect-from-go) tutorial I got an error when I tried to run this line: ```go rpc := rpcclient.NewHTTPClient("") ``` It seems that NewHTTPClient returns 2 values ```go func NewHTTPClient(rpcURL string) (*RPCClient, error); ``` and in the example we assign only one variable. I updated the examples with: ```go rpc, err := rpcclient.NewHTTPClient("") if err != nil { panic(err) } ``` There is also a step where `crypto.AddressFromBech32` is used but I didn't found when the `crypto` was imported so I also added it in the doc: ```go import ( ... crypto "github.com/gnolang/gno/tm2/pkg/crypto" ) ``` --------- Co-authored-by: Morgan --- docs/how-to-guides/connecting-from-go.md | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/docs/how-to-guides/connecting-from-go.md b/docs/how-to-guides/connecting-from-go.md index cb6ed0547b6..29067fe0ca1 100644 --- a/docs/how-to-guides/connecting-from-go.md +++ b/docs/how-to-guides/connecting-from-go.md @@ -109,7 +109,10 @@ A few things to note: You can initialize the RPC Client used to connect to the Gno.land network with the following line: ```go -rpc := rpcclient.NewHTTPClient("") +rpc, err := rpcclient.NewHTTPClient("") +if err != nil { + panic(err) +} ``` A list of Gno.land network endpoints & chain IDs can be found in the [Gno RPC @@ -139,7 +142,10 @@ func main() { } // Initialize the RPC client - rpc := rpcclient.NewHTTPClient("") + rpc, err := rpcclient.NewHTTPClient("") + if err != nil { + panic(err) + } // Initialize the gnoclient client := gnoclient.Client{ @@ -158,6 +164,13 @@ To send transactions to the chain, we need to know the account number (ID) and sequence (nonce). We can get this information by querying the chain with the `QueryAccount` function: +```go +import ( + ... + "github.com/gnolang/gno/tm2/pkg/crypto" +) +``` + ```go // Convert Gno address string to `crypto.Address` addr, err := crypto.AddressFromBech32("g1jg8mtutu9khhfwc4nxmuhcpftf0pajdhfvsqf5") // your Gno address From f0bc61176e9193df8115ef27d46c6d91e57d713d Mon Sep 17 00:00:00 2001 From: Manfred Touron <94029+moul@users.noreply.github.com> Date: Wed, 19 Jun 2024 19:20:06 +0200 Subject: [PATCH 22/26] feat: add r/demo/bar20 example (#2388) ```go // Package bar20 is similar to foo20 but exposes a safe-object that can be used // by `maketx run`, another contract importing foo20, and in the future when // we'll support `maketx call Token.XXX`. ``` This package currently has limited functionality, but it should become more useful in the future. I'm using it to demonstrate the rationale for having two implementations in the `grc20` package - one with a banker, and one with a safe object. Related with #2314 --------- Signed-off-by: moul <94029+moul@users.noreply.github.com> --- examples/gno.land/r/demo/bar20/bar20.gno | 46 +++++++++++++++++++ examples/gno.land/r/demo/bar20/bar20_test.gno | 31 +++++++++++++ examples/gno.land/r/demo/bar20/gno.mod | 7 +++ 3 files changed, 84 insertions(+) create mode 100644 examples/gno.land/r/demo/bar20/bar20.gno create mode 100644 examples/gno.land/r/demo/bar20/bar20_test.gno create mode 100644 examples/gno.land/r/demo/bar20/gno.mod diff --git a/examples/gno.land/r/demo/bar20/bar20.gno b/examples/gno.land/r/demo/bar20/bar20.gno new file mode 100644 index 00000000000..7388d87d24d --- /dev/null +++ b/examples/gno.land/r/demo/bar20/bar20.gno @@ -0,0 +1,46 @@ +// Package bar20 is similar to foo20 but exposes a safe-object that can be used +// by `maketx run`, another contract importing foo20, and in the future when +// we'll support `maketx call Token.XXX`. +package bar20 + +import ( + "std" + "strings" + + "gno.land/p/demo/grc/grc20" + "gno.land/p/demo/ufmt" +) + +var ( + banker *grc20.AdminToken // private banker. + Token grc20.IGRC20 // public safe-object. +) + +func init() { + banker = grc20.NewAdminToken("Bar", "BAR", 4) + Token = banker.GRC20() +} + +func Faucet() string { + caller := std.PrevRealm().Addr() + if err := banker.Mint(caller, 1_000_000); err != nil { + return "error: " + err.Error() + } + return "OK" +} + +func Render(path string) string { + parts := strings.Split(path, "/") + c := len(parts) + + switch { + case path == "": + return banker.RenderHome() // XXX: should be Token.RenderHome() + case c == 2 && parts[0] == "balance": + owner := std.Address(parts[1]) + balance, _ := Token.BalanceOf(owner) + return ufmt.Sprintf("%d\n", balance) + default: + return "404\n" + } +} diff --git a/examples/gno.land/r/demo/bar20/bar20_test.gno b/examples/gno.land/r/demo/bar20/bar20_test.gno new file mode 100644 index 00000000000..b2a49ebd864 --- /dev/null +++ b/examples/gno.land/r/demo/bar20/bar20_test.gno @@ -0,0 +1,31 @@ +package bar20 + +import ( + "std" + "testing" + + "gno.land/p/demo/testutils" +) + +func TestPackage(t *testing.T) { + alice := testutils.TestAddress("alice") + std.TestSetRealm(std.NewUserRealm(alice)) + std.TestSetOrigCaller(alice) // XXX: should not need this + + balance, _ := Token.BalanceOf(alice) + expected := uint64(0) + if balance != expected { + t.Errorf("balance should be %d, got %d", expected, balance) + } + + ret := Faucet() + if ret != "OK" { + t.Errorf("faucet should be OK, got %s", ret) + } + + balance, _ = Token.BalanceOf(alice) + expected = uint64(1_000_000) + if balance != expected { + t.Errorf("balance should be %d, got %d", expected, balance) + } +} diff --git a/examples/gno.land/r/demo/bar20/gno.mod b/examples/gno.land/r/demo/bar20/gno.mod new file mode 100644 index 00000000000..d104f0b9987 --- /dev/null +++ b/examples/gno.land/r/demo/bar20/gno.mod @@ -0,0 +1,7 @@ +module bar20 + +require ( + gno.land/p/demo/grc/grc20 v0.0.0-latest + gno.land/p/demo/testutils v0.0.0-latest + gno.land/p/demo/ufmt v0.0.0-latest +) From f60d4d8c03a547ba0e733d84072ef2d57751ab53 Mon Sep 17 00:00:00 2001 From: Leon Hudak <33522493+leohhhn@users.noreply.github.com> Date: Wed, 19 Jun 2024 19:36:36 +0200 Subject: [PATCH 23/26] docs: add 404 link checker / linter (#2394) ## Description This PR cherrypicks the 404 link checker / linter from #2125.
Contributors' checklist... - [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).
--- .github/workflows/docs-404-checker.yml | 31 ++++ docs/Makefile | 12 ++ docs/concepts/effective-gno.md | 2 +- docs/concepts/packages.md | 4 +- docs/concepts/tendermint2.md | 4 +- docs/concepts/testnets.md | 2 +- docs/how-to-guides/simple-library.md | 2 +- docs/reference/network-config.md | 12 +- misc/docs-linter/go.mod | 19 +++ misc/docs-linter/go.sum | 22 +++ misc/docs-linter/main.go | 218 +++++++++++++++++++++++++ misc/docs-linter/main_test.go | 126 ++++++++++++++ 12 files changed, 440 insertions(+), 14 deletions(-) create mode 100644 .github/workflows/docs-404-checker.yml create mode 100644 docs/Makefile create mode 100644 misc/docs-linter/go.mod create mode 100644 misc/docs-linter/go.sum create mode 100644 misc/docs-linter/main.go create mode 100644 misc/docs-linter/main_test.go diff --git a/.github/workflows/docs-404-checker.yml b/.github/workflows/docs-404-checker.yml new file mode 100644 index 00000000000..0fa8985366c --- /dev/null +++ b/.github/workflows/docs-404-checker.yml @@ -0,0 +1,31 @@ +name: "docs / 404 checker" + +on: + push: + paths: + - master + pull_request: + paths: + - "docs/**" + +jobs: + build: + runs-on: ubuntu-latest + + steps: + - name: Checkout code + uses: actions/checkout@v2 + + - name: Set up Go + uses: actions/setup-go@v3 + with: + go-version: '1.21' + + - name: Install dependencies + run: go mod download + + - name: Build docs + run: make -C docs/ build + + - name: Run linter + run: make -C docs/ lint \ No newline at end of file diff --git a/docs/Makefile b/docs/Makefile new file mode 100644 index 00000000000..e5bf557ef75 --- /dev/null +++ b/docs/Makefile @@ -0,0 +1,12 @@ +all: build lint + +# Build the linter +build: + cd ../misc/docs-linter && go build -o ./build/ + +# Run the linter for the docs/ folder +lint: + ../misc/docs-linter/build/linter -path . + +clean: + rm -rf ../misc/docs-linter/build \ No newline at end of file diff --git a/docs/concepts/effective-gno.md b/docs/concepts/effective-gno.md index d08a9089487..8e589f41845 100644 --- a/docs/concepts/effective-gno.md +++ b/docs/concepts/effective-gno.md @@ -679,7 +679,7 @@ For example, if you're creating a coin for cross-chain transfers, Coins are your best bet. They're IBC-ready and their strict rules offer top-notch security. -Read about how to use the Banker module [here](stdlibs/banker). +Read about how to use the Banker module [here](stdlibs/banker.md). #### GRC20 tokens diff --git a/docs/concepts/packages.md b/docs/concepts/packages.md index 79f54d4f59e..cd3e2ace96a 100644 --- a/docs/concepts/packages.md +++ b/docs/concepts/packages.md @@ -12,7 +12,7 @@ The full list of pre-deployed available packages can be found under the [demo pa In Go, the classic key/value data type is represented by the `map` construct. However, while Gno also supports the use of `map`, it is not a viable option as it lacks determinism due to its non-sequential nature. -To address this issue, Gno implements the [AVL Tree](https://en.wikipedia.org/wiki/AVL\_tree) (Adelson-Velsky-Landis Tree) as a solution. The AVL Tree is a self-balancing binary search tree. +To address this issue, Gno implements the [AVL Tree](https://en.wikipedia.org/wiki/AVL_tree) (Adelson-Velsky-Landis Tree) as a solution. The AVL Tree is a self-balancing binary search tree. The `avl` package comprises a set of functions that can manipulate the leaves and nodes of the AVL Tree. @@ -72,7 +72,7 @@ func IsApprovedForAll(owner, operator std.Address) bool * `OwnerOf`: Returns the `owner`'s address of a token specified by its `TokenID`. * `SafeTransferFrom`: Equivalent to the `TransferFrom` function of `grc20`. * The `Safe` prefix indicates that the function runs a check to ensure that the `to` address is a valid address that can receive tokens. - * As you can see from the [code](https://github.com/gnolang/gno/blob/master/examples/gno.land/p/demo/grc/grc721/basic\_nft.gno#L341), the concept of `Safe` has yet to be implemented. + * As you can see from the [code](https://github.com/gnolang/gno/blob/master/examples/gno.land/p/demo/grc/grc721/basic_nft.gno#L341), the concept of `Safe` has yet to be implemented. * `SetApprovalForAll`: Approves all tokens owned by the `owner` to an `operator`. * You may not set multiple `operator`s. * `GetApproved`: Returns the `address` of the `operator` for a token, specified with its `ID`. diff --git a/docs/concepts/tendermint2.md b/docs/concepts/tendermint2.md index a6004606a78..4dd43b0819e 100644 --- a/docs/concepts/tendermint2.md +++ b/docs/concepts/tendermint2.md @@ -34,9 +34,7 @@ on https://github.com/tendermint/tendermint2.** proto3 for encoding/decoding optimization through protoc. - MISSION: be the basis for improving the encoding standard from proto3, because proto3 length-prefixing is slow, and we need "proto4" or "amino2". - - LOOK at the auto-generated proto files! - https://github.com/gnolang/gno/blob/master/pkgs/bft/consensus/types/cstypes.proto - for example. + - LOOK at the [auto-generated proto files](https://github.com/gnolang/gno/blob/master/tm2/pkg/bft/consensus/consensus.proto)! - There was work to remove this from the CosmosSDK because Amino wasn't ready, but now that it is, it makes sense to incorporate it into Tendermint2. diff --git a/docs/concepts/testnets.md b/docs/concepts/testnets.md index 7f0734cdc28..dd6d65085cc 100644 --- a/docs/concepts/testnets.md +++ b/docs/concepts/testnets.md @@ -6,7 +6,7 @@ id: testnets This page documents all Gno.land testnets, what their properties are, and how they are meant to be used. For testnet configuration, visit the -[reference section](../reference/network-config). +[reference section](../reference/network-config.md). Gno.land testnets are categorized by 4 main points: - **Persistence of state** diff --git a/docs/how-to-guides/simple-library.md b/docs/how-to-guides/simple-library.md index 1ae231251d0..923fc98922e 100644 --- a/docs/how-to-guides/simple-library.md +++ b/docs/how-to-guides/simple-library.md @@ -34,7 +34,7 @@ and [Visual Studio Code](https://marketplace.visualstudio.com/items?itemName=har ::: We discussed Gno folder structures more in detail in -the [simple Smart Contract guide](simple-contract.md#1-setting-up-the-work-directory). +the [simple Smart Contract guide](simple-contract.md#local-setup). For now, we will just follow some rules outlined there. Create the main working directory for our Package: diff --git a/docs/reference/network-config.md b/docs/reference/network-config.md index c2ec5409fc9..0da179e8f17 100644 --- a/docs/reference/network-config.md +++ b/docs/reference/network-config.md @@ -4,12 +4,12 @@ id: network-config # Network configurations -| Network | RPC Endpoint | Chain ID | -|-------------|------------------------------------|---------------| -| Portal Loop | https://rpc.gno.land:443 | `portal-loop` | -| Testnet 4 | upcoming | upcoming | -| Testnet 3 | https://rpc.test3.gno.land:443 | `test3` | -| Staging | https://rpc.staging.gno.land:26657 | `test3` | +| Network | RPC Endpoint | Chain ID | +|-------------|-----------------------------------|---------------| +| Portal Loop | https://rpc.gno.land:443 | `portal-loop` | +| Testnet 4 | upcoming | upcoming | +| Testnet 3 | https://rpc.test3.gno.land:443 | `test3` | +| Staging | http://rpc.staging.gno.land:26657 | `staging` | ### WebSocket endpoints All networks follow the same pattern for websocket connections: diff --git a/misc/docs-linter/go.mod b/misc/docs-linter/go.mod new file mode 100644 index 00000000000..2c2840e7a6d --- /dev/null +++ b/misc/docs-linter/go.mod @@ -0,0 +1,19 @@ +module linter + +go 1.21.6 + +require ( + github.com/gnolang/gno v0.0.0-20240516161351-0c9849a8ef0c + github.com/stretchr/testify v1.9.0 + golang.org/x/sync v0.7.0 + mvdan.cc/xurls/v2 v2.5.0 +) + +require ( + github.com/davecgh/go-spew v1.1.1 // indirect + github.com/peterbourgon/ff/v3 v3.4.0 // indirect + github.com/pmezard/go-difflib v1.0.0 // indirect + golang.org/x/sys v0.18.0 // indirect + golang.org/x/term v0.18.0 // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect +) diff --git a/misc/docs-linter/go.sum b/misc/docs-linter/go.sum new file mode 100644 index 00000000000..ab8c3cf7c48 --- /dev/null +++ b/misc/docs-linter/go.sum @@ -0,0 +1,22 @@ +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/gnolang/gno v0.0.0-20240516161351-0c9849a8ef0c h1:jtZ+oN8ZpBM0wYbcFH0B7NjFFzTFqZZmZellSSKtaCE= +github.com/gnolang/gno v0.0.0-20240516161351-0c9849a8ef0c/go.mod h1:YcZbtNIfXVn4jS1pSG8SeG5RVHjyI7FPS3GypZaXxCI= +github.com/peterbourgon/ff/v3 v3.4.0 h1:QBvM/rizZM1cB0p0lGMdmR7HxZeI/ZrBWB4DqLkMUBc= +github.com/peterbourgon/ff/v3 v3.4.0/go.mod h1:zjJVUhx+twciwfDl0zBcFzl4dW8axCRyXE/eKY9RztQ= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= +github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= +golang.org/x/sync v0.7.0 h1:YsImfSBoP9QPYL0xyKJPq0gcaJdG3rInoqxTWbfQu9M= +golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +golang.org/x/sys v0.18.0 h1:DBdB3niSjOA/O0blCZBqDefyWNYveAYMNF1Wum0DYQ4= +golang.org/x/sys v0.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/term v0.18.0 h1:FcHjZXDMxI8mM3nwhX9HlKop4C0YQvCVCdwYl2wOtE8= +golang.org/x/term v0.18.0/go.mod h1:ILwASektA3OnRv7amZ1xhE/KTR+u50pbXfZ03+6Nx58= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +mvdan.cc/xurls/v2 v2.5.0 h1:lyBNOm8Wo71UknhUs4QTFUNNMyxy2JEIaKKo0RWOh+8= +mvdan.cc/xurls/v2 v2.5.0/go.mod h1:yQgaGQ1rFtJUzkmKiHYSSfuQxqfYmd//X6PxvholpeE= diff --git a/misc/docs-linter/main.go b/misc/docs-linter/main.go new file mode 100644 index 00000000000..029b2bf387a --- /dev/null +++ b/misc/docs-linter/main.go @@ -0,0 +1,218 @@ +package main + +import ( + "bufio" + "context" + "errors" + "flag" + "fmt" + "github.com/gnolang/gno/tm2/pkg/commands" + "golang.org/x/sync/errgroup" + "io" + "mvdan.cc/xurls/v2" + "net/http" + "os" + "path/filepath" + "strings" + "sync" +) + +var ( + errEmptyPath = errors.New("you need to pass in a path to scan") + err404Link = errors.New("link returned a 404") + errFound404Links = errors.New("found links resulting in a 404 response status") +) + +type cfg struct { + docsPath string +} + +func main() { + cfg := &cfg{} + + cmd := commands.NewCommand( + commands.Metadata{ + Name: "docs-linter", + ShortUsage: "docs-linter [flags]", + ShortHelp: "Finds broken 404 links in the .md files in the given folder & subfolders", + }, + cfg, + func(ctx context.Context, args []string) error { + return execLint(cfg, ctx) + }) + + cmd.Execute(context.Background(), os.Args[1:]) +} + +func (c *cfg) RegisterFlags(fs *flag.FlagSet) { + fs.StringVar( + &c.docsPath, + "path", + "./", + "path to dir to walk for .md files", + ) +} + +func execLint(cfg *cfg, ctx context.Context) error { + if cfg.docsPath == "" { + return errEmptyPath + } + + fmt.Println("Linting docs/") + + mdFiles, err := findFilePaths(cfg.docsPath) + if err != nil { + return fmt.Errorf("error finding .md files: %w", err) + } + + urlFileMap := make(map[string]string) + for _, filePath := range mdFiles { + // Extract URLs from each file + urls, err := extractUrls(filePath) + if err != nil { + fmt.Printf("Error extracting URLs from file: %s, %v", filePath, err) + continue + } + // For each url, save what file it was found in + for url, file := range urls { + urlFileMap[url] = file + } + } + + // Filter links by prefix & ignore localhost + var validUrls []string + for url := range urlFileMap { + // Look for http & https only + if strings.HasPrefix(url, "http://") || strings.HasPrefix(url, "https://") { + // Ignore localhost + if !strings.Contains(url, "localhost") && !strings.Contains(url, "127.0.0.1") { + validUrls = append(validUrls, url) + } + } + } + + // Setup parallel checking for links + g, _ := errgroup.WithContext(ctx) + + var ( + lock sync.Mutex + notFoundUrls []string + ) + + for _, url := range validUrls { + url := url + g.Go(func() error { + if err := checkUrl(url); err != nil { + lock.Lock() + notFoundUrls = append(notFoundUrls, fmt.Sprintf(">>> %s (found in file: %s)", url, urlFileMap[url])) + lock.Unlock() + } + + return nil + }) + } + + if err := g.Wait(); err != nil { + return err + } + + // Print out the URLs that returned a 404 along with the file names + if len(notFoundUrls) > 0 { + for _, result := range notFoundUrls { + fmt.Println(result) + } + + return errFound404Links + } + + return nil +} + +// findFilePaths gathers the file paths for specific file types +func findFilePaths(startPath string) ([]string, error) { + filePaths := make([]string, 0) + + walkFn := func(path string, info os.FileInfo, err error) error { + if err != nil { + return fmt.Errorf("error accessing file: %w", err) + } + + // Check if the file is a dir + if info.IsDir() { + return nil + } + + // Check if the file type matches + if !strings.HasSuffix(info.Name(), ".md") { + return nil + } + + // File is not a directory + filePaths = append(filePaths, path) + + return nil + } + + // Walk the directory root recursively + if walkErr := filepath.Walk(startPath, walkFn); walkErr != nil { + return nil, fmt.Errorf("unable to walk directory, %w", walkErr) + } + + return filePaths, nil +} + +// extractUrls extracts URLs from a file and maps them to the file +func extractUrls(filePath string) (map[string]string, error) { + file, err := os.Open(filePath) + if err != nil { + return nil, err + } + + cleanup := func() error { + if closeErr := file.Close(); closeErr != nil { + return fmt.Errorf("unable to gracefully close file, %w", closeErr) + } + return nil + } + + scanner := bufio.NewScanner(file) + urls := make(map[string]string) + + // Scan file line by line + for scanner.Scan() { + line := scanner.Text() + + // Extract links + rxStrict := xurls.Strict() + url := rxStrict.FindString(line) + + // Check for empty links and skip them + if url == " " || len(url) == 0 { + continue + } + + urls[url] = filePath + } + + return urls, cleanup() +} + +// checkUrl checks if a URL is a 404 +func checkUrl(url string) error { + // Attempt to retrieve the HTTP header + resp, err := http.Get(url) + if err != nil || resp.StatusCode == http.StatusNotFound { + return err404Link + } + + // Ensure the response body is closed properly + cleanup := func(Body io.ReadCloser) error { + if err := Body.Close(); err != nil { + return fmt.Errorf("could not close response properly: %w", err) + } + + return nil + } + + return cleanup(resp.Body) +} diff --git a/misc/docs-linter/main_test.go b/misc/docs-linter/main_test.go new file mode 100644 index 00000000000..ceb87fefeda --- /dev/null +++ b/misc/docs-linter/main_test.go @@ -0,0 +1,126 @@ +package main + +import ( + "context" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + "os" + "path/filepath" + "sort" + "strconv" + "testing" + "time" +) + +func TestEmptyPathError(t *testing.T) { + t.Parallel() + + cfg := &cfg{ + docsPath: "", + } + + ctx, cancelFn := context.WithTimeout(context.Background(), time.Second*5) + defer cancelFn() + + assert.ErrorIs(t, execLint(cfg, ctx), errEmptyPath) +} + +func TestExtractLinks(t *testing.T) { + t.Parallel() + + // Generate temporary source dir + sourceDir, err := os.MkdirTemp(".", "sourceDir") + require.NoError(t, err) + t.Cleanup(removeDir(t, sourceDir)) + + // Create mock files with random links + mockFiles := map[string]string{ + "file1.md": "This is a test file with a link: https://example.com.\nAnother link: http://example.org.", + "file2.md": "Markdown content with a link: https://example.com/page.", + "file3.md": "Links in a list:\n- https://example.com/item1\n- https://example.org/item2", + } + + for fileName, content := range mockFiles { + filePath := filepath.Join(sourceDir, fileName) + err := os.WriteFile(filePath, []byte(content), 0644) + require.NoError(t, err) + } + + // Expected URLs and their corresponding files + expectedUrls := map[string]string{ + "https://example.com": filepath.Join(sourceDir, "file1.md"), + "http://example.org": filepath.Join(sourceDir, "file1.md"), + "https://example.com/page": filepath.Join(sourceDir, "file2.md"), + "https://example.com/item1": filepath.Join(sourceDir, "file3.md"), + "https://example.org/item2": filepath.Join(sourceDir, "file3.md"), + } + + // Extract URLs from each file in the sourceDir + for fileName := range mockFiles { + filePath := filepath.Join(sourceDir, fileName) + extractedUrls, err := extractUrls(filePath) + require.NoError(t, err) + + // Verify that the extracted URLs match the expected URLs + for url, expectedFile := range expectedUrls { + if expectedFile == filePath { + require.Equal(t, expectedFile, extractedUrls[url], "URL: %s not correctly mapped to file: %s", url, expectedFile) + } + } + } +} + +func TestFindFilePaths(t *testing.T) { + t.Parallel() + + tempDir, err := os.MkdirTemp(".", "test") + require.NoError(t, err) + t.Cleanup(removeDir(t, tempDir)) + + numSourceFiles := 20 + testFiles := make([]string, numSourceFiles) + + for i := 0; i < numSourceFiles; i++ { + testFiles[i] = "sourceFile" + strconv.Itoa(i) + ".md" + } + + for _, file := range testFiles { + filePath := filepath.Join(tempDir, file) + err := os.MkdirAll(filepath.Dir(filePath), os.ModePerm) + require.NoError(t, err) + + _, err = os.Create(filePath) + require.NoError(t, err) + } + + results, err := findFilePaths(tempDir) + require.NoError(t, err) + + expectedResults := make([]string, 0, len(testFiles)) + + for _, testFile := range testFiles { + expectedResults = append(expectedResults, filepath.Join(tempDir, testFile)) + } + + sort.Slice(results, func(i, j int) bool { + return results[i] < results[j] + }) + + sort.Slice(expectedResults, func(i, j int) bool { + return expectedResults[i] < expectedResults[j] + }) + + require.Equal(t, len(results), len(expectedResults)) + + for i, result := range results { + if result != expectedResults[i] { + require.Equal(t, result, expectedResults[i]) + } + } +} + +func removeDir(t *testing.T, dirPath string) func() { + return func() { + require.NoError(t, os.RemoveAll(dirPath)) + } +} From 6825293c6f0a167be38c38f1b8a264a3f3d7b9b3 Mon Sep 17 00:00:00 2001 From: Manfred Touron <94029+moul@users.noreply.github.com> Date: Wed, 19 Jun 2024 19:43:02 +0200 Subject: [PATCH 24/26] feat: refactor govdao structure and examples (#2379) - remove `gov/integration/` - remove `gov/proposals/` - move the integration test in `gov/dao/*test.gno` - add `r/sys/validators.Render()` Signed-off-by: moul <94029+moul@users.noreply.github.com> --- .../gno.land/r/gov/dao/prop1_filetest.gno | 85 +++++++++++++++++++ examples/gno.land/r/gov/integration/gno.mod | 3 - .../r/gov/integration/integration.gno | 4 - .../gno.land/r/gov/integration/z_filetest.gno | 45 ---------- .../gno.land/r/gov/proposals/prop1/gno.mod | 6 -- .../gno.land/r/gov/proposals/prop1/prop1.gno | 36 -------- .../gno.land/r/sys/validators/validators.gno | 13 +++ 7 files changed, 98 insertions(+), 94 deletions(-) create mode 100644 examples/gno.land/r/gov/dao/prop1_filetest.gno delete mode 100644 examples/gno.land/r/gov/integration/gno.mod delete mode 100644 examples/gno.land/r/gov/integration/integration.gno delete mode 100644 examples/gno.land/r/gov/integration/z_filetest.gno delete mode 100644 examples/gno.land/r/gov/proposals/prop1/gno.mod delete mode 100644 examples/gno.land/r/gov/proposals/prop1/prop1.gno diff --git a/examples/gno.land/r/gov/dao/prop1_filetest.gno b/examples/gno.land/r/gov/dao/prop1_filetest.gno new file mode 100644 index 00000000000..7072618a4a7 --- /dev/null +++ b/examples/gno.land/r/gov/dao/prop1_filetest.gno @@ -0,0 +1,85 @@ +// Please note that this package is intended for demonstration purposes only. +// You could execute this code (the init part) by running a `maketx run` command +// or by uploading a similar package to a personal namespace. +// +// For the specific case of validators, a `r/gnoland/valopers` will be used to +// organize the lifecycle of validators (register, etc), and this more complex +// contract will be responsible to generate proposals. +package main + +import ( + "std" + + govdao "gno.land/r/gov/dao" + "gno.land/r/sys/validators" +) + +func init() { + // Create the validators change proposal. + changesFn := func() []validators.Change { + return []validators.Change{ + // add a new validator. + {Address: std.Address("g12345678"), Power: 1}, + // remove an existing validator. + {Address: std.Address("g000000000"), Power: 0}, + } + } + + // Wraps changesFn to emit a certified event only if executed from a + // complete governance proposal process. + executor := validators.NewPropExecutor(changesFn) + + // Create a proposal. + // XXX: payment + comment := "manual valset changes proposal example" + govdao.Propose(comment, executor) +} + +func main() { + println("--") + println(govdao.Render("")) + println("--") + println(govdao.Render("1")) + println("--") + govdao.VoteOnProposal(1, "YES") + println("--") + println(govdao.Render("1")) + println("--") + println(validators.Render("")) + println("--") + govdao.ExecuteProposal(1) + println("--") + println(govdao.Render("1")) + println("--") + println(validators.Render("")) +} + +// Output: +// -- +// - [/r/gov/dao:0](0) - manual valset changes proposal example (by g1wymu47drhr0kuq2098m792lytgtj2nyx77yrsm) +// -- +// # Prop#0 +// +// manual valset changes proposal example +// Status: active +// Author: g1wymu47drhr0kuq2098m792lytgtj2nyx77yrsm +// -- +// -- +// # Prop#0 +// +// manual valset changes proposal example +// Status: accepted +// Author: g1wymu47drhr0kuq2098m792lytgtj2nyx77yrsm +// -- +// No valset changes to apply. +// -- +// -- +// # Prop#0 +// +// manual valset changes proposal example +// Status: success +// Author: g1wymu47drhr0kuq2098m792lytgtj2nyx77yrsm +// -- +// Valset changes to apply: +// - g12345678 (1) +// - g000000000 (0) diff --git a/examples/gno.land/r/gov/integration/gno.mod b/examples/gno.land/r/gov/integration/gno.mod deleted file mode 100644 index f584f375133..00000000000 --- a/examples/gno.land/r/gov/integration/gno.mod +++ /dev/null @@ -1,3 +0,0 @@ -// Draft - -module integration diff --git a/examples/gno.land/r/gov/integration/integration.gno b/examples/gno.land/r/gov/integration/integration.gno deleted file mode 100644 index 5b47b3dec83..00000000000 --- a/examples/gno.land/r/gov/integration/integration.gno +++ /dev/null @@ -1,4 +0,0 @@ -// Package integration tests the govdao ecosystem from an external perspective. -// It aims to confirm that the system can remain static while supporting -// additional DAO use cases over time. -package integration diff --git a/examples/gno.land/r/gov/integration/z_filetest.gno b/examples/gno.land/r/gov/integration/z_filetest.gno deleted file mode 100644 index a85588e4f11..00000000000 --- a/examples/gno.land/r/gov/integration/z_filetest.gno +++ /dev/null @@ -1,45 +0,0 @@ -package main - -import ( - govdao "gno.land/r/gov/dao" - _ "gno.land/r/gov/proposals/prop1" -) - -func main() { - println("--") - println(govdao.Render("")) - println("--") - println(govdao.Render("1")) - println("--") - govdao.VoteOnProposal(1, "YES") - println("--") - println(govdao.Render("1")) - println("--") - govdao.ExecuteProposal(1) - println("--") - println(govdao.Render("1")) -} - -// Output: -// -- -// - [/r/gov/dao:0](0) - manual valset changes proposal example (by g1tk0fscr3p5g8hnhxq6v93jxcpm5g3cstlxfxa3) -// -- -// # Prop#0 -// -// manual valset changes proposal example -// Status: active -// Author: g1tk0fscr3p5g8hnhxq6v93jxcpm5g3cstlxfxa3 -// -- -// -- -// # Prop#0 -// -// manual valset changes proposal example -// Status: accepted -// Author: g1tk0fscr3p5g8hnhxq6v93jxcpm5g3cstlxfxa3 -// -- -// -- -// # Prop#0 -// -// manual valset changes proposal example -// Status: success -// Author: g1tk0fscr3p5g8hnhxq6v93jxcpm5g3cstlxfxa3 diff --git a/examples/gno.land/r/gov/proposals/prop1/gno.mod b/examples/gno.land/r/gov/proposals/prop1/gno.mod deleted file mode 100644 index 97faf2aff27..00000000000 --- a/examples/gno.land/r/gov/proposals/prop1/gno.mod +++ /dev/null @@ -1,6 +0,0 @@ -module gno.land/r/gov/proposals/prop1 - -require ( - gno.land/r/gov/dao v0.0.0-latest - gno.land/r/sys/validators v0.0.0-latest -) diff --git a/examples/gno.land/r/gov/proposals/prop1/prop1.gno b/examples/gno.land/r/gov/proposals/prop1/prop1.gno deleted file mode 100644 index 68cd9d60bfa..00000000000 --- a/examples/gno.land/r/gov/proposals/prop1/prop1.gno +++ /dev/null @@ -1,36 +0,0 @@ -// Package prop1 is an example of proposal creation using a contract. -// -// Please note that this package is intended for demonstration purposes only. -// You could execute this code by running a `maketx run` command or by uploading -// a similar package to a personal namespace. -// -// For the specific case of validators, a `r/gnoland/valopers` will be used to -// organize the lifecycle of validators (register, etc), and this more complex -// contract will be responsible to generate proposals. -package prop1 - -import ( - "std" - - govdao "gno.land/r/gov/dao" - "gno.land/r/sys/validators" -) - -func init() { - // Create the validators change proposal. - changesFn := func() []validators.Change { - return []validators.Change{ - {Address: std.Address("g12345678"), Power: 1}, // add a new validator - {Address: std.Address("g000000000"), Power: 0}, // remove an existing validator - } - } - - // Wraps changesFn to emit a certified event only if executed from a - // complete governance proposal process. - executor := validators.NewPropExecutor(changesFn) - - // Create a proposal. - // XXX: payment - comment := "manual valset changes proposal example" - govdao.Propose(comment, executor) -} diff --git a/examples/gno.land/r/sys/validators/validators.gno b/examples/gno.land/r/sys/validators/validators.gno index 5fb08ebbfc7..669b688727a 100644 --- a/examples/gno.land/r/sys/validators/validators.gno +++ b/examples/gno.land/r/sys/validators/validators.gno @@ -3,6 +3,7 @@ package validators import ( "std" + "strconv" "gno.land/p/gov/proposal" ) @@ -45,3 +46,15 @@ func getAndResetChanges() []Change { unappliedChanges = []Change{} return cpy } + +func Render(_ string) string { + if len(unappliedChanges) == 0 { + return "No valset changes to apply." + } + + output := "Valset changes to apply:\n" + for _, change := range unappliedChanges { + output += "- " + string(change.Address) + " (" + strconv.Itoa(change.Power) + ")\n" + } + return output +} From eef00390b89e1b30671b9c73475884bcdaee3d2f Mon Sep 17 00:00:00 2001 From: Jae Kwon <53785+jaekwon@users.noreply.github.com> Date: Wed, 19 Jun 2024 17:39:22 -0700 Subject: [PATCH 25/26] fix: (gnovm) star expr assign for #1919 (#2255) This is a complete solution, alternative to #1919, and (I think) closes #1326. It creates a new container for "baseless" (floating) values constructed via `new(xxx)` or `&struct{}`, which currently do not have a base containing object for that value, and are currently represented as PointerValues with .Base set to nil. The containing object is like a Block but minimal -- it only contains one Value, and has no Source or Parent. The modifications to realm.go allow for proper ref-counting so that even when there are multiple references to the baseless value, and even when the value is primitive, gc and ref-counting works (since the containing HeapItemValue is ref-counted). PointerValue.Base should now never be nil. See also https://github.com/gnolang/gno/pull/1919#issuecomment-2144059991 for why the previous solution doesn't work. A better optimization than the one mentioned in the comment above, is to always store the HeapItemValue along with the Value, since the Value's refcount should always be 1. This is left for the future, after first checking that this invariant is true. --------- Co-authored-by: deelawn --- examples/gno.land/p/demo/avl/z_0_filetest.gno | 172 +++--- examples/gno.land/p/demo/avl/z_1_filetest.gno | 166 +++--- examples/gno.land/p/demo/avl/z_2_filetest.gno | 166 +++--- .../gno.land/r/demo/boards/z_4_filetest.gno | 547 ++++++++---------- examples/gno.land/r/demo/nft/z_0_filetest.gno | 110 ++-- gnovm/pkg/gnolang/alloc.go | 10 + gnovm/pkg/gnolang/machine.go | 6 +- gnovm/pkg/gnolang/ownership.go | 10 +- gnovm/pkg/gnolang/package.go | 1 + gnovm/pkg/gnolang/realm.go | 122 ++-- gnovm/pkg/gnolang/store.go | 2 +- gnovm/pkg/gnolang/uverse.go | 12 +- gnovm/pkg/gnolang/values.go | 33 +- gnovm/pkg/gnolang/values_string.go | 5 + .../more/realm_compositelit_filetest.gno | 49 +- gnovm/tests/files/heap_item_value.gno | 178 ++++++ gnovm/tests/files/heap_item_value_init.gno | 185 ++++++ gnovm/tests/files/issue_1326.gno | 64 ++ gnovm/tests/files/star_assign.gno | 54 ++ gnovm/tests/files/zrealm3.gno | 44 +- gnovm/tests/files/zrealm4.gno | 28 +- gnovm/tests/files/zrealm5.gno | 71 ++- gnovm/tests/files/zrealm6.gno | 97 ++-- gnovm/tests/files/zrealm7.gno | 183 +++--- gnovm/tests/files/zrealm_avl0.gno | 172 +++--- gnovm/tests/files/zrealm_avl1.gno | 166 +++--- gnovm/tests/files/zrealm_avl2.gno | 172 +++--- gnovm/tests/files/zrealm_example.gno | 116 ++-- gnovm/tests/files/zrealm_std1_stdlibs.gno | 2 +- gnovm/tests/files/zrealm_std2_stdlibs.gno | 2 +- gnovm/tests/files/zrealm_tests0_stdlibs.gno | 109 ++-- 31 files changed, 1820 insertions(+), 1234 deletions(-) create mode 100644 gnovm/tests/files/heap_item_value.gno create mode 100644 gnovm/tests/files/heap_item_value_init.gno create mode 100644 gnovm/tests/files/issue_1326.gno create mode 100644 gnovm/tests/files/star_assign.gno diff --git a/examples/gno.land/p/demo/avl/z_0_filetest.gno b/examples/gno.land/p/demo/avl/z_0_filetest.gno index e91788ac8eb..e3f1363e205 100644 --- a/examples/gno.land/p/demo/avl/z_0_filetest.gno +++ b/examples/gno.land/p/demo/avl/z_0_filetest.gno @@ -25,67 +25,25 @@ func main() { // Realm: // switchrealm["gno.land/r/test"] // u[a8ada09dee16d791fd406d629fe29bb0ed084a30:4]={ -// "Fields": [ -// { -// "T": { -// "@type": "/gno.PrimitiveType", -// "value": "16" -// }, -// "V": { -// "@type": "/gno.StringValue", -// "value": "key0" -// } -// }, -// { -// "T": { -// "@type": "/gno.PrimitiveType", -// "value": "16" -// }, -// "V": { -// "@type": "/gno.StringValue", -// "value": "value0" -// } -// }, -// { -// "T": { -// "@type": "/gno.PrimitiveType", -// "value": "64" -// } -// }, -// { -// "N": "AQAAAAAAAAA=", -// "T": { -// "@type": "/gno.PrimitiveType", -// "value": "32" -// } -// }, -// { -// "T": { -// "@type": "/gno.PointerType", -// "Elt": { -// "@type": "/gno.RefType", -// "ID": "gno.land/p/demo/avl.Node" -// } -// } -// }, -// { -// "T": { -// "@type": "/gno.PointerType", -// "Elt": { -// "@type": "/gno.RefType", -// "ID": "gno.land/p/demo/avl.Node" -// } -// } -// } -// ], // "ObjectInfo": { // "ID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:4", -// "ModTime": "5", -// "OwnerID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:5", +// "ModTime": "7", +// "OwnerID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:7", // "RefCount": "1" +// }, +// "Value": { +// "T": { +// "@type": "/gno.RefType", +// "ID": "gno.land/p/demo/avl.Node" +// }, +// "V": { +// "@type": "/gno.RefValue", +// "Hash": "627e8e517e7ae5db0f3b753e2a32b607989198b6", +// "ObjectID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:5" +// } // } // } -// c[a8ada09dee16d791fd406d629fe29bb0ed084a30:6]={ +// c[a8ada09dee16d791fd406d629fe29bb0ed084a30:9]={ // "Fields": [ // { // "T": { @@ -140,13 +98,32 @@ func main() { // } // ], // "ObjectInfo": { -// "ID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:6", +// "ID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:9", // "ModTime": "0", -// "OwnerID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:5", +// "OwnerID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:8", // "RefCount": "1" // } // } -// c[a8ada09dee16d791fd406d629fe29bb0ed084a30:5]={ +// c[a8ada09dee16d791fd406d629fe29bb0ed084a30:8]={ +// "ObjectInfo": { +// "ID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:8", +// "ModTime": "0", +// "OwnerID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:7", +// "RefCount": "1" +// }, +// "Value": { +// "T": { +// "@type": "/gno.RefType", +// "ID": "gno.land/p/demo/avl.Node" +// }, +// "V": { +// "@type": "/gno.RefValue", +// "Hash": "b28057ab7be6383785c0a5503e8a531bdbc21851", +// "ObjectID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:9" +// } +// } +// } +// c[a8ada09dee16d791fd406d629fe29bb0ed084a30:7]={ // "Fields": [ // { // "T": { @@ -183,19 +160,13 @@ func main() { // }, // "V": { // "@type": "/gno.PointerValue", -// "Base": null, +// "Base": { +// "@type": "/gno.RefValue", +// "Hash": "6da365f0d6cacbcdf53cd5a4b125803cddce08c2", +// "ObjectID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:4" +// }, // "Index": "0", -// "TV": { -// "T": { -// "@type": "/gno.RefType", -// "ID": "gno.land/p/demo/avl.Node" -// }, -// "V": { -// "@type": "/gno.RefValue", -// "Hash": "091729e38bda8724bce4c314f9624b91af679459", -// "ObjectID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:4" -// } -// } +// "TV": null // } // }, // { @@ -208,27 +179,40 @@ func main() { // }, // "V": { // "@type": "/gno.PointerValue", -// "Base": null, +// "Base": { +// "@type": "/gno.RefValue", +// "Hash": "f216afe7b5a17f4ebdbb98dceccedbc22e237596", +// "ObjectID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:8" +// }, // "Index": "0", -// "TV": { -// "T": { -// "@type": "/gno.RefType", -// "ID": "gno.land/p/demo/avl.Node" -// }, -// "V": { -// "@type": "/gno.RefValue", -// "Hash": "0b5493aa4ea42087780bdfcaebab2c3eec351c15", -// "ObjectID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:6" -// } -// } +// "TV": null // } // } // ], // "ObjectInfo": { -// "ID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:5", +// "ID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:7", +// "ModTime": "0", +// "OwnerID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:6", +// "RefCount": "1" +// } +// } +// c[a8ada09dee16d791fd406d629fe29bb0ed084a30:6]={ +// "ObjectInfo": { +// "ID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:6", // "ModTime": "0", // "OwnerID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:2", // "RefCount": "1" +// }, +// "Value": { +// "T": { +// "@type": "/gno.RefType", +// "ID": "gno.land/p/demo/avl.Node" +// }, +// "V": { +// "@type": "/gno.RefValue", +// "Hash": "ff1a50d8489090af37a2c7766d659f0d717939b5", +// "ObjectID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:7" +// } // } // } // u[a8ada09dee16d791fd406d629fe29bb0ed084a30:2]={ @@ -236,7 +220,7 @@ func main() { // "ObjectInfo": { // "ID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:2", // "IsEscaped": true, -// "ModTime": "4", +// "ModTime": "5", // "RefCount": "2" // }, // "Parent": null, @@ -333,19 +317,13 @@ func main() { // }, // "V": { // "@type": "/gno.PointerValue", -// "Base": null, +// "Base": { +// "@type": "/gno.RefValue", +// "Hash": "ae86874f9b47fa5e64c30b3e92e9d07f2ec967a4", +// "ObjectID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:6" +// }, // "Index": "0", -// "TV": { -// "T": { -// "@type": "/gno.RefType", -// "ID": "gno.land/p/demo/avl.Node" -// }, -// "V": { -// "@type": "/gno.RefValue", -// "Hash": "6c9948281d4c60b2d95233b76388d54d8b1a2fad", -// "ObjectID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:5" -// } -// } +// "TV": null // } // } // ] diff --git a/examples/gno.land/p/demo/avl/z_1_filetest.gno b/examples/gno.land/p/demo/avl/z_1_filetest.gno index cdd56a5ad89..a6d2205e240 100644 --- a/examples/gno.land/p/demo/avl/z_1_filetest.gno +++ b/examples/gno.land/p/demo/avl/z_1_filetest.gno @@ -24,7 +24,7 @@ func main() { // Realm: // switchrealm["gno.land/r/test"] -// c[a8ada09dee16d791fd406d629fe29bb0ed084a30:9]={ +// c[a8ada09dee16d791fd406d629fe29bb0ed084a30:15]={ // "Fields": [ // { // "T": { @@ -79,13 +79,32 @@ func main() { // } // ], // "ObjectInfo": { -// "ID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:9", +// "ID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:15", // "ModTime": "0", -// "OwnerID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:8", +// "OwnerID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:14", // "RefCount": "1" // } // } -// c[a8ada09dee16d791fd406d629fe29bb0ed084a30:8]={ +// c[a8ada09dee16d791fd406d629fe29bb0ed084a30:14]={ +// "ObjectInfo": { +// "ID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:14", +// "ModTime": "0", +// "OwnerID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:13", +// "RefCount": "1" +// }, +// "Value": { +// "T": { +// "@type": "/gno.RefType", +// "ID": "gno.land/p/demo/avl.Node" +// }, +// "V": { +// "@type": "/gno.RefValue", +// "Hash": "143aebc820da33550f7338723fb1e2eec575b196", +// "ObjectID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:15" +// } +// } +// } +// c[a8ada09dee16d791fd406d629fe29bb0ed084a30:13]={ // "Fields": [ // { // "T": { @@ -122,19 +141,13 @@ func main() { // }, // "V": { // "@type": "/gno.PointerValue", -// "Base": null, +// "Base": { +// "@type": "/gno.RefValue", +// "Hash": "2f3adc5d0f2a3fe0331cfa93572a7abdde14c9aa", +// "ObjectID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:8" +// }, // "Index": "0", -// "TV": { -// "T": { -// "@type": "/gno.RefType", -// "ID": "gno.land/p/demo/avl.Node" -// }, -// "V": { -// "@type": "/gno.RefValue", -// "Hash": "7a8a63e17a567d7b0891ac89d5cd90072a73787d", -// "ObjectID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:6" -// } -// } +// "TV": null // } // }, // { @@ -147,30 +160,43 @@ func main() { // }, // "V": { // "@type": "/gno.PointerValue", -// "Base": null, +// "Base": { +// "@type": "/gno.RefValue", +// "Hash": "2e733a8e9e74fe14f0a5d10fb0f6728fa53d052d", +// "ObjectID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:14" +// }, // "Index": "0", -// "TV": { -// "T": { -// "@type": "/gno.RefType", -// "ID": "gno.land/p/demo/avl.Node" -// }, -// "V": { -// "@type": "/gno.RefValue", -// "Hash": "ab5a297f4eb033d88bdf1677f4dc151ccb9fde9f", -// "ObjectID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:9" -// } -// } +// "TV": null // } // } // ], // "ObjectInfo": { -// "ID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:8", +// "ID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:13", // "ModTime": "0", -// "OwnerID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:7", +// "OwnerID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:12", // "RefCount": "1" // } // } -// c[a8ada09dee16d791fd406d629fe29bb0ed084a30:7]={ +// c[a8ada09dee16d791fd406d629fe29bb0ed084a30:12]={ +// "ObjectInfo": { +// "ID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:12", +// "ModTime": "0", +// "OwnerID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:11", +// "RefCount": "1" +// }, +// "Value": { +// "T": { +// "@type": "/gno.RefType", +// "ID": "gno.land/p/demo/avl.Node" +// }, +// "V": { +// "@type": "/gno.RefValue", +// "Hash": "fe20a19f956511f274dc77854e9e5468387260f4", +// "ObjectID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:13" +// } +// } +// } +// c[a8ada09dee16d791fd406d629fe29bb0ed084a30:11]={ // "Fields": [ // { // "T": { @@ -207,19 +233,13 @@ func main() { // }, // "V": { // "@type": "/gno.PointerValue", -// "Base": null, +// "Base": { +// "@type": "/gno.RefValue", +// "Hash": "c89a71bdf045e8bde2059dc9d33839f916e02e5d", +// "ObjectID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:6" +// }, // "Index": "0", -// "TV": { -// "T": { -// "@type": "/gno.RefType", -// "ID": "gno.land/p/demo/avl.Node" -// }, -// "V": { -// "@type": "/gno.RefValue", -// "Hash": "627e8e517e7ae5db0f3b753e2a32b607989198b6", -// "ObjectID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:5" -// } -// } +// "TV": null // } // }, // { @@ -232,27 +252,40 @@ func main() { // }, // "V": { // "@type": "/gno.PointerValue", -// "Base": null, +// "Base": { +// "@type": "/gno.RefValue", +// "Hash": "90fa67f8c47db4b9b2a60425dff08d5a3385100f", +// "ObjectID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:12" +// }, // "Index": "0", -// "TV": { -// "T": { -// "@type": "/gno.RefType", -// "ID": "gno.land/p/demo/avl.Node" -// }, -// "V": { -// "@type": "/gno.RefValue", -// "Hash": "fe8afd501233fb95375016199f0443b3c6ab1fbc", -// "ObjectID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:8" -// } -// } +// "TV": null // } // } // ], // "ObjectInfo": { -// "ID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:7", +// "ID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:11", +// "ModTime": "0", +// "OwnerID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:10", +// "RefCount": "1" +// } +// } +// c[a8ada09dee16d791fd406d629fe29bb0ed084a30:10]={ +// "ObjectInfo": { +// "ID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:10", // "ModTime": "0", // "OwnerID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:2", // "RefCount": "1" +// }, +// "Value": { +// "T": { +// "@type": "/gno.RefType", +// "ID": "gno.land/p/demo/avl.Node" +// }, +// "V": { +// "@type": "/gno.RefValue", +// "Hash": "83e42caaf53070dd95b5f859053eb51ed900bbda", +// "ObjectID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:11" +// } // } // } // u[a8ada09dee16d791fd406d629fe29bb0ed084a30:2]={ @@ -260,7 +293,7 @@ func main() { // "ObjectInfo": { // "ID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:2", // "IsEscaped": true, -// "ModTime": "6", +// "ModTime": "9", // "RefCount": "2" // }, // "Parent": null, @@ -357,21 +390,16 @@ func main() { // }, // "V": { // "@type": "/gno.PointerValue", -// "Base": null, +// "Base": { +// "@type": "/gno.RefValue", +// "Hash": "1faa9fa4ba1935121a6d3f0a623772e9d4499b0a", +// "ObjectID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:10" +// }, // "Index": "0", -// "TV": { -// "T": { -// "@type": "/gno.RefType", -// "ID": "gno.land/p/demo/avl.Node" -// }, -// "V": { -// "@type": "/gno.RefValue", -// "Hash": "c5eefc40ed065461b4a920c1349ed734ffdead8f", -// "ObjectID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:7" -// } -// } +// "TV": null // } // } // ] // } // d[a8ada09dee16d791fd406d629fe29bb0ed084a30:4] +// d[a8ada09dee16d791fd406d629fe29bb0ed084a30:5] diff --git a/examples/gno.land/p/demo/avl/z_2_filetest.gno b/examples/gno.land/p/demo/avl/z_2_filetest.gno index 65181bffcac..1d3f20651ed 100644 --- a/examples/gno.land/p/demo/avl/z_2_filetest.gno +++ b/examples/gno.land/p/demo/avl/z_2_filetest.gno @@ -23,7 +23,7 @@ func main() { // Realm: // switchrealm["gno.land/r/test"] -// c[a8ada09dee16d791fd406d629fe29bb0ed084a30:10]={ +// c[a8ada09dee16d791fd406d629fe29bb0ed084a30:16]={ // "Fields": [ // { // "T": { @@ -78,13 +78,32 @@ func main() { // } // ], // "ObjectInfo": { -// "ID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:10", +// "ID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:16", // "ModTime": "0", -// "OwnerID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:9", +// "OwnerID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:15", // "RefCount": "1" // } // } -// c[a8ada09dee16d791fd406d629fe29bb0ed084a30:9]={ +// c[a8ada09dee16d791fd406d629fe29bb0ed084a30:15]={ +// "ObjectInfo": { +// "ID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:15", +// "ModTime": "0", +// "OwnerID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:14", +// "RefCount": "1" +// }, +// "Value": { +// "T": { +// "@type": "/gno.RefType", +// "ID": "gno.land/p/demo/avl.Node" +// }, +// "V": { +// "@type": "/gno.RefValue", +// "Hash": "db333c89cd6773709e031f1f4e4ed4d3fed66c11", +// "ObjectID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:16" +// } +// } +// } +// c[a8ada09dee16d791fd406d629fe29bb0ed084a30:14]={ // "Fields": [ // { // "T": { @@ -121,19 +140,13 @@ func main() { // }, // "V": { // "@type": "/gno.PointerValue", -// "Base": null, +// "Base": { +// "@type": "/gno.RefValue", +// "Hash": "849a50d6c78d65742752e3c89ad8dd556e2e63cb", +// "ObjectID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:9" +// }, // "Index": "0", -// "TV": { -// "T": { -// "@type": "/gno.RefType", -// "ID": "gno.land/p/demo/avl.Node" -// }, -// "V": { -// "@type": "/gno.RefValue", -// "Hash": "213baed7e3326f2403b5f30e5d4397510ba4f37d", -// "ObjectID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:7" -// } -// } +// "TV": null // } // }, // { @@ -146,30 +159,43 @@ func main() { // }, // "V": { // "@type": "/gno.PointerValue", -// "Base": null, +// "Base": { +// "@type": "/gno.RefValue", +// "Hash": "b4fc2fdd2d0fe936c87ed2ace97136cffeed207f", +// "ObjectID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:15" +// }, // "Index": "0", -// "TV": { -// "T": { -// "@type": "/gno.RefType", -// "ID": "gno.land/p/demo/avl.Node" -// }, -// "V": { -// "@type": "/gno.RefValue", -// "Hash": "be751422ef4c2bc068a456f9467d2daca27db8ca", -// "ObjectID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:10" -// } -// } +// "TV": null // } // } // ], // "ObjectInfo": { -// "ID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:9", +// "ID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:14", +// "ModTime": "0", +// "OwnerID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:13", +// "RefCount": "1" +// } +// } +// c[a8ada09dee16d791fd406d629fe29bb0ed084a30:13]={ +// "ObjectInfo": { +// "ID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:13", // "ModTime": "0", -// "OwnerID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:8", +// "OwnerID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:12", // "RefCount": "1" +// }, +// "Value": { +// "T": { +// "@type": "/gno.RefType", +// "ID": "gno.land/p/demo/avl.Node" +// }, +// "V": { +// "@type": "/gno.RefValue", +// "Hash": "a1160b0060ad752dbfe5fe436f7734bb19136150", +// "ObjectID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:14" +// } // } // } -// c[a8ada09dee16d791fd406d629fe29bb0ed084a30:8]={ +// c[a8ada09dee16d791fd406d629fe29bb0ed084a30:12]={ // "Fields": [ // { // "T": { @@ -206,19 +232,13 @@ func main() { // }, // "V": { // "@type": "/gno.PointerValue", -// "Base": null, +// "Base": { +// "@type": "/gno.RefValue", +// "Hash": "fd95e08763159ac529e26986d652e752e78b6325", +// "ObjectID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:7" +// }, // "Index": "0", -// "TV": { -// "T": { -// "@type": "/gno.RefType", -// "ID": "gno.land/p/demo/avl.Node" -// }, -// "V": { -// "@type": "/gno.RefValue", -// "Hash": "af4d0b158681d85eb2a7f6888b39a05ca7b790ee", -// "ObjectID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:6" -// } -// } +// "TV": null // } // }, // { @@ -231,27 +251,40 @@ func main() { // }, // "V": { // "@type": "/gno.PointerValue", -// "Base": null, +// "Base": { +// "@type": "/gno.RefValue", +// "Hash": "3ecdcf148fe2f9e97b72a3bedf303b2ba56d4f4b", +// "ObjectID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:13" +// }, // "Index": "0", -// "TV": { -// "T": { -// "@type": "/gno.RefType", -// "ID": "gno.land/p/demo/avl.Node" -// }, -// "V": { -// "@type": "/gno.RefValue", -// "Hash": "ef853d70e334fd2c807d6c2c751da1fcd1e5ad58", -// "ObjectID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:9" -// } -// } +// "TV": null // } // } // ], // "ObjectInfo": { -// "ID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:8", +// "ID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:12", +// "ModTime": "0", +// "OwnerID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:11", +// "RefCount": "1" +// } +// } +// c[a8ada09dee16d791fd406d629fe29bb0ed084a30:11]={ +// "ObjectInfo": { +// "ID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:11", // "ModTime": "0", // "OwnerID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:4", // "RefCount": "1" +// }, +// "Value": { +// "T": { +// "@type": "/gno.RefType", +// "ID": "gno.land/p/demo/avl.Node" +// }, +// "V": { +// "@type": "/gno.RefValue", +// "Hash": "63126557dba88f8556f7a0ccbbfc1d218ae7a302", +// "ObjectID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:12" +// } // } // } // u[a8ada09dee16d791fd406d629fe29bb0ed084a30:4]={ @@ -266,27 +299,22 @@ func main() { // }, // "V": { // "@type": "/gno.PointerValue", -// "Base": null, +// "Base": { +// "@type": "/gno.RefValue", +// "Hash": "425bc3bff1f4c36b175d055ed8b2c289123fcca1", +// "ObjectID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:11" +// }, // "Index": "0", -// "TV": { -// "T": { -// "@type": "/gno.RefType", -// "ID": "gno.land/p/demo/avl.Node" -// }, -// "V": { -// "@type": "/gno.RefValue", -// "Hash": "3a5af0895c2c45b8a5e894644bcd689f1fdc4785", -// "ObjectID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:8" -// } -// } +// "TV": null // } // } // ], // "ObjectInfo": { // "ID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:4", -// "ModTime": "7", +// "ModTime": "10", // "OwnerID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:2", // "RefCount": "1" // } // } // d[a8ada09dee16d791fd406d629fe29bb0ed084a30:5] +// d[a8ada09dee16d791fd406d629fe29bb0ed084a30:6] diff --git a/examples/gno.land/r/demo/boards/z_4_filetest.gno b/examples/gno.land/r/demo/boards/z_4_filetest.gno index bb98fa289ba..a8b932db892 100644 --- a/examples/gno.land/r/demo/boards/z_4_filetest.gno +++ b/examples/gno.land/r/demo/boards/z_4_filetest.gno @@ -48,83 +48,26 @@ func main() { // Realm: // switchrealm["gno.land/r/demo/users"] // switchrealm["gno.land/r/demo/boards"] -// u[f6dbf411da22e67d74cd7ddba6a76cd7e14a4822:101]={ -// "Fields": [ -// { -// "T": { -// "@type": "/gno.PrimitiveType", -// "value": "16" -// }, -// "V": { -// "@type": "/gno.StringValue", -// "value": "0000000003" -// } -// }, -// { -// "T": { -// "@type": "/gno.PointerType", -// "Elt": { -// "@type": "/gno.RefType", -// "ID": "gno.land/r/demo/boards.Post" -// } -// }, -// "V": { -// "@type": "/gno.PointerValue", -// "Base": null, -// "Index": "0", -// "TV": { -// "T": { -// "@type": "/gno.RefType", -// "ID": "gno.land/r/demo/boards.Post" -// }, -// "V": { -// "@type": "/gno.RefValue", -// "Escaped": true, -// "ObjectID": "f6dbf411da22e67d74cd7ddba6a76cd7e14a4822:102" -// } -// } -// } -// }, -// { -// "T": { -// "@type": "/gno.PrimitiveType", -// "value": "64" -// } -// }, -// { -// "N": "AQAAAAAAAAA=", -// "T": { -// "@type": "/gno.PrimitiveType", -// "value": "32" -// } -// }, -// { -// "T": { -// "@type": "/gno.PointerType", -// "Elt": { -// "@type": "/gno.RefType", -// "ID": "gno.land/p/demo/avl.Node" -// } -// } -// }, -// { -// "T": { -// "@type": "/gno.PointerType", -// "Elt": { -// "@type": "/gno.RefType", -// "ID": "gno.land/p/demo/avl.Node" -// } -// } -// } -// ], +// u[f6dbf411da22e67d74cd7ddba6a76cd7e14a4822:111]={ // "ObjectInfo": { -// "ID": "f6dbf411da22e67d74cd7ddba6a76cd7e14a4822:101", -// "ModTime": "109", -// "OwnerID": "f6dbf411da22e67d74cd7ddba6a76cd7e14a4822:109", +// "ID": "f6dbf411da22e67d74cd7ddba6a76cd7e14a4822:111", +// "ModTime": "123", +// "OwnerID": "f6dbf411da22e67d74cd7ddba6a76cd7e14a4822:123", // "RefCount": "1" +// }, +// "Value": { +// "T": { +// "@type": "/gno.RefType", +// "ID": "gno.land/p/demo/avl.Node" +// }, +// "V": { +// "@type": "/gno.RefValue", +// "Hash": "68663c8895d37d479e417c11e21badfe21345c61", +// "ObjectID": "f6dbf411da22e67d74cd7ddba6a76cd7e14a4822:112" +// } // } // } -// c[f6dbf411da22e67d74cd7ddba6a76cd7e14a4822:110]={ +// c[f6dbf411da22e67d74cd7ddba6a76cd7e14a4822:125]={ // "Fields": [ // { // "T": { @@ -146,19 +89,13 @@ func main() { // }, // "V": { // "@type": "/gno.PointerValue", -// "Base": null, +// "Base": { +// "@type": "/gno.RefValue", +// "Escaped": true, +// "ObjectID": "f6dbf411da22e67d74cd7ddba6a76cd7e14a4822:126" +// }, // "Index": "0", -// "TV": { -// "T": { -// "@type": "/gno.RefType", -// "ID": "gno.land/r/demo/boards.Post" -// }, -// "V": { -// "@type": "/gno.RefValue", -// "Escaped": true, -// "ObjectID": "f6dbf411da22e67d74cd7ddba6a76cd7e14a4822:111" -// } -// } +// "TV": null // } // }, // { @@ -194,13 +131,32 @@ func main() { // } // ], // "ObjectInfo": { -// "ID": "f6dbf411da22e67d74cd7ddba6a76cd7e14a4822:110", +// "ID": "f6dbf411da22e67d74cd7ddba6a76cd7e14a4822:125", +// "ModTime": "0", +// "OwnerID": "f6dbf411da22e67d74cd7ddba6a76cd7e14a4822:124", +// "RefCount": "1" +// } +// } +// c[f6dbf411da22e67d74cd7ddba6a76cd7e14a4822:124]={ +// "ObjectInfo": { +// "ID": "f6dbf411da22e67d74cd7ddba6a76cd7e14a4822:124", // "ModTime": "0", -// "OwnerID": "f6dbf411da22e67d74cd7ddba6a76cd7e14a4822:109", +// "OwnerID": "f6dbf411da22e67d74cd7ddba6a76cd7e14a4822:123", // "RefCount": "1" +// }, +// "Value": { +// "T": { +// "@type": "/gno.RefType", +// "ID": "gno.land/p/demo/avl.Node" +// }, +// "V": { +// "@type": "/gno.RefValue", +// "Hash": "3f34ac77289aa1d5f9a2f8b6d083138325816fb0", +// "ObjectID": "f6dbf411da22e67d74cd7ddba6a76cd7e14a4822:125" +// } // } // } -// c[f6dbf411da22e67d74cd7ddba6a76cd7e14a4822:109]={ +// c[f6dbf411da22e67d74cd7ddba6a76cd7e14a4822:123]={ // "Fields": [ // { // "T": { @@ -237,19 +193,13 @@ func main() { // }, // "V": { // "@type": "/gno.PointerValue", -// "Base": null, +// "Base": { +// "@type": "/gno.RefValue", +// "Hash": "94a6665a44bac6ede7f3e3b87173e537b12f9532", +// "ObjectID": "f6dbf411da22e67d74cd7ddba6a76cd7e14a4822:111" +// }, // "Index": "0", -// "TV": { -// "T": { -// "@type": "/gno.RefType", -// "ID": "gno.land/p/demo/avl.Node" -// }, -// "V": { -// "@type": "/gno.RefValue", -// "Hash": "b58581159917d8d7ad0992009d7184fc8ca00fcc", -// "ObjectID": "f6dbf411da22e67d74cd7ddba6a76cd7e14a4822:101" -// } -// } +// "TV": null // } // }, // { @@ -262,30 +212,43 @@ func main() { // }, // "V": { // "@type": "/gno.PointerValue", -// "Base": null, +// "Base": { +// "@type": "/gno.RefValue", +// "Hash": "bc8e5b4e782a0bbc4ac9689681f119beb7b34d59", +// "ObjectID": "f6dbf411da22e67d74cd7ddba6a76cd7e14a4822:124" +// }, // "Index": "0", -// "TV": { -// "T": { -// "@type": "/gno.RefType", -// "ID": "gno.land/p/demo/avl.Node" -// }, -// "V": { -// "@type": "/gno.RefValue", -// "Hash": "fb593e86d35aaf607e0d21e6bd4f84519c44585f", -// "ObjectID": "f6dbf411da22e67d74cd7ddba6a76cd7e14a4822:110" -// } -// } +// "TV": null // } // } // ], // "ObjectInfo": { -// "ID": "f6dbf411da22e67d74cd7ddba6a76cd7e14a4822:109", +// "ID": "f6dbf411da22e67d74cd7ddba6a76cd7e14a4822:123", // "ModTime": "0", -// "OwnerID": "f6dbf411da22e67d74cd7ddba6a76cd7e14a4822:96", +// "OwnerID": "f6dbf411da22e67d74cd7ddba6a76cd7e14a4822:122", // "RefCount": "1" // } // } -// c[f6dbf411da22e67d74cd7ddba6a76cd7e14a4822:112]={ +// c[f6dbf411da22e67d74cd7ddba6a76cd7e14a4822:122]={ +// "ObjectInfo": { +// "ID": "f6dbf411da22e67d74cd7ddba6a76cd7e14a4822:122", +// "ModTime": "0", +// "OwnerID": "f6dbf411da22e67d74cd7ddba6a76cd7e14a4822:106", +// "RefCount": "1" +// }, +// "Value": { +// "T": { +// "@type": "/gno.RefType", +// "ID": "gno.land/p/demo/avl.Node" +// }, +// "V": { +// "@type": "/gno.RefValue", +// "Hash": "9957eadbc91dd32f33b0d815e041a32dbdea0671", +// "ObjectID": "f6dbf411da22e67d74cd7ddba6a76cd7e14a4822:123" +// } +// } +// } +// c[f6dbf411da22e67d74cd7ddba6a76cd7e14a4822:128]={ // "Fields": [ // { // "T": { @@ -298,13 +261,13 @@ func main() { // } // ], // "ObjectInfo": { -// "ID": "f6dbf411da22e67d74cd7ddba6a76cd7e14a4822:112", +// "ID": "f6dbf411da22e67d74cd7ddba6a76cd7e14a4822:128", // "ModTime": "0", -// "OwnerID": "f6dbf411da22e67d74cd7ddba6a76cd7e14a4822:111", +// "OwnerID": "f6dbf411da22e67d74cd7ddba6a76cd7e14a4822:127", // "RefCount": "1" // } // } -// c[f6dbf411da22e67d74cd7ddba6a76cd7e14a4822:113]={ +// c[f6dbf411da22e67d74cd7ddba6a76cd7e14a4822:129]={ // "Fields": [ // { // "T": { @@ -317,13 +280,13 @@ func main() { // } // ], // "ObjectInfo": { -// "ID": "f6dbf411da22e67d74cd7ddba6a76cd7e14a4822:113", +// "ID": "f6dbf411da22e67d74cd7ddba6a76cd7e14a4822:129", // "ModTime": "0", -// "OwnerID": "f6dbf411da22e67d74cd7ddba6a76cd7e14a4822:111", +// "OwnerID": "f6dbf411da22e67d74cd7ddba6a76cd7e14a4822:127", // "RefCount": "1" // } // } -// c[f6dbf411da22e67d74cd7ddba6a76cd7e14a4822:114]={ +// c[f6dbf411da22e67d74cd7ddba6a76cd7e14a4822:130]={ // "Fields": [ // { // "T": { @@ -336,13 +299,13 @@ func main() { // } // ], // "ObjectInfo": { -// "ID": "f6dbf411da22e67d74cd7ddba6a76cd7e14a4822:114", +// "ID": "f6dbf411da22e67d74cd7ddba6a76cd7e14a4822:130", // "ModTime": "0", -// "OwnerID": "f6dbf411da22e67d74cd7ddba6a76cd7e14a4822:111", +// "OwnerID": "f6dbf411da22e67d74cd7ddba6a76cd7e14a4822:127", // "RefCount": "1" // } // } -// c[f6dbf411da22e67d74cd7ddba6a76cd7e14a4822:115]={ +// c[f6dbf411da22e67d74cd7ddba6a76cd7e14a4822:131]={ // "Fields": [ // { // "N": "AAAAgJSeXbo=", @@ -379,13 +342,13 @@ func main() { // } // ], // "ObjectInfo": { -// "ID": "f6dbf411da22e67d74cd7ddba6a76cd7e14a4822:115", +// "ID": "f6dbf411da22e67d74cd7ddba6a76cd7e14a4822:131", // "ModTime": "0", -// "OwnerID": "f6dbf411da22e67d74cd7ddba6a76cd7e14a4822:111", +// "OwnerID": "f6dbf411da22e67d74cd7ddba6a76cd7e14a4822:127", // "RefCount": "1" // } // } -// c[f6dbf411da22e67d74cd7ddba6a76cd7e14a4822:116]={ +// c[f6dbf411da22e67d74cd7ddba6a76cd7e14a4822:132]={ // "Fields": [ // { // "T": { @@ -410,13 +373,13 @@ func main() { // } // ], // "ObjectInfo": { -// "ID": "f6dbf411da22e67d74cd7ddba6a76cd7e14a4822:116", +// "ID": "f6dbf411da22e67d74cd7ddba6a76cd7e14a4822:132", // "ModTime": "0", -// "OwnerID": "f6dbf411da22e67d74cd7ddba6a76cd7e14a4822:111", +// "OwnerID": "f6dbf411da22e67d74cd7ddba6a76cd7e14a4822:127", // "RefCount": "1" // } // } -// c[f6dbf411da22e67d74cd7ddba6a76cd7e14a4822:111]={ +// c[f6dbf411da22e67d74cd7ddba6a76cd7e14a4822:127]={ // "Fields": [ // { // "T": { @@ -428,19 +391,13 @@ func main() { // }, // "V": { // "@type": "/gno.PointerValue", -// "Base": null, +// "Base": { +// "@type": "/gno.RefValue", +// "Escaped": true, +// "ObjectID": "f6dbf411da22e67d74cd7ddba6a76cd7e14a4822:84" +// }, // "Index": "0", -// "TV": { -// "T": { -// "@type": "/gno.RefType", -// "ID": "gno.land/r/demo/boards.Board" -// }, -// "V": { -// "@type": "/gno.RefValue", -// "Escaped": true, -// "ObjectID": "f6dbf411da22e67d74cd7ddba6a76cd7e14a4822:81" -// } -// } +// "TV": null // } // }, // { @@ -487,8 +444,8 @@ func main() { // }, // "V": { // "@type": "/gno.RefValue", -// "Hash": "130542396d7549d1d516a3ef4a63bb44ef3da06f", -// "ObjectID": "f6dbf411da22e67d74cd7ddba6a76cd7e14a4822:112" +// "Hash": "f91e355bd19240f0f3350a7fa0e6a82b72225916", +// "ObjectID": "f6dbf411da22e67d74cd7ddba6a76cd7e14a4822:128" // } // }, // { @@ -498,8 +455,8 @@ func main() { // }, // "V": { // "@type": "/gno.RefValue", -// "Hash": "80acd8746478317194b8546170335c796a4dfb3f", -// "ObjectID": "f6dbf411da22e67d74cd7ddba6a76cd7e14a4822:113" +// "Hash": "9ee9c4117be283fc51ffcc5ecd65b75ecef5a9dd", +// "ObjectID": "f6dbf411da22e67d74cd7ddba6a76cd7e14a4822:129" // } // }, // { @@ -509,8 +466,8 @@ func main() { // }, // "V": { // "@type": "/gno.RefValue", -// "Hash": "c1a8f769f3b9d52dd38ac4759116edaca287636f", -// "ObjectID": "f6dbf411da22e67d74cd7ddba6a76cd7e14a4822:114" +// "Hash": "eb768b0140a5fe95f9c58747f0960d647dacfd42", +// "ObjectID": "f6dbf411da22e67d74cd7ddba6a76cd7e14a4822:130" // } // }, // { @@ -540,8 +497,8 @@ func main() { // }, // "V": { // "@type": "/gno.RefValue", -// "Hash": "1dd77a196db00a4d1a3471539279df79f6ae950e", -// "ObjectID": "f6dbf411da22e67d74cd7ddba6a76cd7e14a4822:115" +// "Hash": "f56a463a97d103e183f1f368bf00a2ce99d4de88", +// "ObjectID": "f6dbf411da22e67d74cd7ddba6a76cd7e14a4822:131" // } // }, // { @@ -551,95 +508,57 @@ func main() { // }, // "V": { // "@type": "/gno.RefValue", -// "Hash": "c3a60b602b564d07677a212372f4ac1cae4270fd", -// "ObjectID": "f6dbf411da22e67d74cd7ddba6a76cd7e14a4822:116" +// "Hash": "bed4afa8ffdbbf775451c947fc68b27a345ce32a", +// "ObjectID": "f6dbf411da22e67d74cd7ddba6a76cd7e14a4822:132" // } // } // ], // "ObjectInfo": { -// "ID": "f6dbf411da22e67d74cd7ddba6a76cd7e14a4822:111", +// "ID": "f6dbf411da22e67d74cd7ddba6a76cd7e14a4822:127", +// "ModTime": "0", +// "OwnerID": "f6dbf411da22e67d74cd7ddba6a76cd7e14a4822:126", +// "RefCount": "1" +// } +// } +// c[f6dbf411da22e67d74cd7ddba6a76cd7e14a4822:126]={ +// "ObjectInfo": { +// "ID": "f6dbf411da22e67d74cd7ddba6a76cd7e14a4822:126", // "IsEscaped": true, // "ModTime": "0", // "RefCount": "2" +// }, +// "Value": { +// "T": { +// "@type": "/gno.RefType", +// "ID": "gno.land/r/demo/boards.Post" +// }, +// "V": { +// "@type": "/gno.RefValue", +// "Hash": "0651ea376feea18422dbe079f9d7fcbe3dfd32ad", +// "ObjectID": "f6dbf411da22e67d74cd7ddba6a76cd7e14a4822:127" +// } // } // } -// u[f6dbf411da22e67d74cd7ddba6a76cd7e14a4822:108]={ -// "Fields": [ -// { -// "T": { -// "@type": "/gno.PrimitiveType", -// "value": "16" -// }, -// "V": { -// "@type": "/gno.StringValue", -// "value": "0000000003" -// } -// }, -// { -// "T": { -// "@type": "/gno.PointerType", -// "Elt": { -// "@type": "/gno.RefType", -// "ID": "gno.land/r/demo/boards.Post" -// } -// }, -// "V": { -// "@type": "/gno.PointerValue", -// "Base": null, -// "Index": "0", -// "TV": { -// "T": { -// "@type": "/gno.RefType", -// "ID": "gno.land/r/demo/boards.Post" -// }, -// "V": { -// "@type": "/gno.RefValue", -// "Escaped": true, -// "ObjectID": "f6dbf411da22e67d74cd7ddba6a76cd7e14a4822:102" -// } -// } -// } -// }, -// { -// "T": { -// "@type": "/gno.PrimitiveType", -// "value": "64" -// } -// }, -// { -// "N": "AQAAAAAAAAA=", -// "T": { -// "@type": "/gno.PrimitiveType", -// "value": "32" -// } -// }, -// { -// "T": { -// "@type": "/gno.PointerType", -// "Elt": { -// "@type": "/gno.RefType", -// "ID": "gno.land/p/demo/avl.Node" -// } -// } -// }, -// { -// "T": { -// "@type": "/gno.PointerType", -// "Elt": { -// "@type": "/gno.RefType", -// "ID": "gno.land/p/demo/avl.Node" -// } -// } -// } -// ], +// u[f6dbf411da22e67d74cd7ddba6a76cd7e14a4822:120]={ // "ObjectInfo": { -// "ID": "f6dbf411da22e67d74cd7ddba6a76cd7e14a4822:108", -// "ModTime": "117", -// "OwnerID": "f6dbf411da22e67d74cd7ddba6a76cd7e14a4822:117", +// "ID": "f6dbf411da22e67d74cd7ddba6a76cd7e14a4822:120", +// "ModTime": "134", +// "OwnerID": "f6dbf411da22e67d74cd7ddba6a76cd7e14a4822:134", // "RefCount": "1" +// }, +// "Value": { +// "T": { +// "@type": "/gno.RefType", +// "ID": "gno.land/p/demo/avl.Node" +// }, +// "V": { +// "@type": "/gno.RefValue", +// "Hash": "dc1f011553dc53e7a846049e08cc77fa35ea6a51", +// "ObjectID": "f6dbf411da22e67d74cd7ddba6a76cd7e14a4822:121" +// } // } // } -// c[f6dbf411da22e67d74cd7ddba6a76cd7e14a4822:118]={ +// c[f6dbf411da22e67d74cd7ddba6a76cd7e14a4822:136]={ // "Fields": [ // { // "T": { @@ -661,19 +580,13 @@ func main() { // }, // "V": { // "@type": "/gno.PointerValue", -// "Base": null, +// "Base": { +// "@type": "/gno.RefValue", +// "Escaped": true, +// "ObjectID": "f6dbf411da22e67d74cd7ddba6a76cd7e14a4822:126" +// }, // "Index": "0", -// "TV": { -// "T": { -// "@type": "/gno.RefType", -// "ID": "gno.land/r/demo/boards.Post" -// }, -// "V": { -// "@type": "/gno.RefValue", -// "Escaped": true, -// "ObjectID": "f6dbf411da22e67d74cd7ddba6a76cd7e14a4822:111" -// } -// } +// "TV": null // } // }, // { @@ -709,13 +622,32 @@ func main() { // } // ], // "ObjectInfo": { -// "ID": "f6dbf411da22e67d74cd7ddba6a76cd7e14a4822:118", +// "ID": "f6dbf411da22e67d74cd7ddba6a76cd7e14a4822:136", +// "ModTime": "0", +// "OwnerID": "f6dbf411da22e67d74cd7ddba6a76cd7e14a4822:135", +// "RefCount": "1" +// } +// } +// c[f6dbf411da22e67d74cd7ddba6a76cd7e14a4822:135]={ +// "ObjectInfo": { +// "ID": "f6dbf411da22e67d74cd7ddba6a76cd7e14a4822:135", // "ModTime": "0", -// "OwnerID": "f6dbf411da22e67d74cd7ddba6a76cd7e14a4822:117", +// "OwnerID": "f6dbf411da22e67d74cd7ddba6a76cd7e14a4822:134", // "RefCount": "1" +// }, +// "Value": { +// "T": { +// "@type": "/gno.RefType", +// "ID": "gno.land/p/demo/avl.Node" +// }, +// "V": { +// "@type": "/gno.RefValue", +// "Hash": "96b86b4585c7f1075d7794180a5581f72733a7ab", +// "ObjectID": "f6dbf411da22e67d74cd7ddba6a76cd7e14a4822:136" +// } // } // } -// c[f6dbf411da22e67d74cd7ddba6a76cd7e14a4822:117]={ +// c[f6dbf411da22e67d74cd7ddba6a76cd7e14a4822:134]={ // "Fields": [ // { // "T": { @@ -752,19 +684,13 @@ func main() { // }, // "V": { // "@type": "/gno.PointerValue", -// "Base": null, +// "Base": { +// "@type": "/gno.RefValue", +// "Hash": "32274e1f28fb2b97d67a1262afd362d370de7faa", +// "ObjectID": "f6dbf411da22e67d74cd7ddba6a76cd7e14a4822:120" +// }, // "Index": "0", -// "TV": { -// "T": { -// "@type": "/gno.RefType", -// "ID": "gno.land/p/demo/avl.Node" -// }, -// "V": { -// "@type": "/gno.RefValue", -// "Hash": "6a86bc7763703c8f2b9d286368921159d6db121c", -// "ObjectID": "f6dbf411da22e67d74cd7ddba6a76cd7e14a4822:108" -// } -// } +// "TV": null // } // }, // { @@ -777,30 +703,43 @@ func main() { // }, // "V": { // "@type": "/gno.PointerValue", -// "Base": null, +// "Base": { +// "@type": "/gno.RefValue", +// "Hash": "c2cfd6aec36a462f35bf02e5bf4a127aa1bb7ac2", +// "ObjectID": "f6dbf411da22e67d74cd7ddba6a76cd7e14a4822:135" +// }, // "Index": "0", -// "TV": { -// "T": { -// "@type": "/gno.RefType", -// "ID": "gno.land/p/demo/avl.Node" -// }, -// "V": { -// "@type": "/gno.RefValue", -// "Hash": "52faa8a2dfefd4b6b6249eff2f9c123ad455e81d", -// "ObjectID": "f6dbf411da22e67d74cd7ddba6a76cd7e14a4822:118" -// } -// } +// "TV": null // } // } // ], // "ObjectInfo": { -// "ID": "f6dbf411da22e67d74cd7ddba6a76cd7e14a4822:117", +// "ID": "f6dbf411da22e67d74cd7ddba6a76cd7e14a4822:134", // "ModTime": "0", -// "OwnerID": "f6dbf411da22e67d74cd7ddba6a76cd7e14a4822:97", +// "OwnerID": "f6dbf411da22e67d74cd7ddba6a76cd7e14a4822:133", // "RefCount": "1" // } // } -// u[f6dbf411da22e67d74cd7ddba6a76cd7e14a4822:81]={ +// c[f6dbf411da22e67d74cd7ddba6a76cd7e14a4822:133]={ +// "ObjectInfo": { +// "ID": "f6dbf411da22e67d74cd7ddba6a76cd7e14a4822:133", +// "ModTime": "0", +// "OwnerID": "f6dbf411da22e67d74cd7ddba6a76cd7e14a4822:107", +// "RefCount": "1" +// }, +// "Value": { +// "T": { +// "@type": "/gno.RefType", +// "ID": "gno.land/p/demo/avl.Node" +// }, +// "V": { +// "@type": "/gno.RefValue", +// "Hash": "5cb875179e86d32c517322af7a323b2a5f3e6cc5", +// "ObjectID": "f6dbf411da22e67d74cd7ddba6a76cd7e14a4822:134" +// } +// } +// } +// u[f6dbf411da22e67d74cd7ddba6a76cd7e14a4822:85]={ // "Fields": [ // { // "N": "AQAAAAAAAAA=", @@ -846,8 +785,8 @@ func main() { // }, // "V": { // "@type": "/gno.RefValue", -// "Hash": "6e8ecb1c773e0e34ba560dcff1b2dee0bc2e5660", -// "ObjectID": "f6dbf411da22e67d74cd7ddba6a76cd7e14a4822:82" +// "Hash": "1d70015c486ccc9bfb7c425152605fabc78be1dd", +// "ObjectID": "f6dbf411da22e67d74cd7ddba6a76cd7e14a4822:86" // } // }, // { @@ -864,8 +803,8 @@ func main() { // }, // "V": { // "@type": "/gno.RefValue", -// "Hash": "796da27e11e6d75db3e0e8f9d633f4559f1b1a82", -// "ObjectID": "f6dbf411da22e67d74cd7ddba6a76cd7e14a4822:83" +// "Hash": "b8ee1687a4f45886912ba624c8513a2a1526b94c", +// "ObjectID": "f6dbf411da22e67d74cd7ddba6a76cd7e14a4822:87" // } // }, // { @@ -875,19 +814,19 @@ func main() { // }, // "V": { // "@type": "/gno.RefValue", -// "Hash": "edb1857302fa916c562cd077cdf2a3626e29ae2b", -// "ObjectID": "f6dbf411da22e67d74cd7ddba6a76cd7e14a4822:84" +// "Hash": "af6ed0268f99b7f369329094eb6dfaea7812708b", +// "ObjectID": "f6dbf411da22e67d74cd7ddba6a76cd7e14a4822:88" // } // } // ], // "ObjectInfo": { -// "ID": "f6dbf411da22e67d74cd7ddba6a76cd7e14a4822:81", -// "IsEscaped": true, -// "ModTime": "108", -// "RefCount": "6" +// "ID": "f6dbf411da22e67d74cd7ddba6a76cd7e14a4822:85", +// "ModTime": "121", +// "OwnerID": "f6dbf411da22e67d74cd7ddba6a76cd7e14a4822:84", +// "RefCount": "1" // } // } -// u[f6dbf411da22e67d74cd7ddba6a76cd7e14a4822:96]={ +// u[f6dbf411da22e67d74cd7ddba6a76cd7e14a4822:106]={ // "Fields": [ // { // "T": { @@ -899,30 +838,24 @@ func main() { // }, // "V": { // "@type": "/gno.PointerValue", -// "Base": null, +// "Base": { +// "@type": "/gno.RefValue", +// "Hash": "9809329dc1ddc5d3556f7a8fa3c2cebcbf65560b", +// "ObjectID": "f6dbf411da22e67d74cd7ddba6a76cd7e14a4822:122" +// }, // "Index": "0", -// "TV": { -// "T": { -// "@type": "/gno.RefType", -// "ID": "gno.land/p/demo/avl.Node" -// }, -// "V": { -// "@type": "/gno.RefValue", -// "Hash": "609e7f519c65f94503427a14f973b4b83989cdc8", -// "ObjectID": "f6dbf411da22e67d74cd7ddba6a76cd7e14a4822:109" -// } -// } +// "TV": null // } // } // ], // "ObjectInfo": { -// "ID": "f6dbf411da22e67d74cd7ddba6a76cd7e14a4822:96", -// "ModTime": "108", -// "OwnerID": "f6dbf411da22e67d74cd7ddba6a76cd7e14a4822:95", +// "ID": "f6dbf411da22e67d74cd7ddba6a76cd7e14a4822:106", +// "ModTime": "121", +// "OwnerID": "f6dbf411da22e67d74cd7ddba6a76cd7e14a4822:105", // "RefCount": "1" // } // } -// u[f6dbf411da22e67d74cd7ddba6a76cd7e14a4822:97]={ +// u[f6dbf411da22e67d74cd7ddba6a76cd7e14a4822:107]={ // "Fields": [ // { // "T": { @@ -934,26 +867,20 @@ func main() { // }, // "V": { // "@type": "/gno.PointerValue", -// "Base": null, +// "Base": { +// "@type": "/gno.RefValue", +// "Hash": "ceae9a1c4ed28bb51062e6ccdccfad0caafd1c4f", +// "ObjectID": "f6dbf411da22e67d74cd7ddba6a76cd7e14a4822:133" +// }, // "Index": "0", -// "TV": { -// "T": { -// "@type": "/gno.RefType", -// "ID": "gno.land/p/demo/avl.Node" -// }, -// "V": { -// "@type": "/gno.RefValue", -// "Hash": "6760340f5b40e05221dc530940683b0b9a422503", -// "ObjectID": "f6dbf411da22e67d74cd7ddba6a76cd7e14a4822:117" -// } -// } +// "TV": null // } // } // ], // "ObjectInfo": { -// "ID": "f6dbf411da22e67d74cd7ddba6a76cd7e14a4822:97", -// "ModTime": "108", -// "OwnerID": "f6dbf411da22e67d74cd7ddba6a76cd7e14a4822:95", +// "ID": "f6dbf411da22e67d74cd7ddba6a76cd7e14a4822:107", +// "ModTime": "121", +// "OwnerID": "f6dbf411da22e67d74cd7ddba6a76cd7e14a4822:105", // "RefCount": "1" // } // } diff --git a/examples/gno.land/r/demo/nft/z_0_filetest.gno b/examples/gno.land/r/demo/nft/z_0_filetest.gno index 9e8010abaf5..0595e76a0ed 100644 --- a/examples/gno.land/r/demo/nft/z_0_filetest.gno +++ b/examples/gno.land/r/demo/nft/z_0_filetest.gno @@ -22,7 +22,7 @@ func main() { // Realm: // switchrealm["gno.land/r/demo/nft"] // switchrealm["gno.land/r/demo/nft"] -// c[67c479d3d51d4056b2f4111d5352912a00be311e:8]={ +// c[67c479d3d51d4056b2f4111d5352912a00be311e:11]={ // "Fields": [ // { // "T": { @@ -62,13 +62,32 @@ func main() { // } // ], // "ObjectInfo": { -// "ID": "67c479d3d51d4056b2f4111d5352912a00be311e:8", +// "ID": "67c479d3d51d4056b2f4111d5352912a00be311e:11", // "ModTime": "0", -// "OwnerID": "67c479d3d51d4056b2f4111d5352912a00be311e:7", +// "OwnerID": "67c479d3d51d4056b2f4111d5352912a00be311e:10", // "RefCount": "1" // } // } -// c[67c479d3d51d4056b2f4111d5352912a00be311e:7]={ +// c[67c479d3d51d4056b2f4111d5352912a00be311e:10]={ +// "ObjectInfo": { +// "ID": "67c479d3d51d4056b2f4111d5352912a00be311e:10", +// "ModTime": "0", +// "OwnerID": "67c479d3d51d4056b2f4111d5352912a00be311e:9", +// "RefCount": "1" +// }, +// "Value": { +// "T": { +// "@type": "/gno.RefType", +// "ID": "gno.land/r/demo/nft.NFToken" +// }, +// "V": { +// "@type": "/gno.RefValue", +// "Hash": "564a9e78be869bd258fc3c9ad56f5a75ed68818f", +// "ObjectID": "67c479d3d51d4056b2f4111d5352912a00be311e:11" +// } +// } +// } +// c[67c479d3d51d4056b2f4111d5352912a00be311e:9]={ // "Fields": [ // { // "T": { @@ -90,19 +109,13 @@ func main() { // }, // "V": { // "@type": "/gno.PointerValue", -// "Base": null, +// "Base": { +// "@type": "/gno.RefValue", +// "Hash": "b53ffc464e1b5655d19b9d5277f3491717c24aca", +// "ObjectID": "67c479d3d51d4056b2f4111d5352912a00be311e:10" +// }, // "Index": "0", -// "TV": { -// "T": { -// "@type": "/gno.RefType", -// "ID": "gno.land/r/demo/nft.NFToken" -// }, -// "V": { -// "@type": "/gno.RefValue", -// "Hash": "c06f58d0ff2bc26ad3e65e953b127a0d03353e97", -// "ObjectID": "67c479d3d51d4056b2f4111d5352912a00be311e:8" -// } -// } +// "TV": null // } // }, // { @@ -138,13 +151,32 @@ func main() { // } // ], // "ObjectInfo": { -// "ID": "67c479d3d51d4056b2f4111d5352912a00be311e:7", +// "ID": "67c479d3d51d4056b2f4111d5352912a00be311e:9", // "ModTime": "0", -// "OwnerID": "67c479d3d51d4056b2f4111d5352912a00be311e:5", +// "OwnerID": "67c479d3d51d4056b2f4111d5352912a00be311e:8", // "RefCount": "1" // } // } -// u[67c479d3d51d4056b2f4111d5352912a00be311e:5]={ +// c[67c479d3d51d4056b2f4111d5352912a00be311e:8]={ +// "ObjectInfo": { +// "ID": "67c479d3d51d4056b2f4111d5352912a00be311e:8", +// "ModTime": "0", +// "OwnerID": "67c479d3d51d4056b2f4111d5352912a00be311e:6", +// "RefCount": "1" +// }, +// "Value": { +// "T": { +// "@type": "/gno.RefType", +// "ID": "gno.land/p/demo/avl.Node" +// }, +// "V": { +// "@type": "/gno.RefValue", +// "Hash": "b1d928b3716b147c92730e8d234162bec2f0f2fc", +// "ObjectID": "67c479d3d51d4056b2f4111d5352912a00be311e:9" +// } +// } +// } +// u[67c479d3d51d4056b2f4111d5352912a00be311e:6]={ // "Fields": [ // { // "T": { @@ -156,30 +188,24 @@ func main() { // }, // "V": { // "@type": "/gno.PointerValue", -// "Base": null, +// "Base": { +// "@type": "/gno.RefValue", +// "Hash": "75850e56fa2c3c8b6d6814b1f150919b75355752", +// "ObjectID": "67c479d3d51d4056b2f4111d5352912a00be311e:8" +// }, // "Index": "0", -// "TV": { -// "T": { -// "@type": "/gno.RefType", -// "ID": "gno.land/p/demo/avl.Node" -// }, -// "V": { -// "@type": "/gno.RefValue", -// "Hash": "45a64533aa57b49b6b4a1d3f6de79db8bea3a710", -// "ObjectID": "67c479d3d51d4056b2f4111d5352912a00be311e:7" -// } -// } +// "TV": null // } // } // ], // "ObjectInfo": { -// "ID": "67c479d3d51d4056b2f4111d5352912a00be311e:5", -// "ModTime": "6", -// "OwnerID": "67c479d3d51d4056b2f4111d5352912a00be311e:4", +// "ID": "67c479d3d51d4056b2f4111d5352912a00be311e:6", +// "ModTime": "7", +// "OwnerID": "67c479d3d51d4056b2f4111d5352912a00be311e:5", // "RefCount": "1" // } // } -// u[67c479d3d51d4056b2f4111d5352912a00be311e:4]={ +// u[67c479d3d51d4056b2f4111d5352912a00be311e:5]={ // "Fields": [ // {}, // { @@ -196,8 +222,8 @@ func main() { // }, // "V": { // "@type": "/gno.RefValue", -// "Hash": "dad3106a54e1facb92bce473898b8aec0eb930ff", -// "ObjectID": "67c479d3d51d4056b2f4111d5352912a00be311e:5" +// "Hash": "700d932c087f30499941de2b589867dc17aaea5a", +// "ObjectID": "67c479d3d51d4056b2f4111d5352912a00be311e:6" // } // }, // { @@ -207,15 +233,15 @@ func main() { // }, // "V": { // "@type": "/gno.RefValue", -// "Hash": "05ab6746ea84b55ca133806af215d99a1c4b045e", -// "ObjectID": "67c479d3d51d4056b2f4111d5352912a00be311e:6" +// "Hash": "e06585aff551113920c929453ea40250f3cc01bc", +// "ObjectID": "67c479d3d51d4056b2f4111d5352912a00be311e:7" // } // } // ], // "ObjectInfo": { -// "ID": "67c479d3d51d4056b2f4111d5352912a00be311e:4", -// "ModTime": "6", -// "OwnerID": "67c479d3d51d4056b2f4111d5352912a00be311e:2", +// "ID": "67c479d3d51d4056b2f4111d5352912a00be311e:5", +// "ModTime": "7", +// "OwnerID": "67c479d3d51d4056b2f4111d5352912a00be311e:4", // "RefCount": "1" // } // } diff --git a/gnovm/pkg/gnolang/alloc.go b/gnovm/pkg/gnolang/alloc.go index 495be0d2dc2..6fef5eda834 100644 --- a/gnovm/pkg/gnolang/alloc.go +++ b/gnovm/pkg/gnolang/alloc.go @@ -62,6 +62,7 @@ const ( // allocPackge = 1 allocAmino = _allocBase + _allocPointer + _allocAny allocAminoByte = 10 // XXX + allocHeapItem = _allocBase + _allocPointer + _allocTypedValue ) func NewAllocator(maxBytes int64) *Allocator { @@ -180,6 +181,10 @@ func (alloc *Allocator) AllocateAmino(l int64) { alloc.Allocate(allocAmino + allocAminoByte*l) } +func (alloc *Allocator) AllocateHeapItem() { + alloc.Allocate(allocHeapItem) +} + //---------------------------------------- // constructor utilities. @@ -291,3 +296,8 @@ func (alloc *Allocator) NewType(t Type) Type { alloc.AllocateType() return t } + +func (alloc *Allocator) NewHeapItem(tv TypedValue) *HeapItemValue { + alloc.AllocateHeapItem() + return &HeapItemValue{Value: tv} +} diff --git a/gnovm/pkg/gnolang/machine.go b/gnovm/pkg/gnolang/machine.go index 48a2145af3a..864384ea122 100644 --- a/gnovm/pkg/gnolang/machine.go +++ b/gnovm/pkg/gnolang/machine.go @@ -1956,9 +1956,11 @@ func (m *Machine) PopAsPointer(lx Expr) PointerValue { return ptr case *CompositeLitExpr: // for *RefExpr tv := *m.PopValue() + hv := m.Alloc.NewHeapItem(tv) return PointerValue{ - TV: &tv, // heap alloc - Base: nil, + TV: &hv.Value, + Base: hv, + Index: 0, } default: panic("should not happen") diff --git a/gnovm/pkg/gnolang/ownership.go b/gnovm/pkg/gnolang/ownership.go index f2afc393d05..24d70b5dd84 100644 --- a/gnovm/pkg/gnolang/ownership.go +++ b/gnovm/pkg/gnolang/ownership.go @@ -129,6 +129,7 @@ var ( _ Object = &BoundMethodValue{} _ Object = &MapValue{} _ Object = &Block{} + _ Object = &HeapItemValue{} ) type ObjectInfo struct { @@ -332,11 +333,7 @@ func (tv *TypedValue) GetFirstObject(store Store) Object { // something in it; in that case, ignore the base. That will // likely require maybe a preparation step in persistence // ( or unlikely, a second type of ref-counting). - if cv.Base != nil { - return cv.Base.(Object) - } else { - return cv.TV.GetFirstObject(store) - } + return cv.Base.(Object) case *ArrayValue: return cv case *SliceValue: @@ -359,6 +356,9 @@ func (tv *TypedValue) GetFirstObject(store Store) Object { oo := store.GetObject(cv.ObjectID) tv.V = oo return oo + case *HeapItemValue: + // should only appear in PointerValue.Base + panic("heap item value should only appear as a pointer's base") default: return nil } diff --git a/gnovm/pkg/gnolang/package.go b/gnovm/pkg/gnolang/package.go index 4d4cb5aaf45..e2fdb2580ca 100644 --- a/gnovm/pkg/gnolang/package.go +++ b/gnovm/pkg/gnolang/package.go @@ -31,6 +31,7 @@ var Package = amino.RegisterPackage(amino.NewPackage( // &NativeValue{}, &Block{}, RefValue{}, + &HeapItemValue{}, //---------------------------------------- // Realm/Object diff --git a/gnovm/pkg/gnolang/realm.go b/gnovm/pkg/gnolang/realm.go index 0036f9a54bf..3a55b2e14b4 100644 --- a/gnovm/pkg/gnolang/realm.go +++ b/gnovm/pkg/gnolang/realm.go @@ -147,6 +147,12 @@ func (rlm *Realm) DidUpdate(po, xo, co Object) { if po.GetObjectID().PkgID != rlm.ID { panic("cannot modify external-realm or non-realm object") } + + // XXX check if this boosts performance + // XXX with broad integration benchmarking. + // XXX if co == xo { + // XXX } + // From here on, po is real (not new-real). // Updates to .newCreated/.newEscaped /.newDeleted made here. (first gen) // More appends happen during FinalizeRealmTransactions(). (second+ gen) @@ -723,18 +729,6 @@ func (rlm *Realm) saveObject(store Store, oo Object) { if oid.IsZero() { panic("unexpected zero object id") } - /* XXX DELETE - // ensure all types were already saved (@ preprocessor). - if debug { - types := getUnsavedTypes(oo, nil) - for _, typ := range types { - tid := typ.TypeID() - if store.GetType(tid) == nil { - panic("missing type") - } - } - } - */ // set hash to escape index. if oo.GetIsNewEscaped() { oo.SetIsNewEscaped(false) @@ -822,11 +816,10 @@ func getChildObjects(val Value, more []Value) []Value { case DataByteValue: panic("cannot get children from data byte objects") case PointerValue: - if cv.Base != nil { - more = getSelfOrChildObjects(cv.Base, more) - } else { - more = getSelfOrChildObjects(cv.TV.V, more) + if cv.Base == nil { + panic("should not happen") } + more = getSelfOrChildObjects(cv.Base, more) return more case *ArrayValue: for _, ctv := range cv.List { @@ -868,8 +861,14 @@ func getChildObjects(val Value, more []Value) []Value { for _, ctv := range cv.Values { more = getSelfOrChildObjects(ctv.V, more) } + // Generally the parent block must also be persisted. + // Otherwise NamePath may not resolve when referencing + // a parent block. more = getSelfOrChildObjects(cv.Parent, more) return more + case *HeapItemValue: + more = getSelfOrChildObjects(cv.Value.V, more) + return more case *NativeValue: panic("native values not supported") default: @@ -935,7 +934,7 @@ func copyMethods(methods []TypedValue) []TypedValue { // gets saved (e.g. from *Machine.savePackage()). res[i] = TypedValue{ T: copyTypeWithRefs(mtv.T), - V: copyValueWithRefs(nil, mtv.V), + V: copyValueWithRefs(mtv.V), } } return res @@ -1054,7 +1053,7 @@ func copyTypeWithRefs(typ Type) Type { // persistence bytes serialization. // Also checks for integrity of immediate children -- they must already be // persistent (real), and not dirty, or else this function panics. -func copyValueWithRefs(parent Object, val Value) Value { +func copyValueWithRefs(val Value) Value { switch cv := val.(type) { case nil: return nil @@ -1067,33 +1066,25 @@ func copyValueWithRefs(parent Object, val Value) Value { case DataByteValue: panic("cannot copy data byte value with references") case PointerValue: - if cv.Base != nil { - return PointerValue{ - /* - already represented in .Base[Index]: - TypedValue: &TypedValue{ - T: cv.TypedValue.T, - V: copyValueWithRefs(cv.TypedValue.V), - }, - */ - Base: toRefValue(parent, cv.Base), - Index: cv.Index, - } - } else { - etv := refOrCopyValue(parent, *cv.TV) - return PointerValue{ - TV: &etv, - /* - Base: nil, - Index: 0, - */ - } + if cv.Base == nil { + panic("should not happen") + } + return PointerValue{ + /* + already represented in .Base[Index]: + TypedValue: &TypedValue{ + T: cv.TypedValue.T, + V: copyValueWithRefs(cv.TypedValue.V), + }, + */ + Base: toRefValue(cv.Base), + Index: cv.Index, } case *ArrayValue: if cv.Data == nil { list := make([]TypedValue, len(cv.List)) for i, etv := range cv.List { - list[i] = refOrCopyValue(cv, etv) + list[i] = refOrCopyValue(etv) } return &ArrayValue{ ObjectInfo: cv.ObjectInfo.Copy(), @@ -1107,7 +1098,7 @@ func copyValueWithRefs(parent Object, val Value) Value { } case *SliceValue: return &SliceValue{ - Base: toRefValue(parent, cv.Base), + Base: toRefValue(cv.Base), Offset: cv.Offset, Length: cv.Length, Maxcap: cv.Maxcap, @@ -1115,7 +1106,7 @@ func copyValueWithRefs(parent Object, val Value) Value { case *StructValue: fields := make([]TypedValue, len(cv.Fields)) for i, ftv := range cv.Fields { - fields[i] = refOrCopyValue(cv, ftv) + fields[i] = refOrCopyValue(ftv) } return &StructValue{ ObjectInfo: cv.ObjectInfo.Copy(), @@ -1129,7 +1120,7 @@ func copyValueWithRefs(parent Object, val Value) Value { } var closure Value if cv.Closure != nil { - closure = toRefValue(parent, cv.Closure) + closure = toRefValue(cv.Closure) } // nativeBody funcs which don't come from NativeStore (and thus don't // have NativePkg/Name) can't be persisted, and should not be able @@ -1150,8 +1141,8 @@ func copyValueWithRefs(parent Object, val Value) Value { NativeName: cv.NativeName, } case *BoundMethodValue: - fnc := copyValueWithRefs(cv, cv.Func).(*FuncValue) - rtv := refOrCopyValue(cv, cv.Receiver) + fnc := copyValueWithRefs(cv.Func).(*FuncValue) + rtv := refOrCopyValue(cv.Receiver) return &BoundMethodValue{ ObjectInfo: cv.ObjectInfo.Copy(), // XXX ??? Func: fnc, @@ -1160,8 +1151,8 @@ func copyValueWithRefs(parent Object, val Value) Value { case *MapValue: list := &MapList{} for cur := cv.List.Head; cur != nil; cur = cur.Next { - key2 := refOrCopyValue(cv, cur.Key) - val2 := refOrCopyValue(cv, cur.Value) + key2 := refOrCopyValue(cur.Key) + val2 := refOrCopyValue(cur.Value) list.Append(nilAllocator, key2).Value = val2 } return &MapValue{ @@ -1171,10 +1162,10 @@ func copyValueWithRefs(parent Object, val Value) Value { case TypeValue: return toTypeValue(copyTypeWithRefs(cv.Type)) case *PackageValue: - block := toRefValue(cv, cv.Block) + block := toRefValue(cv.Block) fblocks := make([]Value, len(cv.FBlocks)) for i, fb := range cv.FBlocks { - fblocks[i] = toRefValue(cv, fb) + fblocks[i] = toRefValue(fb) } return &PackageValue{ ObjectInfo: cv.ObjectInfo.Copy(), @@ -1189,11 +1180,11 @@ func copyValueWithRefs(parent Object, val Value) Value { source := toRefNode(cv.Source) vals := make([]TypedValue, len(cv.Values)) for i, tv := range cv.Values { - vals[i] = refOrCopyValue(cv, tv) + vals[i] = refOrCopyValue(tv) } var bparent Value if cv.Parent != nil { - bparent = toRefValue(parent, cv.Parent) + bparent = toRefValue(cv.Parent) } bl := &Block{ ObjectInfo: cv.ObjectInfo.Copy(), @@ -1205,6 +1196,24 @@ func copyValueWithRefs(parent Object, val Value) Value { return bl case RefValue: return cv + case *HeapItemValue: + // NOTE: While this could be eliminated sometimes with some + // intelligence prior to persistence, to unwrap the + // HeapItemValue in case where the HeapItemValue only has + // refcount of 1, + // + // 1. The HeapItemValue is necessary when the .Value is a + // primitive non-object anyways, and + // 2. This would mean PointerValue.Base is nil, and we'd need + // additional logic to re-wrap when necessary, and + // 3. And with the above point, it's not clear the result + // would be any faster. But this is something we could + // explore after launch. + hiv := &HeapItemValue{ + ObjectInfo: cv.ObjectInfo.Copy(), + Value: refOrCopyValue(cv.Value), + } + return hiv case *NativeValue: panic("native values not supported") default: @@ -1376,6 +1385,9 @@ func fillTypesOfValue(store Store, val Value) Value { panic("native values not supported") case RefValue: // do nothing return cv + case *HeapItemValue: + fillTypesTV(store, &cv.Value) + return cv default: panic(fmt.Sprintf( "unexpected type %v", @@ -1423,7 +1435,7 @@ func toRefNode(bn BlockNode) RefNode { } } -func toRefValue(parent Object, val Value) RefValue { +func toRefValue(val Value) RefValue { // TODO use type switch stmt. if ref, ok := val.(RefValue); ok { return ref @@ -1496,15 +1508,15 @@ func ensureUniq(oozz ...[]Object) { } } -func refOrCopyValue(parent Object, tv TypedValue) TypedValue { +func refOrCopyValue(tv TypedValue) TypedValue { if tv.T != nil { tv.T = refOrCopyType(tv.T) } if obj, ok := tv.V.(Object); ok { - tv.V = toRefValue(parent, obj) + tv.V = toRefValue(obj) return tv } else { - tv.V = copyValueWithRefs(parent, tv.V) + tv.V = copyValueWithRefs(tv.V) return tv } } diff --git a/gnovm/pkg/gnolang/store.go b/gnovm/pkg/gnolang/store.go index 3db53213f8b..b2ec25e2778 100644 --- a/gnovm/pkg/gnolang/store.go +++ b/gnovm/pkg/gnolang/store.go @@ -305,7 +305,7 @@ func (ds *defaultStore) loadObjectSafe(oid ObjectID) Object { func (ds *defaultStore) SetObject(oo Object) { oid := oo.GetObjectID() // replace children/fields with Ref. - o2 := copyValueWithRefs(nil, oo) + o2 := copyValueWithRefs(oo) // marshal to binary. bz := amino.MustMarshalAny(o2) // set hash. diff --git a/gnovm/pkg/gnolang/uverse.go b/gnovm/pkg/gnolang/uverse.go index df16ecf0ad9..880a75396ca 100644 --- a/gnovm/pkg/gnolang/uverse.go +++ b/gnovm/pkg/gnolang/uverse.go @@ -911,16 +911,18 @@ func UverseNode() *PackageNode { tt := arg0.TV.GetType() vv := defaultValue(m.Alloc, tt) m.Alloc.AllocatePointer() + hi := m.Alloc.NewHeapItem(TypedValue{ + T: tt, + V: vv, + }) m.PushValue(TypedValue{ T: m.Alloc.NewType(&PointerType{ Elt: tt, }), V: PointerValue{ - TV: &TypedValue{ - T: tt, - V: vv, - }, - Base: nil, + TV: &hi.Value, + Base: hi, + Index: 0, }, }) return diff --git a/gnovm/pkg/gnolang/values.go b/gnovm/pkg/gnolang/values.go index 344977a849c..d38c083428c 100644 --- a/gnovm/pkg/gnolang/values.go +++ b/gnovm/pkg/gnolang/values.go @@ -41,6 +41,7 @@ func (*PackageValue) assertValue() {} func (*NativeValue) assertValue() {} func (*Block) assertValue() {} func (RefValue) assertValue() {} +func (*HeapItemValue) assertValue() {} const ( nilStr = "nil" @@ -64,6 +65,7 @@ var ( _ Value = &NativeValue{} _ Value = &Block{} _ Value = RefValue{} + _ Value = &HeapItemValue{} ) // ---------------------------------------- @@ -166,14 +168,20 @@ func (dbv DataByteValue) SetByte(b byte) { // Index is -1 for the shared "_" block var, // and -2 for (gno and native) map items. // +// A pointer constructed via a &x{} composite lit expression or constructed via +// new() or make() will have a virtual HeapItemValue as base. +// // Allocation for PointerValue is not immediate, // as usually PointerValues are temporary for assignment // or binary operations. When a pointer is to be // allocated, *Allocator.AllocatePointer() is called separately, // as in OpRef. +// +// Since PointerValue is used internally for assignment etc, +// it MUST stay minimal for computational efficiency. type PointerValue struct { TV *TypedValue // escape val if pointer to var. - Base Value // array/struct/block. + Base Value // array/struct/block, or heapitem. Index int // list/fields/values index, or -1 or -2 (see below). Key *TypedValue `json:",omitempty"` // for maps. } @@ -2336,12 +2344,12 @@ func (tv *TypedValue) GetSlice2(alloc *Allocator, low, high, max int) TypedValue // TODO rename to BlockValue. type Block struct { - ObjectInfo // for closures - Source BlockNode - Values []TypedValue - Parent Value - Blank TypedValue // captures "_" // XXX remove and replace with global instance. - bodyStmt bodyStmt // XXX expose for persistence, not needed for MVP. + ObjectInfo + Source BlockNode + Values []TypedValue + Parent Value + Blank TypedValue // captures "_" // XXX remove and replace with global instance. + bodyStmt bodyStmt // XXX expose for persistence, not needed for MVP. } // NOTE: for allocation, use *Allocator.NewBlock. @@ -2501,6 +2509,15 @@ type RefValue struct { Hash ValueHash `json:",omitempty"` } +// Base for a detached singleton (e.g. new(int) or &struct{}) +// Conceptually like a Block that holds one value. +// NOTE: could be renamed to HeapItemBaseValue. +// See also note in realm.go about auto-unwrapping. +type HeapItemValue struct { + ObjectInfo + Value TypedValue +} + // ---------------------------------------- func defaultStructFields(alloc *Allocator, st *StructType) []TypedValue { @@ -2629,6 +2646,8 @@ func fillValueTV(store Store, tv *TypedValue) *TypedValue { case *Block: vpv := cb.GetPointerToInt(store, cv.Index) cv.TV = vpv.TV // TODO optimize? + case *HeapItemValue: + cv.TV = &cb.Value default: panic("should not happen") } diff --git a/gnovm/pkg/gnolang/values_string.go b/gnovm/pkg/gnolang/values_string.go index 4ae05c8a97d..204fab62c86 100644 --- a/gnovm/pkg/gnolang/values_string.go +++ b/gnovm/pkg/gnolang/values_string.go @@ -258,6 +258,11 @@ func (v RefValue) String() string { v.PkgPath) } +func (v *HeapItemValue) String() string { + return fmt.Sprintf("heapitem(%v)", + v.Value) +} + // ---------------------------------------- // *TypedValue.Sprint diff --git a/gnovm/tests/files/assign_unnamed_type/more/realm_compositelit_filetest.gno b/gnovm/tests/files/assign_unnamed_type/more/realm_compositelit_filetest.gno index 6549d1824ed..6ef12bd33d4 100644 --- a/gnovm/tests/files/assign_unnamed_type/more/realm_compositelit_filetest.gno +++ b/gnovm/tests/files/assign_unnamed_type/more/realm_compositelit_filetest.gno @@ -30,7 +30,7 @@ func main() { // Realm: // switchrealm["gno.land/r/test"] -// c[a8ada09dee16d791fd406d629fe29bb0ed084a30:5]={ +// c[a8ada09dee16d791fd406d629fe29bb0ed084a30:6]={ // "Data": null, // "List": [ // { @@ -41,13 +41,13 @@ func main() { // } // ], // "ObjectInfo": { -// "ID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:5", +// "ID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:6", // "ModTime": "0", -// "OwnerID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:4", +// "OwnerID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:5", // "RefCount": "1" // } // } -// c[a8ada09dee16d791fd406d629fe29bb0ed084a30:4]={ +// c[a8ada09dee16d791fd406d629fe29bb0ed084a30:5]={ // "Fields": [ // { // "T": { @@ -58,8 +58,8 @@ func main() { // "@type": "/gno.SliceValue", // "Base": { // "@type": "/gno.RefValue", -// "Hash": "9263ebf7e55e2d929e9c190bc4490ee58db148ec", -// "ObjectID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:5" +// "Hash": "e256933ba4dfda233a7edb0902880d554118ba6e", +// "ObjectID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:6" // }, // "Length": "1", // "Maxcap": "1", @@ -68,10 +68,29 @@ func main() { // } // ], // "ObjectInfo": { +// "ID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:5", +// "ModTime": "0", +// "OwnerID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:4", +// "RefCount": "1" +// } +// } +// c[a8ada09dee16d791fd406d629fe29bb0ed084a30:4]={ +// "ObjectInfo": { // "ID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:4", // "ModTime": "0", // "OwnerID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:2", // "RefCount": "1" +// }, +// "Value": { +// "T": { +// "@type": "/gno.RefType", +// "ID": "gno.land/r/test.Int" +// }, +// "V": { +// "@type": "/gno.RefValue", +// "Hash": "2b8a024c53e94431e6203115feaf86b36413d7b2", +// "ObjectID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:5" +// } // } // } // u[a8ada09dee16d791fd406d629fe29bb0ed084a30:2]={ @@ -209,19 +228,13 @@ func main() { // }, // "V": { // "@type": "/gno.PointerValue", -// "Base": null, +// "Base": { +// "@type": "/gno.RefValue", +// "Hash": "3c89d875f7d6daa94113aa4c7e03432ba56202c2", +// "ObjectID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:4" +// }, // "Index": "0", -// "TV": { -// "T": { -// "@type": "/gno.RefType", -// "ID": "gno.land/r/test.Int" -// }, -// "V": { -// "@type": "/gno.RefValue", -// "Hash": "91ebdb8ff6b68e0b93179fae022213185a450649", -// "ObjectID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:4" -// } -// } +// "TV": null // } // } // ] diff --git a/gnovm/tests/files/heap_item_value.gno b/gnovm/tests/files/heap_item_value.gno new file mode 100644 index 00000000000..fe2873f9b60 --- /dev/null +++ b/gnovm/tests/files/heap_item_value.gno @@ -0,0 +1,178 @@ +// PKGPATH: gno.land/r/test +package test + +type S struct { + A int +} + +var a, b *S + +func main() { + a = new(S) + a.A = 4 + b = a +} + +// Realm: +// switchrealm["gno.land/r/test"] +// c[a8ada09dee16d791fd406d629fe29bb0ed084a30:5]={ +// "Fields": [ +// { +// "N": "BAAAAAAAAAA=", +// "T": { +// "@type": "/gno.PrimitiveType", +// "value": "32" +// } +// } +// ], +// "ObjectInfo": { +// "ID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:5", +// "ModTime": "0", +// "OwnerID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:4", +// "RefCount": "1" +// } +// } +// c[a8ada09dee16d791fd406d629fe29bb0ed084a30:4]={ +// "ObjectInfo": { +// "ID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:4", +// "IsEscaped": true, +// "ModTime": "0", +// "RefCount": "2" +// }, +// "Value": { +// "T": { +// "@type": "/gno.RefType", +// "ID": "gno.land/r/test.S" +// }, +// "V": { +// "@type": "/gno.RefValue", +// "Hash": "8c001dde13b1f4dc01fc6d3a5bb4bc0cdfe2a50b", +// "ObjectID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:5" +// } +// } +// } +// u[a8ada09dee16d791fd406d629fe29bb0ed084a30:2]={ +// "Blank": {}, +// "ObjectInfo": { +// "ID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:2", +// "IsEscaped": true, +// "ModTime": "3", +// "RefCount": "2" +// }, +// "Parent": null, +// "Source": { +// "@type": "/gno.RefNode", +// "BlockNode": null, +// "Location": { +// "File": "", +// "Line": "0", +// "Nonce": "0", +// "PkgPath": "gno.land/r/test" +// } +// }, +// "Values": [ +// { +// "T": { +// "@type": "/gno.TypeType" +// }, +// "V": { +// "@type": "/gno.TypeValue", +// "Type": { +// "@type": "/gno.DeclaredType", +// "Base": { +// "@type": "/gno.StructType", +// "Fields": [ +// { +// "Embedded": false, +// "Name": "A", +// "Tag": "", +// "Type": { +// "@type": "/gno.PrimitiveType", +// "value": "32" +// } +// } +// ], +// "PkgPath": "gno.land/r/test" +// }, +// "Methods": [], +// "Name": "S", +// "PkgPath": "gno.land/r/test" +// } +// } +// }, +// { +// "T": { +// "@type": "/gno.FuncType", +// "Params": [], +// "Results": [] +// }, +// "V": { +// "@type": "/gno.FuncValue", +// "Closure": { +// "@type": "/gno.RefValue", +// "Escaped": true, +// "ObjectID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:3" +// }, +// "FileName": "main.gno", +// "IsMethod": false, +// "Name": "main", +// "NativeName": "", +// "NativePkg": "", +// "PkgPath": "gno.land/r/test", +// "Source": { +// "@type": "/gno.RefNode", +// "BlockNode": null, +// "Location": { +// "File": "main.gno", +// "Line": "10", +// "Nonce": "0", +// "PkgPath": "gno.land/r/test" +// } +// }, +// "Type": { +// "@type": "/gno.FuncType", +// "Params": [], +// "Results": [] +// } +// } +// }, +// { +// "T": { +// "@type": "/gno.PointerType", +// "Elt": { +// "@type": "/gno.RefType", +// "ID": "gno.land/r/test.S" +// } +// }, +// "V": { +// "@type": "/gno.PointerValue", +// "Base": { +// "@type": "/gno.RefValue", +// "Escaped": true, +// "ObjectID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:4" +// }, +// "Index": "0", +// "TV": null +// } +// }, +// { +// "T": { +// "@type": "/gno.PointerType", +// "Elt": { +// "@type": "/gno.RefType", +// "ID": "gno.land/r/test.S" +// } +// }, +// "V": { +// "@type": "/gno.PointerValue", +// "Base": { +// "@type": "/gno.RefValue", +// "Escaped": true, +// "ObjectID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:4" +// }, +// "Index": "0", +// "TV": null +// } +// } +// ] +// } diff --git a/gnovm/tests/files/heap_item_value_init.gno b/gnovm/tests/files/heap_item_value_init.gno new file mode 100644 index 00000000000..0d1db7bcb76 --- /dev/null +++ b/gnovm/tests/files/heap_item_value_init.gno @@ -0,0 +1,185 @@ +// PKGPATH: gno.land/r/test +package test + +type S struct { + A *int +} + +var a, b *S + +func init() { + a = new(S) + a.A = new(int) + *a.A = 4 +} + +func main() { + b = a +} + +// Realm: +// switchrealm["gno.land/r/test"] +// u[a8ada09dee16d791fd406d629fe29bb0ed084a30:2]={ +// "Blank": {}, +// "ObjectInfo": { +// "ID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:2", +// "IsEscaped": true, +// "ModTime": "6", +// "RefCount": "2" +// }, +// "Parent": null, +// "Source": { +// "@type": "/gno.RefNode", +// "BlockNode": null, +// "Location": { +// "File": "", +// "Line": "0", +// "Nonce": "0", +// "PkgPath": "gno.land/r/test" +// } +// }, +// "Values": [ +// { +// "T": { +// "@type": "/gno.TypeType" +// }, +// "V": { +// "@type": "/gno.TypeValue", +// "Type": { +// "@type": "/gno.DeclaredType", +// "Base": { +// "@type": "/gno.StructType", +// "Fields": [ +// { +// "Embedded": false, +// "Name": "A", +// "Tag": "", +// "Type": { +// "@type": "/gno.PointerType", +// "Elt": { +// "@type": "/gno.PrimitiveType", +// "value": "32" +// } +// } +// } +// ], +// "PkgPath": "gno.land/r/test" +// }, +// "Methods": [], +// "Name": "S", +// "PkgPath": "gno.land/r/test" +// } +// } +// }, +// { +// "T": { +// "@type": "/gno.FuncType", +// "Params": [], +// "Results": [] +// }, +// "V": { +// "@type": "/gno.FuncValue", +// "Closure": { +// "@type": "/gno.RefValue", +// "Escaped": true, +// "ObjectID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:3" +// }, +// "FileName": "main.gno", +// "IsMethod": false, +// "Name": "init.1", +// "NativeName": "", +// "NativePkg": "", +// "PkgPath": "gno.land/r/test", +// "Source": { +// "@type": "/gno.RefNode", +// "BlockNode": null, +// "Location": { +// "File": "main.gno", +// "Line": "10", +// "Nonce": "0", +// "PkgPath": "gno.land/r/test" +// } +// }, +// "Type": { +// "@type": "/gno.FuncType", +// "Params": [], +// "Results": [] +// } +// } +// }, +// { +// "T": { +// "@type": "/gno.FuncType", +// "Params": [], +// "Results": [] +// }, +// "V": { +// "@type": "/gno.FuncValue", +// "Closure": { +// "@type": "/gno.RefValue", +// "Escaped": true, +// "ObjectID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:3" +// }, +// "FileName": "main.gno", +// "IsMethod": false, +// "Name": "main", +// "NativeName": "", +// "NativePkg": "", +// "PkgPath": "gno.land/r/test", +// "Source": { +// "@type": "/gno.RefNode", +// "BlockNode": null, +// "Location": { +// "File": "main.gno", +// "Line": "16", +// "Nonce": "0", +// "PkgPath": "gno.land/r/test" +// } +// }, +// "Type": { +// "@type": "/gno.FuncType", +// "Params": [], +// "Results": [] +// } +// } +// }, +// { +// "T": { +// "@type": "/gno.PointerType", +// "Elt": { +// "@type": "/gno.RefType", +// "ID": "gno.land/r/test.S" +// } +// }, +// "V": { +// "@type": "/gno.PointerValue", +// "Base": { +// "@type": "/gno.RefValue", +// "Escaped": true, +// "ObjectID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:4" +// }, +// "Index": "0", +// "TV": null +// } +// }, +// { +// "T": { +// "@type": "/gno.PointerType", +// "Elt": { +// "@type": "/gno.RefType", +// "ID": "gno.land/r/test.S" +// } +// }, +// "V": { +// "@type": "/gno.PointerValue", +// "Base": { +// "@type": "/gno.RefValue", +// "Escaped": true, +// "ObjectID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:4" +// }, +// "Index": "0", +// "TV": null +// } +// } +// ] +// } diff --git a/gnovm/tests/files/issue_1326.gno b/gnovm/tests/files/issue_1326.gno new file mode 100644 index 00000000000..a86058a63e0 --- /dev/null +++ b/gnovm/tests/files/issue_1326.gno @@ -0,0 +1,64 @@ +// PKGPATH: gno.land/r/test +package test + +import ( + "strconv" +) + +func init() { + New() + println(Delta()) +} + +func main() { + println(Delta()) +} + +type Move struct { + N1, N2, N3 byte +} + +type S struct { + Moves []Move +} + +func (s S) clone() S { + mv := s.Moves + return S{Moves: mv} +} + +func (olds S) change() S { + s := olds.clone() + + counter++ + s.Moves = append([]Move{}, s.Moves...) + s.Moves = append(s.Moves, Move{counter, counter, counter}) + return s +} + +var ( + el *S + counter byte +) + +func New() { + el = new(S) +} + +func Delta() string { + n := el.change() + *el = n + return Values() +} + +func Values() string { + s := "" + for _, val := range el.Moves { + s += strconv.Itoa(int(val.N1)) + "," + strconv.Itoa(int(val.N2)) + "," + strconv.Itoa(int(val.N3)) + ";" + } + return s +} + +// Output: +// 1,1,1; +// 1,1,1;2,2,2; diff --git a/gnovm/tests/files/star_assign.gno b/gnovm/tests/files/star_assign.gno new file mode 100644 index 00000000000..e40fe2794ac --- /dev/null +++ b/gnovm/tests/files/star_assign.gno @@ -0,0 +1,54 @@ +// PKGPATH: gno.land/r/test +package test + +import ( + "gno.land/p/demo/ufmt" +) + +type A struct { + nums []int +} + +var ( + intPtr *int + strPtr *string + aPtr *A + concretePtr *int + concreteValue int +) + +func init() { + New() +} + +func main() { + Delta() + println(Values()) +} + +func New() { + intPtr = new(int) + strPtr = new(string) + aPtr = &A{} + concretePtr = &concreteValue +} + +func Delta() { + *intPtr++ + *strPtr += "hello" + *aPtr = A{nums: []int{8, 5, 8}} + *concretePtr = 100 +} + +func Values() string { + var results string + results += ufmt.Sprintf("%d, %s, %d, %d", *intPtr, *strPtr, *concretePtr, concreteValue) + for _, n := range aPtr.nums { + results += ufmt.Sprintf(", %d", n) + } + + return results +} + +// Output: +// 1, hello, 100, 100, 8, 5, 8 diff --git a/gnovm/tests/files/zrealm3.gno b/gnovm/tests/files/zrealm3.gno index da8a581375c..8e2b9827322 100644 --- a/gnovm/tests/files/zrealm3.gno +++ b/gnovm/tests/files/zrealm3.gno @@ -25,7 +25,7 @@ func main() { // Realm: // switchrealm["gno.land/r/test"] -// c[a8ada09dee16d791fd406d629fe29bb0ed084a30:5]={ +// c[a8ada09dee16d791fd406d629fe29bb0ed084a30:7]={ // "Fields": [ // { // "T": { @@ -57,10 +57,29 @@ func main() { // } // ], // "ObjectInfo": { -// "ID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:5", +// "ID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:7", +// "ModTime": "0", +// "OwnerID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:6", +// "RefCount": "1" +// } +// } +// c[a8ada09dee16d791fd406d629fe29bb0ed084a30:6]={ +// "ObjectInfo": { +// "ID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:6", // "ModTime": "0", // "OwnerID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:2", // "RefCount": "1" +// }, +// "Value": { +// "T": { +// "@type": "/gno.RefType", +// "ID": "gno.land/r/test.Node" +// }, +// "V": { +// "@type": "/gno.RefValue", +// "Hash": "567a18d9c7594ece7956ce54384b0858888bb834", +// "ObjectID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:7" +// } // } // } // u[a8ada09dee16d791fd406d629fe29bb0ed084a30:2]={ @@ -68,7 +87,7 @@ func main() { // "ObjectInfo": { // "ID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:2", // "IsEscaped": true, -// "ModTime": "4", +// "ModTime": "5", // "RefCount": "2" // }, // "Parent": null, @@ -238,21 +257,16 @@ func main() { // }, // "V": { // "@type": "/gno.PointerValue", -// "Base": null, +// "Base": { +// "@type": "/gno.RefValue", +// "Hash": "8197b7c5b4f2c7bf9c12b1c614f6b4dc6e7ce8dd", +// "ObjectID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:6" +// }, // "Index": "0", -// "TV": { -// "T": { -// "@type": "/gno.RefType", -// "ID": "gno.land/r/test.Node" -// }, -// "V": { -// "@type": "/gno.RefValue", -// "Hash": "b1d00c9606ffbb00b2aa3d475c5a390514f6dc14", -// "ObjectID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:5" -// } -// } +// "TV": null // } // } // ] // } // d[a8ada09dee16d791fd406d629fe29bb0ed084a30:4] +// d[a8ada09dee16d791fd406d629fe29bb0ed084a30:5] diff --git a/gnovm/tests/files/zrealm4.gno b/gnovm/tests/files/zrealm4.gno index 4f5254b6951..8a4bac1fe32 100644 --- a/gnovm/tests/files/zrealm4.gno +++ b/gnovm/tests/files/zrealm4.gno @@ -23,7 +23,7 @@ func main() { // Realm: // switchrealm["gno.land/r/test"] -// u[a8ada09dee16d791fd406d629fe29bb0ed084a30:4]={ +// u[a8ada09dee16d791fd406d629fe29bb0ed084a30:5]={ // "Fields": [ // { // "T": { @@ -72,9 +72,9 @@ func main() { // } // ], // "ObjectInfo": { -// "ID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:4", -// "ModTime": "4", -// "OwnerID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:2", +// "ID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:5", +// "ModTime": "5", +// "OwnerID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:4", // "RefCount": "1" // } // } @@ -83,7 +83,7 @@ func main() { // "ObjectInfo": { // "ID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:2", // "IsEscaped": true, -// "ModTime": "4", +// "ModTime": "5", // "RefCount": "2" // }, // "Parent": null, @@ -180,19 +180,13 @@ func main() { // }, // "V": { // "@type": "/gno.PointerValue", -// "Base": null, +// "Base": { +// "@type": "/gno.RefValue", +// "Hash": "7b9d58f40430bbbcbafd47eefb7a6dd342477f71", +// "ObjectID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:4" +// }, // "Index": "0", -// "TV": { -// "T": { -// "@type": "/gno.RefType", -// "ID": "github.com/gnolang/gno/_test/timtadh/data_structures/tree/avl.AvlNode" -// }, -// "V": { -// "@type": "/gno.RefValue", -// "Hash": "de0c4b2dd935220f7d37d10fc9feb1448bfb011d", -// "ObjectID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:4" -// } -// } +// "TV": null // } // } // ] diff --git a/gnovm/tests/files/zrealm5.gno b/gnovm/tests/files/zrealm5.gno index ebe107290e7..108483a435c 100644 --- a/gnovm/tests/files/zrealm5.gno +++ b/gnovm/tests/files/zrealm5.gno @@ -23,7 +23,7 @@ func main() { // Realm: // switchrealm["gno.land/r/test"] -// c[a8ada09dee16d791fd406d629fe29bb0ed084a30:5]={ +// c[a8ada09dee16d791fd406d629fe29bb0ed084a30:7]={ // "Fields": [ // { // "T": { @@ -72,13 +72,32 @@ func main() { // } // ], // "ObjectInfo": { -// "ID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:5", +// "ID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:7", // "ModTime": "0", -// "OwnerID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:4", +// "OwnerID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:6", +// "RefCount": "1" +// } +// } +// c[a8ada09dee16d791fd406d629fe29bb0ed084a30:6]={ +// "ObjectInfo": { +// "ID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:6", +// "ModTime": "0", +// "OwnerID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:5", // "RefCount": "1" +// }, +// "Value": { +// "T": { +// "@type": "/gno.RefType", +// "ID": "github.com/gnolang/gno/_test/timtadh/data_structures/tree/avl.AvlNode" +// }, +// "V": { +// "@type": "/gno.RefValue", +// "Hash": "8a86634afa28ef7d7a1f4272255637f16daae2cd", +// "ObjectID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:7" +// } // } // } -// u[a8ada09dee16d791fd406d629fe29bb0ed084a30:4]={ +// u[a8ada09dee16d791fd406d629fe29bb0ed084a30:5]={ // "Fields": [ // { // "T": { @@ -126,26 +145,20 @@ func main() { // }, // "V": { // "@type": "/gno.PointerValue", -// "Base": null, +// "Base": { +// "@type": "/gno.RefValue", +// "Hash": "7c63a8fd451cd7c470c1851f1ead037246422ded", +// "ObjectID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:6" +// }, // "Index": "0", -// "TV": { -// "T": { -// "@type": "/gno.RefType", -// "ID": "github.com/gnolang/gno/_test/timtadh/data_structures/tree/avl.AvlNode" -// }, -// "V": { -// "@type": "/gno.RefValue", -// "Hash": "1a4158d473290431f9d4f9c5a85a3b6697640f2a", -// "ObjectID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:5" -// } -// } +// "TV": null // } // } // ], // "ObjectInfo": { -// "ID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:4", -// "ModTime": "4", -// "OwnerID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:2", +// "ID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:5", +// "ModTime": "5", +// "OwnerID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:4", // "RefCount": "1" // } // } @@ -154,7 +167,7 @@ func main() { // "ObjectInfo": { // "ID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:2", // "IsEscaped": true, -// "ModTime": "4", +// "ModTime": "5", // "RefCount": "2" // }, // "Parent": null, @@ -251,19 +264,13 @@ func main() { // }, // "V": { // "@type": "/gno.PointerValue", -// "Base": null, +// "Base": { +// "@type": "/gno.RefValue", +// "Hash": "7b9d58f40430bbbcbafd47eefb7a6dd342477f71", +// "ObjectID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:4" +// }, // "Index": "0", -// "TV": { -// "T": { -// "@type": "/gno.RefType", -// "ID": "github.com/gnolang/gno/_test/timtadh/data_structures/tree/avl.AvlNode" -// }, -// "V": { -// "@type": "/gno.RefValue", -// "Hash": "011a2960ff92aedda8acd122b9f4d251902e0cd8", -// "ObjectID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:4" -// } -// } +// "TV": null // } // } // ] diff --git a/gnovm/tests/files/zrealm6.gno b/gnovm/tests/files/zrealm6.gno index 9884ab1909c..ff5e7e758a1 100644 --- a/gnovm/tests/files/zrealm6.gno +++ b/gnovm/tests/files/zrealm6.gno @@ -24,7 +24,7 @@ func main() { // Realm: // switchrealm["gno.land/r/test"] -// c[a8ada09dee16d791fd406d629fe29bb0ed084a30:6]={ +// c[a8ada09dee16d791fd406d629fe29bb0ed084a30:9]={ // "Fields": [ // { // "T": { @@ -73,13 +73,32 @@ func main() { // } // ], // "ObjectInfo": { -// "ID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:6", +// "ID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:9", // "ModTime": "0", -// "OwnerID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:5", +// "OwnerID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:8", // "RefCount": "1" // } // } -// u[a8ada09dee16d791fd406d629fe29bb0ed084a30:5]={ +// c[a8ada09dee16d791fd406d629fe29bb0ed084a30:8]={ +// "ObjectInfo": { +// "ID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:8", +// "ModTime": "0", +// "OwnerID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:7", +// "RefCount": "1" +// }, +// "Value": { +// "T": { +// "@type": "/gno.RefType", +// "ID": "github.com/gnolang/gno/_test/timtadh/data_structures/tree/avl.AvlNode" +// }, +// "V": { +// "@type": "/gno.RefValue", +// "Hash": "34a46349a2bc1b58591d0222a145b585452683be", +// "ObjectID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:9" +// } +// } +// } +// u[a8ada09dee16d791fd406d629fe29bb0ed084a30:7]={ // "Fields": [ // { // "T": { @@ -127,30 +146,24 @@ func main() { // }, // "V": { // "@type": "/gno.PointerValue", -// "Base": null, +// "Base": { +// "@type": "/gno.RefValue", +// "Hash": "81074f5da453299a913435a2ddd05248ee012f8c", +// "ObjectID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:8" +// }, // "Index": "0", -// "TV": { -// "T": { -// "@type": "/gno.RefType", -// "ID": "github.com/gnolang/gno/_test/timtadh/data_structures/tree/avl.AvlNode" -// }, -// "V": { -// "@type": "/gno.RefValue", -// "Hash": "b1719c55a9b07d432385f020b0bdbc678ba2b9ac", -// "ObjectID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:6" -// } -// } +// "TV": null // } // } // ], // "ObjectInfo": { -// "ID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:5", -// "ModTime": "5", -// "OwnerID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:4", +// "ID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:7", +// "ModTime": "7", +// "OwnerID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:6", // "RefCount": "1" // } // } -// u[a8ada09dee16d791fd406d629fe29bb0ed084a30:4]={ +// u[a8ada09dee16d791fd406d629fe29bb0ed084a30:5]={ // "Fields": [ // { // "T": { @@ -198,26 +211,20 @@ func main() { // }, // "V": { // "@type": "/gno.PointerValue", -// "Base": null, +// "Base": { +// "@type": "/gno.RefValue", +// "Hash": "7c63a8fd451cd7c470c1851f1ead037246422ded", +// "ObjectID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:6" +// }, // "Index": "0", -// "TV": { -// "T": { -// "@type": "/gno.RefType", -// "ID": "github.com/gnolang/gno/_test/timtadh/data_structures/tree/avl.AvlNode" -// }, -// "V": { -// "@type": "/gno.RefValue", -// "Hash": "8d00c3fa6c15cb0d78dcbaa23df49f96bbc9591b", -// "ObjectID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:5" -// } -// } +// "TV": null // } // } // ], // "ObjectInfo": { -// "ID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:4", -// "ModTime": "5", -// "OwnerID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:2", +// "ID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:5", +// "ModTime": "7", +// "OwnerID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:4", // "RefCount": "1" // } // } @@ -226,7 +233,7 @@ func main() { // "ObjectInfo": { // "ID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:2", // "IsEscaped": true, -// "ModTime": "5", +// "ModTime": "7", // "RefCount": "2" // }, // "Parent": null, @@ -323,19 +330,13 @@ func main() { // }, // "V": { // "@type": "/gno.PointerValue", -// "Base": null, +// "Base": { +// "@type": "/gno.RefValue", +// "Hash": "ade9fce2a987ef1924040a1d75c0172410c66952", +// "ObjectID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:4" +// }, // "Index": "0", -// "TV": { -// "T": { -// "@type": "/gno.RefType", -// "ID": "github.com/gnolang/gno/_test/timtadh/data_structures/tree/avl.AvlNode" -// }, -// "V": { -// "@type": "/gno.RefValue", -// "Hash": "8f2cb2a771ddc55ab5798b791e16df547c94d862", -// "ObjectID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:4" -// } -// } +// "TV": null // } // } // ] diff --git a/gnovm/tests/files/zrealm7.gno b/gnovm/tests/files/zrealm7.gno index a706ffcad78..e6fd99503be 100644 --- a/gnovm/tests/files/zrealm7.gno +++ b/gnovm/tests/files/zrealm7.gno @@ -25,7 +25,7 @@ func main() { // Realm: // switchrealm["gno.land/r/test"] -// c[a8ada09dee16d791fd406d629fe29bb0ed084a30:7]={ +// c[a8ada09dee16d791fd406d629fe29bb0ed084a30:11]={ // "Fields": [ // { // "T": { @@ -74,13 +74,32 @@ func main() { // } // ], // "ObjectInfo": { -// "ID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:7", +// "ID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:11", // "ModTime": "0", -// "OwnerID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:6", +// "OwnerID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:10", // "RefCount": "1" // } // } -// u[a8ada09dee16d791fd406d629fe29bb0ed084a30:6]={ +// c[a8ada09dee16d791fd406d629fe29bb0ed084a30:10]={ +// "ObjectInfo": { +// "ID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:10", +// "ModTime": "0", +// "OwnerID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:9", +// "RefCount": "1" +// }, +// "Value": { +// "T": { +// "@type": "/gno.RefType", +// "ID": "github.com/gnolang/gno/_test/timtadh/data_structures/tree/avl.AvlNode" +// }, +// "V": { +// "@type": "/gno.RefValue", +// "Hash": "42cd813e173ad23c7873e9605901e8bea1176c96", +// "ObjectID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:11" +// } +// } +// } +// u[a8ada09dee16d791fd406d629fe29bb0ed084a30:9]={ // "Fields": [ // { // "T": { @@ -128,30 +147,43 @@ func main() { // }, // "V": { // "@type": "/gno.PointerValue", -// "Base": null, +// "Base": { +// "@type": "/gno.RefValue", +// "Hash": "4f88fcdc73a4a94905e8e4044aa50c2ec7bf2227", +// "ObjectID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:10" +// }, // "Index": "0", -// "TV": { -// "T": { -// "@type": "/gno.RefType", -// "ID": "github.com/gnolang/gno/_test/timtadh/data_structures/tree/avl.AvlNode" -// }, -// "V": { -// "@type": "/gno.RefValue", -// "Hash": "2ac7cc7e6fdb1ff6dc1f340486011f1449757d85", -// "ObjectID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:7" -// } -// } +// "TV": null // } // } // ], // "ObjectInfo": { -// "ID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:6", -// "ModTime": "6", -// "OwnerID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:5", +// "ID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:9", +// "ModTime": "9", +// "OwnerID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:8", +// "RefCount": "1" +// } +// } +// u[a8ada09dee16d791fd406d629fe29bb0ed084a30:8]={ +// "ObjectInfo": { +// "ID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:8", +// "ModTime": "9", +// "OwnerID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:7", // "RefCount": "1" +// }, +// "Value": { +// "T": { +// "@type": "/gno.RefType", +// "ID": "github.com/gnolang/gno/_test/timtadh/data_structures/tree/avl.AvlNode" +// }, +// "V": { +// "@type": "/gno.RefValue", +// "Hash": "2c172bbe0183ccc73c59d9acb196c45b0331c39e", +// "ObjectID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:9" +// } // } // } -// u[a8ada09dee16d791fd406d629fe29bb0ed084a30:4]={ +// u[a8ada09dee16d791fd406d629fe29bb0ed084a30:7]={ // "Fields": [ // { // "T": { @@ -160,7 +192,7 @@ func main() { // }, // "V": { // "@type": "/gno.StringValue", -// "value": "key0" +// "value": "key1" // } // }, // { @@ -170,11 +202,11 @@ func main() { // }, // "V": { // "@type": "/gno.StringValue", -// "value": "value0" +// "value": "value1" // } // }, // { -// "N": "AQAAAAAAAAA=", +// "N": "AwAAAAAAAAA=", // "T": { // "@type": "/gno.PrimitiveType", // "value": "32" @@ -187,6 +219,16 @@ func main() { // "@type": "/gno.RefType", // "ID": "github.com/gnolang/gno/_test/timtadh/data_structures/tree/avl.AvlNode" // } +// }, +// "V": { +// "@type": "/gno.PointerValue", +// "Base": { +// "@type": "/gno.RefValue", +// "Hash": "a4fa9bdf45caf8c6b5be7a3752704423817b3ef2", +// "ObjectID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:4" +// }, +// "Index": "0", +// "TV": null // } // }, // { @@ -196,13 +238,23 @@ func main() { // "@type": "/gno.RefType", // "ID": "github.com/gnolang/gno/_test/timtadh/data_structures/tree/avl.AvlNode" // } +// }, +// "V": { +// "@type": "/gno.PointerValue", +// "Base": { +// "@type": "/gno.RefValue", +// "Hash": "43f69f24b7827a331921b4af0f667346d186e0c3", +// "ObjectID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:8" +// }, +// "Index": "0", +// "TV": null // } // } // ], // "ObjectInfo": { -// "ID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:4", -// "ModTime": "6", -// "OwnerID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:2", +// "ID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:7", +// "ModTime": "9", +// "OwnerID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:6", // "RefCount": "1" // } // } @@ -215,7 +267,7 @@ func main() { // }, // "V": { // "@type": "/gno.StringValue", -// "value": "key1" +// "value": "key0" // } // }, // { @@ -225,11 +277,11 @@ func main() { // }, // "V": { // "@type": "/gno.StringValue", -// "value": "value1" +// "value": "value0" // } // }, // { -// "N": "AwAAAAAAAAA=", +// "N": "AQAAAAAAAAA=", // "T": { // "@type": "/gno.PrimitiveType", // "value": "32" @@ -242,22 +294,6 @@ func main() { // "@type": "/gno.RefType", // "ID": "github.com/gnolang/gno/_test/timtadh/data_structures/tree/avl.AvlNode" // } -// }, -// "V": { -// "@type": "/gno.PointerValue", -// "Base": null, -// "Index": "0", -// "TV": { -// "T": { -// "@type": "/gno.RefType", -// "ID": "github.com/gnolang/gno/_test/timtadh/data_structures/tree/avl.AvlNode" -// }, -// "V": { -// "@type": "/gno.RefValue", -// "Hash": "a0af92becf7bef8d5d71c94e8f8f044e4cfe526d", -// "ObjectID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:4" -// } -// } // } // }, // { @@ -267,38 +303,41 @@ func main() { // "@type": "/gno.RefType", // "ID": "github.com/gnolang/gno/_test/timtadh/data_structures/tree/avl.AvlNode" // } -// }, -// "V": { -// "@type": "/gno.PointerValue", -// "Base": null, -// "Index": "0", -// "TV": { -// "T": { -// "@type": "/gno.RefType", -// "ID": "github.com/gnolang/gno/_test/timtadh/data_structures/tree/avl.AvlNode" -// }, -// "V": { -// "@type": "/gno.RefValue", -// "Hash": "752161efcfe5a3e2ef70c03ff4354097f09ada56", -// "ObjectID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:6" -// } -// } // } // } // ], // "ObjectInfo": { // "ID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:5", -// "ModTime": "6", +// "ModTime": "9", // "OwnerID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:4", // "RefCount": "1" // } // } +// u[a8ada09dee16d791fd406d629fe29bb0ed084a30:6]={ +// "ObjectInfo": { +// "ID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:6", +// "ModTime": "9", +// "OwnerID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:5", +// "RefCount": "1" +// }, +// "Value": { +// "T": { +// "@type": "/gno.RefType", +// "ID": "github.com/gnolang/gno/_test/timtadh/data_structures/tree/avl.AvlNode" +// }, +// "V": { +// "@type": "/gno.RefValue", +// "Hash": "f56fbd9c8db299689cc0cf806fe741b6a6e641e6", +// "ObjectID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:7" +// } +// } +// } // u[a8ada09dee16d791fd406d629fe29bb0ed084a30:2]={ // "Blank": {}, // "ObjectInfo": { // "ID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:2", // "IsEscaped": true, -// "ModTime": "6", +// "ModTime": "9", // "RefCount": "2" // }, // "Parent": null, @@ -395,19 +434,13 @@ func main() { // }, // "V": { // "@type": "/gno.PointerValue", -// "Base": null, +// "Base": { +// "@type": "/gno.RefValue", +// "Hash": "450aef9858564ed4ec1c418f1e8dac828079016b", +// "ObjectID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:6" +// }, // "Index": "0", -// "TV": { -// "T": { -// "@type": "/gno.RefType", -// "ID": "github.com/gnolang/gno/_test/timtadh/data_structures/tree/avl.AvlNode" -// }, -// "V": { -// "@type": "/gno.RefValue", -// "Hash": "c59d05a21bf190551bb15a8b9d41a9e8da717f3d", -// "ObjectID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:5" -// } -// } +// "TV": null // } // } // ] diff --git a/gnovm/tests/files/zrealm_avl0.gno b/gnovm/tests/files/zrealm_avl0.gno index e91788ac8eb..e3f1363e205 100644 --- a/gnovm/tests/files/zrealm_avl0.gno +++ b/gnovm/tests/files/zrealm_avl0.gno @@ -25,67 +25,25 @@ func main() { // Realm: // switchrealm["gno.land/r/test"] // u[a8ada09dee16d791fd406d629fe29bb0ed084a30:4]={ -// "Fields": [ -// { -// "T": { -// "@type": "/gno.PrimitiveType", -// "value": "16" -// }, -// "V": { -// "@type": "/gno.StringValue", -// "value": "key0" -// } -// }, -// { -// "T": { -// "@type": "/gno.PrimitiveType", -// "value": "16" -// }, -// "V": { -// "@type": "/gno.StringValue", -// "value": "value0" -// } -// }, -// { -// "T": { -// "@type": "/gno.PrimitiveType", -// "value": "64" -// } -// }, -// { -// "N": "AQAAAAAAAAA=", -// "T": { -// "@type": "/gno.PrimitiveType", -// "value": "32" -// } -// }, -// { -// "T": { -// "@type": "/gno.PointerType", -// "Elt": { -// "@type": "/gno.RefType", -// "ID": "gno.land/p/demo/avl.Node" -// } -// } -// }, -// { -// "T": { -// "@type": "/gno.PointerType", -// "Elt": { -// "@type": "/gno.RefType", -// "ID": "gno.land/p/demo/avl.Node" -// } -// } -// } -// ], // "ObjectInfo": { // "ID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:4", -// "ModTime": "5", -// "OwnerID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:5", +// "ModTime": "7", +// "OwnerID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:7", // "RefCount": "1" +// }, +// "Value": { +// "T": { +// "@type": "/gno.RefType", +// "ID": "gno.land/p/demo/avl.Node" +// }, +// "V": { +// "@type": "/gno.RefValue", +// "Hash": "627e8e517e7ae5db0f3b753e2a32b607989198b6", +// "ObjectID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:5" +// } // } // } -// c[a8ada09dee16d791fd406d629fe29bb0ed084a30:6]={ +// c[a8ada09dee16d791fd406d629fe29bb0ed084a30:9]={ // "Fields": [ // { // "T": { @@ -140,13 +98,32 @@ func main() { // } // ], // "ObjectInfo": { -// "ID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:6", +// "ID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:9", // "ModTime": "0", -// "OwnerID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:5", +// "OwnerID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:8", // "RefCount": "1" // } // } -// c[a8ada09dee16d791fd406d629fe29bb0ed084a30:5]={ +// c[a8ada09dee16d791fd406d629fe29bb0ed084a30:8]={ +// "ObjectInfo": { +// "ID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:8", +// "ModTime": "0", +// "OwnerID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:7", +// "RefCount": "1" +// }, +// "Value": { +// "T": { +// "@type": "/gno.RefType", +// "ID": "gno.land/p/demo/avl.Node" +// }, +// "V": { +// "@type": "/gno.RefValue", +// "Hash": "b28057ab7be6383785c0a5503e8a531bdbc21851", +// "ObjectID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:9" +// } +// } +// } +// c[a8ada09dee16d791fd406d629fe29bb0ed084a30:7]={ // "Fields": [ // { // "T": { @@ -183,19 +160,13 @@ func main() { // }, // "V": { // "@type": "/gno.PointerValue", -// "Base": null, +// "Base": { +// "@type": "/gno.RefValue", +// "Hash": "6da365f0d6cacbcdf53cd5a4b125803cddce08c2", +// "ObjectID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:4" +// }, // "Index": "0", -// "TV": { -// "T": { -// "@type": "/gno.RefType", -// "ID": "gno.land/p/demo/avl.Node" -// }, -// "V": { -// "@type": "/gno.RefValue", -// "Hash": "091729e38bda8724bce4c314f9624b91af679459", -// "ObjectID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:4" -// } -// } +// "TV": null // } // }, // { @@ -208,27 +179,40 @@ func main() { // }, // "V": { // "@type": "/gno.PointerValue", -// "Base": null, +// "Base": { +// "@type": "/gno.RefValue", +// "Hash": "f216afe7b5a17f4ebdbb98dceccedbc22e237596", +// "ObjectID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:8" +// }, // "Index": "0", -// "TV": { -// "T": { -// "@type": "/gno.RefType", -// "ID": "gno.land/p/demo/avl.Node" -// }, -// "V": { -// "@type": "/gno.RefValue", -// "Hash": "0b5493aa4ea42087780bdfcaebab2c3eec351c15", -// "ObjectID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:6" -// } -// } +// "TV": null // } // } // ], // "ObjectInfo": { -// "ID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:5", +// "ID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:7", +// "ModTime": "0", +// "OwnerID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:6", +// "RefCount": "1" +// } +// } +// c[a8ada09dee16d791fd406d629fe29bb0ed084a30:6]={ +// "ObjectInfo": { +// "ID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:6", // "ModTime": "0", // "OwnerID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:2", // "RefCount": "1" +// }, +// "Value": { +// "T": { +// "@type": "/gno.RefType", +// "ID": "gno.land/p/demo/avl.Node" +// }, +// "V": { +// "@type": "/gno.RefValue", +// "Hash": "ff1a50d8489090af37a2c7766d659f0d717939b5", +// "ObjectID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:7" +// } // } // } // u[a8ada09dee16d791fd406d629fe29bb0ed084a30:2]={ @@ -236,7 +220,7 @@ func main() { // "ObjectInfo": { // "ID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:2", // "IsEscaped": true, -// "ModTime": "4", +// "ModTime": "5", // "RefCount": "2" // }, // "Parent": null, @@ -333,19 +317,13 @@ func main() { // }, // "V": { // "@type": "/gno.PointerValue", -// "Base": null, +// "Base": { +// "@type": "/gno.RefValue", +// "Hash": "ae86874f9b47fa5e64c30b3e92e9d07f2ec967a4", +// "ObjectID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:6" +// }, // "Index": "0", -// "TV": { -// "T": { -// "@type": "/gno.RefType", -// "ID": "gno.land/p/demo/avl.Node" -// }, -// "V": { -// "@type": "/gno.RefValue", -// "Hash": "6c9948281d4c60b2d95233b76388d54d8b1a2fad", -// "ObjectID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:5" -// } -// } +// "TV": null // } // } // ] diff --git a/gnovm/tests/files/zrealm_avl1.gno b/gnovm/tests/files/zrealm_avl1.gno index cdd56a5ad89..a6d2205e240 100644 --- a/gnovm/tests/files/zrealm_avl1.gno +++ b/gnovm/tests/files/zrealm_avl1.gno @@ -24,7 +24,7 @@ func main() { // Realm: // switchrealm["gno.land/r/test"] -// c[a8ada09dee16d791fd406d629fe29bb0ed084a30:9]={ +// c[a8ada09dee16d791fd406d629fe29bb0ed084a30:15]={ // "Fields": [ // { // "T": { @@ -79,13 +79,32 @@ func main() { // } // ], // "ObjectInfo": { -// "ID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:9", +// "ID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:15", // "ModTime": "0", -// "OwnerID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:8", +// "OwnerID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:14", // "RefCount": "1" // } // } -// c[a8ada09dee16d791fd406d629fe29bb0ed084a30:8]={ +// c[a8ada09dee16d791fd406d629fe29bb0ed084a30:14]={ +// "ObjectInfo": { +// "ID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:14", +// "ModTime": "0", +// "OwnerID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:13", +// "RefCount": "1" +// }, +// "Value": { +// "T": { +// "@type": "/gno.RefType", +// "ID": "gno.land/p/demo/avl.Node" +// }, +// "V": { +// "@type": "/gno.RefValue", +// "Hash": "143aebc820da33550f7338723fb1e2eec575b196", +// "ObjectID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:15" +// } +// } +// } +// c[a8ada09dee16d791fd406d629fe29bb0ed084a30:13]={ // "Fields": [ // { // "T": { @@ -122,19 +141,13 @@ func main() { // }, // "V": { // "@type": "/gno.PointerValue", -// "Base": null, +// "Base": { +// "@type": "/gno.RefValue", +// "Hash": "2f3adc5d0f2a3fe0331cfa93572a7abdde14c9aa", +// "ObjectID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:8" +// }, // "Index": "0", -// "TV": { -// "T": { -// "@type": "/gno.RefType", -// "ID": "gno.land/p/demo/avl.Node" -// }, -// "V": { -// "@type": "/gno.RefValue", -// "Hash": "7a8a63e17a567d7b0891ac89d5cd90072a73787d", -// "ObjectID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:6" -// } -// } +// "TV": null // } // }, // { @@ -147,30 +160,43 @@ func main() { // }, // "V": { // "@type": "/gno.PointerValue", -// "Base": null, +// "Base": { +// "@type": "/gno.RefValue", +// "Hash": "2e733a8e9e74fe14f0a5d10fb0f6728fa53d052d", +// "ObjectID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:14" +// }, // "Index": "0", -// "TV": { -// "T": { -// "@type": "/gno.RefType", -// "ID": "gno.land/p/demo/avl.Node" -// }, -// "V": { -// "@type": "/gno.RefValue", -// "Hash": "ab5a297f4eb033d88bdf1677f4dc151ccb9fde9f", -// "ObjectID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:9" -// } -// } +// "TV": null // } // } // ], // "ObjectInfo": { -// "ID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:8", +// "ID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:13", // "ModTime": "0", -// "OwnerID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:7", +// "OwnerID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:12", // "RefCount": "1" // } // } -// c[a8ada09dee16d791fd406d629fe29bb0ed084a30:7]={ +// c[a8ada09dee16d791fd406d629fe29bb0ed084a30:12]={ +// "ObjectInfo": { +// "ID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:12", +// "ModTime": "0", +// "OwnerID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:11", +// "RefCount": "1" +// }, +// "Value": { +// "T": { +// "@type": "/gno.RefType", +// "ID": "gno.land/p/demo/avl.Node" +// }, +// "V": { +// "@type": "/gno.RefValue", +// "Hash": "fe20a19f956511f274dc77854e9e5468387260f4", +// "ObjectID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:13" +// } +// } +// } +// c[a8ada09dee16d791fd406d629fe29bb0ed084a30:11]={ // "Fields": [ // { // "T": { @@ -207,19 +233,13 @@ func main() { // }, // "V": { // "@type": "/gno.PointerValue", -// "Base": null, +// "Base": { +// "@type": "/gno.RefValue", +// "Hash": "c89a71bdf045e8bde2059dc9d33839f916e02e5d", +// "ObjectID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:6" +// }, // "Index": "0", -// "TV": { -// "T": { -// "@type": "/gno.RefType", -// "ID": "gno.land/p/demo/avl.Node" -// }, -// "V": { -// "@type": "/gno.RefValue", -// "Hash": "627e8e517e7ae5db0f3b753e2a32b607989198b6", -// "ObjectID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:5" -// } -// } +// "TV": null // } // }, // { @@ -232,27 +252,40 @@ func main() { // }, // "V": { // "@type": "/gno.PointerValue", -// "Base": null, +// "Base": { +// "@type": "/gno.RefValue", +// "Hash": "90fa67f8c47db4b9b2a60425dff08d5a3385100f", +// "ObjectID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:12" +// }, // "Index": "0", -// "TV": { -// "T": { -// "@type": "/gno.RefType", -// "ID": "gno.land/p/demo/avl.Node" -// }, -// "V": { -// "@type": "/gno.RefValue", -// "Hash": "fe8afd501233fb95375016199f0443b3c6ab1fbc", -// "ObjectID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:8" -// } -// } +// "TV": null // } // } // ], // "ObjectInfo": { -// "ID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:7", +// "ID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:11", +// "ModTime": "0", +// "OwnerID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:10", +// "RefCount": "1" +// } +// } +// c[a8ada09dee16d791fd406d629fe29bb0ed084a30:10]={ +// "ObjectInfo": { +// "ID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:10", // "ModTime": "0", // "OwnerID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:2", // "RefCount": "1" +// }, +// "Value": { +// "T": { +// "@type": "/gno.RefType", +// "ID": "gno.land/p/demo/avl.Node" +// }, +// "V": { +// "@type": "/gno.RefValue", +// "Hash": "83e42caaf53070dd95b5f859053eb51ed900bbda", +// "ObjectID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:11" +// } // } // } // u[a8ada09dee16d791fd406d629fe29bb0ed084a30:2]={ @@ -260,7 +293,7 @@ func main() { // "ObjectInfo": { // "ID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:2", // "IsEscaped": true, -// "ModTime": "6", +// "ModTime": "9", // "RefCount": "2" // }, // "Parent": null, @@ -357,21 +390,16 @@ func main() { // }, // "V": { // "@type": "/gno.PointerValue", -// "Base": null, +// "Base": { +// "@type": "/gno.RefValue", +// "Hash": "1faa9fa4ba1935121a6d3f0a623772e9d4499b0a", +// "ObjectID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:10" +// }, // "Index": "0", -// "TV": { -// "T": { -// "@type": "/gno.RefType", -// "ID": "gno.land/p/demo/avl.Node" -// }, -// "V": { -// "@type": "/gno.RefValue", -// "Hash": "c5eefc40ed065461b4a920c1349ed734ffdead8f", -// "ObjectID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:7" -// } -// } +// "TV": null // } // } // ] // } // d[a8ada09dee16d791fd406d629fe29bb0ed084a30:4] +// d[a8ada09dee16d791fd406d629fe29bb0ed084a30:5] diff --git a/gnovm/tests/files/zrealm_avl2.gno b/gnovm/tests/files/zrealm_avl2.gno index 8ecf6ba52bc..a89f0540f47 100644 --- a/gnovm/tests/files/zrealm_avl2.gno +++ b/gnovm/tests/files/zrealm_avl2.gno @@ -24,67 +24,25 @@ func main() { // Realm: // switchrealm["gno.land/r/test"] // u[a8ada09dee16d791fd406d629fe29bb0ed084a30:5]={ -// "Fields": [ -// { -// "T": { -// "@type": "/gno.PrimitiveType", -// "value": "16" -// }, -// "V": { -// "@type": "/gno.StringValue", -// "value": "key1" -// } -// }, -// { -// "T": { -// "@type": "/gno.PrimitiveType", -// "value": "16" -// }, -// "V": { -// "@type": "/gno.StringValue", -// "value": "value1" -// } -// }, -// { -// "T": { -// "@type": "/gno.PrimitiveType", -// "value": "64" -// } -// }, -// { -// "N": "AQAAAAAAAAA=", -// "T": { -// "@type": "/gno.PrimitiveType", -// "value": "32" -// } -// }, -// { -// "T": { -// "@type": "/gno.PointerType", -// "Elt": { -// "@type": "/gno.RefType", -// "ID": "gno.land/p/demo/avl.Node" -// } -// } -// }, -// { -// "T": { -// "@type": "/gno.PointerType", -// "Elt": { -// "@type": "/gno.RefType", -// "ID": "gno.land/p/demo/avl.Node" -// } -// } -// } -// ], // "ObjectInfo": { // "ID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:5", -// "ModTime": "6", -// "OwnerID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:6", +// "ModTime": "8", +// "OwnerID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:8", // "RefCount": "1" +// }, +// "Value": { +// "T": { +// "@type": "/gno.RefType", +// "ID": "gno.land/p/demo/avl.Node" +// }, +// "V": { +// "@type": "/gno.RefValue", +// "Hash": "0b5493aa4ea42087780bdfcaebab2c3eec351c15", +// "ObjectID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:6" +// } // } // } -// c[a8ada09dee16d791fd406d629fe29bb0ed084a30:7]={ +// c[a8ada09dee16d791fd406d629fe29bb0ed084a30:10]={ // "Fields": [ // { // "T": { @@ -139,13 +97,32 @@ func main() { // } // ], // "ObjectInfo": { -// "ID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:7", +// "ID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:10", +// "ModTime": "0", +// "OwnerID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:9", +// "RefCount": "1" +// } +// } +// c[a8ada09dee16d791fd406d629fe29bb0ed084a30:9]={ +// "ObjectInfo": { +// "ID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:9", // "ModTime": "0", -// "OwnerID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:6", +// "OwnerID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:8", // "RefCount": "1" +// }, +// "Value": { +// "T": { +// "@type": "/gno.RefType", +// "ID": "gno.land/p/demo/avl.Node" +// }, +// "V": { +// "@type": "/gno.RefValue", +// "Hash": "be751422ef4c2bc068a456f9467d2daca27db8ca", +// "ObjectID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:10" +// } // } // } -// c[a8ada09dee16d791fd406d629fe29bb0ed084a30:6]={ +// c[a8ada09dee16d791fd406d629fe29bb0ed084a30:8]={ // "Fields": [ // { // "T": { @@ -182,19 +159,13 @@ func main() { // }, // "V": { // "@type": "/gno.PointerValue", -// "Base": null, +// "Base": { +// "@type": "/gno.RefValue", +// "Hash": "9fa04d8791e205a6de2eedce81bb4dbd0883cac7", +// "ObjectID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:5" +// }, // "Index": "0", -// "TV": { -// "T": { -// "@type": "/gno.RefType", -// "ID": "gno.land/p/demo/avl.Node" -// }, -// "V": { -// "@type": "/gno.RefValue", -// "Hash": "23c8d928ce614d559719cb47e71a75a456b49a2a", -// "ObjectID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:5" -// } -// } +// "TV": null // } // }, // { @@ -207,27 +178,40 @@ func main() { // }, // "V": { // "@type": "/gno.PointerValue", -// "Base": null, +// "Base": { +// "@type": "/gno.RefValue", +// "Hash": "a55a6a6b2027d6ec5e322aa32d4269b974fe1a4f", +// "ObjectID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:9" +// }, // "Index": "0", -// "TV": { -// "T": { -// "@type": "/gno.RefType", -// "ID": "gno.land/p/demo/avl.Node" -// }, -// "V": { -// "@type": "/gno.RefValue", -// "Hash": "fc92b122743503329a416d02fb4fe84cbca6dc57", -// "ObjectID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:7" -// } -// } +// "TV": null // } // } // ], // "ObjectInfo": { -// "ID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:6", +// "ID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:8", +// "ModTime": "0", +// "OwnerID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:7", +// "RefCount": "1" +// } +// } +// c[a8ada09dee16d791fd406d629fe29bb0ed084a30:7]={ +// "ObjectInfo": { +// "ID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:7", // "ModTime": "0", // "OwnerID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:4", // "RefCount": "1" +// }, +// "Value": { +// "T": { +// "@type": "/gno.RefType", +// "ID": "gno.land/p/demo/avl.Node" +// }, +// "V": { +// "@type": "/gno.RefValue", +// "Hash": "03d901636a4e56d5bd32a75a7b923c7700c8859a", +// "ObjectID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:8" +// } // } // } // u[a8ada09dee16d791fd406d629fe29bb0ed084a30:4]={ @@ -242,25 +226,19 @@ func main() { // }, // "V": { // "@type": "/gno.PointerValue", -// "Base": null, +// "Base": { +// "@type": "/gno.RefValue", +// "Hash": "2c8281b6c5a347a3d3aeedb74e61f081060ac050", +// "ObjectID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:7" +// }, // "Index": "0", -// "TV": { -// "T": { -// "@type": "/gno.RefType", -// "ID": "gno.land/p/demo/avl.Node" -// }, -// "V": { -// "@type": "/gno.RefValue", -// "Hash": "e6d40c7e6f2c94668ab964b4c356d7cbd537a2b5", -// "ObjectID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:6" -// } -// } +// "TV": null // } // } // ], // "ObjectInfo": { // "ID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:4", -// "ModTime": "5", +// "ModTime": "6", // "OwnerID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:2", // "RefCount": "1" // } diff --git a/gnovm/tests/files/zrealm_example.gno b/gnovm/tests/files/zrealm_example.gno index 1ce70c04390..45aeb7c5ddb 100644 --- a/gnovm/tests/files/zrealm_example.gno +++ b/gnovm/tests/files/zrealm_example.gno @@ -24,7 +24,7 @@ func main() { // Realm: // switchrealm["gno.land/r/example"] -// c[1ffd45e074aa1b8df562907c95ad97526b7ca187:8]={ +// c[1ffd45e074aa1b8df562907c95ad97526b7ca187:11]={ // "Fields": [ // { // "T": { @@ -37,13 +37,13 @@ func main() { // } // ], // "ObjectInfo": { -// "ID": "1ffd45e074aa1b8df562907c95ad97526b7ca187:8", +// "ID": "1ffd45e074aa1b8df562907c95ad97526b7ca187:11", // "ModTime": "0", -// "OwnerID": "1ffd45e074aa1b8df562907c95ad97526b7ca187:7", +// "OwnerID": "1ffd45e074aa1b8df562907c95ad97526b7ca187:10", // "RefCount": "1" // } // } -// c[1ffd45e074aa1b8df562907c95ad97526b7ca187:7]={ +// c[1ffd45e074aa1b8df562907c95ad97526b7ca187:10]={ // "Fields": [ // { // "T": { @@ -72,19 +72,38 @@ func main() { // }, // "V": { // "@type": "/gno.RefValue", -// "Hash": "c3dc30d2f2a57a0eeb4336dae59355aa7bee0ff5", -// "ObjectID": "1ffd45e074aa1b8df562907c95ad97526b7ca187:8" +// "Hash": "f190df54e397e2006cee3fc525bcc1b4d556e4c4", +// "ObjectID": "1ffd45e074aa1b8df562907c95ad97526b7ca187:11" // } // } // ], // "ObjectInfo": { -// "ID": "1ffd45e074aa1b8df562907c95ad97526b7ca187:7", +// "ID": "1ffd45e074aa1b8df562907c95ad97526b7ca187:10", // "ModTime": "0", -// "OwnerID": "1ffd45e074aa1b8df562907c95ad97526b7ca187:6", +// "OwnerID": "1ffd45e074aa1b8df562907c95ad97526b7ca187:9", // "RefCount": "1" // } // } -// c[1ffd45e074aa1b8df562907c95ad97526b7ca187:6]={ +// c[1ffd45e074aa1b8df562907c95ad97526b7ca187:9]={ +// "ObjectInfo": { +// "ID": "1ffd45e074aa1b8df562907c95ad97526b7ca187:9", +// "ModTime": "0", +// "OwnerID": "1ffd45e074aa1b8df562907c95ad97526b7ca187:8", +// "RefCount": "1" +// }, +// "Value": { +// "T": { +// "@type": "/gno.RefType", +// "ID": "gno.land/p/demo/dom.Post" +// }, +// "V": { +// "@type": "/gno.RefValue", +// "Hash": "a74fad6da10f1cec74ad3a8751490b4dca957761", +// "ObjectID": "1ffd45e074aa1b8df562907c95ad97526b7ca187:10" +// } +// } +// } +// c[1ffd45e074aa1b8df562907c95ad97526b7ca187:8]={ // "Fields": [ // { // "T": { @@ -106,19 +125,13 @@ func main() { // }, // "V": { // "@type": "/gno.PointerValue", -// "Base": null, +// "Base": { +// "@type": "/gno.RefValue", +// "Hash": "8b11b3d07ddeb034f70a114c9433ec6bd5cbf899", +// "ObjectID": "1ffd45e074aa1b8df562907c95ad97526b7ca187:9" +// }, // "Index": "0", -// "TV": { -// "T": { -// "@type": "/gno.RefType", -// "ID": "gno.land/p/demo/dom.Post" -// }, -// "V": { -// "@type": "/gno.RefValue", -// "Hash": "f5d48c5a050326190d971fabb76835de31f83b20", -// "ObjectID": "1ffd45e074aa1b8df562907c95ad97526b7ca187:7" -// } -// } +// "TV": null // } // }, // { @@ -154,13 +167,32 @@ func main() { // } // ], // "ObjectInfo": { -// "ID": "1ffd45e074aa1b8df562907c95ad97526b7ca187:6", +// "ID": "1ffd45e074aa1b8df562907c95ad97526b7ca187:8", // "ModTime": "0", -// "OwnerID": "1ffd45e074aa1b8df562907c95ad97526b7ca187:5", +// "OwnerID": "1ffd45e074aa1b8df562907c95ad97526b7ca187:7", // "RefCount": "1" // } // } -// u[1ffd45e074aa1b8df562907c95ad97526b7ca187:5]={ +// c[1ffd45e074aa1b8df562907c95ad97526b7ca187:7]={ +// "ObjectInfo": { +// "ID": "1ffd45e074aa1b8df562907c95ad97526b7ca187:7", +// "ModTime": "0", +// "OwnerID": "1ffd45e074aa1b8df562907c95ad97526b7ca187:6", +// "RefCount": "1" +// }, +// "Value": { +// "T": { +// "@type": "/gno.RefType", +// "ID": "gno.land/p/demo/avl.Node" +// }, +// "V": { +// "@type": "/gno.RefValue", +// "Hash": "869abdac30a3ae78b2191806e1c894c48e399122", +// "ObjectID": "1ffd45e074aa1b8df562907c95ad97526b7ca187:8" +// } +// } +// } +// u[1ffd45e074aa1b8df562907c95ad97526b7ca187:6]={ // "Fields": [ // { // "T": { @@ -172,30 +204,24 @@ func main() { // }, // "V": { // "@type": "/gno.PointerValue", -// "Base": null, +// "Base": { +// "@type": "/gno.RefValue", +// "Hash": "a919087d0eba652876f9a8df18b30ec5ddc8c26e", +// "ObjectID": "1ffd45e074aa1b8df562907c95ad97526b7ca187:7" +// }, // "Index": "0", -// "TV": { -// "T": { -// "@type": "/gno.RefType", -// "ID": "gno.land/p/demo/avl.Node" -// }, -// "V": { -// "@type": "/gno.RefValue", -// "Hash": "e373f3e5c834170fe6e8b6cf5a95d185e80b0ad7", -// "ObjectID": "1ffd45e074aa1b8df562907c95ad97526b7ca187:6" -// } -// } +// "TV": null // } // } // ], // "ObjectInfo": { -// "ID": "1ffd45e074aa1b8df562907c95ad97526b7ca187:5", -// "ModTime": "5", -// "OwnerID": "1ffd45e074aa1b8df562907c95ad97526b7ca187:4", +// "ID": "1ffd45e074aa1b8df562907c95ad97526b7ca187:6", +// "ModTime": "6", +// "OwnerID": "1ffd45e074aa1b8df562907c95ad97526b7ca187:5", // "RefCount": "1" // } // } -// u[1ffd45e074aa1b8df562907c95ad97526b7ca187:4]={ +// u[1ffd45e074aa1b8df562907c95ad97526b7ca187:5]={ // "Fields": [ // { // "T": { @@ -214,8 +240,8 @@ func main() { // }, // "V": { // "@type": "/gno.RefValue", -// "Hash": "05c2d0709574f676715a23d0161d2e151c0b21c7", -// "ObjectID": "1ffd45e074aa1b8df562907c95ad97526b7ca187:5" +// "Hash": "dfdeb7ed80c5b030c3a5e9701d00c66203de6f57", +// "ObjectID": "1ffd45e074aa1b8df562907c95ad97526b7ca187:6" // } // }, // { @@ -227,9 +253,9 @@ func main() { // } // ], // "ObjectInfo": { -// "ID": "1ffd45e074aa1b8df562907c95ad97526b7ca187:4", -// "ModTime": "5", -// "OwnerID": "1ffd45e074aa1b8df562907c95ad97526b7ca187:2", +// "ID": "1ffd45e074aa1b8df562907c95ad97526b7ca187:5", +// "ModTime": "6", +// "OwnerID": "1ffd45e074aa1b8df562907c95ad97526b7ca187:4", // "RefCount": "1" // } // } diff --git a/gnovm/tests/files/zrealm_std1_stdlibs.gno b/gnovm/tests/files/zrealm_std1_stdlibs.gno index 87f75bcb871..d75a2c60b71 100644 --- a/gnovm/tests/files/zrealm_std1_stdlibs.gno +++ b/gnovm/tests/files/zrealm_std1_stdlibs.gno @@ -25,7 +25,7 @@ func main() { } // Output: -// (slice[ref(1ed29bd278d735e20e296bd4afe927501941392f:4)] std.AddressList) +// (slice[ref(1ed29bd278d735e20e296bd4afe927501941392f:5)] std.AddressList) // error: address already exists // has: true // has: false diff --git a/gnovm/tests/files/zrealm_std2_stdlibs.gno b/gnovm/tests/files/zrealm_std2_stdlibs.gno index 1ae1fb4a881..810210c6160 100644 --- a/gnovm/tests/files/zrealm_std2_stdlibs.gno +++ b/gnovm/tests/files/zrealm_std2_stdlibs.gno @@ -26,7 +26,7 @@ func main() { } // Output: -// (slice[ref(1ed29bd278d735e20e296bd4afe927501941392f:4)] std.AddressList) +// (slice[ref(1ed29bd278d735e20e296bd4afe927501941392f:5)] std.AddressList) // error: address already exists // has: true // has: false diff --git a/gnovm/tests/files/zrealm_tests0_stdlibs.gno b/gnovm/tests/files/zrealm_tests0_stdlibs.gno index d68c1f652f7..bfd4ad30a1e 100644 --- a/gnovm/tests/files/zrealm_tests0_stdlibs.gno +++ b/gnovm/tests/files/zrealm_tests0_stdlibs.gno @@ -23,7 +23,7 @@ func main() { // Realm: // switchrealm["gno.land/r/demo/tests"] -// c[0ffe7732b4d549b4cf9ec18bd68641cd2c75ad0a:14]={ +// c[0ffe7732b4d549b4cf9ec18bd68641cd2c75ad0a:18]={ // "Fields": [ // { // "T": { @@ -37,13 +37,32 @@ func main() { // } // ], // "ObjectInfo": { -// "ID": "0ffe7732b4d549b4cf9ec18bd68641cd2c75ad0a:14", +// "ID": "0ffe7732b4d549b4cf9ec18bd68641cd2c75ad0a:18", // "ModTime": "0", -// "OwnerID": "0ffe7732b4d549b4cf9ec18bd68641cd2c75ad0a:13", +// "OwnerID": "0ffe7732b4d549b4cf9ec18bd68641cd2c75ad0a:17", // "RefCount": "1" // } // } -// c[0ffe7732b4d549b4cf9ec18bd68641cd2c75ad0a:13]={ +// c[0ffe7732b4d549b4cf9ec18bd68641cd2c75ad0a:17]={ +// "ObjectInfo": { +// "ID": "0ffe7732b4d549b4cf9ec18bd68641cd2c75ad0a:17", +// "ModTime": "0", +// "OwnerID": "0ffe7732b4d549b4cf9ec18bd68641cd2c75ad0a:16", +// "RefCount": "1" +// }, +// "Value": { +// "T": { +// "@type": "/gno.RefType", +// "ID": "gno.land/r/demo/tests_foo.FooStringer" +// }, +// "V": { +// "@type": "/gno.RefValue", +// "Hash": "d3d6ffa52602f2bc976051d79294d219750aca64", +// "ObjectID": "0ffe7732b4d549b4cf9ec18bd68641cd2c75ad0a:18" +// } +// } +// } +// c[0ffe7732b4d549b4cf9ec18bd68641cd2c75ad0a:16]={ // "Data": null, // "List": [ // { @@ -56,19 +75,13 @@ func main() { // }, // "V": { // "@type": "/gno.PointerValue", -// "Base": null, +// "Base": { +// "@type": "/gno.RefValue", +// "Hash": "4ea1e08156f3849b74a0f41f92cd4b48fb94926b", +// "ObjectID": "0ffe7732b4d549b4cf9ec18bd68641cd2c75ad0a:11" +// }, // "Index": "0", -// "TV": { -// "T": { -// "@type": "/gno.RefType", -// "ID": "gno.land/r/demo/tests_foo.FooStringer" -// }, -// "V": { -// "@type": "/gno.RefValue", -// "Hash": "63ef2b51ca911a9b1727588bacb958ec3cb2a392", -// "ObjectID": "0ffe7732b4d549b4cf9ec18bd68641cd2c75ad0a:10" -// } -// } +// "TV": null // } // }, // { @@ -81,19 +94,13 @@ func main() { // }, // "V": { // "@type": "/gno.PointerValue", -// "Base": null, +// "Base": { +// "@type": "/gno.RefValue", +// "Hash": "ce86ea1156e75a44cd9d7ba2261819b100aa4ed1", +// "ObjectID": "0ffe7732b4d549b4cf9ec18bd68641cd2c75ad0a:14" +// }, // "Index": "0", -// "TV": { -// "T": { -// "@type": "/gno.RefType", -// "ID": "gno.land/r/demo/tests_foo.FooStringer" -// }, -// "V": { -// "@type": "/gno.RefValue", -// "Hash": "54c554e1d1f61e19feb13bb229f43540338c0f8f", -// "ObjectID": "0ffe7732b4d549b4cf9ec18bd68641cd2c75ad0a:12" -// } -// } +// "TV": null // } // }, // { @@ -106,24 +113,18 @@ func main() { // }, // "V": { // "@type": "/gno.PointerValue", -// "Base": null, +// "Base": { +// "@type": "/gno.RefValue", +// "Hash": "b66192fbd8a8dde79b6f854b5cc3c4cc965cfd92", +// "ObjectID": "0ffe7732b4d549b4cf9ec18bd68641cd2c75ad0a:17" +// }, // "Index": "0", -// "TV": { -// "T": { -// "@type": "/gno.RefType", -// "ID": "gno.land/r/demo/tests_foo.FooStringer" -// }, -// "V": { -// "@type": "/gno.RefValue", -// "Hash": "4e50e2cdaeb022a6fcbdb96d9fbd7f3af8df1379", -// "ObjectID": "0ffe7732b4d549b4cf9ec18bd68641cd2c75ad0a:14" -// } -// } +// "TV": null // } // } // ], // "ObjectInfo": { -// "ID": "0ffe7732b4d549b4cf9ec18bd68641cd2c75ad0a:13", +// "ID": "0ffe7732b4d549b4cf9ec18bd68641cd2c75ad0a:16", // "ModTime": "0", // "OwnerID": "0ffe7732b4d549b4cf9ec18bd68641cd2c75ad0a:2", // "RefCount": "1" @@ -134,7 +135,7 @@ func main() { // "ObjectInfo": { // "ID": "0ffe7732b4d549b4cf9ec18bd68641cd2c75ad0a:2", // "IsEscaped": true, -// "ModTime": "12", +// "ModTime": "15", // "RefCount": "5" // }, // "Parent": null, @@ -1511,8 +1512,8 @@ func main() { // "@type": "/gno.SliceValue", // "Base": { // "@type": "/gno.RefValue", -// "Hash": "5f12a61dd16d828be8584debc0e395e8d2136acb", -// "ObjectID": "0ffe7732b4d549b4cf9ec18bd68641cd2c75ad0a:13" +// "Hash": "ad25f70f66c8c53042afd1377e5ff5ab744bf1a5", +// "ObjectID": "0ffe7732b4d549b4cf9ec18bd68641cd2c75ad0a:16" // }, // "Length": "3", // "Maxcap": "3", @@ -1529,19 +1530,13 @@ func main() { // }, // "V": { // "@type": "/gno.PointerValue", -// "Base": null, +// "Base": { +// "@type": "/gno.RefValue", +// "Hash": "b662d2bfde61831128c908a3d1afff97e05e6227", +// "ObjectID": "0ffe7732b4d549b4cf9ec18bd68641cd2c75ad0a:7" +// }, // "Index": "0", -// "TV": { -// "T": { -// "@type": "/gno.RefType", -// "ID": "gno.land/r/demo/tests.Int" -// }, -// "V": { -// "@type": "/gno.RefValue", -// "Hash": "90b77781ec2b1e153ac020b1102354174bde972e", -// "ObjectID": "0ffe7732b4d549b4cf9ec18bd68641cd2c75ad0a:7" -// } -// } +// "TV": null // } // }, // { @@ -1595,7 +1590,7 @@ func main() { // } // ] // } -// d[0ffe7732b4d549b4cf9ec18bd68641cd2c75ad0a:11] +// d[0ffe7732b4d549b4cf9ec18bd68641cd2c75ad0a:13] // switchrealm["gno.land/r/demo/tests_foo"] // switchrealm["gno.land/r/demo/tests_foo"] // switchrealm["gno.land/r/demo/tests_foo"] From d2d34eb69026dd85f1adadb138b8006cbce31ccd Mon Sep 17 00:00:00 2001 From: thinhnx-var <168700277+thinhnx-var@users.noreply.github.com> Date: Thu, 20 Jun 2024 14:15:55 +0700 Subject: [PATCH 26/26] fix(examples): update /r/demo/bar20/gno.mod (#2398)
Contributors' checklist... - [ ] Added new tests, or not needed, or not feasible - [ ] Provided an example (e.g. screenshot) to aid review or the PR is self-explanatory - [ ] Updated the official documentation or not needed - [ ] No breaking changes were made, or a `BREAKING CHANGE: xxx` message was included in the description - [ ] 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).
Update /r/demo/bar20/gno.mod because of failing pipeline --- examples/gno.land/r/demo/bar20/gno.mod | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/gno.land/r/demo/bar20/gno.mod b/examples/gno.land/r/demo/bar20/gno.mod index d104f0b9987..fd804beb4c4 100644 --- a/examples/gno.land/r/demo/bar20/gno.mod +++ b/examples/gno.land/r/demo/bar20/gno.mod @@ -1,4 +1,4 @@ -module bar20 +module gno.land/r/demo/bar20 require ( gno.land/p/demo/grc/grc20 v0.0.0-latest