diff --git a/.github/golangci.yml b/.github/golangci.yml index 140e4dffc12..8eb52dbbf22 100644 --- a/.github/golangci.yml +++ b/.github/golangci.yml @@ -90,4 +90,4 @@ issues: linters: - errorlint # Disabled linting of error comparisons, because of lacking std lib support - path: gnovm/pkg/gnolang - text: "string `(cross|.no realm.|crossing)` has (\\d+) occurrences, make it a constant" + text: "string `(realm|cross|.no realm.|crossing)` has (\\d+) occurrences, make it a constant" diff --git a/contribs/gnodev/cmd/gnodev/setup_loader.go b/contribs/gnodev/cmd/gnodev/setup_loader.go index 69342657352..e23f4f94b6f 100644 --- a/contribs/gnodev/cmd/gnodev/setup_loader.go +++ b/contribs/gnodev/cmd/gnodev/setup_loader.go @@ -88,12 +88,11 @@ func setupPackagesResolver(logger *slog.Logger, cfg *AppConfig, dirs ...string) } func guessPathGnoMod(dir string) (path string, ok bool) { - modfile, err := gnomod.ParseAt(dir) - if err == nil { - return modfile.Module.Mod.Path, true + modfile, err := gnomod.ParseDir(dir) + if err != nil { + return "", false } - - return "", false + return modfile.Module.Mod.Path, true } var reInvalidChar = regexp.MustCompile(`[^\w_-]`) diff --git a/contribs/gnodev/pkg/packages/package.go b/contribs/gnodev/pkg/packages/package.go index f3215480ed9..c66870d84a0 100644 --- a/contribs/gnodev/pkg/packages/package.go +++ b/contribs/gnodev/pkg/packages/package.go @@ -1,11 +1,11 @@ package packages import ( + "errors" "fmt" "go/parser" "go/token" "os" - "path/filepath" "github.com/gnolang/gno/gnovm/pkg/gnolang" "github.com/gnolang/gno/gnovm/pkg/gnomod" @@ -27,19 +27,19 @@ type Package struct { } func ReadPackageFromDir(fset *token.FileSet, path, dir string) (*Package, error) { - modpath := filepath.Join(dir, "gno.mod") - if _, err := os.Stat(modpath); err == nil { - draft, err := isDraftFile(modpath) - if err != nil { - return nil, err - } - - // Skip draft package - // XXX: We could potentially do that in a middleware, but doing this - // here avoid to potentially parse broken files - if draft { + mod, err := gnomod.ParseDir(dir) + switch { + case err == nil: + if mod.Draft { + // Skip draft package + // XXX: We could potentially do that in a middleware, but doing this + // here avoid to potentially parse broken files return nil, ErrResolverPackageSkip } + case errors.Is(err, os.ErrNotExist), errors.Is(err, gnomod.ErrGnoModNotFound): + // gno.mod is not present, continue anyway + default: + return nil, err } mempkg, err := gnolang.ReadMemPackage(dir, path) @@ -63,7 +63,7 @@ func ReadPackageFromDir(fset *token.FileSet, path, dir string) (*Package, error) } func validateMemPackage(fset *token.FileSet, mempkg *std.MemPackage) error { - if mempkg.IsEmpty() { + if isMemPackageEmpty(mempkg) { return fmt.Errorf("empty package: %w", ErrResolverPackageSkip) } @@ -87,16 +87,16 @@ func validateMemPackage(fset *token.FileSet, mempkg *std.MemPackage) error { return nil } -func isDraftFile(modpath string) (bool, error) { - modfile, err := os.ReadFile(modpath) - if err != nil { - return false, fmt.Errorf("unable to read file %q: %w", modpath, err) +func isMemPackageEmpty(mempkg *std.MemPackage) bool { + if mempkg.IsEmpty() { + return true } - mod, err := gnomod.Parse(modpath, modfile) - if err != nil { - return false, fmt.Errorf("unable to parse `gno.mod`: %w", err) + for _, file := range mempkg.Files { + if isGnoFile(file.Name) || file.Name == "gno.mod" { + return false + } } - return mod.Draft, nil + return true } diff --git a/contribs/gnodev/pkg/packages/resolver.go b/contribs/gnodev/pkg/packages/resolver.go index 9ed9269b6d8..3f9a8eea085 100644 --- a/contribs/gnodev/pkg/packages/resolver.go +++ b/contribs/gnodev/pkg/packages/resolver.go @@ -199,10 +199,6 @@ func PackageCheckerMiddleware(logger *slog.Logger) MiddlewareHandler { return nil, err } - if err := pkg.Validate(); err != nil { - return nil, fmt.Errorf("invalid package %q: %w", path, err) - } - // Post-process each file in the package. for _, file := range pkg.Files { fname := file.Name diff --git a/examples/Makefile b/examples/Makefile index 2c2c03f5e32..9e95cac6399 100644 --- a/examples/Makefile +++ b/examples/Makefile @@ -44,6 +44,10 @@ test.fast: lint: go run ../gnovm/cmd/gno lint -v . +.PHONY: fix +fix: + go run ../gnovm/cmd/gno fix -v . + .PHONY: test.sync test.sync: go run ../gnovm/cmd/gno test -v --update-golden-tests ./... diff --git a/examples/gno.land/p/demo/grc/grc20/token_test.gno b/examples/gno.land/p/demo/grc/grc20/token_test.gno index 8bd1f4b3c61..d526727722c 100644 --- a/examples/gno.land/p/demo/grc/grc20/token_test.gno +++ b/examples/gno.land/p/demo/grc/grc20/token_test.gno @@ -95,9 +95,8 @@ func TestMintOverflow(t *testing.T) { func TestTransferFromAtomicity(t *testing.T) { var ( - owner = testutils.TestAddress("owner") - spender = testutils.TestAddress("spender") - recipient = testutils.TestAddress("recipient") + owner = testutils.TestAddress("owner") + spender = testutils.TestAddress("spender") invalidRecipient = std.Address("") ) diff --git a/examples/gno.land/p/moul/collection/collection_test.gno b/examples/gno.land/p/moul/collection/collection_test.gno index ea2e493df3f..8c191492f14 100644 --- a/examples/gno.land/p/moul/collection/collection_test.gno +++ b/examples/gno.land/p/moul/collection/collection_test.gno @@ -131,7 +131,7 @@ func TestUpdates(t *testing.T) { p2 := &Person{Name: "Bob", Username: "bob456"} id1 := c.Set(p1) - id2 := c.Set(p2) + c.Set(p2) tests := []struct { name string @@ -254,7 +254,7 @@ func TestEdgeCases(t *testing.T) { if entry == nil { return false } - id, err := seqid.FromString(entry.ID) + _, err := seqid.FromString(entry.ID) if err != nil { return false } @@ -330,7 +330,7 @@ func TestIndexOptions(t *testing.T) { return v.(*Person).Username }, UniqueIndex) - id1 := c.Set(&Person{Username: "Alice"}) + c.Set(&Person{Username: "Alice"}) return c.Set(&Person{Username: "Alice"}) // Should fail }, wantID: false, @@ -342,7 +342,7 @@ func TestIndexOptions(t *testing.T) { return v.(*Person).Email }, UniqueIndex|CaseInsensitiveIndex) - id1 := c.Set(&Person{Email: "test@example.com"}) + c.Set(&Person{Email: "test@example.com"}) return c.Set(&Person{Email: "TEST@EXAMPLE.COM"}) // Should fail }, wantID: false, @@ -372,7 +372,7 @@ func TestIndexOptions(t *testing.T) { return v.(*Person).Name }, UniqueIndex|CaseInsensitiveIndex|SparseIndex) - id1 := c.Set(&Person{Name: "Alice"}) + c.Set(&Person{Name: "Alice"}) return c.Set(&Person{Name: "ALICE"}) // Should fail }, wantID: false, diff --git a/examples/gno.land/p/moul/helplink/helplink.gno b/examples/gno.land/p/moul/helplink/helplink.gno index d1a03759cdf..55bcf4c24a0 100644 --- a/examples/gno.land/p/moul/helplink/helplink.gno +++ b/examples/gno.land/p/moul/helplink/helplink.gno @@ -51,13 +51,13 @@ func (r Realm) prefix() string { } // local realm -> /realm - realm := string(r) - if strings.HasPrefix(realm, chainDomain) { - return strings.TrimPrefix(realm, chainDomain) + rlmstr := string(r) + if strings.HasPrefix(rlmstr, chainDomain) { + return strings.TrimPrefix(rlmstr, chainDomain) } // remote realm -> https://remote.land/realm - return "https://" + string(r) + return "https://" + rlmstr } // Func returns a markdown link for the specified function with optional diff --git a/examples/gno.land/p/moul/txlink/txlink.gno b/examples/gno.land/p/moul/txlink/txlink.gno index b88fb1ede16..0aa7e8614e2 100644 --- a/examples/gno.land/p/moul/txlink/txlink.gno +++ b/examples/gno.land/p/moul/txlink/txlink.gno @@ -134,9 +134,9 @@ func (r Realm) prefix() string { } // local realm -> /realm - realm := string(r) - if strings.HasPrefix(realm, chainDomain) { - return strings.TrimPrefix(realm, chainDomain) + rlm := string(r) + if strings.HasPrefix(rlm, chainDomain) { + return strings.TrimPrefix(rlm, chainDomain) } // remote realm -> https://remote.land/realm diff --git a/examples/gno.land/r/demo/atomicswap/atomicswap_test.gno b/examples/gno.land/r/demo/atomicswap/atomicswap_test.gno index 9d2ad09610d..162b55da063 100644 --- a/examples/gno.land/r/demo/atomicswap/atomicswap_test.gno +++ b/examples/gno.land/r/demo/atomicswap/atomicswap_test.gno @@ -370,7 +370,6 @@ func TestNewGRC20Swap_Refund(t *testing.T) { rlm := std.DerivePkgAddr("gno.land/r/demo/atomicswap") hashlock := sha256.Sum256([]byte("secret")) hashlockHex := hex.EncodeToString(hashlock[:]) - timelock := time.Now().Add(defaultTimelockDuration) test20.PrivateLedger.Mint(sender, 100_000) test20.PrivateLedger.Approve(sender, rlm, 70_000) diff --git a/examples/gno.land/r/demo/boards/z_5_filetest.gno b/examples/gno.land/r/demo/boards/z_5_filetest.gno index cb0a9c27800..9da23591384 100644 --- a/examples/gno.land/r/demo/boards/z_5_filetest.gno +++ b/examples/gno.land/r/demo/boards/z_5_filetest.gno @@ -23,12 +23,12 @@ func init() { bid = cross(boards.CreateBoard)("test_board") cross(boards.CreateThread)(bid, "First Post (title)", "Body of the first post. (body)") pid = cross(boards.CreateThread)(bid, "Second Post (title)", "Body of the second post. (body)") - rid := cross(boards.CreateReply)(bid, pid, pid, "Reply of the second post") + _ = cross(boards.CreateReply)(bid, pid, pid, "Reply of the second post") } func main() { testing.SetRealm(std.NewUserRealm(std.Address("g1wymu47drhr0kuq2098m792lytgtj2nyx77yrsm"))) - rid2 := cross(boards.CreateReply)(bid, pid, pid, "Second reply of the second post\n") + _ = cross(boards.CreateReply)(bid, pid, pid, "Second reply of the second post\n") println(boards.Render("test_board/" + strconv.Itoa(int(pid)))) } diff --git a/examples/gno.land/r/demo/tests/z2_filetest.gno b/examples/gno.land/r/demo/tests/z2_filetest.gno index 94e9b51ee94..549a5e2bbb8 100644 --- a/examples/gno.land/r/demo/tests/z2_filetest.gno +++ b/examples/gno.land/r/demo/tests/z2_filetest.gno @@ -12,8 +12,8 @@ import ( // When 2 or more realms in the frames, PreviousRealm returns the second to last func main() { var ( - eoa = testutils.TestAddress("someone") - rTestsAddr = std.DerivePkgAddr("gno.land/r/demo/tests") + eoa = testutils.TestAddress("someone") + _ = std.DerivePkgAddr("gno.land/r/demo/tests") ) testing.SetOriginCaller(eoa) println("tests.GetPreviousRealm().Address(): ", cross(tests.GetPreviousRealm)().Address()) diff --git a/examples/gno.land/r/gnoland/faucet/z3_filetest.gno b/examples/gno.land/r/gnoland/faucet/z3_filetest.gno index f4c55bbc928..6140bac7f03 100644 --- a/examples/gno.land/r/gnoland/faucet/z3_filetest.gno +++ b/examples/gno.land/r/gnoland/faucet/z3_filetest.gno @@ -21,7 +21,7 @@ func main() { controlleraddr1 = testutils.TestAddress("controller1") controlleraddr2 = testutils.TestAddress("controller2") testaddr1 = testutils.TestAddress("test1") - testaddr2 = testutils.TestAddress("test2") + _ = testutils.TestAddress("test2") ) testing.SetRealm(std.NewUserRealm(adminaddr)) err := cross(faucet.AdminAddController)(controlleraddr1) diff --git a/examples/gno.land/r/gnoland/monit/monit_test.gno b/examples/gno.land/r/gnoland/monit/monit_test.gno index b08f30cb632..362a05c6fad 100644 --- a/examples/gno.land/r/gnoland/monit/monit_test.gno +++ b/examples/gno.land/r/gnoland/monit/monit_test.gno @@ -78,7 +78,6 @@ func TestReset(t *testing.T) { // Initial state check initialCounter := counter initialLastUpdate := lastUpdate - initialLastCaller := lastCaller initialStatus := wd.Status() // Call Incr to change the state diff --git a/examples/gno.land/r/gnoland/users/v1/z_0_prop1_filetest.gno b/examples/gno.land/r/gnoland/users/v1/z_0_prop1_filetest.gno index f57d4f5656d..79cd821740f 100644 --- a/examples/gno.land/r/gnoland/users/v1/z_0_prop1_filetest.gno +++ b/examples/gno.land/r/gnoland/users/v1/z_0_prop1_filetest.gno @@ -9,7 +9,7 @@ import ( "gno.land/p/demo/testutils" users "gno.land/r/gnoland/users/v1" "gno.land/r/gov/dao" - "gno.land/r/gov/dao/v3/init" + daov3init "gno.land/r/gov/dao/v3/init" susers "gno.land/r/sys/users" ) @@ -17,7 +17,7 @@ import ( var c std.Address = std.OriginCaller() func init() { - init.InitWithUsers(c) + daov3init.InitWithUsers(c) alice := testutils.TestAddress("alice") diff --git a/examples/gno.land/r/gnoland/users/v1/z_1_prop2_filetest.gno b/examples/gno.land/r/gnoland/users/v1/z_1_prop2_filetest.gno index a21bbdb04aa..84b7fc24ce3 100644 --- a/examples/gno.land/r/gnoland/users/v1/z_1_prop2_filetest.gno +++ b/examples/gno.land/r/gnoland/users/v1/z_1_prop2_filetest.gno @@ -9,7 +9,7 @@ import ( "gno.land/p/demo/testutils" users "gno.land/r/gnoland/users/v1" "gno.land/r/gov/dao" - "gno.land/r/gov/dao/v3/init" + daov3init "gno.land/r/gov/dao/v3/init" susers "gno.land/r/sys/users" ) @@ -18,7 +18,7 @@ import ( var c std.Address = std.OriginCaller() func init() { - init.InitWithUsers(c) + daov3init.InitWithUsers(c) alice := testutils.TestAddress("alice") diff --git a/examples/gno.land/r/gnoland/users/z_0_filetest.gno b/examples/gno.land/r/gnoland/users/z_0_filetest.gno index ff4dfaeb9e1..c376d3b4f9c 100644 --- a/examples/gno.land/r/gnoland/users/z_0_filetest.gno +++ b/examples/gno.land/r/gnoland/users/z_0_filetest.gno @@ -7,7 +7,7 @@ import ( "gno.land/p/demo/testutils" "gno.land/r/gnoland/users" "gno.land/r/gov/dao" - "gno.land/r/gov/dao/v3/init" + ini "gno.land/r/gov/dao/v3/init" ) var ( @@ -17,7 +17,7 @@ var ( func init() { testing.SetRealm(std.NewUserRealm(alice)) c := std.OriginCaller() - init.InitWithUsers(c) + ini.InitWithUsers(c) pReq := users.ProposeNewRelease("gno.land/r/gnoland/users/v2", "This is a note!") diff --git a/examples/gno.land/r/gnoland/valopers_proposal/proposal_test.gno b/examples/gno.land/r/gnoland/valopers_proposal/proposal_test.gno index 6ce1edc935f..c335974721e 100644 --- a/examples/gno.land/r/gnoland/valopers_proposal/proposal_test.gno +++ b/examples/gno.land/r/gnoland/valopers_proposal/proposal_test.gno @@ -42,10 +42,8 @@ func TestValopers_ProposeNewValidator(t *testing.T) { cross(valopers.UpdateKeepRunning)(g1user, false) }) - var valoper valopers.Valoper - urequire.NotPanics(t, func() { - valoper = valopers.GetByAddr(g1user) + valopers.GetByAddr(g1user) }) // Send coins to be able to make a proposal @@ -79,7 +77,7 @@ func TestValopers_ProposeNewValidator(t *testing.T) { urequire.NotPanics(t, func() { pr := NewValidatorProposalRequest(g1user) - pid := cross(dao.MustCreateProposal)(pr) + pid = cross(dao.MustCreateProposal)(pr) }) proposal, err := cross(dao.GetProposal)(pid) // index starts from 0 @@ -99,10 +97,8 @@ func TestValopers_ProposeNewValidator(t *testing.T) { // Send coins to be able to register a valoper testing.SetOriginSend(std.Coins{std.NewCoin("ugnot", registerMinFee)}) - var valoper valopers.Valoper - urequire.NotPanics(t, func() { - valoper = valopers.GetByAddr(g1user) + valopers.GetByAddr(g1user) }) urequire.NotPanics(t, func() { diff --git a/examples/gno.land/r/gov/dao/v3/memberstore/memberstore.gno b/examples/gno.land/r/gov/dao/v3/memberstore/memberstore.gno index e8f68f835c2..bb5f5aed8d6 100644 --- a/examples/gno.land/r/gov/dao/v3/memberstore/memberstore.gno +++ b/examples/gno.land/r/gov/dao/v3/memberstore/memberstore.gno @@ -122,9 +122,9 @@ func Render(string) string { // Get gets the Members store func Get() MembersByTier { - realm := std.CurrentRealm().PkgPath() - if !dao.InAllowedDAOs(realm) { - panic("this Realm is not allowed to get the Members data: " + realm) + currealm := std.CurrentRealm().PkgPath() + if !dao.InAllowedDAOs(currealm) { + panic("this Realm is not allowed to get the Members data: " + currealm) } return members diff --git a/examples/gno.land/r/gov/dao/v3/memberstore/memberstore_test.gno b/examples/gno.land/r/gov/dao/v3/memberstore/memberstore_test.gno index e5ba6e9b517..8a16b88cebb 100644 --- a/examples/gno.land/r/gov/dao/v3/memberstore/memberstore_test.gno +++ b/examples/gno.land/r/gov/dao/v3/memberstore/memberstore_test.gno @@ -5,7 +5,6 @@ import ( "strconv" "testing" - "gno.land/p/demo/avl" "gno.land/p/demo/urequire" ) @@ -115,7 +114,7 @@ func TestCreateMembers(t *testing.T) { } func addMembers(ms MembersByTier, c int, tier string) { - mt := avl.NewTree() + // mt := avl.NewTree() XXX ms.SetTier(tier) for i := 0; i < c; i++ { addr := std.Address(strconv.Itoa(i) + tier) diff --git a/examples/gno.land/r/leon/hor/datasource_test.gno b/examples/gno.land/r/leon/hor/datasource_test.gno index 207314db81b..5371ba3f7c5 100644 --- a/examples/gno.land/r/leon/hor/datasource_test.gno +++ b/examples/gno.land/r/leon/hor/datasource_test.gno @@ -155,7 +155,7 @@ func TestItemRecord(t *testing.T) { wantContent := `### [Test Realm](/r/demo/test) This is a test realm in the Hall of Fame -by demo +by [@demo](/r/gnoland/users/v1:demo) Submitted at Block #42 diff --git a/examples/gno.land/r/leon/hor/hof_test.gno b/examples/gno.land/r/leon/hor/hof_test.gno index 54d2a016f70..a7f4bbc4b81 100644 --- a/examples/gno.land/r/leon/hor/hof_test.gno +++ b/examples/gno.land/r/leon/hor/hof_test.gno @@ -125,7 +125,7 @@ func TestDelete(t *testing.T) { }) i, _ := exhibition.items.Get(rlmPath) - id := i.(*Item).id + _ = i.(*Item).id uassert.NotPanics(t, func() { cross(Delete)(rlmPath) @@ -137,7 +137,7 @@ func TestDelete(t *testing.T) { func itemExists(t *testing.T, rlmPath string) bool { t.Helper() - i, ok1 := exhibition.items.Get(rlmPath) + _, ok1 := exhibition.items.Get(rlmPath) return ok1 } @@ -210,11 +210,11 @@ func TestSortByUpvote(t *testing.T) { cross(Upvote)(rlmPath5) // We are displaying data in reverse order in render, so items should be sorted in reverse order - firstKey, firstRawValue := exhibition.itemsSortedByUpvotes.GetByIndex(0) + _, firstRawValue := exhibition.itemsSortedByUpvotes.GetByIndex(0) firstValue := firstRawValue.(*Item) uassert.Equal(t, firstValue.pkgpath, rlmPath3) - secondKey, secondRawValue := exhibition.itemsSortedByUpvotes.GetByIndex(1) + _, secondRawValue := exhibition.itemsSortedByUpvotes.GetByIndex(1) secondValue := secondRawValue.(*Item) uassert.Equal(t, secondValue.pkgpath, rlmPath4) } @@ -268,13 +268,13 @@ func TestSortByDownvote(t *testing.T) { cross(Downvote)(rlmPath5) // We are dispalying data is reverse order in render, so items should be sorted in reverse order - firstKey, firstRawValue := exhibition.itemsSortedByDownvotes.GetByIndex(0) + _, firstRawValue := exhibition.itemsSortedByDownvotes.GetByIndex(0) firstValue := firstRawValue.(*Item) uassert.Equal(t, firstValue.pkgpath, rlmPath3) - secondKey, secondRawValue := exhibition.itemsSortedByDownvotes.GetByIndex(1) + _, secondRawValue := exhibition.itemsSortedByDownvotes.GetByIndex(1) secondValue := secondRawValue.(*Item) @@ -313,13 +313,13 @@ func TestSortByCreation(t *testing.T) { cross(Register)(validTitle, validDesc) // We are dispalying data is reverse order in render, so items should be sorted in reverse order - firstKey, firstRawValue := exhibition.itemsSortedByCreation.GetByIndex(0) + _, firstRawValue := exhibition.itemsSortedByCreation.GetByIndex(0) firstValue := firstRawValue.(*Item) uassert.Equal(t, firstValue.pkgpath, rlmPath3) - secondKey, secondRawValue := exhibition.itemsSortedByCreation.GetByIndex(1) + _, secondRawValue := exhibition.itemsSortedByCreation.GetByIndex(1) secondValue := secondRawValue.(*Item) diff --git a/examples/gno.land/r/morgan/chess/chess_test.gno b/examples/gno.land/r/morgan/chess/chess_test.gno index a6b7669ce48..d5547366d2e 100644 --- a/examples/gno.land/r/morgan/chess/chess_test.gno +++ b/examples/gno.land/r/morgan/chess/chess_test.gno @@ -587,7 +587,7 @@ func runCommandTest(t *testing.T, command string) { t.Run(testName, func(t *testing.T) { cleanup() bufs := make(map[string]string, 3) - for idx, f := range funcs { + for _, f := range funcs { if _, ok := f.(interface{ Checker() }); ok { f.Run(t, bufs) } else { diff --git a/examples/gno.land/r/morgan/chess/lobby_test.gno b/examples/gno.land/r/morgan/chess/lobby_test.gno index 4efadcab02d..b336188e585 100644 --- a/examples/gno.land/r/morgan/chess/lobby_test.gno +++ b/examples/gno.land/r/morgan/chess/lobby_test.gno @@ -153,7 +153,7 @@ func TestLobbyGameFound(t *testing.T) { } testing.SetRealm(std.NewUserRealm(tc.caller)) - game := cross(LobbyGameFound)() + cross(LobbyGameFound)() if tc.check != nil { tc.check(t) diff --git a/examples/gno.land/r/sys/params/unlock_test.gno b/examples/gno.land/r/sys/params/unlock_test.gno index b6ef7813eb3..c8544256bbb 100644 --- a/examples/gno.land/r/sys/params/unlock_test.gno +++ b/examples/gno.land/r/sys/params/unlock_test.gno @@ -7,7 +7,7 @@ import ( "gno.land/p/demo/testutils" "gno.land/p/demo/urequire" "gno.land/r/gov/dao" - "gno.land/r/gov/dao/v3/init" + ini "gno.land/r/gov/dao/v3/init" ) var ( @@ -16,7 +16,7 @@ var ( func init() { testing.SetRealm(std.NewUserRealm(g1user)) - init.InitWithUsers(g1user) + ini.InitWithUsers(g1user) } func TestProUnlockTransfer(t *testing.T) { @@ -48,7 +48,7 @@ func TestExeUnlockTransfer(t *testing.T) { pr := ProposeUnlockTransferRequest() id := cross(dao.MustCreateProposal)(pr) - p, err := cross(dao.GetProposal)(id) + _, err := cross(dao.GetProposal)(id) urequire.NoError(t, err) // urequire.True(t, dao.Active == p.Status()) // TODO diff --git a/examples/gno.land/r/x/nir1218_evaluation_proposal/committee_test.gno b/examples/gno.land/r/x/nir1218_evaluation_proposal/committee_test.gno index 4dd72c5d616..68e8cbe8c19 100644 --- a/examples/gno.land/r/x/nir1218_evaluation_proposal/committee_test.gno +++ b/examples/gno.land/r/x/nir1218_evaluation_proposal/committee_test.gno @@ -65,7 +65,7 @@ func TestCategoryEvaluationCriteria(t *testing.T) { testing.SetOriginCaller(member) approved := c.ApproveCategory(category, VoteYes) if !approved { - value, exists := c.categories.Get(category) + value, _ := c.categories.Get(category) gotCategory := value.(*Category) t.Errorf("Approved First Committee category got %s expected %s", gotCategory.status, "Approved") } diff --git a/examples/gno.land/r/x/nir1218_evaluation_proposal/evaluation_test.gno b/examples/gno.land/r/x/nir1218_evaluation_proposal/evaluation_test.gno index f9e0913010d..176023dc806 100644 --- a/examples/gno.land/r/x/nir1218_evaluation_proposal/evaluation_test.gno +++ b/examples/gno.land/r/x/nir1218_evaluation_proposal/evaluation_test.gno @@ -28,7 +28,7 @@ var ( func TestEvaluationAddContribution(t *testing.T) { pr := NewPullRequest(id, name, description, status, category) - contributionId, ok := e.AddContribution(pr, address) + contributionId, _ := e.AddContribution(pr, address) t.Run("", func(t *testing.T) { if contributionId != id { diff --git a/examples/no_cycles_test.go b/examples/no_cycles_test.go index 416e77fe069..aa52f2bfbd1 100644 --- a/examples/no_cycles_test.go +++ b/examples/no_cycles_test.go @@ -11,6 +11,7 @@ import ( "testing" "github.com/gnolang/gno/gnovm/pkg/gnoenv" + "github.com/gnolang/gno/gnovm/pkg/gnolang" "github.com/gnolang/gno/gnovm/pkg/gnomod" "github.com/gnolang/gno/gnovm/pkg/packages" "github.com/gnolang/gno/tm2/pkg/std" @@ -28,7 +29,7 @@ func TestNoCycles(t *testing.T) { require.NoError(t, err) // find examples - examples, err := gnomod.ListPkgs(filepath.Join(gnoRoot, "examples")) + examples, err := gnolang.ReadPkgListFromDir(filepath.Join(gnoRoot, "examples")) require.NoError(t, err) for _, example := range examples { if example.Draft { diff --git a/gno.land/pkg/gnoland/genesis.go b/gno.land/pkg/gnoland/genesis.go index 8633a80e999..3d665a516c9 100644 --- a/gno.land/pkg/gnoland/genesis.go +++ b/gno.land/pkg/gnoland/genesis.go @@ -175,7 +175,7 @@ func LoadGenesisTxsFile(path string, chainID string, genesisRemote string) ([]Tx // It creates and returns a list of transactions based on these packages. func LoadPackagesFromDir(dir string, creator bft.Address, fee std.Fee) ([]TxWithMetadata, error) { // list all packages from target path - pkgs, err := gnomod.ListPkgs(dir) + pkgs, err := gno.ReadPkgListFromDir(dir) if err != nil { return nil, fmt.Errorf("listing gno packages from gnomod: %w", err) } @@ -208,8 +208,8 @@ func LoadPackage(pkg gnomod.Pkg, creator bft.Address, fee std.Fee, deposit std.C var tx std.Tx // Open files in directory as MemPackage. - memPkg := gno.MustReadMemPackage(pkg.Dir, pkg.Name) - err := memPkg.Validate() + mpkg := gno.MustReadMemPackage(pkg.Dir, pkg.Name) + err := gno.ValidateMemPackage(mpkg) if err != nil { return tx, fmt.Errorf("invalid package: %w", err) } @@ -219,7 +219,7 @@ func LoadPackage(pkg gnomod.Pkg, creator bft.Address, fee std.Fee, deposit std.C tx.Msgs = []std.Msg{ vmm.MsgAddPackage{ Creator: creator, - Package: memPkg, + Package: mpkg, Deposit: deposit, }, } diff --git a/gno.land/pkg/integration/pkgloader.go b/gno.land/pkg/integration/pkgloader.go index 3074a1abc8e..95a5dbe5881 100644 --- a/gno.land/pkg/integration/pkgloader.go +++ b/gno.land/pkg/integration/pkgloader.go @@ -84,14 +84,14 @@ func (pl *PkgsLoader) LoadPackages(creatorKey crypto.PrivKey, fee std.Fee, depos return txs, nil } -func (pl *PkgsLoader) LoadAllPackagesFromDir(path string) error { +func (pl *PkgsLoader) LoadAllPackagesFromDir(dir string) error { // list all packages from target path - pkgslist, err := gnomod.ListPkgs(path) + pkglist, err := gnolang.ReadPkgListFromDir(dir) if err != nil { return fmt.Errorf("listing gno packages from gnomod: %w", err) } - for _, pkg := range pkgslist { + for _, pkg := range pkglist { if !pl.exist(pkg) { pl.add(pkg) } @@ -115,11 +115,11 @@ func (pl *PkgsLoader) LoadPackage(modroot string, path, name string) error { if currentPkg.Name == "" { // Load `gno.mod` information - gnoModPath := filepath.Join(currentPkg.Dir, "gno.mod") - gm, err := gnomod.ParseGnoMod(gnoModPath) + gm, err := gnomod.ParseDir(currentPkg.Dir) if err != nil { - return fmt.Errorf("unable to load %q: %w", gnoModPath, err) + return fmt.Errorf("unable to load %q: %w", currentPkg.Dir, err) } + gm.Sanitize() // Override package info with mod infos diff --git a/gno.land/pkg/integration/testdata/gc.txtar b/gno.land/pkg/integration/testdata/gc.txtar index ffbca5b84be..6dbac65f3c7 100644 --- a/gno.land/pkg/integration/testdata/gc.txtar +++ b/gno.land/pkg/integration/testdata/gc.txtar @@ -6,7 +6,7 @@ loadpkg gno.land/r/gc $WORK/r/gc gnoland start gnokey maketx call -pkgpath gno.land/r/gc -func Alloc -gas-fee 100000ugnot -gas-wanted 3000000 -simulate skip -broadcast -chainid tendermint_test test1 -stdout 'GAS USED: 507741' +stdout 'GAS USED: 508221' -- r/gc/gc.gno -- package gc diff --git a/gno.land/pkg/integration/testdata/gnokey_gasfee.txtar b/gno.land/pkg/integration/testdata/gnokey_gasfee.txtar index 3e4dd517d7f..c55ad7fc17c 100644 --- a/gno.land/pkg/integration/testdata/gnokey_gasfee.txtar +++ b/gno.land/pkg/integration/testdata/gnokey_gasfee.txtar @@ -11,8 +11,8 @@ stdout '"coins": "10000000000000ugnot"' # Tx add package -simulate only, estimate gas used and gas fee gnokey maketx addpkg -pkgdir $WORK/hello -pkgpath gno.land/r/hello -gas-wanted 2000000 -gas-fee 1000000ugnot -broadcast -chainid tendermint_test -simulate only test1 -stdout 'GAS USED: 186176' -stdout 'INFO: estimated gas usage: 186176, gas fee: 196ugnot, current gas price: 1000gas/1ugnot' +stdout 'GAS USED: 186496' +stdout 'INFO: estimated gas usage: 186496, gas fee: 196ugnot, current gas price: 1000gas/1ugnot' ## No fee was charged, and the sequence number did not change. gnokey query auth/accounts/$test1_user_addr diff --git a/gno.land/pkg/integration/testdata/simulate_gas.txtar b/gno.land/pkg/integration/testdata/simulate_gas.txtar index 2119e90424f..16c7c1ff5f3 100644 --- a/gno.land/pkg/integration/testdata/simulate_gas.txtar +++ b/gno.land/pkg/integration/testdata/simulate_gas.txtar @@ -6,11 +6,11 @@ gnoland start # simulate only gnokey maketx call -pkgpath gno.land/r/simulate -func Hello -gas-fee 1000000ugnot -gas-wanted 2000000 -broadcast -chainid=tendermint_test -simulate only test1 -stdout 'GAS USED: 104694' +stdout 'GAS USED: 105014' # simulate skip gnokey maketx call -pkgpath gno.land/r/simulate -func Hello -gas-fee 1000000ugnot -gas-wanted 2000000 -broadcast -chainid=tendermint_test -simulate skip test1 -stdout 'GAS USED: 104694' # same as simulate only +stdout 'GAS USED: 105014' # same as simulate only -- package/package.gno -- diff --git a/gno.land/pkg/sdk/vm/keeper.go b/gno.land/pkg/sdk/vm/keeper.go index bc6f561d55e..6721308bca6 100644 --- a/gno.land/pkg/sdk/vm/keeper.go +++ b/gno.land/pkg/sdk/vm/keeper.go @@ -175,11 +175,14 @@ func (vm *VMKeeper) LoadStdlib(ctx sdk.Context, stdlibDir string) { func loadStdlib(store gno.Store, stdlibDir string) { stdlibInitList := stdlibs.InitOrder() for _, lib := range stdlibInitList { - if lib == "testing" { - // XXX: testing is skipped for now while it uses testing-only packages + parts := strings.Split(lib, "/") + if len(parts) > 0 && parts[0] == "testing" { + // XXX: testing and sub testing packages are skipped for + // now while it uses testing-only packages // like fmt and encoding/json continue } + loadStdlibPackage(lib, stdlibDir, store) } } @@ -339,7 +342,7 @@ func (vm *VMKeeper) AddPackage(ctx sdk.Context, msg MsgAddPackage) (err error) { if creatorAcc == nil { return std.ErrUnknownAddress(fmt.Sprintf("account %s does not exist, it must receive coins to be created", creator)) } - if err := msg.Package.Validate(); err != nil { + if err := gno.ValidateMemPackage(msg.Package); err != nil { return ErrInvalidPkgPath(err.Error()) } if !strings.HasPrefix(pkgPath, chainDomain+"/") { @@ -359,8 +362,8 @@ func (vm *VMKeeper) AddPackage(ctx sdk.Context, msg MsgAddPackage) (err error) { } // Validate Gno syntax and type check. - format := true - if err := gno.TypeCheckMemPackage(memPkg, gnostore, format); err != nil { + _, _, err = gno.TypeCheckMemPackage(memPkg, gnostore, gno.ParseModeProduction) + if err != nil { return ErrTypeCheck(err) } @@ -584,13 +587,13 @@ func (vm *VMKeeper) Run(ctx sdk.Context, msg MsgRun) (res string, err error) { if callerAcc == nil { return "", std.ErrUnknownAddress(fmt.Sprintf("account %s does not exist, it must receive coins to be created", caller)) } - if err := msg.Package.Validate(); err != nil { + if err := gno.ValidateMemPackage(msg.Package); err != nil { return "", ErrInvalidPkgPath(err.Error()) } // Validate Gno syntax and type check. - format := false - if err = gno.TypeCheckMemPackage(memPkg, gnostore, format); err != nil { + _, _, err = gno.TypeCheckMemPackage(memPkg, gnostore, gno.ParseModeProduction) + if err != nil { return "", ErrTypeCheck(err) } diff --git a/gnovm/adr/pr4264_lint_transpile.md b/gnovm/adr/pr4264_lint_transpile.md new file mode 100644 index 00000000000..50b9f916079 --- /dev/null +++ b/gnovm/adr/pr4264_lint_transpile.md @@ -0,0 +1,49 @@ +The steps of Gno 0.0 --> Gno 0.9 transpiling. + 1. `GetMemPackage()`, `ReadMemPackage()`, .... + 2. `ParseGnoMod()`: parse gno.mod (if any) and compare versions. + 3. `GoParse*()`: parse Gno to Go AST with go/parser. + 4. `Prepare*()`: minimal Go AST mutations for Gno VM compat. + 5. `gno.MustParseFile()`: re-parse prepared AST + 6. `m.PreprocessFiles()`: normal Gno AST preprocessing. + 7. `FindXforms*()`: Gno AST static analaysis to produce line-based xforms. + 8. `Transpile*()` Part 1: re-key xforms from line-based to Go node-based. + 9. `Transpile*()` Part 2: main Go AST mutations for Gno upgrade. + 10. `mpkg.WriteTo()`: write mem package to disk. + +In `cmd/gno/tool_fix.go` each step is grouped into three stages for all dirs: + * Stage 1: (for all dirs) + 1. `gno.ReadMemPackage()` + 2. `gno.TypeCheckMemPackage()` > `ParseGnoMod() + 3. `gno.TypeCheckMemPackage()` > `GoParseMemPackage() + `gno.TypeCheckMemPackage()` > `g.cfg.Check() + 4. `PrepareGno0p9()` + 5. `sourceAndTestFileset()` > `gno.MustParseFile()` + 6. `tm.PreprocessFiles()` + 7. `gno.FindXformsGno0p9()` + * Stage 2: + 8. `gno.TranspileGno0p9()` Part 1 + 9. `gno.TranspileGno0p9()` Part 2 + * Stage 3: + 10. `mpkg.WriteTo()` + +In `cmd/gno/tool_lint.go` each step is grouped into two stages for all dirs, +and some steps are omited as compared to `tool_fix.go`: + * Stage 1: (for all dirs) + 1. `gno.ReadMemPackage()` + 2. `gno.TypeCheckMemPackage()` > `ParseGnoMod() + 3. `gno.TypeCheckMemPackage()` > `GoParseMemPackage() + `gno.TypeCheckMemPackage()` > `g.cfg.Check() + 4. `sourceAndTestFileset()` > `gno.MustParseFile()` + 5. `tm.PreprocessFiles()` + * Stage 2: + 6. `mpkg.WriteTo()` + +In `pkg/gnolang/gotypecheck.go`, `TypeCheck*()` diverges at step 4 and terminates: + 1. `mpkg` provided as argument + 2. `ParseGnoMod() + 3. `GoParseMemPackage() + 4. `gimp.cfg.Check(): Go type-checker + +In `pkg/test/imports.go`, `_processMemPackage()` after loading when .PreprocessOnly: + 3. `GoParseMemPackage()` + 4. `PrepareGno0p9()` diff --git a/gnovm/cmd/benchops/run.go b/gnovm/cmd/benchops/run.go index e63bbcd5e10..5f72bcb18e3 100644 --- a/gnovm/cmd/benchops/run.go +++ b/gnovm/cmd/benchops/run.go @@ -103,10 +103,10 @@ func addPackage(gstore gno.Store, dir string, pkgPath string) *gno.PackageValue }) defer m.Release() - memPkg := gno.MustReadMemPackage(dir, pkgPath) + mpkg := gno.MustReadMemPackage(dir, pkgPath) // pare the file, create pn, pv and save the values in m.store - _, pv := m.RunMemPackage(memPkg, true) + _, pv := m.RunMemPackage(mpkg, true) return pv } @@ -122,8 +122,8 @@ func loadStdlibs(bstore BenchStore) { return nil, nil } - memPkg := gno.MustReadMemPackage(stdlibPath, pkgPath) - if memPkg.IsEmpty() { + mpkg := gno.MustReadMemPackage(stdlibPath, pkgPath) + if mpkg.IsEmpty() { // no gno files are present, skip this package return nil, nil } @@ -135,7 +135,7 @@ func loadStdlibs(bstore BenchStore) { Store: newStore, }) defer m2.Release() - return m2.RunMemPackage(memPkg, true) + return m2.RunMemPackage(mpkg, true) } bstore.gnoStore.SetPackageGetter(getPackage) diff --git a/gnovm/cmd/gno/common.go b/gnovm/cmd/gno/common.go new file mode 100644 index 00000000000..5eeb02ef39a --- /dev/null +++ b/gnovm/cmd/gno/common.go @@ -0,0 +1,334 @@ +package main + +import ( + "bytes" + "fmt" + "go/scanner" + "go/types" + "io" + "os" + "path/filepath" + "regexp" + "strings" + + gno "github.com/gnolang/gno/gnovm/pkg/gnolang" + "github.com/gnolang/gno/gnovm/pkg/test" + "github.com/gnolang/gno/tm2/pkg/std" + "go.uber.org/multierr" +) + +type gnoCode string + +const ( + gnoUnknownError gnoCode = "gnoUnknownError" + gnoReadError gnoCode = "gnoReadError" + gnoImportError gnoCode = "gnoImportError" + gnoGnoModError gnoCode = "gnoGnoModError" + gnoPreprocessError gnoCode = "gnoPreprocessError" + gnoParserError gnoCode = "gnoParserError" + gnoTypeCheckError gnoCode = "gnoTypeCheckError" + + // TODO: add new gno codes here. +) + +type gnoIssue struct { + Code gnoCode + Msg string + Confidence float64 // 1 is 100% + Location string // file:line, or equivalent + // TODO: consider writing fix suggestions +} + +func (i gnoIssue) String() string { + // TODO: consider crafting a doc URL based on Code. + return fmt.Sprintf("%s: %s (code=%s)", i.Location, i.Msg, i.Code) +} + +// Gno parses and sorts mpkg files into the following filesets: +// - fset: all normal and _test.go files in package excluding `package xxx_test` +// integration *_test.gno files. +// - _tests: `package xxx_test` integration *_test.gno files. +// - ftests: *_filetest.gno file tests, each in their own file set. +func sourceAndTestFileset(mpkg *std.MemPackage) ( + all, fset *gno.FileSet, _tests *gno.FileSet, ftests []*gno.FileSet, +) { + all = &gno.FileSet{} + fset = &gno.FileSet{} + _tests = &gno.FileSet{} + for _, mfile := range mpkg.Files { + if !strings.HasSuffix(mfile.Name, ".gno") { + continue // Skip non-GNO files + } + + n := gno.MustParseFile(mfile.Name, mfile.Body) + if n == nil { + continue // Skip empty files + } + all.AddFiles(n) + if strings.HasSuffix(mfile.Name, "_filetest.gno") { + // A _filetest.gno is a package of its own. + ftset := &gno.FileSet{} + ftset.AddFiles(n) + ftests = append(ftests, ftset) + } else if strings.HasSuffix(mfile.Name, "_test.gno") && + strings.HasSuffix(string(n.PkgName), "_test") { + // A xxx_file integration test is a package of its own. + _tests.AddFiles(n) + } else { + // All normal package files and, + // _test.gno files that aren't xxx_test. + fset.AddFiles(n) + } + } + return +} + +func parsePkgPathDirective(body string, defaultPkgPath string) (string, error) { + dirs, err := test.ParseDirectives(bytes.NewReader([]byte(body))) + if err != nil { + return "", fmt.Errorf("error parsing directives: %w", err) + } + return dirs.FirstDefault(test.DirectivePkgPath, defaultPkgPath), nil +} + +type processedFileSet struct { + pn *gno.PackageNode + fset *gno.FileSet +} + +type processedPackage struct { + dir string // dirctory + mpkg *std.MemPackage // includes all files + normal processedFileSet // includes all prod (and some *_test.gno) files + _tests processedFileSet // includes all xxx_test *_test.gno integration files + ftests []processedFileSet // includes all *_filetest.gno filetest files +} + +func (ppkg *processedPackage) AddNormal(pn *gno.PackageNode, fset *gno.FileSet) { + if ppkg.normal != (processedFileSet{}) { + panic("normal processed fileset already set") + } + ppkg.normal = processedFileSet{pn, fset} +} + +func (ppkg *processedPackage) AddUnderscoreTests(pn *gno.PackageNode, fset *gno.FileSet) { + if ppkg._tests != (processedFileSet{}) { + panic("_test processed fileset already set") + } + ppkg._tests = processedFileSet{pn, fset} +} + +func (ppkg *processedPackage) AddFileTest(pn *gno.PackageNode, fset *gno.FileSet) { + if len(fset.Files) != 1 { + panic("filetests must have filesets of length 1") + } + fname := fset.Files[0].Name + if !strings.HasSuffix(string(fname), "_filetest.gno") { + panic(fmt.Sprintf("expected *_filetest.gno but got %q", fname)) + } + for _, ftest := range ppkg.ftests { + if ftest.fset.Files[0].Name == fname { + panic(fmt.Sprintf("fileetest with name %q already exists", fname)) + } + } + ppkg.ftests = append(ppkg.ftests, processedFileSet{pn, fset}) +} + +func (ppkg *processedPackage) GetFileTest(fname gno.Name) processedFileSet { + if !strings.HasSuffix(string(fname), "_filetest.gno") { + panic(fmt.Sprintf("expected *_filetest.gno but got %q", fname)) + } + for _, ftest := range ppkg.ftests { + if ftest.fset.Files[0].Name == fname { + return ftest + } + } + panic(fmt.Sprintf("processedFileSet for filetest %q not found", fname)) +} + +// reParseRecover is a regex designed to parse error details from a string. +// It extracts the file location, line number, and error message from a +// formatted error string. +// XXX: Ideally, error handling should encapsulate location details within a +// dedicated error type. +const ( + rePos = `(?:` + `\d+(?::\d+)?` + `)` // NOTE: allows the omission of columns, more relaxed than gno.Pos. + reSpan = `(?:` + rePos + `-` + rePos + `)` + rePosOrSpan = `(?:` + reSpan + `|` + rePos + `)` +) + +var reParseRecover = regexp.MustCompile(`^([^:]+):(` + rePosOrSpan + `):? *(.*)$`) + +func printError(w io.WriteCloser, dir, pkgPath string, err error) { + switch err := err.(type) { + case *gno.PreprocessError: + err2 := err.Unwrap() + // XXX probably no need for guessing, replace with exact issue. + fmt.Fprintln(w, guessIssueFromError( + dir, pkgPath, err2, gnoPreprocessError).String()) + case gno.ImportError: + // NOTE: gnovm/pkg/test.LoadImport will return a + // ImportNotFoundError with format ": unknown import path: + // ", while gimp.ImportFrom() doesn't know so + // returns a ImportNotFoundError with format "unknown import + // path: "; but Go .Check ends up returning a types.Error + // instead, as seen in the hack in the next clause. So + // test.LoadImport needs this and guessing isn't needed. + fmt.Fprintln(w, gnoIssue{ + Code: gnoImportError, + Msg: err.GetMsg(), + Confidence: 1, + Location: err.GetLocation(), + }) + case types.Error: + loc := err.Fset.Position(err.Pos).String() + loc = guessFilePathLoc(loc, pkgPath, dir) + code := gnoTypeCheckError + if strings.Contains(err.Msg, "(unknown import path \"") { + // NOTE: This is a bit of a hack. + // See gimp.ImportFrom() comment on ImportNotFoundError + // on why this is necessary, and how to make it less hacky. + code = gnoImportError + } + fmt.Fprintln(w, gnoIssue{ + Code: code, + Msg: err.Msg, + Confidence: 1, + Location: loc, + }) + case scanner.ErrorList: + for _, err := range err { + loc := err.Pos.String() + loc = guessFilePathLoc(loc, pkgPath, dir) + fmt.Fprintln(w, gnoIssue{ + Code: gnoParserError, + Msg: err.Msg, + Confidence: 1, + Location: loc, + }) + } + case scanner.Error: + loc := err.Pos.String() + loc = guessFilePathLoc(loc, pkgPath, dir) + fmt.Fprintln(w, gnoIssue{ + Code: gnoParserError, + Msg: err.Msg, + Confidence: 1, + Location: loc, + }) + default: // error type + errors := multierr.Errors(err) + if len(errors) == 1 { + fmt.Fprintln(w, guessIssueFromError( + dir, + pkgPath, + err, + gnoUnknownError, + ).String()) + return + } + for _, err := range errors { + printError(w, dir, pkgPath, err) + } + } +} + +func catchPanic(dir, pkgPath string, stderr io.WriteCloser, action func()) (didPanic bool) { + // If this gets out of hand (e.g. with nested catchPanic with need for + // selective catching) then pass in a bool instead. + if os.Getenv("DEBUG_PANIC") != "1" { + defer func() { + // Errors catched here mostly come from: + // gnovm/pkg/gnolang/preprocess.go + r := recover() + if r == nil { + return + } + didPanic = true + if err, ok := r.(error); ok { + printError(stderr, dir, pkgPath, err) + } else { + panic(r) + } + }() + } + + action() + return +} + +func guessIssueFromError(dir, pkgPath string, err error, code gnoCode) gnoIssue { + var issue gnoIssue + issue.Confidence = 1 + issue.Code = code + + parsedError := strings.TrimSpace(err.Error()) + matches := reParseRecover.FindStringSubmatch(parsedError) + + if len(matches) > 0 { + errPath := matches[1] + errLoc := matches[2] + errMsg := matches[3] + errPath = guessFilePathLoc(errPath, pkgPath, dir) + errPath = filepath.Clean(errPath) + issue.Location = errPath + ":" + errLoc + issue.Msg = strings.TrimSpace(errMsg) + } else { + issue.Location = fmt.Sprintf("%s:0", filepath.Clean(pkgPath)) + issue.Msg = err.Error() + } + return issue +} + +// Takes a location string `s` and tries to convert to a path based on `dir`. +// NOTE: s may not be in pkgPath (e.g. for type-check errors on imports). +// Do not make a transformation unless the answer is highly unlikely to be incorrect. +// Otherwise debugging may be painful. Better to return s as is. +func guessFilePathLoc(s, pkgPath, dir string) string { + if !dirExists(dir) { + panic(fmt.Sprintf("dir %q does not exist", dir)) + } + s = filepath.Clean(s) + pkgPath = filepath.Clean(pkgPath) + dir = filepath.Clean(dir) + // s already in dir. + if strings.HasPrefix(s, dir) { + return s + } + // s in pkgPath. + if strings.HasPrefix(s, pkgPath+"/") { + fname := s[len(pkgPath+"/"):] + fpath := filepath.Join(dir, fname) + return fpath + } + // "GNOROOT". + if strings.HasSuffix(dir, pkgPath) { + gnoRoot := dir[len(dir)-len(pkgPath):] + // s is maybe / + if strings.Contains(s, "/") { + fpath := gnoRoot + s + if fileExists(fpath) { + return fpath + } + } + } + // s is a filename. + if !strings.Contains(s, "/") { + fpath := filepath.Join(dir, s) + if fileExists(fpath) { + return fpath + } + } + // dunno. + return s +} + +func dirExists(dir string) bool { + info, err := os.Stat(dir) + return !os.IsNotExist(err) && info.IsDir() +} + +func fileExists(fpath string) bool { + info, err := os.Stat(fpath) + return !os.IsNotExist(err) && !info.IsDir() +} diff --git a/gnovm/cmd/gno/main.go b/gnovm/cmd/gno/main.go index ae4559eb080..90c9540d4e4 100644 --- a/gnovm/cmd/gno/main.go +++ b/gnovm/cmd/gno/main.go @@ -28,7 +28,7 @@ func newGnocliCmd(io commands.IO) *commands.Command { newCleanCmd(io), newDocCmd(io), newEnvCmd(io), - // fix + newFixCmd(io), newFmtCmd(io), // generate // get diff --git a/gnovm/cmd/gno/main_test.go b/gnovm/cmd/gno/main_test.go index 2ea3e31f977..73e9bb7abf7 100644 --- a/gnovm/cmd/gno/main_test.go +++ b/gnovm/cmd/gno/main_test.go @@ -14,6 +14,12 @@ import ( "github.com/stretchr/testify/require" ) +const div = "--------------------------------------------------------------------------------\n" + +func divHeader(label string) string { + return label + " " + div[len(label)+1:] +} + func TestMain_Gno(t *testing.T) { tc := []testMainCase{ {args: []string{""}, errShouldBe: "flag: help requested"}, @@ -69,7 +75,7 @@ func testMainCaseRun(t *testing.T, tc []testMainCase) { if stdoutShouldBeEmpty { require.Empty(t, mockOut.String(), "stdout should be empty") } else { - t.Log("stdout", mockOut.String()) + t.Log(divHeader("stdout"), mockOut.String()) if test.stdoutShouldContain != "" { require.Contains(t, mockOut.String(), test.stdoutShouldContain, "stdout should contain") } @@ -81,7 +87,7 @@ func testMainCaseRun(t *testing.T, tc []testMainCase) { if stderrShouldBeEmpty { require.Empty(t, mockErr.String(), "stderr should be empty") } else { - t.Log("stderr", mockErr.String()) + t.Log(divHeader("stderr"), mockErr.String()) if test.stderrShouldContain != "" { require.Contains(t, mockErr.String(), test.stderrShouldContain, "stderr should contain") } @@ -94,7 +100,7 @@ func testMainCaseRun(t *testing.T, tc []testMainCase) { defer func() { if r := recover(); r != nil { output := fmt.Sprintf("%v", r) - t.Log("recover", output) + t.Log(divHeader("recover"), output) require.False(t, recoverShouldBeEmpty, "should not panic") require.True(t, errShouldBeEmpty, "should not return an error") if test.recoverShouldContain != "" { diff --git a/gnovm/cmd/gno/mod.go b/gnovm/cmd/gno/mod.go index d007300576e..b1747f27417 100644 --- a/gnovm/cmd/gno/mod.go +++ b/gnovm/cmd/gno/mod.go @@ -10,6 +10,7 @@ import ( "github.com/gnolang/gno/gnovm/cmd/gno/internal/pkgdownload" "github.com/gnolang/gno/gnovm/cmd/gno/internal/pkgdownload/rpcpkgfetcher" + gno "github.com/gnolang/gno/gnovm/pkg/gnolang" "github.com/gnolang/gno/gnovm/pkg/gnomod" "github.com/gnolang/gno/gnovm/pkg/packages" "github.com/gnolang/gno/tm2/pkg/commands" @@ -179,7 +180,7 @@ func execModGraph(cfg *modGraphCfg, args []string, io commands.IO) error { stdout := io.Out() - pkgs, err := gnomod.ListPkgs(args[0]) + pkgs, err := gno.ReadPkgListFromDir(args[0]) if err != nil { return err } @@ -223,7 +224,7 @@ func execModDownload(cfg *modDownloadCfg, args []string, io commands.IO) error { } // parse gno.mod - gnoMod, err := gnomod.Parse(modPath, data) + gnoMod, err := gnomod.ParseBytes(modPath, data) if err != nil { return fmt.Errorf("parse: %w", err) } @@ -307,7 +308,7 @@ func execModTidy(cfg *modTidyCfg, args []string, io commands.IO) error { } if cfg.recursive { - pkgs, err := gnomod.ListPkgs(wd) + pkgs, err := gno.ReadPkgListFromDir(wd) if err != nil { return err } @@ -324,8 +325,8 @@ func execModTidy(cfg *modTidyCfg, args []string, io commands.IO) error { } func modTidyOnce(cfg *modTidyCfg, wd, pkgdir string, io commands.IO) error { - fname := filepath.Join(pkgdir, "gno.mod") - relpath, err := filepath.Rel(wd, fname) + fpath := filepath.Join(pkgdir, "gno.mod") + relpath, err := filepath.Rel(wd, fpath) if err != nil { return err } @@ -333,12 +334,12 @@ func modTidyOnce(cfg *modTidyCfg, wd, pkgdir string, io commands.IO) error { io.ErrPrintfln("%s", relpath) } - gm, err := gnomod.ParseGnoMod(fname) + gm, err := gnomod.ParseFilepath(fpath) if err != nil { return err } - gm.Write(fname) + gm.WriteFile(fpath) return nil } @@ -351,8 +352,8 @@ func execModWhy(args []string, io commands.IO) error { if err != nil { return err } - fname := filepath.Join(wd, "gno.mod") - gm, err := gnomod.ParseGnoMod(fname) + fpath := filepath.Join(wd, "gno.mod") + gm, err := gnomod.ParseFilepath(fpath) if err != nil { return err } diff --git a/gnovm/cmd/gno/run.go b/gnovm/cmd/gno/run.go index 45b205bee52..ebda752d649 100644 --- a/gnovm/cmd/gno/run.go +++ b/gnovm/cmd/gno/run.go @@ -17,7 +17,7 @@ import ( "github.com/gnolang/gno/tm2/pkg/std" ) -type runCfg struct { +type runCmd struct { verbose bool rootDir string expr string @@ -25,8 +25,8 @@ type runCfg struct { debugAddr string } -func newRunCmd(io commands.IO) *commands.Command { - cfg := &runCfg{} +func newRunCmd(cio commands.IO) *commands.Command { + cfg := &runCmd{} return commands.NewCommand( commands.Metadata{ @@ -36,12 +36,12 @@ func newRunCmd(io commands.IO) *commands.Command { }, cfg, func(_ context.Context, args []string) error { - return execRun(cfg, args, io) + return execRun(cfg, args, cio) }, ) } -func (c *runCfg) RegisterFlags(fs *flag.FlagSet) { +func (c *runCmd) RegisterFlags(fs *flag.FlagSet) { fs.BoolVar( &c.verbose, "v", @@ -78,7 +78,7 @@ func (c *runCfg) RegisterFlags(fs *flag.FlagSet) { ) } -func execRun(cfg *runCfg, args []string, io commands.IO) error { +func execRun(cfg *runCmd, args []string, cio commands.IO) error { if len(args) == 0 { return flag.ErrHelp } @@ -87,9 +87,9 @@ func execRun(cfg *runCfg, args []string, io commands.IO) error { cfg.rootDir = gnoenv.RootDir() } - stdin := io.In() - stdout := io.Out() - stderr := io.Err() + stdin := cio.In() + stdout := cio.Out() + stderr := cio.Err() // init store and machine output := test.OutputWithError(stdout, stderr) @@ -136,12 +136,12 @@ func execRun(cfg *runCfg, args []string, io commands.IO) error { return runExpr(m, cfg.expr) } -func parseFiles(fnames []string, stderr io.WriteCloser) ([]*gno.FileNode, error) { - files := make([]*gno.FileNode, 0, len(fnames)) - var hasError bool - for _, fname := range fnames { - if s, err := os.Stat(fname); err == nil && s.IsDir() { - subFns, err := listNonTestFiles(fname) +func parseFiles(fpaths []string, stderr io.WriteCloser) ([]*gno.FileNode, error) { + files := make([]*gno.FileNode, 0, len(fpaths)) + var didPanic bool + for _, fpath := range fpaths { + if s, err := os.Stat(fpath); err == nil && s.IsDir() { + subFns, err := listNonTestFiles(fpath) if err != nil { return nil, err } @@ -157,12 +157,13 @@ func parseFiles(fnames []string, stderr io.WriteCloser) ([]*gno.FileNode, error) return nil, err } - hasError = catchRuntimeError(fname, fname, stderr, func() { - files = append(files, gno.MustReadFile(fname)) + dir, fname := filepath.Split(fpath) + didPanic = catchPanic(dir, fname, stderr, func() { + files = append(files, gno.MustReadFile(fpath)) }) } - if hasError { + if didPanic { return nil, commands.ExitCodeError(1) } return files, nil diff --git a/gnovm/cmd/gno/run_test.go b/gnovm/cmd/gno/run_test.go index 711420ff1d5..5ef7cc66807 100644 --- a/gnovm/cmd/gno/run_test.go +++ b/gnovm/cmd/gno/run_test.go @@ -90,10 +90,10 @@ func TestRunApp(t *testing.T) { args: []string{"run", "../../tests/integ/several-files-multiple-errors/"}, stderrShouldContain: func() string { lines := []string{ - "../../tests/integ/several-files-multiple-errors/file2.gno:3:5: expected 'IDENT', found '{' (code=2)", - "../../tests/integ/several-files-multiple-errors/file2.gno:5:1: expected type, found '}' (code=2)", - "../../tests/integ/several-files-multiple-errors/main.gno:5:5: expected ';', found example (code=2)", - "../../tests/integ/several-files-multiple-errors/main.gno:6:2: expected '}', found 'EOF' (code=2)", + "../../tests/integ/several-files-multiple-errors/file2.gno:3:5: expected 'IDENT', found '{' (code=gnoParserError)", + "../../tests/integ/several-files-multiple-errors/file2.gno:5:1: expected type, found '}' (code=gnoParserError)", + "../../tests/integ/several-files-multiple-errors/main.gno:5:5: expected ';', found example (code=gnoParserError)", + "../../tests/integ/several-files-multiple-errors/main.gno:6:2: expected '}', found 'EOF' (code=gnoParserError)", } return strings.Join(lines, "\n") + "\n" }(), diff --git a/gnovm/cmd/gno/test.go b/gnovm/cmd/gno/test.go index 0d9a642cd53..970cbf2c5c4 100644 --- a/gnovm/cmd/gno/test.go +++ b/gnovm/cmd/gno/test.go @@ -17,7 +17,7 @@ import ( "github.com/gnolang/gno/tm2/pkg/commands" ) -type testCfg struct { +type testCmd struct { verbose bool failfast bool rootDir string @@ -31,7 +31,7 @@ type testCfg struct { } func newTestCmd(io commands.IO) *commands.Command { - cfg := &testCfg{} + cmd := &testCmd{} return commands.NewCommand( commands.Metadata{ @@ -89,14 +89,14 @@ the execution of the tests. This makes testing faster, but means that the initialization of imported pure packages cannot be checked in filetests. `, }, - cfg, + cmd, func(_ context.Context, args []string) error { - return execTest(cfg, args, io) + return execTest(cmd, args, io) }, ) } -func (c *testCfg) RegisterFlags(fs *flag.FlagSet) { +func (c *testCmd) RegisterFlags(fs *flag.FlagSet) { fs.BoolVar( &c.verbose, "v", @@ -168,15 +168,15 @@ func (c *testCfg) RegisterFlags(fs *flag.FlagSet) { ) } -func execTest(cfg *testCfg, args []string, io commands.IO) error { +func execTest(cmd *testCmd, args []string, io commands.IO) error { // Default to current directory if no args provided if len(args) == 0 { args = []string{"."} } - // guess opts.RootDir - if cfg.rootDir == "" { - cfg.rootDir = gnoenv.RootDir() + // Guess opts.RootDir. + if cmd.rootDir == "" { + cmd.rootDir = gnoenv.RootDir() } paths, err := targetsFromPatterns(args) @@ -189,10 +189,10 @@ func execTest(cfg *testCfg, args []string, io commands.IO) error { return nil } - if cfg.timeout > 0 { + if cmd.timeout > 0 { go func() { - time.Sleep(cfg.timeout) - panic("test timed out after " + cfg.timeout.String()) + time.Sleep(cmd.timeout) + panic("test timed out after " + cmd.timeout.String()) }() } @@ -203,17 +203,17 @@ func execTest(cfg *testCfg, args []string, io commands.IO) error { // Set up options to run tests. stdout := goio.Discard - if cfg.verbose { + if cmd.verbose { stdout = io.Out() } - opts := test.NewTestOptions(cfg.rootDir, stdout, io.Err()) - opts.RunFlag = cfg.run - opts.Sync = cfg.updateGoldenTests - opts.Verbose = cfg.verbose - opts.Metrics = cfg.printRuntimeMetrics - opts.Events = cfg.printEvents - opts.Debug = cfg.debug - opts.FailfastFlag = cfg.failfast + opts := test.NewTestOptions(cmd.rootDir, stdout, io.Err()) + opts.RunFlag = cmd.run + opts.Sync = cmd.updateGoldenTests + opts.Verbose = cmd.verbose + opts.Metrics = cmd.printRuntimeMetrics + opts.Events = cmd.printEvents + opts.Debug = cmd.debug + opts.FailfastFlag = cmd.failfast buildErrCount := 0 testErrCount := 0 @@ -227,44 +227,48 @@ func execTest(cfg *testCfg, args []string, io commands.IO) error { io.ErrPrintfln("? %s \t[no test files]", pkg.Dir) continue } - // Determine gnoPkgPath by reading gno.mod - modfile, _ := gnomod.ParseAt(pkg.Dir) - gnoPkgPath, ok := determinePkgPath(modfile, pkg.Dir, cfg.rootDir) + + // Determine pkgPath by reading gno.mod from disk. + // TODO: Have ReadMemPackage handle it. + modfile, _ := gnomod.ParseDir(pkg.Dir) + pkgPath, ok := determinePkgPath(modfile, pkg.Dir, cmd.rootDir) if !ok { - io.ErrPrintfln("--- WARNING: unable to read package path from gno.mod or gno root directory; try creating a gno.mod file") + io.ErrPrintfln("WARNING: unable to read package path from gno.mod or gno root directory; try creating a gno.mod file") } - memPkg := gno.MustReadMemPackage(pkg.Dir, gnoPkgPath) - - var hasError bool + // Read MemPackage. + mpkg := gno.MustReadMemPackage(pkg.Dir, pkgPath) + // Lint/typecheck/format. + // (gno.mod will be read again). + var didPanic, didError bool startedAt := time.Now() - runtimeError := catchRuntimeError(pkg.Dir, gnoPkgPath, io.Err(), func() { + didPanic = catchPanic(pkg.Dir, pkgPath, io.Err(), func() { if modfile == nil || !modfile.Draft { - foundErr, lintErr := lintTypeCheck(io, pkg.Dir, memPkg, opts.TestStore) - if lintErr != nil { - io.ErrPrintln(lintErr) - hasError = true - } else if foundErr { - hasError = true + if _, _, errs := lintTypeCheck(io, pkg.Dir, mpkg, opts.TestStore); errs != nil { + didError = true + // already printed in lintTypeCheck. + // io.ErrPrintln(errs) + return } - } else if cfg.verbose { - io.ErrPrintfln("%s: module is draft, skipping type check", gnoPkgPath) + } else if cmd.verbose { + io.ErrPrintfln("%s: module is draft, skipping type check", pkgPath) + } + errs := test.Test(mpkg, pkg.Dir, opts) + if errs != nil { + didError = true + io.ErrPrintln(errs) + return } - err = test.Test(memPkg, pkg.Dir, opts) }) - hasError = hasError || runtimeError + // Print status with duration. duration := time.Since(startedAt) dstr := fmtDuration(duration) - - if hasError || err != nil { - if err != nil { - io.ErrPrintfln("%s: test pkg: %v", pkg.Dir, err) - } + if didPanic || didError { io.ErrPrintfln("FAIL %s \t%s", pkg.Dir, dstr) testErrCount++ - if cfg.failfast { + if cmd.failfast { return fail() } } else { @@ -282,12 +286,11 @@ func determinePkgPath(modfile *gnomod.File, dir, rootDir string) (string, bool) if modfile != nil { return modfile.Module.Mod.Path, true } - - if path := pkgPathFromRootDir(dir, rootDir); path != "" { - return path, true + if pkgPath := pkgPathFromRootDir(dir, rootDir); pkgPath != "" { + return pkgPath, true } // unable to read pkgPath from gno.mod, use a deterministic path. - return "gno.land/r/txtar", false // XXX: gno.land hardcoded for convenience. + return "gno.land/r/test", false // XXX: gno.land hardcoded for convenience. } // attempts to determine the full gno pkg path by analyzing the directory. diff --git a/gnovm/cmd/gno/testdata/lint/bad_import.txtar b/gnovm/cmd/gno/testdata/lint/bad_import.txtar index e2c0431443c..f8214ba8f1f 100644 --- a/gnovm/cmd/gno/testdata/lint/bad_import.txtar +++ b/gnovm/cmd/gno/testdata/lint/bad_import.txtar @@ -19,4 +19,4 @@ module gno.land/p/test -- stdout.golden -- -- stderr.golden -- -bad_file.gno:3:8: unknown import path python (code=2) +bad_file.gno:3:8: unknown import path "python" (code=gnoImportError) diff --git a/gnovm/cmd/gno/testdata/lint/file_error.txtar b/gnovm/cmd/gno/testdata/lint/file_error.txtar index 4fa50c6da81..0ab3b6897c6 100644 --- a/gnovm/cmd/gno/testdata/lint/file_error.txtar +++ b/gnovm/cmd/gno/testdata/lint/file_error.txtar @@ -20,4 +20,5 @@ module gno.land/p/test -- stdout.golden -- -- stderr.golden -- -i_have_error_test.gno:6:7: name undefined_variable not declared (code=2) +i_have_error_test.gno:6:7: undefined: undefined_variable (code=gnoTypeCheckError) +i_have_error_test.gno:6:2: declared and not used: i (code=gnoTypeCheckError) diff --git a/gnovm/cmd/gno/testdata/lint/no_error.txtar b/gnovm/cmd/gno/testdata/lint/no_error.txtar index 5dd3b164952..5e3e6db8a39 100644 --- a/gnovm/cmd/gno/testdata/lint/no_error.txtar +++ b/gnovm/cmd/gno/testdata/lint/no_error.txtar @@ -1,6 +1,6 @@ # testing simple gno lint command with any error -gno lint ./good_file.gno +gno lint . cmp stdout stdout.golden cmp stdout stderr.golden @@ -15,5 +15,6 @@ func main() { -- gno.mod -- module gno.land/p/demo/test +gno 0.9 -- stdout.golden -- -- stderr.golden -- diff --git a/gnovm/cmd/gno/testdata/lint/no_gnomod.txtar b/gnovm/cmd/gno/testdata/lint/no_gnomod.txtar index b5a046a7095..51462ad2b4b 100644 --- a/gnovm/cmd/gno/testdata/lint/no_gnomod.txtar +++ b/gnovm/cmd/gno/testdata/lint/no_gnomod.txtar @@ -1,6 +1,6 @@ # gno lint: no gnomod -! gno lint . +gno lint . cmp stdout stdout.golden cmp stderr stderr.golden @@ -14,4 +14,4 @@ func main() { -- stdout.golden -- -- stderr.golden -- -./.: parsing gno.mod at ./.: gno.mod file not found in current or any parent directory (code=1) +auto-generated "gno.mod" diff --git a/gnovm/cmd/gno/testdata/lint/not_declared.txtar b/gnovm/cmd/gno/testdata/lint/not_declared.txtar index ac56b27e0df..90682638b26 100644 --- a/gnovm/cmd/gno/testdata/lint/not_declared.txtar +++ b/gnovm/cmd/gno/testdata/lint/not_declared.txtar @@ -18,5 +18,4 @@ module gno.land/p/demo/hello -- stdout.golden -- -- stderr.golden -- -bad_file.gno:4:2: undefined: hello (code=4) -bad_file.gno:4:2: name hello not declared (code=2) +bad_file.gno:4:2: undefined: hello (code=gnoTypeCheckError) diff --git a/gnovm/cmd/gno/testdata/test/flag_run.txtar b/gnovm/cmd/gno/testdata/test/flag_run.txtar index 31cc10cf3a3..629a6479026 100644 --- a/gnovm/cmd/gno/testdata/test/flag_run.txtar +++ b/gnovm/cmd/gno/testdata/test/flag_run.txtar @@ -85,7 +85,6 @@ package run package run import ( - "fmt" "testing" ) diff --git a/gnovm/cmd/gno/testdata/test/lint_error.txtar b/gnovm/cmd/gno/testdata/test/lint_error.txtar index ff6bf3d6018..5b2af40cb61 100644 --- a/gnovm/cmd/gno/testdata/test/lint_error.txtar +++ b/gnovm/cmd/gno/testdata/test/lint_error.txtar @@ -1,9 +1,9 @@ -# Test with a valid _test.gno file +# Test with a valid _test.gno file with invalid file. ! gno test -v . -stdout 'hello123' -stderr 'PASS: TestAlwaysValid' +#stdout 'hello123' +#stderr 'PASS: TestAlwaysValid' stderr 'declared and not used: x' stderr 'FAIL' diff --git a/gnovm/cmd/gno/testdata/test/lint_noerror.txtar b/gnovm/cmd/gno/testdata/test/lint_noerror.txtar new file mode 100644 index 00000000000..84d76855ee0 --- /dev/null +++ b/gnovm/cmd/gno/testdata/test/lint_noerror.txtar @@ -0,0 +1,22 @@ +# Test with a valid _test.gno file. + +gno test -v . + +stdout 'hello123' +stderr 'PASS: TestAlwaysValid' + +-- valid.gno -- +package valid + +func fn() { + println("hello123") +} + +-- valid_test.gno -- +package valid + +import "testing" + +func TestAlwaysValid(t *testing.T) { + fn() +} diff --git a/gnovm/cmd/gno/testdata/test/no_path_flag_run.txtar b/gnovm/cmd/gno/testdata/test/no_path_flag_run.txtar index 3db2a4c9295..4c609a7b03d 100644 --- a/gnovm/cmd/gno/testdata/test/no_path_flag_run.txtar +++ b/gnovm/cmd/gno/testdata/test/no_path_flag_run.txtar @@ -83,7 +83,6 @@ package run package run import ( - "fmt" "testing" ) @@ -96,4 +95,4 @@ func TestRun(t *testing.T) { for _, tc := range cases { t.Run(tc, func(t *testing.T) {}) } -} \ No newline at end of file +} diff --git a/gnovm/cmd/gno/testdata/test/unknown_package.txtar b/gnovm/cmd/gno/testdata/test/unknown_package.txtar index 0611d3440a4..de70adf426f 100644 --- a/gnovm/cmd/gno/testdata/test/unknown_package.txtar +++ b/gnovm/cmd/gno/testdata/test/unknown_package.txtar @@ -3,7 +3,8 @@ ! gno test -v . ! stdout .+ -stderr 'contract.gno:3:8: unknown import path foobarbaz' +# XXX catch and convert to gnoImportError +stderr 'contract.gno:3:8: could not import foobarbaz \(unknown import path "foobarbaz"\) \(code=gnoImportError\)' -- contract.gno -- package contract diff --git a/gnovm/cmd/gno/tool_fix.go b/gnovm/cmd/gno/tool_fix.go new file mode 100644 index 00000000000..5affa569d33 --- /dev/null +++ b/gnovm/cmd/gno/tool_fix.go @@ -0,0 +1,449 @@ +package main + +import ( + "bytes" + "context" + "errors" + "flag" + "fmt" + goio "io" + "io/fs" + "os" + "path" + "path/filepath" + "slices" + + "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/test" + "github.com/gnolang/gno/tm2/pkg/commands" + "github.com/gnolang/gno/tm2/pkg/std" +) + +/* +Translate Interrealm Spec 2 to Interrealm Spec 3 (Gno 0.9) + + - Interrealm Spec 1: Original; every realm function is (automatically) + a crossing function. This was working for our examples and was + conceptually simple, but several problems were identified late in + development; + + 1. p package code copied over to r realms would behave differently + with respect to std.CurrentRealm() and std.PreviousRealm(). It will + become typical after launch that p code gets copied to r code for + cutstom patchces; and potential p code will first to be tested in + more mutable r realms. + + 2. a reentrancy issue exists where r realm's calls to some variable + function/method `var A func(...)...` are usually of functions + declared in external realms (such as callback functions expected to + be provided by the external realm) but instead ends up being a + function declared in the the same r realm, an expected realm + boundary isn't there, and may lead to exploits. + + - Interrealm Spec 2: With explicit cross(fn)(...) and crossing() + declarations. The previous problems were solved by explicit crossing() + declarations in realm functions (solves 1), and explicit + cross(fn)(...) calls (solves 2 for the most part). But more problems + were identified after most of the migration was done for examples from + spec 1 to spec 2: + + 3. a reentrancy issue where if calls to r realm's function/method + A() are usually expected to be done by external realms (creating a + realm boundary), but the external caller does things to get the r + realm to call its own A(), the expected realm boundary isn't created + and may lead to exploits. + + 3.A. As a more concrete example of problem 3, when a realm takes as + parameter a callback function `cb func(...)...` that isn't expected + to be a crossing function and thus not explicitly crossed into. An + external user or realm can then craft a function literal expression + that calls the aforementioned realm's crossing functions without an + explicit cross(fn)(...) call, thereby again dissolving a realm + function boundary where one should be. + + 4. Users didn't like the cross(fn)(...) syntax. + + - Interrealm Spec 3: With @cross decorator and `cur realm` first + argument type. Instead of declaring a crossing-function with + `crossing()` as the first statement the @cross decorator is used for + package/file level function/methods declarations. Function literals + can likewise be declared crossing by being wrapped like + cross(func(...)...{}). When calling from within the same realm + (without creating a realm boundary), the `cur` value is passed through + to the called function's via its first argument; but when a realm + boundary is intended, `nil` is passed in instead. This resolves + problem 3.A because a non-crossing function literal would not be + declared with the `cur realm` first argument, and thus a non-crossing + call of the same realm's crossing function would not be syntactically + possible. + +---------------------------------------- + +Also refer to the [Lint and Transpile ADR](./adr/pr4264_lint_transpile.md). +*/ + +type fixCmd struct { + verbose bool + rootDir string + filetestsOnly bool + // min_confidence: minimum confidence of a problem to print it + // (default 0.8) auto-fix: apply suggested fixes automatically. +} + +func newFixCmd(cio commands.IO) *commands.Command { + cmd := &fixCmd{} + + return commands.NewCommand( + commands.Metadata{ + Name: "fix", + ShortUsage: "fix [flags] [...]", + ShortHelp: "runs the fixer for the specified packages", + }, + cmd, + func(_ context.Context, args []string) error { + return execFix(cmd, args, cio) + }, + ) +} + +func (c *fixCmd) RegisterFlags(fs *flag.FlagSet) { + rootdir := gnoenv.RootDir() + + fs.BoolVar(&c.verbose, "v", false, "verbose output when fixning") + fs.StringVar(&c.rootDir, "root-dir", rootdir, "clone location of github.com/gnolang/gno (gno tries to guess it)") + fs.BoolVar(&c.filetestsOnly, "only-filetests", false, "dir only contains filetests. not recursive.") +} + +func execFix(cmd *fixCmd, args []string, cio commands.IO) error { + // Show a help message by default. + if len(args) == 0 { + return flag.ErrHelp + } + + // Guess cmd.RootDir. + if cmd.rootDir == "" { + cmd.rootDir = gnoenv.RootDir() + } + + var dirs []string + var hasError bool + var err error + + if cmd.filetestsOnly { + dirs = slices.Clone(args) + } else { + dirs, err = gnoPackagesFromArgsRecursively(args) + if err != nil { + return fmt.Errorf("list packages from args: %w", err) + } + } + + bs, ts := test.StoreWithOptions( + cmd.rootDir, goio.Discard, + test.StoreOptions{PreprocessOnly: true, FixFrom: gno.GnoVerMissing}, + ) + ppkgs := map[string]processedPackage{} + + if cmd.verbose { + cio.ErrPrintfln("flinting directories: %v", dirs) + } + //---------------------------------------- + // FIX STAGE 1: Type-check and lint. + for _, dir := range dirs { + if cmd.verbose { + cio.ErrPrintfln("fixing %q", dir) + } + + // Only supports directories. + // You should fix all directories at once to avoid dependency issues. + info, err := os.Stat(dir) + if err == nil && !info.IsDir() { + dir = filepath.Dir(dir) + } + + // Read and parse gno.mod directly. + fpath := path.Join(dir, "gno.mod") + mod, err := gnomod.ParseFilepath(fpath) + if errors.Is(err, fs.ErrNotExist) { + // Make a temporary gno.mod (but don't write it yet) + modstr := gno.GenGnoModMissing("gno.land/r/xxx_myrealm_xxx/xxx_fixme_xxx") + mod, err = gnomod.ParseBytes("gno.mod", []byte(modstr)) + if err != nil { + panic(fmt.Errorf("unexpected panic parsing default gno.mod bytes: %w", err)) + } + } else { + switch mod.GetGno() { + case gno.GnoVerLatest: + if cmd.verbose { + cio.ErrPrintfln("%s: module is up to date, skipping fix", dir) + } + continue // nothing to do. + case gno.GnoVerMissing: + // good, fix it. + default: + cio.ErrPrintfln("%s: unrecognized gno.mod version %q, skipping fix", dir, mod.GetGno()) + continue // skip it. + } + } + if err != nil { + issue := gnoIssue{ + Code: gnoGnoModError, + Confidence: 1, // ?? + Location: fpath, + Msg: err.Error(), + } + cio.ErrPrintln(issue) + hasError = true + return commands.ExitCodeError(1) + } + if mod.Draft { + cio.ErrPrintfln("%s: module is draft, skipping fix", dir) + continue + } + + // See adr/pr4264_fix_transpile.md + // FIX STEP 1: ReadMemPackage() + // Read MemPackage with pkgPath. + pkgPath, _ := determinePkgPath(mod, dir, cmd.rootDir) + mpkg, err := gno.ReadMemPackage(dir, pkgPath) + if err != nil { + printError(cio.Err(), dir, pkgPath, err) + hasError = true + continue + } + + // Filter out filetests that fail type-check. + if cmd.filetestsOnly { + filterInvalidFiletests(cio, mpkg) + } + + // Perform imports using the parent store. + if err := test.LoadImports(ts, mpkg); err != nil { + printError(cio.Err(), dir, pkgPath, err) + hasError = true + continue + } + + // Handle runtime errors + didPanic := catchPanic(dir, pkgPath, cio.Err(), func() { + // Wrap in cache wrap so execution of the fixer + // doesn't impact other packages. + cw := bs.CacheWrap() + gs := ts.BeginTransaction(cw, cw, nil) + + // These are Go types. + ppkg := processedPackage{mpkg: mpkg, dir: dir} + // Run type checking + // FIX STEP 2: ParseGnoMod() + // FIX STEP 3: GoParse*() + // + // lintTypeCheck(mpkg) --> + // TypeCheckMemPackage(mpkg) --> + // imp.typeCheckMemPackage(mpkg) + // ParseGnoMod(mpkg); + // GoParseMemPackage(mpkg); + // g.cmd.Check(); + + _, tfiles, errs := lintTypeCheck(cio, dir, mpkg, gs) + if errs != nil { + // cio.ErrPrintln(errs) already printed. + hasError = true + return + } + + // FIX STEP 4: Prepare*() + // Construct machine for preprocessing. + tm := test.Machine(gs, goio.Discard, pkgPath, false) + defer tm.Release() + + // Prepare Go AST for preprocessing. + allgofs := append(tfiles.SourceFiles, tfiles.TestPackageFiles...) + allgofs = append(allgofs, tfiles.TestFiles...) + errs = gno.PrepareGno0p9(tfiles.FileSet, allgofs, mpkg) + if errs != nil { + cio.ErrPrintln(errs) + hasError = true + return // Prepare must succeed. + } + + // FIX STEP 5: re-parse + // Gno parse source fileset and test filesets. + _, fset, _tests, ftests := sourceAndTestFileset(mpkg) // , cmd.filetestsOnly) + + { + // FIX STEP 6: PreprocessFiles() + // Preprocess fset files (w/ some _test.gno). + cw := bs.CacheWrap() + gs := ts.BeginTransaction(cw, cw, nil) + tm.Store = gs + pn, _ := tm.PreprocessFiles( + mpkg.Name, mpkg.Path, fset, false, false, gno.GnoVerMissing) + ppkg.AddNormal(pn, fset) + + // FIX STEP 7: FindXforms(): + // FindXforms for all files if outdated. + // Use the preprocessor to collect the + // transformations needed to be done. + // They are collected in + // pn.GetAttribute("XREALMFORM") + for _, fn := range fset.Files { + gno.FindXformsGno0p9(gs, pn, fn) + } + } + { + // FIX STEP 6: PreprocessFiles() + // Preprocess xxx_test files (some _test.gno). + cw := bs.CacheWrap() + gs := ts.BeginTransaction(cw, cw, nil) + tm.Store = gs + pn, _ := tm.PreprocessFiles( + mpkg.Name+"_test", mpkg.Path+"_test", _tests, false, false, gno.GnoVerMissing) + ppkg.AddUnderscoreTests(pn, _tests) + + // FIX STEP 7: FindXforms(): + // FindXforms for all files if outdated. + // Use the preprocessor to collect the + // transformations needed to be done. + // They are collected in + // pn.GetAttribute("XREALMFORM") + for _, fn := range _tests.Files { + gno.FindXformsGno0p9(gs, pn, fn) + } + } + { + // FIX STEP 6: PreprocessFiles() + // Preprocess _filetest.gno files. + for i, fset := range ftests { + cw := bs.CacheWrap() + gs := ts.BeginTransaction(cw, cw, nil) + tm.Store = gs + fname := string(fset.Files[0].Name) + mfile := mpkg.GetFile(fname) + pkgPath := fmt.Sprintf("%s_filetest%d", mpkg.Path, i) + pkgPath, err = parsePkgPathDirective(mfile.Body, pkgPath) + if err != nil { + cio.ErrPrintln(err) + hasError = true + continue + } + pkgName := string(fset.Files[0].PkgName) + pn, _ := tm.PreprocessFiles(pkgName, pkgPath, fset, false, false, gno.GnoVerMissing) + ppkg.AddFileTest(pn, fset) + + // FIX STEP 7: FindXforms(): + // FindXforms for all files if outdated. + // Use the preprocessor to collect the + // transformations needed to be done. + // They are collected in + // pn.GetAttribute("XREALMFORM") + for _, fn := range fset.Files { + gno.FindXformsGno0p9(gs, pn, fn) + } + } + } + + // Record results. + ppkgs[dir] = ppkg + }) + if didPanic { + hasError = true + } + } + if hasError { + return commands.ExitCodeError(1) + } + + //---------------------------------------- + // FIX STAGE 2: Transpile to Gno 0.9 + // Must be a separate stage because dirs depend on each other. + for _, dir := range dirs { + ppkg, ok := ppkgs[dir] + if !ok { + // Happens when fixing a file, (XXX fix this case) + // but also happens when preprocessing isn't needed. + continue + } + + // Sanity check. + mod, err := gno.ParseCheckGnoMod(ppkg.mpkg) + if mod.GetGno() != gno.GnoVerMissing { + panic("should not happen") + } + + // FIX STEP 8 & 9: gno.TranspileGno0p9() Part 1 & 2 + mpkg := ppkg.mpkg + transpileProcessedFileSet := func(pfs processedFileSet) error { + pn, fset := pfs.pn, pfs.fset + xforms1, _ := pn.GetAttribute(gno.ATTR_GNO0P9_XFORMS).(map[string]struct{}) + err = gno.TranspileGno0p9(mpkg, dir, pn, fset.GetFileNames(), xforms1) + return err + } + err = transpileProcessedFileSet(ppkg.normal) + if err != nil { + return err + } + err = transpileProcessedFileSet(ppkg._tests) + if err != nil { + return err + } + for _, ftest := range ppkg.ftests { + err = transpileProcessedFileSet(ftest) + if err != nil { + return err + } + } + } + if hasError { + return commands.ExitCodeError(1) + } + + //---------------------------------------- + // FIX STAGE 3: Write. + // Must be a separate stage to prevent partial writes. + for _, dir := range dirs { + ppkg, ok := ppkgs[dir] + if !ok { + // Happens when fixing a file, (XXX fix this case) + // but also happens when preprocessing isn't needed. + continue + } + + // Write version to gno.mod. + mod, err := gno.ParseCheckGnoMod(ppkg.mpkg) + if err != nil { + // should have been auto-generated. + panic("missing gno.mod") + } + mod.SetGno(gno.GnoVerLatest) + ppkg.mpkg.SetFile("gno.mod", mod.WriteString()) + + // FIX STEP 10: mpkg.WriteTo(): + err = ppkg.mpkg.WriteTo(dir) + if err != nil { + return err + } + } + + return nil +} + +// When in filetestsOnly mode, filter out files that are known to have a +// type-check error. These files will be deleted from the mpkg. +// They are only deleted from mpkg; gno fix will not affect the files +// already on disk. +func filterInvalidFiletests(cio commands.IO, mpkg *std.MemPackage) { + for _, mfile := range mpkg.Files { + dirs, err := test.ParseDirectives(bytes.NewReader([]byte(mfile.Body))) + if err != nil { + panic(fmt.Errorf("error parsing directives: %w", err)) + } + tcErr := dirs.FirstDefault(test.DirectiveTypeCheckError, "") + if tcErr != "" { + cio.Printfln("skipping invalid filetest %q", mfile.Name) + mpkg.DeleteFile(mfile.Name) + continue + } + } +} diff --git a/gnovm/cmd/gno/tool_lint.go b/gnovm/cmd/gno/tool_lint.go index d772f877403..e1308e4d96b 100644 --- a/gnovm/cmd/gno/tool_lint.go +++ b/gnovm/cmd/gno/tool_lint.go @@ -5,13 +5,11 @@ import ( "errors" "flag" "fmt" - "go/scanner" "go/types" goio "io" + "io/fs" "os" "path/filepath" - "regexp" - "strings" "github.com/gnolang/gno/gnovm/pkg/gnoenv" gno "github.com/gnolang/gno/gnovm/pkg/gnolang" @@ -22,15 +20,21 @@ import ( "go.uber.org/multierr" ) -type lintCfg struct { - verbose bool - rootDir string - // min_confidence: minimum confidence of a problem to print it (default 0.8) - // auto-fix: apply suggested fixes automatically. +/* + Linting. + Refer to the [Lint and Transpile ADR](./adr/pr4264_lint_transpile.md). +*/ + +type lintCmd struct { + verbose bool + rootDir string + autoGnomod bool + // min_confidence: minimum confidence of a problem to print it + // (default 0.8) auto-fix: apply suggested fixes automatically. } func newLintCmd(io commands.IO) *commands.Command { - cfg := &lintCfg{} + cmd := &lintCmd{} return commands.NewCommand( commands.Metadata{ @@ -38,59 +42,33 @@ func newLintCmd(io commands.IO) *commands.Command { ShortUsage: "lint [flags] [...]", ShortHelp: "runs the linter for the specified packages", }, - cfg, + cmd, func(_ context.Context, args []string) error { - return execLint(cfg, args, io) + return execLint(cmd, args, io) }, ) } -func (c *lintCfg) RegisterFlags(fs *flag.FlagSet) { +func (c *lintCmd) RegisterFlags(fs *flag.FlagSet) { rootdir := gnoenv.RootDir() fs.BoolVar(&c.verbose, "v", false, "verbose output when lintning") fs.StringVar(&c.rootDir, "root-dir", rootdir, "clone location of github.com/gnolang/gno (gno tries to guess it)") + fs.BoolVar(&c.autoGnomod, "auto-gnomod", true, "auto-generate gno.mod file if not already present.") } -type lintCode int - -const ( - lintUnknown lintCode = iota - lintGnoMod - lintGnoError - lintParserError - lintTypeCheckError - - // TODO: add new linter codes here. -) - -type lintIssue struct { - Code lintCode - Msg string - Confidence float64 // 1 is 100% - Location string // file:line, or equivalent - // TODO: consider writing fix suggestions -} - -func (i lintIssue) String() string { - // TODO: consider crafting a doc URL based on Code. - return fmt.Sprintf("%s: %s (code=%d)", i.Location, i.Msg, i.Code) -} - -func execLint(cfg *lintCfg, args []string, io commands.IO) error { - if len(args) < 1 { +func execLint(cmd *lintCmd, args []string, io commands.IO) error { + // Show a help message by default. + if len(args) == 0 { return flag.ErrHelp } - var ( - verbose = cfg.verbose - rootDir = cfg.rootDir - ) - if rootDir == "" { - rootDir = gnoenv.RootDir() + // Guess opts.RootDir. + if cmd.rootDir == "" { + cmd.rootDir = gnoenv.RootDir() } - dirPaths, err := gnoPackagesFromArgsRecursively(args) + dirs, err := gnoPackagesFromArgsRecursively(args) if err != nil { return fmt.Errorf("list packages from args: %w", err) } @@ -98,237 +76,215 @@ func execLint(cfg *lintCfg, args []string, io commands.IO) error { hasError := false bs, ts := test.StoreWithOptions( - rootDir, goio.Discard, + cmd.rootDir, goio.Discard, test.StoreOptions{PreprocessOnly: true}, ) + ppkgs := map[string]processedPackage{} - for _, dirPath := range dirPaths { - if verbose { - io.ErrPrintln(dirPath) + if cmd.verbose { + io.ErrPrintfln("flinting directories: %v", dirs) + } + //---------------------------------------- + // LINT STAGE 1: Typecheck and lint. + for _, dir := range dirs { + if cmd.verbose { + io.ErrPrintfln("linting %q", dir) } - info, err := os.Stat(dirPath) + // XXX Currently the linter only supports linting directories. + // In order to support linting individual files, we need to + // refactor this code to work with mempackages, not dirs, and + // cmd/gno/util.go needs to be refactored to return mempackages + // rather than dirs. Commands like `gno lint a.gno b.gno` + // should create a temporary package from just those files. We + // could also load mempackages lazily for memory efficiency. + info, err := os.Stat(dir) if err == nil && !info.IsDir() { - dirPath = filepath.Dir(dirPath) + dir = filepath.Dir(dir) } - // Check if 'gno.mod' exists - gmFile, err := gnomod.ParseAt(dirPath) + // Read and parse gno.mod directly. + fpath := filepath.Join(dir, "gno.mod") + mod, err := gnomod.ParseFilepath(fpath) + if errors.Is(err, fs.ErrNotExist) { + if cmd.autoGnomod { + modstr := gno.GenGnoModDefault("gno.land/r/xxx_myrealm_xxx/xxx_fixme_xxx") + mod, err = gnomod.ParseBytes("gno.mod", []byte(modstr)) + if err != nil { + panic(fmt.Errorf("unexpected panic parsing default gno.mod bytes: %w", err)) + } + io.ErrPrintfln("auto-generated %q", fpath) + err = mod.WriteFile(fpath) + if err != nil { + panic(fmt.Errorf("unexpected panic writing to %q: %w", fpath, err)) + } + // err == nil. + } + } if err != nil { - issue := lintIssue{ - Code: lintGnoMod, - Confidence: 1, - Location: dirPath, + issue := gnoIssue{ + Code: gnoGnoModError, + Confidence: 1, // ?? + Location: fpath, Msg: err.Error(), } io.ErrPrintln(issue) hasError = true + return commands.ExitCodeError(1) } - pkgPath, _ := determinePkgPath(gmFile, dirPath, cfg.rootDir) - memPkg, err := gno.ReadMemPackage(dirPath, pkgPath) + // See adr/pr4264_lint_transpile.md + // LINT STEP 1: ReadMemPackage() + // Read MemPackage with pkgPath. + pkgPath, _ := determinePkgPath(mod, dir, cmd.rootDir) + mpkg, err := gno.ReadMemPackage(dir, pkgPath) if err != nil { - io.ErrPrintln(issueFromError(dirPath, pkgPath, err).String()) + printError(io.Err(), dir, pkgPath, err) hasError = true continue } // Perform imports using the parent store. - if err := test.LoadImports(ts, memPkg); err != nil { - io.ErrPrintln(issueFromError(dirPath, pkgPath, err).String()) + if err := test.LoadImports(ts, mpkg); err != nil { + printError(io.Err(), dir, pkgPath, err) hasError = true continue } // Handle runtime errors - hasRuntimeErr := catchRuntimeError(dirPath, pkgPath, io.Err(), func() { - // Wrap in cache wrap so execution of the linter doesn't impact - // other packages. + didPanic := catchPanic(dir, pkgPath, io.Err(), func() { + // Wrap in cache wrap so execution of the linter + // doesn't impact other packages. cw := bs.CacheWrap() gs := ts.BeginTransaction(cw, cw, nil) + // These are Go types. + ppkg := processedPackage{mpkg: mpkg, dir: dir} + var errs error + // Run type checking - if gmFile == nil || !gmFile.Draft { - foundErr, err := lintTypeCheck(io, dirPath, memPkg, gs) - if err != nil { - io.ErrPrintln(err) - hasError = true - } else if foundErr { + // LINT STEP 2: ParseGnoMod() + // STEP 3: GoParse*() + // + // lintTypeCheck(mpkg) --> + // TypeCheckMemPackage(mpkg) --> + // imp.typeCheckMemPackage(mpkg) + // ParseGnoMod(mpkg); + // GoParseMemPackage(mpkg); + // g.cmd.Check(); + if !mod.Draft { + _, _, errs = lintTypeCheck(io, dir, mpkg, gs) + if errs != nil { + // io.ErrPrintln(errs) printed above. hasError = true + return } - } else if verbose { - io.ErrPrintfln("%s: module is draft, skipping type check", dirPath) + } else if cmd.verbose { + io.ErrPrintfln("%s: module is draft, skipping type check", dir) } + // Construct machine for testing. tm := test.Machine(gs, goio.Discard, pkgPath, false) - defer tm.Release() - // Check test files - packageFiles := sourceAndTestFileset(memPkg) + // LINT STEP 4: re-parse + // Gno parse source fileset and test filesets. + _, fset, _tests, ftests := sourceAndTestFileset(mpkg) - tm.PreprocessFiles(memPkg.Name, pkgPath, packageFiles, false, false) + { + // LINT STEP 5: PreprocessFiles() + // Preprocess fset files (w/ some _test.gno). + pn, _ := tm.PreprocessFiles( + mpkg.Name, mpkg.Path, fset, false, false, "") + ppkg.AddNormal(pn, fset) + } + { + // LINT STEP 5: PreprocessFiles() + // Preprocess _test files (all _test.gno). + cw := bs.CacheWrap() + gs := ts.BeginTransaction(cw, cw, nil) + tm.Store = gs + pn, _ := tm.PreprocessFiles( + mpkg.Name+"_test", mpkg.Path+"_test", _tests, false, false, "") + ppkg.AddUnderscoreTests(pn, _tests) + } + { + // LINT STEP 5: PreprocessFiles() + // Preprocess _filetest.gno files. + for i, fset := range ftests { + cw := bs.CacheWrap() + gs := ts.BeginTransaction(cw, cw, nil) + tm.Store = gs + fname := string(fset.Files[0].Name) + mfile := mpkg.GetFile(fname) + pkgPath := fmt.Sprintf("%s_filetest%d", mpkg.Path, i) + pkgPath, err = parsePkgPathDirective(mfile.Body, pkgPath) + if err != nil { + io.ErrPrintln(err) + hasError = true + continue + } + pkgName := string(fset.Files[0].PkgName) + pn, _ := tm.PreprocessFiles(pkgName, pkgPath, fset, false, false, "") + ppkg.AddFileTest(pn, fset) + } + } + + // Record results. + ppkgs[dir] = ppkg }) - if hasRuntimeErr { + if didPanic { hasError = true } } - if hasError { return commands.ExitCodeError(1) } - return nil -} - -func lintTypeCheck(io commands.IO, dirPath string, memPkg *std.MemPackage, testStore gno.Store) (errorsFound bool, err error) { - tcErr := gno.TypeCheckMemPackageTest(memPkg, testStore) - if tcErr == nil { - return false, nil - } - - errs := multierr.Errors(tcErr) - for _, err := range errs { - switch err := err.(type) { - case types.Error: - loc := err.Fset.Position(err.Pos).String() - loc = replaceWithDirPath(loc, memPkg.Path, dirPath) - io.ErrPrintln(lintIssue{ - Code: lintTypeCheckError, - Msg: err.Msg, - Confidence: 1, - Location: loc, - }) - case scanner.ErrorList: - for _, scErr := range err { - loc := scErr.Pos.String() - loc = replaceWithDirPath(loc, memPkg.Path, dirPath) - io.ErrPrintln(lintIssue{ - Code: lintParserError, - Msg: scErr.Msg, - Confidence: 1, - Location: loc, - }) - } - case scanner.Error: - loc := err.Pos.String() - loc = replaceWithDirPath(loc, memPkg.Path, dirPath) - io.ErrPrintln(lintIssue{ - Code: lintParserError, - Msg: err.Msg, - Confidence: 1, - Location: loc, - }) - default: - return false, fmt.Errorf("unexpected error type: %T", err) - } - } - return true, nil -} - -func sourceAndTestFileset(memPkg *std.MemPackage) *gno.FileSet { - testfiles := &gno.FileSet{} - for _, mfile := range memPkg.Files { - if !strings.HasSuffix(mfile.Name, ".gno") { - continue // Skip non-GNO files + //---------------------------------------- + // LINT STAGE 2: Write. + // Must be a separate stage to prevent partial writes. + for _, dir := range dirs { + ppkg, ok := ppkgs[dir] + if !ok { + panic("where did it go") } - n := gno.MustParseFile(mfile.Name, mfile.Body) - if n == nil { - continue // Skip empty files - } - - // XXX: package ending with `_test` is not supported yet - if !strings.HasSuffix(mfile.Name, "_filetest.gno") && - !strings.HasSuffix(string(n.PkgName), "_test") { - // Keep only test files - testfiles.AddFiles(n) + // LINT STEP 6: mpkg.WriteTo(): + err := ppkg.mpkg.WriteTo(dir) + if err != nil { + return err } } - return testfiles -} - -func guessSourcePath(pkg, source string) string { - if info, err := os.Stat(pkg); !os.IsNotExist(err) && !info.IsDir() { - pkg = filepath.Dir(pkg) - } - - sourceJoin := filepath.Join(pkg, source) - if _, err := os.Stat(sourceJoin); !os.IsNotExist(err) { - return filepath.Clean(sourceJoin) - } - if _, err := os.Stat(source); !os.IsNotExist(err) { - return filepath.Clean(source) - } - - return filepath.Clean(pkg) -} - -// reParseRecover is a regex designed to parse error details from a string. -// It extracts the file location, line number, and error message from a formatted error string. -// XXX: Ideally, error handling should encapsulate location details within a dedicated error type. -var reParseRecover = regexp.MustCompile(`^([^:]+)((?::(?:\d+)){1,2}):? *(.*)$`) - -func catchRuntimeError(dirPath, pkgPath string, stderr goio.WriteCloser, action func()) (hasError bool) { - defer func() { - // Errors catched here mostly come from: gnovm/pkg/gnolang/preprocess.go - r := recover() - if r == nil { - return - } - hasError = true - switch verr := r.(type) { - case *gno.PreprocessError: - err := verr.Unwrap() - fmt.Fprintln(stderr, issueFromError(dirPath, pkgPath, err).String()) - case error: - errors := multierr.Errors(verr) - for _, err := range errors { - errList, ok := err.(scanner.ErrorList) - if ok { - for _, errorInList := range errList { - fmt.Fprintln(stderr, issueFromError(dirPath, pkgPath, errorInList).String()) - } - } else { - fmt.Fprintln(stderr, issueFromError(dirPath, pkgPath, err).String()) - } - } - case string: - fmt.Fprintln(stderr, issueFromError(dirPath, pkgPath, errors.New(verr)).String()) - default: - panic(r) - } - }() - - action() - return + return nil } -func issueFromError(dirPath, pkgPath string, err error) lintIssue { - var issue lintIssue - issue.Confidence = 1 - issue.Code = lintGnoError - - parsedError := strings.TrimSpace(err.Error()) - parsedError = replaceWithDirPath(parsedError, pkgPath, dirPath) - parsedError = strings.TrimPrefix(parsedError, pkgPath+"/") - - matches := reParseRecover.FindStringSubmatch(parsedError) - if len(matches) > 0 { - sourcepath := guessSourcePath(pkgPath, matches[1]) - issue.Location = sourcepath + matches[2] - issue.Msg = strings.TrimSpace(matches[3]) - } else { - issue.Location = fmt.Sprintf("%s:0", filepath.Clean(pkgPath)) - issue.Msg = err.Error() +// Wrapper around TypeCheckMemPackage() to io.ErrPrintln(gnoIssue{}). +// Prints and returns errors. Panics upon an unexpected error. +func lintTypeCheck( + // Args: + io commands.IO, + dir string, + mpkg *std.MemPackage, + testStore gno.Store) ( + // Results: + gopkg *types.Package, + tfiles *gno.TypeCheckFilesResult, + lerr error, +) { + //---------------------------------------- + + // gno.TypeCheckMemPackage(mpkg, testStore) + var tcErrs error + gopkg, tfiles, tcErrs = gno.TypeCheckMemPackage(mpkg, testStore, gno.ParseModeAll) + + // Print errors, and return the first unexpected error. + errors := multierr.Errors(tcErrs) + for _, err := range errors { + printError(io.Err(), dir, mpkg.Path, err) } - return issue -} -func replaceWithDirPath(s, pkgPath, dirPath string) string { - if strings.HasPrefix(s, pkgPath) { - return filepath.Clean(dirPath + s[len(pkgPath):]) - } - return s + lerr = tcErrs + return } diff --git a/gnovm/cmd/gno/tool_lint_test.go b/gnovm/cmd/gno/tool_lint_test.go index aaffcbaddff..f7520c3718e 100644 --- a/gnovm/cmd/gno/tool_lint_test.go +++ b/gnovm/cmd/gno/tool_lint_test.go @@ -12,33 +12,33 @@ func TestLintApp(t *testing.T) { errShouldBe: "flag: help requested", }, { - args: []string{"lint", "../../tests/integ/run_main/"}, - stderrShouldContain: "./../../tests/integ/run_main: gno.mod file not found in current or any parent directory (code=1)", + args: []string{"lint", "../../tests/integ/run_main/", "-auto-gnomod=false"}, + stderrShouldContain: "../../tests/integ/run_main/gno.mod: could not read gno.mod file: stat ../../tests/integ/run_main/gno.mod: no such file or directory (code=gnoGnoModError)", errShouldBe: "exit code: 1", }, { args: []string{"lint", "../../tests/integ/undefined_variable_test/undefined_variables_test.gno"}, - stderrShouldContain: "undefined_variables_test.gno:6:28: name toto not declared (code=2)", + stderrShouldContain: "../../tests/integ/undefined_variable_test/undefined_variables_test.gno:6:28: undefined: toto (code=gnoTypeCheckError)", errShouldBe: "exit code: 1", }, { args: []string{"lint", "../../tests/integ/package_not_declared/main.gno"}, - stderrShouldContain: "main.gno:4:2: name fmt not declared (code=2)", + stderrShouldContain: "../../tests/integ/package_not_declared/main.gno:4:2: undefined: fmt (code=gnoTypeCheckError)", errShouldBe: "exit code: 1", }, { args: []string{"lint", "../../tests/integ/several-lint-errors/main.gno"}, - stderrShouldContain: "../../tests/integ/several-lint-errors/main.gno:5:5: expected ';', found example (code=3)\n../../tests/integ/several-lint-errors/main.gno:6", + stderrShouldContain: "../../tests/integ/several-lint-errors/main.gno:5:5: expected ';', found example (code=gnoParserError)\n../../tests/integ/several-lint-errors/main.gno:6", errShouldBe: "exit code: 1", }, { args: []string{"lint", "../../tests/integ/several-files-multiple-errors/main.gno"}, stderrShouldContain: func() string { lines := []string{ - "../../tests/integ/several-files-multiple-errors/file2.gno:3:5: expected 'IDENT', found '{' (code=3)", - "../../tests/integ/several-files-multiple-errors/file2.gno:5:1: expected type, found '}' (code=3)", - "../../tests/integ/several-files-multiple-errors/main.gno:5:5: expected ';', found example (code=3)", - "../../tests/integ/several-files-multiple-errors/main.gno:6:2: expected '}', found 'EOF' (code=3)", + "../../tests/integ/several-files-multiple-errors/file2.gno:3:5: expected 'IDENT', found '{' (code=gnoParserError)", + "../../tests/integ/several-files-multiple-errors/file2.gno:5:1: expected type, found '}' (code=gnoParserError)", + "../../tests/integ/several-files-multiple-errors/main.gno:5:5: expected ';', found example (code=gnoParserError)", + "../../tests/integ/several-files-multiple-errors/main.gno:6:2: expected '}', found 'EOF' (code=gnoParserError)", } return strings.Join(lines, "\n") + "\n" }(), @@ -54,12 +54,12 @@ func TestLintApp(t *testing.T) { }, { args: []string{"lint", "../../tests/integ/invalid_gno_file/"}, - stderrShouldContain: "../../tests/integ/invalid_gno_file/invalid.gno:1:1: expected 'package', found packag (code=2)", + stderrShouldContain: "../../tests/integ/invalid_gno_file/invalid.gno:1:1: expected 'package', found packag (code=gnoParserError)", errShouldBe: "exit code: 1", }, { args: []string{"lint", "../../tests/integ/typecheck_missing_return/"}, - stderrShouldContain: "../../tests/integ/typecheck_missing_return/main.gno:5:1: missing return (code=4)", + stderrShouldContain: "../../tests/integ/typecheck_missing_return/main.gno:5:1: missing return (code=gnoTypeCheckError)", errShouldBe: "exit code: 1", }, { diff --git a/gnovm/cmd/gno/tool_transpile.go b/gnovm/cmd/gno/tool_transpile.go index 1e3081ca2b0..bd312116417 100644 --- a/gnovm/cmd/gno/tool_transpile.go +++ b/gnovm/cmd/gno/tool_transpile.go @@ -205,7 +205,7 @@ func transpilePkg(dirPath string, opts *transpileOptions) error { } opts.markAsTranspiled(dirPath) - gmod, err := gnomod.ParseAt(dirPath) + gmod, err := gnomod.ParseDir(dirPath) if err != nil && !errors.Is(err, gnomod.ErrGnoModNotFound) { return err } diff --git a/gnovm/cmd/gno/util.go b/gnovm/cmd/gno/util.go index 697aa94b3c6..564cf1a5645 100644 --- a/gnovm/cmd/gno/util.go +++ b/gnovm/cmd/gno/util.go @@ -27,12 +27,12 @@ func gnoFilesFromArgsRecursively(args []string) ([]string, error) { for _, argPath := range args { info, err := os.Stat(argPath) if err != nil { - return nil, fmt.Errorf("invalid file or package path: %w", err) + return nil, fmt.Errorf("gno: invalid file or package path %q: %w", argPath, err) } if !info.IsDir() { if isGnoFile(fs.FileInfoToDirEntry(info)) { - paths = append(paths, ensurePathPrefix(argPath)) + paths = append(paths, cleanPath(argPath)) } continue @@ -40,7 +40,7 @@ func gnoFilesFromArgsRecursively(args []string) ([]string, error) { // Gather package paths from the directory err = walkDirForGnoFiles(argPath, func(path string) { - paths = append(paths, ensurePathPrefix(path)) + paths = append(paths, cleanPath(path)) }) if err != nil { return nil, fmt.Errorf("unable to walk dir: %w", err) @@ -56,12 +56,12 @@ func gnoFilesFromArgs(args []string) ([]string, error) { for _, argPath := range args { info, err := os.Stat(argPath) if err != nil { - return nil, fmt.Errorf("invalid file or package path: %w", err) + return nil, fmt.Errorf("gno: invalid file or package path %q: %w", argPath, err) } if !info.IsDir() { if isGnoFile(fs.FileInfoToDirEntry(info)) { - paths = append(paths, ensurePathPrefix(argPath)) + paths = append(paths, cleanPath(argPath)) } continue } @@ -73,7 +73,7 @@ func gnoFilesFromArgs(args []string) ([]string, error) { for _, f := range files { if isGnoFile(f) { path := filepath.Join(argPath, f.Name()) - paths = append(paths, ensurePathPrefix(path)) + paths = append(paths, cleanPath(path)) } } } @@ -81,11 +81,15 @@ func gnoFilesFromArgs(args []string) ([]string, error) { return paths, nil } -func ensurePathPrefix(path string) string { +// ensures that the path is absolute or starts with a dot. +// ensures that the path is a dir path. +func cleanPath(path string) string { if filepath.IsAbs(path) { return path } - + if strings.HasPrefix(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. @@ -125,18 +129,18 @@ func gnoPackagesFromArgsRecursively(args []string) ([]string, error) { for _, argPath := range args { info, err := os.Stat(argPath) if err != nil { - return nil, fmt.Errorf("invalid file or package path: %w", err) + return nil, fmt.Errorf("gno: invalid file or package path %q: %w", argPath, err) } if !info.IsDir() { - paths = append(paths, ensurePathPrefix(argPath)) + paths = append(paths, cleanPath(argPath)) continue } // Gather package paths from the directory err = walkDirForGnoFiles(argPath, func(path string) { - paths = append(paths, ensurePathPrefix(path)) + paths = append(paths, cleanPath(path)) }) if err != nil { return nil, fmt.Errorf("unable to walk dir: %w", err) @@ -169,7 +173,7 @@ func targetsFromPatterns(patterns []string) ([]string, error) { info, err := os.Stat(dirToSearch) if err != nil { - return nil, fmt.Errorf("invalid file or package path: %w", err) + return nil, fmt.Errorf("gno: invalid file or package path %q: %w", dirToSearch, err) } // If the pattern is a file or a directory diff --git a/gnovm/pkg/doc/dirs.go b/gnovm/pkg/doc/dirs.go index a5a5e882df6..86739f47769 100644 --- a/gnovm/pkg/doc/dirs.go +++ b/gnovm/pkg/doc/dirs.go @@ -56,7 +56,7 @@ func newDirs(dirs []string, modDirs []string) *bfsDirs { } for _, mdir := range modDirs { - gm, err := gnomod.ParseGnoMod(filepath.Join(mdir, "gno.mod")) + gm, err := gnomod.ParseFilepath(filepath.Join(mdir, "gno.mod")) if err != nil { log.Printf("%v", err) continue diff --git a/gnovm/pkg/doc/json_doc.go b/gnovm/pkg/doc/json_doc.go index 149df178702..b6daf5e1e99 100644 --- a/gnovm/pkg/doc/json_doc.go +++ b/gnovm/pkg/doc/json_doc.go @@ -59,9 +59,9 @@ type JSONType struct { Doc string `json:"doc"` // markdown } -// NewDocumentableFromMemPkg gets the pkgData from memPkg and returns a Documentable -func NewDocumentableFromMemPkg(memPkg *std.MemPackage, unexported bool, symbol, accessible string) (*Documentable, error) { - pd, err := newPkgDataFromMemPkg(memPkg, unexported) +// NewDocumentableFromMemPkg gets the pkgData from mpkg and returns a Documentable +func NewDocumentableFromMemPkg(mpkg *std.MemPackage, unexported bool, symbol, accessible string) (*Documentable, error) { + pd, err := newPkgDataFromMemPkg(mpkg, unexported) if err != nil { return nil, err } diff --git a/gnovm/pkg/doc/json_doc_test.go b/gnovm/pkg/doc/json_doc_test.go index 7cdfccf0084..806dc10c664 100644 --- a/gnovm/pkg/doc/json_doc_test.go +++ b/gnovm/pkg/doc/json_doc_test.go @@ -192,9 +192,9 @@ func TestJSONDocumentation(t *testing.T) { } // Get the JSONDocumentation similar to VMKeeper.QueryDoc - memPkg, err := gnolang.ReadMemPackage(dir, pkgPath) + mpkg, err := gnolang.ReadMemPackage(dir, pkgPath) require.NoError(t, err) - d, err := NewDocumentableFromMemPkg(memPkg, true, "", "") + d, err := NewDocumentableFromMemPkg(mpkg, true, "", "") require.NoError(t, err) jdoc, err := d.WriteJSONDocumentation() require.NoError(t, err) diff --git a/gnovm/pkg/doc/pkg.go b/gnovm/pkg/doc/pkg.go index caab3624deb..76b89bdc4ca 100644 --- a/gnovm/pkg/doc/pkg.go +++ b/gnovm/pkg/doc/pkg.go @@ -38,22 +38,22 @@ type symbolData struct { } func newPkgData(dir bfsDir, unexported bool) (*pkgData, error) { - memPkg, err := gnolang.ReadMemPackage(dir.dir, dir.importPath) + mpkg, err := gnolang.ReadMemPackage(dir.dir, dir.importPath) if err != nil { return nil, fmt.Errorf("commands/doc: read files %q: %w", dir.dir, err) } - return newPkgDataFromMemPkg(memPkg, unexported) + return newPkgDataFromMemPkg(mpkg, unexported) } -func newPkgDataFromMemPkg(memPkg *std.MemPackage, unexported bool) (*pkgData, error) { +func newPkgDataFromMemPkg(mpkg *std.MemPackage, unexported bool) (*pkgData, error) { pkg := &pkgData{ dir: bfsDir{ - importPath: memPkg.Name, - dir: memPkg.Path, + importPath: mpkg.Name, + dir: mpkg.Path, }, fset: token.NewFileSet(), } - for _, file := range memPkg.Files { + for _, file := range mpkg.Files { n := file.Name // Ignore files with prefix . or _ like go tools do. // Ignore _filetest.gno, but not _test.gno, as we use those to compute @@ -66,18 +66,18 @@ func newPkgDataFromMemPkg(memPkg *std.MemPackage, unexported bool) (*pkgData, er } err := pkg.parseFile(n, file.Body, unexported) if err != nil { - fullPath := filepath.Join(memPkg.Path, n) + fullPath := filepath.Join(mpkg.Path, n) return nil, fmt.Errorf("commands/doc: parse file %q: %w", fullPath, err) } } if len(pkg.files) == 0 { - return nil, fmt.Errorf("commands/doc: no valid gno files in %q", memPkg.Path) + return nil, fmt.Errorf("commands/doc: no valid gno files in %q", mpkg.Path) } pkgName := pkg.files[0].Name.Name for _, file := range pkg.files[1:] { if file.Name.Name != pkgName { - return nil, fmt.Errorf("commands/doc: multiple packages (%q / %q) in dir %q", pkgName, file.Name.Name, memPkg.Path) + return nil, fmt.Errorf("commands/doc: multiple packages (%q / %q) in dir %q", pkgName, file.Name.Name, mpkg.Path) } } pkg.name = pkgName diff --git a/gnovm/pkg/gnofmt/package.go b/gnovm/pkg/gnofmt/package.go index c576bd8ee78..837d1b76c0e 100644 --- a/gnovm/pkg/gnofmt/package.go +++ b/gnovm/pkg/gnofmt/package.go @@ -95,8 +95,8 @@ func ParsePackage(fset *token.FileSet, root string, dir string) (Package, error) var pkgpath string // Check for a gno.mod, in which case it will define the module path - gnoModPath := filepath.Join(dir, "gno.mod") - data, err := os.ReadFile(gnoModPath) + modpath := filepath.Join(dir, "gno.mod") + data, err := os.ReadFile(modpath) switch { case os.IsNotExist(err): if len(root) > 0 { @@ -106,19 +106,19 @@ func ParsePackage(fset *token.FileSet, root string, dir string) (Package, error) } case err == nil: - gnoMod, err := gnomod.Parse(gnoModPath, data) + mod, err := gnomod.ParseBytes(modpath, data) if err != nil { - return nil, fmt.Errorf("unable to parse gnomod %q: %w", gnoModPath, err) + return nil, fmt.Errorf("unable to parse gnomod %q: %w", modpath, err) } - gnoMod.Sanitize() - if err := gnoMod.Validate(); err != nil { - return nil, fmt.Errorf("unable to validate gnomod %q: %w", gnoModPath, err) + mod.Sanitize() + if err := mod.Validate(); err != nil { + return nil, fmt.Errorf("unable to validate gnomod %q: %w", modpath, err) } - pkgpath = gnoMod.Module.Mod.Path + pkgpath = mod.Module.Mod.Path default: - return nil, fmt.Errorf("unable to read %q: %w", gnoModPath, err) + return nil, fmt.Errorf("unable to read %q: %w", modpath, err) } return &fsPackage{ diff --git a/gnovm/pkg/gnolang/debugger.go b/gnovm/pkg/gnolang/debugger.go index 22c110db7dd..28517bd830a 100644 --- a/gnovm/pkg/gnolang/debugger.go +++ b/gnovm/pkg/gnolang/debugger.go @@ -753,6 +753,27 @@ func debugLookup(m *Machine, name string) (tv TypedValue, ok bool) { return tv, false } + // XXX The following logic isn't necessary and it isn't correct either. + // XXX See `GetPathForName(Store, Name) ValuePath` in node.go, + // XXX get the path and pass it into the last block.GetPointerTo(). + // XXX That function will find the correct block by depth etc. + // XXX There was some latent bug for case: + // XXX '{in: "b 37\nc\np b\n", out: "(3 int)"},' (debugger test case #51) + // XXX which was revealed by some earlier commits regarding lines + // XXX (Node now has not just the starting .Pos but also .End.) + // XXX and is resolved by the following diff to values.go: + // XXX The exact bug probably doesn't matter, as the logic + // XXX should be replaced by the aforementioned block.GetPointerTo(). + // + // --- a/gnovm/pkg/gnolang/values.go + // +++ b/gnovm/pkg/gnolang/values.go + // @@ -2480,6 +2480,7 @@ func (b *Block) ExpandWith(alloc *Allocator, source BlockNode) { + // } + // } + // b.Values = values + // + b.Source = source // otherwise new variables won't show in print or debugger. + // } + // Position to the right block, i.e the first after the last fblock (if any). for i = len(m.Blocks) - 1; i >= 0; i-- { if len(fblocks) == 0 { diff --git a/gnovm/pkg/gnolang/files_test.go b/gnovm/pkg/gnolang/files_test.go index 4b6b7bdc6b0..af1e4da705c 100644 --- a/gnovm/pkg/gnolang/files_test.go +++ b/gnovm/pkg/gnolang/files_test.go @@ -6,6 +6,7 @@ import ( "fmt" "io" "io/fs" + "io/ioutil" "os" "path/filepath" "strings" @@ -54,22 +55,29 @@ func TestFiles(t *testing.T) { // sharedOpts is used for all "short" tests. sharedOpts := newOpts() - dir := "../../tests/" + dir := "../../tests/files" fsys := os.DirFS(dir) - err = fs.WalkDir(fsys, "files", func(path string, de fs.DirEntry, err error) error { + err = fs.WalkDir(fsys, ".", func(path string, de fs.DirEntry, err error) error { switch { case err != nil: return err - case path == "files/extern": + case path == "extern": return fs.SkipDir case de.IsDir(): return nil } - subTestName := path[len("files/"):] + subTestName := path + isHidden := strings.HasPrefix(path, ".") + if isHidden { + t.Run(subTestName, func(t *testing.T) { + t.Skip("skipping hidden") + }) + return nil + } isLong := strings.HasSuffix(path, "_long.gno") if isLong && testing.Short() { t.Run(subTestName, func(t *testing.T) { - t.Skip("skipping in -short") + t.Skip("skipping long (-short)") }) return nil } @@ -145,10 +153,28 @@ func TestStdlibs(t *testing.T) { } fp := filepath.Join(dir, path) - memPkg := gnolang.MustReadMemPackage(fp, path) - t.Run(strings.ReplaceAll(memPkg.Path, "/", "-"), func(t *testing.T) { + + // Exclude empty directories. + files, err := ioutil.ReadDir(fp) + hasFiles := false + if err != nil { + return err + } + for _, file := range files { + if !file.IsDir() && + strings.HasSuffix(file.Name(), ".gno") { + hasFiles = true + } + } + if !hasFiles { + return nil + } + + // Read and run tests. + mpkg := gnolang.MustReadMemPackage(fp, path) + t.Run(strings.ReplaceAll(mpkg.Path, "/", "-"), func(t *testing.T) { capture, opts := sharedCapture, sharedOpts - switch memPkg.Path { + switch mpkg.Path { // Excluded in short case "bufio", @@ -172,7 +198,7 @@ func TestStdlibs(t *testing.T) { capture.Reset() } - err := test.Test(memPkg, "", opts) + err := test.Test(mpkg, "", opts) if !testing.Verbose() { t.Log(capture.String()) } @@ -203,13 +229,13 @@ func TestStdlibs(t *testing.T) { } fp := filepath.Join(testDir, path) - memPkg := gnolang.MustReadMemPackage(fp, path) - t.Run("test-"+strings.ReplaceAll(memPkg.Path, "/", "-"), func(t *testing.T) { + mpkg := gnolang.MustReadMemPackage(fp, path) + t.Run("test-"+strings.ReplaceAll(mpkg.Path, "/", "-"), func(t *testing.T) { if sharedCapture != nil { sharedCapture.Reset() } - err := test.Test(memPkg, "", sharedOpts) + err := test.Test(mpkg, "", sharedOpts) if !testing.Verbose() { t.Log(sharedCapture.String()) } diff --git a/gnovm/pkg/gnolang/gno_test.go b/gnovm/pkg/gnolang/gno_test.go index 1a70c3e21f6..f1c573c43f4 100644 --- a/gnovm/pkg/gnolang/gno_test.go +++ b/gnovm/pkg/gnolang/gno_test.go @@ -171,7 +171,7 @@ func TestConvertTo(t *testing.T) { var g = float32(t) println(g) } - `, `test/main.go:5:12: cannot convert interface{} to float32: need type assertion`, + `, `test/main.go:5:12-22: cannot convert interface{} to float32: need type assertion`, }, { `package test @@ -181,7 +181,7 @@ func TestConvertTo(t *testing.T) { var g = int(t) println(g) } - `, `test/main.go:5:14: cannot convert interface{} to int: need type assertion`, + `, `test/main.go:5:14-20: cannot convert interface{} to int: need type assertion`, }, { `package test @@ -191,7 +191,7 @@ func TestConvertTo(t *testing.T) { var g = int8(t) println(g) } - `, `test/main.go:5:14: cannot convert interface{} to int8: need type assertion`, + `, `test/main.go:5:14-21: cannot convert interface{} to int8: need type assertion`, }, { `package test @@ -201,7 +201,7 @@ func TestConvertTo(t *testing.T) { var g = int16(t) println(g) } - `, `test/main.go:5:14: cannot convert interface{} to int16: need type assertion`, + `, `test/main.go:5:14-22: cannot convert interface{} to int16: need type assertion`, }, { `package test @@ -211,7 +211,7 @@ func TestConvertTo(t *testing.T) { var g = int32(t) println(g) } - `, `test/main.go:5:16: cannot convert interface{} to int32: need type assertion`, + `, `test/main.go:5:16-24: cannot convert interface{} to int32: need type assertion`, }, { `package test @@ -221,7 +221,7 @@ func TestConvertTo(t *testing.T) { var g = int64(t) println(g) } - `, `test/main.go:5:14: cannot convert interface{} to int64: need type assertion`, + `, `test/main.go:5:14-22: cannot convert interface{} to int64: need type assertion`, }, { `package test @@ -231,7 +231,7 @@ func TestConvertTo(t *testing.T) { var g = uint(t) println(g) } - `, `test/main.go:5:14: cannot convert interface{} to uint: need type assertion`, + `, `test/main.go:5:14-21: cannot convert interface{} to uint: need type assertion`, }, { `package test @@ -241,7 +241,7 @@ func TestConvertTo(t *testing.T) { var g = uint8(t) println(g) } - `, `test/main.go:5:14: cannot convert interface{} to uint8: need type assertion`, + `, `test/main.go:5:14-22: cannot convert interface{} to uint8: need type assertion`, }, { `package test @@ -251,7 +251,7 @@ func TestConvertTo(t *testing.T) { var g = uint16(t) println(g) } - `, `test/main.go:5:14: cannot convert interface{} to uint16: need type assertion`, + `, `test/main.go:5:14-23: cannot convert interface{} to uint16: need type assertion`, }, { `package test @@ -261,7 +261,7 @@ func TestConvertTo(t *testing.T) { var g = uint32(t) println(g) } - `, `test/main.go:5:14: cannot convert interface{} to uint32: need type assertion`, + `, `test/main.go:5:14-23: cannot convert interface{} to uint32: need type assertion`, }, { `package test @@ -271,7 +271,7 @@ func TestConvertTo(t *testing.T) { var g = uint64(t) println(g) } - `, `test/main.go:5:14: cannot convert interface{} to uint64: need type assertion`, + `, `test/main.go:5:14-23: cannot convert interface{} to uint64: need type assertion`, }, // Built-in non-numeric types @@ -283,7 +283,7 @@ func TestConvertTo(t *testing.T) { var g = string(t) println(g) } - `, `test/main.go:5:14: cannot convert interface{} to string: need type assertion`, + `, `test/main.go:5:14-23: cannot convert interface{} to string: need type assertion`, }, { `package test @@ -293,7 +293,7 @@ func TestConvertTo(t *testing.T) { var g = bool(t) println(g) } - `, `test/main.go:5:14: cannot convert interface{} to bool: need type assertion`, + `, `test/main.go:5:14-21: cannot convert interface{} to bool: need type assertion`, }, { `package test @@ -303,7 +303,7 @@ func TestConvertTo(t *testing.T) { var g = rune(t) println(g) } - `, `test/main.go:5:14: cannot convert interface{} to int32: need type assertion`, + `, `test/main.go:5:14-21: cannot convert interface{} to int32: need type assertion`, }, { `package test @@ -313,7 +313,7 @@ func TestConvertTo(t *testing.T) { var g = byte(t) println(g) } - `, `test/main.go:5:14: cannot convert interface{} to uint8: need type assertion`, + `, `test/main.go:5:14-21: cannot convert interface{} to uint8: need type assertion`, }, { @@ -325,7 +325,7 @@ func TestConvertTo(t *testing.T) { var g = MyInt(t) println(g) } - `, `test/main.go:6:14: cannot convert interface{} to test.MyInt: need type assertion`, + `, `test/main.go:6:14-22: cannot convert interface{} to test.MyInt: need type assertion`, }, { `package test @@ -334,7 +334,7 @@ func TestConvertTo(t *testing.T) { const a int = -1 println(uint(a)) }`, - `test/main.go:5:14: cannot convert constant of type IntKind to UintKind`, + `test/main.go:5:14-21: cannot convert constant of type IntKind to UintKind`, }, { `package test @@ -343,7 +343,7 @@ func TestConvertTo(t *testing.T) { const a int = -1 println(uint8(a)) }`, - `test/main.go:5:14: cannot convert constant of type IntKind to Uint8Kind`, + `test/main.go:5:14-22: cannot convert constant of type IntKind to Uint8Kind`, }, { `package test @@ -352,7 +352,7 @@ func TestConvertTo(t *testing.T) { const a int = -1 println(uint16(a)) }`, - `test/main.go:5:14: cannot convert constant of type IntKind to Uint16Kind`, + `test/main.go:5:14-23: cannot convert constant of type IntKind to Uint16Kind`, }, { `package test @@ -361,7 +361,7 @@ func TestConvertTo(t *testing.T) { const a int = -1 println(uint32(a)) }`, - `test/main.go:5:14: cannot convert constant of type IntKind to Uint32Kind`, + `test/main.go:5:14-23: cannot convert constant of type IntKind to Uint32Kind`, }, { `package test @@ -370,7 +370,7 @@ func TestConvertTo(t *testing.T) { const a int = -1 println(uint64(a)) }`, - `test/main.go:5:14: cannot convert constant of type IntKind to Uint64Kind`, + `test/main.go:5:14-23: cannot convert constant of type IntKind to Uint64Kind`, }, { `package test @@ -379,7 +379,7 @@ func TestConvertTo(t *testing.T) { const a float32 = 1.5 println(int32(a)) }`, - `test/main.go:5:14: cannot convert constant of type Float32Kind to Int32Kind`, + `test/main.go:5:14-22: cannot convert constant of type Float32Kind to Int32Kind`, }, { `package test @@ -387,7 +387,7 @@ func TestConvertTo(t *testing.T) { func main() { println(int32(1.5)) }`, - `test/main.go:4:14: cannot convert (const (1.5 bigdec)) to integer type`, + `test/main.go:4:14-24: cannot convert (const (1.5 bigdec)) to integer type`, }, { `package test @@ -396,7 +396,7 @@ func TestConvertTo(t *testing.T) { const a float64 = 1.5 println(int64(a)) }`, - `test/main.go:5:14: cannot convert constant of type Float64Kind to Int64Kind`, + `test/main.go:5:14-22: cannot convert constant of type Float64Kind to Int64Kind`, }, { `package test @@ -404,7 +404,7 @@ func TestConvertTo(t *testing.T) { func main() { println(int64(1.5)) }`, - `test/main.go:4:14: cannot convert (const (1.5 bigdec)) to integer type`, + `test/main.go:4:14-24: cannot convert (const (1.5 bigdec)) to integer type`, }, { `package test diff --git a/gnovm/pkg/gnolang/gnomod.go b/gnovm/pkg/gnolang/gnomod.go new file mode 100644 index 00000000000..4d9c5a33e0c --- /dev/null +++ b/gnovm/pkg/gnolang/gnomod.go @@ -0,0 +1,143 @@ +package gnolang + +import ( + "bytes" + "fmt" + "html/template" + "io/fs" + "os" + "path/filepath" + + "github.com/gnolang/gno/gnovm/pkg/gnomod" + "github.com/gnolang/gno/gnovm/pkg/packages" + "github.com/gnolang/gno/tm2/pkg/std" +) + +const gnomodTemplate = `{{/* +This is a comment in a Go template in pkg/gnolang/gnomod.go. +The gnomodTemplate is used with the 'text/template' package +to generate the final gno.mod file. */}} +module {{.PkgPath}} + +gno {{.GnoVersion}}` + +func GenGnoModLatest(pkgPath string) string { return genGnoMod(pkgPath, GnoVerLatest) } +func GenGnoModTesting(pkgPath string) string { return genGnoMod(pkgPath, GnoVerTesting) } +func GenGnoModDefault(pkgPath string) string { return genGnoMod(pkgPath, GnoVerDefault) } +func GenGnoModMissing(pkgPath string) string { return genGnoMod(pkgPath, GnoVerMissing) } + +func genGnoMod(pkgPath string, gnoVersion string) string { + buf := new(bytes.Buffer) + tmpl := template.Must(template.New("").Parse(gnomodTemplate)) + err := tmpl.Execute(buf, struct { + PkgPath string + GnoVersion string + }{pkgPath, gnoVersion}) + if err != nil { + panic(fmt.Errorf("generating gno.mod: %w", err)) + } + return string(buf.Bytes()) +} + +const ( + GnoVerLatest = `0.9` // current version + GnoVerTesting = `0.9` // version of our tests + GnoVerDefault = `0.9` // auto generated gno.mod + GnoVerMissing = `0.0` // missing gno.mod, !autoGnoMod XXX +) + +// ======================================== +// Parses and checks the gno.mod file from mpkg. +// To generate default ones, GenGnoMod*(). +// +// Results: +// - mod: the gno.mod file, or nil if not found. +// - err: wrapped error, or nil if file not found. +func ParseCheckGnoMod(mpkg *std.MemPackage) (mod *gnomod.File, err error) { + if IsStdlib(mpkg.Path) { + // stdlib/extern packages are assumed up to date. + modstr := GenGnoModLatest(mpkg.Path) + mod, _ = gnomod.ParseBytes("/gno.mod", []byte(modstr)) + } else if mpkg.GetFile("gno.mod") == nil { + // gno.mod doesn't exist. + return nil, nil + } else if mod, err = gnomod.ParseMemPackage(mpkg); err != nil { + // error parsing gno.mod. + err = fmt.Errorf("%s/gno.mod: parse error %w", mpkg.Path, err) + } else if mod.Gno == nil { + // gno.mod was never specified; set missing. + mod.SetGno(GnoVerMissing) + } else if mod.Gno.Version == GnoVerLatest { + // current version, nothing to do. + } else { + panic("unsupported gno version " + mod.Gno.Version) + } + return +} + +// ======================================== +// ReadPkgListFromDir() lists all gno packages in the given dir directory. +func ReadPkgListFromDir(dir string) (gnomod.PkgList, error) { + var pkgs []gnomod.Pkg + + err := filepath.WalkDir(dir, func(path string, d fs.DirEntry, err error) error { + if err != nil { + return err + } + if !d.IsDir() { + return nil + } + modPath := filepath.Join(path, "gno.mod") + data, err := os.ReadFile(modPath) + if os.IsNotExist(err) { + return nil + } + if err != nil { + return err + } + + mod, err := gnomod.ParseBytes(modPath, data) + if err != nil { + return fmt.Errorf("parse: %w", err) + } + mod.Sanitize() + if err := mod.Validate(); err != nil { + return fmt.Errorf("failed to validate gno.mod in %s: %w", modPath, err) + } + + pkg, err := ReadMemPackage(path, mod.Module.Mod.Path) + if err != nil { + // ignore package files on error + pkg = &std.MemPackage{} + } + + importsMap, err := packages.Imports(pkg, nil) + if err != nil { + // ignore imports on error + importsMap = nil + } + importsRaw := importsMap.Merge(packages.FileKindPackageSource, packages.FileKindTest, packages.FileKindXTest) + + imports := make([]string, 0, len(importsRaw)) + for _, imp := range importsRaw { + // remove self and standard libraries from imports + if imp.PkgPath != mod.Module.Mod.Path && + !IsStdlib(imp.PkgPath) { + imports = append(imports, imp.PkgPath) + } + } + + pkgs = append(pkgs, gnomod.Pkg{ + Dir: path, + Name: mod.Module.Mod.Path, + Draft: mod.Draft, + Imports: imports, + }) + return nil + }) + if err != nil { + return nil, err + } + + return pkgs, nil +} diff --git a/gnovm/pkg/gnolang/go2gno.go b/gnovm/pkg/gnolang/go2gno.go index f8d7dc707c5..b2ad6079262 100644 --- a/gnovm/pkg/gnolang/go2gno.go +++ b/gnovm/pkg/gnolang/go2gno.go @@ -105,35 +105,41 @@ func ParseFile(filename string, body string) (fn *FileNode, err error) { // TODO(morgan): would be nice to add parser.SkipObjectResolution as we don't // seem to be using its features, but this breaks when testing (specifically redeclaration tests). const parseOpts = parser.ParseComments | parser.DeclarationErrors - f, err := parser.ParseFile(fs, filename, body, parseOpts) + astf, err := parser.ParseFile(fs, filename, body, parseOpts) if err != nil { return nil, err } // Print the imports from the file's AST. // spew.Dump(f) - // recover from Go2Gno. - // NOTE: Go2Gno is best implemented with panics due to inlined toXYZ() calls. - defer func() { - if r := recover(); r != nil { - if rerr, ok := r.(error); ok { - err = errors.Wrap(rerr, "parsing file") - } else { - err = errors.New(fmt.Sprintf("%v", r)).Stacktrace() + // XXX Disable this when running with -debug or similar. + if true { + // Recover from Go2Gno. + // NOTE: Go2Gno is best implemented with panics due to inlined toXYZ() calls. + defer func() { + if r := recover(); r != nil { + if rerr, ok := r.(error); ok { + err = errors.Wrap(rerr, "parsing file") + } else { + err = errors.New(fmt.Sprintf("%v", r)).Stacktrace() + } + return } - return - } - }() - // parse with Go2Gno. - fn = Go2Gno(fs, f).(*FileNode) + }() + } + // Parse with Go2Gno. + fn = Go2Gno(fs, astf).(*FileNode) fn.Name = Name(filename) return fn, nil } -func setLoc(fs *token.FileSet, pos token.Pos, n Node) Node { - posn := fs.Position(pos) - n.SetLine(posn.Line) - n.SetColumn(posn.Column) +// setSpan() will not attempt to overwrite an existing span. +// This usually happens when an inner node is passed outward, +// in which case we want to keep the original specificity. +func setSpan(fs *token.FileSet, gon ast.Node, n Node) Node { + if n.GetSpan().IsZero() { + n.SetSpan(SpanFromGo(fs, gon)) + } return n } @@ -145,7 +151,7 @@ func Go2Gno(fs *token.FileSet, gon ast.Node) (n Node) { if fs != nil { defer func() { if n != nil { - setLoc(fs, gon.Pos(), n) + setSpan(fs, gon, n) } }() } @@ -316,7 +322,7 @@ func Go2Gno(fs *token.FileSet, gon ast.Node) (n Node) { } case *ast.BlockStmt: return &BlockStmt{ - Body: toStmts(fs, gon.List), + Body: toBody(fs, gon), } case *ast.BranchStmt: return &BranchStmt{ @@ -341,13 +347,13 @@ func Go2Gno(fs *token.FileSet, gon ast.Node) (n Node) { Init: toSimp(fs, gon.Init), Cond: toExpr(fs, gon.Cond), Post: toSimp(fs, gon.Post), - Body: toStmts(fs, gon.Body.List), + Body: toBody(fs, gon.Body), } case *ast.IfStmt: thenStmt := IfCaseStmt{ - Body: toStmts(fs, gon.Body.List), + Body: toBody(fs, gon.Body), } - setLoc(fs, gon.Body.Pos(), &thenStmt) + setSpan(fs, gon.Body, &thenStmt) ess := []Stmt(nil) if gon.Else != nil { if _, ok := gon.Else.(*ast.BlockStmt); ok { @@ -360,7 +366,7 @@ func Go2Gno(fs *token.FileSet, gon ast.Node) (n Node) { Body: ess, } if gon.Else != nil { - setLoc(fs, gon.Else.Pos(), &elseStmt) + setSpan(fs, gon.Else, &elseStmt) } return &IfStmt{ Init: toSimp(fs, gon.Init), @@ -392,21 +398,23 @@ func Go2Gno(fs *token.FileSet, gon ast.Node) (n Node) { case *ast.TypeSwitchStmt: switch as := gon.Assign.(type) { case *ast.AssignStmt: - return &SwitchStmt{ + stmt := &SwitchStmt{ Init: toStmt(fs, gon.Init), X: toExpr(fs, as.Rhs[0].(*ast.TypeAssertExpr).X), IsTypeSwitch: true, Clauses: toClauses(fs, gon.Body.List), VarName: toName(as.Lhs[0].(*ast.Ident)), } + return stmt case *ast.ExprStmt: - return &SwitchStmt{ + stmt := &SwitchStmt{ Init: toStmt(fs, gon.Init), X: toExpr(fs, as.X.(*ast.TypeAssertExpr).X), IsTypeSwitch: true, Clauses: toClauses(fs, gon.Body.List), VarName: "", } + return stmt default: panicWithPos("unexpected *ast.TypeSwitchStmt.Assign type %s", reflect.TypeOf(gon.Assign).String()) @@ -650,7 +658,7 @@ func toDecls(fs *token.FileSet, gd *ast.GenDecl) (ds Decls) { Type: tipe, IsAlias: alias, } - setLoc(fs, s.Pos(), td) + setSpan(fs, s, td) ds = append(ds, td) case *ast.ValueSpec: if gd.Tok == token.CONST { @@ -683,7 +691,7 @@ func toDecls(fs *token.FileSet, gd *ast.GenDecl) (ds Decls) { Const: true, } cd.SetAttribute(ATTR_IOTA, si) - setLoc(fs, s.Pos(), cd) + setSpan(fs, s, cd) ds = append(ds, cd) } else { var names []NameExpr @@ -702,7 +710,7 @@ func toDecls(fs *token.FileSet, gd *ast.GenDecl) (ds Decls) { Values: values, Const: false, } - setLoc(fs, s.Pos(), vd) + setSpan(fs, s, vd) ds = append(ds, vd) } case *ast.ImportSpec: @@ -714,7 +722,7 @@ func toDecls(fs *token.FileSet, gd *ast.GenDecl) (ds Decls) { NameExpr: *Nx(toName(s.Name)), PkgPath: path, } - setLoc(fs, s.Pos(), im) + setSpan(fs, s, im) ds = append(ds, im) default: panic(fmt.Sprintf( @@ -752,19 +760,23 @@ func toFields(fs *token.FileSet, fields ...*ast.Field) (ftxs []FieldTypeExpr) { for _, f := range fields { if len(f.Names) == 0 { // a single unnamed field w/ type - ftxs = append(ftxs, FieldTypeExpr{ + ftx := FieldTypeExpr{ NameExpr: *Nx(""), Type: toExpr(fs, f.Type), Tag: toExpr(fs, f.Tag), - }) + } + setSpan(fs, f, &ftx) + ftxs = append(ftxs, ftx) } else { // one or more named fields for _, n := range f.Names { - ftxs = append(ftxs, FieldTypeExpr{ + ftx := FieldTypeExpr{ NameExpr: *Nx(toName(n)), Type: toExpr(fs, f.Type), Tag: toExpr(fs, f.Tag), - }) + } + setSpan(fs, f, &ftx) + ftxs = append(ftxs, ftx) } } } @@ -777,10 +789,12 @@ func toKeyValueExprs(fs *token.FileSet, elts []ast.Expr) (kvxs KeyValueExprs) { if kvx, ok := x.(*ast.KeyValueExpr); ok { kvxs[i] = *Go2Gno(fs, kvx).(*KeyValueExpr) } else { - kvxs[i] = KeyValueExpr{ + kvx := KeyValueExpr{ Key: nil, Value: toExpr(fs, x), } + setSpan(fs, x, &kvx) + kvxs[i] = kvx } } return @@ -811,8 +825,10 @@ func toClauses(fs *token.FileSet, csz []ast.Stmt) []SwitchClauseStmt { } func toSwitchClauseStmt(fs *token.FileSet, cc *ast.CaseClause) SwitchClauseStmt { - return SwitchClauseStmt{ + scs := SwitchClauseStmt{ Cases: toExprs(fs, cc.List), Body: toStmts(fs, cc.Body), } + setSpan(fs, cc, &scs) + return scs } diff --git a/gnovm/pkg/gnolang/gotypecheck.go b/gnovm/pkg/gnolang/gotypecheck.go index e34c5a547b8..e08f195e4ca 100644 --- a/gnovm/pkg/gnolang/gotypecheck.go +++ b/gnovm/pkg/gnolang/gotypecheck.go @@ -1,14 +1,13 @@ package gnolang import ( - "bytes" "fmt" "go/ast" - "go/format" "go/parser" "go/token" "go/types" "path" + "path/filepath" "slices" "strings" @@ -16,7 +15,26 @@ import ( "go.uber.org/multierr" ) -// type checking (using go/types) +/* + Type-checking (using go/types). + Refer to the [Lint and Transpile ADR](./adr/pr4264_lint_transpile.md). + XXX move to pkg/gnolang/importer.go. +*/ + +func makeGnoBuiltins(pkgName string) *std.MemFile { + file := &std.MemFile{ + Name: ".gnobuiltins.gno", // because GoParseMemPackage expects .gno. + Body: fmt.Sprintf(`package %s + +func istypednil(x any) bool { return false } // shim +func crossing() { } // shim +func cross[F any](fn F) F { return fn } // shim +func revive[F any](fn F) any { return nil } // shim +type realm interface{} // shim +`, pkgName), + } + return file +} // MemPackageGetter implements the GetMemPackage() method. It is a subset of // [Store], separated for ease of testing. @@ -24,184 +42,255 @@ type MemPackageGetter interface { GetMemPackage(path string) *std.MemPackage } -// TypeCheckMemPackage performs type validation and checking on the given -// mempkg. To retrieve dependencies, it uses getter. -// -// The syntax checking is performed entirely using Go's go/types package. -// -// If format is true, the code in msmpkg will be automatically updated with the -// formatted source code. -func TypeCheckMemPackage(mempkg *std.MemPackage, getter MemPackageGetter, format bool) error { - return typeCheckMemPackage(mempkg, getter, false, format) +type TypeCheckFilesResult struct { + FileSet *token.FileSet + SourceFiles []*ast.File // All normal .gno files (and _test.gno files if wtests). + TestPackageFiles []*ast.File // All files in test packages (_test.gno & _testfile.gno). + TestFiles []*ast.File // All standalone test files (_testfile.gno). } -// TypeCheckMemPackageTest performs the same type checks as [TypeCheckMemPackage], -// but allows re-declarations. +// TypeCheckMemPackage performs type validation and checking on the given +// mpkg. To retrieve dependencies, it uses getter. // -// Note: like TypeCheckMemPackage, this function ignores tests and filetests. -func TypeCheckMemPackageTest(mempkg *std.MemPackage, getter MemPackageGetter) error { - return typeCheckMemPackage(mempkg, getter, true, false) -} - -func typeCheckMemPackage(mempkg *std.MemPackage, getter MemPackageGetter, testing, format bool) error { - var errs error - imp := &gnoImporter{ - getter: getter, - cache: map[string]gnoImporterResult{}, +// The syntax checking is performed entirely using Go's go/types package. +func TypeCheckMemPackage(mpkg *std.MemPackage, getter MemPackageGetter, pmode ParseMode) ( + pkg *types.Package, tfiles *TypeCheckFilesResult, errs error, +) { + var gimp *gnoImporter + gimp = &gnoImporter{ + pkgPath: mpkg.Path, + getter: getter, + cache: map[string]*gnoImporterResult{}, cfg: &types.Config{ Error: func(err error) { - errs = multierr.Append(errs, err) + gimp.Error(err) }, }, - allowRedefinitions: testing, + errors: nil, } - imp.cfg.Importer = imp + gimp.cfg.Importer = gimp - _, err := imp.parseCheckMemPackage(mempkg, format) - // prefer to return errs instead of err: - // err will generally contain only the first error encountered. - if errs != nil { - return errs - } - return err + strict := true // check gno.mod exists + return gimp.typeCheckMemPackage(mpkg, pmode, strict) } type gnoImporterResult struct { - pkg *types.Package - err error + pkg *types.Package + err error + pending bool // for cyclic import detection } +// gimp. +// gimp type checks. +// gimp remembers. +// gimp. type gnoImporter struct { - getter MemPackageGetter - cache map[string]gnoImporterResult - cfg *types.Config - - // allow symbol redefinitions? (test standard libraries) - allowRedefinitions bool + // when importing self (from xxx_test package) include *_test.gno. + pkgPath string + getter MemPackageGetter + cache map[string]*gnoImporterResult + cfg *types.Config + errors []error // there may be many for a single import + stack []string // stack of pkgpaths for cyclic import detection } // Unused, but satisfies the Importer interface. -func (g *gnoImporter) Import(path string) (*types.Package, error) { - return g.ImportFrom(path, "", 0) +func (gimp *gnoImporter) Import(path string) (*types.Package, error) { + return gimp.ImportFrom(path, "", 0) } -type importNotFoundError string - -func (e importNotFoundError) Error() string { return "import not found: " + string(e) } +// Pass through to cfg.Error for collecting all type-checking errors. +func (gimp *gnoImporter) Error(err error) { + gimp.errors = append(gimp.errors, err) +} // ImportFrom returns the imported package for the given import -// path when imported by a package file located in dir. -func (g *gnoImporter) ImportFrom(path, _ string, _ types.ImportMode) (*types.Package, error) { - if pkg, ok := g.cache[path]; ok { - return pkg.pkg, pkg.err +// pkgPath when imported by a package file located in dir. +func (gimp *gnoImporter) ImportFrom(pkgPath, _ string, _ types.ImportMode) (*types.Package, error) { + if result, ok := gimp.cache[pkgPath]; ok { + if result.pending { + idx := slices.Index(gimp.stack, pkgPath) + cycle := gimp.stack[idx:] + err := ImportCycleError{Cycle: cycle} + // NOTE: see comment below for ImportNotFoundError. + // gimp.importErrors = append(gimp.importErrors, err) + result.err = err + return nil, err + } else { + return result.pkg, result.err + } } - mpkg := g.getter.GetMemPackage(path) + result := &gnoImporterResult{pending: true} + gimp.cache[pkgPath] = result + gimp.stack = append(gimp.stack, pkgPath) + defer func() { + gimp.stack = gimp.stack[:len(gimp.stack)-1] + }() + mpkg := gimp.getter.GetMemPackage(pkgPath) if mpkg == nil { - err := importNotFoundError(path) - g.cache[path] = gnoImporterResult{err: err} + err := ImportNotFoundError{PkgPath: pkgPath} + // NOTE: When returning an err, Go will strip type information. + // When panic'd, the type information will be preserved, but + // the file location information will be lost. Therefore, + // return the error but later in printError() parse the message + // and recast to a gnoImportError. + // TODO: For completeness we could append to a separate slice + // and check presence in gimp.importErrors before converting. + // gimp.importErrors = append(gimp.importErrors, err) + result.err = err + result.pending = false return nil, err } - fmt_ := false - result, err := g.parseCheckMemPackage(mpkg, fmt_) - g.cache[path] = gnoImporterResult{pkg: result, err: err} - return result, err -} - -func (g *gnoImporter) parseCheckMemPackage(mpkg *std.MemPackage, fmt_ bool) (*types.Package, error) { - // This map is used to allow for function re-definitions, which are allowed - // in Gno (testing context) but not in Go. - // This map links each function identifier with a closure to remove its - // associated declaration. - var delFunc map[string]func() - if g.allowRedefinitions { - delFunc = make(map[string]func()) - } - - fset := token.NewFileSet() - files := make([]*ast.File, 0, len(mpkg.Files)) - const parseOpts = parser.ParseComments | parser.DeclarationErrors | parser.SkipObjectResolution - var errs error - for _, file := range mpkg.Files { - // Ignore non-gno files. - // TODO: support filetest type checking. (should probably handle as each its - // own separate pkg, which should also be typechecked) - if !strings.HasSuffix(file.Name, ".gno") || - strings.HasSuffix(file.Name, "_test.gno") || - strings.HasSuffix(file.Name, "_filetest.gno") { - continue - } + pmode := ParseModeProduction // don't parse test files for imports... + if gimp.pkgPath == pkgPath { + // ...unless importing self from a *_test.gno + // file with package name xxx_test. + pmode = ParseModeIntegration + } + strict := false // don't check for gno.mod for imports. + pkg, _, errs := gimp.typeCheckMemPackage(mpkg, pmode, strict) + if errs != nil { + result.err = errs + result.pending = false + return nil, errs + } + result.pkg = pkg + result.err = nil + result.pending = false + return pkg, errs +} - f, err := parser.ParseFile(fset, path.Join(mpkg.Path, file.Name), file.Body, parseOpts) +// Assumes that the code is Gno 0.9. +// If not, first use `gno lint` to transpile the code. +// Returns parsed *types.Package, *token.FileSet, []*ast.File. +// +// Args: +// - pmode: ParseModeAll for type-checking all files. +// ParseModeProduction when type-checking imports. +// - strict: If true errors on gno.mod version mismatch. +func (gimp *gnoImporter) typeCheckMemPackage(mpkg *std.MemPackage, pmode ParseMode, strict bool) ( + pkg *types.Package, tfiles *TypeCheckFilesResult, errs error, +) { + // See adr/pr4264_lint_transpile.md + // STEP 2: Check gno.mod version. + if strict { + _, err := ParseCheckGnoMod(mpkg) if err != nil { - errs = multierr.Append(errs, err) - continue + return nil, nil, err } + } - //---------------------------------------- - // Non-logical formatting transforms + // STEP 3: Parse the mem package to Go AST. + gofset, gofs, _gofs, tgofs, errs := GoParseMemPackage(mpkg, pmode) + if errs != nil { + return nil, nil, errs + } + if pmode == ParseModeProduction && (len(_gofs) > 0 || len(tgofs) > 0) { + panic("unexpected test files from GoParseMemPackage()") + } + if pmode == ParseModeIntegration && (len(_gofs) > 0 || len(tgofs) > 0) { + panic("unexpected xxx_test and *_filetest.gno tests") + } - if delFunc != nil { - deleteOldIdents(delFunc, f) - } + // STEP 3: Add and Parse .gnobuiltins.go file. + file := makeGnoBuiltins(mpkg.Name) + const parseOpts = parser.ParseComments | + parser.DeclarationErrors | + parser.SkipObjectResolution + gmgof, err := parser.ParseFile( + gofset, + path.Join(mpkg.Path, file.Name), + file.Body, + parseOpts) + if err != nil { + panic(fmt.Errorf("error parsing gotypecheck .gnobuiltins.gno file: %w", err)) + } - // Enforce formatting. - // This must happen before logical transforms. - if fmt_ { - var buf bytes.Buffer - err = format.Node(&buf, fset, f) - if err != nil { - errs = multierr.Append(errs, err) - continue - } - file.Body = buf.String() - } + // NOTE: When returning errs from this function, - //---------------------------------------- - // Logical transforms - - // No need to filter because of gnobuiltins.go. - // But keep this code block for future transforms. - /* - // filter crossings for type checker - if err := filterCrossing(f); err != nil { - errs = multierr.Append(errs, err) - continue - } - */ + // STEP 4: Type-check Gno0.9 AST in Go (normal, and _test.gno if ParseModeIntegration). + gofs = append(gofs, gmgof) + // NOTE: .Check doesn't return an err, it appends to .errors. also, + // gimp.errors may already be populated. For example, even after an + // import failure the Go type checker will continue to try to import + // more imports, to collect more errors for the user to see. + numErrs := len(gimp.errors) + pkg, _ = gimp.cfg.Check(mpkg.Path, gofset, gofs, nil) + /* NOTE: Uncomment to fail earlier. + if len(gimp.errors) != numErrs { + errs = multierr.Combine(gimp.errors...) + return + } + */ - files = append(files, f) + // STEP 4: Type-check Gno0.9 AST in Go (xxx_test package if ParseModeAll). + if strings.HasSuffix(mpkg.Name, "_test") { + // e.g. When running a filetest // PKGPATH: xxx_test. + } else { + gmgof.Name = ast.NewIdent(mpkg.Name + "_test") + defer func() { gmgof.Name = ast.NewIdent(mpkg.Name) }() // revert } - if errs != nil { - return nil, errs + _gofs2 := append(_gofs, gmgof) + _, _ = gimp.cfg.Check(mpkg.Path+"_test", gofset, _gofs2, nil) + /* NOTE: Uncomment to fail earlier. + if len(gimp.errors) != numErrs { + errs = multierr.Combine(gimp.errors...) + return } + */ - // Add builtins file. - file := &std.MemFile{ - Name: ".gnobuiltins.go", - Body: fmt.Sprintf(`package %s - -func istypednil(x any) bool { return false } // shim -func crossing() { } // shim -func cross[F any](fn F) F { return fn } // shim -func revive[F any](fn F) any { return nil } // shim -`, mpkg.Name), - } - f, err := parser.ParseFile(fset, path.Join(mpkg.Path, file.Name), file.Body, parseOpts) - if err != nil { - panic("error parsing gotypecheck gnobuiltins.go file") + // STEP 4: Type-check Gno0.9 AST in Go (_filetest.gno if ParseModeAll). + defer func() { gmgof.Name = ast.NewIdent(mpkg.Name) }() // revert + for _, tgof := range tgofs { + // Each filetest is its own package. + // XXX If we're re-parsing the filetest anyways, + // change GoParseMemPackage to not parse into tgofs. + tfname := filepath.Base(gofset.File(tgof.Pos()).Name()) + tpname := tgof.Name.String() + tfile := mpkg.GetFile(tfname) + // XXX If filetest are having issues, consider this: + // pkgPath := fmt.Sprintf("%s_filetest%d", mpkg.Path, i) + pkgPath := mpkg.Path + tmpkg := &std.MemPackage{Name: tpname, Path: pkgPath} + tmpkg.NewFile(tfname, tfile.Body) + bfile := makeGnoBuiltins(tpname) + tmpkg.AddFile(bfile) + gofset2, gofs2, _, tgofs2, _ := GoParseMemPackage(tmpkg, ParseModeAll) + if len(gimp.errors) != numErrs { + /* NOTE: Uncomment to fail earlier. + errs = multierr.Combine(gimp.errors...) + return + */ + continue + } + // gofs2 (.gnobuiltins.gno), tgofs2 (*_testfile.gno) + gofs2 = append(gofs2, tgofs2...) + _, _ = gimp.cfg.Check(tmpkg.Path, gofset2, gofs2, nil) + /* NOTE: Uncomment to fail earlier. + if len(gimp.errors) != numErrs { + errs = multierr.Combine(gimp.errors...) + return + } + */ } - files = append(files, f) - pkg, err := g.cfg.Check(mpkg.Path, fset, files, nil) - return pkg, err + tfiles = &TypeCheckFilesResult{ + FileSet: gofset, + SourceFiles: gofs, + TestPackageFiles: _gofs, + TestFiles: gofs, + } + return pkg, tfiles, multierr.Combine(gimp.errors[numErrs:]...) } -func deleteOldIdents(idents map[string]func(), f *ast.File) { - for _, decl := range f.Decls { +func deleteOldIdents(idents map[string]func(), gof *ast.File) { + for _, decl := range gof.Decls { fd, ok := decl.(*ast.FuncDecl) // ignore methods and init functions //nolint:goconst - if !ok || fd.Recv != nil || fd.Name.Name == "init" { + if !ok || + fd.Recv != nil || + fd.Name.Name == "init" { continue } if del := idents[fd.Name.Name]; del != nil { @@ -209,44 +298,67 @@ func deleteOldIdents(idents map[string]func(), f *ast.File) { } decl := decl idents[fd.Name.Name] = func() { - // NOTE: cannot use the index as a file may contain multiple decls to be removed, - // so removing one would make all "later" indexes wrong. - f.Decls = slices.DeleteFunc(f.Decls, func(d ast.Decl) bool { return decl == d }) + // NOTE: cannot use the index as a file may contain + // multiple decls to be removed, so removing one would + // make all "later" indexes wrong. + gof.Decls = slices.DeleteFunc(gof.Decls, + func(d ast.Decl) bool { return decl == d }) } } } -/* -// This is how ast filtering would have worked. -// Keep this comment block around in case we need it. -func filterCrossing(f *ast.File) (err error) { - astutil.Apply(f, nil, func(c *astutil.Cursor) bool { - switch n := c.Node().(type) { - case *ast.ExprStmt: - if ce, ok := n.X.(*ast.CallExpr); ok { - if id, ok := ce.Fun.(*ast.Ident); ok && id.Name == "crossing" { - // Validate syntax. - if len(ce.Args) != 0 { - err = errors.New("crossing called with non empty parameters") - } - // Delete statement 'crossing()'. - c.Delete() - } - } - case *ast.CallExpr: - if id, ok := n.Fun.(*ast.Ident); ok && id.Name == "cross" { - // Replace expression 'cross(x)' by 'x'. - var a ast.Node - if len(n.Args) == 1 { - a = n.Args[0] - } else { - err = errors.New("cross called with invalid parameters") - } - c.Replace(a) - } - } - return true - }) - return err +//---------------------------------------- +// Errors + +// ImportError is an interface type. +type ImportError interface { + assertImportError() + error + GetLocation() string + GetMsg() string +} + +func (e ImportNotFoundError) assertImportError() {} +func (e ImportCycleError) assertImportError() {} + +var ( + _ ImportError = ImportNotFoundError{} + _ ImportError = ImportCycleError{} +) + +// ImportNotFoundError implements ImportError +type ImportNotFoundError struct { + Location string + PkgPath string +} + +func (e ImportNotFoundError) GetLocation() string { return e.Location } + +func (e ImportNotFoundError) GetMsg() string { return fmt.Sprintf("unknown import path %q", e.PkgPath) } + +func (e ImportNotFoundError) Error() string { return importErrorString(e) } + +// ImportCycleError implements ImportError +type ImportCycleError struct { + Location string + Cycle []string +} + +func (e ImportCycleError) GetLocation() string { return e.Location } + +func (e ImportCycleError) GetMsg() string { + return fmt.Sprintf("cyclic import detected: %s -> %s", strings.Join(e.Cycle, " -> "), e.Cycle[0]) +} + +func (e ImportCycleError) Error() string { return importErrorString(e) } + +// helper +func importErrorString(err ImportError) string { + loc := err.GetLocation() + msg := err.GetMsg() + if loc != "" { + return loc + ": " + msg + } else { + return msg + } } -*/ diff --git a/gnovm/pkg/gnolang/gotypecheck_test.go b/gnovm/pkg/gnolang/gotypecheck_test.go index b7f06b0776e..9eaca8695ab 100644 --- a/gnovm/pkg/gnolang/gotypecheck_test.go +++ b/gnovm/pkg/gnolang/gotypecheck_test.go @@ -138,7 +138,7 @@ func TestTypeCheckMemPackage(t *testing.T) { errContains("assignment mismatch", "too many return values"), }, { - "TestsIgnored", + "TestsAlso", &std.MemPackage{ Name: "hello", Path: "gno.land/p/demo/hello", @@ -151,13 +151,12 @@ func TestTypeCheckMemPackage(t *testing.T) { }, { Name: "hello_test.gno", - Body: `This is not valid Gno code, but it doesn't matter because test - files are not checked.`, + Body: `This is not valid Gno code, and it matters.`, }, }, }, nil, - nil, + errContains("gno.land/p/demo/hello/hello_test.gno:1:1: expected 'package', found This"), }, { "ImportFailed", @@ -175,7 +174,7 @@ func TestTypeCheckMemPackage(t *testing.T) { }, }, mockPackageGetter{}, - errContains("import not found: std"), + errContains("unknown import path \"std\""), }, { "ImportSucceeded", @@ -364,8 +363,7 @@ func TestTypeCheckMemPackage(t *testing.T) { t.Run(tc.name, func(t *testing.T) { t.Parallel() - format := false - err := TypeCheckMemPackage(tc.pkg, tc.getter, format) + _, _, err := TypeCheckMemPackage(tc.pkg, tc.getter, ParseModeIntegration) if tc.check == nil { assert.NoError(t, err) } else { @@ -399,21 +397,21 @@ func TestTypeCheckMemPackage_format(t *testing.T) { } mpkgGetter := mockPackageGetter{} - format := false - err := TypeCheckMemPackage(pkg, mpkgGetter, format) + _, _, err := TypeCheckMemPackage(pkg, mpkgGetter, ParseModeIntegration) assert.NoError(t, err) assert.Equal(t, input, pkg.Files[0].Body) // unchanged - expected := `package hello + /* XXX TypeChecker no longer does the formatting. + expected := `package hello -func Hello(name string) string { - return "hello" + name -} -` + func Hello(name string) string { + return "hello" + name + } + ` - format = true - err = TypeCheckMemPackage(pkg, mpkgGetter, format) - assert.NoError(t, err) - assert.NotEqual(t, input, pkg.Files[0].Body) - assert.Equal(t, expected, pkg.Files[0].Body) + _, _, err = TypeCheckMemPackage(pkg, mpkgGetter) + assert.NoError(t, err) + assert.NotEqual(t, input, pkg.Files[0].Body) + assert.Equal(t, expected, pkg.Files[0].Body) + */ } diff --git a/gnovm/pkg/gnolang/helpers.go b/gnovm/pkg/gnolang/helpers.go index 15b484cff55..51a1298ea39 100644 --- a/gnovm/pkg/gnolang/helpers.go +++ b/gnovm/pkg/gnolang/helpers.go @@ -72,7 +72,9 @@ func IsPPackagePath(pkgPath string) bool { return true } -// IsStdlib determines whether s is a pkgpath for a standard library. +// IsStdlib determines whether s is a pkgpath for a standard library. If it +// doesn't start with a domain (e.g. has a dot), it is stdlib. This +// implementation ignores dots after the first slash. func IsStdlib(s string) bool { idx := strings.IndexByte(s, '/') if idx < 0 { @@ -82,6 +84,10 @@ func IsStdlib(s string) bool { return strings.IndexByte(s[:idx+1], '.') < 0 } +func IsTestFile(file string) bool { + return strings.HasSuffix(file, "_test.gno") || strings.HasSuffix(file, "_filetest.gno") +} + // ---------------------------------------- // AST Construction (Expr) // These are copied over from go-amino-x, but produces Gno ASTs. diff --git a/gnovm/pkg/gnolang/internal/softfloat/runtime_softfloat64.go b/gnovm/pkg/gnolang/internal/softfloat/runtime_softfloat64.go index 7623b9c2077..5c8898b1d59 100644 --- a/gnovm/pkg/gnolang/internal/softfloat/runtime_softfloat64.go +++ b/gnovm/pkg/gnolang/internal/softfloat/runtime_softfloat64.go @@ -418,6 +418,7 @@ func fintto64(val int64) (f uint64) { } return fpack64(fs, mant, int(mantbits64), 0) } + func fintto32(val int64) (f uint32) { fs := uint64(val) & (1 << 63) mant := uint64(val) diff --git a/gnovm/pkg/gnolang/machine.go b/gnovm/pkg/gnolang/machine.go index 12583261a07..857493aa13d 100644 --- a/gnovm/pkg/gnolang/machine.go +++ b/gnovm/pkg/gnolang/machine.go @@ -196,9 +196,9 @@ func (m *Machine) SetActivePackage(pv *PackageValue) { // to support cases of stdlibs processed through [RunMemPackagesWithOverrides]. func (m *Machine) PreprocessAllFilesAndSaveBlockNodes() { ch := m.Store.IterMemPackage() - for memPkg := range ch { - fset := ParseMemPackage(memPkg) - pn := NewPackageNode(Name(memPkg.Name), memPkg.Path, fset) + for mpkg := range ch { + fset := ParseMemPackage(mpkg) + pn := NewPackageNode(Name(mpkg.Name), mpkg.Path, fset) m.Store.SetBlockNode(pn) PredefineFileSet(m.Store, pn, fset) for _, fn := range fset.Files { @@ -224,39 +224,43 @@ func (m *Machine) PreprocessAllFilesAndSaveBlockNodes() { //---------------------------------------- // top level Run* methods. -// Parses files, sets the package if doesn't exist, runs files, saves mempkg -// and corresponding package node, package value, and types to store. Save -// is set to false for tests where package values may be native. -func (m *Machine) RunMemPackage(memPkg *std.MemPackage, save bool) (*PackageNode, *PackageValue) { +// Sorts the package, then sets the package if doesn't exist, runs files, saves +// mpkg and corresponding package node, package value, and types to store. Save +// is set to false for tests where package values may be native. NOTE: Does +// not validate the mpkg. Caller must validate the mpkg before calling. +func (m *Machine) RunMemPackage(mpkg *std.MemPackage, save bool) (*PackageNode, *PackageValue) { if bm.OpsEnabled || bm.StorageEnabled { bm.InitMeasure() } if bm.StorageEnabled { defer bm.FinishStore() } - return m.runMemPackage(memPkg, save, false) + return m.runMemPackage(mpkg, save, false) } // RunMemPackageWithOverrides works as [RunMemPackage], however after parsing, -// declarations are filtered removing duplicate declarations. -// To control which declaration overrides which, use [ReadMemPackageFromList], -// putting the overrides at the top of the list. -func (m *Machine) RunMemPackageWithOverrides(memPkg *std.MemPackage, save bool) (*PackageNode, *PackageValue) { - return m.runMemPackage(memPkg, save, true) +// declarations are filtered removing duplicate declarations. To control which +// declaration overrides which, use [ReadMemPackageFromList], putting the +// overrides at the top of the list. NOTE: Does not validate the mpkg, except +// when saving validates with type MemPackageTypeAny. +func (m *Machine) RunMemPackageWithOverrides(mpkg *std.MemPackage, save bool) (*PackageNode, *PackageValue) { + return m.runMemPackage(mpkg, save, true) } -func (m *Machine) runMemPackage(memPkg *std.MemPackage, save, overrides bool) (*PackageNode, *PackageValue) { +func (m *Machine) runMemPackage(mpkg *std.MemPackage, save, overrides bool) (*PackageNode, *PackageValue) { + // sort mpkg. + mpkg.Sort() // parse files. - files := ParseMemPackage(memPkg) + files := ParseMemPackage(mpkg) // make and set package if doesn't exist. pn := (*PackageNode)(nil) pv := (*PackageValue)(nil) - if m.Package != nil && m.Package.PkgPath == memPkg.Path { + if m.Package != nil && m.Package.PkgPath == mpkg.Path { pv = m.Package - loc := PackageNodeLocation(memPkg.Path) + loc := PackageNodeLocation(mpkg.Path) pn = m.Store.GetBlockNode(loc).(*PackageNode) } else { - pn = NewPackageNode(Name(memPkg.Name), memPkg.Path, &FileSet{}) + pn = NewPackageNode(Name(mpkg.Name), mpkg.Path, &FileSet{}) pv = pn.NewPackage() m.Store.SetBlockNode(pn) m.Store.SetCachePackage(pv) @@ -280,7 +284,7 @@ func (m *Machine) runMemPackage(memPkg *std.MemPackage, save, overrides bool) (* if save { m.resavePackageValues(throwaway) // store mempackage - m.Store.AddMemPackage(memPkg) + m.Store.AddMemPackage(mpkg, MemPackageTypeAny) if throwaway != nil { m.Realm = nil } @@ -431,6 +435,7 @@ func (m *Machine) Stacktrace() (stacktrace Stacktrace) { // Production must not use this, because realm package init // must happen after persistence and realm finalization, // then changes from init persisted again. +// m.Package must match fns's package path. func (m *Machine) RunFiles(fns ...*FileNode) { pv := m.Package if pv == nil { @@ -458,14 +463,19 @@ func (m *Machine) RunFiles(fns ...*FileNode) { } // PreprocessFiles runs Preprocess on the given files. It is used to detect -// compile-time errors in the package. -func (m *Machine) PreprocessFiles(pkgName, pkgPath string, fset *FileSet, save, withOverrides bool) (*PackageNode, *PackageValue) { +// compile-time errors in the package. It is also usde to preprocess files from +// the package getter for tests, e.g. from "gnovm/tests/files/extern/*", or from +// "examples/*". +func (m *Machine) PreprocessFiles(pkgName, pkgPath string, fset *FileSet, save, withOverrides bool, fixFrom string) (*PackageNode, *PackageValue) { if !withOverrides { if err := checkDuplicates(fset); err != nil { panic(fmt.Errorf("running package %q: %w", pkgName, err)) } } pn := NewPackageNode(Name(pkgName), pkgPath, fset) + if fixFrom != "" { + pn.SetAttribute(ATTR_FIX_FROM, fixFrom) + } pv := pn.NewPackage() pb := pv.GetBlock(m.Store) m.SetActivePackage(pv) @@ -505,6 +515,7 @@ func (m *Machine) PreprocessFiles(pkgName, pkgPath string, fset *FileSet, save, // Add files to the package's *FileSet and run decls in them. // This will also run each init function encountered. // Returns the updated typed values of package. +// m.Package must match fns's package path. func (m *Machine) runFileDecls(withOverrides bool, fns ...*FileNode) []TypedValue { // Files' package names must match the machine's active one. // if there is one. @@ -597,8 +608,8 @@ func (m *Machine) runFileDecls(withOverrides bool, fns ...*FileNode) []TypedValu continue } else { // is an undefined dependency. panic(fmt.Sprintf( - "dependency %s not defined in fileset with files %v", - dep, fs.FileNames())) + "%s/%s:%s: dependency %s not defined in fileset with files %v", + pv.PkgPath, fn.Name, decl.GetPos().String(), dep, fs.FileNames())) } } // if dep already in loopfindr, abort. @@ -609,7 +620,8 @@ func (m *Machine) runFileDecls(withOverrides bool, fns ...*FileNode) []TypedValu continue } else { panic(fmt.Sprintf( - "loop in variable initialization: dependency trail %v circularly depends on %s", loopfindr, dep)) + "%s/%s:%s: loop in variable initialization: dependency trail %v circularly depends on %s", + pv.PkgPath, fn.Name, decl.GetPos().String(), loopfindr, dep)) } } // run dependency declaration @@ -808,8 +820,10 @@ func (m *Machine) EvalStaticTypeOf(last BlockNode, x Expr) Type { if debug { m.Printf("Machine.EvalStaticTypeOf(%v, %v)\n", last, x) } - // X must have been preprocessed. - if x.GetAttribute(ATTR_PREPROCESSED) == nil { + // X must have been preprocessed or a predefined func lit expr. + if x.GetAttribute(ATTR_PREPROCESSED) == nil && + x.GetAttribute(ATTR_PREPROCESS_SKIPPED) == nil && + x.GetAttribute(ATTR_PREPROCESS_INCOMPLETE) == nil { panic(fmt.Sprintf( "Machine.EvalStaticTypeOf(x) expression not yet preprocessed: %s", x.String())) @@ -2331,7 +2345,6 @@ func (m *Machine) String() string { if m == nil { return "Machine:nil" } - // Calculate some reasonable total length to avoid reallocation // Assuming an average length of 32 characters per string var ( @@ -2342,43 +2355,31 @@ func (m *Machine) String() string { obsLength = len(m.Blocks) * 32 fsLength = len(m.Frames) * 32 exceptionsLength = m.Exception.NumExceptions() * 32 - - totalLength = vsLength + ssLength + xsLength + bsLength + obsLength + fsLength + exceptionsLength + totalLength = vsLength + ssLength + xsLength + bsLength + obsLength + fsLength + exceptionsLength ) - var sb strings.Builder builder := &sb // Pointer for use in fmt.Fprintf. builder.Grow(totalLength) - fmt.Fprintf(builder, "Machine:\n Stage: %v\n Op: %v\n Values: (len: %d)\n", m.Stage, m.Ops[:m.NumOps], m.NumValues) - for i := m.NumValues - 1; i >= 0; i-- { fmt.Fprintf(builder, " #%d %v\n", i, m.Values[i]) } - builder.WriteString(" Exprs:\n") - for i := len(m.Exprs) - 1; i >= 0; i-- { fmt.Fprintf(builder, " #%d %v\n", i, m.Exprs[i]) } - builder.WriteString(" Stmts:\n") - for i := len(m.Stmts) - 1; i >= 0; i-- { fmt.Fprintf(builder, " #%d %v\n", i, m.Stmts[i]) } - builder.WriteString(" Blocks:\n") - for i := len(m.Blocks) - 1; i > 0; i-- { b := m.Blocks[i] if b == nil { continue } - gen := builder.Len()/3 + 1 gens := "@" // strings.Repeat("@", gen) - if pv, ok := b.Source.(*PackageNode); ok { // package blocks have too much, so just // print the pkgpath. @@ -2387,7 +2388,6 @@ func (m *Machine) String() string { bsi := b.StringIndented(" ") fmt.Fprintf(builder, " %s(%d) %s\n", gens, gen, bsi) } - // Update b switch bp := b.Parent.(type) { case nil: @@ -2401,16 +2401,12 @@ func (m *Machine) String() string { panic("should not happen") } } - builder.WriteString(" Blocks (other):\n") - for i := len(m.Blocks) - 2; i >= 0; i-- { b := m.Blocks[i] - if b == nil || b.Source == nil { continue } - if _, ok := b.Source.(*PackageNode); ok { break // done, skip *PackageNode. } else { @@ -2418,22 +2414,17 @@ func (m *Machine) String() string { b.StringIndented(" ")) } } - builder.WriteString(" Frames:\n") - for i := len(m.Frames) - 1; i >= 0; i-- { fmt.Fprintf(builder, " #%d %s\n", i, m.Frames[i]) } - if m.Realm != nil { fmt.Fprintf(builder, " Realm:\n %s\n", m.Realm.Path) } - if m.Exception != nil { builder.WriteString(" Exception:\n") fmt.Fprintf(builder, " %s\n", m.Exception.Sprint(m)) } - return builder.String() } @@ -2441,16 +2432,13 @@ func (m *Machine) ExceptionStacktrace() string { if m.Exception == nil { return "" } - var builder strings.Builder - last := m.Exception first := m.Exception var numPrevious int for ; first.Previous != nil; first = first.Previous { numPrevious++ } - builder.WriteString(first.StringWithStacktrace(m)) if numPrevious >= 2 { fmt.Fprintf(&builder, "... %d panic(s) elided ...\n", numPrevious-1) diff --git a/gnovm/pkg/gnolang/mempackage.go b/gnovm/pkg/gnolang/mempackage.go new file mode 100644 index 00000000000..d8f8594c6de --- /dev/null +++ b/gnovm/pkg/gnolang/mempackage.go @@ -0,0 +1,162 @@ +package gnolang + +import ( + "fmt" + "path" + "regexp" + "slices" + "strings" + + "github.com/gnolang/gno/tm2/pkg/std" + "go.uber.org/multierr" +) + +var ( + // NOTE: These are further restrictions upon the validation that already happens by std.MemPackage.Validate(). + // sub.domain.com/a/any + // sub.domain.com/b/single + // sub.domain.com/c/letter + // sub.domain.com/d/works + // sub.domain.com/r/realm + // sub.domain.com/r/realm/path + // sub.domain.com/p/package/path + // See also tm2/pkg/std/memfile.go. + // XXX test exhaustively balanced futureproof vs restrictive. + reGnoPkgPathURL = regexp.MustCompile(`^([a-z0-9-]+\.)*[a-z0-9-]+\.[a-z]{2,}\/(?:[a-z])(?:\/_?[a-z][a-z0-9_]*)+$`) + reGnoPkgPathStd = regexp.MustCompile(`^([a-z][a-z0-9_]*\/)*[a-z][a-z0-9_]+$`) +) + +var ( + allowedMemPackageFiles = []string{ + "LICENSE", + "README.md", + "gno.mod", + } + allowedMemPackageFileExtensions = []string{ + ".gno", + } + badMemPackageFileExtensions = []string{ + ".gen.go", + } +) + +type MemPackageType string + +const ( + MemPackageTypeAny MemPackageType = "MemPackageTypeAny" // anything but not filetests only + MemPackageTypeStdlib MemPackageType = "MemPackageTypeStdlib" // stdlibs only + MemPackageTypeNormal MemPackageType = "MemPackageTypeNormal" // no stdlibs, gno pkg path, may include filetests + MemPackageTypeFiletests MemPackageType = "MemPackageTypeFiletests" // filetests only +) + +type ValidateMemPackageOptions struct { + Type MemPackageType +} + +// Validates a non-stdlib mempackage. +func ValidateMemPackage(mpkg *std.MemPackage) error { + return ValidateMemPackageWithOptions(mpkg, ValidateMemPackageOptions{ + Type: MemPackageTypeNormal, // Keep this for defensiveness. + }) +} + +func ValidateMemPackageWithOptions(mpkg *std.MemPackage, opts ValidateMemPackageOptions) (errs error) { + // Check for file sorting, string lengths, uniqueness... + err := mpkg.ValidateBasic() + if err != nil { + return err + } + // Validate mpkg path. + if true && // none of these match... + !reGnoPkgPathURL.MatchString(mpkg.Path) && + !reGnoPkgPathStd.MatchString(mpkg.Path) && + opts.Type != MemPackageTypeAny { // .ValidateBasic() ensured rePkgPathRUL + return fmt.Errorf("invalid package/realm path %q", mpkg.Path) + } + // Check stdlib. + isStdlib := IsStdlib(mpkg.Path) + if isStdlib && !(opts.Type == MemPackageTypeStdlib || opts.Type == MemPackageTypeAny) { + return fmt.Errorf("invalid package path %q: unexpected stdlib-type path", mpkg.Path) + } + if !isStdlib && opts.Type == MemPackageTypeStdlib { + return fmt.Errorf("invalid package path %q: expected stdlib-type path", mpkg.Path) + } + allowedMemPackageFileExtensions := allowedMemPackageFileExtensions + if isStdlib { // Allow transpilation to work on stdlib with native functions. + allowedMemPackageFileExtensions = append(allowedMemPackageFileExtensions, ".go") + } + // Validate package name. + if err := validatePkgName(Name(mpkg.Name)); err != nil { + return err + } + // Validate files. + if mpkg.IsEmpty() { + return fmt.Errorf("package has no files") + } + numGnoFiles := 0 + pkgNameFound := false + for _, mfile := range mpkg.Files { + // Validate file name. + fname := mfile.Name + if endsWithAny(fname, badMemPackageFileExtensions) { + errs = multierr.Append(errs, fmt.Errorf("invalid file %q: illegal file extension", fname)) + continue + } + if strings.HasPrefix(fname, ".") { + errs = multierr.Append(errs, fmt.Errorf("invalid file %q: file name cannot start with a dot", fname)) + continue + } + if strings.Contains(fname, "/") { + errs = multierr.Append(errs, fmt.Errorf("invalid file %q: file name cannot contain a slash", fname)) + continue + } + if !endsWithAny(fname, allowedMemPackageFileExtensions) { + if !slices.Contains(allowedMemPackageFiles, fname) { + errs = multierr.Append(errs, fmt.Errorf("invalid file %q: unrecognized file type", fname)) + continue + } + } + // Validate .gno package names. + if strings.HasSuffix(fname, ".gno") { + numGnoFiles += 1 + pkgName, err := PackageNameFromFileBody(path.Join(mpkg.Path, fname), mfile.Body) + if err != nil { + errs = multierr.Append(errs, err) + continue + } + if pkgName != Name(mpkg.Name) { // Check validity but skip if mpkg.Name (already checked). + if err := validatePkgName(pkgName); err != nil { + errs = multierr.Append(errs, fmt.Errorf("invalid file %q: invalid package name", pkgName)) + continue + } + } + if opts.Type == MemPackageTypeFiletests || strings.HasSuffix(fname, "_filetest.gno") { + // Any valid package name is OK for filetests. + if pkgName == Name(mpkg.Name) { + pkgNameFound = true + } + } else if strings.HasSuffix(fname, "_test.gno") { + if pkgName == Name(mpkg.Name) || pkgName == Name(mpkg.Name)+"_test" { + pkgNameFound = true + } else { + errs = multierr.Append(errs, fmt.Errorf("invalid file %q: invalid package name", pkgName)) + continue + } + } else { + if pkgName == Name(mpkg.Name) { + pkgNameFound = true + } else if opts.Type != MemPackageTypeFiletests { + errs = multierr.Append(errs, fmt.Errorf("invalid file %q: invalid package name", pkgName)) + continue + } + } + } + } + if numGnoFiles == 0 { + errs = multierr.Append(errs, fmt.Errorf("package has no .gno files")) + } + if (opts.Type != MemPackageTypeFiletests) && !pkgNameFound { + errs = multierr.Append(errs, fmt.Errorf("package name %q not found in files", mpkg.Name)) + } + return errs +} diff --git a/gnovm/pkg/gnolang/nodes.go b/gnovm/pkg/gnolang/nodes.go index fb2c79826a7..e2c5b11e9fc 100644 --- a/gnovm/pkg/gnolang/nodes.go +++ b/gnovm/pkg/gnolang/nodes.go @@ -113,31 +113,14 @@ const ( type Name string -// ---------------------------------------- -// Location -// Acts as an identifier for nodes. - -type Location struct { - PkgPath string - File string - Line int - Column int -} - -func (loc Location) String() string { - return fmt.Sprintf("%s/%s:%d:%d", - loc.PkgPath, - loc.File, - loc.Line, - loc.Column, - ) -} +type Names []Name -func (loc Location) IsZero() bool { - return loc.PkgPath == "" && - loc.File == "" && - loc.Line == 0 && - loc.Column == 0 +func (ns Names) Join(j string) string { + ss := make([]string, 0, len(ns)) + for _, n := range ns { + ss = append(ss, string(n)) + } + return strings.Join(ss, j) } // ---------------------------------------- @@ -149,42 +132,29 @@ func (loc Location) IsZero() bool { type GnoAttribute string +// XXX once everything is done, convert to a uint64 bitflag. const ( - ATTR_PREPROCESSED GnoAttribute = "ATTR_PREPROCESSED" - ATTR_PREDEFINED GnoAttribute = "ATTR_PREDEFINED" - ATTR_TYPE_VALUE GnoAttribute = "ATTR_TYPE_VALUE" - ATTR_TYPEOF_VALUE GnoAttribute = "ATTR_TYPEOF_VALUE" - ATTR_IOTA GnoAttribute = "ATTR_IOTA" - ATTR_HEAP_DEFINES GnoAttribute = "ATTR_HEAP_DEFINES" // []Name heap items. - ATTR_HEAP_USES GnoAttribute = "ATTR_HEAP_USES" // []Name heap items used. - ATTR_SHIFT_RHS GnoAttribute = "ATTR_SHIFT_RHS" - ATTR_LAST_BLOCK_STMT GnoAttribute = "ATTR_LAST_BLOCK_STMT" - ATTR_GLOBAL GnoAttribute = "ATTR_GLOBAL" - ATTR_PACKAGE_REF GnoAttribute = "ATTR_PACKAGE_REF" - ATTR_PACKAGE_DECL GnoAttribute = "ATTR_PACKAGE_DECL" + ATTR_PREPROCESSED GnoAttribute = "ATTR_PREPROCESSED" + ATTR_PREPROCESS_SKIPPED GnoAttribute = "ATTR_PREPROCESS_SKIPPED" + ATTR_PREPROCESS_INCOMPLETE GnoAttribute = "ATTR_PREPROCESS_INCOMPLETE" + ATTR_PREDEFINED GnoAttribute = "ATTR_PREDEFINED" + ATTR_TYPE_VALUE GnoAttribute = "ATTR_TYPE_VALUE" + ATTR_TYPEOF_VALUE GnoAttribute = "ATTR_TYPEOF_VALUE" + ATTR_IOTA GnoAttribute = "ATTR_IOTA" + ATTR_HEAP_DEFINES GnoAttribute = "ATTR_HEAP_DEFINES" // []Name heap items. + ATTR_HEAP_USES GnoAttribute = "ATTR_HEAP_USES" // []Name heap items used. + ATTR_SHIFT_RHS GnoAttribute = "ATTR_SHIFT_RHS" + ATTR_LAST_BLOCK_STMT GnoAttribute = "ATTR_LAST_BLOCK_STMT" + ATTR_PACKAGE_REF GnoAttribute = "ATTR_PACKAGE_REF" + ATTR_PACKAGE_DECL GnoAttribute = "ATTR_PACKAGE_DECL" + ATTR_FIX_FROM GnoAttribute = "ATTR_FIX_FROM" // gno fix this version. ) +// Embedded in each Node. type Attributes struct { - Line int - Column int - Label Name - data map[GnoAttribute]any // not persisted -} - -func (attr *Attributes) GetLine() int { - return attr.Line -} - -func (attr *Attributes) SetLine(line int) { - attr.Line = line -} - -func (attr *Attributes) GetColumn() int { - return attr.Column -} - -func (attr *Attributes) SetColumn(column int) { - attr.Column = column + Span // Node.Line is the start. + Label Name + data map[GnoAttribute]any // not persisted } func (attr *Attributes) GetLabel() Name { @@ -220,6 +190,22 @@ func (attr *Attributes) DelAttribute(key GnoAttribute) { delete(attr.data, key) } +func (attr *Attributes) GetAttributeKeys() []GnoAttribute { + res := make([]GnoAttribute, 0, len(attr.data)) + for key := range attr.data { + res = append(res, key) + } + return res +} + +func (attr *Attributes) String() string { + panic("should not use") // node should override Pos/Span/Location methods. +} + +func (attr *Attributes) IsZero() bool { + panic("should not use") // node should override Pos/Span/Location methods. +} + // ---------------------------------------- // Node @@ -227,10 +213,11 @@ type Node interface { assertNode() String() string Copy() Node + GetPos() Pos GetLine() int - SetLine(int) GetColumn() int - SetColumn(int) + GetSpan() Span + SetSpan(Span) // once. GetLabel() Name SetLabel(Name) HasAttribute(key GnoAttribute) bool @@ -454,7 +441,7 @@ func (x *CallExpr) isCrossing() bool { func (x *CallExpr) SetWithCross() { if !x.isWithCross() { - panic("expected cross(fn)(...)") + panic("expected fn(cur,...)") } x.WithCross = true } @@ -1170,6 +1157,13 @@ type FileSet struct { Files []*FileNode } +func (fs FileSet) GetFileNames() (fnames []Name) { + for _, fnode := range fs.Files { + fnames = append(fnames, fnode.Name) + } + return +} + // PackageNameFromFileBody extracts the package name from the given Gno code body. // The 'name' parameter is used for better error traces, and 'body' contains the Gno code. func PackageNameFromFileBody(name, body string) (Name, error) { @@ -1191,10 +1185,10 @@ func MustPackageNameFromFileBody(name, body string) Name { return pkgName } -// ReadMemPackage initializes a new MemPackage by reading the OS directory -// at dir, and saving it with the given pkgPath (import path). -// The resulting MemPackage will contain the names and content of all *.gno files, -// and additionally README.md, LICENSE. +// ReadMemPackage initializes a new MemPackage by reading the OS directory at +// dir, and saving it with the given pkgPath (import path). The resulting +// MemPackage will contain the names and content of all *.gno files, and +// additionally README.md, LICENSE. // // ReadMemPackage does not perform validation aside from the package's name; // the files are not parsed but their contents are merely stored inside a MemFile. @@ -1206,30 +1200,23 @@ func ReadMemPackage(dir string, pkgPath string) (*std.MemPackage, error) { if err != nil { return nil, err } - allowedFiles := []string{ // make case insensitive? - "LICENSE", - "README.md", - } - allowedFileExtensions := []string{ - ".gno", - } - // exceptions to allowedFileExtensions - var rejectedFileExtensions []string + // exceptions to allowedMemPackageFileExtensions + var badFileExtensions []string if IsStdlib(pkgPath) { // Allows transpilation to work on stdlibs with native fns. - allowedFileExtensions = append(allowedFileExtensions, ".go") - rejectedFileExtensions = []string{".gen.go"} + allowedMemPackageFileExtensions = append(allowedMemPackageFileExtensions, ".go") + badFileExtensions = []string{".gen.go"} } list := make([]string, 0, len(files)) for _, file := range files { // Ignore directories and hidden files, only include allowed files & extensions, - // then exclude files that are of the rejected extensions. + // then exclude files that are of the bad extensions. if file.IsDir() || strings.HasPrefix(file.Name(), ".") || - (!endsWithAny(file.Name(), allowedFileExtensions) && !slices.Contains(allowedFiles, file.Name())) || - endsWithAny(file.Name(), rejectedFileExtensions) { + (!endsWithAny(file.Name(), allowedMemPackageFileExtensions) && !slices.Contains(allowedMemPackageFiles, file.Name())) || + endsWithAny(file.Name(), badFileExtensions) { continue } list = append(list, filepath.Join(dir, file.Name())) @@ -1252,48 +1239,104 @@ func MustReadMemPackage(dir string, pkgPath string) *std.MemPackage { return pkg } -// ReadMemPackageFromList creates a new [std.MemPackage] with the specified pkgPath, -// containing the contents of all the files provided in the list slice. -// No parsing or validation is done on the filenames. +// ReadMemPackageFromList creates a new [std.MemPackage] with the specified +// pkgPath, containing the contents of all the files provided in the list +// slice. No parsing is done on the file bodies except package names for +// validation. The returned mempackage must be validated separately with +// gno.ValidateMemPackage(). // -// NOTE: errors out if package name is invalid (characters must be alphanumeric or _, -// lowercase, and must start with a letter). +// Returns both read mempackage and (multi)error if package name is invalid +// (characters must be alphanumeric or _, lowercase, and must start with a +// letter, and be the same for normal files and normal *_test.gno files, and +// xxx_test for integration tests). Filetest package names are not checked. If +// the only file present is a single filetest, its package name is used. +// +// XXX TODO pkgPath should instead be derived by inspecting the contents, among +// them the gno.mod file. func ReadMemPackageFromList(list []string, pkgPath string) (*std.MemPackage, error) { - memPkg := &std.MemPackage{Path: pkgPath} - var pkgName Name + mpkg := &std.MemPackage{Path: pkgPath} + var pkgName Name // normal file pkg name + var pkgNameDiffers bool // normal file pkg name is inconsistent + var pkgNameFT Name // filetest pkg name + var pkgNameFTDiffers bool // filetest pkg name is inconsistent + var errs error // all errors minus filetest pkg name errors. for _, fpath := range list { fname := filepath.Base(fpath) bz, err := os.ReadFile(fpath) if err != nil { return nil, err } - // XXX: should check that all pkg names are the same (else package is invalid) - if pkgName == "" && strings.HasSuffix(fname, ".gno") { - pkgName, err = PackageNameFromFileBody(path.Join(pkgPath, fname), string(bz)) + // Check that all pkg names are the same (else package is invalid). + // Try to derive the package name, but this is not a replacement + // for gno.ValidateMemPackage(). + if strings.HasSuffix(fname, ".gno") { + var pkgName2 Name + pkgName2, err = PackageNameFromFileBody(path.Join(pkgPath, fname), string(bz)) if err != nil { - return nil, err + errs = multierr.Append(errs, err) + continue } - if strings.HasSuffix(string(pkgName), "_test") { - pkgName = pkgName[:len(pkgName)-len("_test")] + if strings.HasSuffix(fname, "_filetest.gno") { + // Filetests may have arbitrary package names. + // pkgName2 (of this file) may be unrelated to + // pkgName of the mem package. + if pkgNameFT == "" && !pkgNameFTDiffers { + pkgNameFT = pkgName2 + } else if pkgNameFT != pkgName2 { + pkgNameFT = "" + pkgNameFTDiffers = true + } + } else { + if strings.HasSuffix(string(pkgName2), "_test") { + pkgName2 = pkgName2[:len(pkgName2)-len("_test")] + } + if pkgName == "" && !pkgNameDiffers { + pkgName = pkgName2 + } else if pkgName != pkgName2 { + // This happens when transpiling + // tests/files; both mpkg and errors + // will be returned. + pkgName = "" + pkgNameDiffers = true + errs = multierr.Append(errs, fmt.Errorf("%s:0: expected package name %q but got %q", fpath, pkgName, pkgName2)) + } } } - memPkg.Files = append(memPkg.Files, + mpkg.Files = append(mpkg.Files, &std.MemFile{ Name: fname, Body: string(bz), }) } - memPkg.Name = string(pkgName) - - // If no .gno files are present, package simply does not exist. - if !memPkg.IsEmpty() { - if err := validatePkgName(string(pkgName)); err != nil { - return nil, err - } + // If there were any errors so far, return error. + if errs != nil { + return mpkg, errs + } + // If mpkg is empty, return an error + if mpkg.IsEmpty() { + return mpkg, fmt.Errorf("package has no files") + } + // If pkgNameDiffers, return mpkg and the errors. + if pkgNameDiffers { + return mpkg, errs + } + // If only filetests with the same name, its package name is used. + if pkgName == "" && !pkgNameDiffers && !pkgNameFTDiffers { + pkgName = pkgNameFT + } + // Still no pkgName or invalid; ensure error. + if pkgName == "" { + pkgName = "xxxinvalidpackagenamexxx" // sensible default + errs = multierr.Append(errs, fmt.Errorf("package name could be determined")) + } else if err := validatePkgName(pkgName); err != nil { + errs = multierr.Append(errs, err) + return mpkg, errs } - return memPkg, nil + mpkg.Name = string(pkgName) + mpkg.Sort() // sort files for gno.ValidateMemPackage(). + return mpkg, nil } // MustReadMemPackageFromList is a wrapper around [ReadMemPackageFromList] that panics on error. @@ -1305,28 +1348,29 @@ func MustReadMemPackageFromList(list []string, pkgPath string) *std.MemPackage { return pkg } -// ParseMemPackage executes [ParseFile] on each file of the memPkg, excluding +// ParseMemPackage executes [ParseFile] on each file of the mpkg, excluding // test and spurious (non-gno) files. The resulting *FileSet is returned. // -// If one of the files has a different package name than memPkg.Name, +// If one of the files has a different package name than mpkg.Name, // or [ParseFile] returns an error, ParseMemPackage panics. -func ParseMemPackage(memPkg *std.MemPackage) (fset *FileSet) { +func ParseMemPackage(mpkg *std.MemPackage) (fset *FileSet) { fset = &FileSet{} var errs error - for _, mfile := range memPkg.Files { + for _, mfile := range mpkg.Files { if !strings.HasSuffix(mfile.Name, ".gno") || - endsWithAny(mfile.Name, []string{"_test.gno", "_filetest.gno"}) { - continue // skip spurious or test file. + endsWithAny(mfile.Name, []string{"_test.gno", "_filetest.gno"}) || + mfile.Name == "gno.mod" { + continue // skip spurious or test or gno.mod file. } n, err := ParseFile(mfile.Name, mfile.Body) if err != nil { errs = multierr.Append(errs, err) continue } - if memPkg.Name != string(n.PkgName) { + if mpkg.Name != string(n.PkgName) { panic(fmt.Sprintf( "expected package name [%s] but got [%s]", - memPkg.Name, n.PkgName)) + mpkg.Name, n.PkgName)) } // add package file. fset.AddFiles(n) @@ -1418,8 +1462,6 @@ type PackageNode struct { func PackageNodeLocation(path string) Location { return Location{ PkgPath: path, - File: "", - Line: 0, } } @@ -1592,7 +1634,7 @@ type BlockNode interface { GetValueRef(Store, Name, bool) *TypedValue GetStaticTypeOf(Store, Name) Type GetStaticTypeOfAt(Store, ValuePath) Type - Predefine(bool, Name) + Reserve(bool, Name) Define(Name, TypedValue) Define2(bool, Name, Type, TypedValue) GetBody() Body @@ -1932,14 +1974,14 @@ func (sb *StaticBlock) GetLocalIndex(n Name) (uint16, bool) { // Implemented BlockNode. // This method is too slow for runtime, but it is used // during preprocessing to compute types. -// If skipPredefined, skips over names that are only predefined. -// Returns nil if not defined. -func (sb *StaticBlock) GetValueRef(store Store, n Name, skipPredefined bool) *TypedValue { +// If ignoreReserved, skips over names that are only reserved (and neither predefined nor defined). +// Returns nil if not found. +func (sb *StaticBlock) GetValueRef(store Store, n Name, ignoreReserved bool) *TypedValue { idx, ok := sb.GetLocalIndex(n) bb := &sb.Block bp := sb.GetParentNode(store) for { - if ok && (!skipPredefined || sb.Types[idx] != nil) { + if ok && (!ignoreReserved || sb.Types[idx] != nil) { return bb.GetPointerToInt(store, int(idx)).TV } else if bp != nil { idx, ok = bp.GetLocalIndex(n) @@ -1968,7 +2010,7 @@ func (sb *StaticBlock) Define(n Name, tv TypedValue) { } // Set type to nil, only reserving the name. -func (sb *StaticBlock) Predefine(isConst bool, n Name) { +func (sb *StaticBlock) Reserve(isConst bool, n Name) { _, exists := sb.GetLocalIndex(n) if !exists { sb.Define2(isConst, n, nil, anyValue(nil)) @@ -2309,9 +2351,9 @@ var rePkgName = regexp.MustCompile(`^[a-z][a-z0-9_]+$`) // TODO: consider length restrictions. // If this function is changed, ReadMemPackage's documentation should be updated accordingly. -func validatePkgName(name string) error { - if !rePkgName.MatchString(name) { - return fmt.Errorf("cannot create package with invalid name %q", name) +func validatePkgName(name Name) error { + if !rePkgName.MatchString(string(name)) { + return fmt.Errorf("invalid package name %q", name) } return nil } diff --git a/gnovm/pkg/gnolang/nodes_span.go b/gnovm/pkg/gnolang/nodes_span.go new file mode 100644 index 00000000000..747c94265ae --- /dev/null +++ b/gnovm/pkg/gnolang/nodes_span.go @@ -0,0 +1,238 @@ +package gnolang + +import ( + "fmt" + "go/ast" + "go/token" + "strings" +) + +/* ======================================== +``` +{ + Attributes{ + Label Name + Span{ + Pos{ + Line int + Column int + End:Pos{ + Line int + Column int + StaticBlock{ + Loc:Location{ + Span{ +{ + Attributes{ + Label Name + Span{ + Pos{ + Line int + Column int + End:Pos{ + Line int + Column int +``` +======================================== */ + +// Pos(isition) +type Pos struct { + Line int + Column int +} + +func (p Pos) GetPos() Pos { + return p +} + +func (p Pos) GetLine() int { + return p.Line +} + +func (p Pos) GetColumn() int { + return p.Column +} + +func (p Pos) Compare(p2 Pos) int { + switch { + case p.Line < p2.Line: + return -1 + case p.Line == p2.Line: + break + case p.Line > p2.Line: + return 1 + default: + panic("should not happen") + } + switch { + case p.Column < p2.Column: + return -1 + case p.Column == p2.Column: + return 0 + case p.Column > p2.Column: + return 1 + default: + panic("should not happen") + } +} + +// Overridden by Attributes.String(). +func (p Pos) String() string { + return fmt.Sprintf("%d:%d", p.Line, p.Column) +} + +// Overridden by Attributes.IsZero(). +// NOTE: DO NOT CHANGE. +func (p Pos) IsZero() bool { + return p == Pos{} +} + +// ---------------------------------------- +// Span +// Has a start (pos) and an end. +type Span struct { + Pos // start + End Pos + Num int // positive if conflicts. +} + +func SpanFromGo(gofs *token.FileSet, gon ast.Node) Span { + pos := gon.Pos() + end := gon.End() + posn := gofs.Position(pos) + endn := gofs.Position(end) + return Span{ + Pos: Pos{posn.Line, posn.Column}, + End: Pos{endn.Line, endn.Column}, + } +} + +func (s Span) GetSpan() Span { + return s +} + +// If you need to update the span/pos/location of a node it should be re-parsed +// from an updated AST. This is important because location is used as identity. +// Anyone with a node can still mutate these fields directly; the method guides. +// If you need to override the span (e.g. constructing a Location by mutating +// a copy) then call SetSpanOverride() instead of directly assigning to .Span. +func (s *Span) SetSpan(s2 Span) { + if !s.IsZero() && (*s != s2) { + panic(".Span can ony be set once. s:" + s.String() + " s2:" + s2.String()) + } + *s = s2 +} + +// See documentation for SetSpan(). +func (s *Span) SetSpanOverride(s2 Span) { + *s = s2 +} + +// Overridden by Attributes.String(). +func (s Span) String() string { + if s.Pos.Line == s.End.Line { + return fmt.Sprintf("%d:%d-%d%s", + s.Pos.Line, s.Pos.Column, s.End.Column, + strings.Repeat("'", s.Num), // e.g. 1:1-12' + ) + } else { + return fmt.Sprintf("%s-%s%s", + s.Pos.String(), s.End.String(), + strings.Repeat("'", s.Num), // e.g. 1:1-3:4''' + ) + } +} + +// Overridden by Attributes.IsZero(). +// NOTE: DO NOT CHANGE. +func (s Span) IsZero() bool { + return s == Span{} +} + +// Suitable for Node. Less means earlier / higher level. +// Start (.Pos) determines node order before .End/ .Num, +// then the end (greater means containing, thus sooner), +// then the num (smaller means containing, thus sooner). +func (s Span) Compare(s2 Span) int { + switch s.Pos.Compare(s2.Pos) { + case -1: // s.Pos < s2.Pos + return -1 + case 0: // s.Pos == s2.Pos + break + case 1: // s.Pos > s2.Pos + return 1 + default: + panic("should not happen") + } + switch s.End.Compare(s2.End) { + case -1: // s.End < s2.End + return 1 // see comment + case 0: // s.End == s2.End + break + case 1: + return -1 // see comment + default: + panic("should not happen") + } + switch { + case s.Num < s2.Num: + return -1 + case s.Num == s2.Num: + return 0 + case s.Num > s2.Num: + return 1 + default: + panic("should not happen") + } +} + +// Union() returns a span for a new containing node w/ .Num possibly negative. +// NOTE: Span union math based on lines and columns, not the same math as for +// 2D container boxes. 2D has cardinality of 2, and span has cardinality of 1. +// See Span.Compare() to see a quirk where a greater end can mean lesser span. +// (we assume our 3D world has a cardinality of 3 but what if it is really 2?) +func (s Span) Union(s2 Span) (res Span) { + if s.Pos.Compare(s2.Pos) < 0 { + res.Pos = s.Pos + } else { + res.Pos = s2.Pos + } + if s.End.Compare(s2.End) < 0 { + res.End = s2.End + } else { + res.End = s.End + } + // Only when s == s2 does .Num get set. + if s.Pos == s2.Pos && s.End == s2.End { + res.Num = min(s.Num, s2.Num) - 1 // maybe < 0. + } else { + res.Num = 0 // starts with zero. + } + return +} + +// ---------------------------------------- +// Location +// A Location is also an identifier for nodes. +// BlockNodes have these, while all Nodes have only .Span. +// (.Span field is duplicated in Node.Attributes and BlockNode.Location) +type Location struct { + PkgPath string + File string + Span +} + +// Overridden by Attributes.String(). +func (loc Location) String() string { + return fmt.Sprintf("%s/%s:%s", + loc.PkgPath, + loc.File, + loc.Span.String(), + ) +} + +// Overridden by Attributes.IsZero(). +// NOTE: DO NOT CHANGE. +func (loc Location) IsZero() bool { + return loc == Location{} +} diff --git a/gnovm/pkg/gnolang/nodes_string.go b/gnovm/pkg/gnolang/nodes_string.go index d577b0b1d84..86dedc11551 100644 --- a/gnovm/pkg/gnolang/nodes_string.go +++ b/gnovm/pkg/gnolang/nodes_string.go @@ -458,7 +458,7 @@ func (x FileNode) String() string { } func (x PackageNode) String() string { - return fmt.Sprintf("package(%s)", x.PkgName) + return fmt.Sprintf("package(%s %s)", x.PkgName, x.PkgPath) } func (rn RefNode) String() string { diff --git a/gnovm/pkg/gnolang/preprocess.go b/gnovm/pkg/gnolang/preprocess.go index 20317ad5267..cef545b6553 100644 --- a/gnovm/pkg/gnolang/preprocess.go +++ b/gnovm/pkg/gnolang/preprocess.go @@ -14,26 +14,32 @@ import ( ) const ( - blankIdentifier = "_" + debugFind = false // toggle when debugging. + + blankIdentifier = "_" + AttrPreprocessFuncLitExpr = "FuncLitExpr" ) -// In the case of a *FileSet, some declaration steps have to happen -// in a restricted parallel way across all the files. -// Anything predefined or preprocessed here get skipped during the Preprocess -// phase. +// Predefine (initStaticBlocks) and partially evaluates all names +// not inside function bodies. +// +// This function must be called on *FileSets because declarations +// in file sets may be unordered. func PredefineFileSet(store Store, pn *PackageNode, fset *FileSet) { // First, initialize all file nodes and connect to package node. // This will also reserve names on BlockNode.StaticBlock by - // calling StaticBlock.Predefine(). + // calling StaticBlock.Reserve(). + // + // NOTE: The calls to .Reserve() in initStaticBlock() below only + // reserve the name for determining the value path index. What comes + // later after this for-loop is a partial definition for *FuncDecl + // function declarations which will get filled out later during + // preprocessing. for _, fn := range fset.Files { setNodeLines(fn) setNodeLocations(pn.PkgPath, string(fn.Name), fn) initStaticBlocks(store, pn, fn) } - // NOTE: The calls to .Predefine() above is more of a name reservation, - // and what comes later in PredefineFileset() below is a second type of - // pre-defining mixed with defining, where recursive types are defined - // first and then filled out later. // NOTE: much of what follows is duplicated for a single *FileNode // in the main Preprocess translation function. Keep synced. @@ -53,8 +59,8 @@ func PredefineFileSet(store Store, pn *PackageNode, fset *FileSet) { } // recursively predefine dependencies. - d2, _ := predefineNow(store, fn, d) - fn.Decls[i] = d2 + predefineRecursively(store, fn, d) + fn.Decls[i] = d } } } @@ -72,8 +78,8 @@ func PredefineFileSet(store Store, pn *PackageNode, fset *FileSet) { } // recursively predefine dependencies. - d2, _ := predefineNow(store, fn, d) - fn.Decls[i] = d2 + predefineRecursively(store, fn, d) + fn.Decls[i] = d } } } @@ -91,8 +97,8 @@ func PredefineFileSet(store Store, pn *PackageNode, fset *FileSet) { } // recursively predefine dependencies. - d2, _ := predefineNow(store, fn, d) - fn.Decls[i] = d2 + predefineRecursively(store, fn, d) + fn.Decls[i] = d } } } @@ -107,35 +113,55 @@ func PredefineFileSet(store Store, pn *PackageNode, fset *FileSet) { continue } + // Split multiple value decls into separate ones. + // NOTE: As a strange quirk of Go, intra-dependent + // value declarations like `var a, b, c = 1, a, b` is + // only allowed at the package level, but not within a + // function. Gno2 may allow this type of declaration, + // and when it does the following splitting logic will + // need to be duplicated in the Preprocessor. if vd, ok := d.(*ValueDecl); ok && len(vd.NameExprs) > 1 && len(vd.Values) == len(vd.NameExprs) { + var iota_ any + if len(vd.Attributes.data) > 0 { + // TODO: use a uint64 bitflag and faster operations. + keys := vd.GetAttributeKeys() + for _, key := range keys { + switch key { + case ATTR_IOTA: + iota_ = vd.GetAttribute(key) + default: + // defensive. + panic("unexpected attribute") + } + } + } split := make([]Decl, len(vd.NameExprs)) - for j := range vd.NameExprs { - base := vd.Copy().(*ValueDecl) - base.NameExprs = NameExprs{NameExpr{ - Attributes: base.NameExprs[j].Attributes, - Path: base.NameExprs[j].Path, - Name: base.NameExprs[j].Name, - Type: NameExprTypeDefine, - }} - - if j < len(base.Values) { - base.Values = Exprs{base.Values[j].Copy().(Expr)} + part := &ValueDecl{ + NameExprs: NameExprs{{ + Attributes: vd.NameExprs[j].Attributes, + Path: vd.NameExprs[j].Path, + Name: vd.NameExprs[j].Name, + Type: NameExprTypeDefine, + }}, + Type: vd.Type, + Values: Exprs{vd.Values[j].Copy().(Expr)}, + Const: vd.Const, } - - split[j], _ = predefineNow(store, fn, base) + if iota_ != nil { + part.SetAttribute(ATTR_IOTA, iota_) + } + predefineRecursively(store, fn, part) + split[j] = part } - fn.Decls = append(fn.Decls[:i], append(split, fn.Decls[i+1:]...)...) //nolint:makezero - i += len(vd.NameExprs) + i += len(vd.NameExprs) - 1 + continue + } else { + // recursively predefine dependencies. + predefineRecursively(store, fn, d) continue } - - d.SetAttribute(ATTR_GLOBAL, true) - // recursively predefine dependencies. - d2, _ := predefineNow(store, fn, d) - - fn.Decls[i] = d2 } } } @@ -172,7 +198,7 @@ func initStaticBlocks(store Store, ctx BlockNode, bn BlockNode) { // if loopvar, will promote to // NameExprTypeHeapDefine later. nx.Type = NameExprTypeDefine - last.Predefine(false, ln) + last.Reserve(false, ln) } } } @@ -193,7 +219,7 @@ func initStaticBlocks(store Store, ctx BlockNode, bn BlockNode) { } if nn != blankIdentifier { nx.Type = NameExprTypeDefine - last.Predefine(false, nn) + last.Reserve(false, nn) } case *ValueDecl: last2 := skipFile(last) @@ -204,13 +230,13 @@ func initStaticBlocks(store Store, ctx BlockNode, bn BlockNode) { continue } nx.Type = NameExprTypeDefine - last2.Predefine(n.Const, nn) + last2.Reserve(n.Const, nn) } case *TypeDecl: last2 := skipFile(last) nx := &n.NameExpr nx.Type = NameExprTypeDefine - last2.Predefine(true, n.Name) + last2.Reserve(true, n.Name) case *FuncDecl: if n.IsMethod { if n.Recv.Name == "" || n.Recv.Name == blankIdentifier { @@ -234,7 +260,7 @@ func initStaticBlocks(store Store, ctx BlockNode, bn BlockNode) { } nx := &n.NameExpr nx.Type = NameExprTypeDefine - pkg.Predefine(false, n.Name) + pkg.Reserve(false, n.Name) pkg.UnassignableNames = append(pkg.UnassignableNames, n.Name) } case *FuncTypeExpr: @@ -270,7 +296,7 @@ func initStaticBlocks(store Store, ctx BlockNode, bn BlockNode) { ifs := ns[len(ns)-1].(*IfStmt) // anything declared in ifs are copied. for _, n := range ifs.GetBlockNames() { - last.Predefine(false, n) + last.Reserve(false, n) } case *RangeStmt: if n.Op == DEFINE { @@ -278,14 +304,14 @@ func initStaticBlocks(store Store, ctx BlockNode, bn BlockNode) { nx := n.Key.(*NameExpr) if nx.Name != blankIdentifier { nx.Type = NameExprTypeDefine - last.Predefine(false, nx.Name) + last.Reserve(false, nx.Name) } } if n.Value != nil { nx := n.Value.(*NameExpr) if nx.Name != blankIdentifier { nx.Type = NameExprTypeDefine - last.Predefine(false, nx.Name) + last.Reserve(false, nx.Name) } } } @@ -293,7 +319,7 @@ func initStaticBlocks(store Store, ctx BlockNode, bn BlockNode) { for i := range n.Type.Params { px := &n.Type.Params[i].NameExpr px.Type = NameExprTypeDefine - last.Predefine(false, px.Name) + last.Reserve(false, px.Name) } for i := range n.Type.Results { rx := &n.Type.Results[i].NameExpr @@ -302,7 +328,7 @@ func initStaticBlocks(store Store, ctx BlockNode, bn BlockNode) { rx.Name = Name(rn) } rx.Type = NameExprTypeDefine - last.Predefine(false, rx.Name) + last.Reserve(false, rx.Name) } case *SwitchStmt: // n.Varname is declared in each clause. @@ -316,7 +342,7 @@ func initStaticBlocks(store Store, ctx BlockNode, bn BlockNode) { ss := ns[len(ns)-1].(*SwitchStmt) // anything declared in ss.init are copied. for _, n := range ss.GetBlockNames() { - last.Predefine(false, n) + last.Reserve(false, n) } if ss.IsTypeSwitch { if ss.VarName != "" { @@ -325,7 +351,7 @@ func initStaticBlocks(store Store, ctx BlockNode, bn BlockNode) { // > Switch varnames cannot be // captured as heap items. // [test](../gnovm/tests/files/closure11_known.gno) - last.Predefine(false, ss.VarName) + last.Reserve(false, ss.VarName) } } else { if ss.VarName != "" { @@ -335,7 +361,7 @@ func initStaticBlocks(store Store, ctx BlockNode, bn BlockNode) { case *FuncDecl: if n.IsMethod { n.Recv.NameExpr.Type = NameExprTypeDefine - n.Predefine(false, n.Recv.Name) + n.Reserve(false, n.Recv.Name) } for i := range n.Type.Params { px := &n.Type.Params[i].NameExpr @@ -343,7 +369,7 @@ func initStaticBlocks(store Store, ctx BlockNode, bn BlockNode) { panic("should not happen") } px.Type = NameExprTypeDefine - n.Predefine(false, px.Name) + n.Reserve(false, px.Name) } for i := range n.Type.Results { rx := &n.Type.Results[i].NameExpr @@ -352,7 +378,7 @@ func initStaticBlocks(store Store, ctx BlockNode, bn BlockNode) { rx.Name = Name(rn) } rx.Type = NameExprTypeDefine - n.Predefine(false, rx.Name) + n.Reserve(false, rx.Name) } } return n, TRANS_CONTINUE @@ -384,9 +410,8 @@ func doRecover(stack []BlockNode, n Node) { // before re-throwing the error, append location information to message. last := stack[len(stack)-1] loc := last.GetLocation() - if nline := n.GetLine(); nline > 0 { - loc.Line = nline - loc.Column = n.GetColumn() + if !n.GetSpan().IsZero() { + loc.SetSpanOverride(n.GetSpan()) } var err error @@ -430,6 +455,7 @@ var preprocessing atomic.Int32 // - Assigns BlockValuePath to NameExprs. // - TODO document what it does. func Preprocess(store Store, ctx BlockNode, n Node) Node { + clearSkip := false // First init static blocks of blocknodes. // This may have already happened. // Keep this function idemponent. @@ -440,12 +466,31 @@ func Preprocess(store Store, ctx BlockNode, n Node) Node { if stage != TRANS_ENTER { return n, TRANS_CONTINUE } + if _, ok := n.(*FuncLitExpr); ok { + if n.GetAttribute(ATTR_PREPROCESS_SKIPPED) == AttrPreprocessFuncLitExpr { + clearSkip = true // clear what preprocess1 will do. + return n, TRANS_SKIP + } + } if bn, ok := n.(BlockNode); ok { initStaticBlocks(store, ctx, bn) return n, TRANS_SKIP } return n, TRANS_CONTINUE }) + if clearSkip { + defer func() { + Transcribe(n, + func(ns []Node, ftype TransField, index int, n Node, stage TransStage) (Node, TransCtrl) { + if stage != TRANS_ENTER { + return n, TRANS_CONTINUE + } + n.DelAttribute(ATTR_PREPROCESS_SKIPPED) + n.DelAttribute(ATTR_PREPROCESS_INCOMPLETE) + return n, TRANS_CONTINUE + }) + }() + } // Bulk of the preprocessor function n = preprocess1(store, ctx, n) @@ -463,6 +508,11 @@ func Preprocess(store Store, ctx BlockNode, n Node) Node { if stage != TRANS_ENTER { return n, TRANS_CONTINUE } + if _, ok := n.(*FuncLitExpr); ok { + if n.GetAttribute(ATTR_PREPROCESS_SKIPPED) == AttrPreprocessFuncLitExpr { + return n, TRANS_SKIP + } + } if bn, ok := n.(BlockNode); ok { // findGotoLoopDefines(ctx, bn) findHeapDefinesByUse(ctx, bn) @@ -528,7 +578,7 @@ func preprocess1(store Store, ctx BlockNode, n Node) Node { _, ok := last.GetLocalIndex(ln) if !ok { // initial declaration to be re-defined. - last.Predefine(false, ln) + last.Reserve(false, ln) } else { // do not redeclare. } @@ -553,22 +603,12 @@ func preprocess1(store Store, ctx BlockNode, n Node) Node { checkValDefineMismatch(cd) } - isGlobal := true - - for i := len(ns) - 1; i > 0; i-- { - if _, ok := ns[i].(*FuncDecl); ok { - isGlobal = false - } - } - - d.SetAttribute(ATTR_GLOBAL, isGlobal) - // recursively predefine dependencies. - d2, ppd := predefineNow(store, last, d) - if ppd { - return d2, TRANS_SKIP + preprocessed := predefineRecursively(store, last, d) + if preprocessed { + return d, TRANS_SKIP } else { - return d2, TRANS_CONTINUE + return d, TRANS_CONTINUE } } @@ -688,6 +728,21 @@ func preprocess1(store Store, ctx BlockNode, n Node) Node { case *FuncLitExpr: // retrieve cached function type. ft := evalStaticType(store, last, &n.Type).(*FuncType) + if n.GetAttribute(ATTR_PREPROCESS_SKIPPED) == AttrPreprocessFuncLitExpr { + // Machine still needs it. Clear it @ initStaticBlocks. + // n.DelAttribute(ATTR_PREPROCESS_SKIPPED) + for _, p := range ns { + // Prevent parents from being marked as attr + // preprocessed. Be not concerned about any inner + // Preprocess() calls for newly constructed nodes: + // either this node will be inside it, in which case it + // too will be marked incomplete, or, it won't be + // inside it, in which case it will complete. + p.SetAttribute(ATTR_PREPROCESS_INCOMPLETE, true) + } + // n.SetAttribute(ATTR_PREPROCESS_INCOMPLETE, true) + return n, TRANS_SKIP + } // push func body block. pushInitBlock(n, &last, &stack) // define parameters in new block. @@ -791,7 +846,7 @@ func preprocess1(store Store, ctx BlockNode, n Node) Node { // TRANS_BLOCK ----------------------- case *FuncDecl: // retrieve cached function type. - // the type and receiver are already set in predefineNow. + // the type and receiver are already set in predefineRecursively. ft := getType(&n.Type).(*FuncType) // push func body block. @@ -847,8 +902,8 @@ func preprocess1(store Store, ctx BlockNode, n Node) Node { } else { // recursively predefine // dependencies. - d2, _ := predefineNow(store, n, d) - n.Decls[i] = d2 + predefineRecursively(store, n, d) + n.Decls[i] = d } } } @@ -864,8 +919,8 @@ func preprocess1(store Store, ctx BlockNode, n Node) Node { } else { // recursively predefine // dependencies. - d2, _ := predefineNow(store, n, d) - n.Decls[i] = d2 + predefineRecursively(store, n, d) + n.Decls[i] = d } } } @@ -881,8 +936,8 @@ func preprocess1(store Store, ctx BlockNode, n Node) Node { } else { // recursively predefine // dependencies. - d2, _ := predefineNow(store, n, d) - n.Decls[i] = d2 + predefineRecursively(store, n, d) + n.Decls[i] = d } } } @@ -897,8 +952,8 @@ func preprocess1(store Store, ctx BlockNode, n Node) Node { } else { // recursively predefine // dependencies. - d2, _ := predefineNow(store, n, d) - n.Decls[i] = d2 + predefineRecursively(store, n, d) + n.Decls[i] = d } } } @@ -930,7 +985,7 @@ func preprocess1(store Store, ctx BlockNode, n Node) Node { case TRANS_LEAVE: // mark as preprocessed so that it can be used // in evalStaticType(store,). - n.SetAttribute(ATTR_PREPROCESSED, true) + setPreprocessed(n) // Defer pop block from stack. // NOTE: DO NOT USE TRANS_SKIP WITHIN BLOCK @@ -1556,7 +1611,7 @@ func preprocess1(store Store, ctx BlockNode, n Node) Node { // for (*a)[low : high : max] dt = dt.Elem() n.X = &StarExpr{X: n.X} - n.X.SetAttribute(ATTR_PREPROCESSED, true) + setPreprocessed(n.X) } switch dt.Kind() { case StringKind, ArrayKind, SliceKind: @@ -1762,7 +1817,7 @@ func preprocess1(store Store, ctx BlockNode, n Node) Node { // // convert to (&x).m, but leave xt as is. n.X = &RefExpr{X: n.X} - n.X.SetAttribute(ATTR_PREPROCESSED, true) + setPreprocessed(n.X) switch tr[len(tr)-1].Type { case VPDerefPtrMethod: // When ptr method was called like x.y.z(), where x @@ -1788,7 +1843,7 @@ func preprocess1(store Store, ctx BlockNode, n Node) Node { // is not pointer type, replace n.X with // &RefExpr{X: n.X}. n.X = &RefExpr{X: n.X} - n.X.SetAttribute(ATTR_PREPROCESSED, true) + setPreprocessed(n.X) } // bound method or underlying. // TODO check for unexported fields. @@ -1969,7 +2024,7 @@ func preprocess1(store Store, ctx BlockNode, n Node) Node { Op: DEFINE, Rhs: n.Rhs, } - dsx.SetLine(n.Line) + // dsx.SetSpan(n.GetSpan()) dsx = Preprocess(store, last, dsx).(*AssignStmt) // step3: @@ -1987,7 +2042,7 @@ func preprocess1(store Store, ctx BlockNode, n Node) Node { Op: ASSIGN, Rhs: copyExprs(tmpExprs), } - asx.SetLine(n.Line) + // asx.SetSpan(n.GetSpan()) asx = Preprocess(store, last, asx).(*AssignStmt) // step4: @@ -2243,11 +2298,23 @@ func preprocess1(store Store, ctx BlockNode, n Node) Node { // TRANS_LEAVE ----------------------- case *TypeDecl: - // Construct new Type, where any recursive - // references refer to the old Type declared - // during *TypeDecl:ENTER. Then, copy over the - // values, completing the recursion. + // 'tmp' is a newly constructed type value, where + // any recursive references refer to the + // original type constructed by predefineRecursively() + // during during *TypeDecl:ENTER. + // + // For recursive definitions 'tmp' is a new + // unnamed type that is different than the + // original, but its elements will contain the + // original. It is later copied back into the + // original type, thus completing the recursive + // definition. (thus called 'tmp') tmp := evalStaticType(store, last, n.Type) + // 'dst' is the actual original type structure + // as contructed by predefineRecursively(). + // + // In short, the relationship between tmp and dst is: + // `type dst tmp`. dst := last.GetValueRef(store, n.Name, true).GetType() switch dst := dst.(type) { case *FuncType: @@ -2265,24 +2332,21 @@ func preprocess1(store Store, ctx BlockNode, n Node) Node { case *StructType: *dst = *(tmp.(*StructType)) case *DeclaredType: - // if store has this type, use that. - tid := DeclaredTypeID(lastpn.PkgPath, last.GetLocation(), n.Name) - exists := false - if dt := store.GetTypeSafe(tid); dt != nil { - dst = dt.(*DeclaredType) - last.GetValueRef(store, n.Name, true).SetType(dst) - exists = true - } - if !exists { - // otherwise construct new *DeclaredType. - // NOTE: this is where declared types are - // actually instantiated, not in + if n.IsAlias { + // Nothing to do. + } else { + // Construct a temporary new *DeclaredType + // and copy value to dst to keep the original pointer. + // + // NOTE: this is where the structured value + // (e.g. *ArrayType, *StructType) of declared + // types are actually instantiated, not in // machine.go:runDeclaration(). - dt2 := declareWith(lastpn.PkgPath, last, n.Name, tmp) + tmp2 := declareWith(lastpn.PkgPath, last, n.Name, tmp) // if !n.IsAlias { // not sure why this was here. - dt2.Seal() + tmp2.Seal() // } - *dst = *dt2 + *dst = *tmp2 } case PrimitiveType: dst = tmp.(PrimitiveType) @@ -2811,6 +2875,7 @@ func findHeapDefinesByUse(ctx BlockNode, bn BlockNode) { }) } +// TODO consider adding to Names type. func addName(names []Name, name Name) []Name { if !slices.Contains(names, name) { names = append(names, name) @@ -2880,9 +2945,9 @@ func addHeapCapture(dbn BlockNode, fle *FuncLitExpr, depth int, nx *NameExpr) (i panic("should not happen, idx not found") } -// finds the first FuncLitExpr in the stack at or after stop. -// returns the depth of first closure, 1 if stop itself is a closure, -// or 0 if not found. +// finds the first FuncLitExpr in the stack after (excluding) stop. returns +// the depth of first closure, 1 if last stack item itself is a closure, or 0 +// if not found. func findFirstClosure(stack []BlockNode, stop BlockNode) (fle *FuncLitExpr, depth int, found bool) { faux := 0 // count faux block for i := len(stack) - 1; i >= 0; i-- { @@ -2912,6 +2977,35 @@ func findFirstClosure(stack []BlockNode, stop BlockNode) (fle *FuncLitExpr, dept return } +// finds the last FuncLitExpr in the stack at (including) or after stop. +// returns the depth of last function, 1 if last stack item itself is a +// closure, or 0 if not found. +func findLastFunction(last BlockNode, stop BlockNode) (fn BlockNode, depth int, found bool) { + faux := 0 // count faux block + depth_ := 0 // working value + for stbn := last; stbn != stop; stbn = stbn.GetParentNode(nil) { + depth_ += 1 + switch stbn := stbn.(type) { + case *FuncLitExpr, *FuncDecl: + fn = stbn + depth = depth_ - faux + found = true + return + default: + if fauxChildBlockNode(stbn) { + faux++ + } + if stbn == stop { + return + } + } + } + // This can happen e.g. if stop is a package but we are + // Preprocess()'ing an expression such as `func(){ ... }()` from + // Machine.Eval() on an already preprocessed package. + return +} + // If a name is used as a heap item, Convert all other uses of such names // for heap use. If a name of type heap define is not actually used // as heap use, demotes them. @@ -3162,10 +3256,9 @@ func copyFromFauxBlock(bn BlockNode, orig BlockNode) { } } -// Evaluates the value of x which is expected to be a typeval. +// Evaluates (constructs) the value of x which is expected to be a typeval. // Caches the result as an attribute of x. -// To discourage mis-use, expects x to already be -// preprocessed. +// To discourage mis-use, expects x to already be preprocessed. func evalStaticType(store Store, last BlockNode, x Expr) Type { if t, ok := x.GetAttribute(ATTR_TYPE_VALUE).(Type); ok { return t @@ -3365,8 +3458,8 @@ func evalConst(store Store, last BlockNode, x Expr) *ConstExpr { TypedValue: cv, } } - cx.SetLine(x.GetLine()) - cx.SetAttribute(ATTR_PREPROCESSED, true) + // cx.SetSpan(x.GetSpan()) + setPreprocessed(cx) setConstAttrs(cx) return cx } @@ -3374,8 +3467,8 @@ func evalConst(store Store, last BlockNode, x Expr) *ConstExpr { func constType(source Expr, t Type) *constTypeExpr { cx := &constTypeExpr{Source: source} cx.Type = t - cx.SetLine(source.GetLine()) - cx.SetAttribute(ATTR_PREPROCESSED, true) + // cx.SetSpan(source.GetSpan()) + setPreprocessed(cx) return cx } @@ -3390,6 +3483,12 @@ func setConstAttrs(cx *ConstExpr) { } } +func setPreprocessed(x Expr) { + if x.GetAttribute(ATTR_PREPROCESS_INCOMPLETE) == nil { + x.SetAttribute(ATTR_PREPROCESSED, true) + } +} + func packageOf(last BlockNode) *PackageNode { for { if pn, ok := last.(*PackageNode); ok { @@ -3760,92 +3859,6 @@ func convertConst(store Store, last BlockNode, n Node, cx *ConstExpr, t Type) { } } -func assertTypeDeclNoCycle(store Store, last BlockNode, td *TypeDecl, stack *[]Name) { - assertTypeDeclNoCycle2(store, last, td.Type, stack, false, td.IsAlias) -} - -func assertTypeDeclNoCycle2(store Store, last BlockNode, x Expr, stack *[]Name, indirect bool, isAlias bool) { - if x == nil { - panic("unexpected nil expression when checking for type declaration cycles") - } - - var lastX Expr - defer func() { - if _, ok := lastX.(*NameExpr); ok { - // pop stack - *stack = (*stack)[:len(*stack)-1] - } - }() - - switch cx := x.(type) { - case *NameExpr: - var msg string - - // Function to build the error message - buildMessage := func() string { - for j := range *stack { - msg += fmt.Sprintf("%s -> ", (*stack)[j]) - } - return msg + string(cx.Name) // Append the current name last - } - - // Check for existence of cx.Name in stack - findCycle := func() { - for _, n := range *stack { - if n == cx.Name { - msg = buildMessage() - panic(fmt.Sprintf("invalid recursive type: %s", msg)) - } - } - } - - if indirect && !isAlias { - *stack = (*stack)[:0] - } else { - findCycle() - *stack = append(*stack, cx.Name) - lastX = cx - } - - return - case *SelectorExpr: - assertTypeDeclNoCycle2(store, last, cx.X, stack, indirect, isAlias) - case *StarExpr: - assertTypeDeclNoCycle2(store, last, cx.X, stack, true, isAlias) - case *FieldTypeExpr: - assertTypeDeclNoCycle2(store, last, cx.Type, stack, indirect, isAlias) - case *ArrayTypeExpr: - if cx.Len != nil { - assertTypeDeclNoCycle2(store, last, cx.Len, stack, indirect, isAlias) - } - assertTypeDeclNoCycle2(store, last, cx.Elt, stack, indirect, isAlias) - case *SliceTypeExpr: - assertTypeDeclNoCycle2(store, last, cx.Elt, stack, true, isAlias) - case *InterfaceTypeExpr: - for i := range cx.Methods { - assertTypeDeclNoCycle2(store, last, &cx.Methods[i], stack, indirect, isAlias) - } - case *ChanTypeExpr: - assertTypeDeclNoCycle2(store, last, cx.Value, stack, true, isAlias) - case *FuncTypeExpr: - for i := range cx.Params { - assertTypeDeclNoCycle2(store, last, &cx.Params[i], stack, true, isAlias) - } - for i := range cx.Results { - assertTypeDeclNoCycle2(store, last, &cx.Results[i], stack, true, isAlias) - } - case *MapTypeExpr: - assertTypeDeclNoCycle2(store, last, cx.Key, stack, true, isAlias) - assertTypeDeclNoCycle2(store, last, cx.Value, stack, true, isAlias) - case *StructTypeExpr: - for i := range cx.Fields { - assertTypeDeclNoCycle2(store, last, &cx.Fields[i], stack, indirect, isAlias) - } - default: - } - return -} - // 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 @@ -3854,658 +3867,264 @@ func assertTypeDeclNoCycle2(store Store, last BlockNode, x Expr, stack *[]Name, // NOTE: has no side effects except for the case of composite // type expressions, which must get preprocessed for inner // composite type eliding to work. -func findUndefined(store Store, last BlockNode, x Expr) (un Name) { - return findUndefined2(store, last, x, nil, true) +// +// Args: +// - direct: If true x must not be a *NameExpr in stack/defining (illegal direct recursion). +// - elide: For composite type eliding. +// +// Returns: +// - un: undefined dependency's name if any +// - directR: if un != "", `direct` passed to final name expr. +// NOTE: 'direct' is passed through, or becomes overridden with false and +// passed to higher/later calls in the stack, and the `direct` argument +// seen at the top of the stack is returned all the way back. +func findUndefinedV(store Store, last BlockNode, x Expr, stack []Name, defining map[Name]struct{}, direct bool, elide Type) (un Name, directR bool) { + return findUndefinedAny(store, last, x, stack, defining, false, direct, false, elide) } -// finds the next undefined identifier and returns it if it is global -func findUndefined2SkipLocals(store Store, last BlockNode, x Expr, t Type) Name { - name := findUndefinedGlobal(store, last, x, t) +func findUndefinedT(store Store, last BlockNode, x Expr, stack []Name, defining map[Name]struct{}, isalias bool, direct bool) (un Name, directR bool) { + return findUndefinedAny(store, last, x, stack, defining, isalias, direct, true, nil) +} - if name == "" { - return "" +func findUndefinedAny(store Store, last BlockNode, x Expr, stack []Name, defining map[Name]struct{}, isalias bool, direct bool, astype bool, elide Type) (un Name, directR bool) { + if debugFind { + fmt.Printf("findUndefinedAny(%v, %v, %v, isalias=%v, direct=%v, astype=%v, elide=%v\n", x, stack, defining, isalias, direct, astype, elide) } - - existsLocal := func(name Name, bn BlockNode) bool { - curr := bn - for { - currNames := curr.GetBlockNames() - - if slices.Contains(currNames, name) { - return true - } - - newcurr := bn.GetStaticBlock().GetParentNode(store) - - if curr == newcurr { - return false + if x == nil { + return + } + switch cx := x.(type) { + case *NameExpr: + if _, ok := UverseNode().GetLocalIndex(cx.Name); ok { + return + } + /* + if _, ok := defining[cx.Name]; !ok { + return cx.Name } - curr = newcurr - - if curr == nil { - return false + else if idx, ok := UverseNode().GetLocalIndex(tx.Name); ok { + // uverse name + path := NewValuePathUverse(idx, tx.Name) + tv := Uverse().GetValueAt(nil, path) + t = tv.GetType() + } else { + // yet undefined + un = tx.Name + directR = direct // returns along callstack. + untype = true + return + } + */ + // XXX simplify + if direct { + if astype { + if _, ok := defining[cx.Name]; ok { + panic(fmt.Sprintf("invalid recursive type: %s -> %s", + Names(stack).Join(" -> "), cx.Name)) + } + if tv := last.GetValueRef(store, cx.Name, true); tv != nil { + return + } + } else { + if tv := last.GetValueRef(store, cx.Name, true); tv != nil { + return + } + return cx.Name, direct } - - _, isFile := curr.(*FileNode) - - if isFile { - return false + } else { + if tv := last.GetValueRef(store, cx.Name, true); tv != nil { + return } } - } - - pkg := packageOf(last) - - if _, _, ok := pkg.FileSet.GetDeclForSafe(name); !ok { - return "" - } - - isLocal := existsLocal(name, last) - - if isLocal { - return "" - } - - return name -} - -func findUndefinedStmt(store Store, last BlockNode, stmt Stmt, t Type) Name { - switch s := stmt.(type) { - case *TypeDecl: - un := findUndefined2SkipLocals(store, last, s.Type, t) - + return cx.Name, direct + case *BasicLitExpr: + return + case *BinaryExpr: + un, directR = findUndefinedV(store, last, cx.Left, stack, defining, direct, nil) if un != "" { - return un + return } - case *ValueDecl: - un := findUndefined2SkipLocals(store, last, s.Type, t) - + un, directR = findUndefinedV(store, last, cx.Right, stack, defining, direct, nil) if un != "" { - return un + return } - for _, rh := range s.Values { - un := findUndefined2SkipLocals(store, last, rh, t) - + case *SelectorExpr: + return findUndefinedV(store, last, cx.X, stack, defining, direct, nil) + case *SliceExpr: + un, directR = findUndefinedV(store, last, cx.X, stack, defining, direct, nil) + if un != "" { + return + } + if cx.Low != nil { + un, directR = findUndefinedV(store, last, cx.Low, stack, defining, direct, nil) if un != "" { - return un + return } } - case *DeclStmt: - for _, rh := range s.Body { - un := findUndefinedStmt(store, last, rh, t) - + if cx.High != nil { + un, directR = findUndefinedV(store, last, cx.High, stack, defining, direct, nil) if un != "" { - return un + return } } - case *IncDecStmt: - un := findUndefined2SkipLocals(store, last, s.X, t) - - if un != "" { - return un - } - case *BlockStmt: - for _, rh := range s.Body { - un := findUndefinedStmt(store, s, rh, t) - + if cx.Max != nil { + un, directR = findUndefinedV(store, last, cx.Max, stack, defining, direct, nil) if un != "" { - return un + return } } - case *DeferStmt: - un := findUndefined2SkipLocals(store, last, s.Call.Func, t) - + case *StarExpr: // POINTER & DEREF + // NOTE: *StarExpr can either mean dereference, or a pointer type. + // It's not only confusing for new developers, it causes complexity + // in type checking. A *StarExpr is indirect as a type unless alias. + if astype { + return findUndefinedT(store, last, cx.X, stack, defining, isalias, isalias) + } else { + return findUndefinedV(store, last, cx.X, stack, defining, direct, nil) + } + case *RefExpr: + return findUndefinedV(store, last, cx.X, stack, defining, direct, nil) + case *TypeAssertExpr: + un, directR = findUndefinedV(store, last, cx.X, stack, defining, direct, nil) if un != "" { - return un + return } - - for _, rh := range s.Call.Args { - un = findUndefined2SkipLocals(store, last, rh, t) - + return findUndefinedT(store, last, cx.Type, stack, defining, isalias, direct) + case *UnaryExpr: + return findUndefinedV(store, last, cx.X, stack, defining, direct, nil) + case *CompositeLitExpr: + var ct Type + if cx.Type == nil { + if elide == nil { + panic("cannot elide unknown composite type") + } + ct = elide + cx.Type = constType(cx, elide) + } else { + un, directR = findUndefinedT(store, last, cx.Type, stack, defining, isalias, astype && direct) if un != "" { - return un + return } + // preprocess now for eliding purposes. + // TODO recursive preprocessing here is hacky, find a better + // way. This cannot be done asynchronously, cuz undefined + // names ought to be returned immediately to let the caller + // predefine it. + cx.Type = Preprocess(store, last, cx.Type).(Expr) // recursive + ct = evalStaticType(store, last, cx.Type) + // elide composite lit element (nested) composite types. + elideCompositeElements(cx, ct) } - case *SwitchStmt: - un := findUndefined2SkipLocals(store, last, s.X, t) - if un != "" { - return un + switch ct.Kind() { + case ArrayKind, SliceKind, MapKind: + for _, kvx := range cx.Elts { + un, directR = findUndefinedV(store, last, kvx.Key, stack, defining, direct, nil) + if un != "" { + return + } + un, directR = findUndefinedV(store, last, kvx.Value, stack, defining, direct, ct.Elem()) + if un != "" { + return + } + } + case StructKind: + for _, kvx := range cx.Elts { + un, directR = findUndefinedV(store, last, kvx.Value, stack, defining, direct, nil) + if un != "" { + return + } + } + default: + panic(fmt.Sprintf( + "unexpected composite lit type %s", + ct.String())) } - - un = findUndefinedStmt(store, last, s.Init, t) + case *FuncLitExpr: + un, directR = findUndefinedT(store, last, &cx.Type, stack, defining, isalias, astype && isalias) if un != "" { - return un + return } - - for _, b := range s.Clauses { - b := b - un = findUndefinedStmt(store, s, &b, t) - + _, _, found := findLastFunction(last, nil) + if !found { + cx.SetAttribute(ATTR_PREPROCESS_SKIPPED, AttrPreprocessFuncLitExpr) + } + case *FieldTypeExpr: // FIELD + return findUndefinedT(store, last, cx.Type, stack, defining, isalias, direct) + case *ArrayTypeExpr: + if cx.Len != nil { + un, directR = findUndefinedV(store, last, cx.Len, stack, defining, direct, nil) if un != "" { - return un + return } } - case *SwitchClauseStmt: - for _, rh := range s.Cases { - un := findUndefined2SkipLocals(store, last, rh, t) - + return findUndefinedT(store, last, cx.Elt, stack, defining, isalias, direct) + case *SliceTypeExpr: + return findUndefinedT(store, last, cx.Elt, stack, defining, isalias, astype && isalias) + case *InterfaceTypeExpr: + for i := range cx.Methods { + method := &cx.Methods[i] + direct2 := false + if _, ok := method.Type.(*NameExpr); ok { + direct2 = true + } + un, directR = findUndefinedT(store, last, &cx.Methods[i], stack, defining, isalias, direct2) if un != "" { - return un + return } } - - for _, b := range s.Body { - un := findUndefinedStmt(store, last, b, t) - + case *ChanTypeExpr: + return findUndefinedT(store, last, cx.Value, stack, defining, isalias, astype && isalias) + case *FuncTypeExpr: + for i := range cx.Params { + un, directR = findUndefinedT(store, last, &cx.Params[i], stack, defining, isalias, astype && isalias) if un != "" { - return un + return } } - - case *ExprStmt: - return findUndefined2SkipLocals(store, last, s.X, t) - case *AssignStmt: - for _, rh := range s.Rhs { - un := findUndefined2SkipLocals(store, last, rh, t) - + for i := range cx.Results { + un, directR = findUndefinedT(store, last, &cx.Results[i], stack, defining, isalias, astype && isalias) if un != "" { - return un + return } } - case *IfStmt: - un := findUndefinedStmt(store, last, s.Init, t) + case *MapTypeExpr: // MAP + un, directR = findUndefinedT(store, last, cx.Key, stack, defining, isalias, astype && isalias) if un != "" { - return un + return } - - un = findUndefined2SkipLocals(store, last, s.Cond, t) + // e.g.; + // type Int = map[Int]IntIllegal; + // type Int = struct{Int}; + // type Int = *Int; + un, directR = findUndefinedT(store, last, cx.Value, stack, defining, isalias, isalias) if un != "" { - return un + return } - - un = findUndefinedStmt(store, last, &s.Else, t) - if un != "" { - return un - } - - un = findUndefinedStmt(store, last, &s.Then, t) - if un != "" { - return un - } - case *IfCaseStmt: - for _, b := range s.Body { - un := findUndefinedStmt(store, last, b, t) - - if un != "" { - return un - } - } - case *ReturnStmt: - for _, b := range s.Results { - un := findUndefined2SkipLocals(store, last, b, t) - if un != "" { - return un - } - } - case *RangeStmt: - un := findUndefined2SkipLocals(store, last, s.X, t) - if un != "" { - return un - } - - for _, b := range s.Body { - un := findUndefinedStmt(store, last, b, t) - if un != "" { - return un - } - } - case *ForStmt: - un := findUndefinedStmt(store, s, s.Init, t) - if un != "" { - return un - } - - un = findUndefined2SkipLocals(store, s, s.Cond, t) - if un != "" { - return un - } - - un = findUndefinedStmt(store, s, s.Post, t) - if un != "" { - return un - } - - for _, b := range s.Body { - un := findUndefinedStmt(store, last, b, t) - if un != "" { - return un - } - } - case *BranchStmt: - case nil: - return "" - default: - panic(fmt.Sprintf("findUndefinedStmt: %T not supported", s)) - } - return "" -} - -func getGlobalValueRef(sb BlockNode, store Store, n Name) *TypedValue { - sbb := sb.GetStaticBlock() - idx, ok := sb.GetLocalIndex(n) - bb := &sb.GetStaticBlock().Block - bp := sb.GetParentNode(store) - - for { - if ok && sbb.Types[idx] != nil && (bp == nil || bp.GetParentNode(store) == nil) { - return bb.GetPointerToInt(store, int(idx)).TV - } else if bp != nil { - idx, ok = bp.GetLocalIndex(n) - sbb = bp.GetStaticBlock() - bb = sbb.GetBlock() - bp = bp.GetParentNode(store) - } else { - return nil - } - } -} - -func findUndefinedGlobal(store Store, last BlockNode, x Expr, t Type) (un Name) { - if x == nil { - return - } - switch cx := x.(type) { - case *NameExpr: - if tv := getGlobalValueRef(last, store, cx.Name); tv != nil { - return - } - - if _, ok := UverseNode().GetLocalIndex(cx.Name); ok { - // XXX NOTE even if the name is shadowed by a file - // level declaration, it is fine to return here as it - // will be predefined later. - return - } - - return cx.Name - case *BasicLitExpr: - return - case *BinaryExpr: - un = findUndefinedGlobal(store, last, cx.Left, nil) - if un != "" { - return - } - un = findUndefinedGlobal(store, last, cx.Right, nil) - if un != "" { - return - } - case *SelectorExpr: - return findUndefinedGlobal(store, last, cx.X, nil) - case *SliceExpr: - un = findUndefinedGlobal(store, last, cx.X, nil) - if un != "" { - return - } - if cx.Low != nil { - un = findUndefinedGlobal(store, last, cx.Low, nil) - if un != "" { - return - } - } - if cx.High != nil { - un = findUndefinedGlobal(store, last, cx.High, nil) - if un != "" { - return - } - } - if cx.Max != nil { - un = findUndefinedGlobal(store, last, cx.Max, nil) - if un != "" { - return - } - } - case *StarExpr: - return findUndefinedGlobal(store, last, cx.X, nil) - case *RefExpr: - return findUndefinedGlobal(store, last, cx.X, nil) - case *TypeAssertExpr: - un = findUndefinedGlobal(store, last, cx.X, nil) - if un != "" { - return - } - return findUndefinedGlobal(store, last, cx.Type, nil) - case *UnaryExpr: - return findUndefinedGlobal(store, last, cx.X, nil) - case *CompositeLitExpr: - var ct Type - if cx.Type == nil { - if t == nil { - panic("cannot elide unknown composite type") - } - ct = t - cx.Type = constType(cx, t) - } else { - un = findUndefinedGlobal(store, last, cx.Type, nil) - if un != "" { - return - } - // preprocess now for eliding purposes. - // TODO recursive preprocessing here is hacky, find a better - // way. This cannot be done asynchronously, cuz undefined - // names ought to be returned immediately to let the caller - // predefine it. - cx.Type = Preprocess(store, last, cx.Type).(Expr) // recursive - ct = evalStaticType(store, last, cx.Type) - // elide composite lit element (nested) composite types. - elideCompositeElements(cx, ct) - } - switch ct.Kind() { - case ArrayKind, SliceKind, MapKind: - for _, kvx := range cx.Elts { - un = findUndefinedGlobal(store, last, kvx.Key, nil) - if un != "" { - return - } - un = findUndefinedGlobal(store, last, kvx.Value, ct.Elem()) - if un != "" { - return - } - } - case StructKind: - for _, kvx := range cx.Elts { - un = findUndefinedGlobal(store, last, kvx.Value, nil) - if un != "" { - return - } - } - default: - panic(fmt.Sprintf( - "unexpected composite lit type %s", - ct.String())) - } - case *FuncLitExpr: - for _, stmt := range cx.Body { - un = findUndefinedStmt(store, cx, stmt, t) - - if un != "" { - return - } - } - return findUndefinedGlobal(store, last, &cx.Type, nil) - case *FieldTypeExpr: - return findUndefinedGlobal(store, last, cx.Type, nil) - case *ArrayTypeExpr: - if cx.Len != nil { - un = findUndefinedGlobal(store, last, cx.Len, nil) - if un != "" { - return - } - } - return findUndefinedGlobal(store, last, cx.Elt, nil) - case *SliceTypeExpr: - return findUndefinedGlobal(store, last, cx.Elt, nil) - case *InterfaceTypeExpr: - for i := range cx.Methods { - un = findUndefinedGlobal(store, last, &cx.Methods[i], nil) - if un != "" { - return - } - } - case *ChanTypeExpr: - return findUndefinedGlobal(store, last, cx.Value, nil) - case *FuncTypeExpr: - for i := range cx.Params { - un = findUndefinedGlobal(store, last, &cx.Params[i], nil) - if un != "" { - return - } - } - for i := range cx.Results { - un = findUndefinedGlobal(store, last, &cx.Results[i], nil) - if un != "" { - return - } - } - case *MapTypeExpr: - un = findUndefinedGlobal(store, last, cx.Key, nil) - if un != "" { - return - } - un = findUndefinedGlobal(store, last, cx.Value, nil) - if un != "" { - return - } - case *StructTypeExpr: - for i := range cx.Fields { - un = findUndefinedGlobal(store, last, &cx.Fields[i], nil) - if un != "" { - return - } - } - case *CallExpr: - un = findUndefinedGlobal(store, last, cx.Func, nil) - if un != "" { - return - } - for i := range cx.Args { - un = findUndefinedGlobal(store, last, cx.Args[i], nil) - if un != "" { - return - } - } - case *IndexExpr: - un = findUndefinedGlobal(store, last, cx.X, nil) - if un != "" { - return - } - un = findUndefinedGlobal(store, last, cx.Index, nil) - if un != "" { - return - } - case *constTypeExpr: - return - case *ConstExpr: - return - default: - panic(fmt.Sprintf( - "unexpected expr: %v (%v)", - x, reflect.TypeOf(x))) - } - return -} - -func findUndefined2(store Store, last BlockNode, x Expr, t Type, skipPredefined bool) (un Name) { - if x == nil { - return - } - switch cx := x.(type) { - case *NameExpr: - if tv := last.GetValueRef(store, cx.Name, skipPredefined); tv != nil { - return - } - if _, ok := UverseNode().GetLocalIndex(cx.Name); ok { - // XXX NOTE even if the name is shadowed by a file - // level declaration, it is fine to return here as it - // will be predefined later. - return - } - return cx.Name - case *BasicLitExpr: - return - case *BinaryExpr: - un = findUndefined2(store, last, cx.Left, nil, skipPredefined) - if un != "" { - return - } - un = findUndefined2(store, last, cx.Right, nil, skipPredefined) - if un != "" { - return - } - case *SelectorExpr: - return findUndefined2(store, last, cx.X, nil, skipPredefined) - case *SliceExpr: - un = findUndefined2(store, last, cx.X, nil, skipPredefined) - if un != "" { - return - } - if cx.Low != nil { - un = findUndefined2(store, last, cx.Low, nil, skipPredefined) - if un != "" { - return - } - } - if cx.High != nil { - un = findUndefined2(store, last, cx.High, nil, skipPredefined) - if un != "" { - return - } - } - if cx.Max != nil { - un = findUndefined2(store, last, cx.Max, nil, skipPredefined) - if un != "" { - return - } - } - case *StarExpr: - return findUndefined2(store, last, cx.X, nil, skipPredefined) - case *RefExpr: - return findUndefined2(store, last, cx.X, nil, skipPredefined) - case *TypeAssertExpr: - un = findUndefined2(store, last, cx.X, nil, skipPredefined) - if un != "" { - return - } - return findUndefined2(store, last, cx.Type, nil, skipPredefined) - case *UnaryExpr: - return findUndefined2(store, last, cx.X, nil, skipPredefined) - case *CompositeLitExpr: - var ct Type - if cx.Type == nil { - if t == nil { - panic("cannot elide unknown composite type") - } - ct = t - cx.Type = constType(cx, t) - } else { - un = findUndefined2(store, last, cx.Type, nil, skipPredefined) - if un != "" { - return - } - // preprocess now for eliding purposes. - // TODO recursive preprocessing here is hacky, find a better - // way. This cannot be done asynchronously, cuz undefined - // names ought to be returned immediately to let the caller - // predefine it. - cx.Type = Preprocess(store, last, cx.Type).(Expr) // recursive - ct = evalStaticType(store, last, cx.Type) - // elide composite lit element (nested) composite types. - elideCompositeElements(cx, ct) - } - switch ct.Kind() { - case ArrayKind, SliceKind, MapKind: - for _, kvx := range cx.Elts { - un = findUndefined2(store, last, kvx.Key, nil, skipPredefined) - if un != "" { - return - } - un = findUndefined2(store, last, kvx.Value, ct.Elem(), skipPredefined) - if un != "" { - return - } - } - case StructKind: - for _, kvx := range cx.Elts { - un = findUndefined2(store, last, kvx.Value, nil, skipPredefined) - if un != "" { - return - } - } - default: - panic(fmt.Sprintf( - "unexpected composite lit type %s", - ct.String())) - } - case *FuncLitExpr: - if cx.GetAttribute(ATTR_GLOBAL) == true { - for _, stmt := range cx.Body { - un = findUndefinedStmt(store, cx, stmt, t) - - if un != "" { - return - } - } - } - - return findUndefined2(store, last, &cx.Type, nil, skipPredefined) - case *FieldTypeExpr: - return findUndefined2(store, last, cx.Type, nil, skipPredefined) - case *ArrayTypeExpr: - if cx.Len != nil { - un = findUndefined2(store, last, cx.Len, nil, skipPredefined) - if un != "" { - return - } - } - return findUndefined2(store, last, cx.Elt, nil, skipPredefined) - case *SliceTypeExpr: - return findUndefined2(store, last, cx.Elt, nil, skipPredefined) - case *InterfaceTypeExpr: - for i := range cx.Methods { - un = findUndefined2(store, last, &cx.Methods[i], nil, skipPredefined) - if un != "" { - return - } - } - case *ChanTypeExpr: - return findUndefined2(store, last, cx.Value, nil, skipPredefined) - case *FuncTypeExpr: - for i := range cx.Params { - un = findUndefined2(store, last, &cx.Params[i], nil, skipPredefined) - if un != "" { - return - } - } - for i := range cx.Results { - un = findUndefined2(store, last, &cx.Results[i], nil, skipPredefined) - if un != "" { - return - } - } - case *MapTypeExpr: - un = findUndefined2(store, last, cx.Key, nil, skipPredefined) - if un != "" { - return - } - un = findUndefined(store, last, cx.Value) - if un != "" { - return - } - case *StructTypeExpr: + case *StructTypeExpr: // STRUCT for i := range cx.Fields { - un = findUndefined2(store, last, &cx.Fields[i], nil, skipPredefined) + un, directR = findUndefinedT(store, last, &cx.Fields[i], stack, defining, isalias, direct) if un != "" { return } } case *CallExpr: - cx.Func.SetAttribute(ATTR_GLOBAL, cx.GetAttribute(ATTR_GLOBAL)) - un = findUndefined2(store, last, cx.Func, nil, skipPredefined) + un, directR = findUndefinedV(store, last, cx.Func, stack, defining, direct, nil) if un != "" { return } for i := range cx.Args { - un = findUndefined2(store, last, cx.Args[i], nil, skipPredefined) + un, directR = findUndefinedV(store, last, cx.Args[i], stack, defining, direct, nil) if un != "" { return } } case *IndexExpr: - un = findUndefined2(store, last, cx.X, nil, skipPredefined) + un, directR = findUndefinedV(store, last, cx.X, stack, defining, direct, nil) if un != "" { return } - un = findUndefined2(store, last, cx.Index, nil, skipPredefined) + un, directR = findUndefinedV(store, last, cx.Index, stack, defining, direct, nil) if un != "" { return } @@ -4567,179 +4186,122 @@ func checkIntegerKind(xt Type) { } } -// predefineNow() pre-defines (with empty placeholders) all -// declaration names, and then preprocesses all type/value decls, and -// partially processes func decls. +// predefineRecursively() recursively defines or predefines (partially defines) +// all package level declaration names. *FuncDecl and *ValueDecl declarations +// are predefined (partially defined) while *ImportDecl and *TypeDecl are fully +// defined. // -// The recursive base procedure is split into two parts: +// It assumes that initStaticBlock has been called so that names are pre-reserved. // -// First, tryPredefine(), which first predefines with placeholder -// values/types to support recursive types, then returns yet -// un-predefined dependencies. +// It does NOT enter function bodies. // -// Second, which immediately preprocesses type/value declarations -// after dependencies have first been predefined, or partially -// preprocesses function declarations (which may not be completely -// preprocess-able before other file-level declarations are -// preprocessed). -func predefineNow(store Store, last BlockNode, d Decl) (Decl, bool) { +// This function works for all block nodes and is called for all declarations, +// but in two stages: in the first stage at the file level, and the second +// stage while preprocessing the body of each function. +// +// Returns true if the result was also preprocessed for *ImportDecl, *TypeDecl +// and *ValueDecl. *ValueDecl values are NOT evaluated at this stage. *FuncDecl +// are only partially defined and also only partially preprocessed. +func predefineRecursively(store Store, last BlockNode, d Decl) bool { defer doRecover([]BlockNode{last}, d) - stack := &[]Name{} - return predefineNow2(store, last, d, stack) + stack := []Name{} + defining := make(map[Name]struct{}) + direct := true + return predefineRecursively2(store, last, d, stack, defining, direct) } -func predefineNow2(store Store, last BlockNode, d Decl, stack *[]Name) (Decl, bool) { +// `stack` and `defining` are used for cycle detection. They hold the same data. +// NOTE: `stack` never truncates; a slice is used instead of a map to show a +// helpful message when a circular declaration is found. `defining` is also used as +// a map to ensure best time performance of circular definition detection. +func predefineRecursively2(store Store, last BlockNode, d Decl, stack []Name, defining map[Name]struct{}, direct bool) bool { pkg := packageOf(last) - stackLen := len(*stack) - // pre-register d.GetName() to detect circular definition. + + // NOTE: predefine fileset breaks up circular definitions like + // `var a, b, c = 1, a, b` which is only legal at the file level. for _, dn := range d.GetDeclNames() { if isUverseName(dn) { panic(fmt.Sprintf( "builtin identifiers cannot be shadowed: %s", dn)) } - *stack = append(*stack, dn) - } - if stackLen != len(*stack) { - defer func() { - *stack = (*stack)[:stackLen] - }() - } - - // check type decl cycle - if td, ok := d.(*TypeDecl); ok { - // recursively check - assertTypeDeclNoCycle(store, last, td, stack) + stack = append(stack, dn) + defining[dn] = struct{}{} } + // After definition, remove items from map. + // The stack doesn't need to be truncated because + // the caller's stack slice remains the same regardless, + // but the defining map must remove predefined names, + // otherwise later declarations will fail. + defer func() { + for _, dn := range d.GetDeclNames() { + delete(defining, dn) + } + }() - // recursively predefine dependencies. + // recursively predefine any dependencies. + var un Name // undefined name + var untype bool + var directR bool + // var direct = true // invalid cycle detection for { - un := tryPredefine(store, pkg, last, d) + un, untype, directR = tryPredefine(store, pkg, last, d, stack, defining, direct) + if debugFind { + fmt.Printf("tryPredefine(%v, %v, defining=%v, direct=%v)-->un=%v,untype=%v,direct2=%v\n", d, stack, defining, direct, un, untype, directR) + } if un != "" { - // check circularity. - if slices.Contains(*stack, un) { - panic(fmt.Sprintf("constant definition loop with %s", un)) + // `un` is undefined, so define recursively. + // first, check circularity. + if _, exists := defining[un]; exists { + if untype { + panic(fmt.Sprintf("invalid recursive type: %s -> %s", + Names(stack).Join(" -> "), un)) + } else { + panic(fmt.Sprintf("invalid recursive value: %s -> %s", + Names(stack).Join(" -> "), un)) + } } // look up dependency declaration from fileset. - file, decl := pkg.FileSet.GetDeclFor(un) + file, unDecl := pkg.FileSet.GetDeclFor(un) // preprocess if not already preprocessed. if !file.IsInitialized() { panic("all types from files in file-set should have already been predefined") } - - declaration := *decl - declaration.SetAttribute(ATTR_GLOBAL, true) - - // predefine dependency (recursive). - *decl, _ = predefineNow2(store, file, declaration, stack) + // predefine dependency recursively. + // `directR` is passed on. + predefineRecursively2(store, file, *unDecl, stack, defining, directR) } else { - break + break // predefine successfully performed. } } switch cd := d.(type) { case *FuncDecl: - // *FuncValue/*FuncType is mostly empty still; here - // we just fill the func type (and recv if method). - // NOTE: unlike the *ValueDecl case, this case doesn't - // preprocess d itself (only d.Type). - if cd.IsMethod { - if cd.Recv.Name == "" || cd.Recv.Name == blankIdentifier { - panic("cd.Recv.Name should have been set in initStaticBlocks") - } - cd.Recv = *Preprocess(store, last, &cd.Recv).(*FieldTypeExpr) - cd.Type = *Preprocess(store, last, &cd.Type).(*FuncTypeExpr) - rft := evalStaticType(store, last, &cd.Recv).(FieldType) - rt := rft.Type - ft := evalStaticType(store, last, &cd.Type).(*FuncType) - ft = ft.UnboundType(rft) - dt := (*DeclaredType)(nil) - - // check base type of receiver type, should not be pointer type or interface type - assertValidReceiverType := func(t Type) { - if _, ok := t.(*PointerType); ok { - panic(fmt.Sprintf("invalid receiver type %v (base type is pointer type)", rt)) - } - if _, ok := t.(*InterfaceType); ok { - panic(fmt.Sprintf("invalid receiver type %v (base type is interface type)", rt)) - } - } - - if pt, ok := rt.(*PointerType); ok { - assertValidReceiverType(pt.Elem()) - if ddt, ok := pt.Elem().(*DeclaredType); ok { - assertValidReceiverType(baseOf(ddt)) - dt = ddt - } else { - panic("should not happen") - } - } else if ddt, ok := rt.(*DeclaredType); ok { - assertValidReceiverType(baseOf(ddt)) - dt = ddt - } else { - panic("should not happen") - } - // The body may get altered during preprocessing later. - if !dt.TryDefineMethod(&FuncValue{ - Type: ft, - IsMethod: true, - Source: cd, - Name: cd.Name, - Parent: nil, // set lazily - FileName: fileNameOf(last), - PkgPath: pkg.PkgPath, - Crossing: cd.Body.isCrossing(), - body: cd.Body, - nativeBody: nil, - }) { - // Revert to old function declarations in the package we're preprocessing. - pkg := packageOf(last) - pkg.StaticBlock.revertToOld() - panic(fmt.Sprintf("redeclaration of method %s.%s", - dt.Name, cd.Name)) - } - } else { - if cd.Name == "init" { - panic("cd.Name 'init' should have been appended with a number in initStaticBlocks") - } - ftv := pkg.GetValueRef(store, cd.Name, true) - ft := ftv.T.(*FuncType) - cd.Type = *Preprocess(store, last, &cd.Type).(*FuncTypeExpr) - ft2 := evalStaticType(store, last, &cd.Type).(*FuncType) - if !ft.IsZero() { - // redefining function. - // make sure the type is the same. - if ft.TypeID() != ft2.TypeID() { - panic(fmt.Sprintf( - "Redefinition (%s) cannot change .T; was %v, new %v", - cd, ft, ft2)) - } - // keep the orig type. - } else { - *ft = *ft2 - } - // XXX replace attr w/ ft? - // return Preprocess(store, last, cd).(Decl), true - } - // Full type declaration/preprocessing already done in tryPredefine - return d, false + // We cannot Preprocess the body of *FuncDecl as it may + // refer to package names in any order. + return false case *ValueDecl: - return Preprocess(store, last, cd).(Decl), true + vd2 := Preprocess(store, last, cd).(*ValueDecl) + *cd = *vd2 + return true case *TypeDecl: - return Preprocess(store, last, cd).(Decl), true + td2 := Preprocess(store, last, cd).(*TypeDecl) + *cd = *td2 + return true + case *ImportDecl: + id2 := Preprocess(store, last, cd).(*ImportDecl) + *cd = *id2 + return true default: - return d, false + panic("should not happen") } } -// If a dependent name is not yet defined, that name is -// returned; this return value is used by the caller to -// enforce declaration order. If a dependent type is not yet -// defined (preprocessed), that type is fully preprocessed. -// Besides defining the type (and immediate dependent types -// of d) onto last (or packageOf(last)), there are no other -// side effects. This function works for all block nodes and -// must be called for name declarations within (non-file, -// non-package) stmt bodies. -func tryPredefine(store Store, pkg *PackageNode, last BlockNode, d Decl) (un Name) { +// If a dependent name is not yet defined, that name is returned; this return +// value is used by the caller to enforce declaration order. +// +// If all dependencies are met, constructs and empty definition value (for a +// *TypeDecl is a TypeValue) and sets it on last. As an exception, *FuncDecls +// will preprocess receiver/argument/result types recursively. +func tryPredefine(store Store, pkg *PackageNode, last BlockNode, d Decl, stack []Name, defining map[Name]struct{}, direct bool) (un Name, untype bool, directR bool) { if d.GetAttribute(ATTR_PREDEFINED) == true { panic(fmt.Sprintf("decl node already predefined! %v", d)) } @@ -4769,7 +4331,7 @@ func tryPredefine(store Store, pkg *PackageNode, last BlockNode, d Decl) (un Nam // NOTE: imports from "pure packages" are actually sometimes // allowed, most notably filetests. - if IsPPackagePath(pkg.PkgPath) && IsRealmPath(d.PkgPath) { + if IsPPackagePath(pkg.PkgPath) && IsRealmPath(d.PkgPath) && !IsTestFile(last.GetLocation().File) { panic(fmt.Sprintf("pure package path %q cannot import realm path %q", pkg.PkgPath, d.PkgPath)) } @@ -4811,15 +4373,19 @@ func tryPredefine(store Store, pkg *PackageNode, last BlockNode, d Decl) (un Nam if isBlankIdentifier(d.Type) { panic("cannot use _ as value or type") } - - un = findUndefined(store, last, d.Type) + isalias := false // a value decl can't be. + un, directR = findUndefinedT(store, last, d.Type, stack, defining, isalias, false) // XXX if un != "" { + untype = true return } + // NOTE: cyclic *ValueDecl at the package/file level such as + // `var a, b, c = 1, a, b` was already split up before reaching + // here, whereas they are illegal inside a function. for _, vx := range d.Values { - vx.SetAttribute(ATTR_GLOBAL, d.GetAttribute(ATTR_GLOBAL)) - un = findUndefined(store, last, vx) + un, directR = findUndefinedV(store, last, vx, stack, defining, direct, nil) if un != "" { + untype = false return } } @@ -4860,34 +4426,33 @@ func tryPredefine(store Store, pkg *PackageNode, last BlockNode, d Decl) (un Nam if isBlankIdentifier(tx) { panic("cannot use _ as value or type") } - // do not allow nil as type. if tx.Name == "nil" { panic("nil is not a type") } - + // sanity check. if tv := last.GetValueRef(store, tx.Name, true); tv != nil { t = tv.GetType() if dt, ok := t.(*DeclaredType); ok { if !dt.sealed { - // predefineNow preprocessed dependent types. + // predefineRecursively should have + // already preprocessed dependent types! panic("should not happen") } } - } else if idx, ok := UverseNode().GetLocalIndex(tx.Name); ok { + } + // set t for proper type. + if idx, ok := UverseNode().GetLocalIndex(tx.Name); ok { // uverse name path := NewValuePathUverse(idx, tx.Name) tv := Uverse().GetValueAt(nil, path) t = tv.GetType() - } else { - // yet undefined - un = tx.Name - return } case *SelectorExpr: // get package value. - un = findUndefined(store, last, tx.X) + un, directR = findUndefinedV(store, last, tx.X, stack, defining, false, nil) if un != "" { + untype = true return } pkgName := tx.X.(*NameExpr).Name @@ -4922,29 +4487,87 @@ func tryPredefine(store Store, pkg *PackageNode, last BlockNode, d Decl) (un Nam // last2.Define(d.Name, asValue(t)) last2.Define2(true, d.Name, t, asValue(t)) d.Path = last.GetPathForName(store, d.Name) - } - // after predefinitions, return any undefined dependencies. - un = findUndefined(store, last, d.Type) + } // END if !isLocallyDefined(last2, d.Name) { + // now it is or was locally defined. + + // after predefinitions (for reasonable recursion support), + // return any undefined dependencies. + un, directR = findUndefinedAny( + store, last, d.Type, stack, defining, d.IsAlias, direct, true, nil) if un != "" { + untype = true return } + // END *TypeDecl case *FuncDecl: - un = findUndefined(store, last, &d.Type) + un, directR = findUndefinedT(store, last, &d.Type, stack, defining, false, false) if un != "" { + untype = true return } if d.IsMethod { - // define method. - // methods are defined as struct fields, not - // in the last block. receiver isn't - // processed until FuncDecl:BLOCK. - un = findUndefined(store, last, &d.Recv) + un, directR = findUndefinedT(store, last, &d.Recv, stack, defining, false, false) if un != "" { + untype = true return } + if d.Recv.Name == "" || d.Recv.Name == blankIdentifier { + panic("d.Recv.Name should have been set in initStaticBlocks") + } + d.Recv = *Preprocess(store, last, &d.Recv).(*FieldTypeExpr) + d.Type = *Preprocess(store, last, &d.Type).(*FuncTypeExpr) + rft := evalStaticType(store, last, &d.Recv).(FieldType) + rt := rft.Type + ft := evalStaticType(store, last, &d.Type).(*FuncType) + ft = ft.UnboundType(rft) + dt := (*DeclaredType)(nil) + + // check base type of receiver type, should not be pointer type or interface type + assertValidReceiverType := func(t Type) { + if _, ok := t.(*PointerType); ok { + panic(fmt.Sprintf("invalid receiver type %v (base type is pointer type)", rt)) + } + if _, ok := t.(*InterfaceType); ok { + panic(fmt.Sprintf("invalid receiver type %v (base type is interface type)", rt)) + } + } + + if pt, ok := rt.(*PointerType); ok { + assertValidReceiverType(pt.Elem()) + if ddt, ok := pt.Elem().(*DeclaredType); ok { + assertValidReceiverType(baseOf(ddt)) + dt = ddt + } else { + panic("should not happen") + } + } else if ddt, ok := rt.(*DeclaredType); ok { + assertValidReceiverType(baseOf(ddt)) + dt = ddt + } else { + panic("should not happen") + } + // The body may get altered during preprocessing later. + if !dt.TryDefineMethod(&FuncValue{ + Type: ft, + IsMethod: true, + Source: d, + Name: d.Name, + Parent: nil, // set lazily + FileName: fileNameOf(last), + PkgPath: pkg.PkgPath, + Crossing: d.Body.isCrossing(), + body: d.Body, + nativeBody: nil, + }) { + // Revert to old function declarations in the package we're preprocessing. + pkg := packageOf(last) + pkg.StaticBlock.revertToOld() + panic(fmt.Sprintf("redeclaration of method %s.%s", + dt.Name, d.Name)) + } } else { if d.Name == "init" { - panic("cd.Name 'init' should have been appended with a number in initStaticBlocks") + panic("d.Name 'init' should have been appended with a number in initStaticBlocks") } // define package-level function. ft := &FuncType{} @@ -4973,22 +4596,43 @@ func tryPredefine(store Store, pkg *PackageNode, last BlockNode, d Decl) (un Nam fv.NativePkg = pkg.PkgPath fv.NativeName = d.Name } + // Set placeholder ft and fv. pkg.Define(d.Name, TypedValue{ T: ft, V: fv, }) + /* XXX delete if d.Name == "init" { // init functions can't be referenced. } else { d.Path = last.GetPathForName(store, d.Name) } + if d.Name == "init" { + panic("d.Name 'init' should have been appended with a number in initStaticBlocks") + } + */ + d.Type = *Preprocess(store, last, &d.Type).(*FuncTypeExpr) + ft2 := evalStaticType(store, last, &d.Type).(*FuncType) + if !ft.IsZero() { + // redefining function. + // make sure the type is the same. + if ft.TypeID() != ft2.TypeID() { + panic(fmt.Sprintf( + "Redefinition (%s) cannot change .T; was %v, new %v", + d, ft, ft2)) + } + // keep the orig type. + } else { + *ft = *ft2 + } } default: panic(fmt.Sprintf( "unexpected declaration type %v", d.String())) } - return "" + // predefine complete. + return "", false, false // zero values } var reExpectedPkgName = regexp.MustCompile(`(?:^|/)([^/]+)(?:/v\d+)?$`) @@ -5011,7 +4655,7 @@ func constInt(source Expr, i int64) *ConstExpr { cx := &ConstExpr{Source: source} cx.T = IntType cx.SetInt(i) - cx.SetAttribute(ATTR_PREPROCESSED, true) + setPreprocessed(cx) return cx } @@ -5019,7 +4663,7 @@ func constUntypedBigint(source Expr, i64 int64) *ConstExpr { cx := &ConstExpr{Source: source} cx.T = UntypedBigintType cx.V = BigintValue{big.NewInt(i64)} - cx.SetAttribute(ATTR_PREPROCESSED, true) + setPreprocessed(cx) return cx } @@ -5055,9 +4699,11 @@ func fillNameExprPath(last BlockNode, nx *NameExpr, isDefineLHS bool) { // If not DEFINE_LHS, yet is statically undefined, set path from parent. if !isDefineLHS { if last.GetStaticTypeOf(nil, nx.Name) == nil { - // NOTE: We cannot simply call last.GetPathForName() as below here, - // because .GetPathForName() doesn't distinguish between predefined - // and declared variables. See tests/files/define1.go for test case. + // NOTE: We cannot simply call last.GetPathForName() as + // below here, because .GetPathForName() doesn't + // distinguish between undefined reserved and and + // (pre)defined variables. See tests/files/define1.go + // for test case. var path ValuePath var i int = 0 var fauxChild int = 0 @@ -5389,20 +5035,44 @@ func isLocallyDefined2(bn BlockNode, n Name) bool { // ---------------------------------------- // setNodeLines & setNodeLocations -func setNodeLines(n Node) { - lastLine := 0 - Transcribe(n, func(ns []Node, ftype TransField, index int, n Node, stage TransStage) (Node, TransCtrl) { - if stage != TRANS_ENTER { +func setNodeLines(nn Node) { + var all Span // if nn has no span defined, derive one from its contents. + Transcribe(nn, func(ns []Node, ftype TransField, index int, n Node, stage TransStage) (Node, TransCtrl) { + switch stage { + case TRANS_ENTER: + nspan := n.GetSpan() + if nspan.IsZero() { + if len(ns) == 0 { + // Handled by TRANS_LEAVE. Case A. + return n, TRANS_CONTINUE + } + lastSpan := ns[len(ns)-1].GetSpan() + if lastSpan.IsZero() { + // Handled by TRANS_LEAVE too. Case B. + return n, TRANS_CONTINUE + } else { + // Derive from parent with .Num++. + nspan = lastSpan + nspan.Num += 1 + n.SetSpan(nspan) + return n, TRANS_CONTINUE + } + } else { + // Expand all with nspan. + all = all.Union(nspan) + return n, TRANS_CONTINUE + } + case TRANS_LEAVE: + // TODO: Validate that all spans of elements are + // strictly contained. + nspan := n.GetSpan() + if nspan.IsZero() { + // Case A: len(ns) == 0 + // Case b: len(ns) > 0. + n.SetSpan(all) + } return n, TRANS_CONTINUE } - line := n.GetLine() - if line == lastLine { - } else if line == 0 { - line = lastLine - } else { - lastLine = line - } - n.SetLine(line) return n, TRANS_CONTINUE }) } @@ -5423,8 +5093,7 @@ func setNodeLocations(pkgPath string, fileName string, n Node) { loc := Location{ PkgPath: pkgPath, File: fileName, - Line: bn.GetLine(), - Column: bn.GetColumn(), + Span: bn.GetSpan(), } bn.SetLocation(loc) } diff --git a/gnovm/pkg/gnolang/realm.go b/gnovm/pkg/gnolang/realm.go index 41ed8ec1957..73a02705869 100644 --- a/gnovm/pkg/gnolang/realm.go +++ b/gnovm/pkg/gnolang/realm.go @@ -1265,6 +1265,8 @@ func copyValueWithRefs(val Value) Value { // fillTypes // (fully) fills the type. +// The store stores RefTypes, but this function fills it. +// This lets the store be independent of laziness. func fillType(store Store, typ Type) Type { switch ct := typ.(type) { case nil: diff --git a/gnovm/pkg/gnolang/store.go b/gnovm/pkg/gnolang/store.go index 5a8163e97cd..85e56fabee5 100644 --- a/gnovm/pkg/gnolang/store.go +++ b/gnovm/pkg/gnolang/store.go @@ -61,7 +61,7 @@ type Store interface { // Upon restart, all packages will be re-preprocessed; This // loads BlockNodes and Types onto the store for persistence // version 1. - AddMemPackage(memPkg *std.MemPackage) + AddMemPackage(mpkg *std.MemPackage, mtype MemPackageType) GetMemPackage(path string) *std.MemPackage GetMemFile(path string, name string) *std.MemFile FindPathsByPrefix(prefix string) iter.Seq[string] @@ -787,7 +787,7 @@ func (ds *defaultStore) incGetPackageIndexCounter() uint64 { } } -func (ds *defaultStore) AddMemPackage(memPkg *std.MemPackage) { +func (ds *defaultStore) AddMemPackage(mpkg *std.MemPackage, mtype MemPackageType) { if bm.OpsEnabled { bm.PauseOpCode() defer bm.ResumeOpCode() @@ -800,14 +800,18 @@ func (ds *defaultStore) AddMemPackage(memPkg *std.MemPackage) { bm.StopStore(size) }() } - memPkg.Validate() // NOTE: duplicate validation. + err := ValidateMemPackageWithOptions(mpkg, + ValidateMemPackageOptions{Type: mtype}) + if err != nil { + panic(fmt.Errorf("invalid mempackage: %w", err)) + } ctr := ds.incGetPackageIndexCounter() idxkey := []byte(backendPackageIndexKey(ctr)) - bz := amino.MustMarshal(memPkg) + bz := amino.MustMarshal(mpkg) gas := overflow.Mulp(ds.gasConfig.GasAddMemPackage, store.Gas(len(bz))) ds.consumeGas(gas, GasAddMemPackageDesc) - ds.baseStore.Set(idxkey, []byte(memPkg.Path)) - pathkey := []byte(backendPackagePathKey(memPkg.Path)) + ds.baseStore.Set(idxkey, []byte(mpkg.Path)) + pathkey := []byte(backendPackagePathKey(mpkg.Path)) ds.iavlStore.Set(pathkey, bz) size = len(bz) } @@ -850,21 +854,21 @@ func (ds *defaultStore) getMemPackage(path string, isRetry bool) *std.MemPackage gas := overflow.Mulp(ds.gasConfig.GasGetMemPackage, store.Gas(len(bz))) ds.consumeGas(gas, GasGetMemPackageDesc) - var memPkg *std.MemPackage - amino.MustUnmarshal(bz, &memPkg) + var mpkg *std.MemPackage + amino.MustUnmarshal(bz, &mpkg) size = len(bz) - return memPkg + return mpkg } // GetMemFile retrieves the MemFile with the given name, contained in the // MemPackage at the given path. It returns nil if the file or the package // do not exist. func (ds *defaultStore) GetMemFile(path string, name string) *std.MemFile { - memPkg := ds.GetMemPackage(path) - if memPkg == nil { + mpkg := ds.GetMemPackage(path) + if mpkg == nil { return nil } - memFile := memPkg.GetFile(name) + memFile := mpkg.GetFile(name) return memFile } @@ -912,8 +916,8 @@ func (ds *defaultStore) IterMemPackage() <-chan *std.MemPackage { panic(fmt.Sprintf( "missing package index %d", i)) } - memPkg := ds.GetMemPackage(string(path)) - ch <- memPkg + mpkg := ds.GetMemPackage(string(path)) + ch <- mpkg } close(ch) }() diff --git a/gnovm/pkg/gnolang/store_test.go b/gnovm/pkg/gnolang/store_test.go index efd51d4dc69..14d6b671c86 100644 --- a/gnovm/pkg/gnolang/store_test.go +++ b/gnovm/pkg/gnolang/store_test.go @@ -82,7 +82,7 @@ func TestCopyFromCachedStore(t *testing.T) { Files: []*std.MemFile{ {Name: "math.gno", Body: "package math"}, }, - }) + }, MemPackageTypeAny) // Create dest store and copy. d1, d2 := memdb.NewMemDB(), memdb.NewMemDB() @@ -144,7 +144,7 @@ func TestFindByPrefix(t *testing.T) { Files: []*std.MemFile{ {Name: lib + ".gno", Body: "package " + lib}, }, - }) + }, MemPackageTypeAny) } // Add pkgs @@ -156,7 +156,7 @@ func TestFindByPrefix(t *testing.T) { Files: []*std.MemFile{ {Name: name + ".gno", Body: "package " + name}, }, - }) + }, MemPackageTypeAny) } for _, tc := range cases { diff --git a/gnovm/pkg/gnolang/string_methods.go b/gnovm/pkg/gnolang/string_methods.go index cc26831b481..5a2f0947773 100644 --- a/gnovm/pkg/gnolang/string_methods.go +++ b/gnovm/pkg/gnolang/string_methods.go @@ -51,6 +51,7 @@ func (i Kind) String() string { } return _Kind_name[_Kind_index[i]:_Kind_index[i+1]] } + func _() { // An "invalid array index" compiler error signifies that the constant values have changed. // Re-run the stringer command to generate them again. @@ -274,6 +275,7 @@ func (i Op) String() string { } return "Op(" + strconv.FormatInt(int64(i), 10) + ")" } + func _() { // An "invalid array index" compiler error signifies that the constant values have changed. // Re-run the stringer command to generate them again. @@ -293,6 +295,7 @@ func (i TransCtrl) String() string { } return _TransCtrl_name[_TransCtrl_index[i]:_TransCtrl_index[i+1]] } + func _() { // An "invalid array index" compiler error signifies that the constant values have changed. // Re-run the stringer command to generate them again. @@ -388,6 +391,7 @@ func (i TransField) String() string { } return _TransField_name[_TransField_index[i]:_TransField_index[i+1]] } + func _() { // An "invalid array index" compiler error signifies that the constant values have changed. // Re-run the stringer command to generate them again. @@ -426,6 +430,7 @@ func (i VPType) String() string { return "VPType(" + strconv.FormatInt(int64(i), 10) + ")" } } + func _() { // An "invalid array index" compiler error signifies that the constant values have changed. // Re-run the stringer command to generate them again. diff --git a/gnovm/pkg/gnolang/transpile_gno0p9.go b/gnovm/pkg/gnolang/transpile_gno0p9.go new file mode 100644 index 00000000000..668b59e09c1 --- /dev/null +++ b/gnovm/pkg/gnolang/transpile_gno0p9.go @@ -0,0 +1,649 @@ +package gnolang + +import ( + "bytes" + "errors" + "fmt" + "go/ast" + gofmt "go/format" + "go/parser" + "go/token" + "path" + "path/filepath" + "strings" + + "go.uber.org/multierr" + "golang.org/x/tools/go/ast/astutil" + + "github.com/gnolang/gno/gnovm/pkg/gnomod" + "github.com/gnolang/gno/tm2/pkg/std" +) + +/* + Transpiling old Gno code to Gno 0.9. + Refer to the [Lint and Transpile ADR](./adr/pr4264_lint_transpile.md). + + ParseCheckGnoMod() defined in pkg/gnolang/gnomod.go. +*/ + +type ParseMode int + +const ( + // no test files. + ParseModeProduction ParseMode = iota + // production and test files when xxx_test tests import xxx package. + ParseModeIntegration + // all files even including *_filetest.gno; for linting and testing. + ParseModeAll + // a directory of file tests. consider all to be filetests. + ParseModeOnlyFiletests +) + +// ======================================== +// Go parse the Gno source in mpkg to Go's *token.FileSet and +// []ast.File with `go/parser`. +// +// Args: +// - pmode: see documentation for ParseMode. +// +// Results: +// - gofs: all normal .gno files (and _test.gno files if wtests). +// - _gofs: all xxx_test package _test.gno files if wtests. +// - tgofs: all _testfile.gno test files. +// +// XXX move to pkg/gnolang/gotypecheck.go? +func GoParseMemPackage(mpkg *std.MemPackage, pmode ParseMode) ( + gofset *token.FileSet, gofs, _gofs, tgofs []*ast.File, errs error, +) { + gofset = token.NewFileSet() + + // This map is used to allow for function re-definitions, which are + // allowed in Gno (testing context) but not in Go. This map links + // each function identifier with a closure to remove its associated + // declaration. + delFunc := make(map[string]func()) + + // Go parse and collect files from mpkg. + for _, file := range mpkg.Files { + // Ignore non-gno files. + if !strings.HasSuffix(file.Name, ".gno") { + continue + } + // Ignore _test/_filetest.gno files depending. + switch pmode { + case ParseModeProduction: + if strings.HasSuffix(file.Name, "_test.gno") || + strings.HasSuffix(file.Name, "_filetest.gno") { + continue + } + case ParseModeIntegration: + if strings.HasSuffix(file.Name, "_filetest.gno") { + continue + } + case ParseModeAll, ParseModeOnlyFiletests: + // include all + default: + panic("should not happen") + } + // Go parse file. + const parseOpts = parser.ParseComments | + parser.DeclarationErrors | + parser.SkipObjectResolution + gof, err := parser.ParseFile( + gofset, path.Join(mpkg.Path, file.Name), + file.Body, + parseOpts) + if err != nil { + errs = multierr.Append(errs, err) + continue + } + deleteOldIdents(delFunc, gof) + // The *ast.File passed all filters. + if strings.HasSuffix(file.Name, "_filetest.gno") || + pmode == ParseModeOnlyFiletests { + tgofs = append(tgofs, gof) + } else if strings.HasSuffix(file.Name, "_test.gno") && + strings.HasSuffix(gof.Name.String(), "_test") { + if pmode == ParseModeIntegration { + // never wanted these gofs. + // (we do want other *_test.gno in gofs) + } else { + _gofs = append(_gofs, gof) + } + } else { // normal *_test.gno here for integration testing. + gofs = append(gofs, gof) + } + } + if errs != nil { + return gofset, gofs, _gofs, tgofs, errs + } + // END processing all files. + return +} + +// ======================================== +// Prepare Gno 0.0 for Gno 0.9. +// +// When Gno syntax breaks in higher versions, existing code must first be +// pre-transcribed such that the Gno preprocessor won't panic. This allows +// old Gno code to be preprocessed and used by the Gno VM for static +// analysis. More transpiling will happen later after the preprocessed Gno +// AST is scanned for mutations on the Go AST which follows. Any changes are +// applied directly on the mempackage. +// +// * Renames 'realm' to 'realm_' to avoid conflict with new uverse type. +// +// Args: +// - mpkg: writes (mutated) AST to mempackage if not nil. +// +// Results: +// - errs: returned in aggregate as a multierr type. +func PrepareGno0p9(gofset *token.FileSet, gofs []*ast.File, mpkg *std.MemPackage) (errs error) { + for _, gof := range gofs { + // AST transform for Gno 0.9. + err := prepareGno0p9(gof) + if err != nil { + errs = multierr.Append(errs, err) + continue + } + } + errs = WriteToMemPackage(gofset, gofs, mpkg) + return +} + +// Minimal AST mutation(s) for Gno 0.9. +// - Renames 'realm' to '_realm' to avoid conflict with new builtin "realm". +func prepareGno0p9(f *ast.File) (err error) { + astutil.Apply(f, func(c *astutil.Cursor) bool { + switch gon := c.Node().(type) { + case *ast.Ident: + if gon.Name == "realm" { + // XXX: optimistic. + gon.Name = "_realm" + } + } + return true + }, nil) + return err +} + +//======================================== +// Find Xforms for Gno 0.0 --> Gno 0.9. + +// Xform represents a single needed transform. +type Xform struct { + Type string + Location +} + +// Finds Xforms for Gno 0.9 from the Gno AST and stores them pn +// ATTR_GNO0P9_XFORMS. +func FindXformsGno0p9(store Store, pn *PackageNode, bn BlockNode) { + // create stack of BlockNodes. + var stack []BlockNode = make([]BlockNode, 0, 32) + var last BlockNode = pn + stack = append(stack, last) + + // Iterate over all nodes recursively. + _ = Transcribe(bn, func(ns []Node, ftype TransField, index int, n Node, stage TransStage) (Node, TransCtrl) { + defer doRecover(stack, n) + + switch stage { + // ---------------------------------------- + case TRANS_BLOCK: + pushInitBlock(n.(BlockNode), &last, &stack) + + // ---------------------------------------- + case TRANS_LEAVE: + // Pop block from stack. + // NOTE: DO NOT USE TRANS_SKIP WITHIN BLOCK + // NODES, AS TRANS_LEAVE WILL BE SKIPPED; OR + // POP BLOCK YOURSELF. + defer func() { + switch n.(type) { + case BlockNode: + stack = stack[:len(stack)-1] + last = stack[len(stack)-1] + } + }() + + switch n := n.(type) { + case *CallExpr: + if _, ok := n.Func.(*constTypeExpr); ok { + return n, TRANS_CONTINUE + } else if cx, ok := n.Func.(*ConstExpr); ok { + if cx.TypedValue.T.Kind() != FuncKind { + return n, TRANS_CONTINUE + } + fv := cx.GetFunc() + if fv.PkgPath == uversePkgPath && fv.Name == "cross" { + // Add a nil realm as first argument. + pc, ok := ns[len(ns)-1].(*CallExpr) + if !ok { + panic("cross(fn) must be followed by a call") + } + loc := last.GetLocation() + addXform1(pn, loc.PkgPath, loc.File, pc.GetSpan(), XTYPE_ADD_NILREALM) + } else if fv.PkgPath == uversePkgPath && fv.Name == "crossing" { + if !IsRealmPath(pn.PkgPath) { + panic("crossing() is only allowed in realm packages") + } + // Add `cur realm` as first argument to func decl. + loc := last.GetLocation() + addXform1(pn, loc.PkgPath, loc.File, loc.Span, XTYPE_ADD_CURFUNC) + } else if fv.PkgPath == uversePkgPath && fv.Name == "attach" { + // reserve attach() so we can support it later. + panic("attach() not yet supported") + } + } else { + // Already handled, added XTYPE_ADD_NILREALM + // from the "cross" case above. + if n.WithCross { + // Is a cross(fn)(...) call. + // Leave it alone. + return n, TRANS_CONTINUE + } + pv := pn.NewPackage() // temporary + store := store.BeginTransaction(nil, nil, nil) + store.SetCachePackage(pv) + m := NewMachine("x", store) + defer m.Release() + tv := TypedValue{} + func() { + // cannot be resolved statically + defer func() { + recover() + // fmt.Println("FAILED TO EVALSTATIC", n.Func, r) + }() + // try to evaluate n.Func. + tv = m.EvalStatic(last, n.Func) + }() + switch cv := tv.V.(type) { + case nil: + return n, TRANS_CONTINUE + case TypeValue: + return n, TRANS_CONTINUE + case *FuncValue: + if cv.IsCrossing() { + // Not cross-called, so add `cur` as first argument. + loc := last.GetLocation() + addXform1(pn, loc.PkgPath, loc.File, n.GetSpan(), XTYPE_ADD_CURCALL) + } + case *BoundMethodValue: + if cv.IsCrossing() { + // Not cross-called, so add `cur` as first argument. + loc := last.GetLocation() + addXform1(pn, loc.PkgPath, loc.File, n.GetSpan(), XTYPE_ADD_CURCALL) + } + } + } + } + // end type switch statement + // END TRANS_LEAVE ----------------------- + return n, TRANS_CONTINUE + } + return n, TRANS_CONTINUE + }) +} + +type xtype string + +const ( + XTYPE_ADD_CURCALL xtype = "ADD_CURCALL" + XTYPE_ADD_CURFUNC = "ADD_CURFUNC" + XTYPE_ADD_NILREALM = "ADD_NILREALM" +) + +const ATTR_GNO0P9_XFORMS = "ATTR_GNO0P9_XFORMS" + +// Called from FindXformsGno0p9(). +// p: pkgpath, f: filename +func addXform1(n Node, p string, f string, s Span, x xtype) { + // key: p/f:s+x + xforms1, _ := n.GetAttribute(ATTR_GNO0P9_XFORMS).(map[string]struct{}) + if xforms1 == nil { + xforms1 = make(map[string]struct{}) + n.SetAttribute(ATTR_GNO0P9_XFORMS, xforms1) + } + xform1 := fmt.Sprintf("%s/%s:%v+%s", p, f, s, x) + if _, exists := xforms1[xform1]; exists { + panic("cannot trample existing item") + } + xforms1[xform1] = struct{}{} + fmt.Printf("xpiling to Gno 0.9: +%q\n", xform1) +} + +// Called from transpileGno0p9_part1 to translate p/f:l:c+x to n. +func addXform2IfMatched( + xforms1 map[string]struct{}, + xforms2 map[ast.Node]string, + gon ast.Node, p string, f string, s Span, x xtype, +) { + xform1 := fmt.Sprintf("%s/%s:%v+%s", p, f, s, x) + if _, exists := xforms1[xform1]; exists { + if prior, exists := xforms2[gon]; exists { + fmt.Println("xform2 already exists. prior:", prior, "new:", xform1) + panic("oops, need to refactor xforms2 to allow multiple xforms per node?") + } + xforms2[gon] = xform1 + } else { + // for debugging: + // fmt.Println("not found", xform1) + } +} + +// ======================================== +// Transpiles existing Gno code to Gno 0.9. +// +// Writes in place if dir is provided. Transpiled packages will have their +// gno.mod Gno version to 0.9. +// +// Args: +// - dir: where to write to. +// - pn: package node of fnames +// - fnames: file names (subset of mpkg) to transpile. +// - xforms1: result of FindGno0p9Xforms(). +func TranspileGno0p9(mpkg *std.MemPackage, dir string, pn *PackageNode, fnames []Name, xforms1 map[string]struct{}) error { + // NOTE: The pkgPath may be different than mpkg.Path + // e.g. for filetests or xxx_test tests. + pkgPath := pn.PkgPath + + // Return if gno.mod is current. + var mod *gnomod.File + var err error + mod, err = ParseCheckGnoMod(mpkg) + if err == nil { + if mod.GetGno() != GnoVerMissing { + return fmt.Errorf("cannot transpile to gno 0.9: expected gno 0.0 but got %s", + mod.GetGno()) + } + } + + // Go parse and collect files from mpkg. + gofset := token.NewFileSet() + var errs error + var xall int = 0 // number translated from part 1 + for _, fname := range fnames { + if !strings.HasSuffix(string(fname), ".gno") { + panic(fmt.Sprintf("expected a .gno file but got %q", fname)) + } + mfile := mpkg.GetFile(string(fname)) + // Go parse file. + const parseOpts = parser.ParseComments | + parser.DeclarationErrors | + parser.SkipObjectResolution + gof, err := parser.ParseFile( + gofset, + path.Join(mpkg.Path, mfile.Name), + mfile.Body, + parseOpts) + if err != nil { + errs = multierr.Append(errs, err) + continue + } + // Transpile Part 1: re-key xforms1 by ast.Node. + xnum, xforms2, err := transpileGno0p9_part1(pkgPath, gofset, mfile.Name, gof, xforms1) + if err != nil { + errs = multierr.Append(errs, err) + continue + } + xall += xnum + // Transpile Part 2: main Go AST transform for Gno 0.9. + if err := transpileGno0p9_part2(pkgPath, gofset, mfile.Name, gof, xforms2); err != nil { + errs = multierr.Append(errs, err) + continue + } + // Write transformed Go AST to memfile. + if err := WriteToMemFile(gofset, gof, mfile); err != nil { + errs = multierr.Append(errs, err) + continue + } + } + if errs != nil { + return errs + } + // END processing all memfiles. + + // Ensure that all xforms were translated. + if xall != len(xforms1) { + // this is likely some bug in find* or part 1. + panic("some xform items were not translated") + } + + return nil +} + +// Transpile Step 1: re-key xforms1 by ast.Node. +// +// We can't just apply as we encounter matches in xforms1 unfortunately because +// it causes the lines to shift. So we first convert xforms1 into a map keyed +// by node and then do the actual transpiling in step 2. +// +// Results: +// - xfound: number of items matched for file with name `fname` (for integrity) +func transpileGno0p9_part1(pkgPath string, gofs *token.FileSet, fname string, gof *ast.File, xforms1 map[string]struct{}) (xfound int, xforms2 map[ast.Node]string, err error) { + xforms2 = make(map[ast.Node]string, len(xforms1)) + + astutil.Apply(gof, func(c *astutil.Cursor) bool { + // Main switch on c.Node() type. + switch gon := c.Node().(type) { + case *ast.FuncLit: + span := SpanFromGo(gofs, gon) + addXform2IfMatched( + xforms1, xforms2, gon, + pkgPath, fname, span, + XTYPE_ADD_CURFUNC) + case *ast.FuncDecl: + span := SpanFromGo(gofs, gon) + addXform2IfMatched( + xforms1, xforms2, gon, + pkgPath, fname, span, + XTYPE_ADD_CURFUNC) + case *ast.CallExpr: + span := SpanFromGo(gofs, gon) + addXform2IfMatched( + xforms1, xforms2, gon, + pkgPath, fname, span, + XTYPE_ADD_CURCALL) + addXform2IfMatched( + xforms1, xforms2, gon, + pkgPath, fname, span, + XTYPE_ADD_NILREALM) + } + return true + }, nil) + + // Check that all xforms1 items were translated to xforms2. + xfound = checkXforms(xforms1, xforms2, fname) + return xfound, xforms2, err +} + +// Check that xforms1 items were translated to xforms2 items for file named fname. +// Returns the number of items matched for file. +func checkXforms(xforms1 map[string]struct{}, xforms2 map[ast.Node]string, fname string) int { + mismatch := false + found := 0 +XFORMS1_LOOP: + for xform1 := range xforms1 { + if !strings.Contains(xform1, "/"+fname) { + continue + } + for _, xform2 := range xforms2 { + if xform1 == xform2 { + // good. + found += 1 + continue XFORMS1_LOOP + } + } + fmt.Println("xform2 item not found for xform1:", xform1, len(xforms2)) + for _, xform2 := range xforms2 { + fmt.Println("xform2:", xform2) + } + mismatch = true + } + if mismatch { + for xform1 := range xforms1 { + fmt.Println("xform1:", xform1) + } + for n2, xform2 := range xforms2 { + fmt.Println("xform2:", xform2, n2) + } + panic("xforms1 and xforms2 don't match") + } + /* + if len(xforms1) != len(xforms2) { + panic("xforms1 and xforms2 length don't match") + } + */ + return found // good +} + +// The main Go AST transpiling logic to make Gno code Gno 0.9. +func transpileGno0p9_part2(pkgPath string, fs *token.FileSet, fname string, gof *ast.File, xforms2 map[ast.Node]string) (err error) { + lastLine := 0 + didRemoveCrossing := false + setLast := func(end token.Pos) { + posn := fs.Position(end) + lastLine = posn.Line + } + getLine := func(pos token.Pos) int { + return fs.Position(pos).Line + } + inXforms2 := func(gon ast.Node, x xtype) bool { + if xforms2 == nil { + return false + } + value := xforms2[gon] + if strings.HasSuffix(value, "+"+string(x)) { + return true + } + return false + } + + astutil.Apply(gof, func(c *astutil.Cursor) bool { + // Handle newlines after crossing + if didRemoveCrossing { + gon := c.Node() + line := getLine(gon.Pos()) + tf := fs.File(gon.Pos()) + if lastLine < line { + // lastLine - 1 is the deleted crossing(). + tf.MergeLine(lastLine - 1) + // and the next empty line too. + tf.MergeLine(lastLine) + } + didRemoveCrossing = false + } + + // Main switch on c.Node() type. + switch gon := c.Node().(type) { + case *ast.Ident: + if gon.Name == "realm_XXX_TRANSPILE" { + // Impostor varname 'realm' will become + // renamed, so reclaim 'realm'. + gon.Name = "realm" + } else if gon.Name == "realm" { + // Rename name to _realm to avoid conflict with new builtin "realm". + // XXX: optimistic. + gon.Name = "_realm" + } + case *ast.ExprStmt: + if ce, ok := gon.X.(*ast.CallExpr); ok { + if id, ok := ce.Fun.(*ast.Ident); ok && id.Name == "crossing" { + // Validate syntax. + if len(ce.Args) != 0 { + err = errors.New("crossing called with non empty parameters") + } + // Delete statement 'crossing()'. + c.Delete() + didRemoveCrossing = true + setLast(gon.End()) + return false + } + } + case *ast.FuncLit: + if inXforms2(gon, XTYPE_ADD_CURFUNC) { + gon.Type.Params.List = append([]*ast.Field{{ + Names: []*ast.Ident{ast.NewIdent("cur")}, + Type: ast.NewIdent("realm_XXX_TRANSPILE"), + }}, gon.Type.Params.List...) + delete(xforms2, gon) + } + case *ast.FuncDecl: + if inXforms2(gon, XTYPE_ADD_CURFUNC) { + gon.Type.Params.List = append([]*ast.Field{{ + Names: []*ast.Ident{ast.NewIdent("cur")}, + Type: ast.NewIdent("realm_XXX_TRANSPILE"), + }}, gon.Type.Params.List...) + delete(xforms2, gon) + } + case *ast.CallExpr: + if inXforms2(gon, XTYPE_ADD_CURCALL) { + gon.Args = append([]ast.Expr{ast.NewIdent("cur")}, gon.Args...) + delete(xforms2, gon) + } else if inXforms2(gon, XTYPE_ADD_NILREALM) { + gon.Args = append([]ast.Expr{ast.NewIdent("nil")}, gon.Args...) + delete(xforms2, gon) + } + if id, ok := gon.Fun.(*ast.Ident); ok && id.Name == "cross" { + // Replace expression 'cross(x)' by 'x'. + // In Gno 0.9 @cross decorator is used instead. + if len(gon.Args) == 1 { + c.Replace(gon.Args[0]) + } else { + err = errors.New("cross called with invalid parameters") + } + return true + } + } + return true + }, nil) + + // Verify that all xforms2 items were consumed. + if len(xforms2) > 0 { + for gon, xform2 := range xforms2 { + fmt.Println("left over:", xform2, gon) + } + panic("Xform items left over") + } + + return err +} + +// ======================================== +// WriteToMemPackage writes Go AST to a mempackage +// This is useful for preparing prior version code for the preprocessor. +func WriteToMemPackage(gofset *token.FileSet, gofs []*ast.File, mpkg *std.MemPackage) error { + for _, gof := range gofs { + fpath := gofset.File(gof.Pos()).Name() + _, fname := filepath.Split(fpath) + mfile := mpkg.GetFile(fname) + if mfile == nil { + if strings.HasPrefix(fname, ".") { + // Hidden files like .gnobuiltins.gno that + // start with a dot should not get written to + // the mempackage. + continue + } else { + return fmt.Errorf("missing memfile %q", mfile) + } + } + err := WriteToMemFile(gofset, gof, mfile) + if err != nil { + return fmt.Errorf("writing to mempackage %q: %w", + mpkg.Path, err) + } + } + return nil +} + +func WriteToMemFile(gofset *token.FileSet, gof *ast.File, mfile *std.MemFile) error { + var buf bytes.Buffer + err := gofmt.Node(&buf, gofset, gof) + if err != nil { + return fmt.Errorf("writing to memfile %q: %w", + mfile.Name, err) + } + mfile.Body = buf.String() + return nil +} diff --git a/gnovm/pkg/gnolang/type_check.go b/gnovm/pkg/gnolang/type_check.go index 8df92f0d0e0..4fe09b48beb 100644 --- a/gnovm/pkg/gnolang/type_check.go +++ b/gnovm/pkg/gnolang/type_check.go @@ -177,7 +177,7 @@ func assertComparable2(dt Type) { } } -func maybeNil(t Type) bool { +func mayBeNil(t Type) bool { switch baseOf(t).(type) { case *SliceType, *FuncType, *MapType, *InterfaceType, *PointerType, *ChanType: // we don't have unsafePointer return true @@ -395,7 +395,6 @@ func checkValDefineMismatch(n Node) { if numNames > numValues { panic(fmt.Sprintf("missing init expr for %s", valueDecl.NameExprs[numValues].String())) } - panic(fmt.Sprintf("extra init expr %s", values[numNames].String())) } @@ -405,7 +404,7 @@ func checkValDefineMismatch(n Node) { // 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(n Node, xt, dt Type, autoNative bool) error { +func checkAssignableTo(n Node, xt, dt Type, autoNative bool) (err error) { if debug { debug.Printf("checkAssignableTo, xt: %v dt: %v \n", xt, dt) } @@ -414,20 +413,20 @@ func checkAssignableTo(n Node, xt, dt Type, autoNative bool) error { if dt == nil || dt.Kind() == InterfaceKind { return nil } - if !maybeNil(dt) { + if !mayBeNil(dt) { switch n := n.(type) { case *ValueDecl: - panic(fmt.Sprintf("cannot use nil as %v value in variable declaration", dt)) + return errors.New("cannot use nil as %v value in variable declaration", dt) case *AssignStmt: - panic(fmt.Sprintf("cannot use nil as %v value in assignment", dt)) + return errors.New("cannot use nil as %v value in assignment", dt) case *CompositeLitExpr: - panic(fmt.Sprintf("cannot use nil as %v value in array, slice literal or map literal", dt)) + return errors.New("cannot use nil as %v value in array, slice literal or map literal", dt) case *CallExpr: - panic(fmt.Sprintf("cannot use nil as %v value in argument to %v", dt, n.Func)) + return errors.New("cannot use nil as %v value in argument to %v", dt, n.Func) case *BinaryExpr: - panic(fmt.Sprintf("invalid operation: %v (mismatched types %v and untyped nil)", n, dt)) + return errors.New("invalid operation: %v (mismatched types %v and untyped nil)", n, dt) default: - panic(fmt.Sprintf("cannot use nil as %v value", dt)) + return errors.New("cannot use nil as %v value", dt) } } return nil @@ -451,7 +450,7 @@ func checkAssignableTo(n Node, xt, dt Type, autoNative bool) error { err.Error()) } } else { - return errors.New("should not happen") + panic("should not happen") } } @@ -540,9 +539,9 @@ func checkAssignableTo(n Node, xt, dt Type, autoNative bool) error { Uint32Kind, Uint64Kind, BigdecKind, Float32Kind, Float64Kind: return nil // ok default: - panic(fmt.Sprintf( + return errors.New( "cannot use untyped Bigdec as %s", - dt.Kind())) + dt.Kind()) } case UntypedBigintType: switch dt.Kind() { @@ -569,7 +568,7 @@ func checkAssignableTo(n Node, xt, dt Type, autoNative bool) error { default: if isUntyped(xt) { - panic("unexpected untyped type") + return errors.New("unexpected untyped type") } if xt.TypeID() == cdt.TypeID() { return nil // ok @@ -623,7 +622,7 @@ func checkAssignableTo(n Node, xt, dt Type, autoNative bool) error { return nil } case *InterfaceType: - return errors.New("should not happen") + panic("should not happen") case *DeclaredType: panic("should not happen") case *FuncType, *StructType, *PackageType, *ChanType, *TypeType: @@ -721,9 +720,9 @@ func (x *BinaryExpr) assertShiftExprCompatible2(t Type) { // Overall,it efficiently filters out incompatible expressions, stopping before the next // checkOrConvertType() operation to optimize performance. func (x *BinaryExpr) AssertCompatible(lt, rt Type) { - xt, dt := lt, rt + xt, dt, swapped := lt, rt, false if shouldSwapOnSpecificity(lt, rt) { - xt, dt = dt, xt + xt, dt, swapped = dt, xt, true } if isComparison(x.Op) { @@ -735,7 +734,7 @@ func (x *BinaryExpr) AssertCompatible(lt, rt Type) { } case LSS, LEQ, GTR, GEQ: if checker, ok := binaryChecker[x.Op]; ok { - x.checkCompatibility(x, xt, dt, checker, x.Op.TokenString()) + x.checkCompatibility(x, xt, dt, checker, x.Op.TokenString(), swapped) } else { panic(fmt.Sprintf("checker for %s does not exist", x.Op)) } @@ -744,7 +743,7 @@ func (x *BinaryExpr) AssertCompatible(lt, rt Type) { } } else { if checker, ok := binaryChecker[x.Op]; ok { - x.checkCompatibility(x, xt, dt, checker, x.Op.TokenString()) + x.checkCompatibility(x, xt, dt, checker, x.Op.TokenString(), swapped) } else { panic(fmt.Sprintf("checker for %s does not exist", x.Op)) } @@ -772,16 +771,29 @@ func (x *BinaryExpr) AssertCompatible(lt, rt Type) { // 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(n Node, xt, dt Type, checker func(t Type) bool, OpStr string) { +func (x *BinaryExpr) checkCompatibility(n Node, xt, dt Type, checker func(t Type) bool, OpStr string, swapped bool) { if !checker(dt) { panic(fmt.Sprintf("operator %s not defined on: %v", OpStr, kindString(dt))) } + // display xt as "untyped nil" if nil as Go does. + untypedNil := func(t Type) string { + if t == nil { + return "untyped nil" + } else { + return t.String() + } + } + // if both typed if !isUntyped(xt) && !isUntyped(dt) { err := checkAssignableTo(n, xt, dt, false) if err != nil { - panic(fmt.Sprintf("invalid operation: mismatched types %v and %v", xt, dt)) + if swapped { + panic(fmt.Sprintf("invalid operation: %v (mismatched types %v and %v)", n, dt, untypedNil(xt))) + } else { + panic(fmt.Sprintf("invalid operation: %v (mismatched types %v and %v)", n, untypedNil(xt), dt)) + } } } } diff --git a/gnovm/pkg/gnolang/type_check_test.go b/gnovm/pkg/gnolang/type_check_test.go index 7fddf2c65d0..dbb4f543a75 100644 --- a/gnovm/pkg/gnolang/type_check_test.go +++ b/gnovm/pkg/gnolang/type_check_test.go @@ -10,7 +10,7 @@ func TestCheckAssignableTo(t *testing.T) { xt Type dt Type autoNative bool - wantPanic bool + wantError string }{ { name: "nil to nil", @@ -30,8 +30,8 @@ func TestCheckAssignableTo(t *testing.T) { { name: "nil to non-nillable", xt: nil, - dt: PrimitiveType(StringKind), - wantPanic: true, + dt: StringType, + wantError: "cannot use nil as string value", }, { name: "interface to interface", @@ -44,14 +44,14 @@ func TestCheckAssignableTo(t *testing.T) { tt := tt t.Run(tt.name, func(t *testing.T) { t.Parallel() - if tt.wantPanic { - defer func() { - if r := recover(); r == nil { - t.Errorf("checkAssignableTo() did not panic, want panic") - } - }() + err := checkAssignableTo(nil, tt.xt, tt.dt, tt.autoNative) + if tt.wantError != "" { + if err.Error() != tt.wantError { + t.Errorf("checkAssignableTo() returned wrong error: want: %v got: %v", tt.wantError, err.Error()) + } + } else if err != nil { + t.Errorf("checkAssignableTo() returned unexpected wrong error: got: %v", err.Error()) } - checkAssignableTo(nil, tt.xt, tt.dt, tt.autoNative) }) } } diff --git a/gnovm/pkg/gnolang/types.go b/gnovm/pkg/gnolang/types.go index c102c033aeb..c9c2adaf391 100644 --- a/gnovm/pkg/gnolang/types.go +++ b/gnovm/pkg/gnolang/types.go @@ -1269,16 +1269,9 @@ func (ft *FuncType) TypeID() TypeID { // this exchangeability is useful to denote type semantics. ps := FieldTypeList(ft.Params) rs := FieldTypeList(ft.Results) - /* - pp := "" - if ps.HasUnexported() || rs.HasUnexported() { - pp = fmt.Sprintf("@%q", ft.PkgPath) - } - */ if ft.typeid.IsZero() { ft.typeid = typeidf( "func(%s)(%s)", - // pp, ps.UnnamedTypeID(), rs.UnnamedTypeID(), ) @@ -1289,12 +1282,15 @@ func (ft *FuncType) TypeID() TypeID { func (ft *FuncType) String() string { switch len(ft.Results) { case 0: + // XXX add ->() return fmt.Sprintf("func(%s)", FieldTypeList(ft.Params).StringForFunc()) case 1: + // XXX add ->() return fmt.Sprintf("func(%s) %s", FieldTypeList(ft.Params).StringForFunc(), ft.Results[0].Type.String()) default: + // XXX make ()->() return fmt.Sprintf("func(%s) (%s)", FieldTypeList(ft.Params).StringForFunc(), FieldTypeList(ft.Results).StringForFunc()) @@ -1484,6 +1480,11 @@ func (dt *DeclaredType) checkSeal() { func (dt *DeclaredType) TypeID() TypeID { if dt.typeid.IsZero() { dt.typeid = DeclaredTypeID(dt.PkgPath, dt.Loc, dt.Name) + } else { + // XXX delete this if tests pass. + if dt.typeid != DeclaredTypeID(dt.PkgPath, dt.Loc, dt.Name) { + panic("should not happen") + } } return dt.typeid } @@ -2100,6 +2101,7 @@ func fillEmbeddedName(ft *FieldType) { case *DeclaredType: ft.Name = ct.Name default: + // should not happen, panic("should not happen") } case *DeclaredType: diff --git a/gnovm/pkg/gnolang/uverse.go b/gnovm/pkg/gnolang/uverse.go index 7d15e6d993b..ef1c2b46301 100644 --- a/gnovm/pkg/gnolang/uverse.go +++ b/gnovm/pkg/gnolang/uverse.go @@ -59,6 +59,45 @@ var gStringerType = &DeclaredType{ sealed: true, } +var gRealmType = &DeclaredType{ + PkgPath: uversePkgPath, + Name: "realm", + Base: &InterfaceType{ + PkgPath: uversePkgPath, + Methods: []FieldType{ + { + Name: "Addr", + Type: &FuncType{ + Params: nil, + Results: []FieldType{ + { + // Name: "", + Type: StringType, // NOT std.Address. + }, + }, + }, + }, + { + Name: "Prev", + Type: &FuncType{ + Params: nil, + Results: []FieldType{ + { + // Name: "", + Type: nil, // gets filled in init() below. + }, + }, + }, + }, + }, + }, + sealed: true, +} + +func init() { + gRealmType.Base.(*InterfaceType).Methods[1].Type.(*FuncType).Results[0].Type = gRealmType +} + // ---------------------------------------- // Uverse package @@ -752,6 +791,10 @@ func makeUverseNode() { } }, ) + + //---------------------------------------- + // Gno2 types + def("realm", asValue(gRealmType)) defNative("crossing", nil, // params nil, // results @@ -843,6 +886,7 @@ func makeUverseNode() { // implementing istypednil() is annoying, while istypednil() shouldn't // require reflect, Gno should therefore offer istypednil() as a uverse // function. + // XXX REMOVE, move to std function. defNative("istypednil", Flds( // params "x", AnyT(), diff --git a/gnovm/pkg/gnolang/values.go b/gnovm/pkg/gnolang/values.go index 54021302309..c625c4d8e03 100644 --- a/gnovm/pkg/gnolang/values.go +++ b/gnovm/pkg/gnolang/values.go @@ -2480,6 +2480,7 @@ func (b *Block) ExpandWith(alloc *Allocator, source BlockNode) { } } b.Values = values + b.Source = source // otherwise new variables won't show in print or debugger. } // NOTE: RefValue Object methods declared in ownership.go diff --git a/gnovm/pkg/gnomod/file.go b/gnovm/pkg/gnomod/file.go index a1c77b51e45..4607e539739 100644 --- a/gnovm/pkg/gnomod/file.go +++ b/gnovm/pkg/gnomod/file.go @@ -22,13 +22,36 @@ import ( type File struct { Draft bool Module *modfile.Module - Go *modfile.Go + Gno *modfile.Go Replace []*modfile.Replace Syntax *modfile.FileSyntax } -func (f *File) AddModuleStmt(path string) error { +func (f *File) GetGno() (version string) { + if f.Gno == nil { + return "0.0" + } else { + return f.Gno.Version + } +} + +func (f *File) SetGno(version string) { + if f.Syntax == nil { + f.Syntax = new(modfile.FileSyntax) + } + if f.Gno == nil { + f.Gno = &modfile.Go{ + Version: version, + Syntax: addLine(f.Syntax, nil, "gno", version), + } + } else { + f.Gno.Version = version + updateLine(f.Gno.Syntax, "gno", version) + } +} + +func (f *File) SetModule(path string) { if f.Syntax == nil { f.Syntax = new(modfile.FileSyntax) } @@ -41,10 +64,9 @@ func (f *File) AddModuleStmt(path string) error { f.Module.Mod.Path = path updateLine(f.Module.Syntax, "module", modfile.AutoQuote(path)) } - return nil } -func (f *File) AddComment(text string) { +func (f *File) SetComment(text string) { if f.Syntax == nil { f.Syntax = new(modfile.FileSyntax) } @@ -59,18 +81,17 @@ func (f *File) AddComment(text string) { }) } -func (f *File) AddReplace(oldPath, oldVers, newPath, newVers string) error { - return addReplace(f.Syntax, &f.Replace, oldPath, oldVers, newPath, newVers) +func (f *File) AddReplace(oldPath, oldVers, newPath, newVers string) { + addReplace(f.Syntax, &f.Replace, oldPath, oldVers, newPath, newVers) } -func (f *File) DropReplace(oldPath, oldVers string) error { +func (f *File) DropReplace(oldPath, oldVers string) { for _, r := range f.Replace { if r.Old.Path == oldPath && r.Old.Version == oldVers { markLineAsRemoved(r.Syntax) *r = modfile.Replace{} } } - return nil } // Validate validates gno.mod @@ -96,16 +117,23 @@ func (f *File) Resolve(m module.Version) module.Version { } // writes file to the given absolute file path -func (f *File) Write(fname string) error { +func (f *File) WriteFile(fpath string) error { f.Syntax.Cleanup() data := modfile.Format(f.Syntax) - err := os.WriteFile(fname, data, 0o644) + err := os.WriteFile(fpath, data, 0o644) if err != nil { - return fmt.Errorf("writefile %q: %w", fname, err) + return fmt.Errorf("writefile %q: %w", fpath, err) } return nil } +// writes to a string +func (f *File) WriteString() string { + f.Syntax.Cleanup() + data := modfile.Format(f.Syntax) + return string(data) +} + func (f *File) Sanitize() { removeDups(f.Syntax, &f.Replace) } diff --git a/gnovm/pkg/gnomod/gnomod.go b/gnovm/pkg/gnomod/gnomod.go index 3d2adc2a1aa..4ea285e34f6 100644 --- a/gnovm/pkg/gnomod/gnomod.go +++ b/gnovm/pkg/gnomod/gnomod.go @@ -40,8 +40,8 @@ func CreateGnoModFile(rootDir, modPath string) error { } modfile := new(File) - modfile.AddModuleStmt(modPath) - modfile.Write(filepath.Join(rootDir, "gno.mod")) + modfile.SetModule(modPath) + modfile.WriteFile(filepath.Join(rootDir, "gno.mod")) return nil } diff --git a/gnovm/pkg/gnomod/parse.go b/gnovm/pkg/gnomod/parse.go index edee8d2d3b5..c0cca1318aa 100644 --- a/gnovm/pkg/gnomod/parse.go +++ b/gnovm/pkg/gnomod/parse.go @@ -1,19 +1,24 @@ package gnomod import ( + "errors" "fmt" "os" "path/filepath" "reflect" + "regexp" "strings" + "github.com/gnolang/gno/tm2/pkg/std" "golang.org/x/mod/modfile" "golang.org/x/mod/module" ) -// ParseAt parses, validates and returns a gno.mod file located at dir or at +var ErrNoModFile = errors.New("gno.mod doesn't exist") + +// ParseDir parses, validates and returns a gno.mod file located at dir or at // dir's parents. -func ParseAt(dir string) (*File, error) { +func ParseDir(dir string) (*File, error) { ferr := func(err error) (*File, error) { return nil, fmt.Errorf("parsing gno.mod at %s: %w", dir, err) } @@ -27,12 +32,12 @@ func ParseAt(dir string) (*File, error) { if err != nil { return ferr(err) } - fname := filepath.Join(rd, "gno.mod") - b, err := os.ReadFile(fname) + fpath := filepath.Join(rd, "gno.mod") + b, err := os.ReadFile(fpath) if err != nil { return ferr(err) } - gm, err := Parse(fname, b) + gm, err := ParseBytes(fpath, b) if err != nil { return ferr(err) } @@ -42,40 +47,36 @@ func ParseAt(dir string) (*File, error) { return gm, nil } -// tries to parse gno mod file given the filename, using Parse and Validate from -// the gnomod package -// -// TODO(tb): replace by `gnomod.ParseAt` ? The key difference is the latter -// looks for gno.mod in parent directories, while this function doesn't. -func ParseGnoMod(fname string) (*File, error) { - file, err := os.Stat(fname) +// Tries to parse gno mod file given the file path, using ParseBytes and Validate. +func ParseFilepath(fpath string) (*File, error) { + file, err := os.Stat(fpath) if err != nil { return nil, fmt.Errorf("could not read gno.mod file: %w", err) } if file.IsDir() { - return nil, fmt.Errorf("invalid gno.mod at %q: is a directory", fname) + return nil, fmt.Errorf("invalid gno.mod at %q: is a directory", fpath) } - b, err := os.ReadFile(fname) + b, err := os.ReadFile(fpath) if err != nil { return nil, fmt.Errorf("could not read gno.mod file: %w", err) } - gm, err := Parse(fname, b) + gm, err := ParseBytes(fpath, b) if err != nil { - return nil, fmt.Errorf("error parsing gno.mod file at %q: %w", fname, err) + return nil, fmt.Errorf("error parsing gno.mod file at %q: %w", fpath, err) } if err := gm.Validate(); err != nil { - return nil, fmt.Errorf("error validating gno.mod file at %q: %w", fname, err) + return nil, fmt.Errorf("error validating gno.mod file at %q: %w", fpath, err) } return gm, nil } -// Parse parses and returns a gno.mod file. +// ParseBytes parses and returns a gno.mod file. // -// - file is the name of the file, used in positions and errors. +// - fname is the name of the file, used in positions and errors. // - data is the content of the file. -func Parse(file string, data []byte) (*File, error) { - fs, err := parse(file, data) +func ParseBytes(fname string, data []byte) (*File, error) { + fs, err := parse(fname, data) if err != nil { return nil, err } @@ -91,7 +92,7 @@ func Parse(file string, data []byte) (*File, error) { case *modfile.LineBlock: if len(x.Token) > 1 { errs = append(errs, modfile.Error{ - Filename: file, + Filename: fname, Pos: x.Start, Err: fmt.Errorf("unknown block type: %s", strings.Join(x.Token, " ")), }) @@ -100,7 +101,7 @@ func Parse(file string, data []byte) (*File, error) { switch x.Token[0] { default: errs = append(errs, modfile.Error{ - Filename: file, + Filename: fname, Pos: x.Start, Err: fmt.Errorf("unknown block type: %s", strings.Join(x.Token, " ")), }) @@ -123,6 +124,33 @@ func Parse(file string, data []byte) (*File, error) { return f, nil } +// Parse gno.mod from MemPackage, or return nil and error. +func ParseMemPackage(mpkg *std.MemPackage) (*File, error) { + mf := mpkg.GetFile("gno.mod") + if mf == nil { + return nil, fmt.Errorf( + "gno.mod not in mem package %s (name=%s): %w", + mpkg.Path, mpkg.Name, os.ErrNotExist, + ) + } + mod, err := ParseBytes(mf.Name, []byte(mf.Body)) + if err != nil { + return nil, err + } + return mod, nil +} + +// Must parse gno.mod from MemPackage. +func MustParseMemPackage(mpkg *std.MemPackage) *File { + mod, err := ParseMemPackage(mpkg) + if err != nil { + panic(fmt.Errorf("parsing mempackage %w", err)) + } + return mod +} + +var reGnoVersion = regexp.MustCompile(`^([0-9][0-9]*)\.(0|[1-9][0-9]*)(\.(0|[1-9][0-9]*))?([a-z]+[0-9]+)?$`) + func (f *File) add(errs *modfile.ErrorList, block *modfile.LineBlock, line *modfile.Line, verb string, args []string) { wrapError := func(err error) { *errs = append(*errs, modfile.Error{ @@ -139,25 +167,25 @@ func (f *File) add(errs *modfile.ErrorList, block *modfile.LineBlock, line *modf default: errorf("unknown directive: %s", verb) - case "go": - if f.Go != nil { - errorf("repeated go statement") + case "gno": + if f.Gno != nil { + errorf("repeated gno statement") return } if len(args) != 1 { - errorf("go directive expects exactly one argument") + errorf("gno directive expects exactly one argument") return - } else if !modfile.GoVersionRE.MatchString(args[0]) { + } else if !reGnoVersion.MatchString(args[0]) { fixed := false if !fixed { - errorf("invalid go version '%s': must match format 1.23", args[0]) + errorf("invalid gno version %s: must match format 1.23", args[0]) return } } line := reflect.ValueOf(line).Interface().(*modfile.Line) - f.Go = &modfile.Go{Syntax: line} - f.Go.Version = args[0] + f.Gno = &modfile.Go{Syntax: line} + f.Gno.Version = args[0] case "module": if f.Module != nil { diff --git a/gnovm/pkg/gnomod/parse_test.go b/gnovm/pkg/gnomod/parse_test.go index ff3de63e1bd..2f44d5830cd 100644 --- a/gnovm/pkg/gnomod/parse_test.go +++ b/gnovm/pkg/gnomod/parse_test.go @@ -113,7 +113,7 @@ func TestModuleDeprecated(t *testing.T) { }, } { t.Run(tc.desc, func(t *testing.T) { - f, err := Parse("in", []byte(tc.in)) + f, err := ParseBytes("in", []byte(tc.in)) assert.Nil(t, err) assert.Equal(t, tc.expected, f.Module.Deprecated) }) @@ -164,14 +164,14 @@ func TestParseDraft(t *testing.T) { }, } { t.Run(tc.desc, func(t *testing.T) { - f, err := Parse("in", []byte(tc.in)) + f, err := ParseBytes("in", []byte(tc.in)) assert.Nil(t, err) assert.Equal(t, tc.expected, f.Draft) }) } } -func TestParseGnoMod(t *testing.T) { +func TestParseFilepath(t *testing.T) { pkgDir := "bar" for _, tc := range []struct { desc, modData, modPath, errShouldContain string @@ -228,7 +228,7 @@ func TestParseGnoMod(t *testing.T) { // Create gno package createGnoModPkg(t, tempDir, pkgDir, tc.modData) - _, err := ParseGnoMod(filepath.Join(tempDir, tc.modPath)) + _, err := ParseFilepath(filepath.Join(tempDir, tc.modPath)) if tc.errShouldContain != "" { assert.ErrorContains(t, err, tc.errShouldContain) } else { @@ -270,7 +270,7 @@ func TestParseWithInvalidModulePath(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - _, err := Parse("gno.mod", []byte(tt.modData)) + _, err := ParseBytes("gno.mod", []byte(tt.modData)) if tt.errMsg != "" { assert.Error(t, err) assert.Contains(t, err.Error(), tt.errMsg) diff --git a/gnovm/pkg/gnomod/pkg.go b/gnovm/pkg/gnomod/pkg.go index 87233190338..af776c98c23 100644 --- a/gnovm/pkg/gnomod/pkg.go +++ b/gnovm/pkg/gnomod/pkg.go @@ -2,14 +2,9 @@ package gnomod import ( "fmt" - "io/fs" "os" "path/filepath" "strings" - - "github.com/gnolang/gno/gnovm/pkg/gnolang" - "github.com/gnolang/gno/gnovm/pkg/packages" - "github.com/gnolang/gno/tm2/pkg/std" ) type Pkg struct { @@ -86,72 +81,6 @@ func visitPackage(pkg Pkg, pkgs []Pkg, visited, onStack map[string]bool, sortedP return nil } -// ListPkgs lists all gno packages in the given root directory. -func ListPkgs(root string) (PkgList, error) { - var pkgs []Pkg - - err := filepath.WalkDir(root, func(path string, d fs.DirEntry, err error) error { - if err != nil { - return err - } - if !d.IsDir() { - return nil - } - gnoModPath := filepath.Join(path, "gno.mod") - data, err := os.ReadFile(gnoModPath) - if os.IsNotExist(err) { - return nil - } - if err != nil { - return err - } - - gnoMod, err := Parse(gnoModPath, data) - if err != nil { - return fmt.Errorf("parse: %w", err) - } - gnoMod.Sanitize() - if err := gnoMod.Validate(); err != nil { - return fmt.Errorf("failed to validate gno.mod in %s: %w", gnoModPath, err) - } - - pkg, err := gnolang.ReadMemPackage(path, gnoMod.Module.Mod.Path) - if err != nil { - // ignore package files on error - pkg = &std.MemPackage{} - } - - importsMap, err := packages.Imports(pkg, nil) - if err != nil { - // ignore imports on error - importsMap = nil - } - importsRaw := importsMap.Merge(packages.FileKindPackageSource, packages.FileKindTest, packages.FileKindXTest) - - imports := make([]string, 0, len(importsRaw)) - for _, imp := range importsRaw { - // remove self and standard libraries from imports - if imp.PkgPath != gnoMod.Module.Mod.Path && - !gnolang.IsStdlib(imp.PkgPath) { - imports = append(imports, imp.PkgPath) - } - } - - pkgs = append(pkgs, Pkg{ - Dir: path, - Name: gnoMod.Module.Mod.Path, - Draft: gnoMod.Draft, - Imports: imports, - }) - return nil - }) - if err != nil { - return nil, err - } - - return pkgs, nil -} - // GetNonDraftPkgs returns packages that are not draft // and have no direct or indirect draft dependencies. func (sp SortedPkgList) GetNonDraftPkgs() SortedPkgList { diff --git a/gnovm/pkg/gnomod/pkg_test.go b/gnovm/pkg/gnomod/pkg_test.go index 7c3035a4b7b..76ceb1395a4 100644 --- a/gnovm/pkg/gnomod/pkg_test.go +++ b/gnovm/pkg/gnomod/pkg_test.go @@ -1,13 +1,16 @@ -package gnomod +package gnomod_test import ( "os" "path/filepath" "testing" - "github.com/gnolang/gno/tm2/pkg/testutils" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" + + gno "github.com/gnolang/gno/gnovm/pkg/gnolang" + "github.com/gnolang/gno/gnovm/pkg/gnomod" + "github.com/gnolang/gno/tm2/pkg/testutils" ) func TestListAndNonDraftPkgs(t *testing.T) { @@ -15,7 +18,7 @@ func TestListAndNonDraftPkgs(t *testing.T) { desc string in []struct{ name, modfile string } - outListPkgs []string + outPkgList []string outNonDraftPkgs []string }{ { @@ -37,7 +40,7 @@ func TestListAndNonDraftPkgs(t *testing.T) { `module baz`, }, }, - outListPkgs: []string{"foo", "bar", "baz"}, + outPkgList: []string{"foo", "bar", "baz"}, outNonDraftPkgs: []string{"foo", "bar", "baz"}, }, { @@ -58,7 +61,7 @@ func TestListAndNonDraftPkgs(t *testing.T) { module qux`, }, }, - outListPkgs: []string{"foo", "baz", "qux"}, + outPkgList: []string{"foo", "baz", "qux"}, outNonDraftPkgs: []string{"foo", "baz"}, }, } { @@ -74,11 +77,11 @@ func TestListAndNonDraftPkgs(t *testing.T) { } // List packages - pkgs, err := ListPkgs(dirPath) + pkgs, err := gno.ReadPkgListFromDir(dirPath) require.NoError(t, err) - assert.Equal(t, len(tc.outListPkgs), len(pkgs)) + assert.Equal(t, len(tc.outPkgList), len(pkgs)) for _, p := range pkgs { - assert.Contains(t, tc.outListPkgs, p.Name) + assert.Contains(t, tc.outPkgList, p.Name) } // Sort packages @@ -111,17 +114,17 @@ func createGnoModPkg(t *testing.T, dirPath, pkgName, modData string) { func TestSortPkgs(t *testing.T) { for _, tc := range []struct { desc string - in PkgList + in gnomod.PkgList expected []string shouldErr bool }{ { desc: "empty_input", - in: []Pkg{}, + in: []gnomod.Pkg{}, expected: make([]string, 0), }, { desc: "no_dependencies", - in: []Pkg{ + in: []gnomod.Pkg{ {Name: "pkg1", Dir: "/path/to/pkg1", Imports: []string{}}, {Name: "pkg2", Dir: "/path/to/pkg2", Imports: []string{}}, {Name: "pkg3", Dir: "/path/to/pkg3", Imports: []string{}}, @@ -129,20 +132,20 @@ func TestSortPkgs(t *testing.T) { expected: []string{"pkg1", "pkg2", "pkg3"}, }, { desc: "circular_dependencies", - in: []Pkg{ + in: []gnomod.Pkg{ {Name: "pkg1", Dir: "/path/to/pkg1", Imports: []string{"pkg2"}}, {Name: "pkg2", Dir: "/path/to/pkg2", Imports: []string{"pkg1"}}, }, shouldErr: true, }, { desc: "missing_dependencies", - in: []Pkg{ + in: []gnomod.Pkg{ {Name: "pkg1", Dir: "/path/to/pkg1", Imports: []string{"pkg2"}}, }, shouldErr: true, }, { desc: "valid_dependencies", - in: []Pkg{ + in: []gnomod.Pkg{ {Name: "pkg1", Dir: "/path/to/pkg1", Imports: []string{"pkg2"}}, {Name: "pkg2", Dir: "/path/to/pkg2", Imports: []string{"pkg3"}}, {Name: "pkg3", Dir: "/path/to/pkg3", Imports: []string{}}, diff --git a/gnovm/pkg/gnomod/read.go b/gnovm/pkg/gnomod/read.go index 19b3a3b4c82..46b31b97daf 100644 --- a/gnovm/pkg/gnomod/read.go +++ b/gnovm/pkg/gnomod/read.go @@ -955,7 +955,7 @@ func addLine(x *modfile.FileSyntax, hint modfile.Expr, tokens ...string) *modfil return newl } -func addReplace(syntax *modfile.FileSyntax, replace *[]*modfile.Replace, oldPath, oldVers, newPath, newVers string) error { +func addReplace(syntax *modfile.FileSyntax, replace *[]*modfile.Replace, oldPath, oldVers, newPath, newVers string) { need := true oldv := module.Version{Path: oldPath, Version: oldVers} newv := module.Version{Path: newPath, Version: newVers} @@ -989,5 +989,4 @@ func addReplace(syntax *modfile.FileSyntax, replace *[]*modfile.Replace, oldPath if need { *replace = append(*replace, &modfile.Replace{Old: oldv, New: newv, Syntax: addLine(syntax, hint, tokens...)}) } - return nil } diff --git a/gnovm/pkg/gnomod/read_test.go b/gnovm/pkg/gnomod/read_test.go index d9c35205a51..09a706128d0 100644 --- a/gnovm/pkg/gnomod/read_test.go +++ b/gnovm/pkg/gnomod/read_test.go @@ -105,22 +105,23 @@ func TestParseVersions(t *testing.T) { ok bool }{ // go lines - {desc: "empty", input: "module m\ngo \n", ok: false}, - {desc: "one", input: "module m\ngo 1\n", ok: false}, - {desc: "two", input: "module m\ngo 1.22\n", ok: true}, - {desc: "three", input: "module m\ngo 1.22.333", ok: true}, - {desc: "before", input: "module m\ngo v1.2\n", ok: false}, - {desc: "after", input: "module m\ngo 1.2rc1\n", ok: true}, - {desc: "space", input: "module m\ngo 1.2 3.4\n", ok: false}, - {desc: "alt1", input: "module m\ngo 1.2.3\n", ok: true}, - {desc: "alt2", input: "module m\ngo 1.2rc1\n", ok: true}, - {desc: "alt3", input: "module m\ngo 1.2beta1\n", ok: true}, - {desc: "alt4", input: "module m\ngo 1.2.beta1\n", ok: false}, + {desc: "empty", input: "module m\ngno \n", ok: false}, + {desc: "one", input: "module m\ngno 1\n", ok: false}, + {desc: "two", input: "module m\ngno 1.22\n", ok: true}, + {desc: "two go", input: "module m\ngo 1.22\n", ok: false}, + {desc: "three", input: "module m\ngno 1.22.333", ok: true}, + {desc: "before", input: "module m\ngno v1.2\n", ok: false}, + {desc: "after", input: "module m\ngno 1.2rc1\n", ok: true}, + {desc: "space", input: "module m\ngno 1.2 3.4\n", ok: false}, + {desc: "alt1", input: "module m\ngno 1.2.3\n", ok: true}, + {desc: "alt2", input: "module m\ngno 1.2rc1\n", ok: true}, + {desc: "alt3", input: "module m\ngno 1.2beta1\n", ok: true}, + {desc: "alt4", input: "module m\ngno 1.2.beta1\n", ok: false}, } t.Run("Strict", func(t *testing.T) { for _, test := range tests { t.Run(test.desc, func(t *testing.T) { - if _, err := Parse("gno.mod", []byte(test.input)); err == nil && !test.ok { + if _, err := ParseBytes("gno.mod", []byte(test.input)); err == nil && !test.ok { t.Error("unexpected success") } else if err != nil && test.ok { t.Errorf("unexpected error: %v", err) @@ -169,7 +170,7 @@ comments before "// e" }, } { t.Run(test.desc, func(t *testing.T) { - f, err := Parse("gno.mod", []byte(test.input)) + f, err := ParseBytes("gno.mod", []byte(test.input)) if err != nil { t.Fatal(err) } @@ -210,7 +211,33 @@ comments before "// e" } } -var addModuleStmtTests = []struct { +var setGnoTests = []struct { + desc string + in string + version string + out string +}{ + { + `existing`, + ` + gno 0.0 + `, + "0.9", + ` + gno 0.9 + `, + }, + { + `new`, + ``, + "0.9", + ` + gno 0.9 + `, + }, +} + +var setModuleTests = []struct { desc string in string path string @@ -312,13 +339,25 @@ var dropReplaceTests = []struct { }, } -func TestAddModuleStmt(t *testing.T) { - for _, tt := range addModuleStmtTests { +func TestSetGno(t *testing.T) { + for _, tt := range setGnoTests { t.Run(tt.desc, func(t *testing.T) { testEdit(t, tt.in, tt.out, func(f *File) error { - err := f.AddModuleStmt(tt.path) + f.SetGno(tt.version) f.Syntax.Cleanup() - return err + return nil + }) + }) + } +} + +func TestSetModule(t *testing.T) { + for _, tt := range setModuleTests { + t.Run(tt.desc, func(t *testing.T) { + testEdit(t, tt.in, tt.out, func(f *File) error { + f.SetModule(tt.path) + f.Syntax.Cleanup() + return nil }) }) } @@ -340,9 +379,9 @@ func TestDropReplace(t *testing.T) { for _, tt := range dropReplaceTests { t.Run(tt.desc, func(t *testing.T) { testEdit(t, tt.in, tt.out, func(f *File) error { - err := f.DropReplace(tt.path, tt.vers) + f.DropReplace(tt.path, tt.vers) f.Syntax.Cleanup() - return err + return nil }) }) } @@ -350,11 +389,11 @@ func TestDropReplace(t *testing.T) { func testEdit(t *testing.T, in, want string, transform func(f *File) error) *File { t.Helper() - f, err := Parse("in", []byte(in)) + f, err := ParseBytes("in", []byte(in)) if err != nil { t.Fatal(err) } - g, err := Parse("out", []byte(want)) + g, err := ParseBytes("out", []byte(want)) if err != nil { t.Fatal(err) } diff --git a/gnovm/pkg/gnomod/utils.go b/gnovm/pkg/gnomod/utils.go index fe1d0ed79be..ba352576390 100644 --- a/gnovm/pkg/gnomod/utils.go +++ b/gnovm/pkg/gnomod/utils.go @@ -4,6 +4,9 @@ import ( "errors" "os" "path/filepath" + "testing" + + "github.com/stretchr/testify/require" ) // ErrGnoModNotFound is returned by [FindRootDir] when, even after traversing @@ -34,3 +37,16 @@ func FindRootDir(absPath string) (string, error) { return "", ErrGnoModNotFound } + +func createGnoModPkg(t *testing.T, dirPath, pkgName, modData string) { + t.Helper() + + // Create package dir + pkgDirPath := filepath.Join(dirPath, pkgName) + err := os.MkdirAll(pkgDirPath, 0o755) + require.NoError(t, err) + + // Create gno.mod + err = os.WriteFile(filepath.Join(pkgDirPath, "gno.mod"), []byte(modData), 0o644) + require.NoError(t, err) +} diff --git a/gnovm/pkg/repl/repl_test.go b/gnovm/pkg/repl/repl_test.go index 58b75188dde..5f5162881d3 100644 --- a/gnovm/pkg/repl/repl_test.go +++ b/gnovm/pkg/repl/repl_test.go @@ -69,7 +69,7 @@ var fixtures = []struct { CodeSteps: []step{ { Line: "importasdasd", - Error: "test/test1.gno:7:2: name importasdasd not declared", + Error: "test/test1.gno:7:2-14: name importasdasd not declared", }, { Line: "var a := 1", diff --git a/gnovm/pkg/test/errors.go b/gnovm/pkg/test/errors.go new file mode 100644 index 00000000000..f66aabb8b4c --- /dev/null +++ b/gnovm/pkg/test/errors.go @@ -0,0 +1,16 @@ +package test + +import "fmt" + +// XXX use it; this isn't used yet. +type TestImportError struct { + PkgPath string +} + +func (err TestImportError) Error() string { + return fmt.Sprintf("unknown package path %q", err.PkgPath) +} + +func (err TestImportError) String() string { + return fmt.Sprintf("TestImportError(%q)", err.Error()) +} diff --git a/gnovm/pkg/test/filetest.go b/gnovm/pkg/test/filetest.go index 06f1ce30fc9..f652f55237d 100644 --- a/gnovm/pkg/test/filetest.go +++ b/gnovm/pkg/test/filetest.go @@ -6,6 +6,7 @@ import ( "encoding/json" "fmt" "io" + "path/filepath" "regexp" "runtime/debug" "slices" @@ -22,14 +23,14 @@ import ( // RunFiletest executes the program in source as a filetest. // If opts.Sync is enabled, and the filetest's golden output has changed, // the first string is set to the new generated content of the file. -func (opts *TestOptions) RunFiletest(filename string, source []byte) (string, error) { +func (opts *TestOptions) RunFiletest(fname string, source []byte) (string, error) { opts.outWriter.w = opts.Output opts.outWriter.errW = opts.Error - return opts.runFiletest(filename, source) + return opts.runFiletest(fname, source) } -func (opts *TestOptions) runFiletest(filename string, source []byte) (string, error) { +func (opts *TestOptions) runFiletest(fname string, source []byte) (string, error) { dirs, err := ParseDirectives(bytes.NewReader(source)) if err != nil { return "", fmt.Errorf("error parsing directives: %w", err) @@ -64,7 +65,7 @@ func (opts *TestOptions) runFiletest(filename string, source []byte) (string, er ReviveEnabled: true, }) defer m.Release() - result := opts.runTest(m, pkgPath, filename, source, opslog) + result := opts.runTest(m, pkgPath, fname, source, opslog) // updated tells whether the directives have been updated, and as such // a new generated filetest should be returned. @@ -223,12 +224,13 @@ type runResult struct { GoPanicStack []byte } -func (opts *TestOptions) runTest(m *gno.Machine, pkgPath, filename string, content []byte, opslog io.Writer) (rr runResult) { +func (opts *TestOptions) runTest(m *gno.Machine, pkgPath, fname string, content []byte, opslog io.Writer) (rr runResult) { pkgName := gno.Name(pkgPath[strings.LastIndexByte(pkgPath, '/')+1:]) tcError := "" + fname = filepath.Base(fname) // Eagerly load imports. - // This is executed using opts.Store, rather than the transaction store; + // LoadImports is run using opts.Store, rather than the transaction store; // it allows us to only have to load the imports once (and re-use the cached // versions). Running the tests in separate "transactions" means that they // don't get the parent store dirty. @@ -236,7 +238,8 @@ func (opts *TestOptions) runTest(m *gno.Machine, pkgPath, filename string, conte Name: string(pkgName), Path: pkgPath, Files: []*std.MemFile{ - {Name: filename, Body: string(content)}, + {Name: "gno.mod", Body: gno.GenGnoModLatest(pkgPath)}, + {Name: fname, Body: string(content)}, }, }); err != nil { // NOTE: we perform this here, so we can capture the runResult. @@ -274,18 +277,16 @@ func (opts *TestOptions) runTest(m *gno.Machine, pkgPath, filename string, conte // Use last element after / (works also if slash is missing). if !gno.IsRealmPath(pkgPath) { // Type check. - memPkg := &std.MemPackage{ + mpkg := &std.MemPackage{ Name: string(pkgName), Path: pkgPath, Files: []*std.MemFile{ - { - Name: filename, - Body: string(content), - }, + {Name: "gno.mod", Body: "gno 0.9"}, + {Name: fname, Body: string(content)}, }, } // Validate Gno syntax and type check. - if err := gno.TypeCheckMemPackageTest(memPkg, m.Store); err != nil { + if _, _, err := gno.TypeCheckMemPackage(mpkg, m.Store, gno.ParseModeAll); err != nil { tcError = fmt.Sprintf("%v", err.Error()) } @@ -296,7 +297,7 @@ func (opts *TestOptions) runTest(m *gno.Machine, pkgPath, filename string, conte m.Store.SetCachePackage(pv) m.SetActivePackage(pv) m.Context.(*teststd.TestExecContext).OriginCaller = DefaultCaller - n := gno.MustParseFile(filename, string(content)) + n := gno.MustParseFile(fname, string(content)) m.RunFiles(n) m.RunMain() @@ -306,29 +307,27 @@ func (opts *TestOptions) runTest(m *gno.Machine, pkgPath, filename string, conte // Remove filetest from name, as that can lead to the package not being // parsed correctly when using RunMemPackage. - filename = strings.ReplaceAll(filename, "_filetest", "") + fname = strings.ReplaceAll(fname, "_filetest", "") // save package using realm crawl procedure. - memPkg := &std.MemPackage{ + mpkg := &std.MemPackage{ Name: string(pkgName), Path: pkgPath, Files: []*std.MemFile{ - { - Name: filename, - Body: string(content), - }, + {Name: "gno.mod", Body: "gno 0.9"}, + {Name: fname, Body: string(content)}, }, } orig, tx := m.Store, m.Store.BeginTransaction(nil, nil, nil) m.Store = tx // Validate Gno syntax and type check. - if err := gno.TypeCheckMemPackageTest(memPkg, m.Store); err != nil { + if _, _, err := gno.TypeCheckMemPackage(mpkg, m.Store, gno.ParseModeAll); err != nil { tcError = fmt.Sprintf("%v", err.Error()) } // Run decls and init functions. - m.RunMemPackage(memPkg, true) + m.RunMemPackage(mpkg, true) // Clear store cache and reconstruct machine from committed info // (mimicking on-chain behaviour). tx.Write() diff --git a/gnovm/pkg/test/imports.go b/gnovm/pkg/test/imports.go index 7c04acb8a67..793970ab766 100644 --- a/gnovm/pkg/test/imports.go +++ b/gnovm/pkg/test/imports.go @@ -30,6 +30,13 @@ type StoreOptions struct { // [gno.Machine.PreprocessFiles]. It avoids executing code for contexts // which only intend to perform a type check, ie. `gno lint`. PreprocessOnly bool + + // When transpiling code in examples/ we use the test store. gno fix may need + // gno.mod to not be auto-generated when importing from the test store. + DoNotGenerateGnoMod bool + + // XXX + FixFrom string } // NOTE: this isn't safe, should only be used for testing. @@ -40,9 +47,14 @@ func Store( baseStore storetypes.CommitStore, resStore gno.Store, ) { - return StoreWithOptions(rootDir, output, StoreOptions{}) + return StoreWithOptions( + rootDir, + output, + StoreOptions{}, + ) } +// ======================================== // StoreWithOptions is a variant of [Store] which additionally accepts a // [StoreOptions] argument. func StoreWithOptions( @@ -53,15 +65,50 @@ func StoreWithOptions( baseStore storetypes.CommitStore, resStore gno.Store, ) { - processMemPackage := func(m *gno.Machine, memPkg *std.MemPackage, save bool) (*gno.PackageNode, *gno.PackageValue) { - return m.RunMemPackage(memPkg, save) - } - if opts.PreprocessOnly { - processMemPackage = func(m *gno.Machine, memPkg *std.MemPackage, save bool) (*gno.PackageNode, *gno.PackageValue) { - m.Store.AddMemPackage(memPkg) - return m.PreprocessFiles(memPkg.Name, memPkg.Path, gno.ParseMemPackage(memPkg), save, false) + //---------------------------------------- + // process the mempackage after gno.MustReadMemPackage(). + // * m.PreprocessFiles() if opts.PreprocessOnly. + // * m.RunMemPackage() otherwise. + _processMemPackage := func( + m *gno.Machine, mpkg *std.MemPackage, save bool) ( + pn *gno.PackageNode, pv *gno.PackageValue, + ) { + if opts.PreprocessOnly { + // Check the gno.mod gno version. + mod, err := gno.ParseCheckGnoMod(mpkg) + if err != nil { + panic(fmt.Errorf("test store parsing gno.mod: %w", err)) + } + if mod.GetGno() == gno.GnoVerMissing { + // In order to translate into a newer Gno version with + // the preprocessor make a slight modifications to the + // AST. This needs to happen even for imports, because + // the preprocessor requires imports also preprocessed. + // This is because the linter uses pkg/test/imports.go. + gofset, gofs, _gofs, tgofs, errs := gno.GoParseMemPackage( + mpkg, gno.ParseModeAll) + if errs != nil { + panic(fmt.Errorf("test store parsing: %w", errs)) + } + allgofs := append(gofs, _gofs...) + allgofs = append(allgofs, tgofs...) + errs = gno.PrepareGno0p9(gofset, allgofs, mpkg) + if errs != nil { + panic(fmt.Errorf("test store preparing AST: %w", errs)) + } + } + m.Store.AddMemPackage(mpkg, gno.MemPackageTypeAny) + return m.PreprocessFiles( + mpkg.Name, mpkg.Path, + gno.ParseMemPackage(mpkg), + save, false, "") + } else { + return m.RunMemPackage(mpkg, save) } } + + //---------------------------------------- + // Main entrypoint for new test imports. getPackage := func(pkgPath string, store gno.Store) (pn *gno.PackageNode, pv *gno.PackageValue) { if pkgPath == "" { panic(fmt.Sprintf("invalid zero package path in testStore().pkgGetter")) @@ -72,7 +119,7 @@ func StoreWithOptions( const testPath = "github.com/gnolang/gno/_test/" if strings.HasPrefix(pkgPath, testPath) { baseDir := filepath.Join(rootDir, "gnovm", "tests", "files", "extern", pkgPath[len(testPath):]) - memPkg := gno.MustReadMemPackage(baseDir, pkgPath) + mpkg := gno.MustReadMemPackage(baseDir, pkgPath) send := std.Coins{} ctx := Context("", pkgPath, send) m2 := gno.NewMachineWithOptions(gno.MachineOptions{ @@ -82,7 +129,7 @@ func StoreWithOptions( Context: ctx, ReviveEnabled: true, }) - return processMemPackage(m2, memPkg, true) + return _processMemPackage(m2, mpkg, true) } } @@ -95,8 +142,8 @@ func StoreWithOptions( // if examples package... examplePath := filepath.Join(rootDir, "examples", pkgPath) if osm.DirExists(examplePath) { - memPkg := gno.MustReadMemPackage(examplePath, pkgPath) - if memPkg.IsEmpty() { + mpkg := gno.MustReadMemPackage(examplePath, pkgPath) + if mpkg.IsEmpty() { panic(fmt.Sprintf("found an empty package %q", pkgPath)) } @@ -109,10 +156,14 @@ func StoreWithOptions( Context: ctx, ReviveEnabled: true, }) - return processMemPackage(m2, memPkg, true) + return _processMemPackage(m2, mpkg, true) } + return nil, nil } + + //---------------------------------------- + // Construct new stores db := memdb.NewMemDB() baseStore = dbadapter.StoreConstructor(db, storetypes.StoreOptions{}) // Make a new store. @@ -151,7 +202,7 @@ func loadStdlib(rootDir, pkgPath string, store gno.Store, stdout io.Writer, prep return nil, nil } - memPkg := gno.MustReadMemPackageFromList(files, pkgPath) + mpkg := gno.MustReadMemPackageFromList(files, pkgPath) m2 := gno.NewMachineWithOptions(gno.MachineOptions{ // NOTE: see also pkgs/sdk/vm/builtins.go // Needs PkgPath != its name because TestStore.getPackage is the package @@ -162,11 +213,11 @@ func loadStdlib(rootDir, pkgPath string, store gno.Store, stdout io.Writer, prep ReviveEnabled: true, }) if preprocessOnly { - m2.Store.AddMemPackage(memPkg) - return m2.PreprocessFiles(memPkg.Name, memPkg.Path, gno.ParseMemPackage(memPkg), true, true) + m2.Store.AddMemPackage(mpkg, gno.MemPackageTypeStdlib) + return m2.PreprocessFiles(mpkg.Name, mpkg.Path, gno.ParseMemPackage(mpkg), true, true, "") } // TODO: make this work when using gno lint. - return m2.RunMemPackageWithOverrides(memPkg, true) + return m2.RunMemPackageWithOverrides(mpkg, true) } type stackWrappedError struct { @@ -184,7 +235,7 @@ func (e *stackWrappedError) String() string { // from the store. This is mostly useful for "eager import loading", whereby all // imports are pre-loaded in a permanent store, so that the tests can use // ephemeral transaction stores. -func LoadImports(store gno.Store, memPkg *std.MemPackage) (err error) { +func LoadImports(store gno.Store, mpkg *std.MemPackage) (err error) { defer func() { // This is slightly different from other similar error handling; we do not have a // machine to work with, as this comes from an import; so we need @@ -206,7 +257,7 @@ func LoadImports(store gno.Store, memPkg *std.MemPackage) (err error) { }() fset := token.NewFileSet() - importsMap, err := packages.Imports(memPkg, fset) + importsMap, err := packages.Imports(mpkg, fset) if err != nil { return err } @@ -219,7 +270,7 @@ func LoadImports(store gno.Store, memPkg *std.MemPackage) (err error) { } pkg := store.GetPackage(imp.PkgPath, true) if pkg == nil { - return fmt.Errorf("%v: unknown import path %v", fset.Position(imp.Spec.Pos()).String(), imp.PkgPath) + return gno.ImportNotFoundError{Location: fset.Position(imp.Spec.Pos()).String(), PkgPath: imp.PkgPath} } } return nil diff --git a/gnovm/pkg/test/test.go b/gnovm/pkg/test/test.go index 945fba6c535..853aad8c215 100644 --- a/gnovm/pkg/test/test.go +++ b/gnovm/pkg/test/test.go @@ -205,27 +205,27 @@ func tee(ptr *io.Writer, dst io.Writer) (revert func()) { } } -// Test runs tests on the specified memPkg. +// Test runs tests on the specified mpkg. // fsDir is the directory on filesystem of package; it's used in case opts.Sync // is enabled, and points to the directory where the files are contained if they // are to be updated. // opts is a required set of options, which is often shared among different // tests; you can use [NewTestOptions] for a common base configuration. -func Test(memPkg *std.MemPackage, fsDir string, opts *TestOptions) error { +func Test(mpkg *std.MemPackage, fsDir string, opts *TestOptions) error { opts.outWriter.w = opts.Output opts.outWriter.errW = opts.Error var errs error // Eagerly load imports. - if err := LoadImports(opts.TestStore, memPkg); err != nil { + if err := LoadImports(opts.TestStore, mpkg); err != nil { return err } // Stands for "test", "integration test", and "filetest". // "integration test" are the test files with `package xxx_test` (they are // not necessarily integration tests, it's just for our internal reference.) - tset, itset, itfiles, ftfiles := parseMemPackageTests(memPkg) + tset, itset, itfiles, ftfiles := parseMemPackageTests(mpkg) // Testing with *_test.gno if len(tset.Files)+len(itset.Files) > 0 { @@ -237,7 +237,7 @@ func Test(memPkg *std.MemPackage, fsDir string, opts *TestOptions) error { // Run test files in pkg. if len(tset.Files) > 0 { - err := opts.runTestFiles(memPkg, tset, gs) + err := opts.runTestFiles(mpkg, tset, gs) if err != nil { errs = multierr.Append(errs, err) } @@ -246,8 +246,8 @@ func Test(memPkg *std.MemPackage, fsDir string, opts *TestOptions) error { // Test xxx_test pkg. if len(itset.Files) > 0 { itPkg := &std.MemPackage{ - Name: memPkg.Name + "_test", - Path: memPkg.Path + "_test", + Name: mpkg.Name + "_test", + Path: mpkg.Path + "_test", Files: itfiles, } @@ -303,7 +303,7 @@ func Test(memPkg *std.MemPackage, fsDir string, opts *TestOptions) error { } func (opts *TestOptions) runTestFiles( - memPkg *std.MemPackage, + mpkg *std.MemPackage, files *gno.FileSet, gs gno.TransactionStore, ) (errs error) { @@ -321,7 +321,7 @@ func (opts *TestOptions) runTestFiles( } }() - tests := loadTestFuncs(memPkg.Name, files) + tests := loadTestFuncs(mpkg.Name, files) var alloc *gno.Allocator if opts.Metrics { @@ -331,12 +331,12 @@ func (opts *TestOptions) runTestFiles( opts.TestStore.SetLogStoreOps(nil) // Check if we already have the package - it may have been eagerly loaded. - m = Machine(gs, opts.WriterForStore(), memPkg.Path, opts.Debug) + m = Machine(gs, opts.WriterForStore(), mpkg.Path, opts.Debug) m.Alloc = alloc - if gs.GetMemPackage(memPkg.Path) == nil { - m.RunMemPackage(memPkg, true) + if gs.GetMemPackage(mpkg.Path) == nil { + m.RunMemPackage(mpkg, true) } else { - m.SetActivePackage(gs.GetPackage(memPkg.Path, false)) + m.SetActivePackage(gs.GetPackage(mpkg.Path, false)) } pv := m.Package @@ -352,7 +352,7 @@ func (opts *TestOptions) runTestFiles( // - Run the test files before this for loop (but persist it to store; // RunFiles doesn't do that currently) // - Wrap here. - m = Machine(gs, opts.WriterForStore(), memPkg.Path, opts.Debug) + m = Machine(gs, opts.WriterForStore(), mpkg.Path, opts.Debug) m.Alloc = alloc.Reset() m.SetActivePackage(pv) @@ -386,7 +386,7 @@ func (opts *TestOptions) runTestFiles( Type: gno.Sel(testingcx, "InternalTest"), Elts: gno.KeyValueExprs{ // XXX Consider this. - // {Key: gno.X("Name"), Value: gno.Str(memPkg.Path + "/" + tf.Filename + "." + tf.Name)}, + // {Key: gno.X("Name"), Value: gno.Str(mpkg.Path + "/" + tf.Filename + "." + tf.Name)}, {Key: gno.X("Name"), Value: gno.Str(tf.Name)}, {Key: gno.X("F"), Value: gno.Nx(tf.Name)}, }, @@ -481,12 +481,12 @@ func loadTestFuncs(pkgName string, tfiles *gno.FileSet) (rt []testFunc) { return } -// parseMemPackageTests parses test files (skipping filetests) in the memPkg. -func parseMemPackageTests(memPkg *std.MemPackage) (tset, itset *gno.FileSet, itfiles, ftfiles []*std.MemFile) { +// parseMemPackageTests parses test files (skipping filetests) in the mpkg. +func parseMemPackageTests(mpkg *std.MemPackage) (tset, itset *gno.FileSet, itfiles, ftfiles []*std.MemFile) { tset = &gno.FileSet{} itset = &gno.FileSet{} var errs error - for _, mfile := range memPkg.Files { + for _, mfile := range mpkg.Files { if !strings.HasSuffix(mfile.Name, ".gno") { continue // skip this file. } @@ -502,17 +502,17 @@ func parseMemPackageTests(memPkg *std.MemPackage) (tset, itset *gno.FileSet, itf switch { case strings.HasSuffix(mfile.Name, "_filetest.gno"): ftfiles = append(ftfiles, mfile) - case strings.HasSuffix(mfile.Name, "_test.gno") && memPkg.Name == string(n.PkgName): + case strings.HasSuffix(mfile.Name, "_test.gno") && mpkg.Name == string(n.PkgName): tset.AddFiles(n) - case strings.HasSuffix(mfile.Name, "_test.gno") && memPkg.Name+"_test" == string(n.PkgName): + case strings.HasSuffix(mfile.Name, "_test.gno") && mpkg.Name+"_test" == string(n.PkgName): itset.AddFiles(n) itfiles = append(itfiles, mfile) - case memPkg.Name == string(n.PkgName): + case mpkg.Name == string(n.PkgName): // normal package file default: panic(fmt.Sprintf( "expected package name [%s] or [%s_test] but got [%s] file [%s]", - memPkg.Name, memPkg.Name, n.PkgName, mfile)) + mpkg.Name, mpkg.Name, n.PkgName, mfile)) } } if errs != nil { diff --git a/gnovm/stdlibs/crypto/bech32/bech32_test.gno b/gnovm/stdlibs/crypto/bech32/bech32_test.gno index 3f637c40345..9525323403a 100644 --- a/gnovm/stdlibs/crypto/bech32/bech32_test.gno +++ b/gnovm/stdlibs/crypto/bech32/bech32_test.gno @@ -10,7 +10,7 @@ import ( "encoding/hex" "fmt" "strings" - "testing" + testing "testing/base" ) // TestBech32 tests whether decoding and re-encoding the valid BIP-173 test diff --git a/gnovm/stdlibs/encoding/csv/writer_test.gno b/gnovm/stdlibs/encoding/csv/writer_test.gno index 1407f3c670a..40d147b6a6c 100644 --- a/gnovm/stdlibs/encoding/csv/writer_test.gno +++ b/gnovm/stdlibs/encoding/csv/writer_test.gno @@ -6,7 +6,6 @@ package csv import ( "bytes" - "encoding/csv" "errors" "strings" "testing" @@ -21,7 +20,7 @@ func TestWriteCSV(t *testing.T) { } var buf bytes.Buffer - w := csv.NewWriter(&buf) + w := NewWriter(&buf) err := w.WriteAll(records) if err != nil { t.Errorf("Unexpected error: %v", err) @@ -74,7 +73,7 @@ var writeTests = []struct { func TestWrite(t *testing.T) { for n, tt := range writeTests { b := &strings.Builder{} - f := csv.NewWriter(b) + f := NewWriter(b) f.UseCRLF = tt.UseCRLF if tt.Comma != 0 { f.Comma = tt.Comma @@ -98,7 +97,7 @@ func (e errorWriter) Write(b []byte) (int, error) { func TestError(t *testing.T) { b := &bytes.Buffer{} - f := csv.NewWriter(b) + f := NewWriter(b) f.Write([]string{"abc"}) f.Flush() err := f.Error() @@ -106,7 +105,7 @@ func TestError(t *testing.T) { t.Errorf("Unexpected error: %s\n", err) } - f = csv.NewWriter(errorWriter{}) + f = NewWriter(errorWriter{}) f.Write([]string{"abc"}) f.Flush() err = f.Error() @@ -124,7 +123,7 @@ var benchmarkWriteData = [][]string{ func BenchmarkWrite(b *testing.B) { for i := 0; i < b.N; i++ { - w := csv.NewWriter(&bytes.Buffer{}) + w := NewWriter(&bytes.Buffer{}) err := w.WriteAll(benchmarkWriteData) if err != nil { b.Fatal(err) diff --git a/gnovm/stdlibs/generated.go b/gnovm/stdlibs/generated.go index 53206675e74..c8253148820 100644 --- a/gnovm/stdlibs/generated.go +++ b/gnovm/stdlibs/generated.go @@ -14,6 +14,7 @@ import ( libs_std "github.com/gnolang/gno/gnovm/stdlibs/std" libs_sys_params "github.com/gnolang/gno/gnovm/stdlibs/sys/params" libs_testing "github.com/gnolang/gno/gnovm/stdlibs/testing" + libs_testing_base "github.com/gnolang/gno/gnovm/stdlibs/testing/base" libs_time "github.com/gnolang/gno/gnovm/stdlibs/time" ) @@ -1134,6 +1135,68 @@ var nativeFuncs = [...]NativeFunc{ p0, p1, p2, p3) }, }, + { + "testing", + "matchString", + []gno.FieldTypeExpr{ + {NameExpr: *gno.Nx("p0"), Type: gno.X("string")}, + {NameExpr: *gno.Nx("p1"), Type: gno.X("string")}, + }, + []gno.FieldTypeExpr{ + {NameExpr: *gno.Nx("r0"), Type: gno.X("bool")}, + {NameExpr: *gno.Nx("r1"), Type: gno.X("string")}, + }, + false, + func(m *gno.Machine) { + b := m.LastBlock() + var ( + p0 string + rp0 = reflect.ValueOf(&p0).Elem() + p1 string + rp1 = reflect.ValueOf(&p1).Elem() + ) + + tv0 := b.GetPointerTo(nil, gno.NewValuePathBlock(1, 0, "")).TV + tv0.DeepFill(m.Store) + gno.Gno2GoValue(tv0, rp0) + tv1 := b.GetPointerTo(nil, gno.NewValuePathBlock(1, 1, "")).TV + tv1.DeepFill(m.Store) + gno.Gno2GoValue(tv1, rp1) + + r0, r1 := libs_testing.X_matchString(p0, p1) + + m.PushValue(gno.Go2GnoValue( + m.Alloc, + m.Store, + reflect.ValueOf(&r0).Elem(), + )) + m.PushValue(gno.Go2GnoValue( + m.Alloc, + m.Store, + reflect.ValueOf(&r1).Elem(), + )) + }, + }, + { + "testing", + "recoverWithStacktrace", + []gno.FieldTypeExpr{}, + []gno.FieldTypeExpr{ + {NameExpr: *gno.Nx("r0"), Type: gno.AnyT()}, + {NameExpr: *gno.Nx("r1"), Type: gno.X("string")}, + }, + false, + func(m *gno.Machine) { + r0, r1 := libs_testing.X_recoverWithStacktrace() + + m.PushValue(r0) + m.PushValue(gno.Go2GnoValue( + m.Alloc, + m.Store, + reflect.ValueOf(&r1).Elem(), + )) + }, + }, { "testing", "unixNano", @@ -1153,7 +1216,25 @@ var nativeFuncs = [...]NativeFunc{ }, }, { - "testing", + "testing/base", + "unixNano", + []gno.FieldTypeExpr{}, + []gno.FieldTypeExpr{ + {NameExpr: *gno.Nx("r0"), Type: gno.X("int64")}, + }, + false, + func(m *gno.Machine) { + r0 := libs_testing_base.X_unixNano() + + m.PushValue(gno.Go2GnoValue( + m.Alloc, + m.Store, + reflect.ValueOf(&r0).Elem(), + )) + }, + }, + { + "testing/base", "recoverWithStacktrace", []gno.FieldTypeExpr{}, []gno.FieldTypeExpr{ @@ -1162,7 +1243,7 @@ var nativeFuncs = [...]NativeFunc{ }, false, func(m *gno.Machine) { - r0, r1 := libs_testing.X_recoverWithStacktrace() + r0, r1 := libs_testing_base.X_recoverWithStacktrace() m.PushValue(r0) m.PushValue(gno.Go2GnoValue( @@ -1173,7 +1254,7 @@ var nativeFuncs = [...]NativeFunc{ }, }, { - "testing", + "testing/base", "matchString", []gno.FieldTypeExpr{ {NameExpr: *gno.Nx("p0"), Type: gno.X("string")}, @@ -1200,7 +1281,7 @@ var nativeFuncs = [...]NativeFunc{ tv1.DeepFill(m.Store) gno.Gno2GoValue(tv1, rp1) - r0, r1 := libs_testing.X_matchString(p0, p1) + r0, r1 := libs_testing_base.X_matchString(p0, p1) m.PushValue(gno.Go2GnoValue( m.Alloc, @@ -1322,6 +1403,7 @@ var initOrder = [...]string{ "runtime", "std", "sys/params", + "testing/base", "time", "testing", "unicode/utf16", diff --git a/gnovm/stdlibs/math/overflow/overflow_test.gno b/gnovm/stdlibs/math/overflow/overflow_test.gno index b7881aec480..72898307b3b 100644 --- a/gnovm/stdlibs/math/overflow/overflow_test.gno +++ b/gnovm/stdlibs/math/overflow/overflow_test.gno @@ -2,7 +2,7 @@ package overflow import ( "math" - "testing" + testing "testing/base" ) // sample all possibilities of 8 bit numbers diff --git a/gnovm/stdlibs/std/crypto_test.gno b/gnovm/stdlibs/std/crypto_test.gno index 70b42e43860..65c8242a74b 100644 --- a/gnovm/stdlibs/std/crypto_test.gno +++ b/gnovm/stdlibs/std/crypto_test.gno @@ -1,7 +1,7 @@ package std import ( - "testing" + testing "testing/base" ) func TestValid(t *testing.T) { diff --git a/gnovm/stdlibs/std/emit_event_test.go b/gnovm/stdlibs/std/emit_event_test.go index 05532d49707..873b0ac7a0a 100644 --- a/gnovm/stdlibs/std/emit_event_test.go +++ b/gnovm/stdlibs/std/emit_event_test.go @@ -21,8 +21,10 @@ func pushFuncFrame(m *gno.Machine, name gno.Name) { fd.SetLocation(gno.Location{ PkgPath: pkgPath, File: fileName, - Line: line, // fake unique line no - Column: 0, // fake column + Span: gno.Span{ // fake unique span. + Pos: gno.Pos{Line: line, Column: 0}, + End: gno.Pos{Line: line, Column: 100}, + }, }) line++ fv := &gno.FuncValue{Name: name, PkgPath: m.Package.PkgPath, Source: fd} diff --git a/gnovm/stdlibs/strings/builder_test.gno b/gnovm/stdlibs/strings/builder_test.gno index 1bbff0249ad..ec0283349d5 100644 --- a/gnovm/stdlibs/strings/builder_test.gno +++ b/gnovm/stdlibs/strings/builder_test.gno @@ -7,7 +7,7 @@ package strings_test import ( "bytes" "strings" - "testing" + testing "testing/base" "unicode/utf8" ) diff --git a/gnovm/stdlibs/strings/printtrie_test.gno b/gnovm/stdlibs/strings/printtrie_test.gno index a51208f4756..7057498bbe6 100644 --- a/gnovm/stdlibs/strings/printtrie_test.gno +++ b/gnovm/stdlibs/strings/printtrie_test.gno @@ -2,7 +2,7 @@ package strings_test import ( "strings" - "testing" + testing "testing/base" ) func TestGenericTrieBuilding(t *testing.T) { diff --git a/gnovm/stdlibs/strings/reader_test.gno b/gnovm/stdlibs/strings/reader_test.gno index a8047311550..2363023f190 100644 --- a/gnovm/stdlibs/strings/reader_test.gno +++ b/gnovm/stdlibs/strings/reader_test.gno @@ -7,7 +7,7 @@ package strings_test import ( "io" "strings" - "testing" + testing "testing/base" ) func TestReader(t *testing.T) { diff --git a/gnovm/stdlibs/strings/replace_test.gno b/gnovm/stdlibs/strings/replace_test.gno index dc4858dcc5c..52e92c60255 100644 --- a/gnovm/stdlibs/strings/replace_test.gno +++ b/gnovm/stdlibs/strings/replace_test.gno @@ -8,7 +8,7 @@ import ( "bytes" "fmt" "strings" - "testing" + testing "testing/base" ) var htmlEscaper = strings.NewReplacer( diff --git a/gnovm/stdlibs/testing/base/README.md b/gnovm/stdlibs/testing/base/README.md new file mode 100644 index 00000000000..b23d14e9da7 --- /dev/null +++ b/gnovm/stdlibs/testing/base/README.md @@ -0,0 +1,4 @@ +This package exists because we add many things into `testing` beyond Go's +`testing` module, and this creates circular dependencies in our own standard +libraries. Standard library packages like crypto/bech32 need to import +`testing/base` instead of `testing`. diff --git a/gnovm/stdlibs/testing/base/match.gno b/gnovm/stdlibs/testing/base/match.gno new file mode 100644 index 00000000000..25d1da808c0 --- /dev/null +++ b/gnovm/stdlibs/testing/base/match.gno @@ -0,0 +1,165 @@ +package base + +// Most of the code in this file is extracted from golang's src/testing/match.go. +// +// Copyright 2015 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. + +import ( + "fmt" + "strings" + "unicode" +) + +type filterMatch interface { + // matches checks the name against the receiver's pattern strings using the + // given match function. + matches(name []string) (ok, partial bool) + + // verify checks that the receiver's pattern strings are valid filters by + // calling the given match function. + verify(name string) error +} + +// simpleMatch matches a test name if all of the pattern strings match in +// sequence. +type simpleMatch []string + +// alternationMatch matches a test name if one of the alternations match. +type alternationMatch []filterMatch + +func (m simpleMatch) matches(name []string) (ok, partial bool) { + for i, s := range name { + if i >= len(m) { + break + } + if ok, _ := matchString(m[i], s); !ok { + return false, false + } + } + return true, len(name) < len(m) +} + +func (m simpleMatch) verify(name string) error { + for i, s := range m { + m[i] = rewrite(s) + } + // Verify filters before doing any processing. + for i, s := range m { + if _, err := matchString(s, "non-empty"); err != "" { + return fmt.Errorf("element %d of %s (%q): %s", i, name, s, err) + } + } + return nil +} + +func (m alternationMatch) matches(name []string) (ok, partial bool) { + for _, m := range m { + if ok, partial = m.matches(name); ok { + return ok, partial + } + } + return false, false +} + +func (m alternationMatch) verify(name string) error { + for i, m := range m { + if err := m.verify(name); err != nil { + return fmt.Errorf("alternation %d of %s", i, err) + } + } + return nil +} + +func splitRegexp(s string) filterMatch { + a := make(simpleMatch, 0, strings.Count(s, "/")) + b := make(alternationMatch, 0, strings.Count(s, "|")) + cs := 0 + cp := 0 + for i := 0; i < len(s); { + switch s[i] { + case '[': + cs++ + case ']': + if cs--; cs < 0 { // An unmatched ']' is legal. + cs = 0 + } + case '(': + if cs == 0 { + cp++ + } + case ')': + if cs == 0 { + cp-- + } + case '\\': + i++ + case '/': + if cs == 0 && cp == 0 { + a = append(a, s[:i]) + s = s[i+1:] + i = 0 + continue + } + case '|': + if cs == 0 && cp == 0 { + a = append(a, s[:i]) + s = s[i+1:] + i = 0 + b = append(b, a) + a = make(simpleMatch, 0, len(a)) + continue + } + } + i++ + } + + a = append(a, s) + if len(b) == 0 { + return a + } + return append(b, a) +} + +// rewrite rewrites a subname to having only printable characters and no white +// space. +func rewrite(s string) string { + b := []byte{} + for _, r := range s { + switch { + case isSpace(r): + b = append(b, '_') + case !unicode.IsPrint(r): + s := simpleQuoteRune(r) + b = append(b, s[1:len(s)-1]...) + default: + b = append(b, string(r)...) + } + } + return string(b) +} + +// simpleQuoteRune does not follow the original strconv.QuoteRune. +func simpleQuoteRune(r rune) string { + return "." +} + +func isSpace(r rune) bool { + if r < 0x2000 { + switch r { + // Note: not the same as Unicode Z class. + case '\t', '\n', '\v', '\f', '\r', ' ', 0x85, 0xA0, 0x1680: + return true + } + } else { + if r <= 0x200a { + return true + } + switch r { + case 0x2028, 0x2029, 0x202f, 0x205f, 0x3000: + return true + } + } + return false +} diff --git a/gnovm/stdlibs/testing/base/testing.gno b/gnovm/stdlibs/testing/base/testing.gno new file mode 100644 index 00000000000..7466af1fce2 --- /dev/null +++ b/gnovm/stdlibs/testing/base/testing.gno @@ -0,0 +1,384 @@ +// Shim for Go's "testing" package to support minimal testing types. +package base + +import ( + "fmt" + "os" + "strconv" + "strings" +) + +// ---------------------------------------- +// Top level functions + +// SkipErr is the type of the panic created by SkipNow +// and FailNow. Having it as a simple string means that it can be fmt.Printf'd +// easily (and doesn't get "corrupted" through gno2go). +type SkipErr string + +func (s SkipErr) Error() string { + return string(s) +} + +// Recover functions like recover(), but it ensures that the recovered error is +// not an internal error of the testing package. +// +// Due to a lack of goroutines and thus runtime.Goexit, gno's testing system resorts +// to panics to abort testing with FailNow (and Fatal* functions) or SkipNow +// (and Skip* functions). +// +// NOTE: Recover() is likely to be removed. +func Recover(result Setter) { + r := recover() + if _, ok := r.(SkipErr); !ok { + result.Set(r) + return + } + + panic(r) +} + +type Setter interface { + Set(v any) +} + +func Short() bool { + return true // TODO configure somehow. +} + +func Verbose() bool { + return true // TODO configure somehow. +} + +// Like AllocsPerRun() but returns an integer. +// TODO: actually compute allocations; for now return 0. +func AllocsPerRun2(runs int, f func()) (total int) { + for i := 0; i < runs; i++ { + f() + } + return 0 +} + +// ---------------------------------------- +// T + +type T struct { + name string + failed bool + skipped bool + subs []*T + parent *T + output []byte // Output generated by test + verbose bool + failfast bool + runFilter filterMatch + dur string +} + +func NewT(name string) *T { + return &T{name: name} +} + +type testingFunc func(*T) + +// Not yet implemented: +// func (t *T) Cleanup(f func()) { +// func (t *T) Deadline() (deadline time.Time, ok bool) +func (t *T) Error(args ...any) { + t.Log(args...) + t.Fail() +} + +func (t *T) Errorf(format string, args ...any) { + t.Logf(format, args...) + t.Fail() +} + +func (t *T) Fail() { + t.failed = true +} + +func (t *T) FailNow() { + t.Fail() + panic(SkipErr("testing: you have recovered a panic attempting to interrupt a test, as a consequence of FailNow. " + + "Use testing.Recover to recover panics within tests")) +} + +func (t *T) Failed() bool { + if t.failed { + return true + } + for _, sub := range t.subs { + if sub.Failed() { + return true + } + } + return false +} + +// only called when verbose == false +func (t *T) printFailure() { + fmt.Fprintf(os.Stderr, "--- FAIL: %s (%s)\n", t.name, t.dur) + if t.failed { + fmt.Fprint(os.Stderr, string(t.output)) + } + for _, sub := range t.subs { + if sub.Failed() { + sub.printFailure() + } + } +} + +func (t *T) Fatal(args ...any) { + t.Log(args...) + t.FailNow() +} + +func (t *T) Fatalf(format string, args ...any) { + t.Logf(format, args...) + t.FailNow() +} + +func (t *T) Log(args ...any) { + t.log(fmt.Sprintln(args...)) +} + +func (t *T) Logf(format string, args ...any) { + t.log(fmt.Sprintf(format, args...)) + t.log(fmt.Sprintln()) +} + +func (t *T) Name() string { + return t.name +} + +func (t *T) Parallel() { + // does nothing. +} + +func (t *T) Run(name string, f testingFunc) bool { + fullName := t.name + "/" + rewrite(name) + + subT := &T{ + parent: t, + name: fullName, + verbose: t.verbose, + runFilter: t.runFilter, + } + + if t.failfast && t.Failed() { + return false + } + + t.subs = append(t.subs, subT) + + tRunner(subT, f, t.verbose) + return true +} + +func (t *T) Setenv(key, value string) { + panic("not yet implemented") +} + +func (t *T) Skip(args ...any) { + t.Log(args...) + t.SkipNow() +} + +func (t *T) SkipNow() { + t.skipped = true + panic(SkipErr("testing: you have recovered a panic attempting to interrupt a test, as a consequence of SkipNow. " + + "Use testing.Recover to recover panics within tests")) +} + +func (t *T) Skipped() bool { + return t.skipped +} + +func (t *T) Skipf(format string, args ...any) { + t.Logf(format, args...) + t.SkipNow() +} + +func (t *T) TempDir() string { + panic("not yet implemented") +} + +func (t *T) Helper() { +} + +func (t *T) log(s string) { + if t.verbose { + // verbose, print immediately + fmt.Fprint(os.Stderr, s) + } else { + // defer printing only if test is failed + t.output = append(t.output, s...) + } +} + +type Report struct { + Failed bool + Skipped bool +} + +func (r *Report) marshal() string { + failed := "false" + skipped := "false" + if r.Failed { + failed = "true" + } + if r.Skipped { + skipped = "true" + } + return `{"Failed":` + failed + `,"Skipped":` + skipped + `}` +} + +func (t *T) report() Report { + return Report{ + Failed: t.Failed(), + Skipped: t.skipped, + } +} + +// ---------------------------------------- +// B +// TODO: actually implement + +type B struct { + N int +} + +func (b *B) Cleanup(f func()) { panic("not yet implemented") } +func (b *B) Error(args ...any) { panic("not yet implemented") } +func (b *B) Errorf(format string, args ...any) { panic("not yet implemented") } +func (b *B) Fail() { panic("not yet implemented") } +func (b *B) FailNow() { panic("not yet implemented") } +func (b *B) Failed() bool { panic("not yet implemented") } +func (b *B) Fatal(args ...any) { panic("not yet implemented") } +func (b *B) Fatalf(format string, args ...any) { panic("not yet implemented") } +func (b *B) Helper() { panic("not yet implemented") } +func (b *B) Log(args ...any) { panic("not yet implemented") } +func (b *B) Logf(format string, args ...any) { panic("not yet implemented") } +func (b *B) Name() string { panic("not yet implemented") } +func (b *B) ReportAllocs() { panic("not yet implemented") } +func (b *B) ReportMetric(n float64, unit string) { panic("not yet implemented") } +func (b *B) ResetTimer() { panic("not yet implemented") } +func (b *B) Run(name string, f func(b *B)) bool { panic("not yet implemented") } +func (b *B) RunParallel(body func(*PB)) { panic("not yet implemented") } +func (b *B) SetBytes(n int64) { panic("not yet implemented") } +func (b *B) SetParallelism(p int) { panic("not yet implemented") } +func (b *B) Setenv(key, value string) { panic("not yet implemented") } +func (b *B) Skip(args ...any) { panic("not yet implemented") } +func (b *B) SkipNow() { panic("not yet implemented") } +func (b *B) Skipf(format string, args ...any) { panic("not yet implemented") } +func (b *B) Skipped() bool { panic("not yet implemented") } +func (b *B) StartTimer() { panic("not yet implemented") } +func (b *B) StopTimer() { panic("not yet implemented") } +func (b *B) TempDir() string { panic("not yet implemented") } + +// ---------------------------------------- +// PB +// TODO: actually implement + +type PB struct{} + +func (pb *PB) Next() bool { panic("not yet implemented") } + +type InternalTest struct { + Name string + F testingFunc +} + +func (t *T) shouldRun(name string) bool { + if t.runFilter == nil { + return true + } + + elem := strings.Split(name, "/") + ok, partial := t.runFilter.matches(elem) + _ = partial // we don't care right now + return ok +} + +func RunTest(runFlag string, verbose bool, failfast bool, test InternalTest) (ret string) { + t := &T{ + name: test.Name, + verbose: verbose, + failfast: failfast, + } + + if runFlag != "" { + t.runFilter = splitRegexp(runFlag) + } + + tRunner(t, test.F, verbose) + if !t.verbose && t.Failed() { + // use printFailure to print output log of this + // and/or any subtests that may have failed. + t.printFailure() + } + + report := t.report() + return report.marshal() +} + +func formatDur(dur int64) string { + // XXX switch to FormatFloat after it's been added + // 1 sec = 1e9 nsec + // this gets us the "centiseconds" which is what we show in tests. + dstr := strconv.Itoa(int(dur / 1e7)) + if len(dstr) < 3 { + const pad = "000" + dstr = pad[:3-len(dstr)] + dstr + } + return dstr[:len(dstr)-2] + "." + dstr[len(dstr)-2:] + "s" +} + +// used to calculate execution times; only present in testing stdlibs +func unixNano() int64 + +// recovers panics and returns their related stacktraces, as well +func recoverWithStacktrace() (interface{}, string) + +// used to filter tests, we can't directly use regexp here due to a cyclic import; only present in testing stdlibs +func matchString(pat, str string) (bool, string) + +func tRunner(t *T, fn testingFunc, verbose bool) { + if !t.shouldRun(t.name) { + return + } + + start := unixNano() + + defer func() { + err, st := recoverWithStacktrace() + switch err.(type) { + case nil: + case SkipErr: + default: + t.Fail() + fmt.Fprintf(os.Stderr, "panic: %v\nStacktrace:\n%s\n", err, st) + } + + dur := unixNano() - start + t.dur = formatDur(dur) + + if t.verbose { + switch { + case t.Failed(): + fmt.Fprintf(os.Stderr, "--- FAIL: %s (%s)\n", t.name, t.dur) + case t.skipped: + fmt.Fprintf(os.Stderr, "--- SKIP: %s (%s)\n", t.name, t.dur) + case t.verbose: + fmt.Fprintf(os.Stderr, "--- PASS: %s (%s)\n", t.name, t.dur) + } + } + }() + + if verbose { + fmt.Fprintf(os.Stderr, "=== RUN %s\n", t.name) + } + + fn(t) +} diff --git a/gnovm/stdlibs/testing/base/testing.go b/gnovm/stdlibs/testing/base/testing.go new file mode 100644 index 00000000000..520f333b563 --- /dev/null +++ b/gnovm/stdlibs/testing/base/testing.go @@ -0,0 +1,18 @@ +package base + +import ( + "github.com/gnolang/gno/gnovm/pkg/gnolang" +) + +func X_unixNano() int64 { + // only implemented in testing stdlibs + return 0 +} + +func X_matchString(pat, str string) (bool, string) { + panic("only implemented in testing stdlibs") +} + +func X_recoverWithStacktrace() (gnolang.TypedValue, string) { + panic("only available in testing stdlibs") +} diff --git a/gnovm/stdlibs/testing/testing.gno b/gnovm/stdlibs/testing/testing.gno index 9b9859642c3..00b1c041391 100644 --- a/gnovm/stdlibs/testing/testing.gno +++ b/gnovm/stdlibs/testing/testing.gno @@ -2,23 +2,19 @@ package testing import ( - "fmt" - "os" - "strconv" - "strings" + "testing/base" ) -// ---------------------------------------- -// Top level functions +// NOTE almost everything actually declared in testing/base -// skipErr is the type of the panic created by SkipNow -// and FailNow. Having it as a simple string means that it can be fmt.Printf'd -// easily (and doesn't get "corrupted" through gno2go). -type skipErr string +// NOTE These native functions are duplicated in testing and testing/base, +// and also all overridden in test/stdlibs/testing and test/stdlibs/testing/base. +func matchString(pat, str string) (bool, string) +func recoverWithStacktrace() (interface{}, string) +func unixNano() int64 -func (s skipErr) Error() string { - return string(s) -} +// ---------------------------------------- +// Top level functions // Recover functions like recover(), but it ensures that the recovered error is // not an internal error of the testing package. @@ -28,357 +24,39 @@ func (s skipErr) Error() string { // (and Skip* functions). // // NOTE: Recover() is likely to be removed. -func Recover(result Setter) { - r := recover() - if _, ok := r.(skipErr); !ok { - result.Set(r) - return - } - - panic(r) -} +var Recover = base.Recover -type Setter interface { - Set(v any) -} +type Setter = base.Setter -func Short() bool { - return true // TODO configure somehow. -} +var Short = base.Short -func Verbose() bool { - return true // TODO configure somehow. -} +var Verbose = base.Verbose // Like AllocsPerRun() but returns an integer. // TODO: actually compute allocations; for now return 0. -func AllocsPerRun2(runs int, f func()) (total int) { - for i := 0; i < runs; i++ { - f() - } - return 0 -} +var AllocsPerRun2 = base.AllocsPerRun2 // ---------------------------------------- // T -type T struct { - name string - failed bool - skipped bool - subs []*T - parent *T - output []byte // Output generated by test - verbose bool - failfast bool - runFilter filterMatch - dur string -} - -func NewT(name string) *T { - return &T{name: name} -} - -type testingFunc func(*T) - -// Not yet implemented: -// func (t *T) Cleanup(f func()) { -// func (t *T) Deadline() (deadline time.Time, ok bool) -func (t *T) Error(args ...any) { - t.Log(args...) - t.Fail() -} - -func (t *T) Errorf(format string, args ...any) { - t.Logf(format, args...) - t.Fail() -} - -func (t *T) Fail() { - t.failed = true -} - -func (t *T) FailNow() { - t.Fail() - panic(skipErr("testing: you have recovered a panic attempting to interrupt a test, as a consequence of FailNow. " + - "Use testing.Recover to recover panics within tests")) -} - -func (t *T) Failed() bool { - if t.failed { - return true - } - for _, sub := range t.subs { - if sub.Failed() { - return true - } - } - return false -} - -// only called when verbose == false -func (t *T) printFailure() { - fmt.Fprintf(os.Stderr, "--- FAIL: %s (%s)\n", t.name, t.dur) - if t.failed { - fmt.Fprint(os.Stderr, string(t.output)) - } - for _, sub := range t.subs { - if sub.Failed() { - sub.printFailure() - } - } -} - -func (t *T) Fatal(args ...any) { - t.Log(args...) - t.FailNow() -} - -func (t *T) Fatalf(format string, args ...any) { - t.Logf(format, args...) - t.FailNow() -} - -func (t *T) Log(args ...any) { - t.log(fmt.Sprintln(args...)) -} - -func (t *T) Logf(format string, args ...any) { - t.log(fmt.Sprintf(format, args...)) - t.log(fmt.Sprintln()) -} - -func (t *T) Name() string { - return t.name -} - -func (t *T) Parallel() { - // does nothing. -} - -func (t *T) Run(name string, f testingFunc) bool { - fullName := t.name + "/" + rewrite(name) - - subT := &T{ - parent: t, - name: fullName, - verbose: t.verbose, - runFilter: t.runFilter, - } - - if t.failfast && t.Failed() { - return false - } - - t.subs = append(t.subs, subT) - - tRunner(subT, f, t.verbose) - return true -} - -func (t *T) Setenv(key, value string) { - panic("not yet implemented") -} - -func (t *T) Skip(args ...any) { - t.Log(args...) - t.SkipNow() -} +type T = base.T -func (t *T) SkipNow() { - t.skipped = true - panic(skipErr("testing: you have recovered a panic attempting to interrupt a test, as a consequence of SkipNow. " + - "Use testing.Recover to recover panics within tests")) -} +var NewT = base.NewT -func (t *T) Skipped() bool { - return t.skipped -} - -func (t *T) Skipf(format string, args ...any) { - t.Logf(format, args...) - t.SkipNow() -} - -func (t *T) TempDir() string { - panic("not yet implemented") -} - -func (t *T) Helper() { -} - -func (t *T) log(s string) { - if t.verbose { - // verbose, print immediately - fmt.Fprint(os.Stderr, s) - } else { - // defer printing only if test is failed - t.output = append(t.output, s...) - } -} - -type Report struct { - Failed bool - Skipped bool -} - -func (r *Report) marshal() string { - failed := "false" - skipped := "false" - if r.Failed { - failed = "true" - } - if r.Skipped { - skipped = "true" - } - return `{"Failed":` + failed + `,"Skipped":` + skipped + `}` -} - -func (t *T) report() Report { - return Report{ - Failed: t.Failed(), - Skipped: t.skipped, - } -} +type Report = base.Report // ---------------------------------------- // B // TODO: actually implement -type B struct { - N int -} - -func (b *B) Cleanup(f func()) { panic("not yet implemented") } -func (b *B) Error(args ...any) { panic("not yet implemented") } -func (b *B) Errorf(format string, args ...any) { panic("not yet implemented") } -func (b *B) Fail() { panic("not yet implemented") } -func (b *B) FailNow() { panic("not yet implemented") } -func (b *B) Failed() bool { panic("not yet implemented") } -func (b *B) Fatal(args ...any) { panic("not yet implemented") } -func (b *B) Fatalf(format string, args ...any) { panic("not yet implemented") } -func (b *B) Helper() { panic("not yet implemented") } -func (b *B) Log(args ...any) { panic("not yet implemented") } -func (b *B) Logf(format string, args ...any) { panic("not yet implemented") } -func (b *B) Name() string { panic("not yet implemented") } -func (b *B) ReportAllocs() { panic("not yet implemented") } -func (b *B) ReportMetric(n float64, unit string) { panic("not yet implemented") } -func (b *B) ResetTimer() { panic("not yet implemented") } -func (b *B) Run(name string, f func(b *B)) bool { panic("not yet implemented") } -func (b *B) RunParallel(body func(*PB)) { panic("not yet implemented") } -func (b *B) SetBytes(n int64) { panic("not yet implemented") } -func (b *B) SetParallelism(p int) { panic("not yet implemented") } -func (b *B) Setenv(key, value string) { panic("not yet implemented") } -func (b *B) Skip(args ...any) { panic("not yet implemented") } -func (b *B) SkipNow() { panic("not yet implemented") } -func (b *B) Skipf(format string, args ...any) { panic("not yet implemented") } -func (b *B) Skipped() bool { panic("not yet implemented") } -func (b *B) StartTimer() { panic("not yet implemented") } -func (b *B) StopTimer() { panic("not yet implemented") } -func (b *B) TempDir() string { panic("not yet implemented") } +type B = base.B // ---------------------------------------- // PB // TODO: actually implement -type PB struct{} - -func (pb *PB) Next() bool { panic("not yet implemented") } - -type InternalTest struct { - Name string - F testingFunc -} - -func (t *T) shouldRun(name string) bool { - if t.runFilter == nil { - return true - } - - elem := strings.Split(name, "/") - ok, partial := t.runFilter.matches(elem) - _ = partial // we don't care right now - return ok -} - -func RunTest(runFlag string, verbose bool, failfast bool, test InternalTest) (ret string) { - t := &T{ - name: test.Name, - verbose: verbose, - failfast: failfast, - } - - if runFlag != "" { - t.runFilter = splitRegexp(runFlag) - } - - tRunner(t, test.F, verbose) - if !t.verbose && t.Failed() { - // use printFailure to print output log of this - // and/or any subtests that may have failed. - t.printFailure() - } - - report := t.report() - return report.marshal() -} - -func formatDur(dur int64) string { - // XXX switch to FormatFloat after it's been added - // 1 sec = 1e9 nsec - // this gets us the "centiseconds" which is what we show in tests. - dstr := strconv.Itoa(int(dur / 1e7)) - if len(dstr) < 3 { - const pad = "000" - dstr = pad[:3-len(dstr)] + dstr - } - return dstr[:len(dstr)-2] + "." + dstr[len(dstr)-2:] + "s" -} - -// used to calculate execution times; only present in testing stdlibs -func unixNano() int64 - -// recovers panics and returns their related stacktraces, as well -func recoverWithStacktrace() (interface{}, string) - -// used to filter tests, we can't directly use regexp here due to a cyclic import; only present in testing stdlibs -func matchString(pat, str string) (bool, string) - -func tRunner(t *T, fn testingFunc, verbose bool) { - if !t.shouldRun(t.name) { - return - } - - start := unixNano() - - defer func() { - err, st := recoverWithStacktrace() - switch err.(type) { - case nil: - case skipErr: - default: - t.Fail() - fmt.Fprintf(os.Stderr, "panic: %v\nStacktrace:\n%s\n", err, st) - } - - dur := unixNano() - start - t.dur = formatDur(dur) - - if t.verbose { - switch { - case t.Failed(): - fmt.Fprintf(os.Stderr, "--- FAIL: %s (%s)\n", t.name, t.dur) - case t.skipped: - fmt.Fprintf(os.Stderr, "--- SKIP: %s (%s)\n", t.name, t.dur) - case t.verbose: - fmt.Fprintf(os.Stderr, "--- PASS: %s (%s)\n", t.name, t.dur) - } - } - }() +type PB = base.PB - if verbose { - fmt.Fprintf(os.Stderr, "=== RUN %s\n", t.name) - } +type InternalTest = base.InternalTest - fn(t) -} +var RunTest = base.RunTest diff --git a/gnovm/tests/files/access1.gno b/gnovm/tests/files/access1.gno index b5d28727386..e3ffc5ca296 100644 --- a/gnovm/tests/files/access1.gno +++ b/gnovm/tests/files/access1.gno @@ -9,7 +9,7 @@ func main() { } // Error: -// main/files/access1.gno:8:10: cannot access gno.land/p/demo/testutils.testVar2 from main +// main/access1.gno:8:10-28: cannot access gno.land/p/demo/testutils.testVar2 from main // TypeCheckError: -// main/files/access1.gno:8:20: name testVar2 not exported by package testutils +// main/access1.gno:8:20: name testVar2 not exported by package testutils diff --git a/gnovm/tests/files/access4.gno b/gnovm/tests/files/access4.gno index 99ba4f1daeb..64916b1d412 100644 --- a/gnovm/tests/files/access4.gno +++ b/gnovm/tests/files/access4.gno @@ -10,7 +10,7 @@ func main() { } // Error: -// main/files/access4.gno:9:10: cannot access gno.land/p/demo/testutils.TestAccessStruct.privateField from main +// main/access4.gno:9:10-24: cannot access gno.land/p/demo/testutils.TestAccessStruct.privateField from main // TypeCheckError: -// main/files/access4.gno:9:12: x.privateField undefined (cannot refer to unexported field privateField) +// main/access4.gno:9:12: x.privateField undefined (cannot refer to unexported field privateField) diff --git a/gnovm/tests/files/access6.gno b/gnovm/tests/files/access6.gno index 54521096e6d..679972120bb 100644 --- a/gnovm/tests/files/access6.gno +++ b/gnovm/tests/files/access6.gno @@ -16,7 +16,7 @@ func main() { } // Error: -// main/files/access6.gno:15:2: main.mystruct does not implement gno.land/p/demo/testutils.PrivateInterface (missing method privateMethod) +// main/access6.gno:15:2-36: main.mystruct does not implement gno.land/p/demo/testutils.PrivateInterface (missing method privateMethod) // TypeCheckError: -// main/files/access6.gno:15:34: cannot use x (variable of struct type mystruct) as testutils.PrivateInterface value in argument to testutils.PrintPrivateInterface: mystruct does not implement testutils.PrivateInterface (unexported method privateMethod) +// main/access6.gno:15:34: cannot use x (variable of struct type mystruct) as testutils.PrivateInterface value in argument to testutils.PrintPrivateInterface: mystruct does not implement testutils.PrivateInterface (unexported method privateMethod) diff --git a/gnovm/tests/files/access7.gno b/gnovm/tests/files/access7.gno index 4e4d6edc312..74f3dfbb92f 100644 --- a/gnovm/tests/files/access7.gno +++ b/gnovm/tests/files/access7.gno @@ -20,7 +20,7 @@ func main() { } // Error: -// main/files/access7.gno:19:2: main.PrivateInterface2 does not implement gno.land/p/demo/testutils.PrivateInterface (missing method privateMethod) +// main/access7.gno:19:2-36: main.PrivateInterface2 does not implement gno.land/p/demo/testutils.PrivateInterface (missing method privateMethod) // TypeCheckError: -// main/files/access7.gno:19:34: cannot use x (variable of interface type PrivateInterface2) as testutils.PrivateInterface value in argument to testutils.PrintPrivateInterface: PrivateInterface2 does not implement testutils.PrivateInterface (missing method privateMethod) +// main/access7.gno:19:34: cannot use x (variable of interface type PrivateInterface2) as testutils.PrivateInterface value in argument to testutils.PrintPrivateInterface: PrivateInterface2 does not implement testutils.PrivateInterface (missing method privateMethod) diff --git a/gnovm/tests/files/add3.gno b/gnovm/tests/files/add3.gno index bb2645a3e09..20509f25dcd 100644 --- a/gnovm/tests/files/add3.gno +++ b/gnovm/tests/files/add3.gno @@ -6,7 +6,7 @@ func main() { } // Error: -// main/files/add3.gno:5:7: invalid operation: a + (const (undefined)) (mismatched types int and untyped nil) +// main/add3.gno:5:7-14: invalid operation: a + (const (undefined)) (mismatched types int and untyped nil) // TypeCheckError: -// main/files/add3.gno:5:7: invalid operation: a + nil (mismatched types int and untyped nil); main/files/add3.gno:5:2: declared and not used: i +// main/add3.gno:5:7: invalid operation: a + nil (mismatched types int and untyped nil); main/add3.gno:5:2: declared and not used: i diff --git a/gnovm/tests/files/addressable_10a_err.gno b/gnovm/tests/files/addressable_10a_err.gno index 29bd99016d6..27e74c68b0e 100644 --- a/gnovm/tests/files/addressable_10a_err.gno +++ b/gnovm/tests/files/addressable_10a_err.gno @@ -14,4 +14,4 @@ func getPtr() *S { // illegal assignment X expression type *gnolang.CallExpr // TypeCheckError: -// main/files/addressable_10a_err.gno:4:11: invalid operation: cannot take address of getPtr() (value of type *S) +// main/addressable_10a_err.gno:4:11: invalid operation: cannot take address of getPtr() (value of type *S) diff --git a/gnovm/tests/files/addressable_10b_err.gno b/gnovm/tests/files/addressable_10b_err.gno index 1007db5404c..ef8d28dbe45 100644 --- a/gnovm/tests/files/addressable_10b_err.gno +++ b/gnovm/tests/files/addressable_10b_err.gno @@ -12,4 +12,4 @@ func main() { // illegal assignment X expression type *gnolang.CallExpr // TypeCheckError: -// main/files/addressable_10b_err.gno:8:11: invalid operation: cannot take address of new(S) (value of type *S) +// main/addressable_10b_err.gno:8:11: invalid operation: cannot take address of new(S) (value of type *S) diff --git a/gnovm/tests/files/addressable_1a_err.gno b/gnovm/tests/files/addressable_1a_err.gno index ff52cc5d5c4..e1c2066680d 100644 --- a/gnovm/tests/files/addressable_1a_err.gno +++ b/gnovm/tests/files/addressable_1a_err.gno @@ -5,4 +5,4 @@ func main() { } // TypeCheckError: -// main/files/addressable_1a_err.gno:4:7: invalid operation: cannot take address of [1]int{…}[0] (value of type int) +// main/addressable_1a_err.gno:4:7: invalid operation: cannot take address of [1]int{…}[0] (value of type int) diff --git a/gnovm/tests/files/addressable_1b_err.gno b/gnovm/tests/files/addressable_1b_err.gno index b625f553117..279c68d0ac8 100644 --- a/gnovm/tests/files/addressable_1b_err.gno +++ b/gnovm/tests/files/addressable_1b_err.gno @@ -5,4 +5,4 @@ func main() { } // TypeCheckError: -// main/files/addressable_1b_err.gno:4:6: invalid operation: cannot slice [1]int{…} (value of type [1]int) (value not addressable) +// main/addressable_1b_err.gno:4:6: invalid operation: cannot slice [1]int{…} (value of type [1]int) (value not addressable) diff --git a/gnovm/tests/files/addressable_1c_rrr.gno b/gnovm/tests/files/addressable_1c_rrr.gno index fd22e3f2276..c089bed4bef 100644 --- a/gnovm/tests/files/addressable_1c_rrr.gno +++ b/gnovm/tests/files/addressable_1c_rrr.gno @@ -10,4 +10,4 @@ func getArr() [1]int { } // TypeCheckError: -// main/files/addressable_1c_rrr.gno:4:7: invalid operation: cannot take address of getArr()[0] (value of type int) +// main/addressable_1c_rrr.gno:4:7: invalid operation: cannot take address of getArr()[0] (value of type int) diff --git a/gnovm/tests/files/addressable_1d_err.gno b/gnovm/tests/files/addressable_1d_err.gno index be3c2b380a1..30b5005b770 100644 --- a/gnovm/tests/files/addressable_1d_err.gno +++ b/gnovm/tests/files/addressable_1d_err.gno @@ -9,4 +9,4 @@ func getArr() [1]int { } // TypeCheckError: -// main/files/addressable_1d_err.gno:4:6: invalid operation: cannot slice getArr() (value of type [1]int) (value not addressable) +// main/addressable_1d_err.gno:4:6: invalid operation: cannot slice getArr() (value of type [1]int) (value not addressable) diff --git a/gnovm/tests/files/addressable_2a_err.gno b/gnovm/tests/files/addressable_2a_err.gno index e27187f36df..61694ec202a 100644 --- a/gnovm/tests/files/addressable_2a_err.gno +++ b/gnovm/tests/files/addressable_2a_err.gno @@ -8,4 +8,4 @@ func main() { // illegal assignment X expression type *gnolang.SliceExpr // TypeCheckError: -// main/files/addressable_2a_err.gno:4:7: invalid operation: cannot take address of []int{…}[:] (value of type []int) +// main/addressable_2a_err.gno:4:7: invalid operation: cannot take address of []int{…}[:] (value of type []int) diff --git a/gnovm/tests/files/addressable_2b_err.gno b/gnovm/tests/files/addressable_2b_err.gno index 6bd40b83881..e7af94aa4ec 100644 --- a/gnovm/tests/files/addressable_2b_err.gno +++ b/gnovm/tests/files/addressable_2b_err.gno @@ -12,4 +12,4 @@ func getSlice() []int { // illegal assignment X expression type *gnolang.CallExpr // TypeCheckError: -// main/files/addressable_2b_err.gno:4:7: invalid operation: cannot take address of getSlice() (value of type []int) +// main/addressable_2b_err.gno:4:7: invalid operation: cannot take address of getSlice() (value of type []int) diff --git a/gnovm/tests/files/addressable_3a_err.gno b/gnovm/tests/files/addressable_3a_err.gno index 70a83dbe9ba..743c2453ea9 100644 --- a/gnovm/tests/files/addressable_3a_err.gno +++ b/gnovm/tests/files/addressable_3a_err.gno @@ -11,4 +11,4 @@ func main() { } // TypeCheckError: -// main/files/addressable_3a_err.gno:10:7: invalid operation: cannot take address of S{…}.i (value of type int) +// main/addressable_3a_err.gno:10:7: invalid operation: cannot take address of S{…}.i (value of type int) diff --git a/gnovm/tests/files/addressable_3b_err.gno b/gnovm/tests/files/addressable_3b_err.gno index 3b15a86efae..1cf2a37c3c3 100644 --- a/gnovm/tests/files/addressable_3b_err.gno +++ b/gnovm/tests/files/addressable_3b_err.gno @@ -13,4 +13,4 @@ func getStruct() S { } // TypeCheckError: -// main/files/addressable_3b_err.gno:8:7: invalid operation: cannot take address of getStruct().i (value of type int) +// main/addressable_3b_err.gno:8:7: invalid operation: cannot take address of getStruct().i (value of type int) diff --git a/gnovm/tests/files/addressable_3c_err.gno b/gnovm/tests/files/addressable_3c_err.gno index 637876386ae..8a446b952be 100644 --- a/gnovm/tests/files/addressable_3c_err.gno +++ b/gnovm/tests/files/addressable_3c_err.gno @@ -14,4 +14,4 @@ func main() { } // TypeCheckError: -// main/files/addressable_3c_err.gno:13:7: invalid operation: cannot take address of makeT().Mp (value of type *int) +// main/addressable_3c_err.gno:13:7: invalid operation: cannot take address of makeT().Mp (value of type *int) diff --git a/gnovm/tests/files/addressable_3d_err.gno b/gnovm/tests/files/addressable_3d_err.gno index 28eadef7a5a..bed727d9bcb 100644 --- a/gnovm/tests/files/addressable_3d_err.gno +++ b/gnovm/tests/files/addressable_3d_err.gno @@ -8,4 +8,4 @@ func main() { // illegal assignment X expression type *gnolang.RefExpr // TypeCheckError: -// main/files/addressable_3d_err.gno:4:7: invalid operation: cannot take address of (&struct{}{}) (value of type *struct{}) +// main/addressable_3d_err.gno:4:7: invalid operation: cannot take address of (&struct{}{}) (value of type *struct{}) diff --git a/gnovm/tests/files/addressable_4a_err.gno b/gnovm/tests/files/addressable_4a_err.gno index e088329c7eb..99ac914b8c6 100644 --- a/gnovm/tests/files/addressable_4a_err.gno +++ b/gnovm/tests/files/addressable_4a_err.gno @@ -6,4 +6,4 @@ func main() { } // TypeCheckError: -// main/files/addressable_4a_err.gno:5:7: invalid operation: cannot take address of greeting[2] (value of type byte) +// main/addressable_4a_err.gno:5:7: invalid operation: cannot take address of greeting[2] (value of type byte) diff --git a/gnovm/tests/files/addressable_5a_err_stdlibs.gno b/gnovm/tests/files/addressable_5a_err_stdlibs.gno index 7e6d1fc3f6e..1ff59bc38d1 100644 --- a/gnovm/tests/files/addressable_5a_err_stdlibs.gno +++ b/gnovm/tests/files/addressable_5a_err_stdlibs.gno @@ -11,4 +11,4 @@ func main() { // illegal assignment X expression type *gnolang.ConstExpr // TypeCheckError: -// main/files/addressable_5a_err_stdlibs.gno:7:7: invalid operation: cannot take address of math.MaxUint8 (untyped int constant 255) +// main/addressable_5a_err_stdlibs.gno:7:7: invalid operation: cannot take address of math.MaxUint8 (untyped int constant 255) diff --git a/gnovm/tests/files/addressable_5b_err_stdlibs.gno b/gnovm/tests/files/addressable_5b_err_stdlibs.gno index 1a50fb98c08..2cedc365020 100644 --- a/gnovm/tests/files/addressable_5b_err_stdlibs.gno +++ b/gnovm/tests/files/addressable_5b_err_stdlibs.gno @@ -11,4 +11,4 @@ func main() { // illegal assignment X expression type *gnolang.ConstExpr // TypeCheckError: -// main/files/addressable_5b_err_stdlibs.gno:7:7: invalid operation: cannot take address of std.BankerTypeReadonly (constant 0 of uint8 type std.BankerType) +// main/addressable_5b_err_stdlibs.gno:7:7: invalid operation: cannot take address of std.BankerTypeReadonly (constant 0 of uint8 type std.BankerType) diff --git a/gnovm/tests/files/addressable_5c_err.gno b/gnovm/tests/files/addressable_5c_err.gno index 37c541c30ac..00c7443edf5 100644 --- a/gnovm/tests/files/addressable_5c_err.gno +++ b/gnovm/tests/files/addressable_5c_err.gno @@ -10,4 +10,4 @@ func main() { // illegal assignment X expression type *gnolang.ConstExpr // TypeCheckError: -// main/files/addressable_5c_err.gno:6:7: invalid operation: cannot take address of a (untyped int constant 1) +// main/addressable_5c_err.gno:6:7: invalid operation: cannot take address of a (untyped int constant 1) diff --git a/gnovm/tests/files/addressable_5d_err.gno b/gnovm/tests/files/addressable_5d_err.gno index d854c01fb86..8c312369499 100644 --- a/gnovm/tests/files/addressable_5d_err.gno +++ b/gnovm/tests/files/addressable_5d_err.gno @@ -10,4 +10,4 @@ func main() { // illegal assignment X expression type *gnolang.ConstExpr // TypeCheckError: -// main/files/addressable_5d_err.gno:6:7: invalid operation: cannot take address of a (constant 1 of type int) +// main/addressable_5d_err.gno:6:7: invalid operation: cannot take address of a (constant 1 of type int) diff --git a/gnovm/tests/files/addressable_6a_err.gno b/gnovm/tests/files/addressable_6a_err.gno index c7b13c3b49e..22a184296cf 100644 --- a/gnovm/tests/files/addressable_6a_err.gno +++ b/gnovm/tests/files/addressable_6a_err.gno @@ -10,4 +10,4 @@ func main() { // illegal assignment X expression type *gnolang.TypeAssertExpr // TypeCheckError: -// main/files/addressable_6a_err.gno:6:11: invalid operation: cannot take address of i.(int) (comma, ok expression of type int) +// main/addressable_6a_err.gno:6:11: invalid operation: cannot take address of i.(int) (comma, ok expression of type int) diff --git a/gnovm/tests/files/addressable_6b_err.gno b/gnovm/tests/files/addressable_6b_err.gno index e75515b98f7..96e8a452086 100644 --- a/gnovm/tests/files/addressable_6b_err.gno +++ b/gnovm/tests/files/addressable_6b_err.gno @@ -14,4 +14,4 @@ func main() { // &(9 int) // TypeCheckError: -// main/files/addressable_6b_err.gno:10:11: invalid operation: cannot take address of i.(S).a (value of type int) +// main/addressable_6b_err.gno:10:11: invalid operation: cannot take address of i.(S).a (value of type int) diff --git a/gnovm/tests/files/addressable_6c_err.gno b/gnovm/tests/files/addressable_6c_err.gno index 27c9ea2e21f..addd7fcc09a 100644 --- a/gnovm/tests/files/addressable_6c_err.gno +++ b/gnovm/tests/files/addressable_6c_err.gno @@ -10,4 +10,4 @@ func main() { // &(1 int) // TypeCheckError: -// main/files/addressable_6c_err.gno:6:11: invalid operation: cannot take address of i.([1]int)[0] (value of type int) +// main/addressable_6c_err.gno:6:11: invalid operation: cannot take address of i.([1]int)[0] (value of type int) diff --git a/gnovm/tests/files/addressable_6d_err.gno b/gnovm/tests/files/addressable_6d_err.gno index 1342e4341ed..ab6d763cdc5 100644 --- a/gnovm/tests/files/addressable_6d_err.gno +++ b/gnovm/tests/files/addressable_6d_err.gno @@ -12,4 +12,4 @@ func getSlice() any { // illegal assignment X expression type *gnolang.TypeAssertExpr // TypeCheckError: -// main/files/addressable_6d_err.gno:4:7: invalid operation: cannot take address of getSlice().([]int) (comma, ok expression of type []int) +// main/addressable_6d_err.gno:4:7: invalid operation: cannot take address of getSlice().([]int) (comma, ok expression of type []int) diff --git a/gnovm/tests/files/addressable_7a_err.gno b/gnovm/tests/files/addressable_7a_err.gno index 2af4bad7a80..811e1a07daf 100644 --- a/gnovm/tests/files/addressable_7a_err.gno +++ b/gnovm/tests/files/addressable_7a_err.gno @@ -9,7 +9,7 @@ func main() { } // Error: -// main/files/addressable_7a_err.gno:8:2: getTypeOf() only supports *CallExpr with 1 result, got ([]int,[]string) +// main/addressable_7a_err.gno:8:2-12: getTypeOf() only supports *CallExpr with 1 result, got ([]int,[]string) // TypeCheckError: -// main/files/addressable_7a_err.gno:8:7: multiple-value foo() (value of type ([]int, []string)) in single-value context +// main/addressable_7a_err.gno:8:7: multiple-value foo() (value of type ([]int, []string)) in single-value context diff --git a/gnovm/tests/files/addressable_7b_err.gno b/gnovm/tests/files/addressable_7b_err.gno index c86f65127dc..7655aecc595 100644 --- a/gnovm/tests/files/addressable_7b_err.gno +++ b/gnovm/tests/files/addressable_7b_err.gno @@ -5,7 +5,7 @@ func main() { } // Error: -// main/files/addressable_7b_err.gno:4:2: RHS should not be &((const (9 int))) when len(Lhs) > len(Rhs) +// main/addressable_7b_err.gno:4:2-16: RHS should not be &((const (9 int))) when len(Lhs) > len(Rhs) // TypeCheckError: -// main/files/addressable_7b_err.gno:4:10: invalid operation: cannot take address of int(9) (constant 9 of type int) +// main/addressable_7b_err.gno:4:10: invalid operation: cannot take address of int(9) (constant 9 of type int) diff --git a/gnovm/tests/files/addressable_8a_err.gno b/gnovm/tests/files/addressable_8a_err.gno index 61be68ee8aa..fd5e1e23ef7 100644 --- a/gnovm/tests/files/addressable_8a_err.gno +++ b/gnovm/tests/files/addressable_8a_err.gno @@ -8,4 +8,4 @@ func main() { // illegal assignment X expression type *gnolang.FuncLitExpr // TypeCheckError: -// main/files/addressable_8a_err.gno:4:7: invalid operation: cannot take address of (func() literal) (value of type func()) +// main/addressable_8a_err.gno:4:7: invalid operation: cannot take address of (func() literal) (value of type func()) diff --git a/gnovm/tests/files/addressable_9a_err.gno b/gnovm/tests/files/addressable_9a_err.gno index dc2af72c314..321371a641f 100644 --- a/gnovm/tests/files/addressable_9a_err.gno +++ b/gnovm/tests/files/addressable_9a_err.gno @@ -10,4 +10,4 @@ func main() { // &(5 int) // TypeCheckError: -// main/files/addressable_9a_err.gno:6:11: invalid operation: cannot take address of m[4] (map index expression of type int) +// main/addressable_9a_err.gno:6:11: invalid operation: cannot take address of m[4] (map index expression of type int) diff --git a/gnovm/tests/files/addressable_9b_err.gno b/gnovm/tests/files/addressable_9b_err.gno index e8b8bad51ef..bccd3b2a035 100644 --- a/gnovm/tests/files/addressable_9b_err.gno +++ b/gnovm/tests/files/addressable_9b_err.gno @@ -15,4 +15,4 @@ func main() { // &(7 int) // TypeCheckError: -// main/files/addressable_9b_err.gno:11:11: invalid operation: cannot take address of mmm[3][3].i (value of type int) +// main/addressable_9b_err.gno:11:11: invalid operation: cannot take address of mmm[3][3].i (value of type int) diff --git a/gnovm/tests/files/alloc_0.gno b/gnovm/tests/files/alloc_0.gno index 5b3fb2662b7..29ba33d6b5f 100644 --- a/gnovm/tests/files/alloc_0.gno +++ b/gnovm/tests/files/alloc_0.gno @@ -16,7 +16,7 @@ func main() { } // Output: -// MemStats: Allocator{maxBytes:100000000, bytes:6358} +// MemStats: Allocator{maxBytes:100000000, bytes:6346} // TypeCheckError: -// main/files/alloc_0.gno:13:2: declared and not used: f1 +// main/alloc_0.gno:13:2: declared and not used: f1 diff --git a/gnovm/tests/files/alloc_1.gno b/gnovm/tests/files/alloc_1.gno index 90f6d1b7824..fe78d98c8ce 100644 --- a/gnovm/tests/files/alloc_1.gno +++ b/gnovm/tests/files/alloc_1.gno @@ -21,7 +21,7 @@ func main() { } // Output: -// MemStats: Allocator{maxBytes:100000000, bytes:7608} +// MemStats: Allocator{maxBytes:100000000, bytes:7596} // TypeCheckError: -// main/files/alloc_1.gno:18:2: declared and not used: S1 +// main/alloc_1.gno:18:2: declared and not used: S1 diff --git a/gnovm/tests/files/alloc_2.gno b/gnovm/tests/files/alloc_2.gno index c2edc5e50f8..ce035e8418c 100644 --- a/gnovm/tests/files/alloc_2.gno +++ b/gnovm/tests/files/alloc_2.gno @@ -13,4 +13,4 @@ func main() { // allocation limit exceeded // TypeCheckError: -// main/files/alloc_2.gno:8:2: declared and not used: data +// main/alloc_2.gno:8:2: declared and not used: data diff --git a/gnovm/tests/files/alloc_3.gno b/gnovm/tests/files/alloc_3.gno index 473bdd17b0d..49e8c4518bd 100644 --- a/gnovm/tests/files/alloc_3.gno +++ b/gnovm/tests/files/alloc_3.gno @@ -11,7 +11,7 @@ func main() { } // Output: -// MemStats after GC: Allocator{maxBytes:110000000, bytes:5704} +// MemStats after GC: Allocator{maxBytes:110000000, bytes:5692} // TypeCheckError: -// main/files/alloc_3.gno:7:2: declared and not used: data +// main/alloc_3.gno:7:2: declared and not used: data diff --git a/gnovm/tests/files/alloc_4.gno b/gnovm/tests/files/alloc_4.gno index c6abcb497f6..51181950db4 100644 --- a/gnovm/tests/files/alloc_4.gno +++ b/gnovm/tests/files/alloc_4.gno @@ -22,5 +22,5 @@ func main() { } // Output: -// memstats in main after first GC: Allocator{maxBytes:50000, bytes:11438} -// memstats in main after second GC: Allocator{maxBytes:50000, bytes:7069} +// memstats in main after first GC: Allocator{maxBytes:50000, bytes:11426} +// memstats in main after second GC: Allocator{maxBytes:50000, bytes:7057} diff --git a/gnovm/tests/files/alloc_5.gno b/gnovm/tests/files/alloc_5.gno index 06689499924..7bc5838353b 100644 --- a/gnovm/tests/files/alloc_5.gno +++ b/gnovm/tests/files/alloc_5.gno @@ -5,6 +5,9 @@ import "runtime" func gen() { data := make([]byte, 50*1024*1024) + if false { + println(data) + } } // this is mainly for gas usage check @@ -19,7 +22,4 @@ func main() { } // Output: -// memstats in main after GC: Allocator{maxBytes:100000000, bytes:6048} - -// TypeCheckError: -// main/files/alloc_5.gno:7:2: declared and not used: data +// memstats in main after GC: Allocator{maxBytes:100000000, bytes:6036} diff --git a/gnovm/tests/files/alloc_6.gno b/gnovm/tests/files/alloc_6.gno index 8ed11220473..70e0264f83e 100644 --- a/gnovm/tests/files/alloc_6.gno +++ b/gnovm/tests/files/alloc_6.gno @@ -7,13 +7,13 @@ func main() { var a = func() int { return 1 } + if false { + a() + } runtime.GC() println("memstats in main after GC: ", runtime.MemStats()) } // Output: -// memstats in main after GC: Allocator{maxBytes:100000000, bytes:6048} - -// TypeCheckError: -// main/files/alloc_6.gno:7:6: declared and not used: a +// memstats in main after GC: Allocator{maxBytes:100000000, bytes:6036} diff --git a/gnovm/tests/files/alloc_6a.gno b/gnovm/tests/files/alloc_6a.gno index aa34b938bc6..4f400a43dd9 100644 --- a/gnovm/tests/files/alloc_6a.gno +++ b/gnovm/tests/files/alloc_6a.gno @@ -8,6 +8,9 @@ func main() { var a = func() int { return 1 } + if false { + a() + } runtime.GC() } @@ -15,7 +18,4 @@ func main() { } // Output: -// memstats in main after GC: Allocator{maxBytes:100000000, bytes:6554} - -// TypeCheckError: -// main/files/alloc_6a.gno:8:7: declared and not used: a +// memstats in main after GC: Allocator{maxBytes:100000000, bytes:6542} diff --git a/gnovm/tests/files/alloc_7.gno b/gnovm/tests/files/alloc_7.gno index a4607f15700..ad746975fb3 100644 --- a/gnovm/tests/files/alloc_7.gno +++ b/gnovm/tests/files/alloc_7.gno @@ -13,7 +13,7 @@ func main() { } // Output: -// MemStats: Allocator{maxBytes:100000000, bytes:5888} +// MemStats: Allocator{maxBytes:100000000, bytes:5876} // TypeCheckError: -// main/files/alloc_7.gno:10:2: declared and not used: s1 +// main/alloc_7.gno:10:2: declared and not used: s1 diff --git a/gnovm/tests/files/array3.gno b/gnovm/tests/files/array3.gno index 8402bbb32b8..78272fcc6ee 100644 --- a/gnovm/tests/files/array3.gno +++ b/gnovm/tests/files/array3.gno @@ -11,4 +11,4 @@ func main() { // runtime error: index out of range [3] with length 3 // TypeCheckError: -// main/files/array3.gno:6:20: index 3 is out of bounds (>= 3) +// main/array3.gno:6:20: index 3 is out of bounds (>= 3) diff --git a/gnovm/tests/files/array4.gno b/gnovm/tests/files/array4.gno index 3e6d2ca2f92..6892022abfb 100644 --- a/gnovm/tests/files/array4.gno +++ b/gnovm/tests/files/array4.gno @@ -8,4 +8,4 @@ func main() { // duplicate index 2 in array or slice literal // TypeCheckError: -// main/files/array4.gno:4:26: duplicate index 2 in array or slice literal; main/files/array4.gno:4:2: declared and not used: a +// main/array4.gno:4:26: duplicate index 2 in array or slice literal; main/array4.gno:4:2: declared and not used: a diff --git a/gnovm/tests/files/array5.gno b/gnovm/tests/files/array5.gno index 922cfd6c705..0ef5bd66451 100644 --- a/gnovm/tests/files/array5.gno +++ b/gnovm/tests/files/array5.gno @@ -8,4 +8,4 @@ func main() { // duplicate index 1 in array or slice literal // TypeCheckError: -// main/files/array5.gno:4:20: duplicate index 1 in array or slice literal; main/files/array5.gno:4:2: declared and not used: a +// main/array5.gno:4:20: duplicate index 1 in array or slice literal; main/array5.gno:4:2: declared and not used: a diff --git a/gnovm/tests/files/assign11.gno b/gnovm/tests/files/assign11.gno index 8f6f22607ad..a3f5b82c850 100644 --- a/gnovm/tests/files/assign11.gno +++ b/gnovm/tests/files/assign11.gno @@ -7,7 +7,7 @@ func main() { } // Error: -// main/files/assign11.gno:6:2: assignment mismatch: 3 variables but fmt.Println returns 2 values +// main/assign11.gno:6:2-31: assignment mismatch: 3 variables but fmt.Println returns 2 values // TypeCheckError: -// main/files/assign11.gno:6:12: assignment mismatch: 3 variables but fmt.Println returns 2 values +// main/assign11.gno:6:12: assignment mismatch: 3 variables but fmt.Println returns 2 values diff --git a/gnovm/tests/files/assign12.gno b/gnovm/tests/files/assign12.gno index b139c6b12ad..6b510dc8ab2 100644 --- a/gnovm/tests/files/assign12.gno +++ b/gnovm/tests/files/assign12.gno @@ -8,7 +8,7 @@ func main() { } // Error: -// main/files/assign12.gno:6:2: assignment mismatch: 3 variables but fmt.Println returns 2 values +// main/assign12.gno:6:2-32: assignment mismatch: 3 variables but fmt.Println returns 2 values // TypeCheckError: -// main/files/assign12.gno:6:13: assignment mismatch: 3 variables but fmt.Println returns 2 values +// main/assign12.gno:6:13: assignment mismatch: 3 variables but fmt.Println returns 2 values diff --git a/gnovm/tests/files/assign22.gno b/gnovm/tests/files/assign22.gno index e52d04d66c3..8e214e3e73c 100644 --- a/gnovm/tests/files/assign22.gno +++ b/gnovm/tests/files/assign22.gno @@ -9,7 +9,7 @@ func main() { } // Error: -// main/files/assign22.gno:7:2: assignment operator <<= requires only one expression on lhs and rhs +// main/assign22.gno:7:2-18: assignment operator <<= requires only one expression on lhs and rhs // TypeCheckError: -// main/files/assign22.gno:7:8: assignment operation <<= requires single-valued expressions; main/files/assign22.gno:4:2: declared and not used: m +// main/assign22.gno:7:8: assignment operation <<= requires single-valued expressions; main/assign22.gno:4:2: declared and not used: m diff --git a/gnovm/tests/files/assign23.gno b/gnovm/tests/files/assign23.gno index 3f35605c428..7c1a3f8e0dd 100644 --- a/gnovm/tests/files/assign23.gno +++ b/gnovm/tests/files/assign23.gno @@ -9,7 +9,7 @@ func main() { } // Error: -// main/files/assign23.gno:7:2: assignment operator += requires only one expression on lhs and rhs +// main/assign23.gno:7:2-17: assignment operator += requires only one expression on lhs and rhs // TypeCheckError: -// main/files/assign23.gno:7:8: assignment operation += requires single-valued expressions; main/files/assign23.gno:4:2: declared and not used: m +// main/assign23.gno:7:8: assignment operation += requires single-valued expressions; main/assign23.gno:4:2: declared and not used: m diff --git a/gnovm/tests/files/assign24.gno b/gnovm/tests/files/assign24.gno index 9b9ce01c0bc..4a61095be61 100644 --- a/gnovm/tests/files/assign24.gno +++ b/gnovm/tests/files/assign24.gno @@ -5,7 +5,7 @@ func main() { } // Error: -// main/files/assign24.gno:4:2: assignment mismatch: 2 variable(s) but 1 value(s) +// main/assign24.gno:4:2-11: assignment mismatch: 2 variable(s) but 1 value(s) // TypeCheckError: -// main/files/assign24.gno:4:10: assignment mismatch: 2 variables but 1 value; main/files/assign24.gno:4:2: declared and not used: a; main/files/assign24.gno:4:5: declared and not used: b +// main/assign24.gno:4:10: assignment mismatch: 2 variables but 1 value; main/assign24.gno:4:2: declared and not used: a; main/assign24.gno:4:5: declared and not used: b diff --git a/gnovm/tests/files/assign25.gno b/gnovm/tests/files/assign25.gno index 73e79575f1f..011c84375db 100644 --- a/gnovm/tests/files/assign25.gno +++ b/gnovm/tests/files/assign25.gno @@ -11,7 +11,7 @@ func main() { } // Error: -// main/files/assign25.gno:8:2: assignment mismatch: 3 variable(s) but 2 value(s) +// main/assign25.gno:8:2-21: assignment mismatch: 3 variable(s) but 2 value(s) // TypeCheckError: -// main/files/assign25.gno:8:13: assignment mismatch: 3 variables but 2 values +// main/assign25.gno:8:13: assignment mismatch: 3 variables but 2 values diff --git a/gnovm/tests/files/assign25b.gno b/gnovm/tests/files/assign25b.gno index 7e1fbd77fea..567949d2951 100644 --- a/gnovm/tests/files/assign25b.gno +++ b/gnovm/tests/files/assign25b.gno @@ -11,7 +11,7 @@ func main() { } // Error: -// main/files/assign25b.gno:8:2: assignment mismatch: 3 variable(s) but 4 value(s) +// main/assign25b.gno:8:2-27: assignment mismatch: 3 variable(s) but 4 value(s) // TypeCheckError: -// main/files/assign25b.gno:8:13: assignment mismatch: 3 variables but 4 values +// main/assign25b.gno:8:13: assignment mismatch: 3 variables but 4 values diff --git a/gnovm/tests/files/assign25c.gno b/gnovm/tests/files/assign25c.gno index 8143c93580a..ba41e534aeb 100644 --- a/gnovm/tests/files/assign25c.gno +++ b/gnovm/tests/files/assign25c.gno @@ -12,7 +12,7 @@ func main() { } // Error: -// main/files/assign25c.gno:10:2: assignment mismatch: 3 variable(s) but 2 value(s) +// main/assign25c.gno:10:2-19: assignment mismatch: 3 variable(s) but 2 value(s) // TypeCheckError: -// main/files/assign25c.gno:10:13: assignment mismatch: 3 variables but 2 values +// main/assign25c.gno:10:13: assignment mismatch: 3 variables but 2 values diff --git a/gnovm/tests/files/assign25d.gno b/gnovm/tests/files/assign25d.gno index 7f74b8ef779..73e25b50026 100644 --- a/gnovm/tests/files/assign25d.gno +++ b/gnovm/tests/files/assign25d.gno @@ -12,7 +12,7 @@ func main() { } // Error: -// main/files/assign25d.gno:10:2: assignment mismatch: 3 variable(s) but 4 value(s) +// main/assign25d.gno:10:2-25: assignment mismatch: 3 variable(s) but 4 value(s) // TypeCheckError: -// main/files/assign25d.gno:10:13: assignment mismatch: 3 variables but 4 values +// main/assign25d.gno:10:13: assignment mismatch: 3 variables but 4 values diff --git a/gnovm/tests/files/assign26.gno b/gnovm/tests/files/assign26.gno index 5feda78e47b..993f7914e41 100644 --- a/gnovm/tests/files/assign26.gno +++ b/gnovm/tests/files/assign26.gno @@ -6,7 +6,7 @@ func main() { } // Error: -// main/files/assign26.gno:5:2: assignment mismatch: 3 variable(s) but 1 value(s) +// main/assign26.gno:5:2-20: assignment mismatch: 3 variable(s) but 1 value(s) // TypeCheckError: -// main/files/assign26.gno:5:13: assignment mismatch: 3 variables but 1 value; main/files/assign26.gno:5:2: declared and not used: a; main/files/assign26.gno:5:5: declared and not used: b; main/files/assign26.gno:5:8: declared and not used: c +// main/assign26.gno:5:13: assignment mismatch: 3 variables but 1 value; main/assign26.gno:5:2: declared and not used: a; main/assign26.gno:5:5: declared and not used: b; main/assign26.gno:5:8: declared and not used: c diff --git a/gnovm/tests/files/assign27.gno b/gnovm/tests/files/assign27.gno index 8130c6b1902..bdd17cb7b5f 100644 --- a/gnovm/tests/files/assign27.gno +++ b/gnovm/tests/files/assign27.gno @@ -6,7 +6,7 @@ func main() { } // Error: -// main/files/assign27.gno:5:2: assignment mismatch: 3 variable(s) but 1 value(s) +// main/assign27.gno:5:2-17: assignment mismatch: 3 variable(s) but 1 value(s) // TypeCheckError: -// main/files/assign27.gno:5:13: assignment mismatch: 3 variables but 1 value; main/files/assign27.gno:5:2: declared and not used: a; main/files/assign27.gno:5:5: declared and not used: b; main/files/assign27.gno:5:8: declared and not used: c +// main/assign27.gno:5:13: assignment mismatch: 3 variables but 1 value; main/assign27.gno:5:2: declared and not used: a; main/assign27.gno:5:5: declared and not used: b; main/assign27.gno:5:8: declared and not used: c diff --git a/gnovm/tests/files/assign28.gno b/gnovm/tests/files/assign28.gno index 544e2a14756..1c292af338c 100644 --- a/gnovm/tests/files/assign28.gno +++ b/gnovm/tests/files/assign28.gno @@ -8,7 +8,7 @@ func main() { } // Error: -// main/files/assign28.gno:6:2: assignment mismatch: 2 variable(s) but 3 value(s) +// main/assign28.gno:6:2-17: assignment mismatch: 2 variable(s) but 3 value(s) // TypeCheckError: -// main/files/assign28.gno:6:10: assignment mismatch: 2 variables but 3 values +// main/assign28.gno:6:10: assignment mismatch: 2 variables but 3 values diff --git a/gnovm/tests/files/assign29.gno b/gnovm/tests/files/assign29.gno index 476eedefd4c..2045750791a 100644 --- a/gnovm/tests/files/assign29.gno +++ b/gnovm/tests/files/assign29.gno @@ -5,7 +5,7 @@ func main() { } // Error: -// main/files/assign29.gno:4:2: struct{} (type) is not an expression +// main/assign29.gno:4:2-15: struct{} (type) is not an expression // TypeCheckError: -// main/files/assign29.gno:4:7: struct{} (type) is not an expression; main/files/assign29.gno:4:2: declared and not used: t +// main/assign29.gno:4:7: struct{} (type) is not an expression; main/assign29.gno:4:2: declared and not used: t diff --git a/gnovm/tests/files/assign29_native.gno b/gnovm/tests/files/assign29_native.gno index 04f385d4b00..2aa52335610 100644 --- a/gnovm/tests/files/assign29_native.gno +++ b/gnovm/tests/files/assign29_native.gno @@ -14,4 +14,4 @@ func main() { // cannot directly modify readonly tainted object (w/o method): (const (ref(time) package{})).Now // TypeCheckError: -// main/files/assign29_native.gno:8:2: use of package time not in selector; main/files/assign29_native.gno:8:2: cannot assign to time.Now (neither addressable nor a map index expression) +// main/assign29_native.gno:8:2: use of package time not in selector; main/assign29_native.gno:8:2: cannot assign to time.Now (neither addressable nor a map index expression) diff --git a/gnovm/tests/files/assign30.gno b/gnovm/tests/files/assign30.gno index 12ddb6f5b45..a4c40205021 100644 --- a/gnovm/tests/files/assign30.gno +++ b/gnovm/tests/files/assign30.gno @@ -5,7 +5,7 @@ func main() { } // Error: -// main/files/assign30.gno:4:2: *struct{} (type) is not an expression +// main/assign30.gno:4:2-16: *struct{} (type) is not an expression // TypeCheckError: -// main/files/assign30.gno:4:7: *struct{} (type) is not an expression; main/files/assign30.gno:4:2: declared and not used: t +// main/assign30.gno:4:7: *struct{} (type) is not an expression; main/assign30.gno:4:2: declared and not used: t diff --git a/gnovm/tests/files/assign31.gno b/gnovm/tests/files/assign31.gno index c251957d34a..a9fc7332144 100644 --- a/gnovm/tests/files/assign31.gno +++ b/gnovm/tests/files/assign31.gno @@ -6,7 +6,7 @@ func main() { } // Error: -// main/files/assign31.gno:4:2: use of untyped nil in assignment +// main/assign31.gno:4:2-10: use of untyped nil in assignment // TypeCheckError: -// main/files/assign31.gno:4:7: use of untyped nil in assignment +// main/assign31.gno:4:7: use of untyped nil in assignment diff --git a/gnovm/tests/files/assign33.gno b/gnovm/tests/files/assign33.gno index fdf5c2b3e42..a73de8c10cf 100644 --- a/gnovm/tests/files/assign33.gno +++ b/gnovm/tests/files/assign33.gno @@ -10,7 +10,7 @@ func main() { } // Error: -// main/files/assign33.gno:8:6: cannot use foo() (value of type bool) as int value in assignment +// main/assign33.gno:8:6-22: cannot use foo() (value of type bool) as int value in assignment // TypeCheckError: -// main/files/assign33.gno:8:17: cannot use foo() (value of type bool) as int value in assignment +// main/assign33.gno:8:17: cannot use foo() (value of type bool) as int value in assignment diff --git a/gnovm/tests/files/assign35.gno b/gnovm/tests/files/assign35.gno index e4c7aa59c04..6c25e774b6e 100644 --- a/gnovm/tests/files/assign35.gno +++ b/gnovm/tests/files/assign35.gno @@ -11,7 +11,7 @@ func main() { } // Error: -// main/files/assign35.gno:8:2: multiple-value foo (value of type [int bool]) in single-value context +// main/assign35.gno:8:2-18: multiple-value foo (value of type [int bool]) in single-value context // TypeCheckError: -// main/files/assign35.gno:8:13: multiple-value foo() (value of type (int, bool)) in single-value context +// main/assign35.gno:8:13: multiple-value foo() (value of type (int, bool)) in single-value context diff --git a/gnovm/tests/files/assign37.gno b/gnovm/tests/files/assign37.gno index be26a7e5993..f7ceb3f1e1c 100644 --- a/gnovm/tests/files/assign37.gno +++ b/gnovm/tests/files/assign37.gno @@ -7,7 +7,7 @@ func main() { } // Error: -// main/files/assign37.gno:6:2: f (no value) used as value +// main/assign37.gno:6:2-10: f (no value) used as value // TypeCheckError: -// main/files/assign37.gno:6:7: f() (no value) used as value; main/files/assign37.gno:6:2: declared and not used: a +// main/assign37.gno:6:7: f() (no value) used as value; main/assign37.gno:6:2: declared and not used: a diff --git a/gnovm/tests/files/assign37b.gno b/gnovm/tests/files/assign37b.gno index 8ccc1548f80..7508ea65c52 100644 --- a/gnovm/tests/files/assign37b.gno +++ b/gnovm/tests/files/assign37b.gno @@ -9,7 +9,7 @@ func main() { } // Error: -// main/files/assign37b.gno:8:2: f (no value) used as value +// main/assign37b.gno:8:2-18: f (no value) used as value // TypeCheckError: -// main/files/assign37b.gno:8:10: f() (no value) used as value; main/files/assign37b.gno:8:15: f() (no value) used as value; main/files/assign37b.gno:8:2: declared and not used: a; main/files/assign37b.gno:8:5: declared and not used: b; main/files/assign37b.gno:3:8: "fmt" imported and not used +// main/assign37b.gno:8:10: f() (no value) used as value; main/assign37b.gno:8:15: f() (no value) used as value; main/assign37b.gno:8:2: declared and not used: a; main/assign37b.gno:8:5: declared and not used: b; main/assign37b.gno:3:8: "fmt" imported and not used diff --git a/gnovm/tests/files/assign38.gno b/gnovm/tests/files/assign38.gno index 43722b36958..b19a367161c 100644 --- a/gnovm/tests/files/assign38.gno +++ b/gnovm/tests/files/assign38.gno @@ -7,7 +7,7 @@ func main() { } // Error: -// main/files/assign38.gno:5:2: cannot use nil as int value in assignment +// main/assign38.gno:5:2-9: cannot use nil as int value in assignment // TypeCheckError: -// main/files/assign38.gno:5:6: cannot use nil as int value in assignment +// main/assign38.gno:5:6: cannot use nil as int value in assignment diff --git a/gnovm/tests/files/assign_unnamed_type/append/named_unnamed_type2_filetest.gno b/gnovm/tests/files/assign_unnamed_type/append/named_unnamed_type2_filetest.gno index bbd9e00919f..e6d78418338 100644 --- a/gnovm/tests/files/assign_unnamed_type/append/named_unnamed_type2_filetest.gno +++ b/gnovm/tests/files/assign_unnamed_type/append/named_unnamed_type2_filetest.gno @@ -13,4 +13,7 @@ func main() { } // Error: -// main/files/assign_unnamed_type/append/named_unnamed_type2_filetest.gno:11:7: cannot use int as int64 +// main/named_unnamed_type2_filetest.gno:11:7-32: cannot use int as int64 + +// TypeCheckError: +// main/named_unnamed_type2_filetest.gno:11:23: cannot use nlist (variable of slice type nat) as []int64 value in argument to append 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 e41e6c6f21f..4653b6eaa11 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,7 @@ func main() { } // Error: -// main/files/assign_unnamed_type/method/declaredType6_filetest.gno:15:2: cannot use []main.c as []main.word +// main/declaredType6_filetest.gno:15:2-14: cannot use []main.c as []main.word + +// TypeCheckError: +// main/declaredType6_filetest.gno:15:8: cannot use []c{…} (value of type []c) as nat value in assignment 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 673c48725b8..c31ccccaa09 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,7 @@ func main() { } // Error: -// main/files/assign_unnamed_type/method/declaredType6b_filetest.gno:15:2: cannot use []uint as []main.word +// main/declaredType6b_filetest.gno:15:2-17: cannot use []uint as []main.word + +// TypeCheckError: +// main/declaredType6b_filetest.gno:15:8: cannot use []uint{…} (value of type []uint) as nat value in assignment diff --git a/gnovm/tests/files/assign_unnamed_type/more/assgin_interface2_filetest.gno b/gnovm/tests/files/assign_unnamed_type/more/assgin_interface2_filetest.gno index c30933f45ba..b1ba2d20283 100644 --- a/gnovm/tests/files/assign_unnamed_type/more/assgin_interface2_filetest.gno +++ b/gnovm/tests/files/assign_unnamed_type/more/assgin_interface2_filetest.gno @@ -12,3 +12,6 @@ func main() { // Output: // (slice[(1 int)] main.nat) + +// TypeCheckError: +// main/assgin_interface2_filetest.gno:6:6: declared and not used: a diff --git a/gnovm/tests/files/assign_unnamed_type/more/assgin_two_filetest.gno b/gnovm/tests/files/assign_unnamed_type/more/assgin_two_filetest.gno index b2cdc14ff77..05b29671e0c 100644 --- a/gnovm/tests/files/assign_unnamed_type/more/assgin_two_filetest.gno +++ b/gnovm/tests/files/assign_unnamed_type/more/assgin_two_filetest.gno @@ -15,4 +15,7 @@ func main() { } // Error: -// main/files/assign_unnamed_type/more/assgin_two_filetest.gno:11:2: cannot use main.nat2 as main.nat without explicit conversion +// main/assgin_two_filetest.gno:11:2-7: cannot use main.nat2 as main.nat without explicit conversion + +// TypeCheckError: +// main/assgin_two_filetest.gno:11:6: cannot use b (variable of slice type nat2) as nat value in assignment diff --git a/gnovm/tests/files/assign_unnamed_type/more/errors2_filetest.gno b/gnovm/tests/files/assign_unnamed_type/more/errors2_filetest.gno index 2588b904a77..d41550994e5 100644 --- a/gnovm/tests/files/assign_unnamed_type/more/errors2_filetest.gno +++ b/gnovm/tests/files/assign_unnamed_type/more/errors2_filetest.gno @@ -15,3 +15,6 @@ func main() { // Output: // some error + +// TypeCheckError: +// main/errors2_filetest.gno:12:2: declared and not used: b diff --git a/gnovm/tests/files/assign_unnamed_type/more/return_interface1_filetest.gno b/gnovm/tests/files/assign_unnamed_type/more/return_interface1_filetest.gno index 7b6be664d96..03cee01a97f 100644 --- a/gnovm/tests/files/assign_unnamed_type/more/return_interface1_filetest.gno +++ b/gnovm/tests/files/assign_unnamed_type/more/return_interface1_filetest.gno @@ -12,4 +12,7 @@ func main() { } // Error: -// main/files/assign_unnamed_type/more/return_interface1_filetest.gno:10:2: cannot use interface {} as uint +// main/return_interface1_filetest.gno:10:2-10: cannot use interface {} as uint + +// TypeCheckError: +// main/return_interface1_filetest.gno:10:6: cannot use x1() (value of interface type any) as uint value in assignment: need type assertion; main/return_interface1_filetest.gno:9:6: declared and not used: a diff --git a/gnovm/tests/files/assign_unnamed_type/more/return_interface_filetest.gno b/gnovm/tests/files/assign_unnamed_type/more/return_interface_filetest.gno index 4fcc90eaa83..bd4eb6e480a 100644 --- a/gnovm/tests/files/assign_unnamed_type/more/return_interface_filetest.gno +++ b/gnovm/tests/files/assign_unnamed_type/more/return_interface_filetest.gno @@ -16,4 +16,7 @@ func main() { } // Error: -// main/files/assign_unnamed_type/more/return_interface_filetest.gno:13:2: cannot use interface {} as []int +// main/return_interface_filetest.gno:13:2-9: cannot use interface {} as []int + +// TypeCheckError: +// main/return_interface_filetest.gno:13:6: cannot use x() (value of interface type any) as nat value in assignment: need type assertion diff --git a/gnovm/tests/files/assign_unnamed_type/unnamedtype0b_filetest.gno b/gnovm/tests/files/assign_unnamed_type/unnamedtype0b_filetest.gno index 0c7b03df575..eec32dd2b7c 100644 --- a/gnovm/tests/files/assign_unnamed_type/unnamedtype0b_filetest.gno +++ b/gnovm/tests/files/assign_unnamed_type/unnamedtype0b_filetest.gno @@ -14,4 +14,7 @@ func main() { } // Error: -// main/files/assign_unnamed_type/unnamedtype0b_filetest.gno:11:2: cannot use []main.word as []int +// main/unnamedtype0b_filetest.gno:11:2-7: cannot use []main.word as []int + +// TypeCheckError: +// main/unnamedtype0b_filetest.gno:11:6: cannot use b (variable of type []word) as nat value in assignment diff --git a/gnovm/tests/files/blankidentifier0.gno b/gnovm/tests/files/blankidentifier0.gno index 83ccc62c8b2..02971c881dd 100644 --- a/gnovm/tests/files/blankidentifier0.gno +++ b/gnovm/tests/files/blankidentifier0.gno @@ -5,7 +5,7 @@ func main() { } // Error: -// main/files/blankidentifier0.gno:4:6: cannot use _ as value or type +// main/blankidentifier0.gno:4:6-7: cannot use _ as value or type // TypeCheckError: -// main/files/blankidentifier0.gno:4:6: cannot use _ as value or type +// main/blankidentifier0.gno:4:6: cannot use _ as value or type diff --git a/gnovm/tests/files/blankidentifier2.gno b/gnovm/tests/files/blankidentifier2.gno index aff69d225c5..d579d7c0096 100644 --- a/gnovm/tests/files/blankidentifier2.gno +++ b/gnovm/tests/files/blankidentifier2.gno @@ -6,7 +6,7 @@ func main() { } // Error: -// main/files/blankidentifier2.gno:4:6: cannot use _ as value or type +// main/blankidentifier2.gno:4:6-9: cannot use _ as value or type // TypeCheckError: -// main/files/blankidentifier2.gno:4:8: cannot use _ as value or type +// main/blankidentifier2.gno:4:8: cannot use _ as value or type diff --git a/gnovm/tests/files/blankidentifier3.gno b/gnovm/tests/files/blankidentifier3.gno index 794c5034350..36afc0a5c99 100644 --- a/gnovm/tests/files/blankidentifier3.gno +++ b/gnovm/tests/files/blankidentifier3.gno @@ -7,7 +7,7 @@ func main() { } // Error: -// main/files/blankidentifier3.gno:3:6: cannot use _ as value or type +// main/blankidentifier3.gno:3:6-9: cannot use _ as value or type // TypeCheckError: -// main/files/blankidentifier3.gno:3:8: cannot use _ as value or type +// main/blankidentifier3.gno:3:8: cannot use _ as value or type diff --git a/gnovm/tests/files/blankidentifier6.gno b/gnovm/tests/files/blankidentifier6.gno index 531a520491d..4f865f865a7 100644 --- a/gnovm/tests/files/blankidentifier6.gno +++ b/gnovm/tests/files/blankidentifier6.gno @@ -21,7 +21,7 @@ func main() { } // Error: -// main/files/blankidentifier6.gno:18:13: cannot use _ as value or type +// main/blankidentifier6.gno:18:13-14: cannot use _ as value or type // TypeCheckError: -// main/files/blankidentifier6.gno:18:13: cannot use _ as value or type +// main/blankidentifier6.gno:18:13: cannot use _ as value or type diff --git a/gnovm/tests/files/block2.gno b/gnovm/tests/files/block2.gno index 6738c76bf40..6cbe7902d1e 100644 --- a/gnovm/tests/files/block2.gno +++ b/gnovm/tests/files/block2.gno @@ -547,4 +547,4 @@ func main() { } // Error: -// main/files/block2.gno:419:129: exceeded maximum VPBlock depth (127) +// main/block2.gno:419:129-130: exceeded maximum VPBlock depth (127) diff --git a/gnovm/tests/files/bltn0.gno b/gnovm/tests/files/bltn0.gno index 89fc32b5a41..cfce6e60a65 100644 --- a/gnovm/tests/files/bltn0.gno +++ b/gnovm/tests/files/bltn0.gno @@ -6,7 +6,7 @@ func main() { } // Error: -// main/files/bltn0.gno:4:7: use of builtin println not in function call +// main/bltn0.gno:4:7-14: use of builtin println not in function call // TypeCheckError: -// main/files/bltn0.gno:4:7: println (built-in) must be called +// main/bltn0.gno:4:7: println (built-in) must be called diff --git a/gnovm/tests/files/bool6.gno b/gnovm/tests/files/bool6.gno index e7ba8390932..9d9913ffa76 100644 --- a/gnovm/tests/files/bool6.gno +++ b/gnovm/tests/files/bool6.gno @@ -9,7 +9,7 @@ func X() string { } // Error: -// main/files/bool6.gno:8:9: operator || not defined on: StringKind +// main/bool6.gno:8:9-27: operator || not defined on: StringKind // TypeCheckError: -// main/files/bool6.gno:8:9: invalid operation: operator || not defined on "hello" (untyped string constant) +// main/bool6.gno:8:9: invalid operation: operator || not defined on "hello" (untyped string constant) diff --git a/gnovm/tests/files/break0.gno b/gnovm/tests/files/break0.gno index a7c71282a9b..8eddc7af32d 100644 --- a/gnovm/tests/files/break0.gno +++ b/gnovm/tests/files/break0.gno @@ -5,7 +5,7 @@ func main() { } // Error: -// main/files/break0.gno:4:2: break statement out of place +// main/break0.gno:4:2-7: break statement out of place // TypeCheckError: -// main/files/break0.gno:4:2: break not in for, switch, or select statement +// main/break0.gno:4:2: break not in for, switch, or select statement diff --git a/gnovm/tests/files/cap10.gno b/gnovm/tests/files/cap10.gno index 94cca338f97..3dcf1eab218 100644 --- a/gnovm/tests/files/cap10.gno +++ b/gnovm/tests/files/cap10.gno @@ -8,4 +8,4 @@ func main() { // unexpected type for cap(): struct{A int} // TypeCheckError: -// main/files/cap10.gno:4:21: invalid argument: struct{A int}{} (value of type struct{A int}) for built-in cap +// main/cap10.gno:4:21: invalid argument: struct{A int}{} (value of type struct{A int}) for built-in cap diff --git a/gnovm/tests/files/cap7.gno b/gnovm/tests/files/cap7.gno index 9f059ec4a16..92650747ce5 100644 --- a/gnovm/tests/files/cap7.gno +++ b/gnovm/tests/files/cap7.gno @@ -9,4 +9,4 @@ func main() { // unexpected type for cap(): string // TypeCheckError: -// main/files/cap7.gno:5:21: invalid argument: s (variable of type string) for built-in cap +// main/cap7.gno:5:21: invalid argument: s (variable of type string) for built-in cap diff --git a/gnovm/tests/files/cap8.gno b/gnovm/tests/files/cap8.gno index 99bcf6e4aa9..4c8e504394a 100644 --- a/gnovm/tests/files/cap8.gno +++ b/gnovm/tests/files/cap8.gno @@ -9,4 +9,4 @@ func main() { // unexpected type for cap(): *int // TypeCheckError: -// main/files/cap8.gno:5:21: invalid argument: i (variable of type *int) for built-in cap +// main/cap8.gno:5:21: invalid argument: i (variable of type *int) for built-in cap diff --git a/gnovm/tests/files/cap9.gno b/gnovm/tests/files/cap9.gno index a7025a5d064..a1b66734d64 100644 --- a/gnovm/tests/files/cap9.gno +++ b/gnovm/tests/files/cap9.gno @@ -9,4 +9,4 @@ func main() { // unexpected type for cap(): *int // TypeCheckError: -// main/files/cap9.gno:5:21: invalid argument: i (variable of type *int) for built-in cap +// main/cap9.gno:5:21: invalid argument: i (variable of type *int) for built-in cap diff --git a/gnovm/tests/files/circular_constant.gno b/gnovm/tests/files/circular_constant.gno index b87a64c3b69..f5aa5b98cbb 100644 --- a/gnovm/tests/files/circular_constant.gno +++ b/gnovm/tests/files/circular_constant.gno @@ -7,7 +7,7 @@ func main() { } // Error: -// main/files/circular_constant.gno:3:7: constant definition loop with A +// main/circular_constant.gno:3:7-12: invalid recursive value: A -> B -> A // TypeCheckError: -// main/files/circular_constant.gno:3:7: initialization cycle for A; main/files/circular_constant.gno:3:7: A refers to B; main/files/circular_constant.gno:4:7: B refers to A +// main/circular_constant.gno:3:7: initialization cycle for A; main/circular_constant.gno:3:7: A refers to B; main/circular_constant.gno:4:7: B refers to A diff --git a/gnovm/tests/files/closure.gno b/gnovm/tests/files/closure.gno index 932e4d69ff1..3804ef8dc7d 100644 --- a/gnovm/tests/files/closure.gno +++ b/gnovm/tests/files/closure.gno @@ -13,7 +13,7 @@ var b = func() { } // Error: -// main/files/closure.gno:7:5: constant definition loop with a +// main/closure.gno:7:5: loop in variable initialization: dependency trail [b a] circularly depends on b // TypeCheckError: -// main/files/closure.gno:7:5: initialization cycle for a; main/files/closure.gno:7:5: a refers to b; main/files/closure.gno:11:5: b refers to a +// main/closure.gno:7:5: initialization cycle for a; main/closure.gno:7:5: a refers to b; main/closure.gno:11:5: b refers to a diff --git a/gnovm/tests/files/closure9.gno b/gnovm/tests/files/closure9.gno index 41b5a16b2b0..98392401f48 100644 --- a/gnovm/tests/files/closure9.gno +++ b/gnovm/tests/files/closure9.gno @@ -26,4 +26,4 @@ func makeClosure(a int) (b int, c func(bool)) { // 1 2 0 // TypeCheckError: -// main/files/closure9.gno:8:2: declared and not used: b +// main/closure9.gno:8:2: declared and not used: b diff --git a/gnovm/tests/files/comp5.gno b/gnovm/tests/files/comp5.gno index dd190deff8a..718520199d1 100644 --- a/gnovm/tests/files/comp5.gno +++ b/gnovm/tests/files/comp5.gno @@ -23,4 +23,4 @@ func main() { // znil == y true // TypeCheckError: -// main/files/comp5.gno:7:2: declared and not used: x +// main/comp5.gno:7:2: declared and not used: x diff --git a/gnovm/tests/files/composite15.gno b/gnovm/tests/files/composite15.gno index 3851da0ffbe..de8cac0d09d 100644 --- a/gnovm/tests/files/composite15.gno +++ b/gnovm/tests/files/composite15.gno @@ -13,4 +13,4 @@ func main() { // slice[(0 int),(2 int),(0 int),(4 int)] // TypeCheckError: -// main/files/composite15.gno:6:3: index a must be integer constant; main/files/composite15.gno:7:3: index c must be integer constant +// main/composite15.gno:6:3: index a must be integer constant; main/composite15.gno:7:3: index c must be integer constant diff --git a/gnovm/tests/files/composite16.gno b/gnovm/tests/files/composite16.gno index 3262b6350cb..fd6ee6dc4dc 100644 --- a/gnovm/tests/files/composite16.gno +++ b/gnovm/tests/files/composite16.gno @@ -21,4 +21,4 @@ func main() { // slice[(0 int),(2 int),(0 int),(4 int)] // TypeCheckError: -// main/files/composite16.gno:10:3: index x(1) must be integer constant; main/files/composite16.gno:11:3: index x(3) must be integer constant +// main/composite16.gno:10:3: index x(1) must be integer constant; main/composite16.gno:11:3: index x(3) must be integer constant diff --git a/gnovm/tests/files/const23.gno b/gnovm/tests/files/const23.gno index b27d02a1a86..fa796fa325a 100644 --- a/gnovm/tests/files/const23.gno +++ b/gnovm/tests/files/const23.gno @@ -8,7 +8,7 @@ func main() { } // Error: -// main/files/const23.gno:6:8: invalid constant type []string +// main/const23.gno:6:8-31: invalid constant type []string // TypeCheckError: -// main/files/const23.gno:6:10: invalid constant type []string +// main/const23.gno:6:10: invalid constant type []string diff --git a/gnovm/tests/files/const25.gno b/gnovm/tests/files/const25.gno index e0091bd0c90..f1049e188f8 100644 --- a/gnovm/tests/files/const25.gno +++ b/gnovm/tests/files/const25.gno @@ -8,7 +8,7 @@ func main() { } // Error: -// main/files/const25.gno:6:8: [](const-type string){(const ("1" string))} (variable of type []string) is not constant +// main/const25.gno:6:8-25: [](const-type string){(const ("1" string))} (variable of type []string) is not constant // TypeCheckError: -// main/files/const25.gno:6:12: []string{…} (value of type []string) is not constant +// main/const25.gno:6:12: []string{…} (value of type []string) is not constant diff --git a/gnovm/tests/files/const26.gno b/gnovm/tests/files/const26.gno index 80b1704d8ae..03c9a2346ff 100644 --- a/gnovm/tests/files/const26.gno +++ b/gnovm/tests/files/const26.gno @@ -12,7 +12,7 @@ func main() { } // Error: -// main/files/const26.gno:10:8: v() (value of type string) is not constant +// main/const26.gno:10:8-15: v() (value of type string) is not constant // TypeCheckError: -// main/files/const26.gno:10:12: v() (value of type string) is not constant +// main/const26.gno:10:12: v() (value of type string) is not constant diff --git a/gnovm/tests/files/const27.gno b/gnovm/tests/files/const27.gno index 9ee15e948a6..8c18f3c4dbe 100644 --- a/gnovm/tests/files/const27.gno +++ b/gnovm/tests/files/const27.gno @@ -13,7 +13,7 @@ func main() { } // Error: -// main/files/const27.gno:11:8: i.((const-type int)) (comma, ok expression of type (const-type int)) is not constant +// main/const27.gno:11:8-23: i.((const-type int)) (comma, ok expression of type (const-type int)) is not constant // TypeCheckError: -// main/files/const27.gno:11:11: missing init expr for ok; main/files/const27.gno:11:16: i.(int) (comma, ok expression of type int) is not constant +// main/const27.gno:11:11: missing init expr for ok; main/const27.gno:11:16: i.(int) (comma, ok expression of type int) is not constant diff --git a/gnovm/tests/files/const28.gno b/gnovm/tests/files/const28.gno index 4bff2ea8108..2f534c38844 100644 --- a/gnovm/tests/files/const28.gno +++ b/gnovm/tests/files/const28.gno @@ -9,7 +9,7 @@ func main() { } // Error: -// main/files/const28.gno:7:8: s[(const (0 int))] (variable of type string) is not constant +// main/const28.gno:7:8-20: s[(const (0 int))] (variable of type string) is not constant // TypeCheckError: -// main/files/const28.gno:7:11: missing init expr for ok; main/files/const28.gno:7:16: s[0] (variable of type string) is not constant +// main/const28.gno:7:11: missing init expr for ok; main/const28.gno:7:16: s[0] (variable of type string) is not constant diff --git a/gnovm/tests/files/const29.gno b/gnovm/tests/files/const29.gno index d6f9a4a7532..26bc887f5c2 100644 --- a/gnovm/tests/files/const29.gno +++ b/gnovm/tests/files/const29.gno @@ -9,7 +9,7 @@ func main() { } // Error: -// main/files/const29.gno:7:8: s (variable of type string) is not constant +// main/const29.gno:7:8-13: s (variable of type string) is not constant // TypeCheckError: -// main/files/const29.gno:7:12: s (variable of type string) is not constant +// main/const29.gno:7:12: s (variable of type string) is not constant diff --git a/gnovm/tests/files/const30.gno b/gnovm/tests/files/const30.gno index 77915f5db4a..1d1a70c3f59 100644 --- a/gnovm/tests/files/const30.gno +++ b/gnovm/tests/files/const30.gno @@ -12,7 +12,7 @@ func main() { } // Error: -// main/files/const30.gno:10:8: v (no value) used as value +// main/const30.gno:10:8-15: v (no value) used as value // TypeCheckError: -// main/files/const30.gno:10:12: v() (no value) used as value +// main/const30.gno:10:12: v() (no value) used as value diff --git a/gnovm/tests/files/const31.gno b/gnovm/tests/files/const31.gno index afda0cb8bb2..f5478106682 100644 --- a/gnovm/tests/files/const31.gno +++ b/gnovm/tests/files/const31.gno @@ -12,7 +12,7 @@ func main() { } // Error: -// main/files/const31.gno:10:8: (const (v func() (string, string)))() (variable of type (string,string)) is not constant +// main/const31.gno:10:8-18: (const (v func() (string, string)))() (variable of type (string,string)) is not constant // TypeCheckError: -// main/files/const31.gno:10:11: missing init expr for v; main/files/const31.gno:10:15: multiple-value v() (value of type (string, string)) in single-value context +// main/const31.gno:10:11: missing init expr for v; main/const31.gno:10:15: multiple-value v() (value of type (string, string)) in single-value context diff --git a/gnovm/tests/files/const32.gno b/gnovm/tests/files/const32.gno index e199a1a1b8f..92b83a43691 100644 --- a/gnovm/tests/files/const32.gno +++ b/gnovm/tests/files/const32.gno @@ -8,7 +8,7 @@ func main() { } // Error: -// main/files/const32.gno:6:8: [](const-type string){} (variable of type []string) is not constant +// main/const32.gno:6:8-35: [](const-type string){} (variable of type []string) is not constant // TypeCheckError: -// main/files/const32.gno:6:12: 1 + 2 + len([]string{}) (value of type int) is not constant +// main/const32.gno:6:12: 1 + 2 + len([]string{}) (value of type int) is not constant diff --git a/gnovm/tests/files/const33.gno b/gnovm/tests/files/const33.gno index 8b7100cbd1c..9ccf0c175db 100644 --- a/gnovm/tests/files/const33.gno +++ b/gnovm/tests/files/const33.gno @@ -10,7 +10,7 @@ func main() { } // Error: -// main/files/const33.gno:6:7: x (variable of type int) is not constant +// main/const33.gno:6:7-17: x (variable of type int) is not constant // TypeCheckError: -// main/files/const33.gno:6:11: x == y (untyped bool value) is not constant +// main/const33.gno:6:11: x == y (untyped bool value) is not constant diff --git a/gnovm/tests/files/const34.gno b/gnovm/tests/files/const34.gno index df77a34ff87..def38d3e379 100644 --- a/gnovm/tests/files/const34.gno +++ b/gnovm/tests/files/const34.gno @@ -7,7 +7,7 @@ func main() { } // Error: -// main/files/const34.gno:3:7: func func(){ (const (println func(...interface {})))((const ("hey" string))) } (variable of type func()) is not constant +// main/const34.gno:3:7-36: func func(){ println("hey") } (variable of type func()) is not constant // TypeCheckError: -// main/files/const34.gno:3:11: (func() literal) (value of type func()) is not constant +// main/const34.gno:3:11: (func() literal) (value of type func()) is not constant diff --git a/gnovm/tests/files/const35.gno b/gnovm/tests/files/const35.gno index 641e3b0f918..49918e883a2 100644 --- a/gnovm/tests/files/const35.gno +++ b/gnovm/tests/files/const35.gno @@ -9,7 +9,7 @@ func main() { } // Error: -// main/files/const35.gno:5:7: x (variable of type int) is not constant +// main/const35.gno:5:7-21: x (variable of type int) is not constant // TypeCheckError: -// main/files/const35.gno:5:12: +(1 << x) (untyped int value) is not constant +// main/const35.gno:5:12: +(1 << x) (untyped int value) is not constant diff --git a/gnovm/tests/files/const36.gno b/gnovm/tests/files/const36.gno index 8d9f198c5ae..952cb41ceef 100644 --- a/gnovm/tests/files/const36.gno +++ b/gnovm/tests/files/const36.gno @@ -10,7 +10,7 @@ func main() { } // Error: -// main/files/const36.gno:9:8: s.x (variable of type int) is not constant +// main/const36.gno:9:8-15: s.x (variable of type int) is not constant // TypeCheckError: -// main/files/const36.gno:9:12: s.x (variable of type int) is not constant +// main/const36.gno:9:12: s.x (variable of type int) is not constant diff --git a/gnovm/tests/files/const37_native.gno b/gnovm/tests/files/const37_native.gno index 151d4f7731b..e1bcedadd58 100644 --- a/gnovm/tests/files/const37_native.gno +++ b/gnovm/tests/files/const37_native.gno @@ -7,7 +7,7 @@ func main() { } // Error: -// main/files/const37_native.gno:6:8: time.UTC (variable of type *time.Location) is not constant +// main/const37_native.gno:6:8-20: time.UTC (variable of type *time.Location) is not constant // TypeCheckError: -// main/files/const37_native.gno:6:12: time.UTC (variable of type *time.Location) is not constant +// main/const37_native.gno:6:12: time.UTC (variable of type *time.Location) is not constant diff --git a/gnovm/tests/files/const37_stdlibs.gno b/gnovm/tests/files/const37_stdlibs.gno index 6a202270d82..c82ed97a36d 100644 --- a/gnovm/tests/files/const37_stdlibs.gno +++ b/gnovm/tests/files/const37_stdlibs.gno @@ -7,7 +7,7 @@ func main() { } // Error: -// main/files/const37_stdlibs.gno:6:8: time.UTC (variable of type *time.Location) is not constant +// main/const37_stdlibs.gno:6:8-20: time.UTC (variable of type *time.Location) is not constant // TypeCheckError: -// main/files/const37_stdlibs.gno:6:12: time.UTC (variable of type *time.Location) is not constant +// main/const37_stdlibs.gno:6:12: time.UTC (variable of type *time.Location) is not constant diff --git a/gnovm/tests/files/const38.gno b/gnovm/tests/files/const38.gno index c51bdf3b525..a37460025db 100644 --- a/gnovm/tests/files/const38.gno +++ b/gnovm/tests/files/const38.gno @@ -8,7 +8,7 @@ func main() { } // Error: -// main/files/const38.gno:7:8: v.Denom (variable of type string) is not constant +// main/const38.gno:7:8-19: v.Denom (variable of type string) is not constant // TypeCheckError: -// main/files/const38.gno:7:12: v.Denom (variable of type string) is not constant +// main/const38.gno:7:12: v.Denom (variable of type string) is not constant diff --git a/gnovm/tests/files/const39.gno b/gnovm/tests/files/const39.gno index b843c5b36c6..0954c5292c6 100644 --- a/gnovm/tests/files/const39.gno +++ b/gnovm/tests/files/const39.gno @@ -11,7 +11,7 @@ func main() { } // Error: -// main/files/const39.gno:10:8: typeval{main.T}.Mv (variable of type func(main.T, int) int) is not constant +// main/const39.gno:10:8-16: typeval{main.T}.Mv (variable of type func(main.T, int) int) is not constant // TypeCheckError: -// main/files/const39.gno:10:12: T.Mv (value of type func(tv T, a int) int) is not constant +// main/const39.gno:10:12: T.Mv (value of type func(tv T, a int) int) is not constant diff --git a/gnovm/tests/files/const40.gno b/gnovm/tests/files/const40.gno index 4ee80ceff65..5bf5340dbf8 100644 --- a/gnovm/tests/files/const40.gno +++ b/gnovm/tests/files/const40.gno @@ -5,7 +5,7 @@ func main() { } // Error: -// main/files/const40.gno:4:8: [(const (0 int))](const-type string){} (variable of type [0]string) is not constant +// main/const40.gno:4:8-23: [(const (0 int))](const-type string){} (variable of type [0]string) is not constant // TypeCheckError: -// main/files/const40.gno:4:12: [0]string{} (value of type [0]string) is not constant +// main/const40.gno:4:12: [0]string{} (value of type [0]string) is not constant diff --git a/gnovm/tests/files/const41.gno b/gnovm/tests/files/const41.gno index ed009dddd35..fcfae2925fd 100644 --- a/gnovm/tests/files/const41.gno +++ b/gnovm/tests/files/const41.gno @@ -5,7 +5,7 @@ func main() { } // Error: -// main/files/const41.gno:4:8: invalid constant type [0]string +// main/const41.gno:4:8-33: invalid constant type [0]string // TypeCheckError: -// main/files/const41.gno:4:10: invalid constant type [0]string +// main/const41.gno:4:10: invalid constant type [0]string diff --git a/gnovm/tests/files/const42.gno b/gnovm/tests/files/const42.gno index 58a3987f8c8..45e7a251623 100644 --- a/gnovm/tests/files/const42.gno +++ b/gnovm/tests/files/const42.gno @@ -5,4 +5,4 @@ func main() { } // TypeCheckError: -// main/files/const42.gno:4:8: missing init expr for t +// main/const42.gno:4:8: missing init expr for t diff --git a/gnovm/tests/files/const43.gno b/gnovm/tests/files/const43.gno index a47483b2c5b..1ae6efc68df 100644 --- a/gnovm/tests/files/const43.gno +++ b/gnovm/tests/files/const43.gno @@ -7,7 +7,7 @@ func main() { } // Error: -// main/files/const43.gno:6:8: a (variable of type [2]int) is not constant +// main/const43.gno:6:8-13: a (variable of type [2]int) is not constant // TypeCheckError: -// main/files/const43.gno:6:12: a (variable of type [2]int) is not constant +// main/const43.gno:6:12: a (variable of type [2]int) is not constant diff --git a/gnovm/tests/files/const44.gno b/gnovm/tests/files/const44.gno index 16196e2d14d..93de134b32b 100644 --- a/gnovm/tests/files/const44.gno +++ b/gnovm/tests/files/const44.gno @@ -7,7 +7,7 @@ func main() { } // Error: -// main/files/const44.gno:3:7: (const (undefined)) (variable of type interface {}) is not constant +// main/const44.gno:3:7-19: (const (undefined)) (variable of type interface {}) is not constant // TypeCheckError: -// main/files/const44.gno:3:11: any(nil) (value of interface type any) is not constant +// main/const44.gno:3:11: any(nil) (value of interface type any) is not constant diff --git a/gnovm/tests/files/const45_b.gno b/gnovm/tests/files/const45_b.gno index df01afcfda4..b8eb7c9cd8a 100644 --- a/gnovm/tests/files/const45_b.gno +++ b/gnovm/tests/files/const45_b.gno @@ -11,7 +11,7 @@ func main() { } // Error: -// main/files/const45_b.gno:7:7: typeval{main.MyStruct}{arr: [](const-type int){(const (1 int)), (const (2 int))}}.arr (variable of type []int) is not constant +// main/const45_b.gno:7:7-46: typeval{main.MyStruct}{arr: [](const-type int){(const (1 int)), (const (2 int))}}.arr (variable of type []int) is not constant // TypeCheckError: -// main/files/const45_b.gno:7:11: len(MyStruct{…}.arr) (value of type int) is not constant +// main/const45_b.gno:7:11: len(MyStruct{…}.arr) (value of type int) is not constant diff --git a/gnovm/tests/files/const48.gno b/gnovm/tests/files/const48.gno index 79423e18f95..4e56a5bf7f8 100644 --- a/gnovm/tests/files/const48.gno +++ b/gnovm/tests/files/const48.gno @@ -6,7 +6,7 @@ func main() { } // Error: -// main/files/const48.gno:4:8: map[(const-type string)] [](const-type int){(const ("arr" string)): (const-type []int){(const (1 int)), (const (2 int))}} (variable of type map[string][]int) is not constant +// main/const48.gno:4:8-48: map[(const-type string)] [](const-type int){(const ("arr" string)): (const-type []int){(const (1 int)), (const (2 int))}} (variable of type map[string][]int) is not constant // TypeCheckError: -// main/files/const48.gno:4:12: len(map[string][]int{…}) (value of type int) is not constant +// main/const48.gno:4:12: len(map[string][]int{…}) (value of type int) is not constant diff --git a/gnovm/tests/files/const49.gno b/gnovm/tests/files/const49.gno index 8974fe65d75..9e74787d87d 100644 --- a/gnovm/tests/files/const49.gno +++ b/gnovm/tests/files/const49.gno @@ -16,4 +16,4 @@ func main() { // 2 // TypeCheckError: -// main/files/const49.gno:3:8: "io" imported and not used +// main/const49.gno:3:8: "io" imported and not used diff --git a/gnovm/tests/files/const50.gno b/gnovm/tests/files/const50.gno index c95b907af09..c513947c11f 100644 --- a/gnovm/tests/files/const50.gno +++ b/gnovm/tests/files/const50.gno @@ -9,7 +9,7 @@ func main() { } // Error: -// main/files/const50.gno:5:7: x (variable of type string) is not constant +// main/const50.gno:5:7-17: x (variable of type string) is not constant // TypeCheckError: -// main/files/const50.gno:5:11: len(x) (value of type int) is not constant +// main/const50.gno:5:11: len(x) (value of type int) is not constant diff --git a/gnovm/tests/files/const55.gno b/gnovm/tests/files/const55.gno index 3c9a0c1e6e5..e9b9b213d0a 100644 --- a/gnovm/tests/files/const55.gno +++ b/gnovm/tests/files/const55.gno @@ -11,7 +11,7 @@ func main() { } // Error: -// main/files/const55.gno:5:2: assignment mismatch: 1 variable(s) but 2 value(s) +// main/const55.gno:5:2-3: assignment mismatch: 1 variable(s) but 2 value(s) // TypeCheckError: -// main/files/const55.gno:5:2: extra init expr at main/files/const55.gno:4:2 +// main/const55.gno:5:2: extra init expr at main/const55.gno:4:2 diff --git a/gnovm/tests/files/const55a.gno b/gnovm/tests/files/const55a.gno index 5a9b4028de6..2521778880d 100644 --- a/gnovm/tests/files/const55a.gno +++ b/gnovm/tests/files/const55a.gno @@ -11,7 +11,7 @@ func main() { } // Error: -// main/files/const55a.gno:5:2: assignment mismatch: 3 variable(s) but 2 value(s) +// main/const55a.gno:5:2-9: assignment mismatch: 3 variable(s) but 2 value(s) // TypeCheckError: -// main/files/const55a.gno:5:8: missing init expr for l +// main/const55a.gno:5:8: missing init expr for l diff --git a/gnovm/tests/files/const60.gno b/gnovm/tests/files/const60.gno index eb1fa4c74b1..e847aa070f7 100644 --- a/gnovm/tests/files/const60.gno +++ b/gnovm/tests/files/const60.gno @@ -9,7 +9,7 @@ func main() { } // Error: -// main/files/const60.gno:4:6: bigint underflows target kind +// main/const60.gno:4:6-14: bigint underflows target kind // TypeCheckError: -// main/files/const60.gno:4:11: constant -2 overflows uint +// main/const60.gno:4:11: constant -2 overflows uint diff --git a/gnovm/tests/files/const61.gno b/gnovm/tests/files/const61.gno index ce3fd699913..c6edc23137f 100644 --- a/gnovm/tests/files/const61.gno +++ b/gnovm/tests/files/const61.gno @@ -9,7 +9,7 @@ func main() { } // Error: -// main/files/const61.gno:4:6: bigint underflows target kind +// main/const61.gno:4:6-15: bigint underflows target kind // TypeCheckError: -// main/files/const61.gno:4:12: constant -1 overflows uint8 +// main/const61.gno:4:12: constant -1 overflows uint8 diff --git a/gnovm/tests/files/const9.gno b/gnovm/tests/files/const9.gno index 5267869040d..e60f02b2e5e 100644 --- a/gnovm/tests/files/const9.gno +++ b/gnovm/tests/files/const9.gno @@ -14,7 +14,7 @@ func main() { } // Error: -// main/files/const9.gno:5:2: constant definition loop with b +// main/const9.gno:5:2-11: invalid recursive value: b -> c -> d -> e -> b // TypeCheckError: -// main/files/const9.gno:6:2: initialization cycle for c; main/files/const9.gno:6:2: c refers to d; main/files/const9.gno:7:2: d refers to e; main/files/const9.gno:8:2: e refers to b; main/files/const9.gno:5:2: b refers to c; main/files/const9.gno:5:2: initialization cycle for b; main/files/const9.gno:5:2: b refers to c; main/files/const9.gno:6:2: c refers to d; main/files/const9.gno:7:2: d refers to e; main/files/const9.gno:8:2: e refers to b +// main/const9.gno:6:2: initialization cycle for c; main/const9.gno:6:2: c refers to d; main/const9.gno:7:2: d refers to e; main/const9.gno:8:2: e refers to b; main/const9.gno:5:2: b refers to c; main/const9.gno:5:2: initialization cycle for b; main/const9.gno:5:2: b refers to c; main/const9.gno:6:2: c refers to d; main/const9.gno:7:2: d refers to e; main/const9.gno:8:2: e refers to b diff --git a/gnovm/tests/files/cont3.gno b/gnovm/tests/files/cont3.gno index def25335acd..ff1934e6479 100644 --- a/gnovm/tests/files/cont3.gno +++ b/gnovm/tests/files/cont3.gno @@ -5,7 +5,7 @@ func main() { } // Error: -// main/files/cont3.gno:4:2: continue statement out of place +// main/cont3.gno:4:2-10: continue statement out of place // TypeCheckError: -// main/files/cont3.gno:4:2: continue not in for statement +// main/cont3.gno:4:2: continue not in for statement diff --git a/gnovm/tests/files/convert4.gno b/gnovm/tests/files/convert4.gno index 5467ecc2d6a..7734b642f4e 100644 --- a/gnovm/tests/files/convert4.gno +++ b/gnovm/tests/files/convert4.gno @@ -5,7 +5,7 @@ func main() { } // Error: -// main/files/convert4.gno:4:10: cannot convert (const (undefined)) to IntKind +// main/convert4.gno:4:10-18: cannot convert (const (undefined)) to IntKind // TypeCheckError: -// main/files/convert4.gno:4:14: cannot convert nil to type int +// main/convert4.gno:4:14: cannot convert nil to type int diff --git a/gnovm/tests/files/convert5.gno b/gnovm/tests/files/convert5.gno index 58f78fc89c7..71af90e1d23 100644 --- a/gnovm/tests/files/convert5.gno +++ b/gnovm/tests/files/convert5.gno @@ -7,7 +7,7 @@ func main() { } // Error: -// main/files/convert5.gno:3:1: cannot convert (const (undefined)) to IntKind +// main/convert5.gno:3:1-7:2: cannot convert (const (undefined)) to IntKind // TypeCheckError: -// main/files/convert5.gno:5:22: cannot use nil as int value in argument to append; main/files/convert5.gno:5:27: cannot use nil as int value in argument to append +// main/convert5.gno:5:22: cannot use nil as int value in argument to append; main/convert5.gno:5:27: cannot use nil as int value in argument to append diff --git a/gnovm/tests/files/convert6.gno b/gnovm/tests/files/convert6.gno index db6885c3563..df3dcb286c1 100644 --- a/gnovm/tests/files/convert6.gno +++ b/gnovm/tests/files/convert6.gno @@ -6,7 +6,7 @@ func main() { } // Error: -// main/files/convert6.gno:5:10: cannot convert constant of type IntKind to UintKind +// main/convert6.gno:5:10-17: cannot convert constant of type IntKind to UintKind // TypeCheckError: -// main/files/convert6.gno:5:15: constant -1 overflows uint +// main/convert6.gno:5:15: constant -1 overflows uint diff --git a/gnovm/tests/files/convert6a.gno b/gnovm/tests/files/convert6a.gno index 6edafaa0434..ac60fdaa3f6 100644 --- a/gnovm/tests/files/convert6a.gno +++ b/gnovm/tests/files/convert6a.gno @@ -6,7 +6,7 @@ func main() { } // Error: -// main/files/convert6a.gno:5:10: cannot convert constant of type IntKind to Uint8Kind +// main/convert6a.gno:5:10-18: cannot convert constant of type IntKind to Uint8Kind // TypeCheckError: -// main/files/convert6a.gno:5:16: constant -1 overflows uint8 +// main/convert6a.gno:5:16: constant -1 overflows uint8 diff --git a/gnovm/tests/files/convert6b.gno b/gnovm/tests/files/convert6b.gno index 6ecb12e7424..04e672215a1 100644 --- a/gnovm/tests/files/convert6b.gno +++ b/gnovm/tests/files/convert6b.gno @@ -6,7 +6,7 @@ func main() { } // Error: -// main/files/convert6b.gno:5:10: cannot convert constant of type IntKind to Uint16Kind +// main/convert6b.gno:5:10-19: cannot convert constant of type IntKind to Uint16Kind // TypeCheckError: -// main/files/convert6b.gno:5:17: constant -1 overflows uint16 +// main/convert6b.gno:5:17: constant -1 overflows uint16 diff --git a/gnovm/tests/files/convert6c.gno b/gnovm/tests/files/convert6c.gno index e5b86791ff9..9701854dce9 100644 --- a/gnovm/tests/files/convert6c.gno +++ b/gnovm/tests/files/convert6c.gno @@ -6,7 +6,7 @@ func main() { } // Error: -// main/files/convert6c.gno:5:10: cannot convert constant of type IntKind to Uint32Kind +// main/convert6c.gno:5:10-19: cannot convert constant of type IntKind to Uint32Kind // TypeCheckError: -// main/files/convert6c.gno:5:17: constant -1 overflows uint32 +// main/convert6c.gno:5:17: constant -1 overflows uint32 diff --git a/gnovm/tests/files/convert6d.gno b/gnovm/tests/files/convert6d.gno index b04300af032..2514263a254 100644 --- a/gnovm/tests/files/convert6d.gno +++ b/gnovm/tests/files/convert6d.gno @@ -6,7 +6,7 @@ func main() { } // Error: -// main/files/convert6d.gno:5:10: cannot convert constant of type IntKind to Uint64Kind +// main/convert6d.gno:5:10-19: cannot convert constant of type IntKind to Uint64Kind // TypeCheckError: -// main/files/convert6d.gno:5:17: constant -1 overflows uint64 +// main/convert6d.gno:5:17: constant -1 overflows uint64 diff --git a/gnovm/tests/files/convert6e.gno b/gnovm/tests/files/convert6e.gno index ddd37147717..98ae7667bf4 100644 --- a/gnovm/tests/files/convert6e.gno +++ b/gnovm/tests/files/convert6e.gno @@ -6,7 +6,7 @@ func main() { } // Error: -// main/files/convert6e.gno:5:10: cannot convert constant of type Float32Kind to Int32Kind +// main/convert6e.gno:5:10-18: cannot convert constant of type Float32Kind to Int32Kind // TypeCheckError: -// main/files/convert6e.gno:5:16: cannot convert a (constant 1.5 of type float32) to type int32 +// main/convert6e.gno:5:16: cannot convert a (constant 1.5 of type float32) to type int32 diff --git a/gnovm/tests/files/convert7.gno b/gnovm/tests/files/convert7.gno index 89b110729e2..d3086fd003a 100644 --- a/gnovm/tests/files/convert7.gno +++ b/gnovm/tests/files/convert7.gno @@ -5,7 +5,7 @@ func main() { } // Error: -// main/files/convert7.gno:4:10: cannot convert (const (1.5 bigdec)) to integer type +// main/convert7.gno:4:10-20: cannot convert (const (1.5 bigdec)) to integer type // TypeCheckError: -// main/files/convert7.gno:4:16: cannot convert 1.5 (untyped float constant) to type int32 +// main/convert7.gno:4:16: cannot convert 1.5 (untyped float constant) to type int32 diff --git a/gnovm/tests/files/convert7a.gno b/gnovm/tests/files/convert7a.gno index fa4fb6e43df..27b04ff83f8 100644 --- a/gnovm/tests/files/convert7a.gno +++ b/gnovm/tests/files/convert7a.gno @@ -6,7 +6,7 @@ func main() { } // Error: -// main/files/convert7a.gno:5:10: cannot convert constant of type Float64Kind to Int64Kind +// main/convert7a.gno:5:10-18: cannot convert constant of type Float64Kind to Int64Kind // TypeCheckError: -// main/files/convert7a.gno:5:16: cannot convert a (constant 1.5 of type float64) to type int64 +// main/convert7a.gno:5:16: cannot convert a (constant 1.5 of type float64) to type int64 diff --git a/gnovm/tests/files/convert7b.gno b/gnovm/tests/files/convert7b.gno index 4f82b6b2c2b..bb92984a470 100644 --- a/gnovm/tests/files/convert7b.gno +++ b/gnovm/tests/files/convert7b.gno @@ -5,7 +5,7 @@ func main() { } // Error: -// main/files/convert7b.gno:4:10: cannot convert (const (1.5 bigdec)) to integer type +// main/convert7b.gno:4:10-20: cannot convert (const (1.5 bigdec)) to integer type // TypeCheckError: -// main/files/convert7b.gno:4:16: cannot convert 1.5 (untyped float constant) to type int64 +// main/convert7b.gno:4:16: cannot convert 1.5 (untyped float constant) to type int64 diff --git a/gnovm/tests/files/defer0.gno b/gnovm/tests/files/defer0.gno index 59cfdd0ea2e..bdfd611d5ce 100644 --- a/gnovm/tests/files/defer0.gno +++ b/gnovm/tests/files/defer0.gno @@ -42,4 +42,4 @@ func main() { // bye1 // TypeCheckError: -// main/files/defer0.gno:9:11: invalid operation: invalid use of ... with built-in println +// main/defer0.gno:9:11: invalid operation: invalid use of ... with built-in println diff --git a/gnovm/tests/files/float0.gno b/gnovm/tests/files/float0.gno index 751c0de73a8..d7b48546ed6 100644 --- a/gnovm/tests/files/float0.gno +++ b/gnovm/tests/files/float0.gno @@ -6,7 +6,7 @@ func main() { } // Error: -// main/files/float0.gno:4:7: cannot convert (const (1.2 bigdec)) to integer type +// main/float0.gno:4:7-15: cannot convert (const (1.2 bigdec)) to integer type // TypeCheckError: -// main/files/float0.gno:4:11: cannot convert 1.2 (untyped float constant) to type int +// main/float0.gno:4:11: cannot convert 1.2 (untyped float constant) to type int diff --git a/gnovm/tests/files/for20.gno b/gnovm/tests/files/for20.gno index 540c0caf90a..a2a71ce487f 100644 --- a/gnovm/tests/files/for20.gno +++ b/gnovm/tests/files/for20.gno @@ -15,4 +15,4 @@ loop: // hey // TypeCheckError: -// main/files/for20.gno:6:1: label loop declared and not used +// main/for20.gno:6:1: label loop declared and not used diff --git a/gnovm/tests/files/for21.gno b/gnovm/tests/files/for21.gno index d74b84476e3..4d55daf6187 100644 --- a/gnovm/tests/files/for21.gno +++ b/gnovm/tests/files/for21.gno @@ -14,7 +14,7 @@ func main() { } // Error: -// main/files/for21.gno:7:17: continue statement out of place +// main/for21.gno:7:17-25: continue statement out of place // TypeCheckError: -// main/files/for21.gno:7:17: continue not in for statement +// main/for21.gno:7:17: continue not in for statement diff --git a/gnovm/tests/files/for22.gno b/gnovm/tests/files/for22.gno index b332dc17268..f86cffd274f 100644 --- a/gnovm/tests/files/for22.gno +++ b/gnovm/tests/files/for22.gno @@ -14,7 +14,7 @@ func main() { } // Error: -// main/files/for22.gno:7:17: fallthrough statement out of place +// main/for22.gno:7:17-28: fallthrough statement out of place // TypeCheckError: -// main/files/for22.gno:7:17: fallthrough statement out of place +// main/for22.gno:7:17: fallthrough statement out of place diff --git a/gnovm/tests/files/for23.gno b/gnovm/tests/files/for23.gno index 69922dcdeb5..5cf96206096 100644 --- a/gnovm/tests/files/for23.gno +++ b/gnovm/tests/files/for23.gno @@ -14,7 +14,7 @@ func main() { } // Error: -// main/files/for23.gno:7:17: break statement out of place +// main/for23.gno:7:17-22: break statement out of place // TypeCheckError: -// main/files/for23.gno:7:17: break not in for, switch, or select statement +// main/for23.gno:7:17: break not in for, switch, or select statement diff --git a/gnovm/tests/files/for24.gno b/gnovm/tests/files/for24.gno index 4bc13f08334..ed79cfba322 100644 --- a/gnovm/tests/files/for24.gno +++ b/gnovm/tests/files/for24.gno @@ -16,7 +16,7 @@ func main() { } // Error: -// main/files/for24.gno:8:21: break statement out of place +// main/for24.gno:8:21-26: break statement out of place // TypeCheckError: -// main/files/for24.gno:8:21: break not in for, switch, or select statement +// main/for24.gno:8:21: break not in for, switch, or select statement diff --git a/gnovm/tests/files/for7.gno b/gnovm/tests/files/for7.gno index 2d4e7e94076..0cfde742ddd 100644 --- a/gnovm/tests/files/for7.gno +++ b/gnovm/tests/files/for7.gno @@ -6,7 +6,7 @@ func main() { } // Error: -// main/files/for7.gno:4:2: expected typed bool kind, but got IntKind +// main/for7.gno:4:2-5:3: expected typed bool kind, but got IntKind // TypeCheckError: -// main/files/for7.gno:4:14: non-boolean condition in for statement +// main/for7.gno:4:14: non-boolean condition in for statement diff --git a/gnovm/tests/files/fun21.gno b/gnovm/tests/files/fun21.gno index fcf4bc5897d..58441462acd 100644 --- a/gnovm/tests/files/fun21.gno +++ b/gnovm/tests/files/fun21.gno @@ -9,9 +9,9 @@ func main() { } // Error: -// main/files/fun21.gno:4:2: expected 1 return values; got 0 +// main/fun21.gno:4:2-8: expected 1 return values; got 0 // TypeCheckError: -// main/files/fun21.gno:4:2: not enough return values +// main/fun21.gno:4:2: not enough return values // have () // want (string) diff --git a/gnovm/tests/files/fun22.gno b/gnovm/tests/files/fun22.gno index 805661fe605..a154d7e6244 100644 --- a/gnovm/tests/files/fun22.gno +++ b/gnovm/tests/files/fun22.gno @@ -7,9 +7,9 @@ func main() { } // Error: -// main/files/fun22.gno:6:2: wrong argument count in call to time.Date; want 8 got 0 +// main/fun22.gno:6:2-13: wrong argument count in call to time.Date; want 8 got 0 // TypeCheckError: -// main/files/fun22.gno:6:12: not enough arguments in call to time.Date +// main/fun22.gno:6:12: not enough arguments in call to time.Date // have () // want (int, time.Month, int, int, int, int, int, *time.Location) diff --git a/gnovm/tests/files/fun23.gno b/gnovm/tests/files/fun23.gno index 371c3818424..199ba1856c9 100644 --- a/gnovm/tests/files/fun23.gno +++ b/gnovm/tests/files/fun23.gno @@ -7,9 +7,9 @@ func main() { } // Error: -// main/files/fun23.gno:3:17: expected 0 return values; got 1 +// main/fun23.gno:3:17-25: expected 0 return values; got 1 // TypeCheckError: -// main/files/fun23.gno:3:24: too many return values +// main/fun23.gno:3:24: too many return values // have (int) // want () diff --git a/gnovm/tests/files/fun24.gno b/gnovm/tests/files/fun24.gno index 9fcca8d708d..ae9a40c29a4 100644 --- a/gnovm/tests/files/fun24.gno +++ b/gnovm/tests/files/fun24.gno @@ -7,7 +7,7 @@ func main() { } // Error: -// main/files/fun24.gno:3:28: cannot use untyped string as IntKind +// main/fun24.gno:3:28-43: cannot use untyped string as IntKind // TypeCheckError: -// main/files/fun24.gno:3:38: cannot use "foo" (untyped string constant) as int value in return statement +// main/fun24.gno:3:38: cannot use "foo" (untyped string constant) as int value in return statement diff --git a/gnovm/tests/files/fun25.gno b/gnovm/tests/files/fun25.gno index 0ec06e2ce75..cb40440a859 100644 --- a/gnovm/tests/files/fun25.gno +++ b/gnovm/tests/files/fun25.gno @@ -7,7 +7,7 @@ func main() { } // Error: -// main/files/fun25.gno:3:35: cannot use string as int +// main/fun25.gno:3:35-46: cannot use string as int // TypeCheckError: -// main/files/fun25.gno:3:42: cannot use x (variable of type string) as int value in return statement +// main/fun25.gno:3:42: cannot use x (variable of type string) as int value in return statement diff --git a/gnovm/tests/files/fun27.gno b/gnovm/tests/files/fun27.gno index 029deaec6e7..22f1f4f738b 100644 --- a/gnovm/tests/files/fun27.gno +++ b/gnovm/tests/files/fun27.gno @@ -13,7 +13,7 @@ func main() { } // Error: -// main/files/fun27.gno:8:2: bigint does not implement main.Foo (missing method foo) +// main/fun27.gno:8:2-10: bigint does not implement main.Foo (missing method foo) // TypeCheckError: -// main/files/fun27.gno:8:9: cannot use 1 (constant of type int) as Foo value in return statement: int does not implement Foo (missing method foo) +// main/fun27.gno:8:9: cannot use 1 (constant of type int) as Foo value in return statement: int does not implement Foo (missing method foo) diff --git a/gnovm/tests/files/fun28.gno b/gnovm/tests/files/fun28.gno index 703a28e927c..1bb1ace7397 100644 --- a/gnovm/tests/files/fun28.gno +++ b/gnovm/tests/files/fun28.gno @@ -7,7 +7,7 @@ func main() { } // Error: -// main/files/fun28.gno:6:2: cannot use nil as int value in argument to f +// main/fun28.gno:6:2-8: cannot use nil as int value in argument to f // TypeCheckError: -// main/files/fun28.gno:6:4: cannot use nil as int value in argument to f +// main/fun28.gno:6:4: cannot use nil as int value in argument to f diff --git a/gnovm/tests/files/fun9.gno b/gnovm/tests/files/fun9.gno index 11e3c033d89..9b7ab6807d3 100644 --- a/gnovm/tests/files/fun9.gno +++ b/gnovm/tests/files/fun9.gno @@ -9,4 +9,4 @@ func main() { } // Output: -// (1 main[main/files/fun9.gno:5:1].myint) +// (1 main[main/fun9.gno:5:1-9:2].myint) diff --git a/gnovm/tests/files/funclit0.gno b/gnovm/tests/files/funclit0.gno new file mode 100644 index 00000000000..11173bb4a29 --- /dev/null +++ b/gnovm/tests/files/funclit0.gno @@ -0,0 +1,18 @@ +package main + +// This tests an issue where the preprocessor was failing after +// implementing ATTR_PREPROCESS_SKIPPED. + +func main() { + var myDep1 string = "hello" + + var myVar1 = func() { + a := myDep1 + println(a) + } + + myVar1() +} + +// Output: +// hello diff --git a/gnovm/tests/files/funclit1.gno b/gnovm/tests/files/funclit1.gno new file mode 100644 index 00000000000..9547dc7b671 --- /dev/null +++ b/gnovm/tests/files/funclit1.gno @@ -0,0 +1,27 @@ +package main + +// This tests an issue where the preprocessor was failing after +// implementing ATTR_PREPROCESS_SKIPPED. + +var myVar0 = func() { + var myDep1 string = "hello" + + var myVar1 = func() { + a := myDep1 + println(a) + } + myVar1() + + println(myDep0) +} + +var myDep0 string = "world" + +func main() { + + myVar0() +} + +// Output: +// hello +// world diff --git a/gnovm/tests/files/funclit2.gno b/gnovm/tests/files/funclit2.gno new file mode 100644 index 00000000000..31968e01ab3 --- /dev/null +++ b/gnovm/tests/files/funclit2.gno @@ -0,0 +1,32 @@ +package main + +// This tests an issue where the preprocessor was failing after +// implementing ATTR_PREPROCESS_SKIPPED. + +var myVar0 = func() { + + var myVar1 = func() { + a := myDep1 + println(a) + } + + // invalid + var myDep1 string = "hello" + + myVar1() + + println(myDep0) +} + +var myDep0 string = "world" + +func main() { + + myVar0() +} + +// Error: +// main/funclit2.gno:9:8-14: name myDep1 not declared + +// TypeCheckError: +// main/funclit2.gno:9:8: undefined: myDep1; main/funclit2.gno:14:6: declared and not used: myDep1 diff --git a/gnovm/tests/files/goto6.gno b/gnovm/tests/files/goto6.gno index 2c8e844ac9f..d9e5cc84d18 100644 --- a/gnovm/tests/files/goto6.gno +++ b/gnovm/tests/files/goto6.gno @@ -24,4 +24,4 @@ func main() { // there // TypeCheckError: -// main/files/goto6.gno:6:2: label nowhere declared and not used +// main/goto6.gno:6:2: label nowhere declared and not used diff --git a/gnovm/tests/files/if2.gno b/gnovm/tests/files/if2.gno index 2152e7315cd..74a4a4a9a8d 100644 --- a/gnovm/tests/files/if2.gno +++ b/gnovm/tests/files/if2.gno @@ -10,7 +10,7 @@ func main() { } // Error: -// main/files/if2.gno:7:2: expected typed bool kind, but got IntKind +// main/if2.gno:7:2-9:3: expected typed bool kind, but got IntKind // TypeCheckError: -// main/files/if2.gno:7:5: non-boolean condition in if statement +// main/if2.gno:7:5: non-boolean condition in if statement diff --git a/gnovm/tests/files/import10.gno b/gnovm/tests/files/import10.gno index ba1f2c37218..c23253674dd 100644 --- a/gnovm/tests/files/import10.gno +++ b/gnovm/tests/files/import10.gno @@ -8,7 +8,7 @@ func main() { } // Error: -// main/files/import10.gno:7:10: package fmt cannot only be referred to in a selector expression +// main/import10.gno:7:10-13: package fmt cannot only be referred to in a selector expression // TypeCheckError: -// main/files/import10.gno:7:10: use of package fmt not in selector +// main/import10.gno:7:10: use of package fmt not in selector diff --git a/gnovm/tests/files/import11.gno b/gnovm/tests/files/import11.gno index 594e9f10698..5beaffd9c77 100644 --- a/gnovm/tests/files/import11.gno +++ b/gnovm/tests/files/import11.gno @@ -10,4 +10,4 @@ func main() { } // Error: -// gno.land/p/demo/bar/files/import11.gno:5:2: pure package path "gno.land/p/demo/bar" cannot import realm path "gno.land/r/demo/tests" +// gno.land/p/demo/bar/import11.gno:5:2-25: pure package path "gno.land/p/demo/bar" cannot import realm path "gno.land/r/demo/tests" diff --git a/gnovm/tests/files/import12.gno b/gnovm/tests/files/import12.gno index a3f3fe4fbf6..9426eb4c500 100644 --- a/gnovm/tests/files/import12.gno +++ b/gnovm/tests/files/import12.gno @@ -11,4 +11,4 @@ func main() { } // Error: -// gno.land/p/demo/files/import12.gno:6:2: cannot import stdlib internal/ package outside of standard library +// gno.land/p/demo/import12.gno:6:2-20: cannot import stdlib internal/ package outside of standard library diff --git a/gnovm/tests/files/import13.gno b/gnovm/tests/files/import13.gno index c0aa0e28a01..64ccdb5db91 100644 --- a/gnovm/tests/files/import13.gno +++ b/gnovm/tests/files/import13.gno @@ -11,4 +11,4 @@ func main() { } // Error: -// gno.land/p/demo/files/import13.gno:6:2: internal/ packages can only be imported by packages rooted at the parent of "internal" +// gno.land/p/demo/import13.gno:6:2-48: internal/ packages can only be imported by packages rooted at the parent of "internal" diff --git a/gnovm/tests/files/import13b.gno b/gnovm/tests/files/import13b.gno index bedebb89b2f..ab5ea4e1fed 100644 --- a/gnovm/tests/files/import13b.gno +++ b/gnovm/tests/files/import13b.gno @@ -11,4 +11,4 @@ func main() { } // Error: -// gno.land/p/demo/files/import13b.gno:6:2: internal/ packages can only be imported by packages rooted at the parent of "internal" +// gno.land/p/demo/import13b.gno:6:2-45: internal/ packages can only be imported by packages rooted at the parent of "internal" diff --git a/gnovm/tests/files/import6.gno b/gnovm/tests/files/import6.gno index f3cd9930eb5..c0a8c54a5cc 100644 --- a/gnovm/tests/files/import6.gno +++ b/gnovm/tests/files/import6.gno @@ -7,4 +7,4 @@ func main() { } // Error: -// github.com/gnolang/gno/_test/c2/c2.gno:3:8: import cycle detected: "github.com/gnolang/gno/_test/c1" (through [github.com/gnolang/gno/_test/c1 github.com/gnolang/gno/_test/c2]) +// github.com/gnolang/gno/_test/c2/c2.gno:3:8-41: import cycle detected: "github.com/gnolang/gno/_test/c1" (through [github.com/gnolang/gno/_test/c1 github.com/gnolang/gno/_test/c2]) diff --git a/gnovm/tests/files/init1.gno b/gnovm/tests/files/init1.gno index 1b5493e8b41..5d25a3d97a3 100644 --- a/gnovm/tests/files/init1.gno +++ b/gnovm/tests/files/init1.gno @@ -9,7 +9,7 @@ func main() { } // Error: -// main/files/init1.gno:8:2: name init not declared +// main/init1.gno:8:2-6: name init not declared // TypeCheckError: -// main/files/init1.gno:8:2: undefined: init +// main/init1.gno:8:2: undefined: init diff --git a/gnovm/tests/files/interface47.gno b/gnovm/tests/files/interface47.gno index 2b00661e4bc..bd7c23ee19b 100644 --- a/gnovm/tests/files/interface47.gno +++ b/gnovm/tests/files/interface47.gno @@ -14,7 +14,7 @@ func main() { } // Error: -// main/files/interface47.gno:13:10: main.Runner does not implement main.Swimmer (missing method Swim) +// main/interface47.gno:13:10-20: main.Runner does not implement main.Swimmer (missing method Swim) // TypeCheckError: -// main/files/interface47.gno:13:18: cannot convert a (variable of interface type Runner) to type Swimmer: Runner does not implement Swimmer (missing method Swim) +// main/interface47.gno:13:18: cannot convert a (variable of interface type Runner) to type Swimmer: Runner does not implement Swimmer (missing method Swim) diff --git a/gnovm/tests/files/invalid_labels0.gno b/gnovm/tests/files/invalid_labels0.gno index 65e072c9871..0fe9d109719 100644 --- a/gnovm/tests/files/invalid_labels0.gno +++ b/gnovm/tests/files/invalid_labels0.gno @@ -11,4 +11,4 @@ FirstLoop: } // Error: -// main/files/invalid_labels0.gno:9:3: cannot find branch label "FirstLoop" +// main/invalid_labels0.gno:9:3-18: cannot find branch label "FirstLoop" diff --git a/gnovm/tests/files/invalid_labels1.gno b/gnovm/tests/files/invalid_labels1.gno index 528a3066ac0..fa08d77e6a4 100644 --- a/gnovm/tests/files/invalid_labels1.gno +++ b/gnovm/tests/files/invalid_labels1.gno @@ -9,7 +9,7 @@ func undefinedLabel() { } // Error: -// files/invalid_labels1.gno:7:9: label UndefinedLabel undefined +// invalid_labels1.gno:7:9: label UndefinedLabel undefined // TypeCheckError: -// main/files/invalid_labels1.gno:7:9: invalid break label UndefinedLabel +// main/invalid_labels1.gno:7:9: invalid break label UndefinedLabel diff --git a/gnovm/tests/files/invalid_labels2.gno b/gnovm/tests/files/invalid_labels2.gno index b28cd05371a..4b515428573 100644 --- a/gnovm/tests/files/invalid_labels2.gno +++ b/gnovm/tests/files/invalid_labels2.gno @@ -12,7 +12,7 @@ FirstLoop: } // Error: -// main/files/invalid_labels2.gno:7:3: cannot find branch label "FirstLoop" +// main/invalid_labels2.gno:7:3-21: cannot find branch label "FirstLoop" // TypeCheckError: -// main/files/invalid_labels2.gno:7:12: invalid continue label FirstLoop; main/files/invalid_labels2.gno:9:1: label FirstLoop declared and not used +// main/invalid_labels2.gno:7:12: invalid continue label FirstLoop; main/invalid_labels2.gno:9:1: label FirstLoop declared and not used diff --git a/gnovm/tests/files/invalid_labels3.gno b/gnovm/tests/files/invalid_labels3.gno index 00061e4efab..b7588aba767 100644 --- a/gnovm/tests/files/invalid_labels3.gno +++ b/gnovm/tests/files/invalid_labels3.gno @@ -9,7 +9,7 @@ func invalidLabelStatement() { } // Error: -// files/invalid_labels3.gno:7:9: label InvalidLabel undefined +// invalid_labels3.gno:7:9: label InvalidLabel undefined // TypeCheckError: -// main/files/invalid_labels3.gno:7:9: invalid break label InvalidLabel +// main/invalid_labels3.gno:7:9: invalid break label InvalidLabel diff --git a/gnovm/tests/files/issue_1096.gno b/gnovm/tests/files/issue_1096.gno index 86ae2820319..cbc8a74d5a9 100644 --- a/gnovm/tests/files/issue_1096.gno +++ b/gnovm/tests/files/issue_1096.gno @@ -397,4 +397,4 @@ func (_ Z) manip2(xs ...X) { // 0 // TypeCheckError: -// main/files/issue_1096.gno:134:2: cannot assign to xm[1].Array[1] (neither addressable nor a map index expression) +// main/issue_1096.gno:134:2: cannot assign to xm[1].Array[1] (neither addressable nor a map index expression) diff --git a/gnovm/tests/files/len7.gno b/gnovm/tests/files/len7.gno index 3078a711f85..387bc0ba3e3 100644 --- a/gnovm/tests/files/len7.gno +++ b/gnovm/tests/files/len7.gno @@ -8,4 +8,4 @@ func main() { // unexpected type for len(): *int // TypeCheckError: -// main/files/len7.gno:4:14: invalid argument: new(int) (value of type *int) for built-in len +// main/len7.gno:4:14: invalid argument: new(int) (value of type *int) for built-in len diff --git a/gnovm/tests/files/len8.gno b/gnovm/tests/files/len8.gno index 3ba6b73fcb0..756b9b4f85c 100644 --- a/gnovm/tests/files/len8.gno +++ b/gnovm/tests/files/len8.gno @@ -10,4 +10,4 @@ func main() { // unexpected type for len(): struct{A int; B int} // TypeCheckError: -// main/files/len8.gno:4:14: invalid argument: struct{A, B int}{} (value of type struct{A int; B int}) for built-in len +// main/len8.gno:4:14: invalid argument: struct{A, B int}{} (value of type struct{A int; B int}) for built-in len diff --git a/gnovm/tests/files/map0.gno b/gnovm/tests/files/map0.gno index 0785ee47e38..7799617e765 100644 --- a/gnovm/tests/files/map0.gno +++ b/gnovm/tests/files/map0.gno @@ -12,4 +12,4 @@ func main() { // duplicate key "hello" in map literal // TypeCheckError: -// main/files/map0.gno:7:3: duplicate key "hello" in map literal; main/files/map0.gno:4:2: declared and not used: m +// main/map0.gno:7:3: duplicate key "hello" in map literal; main/map0.gno:4:2: declared and not used: m diff --git a/gnovm/tests/files/map1.gno b/gnovm/tests/files/map1.gno index ad9fb502df8..b47bef5e1ab 100644 --- a/gnovm/tests/files/map1.gno +++ b/gnovm/tests/files/map1.gno @@ -11,4 +11,4 @@ func main() { } // TypeCheckError: -// main/files/map1.gno:5:2: declared and not used: m +// main/map1.gno:5:2: declared and not used: m diff --git a/gnovm/tests/files/native0.gno b/gnovm/tests/files/native0.gno index a6b8f3e67bf..c62dc541531 100644 --- a/gnovm/tests/files/native0.gno +++ b/gnovm/tests/files/native0.gno @@ -7,4 +7,4 @@ func main() { } // Error: -// main/files/native0.gno:3:1: function invalidNative does not have a body but is not natively defined (did you build after pulling from the repository?) +// main/native0.gno:3:1-28: function invalidNative does not have a body but is not natively defined (did you build after pulling from the repository?) diff --git a/gnovm/tests/files/op7.gno b/gnovm/tests/files/op7.gno index c1479d2a17d..a3211b4b5d2 100644 --- a/gnovm/tests/files/op7.gno +++ b/gnovm/tests/files/op7.gno @@ -14,7 +14,7 @@ func main() { } // Error: -// main/files/op7.gno:11:5: operator > not defined on: InterfaceKind +// main/op7.gno:11:5-19: operator > not defined on: InterfaceKind // TypeCheckError: -// main/files/op7.gno:11:5: invalid operation: err > invalidT (operator > not defined on interface) +// main/op7.gno:11:5: invalid operation: err > invalidT (operator > not defined on interface) diff --git a/gnovm/tests/files/overflow10.gno b/gnovm/tests/files/overflow10.gno index 3fdf9df8bf2..8543b81b38b 100644 --- a/gnovm/tests/files/overflow10.gno +++ b/gnovm/tests/files/overflow10.gno @@ -5,7 +5,7 @@ func main() { } // Error: -// main/files/overflow10.gno:3:1: constant overflows +// main/overflow10.gno:3:1-5:2: constant overflows // TypeCheckError: -// main/files/overflow10.gno:4:13: int64(1) << 65 (constant 36893488147419103232 of type int64) overflows int64 +// main/overflow10.gno:4:13: int64(1) << 65 (constant 36893488147419103232 of type int64) overflows int64 diff --git a/gnovm/tests/files/overflow11.gno b/gnovm/tests/files/overflow11.gno index f103a833a71..cfcfb764b37 100644 --- a/gnovm/tests/files/overflow11.gno +++ b/gnovm/tests/files/overflow11.gno @@ -5,7 +5,7 @@ func main() { } // Error: -// main/files/overflow11.gno:3:1: constant overflows +// main/overflow11.gno:3:1-5:2: constant overflows // TypeCheckError: -// main/files/overflow11.gno:4:13: uint8(1) << 8 (constant 256 of type uint8) overflows uint8 +// main/overflow11.gno:4:13: uint8(1) << 8 (constant 256 of type uint8) overflows uint8 diff --git a/gnovm/tests/files/overflow12.gno b/gnovm/tests/files/overflow12.gno index 3e5c851be0d..cc7f477be44 100644 --- a/gnovm/tests/files/overflow12.gno +++ b/gnovm/tests/files/overflow12.gno @@ -5,7 +5,7 @@ func main() { } // Error: -// main/files/overflow12.gno:3:1: constant overflows +// main/overflow12.gno:3:1-5:2: constant overflows // TypeCheckError: -// main/files/overflow12.gno:4:16: uint16(1) << 16 (constant 65536 of type uint16) overflows uint16 +// main/overflow12.gno:4:16: uint16(1) << 16 (constant 65536 of type uint16) overflows uint16 diff --git a/gnovm/tests/files/overflow13.gno b/gnovm/tests/files/overflow13.gno index fd7352b1d21..296dff22295 100644 --- a/gnovm/tests/files/overflow13.gno +++ b/gnovm/tests/files/overflow13.gno @@ -5,7 +5,7 @@ func main() { } // Error: -// main/files/overflow13.gno:3:1: constant overflows +// main/overflow13.gno:3:1-5:2: constant overflows // TypeCheckError: -// main/files/overflow13.gno:4:13: uint32(1) << 33 (constant 8589934592 of type uint32) overflows uint32 +// main/overflow13.gno:4:13: uint32(1) << 33 (constant 8589934592 of type uint32) overflows uint32 diff --git a/gnovm/tests/files/overflow14.gno b/gnovm/tests/files/overflow14.gno index 0ddaaa6a7d6..357005e24cd 100644 --- a/gnovm/tests/files/overflow14.gno +++ b/gnovm/tests/files/overflow14.gno @@ -5,7 +5,7 @@ func main() { } // Error: -// main/files/overflow14.gno:3:1: constant overflows +// main/overflow14.gno:3:1-5:2: constant overflows // TypeCheckError: -// main/files/overflow14.gno:4:16: uint64(1) << 65 (constant 36893488147419103232 of type uint64) overflows uint64 +// main/overflow14.gno:4:16: uint64(1) << 65 (constant 36893488147419103232 of type uint64) overflows uint64 diff --git a/gnovm/tests/files/overflow16.gno b/gnovm/tests/files/overflow16.gno index 96f69dbc495..0b3e9031e9d 100644 --- a/gnovm/tests/files/overflow16.gno +++ b/gnovm/tests/files/overflow16.gno @@ -6,7 +6,7 @@ func main() { } // Error: -// main/files/overflow16.gno:5:2: bigint overflows target kind +// main/overflow16.gno:5:2-13: bigint overflows target kind // TypeCheckError: -// main/files/overflow16.gno:5:10: cannot use c1 (untyped int constant 340282366920938463463374607431768211456) as int value in argument to built-in println (overflows) +// main/overflow16.gno:5:10: cannot use c1 (untyped int constant 340282366920938463463374607431768211456) as int value in argument to built-in println (overflows) diff --git a/gnovm/tests/files/overflow6.gno b/gnovm/tests/files/overflow6.gno index 7cb9d735bf0..537c7d9e99e 100644 --- a/gnovm/tests/files/overflow6.gno +++ b/gnovm/tests/files/overflow6.gno @@ -5,7 +5,7 @@ func main() { } // Error: -// main/files/overflow6.gno:3:1: constant overflows +// main/overflow6.gno:3:1-5:2: constant overflows // TypeCheckError: -// main/files/overflow6.gno:4:12: int32(1) << 33 (constant 8589934592 of type int32) overflows int32 +// main/overflow6.gno:4:12: int32(1) << 33 (constant 8589934592 of type int32) overflows int32 diff --git a/gnovm/tests/files/overflow7.gno b/gnovm/tests/files/overflow7.gno index 67bb88bd557..ade9c5ba411 100644 --- a/gnovm/tests/files/overflow7.gno +++ b/gnovm/tests/files/overflow7.gno @@ -5,7 +5,7 @@ func main() { } // Error: -// main/files/overflow7.gno:3:1: constant overflows +// main/overflow7.gno:3:1-5:2: constant overflows // TypeCheckError: -// main/files/overflow7.gno:4:13: int8(1) << 8 (constant 256 of type int8) overflows int8 +// main/overflow7.gno:4:13: int8(1) << 8 (constant 256 of type int8) overflows int8 diff --git a/gnovm/tests/files/overflow8.gno b/gnovm/tests/files/overflow8.gno index 8fa549b8c23..40132a73542 100644 --- a/gnovm/tests/files/overflow8.gno +++ b/gnovm/tests/files/overflow8.gno @@ -5,7 +5,7 @@ func main() { } // Error: -// main/files/overflow8.gno:3:1: constant overflows +// main/overflow8.gno:3:1-5:2: constant overflows // TypeCheckError: -// main/files/overflow8.gno:4:13: int16(1) << 16 (constant 65536 of type int16) overflows int16 +// main/overflow8.gno:4:13: int16(1) << 16 (constant 65536 of type int16) overflows int16 diff --git a/gnovm/tests/files/overflow9.gno b/gnovm/tests/files/overflow9.gno index 686dc799ee3..d28ecc7d188 100644 --- a/gnovm/tests/files/overflow9.gno +++ b/gnovm/tests/files/overflow9.gno @@ -5,7 +5,7 @@ func main() { } // Error: -// main/files/overflow9.gno:3:1: constant overflows +// main/overflow9.gno:3:1-5:2: constant overflows // TypeCheckError: -// main/files/overflow9.gno:4:13: int32(1) << 33 (constant 8589934592 of type int32) overflows int32 +// main/overflow9.gno:4:13: int32(1) << 33 (constant 8589934592 of type int32) overflows int32 diff --git a/gnovm/tests/files/panic0.gno b/gnovm/tests/files/panic0.gno index 06460ca9d07..b4813ea76b0 100644 --- a/gnovm/tests/files/panic0.gno +++ b/gnovm/tests/files/panic0.gno @@ -7,7 +7,7 @@ func main() { // Stacktrace: // panic: wtf // main() -// main/files/panic0.gno:4 +// main/panic0.gno:4 // Error: // wtf diff --git a/gnovm/tests/files/panic0a.gno b/gnovm/tests/files/panic0a.gno index 5adfc8a1465..fad9596d26b 100644 --- a/gnovm/tests/files/panic0a.gno +++ b/gnovm/tests/files/panic0a.gno @@ -37,9 +37,9 @@ func main() { // Stacktrace: // panic: wtf // f(v.((const-type int)),lit[0],*pit,&vit<~VPBlock(1,0)>,!b,[](const-type string),typeval{main.S},map[(const-type string)] (const-type string),func(s (const-type string)) .res.0 (const-type string){ ... }) -// main/files/panic0a.gno:9 +// main/panic0a.gno:9 // main() -// main/files/panic0a.gno:22 +// main/panic0a.gno:22 // Error: // wtf diff --git a/gnovm/tests/files/panic0b.gno b/gnovm/tests/files/panic0b.gno index 71983bc2aca..9e40fe4fc32 100644 --- a/gnovm/tests/files/panic0b.gno +++ b/gnovm/tests/files/panic0b.gno @@ -17,17 +17,17 @@ func f() { // Stacktrace: // panic: first // f() -// main/files/panic0b.gno:14 +// main/panic0b.gno:14 // main() -// main/files/panic0b.gno:4 +// main/panic0b.gno:4 // ... 1 panic(s) elided ... // panic: third // defer func(){ ... }() -// main/files/panic0b.gno:9 +// main/panic0b.gno:9 // f() -// main/files/panic0b.gno:8 +// main/panic0b.gno:8 // main() -// main/files/panic0b.gno:4 +// main/panic0b.gno:4 // Error: // first diff --git a/gnovm/tests/files/panic0c.gno b/gnovm/tests/files/panic0c.gno index c331ee3bd17..324b3d8d997 100644 --- a/gnovm/tests/files/panic0c.gno +++ b/gnovm/tests/files/panic0c.gno @@ -79,9 +79,9 @@ func main() { // Stacktrace: // panic: wtf // f(a,true,0,1,1,1,1,1,1,1,1,1,1,1,1,strs,st,m,t) -// main/files/panic0c.gno:28 +// main/panic0c.gno:28 // main() -// main/files/panic0c.gno:57 +// main/panic0c.gno:57 // Error: // wtf diff --git a/gnovm/tests/files/panic1.gno b/gnovm/tests/files/panic1.gno index 91e127c7200..d2bc882fbff 100644 --- a/gnovm/tests/files/panic1.gno +++ b/gnovm/tests/files/panic1.gno @@ -25,10 +25,10 @@ func main() { // Stacktrace: // panic: here // main() -// main/files/panic1.gno:22 +// main/panic1.gno:22 // Error: // here // TypeCheckError: -// main/files/panic1.gno:21:2: declared and not used: test +// main/panic1.gno:21:2: declared and not used: test diff --git a/gnovm/tests/files/panic2a.gno b/gnovm/tests/files/panic2a.gno index 7310d6cce71..b2ff20d7b7c 100644 --- a/gnovm/tests/files/panic2a.gno +++ b/gnovm/tests/files/panic2a.gno @@ -14,262 +14,262 @@ func main() { // Stacktrace: // panic: here // p(i + 1) -// main/files/panic2a.gno:5 +// main/panic2a.gno:5 // p(i + 1) -// main/files/panic2a.gno:7 +// main/panic2a.gno:7 // p(i + 1) -// main/files/panic2a.gno:7 +// main/panic2a.gno:7 // p(i + 1) -// main/files/panic2a.gno:7 +// main/panic2a.gno:7 // p(i + 1) -// main/files/panic2a.gno:7 +// main/panic2a.gno:7 // p(i + 1) -// main/files/panic2a.gno:7 +// main/panic2a.gno:7 // p(i + 1) -// main/files/panic2a.gno:7 +// main/panic2a.gno:7 // p(i + 1) -// main/files/panic2a.gno:7 +// main/panic2a.gno:7 // p(i + 1) -// main/files/panic2a.gno:7 +// main/panic2a.gno:7 // p(i + 1) -// main/files/panic2a.gno:7 +// main/panic2a.gno:7 // p(i + 1) -// main/files/panic2a.gno:7 +// main/panic2a.gno:7 // p(i + 1) -// main/files/panic2a.gno:7 +// main/panic2a.gno:7 // p(i + 1) -// main/files/panic2a.gno:7 +// main/panic2a.gno:7 // p(i + 1) -// main/files/panic2a.gno:7 +// main/panic2a.gno:7 // p(i + 1) -// main/files/panic2a.gno:7 +// main/panic2a.gno:7 // p(i + 1) -// main/files/panic2a.gno:7 +// main/panic2a.gno:7 // p(i + 1) -// main/files/panic2a.gno:7 +// main/panic2a.gno:7 // p(i + 1) -// main/files/panic2a.gno:7 +// main/panic2a.gno:7 // p(i + 1) -// main/files/panic2a.gno:7 +// main/panic2a.gno:7 // p(i + 1) -// main/files/panic2a.gno:7 +// main/panic2a.gno:7 // p(i + 1) -// main/files/panic2a.gno:7 +// main/panic2a.gno:7 // p(i + 1) -// main/files/panic2a.gno:7 +// main/panic2a.gno:7 // p(i + 1) -// main/files/panic2a.gno:7 +// main/panic2a.gno:7 // p(i + 1) -// main/files/panic2a.gno:7 +// main/panic2a.gno:7 // p(i + 1) -// main/files/panic2a.gno:7 +// main/panic2a.gno:7 // p(i + 1) -// main/files/panic2a.gno:7 +// main/panic2a.gno:7 // p(i + 1) -// main/files/panic2a.gno:7 +// main/panic2a.gno:7 // p(i + 1) -// main/files/panic2a.gno:7 +// main/panic2a.gno:7 // p(i + 1) -// main/files/panic2a.gno:7 +// main/panic2a.gno:7 // p(i + 1) -// main/files/panic2a.gno:7 +// main/panic2a.gno:7 // p(i + 1) -// main/files/panic2a.gno:7 +// main/panic2a.gno:7 // p(i + 1) -// main/files/panic2a.gno:7 +// main/panic2a.gno:7 // p(i + 1) -// main/files/panic2a.gno:7 +// main/panic2a.gno:7 // p(i + 1) -// main/files/panic2a.gno:7 +// main/panic2a.gno:7 // p(i + 1) -// main/files/panic2a.gno:7 +// main/panic2a.gno:7 // p(i + 1) -// main/files/panic2a.gno:7 +// main/panic2a.gno:7 // p(i + 1) -// main/files/panic2a.gno:7 +// main/panic2a.gno:7 // p(i + 1) -// main/files/panic2a.gno:7 +// main/panic2a.gno:7 // p(i + 1) -// main/files/panic2a.gno:7 +// main/panic2a.gno:7 // p(i + 1) -// main/files/panic2a.gno:7 +// main/panic2a.gno:7 // p(i + 1) -// main/files/panic2a.gno:7 +// main/panic2a.gno:7 // p(i + 1) -// main/files/panic2a.gno:7 +// main/panic2a.gno:7 // p(i + 1) -// main/files/panic2a.gno:7 +// main/panic2a.gno:7 // p(i + 1) -// main/files/panic2a.gno:7 +// main/panic2a.gno:7 // p(i + 1) -// main/files/panic2a.gno:7 +// main/panic2a.gno:7 // p(i + 1) -// main/files/panic2a.gno:7 +// main/panic2a.gno:7 // p(i + 1) -// main/files/panic2a.gno:7 +// main/panic2a.gno:7 // p(i + 1) -// main/files/panic2a.gno:7 +// main/panic2a.gno:7 // p(i + 1) -// main/files/panic2a.gno:7 +// main/panic2a.gno:7 // p(i + 1) -// main/files/panic2a.gno:7 +// main/panic2a.gno:7 // p(i + 1) -// main/files/panic2a.gno:7 +// main/panic2a.gno:7 // p(i + 1) -// main/files/panic2a.gno:7 +// main/panic2a.gno:7 // p(i + 1) -// main/files/panic2a.gno:7 +// main/panic2a.gno:7 // p(i + 1) -// main/files/panic2a.gno:7 +// main/panic2a.gno:7 // p(i + 1) -// main/files/panic2a.gno:7 +// main/panic2a.gno:7 // p(i + 1) -// main/files/panic2a.gno:7 +// main/panic2a.gno:7 // p(i + 1) -// main/files/panic2a.gno:7 +// main/panic2a.gno:7 // p(i + 1) -// main/files/panic2a.gno:7 +// main/panic2a.gno:7 // p(i + 1) -// main/files/panic2a.gno:7 +// main/panic2a.gno:7 // p(i + 1) -// main/files/panic2a.gno:7 +// main/panic2a.gno:7 // p(i + 1) -// main/files/panic2a.gno:7 +// main/panic2a.gno:7 // p(i + 1) -// main/files/panic2a.gno:7 +// main/panic2a.gno:7 // p(i + 1) -// main/files/panic2a.gno:7 +// main/panic2a.gno:7 // p(i + 1) -// main/files/panic2a.gno:7 +// main/panic2a.gno:7 // ...74 frame(s) elided... // p(i + 1) -// main/files/panic2a.gno:7 +// main/panic2a.gno:7 // p(i + 1) -// main/files/panic2a.gno:7 +// main/panic2a.gno:7 // p(i + 1) -// main/files/panic2a.gno:7 +// main/panic2a.gno:7 // p(i + 1) -// main/files/panic2a.gno:7 +// main/panic2a.gno:7 // p(i + 1) -// main/files/panic2a.gno:7 +// main/panic2a.gno:7 // p(i + 1) -// main/files/panic2a.gno:7 +// main/panic2a.gno:7 // p(i + 1) -// main/files/panic2a.gno:7 +// main/panic2a.gno:7 // p(i + 1) -// main/files/panic2a.gno:7 +// main/panic2a.gno:7 // p(i + 1) -// main/files/panic2a.gno:7 +// main/panic2a.gno:7 // p(i + 1) -// main/files/panic2a.gno:7 +// main/panic2a.gno:7 // p(i + 1) -// main/files/panic2a.gno:7 +// main/panic2a.gno:7 // p(i + 1) -// main/files/panic2a.gno:7 +// main/panic2a.gno:7 // p(i + 1) -// main/files/panic2a.gno:7 +// main/panic2a.gno:7 // p(i + 1) -// main/files/panic2a.gno:7 +// main/panic2a.gno:7 // p(i + 1) -// main/files/panic2a.gno:7 +// main/panic2a.gno:7 // p(i + 1) -// main/files/panic2a.gno:7 +// main/panic2a.gno:7 // p(i + 1) -// main/files/panic2a.gno:7 +// main/panic2a.gno:7 // p(i + 1) -// main/files/panic2a.gno:7 +// main/panic2a.gno:7 // p(i + 1) -// main/files/panic2a.gno:7 +// main/panic2a.gno:7 // p(i + 1) -// main/files/panic2a.gno:7 +// main/panic2a.gno:7 // p(i + 1) -// main/files/panic2a.gno:7 +// main/panic2a.gno:7 // p(i + 1) -// main/files/panic2a.gno:7 +// main/panic2a.gno:7 // p(i + 1) -// main/files/panic2a.gno:7 +// main/panic2a.gno:7 // p(i + 1) -// main/files/panic2a.gno:7 +// main/panic2a.gno:7 // p(i + 1) -// main/files/panic2a.gno:7 +// main/panic2a.gno:7 // p(i + 1) -// main/files/panic2a.gno:7 +// main/panic2a.gno:7 // p(i + 1) -// main/files/panic2a.gno:7 +// main/panic2a.gno:7 // p(i + 1) -// main/files/panic2a.gno:7 +// main/panic2a.gno:7 // p(i + 1) -// main/files/panic2a.gno:7 +// main/panic2a.gno:7 // p(i + 1) -// main/files/panic2a.gno:7 +// main/panic2a.gno:7 // p(i + 1) -// main/files/panic2a.gno:7 +// main/panic2a.gno:7 // p(i + 1) -// main/files/panic2a.gno:7 +// main/panic2a.gno:7 // p(i + 1) -// main/files/panic2a.gno:7 +// main/panic2a.gno:7 // p(i + 1) -// main/files/panic2a.gno:7 +// main/panic2a.gno:7 // p(i + 1) -// main/files/panic2a.gno:7 +// main/panic2a.gno:7 // p(i + 1) -// main/files/panic2a.gno:7 +// main/panic2a.gno:7 // p(i + 1) -// main/files/panic2a.gno:7 +// main/panic2a.gno:7 // p(i + 1) -// main/files/panic2a.gno:7 +// main/panic2a.gno:7 // p(i + 1) -// main/files/panic2a.gno:7 +// main/panic2a.gno:7 // p(i + 1) -// main/files/panic2a.gno:7 +// main/panic2a.gno:7 // p(i + 1) -// main/files/panic2a.gno:7 +// main/panic2a.gno:7 // p(i + 1) -// main/files/panic2a.gno:7 +// main/panic2a.gno:7 // p(i + 1) -// main/files/panic2a.gno:7 +// main/panic2a.gno:7 // p(i + 1) -// main/files/panic2a.gno:7 +// main/panic2a.gno:7 // p(i + 1) -// main/files/panic2a.gno:7 +// main/panic2a.gno:7 // p(i + 1) -// main/files/panic2a.gno:7 +// main/panic2a.gno:7 // p(i + 1) -// main/files/panic2a.gno:7 +// main/panic2a.gno:7 // p(i + 1) -// main/files/panic2a.gno:7 +// main/panic2a.gno:7 // p(i + 1) -// main/files/panic2a.gno:7 +// main/panic2a.gno:7 // p(i + 1) -// main/files/panic2a.gno:7 +// main/panic2a.gno:7 // p(i + 1) -// main/files/panic2a.gno:7 +// main/panic2a.gno:7 // p(i + 1) -// main/files/panic2a.gno:7 +// main/panic2a.gno:7 // p(i + 1) -// main/files/panic2a.gno:7 +// main/panic2a.gno:7 // p(i + 1) -// main/files/panic2a.gno:7 +// main/panic2a.gno:7 // p(i + 1) -// main/files/panic2a.gno:7 +// main/panic2a.gno:7 // p(i + 1) -// main/files/panic2a.gno:7 +// main/panic2a.gno:7 // p(i + 1) -// main/files/panic2a.gno:7 +// main/panic2a.gno:7 // p(i + 1) -// main/files/panic2a.gno:7 +// main/panic2a.gno:7 // p(i + 1) -// main/files/panic2a.gno:7 +// main/panic2a.gno:7 // p(i + 1) -// main/files/panic2a.gno:7 +// main/panic2a.gno:7 // p(i + 1) -// main/files/panic2a.gno:7 +// main/panic2a.gno:7 // p(i + 1) -// main/files/panic2a.gno:7 +// main/panic2a.gno:7 // p(0) -// main/files/panic2a.gno:7 +// main/panic2a.gno:7 // main() -// main/files/panic2a.gno:11 +// main/panic2a.gno:11 // Error: // here diff --git a/gnovm/tests/files/panic2b.gno b/gnovm/tests/files/panic2b.gno index 225800587fb..2f8b4445714 100644 --- a/gnovm/tests/files/panic2b.gno +++ b/gnovm/tests/files/panic2b.gno @@ -17,25 +17,25 @@ func main() { // Stacktrace: // panic: here // p(i + 1) -// main/files/panic2b.gno:8 +// main/panic2b.gno:8 // p(i + 1) -// main/files/panic2b.gno:10 +// main/panic2b.gno:10 // p(i + 1) -// main/files/panic2b.gno:10 +// main/panic2b.gno:10 // p(i + 1) -// main/files/panic2b.gno:10 +// main/panic2b.gno:10 // p(0) -// main/files/panic2b.gno:10 +// main/panic2b.gno:10 // main() -// main/files/panic2b.gno:14 +// main/panic2b.gno:14 // ... 4 panic(s) elided ... // panic: here // defer func(){ ... }() -// main/files/panic2b.gno:5 +// main/panic2b.gno:5 // p(0) -// main/files/panic2b.gno:4 +// main/panic2b.gno:4 // main() -// main/files/panic2b.gno:14 +// main/panic2b.gno:14 // Error: // here diff --git a/gnovm/tests/files/parse_err0.gno b/gnovm/tests/files/parse_err0.gno index 2e428953942..98e5cb15e36 100644 --- a/gnovm/tests/files/parse_err0.gno +++ b/gnovm/tests/files/parse_err0.gno @@ -7,7 +7,7 @@ func () A() func main() {} // Error: -// files/parse_err0.gno:5:1: method has no receiver +// parse_err0.gno:5:1: method has no receiver // TypeCheckError: -// main/files/parse_err0.gno:5:6: method has no receiver +// main/parse_err0.gno:5:6: method has no receiver diff --git a/gnovm/tests/files/parse_err1.gno b/gnovm/tests/files/parse_err1.gno index d2b79226125..6fa57ab0060 100644 --- a/gnovm/tests/files/parse_err1.gno +++ b/gnovm/tests/files/parse_err1.gno @@ -13,7 +13,7 @@ func (n *node) foo(targ, wndex int) { func main() {} // Error: -// files/parse_err1.gno:10:6: invalid operation: more than one index +// parse_err1.gno:10:6: invalid operation: more than one index // TypeCheckError: -// main/files/parse_err1.gno:10:16: invalid operation: more than one index +// main/parse_err1.gno:10:16: invalid operation: more than one index diff --git a/gnovm/tests/files/parse_err2.gno b/gnovm/tests/files/parse_err2.gno index 9c711cff1fe..bfdcd21974f 100644 --- a/gnovm/tests/files/parse_err2.gno +++ b/gnovm/tests/files/parse_err2.gno @@ -13,4 +13,4 @@ func TestAdd(t *testing.T) { } // Error: -// files/parse_err2.gno:12:2: goroutines are not permitted +// parse_err2.gno:12:2: goroutines are not permitted diff --git a/gnovm/tests/files/pkgname1.gno b/gnovm/tests/files/pkgname1.gno index 4e31f5dc9ed..9f849b03b16 100644 --- a/gnovm/tests/files/pkgname1.gno +++ b/gnovm/tests/files/pkgname1.gno @@ -10,7 +10,7 @@ func main() { } // Error: -// main/files/pkgname1.gno:5:2: package name for "github.com/gnolang/gno/_test/bar" ("quux") doesn't match its expected identifier "bar"; the import declaration must specify an identifier +// main/pkgname1.gno:5:2-36: package name for "github.com/gnolang/gno/_test/bar" ("quux") doesn't match its expected identifier "bar"; the import declaration must specify an identifier // TypeCheckError: -// main/files/pkgname1.gno:9:19: undefined: bar; main/files/pkgname1.gno:5:2: "github.com/gnolang/gno/_test/bar" imported as quux and not used +// main/pkgname1.gno:9:19: undefined: bar; main/pkgname1.gno:5:2: "github.com/gnolang/gno/_test/bar" imported as quux and not used diff --git a/gnovm/tests/files/ptr10.gno b/gnovm/tests/files/ptr10.gno index 2ef6346553a..feb8dbd46c4 100644 --- a/gnovm/tests/files/ptr10.gno +++ b/gnovm/tests/files/ptr10.gno @@ -5,7 +5,7 @@ func main() { } // Error: -// main/files/ptr10.gno:4:10: invalid operation: cannot indirect nil +// main/ptr10.gno:4:10-14: invalid operation: cannot indirect nil // TypeCheckError: -// main/files/ptr10.gno:4:11: invalid operation: cannot indirect nil +// main/ptr10.gno:4:11: invalid operation: cannot indirect nil diff --git a/gnovm/tests/files/ptr9.gno b/gnovm/tests/files/ptr9.gno index e5075fb6fc0..fd4f6d09f32 100644 --- a/gnovm/tests/files/ptr9.gno +++ b/gnovm/tests/files/ptr9.gno @@ -6,7 +6,7 @@ func main() { } // Error: -// main/files/ptr9.gno:5:10: invalid operation: cannot indirect v (variable of type int) +// main/ptr9.gno:5:10-12: invalid operation: cannot indirect v (variable of type int) // TypeCheckError: -// main/files/ptr9.gno:5:11: invalid operation: cannot indirect v (variable of type int) +// main/ptr9.gno:5:11: invalid operation: cannot indirect v (variable of type int) diff --git a/gnovm/tests/files/range8.gno b/gnovm/tests/files/range8.gno index 63698dd58e9..7762d097181 100644 --- a/gnovm/tests/files/range8.gno +++ b/gnovm/tests/files/range8.gno @@ -7,7 +7,7 @@ func main() { } // Error: -// main/files/range8.gno:4:2: cannot range over nil +// main/range8.gno:4:2-6:3: cannot range over nil // TypeCheckError: -// main/files/range8.gno:4:20: cannot range over nil +// main/range8.gno:4:20: cannot range over nil diff --git a/gnovm/tests/files/recover10.gno b/gnovm/tests/files/recover10.gno index de083a322a4..4f233b50ff3 100644 --- a/gnovm/tests/files/recover10.gno +++ b/gnovm/tests/files/recover10.gno @@ -9,7 +9,7 @@ func main() { // Stacktrace: // panic: ahhhhh // main() -// main/files/recover10.gno:6 +// main/recover10.gno:6 // Error: // ahhhhh diff --git a/gnovm/tests/files/recover13.gno b/gnovm/tests/files/recover13.gno index 3f3d5053ac0..6b8bfaa754a 100644 --- a/gnovm/tests/files/recover13.gno +++ b/gnovm/tests/files/recover13.gno @@ -15,4 +15,4 @@ func main() { // recover: invalid slice index -1 (index must be non-negative) // TypeCheckError: -// main/files/recover13.gno:11:13: invalid argument: index -1 (constant of type int) must not be negative +// main/recover13.gno:11:13: invalid argument: index -1 (constant of type int) must not be negative diff --git a/gnovm/tests/files/recover16.gno b/gnovm/tests/files/recover16.gno index 50ed4473a79..09dc22db9b7 100644 --- a/gnovm/tests/files/recover16.gno +++ b/gnovm/tests/files/recover16.gno @@ -14,4 +14,4 @@ func main() { // recover: len out of range // TypeCheckError: -// main/files/recover16.gno:10:21: invalid argument: index -1 (constant of type int) must not be negative +// main/recover16.gno:10:21: invalid argument: index -1 (constant of type int) must not be negative diff --git a/gnovm/tests/files/recover1b.gno b/gnovm/tests/files/recover1b.gno index 992be389e18..58a40c0478f 100644 --- a/gnovm/tests/files/recover1b.gno +++ b/gnovm/tests/files/recover1b.gno @@ -13,12 +13,12 @@ func main() { // Stacktrace: // panic: other panic // defer func(){ ... }() -// main/files/recover1b.gno:8 +// main/recover1b.gno:8 // main() -// main/files/recover1b.gno:6 +// main/recover1b.gno:6 // Error: // other panic // TypeCheckError: -// main/files/recover1b.gno:3:8: "fmt" imported and not used +// main/recover1b.gno:3:8: "fmt" imported and not used diff --git a/gnovm/tests/files/recover20.gno b/gnovm/tests/files/recover20.gno index 58e5191d910..ffa4436c16b 100644 --- a/gnovm/tests/files/recover20.gno +++ b/gnovm/tests/files/recover20.gno @@ -13,4 +13,4 @@ func main() { // Stacktrace: // panic: nil pointer dereference // main() -// main/files/recover20.gno:5 +// main/recover20.gno:5 diff --git a/gnovm/tests/files/recover8.gno b/gnovm/tests/files/recover8.gno index 8ee5a1f4e9c..561b2745ef3 100644 --- a/gnovm/tests/files/recover8.gno +++ b/gnovm/tests/files/recover8.gno @@ -23,11 +23,11 @@ func main() { // Stacktrace: // panic: do something panic // defer func(){ ... }() -// main/files/recover8.gno:7 +// main/recover8.gno:7 // doSomething() -// main/files/recover8.gno:4 +// main/recover8.gno:4 // main() -// main/files/recover8.gno:20 +// main/recover8.gno:20 // Error: // do something panic diff --git a/gnovm/tests/files/recursive1.gno b/gnovm/tests/files/recursive1.gno index bfd3e0ebaa0..840a3ca2214 100644 --- a/gnovm/tests/files/recursive1.gno +++ b/gnovm/tests/files/recursive1.gno @@ -10,7 +10,7 @@ func main() { } // Error: -// main/files/recursive1.gno:3:6: invalid recursive type: S -> S +// main/recursive1.gno:3:6-5:2: invalid recursive type: S -> S // TypeCheckError: -// main/files/recursive1.gno:3:6: invalid recursive type: S refers to itself +// main/recursive1.gno:3:6: invalid recursive type: S refers to itself diff --git a/gnovm/tests/files/recursive10.gno b/gnovm/tests/files/recursive10.gno new file mode 100644 index 00000000000..19789fdd57b --- /dev/null +++ b/gnovm/tests/files/recursive10.gno @@ -0,0 +1,17 @@ +package main + +func A() int { return b } +func B() int { return a } + +var a = func() int { return A() }() +var b = func() int { return B() }() + +func main() { + println(a, b) +} + +// Error: +// main/recursive10.gno:3:1: loop in variable initialization: dependency trail [b B a A] circularly depends on b + +// TypeCheckError: +// main/recursive10.gno:6:5: initialization cycle for a; main/recursive10.gno:6:5: a refers to A; main/recursive10.gno:3:6: A refers to b; main/recursive10.gno:7:5: b refers to B; main/recursive10.gno:4:6: B refers to a diff --git a/gnovm/tests/files/recursive11.gno b/gnovm/tests/files/recursive11.gno new file mode 100644 index 00000000000..756796f5f22 --- /dev/null +++ b/gnovm/tests/files/recursive11.gno @@ -0,0 +1,13 @@ +package main + +var A = func() { B() } +var B = func() { A() } + +func main() { +} + +// Error: +// main/recursive11.gno:3:5: loop in variable initialization: dependency trail [B A] circularly depends on B + +// TypeCheckError: +// main/recursive11.gno:3:5: initialization cycle for A; main/recursive11.gno:3:5: A refers to B; main/recursive11.gno:4:5: B refers to A diff --git a/gnovm/tests/files/recursive1c.gno b/gnovm/tests/files/recursive1c.gno index 37a2d9d4d7c..e939bbaf4a5 100644 --- a/gnovm/tests/files/recursive1c.gno +++ b/gnovm/tests/files/recursive1c.gno @@ -14,7 +14,7 @@ func main() { } // Error: -// main/files/recursive1c.gno:5:6: invalid recursive type: S -> S +// main/recursive1c.gno:5:6-7:2: invalid recursive type: S -> S // TypeCheckError: -// main/files/recursive1c.gno:5:6: invalid recursive type: S refers to itself +// main/recursive1c.gno:5:6: invalid recursive type: S refers to itself diff --git a/gnovm/tests/files/recursive1d.gno b/gnovm/tests/files/recursive1d.gno index ecccd9f90e9..7fe0b7618bb 100644 --- a/gnovm/tests/files/recursive1d.gno +++ b/gnovm/tests/files/recursive1d.gno @@ -14,7 +14,7 @@ func main() { } // Error: -// main/files/recursive1d.gno:5:6: invalid recursive type: S -> S +// main/recursive1d.gno:5:6-7:2: invalid recursive type: S -> S // TypeCheckError: -// main/files/recursive1d.gno:5:6: invalid recursive type: S refers to itself +// main/recursive1d.gno:5:6: invalid recursive type: S refers to itself diff --git a/gnovm/tests/files/recursive1e.gno b/gnovm/tests/files/recursive1e.gno index b04e82f9f99..875ac6a2893 100644 --- a/gnovm/tests/files/recursive1e.gno +++ b/gnovm/tests/files/recursive1e.gno @@ -13,4 +13,4 @@ func main() { // (struct{(array[(nil []main.S),(nil []main.S)] [2][]main.S)} main.S) // TypeCheckError: -// main/files/recursive1e.gno:8:9: declared and not used: b +// main/recursive1e.gno:8:9: declared and not used: b diff --git a/gnovm/tests/files/recursive1f.gno b/gnovm/tests/files/recursive1f.gno index 41be4957b89..3ed5e1ecaf0 100644 --- a/gnovm/tests/files/recursive1f.gno +++ b/gnovm/tests/files/recursive1f.gno @@ -10,7 +10,7 @@ func main() { } // Error: -// main/files/recursive1f.gno:4:7: invalid recursive type: S -> S +// main/recursive1f.gno:4:7-6:3: invalid recursive type: S -> S // TypeCheckError: -// main/files/recursive1f.gno:4:7: invalid recursive type: S refers to itself +// main/recursive1f.gno:4:7: invalid recursive type: S refers to itself diff --git a/gnovm/tests/files/recursive2.gno b/gnovm/tests/files/recursive2.gno index e995c68201e..82b52ce7467 100644 --- a/gnovm/tests/files/recursive2.gno +++ b/gnovm/tests/files/recursive2.gno @@ -18,7 +18,7 @@ func main() { } // Error: -// main/files/recursive2.gno:3:6: invalid recursive type: A -> B -> C -> A +// main/recursive2.gno:3:6-5:2: invalid recursive type: A -> B -> C -> A // TypeCheckError: -// main/files/recursive2.gno:3:6: invalid recursive type A; main/files/recursive2.gno:3:6: A refers to B; main/files/recursive2.gno:7:6: B refers to C; main/files/recursive2.gno:11:6: C refers to A +// main/recursive2.gno:3:6: invalid recursive type A; main/recursive2.gno:3:6: A refers to B; main/recursive2.gno:7:6: B refers to C; main/recursive2.gno:11:6: C refers to A diff --git a/gnovm/tests/files/recursive2c.gno b/gnovm/tests/files/recursive2c.gno index 868e3b137ed..e041faf6095 100644 --- a/gnovm/tests/files/recursive2c.gno +++ b/gnovm/tests/files/recursive2c.gno @@ -18,7 +18,7 @@ func main() { } // Error: -// main/files/recursive2c.gno:4:7: name B not defined in fileset with files [files/recursive2c.gno] +// main/recursive2c.gno:4:7-6:3: name B not defined in fileset with files [recursive2c.gno] // TypeCheckError: -// main/files/recursive2c.gno:5:5: undefined: B; main/files/recursive2c.gno:9:5: undefined: C +// main/recursive2c.gno:5:5: undefined: B; main/recursive2c.gno:9:5: undefined: C diff --git a/gnovm/tests/files/recursive4a.gno b/gnovm/tests/files/recursive4a.gno index 4c1d0996c50..c1714480fde 100644 --- a/gnovm/tests/files/recursive4a.gno +++ b/gnovm/tests/files/recursive4a.gno @@ -6,7 +6,7 @@ func main() { } // Error: -// main/files/recursive4a.gno:3:6: invalid recursive type: time -> time +// main/recursive4a.gno:3:6-24: invalid recursive type: time -> time // TypeCheckError: -// main/files/recursive4a.gno:3:6: invalid recursive type: time refers to itself +// main/recursive4a.gno:3:6: invalid recursive type: time refers to itself diff --git a/gnovm/tests/files/recursive5.gno b/gnovm/tests/files/recursive5.gno index 166fbe826a4..c1887d5bfa2 100644 --- a/gnovm/tests/files/recursive5.gno +++ b/gnovm/tests/files/recursive5.gno @@ -10,7 +10,7 @@ func main() { } // Error: -// main/files/recursive5.gno:3:6: invalid recursive type: S -> S +// main/recursive5.gno:3:6-5:2: invalid recursive type: S -> S // TypeCheckError: -// main/files/recursive5.gno:3:6: invalid recursive type: S refers to itself +// main/recursive5.gno:3:6: invalid recursive type: S refers to itself diff --git a/gnovm/tests/files/recursive6a.gno b/gnovm/tests/files/recursive6a.gno index c498b9738e7..e6faa8962f3 100644 --- a/gnovm/tests/files/recursive6a.gno +++ b/gnovm/tests/files/recursive6a.gno @@ -9,7 +9,7 @@ func main() { } // Error: -// main/files/recursive6a.gno:3:6: invalid recursive type: SelfReferencing -> SelfReferencing +// main/recursive6a.gno:3:6-5:2: invalid recursive type: SelfReferencing -> SelfReferencing // TypeCheckError: -// main/files/recursive6a.gno:3:6: invalid recursive type: SelfReferencing refers to itself +// main/recursive6a.gno:3:6: invalid recursive type: SelfReferencing refers to itself diff --git a/gnovm/tests/files/recursive7a.gno b/gnovm/tests/files/recursive7a.gno index a4c0b648111..dae6611ed3f 100644 --- a/gnovm/tests/files/recursive7a.gno +++ b/gnovm/tests/files/recursive7a.gno @@ -5,7 +5,7 @@ type S [2]S func main() {} // Error: -// main/files/recursive7a.gno:3:6: invalid recursive type: S -> S +// main/recursive7a.gno:3:6-12: invalid recursive type: S -> S // TypeCheckError: -// main/files/recursive7a.gno:3:6: invalid recursive type: S refers to itself +// main/recursive7a.gno:3:6: invalid recursive type: S refers to itself diff --git a/gnovm/tests/files/recursive8.gno b/gnovm/tests/files/recursive8.gno index 007ef805aa9..d3bad756fe7 100644 --- a/gnovm/tests/files/recursive8.gno +++ b/gnovm/tests/files/recursive8.gno @@ -5,7 +5,7 @@ type Int Int func main() {} // Error: -// main/files/recursive8.gno:3:6: invalid recursive type: Int -> Int +// main/recursive8.gno:3:6-13: invalid recursive type: Int -> Int // TypeCheckError: -// main/files/recursive8.gno:3:6: invalid recursive type: Int refers to itself +// main/recursive8.gno:3:6: invalid recursive type: Int refers to itself diff --git a/gnovm/tests/files/recursive9.gno b/gnovm/tests/files/recursive9.gno index 4f7c8c7ac13..969edf09dc2 100644 --- a/gnovm/tests/files/recursive9.gno +++ b/gnovm/tests/files/recursive9.gno @@ -5,7 +5,7 @@ type Int = Int func main() {} // Error: -// main/files/recursive9.gno:3:6: invalid recursive type: Int -> Int +// main/recursive9.gno:3:6-15: invalid recursive type: Int -> Int // TypeCheckError: -// main/files/recursive9.gno:3:6: invalid recursive type: Int refers to itself +// main/recursive9.gno:3:6: invalid recursive type: Int refers to itself diff --git a/gnovm/tests/files/recursive9a.gno b/gnovm/tests/files/recursive9a.gno index b9803f70adb..db0c2c9e60a 100644 --- a/gnovm/tests/files/recursive9a.gno +++ b/gnovm/tests/files/recursive9a.gno @@ -5,7 +5,7 @@ type Int = *Int func main() {} // Error: -// main/files/recursive9a.gno:3:6: invalid recursive type: Int -> Int +// main/recursive9a.gno:3:6-16: invalid recursive type: Int -> Int // TypeCheckError: -// main/files/recursive9a.gno:3:6: invalid recursive type: Int refers to itself +// main/recursive9a.gno:3:6: invalid recursive type: Int refers to itself diff --git a/gnovm/tests/files/recursive9b.gno b/gnovm/tests/files/recursive9b.gno index 8c34df37e52..48f5bd4d479 100644 --- a/gnovm/tests/files/recursive9b.gno +++ b/gnovm/tests/files/recursive9b.gno @@ -5,7 +5,7 @@ type Int = func() Int func main() {} // Error: -// main/files/recursive9b.gno:3:6: invalid recursive type: Int -> Int +// main/recursive9b.gno:3:6-22: invalid recursive type: Int -> Int // TypeCheckError: -// main/files/recursive9b.gno:3:6: invalid recursive type: Int refers to itself +// main/recursive9b.gno:3:6: invalid recursive type: Int refers to itself diff --git a/gnovm/tests/files/recursive9c.gno b/gnovm/tests/files/recursive9c.gno index f6a41bbe51c..121f48bf844 100644 --- a/gnovm/tests/files/recursive9c.gno +++ b/gnovm/tests/files/recursive9c.gno @@ -5,7 +5,7 @@ type Int = []Int func main() {} // Error: -// main/files/recursive9c.gno:3:6: invalid recursive type: Int -> Int +// main/recursive9c.gno:3:6-17: invalid recursive type: Int -> Int // TypeCheckError: -// main/files/recursive9c.gno:3:6: invalid recursive type: Int refers to itself +// main/recursive9c.gno:3:6: invalid recursive type: Int refers to itself diff --git a/gnovm/tests/files/recursive9d.gno b/gnovm/tests/files/recursive9d.gno index 43562a92520..66dc8152f61 100644 --- a/gnovm/tests/files/recursive9d.gno +++ b/gnovm/tests/files/recursive9d.gno @@ -7,7 +7,7 @@ type S = struct { func main() {} // Error: -// main/files/recursive9d.gno:3:6: invalid recursive type: S -> S +// main/recursive9d.gno:3:6-5:2: invalid recursive type: S -> S // TypeCheckError: -// main/files/recursive9d.gno:3:6: invalid recursive type: S refers to itself +// main/recursive9d.gno:3:6: invalid recursive type: S refers to itself diff --git a/gnovm/tests/files/redeclaration0.gno b/gnovm/tests/files/redeclaration0.gno index 710f1213072..f0f6f67eca7 100644 --- a/gnovm/tests/files/redeclaration0.gno +++ b/gnovm/tests/files/redeclaration0.gno @@ -11,8 +11,8 @@ func main() { } // Error: -// files/redeclaration0.gno:8:6: foo redeclared in this block -// previous declaration at files/redeclaration0.gno:4:7 +// redeclaration0.gno:8:6: foo redeclared in this block +// previous declaration at redeclaration0.gno:4:7 // TypeCheckError: -// main/files/redeclaration0.gno:8:6: foo redeclared in this block; main/files/redeclaration0.gno:4:7: other declaration of foo; main/files/redeclaration0.gno:9:2: foo (type) is not an expression; main/files/redeclaration0.gno:10:10: foo (type) is not an expression +// main/redeclaration0.gno:8:6: foo redeclared in this block; main/redeclaration0.gno:4:7: other declaration of foo; main/redeclaration0.gno:9:2: foo (type) is not an expression; main/redeclaration0.gno:10:10: foo (type) is not an expression diff --git a/gnovm/tests/files/redeclaration1.gno b/gnovm/tests/files/redeclaration1.gno index cd63b150b89..ca776435817 100644 --- a/gnovm/tests/files/redeclaration1.gno +++ b/gnovm/tests/files/redeclaration1.gno @@ -9,8 +9,8 @@ func main() { } // Error: -// files/redeclaration1.gno:6:6: foo redeclared in this block -// previous declaration at files/redeclaration1.gno:4:6 +// redeclaration1.gno:6:6: foo redeclared in this block +// previous declaration at redeclaration1.gno:4:6 // TypeCheckError: -// main/files/redeclaration1.gno:6:6: foo redeclared in this block; main/files/redeclaration1.gno:4:6: other declaration of foo; main/files/redeclaration1.gno:7:8: cannot use 2 (untyped int constant) as string value in assignment +// main/redeclaration1.gno:6:6: foo redeclared in this block; main/redeclaration1.gno:4:6: other declaration of foo; main/redeclaration1.gno:7:8: cannot use 2 (untyped int constant) as string value in assignment diff --git a/gnovm/tests/files/redeclaration2.gno b/gnovm/tests/files/redeclaration2.gno index 7ff2bec0b57..c178e4607f2 100644 --- a/gnovm/tests/files/redeclaration2.gno +++ b/gnovm/tests/files/redeclaration2.gno @@ -11,8 +11,8 @@ func main() { } // Error: -// files/redeclaration2.gno:8:6: foo redeclared in this block -// previous declaration at files/redeclaration2.gno:4:6 +// redeclaration2.gno:8:6: foo redeclared in this block +// previous declaration at redeclaration2.gno:4:6 // TypeCheckError: -// main/files/redeclaration2.gno:8:6: foo redeclared in this block; main/files/redeclaration2.gno:4:6: other declaration of foo; main/files/redeclaration2.gno:9:8: cannot use 2 (untyped int constant) as struct{yolo string} value in assignment +// main/redeclaration2.gno:8:6: foo redeclared in this block; main/redeclaration2.gno:4:6: other declaration of foo; main/redeclaration2.gno:9:8: cannot use 2 (untyped int constant) as struct{yolo string} value in assignment diff --git a/gnovm/tests/files/redeclaration3.gno b/gnovm/tests/files/redeclaration3.gno index 8105132e688..b0bec6fdb92 100644 --- a/gnovm/tests/files/redeclaration3.gno +++ b/gnovm/tests/files/redeclaration3.gno @@ -10,8 +10,8 @@ func main() { } // Error: -// files/redeclaration3.gno:7:7: foo redeclared in this block -// previous declaration at files/redeclaration3.gno:4:6 +// redeclaration3.gno:7:7: foo redeclared in this block +// previous declaration at redeclaration3.gno:4:6 // TypeCheckError: -// main/files/redeclaration3.gno:7:7: foo redeclared in this block; main/files/redeclaration3.gno:4:6: other declaration of foo; main/files/redeclaration3.gno:8:10: foo is not a type +// main/redeclaration3.gno:7:7: foo redeclared in this block; main/redeclaration3.gno:4:6: other declaration of foo; main/redeclaration3.gno:8:10: foo is not a type diff --git a/gnovm/tests/files/redeclaration4.gno b/gnovm/tests/files/redeclaration4.gno index ee1e067a3dd..7c8c2bca797 100644 --- a/gnovm/tests/files/redeclaration4.gno +++ b/gnovm/tests/files/redeclaration4.gno @@ -11,8 +11,8 @@ func main() { } // Error: -// files/redeclaration4.gno:8:7: foo redeclared in this block -// previous declaration at files/redeclaration4.gno:4:6 +// redeclaration4.gno:8:7: foo redeclared in this block +// previous declaration at redeclaration4.gno:4:6 // TypeCheckError: -// main/files/redeclaration4.gno:8:7: foo redeclared in this block; main/files/redeclaration4.gno:4:6: other declaration of foo; main/files/redeclaration4.gno:9:10: foo is not a type +// main/redeclaration4.gno:8:7: foo redeclared in this block; main/redeclaration4.gno:4:6: other declaration of foo; main/redeclaration4.gno:9:10: foo is not a type diff --git a/gnovm/tests/files/redeclaration5.gno b/gnovm/tests/files/redeclaration5.gno index 25cd562971e..7580813e6a6 100644 --- a/gnovm/tests/files/redeclaration5.gno +++ b/gnovm/tests/files/redeclaration5.gno @@ -11,8 +11,8 @@ func main() { } // Error: -// files/redeclaration5.gno:8:7: foo redeclared in this block -// previous declaration at files/redeclaration5.gno:4:7 +// redeclaration5.gno:8:7: foo redeclared in this block +// previous declaration at redeclaration5.gno:4:7 // TypeCheckError: -// main/files/redeclaration5.gno:8:7: foo redeclared in this block; main/files/redeclaration5.gno:4:7: other declaration of foo +// main/redeclaration5.gno:8:7: foo redeclared in this block; main/redeclaration5.gno:4:7: other declaration of foo diff --git a/gnovm/tests/files/redeclaration7.gno b/gnovm/tests/files/redeclaration7.gno index d987a58d7eb..8aef876dd48 100644 --- a/gnovm/tests/files/redeclaration7.gno +++ b/gnovm/tests/files/redeclaration7.gno @@ -9,5 +9,5 @@ func main() { } // Error: -// files/redeclaration7.gno:5:6: f1 redeclared in this block -// previous declaration at files/redeclaration7.gno:3:6 +// redeclaration7.gno:5:6: f1 redeclared in this block +// previous declaration at redeclaration7.gno:3:6 diff --git a/gnovm/tests/files/redeclaration9.gno b/gnovm/tests/files/redeclaration9.gno index 76f887acce8..a7cfb42f0fc 100644 --- a/gnovm/tests/files/redeclaration9.gno +++ b/gnovm/tests/files/redeclaration9.gno @@ -11,7 +11,7 @@ func main() { } // Error: -// main/files/redeclaration9.gno:7:1: redeclaration of method a.method +// main/redeclaration9.gno:7:1-37: redeclaration of method a.method // TypeCheckError: -// main/files/redeclaration9.gno:7:12: method a.method already declared at main/files/redeclaration9.gno:5:12 +// main/redeclaration9.gno:7:12: method a.method already declared at main/redeclaration9.gno:5:12 diff --git a/gnovm/tests/files/redeclaration_global0.gno b/gnovm/tests/files/redeclaration_global0.gno index 044e4d38ced..fd86fbf82f8 100644 --- a/gnovm/tests/files/redeclaration_global0.gno +++ b/gnovm/tests/files/redeclaration_global0.gno @@ -10,8 +10,8 @@ func main() { } // Error: -// files/redeclaration_global0.gno:5:5: time redeclared in this block -// previous declaration at files/redeclaration_global0.gno:3:6 +// redeclaration_global0.gno:5:5: time redeclared in this block +// previous declaration at redeclaration_global0.gno:3:6 // TypeCheckError: -// main/files/redeclaration_global0.gno:5:5: time redeclared in this block; main/files/redeclaration_global0.gno:3:6: other declaration of time; main/files/redeclaration_global0.gno:8:2: time (type) is not an expression; main/files/redeclaration_global0.gno:9:10: time (type) is not an expression +// main/redeclaration_global0.gno:5:5: time redeclared in this block; main/redeclaration_global0.gno:3:6: other declaration of time; main/redeclaration_global0.gno:8:2: time (type) is not an expression; main/redeclaration_global0.gno:9:10: time (type) is not an expression diff --git a/gnovm/tests/files/redeclaration_global1.gno b/gnovm/tests/files/redeclaration_global1.gno index 256cb0d2b7c..761e2bd605b 100644 --- a/gnovm/tests/files/redeclaration_global1.gno +++ b/gnovm/tests/files/redeclaration_global1.gno @@ -10,8 +10,8 @@ func main() { } // Error: -// files/redeclaration_global1.gno:5:6: time redeclared in this block -// previous declaration at files/redeclaration_global1.gno:3:5 +// redeclaration_global1.gno:5:6: time redeclared in this block +// previous declaration at redeclaration_global1.gno:3:5 // TypeCheckError: -// main/files/redeclaration_global1.gno:5:6: time redeclared in this block; main/files/redeclaration_global1.gno:3:5: other declaration of time; main/files/redeclaration_global1.gno:8:8: time is not a type +// main/redeclaration_global1.gno:5:6: time redeclared in this block; main/redeclaration_global1.gno:3:5: other declaration of time; main/redeclaration_global1.gno:8:8: time is not a type diff --git a/gnovm/tests/files/redeclaration_global5.gno b/gnovm/tests/files/redeclaration_global5.gno index 20e63d74f98..ba29191390e 100644 --- a/gnovm/tests/files/redeclaration_global5.gno +++ b/gnovm/tests/files/redeclaration_global5.gno @@ -12,8 +12,8 @@ func main() { } // Error: -// files/redeclaration_global5.gno:5:6: time redeclared in this block -// previous declaration at files/redeclaration_global5.gno:3:5 +// redeclaration_global5.gno:5:6: time redeclared in this block +// previous declaration at redeclaration_global5.gno:3:5 // TypeCheckError: -// main/files/redeclaration_global5.gno:5:6: time redeclared in this block; main/files/redeclaration_global5.gno:3:5: other declaration of time; main/files/redeclaration_global5.gno:10:7: invalid operation: cannot call non-function time (variable of type int) +// main/redeclaration_global5.gno:5:6: time redeclared in this block; main/redeclaration_global5.gno:3:5: other declaration of time; main/redeclaration_global5.gno:10:7: invalid operation: cannot call non-function time (variable of type int) diff --git a/gnovm/tests/files/redefine6.gno b/gnovm/tests/files/redefine6.gno index c56306bf630..669ce3eab8b 100644 --- a/gnovm/tests/files/redefine6.gno +++ b/gnovm/tests/files/redefine6.gno @@ -6,7 +6,7 @@ func main() { } // Error: -// files/redefine6.gno:5:2: no new variables on left side of := +// redefine6.gno:5:2: no new variables on left side of := // TypeCheckError: -// main/files/redefine6.gno:5:7: no new variables on left side of :=; main/files/redefine6.gno:4:2: declared and not used: a; main/files/redefine6.gno:4:5: declared and not used: b +// main/redefine6.gno:5:7: no new variables on left side of :=; main/redefine6.gno:4:2: declared and not used: a; main/redefine6.gno:4:5: declared and not used: b diff --git a/gnovm/tests/files/slice2.gno b/gnovm/tests/files/slice2.gno index 67e51ca75d8..3fb55e3e52e 100644 --- a/gnovm/tests/files/slice2.gno +++ b/gnovm/tests/files/slice2.gno @@ -8,4 +8,4 @@ func main() { // duplicate index 2 in array or slice literal // TypeCheckError: -// main/files/slice2.gno:4:35: duplicate index 2 in array or slice literal +// main/slice2.gno:4:35: duplicate index 2 in array or slice literal diff --git a/gnovm/tests/files/slice3.gno b/gnovm/tests/files/slice3.gno index ccf2291d92a..88a52a1d229 100644 --- a/gnovm/tests/files/slice3.gno +++ b/gnovm/tests/files/slice3.gno @@ -6,7 +6,7 @@ func main() { } // Error: -// main/files/slice3.gno:4:7: cannot use nil as string value in array, slice literal or map literal +// main/slice3.gno:4:7-20: cannot use nil as string value in array, slice literal or map literal // TypeCheckError: -// main/files/slice3.gno:4:16: cannot use nil as string value in array or slice literal +// main/slice3.gno:4:16: cannot use nil as string value in array or slice literal diff --git a/gnovm/tests/files/slice4.gno b/gnovm/tests/files/slice4.gno index 260bcee6006..90e8c33f412 100644 --- a/gnovm/tests/files/slice4.gno +++ b/gnovm/tests/files/slice4.gno @@ -9,4 +9,4 @@ func main() { // allocation limit exceeded // TypeCheckError: -// main/files/slice4.gno:5:2: declared and not used: b +// main/slice4.gno:5:2: declared and not used: b diff --git a/gnovm/tests/files/struct2b.gno b/gnovm/tests/files/struct2b.gno index 7ff345ff25e..887eed113df 100644 --- a/gnovm/tests/files/struct2b.gno +++ b/gnovm/tests/files/struct2b.gno @@ -14,4 +14,4 @@ func main() { // duplicate field name f in struct literal // TypeCheckError: -// main/files/struct2b.gno:10:26: duplicate field name f in struct literal; main/files/struct2b.gno:10:32: duplicate field name h in struct literal +// main/struct2b.gno:10:26: duplicate field name f in struct literal; main/struct2b.gno:10:32: duplicate field name h in struct literal diff --git a/gnovm/tests/files/switch13.gno b/gnovm/tests/files/switch13.gno index 64ee14f96e4..10c07027637 100644 --- a/gnovm/tests/files/switch13.gno +++ b/gnovm/tests/files/switch13.gno @@ -14,7 +14,7 @@ func main() { } // Error: -// main/files/switch13.gno:8:0: i is not a type +// main/switch13.gno:9:2-10:24: i is not a type // TypeCheckError: -// main/files/switch13.gno:9:7: i is not a type +// main/switch13.gno:9:7: i is not a type diff --git a/gnovm/tests/files/switch19.gno b/gnovm/tests/files/switch19.gno index 1c9f7faef97..bee52b331b8 100644 --- a/gnovm/tests/files/switch19.gno +++ b/gnovm/tests/files/switch19.gno @@ -48,7 +48,7 @@ func main() { } // Error: -// main/files/switch19.gno:34:2: duplicate type main.Bir in type switch +// main/switch19.gno:34:2-41:3: duplicate type main.Bir in type switch // TypeCheckError: -// main/files/switch19.gno:37:7: duplicate case Bir in type switch; main/files/switch19.gno:35:12: previous case +// main/switch19.gno:37:7: duplicate case Bir in type switch; main/switch19.gno:35:12: previous case diff --git a/gnovm/tests/files/switch8.gno b/gnovm/tests/files/switch8.gno index b425fd7ee37..42cbbb89e58 100644 --- a/gnovm/tests/files/switch8.gno +++ b/gnovm/tests/files/switch8.gno @@ -7,7 +7,7 @@ func main() { } // Error: -// main/files/switch8.gno:5:2: fallthrough statement out of place +// main/switch8.gno:5:2-13: fallthrough statement out of place // TypeCheckError: -// main/files/switch8.gno:5:2: fallthrough statement out of place +// main/switch8.gno:5:2: fallthrough statement out of place diff --git a/gnovm/tests/files/switch8b.gno b/gnovm/tests/files/switch8b.gno index a8b1e14536a..9023975847a 100644 --- a/gnovm/tests/files/switch8b.gno +++ b/gnovm/tests/files/switch8b.gno @@ -12,7 +12,7 @@ func main() { } // Error: -// main/files/switch8b.gno:10:3: cannot fallthrough final case in switch +// main/switch8b.gno:10:3-14: cannot fallthrough final case in switch // TypeCheckError: -// main/files/switch8b.gno:10:3: cannot fallthrough final case in switch +// main/switch8b.gno:10:3: cannot fallthrough final case in switch diff --git a/gnovm/tests/files/switch8c.gno b/gnovm/tests/files/switch8c.gno index 5f0dfee4a2c..f5592242d92 100644 --- a/gnovm/tests/files/switch8c.gno +++ b/gnovm/tests/files/switch8c.gno @@ -12,7 +12,7 @@ func main() { } // Error: -// main/files/switch8c.gno:7:3: fallthrough statement out of place +// main/switch8c.gno:7:3-14: fallthrough statement out of place // TypeCheckError: -// main/files/switch8c.gno:7:3: fallthrough statement out of place +// main/switch8c.gno:7:3: fallthrough statement out of place diff --git a/gnovm/tests/files/switch9.gno b/gnovm/tests/files/switch9.gno index efe5f3af22f..e211bcdaa1e 100644 --- a/gnovm/tests/files/switch9.gno +++ b/gnovm/tests/files/switch9.gno @@ -13,7 +13,7 @@ func main() { } // Error: -// main/files/switch9.gno:9:3: cannot fallthrough in type switch +// main/switch9.gno:9:3-14: cannot fallthrough in type switch // TypeCheckError: -// main/files/switch9.gno:9:3: cannot fallthrough in type switch +// main/switch9.gno:9:3: cannot fallthrough in type switch diff --git a/gnovm/tests/files/type30.gno b/gnovm/tests/files/type30.gno index b093d1eb526..29aaf179cf5 100644 --- a/gnovm/tests/files/type30.gno +++ b/gnovm/tests/files/type30.gno @@ -16,7 +16,7 @@ func main() { } // Error: -// main/files/type30.gno:15:10: cannot use main.String as string without explicit conversion +// main/type30.gno:15:10-21: cannot use main.String as string without explicit conversion // TypeCheckError: -// main/files/type30.gno:15:19: cannot use y (variable of string type String) as string value in argument to equal +// main/type30.gno:15:19: cannot use y (variable of string type String) as string value in argument to equal diff --git a/gnovm/tests/files/type31.gno b/gnovm/tests/files/type31.gno index 092cf358969..8fab8a10c8b 100644 --- a/gnovm/tests/files/type31.gno +++ b/gnovm/tests/files/type31.gno @@ -9,7 +9,7 @@ func main() { } // Error: -// main/files/type31.gno:8:10: invalid operation: mismatched types string and main.String +// main/type31.gno:8:10-15: invalid operation: x + y (mismatched types string and main.String) // TypeCheckError: -// main/files/type31.gno:8:10: invalid operation: x + y (mismatched types string and String) +// main/type31.gno:8:10: invalid operation: x + y (mismatched types string and String) diff --git a/gnovm/tests/files/type32.gno b/gnovm/tests/files/type32.gno index f94f8211268..20cbd7edc38 100644 --- a/gnovm/tests/files/type32.gno +++ b/gnovm/tests/files/type32.gno @@ -12,7 +12,7 @@ func main() { } // Error: -// main/files/type32.gno:9:11: invalid operation: mismatched types string and main.S +// main/type32.gno:9:11-22: invalid operation: a + (const (":" string)) + b (mismatched types string and main.S) // TypeCheckError: -// main/files/type32.gno:9:11: invalid operation: a + ":" + b (mismatched types string and S) +// main/type32.gno:9:11: invalid operation: a + ":" + b (mismatched types string and S) diff --git a/gnovm/tests/files/type37.gno b/gnovm/tests/files/type37.gno index 880ef0748b8..801ad404943 100644 --- a/gnovm/tests/files/type37.gno +++ b/gnovm/tests/files/type37.gno @@ -17,7 +17,7 @@ func main() { } // Error: -// main/files/type37.gno:8:1: invalid receiver type main.Arr (base type is pointer type) +// main/type37.gno:8:1-10:2: invalid receiver type main.Arr (base type is pointer type) // TypeCheckError: -// main/files/type37.gno:8:9: invalid receiver type Arr (pointer or interface type); main/files/type37.gno:14:9: Arr(a).Add undefined (type Arr has no field or method Add) +// main/type37.gno:8:9: invalid receiver type Arr (pointer or interface type); main/type37.gno:14:9: Arr(a).Add undefined (type Arr has no field or method Add) diff --git a/gnovm/tests/files/type37b.gno b/gnovm/tests/files/type37b.gno index a6c84955d94..4141b2c0240 100644 --- a/gnovm/tests/files/type37b.gno +++ b/gnovm/tests/files/type37b.gno @@ -19,7 +19,7 @@ func main() { } // Error: -// main/files/type37b.gno:7:1: invalid receiver type **main.Integer (base type is pointer type) +// main/type37b.gno:7:1-9:2: invalid receiver type **main.Integer (base type is pointer type) // TypeCheckError: -// main/files/type37b.gno:7:10: invalid receiver type **Integer; main/files/type37b.gno:16:4: b.Add undefined (type **Integer has no field or method Add) +// main/type37b.gno:7:10: invalid receiver type **Integer; main/type37b.gno:16:4: b.Add undefined (type **Integer has no field or method Add) diff --git a/gnovm/tests/files/type37d.gno b/gnovm/tests/files/type37d.gno index ba0cbcb8108..e5d16e66255 100644 --- a/gnovm/tests/files/type37d.gno +++ b/gnovm/tests/files/type37d.gno @@ -13,7 +13,7 @@ func main() { } // Error: -// main/files/type37d.gno:7:1: invalid receiver type main.IntPtr (base type is pointer type) +// main/type37d.gno:7:1-9:2: invalid receiver type main.IntPtr (base type is pointer type) // TypeCheckError: -// main/files/type37d.gno:7:9: invalid receiver type IntPtr (pointer or interface type); main/files/type37d.gno:12:13: ip.Int undefined (type IntPtr has no field or method Int) +// main/type37d.gno:7:9: invalid receiver type IntPtr (pointer or interface type); main/type37d.gno:12:13: ip.Int undefined (type IntPtr has no field or method Int) diff --git a/gnovm/tests/files/type37e.gno b/gnovm/tests/files/type37e.gno index c897a734c1a..8339783d370 100644 --- a/gnovm/tests/files/type37e.gno +++ b/gnovm/tests/files/type37e.gno @@ -14,7 +14,7 @@ func main() { } // Error: -// main/files/type37e.gno:8:1: invalid receiver type main.Int2 (base type is pointer type) +// main/type37e.gno:8:1-10:2: invalid receiver type main.Int2 (base type is pointer type) // TypeCheckError: -// main/files/type37e.gno:8:10: invalid receiver type Int2 (pointer or interface type); main/files/type37e.gno:13:19: Int2(ip).Int undefined (type Int2 has no field or method Int) +// main/type37e.gno:8:10: invalid receiver type Int2 (pointer or interface type); main/type37e.gno:13:19: Int2(ip).Int undefined (type Int2 has no field or method Int) diff --git a/gnovm/tests/files/type37f.gno b/gnovm/tests/files/type37f.gno index 074f79bbf34..ca2d4c156ed 100644 --- a/gnovm/tests/files/type37f.gno +++ b/gnovm/tests/files/type37f.gno @@ -13,7 +13,7 @@ func main() { } // Error: -// main/files/type37f.gno:7:1: invalid receiver type *main.IntPtr (base type is pointer type) +// main/type37f.gno:7:1-9:2: invalid receiver type *main.IntPtr (base type is pointer type) // TypeCheckError: -// main/files/type37f.gno:7:10: invalid receiver type IntPtr (pointer or interface type) +// main/type37f.gno:7:10: invalid receiver type IntPtr (pointer or interface type) diff --git a/gnovm/tests/files/type39.gno b/gnovm/tests/files/type39.gno index 2b1f6b278a2..52c1b368e92 100644 --- a/gnovm/tests/files/type39.gno +++ b/gnovm/tests/files/type39.gno @@ -19,7 +19,7 @@ func main() { } // Error: -// main/files/type39.gno:7:1: invalid receiver type main.foo (base type is interface type) +// main/type39.gno:7:1-9:2: invalid receiver type main.foo (base type is interface type) // TypeCheckError: -// main/files/type39.gno:7:9: invalid receiver type foo (pointer or interface type) +// main/type39.gno:7:9: invalid receiver type foo (pointer or interface type) diff --git a/gnovm/tests/files/type39a.gno b/gnovm/tests/files/type39a.gno index 4204d1ff081..7c7b5239d8b 100644 --- a/gnovm/tests/files/type39a.gno +++ b/gnovm/tests/files/type39a.gno @@ -21,7 +21,7 @@ func main() { } // Error: -// main/files/type39a.gno:9:1: invalid receiver type main.FF (base type is interface type) +// main/type39a.gno:9:1-11:2: invalid receiver type main.FF (base type is interface type) // TypeCheckError: -// main/files/type39a.gno:9:9: invalid receiver type FF (pointer or interface type); main/files/type39a.gno:20:12: f.echo undefined (type foo has no field or method echo) +// main/type39a.gno:9:9: invalid receiver type FF (pointer or interface type); main/type39a.gno:20:12: f.echo undefined (type foo has no field or method echo) diff --git a/gnovm/tests/files/type39b.gno b/gnovm/tests/files/type39b.gno index 8c89273296c..e98e702895d 100644 --- a/gnovm/tests/files/type39b.gno +++ b/gnovm/tests/files/type39b.gno @@ -19,7 +19,7 @@ func main() { } // Error: -// main/files/type39b.gno:7:1: invalid receiver type *main.foo (base type is interface type) +// main/type39b.gno:7:1-9:2: invalid receiver type *main.foo (base type is interface type) // TypeCheckError: -// main/files/type39b.gno:7:10: invalid receiver type foo (pointer or interface type); main/files/type39b.gno:18:12: f.echo undefined (type *foo is pointer to interface, not interface) +// main/type39b.gno:7:10: invalid receiver type foo (pointer or interface type); main/type39b.gno:18:12: f.echo undefined (type *foo is pointer to interface, not interface) diff --git a/gnovm/tests/files/type41.gno b/gnovm/tests/files/type41.gno index a9b0a171350..2bb267d87d8 100644 --- a/gnovm/tests/files/type41.gno +++ b/gnovm/tests/files/type41.gno @@ -6,7 +6,7 @@ func main() { } // Error: -// main/files/type41.gno:3:6: nil is not a type +// main/type41.gno:3:6-11: nil is not a type // TypeCheckError: -// main/files/type41.gno:3:8: nil is not a type +// main/type41.gno:3:8: nil is not a type diff --git a/gnovm/tests/files/type42.gno b/gnovm/tests/files/type42.gno index f7ee84682d0..f04b10a1634 100644 --- a/gnovm/tests/files/type42.gno +++ b/gnovm/tests/files/type42.gno @@ -10,7 +10,7 @@ func main() { // Output: // (1 main.A) -// ("a" main[main/files/type42.gno:5:1].A) +// ("a" main[main/type42.gno:5:1-9:2].A) // Preprocessed: -// file{ package main; type A (const-type main.A); func main() { (const (println func(...interface {})))((const (1 main.A))); type A (const-type main[main/files/type42.gno:5:1].A); (const (println func(...interface {})))((const ("a" main[main/files/type42.gno:5:1].A))) } } +// file{ package main; type A (const-type main.A); func main() { (const (println func(...interface {})))((const (1 main.A))); type A (const-type main[main/type42.gno:5:1-9:2].A); (const (println func(...interface {})))((const ("a" main[main/type42.gno:5:1-9:2].A))) } } diff --git a/gnovm/tests/files/typeassert1.gno b/gnovm/tests/files/typeassert1.gno index f6609a3d18c..b1d449450d7 100644 --- a/gnovm/tests/files/typeassert1.gno +++ b/gnovm/tests/files/typeassert1.gno @@ -12,7 +12,7 @@ func main() { // Stacktrace: // panic: interface conversion: interface is nil, not main.A // main() -// main/files/typeassert1.gno:9 +// main/typeassert1.gno:9 // Error: // interface conversion: interface is nil, not main.A diff --git a/gnovm/tests/files/typeassert2a.gno b/gnovm/tests/files/typeassert2a.gno index 2ce01bbf28c..5edf1ea07c8 100644 --- a/gnovm/tests/files/typeassert2a.gno +++ b/gnovm/tests/files/typeassert2a.gno @@ -14,9 +14,9 @@ func main() { // Stacktrace: // panic: interface conversion: interface is nil, not main.A // defer func(){ ... }() -// main/files/typeassert2a.gno:10 +// main/typeassert2a.gno:10 // main() -// main/files/typeassert2a.gno:8 +// main/typeassert2a.gno:8 // Error: // interface conversion: interface is nil, not main.A diff --git a/gnovm/tests/files/typeassert3.gno b/gnovm/tests/files/typeassert3.gno index 49ed48e26e6..f75ef53fa50 100644 --- a/gnovm/tests/files/typeassert3.gno +++ b/gnovm/tests/files/typeassert3.gno @@ -12,7 +12,7 @@ func main() { } // Error: -// main/files/typeassert3.gno:9:8: cannot use _ as value or type +// main/typeassert3.gno:9:8-9: cannot use _ as value or type // TypeCheckError: -// main/files/typeassert3.gno:9:8: cannot use _ as value or type +// main/typeassert3.gno:9:8: cannot use _ as value or type diff --git a/gnovm/tests/files/typeassert8.gno b/gnovm/tests/files/typeassert8.gno index 2115ce51303..655ad2555e0 100644 --- a/gnovm/tests/files/typeassert8.gno +++ b/gnovm/tests/files/typeassert8.gno @@ -15,7 +15,7 @@ func main() { } // Error: -// main/files/typeassert8.gno:13:7: invalid operation: r (variable of type []int) is not an interface +// main/typeassert8.gno:13:7-13: invalid operation: r (variable of type []int) is not an interface // TypeCheckError: -// main/files/typeassert8.gno:13:7: invalid operation: r (variable of type []int) is not an interface +// main/typeassert8.gno:13:7: invalid operation: r (variable of type []int) is not an interface diff --git a/gnovm/tests/files/typeassert8a.gno b/gnovm/tests/files/typeassert8a.gno index 9c5a59e3f87..873db750cdb 100644 --- a/gnovm/tests/files/typeassert8a.gno +++ b/gnovm/tests/files/typeassert8a.gno @@ -15,7 +15,7 @@ func main() { } // Error: -// main/files/typeassert8a.gno:13:11: invalid operation: r (variable of type []int) is not an interface +// main/typeassert8a.gno:13:11-17: invalid operation: r (variable of type []int) is not an interface // TypeCheckError: -// main/files/typeassert8a.gno:13:11: invalid operation: r (variable of type []int) is not an interface +// main/typeassert8a.gno:13:11: invalid operation: r (variable of type []int) is not an interface diff --git a/gnovm/tests/files/typeassert9.gno b/gnovm/tests/files/typeassert9.gno index 6ea072661c1..ca9b8a28170 100644 --- a/gnovm/tests/files/typeassert9.gno +++ b/gnovm/tests/files/typeassert9.gno @@ -19,7 +19,7 @@ func main() { // Stacktrace: // panic: interface conversion: interface is nil, not main.Writer // main() -// main/files/typeassert9.gno:16 +// main/typeassert9.gno:16 // Error: // interface conversion: interface is nil, not main.Writer diff --git a/gnovm/tests/files/typeassert9a.gno b/gnovm/tests/files/typeassert9a.gno index 113137f0e3b..4f1ff0e8fbf 100644 --- a/gnovm/tests/files/typeassert9a.gno +++ b/gnovm/tests/files/typeassert9a.gno @@ -16,9 +16,9 @@ func main() { } // Error: -// main/files/typeassert9a.gno:15:6: *main.csvReader does not implement main.Reader (wrong type for method Read) +// main/typeassert9a.gno:15:6-37: *main.csvReader does not implement main.Reader (wrong type for method Read) // TypeCheckError: -// main/files/typeassert9a.gno:15:25: cannot use &csvReader{} (value of type *csvReader) as Reader value in variable declaration: *csvReader does not implement Reader (wrong type for method Read) +// main/typeassert9a.gno:15:25: cannot use &csvReader{} (value of type *csvReader) as Reader value in variable declaration: *csvReader does not implement Reader (wrong type for method Read) // have Read(string) string -// want Read(int) string; main/files/typeassert9a.gno:15:6: declared and not used: csvReader +// want Read(int) string; main/typeassert9a.gno:15:6: declared and not used: csvReader diff --git a/gnovm/tests/files/types/add_a0.gno b/gnovm/tests/files/types/add_a0.gno index 11155847c44..9d314da760f 100644 --- a/gnovm/tests/files/types/add_a0.gno +++ b/gnovm/tests/files/types/add_a0.gno @@ -6,7 +6,7 @@ func main() { } // Error: -// main/files/types/add_a0.gno:5:10: invalid operation: mismatched types int and int8 +// main/add_a0.gno:5:10-26: invalid operation: (const (1 int)) + (const (1 int8)) (mismatched types int and int8) // TypeCheckError: -// main/files/types/add_a0.gno:5:10: invalid operation: int(1) + int8(1) (mismatched types int and int8) +// main/add_a0.gno:5:10: invalid operation: int(1) + int8(1) (mismatched types int and int8) diff --git a/gnovm/tests/files/types/add_a1.gno b/gnovm/tests/files/types/add_a1.gno index 02f097ebc25..8d14006ef90 100644 --- a/gnovm/tests/files/types/add_a1.gno +++ b/gnovm/tests/files/types/add_a1.gno @@ -22,7 +22,7 @@ func main() { } // Error: -// main/files/types/add_a1.gno:21:10: invalid operation: mismatched types main.Error1 and main.Error2 +// main/add_a1.gno:21:10-31: invalid operation: (const (0 main.Error1)) + (const (0 main.Error2)) (mismatched types main.Error1 and main.Error2) // TypeCheckError: -// main/files/types/add_a1.gno:21:10: invalid operation: Error1(0) + Error2(0) (mismatched types Error1 and Error2) +// main/add_a1.gno:21:10: invalid operation: Error1(0) + Error2(0) (mismatched types Error1 and Error2) diff --git a/gnovm/tests/files/types/add_assign_a0.gno b/gnovm/tests/files/types/add_assign_a0.gno index 8553e8bdf26..aa415e3883b 100644 --- a/gnovm/tests/files/types/add_assign_a0.gno +++ b/gnovm/tests/files/types/add_assign_a0.gno @@ -6,7 +6,7 @@ func main() { } // Error: -// main/files/types/add_assign_a0.gno:5:2: invalid operation: mismatched types int and int8 +// main/add_assign_a0.gno:5:2-19: invalid operation: mismatched types int and int8 // TypeCheckError: -// main/files/types/add_assign_a0.gno:5:2: invalid operation: int(0) += int8(1) (mismatched types int and int8) +// main/add_assign_a0.gno:5:2: invalid operation: int(0) += int8(1) (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 index f6f85092ce4..a8ca94cf4b9 100644 --- a/gnovm/tests/files/types/add_assign_a1.gno +++ b/gnovm/tests/files/types/add_assign_a1.gno @@ -22,7 +22,7 @@ func main() { } // Error: -// main/files/types/add_assign_a1.gno:21:2: invalid operation: mismatched types main.Error1 and main.Error2 +// main/add_assign_a1.gno:21:2-24: invalid operation: mismatched types main.Error1 and main.Error2 // TypeCheckError: -// main/files/types/add_assign_a1.gno:21:2: invalid operation: Error1(0) += Error2(0) (mismatched types Error1 and Error2) +// main/add_assign_a1.gno:21:2: invalid operation: Error1(0) += Error2(0) (mismatched types Error1 and Error2) diff --git a/gnovm/tests/files/types/add_assign_a_01.gno b/gnovm/tests/files/types/add_assign_a_01.gno index 494df4f84d9..9d7f90a0f25 100644 --- a/gnovm/tests/files/types/add_assign_a_01.gno +++ b/gnovm/tests/files/types/add_assign_a_01.gno @@ -9,7 +9,7 @@ func main() { } // Error: -// main/files/types/add_assign_a_01.gno:6:2: assignment operator += requires only one expression on lhs and rhs +// main/add_assign_a_01.gno:6:2-14: assignment operator += requires only one expression on lhs and rhs // TypeCheckError: -// main/files/types/add_assign_a_01.gno:6:7: assignment operation += requires single-valued expressions +// main/add_assign_a_01.gno:6:7: assignment operation += requires single-valued expressions diff --git a/gnovm/tests/files/types/add_assign_b0.gno b/gnovm/tests/files/types/add_assign_b0.gno index 94e00216c0c..b465d468854 100644 --- a/gnovm/tests/files/types/add_assign_b0.gno +++ b/gnovm/tests/files/types/add_assign_b0.gno @@ -10,7 +10,7 @@ func main() { } // Error: -// main/files/types/add_assign_b0.gno:8:2: invalid operation: mismatched types int and main.Error +// main/add_assign_b0.gno:8:2-15: invalid operation: mismatched types int and main.Error // TypeCheckError: -// main/files/types/add_assign_b0.gno:8:2: invalid operation: r += Error(1) (mismatched types int and Error) +// main/add_assign_b0.gno:8:2: invalid operation: r += Error(1) (mismatched types int and Error) diff --git a/gnovm/tests/files/types/add_assign_e0.gno b/gnovm/tests/files/types/add_assign_e0.gno index 4a835da40f1..5b0a46aa9c7 100644 --- a/gnovm/tests/files/types/add_assign_e0.gno +++ b/gnovm/tests/files/types/add_assign_e0.gno @@ -25,7 +25,7 @@ func main() { } // Error: -// main/files/types/add_assign_e0.gno:23:2: invalid operation: mismatched types main.Error1 and main.Error2 +// main/add_assign_e0.gno:23:2-10: invalid operation: mismatched types main.Error1 and main.Error2 // TypeCheckError: -// main/files/types/add_assign_e0.gno:23:2: invalid operation: e1 += e2 (mismatched types Error1 and Error2) +// main/add_assign_e0.gno:23:2: invalid operation: e1 += e2 (mismatched types Error1 and Error2) diff --git a/gnovm/tests/files/types/add_assign_f0.gno b/gnovm/tests/files/types/add_assign_f0.gno index 9159a90ff14..13599df0e8e 100644 --- a/gnovm/tests/files/types/add_assign_f0.gno +++ b/gnovm/tests/files/types/add_assign_f0.gno @@ -22,7 +22,7 @@ func main() { } // Error: -// main/files/types/add_assign_f0.gno:20:2: invalid operation: mismatched types int and .uverse.error +// main/add_assign_f0.gno:20:2-13: invalid operation: mismatched types int and .uverse.error // TypeCheckError: -// main/files/types/add_assign_f0.gno:20:2: invalid operation: r += errCmp (mismatched types int and error) +// main/add_assign_f0.gno:20:2: invalid operation: r += errCmp (mismatched types int and error) diff --git a/gnovm/tests/files/types/add_assign_f1.gno b/gnovm/tests/files/types/add_assign_f1.gno index 8552426c881..25d91926955 100644 --- a/gnovm/tests/files/types/add_assign_f1.gno +++ b/gnovm/tests/files/types/add_assign_f1.gno @@ -25,7 +25,7 @@ func main() { } // Error: -// main/files/types/add_assign_f1.gno:21:2: invalid operation: mismatched types main.Error and .uverse.error +// main/add_assign_f1.gno:21:2-13: invalid operation: mismatched types main.Error and .uverse.error // TypeCheckError: -// main/files/types/add_assign_f1.gno:21:2: invalid operation: r += errCmp (mismatched types Error and error) +// main/add_assign_f1.gno:21:2: invalid operation: r += errCmp (mismatched types Error and error) diff --git a/gnovm/tests/files/types/add_assign_f2.gno b/gnovm/tests/files/types/add_assign_f2.gno index e9abf4b6669..6bbcd2aebf1 100644 --- a/gnovm/tests/files/types/add_assign_f2.gno +++ b/gnovm/tests/files/types/add_assign_f2.gno @@ -22,7 +22,7 @@ func main() { } // Error: -// main/files/types/add_assign_f2.gno:20:2: operator += not defined on: InterfaceKind +// main/add_assign_f2.gno:20:2-13: operator += not defined on: InterfaceKind // TypeCheckError: -// main/files/types/add_assign_f2.gno:20:2: invalid operation: errCmp += r (mismatched types error and Error) +// main/add_assign_f2.gno:20:2: invalid operation: errCmp += r (mismatched types error and Error) diff --git a/gnovm/tests/files/types/add_assign_f3.gno b/gnovm/tests/files/types/add_assign_f3.gno index d0befd8fdb1..94bb450101f 100644 --- a/gnovm/tests/files/types/add_assign_f3.gno +++ b/gnovm/tests/files/types/add_assign_f3.gno @@ -29,7 +29,7 @@ func main() { } // Error: -// main/files/types/add_assign_f3.gno:27:2: operator += not defined on: InterfaceKind +// main/add_assign_f3.gno:27:2-10: operator += not defined on: InterfaceKind // TypeCheckError: -// main/files/types/add_assign_f3.gno:27:2: invalid operation: operator + not defined on e1 (variable of interface type E) +// main/add_assign_f3.gno:27:2: invalid operation: operator + not defined on e1 (variable of interface type E) diff --git a/gnovm/tests/files/types/add_b2.gno b/gnovm/tests/files/types/add_b2.gno index 5ab40776aa3..7e5f709e398 100644 --- a/gnovm/tests/files/types/add_b2.gno +++ b/gnovm/tests/files/types/add_b2.gno @@ -6,7 +6,7 @@ func main() { } // Error: -// main/files/types/add_b2.gno:5:10: cannot use untyped Bigint as StringKind +// main/add_b2.gno:5:10-17: cannot use untyped Bigint as StringKind // TypeCheckError: -// main/files/types/add_b2.gno:5:10: invalid operation: 1 + "a" (mismatched types untyped int and untyped string) +// main/add_b2.gno:5:10: invalid operation: 1 + "a" (mismatched types untyped int and untyped string) diff --git a/gnovm/tests/files/types/add_d4.gno b/gnovm/tests/files/types/add_d4.gno index 1c7655bc320..253dd66b0b2 100644 --- a/gnovm/tests/files/types/add_d4.gno +++ b/gnovm/tests/files/types/add_d4.gno @@ -8,7 +8,7 @@ func main() { } // Error: -// main/files/types/add_d4.gno:7:10: operator + not defined on: InterfaceKind +// main/add_d4.gno:7:10-15: operator + not defined on: InterfaceKind // TypeCheckError: -// main/files/types/add_d4.gno:7:10: invalid operation: b + a (mismatched types any and int) +// main/add_d4.gno:7:10: invalid operation: b + a (mismatched types any and int) diff --git a/gnovm/tests/files/types/add_e0.gno b/gnovm/tests/files/types/add_e0.gno index d1b2f73acf9..1640115f0bd 100644 --- a/gnovm/tests/files/types/add_e0.gno +++ b/gnovm/tests/files/types/add_e0.gno @@ -24,7 +24,7 @@ func main() { } // Error: -// main/files/types/add_e0.gno:23:10: invalid operation: mismatched types main.Error1 and main.Error2 +// main/add_e0.gno:23:10-17: invalid operation: e1 + e2 (mismatched types main.Error1 and main.Error2) // TypeCheckError: -// main/files/types/add_e0.gno:23:10: invalid operation: e1 + e2 (mismatched types Error1 and Error2) +// main/add_e0.gno:23:10: invalid operation: e1 + e2 (mismatched types Error1 and Error2) diff --git a/gnovm/tests/files/types/add_f0.gno b/gnovm/tests/files/types/add_f0.gno index e7fa6844fe0..6c78a694430 100644 --- a/gnovm/tests/files/types/add_f0.gno +++ b/gnovm/tests/files/types/add_f0.gno @@ -20,7 +20,7 @@ func main() { } // Error: -// main/files/types/add_f0.gno:19:10: operator + not defined on: InterfaceKind +// main/add_f0.gno:19:10-20: operator + not defined on: InterfaceKind // TypeCheckError: -// main/files/types/add_f0.gno:19:10: cannot convert 1 (untyped int constant) to type interface{Error() string} +// main/add_f0.gno:19:10: cannot convert 1 (untyped int constant) to type interface{Error() string} diff --git a/gnovm/tests/files/types/add_f1.gno b/gnovm/tests/files/types/add_f1.gno index 5a2209fff24..0224c3c3f27 100644 --- a/gnovm/tests/files/types/add_f1.gno +++ b/gnovm/tests/files/types/add_f1.gno @@ -20,7 +20,7 @@ func main() { } // Error: -// main/files/types/add_f1.gno:19:10: operator + not defined on: InterfaceKind +// main/add_f1.gno:19:10-27: operator + not defined on: InterfaceKind // TypeCheckError: -// main/files/types/add_f1.gno:19:10: invalid operation: Error(0) + errCmp (mismatched types Error and error) +// main/add_f1.gno:19:10: invalid operation: Error(0) + errCmp (mismatched types Error and error) diff --git a/gnovm/tests/files/types/add_f2.gno b/gnovm/tests/files/types/add_f2.gno index 5a54dc42ecc..579a3b4375d 100644 --- a/gnovm/tests/files/types/add_f2.gno +++ b/gnovm/tests/files/types/add_f2.gno @@ -28,7 +28,7 @@ func main() { } // Error: -// main/files/types/add_f2.gno:27:10: operator + not defined on: InterfaceKind +// main/add_f2.gno:27:10-17: operator + not defined on: InterfaceKind // TypeCheckError: -// main/files/types/add_f2.gno:27:10: invalid operation: operator + not defined on e1 (variable of interface type E) +// main/add_f2.gno:27:10: invalid operation: operator + not defined on e1 (variable of interface type E) diff --git a/gnovm/tests/files/types/and_a0.gno b/gnovm/tests/files/types/and_a0.gno index cd8e6e3b49c..b7887e6de66 100644 --- a/gnovm/tests/files/types/and_a0.gno +++ b/gnovm/tests/files/types/and_a0.gno @@ -6,7 +6,7 @@ func main() { } // Error: -// main/files/types/and_a0.gno:5:10: invalid operation: mismatched types int and int8 +// main/and_a0.gno:5:10-26: invalid operation: (const (0 int)) & (const (1 int8)) (mismatched types int and int8) // TypeCheckError: -// main/files/types/and_a0.gno:5:10: invalid operation: int(0) & int8(1) (mismatched types int and int8) +// main/and_a0.gno:5:10: invalid operation: int(0) & int8(1) (mismatched types int and int8) diff --git a/gnovm/tests/files/types/and_a1.gno b/gnovm/tests/files/types/and_a1.gno index 2e5df8f5279..7747c7125d9 100644 --- a/gnovm/tests/files/types/and_a1.gno +++ b/gnovm/tests/files/types/and_a1.gno @@ -22,7 +22,7 @@ func main() { } // Error: -// main/files/types/and_a1.gno:21:10: invalid operation: mismatched types main.Error1 and main.Error2 +// main/and_a1.gno:21:10-31: invalid operation: (const (0 main.Error1)) & (const (0 main.Error2)) (mismatched types main.Error1 and main.Error2) // TypeCheckError: -// main/files/types/and_a1.gno:21:10: invalid operation: Error1(0) & Error2(0) (mismatched types Error1 and Error2) +// main/and_a1.gno:21:10: invalid operation: Error1(0) & Error2(0) (mismatched types Error1 and Error2) diff --git a/gnovm/tests/files/types/and_b2.gno b/gnovm/tests/files/types/and_b2.gno index b504ecdc50f..6a6396176f5 100644 --- a/gnovm/tests/files/types/and_b2.gno +++ b/gnovm/tests/files/types/and_b2.gno @@ -6,7 +6,7 @@ func main() { } // Error: -// main/files/types/and_b2.gno:5:10: operator & not defined on: StringKind +// main/and_b2.gno:5:10-17: operator & not defined on: StringKind // TypeCheckError: -// main/files/types/and_b2.gno:5:10: invalid operation: 1 & "a" (mismatched types untyped int and untyped string) +// main/and_b2.gno:5:10: invalid operation: 1 & "a" (mismatched types untyped int and untyped string) diff --git a/gnovm/tests/files/types/and_b3.gno b/gnovm/tests/files/types/and_b3.gno index 3f2c4ed6179..a12f2571a2b 100644 --- a/gnovm/tests/files/types/and_b3.gno +++ b/gnovm/tests/files/types/and_b3.gno @@ -6,7 +6,7 @@ func main() { } // Error: -// main/files/types/and_b3.gno:5:10: operator & not defined on: StringKind +// main/and_b3.gno:5:10-19: operator & not defined on: StringKind // TypeCheckError: -// main/files/types/and_b3.gno:5:10: invalid operation: operator & not defined on "b" (untyped string constant) +// main/and_b3.gno:5:10: invalid operation: operator & not defined on "b" (untyped string constant) diff --git a/gnovm/tests/files/types/and_d0.gno b/gnovm/tests/files/types/and_d0.gno index 5ed24e07460..37e3d3ab2f8 100644 --- a/gnovm/tests/files/types/and_d0.gno +++ b/gnovm/tests/files/types/and_d0.gno @@ -7,7 +7,7 @@ func main() { } // Error: -// main/files/types/and_d0.gno:6:10: operator & not defined on: BigdecKind +// main/and_d0.gno:6:10-17: operator & not defined on: BigdecKind // TypeCheckError: -// main/files/types/and_d0.gno:6:10: invalid operation: operator & not defined on 1.0 (untyped float constant 1) +// main/and_d0.gno:6:10: invalid operation: operator & not defined on 1.0 (untyped float constant 1) diff --git a/gnovm/tests/files/types/and_d4.gno b/gnovm/tests/files/types/and_d4.gno index b3c441ca088..aaecee9bdda 100644 --- a/gnovm/tests/files/types/and_d4.gno +++ b/gnovm/tests/files/types/and_d4.gno @@ -7,7 +7,7 @@ func main() { } // Error: -// main/files/types/and_d4.gno:6:10: operator & not defined on: BigdecKind +// main/and_d4.gno:6:10-17: operator & not defined on: BigdecKind // TypeCheckError: -// main/files/types/and_d4.gno:6:10: invalid operation: operator & not defined on 1.0 (untyped float constant 1) +// main/and_d4.gno:6:10: invalid operation: operator & not defined on 1.0 (untyped float constant 1) diff --git a/gnovm/tests/files/types/and_e0.gno b/gnovm/tests/files/types/and_e0.gno index d6fd41ed2e1..d86dec60d9c 100644 --- a/gnovm/tests/files/types/and_e0.gno +++ b/gnovm/tests/files/types/and_e0.gno @@ -24,7 +24,7 @@ func main() { } // Error: -// main/files/types/and_e0.gno:23:10: invalid operation: mismatched types main.Error1 and main.Error2 +// main/and_e0.gno:23:10-17: invalid operation: e1 & e2 (mismatched types main.Error1 and main.Error2) // TypeCheckError: -// main/files/types/and_e0.gno:23:10: invalid operation: e1 & e2 (mismatched types Error1 and Error2) +// main/and_e0.gno:23:10: invalid operation: e1 & e2 (mismatched types Error1 and Error2) diff --git a/gnovm/tests/files/types/and_f0.gno b/gnovm/tests/files/types/and_f0.gno index 0f3c7e9ff13..521a1b6c7f9 100644 --- a/gnovm/tests/files/types/and_f0.gno +++ b/gnovm/tests/files/types/and_f0.gno @@ -20,7 +20,7 @@ func main() { } // Error: -// main/files/types/and_f0.gno:19:10: operator & not defined on: InterfaceKind +// main/and_f0.gno:19:10-20: operator & not defined on: InterfaceKind // TypeCheckError: -// main/files/types/and_f0.gno:19:10: cannot convert 1 (untyped int constant) to type interface{Error() string} +// main/and_f0.gno:19:10: cannot convert 1 (untyped int constant) to type interface{Error() string} diff --git a/gnovm/tests/files/types/and_f1.gno b/gnovm/tests/files/types/and_f1.gno index 3d7848a2d84..f13791cbfa8 100644 --- a/gnovm/tests/files/types/and_f1.gno +++ b/gnovm/tests/files/types/and_f1.gno @@ -20,7 +20,7 @@ func main() { } // Error: -// main/files/types/and_f1.gno:19:10: operator & not defined on: InterfaceKind +// main/and_f1.gno:19:10-27: operator & not defined on: InterfaceKind // TypeCheckError: -// main/files/types/and_f1.gno:19:10: invalid operation: Error(0) & errCmp (mismatched types Error and error) +// main/and_f1.gno:19:10: invalid operation: Error(0) & errCmp (mismatched types Error and error) diff --git a/gnovm/tests/files/types/and_f2.gno b/gnovm/tests/files/types/and_f2.gno index b1338442aca..a283c9411c1 100644 --- a/gnovm/tests/files/types/and_f2.gno +++ b/gnovm/tests/files/types/and_f2.gno @@ -28,7 +28,7 @@ func main() { } // Error: -// main/files/types/and_f2.gno:27:10: operator & not defined on: InterfaceKind +// main/and_f2.gno:27:10-17: operator & not defined on: InterfaceKind // TypeCheckError: -// main/files/types/and_f2.gno:27:10: invalid operation: operator & not defined on e1 (variable of interface type E) +// main/and_f2.gno:27:10: invalid operation: operator & not defined on e1 (variable of interface type E) diff --git a/gnovm/tests/files/types/assign_call.gno b/gnovm/tests/files/types/assign_call.gno index 1fc0b898738..8eb7f3a3547 100644 --- a/gnovm/tests/files/types/assign_call.gno +++ b/gnovm/tests/files/types/assign_call.gno @@ -11,7 +11,7 @@ func main() { } // Error: -// main/files/types/assign_call.gno:9:2: cannot use int as string +// main/assign_call.gno:9:2-15: cannot use int as string // TypeCheckError: -// main/files/types/assign_call.gno:9:10: cannot use foo() (value of type int) as string value in assignment; main/files/types/assign_call.gno:9:10: cannot use foo() (value of type float32) as string value in assignment; main/files/types/assign_call.gno:8:9: declared and not used: s1 +// main/assign_call.gno:9:10: cannot use foo() (value of type int) as string value in assignment; main/assign_call.gno:9:10: cannot use foo() (value of type float32) as string value in assignment; main/assign_call.gno:8:9: declared and not used: s1 diff --git a/gnovm/tests/files/types/assign_index.gno b/gnovm/tests/files/types/assign_index.gno index cdb10cb6b57..ecd10e17030 100644 --- a/gnovm/tests/files/types/assign_index.gno +++ b/gnovm/tests/files/types/assign_index.gno @@ -11,7 +11,7 @@ func main() { } // Error: -// main/files/types/assign_index.gno:8:2: cannot use int as string +// main/assign_index.gno:8:2-16: cannot use int as string // TypeCheckError: -// main/files/types/assign_index.gno:8:10: cannot use m["a"] (map index expression of type int) as string value in assignment +// main/assign_index.gno:8:10: cannot use m["a"] (map index expression of type int) as string value in assignment diff --git a/gnovm/tests/files/types/assign_index_a.gno b/gnovm/tests/files/types/assign_index_a.gno index 32f16888223..da06a571802 100644 --- a/gnovm/tests/files/types/assign_index_a.gno +++ b/gnovm/tests/files/types/assign_index_a.gno @@ -9,7 +9,7 @@ func main() { } // Error: -// main/files/types/assign_index_a.gno:6:2: cannot use int as string +// main/assign_index_a.gno:6:2-53: cannot use int as string // TypeCheckError: -// main/files/types/assign_index_a.gno:6:10: cannot use map[string]int{…}["a"] (map index expression of type int) as string value in assignment +// main/assign_index_a.gno:6:10: cannot use map[string]int{…}["a"] (map index expression of type int) as string value in assignment diff --git a/gnovm/tests/files/types/assign_index_b.gno b/gnovm/tests/files/types/assign_index_b.gno index ac7559e8f75..9ba17bc7423 100644 --- a/gnovm/tests/files/types/assign_index_b.gno +++ b/gnovm/tests/files/types/assign_index_b.gno @@ -11,7 +11,7 @@ func main() { } // Error: -// main/files/types/assign_index_b.gno:8:2: want bool type got int +// main/assign_index_b.gno:8:2-16: want bool type got int // TypeCheckError: -// main/files/types/assign_index_b.gno:8:10: cannot use m["a"] (untyped bool value) as int value in assignment +// main/assign_index_b.gno:8:10: cannot use m["a"] (untyped bool value) as int value in assignment diff --git a/gnovm/tests/files/types/assign_index_c.gno b/gnovm/tests/files/types/assign_index_c.gno index e3121aa4c35..dc9a3e2099a 100644 --- a/gnovm/tests/files/types/assign_index_c.gno +++ b/gnovm/tests/files/types/assign_index_c.gno @@ -9,7 +9,7 @@ func main() { } // Error: -// main/files/types/assign_index_c.gno:7:2: cannot use int as string +// main/assign_index_c.gno:7:2-11: cannot use int as string // TypeCheckError: -// main/files/types/assign_index_c.gno:7:7: cannot use s[0] (variable of type int) as string value in assignment; main/files/types/assign_index_c.gno:6:6: declared and not used: s1 +// main/assign_index_c.gno:7:7: cannot use s[0] (variable of type int) as string value in assignment; main/assign_index_c.gno:6:6: declared and not used: s1 diff --git a/gnovm/tests/files/types/assign_literal.gno b/gnovm/tests/files/types/assign_literal.gno index 85054756c6b..25fedd04c58 100644 --- a/gnovm/tests/files/types/assign_literal.gno +++ b/gnovm/tests/files/types/assign_literal.gno @@ -5,7 +5,7 @@ func main() { } // Error: -// main/files/types/assign_literal.gno:4:2: cannot assign to (const (1 bigint)) +// main/assign_literal.gno:4:2-7: cannot assign to (const (1 bigint)) // TypeCheckError: -// main/files/types/assign_literal.gno:4:2: cannot assign to 1 (neither addressable nor a map index expression) +// main/assign_literal.gno:4:2: cannot assign to 1 (neither addressable nor a map index expression) diff --git a/gnovm/tests/files/types/assign_literal10a.gno b/gnovm/tests/files/types/assign_literal10a.gno index faf5c3ff3a7..eb2d29f2769 100644 --- a/gnovm/tests/files/types/assign_literal10a.gno +++ b/gnovm/tests/files/types/assign_literal10a.gno @@ -17,7 +17,7 @@ func main() { } // Error: -// main/files/types/assign_literal10a.gno:13:2: cannot assign to s.add() +// main/assign_literal10a.gno:13:2-13: cannot assign to s.add() // TypeCheckError: -// main/files/types/assign_literal10a.gno:13:2: cannot assign to s.add() (neither addressable nor a map index expression) +// main/assign_literal10a.gno:13:2: cannot assign to s.add() (neither addressable nor a map index expression) diff --git a/gnovm/tests/files/types/assign_literal11.gno b/gnovm/tests/files/types/assign_literal11.gno index 276de23cec2..da80b4a8d43 100644 --- a/gnovm/tests/files/types/assign_literal11.gno +++ b/gnovm/tests/files/types/assign_literal11.gno @@ -8,7 +8,7 @@ func main() { } // Error: -// main/files/types/assign_literal11.gno:6:2: cannot assign to const Pi +// main/assign_literal11.gno:6:2-14: cannot assign to const Pi // TypeCheckError: -// main/files/types/assign_literal11.gno:6:2: cannot assign to Pi (neither addressable nor a map index expression) +// main/assign_literal11.gno:6:2: cannot assign to Pi (neither addressable nor a map index expression) diff --git a/gnovm/tests/files/types/assign_literal2.gno b/gnovm/tests/files/types/assign_literal2.gno index 5ce3ef23e06..5ce5897e98c 100644 --- a/gnovm/tests/files/types/assign_literal2.gno +++ b/gnovm/tests/files/types/assign_literal2.gno @@ -6,7 +6,7 @@ func main() { } // Error: -// main/files/types/assign_literal2.gno:5:2: cannot assign to (const (2 bigint)) +// main/assign_literal2.gno:5:2-13: cannot assign to (const (2 bigint)) // TypeCheckError: -// main/files/types/assign_literal2.gno:5:5: cannot assign to 2 (neither addressable nor a map index expression); main/files/types/assign_literal2.gno:4:6: declared and not used: a +// main/assign_literal2.gno:5:5: cannot assign to 2 (neither addressable nor a map index expression); main/assign_literal2.gno:4:6: declared and not used: a diff --git a/gnovm/tests/files/types/assign_literal2_a.gno b/gnovm/tests/files/types/assign_literal2_a.gno index 08414393bcf..6f4ac746c07 100644 --- a/gnovm/tests/files/types/assign_literal2_a.gno +++ b/gnovm/tests/files/types/assign_literal2_a.gno @@ -6,7 +6,7 @@ func main() { } // Error: -// files/types/assign_literal2_a.gno:5:2: no new variables on left side of := +// assign_literal2_a.gno:5:2: no new variables on left side of := // TypeCheckError: -// main/files/types/assign_literal2_a.gno:5:5: non-name 2 on left side of :=; main/files/types/assign_literal2_a.gno:4:6: declared and not used: a +// main/assign_literal2_a.gno:5:5: non-name 2 on left side of :=; main/assign_literal2_a.gno:4:6: declared and not used: a diff --git a/gnovm/tests/files/types/assign_literal3.gno b/gnovm/tests/files/types/assign_literal3.gno index 06f93e7362e..b35f1182f8c 100644 --- a/gnovm/tests/files/types/assign_literal3.gno +++ b/gnovm/tests/files/types/assign_literal3.gno @@ -5,7 +5,7 @@ func main() { } // Error: -// main/files/types/assign_literal3.gno:4:2: cannot assign to uverse true +// main/assign_literal3.gno:4:2-14: cannot assign to uverse true // TypeCheckError: -// main/files/types/assign_literal3.gno:4:2: cannot assign to true (neither addressable nor a map index expression) +// main/assign_literal3.gno:4:2: cannot assign to true (neither addressable nor a map index expression) diff --git a/gnovm/tests/files/types/assign_literal4.gno b/gnovm/tests/files/types/assign_literal4.gno index 8d3b9603e62..12a26a62b4d 100644 --- a/gnovm/tests/files/types/assign_literal4.gno +++ b/gnovm/tests/files/types/assign_literal4.gno @@ -5,7 +5,7 @@ func main() { } // Error: -// main/files/types/assign_literal4.gno:4:2: cannot assign to [](const-type int){(const (1 int)), (const (2 int))} +// main/assign_literal4.gno:4:2-27: cannot assign to [](const-type int){(const (1 int)), (const (2 int))} // TypeCheckError: -// main/files/types/assign_literal4.gno:4:2: cannot assign to []int{…} (neither addressable nor a map index expression) +// main/assign_literal4.gno:4:2: cannot assign to []int{…} (neither addressable nor a map index expression) diff --git a/gnovm/tests/files/types/assign_literal4_a.gno b/gnovm/tests/files/types/assign_literal4_a.gno index 7ebba532a87..ca6429b0da9 100644 --- a/gnovm/tests/files/types/assign_literal4_a.gno +++ b/gnovm/tests/files/types/assign_literal4_a.gno @@ -5,7 +5,7 @@ func main() { } // Error: -// files/types/assign_literal4_a.gno:4:2: no new variables on left side of := +// assign_literal4_a.gno:4:2: no new variables on left side of := // TypeCheckError: -// main/files/types/assign_literal4_a.gno:4:2: non-name []int{…} on left side of := +// main/assign_literal4_a.gno:4:2: non-name []int{…} on left side of := diff --git a/gnovm/tests/files/types/assign_literal5.gno b/gnovm/tests/files/types/assign_literal5.gno index 5de76b70139..9e39a53da5e 100644 --- a/gnovm/tests/files/types/assign_literal5.gno +++ b/gnovm/tests/files/types/assign_literal5.gno @@ -5,7 +5,7 @@ func main() { } // Error: -// main/files/types/assign_literal5.gno:4:2: cannot assign to map[(const-type string)] (const-type int){(const ("a" string)): (const (1 int)), (const ("b" string)): (const (2 int))} +// main/assign_literal5.gno:4:2-65: cannot assign to map[(const-type string)] (const-type int){(const ("a" string)): (const (1 int)), (const ("b" string)): (const (2 int))} // TypeCheckError: -// main/files/types/assign_literal5.gno:4:2: cannot assign to map[string]int{…} (neither addressable nor a map index expression) +// main/assign_literal5.gno:4:2: cannot assign to map[string]int{…} (neither addressable nor a map index expression) diff --git a/gnovm/tests/files/types/assign_literal6.gno b/gnovm/tests/files/types/assign_literal6.gno index 46763d5769d..2a7cd87bd11 100644 --- a/gnovm/tests/files/types/assign_literal6.gno +++ b/gnovm/tests/files/types/assign_literal6.gno @@ -5,7 +5,7 @@ func main() { } // Error: -// main/files/types/assign_literal6.gno:4:2: cannot assign to (const (3 bigint)) +// main/assign_literal6.gno:4:2-11: cannot assign to (const (3 bigint)) // TypeCheckError: -// main/files/types/assign_literal6.gno:4:2: cannot assign to 1 + 2 (neither addressable nor a map index expression) +// main/assign_literal6.gno:4:2: cannot assign to 1 + 2 (neither addressable nor a map index expression) diff --git a/gnovm/tests/files/types/assign_literal7c.gno b/gnovm/tests/files/types/assign_literal7c.gno index 161e3fc34d7..0b4a04f2049 100644 --- a/gnovm/tests/files/types/assign_literal7c.gno +++ b/gnovm/tests/files/types/assign_literal7c.gno @@ -10,7 +10,7 @@ func main() { } // Error: -// main/files/types/assign_literal7c.gno:7:2: cannot assign to str[(const (0 int))] +// main/assign_literal7c.gno:7:2-14: cannot assign to str[(const (0 int))] // TypeCheckError: -// main/files/types/assign_literal7c.gno:7:2: cannot assign to str[0] (neither addressable nor a map index expression) +// main/assign_literal7c.gno:7:2: cannot assign to str[0] (neither addressable nor a map index expression) diff --git a/gnovm/tests/files/types/assign_literal_a.gno b/gnovm/tests/files/types/assign_literal_a.gno index e7c01f51536..4a1e1173725 100644 --- a/gnovm/tests/files/types/assign_literal_a.gno +++ b/gnovm/tests/files/types/assign_literal_a.gno @@ -5,7 +5,7 @@ func main() { } // Error: -// files/types/assign_literal_a.gno:4:2: no new variables on left side of := +// assign_literal_a.gno:4:2: no new variables on left side of := // TypeCheckError: -// main/files/types/assign_literal_a.gno:4:2: non-name 1 on left side of := +// main/assign_literal_a.gno:4:2: non-name 1 on left side of := diff --git a/gnovm/tests/files/types/assign_nil.gno b/gnovm/tests/files/types/assign_nil.gno index 51981cc4427..7965feee8d5 100644 --- a/gnovm/tests/files/types/assign_nil.gno +++ b/gnovm/tests/files/types/assign_nil.gno @@ -8,7 +8,7 @@ func main() { } // Error: -// main/files/types/assign_nil.gno:7:2: cannot assign to uverse nil +// main/assign_nil.gno:7:2-18: cannot assign to uverse nil // TypeCheckError: -// main/files/types/assign_nil.gno:7:5: cannot assign to nil (neither addressable nor a map index expression); main/files/types/assign_nil.gno:6:6: declared and not used: j +// main/assign_nil.gno:7:5: cannot assign to nil (neither addressable nor a map index expression); main/assign_nil.gno:6:6: declared and not used: j diff --git a/gnovm/tests/files/types/assign_nil2.gno b/gnovm/tests/files/types/assign_nil2.gno index a193f6897a5..99a0764a517 100644 --- a/gnovm/tests/files/types/assign_nil2.gno +++ b/gnovm/tests/files/types/assign_nil2.gno @@ -8,7 +8,7 @@ func main() { } // Error: -// main/files/types/assign_nil2.gno:7:2: cannot assign to uverse nil +// main/assign_nil2.gno:7:2-20: cannot assign to uverse nil // TypeCheckError: -// main/files/types/assign_nil2.gno:7:2: cannot assign to nil (neither addressable nor a map index expression); main/files/types/assign_nil2.gno:7:7: cannot assign to nil (neither addressable nor a map index expression); main/files/types/assign_nil2.gno:6:6: declared and not used: ok +// main/assign_nil2.gno:7:2: cannot assign to nil (neither addressable nor a map index expression); main/assign_nil2.gno:7:7: cannot assign to nil (neither addressable nor a map index expression); main/assign_nil2.gno:6:6: declared and not used: ok diff --git a/gnovm/tests/files/types/assign_range_a.gno b/gnovm/tests/files/types/assign_range_a.gno index 6e540c1d467..fe948b1938b 100644 --- a/gnovm/tests/files/types/assign_range_a.gno +++ b/gnovm/tests/files/types/assign_range_a.gno @@ -19,7 +19,7 @@ func main() { } // Error: -// main/files/types/assign_range_a.gno:16:2: cannot use string as int +// main/assign_range_a.gno:16:2-18:3: cannot use string as int // TypeCheckError: -// main/files/types/assign_range_a.gno:16:6: cannot use k (value of type string) as int value in assignment +// main/assign_range_a.gno:16:6: cannot use k (value of type string) as int value in assignment diff --git a/gnovm/tests/files/types/assign_range_a1.gno b/gnovm/tests/files/types/assign_range_a1.gno index 0d59d9acf70..7569101f864 100644 --- a/gnovm/tests/files/types/assign_range_a1.gno +++ b/gnovm/tests/files/types/assign_range_a1.gno @@ -19,7 +19,7 @@ func main() { } // Error: -// main/files/types/assign_range_a1.gno:16:2: cannot assign to (const (6 bigint)) +// main/assign_range_a1.gno:16:2-18:3: cannot assign to (const (6 bigint)) // TypeCheckError: -// main/files/types/assign_range_a1.gno:16:6: cannot assign to 6 (neither addressable nor a map index expression) +// main/assign_range_a1.gno:16:6: cannot assign to 6 (neither addressable nor a map index expression) diff --git a/gnovm/tests/files/types/assign_range_b.gno b/gnovm/tests/files/types/assign_range_b.gno index cd99fdb55cf..ff059e0f515 100644 --- a/gnovm/tests/files/types/assign_range_b.gno +++ b/gnovm/tests/files/types/assign_range_b.gno @@ -17,7 +17,7 @@ func main() { } // Error: -// main/files/types/assign_range_b.gno:14:2: cannot use string as int +// main/assign_range_b.gno:14:2-16:3: cannot use string as int // TypeCheckError: -// main/files/types/assign_range_b.gno:14:9: cannot use v (value of type string) as int value in assignment +// main/assign_range_b.gno:14:9: cannot use v (value of type string) as int value in assignment diff --git a/gnovm/tests/files/types/assign_range_b1.gno b/gnovm/tests/files/types/assign_range_b1.gno index 906dbd03fce..f9e9aa1c07f 100644 --- a/gnovm/tests/files/types/assign_range_b1.gno +++ b/gnovm/tests/files/types/assign_range_b1.gno @@ -17,7 +17,7 @@ func main() { } // Error: -// main/files/types/assign_range_b1.gno:14:2: cannot use string as int +// main/assign_range_b1.gno:14:2-16:3: cannot use string as int // TypeCheckError: -// main/files/types/assign_range_b1.gno:14:9: cannot use v (value of type string) as int value in assignment +// main/assign_range_b1.gno:14:9: cannot use v (value of type string) as int value in assignment diff --git a/gnovm/tests/files/types/assign_range_c.gno b/gnovm/tests/files/types/assign_range_c.gno index f813c7a9f14..38bc23a04eb 100644 --- a/gnovm/tests/files/types/assign_range_c.gno +++ b/gnovm/tests/files/types/assign_range_c.gno @@ -17,7 +17,7 @@ func main() { } // Error: -// main/files/types/assign_range_c.gno:14:2: index type should be int, but got float32 +// main/assign_range_c.gno:14:2-16:3: index type should be int, but got float32 // TypeCheckError: -// main/files/types/assign_range_c.gno:14:6: cannot use k (value of type int) as float32 value in assignment; main/files/types/assign_range_c.gno:14:9: cannot use v (value of type string) as float32 value in assignment +// main/assign_range_c.gno:14:6: cannot use k (value of type int) as float32 value in assignment; main/assign_range_c.gno:14:9: cannot use v (value of type string) as float32 value in assignment diff --git a/gnovm/tests/files/types/assign_range_d.gno b/gnovm/tests/files/types/assign_range_d.gno index 92753e16d99..c5cf654f1be 100644 --- a/gnovm/tests/files/types/assign_range_d.gno +++ b/gnovm/tests/files/types/assign_range_d.gno @@ -11,7 +11,7 @@ func main() { } // Error: -// main/files/types/assign_range_d.gno:8:2: index type should be int, but got float32 +// main/assign_range_d.gno:8:2-10:3: index type should be int, but got float32 // TypeCheckError: -// main/files/types/assign_range_d.gno:8:6: cannot use index (value of type int) as float32 value in assignment; main/files/types/assign_range_d.gno:7:6: declared and not used: value +// main/assign_range_d.gno:8:6: cannot use index (value of type int) as float32 value in assignment; main/assign_range_d.gno:7:6: declared and not used: value diff --git a/gnovm/tests/files/types/assign_range_e.gno b/gnovm/tests/files/types/assign_range_e.gno index e7807737ef0..3c85485dc85 100644 --- a/gnovm/tests/files/types/assign_range_e.gno +++ b/gnovm/tests/files/types/assign_range_e.gno @@ -12,7 +12,7 @@ func main() { } // Error: -// main/files/types/assign_range_e.gno:8:2: value type should be int32, but got int +// main/assign_range_e.gno:8:2-11:3: value type should be int32, but got int // TypeCheckError: -// main/files/types/assign_range_e.gno:8:13: cannot use value (value of type rune) as int value in assignment +// main/assign_range_e.gno:8:13: cannot use value (value of type rune) as int value in assignment diff --git a/gnovm/tests/files/types/assign_rune_a.gno b/gnovm/tests/files/types/assign_rune_a.gno index 7447a6907fd..44cfa5375d0 100644 --- a/gnovm/tests/files/types/assign_rune_a.gno +++ b/gnovm/tests/files/types/assign_rune_a.gno @@ -9,7 +9,7 @@ func main() { } // Error: -// main/files/types/assign_rune_a.gno:7:2: cannot use untyped string as Int32Kind +// main/assign_rune_a.gno:7:2-9: cannot use untyped string as Int32Kind // TypeCheckError: -// main/files/types/assign_rune_a.gno:7:6: cannot use "a" (untyped string constant) as rune value in assignment +// main/assign_rune_a.gno:7:6: cannot use "a" (untyped string constant) as rune value in assignment diff --git a/gnovm/tests/files/types/assign_type_assertion.gno b/gnovm/tests/files/types/assign_type_assertion.gno index 58a5deeab26..ceb28d84897 100644 --- a/gnovm/tests/files/types/assign_type_assertion.gno +++ b/gnovm/tests/files/types/assign_type_assertion.gno @@ -19,7 +19,7 @@ func main() { } // Error: -// main/files/types/assign_type_assertion.gno:13:2: cannot use string as int +// main/assign_type_assertion.gno:13:2-20: cannot use string as int // TypeCheckError: -// main/files/types/assign_type_assertion.gno:13:10: cannot use i.(string) (comma, ok expression of type string) as int value in assignment +// main/assign_type_assertion.gno:13:10: cannot use i.(string) (comma, ok expression of type string) as int value in assignment diff --git a/gnovm/tests/files/types/assign_type_assertion_b.gno b/gnovm/tests/files/types/assign_type_assertion_b.gno index 5f739fc0529..d0aeedd0e04 100644 --- a/gnovm/tests/files/types/assign_type_assertion_b.gno +++ b/gnovm/tests/files/types/assign_type_assertion_b.gno @@ -29,7 +29,7 @@ func main() { } // Error: -// main/files/types/assign_type_assertion_b.gno:22:2: cannot use interface {IsSet func() bool} as int +// main/assign_type_assertion_b.gno:22:2-51: cannot use interface {IsSet func() bool} as int // TypeCheckError: -// main/files/types/assign_type_assertion_b.gno:22:20: cannot use err.(interface{IsSet() bool}) (comma, ok expression of type interface{IsSet() bool}) as int value in assignment; main/files/types/assign_type_assertion_b.gno:25:37: assertedErr.IsSet undefined (type int has no field or method IsSet) +// main/assign_type_assertion_b.gno:22:20: cannot use err.(interface{IsSet() bool}) (comma, ok expression of type interface{IsSet() bool}) as int value in assignment; main/assign_type_assertion_b.gno:25:37: assertedErr.IsSet undefined (type int has no field or method IsSet) diff --git a/gnovm/tests/files/types/assign_type_assertion_c.gno b/gnovm/tests/files/types/assign_type_assertion_c.gno index 1d632090650..4e2baea09bd 100644 --- a/gnovm/tests/files/types/assign_type_assertion_c.gno +++ b/gnovm/tests/files/types/assign_type_assertion_c.gno @@ -30,7 +30,7 @@ func main() { } // Error: -// main/files/types/assign_type_assertion_c.gno:23:2: interface {IsSet func() bool} does not implement interface {IsNotSet func() bool} (missing method IsNotSet) +// main/assign_type_assertion_c.gno:23:2-51: interface {IsSet func() bool} does not implement interface {IsNotSet func() bool} (missing method IsNotSet) // TypeCheckError: -// main/files/types/assign_type_assertion_c.gno:23:20: cannot use err.(interface{IsSet() bool}) (comma, ok expression of type interface{IsSet() bool}) as interface{IsNotSet() bool} value in assignment: interface{IsSet() bool} does not implement interface{IsNotSet() bool} (missing method IsNotSet); main/files/types/assign_type_assertion_c.gno:26:37: assertedErr.IsSet undefined (type interface{IsNotSet() bool} has no field or method IsSet) +// main/assign_type_assertion_c.gno:23:20: cannot use err.(interface{IsSet() bool}) (comma, ok expression of type interface{IsSet() bool}) as interface{IsNotSet() bool} value in assignment: interface{IsSet() bool} does not implement interface{IsNotSet() bool} (missing method IsNotSet); main/assign_type_assertion_c.gno:26:37: assertedErr.IsSet undefined (type interface{IsNotSet() bool} has no field or method IsSet) diff --git a/gnovm/tests/files/types/assign_type_assertion_d.gno b/gnovm/tests/files/types/assign_type_assertion_d.gno index 30585ab524f..de4555ac6a2 100644 --- a/gnovm/tests/files/types/assign_type_assertion_d.gno +++ b/gnovm/tests/files/types/assign_type_assertion_d.gno @@ -22,7 +22,7 @@ func main() { } // Error: -// main/files/types/assign_type_assertion_d.gno:19:2: cannot use main.Dog as main.Robot without explicit conversion +// main/assign_type_assertion_d.gno:19:2-18: cannot use main.Dog as main.Robot without explicit conversion // TypeCheckError: -// main/files/types/assign_type_assertion_d.gno:19:6: cannot use animal.(Dog) (comma, ok expression of struct type Dog) as Robot value in assignment +// main/assign_type_assertion_d.gno:19:6: cannot use animal.(Dog) (comma, ok expression of struct type Dog) as Robot value in assignment diff --git a/gnovm/tests/files/types/assign_type_assertion_e.gno b/gnovm/tests/files/types/assign_type_assertion_e.gno index d00c6cd00aa..3880de6f144 100644 --- a/gnovm/tests/files/types/assign_type_assertion_e.gno +++ b/gnovm/tests/files/types/assign_type_assertion_e.gno @@ -24,7 +24,7 @@ func main() { } // Error: -// main/files/types/assign_type_assertion_e.gno:20:2: cannot use main.Dog as main.Robot without explicit conversion +// main/assign_type_assertion_e.gno:20:2-22: cannot use main.Dog as main.Robot without explicit conversion // TypeCheckError: -// main/files/types/assign_type_assertion_e.gno:20:10: cannot use animal.(Dog) (comma, ok expression of struct type Dog) as Robot value in assignment +// main/assign_type_assertion_e.gno:20:10: cannot use animal.(Dog) (comma, ok expression of struct type Dog) as Robot value in assignment diff --git a/gnovm/tests/files/types/assign_type_assertion_f.gno b/gnovm/tests/files/types/assign_type_assertion_f.gno index 9e45447d105..f15f6d705c9 100644 --- a/gnovm/tests/files/types/assign_type_assertion_f.gno +++ b/gnovm/tests/files/types/assign_type_assertion_f.gno @@ -22,7 +22,7 @@ func main() { } // Error: -// main/files/types/assign_type_assertion_f.gno:19:2: cannot assign to (const (1 bigint)) +// main/assign_type_assertion_f.gno:19:2-22: cannot assign to (const (1 bigint)) // TypeCheckError: -// main/files/types/assign_type_assertion_f.gno:19:2: cannot assign to 1 (neither addressable nor a map index expression) +// main/assign_type_assertion_f.gno:19:2: cannot assign to 1 (neither addressable nor a map index expression) diff --git a/gnovm/tests/files/types/assign_type_assertion_g.gno b/gnovm/tests/files/types/assign_type_assertion_g.gno index c98d76ba762..7443a7fa640 100644 --- a/gnovm/tests/files/types/assign_type_assertion_g.gno +++ b/gnovm/tests/files/types/assign_type_assertion_g.gno @@ -24,7 +24,7 @@ func main() { } // Error: -// main/files/types/assign_type_assertion_g.gno:20:2: want bool type got int +// main/assign_type_assertion_g.gno:20:2-22: want bool type got int // TypeCheckError: -// main/files/types/assign_type_assertion_g.gno:20:10: cannot use animal.(Dog) (untyped bool value) as int value in assignment +// main/assign_type_assertion_g.gno:20:10: cannot use animal.(Dog) (untyped bool value) as int value in assignment diff --git a/gnovm/tests/files/types/bigdec2.gno b/gnovm/tests/files/types/bigdec2.gno index 65930d2b17d..e3da2b13c5c 100644 --- a/gnovm/tests/files/types/bigdec2.gno +++ b/gnovm/tests/files/types/bigdec2.gno @@ -8,7 +8,7 @@ func main() { } // Error: -// main/files/types/bigdec2.gno:7:10: cannot convert untyped bigdec to integer -- 1.2 not an exact integer +// main/bigdec2.gno:7:10-17: cannot convert untyped bigdec to integer -- 1.2 not an exact integer // TypeCheckError: -// main/files/types/bigdec2.gno:7:14: 1.2 (untyped float constant) truncated to uint64 +// main/bigdec2.gno:7:14: 1.2 (untyped float constant) truncated to uint64 diff --git a/gnovm/tests/files/types/bigdec5.gno b/gnovm/tests/files/types/bigdec5.gno index 51cb40cff3c..0d5f3e38c60 100644 --- a/gnovm/tests/files/types/bigdec5.gno +++ b/gnovm/tests/files/types/bigdec5.gno @@ -8,7 +8,7 @@ func main() { } // Error: -// main/files/types/bigdec5.gno:6:2: cannot convert untyped bigdec to integer -- 1.2 not an exact integer +// main/bigdec5.gno:6:2-9: cannot convert untyped bigdec to integer -- 1.2 not an exact integer // TypeCheckError: -// main/files/types/bigdec5.gno:6:6: cannot use 1.2 (untyped float constant) as uint64 value in assignment (truncated) +// main/bigdec5.gno:6:6: cannot use 1.2 (untyped float constant) as uint64 value in assignment (truncated) diff --git a/gnovm/tests/files/types/bigdec_6.gno b/gnovm/tests/files/types/bigdec_6.gno index 8f9c309c535..f3c875a7bad 100644 --- a/gnovm/tests/files/types/bigdec_6.gno +++ b/gnovm/tests/files/types/bigdec_6.gno @@ -5,7 +5,7 @@ func main() { } // Error: -// main/files/types/bigdec_6.gno:4:10: operator % not defined on: BigdecKind +// main/bigdec_6.gno:4:10-17: operator % not defined on: BigdecKind // TypeCheckError: -// main/files/types/bigdec_6.gno:4:10: invalid operation: operator % not defined on 1 (untyped float constant) +// main/bigdec_6.gno:4:10: invalid operation: operator % not defined on 1 (untyped float constant) diff --git a/gnovm/tests/files/types/cmp_array_b.gno b/gnovm/tests/files/types/cmp_array_b.gno index ea0880233cf..f4b361a0562 100644 --- a/gnovm/tests/files/types/cmp_array_b.gno +++ b/gnovm/tests/files/types/cmp_array_b.gno @@ -12,7 +12,7 @@ func main() { } // Error: -// main/files/types/cmp_array_b.gno:10:25: [2][]int is not comparable +// main/cmp_array_b.gno:10:25-31: [2][]int is not comparable // TypeCheckError: -// main/files/types/cmp_array_b.gno:10:25: invalid operation: a == b ([2][]int cannot be compared); main/files/types/cmp_array_b.gno:11:25: invalid operation: a == c ([2][]int cannot be compared) +// main/cmp_array_b.gno:10:25: invalid operation: a == b ([2][]int cannot be compared); main/cmp_array_b.gno:11:25: invalid operation: a == c ([2][]int cannot be compared) diff --git a/gnovm/tests/files/types/cmp_array_c.gno b/gnovm/tests/files/types/cmp_array_c.gno index 00e7d6b2320..fdd62097f0f 100644 --- a/gnovm/tests/files/types/cmp_array_c.gno +++ b/gnovm/tests/files/types/cmp_array_c.gno @@ -12,7 +12,7 @@ func main() { } // Error: -// main/files/types/cmp_array_c.gno:10:25: [2][]int is not comparable +// main/cmp_array_c.gno:10:25-31: [2][]int is not comparable // TypeCheckError: -// main/files/types/cmp_array_c.gno:10:25: invalid operation: a == b ([2][2][]int cannot be compared); main/files/types/cmp_array_c.gno:11:25: invalid operation: a == c ([2][2][]int cannot be compared) +// main/cmp_array_c.gno:10:25: invalid operation: a == b ([2][2][]int cannot be compared); main/cmp_array_c.gno:11:25: invalid operation: a == c ([2][2][]int cannot be compared) diff --git a/gnovm/tests/files/types/cmp_iface_5.gno b/gnovm/tests/files/types/cmp_iface_5.gno index b4c8853f151..a3875fa57b8 100644 --- a/gnovm/tests/files/types/cmp_iface_5.gno +++ b/gnovm/tests/files/types/cmp_iface_5.gno @@ -24,7 +24,7 @@ func main() { } // Error: -// main/files/types/cmp_iface_5.gno:19:5: int64 does not implement .uverse.error (missing method Error) +// main/cmp_iface_5.gno:19:5-23: int64 does not implement .uverse.error (missing method Error) // TypeCheckError: -// main/files/types/cmp_iface_5.gno:19:15: invalid operation: errCmp == int64(1) (mismatched types error and int64) +// main/cmp_iface_5.gno:19:15: invalid operation: errCmp == int64(1) (mismatched types error and int64) diff --git a/gnovm/tests/files/types/cmp_iface_5_stdlibs.gno b/gnovm/tests/files/types/cmp_iface_5_stdlibs.gno index 5427c0aeac2..f1354c9a69b 100644 --- a/gnovm/tests/files/types/cmp_iface_5_stdlibs.gno +++ b/gnovm/tests/files/types/cmp_iface_5_stdlibs.gno @@ -24,7 +24,7 @@ func main() { } // Error: -// main/files/types/cmp_iface_5_stdlibs.gno:19:5: int64 does not implement .uverse.error (missing method Error) +// main/cmp_iface_5_stdlibs.gno:19:5-23: int64 does not implement .uverse.error (missing method Error) // TypeCheckError: -// main/files/types/cmp_iface_5_stdlibs.gno:19:15: invalid operation: errCmp == int64(1) (mismatched types error and int64) +// main/cmp_iface_5_stdlibs.gno:19:15: invalid operation: errCmp == int64(1) (mismatched types error and int64) diff --git a/gnovm/tests/files/types/cmp_pointer.gno b/gnovm/tests/files/types/cmp_pointer.gno index 3a942246d7c..d0a924f8c30 100644 --- a/gnovm/tests/files/types/cmp_pointer.gno +++ b/gnovm/tests/files/types/cmp_pointer.gno @@ -20,7 +20,7 @@ func main() { } // Error: -// main/files/types/cmp_pointer.gno:19:27: cannot use main.Person as main.Worker without explicit conversion +// main/cmp_pointer.gno:19:27-38: cannot use main.Person as main.Worker without explicit conversion // TypeCheckError: -// main/files/types/cmp_pointer.gno:19:33: invalid operation: p1 == p2Ptr (mismatched types *Person and *Worker) +// main/cmp_pointer.gno:19:33: invalid operation: p1 == p2Ptr (mismatched types *Person and *Worker) diff --git a/gnovm/tests/files/types/cmp_primitive_1.gno b/gnovm/tests/files/types/cmp_primitive_1.gno index fedb5d5a041..a27338cd7c0 100644 --- a/gnovm/tests/files/types/cmp_primitive_1.gno +++ b/gnovm/tests/files/types/cmp_primitive_1.gno @@ -19,7 +19,7 @@ func main() { } // Error: -// main/files/types/cmp_primitive_1.gno:14:5: cannot use untyped Bigint as StringKind +// main/cmp_primitive_1.gno:14:5-18: cannot use untyped Bigint as StringKind // TypeCheckError: -// main/files/types/cmp_primitive_1.gno:14:10: invalid operation: 1 == Error(1) (mismatched types untyped int and Error) +// main/cmp_primitive_1.gno:14:10: invalid operation: 1 == Error(1) (mismatched types untyped int and Error) diff --git a/gnovm/tests/files/types/cmp_slice_4.gno b/gnovm/tests/files/types/cmp_slice_4.gno index 5c2498ba365..295513ddf97 100644 --- a/gnovm/tests/files/types/cmp_slice_4.gno +++ b/gnovm/tests/files/types/cmp_slice_4.gno @@ -7,7 +7,7 @@ func main() { } // Error: -// main/files/types/cmp_slice_4.gno:6:10: cannot use int as string +// main/cmp_slice_4.gno:6:10-23: cannot use int as string // TypeCheckError: -// main/files/types/cmp_slice_4.gno:6:15: invalid operation: a == expected (mismatched types int and string) +// main/cmp_slice_4.gno:6:15: invalid operation: a == expected (mismatched types int and string) diff --git a/gnovm/tests/files/types/cmp_struct_a.gno b/gnovm/tests/files/types/cmp_struct_a.gno index a7e9fd70e90..d3d9c8e48e3 100644 --- a/gnovm/tests/files/types/cmp_struct_a.gno +++ b/gnovm/tests/files/types/cmp_struct_a.gno @@ -17,7 +17,7 @@ func main() { } // Error: -// main/files/types/cmp_struct_a.gno:15:25: [2][]int is not comparable +// main/cmp_struct_a.gno:15:25-31: [2][]int is not comparable // TypeCheckError: -// main/files/types/cmp_struct_a.gno:15:25: invalid operation: a == b (struct containing [2][2][]int cannot be compared); main/files/types/cmp_struct_a.gno:16:25: invalid operation: a == c (struct containing [2][2][]int cannot be compared) +// main/cmp_struct_a.gno:15:25: invalid operation: a == b (struct containing [2][2][]int cannot be compared); main/cmp_struct_a.gno:16:25: invalid operation: a == c (struct containing [2][2][]int cannot be compared) diff --git a/gnovm/tests/files/types/cmp_struct_b.gno b/gnovm/tests/files/types/cmp_struct_b.gno index d6f05125218..2ae146ca906 100644 --- a/gnovm/tests/files/types/cmp_struct_b.gno +++ b/gnovm/tests/files/types/cmp_struct_b.gno @@ -16,7 +16,7 @@ func main() { } // Error: -// main/files/types/cmp_struct_b.gno:15:10: cannot use main.foo as main.bar without explicit conversion +// main/cmp_struct_b.gno:15:10-18: cannot use main.foo as main.bar without explicit conversion // TypeCheckError: -// main/files/types/cmp_struct_b.gno:15:16: invalid operation: fa == bb (mismatched types foo and bar) +// main/cmp_struct_b.gno:15:16: invalid operation: fa == bb (mismatched types foo and bar) diff --git a/gnovm/tests/files/types/cmp_struct_c.gno b/gnovm/tests/files/types/cmp_struct_c.gno index 4e97f3c0248..955cc4a02cf 100644 --- a/gnovm/tests/files/types/cmp_struct_c.gno +++ b/gnovm/tests/files/types/cmp_struct_c.gno @@ -16,7 +16,7 @@ func main() { } // Error: -// main/files/types/cmp_struct_c.gno:15:10: main.bar is not comparable +// main/cmp_struct_c.gno:15:10-18: main.bar is not comparable // TypeCheckError: -// main/files/types/cmp_struct_c.gno:15:16: invalid operation: fa == bb (mismatched types foo and bar) +// main/cmp_struct_c.gno:15:16: invalid operation: fa == bb (mismatched types foo and bar) diff --git a/gnovm/tests/files/types/cmp_struct_c1.gno b/gnovm/tests/files/types/cmp_struct_c1.gno index 41180ba75c7..d7bc2bc248a 100644 --- a/gnovm/tests/files/types/cmp_struct_c1.gno +++ b/gnovm/tests/files/types/cmp_struct_c1.gno @@ -16,7 +16,7 @@ func main() { } // Error: -// main/files/types/cmp_struct_c1.gno:15:10: cannot use main.bar as main.foo without explicit conversion +// main/cmp_struct_c1.gno:15:10-18: cannot use main.bar as main.foo without explicit conversion // TypeCheckError: -// main/files/types/cmp_struct_c1.gno:15:16: invalid operation: bb == fa (mismatched types bar and foo) +// main/cmp_struct_c1.gno:15:16: invalid operation: bb == fa (mismatched types bar and foo) diff --git a/gnovm/tests/files/types/cmp_struct_d.gno b/gnovm/tests/files/types/cmp_struct_d.gno index a4342085028..114187ce35d 100644 --- a/gnovm/tests/files/types/cmp_struct_d.gno +++ b/gnovm/tests/files/types/cmp_struct_d.gno @@ -16,7 +16,7 @@ func main() { } // Error: -// main/files/types/cmp_struct_d.gno:15:10: main.bar is not comparable +// main/cmp_struct_d.gno:15:10-18: main.bar is not comparable // TypeCheckError: -// main/files/types/cmp_struct_d.gno:15:16: invalid operation: fa == bb (mismatched types foo and bar) +// main/cmp_struct_d.gno:15:16: invalid operation: fa == bb (mismatched types foo and bar) diff --git a/gnovm/tests/files/types/cmp_struct_e.gno b/gnovm/tests/files/types/cmp_struct_e.gno index 19d855b24d1..4782ffa7f32 100644 --- a/gnovm/tests/files/types/cmp_struct_e.gno +++ b/gnovm/tests/files/types/cmp_struct_e.gno @@ -12,7 +12,7 @@ func main() { } // Error: -// main/files/types/cmp_struct_e.gno:11:10: main.foo is not comparable +// main/cmp_struct_e.gno:11:10-18: main.foo is not comparable // TypeCheckError: -// main/files/types/cmp_struct_e.gno:11:10: invalid operation: fa == fb (struct containing []int cannot be compared) +// main/cmp_struct_e.gno:11:10: invalid operation: fa == fb (struct containing []int cannot be compared) diff --git a/gnovm/tests/files/types/cmp_struct_g.gno b/gnovm/tests/files/types/cmp_struct_g.gno index 7c89f8b0ed2..35d993b25ce 100644 --- a/gnovm/tests/files/types/cmp_struct_g.gno +++ b/gnovm/tests/files/types/cmp_struct_g.gno @@ -18,7 +18,7 @@ func main() { } // Error: -// main/files/types/cmp_struct_g.gno:17:25: cannot use main.Person as main.Dog without explicit conversion +// main/cmp_struct_g.gno:17:25-31: cannot use main.Person as main.Dog without explicit conversion // TypeCheckError: -// main/files/types/cmp_struct_g.gno:17:30: invalid operation: a == b (mismatched types Person and Dog) +// main/cmp_struct_g.gno:17:30: invalid operation: a == b (mismatched types Person and Dog) diff --git a/gnovm/tests/files/types/eql_0a0.gno b/gnovm/tests/files/types/eql_0a0.gno index ba96e18f779..1e679ec01f3 100644 --- a/gnovm/tests/files/types/eql_0a0.gno +++ b/gnovm/tests/files/types/eql_0a0.gno @@ -6,7 +6,7 @@ func main() { } // Error: -// main/files/types/eql_0a0.gno:5:10: cannot use int as int8 +// main/eql_0a0.gno:5:10-27: cannot use int as int8 // TypeCheckError: -// main/files/types/eql_0a0.gno:5:20: invalid operation: int(1) == int8(1) (mismatched types int and int8) +// main/eql_0a0.gno:5:20: invalid operation: int(1) == int8(1) (mismatched types int and int8) diff --git a/gnovm/tests/files/types/eql_0a01.gno b/gnovm/tests/files/types/eql_0a01.gno index 1061b3022dd..53c03e2bfcf 100644 --- a/gnovm/tests/files/types/eql_0a01.gno +++ b/gnovm/tests/files/types/eql_0a01.gno @@ -5,7 +5,7 @@ func main() { } // Error: -// main/files/types/eql_0a01.gno:4:10: is not comparable +// main/eql_0a01.gno:4:10-20: is not comparable // TypeCheckError: -// main/files/types/eql_0a01.gno:4:17: invalid operation: nil == nil (operator == not defined on untyped nil) +// main/eql_0a01.gno:4:17: invalid operation: nil == nil (operator == not defined on untyped nil) diff --git a/gnovm/tests/files/types/eql_0a02.gno b/gnovm/tests/files/types/eql_0a02.gno index 36e73c5652e..fa78f00faac 100644 --- a/gnovm/tests/files/types/eql_0a02.gno +++ b/gnovm/tests/files/types/eql_0a02.gno @@ -8,7 +8,7 @@ func main() { } // Error: -// main/files/types/eql_0a02.gno:7:10: cannot use *int as string +// main/eql_0a02.gno:7:10-21: cannot use *int as string // TypeCheckError: -// main/files/types/eql_0a02.gno:7:20: invalid operation: intPtr == s (mismatched types *int and string) +// main/eql_0a02.gno:7:20: invalid operation: intPtr == s (mismatched types *int and string) diff --git a/gnovm/tests/files/types/eql_0a03.gno b/gnovm/tests/files/types/eql_0a03.gno index 2b982693f07..0f514b58cfa 100644 --- a/gnovm/tests/files/types/eql_0a03.gno +++ b/gnovm/tests/files/types/eql_0a03.gno @@ -9,7 +9,7 @@ func main() { } // Error: -// main/files/types/eql_0a03.gno:8:10: cannot use int8 as int +// main/eql_0a03.gno:8:10-22: cannot use int8 as int // TypeCheckError: -// main/files/types/eql_0a03.gno:8:20: invalid operation: intPtr == &i (mismatched types *int8 and *int) +// main/eql_0a03.gno:8:20: invalid operation: intPtr == &i (mismatched types *int8 and *int) diff --git a/gnovm/tests/files/types/eql_0a1.gno b/gnovm/tests/files/types/eql_0a1.gno index 881e7d795b2..d7b2e8f66a5 100644 --- a/gnovm/tests/files/types/eql_0a1.gno +++ b/gnovm/tests/files/types/eql_0a1.gno @@ -6,7 +6,7 @@ func main() { } // Error: -// main/files/types/eql_0a1.gno:5:10: cannot use int as int8 +// main/eql_0a1.gno:5:10-27: cannot use int as int8 // TypeCheckError: -// main/files/types/eql_0a1.gno:5:20: invalid operation: int(1) != int8(1) (mismatched types int and int8) +// main/eql_0a1.gno:5:20: invalid operation: int(1) != int8(1) (mismatched types int and int8) diff --git a/gnovm/tests/files/types/eql_0a1a0.gno b/gnovm/tests/files/types/eql_0a1a0.gno index b9cf9aa44ec..ebea69b120c 100644 --- a/gnovm/tests/files/types/eql_0a1a0.gno +++ b/gnovm/tests/files/types/eql_0a1a0.gno @@ -6,7 +6,7 @@ func main() { } // Error: -// main/files/types/eql_0a1a0.gno:5:10: cannot use uint64 as uint +// main/eql_0a1a0.gno:5:10-24: cannot use uint64 as uint // TypeCheckError: -// main/files/types/eql_0a1a0.gno:5:23: invalid operation: uint64(1) == a (mismatched types uint64 and uint) +// main/eql_0a1a0.gno:5:23: invalid operation: uint64(1) == a (mismatched types uint64 and uint) diff --git a/gnovm/tests/files/types/eql_0a1a1.gno b/gnovm/tests/files/types/eql_0a1a1.gno index 90c8373c965..770c4970b89 100644 --- a/gnovm/tests/files/types/eql_0a1a1.gno +++ b/gnovm/tests/files/types/eql_0a1a1.gno @@ -6,7 +6,7 @@ func main() { } // Error: -// main/files/types/eql_0a1a1.gno:5:10: cannot use uint as uint64 +// main/eql_0a1a1.gno:5:10-24: cannot use uint as uint64 // TypeCheckError: -// main/files/types/eql_0a1a1.gno:5:15: invalid operation: a == uint64(1) (mismatched types uint and uint64) +// main/eql_0a1a1.gno:5:15: invalid operation: a == uint64(1) (mismatched types uint and uint64) diff --git a/gnovm/tests/files/types/eql_0a1f.gno b/gnovm/tests/files/types/eql_0a1f.gno index 5a6972ea05b..8138d120ce3 100644 --- a/gnovm/tests/files/types/eql_0a1f.gno +++ b/gnovm/tests/files/types/eql_0a1f.gno @@ -7,7 +7,7 @@ func main() { } // Error: -// main/files/types/eql_0a1f.gno:6:10: cannot use int as string +// main/eql_0a1f.gno:6:10-23: cannot use int as string // TypeCheckError: -// main/files/types/eql_0a1f.gno:6:15: invalid operation: a == expected (mismatched types int and string) +// main/eql_0a1f.gno:6:15: invalid operation: a == expected (mismatched types int and string) diff --git a/gnovm/tests/files/types/eql_0a1g.gno b/gnovm/tests/files/types/eql_0a1g.gno index 7b0c3ffb308..3233665295b 100644 --- a/gnovm/tests/files/types/eql_0a1g.gno +++ b/gnovm/tests/files/types/eql_0a1g.gno @@ -7,7 +7,7 @@ func main() { } // Error: -// main/files/types/eql_0a1g.gno:6:10: cannot use int as float32 +// main/eql_0a1g.gno:6:10-16: cannot use int as float32 // TypeCheckError: -// main/files/types/eql_0a1g.gno:6:15: invalid operation: a == b (mismatched types int and float32) +// main/eql_0a1g.gno:6:15: invalid operation: a == b (mismatched types int and float32) diff --git a/gnovm/tests/files/types/eql_0a2.gno b/gnovm/tests/files/types/eql_0a2.gno index a60fec4bd98..2f6eefc9847 100644 --- a/gnovm/tests/files/types/eql_0a2.gno +++ b/gnovm/tests/files/types/eql_0a2.gno @@ -22,7 +22,7 @@ func main() { } // Error: -// main/files/types/eql_0a2.gno:21:10: cannot use main.Error1 as main.Error2 without explicit conversion +// main/eql_0a2.gno:21:10-32: cannot use main.Error1 as main.Error2 without explicit conversion // TypeCheckError: -// main/files/types/eql_0a2.gno:21:23: invalid operation: Error1(0) == Error2(0) (mismatched types Error1 and Error2) +// main/eql_0a2.gno:21:23: invalid operation: Error1(0) == Error2(0) (mismatched types Error1 and Error2) diff --git a/gnovm/tests/files/types/eql_0a3.gno b/gnovm/tests/files/types/eql_0a3.gno index c14d65ed318..f199efe23a6 100644 --- a/gnovm/tests/files/types/eql_0a3.gno +++ b/gnovm/tests/files/types/eql_0a3.gno @@ -22,7 +22,7 @@ func main() { } // Error: -// main/files/types/eql_0a3.gno:21:10: cannot use main.Error1 as main.Error2 without explicit conversion +// main/eql_0a3.gno:21:10-32: cannot use main.Error1 as main.Error2 without explicit conversion // TypeCheckError: -// main/files/types/eql_0a3.gno:21:23: invalid operation: Error1(0) != Error2(0) (mismatched types Error1 and Error2) +// main/eql_0a3.gno:21:23: invalid operation: Error1(0) != Error2(0) (mismatched types Error1 and Error2) diff --git a/gnovm/tests/files/types/eql_0a4.gno b/gnovm/tests/files/types/eql_0a4.gno index b86e1c6d985..23638255bff 100644 --- a/gnovm/tests/files/types/eql_0a4.gno +++ b/gnovm/tests/files/types/eql_0a4.gno @@ -22,7 +22,7 @@ func main() { } // Error: -// main/files/types/eql_0a4.gno:21:10: cannot use main.Error1 as main.Error2 without explicit conversion +// main/eql_0a4.gno:21:10-32: cannot use main.Error1 as main.Error2 without explicit conversion // TypeCheckError: -// main/files/types/eql_0a4.gno:21:23: invalid operation: Error1(0) != Error2(0) (mismatched types Error1 and Error2) +// main/eql_0a4.gno:21:23: invalid operation: Error1(0) != Error2(0) (mismatched types Error1 and Error2) diff --git a/gnovm/tests/files/types/eql_0b2.gno b/gnovm/tests/files/types/eql_0b2.gno index b4eef7012c8..9097c69e0b4 100644 --- a/gnovm/tests/files/types/eql_0b2.gno +++ b/gnovm/tests/files/types/eql_0b2.gno @@ -19,7 +19,7 @@ func main() { } // Error: -// main/files/types/eql_0b2.gno:14:5: cannot use untyped Bigint as StringKind +// main/eql_0b2.gno:14:5-18: cannot use untyped Bigint as StringKind // TypeCheckError: -// main/files/types/eql_0b2.gno:14:10: invalid operation: 1 == Error(1) (mismatched types untyped int and Error) +// main/eql_0b2.gno:14:10: invalid operation: 1 == Error(1) (mismatched types untyped int and Error) diff --git a/gnovm/tests/files/types/eql_0b4.gno b/gnovm/tests/files/types/eql_0b4.gno index 6d0570075e4..ae0d7d41ae1 100644 --- a/gnovm/tests/files/types/eql_0b4.gno +++ b/gnovm/tests/files/types/eql_0b4.gno @@ -10,7 +10,7 @@ func main() { } // Error: -// main/files/types/eql_0b4.gno:9:10: bigint does not implement .uverse.error (missing method Error) +// main/eql_0b4.gno:9:10-21: bigint does not implement .uverse.error (missing method Error) // TypeCheckError: -// main/files/types/eql_0b4.gno:9:10: cannot convert 5 (untyped int constant) to type interface{Error() string} +// main/eql_0b4.gno:9:10: cannot convert 5 (untyped int constant) to type interface{Error() string} diff --git a/gnovm/tests/files/types/eql_0c2.gno b/gnovm/tests/files/types/eql_0c2.gno index d264598303d..c50b1a0a586 100644 --- a/gnovm/tests/files/types/eql_0c2.gno +++ b/gnovm/tests/files/types/eql_0c2.gno @@ -21,7 +21,7 @@ func main() { } // Error: -// main/files/types/eql_0c2.gno:16:5: bigint overflows target kind +// main/eql_0c2.gno:16:5-20: bigint overflows target kind // TypeCheckError: -// main/files/types/eql_0c2.gno:16:17: 128 (untyped int constant) overflows int8 +// main/eql_0c2.gno:16:17: 128 (untyped int constant) overflows int8 diff --git a/gnovm/tests/files/types/eql_0e0.gno b/gnovm/tests/files/types/eql_0e0.gno index f0977ef56bb..45189384e56 100644 --- a/gnovm/tests/files/types/eql_0e0.gno +++ b/gnovm/tests/files/types/eql_0e0.gno @@ -24,7 +24,7 @@ func main() { } // Error: -// main/files/types/eql_0e0.gno:23:10: cannot use main.Error1 as main.Error2 without explicit conversion +// main/eql_0e0.gno:23:10-18: cannot use main.Error1 as main.Error2 without explicit conversion // TypeCheckError: -// main/files/types/eql_0e0.gno:23:16: invalid operation: e1 == e2 (mismatched types Error1 and Error2) +// main/eql_0e0.gno:23:16: invalid operation: e1 == e2 (mismatched types Error1 and Error2) diff --git a/gnovm/tests/files/types/eql_0e1.gno b/gnovm/tests/files/types/eql_0e1.gno index 2b93c02288d..4d356e9b632 100644 --- a/gnovm/tests/files/types/eql_0e1.gno +++ b/gnovm/tests/files/types/eql_0e1.gno @@ -24,7 +24,7 @@ func main() { } // Error: -// main/files/types/eql_0e1.gno:23:10: cannot use main.Error1 as main.Error2 without explicit conversion +// main/eql_0e1.gno:23:10-18: cannot use main.Error1 as main.Error2 without explicit conversion // TypeCheckError: -// main/files/types/eql_0e1.gno:23:16: invalid operation: e1 != e2 (mismatched types Error1 and Error2) +// main/eql_0e1.gno:23:16: invalid operation: e1 != e2 (mismatched types Error1 and Error2) diff --git a/gnovm/tests/files/types/eql_0f0.gno b/gnovm/tests/files/types/eql_0f0.gno index 5b854894c49..05dd68643c1 100644 --- a/gnovm/tests/files/types/eql_0f0.gno +++ b/gnovm/tests/files/types/eql_0f0.gno @@ -25,7 +25,7 @@ func main() { } // Error: -// main/files/types/eql_0f0.gno:19:5: bigint does not implement .uverse.error (missing method Error) +// main/eql_0f0.gno:19:5-16: bigint does not implement .uverse.error (missing method Error) // TypeCheckError: -// main/files/types/eql_0f0.gno:19:5: cannot convert 1 (untyped int constant) to type interface{Error() string} +// main/eql_0f0.gno:19:5: cannot convert 1 (untyped int constant) to type interface{Error() string} diff --git a/gnovm/tests/files/types/eql_0f1.gno b/gnovm/tests/files/types/eql_0f1.gno index 88084a1fa86..f9a1342c300 100644 --- a/gnovm/tests/files/types/eql_0f1.gno +++ b/gnovm/tests/files/types/eql_0f1.gno @@ -25,7 +25,7 @@ func main() { } // Error: -// main/files/types/eql_0f1.gno:19:5: int64 does not implement .uverse.error (missing method Error) +// main/eql_0f1.gno:19:5-23: int64 does not implement .uverse.error (missing method Error) // TypeCheckError: -// main/files/types/eql_0f1.gno:19:17: invalid operation: int64(1) == errCmp (mismatched types int64 and error) +// main/eql_0f1.gno:19:17: invalid operation: int64(1) == errCmp (mismatched types int64 and error) diff --git a/gnovm/tests/files/types/eql_0f14.gno b/gnovm/tests/files/types/eql_0f14.gno index 2db524df181..c4c508a7521 100644 --- a/gnovm/tests/files/types/eql_0f14.gno +++ b/gnovm/tests/files/types/eql_0f14.gno @@ -11,7 +11,7 @@ func main() { } // Error: -// main/files/types/eql_0f14.gno:10:10: cannot use [2]string as [2]int +// main/eql_0f14.gno:10:10-16: cannot use [2]string as [2]int // TypeCheckError: -// main/files/types/eql_0f14.gno:10:15: invalid operation: a == c (mismatched types [2]string and [2]int) +// main/eql_0f14.gno:10:15: invalid operation: a == c (mismatched types [2]string and [2]int) diff --git a/gnovm/tests/files/types/eql_0f16.gno b/gnovm/tests/files/types/eql_0f16.gno index 3a58ff16c36..3eb9293e56e 100644 --- a/gnovm/tests/files/types/eql_0f16.gno +++ b/gnovm/tests/files/types/eql_0f16.gno @@ -17,7 +17,7 @@ func main() { } // Error: -// main/files/types/eql_0f16.gno:16:10: [2]main.word is not comparable +// main/eql_0f16.gno:16:10-16: [2]main.word is not comparable // TypeCheckError: -// main/files/types/eql_0f16.gno:16:10: invalid operation: a == c ([2]word cannot be compared) +// main/eql_0f16.gno:16:10: invalid operation: a == c ([2]word cannot be compared) diff --git a/gnovm/tests/files/types/eql_0f17.gno b/gnovm/tests/files/types/eql_0f17.gno index f1f44fa7001..ff578389710 100644 --- a/gnovm/tests/files/types/eql_0f17.gno +++ b/gnovm/tests/files/types/eql_0f17.gno @@ -10,7 +10,7 @@ func main() { } // Error: -// main/files/types/eql_0f17.gno:9:10: main.f can only be compared to nil +// main/eql_0f17.gno:9:10-16: main.f can only be compared to nil // TypeCheckError: -// main/files/types/eql_0f17.gno:9:10: invalid operation: a == b (func can only be compared to nil) +// main/eql_0f17.gno:9:10: invalid operation: a == b (func can only be compared to nil) diff --git a/gnovm/tests/files/types/eql_0f20.gno b/gnovm/tests/files/types/eql_0f20.gno index da337c4d7c9..4141b4b8eed 100644 --- a/gnovm/tests/files/types/eql_0f20.gno +++ b/gnovm/tests/files/types/eql_0f20.gno @@ -10,7 +10,7 @@ func main() { } // Error: -// main/files/types/eql_0f20.gno:9:10: [2]main.f is not comparable +// main/eql_0f20.gno:9:10-18: [2]main.f is not comparable // TypeCheckError: -// main/files/types/eql_0f20.gno:9:15: invalid operation: a == nil (mismatched types [2]f and untyped nil) +// main/eql_0f20.gno:9:15: invalid operation: a == nil (mismatched types [2]f and untyped nil) diff --git a/gnovm/tests/files/types/eql_0f21.gno b/gnovm/tests/files/types/eql_0f21.gno index 1711ee73fd6..43e0aaff164 100644 --- a/gnovm/tests/files/types/eql_0f21.gno +++ b/gnovm/tests/files/types/eql_0f21.gno @@ -10,7 +10,7 @@ func main() { } // Error: -// main/files/types/eql_0f21.gno:9:10: [2]main.f is not comparable +// main/eql_0f21.gno:9:10-16: [2]main.f is not comparable // TypeCheckError: -// main/files/types/eql_0f21.gno:9:10: invalid operation: a == b ([2]f cannot be compared) +// main/eql_0f21.gno:9:10: invalid operation: a == b ([2]f cannot be compared) diff --git a/gnovm/tests/files/types/eql_0f27.gno b/gnovm/tests/files/types/eql_0f27.gno index 684272f62b1..6ea7ad1775d 100644 --- a/gnovm/tests/files/types/eql_0f27.gno +++ b/gnovm/tests/files/types/eql_0f27.gno @@ -18,7 +18,7 @@ func main() { } // Error: -// main/files/types/eql_0f27.gno:13:5: operator > not defined on: InterfaceKind +// main/eql_0f27.gno:13:5-22: operator > not defined on: InterfaceKind // TypeCheckError: -// main/files/types/eql_0f27.gno:13:5: invalid operation: errCmp1 > errCmp2 (operator > not defined on interface) +// main/eql_0f27.gno:13:5: invalid operation: errCmp1 > errCmp2 (operator > not defined on interface) diff --git a/gnovm/tests/files/types/eql_0f28.gno b/gnovm/tests/files/types/eql_0f28.gno index 5b3e3f2c1a2..b7e69d25a08 100644 --- a/gnovm/tests/files/types/eql_0f28.gno +++ b/gnovm/tests/files/types/eql_0f28.gno @@ -28,7 +28,7 @@ func main() { } // Error: -// main/files/types/eql_0f28.gno:27:10: operator > not defined on: InterfaceKind +// main/eql_0f28.gno:27:10-17: operator > not defined on: InterfaceKind // TypeCheckError: -// main/files/types/eql_0f28.gno:27:10: invalid operation: e1 > e2 (operator > not defined on interface) +// main/eql_0f28.gno:27:10: invalid operation: e1 > e2 (operator > not defined on interface) diff --git a/gnovm/tests/files/types/eql_0f29.gno b/gnovm/tests/files/types/eql_0f29.gno index 79dbb8b493c..47c5ceb654f 100644 --- a/gnovm/tests/files/types/eql_0f29.gno +++ b/gnovm/tests/files/types/eql_0f29.gno @@ -21,7 +21,7 @@ func main() { } // Error: -// main/files/types/eql_0f29.gno:16:5: operator > not defined on: InterfaceKind +// main/eql_0f29.gno:16:5-17: operator > not defined on: InterfaceKind // TypeCheckError: -// main/files/types/eql_0f29.gno:16:5: invalid operation: l > Error(0) (operator > not defined on interface) +// main/eql_0f29.gno:16:5: invalid operation: l > Error(0) (operator > not defined on interface) diff --git a/gnovm/tests/files/types/eql_0f2b.gno b/gnovm/tests/files/types/eql_0f2b.gno index 027a52d72ca..c0b8956b2cf 100644 --- a/gnovm/tests/files/types/eql_0f2b.gno +++ b/gnovm/tests/files/types/eql_0f2b.gno @@ -25,7 +25,7 @@ func main() { } // Error: -// main/files/types/eql_0f2b.gno:19:5: operator <= not defined on: InterfaceKind +// main/eql_0f2b.gno:19:5-23: operator <= not defined on: InterfaceKind // TypeCheckError: -// main/files/types/eql_0f2b.gno:19:17: invalid operation: Error(0) <= errCmp (operator <= not defined on interface) +// main/eql_0f2b.gno:19:17: invalid operation: Error(0) <= errCmp (operator <= not defined on interface) diff --git a/gnovm/tests/files/types/eql_0f2c.gno b/gnovm/tests/files/types/eql_0f2c.gno index 4ac5663e8b1..98768e74fe8 100644 --- a/gnovm/tests/files/types/eql_0f2c.gno +++ b/gnovm/tests/files/types/eql_0f2c.gno @@ -25,7 +25,7 @@ func main() { } // Error: -// main/files/types/eql_0f2c.gno:19:5: operator < not defined on: InterfaceKind +// main/eql_0f2c.gno:19:5-22: operator < not defined on: InterfaceKind // TypeCheckError: -// main/files/types/eql_0f2c.gno:19:16: invalid operation: Error(0) < errCmp (operator < not defined on interface) +// main/eql_0f2c.gno:19:16: invalid operation: Error(0) < errCmp (operator < not defined on interface) diff --git a/gnovm/tests/files/types/eql_0f30.gno b/gnovm/tests/files/types/eql_0f30.gno index 1fd5ab11c96..7c0ec9a2e82 100644 --- a/gnovm/tests/files/types/eql_0f30.gno +++ b/gnovm/tests/files/types/eql_0f30.gno @@ -6,7 +6,7 @@ func main() { } // Error: -// main/files/types/eql_0f30.gno:5:10: []uint8 can only be compared to nil +// main/eql_0f30.gno:5:10-36: []uint8 can only be compared to nil // TypeCheckError: -// main/files/types/eql_0f30.gno:5:10: invalid operation: []byte("a") == []byte("b") (slice can only be compared to nil) +// main/eql_0f30.gno:5:10: invalid operation: []byte("a") == []byte("b") (slice can only be compared to nil) diff --git a/gnovm/tests/files/types/eql_0f30a.gno b/gnovm/tests/files/types/eql_0f30a.gno index ee628a22b19..38607e7eff8 100644 --- a/gnovm/tests/files/types/eql_0f30a.gno +++ b/gnovm/tests/files/types/eql_0f30a.gno @@ -5,7 +5,7 @@ func main() { } // Error: -// main/files/types/eql_0f30a.gno:4:10: map[string]int can only be compared to nil +// main/eql_0f30a.gno:4:10-58: map[string]int can only be compared to nil // TypeCheckError: -// main/files/types/eql_0f30a.gno:4:10: invalid operation: map[string]int{…} == map[string]int{…} (map can only be compared to nil) +// main/eql_0f30a.gno:4:10: invalid operation: map[string]int{…} == map[string]int{…} (map can only be compared to nil) diff --git a/gnovm/tests/files/types/eql_0f30b.gno b/gnovm/tests/files/types/eql_0f30b.gno index 7e26618d199..0948c9b0fdf 100644 --- a/gnovm/tests/files/types/eql_0f30b.gno +++ b/gnovm/tests/files/types/eql_0f30b.gno @@ -10,7 +10,7 @@ func main() { } // Error: -// main/files/types/eql_0f30b.gno:9:10: main.f can only be compared to nil +// main/eql_0f30b.gno:9:10-18: main.f can only be compared to nil // TypeCheckError: -// main/files/types/eql_0f30b.gno:9:10: invalid operation: f1 == f2 (func can only be compared to nil) +// main/eql_0f30b.gno:9:10: invalid operation: f1 == f2 (func can only be compared to nil) diff --git a/gnovm/tests/files/types/eql_0f30d.gno b/gnovm/tests/files/types/eql_0f30d.gno index 7360cc117ab..7b74b955465 100644 --- a/gnovm/tests/files/types/eql_0f30d.gno +++ b/gnovm/tests/files/types/eql_0f30d.gno @@ -5,7 +5,7 @@ func main() { } // Error: -// main/files/types/eql_0f30d.gno:4:10: []int can only be compared to nil +// main/eql_0f30d.gno:4:10-30: []int can only be compared to nil // TypeCheckError: -// main/files/types/eql_0f30d.gno:4:10: invalid operation: []int{…} == []int{…} (slice can only be compared to nil) +// main/eql_0f30d.gno:4:10: invalid operation: []int{…} == []int{…} (slice can only be compared to nil) diff --git a/gnovm/tests/files/types/eql_0f30f.gno b/gnovm/tests/files/types/eql_0f30f.gno index 1274c70738f..4950076d315 100644 --- a/gnovm/tests/files/types/eql_0f30f.gno +++ b/gnovm/tests/files/types/eql_0f30f.gno @@ -8,7 +8,7 @@ func main() { } // Error: -// main/files/types/eql_0f30f.gno:7:10: cannot use [2]int as [3]int +// main/eql_0f30f.gno:7:10-16: cannot use [2]int as [3]int // TypeCheckError: -// main/files/types/eql_0f30f.gno:7:15: invalid operation: a == b (mismatched types [2]int and [3]int) +// main/eql_0f30f.gno:7:15: invalid operation: a == b (mismatched types [2]int and [3]int) diff --git a/gnovm/tests/files/types/eql_0f30g.gno b/gnovm/tests/files/types/eql_0f30g.gno index 57df69cd018..344df0f9002 100644 --- a/gnovm/tests/files/types/eql_0f30g.gno +++ b/gnovm/tests/files/types/eql_0f30g.gno @@ -8,7 +8,7 @@ func main() { } // Error: -// main/files/types/eql_0f30g.gno:7:10: []int can only be compared to nil +// main/eql_0f30g.gno:7:10-16: []int can only be compared to nil // TypeCheckError: -// main/files/types/eql_0f30g.gno:7:15: invalid operation: a == b (mismatched types [2]int and []int) +// main/eql_0f30g.gno:7:15: invalid operation: a == b (mismatched types [2]int and []int) diff --git a/gnovm/tests/files/types/eql_0f41.gno b/gnovm/tests/files/types/eql_0f41.gno index b00c4b8b906..e244b23af71 100644 --- a/gnovm/tests/files/types/eql_0f41.gno +++ b/gnovm/tests/files/types/eql_0f41.gno @@ -32,7 +32,7 @@ func main() { } // Error: -// main/files/types/eql_0f41.gno:27:5: main.animal does not implement .uverse.error (missing method Error) +// main/eql_0f41.gno:27:5-20: main.animal does not implement .uverse.error (missing method Error) // TypeCheckError: -// main/files/types/eql_0f41.gno:27:14: invalid operation: get() == errCmp (mismatched types animal and error) +// main/eql_0f41.gno:27:14: invalid operation: get() == errCmp (mismatched types animal and error) diff --git a/gnovm/tests/files/types/eql_0f8.gno b/gnovm/tests/files/types/eql_0f8.gno index c9f5a795732..46e0b909ce1 100644 --- a/gnovm/tests/files/types/eql_0f8.gno +++ b/gnovm/tests/files/types/eql_0f8.gno @@ -24,7 +24,7 @@ func main() { } // Error: -// main/files/types/eql_0f8.gno:19:5: int64 does not implement .uverse.error (missing method Error) +// main/eql_0f8.gno:19:5-23: int64 does not implement .uverse.error (missing method Error) // TypeCheckError: -// main/files/types/eql_0f8.gno:19:15: invalid operation: errCmp == int64(1) (mismatched types error and int64) +// main/eql_0f8.gno:19:15: invalid operation: errCmp == int64(1) (mismatched types error and int64) diff --git a/gnovm/tests/files/types/explicit_conversion_1.gno b/gnovm/tests/files/types/explicit_conversion_1.gno index c0d55ecbaa3..a426ebe9d23 100644 --- a/gnovm/tests/files/types/explicit_conversion_1.gno +++ b/gnovm/tests/files/types/explicit_conversion_1.gno @@ -10,7 +10,7 @@ func main() { } // Error: -// main/files/types/explicit_conversion_1.gno:7:11: cannot convert StringKind to UintKind +// main/explicit_conversion_1.gno:7:11-32: cannot convert StringKind to UintKind // TypeCheckError: -// main/files/types/explicit_conversion_1.gno:7:16: cannot convert string("hello") (constant "hello" of type string) to type uint +// main/explicit_conversion_1.gno:7:16: cannot convert string("hello") (constant "hello" of type string) to type uint diff --git a/gnovm/tests/files/types/incdec_a1.gno b/gnovm/tests/files/types/incdec_a1.gno index 51859d56412..400dcfc8803 100644 --- a/gnovm/tests/files/types/incdec_a1.gno +++ b/gnovm/tests/files/types/incdec_a1.gno @@ -7,7 +7,7 @@ func main() { } // Error: -// main/files/types/incdec_a1.gno:5:2: operator ++ not defined on: StringKind +// main/incdec_a1.gno:5:2-5: operator ++ not defined on: StringKind // TypeCheckError: -// main/files/types/incdec_a1.gno:5:2: invalid operation: a++ (non-numeric type string) +// main/incdec_a1.gno:5:2: invalid operation: a++ (non-numeric type string) diff --git a/gnovm/tests/files/types/incdec_a4.gno b/gnovm/tests/files/types/incdec_a4.gno index 265882cdf43..89637ed0baa 100644 --- a/gnovm/tests/files/types/incdec_a4.gno +++ b/gnovm/tests/files/types/incdec_a4.gno @@ -15,7 +15,7 @@ func main() { } // Error: -// main/files/types/incdec_a4.gno:12:2: cannot use int8 as main.Int without explicit conversion +// main/incdec_a4.gno:12:2-13: cannot use int8 as main.Int without explicit conversion // TypeCheckError: -// main/files/types/incdec_a4.gno:12:6: cannot use int8(0) (constant 0 of type int8) as Int value in assignment +// main/incdec_a4.gno:12:6: cannot use int8(0) (constant 0 of type int8) as Int value in assignment diff --git a/gnovm/tests/files/types/nil.gno b/gnovm/tests/files/types/nil.gno index 48020635c4c..7815ef6c07b 100644 --- a/gnovm/tests/files/types/nil.gno +++ b/gnovm/tests/files/types/nil.gno @@ -6,7 +6,7 @@ func main() { } // Error: -// main/files/types/nil.gno:5:10: operator + not defined on: nil +// main/nil.gno:5:10-19: operator + not defined on: nil // TypeCheckError: -// main/files/types/nil.gno:5:10: invalid operation: operator + not defined on nil +// main/nil.gno:5:10: invalid operation: operator + not defined on nil diff --git a/gnovm/tests/files/types/or_a0.gno b/gnovm/tests/files/types/or_a0.gno index efa9079e88c..5e19afba622 100644 --- a/gnovm/tests/files/types/or_a0.gno +++ b/gnovm/tests/files/types/or_a0.gno @@ -6,7 +6,7 @@ func main() { } // Error: -// main/files/types/or_a0.gno:5:10: invalid operation: mismatched types int and int8 +// main/or_a0.gno:5:10-26: invalid operation: (const (0 int)) | (const (1 int8)) (mismatched types int and int8) // TypeCheckError: -// main/files/types/or_a0.gno:5:10: invalid operation: int(0) | int8(1) (mismatched types int and int8) +// main/or_a0.gno:5:10: invalid operation: int(0) | int8(1) (mismatched types int and int8) diff --git a/gnovm/tests/files/types/or_a1.gno b/gnovm/tests/files/types/or_a1.gno index 2185f04e5fe..6a9032fdd90 100644 --- a/gnovm/tests/files/types/or_a1.gno +++ b/gnovm/tests/files/types/or_a1.gno @@ -22,7 +22,7 @@ func main() { } // Error: -// main/files/types/or_a1.gno:21:10: invalid operation: mismatched types main.Error1 and main.Error2 +// main/or_a1.gno:21:10-31: invalid operation: (const (0 main.Error1)) | (const (0 main.Error2)) (mismatched types main.Error1 and main.Error2) // TypeCheckError: -// main/files/types/or_a1.gno:21:10: invalid operation: Error1(0) | Error2(0) (mismatched types Error1 and Error2) +// main/or_a1.gno:21:10: invalid operation: Error1(0) | Error2(0) (mismatched types Error1 and Error2) diff --git a/gnovm/tests/files/types/or_b2.gno b/gnovm/tests/files/types/or_b2.gno index 11ccb6460b3..fca17e0ad2b 100644 --- a/gnovm/tests/files/types/or_b2.gno +++ b/gnovm/tests/files/types/or_b2.gno @@ -6,7 +6,7 @@ func main() { } // Error: -// main/files/types/or_b2.gno:5:10: operator | not defined on: StringKind +// main/or_b2.gno:5:10-17: operator | not defined on: StringKind // TypeCheckError: -// main/files/types/or_b2.gno:5:10: invalid operation: 1 | "a" (mismatched types untyped int and untyped string) +// main/or_b2.gno:5:10: invalid operation: 1 | "a" (mismatched types untyped int and untyped string) diff --git a/gnovm/tests/files/types/or_b3.gno b/gnovm/tests/files/types/or_b3.gno index 29bcb070407..ee1b0996d8c 100644 --- a/gnovm/tests/files/types/or_b3.gno +++ b/gnovm/tests/files/types/or_b3.gno @@ -6,7 +6,7 @@ func main() { } // Error: -// main/files/types/or_b3.gno:5:10: operator | not defined on: StringKind +// main/or_b3.gno:5:10-19: operator | not defined on: StringKind // TypeCheckError: -// main/files/types/or_b3.gno:5:10: invalid operation: operator | not defined on "b" (untyped string constant) +// main/or_b3.gno:5:10: invalid operation: operator | not defined on "b" (untyped string constant) diff --git a/gnovm/tests/files/types/or_d0.gno b/gnovm/tests/files/types/or_d0.gno index 72c58b608a7..a466fdd4312 100644 --- a/gnovm/tests/files/types/or_d0.gno +++ b/gnovm/tests/files/types/or_d0.gno @@ -7,7 +7,7 @@ func main() { } // Error: -// main/files/types/or_d0.gno:6:10: operator | not defined on: BigdecKind +// main/or_d0.gno:6:10-17: operator | not defined on: BigdecKind // TypeCheckError: -// main/files/types/or_d0.gno:6:10: invalid operation: operator | not defined on 1.0 (untyped float constant 1) +// main/or_d0.gno:6:10: invalid operation: operator | not defined on 1.0 (untyped float constant 1) diff --git a/gnovm/tests/files/types/or_d4.gno b/gnovm/tests/files/types/or_d4.gno index 5efaf9a1571..7c55dcebd59 100644 --- a/gnovm/tests/files/types/or_d4.gno +++ b/gnovm/tests/files/types/or_d4.gno @@ -7,7 +7,7 @@ func main() { } // Error: -// main/files/types/or_d4.gno:6:10: operator | not defined on: BigdecKind +// main/or_d4.gno:6:10-17: operator | not defined on: BigdecKind // TypeCheckError: -// main/files/types/or_d4.gno:6:10: invalid operation: operator | not defined on 1.0 (untyped float constant 1) +// main/or_d4.gno:6:10: invalid operation: operator | not defined on 1.0 (untyped float constant 1) diff --git a/gnovm/tests/files/types/or_e0.gno b/gnovm/tests/files/types/or_e0.gno index 2c40e2dd814..56984d45252 100644 --- a/gnovm/tests/files/types/or_e0.gno +++ b/gnovm/tests/files/types/or_e0.gno @@ -24,7 +24,7 @@ func main() { } // Error: -// main/files/types/or_e0.gno:23:10: invalid operation: mismatched types main.Error1 and main.Error2 +// main/or_e0.gno:23:10-17: invalid operation: e1 | e2 (mismatched types main.Error1 and main.Error2) // TypeCheckError: -// main/files/types/or_e0.gno:23:10: invalid operation: e1 | e2 (mismatched types Error1 and Error2) +// main/or_e0.gno:23:10: invalid operation: e1 | e2 (mismatched types Error1 and Error2) diff --git a/gnovm/tests/files/types/or_f0.gno b/gnovm/tests/files/types/or_f0.gno index 57ff4817b9a..fd6dca6de9d 100644 --- a/gnovm/tests/files/types/or_f0.gno +++ b/gnovm/tests/files/types/or_f0.gno @@ -20,7 +20,7 @@ func main() { } // Error: -// main/files/types/or_f0.gno:19:10: operator | not defined on: InterfaceKind +// main/or_f0.gno:19:10-20: operator | not defined on: InterfaceKind // TypeCheckError: -// main/files/types/or_f0.gno:19:10: cannot convert 1 (untyped int constant) to type interface{Error() string} +// main/or_f0.gno:19:10: cannot convert 1 (untyped int constant) to type interface{Error() string} diff --git a/gnovm/tests/files/types/or_f1.gno b/gnovm/tests/files/types/or_f1.gno index 480265d8481..e77d640437c 100644 --- a/gnovm/tests/files/types/or_f1.gno +++ b/gnovm/tests/files/types/or_f1.gno @@ -20,7 +20,7 @@ func main() { } // Error: -// main/files/types/or_f1.gno:19:10: operator | not defined on: InterfaceKind +// main/or_f1.gno:19:10-27: operator | not defined on: InterfaceKind // TypeCheckError: -// main/files/types/or_f1.gno:19:10: invalid operation: Error(0) | errCmp (mismatched types Error and error) +// main/or_f1.gno:19:10: invalid operation: Error(0) | errCmp (mismatched types Error and error) diff --git a/gnovm/tests/files/types/or_f2.gno b/gnovm/tests/files/types/or_f2.gno index dd9ef752bdc..b29d56ce028 100644 --- a/gnovm/tests/files/types/or_f2.gno +++ b/gnovm/tests/files/types/or_f2.gno @@ -28,7 +28,7 @@ func main() { } // Error: -// main/files/types/or_f2.gno:27:10: operator | not defined on: InterfaceKind +// main/or_f2.gno:27:10-17: operator | not defined on: InterfaceKind // TypeCheckError: -// main/files/types/or_f2.gno:27:10: invalid operation: operator | not defined on e1 (variable of interface type E) +// main/or_f2.gno:27:10: invalid operation: operator | not defined on e1 (variable of interface type E) diff --git a/gnovm/tests/files/types/overflow_a1.gno b/gnovm/tests/files/types/overflow_a1.gno index 787e8db2d98..de16e76f959 100644 --- a/gnovm/tests/files/types/overflow_a1.gno +++ b/gnovm/tests/files/types/overflow_a1.gno @@ -9,4 +9,4 @@ func main() { // cannot convert untyped bigdec to float64: strconv.ParseFloat: parsing "1E+1000": value out of range // TypeCheckError: -// main/files/types/overflow_a1.gno:5:10: cannot use Huge (untyped float constant 1e+1000) as float64 value in argument to built-in println (overflows) +// main/overflow_a1.gno:5:10: cannot use Huge (untyped float constant 1e+1000) as float64 value in argument to built-in println (overflows) diff --git a/gnovm/tests/files/types/rem_a0.gno b/gnovm/tests/files/types/rem_a0.gno index d57d5b99f7a..48a25429c54 100644 --- a/gnovm/tests/files/types/rem_a0.gno +++ b/gnovm/tests/files/types/rem_a0.gno @@ -6,7 +6,7 @@ func main() { } // Error: -// main/files/types/rem_a0.gno:5:10: invalid operation: mismatched types int and int8 +// main/rem_a0.gno:5:10-26: invalid operation: (const (1 int)) % (const (1 int8)) (mismatched types int and int8) // TypeCheckError: -// main/files/types/rem_a0.gno:5:10: invalid operation: int(1) % int8(1) (mismatched types int and int8) +// main/rem_a0.gno:5:10: invalid operation: int(1) % int8(1) (mismatched types int and int8) diff --git a/gnovm/tests/files/types/rem_a1.gno b/gnovm/tests/files/types/rem_a1.gno index a48e30b6269..2098b0758af 100644 --- a/gnovm/tests/files/types/rem_a1.gno +++ b/gnovm/tests/files/types/rem_a1.gno @@ -22,7 +22,7 @@ func main() { } // Error: -// main/files/types/rem_a1.gno:21:10: invalid operation: mismatched types main.Error1 and main.Error2 +// main/rem_a1.gno:21:10-31: invalid operation: (const (0 main.Error1)) % (const (0 main.Error2)) (mismatched types main.Error1 and main.Error2) // TypeCheckError: -// main/files/types/rem_a1.gno:21:10: invalid operation: Error1(0) % Error2(0) (mismatched types Error1 and Error2) +// main/rem_a1.gno:21:10: invalid operation: Error1(0) % Error2(0) (mismatched types Error1 and Error2) diff --git a/gnovm/tests/files/types/rem_a2.gno b/gnovm/tests/files/types/rem_a2.gno index 41e00f1e7f2..3ff22fd2558 100644 --- a/gnovm/tests/files/types/rem_a2.gno +++ b/gnovm/tests/files/types/rem_a2.gno @@ -5,7 +5,7 @@ func main() { } // Error: -// main/files/types/rem_a2.gno:4:10: invalid operation: division by zero +// main/rem_a2.gno:4:10-15: invalid operation: division by zero // TypeCheckError: -// main/files/types/rem_a2.gno:4:14: invalid operation: division by zero +// main/rem_a2.gno:4:14: invalid operation: division by zero diff --git a/gnovm/tests/files/types/rem_f3.gno b/gnovm/tests/files/types/rem_f3.gno index 61590edbb78..e848f6fe974 100644 --- a/gnovm/tests/files/types/rem_f3.gno +++ b/gnovm/tests/files/types/rem_f3.gno @@ -6,7 +6,7 @@ func main() { } // Error: -// main/files/types/rem_f3.gno:5:10: invalid operation: division by zero +// main/rem_f3.gno:5:10-15: invalid operation: division by zero // TypeCheckError: -// main/files/types/rem_f3.gno:5:14: invalid operation: division by zero +// main/rem_f3.gno:5:14: invalid operation: division by zero diff --git a/gnovm/tests/files/types/runtime_a0.gno b/gnovm/tests/files/types/runtime_a0.gno index b718066b374..621ce7092ef 100644 --- a/gnovm/tests/files/types/runtime_a0.gno +++ b/gnovm/tests/files/types/runtime_a0.gno @@ -6,7 +6,7 @@ func main() { } // Error: -// main/files/types/runtime_a0.gno:5:2: operator ++ not defined on: BoolKind +// main/runtime_a0.gno:5:2-12: operator ++ not defined on: BoolKind // TypeCheckError: -// main/files/types/runtime_a0.gno:5:2: invalid operation: m["foo"]++ (non-numeric type bool) +// main/runtime_a0.gno:5:2: invalid operation: m["foo"]++ (non-numeric type bool) diff --git a/gnovm/tests/files/types/runtime_a3.gno b/gnovm/tests/files/types/runtime_a3.gno index 8654871c4c1..873b5d416a3 100644 --- a/gnovm/tests/files/types/runtime_a3.gno +++ b/gnovm/tests/files/types/runtime_a3.gno @@ -9,7 +9,7 @@ func main() { } // Error: -// main/files/types/runtime_a3.gno:8:2: operator ++ not defined on: InterfaceKind +// main/runtime_a3.gno:8:2-9: operator ++ not defined on: InterfaceKind // TypeCheckError: -// main/files/types/runtime_a3.gno:8:2: invalid operation: gen()++ (non-numeric type any) +// main/runtime_a3.gno:8:2: invalid operation: gen()++ (non-numeric type any) diff --git a/gnovm/tests/files/types/shift_a11.gno b/gnovm/tests/files/types/shift_a11.gno index 340af4f54c6..611666b1c49 100644 --- a/gnovm/tests/files/types/shift_a11.gno +++ b/gnovm/tests/files/types/shift_a11.gno @@ -7,7 +7,7 @@ func main() { } // Error: -// main/files/types/shift_a11.gno:5:7: cannot convert (const ("hello" string)) to type uint +// main/shift_a11.gno:5:7-19: cannot convert (const ("hello" string)) to type uint // TypeCheckError: -// main/files/types/shift_a11.gno:5:12: cannot convert "hello" (untyped string constant) to type uint +// main/shift_a11.gno:5:12: cannot convert "hello" (untyped string constant) to type uint diff --git a/gnovm/tests/files/types/shift_a14.gno b/gnovm/tests/files/types/shift_a14.gno index 0ebef8c7fe4..6b912d3b194 100644 --- a/gnovm/tests/files/types/shift_a14.gno +++ b/gnovm/tests/files/types/shift_a14.gno @@ -7,7 +7,7 @@ func main() { } // Error: -// main/files/types/shift_a14.gno:5:7: operator << not defined on: StringKind +// main/shift_a14.gno:5:7-13: operator << not defined on: StringKind // TypeCheckError: -// main/files/types/shift_a14.gno:5:7: invalid operation: shifted operand a (variable of type string) must be integer +// main/shift_a14.gno:5:7: invalid operation: shifted operand a (variable of type string) must be integer diff --git a/gnovm/tests/files/types/shift_a15.gno b/gnovm/tests/files/types/shift_a15.gno index 1a58dc5315b..863c38069da 100644 --- a/gnovm/tests/files/types/shift_a15.gno +++ b/gnovm/tests/files/types/shift_a15.gno @@ -7,7 +7,7 @@ func main() { } // Error: -// main/files/types/shift_a15.gno:6:2: operator <<= not defined on: StringKind +// main/shift_a15.gno:6:2-9: operator <<= not defined on: StringKind // TypeCheckError: -// main/files/types/shift_a15.gno:6:2: invalid operation: shifted operand a (variable of type string) must be integer +// main/shift_a15.gno:6:2: invalid operation: shifted operand a (variable of type string) must be integer diff --git a/gnovm/tests/files/types/shift_a16.gno b/gnovm/tests/files/types/shift_a16.gno index 1a05561da5a..420d62b1b84 100644 --- a/gnovm/tests/files/types/shift_a16.gno +++ b/gnovm/tests/files/types/shift_a16.gno @@ -6,7 +6,7 @@ func main() { } // Error: -// main/files/types/shift_a16.gno:4:7: operator << not defined on: StringKind +// main/shift_a16.gno:4:7-19: operator << not defined on: StringKind // TypeCheckError: -// main/files/types/shift_a16.gno:4:7: invalid operation: shifted operand "hello" (untyped string constant) must be integer +// main/shift_a16.gno:4:7: invalid operation: shifted operand "hello" (untyped string constant) must be integer diff --git a/gnovm/tests/files/types/shift_a3.gno b/gnovm/tests/files/types/shift_a3.gno index 76a625d11d0..243caac9a00 100644 --- a/gnovm/tests/files/types/shift_a3.gno +++ b/gnovm/tests/files/types/shift_a3.gno @@ -7,7 +7,7 @@ func main() { } // Error: -// main/files/types/shift_a3.gno:5:2: bigint overflows target kind +// main/shift_a3.gno:5:2-19: bigint overflows target kind // TypeCheckError: -// main/files/types/shift_a3.gno:5:10: cannot use 1 << 'a' (untyped int constant 158456325028528675187087900672) as int value in argument to built-in println (overflows) +// main/shift_a3.gno:5:10: cannot use 1 << 'a' (untyped int constant 158456325028528675187087900672) as int value in argument to built-in println (overflows) diff --git a/gnovm/tests/files/types/shift_a7.gno b/gnovm/tests/files/types/shift_a7.gno index ee7cb82f2fc..6efb9981efb 100644 --- a/gnovm/tests/files/types/shift_a7.gno +++ b/gnovm/tests/files/types/shift_a7.gno @@ -6,7 +6,7 @@ func main() { } // Error: -// main/files/types/shift_a7.gno:5:10: cannot convert (const ("a" string)) to type uint +// main/shift_a7.gno:5:10-18: cannot convert (const ("a" string)) to type uint // TypeCheckError: -// main/files/types/shift_a7.gno:5:15: cannot convert "a" (untyped string constant) to type uint +// main/shift_a7.gno:5:15: cannot convert "a" (untyped string constant) to type uint diff --git a/gnovm/tests/files/types/shift_b6.gno b/gnovm/tests/files/types/shift_b6.gno index a537209a303..040e2e5f781 100644 --- a/gnovm/tests/files/types/shift_b6.gno +++ b/gnovm/tests/files/types/shift_b6.gno @@ -27,7 +27,7 @@ func main() { } // Error: -// main/files/types/shift_b6.gno:22:2: bigint does not implement main.R (missing method foo) +// main/shift_b6.gno:22:2-12: bigint does not implement main.R (missing method foo) // TypeCheckError: -// main/files/types/shift_b6.gno:22:6: cannot use 1 << x (value of type int) as R value in assignment: int does not implement R (missing method foo) +// main/shift_b6.gno:22:6: cannot use 1 << x (value of type int) as R value in assignment: int does not implement R (missing method foo) diff --git a/gnovm/tests/files/types/shift_b7.gno b/gnovm/tests/files/types/shift_b7.gno index 67d503503e4..192e949c4f2 100644 --- a/gnovm/tests/files/types/shift_b7.gno +++ b/gnovm/tests/files/types/shift_b7.gno @@ -10,7 +10,7 @@ func main() { } // Error: -// main/files/types/shift_b7.gno:7:7: operator << not defined on: Float32Kind +// main/shift_b7.gno:7:7-24: operator << not defined on: Float32Kind // TypeCheckError: -// main/files/types/shift_b7.gno:7:15: invalid operation: shifted operand 1 (type float32) must be integer +// main/shift_b7.gno:7:15: invalid operation: shifted operand 1 (type float32) must be integer diff --git a/gnovm/tests/files/types/shift_c6.gno b/gnovm/tests/files/types/shift_c6.gno index 3103e449649..d8fa13c399c 100644 --- a/gnovm/tests/files/types/shift_c6.gno +++ b/gnovm/tests/files/types/shift_c6.gno @@ -11,7 +11,7 @@ func main() { } // Error: -// main/files/types/shift_c6.gno:8:2: operator << not defined on: Float32Kind +// main/shift_c6.gno:8:2-12: operator << not defined on: Float32Kind // TypeCheckError: -// main/files/types/shift_c6.gno:8:6: invalid operation: shifted operand 1 (type float32) must be integer +// main/shift_c6.gno:8:6: invalid operation: shifted operand 1 (type float32) must be integer diff --git a/gnovm/tests/files/types/shift_c7.gno b/gnovm/tests/files/types/shift_c7.gno index 23f6d2016d7..093be5f067c 100644 --- a/gnovm/tests/files/types/shift_c7.gno +++ b/gnovm/tests/files/types/shift_c7.gno @@ -11,7 +11,7 @@ func main() { } // Error: -// main/files/types/shift_c7.gno:8:2: operator << not defined on: Float32Kind +// main/shift_c7.gno:8:2-14: operator << not defined on: Float32Kind // TypeCheckError: -// main/files/types/shift_c7.gno:8:6: invalid operation: shifted operand 1 (type float32) must be integer +// main/shift_c7.gno:8:6: invalid operation: shifted operand 1 (type float32) must be integer diff --git a/gnovm/tests/files/types/shift_c8.gno b/gnovm/tests/files/types/shift_c8.gno index 43ef731714f..269f9340a56 100644 --- a/gnovm/tests/files/types/shift_c8.gno +++ b/gnovm/tests/files/types/shift_c8.gno @@ -11,7 +11,7 @@ func main() { } // Error: -// main/files/types/shift_c8.gno:8:2: cannot use int as float32 +// main/shift_c8.gno:8:2-19: cannot use int as float32 // TypeCheckError: -// main/files/types/shift_c8.gno:8:6: cannot use 1 << x + int(1) (value of type int) as float32 value in assignment +// main/shift_c8.gno:8:6: cannot use 1 << x + int(1) (value of type int) as float32 value in assignment diff --git a/gnovm/tests/files/types/shift_d12.gno b/gnovm/tests/files/types/shift_d12.gno index a905ff3f901..0972245a764 100644 --- a/gnovm/tests/files/types/shift_d12.gno +++ b/gnovm/tests/files/types/shift_d12.gno @@ -13,7 +13,7 @@ func main() { } // Error: -// main/files/types/shift_d12.gno:12:2: operator >> not defined on: Float32Kind +// main/shift_d12.gno:12:2-17: operator >> not defined on: Float32Kind // TypeCheckError: -// main/files/types/shift_d12.gno:12:12: invalid operation: shifted operand 1 (type float32) must be integer +// main/shift_d12.gno:12:12: invalid operation: shifted operand 1 (type float32) must be integer diff --git a/gnovm/tests/files/types/shift_d13.gno b/gnovm/tests/files/types/shift_d13.gno index af4f7faa9d5..041d82da6fa 100644 --- a/gnovm/tests/files/types/shift_d13.gno +++ b/gnovm/tests/files/types/shift_d13.gno @@ -14,7 +14,7 @@ func main() { } // Error: -// main/files/types/shift_d13.gno:13:2: cannot use int as float32 +// main/shift_d13.gno:13:2-22: cannot use int as float32 // TypeCheckError: -// main/files/types/shift_d13.gno:13:12: cannot use int(1) >> x (value of type int) as float32 value in argument to foo +// main/shift_d13.gno:13:12: cannot use int(1) >> x (value of type int) as float32 value in argument to foo diff --git a/gnovm/tests/files/types/shift_d27.gno b/gnovm/tests/files/types/shift_d27.gno index ae10c18a466..64e549e1920 100644 --- a/gnovm/tests/files/types/shift_d27.gno +++ b/gnovm/tests/files/types/shift_d27.gno @@ -8,7 +8,7 @@ func main() { } // Error: -// main/files/types/shift_d27.gno:6:2: operator << not defined on: Float32Kind +// main/shift_d27.gno:6:2-15: operator << not defined on: Float32Kind // TypeCheckError: -// main/files/types/shift_d27.gno:6:8: invalid operation: shifted operand 1 (type float32) must be integer +// main/shift_d27.gno:6:8: invalid operation: shifted operand 1 (type float32) must be integer diff --git a/gnovm/tests/files/types/shift_d28.gno b/gnovm/tests/files/types/shift_d28.gno index 9aa72a55dcc..1a2bf7159ba 100644 --- a/gnovm/tests/files/types/shift_d28.gno +++ b/gnovm/tests/files/types/shift_d28.gno @@ -8,7 +8,7 @@ func main() { } // Error: -// main/files/types/shift_d28.gno:6:2: operator << not defined on: Float32Kind +// main/shift_d28.gno:6:2-18: operator << not defined on: Float32Kind // TypeCheckError: -// main/files/types/shift_d28.gno:6:10: invalid operation: shifted operand 1 (type float32) must be integer +// main/shift_d28.gno:6:10: invalid operation: shifted operand 1 (type float32) must be integer diff --git a/gnovm/tests/files/types/shift_d32a.gno b/gnovm/tests/files/types/shift_d32a.gno index b76fbbf3b68..9bbabf33a15 100644 --- a/gnovm/tests/files/types/shift_d32a.gno +++ b/gnovm/tests/files/types/shift_d32a.gno @@ -10,7 +10,7 @@ func main() { } // Error: -// main/files/types/shift_d32a.gno:7:7: cannot convert untyped bigdec to integer -- 1.2 not an exact integer +// main/shift_d32a.gno:7:7-26: cannot convert untyped bigdec to integer -- 1.2 not an exact integer // TypeCheckError: -// main/files/types/shift_d32a.gno:7:16: invalid operation: shifted operand 1.2 (untyped float constant) must be integer +// main/shift_d32a.gno:7:16: invalid operation: shifted operand 1.2 (untyped float constant) must be integer diff --git a/gnovm/tests/files/types/shift_d34.gno b/gnovm/tests/files/types/shift_d34.gno index 1a7bae14ad6..4cacfdb97d9 100644 --- a/gnovm/tests/files/types/shift_d34.gno +++ b/gnovm/tests/files/types/shift_d34.gno @@ -10,7 +10,7 @@ func main() { } // Error: -// main/files/types/shift_d34.gno:7:7: bigint underflows target kind +// main/shift_d34.gno:7:7-29: bigint underflows target kind // TypeCheckError: -// main/files/types/shift_d34.gno:7:14: -(1 << 2) (untyped int constant -4) overflows uint64 +// main/shift_d34.gno:7:14: -(1 << 2) (untyped int constant -4) overflows uint64 diff --git a/gnovm/tests/files/types/shift_d37.gno b/gnovm/tests/files/types/shift_d37.gno index 8eb9644d154..d3bde0117f3 100644 --- a/gnovm/tests/files/types/shift_d37.gno +++ b/gnovm/tests/files/types/shift_d37.gno @@ -6,7 +6,7 @@ func main() { } // Error: -// main/files/types/shift_d37.gno:5:10: operator << not defined on: nil +// main/shift_d37.gno:5:10-18: operator << not defined on: nil // TypeCheckError: -// main/files/types/shift_d37.gno:5:10: invalid operation: shifted operand nil must be integer +// main/shift_d37.gno:5:10: invalid operation: shifted operand nil must be integer diff --git a/gnovm/tests/files/types/shift_d38.gno b/gnovm/tests/files/types/shift_d38.gno index 1bde24123ba..969e1928a5d 100644 --- a/gnovm/tests/files/types/shift_d38.gno +++ b/gnovm/tests/files/types/shift_d38.gno @@ -5,7 +5,7 @@ func main() { } // Error: -// main/files/types/shift_d38.gno:4:10: cannot convert (const (undefined)) to type uint +// main/shift_d38.gno:4:10-18: cannot convert (const (undefined)) to type uint // TypeCheckError: -// main/files/types/shift_d38.gno:4:15: cannot convert nil to type uint +// main/shift_d38.gno:4:15: cannot convert nil to type uint diff --git a/gnovm/tests/files/types/shift_d4.gno b/gnovm/tests/files/types/shift_d4.gno index e50136ed07f..a810e136e45 100644 --- a/gnovm/tests/files/types/shift_d4.gno +++ b/gnovm/tests/files/types/shift_d4.gno @@ -6,7 +6,7 @@ func main() { } // Error: -// main/files/types/shift_d4.gno:4:7: cannot convert BoolKind to Uint64Kind +// main/shift_d4.gno:4:7-27: cannot convert BoolKind to Uint64Kind // TypeCheckError: -// main/files/types/shift_d4.gno:4:14: cannot convert 1 << 2 == 1 >> 2 (untyped bool constant false) to type uint64 +// main/shift_d4.gno:4:14: cannot convert 1 << 2 == 1 >> 2 (untyped bool constant false) to type uint64 diff --git a/gnovm/tests/files/types/shift_d40.gno b/gnovm/tests/files/types/shift_d40.gno index 21650b6947d..9a7cb3ce393 100644 --- a/gnovm/tests/files/types/shift_d40.gno +++ b/gnovm/tests/files/types/shift_d40.gno @@ -7,7 +7,7 @@ func main() { } // Error: -// main/files/types/shift_d40.gno:5:7: operator << not defined on: Float32Kind +// main/shift_d40.gno:5:7-24: operator << not defined on: Float32Kind // TypeCheckError: -// main/files/types/shift_d40.gno:5:17: invalid operation: shifted operand 1 (type float32) must be integer +// main/shift_d40.gno:5:17: invalid operation: shifted operand 1 (type float32) must be integer diff --git a/gnovm/tests/files/types/shift_d41.gno b/gnovm/tests/files/types/shift_d41.gno index 83504fc4821..0ffa0ec29ba 100644 --- a/gnovm/tests/files/types/shift_d41.gno +++ b/gnovm/tests/files/types/shift_d41.gno @@ -7,7 +7,7 @@ func main() { } // Error: -// main/files/types/shift_d41.gno:5:7: operator << not defined on: Float32Kind +// main/shift_d41.gno:5:7-38: operator << not defined on: Float32Kind // TypeCheckError: -// main/files/types/shift_d41.gno:5:31: invalid operation: shifted operand 1 (type float32) must be integer +// main/shift_d41.gno:5:31: invalid operation: shifted operand 1 (type float32) must be integer diff --git a/gnovm/tests/files/types/shift_d44.gno b/gnovm/tests/files/types/shift_d44.gno index 3d79d257702..5ae88205d38 100644 --- a/gnovm/tests/files/types/shift_d44.gno +++ b/gnovm/tests/files/types/shift_d44.gno @@ -7,7 +7,7 @@ func main() { } // Error: -// main/files/types/shift_d44.gno:6:2: operator ++ not defined on: BoolKind +// main/shift_d44.gno:6:2-12: operator ++ not defined on: BoolKind // TypeCheckError: -// main/files/types/shift_d44.gno:6:2: invalid operation: (a == b)++ (non-numeric type untyped bool) +// main/shift_d44.gno:6:2: invalid operation: (a == b)++ (non-numeric type untyped bool) diff --git a/gnovm/tests/files/types/shift_d4a.gno b/gnovm/tests/files/types/shift_d4a.gno index 7d4b0a8a3b9..c6f29c8afbd 100644 --- a/gnovm/tests/files/types/shift_d4a.gno +++ b/gnovm/tests/files/types/shift_d4a.gno @@ -6,7 +6,7 @@ func main() { } // Error: -// main/files/types/shift_d4a.gno:4:7: cannot convert BoolKind to StringKind +// main/shift_d4a.gno:4:7-27: cannot convert BoolKind to StringKind // TypeCheckError: -// main/files/types/shift_d4a.gno:4:14: cannot convert 1 << 2 == 1 >> 2 (untyped bool constant false) to type string +// main/shift_d4a.gno:4:14: cannot convert 1 << 2 == 1 >> 2 (untyped bool constant false) to type string diff --git a/gnovm/tests/files/types/shift_d5.gno b/gnovm/tests/files/types/shift_d5.gno index 3718627dfaa..8bf17d1d70a 100644 --- a/gnovm/tests/files/types/shift_d5.gno +++ b/gnovm/tests/files/types/shift_d5.gno @@ -7,7 +7,7 @@ func main() { } // Error: -// main/files/types/shift_d5.gno:5:2: operator << not defined on: Float64Kind +// main/shift_d5.gno:5:2-15: operator << not defined on: Float64Kind // TypeCheckError: -// main/files/types/shift_d5.gno:5:7: invalid operation: shifted operand 1.0 (type float64) must be integer +// main/shift_d5.gno:5:7: invalid operation: shifted operand 1.0 (type float64) must be integer diff --git a/gnovm/tests/files/types/shift_d50.gno b/gnovm/tests/files/types/shift_d50.gno index 84cbcc4b09d..ab1f16afb7b 100644 --- a/gnovm/tests/files/types/shift_d50.gno +++ b/gnovm/tests/files/types/shift_d50.gno @@ -10,7 +10,7 @@ func main() { } // Error: -// main/files/types/shift_d50.gno:7:7: bigint underflows target kind +// main/shift_d50.gno:7:7-31: bigint underflows target kind // TypeCheckError: -// main/files/types/shift_d50.gno:7:14: -(1.0 << 2) (untyped int constant -4) overflows uint64 +// main/shift_d50.gno:7:14: -(1.0 << 2) (untyped int constant -4) overflows uint64 diff --git a/gnovm/tests/files/types/shift_d51.gno b/gnovm/tests/files/types/shift_d51.gno index fcfddb6b1eb..d01477c737f 100644 --- a/gnovm/tests/files/types/shift_d51.gno +++ b/gnovm/tests/files/types/shift_d51.gno @@ -7,7 +7,7 @@ func main() { } // Error: -// main/files/types/shift_d51.gno:5:2: operator <<= not defined on: Float64Kind +// main/shift_d51.gno:5:2-9: operator <<= not defined on: Float64Kind // TypeCheckError: -// main/files/types/shift_d51.gno:5:2: invalid operation: shifted operand a (variable of type float64) must be integer +// main/shift_d51.gno:5:2: invalid operation: shifted operand a (variable of type float64) must be integer diff --git a/gnovm/tests/files/types/shift_d54.gno b/gnovm/tests/files/types/shift_d54.gno index 696dd10c8e6..5964a5d3261 100644 --- a/gnovm/tests/files/types/shift_d54.gno +++ b/gnovm/tests/files/types/shift_d54.gno @@ -11,7 +11,7 @@ func main() { } // Error: -// main/files/types/shift_d54.gno:8:7: invalid operation: mismatched types int32 and int +// main/shift_d54.gno:8:7-15: invalid operation: b + a << (const (2 uint)) (mismatched types int32 and int) // TypeCheckError: -// main/files/types/shift_d54.gno:8:7: invalid operation: b + a << 2 (mismatched types int32 and int) +// main/shift_d54.gno:8:7: invalid operation: b + a << 2 (mismatched types int32 and int) diff --git a/gnovm/tests/files/types/shift_d56.gno b/gnovm/tests/files/types/shift_d56.gno index b338c874058..000a9670b49 100644 --- a/gnovm/tests/files/types/shift_d56.gno +++ b/gnovm/tests/files/types/shift_d56.gno @@ -13,7 +13,7 @@ func main() { } // Error: -// main/files/types/shift_d56.gno:6:2: cannot use int as int64 +// main/shift_d56.gno:6:2-22: cannot use int as int64 // TypeCheckError: -// main/files/types/shift_d56.gno:6:9: cannot use 1 << 4 + int(1) (constant 17 of type int) as int64 value in return statement +// main/shift_d56.gno:6:9: cannot use 1 << 4 + int(1) (constant 17 of type int) as int64 value in return statement diff --git a/gnovm/tests/files/types/shift_d5b.gno b/gnovm/tests/files/types/shift_d5b.gno index dce39a77c5e..d8464adfc10 100644 --- a/gnovm/tests/files/types/shift_d5b.gno +++ b/gnovm/tests/files/types/shift_d5b.gno @@ -7,7 +7,7 @@ func main() { } // Error: -// main/files/types/shift_d5b.gno:5:7: operator << not defined on: Float32Kind +// main/shift_d5b.gno:5:7-24: operator << not defined on: Float32Kind // TypeCheckError: -// main/files/types/shift_d5b.gno:5:15: invalid operation: shifted operand 1.0 (type float32) must be integer +// main/shift_d5b.gno:5:15: invalid operation: shifted operand 1.0 (type float32) must be integer diff --git a/gnovm/tests/files/types/shift_e0.gno b/gnovm/tests/files/types/shift_e0.gno index 76c01a25526..06d395ae1cb 100644 --- a/gnovm/tests/files/types/shift_e0.gno +++ b/gnovm/tests/files/types/shift_e0.gno @@ -5,7 +5,7 @@ func main() { } // Error: -// main/files/types/shift_e0.gno:4:10: invalid operation: negative shift count: (const (-1 bigint)) +// main/shift_e0.gno:4:10-17: invalid operation: negative shift count: (const (-1 bigint)) // TypeCheckError: -// main/files/types/shift_e0.gno:4:15: invalid operation: negative shift count -1 (untyped int constant) +// main/shift_e0.gno:4:15: invalid operation: negative shift count -1 (untyped int constant) diff --git a/gnovm/tests/files/types/shift_e1.gno b/gnovm/tests/files/types/shift_e1.gno index 7e4ca22be13..6b00c628a7a 100644 --- a/gnovm/tests/files/types/shift_e1.gno +++ b/gnovm/tests/files/types/shift_e1.gno @@ -5,7 +5,7 @@ func main() { } // Error: -// main/files/types/shift_e1.gno:4:10: invalid operation: invalid shift count: (const (2.5848584 float32)) +// main/shift_e1.gno:4:10-36: invalid operation: invalid shift count: (const (2.5848584 float32)) // TypeCheckError: -// main/files/types/shift_e1.gno:4:17: invalid operation: invalid shift count float32(2.58485848) (constant 2.58486 of type float32) +// main/shift_e1.gno:4:17: invalid operation: invalid shift count float32(2.58485848) (constant 2.58486 of type float32) diff --git a/gnovm/tests/files/types/shift_e2.gno b/gnovm/tests/files/types/shift_e2.gno index c409a0527de..6908d8ffa08 100644 --- a/gnovm/tests/files/types/shift_e2.gno +++ b/gnovm/tests/files/types/shift_e2.gno @@ -5,7 +5,7 @@ func main() { } // Error: -// main/files/types/shift_e2.gno:4:10: invalid operation: invalid shift count: (const (1.25 bigdec)) +// main/shift_e2.gno:4:10-19: invalid operation: invalid shift count: (const (1.25 bigdec)) // TypeCheckError: -// main/files/types/shift_e2.gno:4:15: 1.25 (untyped float constant) truncated to uint +// main/shift_e2.gno:4:15: 1.25 (untyped float constant) truncated to uint diff --git a/gnovm/tests/files/types/shift_e3.gno b/gnovm/tests/files/types/shift_e3.gno index 4db44bda080..9fb547f70a4 100644 --- a/gnovm/tests/files/types/shift_e3.gno +++ b/gnovm/tests/files/types/shift_e3.gno @@ -6,7 +6,7 @@ func main() { } // Error: -// main/files/types/shift_e3.gno:5:10: invalid operation: invalid shift count: x +// main/shift_e3.gno:5:10-16: invalid operation: invalid shift count: x // TypeCheckError: -// main/files/types/shift_e3.gno:5:15: invalid operation: shift count x (variable of type float64) must be integer +// main/shift_e3.gno:5:15: invalid operation: shift count x (variable of type float64) must be integer diff --git a/gnovm/tests/files/types/shift_e4.gno b/gnovm/tests/files/types/shift_e4.gno index 716f4802d9c..5c568463efb 100644 --- a/gnovm/tests/files/types/shift_e4.gno +++ b/gnovm/tests/files/types/shift_e4.gno @@ -6,7 +6,7 @@ func main() { } // Error: -// main/files/types/shift_e4.gno:5:10: invalid operation: invalid shift count: x +// main/shift_e4.gno:5:10-16: invalid operation: invalid shift count: x // TypeCheckError: -// main/files/types/shift_e4.gno:5:15: invalid operation: shift count x (variable of type float64) must be integer +// main/shift_e4.gno:5:15: invalid operation: shift count x (variable of type float64) must be integer diff --git a/gnovm/tests/files/types/shift_e7.gno b/gnovm/tests/files/types/shift_e7.gno index 40bd1a1b12b..d9e1a9d8535 100644 --- a/gnovm/tests/files/types/shift_e7.gno +++ b/gnovm/tests/files/types/shift_e7.gno @@ -6,7 +6,7 @@ func main() { } // Error: -// main/files/types/shift_e7.gno:5:2: invalid operation: negative shift count: (-1 bigint) +// main/shift_e7.gno:5:2-10: invalid operation: negative shift count: (-1 bigint) // TypeCheckError: -// main/files/types/shift_e7.gno:5:8: invalid operation: negative shift count -1 (untyped int constant) +// main/shift_e7.gno:5:8: invalid operation: negative shift count -1 (untyped int constant) diff --git a/gnovm/tests/files/types/shift_e7a.gno b/gnovm/tests/files/types/shift_e7a.gno index a4ee105e6a9..09c1982c5a5 100644 --- a/gnovm/tests/files/types/shift_e7a.gno +++ b/gnovm/tests/files/types/shift_e7a.gno @@ -6,7 +6,7 @@ func main() { } // Error: -// main/files/types/shift_e7a.gno:5:10: invalid operation: invalid shift count: a +// main/shift_e7a.gno:5:10-16: invalid operation: invalid shift count: a // TypeCheckError: -// main/files/types/shift_e7a.gno:5:15: invalid operation: shift count a (variable of type float64) must be integer +// main/shift_e7a.gno:5:15: invalid operation: shift count a (variable of type float64) must be integer diff --git a/gnovm/tests/files/types/shift_e7b.gno b/gnovm/tests/files/types/shift_e7b.gno index eb478b4ea01..1e60bbfc0f3 100644 --- a/gnovm/tests/files/types/shift_e7b.gno +++ b/gnovm/tests/files/types/shift_e7b.gno @@ -5,7 +5,7 @@ func main() { } // Error: -// main/files/types/shift_e7b.gno:4:10: invalid operation: invalid shift count: (const (-1 float64)) +// main/shift_e7b.gno:4:10-26: invalid operation: invalid shift count: (const (-1 float64)) // TypeCheckError: -// main/files/types/shift_e7b.gno:4:15: invalid operation: negative shift count float64(-1) (constant -1 of type float64) +// main/shift_e7b.gno:4:15: invalid operation: negative shift count float64(-1) (constant -1 of type float64) diff --git a/gnovm/tests/files/types/shift_e8.gno b/gnovm/tests/files/types/shift_e8.gno index df6ad257419..2dd1a6758d9 100644 --- a/gnovm/tests/files/types/shift_e8.gno +++ b/gnovm/tests/files/types/shift_e8.gno @@ -6,7 +6,7 @@ func main() { } // Error: -// main/files/types/shift_e8.gno:5:2: invalid operation: invalid shift count: (const (1.25 bigdec)) +// main/shift_e8.gno:5:2-12: invalid operation: invalid shift count: (const (1.25 bigdec)) // TypeCheckError: -// main/files/types/shift_e8.gno:5:8: 1.25 (untyped float constant) truncated to uint +// main/shift_e8.gno:5:8: 1.25 (untyped float constant) truncated to uint diff --git a/gnovm/tests/files/types/shift_f1b.gno b/gnovm/tests/files/types/shift_f1b.gno index 57f20483b4d..2c3fe838cd4 100644 --- a/gnovm/tests/files/types/shift_f1b.gno +++ b/gnovm/tests/files/types/shift_f1b.gno @@ -9,7 +9,7 @@ func main() { } // Error: -// main/files/types/shift_f1b.gno:7:2: operator << not defined on: BigdecKind +// main/shift_f1b.gno:7:2-18: operator << not defined on: BigdecKind // TypeCheckError: -// main/files/types/shift_f1b.gno:7:7: invalid operation: shifted operand 1.0 (type float64) must be integer +// main/shift_f1b.gno:7:7: invalid operation: shifted operand 1.0 (type float64) must be integer diff --git a/gnovm/tests/files/types/shift_f2.gno b/gnovm/tests/files/types/shift_f2.gno index 203fdc54fc8..c545eeea52d 100644 --- a/gnovm/tests/files/types/shift_f2.gno +++ b/gnovm/tests/files/types/shift_f2.gno @@ -7,7 +7,7 @@ func main() { } // Error: -// main/files/types/shift_f2.gno:5:6: operator << not defined on: BigdecKind +// main/shift_f2.gno:5:6-22: operator << not defined on: BigdecKind // TypeCheckError: -// main/files/types/shift_f2.gno:5:11: invalid operation: shifted operand 1 (type float64) must be integer +// main/shift_f2.gno:5:11: invalid operation: shifted operand 1 (type float64) must be integer diff --git a/gnovm/tests/files/types/shift_f2a.gno b/gnovm/tests/files/types/shift_f2a.gno index 719539582a1..105d63eefa9 100644 --- a/gnovm/tests/files/types/shift_f2a.gno +++ b/gnovm/tests/files/types/shift_f2a.gno @@ -7,7 +7,7 @@ func main() { } // Error: -// main/files/types/shift_f2a.gno:5:6: operator << not defined on: BigdecKind +// main/shift_f2a.gno:5:6-22: operator << not defined on: BigdecKind // TypeCheckError: -// main/files/types/shift_f2a.gno:5:11: invalid operation: shifted operand 1.0 (type float64) must be integer +// main/shift_f2a.gno:5:11: invalid operation: shifted operand 1.0 (type float64) must be integer diff --git a/gnovm/tests/files/types/shift_f2b.gno b/gnovm/tests/files/types/shift_f2b.gno index e0824f17813..6ab15b20bc0 100644 --- a/gnovm/tests/files/types/shift_f2b.gno +++ b/gnovm/tests/files/types/shift_f2b.gno @@ -7,7 +7,7 @@ func main() { } // Error: -// main/files/types/shift_f2b.gno:5:6: operator << not defined on: BigdecKind +// main/shift_f2b.gno:5:6-22: operator << not defined on: BigdecKind // TypeCheckError: -// main/files/types/shift_f2b.gno:5:18: invalid operation: shifted operand 1 (type float64) must be integer +// main/shift_f2b.gno:5:18: invalid operation: shifted operand 1 (type float64) must be integer diff --git a/gnovm/tests/files/types/shift_f2c.gno b/gnovm/tests/files/types/shift_f2c.gno index 20e918d75da..b8740030739 100644 --- a/gnovm/tests/files/types/shift_f2c.gno +++ b/gnovm/tests/files/types/shift_f2c.gno @@ -7,7 +7,7 @@ func main() { } // Error: -// main/files/types/shift_f2c.gno:5:6: operator << not defined on: BigdecKind +// main/shift_f2c.gno:5:6-22: operator << not defined on: BigdecKind // TypeCheckError: -// main/files/types/shift_f2c.gno:5:16: invalid operation: shifted operand 1.0 (type float64) must be integer +// main/shift_f2c.gno:5:16: invalid operation: shifted operand 1.0 (type float64) must be integer diff --git a/gnovm/tests/files/types/shift_f2d.gno b/gnovm/tests/files/types/shift_f2d.gno index 0fa94fca480..e4fa8e2ef5e 100644 --- a/gnovm/tests/files/types/shift_f2d.gno +++ b/gnovm/tests/files/types/shift_f2d.gno @@ -7,7 +7,7 @@ func main() { } // Error: -// main/files/types/shift_f2d.gno:5:11: incompatible types in binary expression: bigint NEQ bigdec +// main/shift_f2d.gno:5:11-25: incompatible types in binary expression: bigint NEQ bigdec // TypeCheckError: -// main/files/types/shift_f2d.gno:5:11: invalid operation: shifted operand 1 (type float64) must be integer; main/files/types/shift_f2d.gno:5:19: invalid operation: shifted operand 1.0 (type float64) must be integer +// main/shift_f2d.gno:5:11: invalid operation: shifted operand 1 (type float64) must be integer; main/shift_f2d.gno:5:19: invalid operation: shifted operand 1.0 (type float64) must be integer diff --git a/gnovm/tests/files/types/shift_f3.gno b/gnovm/tests/files/types/shift_f3.gno index eb5651237d4..617e6588a1d 100644 --- a/gnovm/tests/files/types/shift_f3.gno +++ b/gnovm/tests/files/types/shift_f3.gno @@ -7,7 +7,7 @@ func main() { } // Error: -// main/files/types/shift_f3.gno:5:6: operator << not defined on: BigdecKind +// main/shift_f3.gno:5:6-21: operator << not defined on: BigdecKind // TypeCheckError: -// main/files/types/shift_f3.gno:5:11: invalid operation: shifted operand 1 (type float64) must be integer +// main/shift_f3.gno:5:11: invalid operation: shifted operand 1 (type float64) must be integer diff --git a/gnovm/tests/files/types/shift_f3a.gno b/gnovm/tests/files/types/shift_f3a.gno index 78b2a5d5983..f46956fd1bb 100644 --- a/gnovm/tests/files/types/shift_f3a.gno +++ b/gnovm/tests/files/types/shift_f3a.gno @@ -7,7 +7,7 @@ func main() { } // Error: -// main/files/types/shift_f3a.gno:5:6: operator << not defined on: BigdecKind +// main/shift_f3a.gno:5:6-21: operator << not defined on: BigdecKind // TypeCheckError: -// main/files/types/shift_f3a.gno:5:11: invalid operation: shifted operand 1.0 (type float64) must be integer +// main/shift_f3a.gno:5:11: invalid operation: shifted operand 1.0 (type float64) must be integer diff --git a/gnovm/tests/files/types/shift_f3b.gno b/gnovm/tests/files/types/shift_f3b.gno index c967e4eff0e..b5d69bb4fc8 100644 --- a/gnovm/tests/files/types/shift_f3b.gno +++ b/gnovm/tests/files/types/shift_f3b.gno @@ -7,7 +7,7 @@ func main() { } // Error: -// main/files/types/shift_f3b.gno:5:6: operator << not defined on: BigdecKind +// main/shift_f3b.gno:5:6-21: operator << not defined on: BigdecKind // TypeCheckError: -// main/files/types/shift_f3b.gno:5:17: invalid operation: shifted operand 1 (type float64) must be integer +// main/shift_f3b.gno:5:17: invalid operation: shifted operand 1 (type float64) must be integer diff --git a/gnovm/tests/files/types/shift_f3c.gno b/gnovm/tests/files/types/shift_f3c.gno index e60b0a2bc25..13413ef8cad 100644 --- a/gnovm/tests/files/types/shift_f3c.gno +++ b/gnovm/tests/files/types/shift_f3c.gno @@ -7,7 +7,7 @@ func main() { } // Error: -// main/files/types/shift_f3c.gno:5:6: operator << not defined on: BigdecKind +// main/shift_f3c.gno:5:6-21: operator << not defined on: BigdecKind // TypeCheckError: -// main/files/types/shift_f3c.gno:5:15: invalid operation: shifted operand 1.0 (type float64) must be integer +// main/shift_f3c.gno:5:15: invalid operation: shifted operand 1.0 (type float64) must be integer diff --git a/gnovm/tests/files/types/typed_nil_a.gno b/gnovm/tests/files/types/typed_nil_a.gno index 14a580dcb19..d5434aa3bc4 100644 --- a/gnovm/tests/files/types/typed_nil_a.gno +++ b/gnovm/tests/files/types/typed_nil_a.gno @@ -15,7 +15,7 @@ func main() { } // Error: -// main/files/types/typed_nil_a.gno:10:5: cannot convert (const (undefined)) to IntKind +// main/typed_nil_a.gno:10:5-17: cannot convert (const (undefined)) to IntKind // TypeCheckError: -// main/files/types/typed_nil_a.gno:10:13: cannot convert nil to type integer +// main/typed_nil_a.gno:10:13: cannot convert nil to type integer diff --git a/gnovm/tests/files/types/unary_a0c.gno b/gnovm/tests/files/types/unary_a0c.gno index 8f1a2a3bd79..3e700f12328 100644 --- a/gnovm/tests/files/types/unary_a0c.gno +++ b/gnovm/tests/files/types/unary_a0c.gno @@ -9,7 +9,7 @@ func main() { } // Error: -// main/files/types/unary_a0c.gno:7:7: operator + not defined on: StringKind +// main/unary_a0c.gno:7:7-9: operator + not defined on: StringKind // TypeCheckError: -// main/files/types/unary_a0c.gno:7:8: invalid operation: operator + not defined on x (variable of type string) +// main/unary_a0c.gno:7:8: invalid operation: operator + not defined on x (variable of type string) diff --git a/gnovm/tests/files/types/unary_a2a.gno b/gnovm/tests/files/types/unary_a2a.gno index cb89774524b..7dc75470a48 100644 --- a/gnovm/tests/files/types/unary_a2a.gno +++ b/gnovm/tests/files/types/unary_a2a.gno @@ -10,7 +10,7 @@ func main() { } // Error: -// main/files/types/unary_a2a.gno:7:7: operator ! not defined on: IntKind +// main/unary_a2a.gno:7:7-9: operator ! not defined on: IntKind // TypeCheckError: -// main/files/types/unary_a2a.gno:7:8: invalid operation: operator ! not defined on a (variable of type int) +// main/unary_a2a.gno:7:8: invalid operation: operator ! not defined on a (variable of type int) diff --git a/gnovm/tests/files/types/unary_a6.gno b/gnovm/tests/files/types/unary_a6.gno index cbbff69bd78..f143c563535 100644 --- a/gnovm/tests/files/types/unary_a6.gno +++ b/gnovm/tests/files/types/unary_a6.gno @@ -9,7 +9,7 @@ func main() { } // Error: -// main/files/types/unary_a6.gno:7:7: operator ^ not defined on: Float64Kind +// main/unary_a6.gno:7:7-9: operator ^ not defined on: Float64Kind // TypeCheckError: -// main/files/types/unary_a6.gno:7:8: invalid operation: operator ^ not defined on x (variable of type float64) +// main/unary_a6.gno:7:8: invalid operation: operator ^ not defined on x (variable of type float64) diff --git a/gnovm/tests/files/var18.gno b/gnovm/tests/files/var18.gno index 8ecf3a6d1f7..2036f0f9d90 100644 --- a/gnovm/tests/files/var18.gno +++ b/gnovm/tests/files/var18.gno @@ -5,7 +5,7 @@ func main() { } // Error: -// main/files/var18.gno:4:6: missing init expr for c +// main/var18.gno:4:6-20: missing init expr for c // TypeCheckError: -// main/files/var18.gno:4:12: missing init expr for c; main/files/var18.gno:4:6: declared and not used: a; main/files/var18.gno:4:9: declared and not used: b; main/files/var18.gno:4:12: declared and not used: c +// main/var18.gno:4:12: missing init expr for c; main/var18.gno:4:6: declared and not used: a; main/var18.gno:4:9: declared and not used: b; main/var18.gno:4:12: declared and not used: c diff --git a/gnovm/tests/files/var19.gno b/gnovm/tests/files/var19.gno index 7beb76863eb..e8968f8a79c 100644 --- a/gnovm/tests/files/var19.gno +++ b/gnovm/tests/files/var19.gno @@ -8,7 +8,7 @@ func main() { } // Error: -// main/files/var19.gno:4:6: missing init expr for c +// main/var19.gno:4:6-24: missing init expr for c // TypeCheckError: -// main/files/var19.gno:4:12: missing init expr for c; main/files/var19.gno:4:19: undefined: a +// main/var19.gno:4:12: missing init expr for c; main/var19.gno:4:19: undefined: a diff --git a/gnovm/tests/files/var20.gno b/gnovm/tests/files/var20.gno index 4886a6b1932..31ebeda7ba9 100644 --- a/gnovm/tests/files/var20.gno +++ b/gnovm/tests/files/var20.gno @@ -9,7 +9,7 @@ func main() { } // Error: -// main/files/var20.gno:8:6: assignment mismatch: 3 variable(s) but r() returns 1 value(s) +// main/var20.gno:8:6-19: assignment mismatch: 3 variable(s) but r() returns 1 value(s) // TypeCheckError: -// main/files/var20.gno:8:16: assignment mismatch: 3 variables but r returns 1 value; main/files/var20.gno:8:6: declared and not used: a; main/files/var20.gno:8:9: declared and not used: b; main/files/var20.gno:8:12: declared and not used: c +// main/var20.gno:8:16: assignment mismatch: 3 variables but r returns 1 value; main/var20.gno:8:6: declared and not used: a; main/var20.gno:8:9: declared and not used: b; main/var20.gno:8:12: declared and not used: c diff --git a/gnovm/tests/files/var21.gno b/gnovm/tests/files/var21.gno index 19a29bb439f..d7f31d666ba 100644 --- a/gnovm/tests/files/var21.gno +++ b/gnovm/tests/files/var21.gno @@ -11,7 +11,7 @@ func main() { } // Error: -// main/files/var21.gno:8:6: multiple-value foo (value of type [int bool]) in single-value context +// main/var21.gno:8:6-21: multiple-value foo (value of type [int bool]) in single-value context // TypeCheckError: -// main/files/var21.gno:8:16: multiple-value foo() (value of type (int, bool)) in single-value context +// main/var21.gno:8:16: multiple-value foo() (value of type (int, bool)) in single-value context diff --git a/gnovm/tests/files/var22.gno b/gnovm/tests/files/var22.gno index c78d5abeb4c..ddeec11d9e4 100644 --- a/gnovm/tests/files/var22.gno +++ b/gnovm/tests/files/var22.gno @@ -11,7 +11,7 @@ func main() { } // Error: -// main/files/var22.gno:8:6: missing init expr for c +// main/var22.gno:8:6-24: missing init expr for c // TypeCheckError: -// main/files/var22.gno:8:12: missing init expr for c; main/files/var22.gno:8:19: multiple-value foo() (value of type (int, bool)) in single-value context +// main/var22.gno:8:12: missing init expr for c; main/var22.gno:8:19: multiple-value foo() (value of type (int, bool)) in single-value context diff --git a/gnovm/tests/files/var22b.gno b/gnovm/tests/files/var22b.gno index 4a90aecf2fa..965738320e6 100644 --- a/gnovm/tests/files/var22b.gno +++ b/gnovm/tests/files/var22b.gno @@ -11,7 +11,7 @@ func main() { } // Error: -// main/files/var22b.gno:8:6: extra init expr foo() +// main/var22b.gno:8:6-30: extra init expr foo() // TypeCheckError: -// main/files/var22b.gno:8:25: extra init expr foo() +// main/var22b.gno:8:25: extra init expr foo() diff --git a/gnovm/tests/files/var22c.gno b/gnovm/tests/files/var22c.gno index cc296246d99..6eaeb907d4e 100644 --- a/gnovm/tests/files/var22c.gno +++ b/gnovm/tests/files/var22c.gno @@ -12,7 +12,7 @@ func main() { } // Error: -// main/files/var22c.gno:10:6: missing init expr for z +// main/var22c.gno:10:6-22: missing init expr for z // TypeCheckError: -// main/files/var22c.gno:10:12: missing init expr for z; main/files/var22c.gno:10:19: multiple-value f() (value of type (a int, b int)) in single-value context +// main/var22c.gno:10:12: missing init expr for z; main/var22c.gno:10:19: multiple-value f() (value of type (a int, b int)) in single-value context diff --git a/gnovm/tests/files/var23.gno b/gnovm/tests/files/var23.gno index fc7b0fd05b4..057ece3371d 100644 --- a/gnovm/tests/files/var23.gno +++ b/gnovm/tests/files/var23.gno @@ -6,7 +6,7 @@ func main() { } // Error: -// main/files/var23.gno:3:5: assignment mismatch: 3 variable(s) but 2 value(s) +// main/var23.gno:3:5-19: assignment mismatch: 3 variable(s) but 2 value(s) // TypeCheckError: -// main/files/var23.gno:3:11: missing init expr for c +// main/var23.gno:3:11: missing init expr for c diff --git a/gnovm/tests/files/var24.gno b/gnovm/tests/files/var24.gno index c5112d6bf97..5d4489eddc4 100644 --- a/gnovm/tests/files/var24.gno +++ b/gnovm/tests/files/var24.gno @@ -6,7 +6,7 @@ func main() { } // Error: -// main/files/var24.gno:5:6: assignment mismatch: 3 variable(s) but 1 value(s) +// main/var24.gno:5:6-23: assignment mismatch: 3 variable(s) but 1 value(s) // TypeCheckError: -// main/files/var24.gno:5:16: assignment mismatch: 3 variables but 1 value; main/files/var24.gno:5:6: declared and not used: a; main/files/var24.gno:5:9: declared and not used: b; main/files/var24.gno:5:12: declared and not used: c +// main/var24.gno:5:16: assignment mismatch: 3 variables but 1 value; main/var24.gno:5:6: declared and not used: a; main/var24.gno:5:9: declared and not used: b; main/var24.gno:5:12: declared and not used: c diff --git a/gnovm/tests/files/var25.gno b/gnovm/tests/files/var25.gno index dd0e3bdf360..73055e94035 100644 --- a/gnovm/tests/files/var25.gno +++ b/gnovm/tests/files/var25.gno @@ -6,7 +6,7 @@ func main() { } // Error: -// main/files/var25.gno:5:6: assignment mismatch: 3 variable(s) but 1 value(s) +// main/var25.gno:5:6-20: assignment mismatch: 3 variable(s) but 1 value(s) // TypeCheckError: -// main/files/var25.gno:5:16: assignment mismatch: 3 variables but 1 value; main/files/var25.gno:5:6: declared and not used: a; main/files/var25.gno:5:9: declared and not used: b; main/files/var25.gno:5:12: declared and not used: c +// main/var25.gno:5:16: assignment mismatch: 3 variables but 1 value; main/var25.gno:5:6: declared and not used: a; main/var25.gno:5:9: declared and not used: b; main/var25.gno:5:12: declared and not used: c diff --git a/gnovm/tests/files/var26.gno b/gnovm/tests/files/var26.gno index 2cc7fed3e85..fec573384a0 100644 --- a/gnovm/tests/files/var26.gno +++ b/gnovm/tests/files/var26.gno @@ -8,7 +8,7 @@ func main() { } // Error: -// main/files/var26.gno:6:6: extra init expr 3 +// main/var26.gno:6:6-20: extra init expr 3 // TypeCheckError: -// main/files/var26.gno:6:19: extra init expr 3 +// main/var26.gno:6:19: extra init expr 3 diff --git a/gnovm/tests/files/var27.gno b/gnovm/tests/files/var27.gno index 05f8e56da22..2f8d65d330b 100644 --- a/gnovm/tests/files/var27.gno +++ b/gnovm/tests/files/var27.gno @@ -80,4 +80,4 @@ var other1 = func() { var something1 = "a string" // TypeCheckError: -// main/files/var27.gno:8:2: declared and not used: a +// main/var27.gno:8:2: declared and not used: a diff --git a/gnovm/tests/files/var31.gno b/gnovm/tests/files/var31.gno index 001e34f88cf..0e7d3454cb1 100644 --- a/gnovm/tests/files/var31.gno +++ b/gnovm/tests/files/var31.gno @@ -5,7 +5,7 @@ func main() { } // Error: -// main/files/var31.gno:4:6: struct{} (type) is not an expression +// main/var31.gno:4:6-18: struct{} (type) is not an expression // TypeCheckError: -// main/files/var31.gno:4:10: struct{} (type) is not an expression; main/files/var31.gno:4:6: declared and not used: t +// main/var31.gno:4:10: struct{} (type) is not an expression; main/var31.gno:4:6: declared and not used: t diff --git a/gnovm/tests/files/var32.gno b/gnovm/tests/files/var32.gno index ec7abb92d95..4f622c25735 100644 --- a/gnovm/tests/files/var32.gno +++ b/gnovm/tests/files/var32.gno @@ -5,7 +5,7 @@ func main() { } // Error: -// main/files/var32.gno:4:6: use of untyped nil in variable declaration +// main/var32.gno:4:6-13: use of untyped nil in variable declaration // TypeCheckError: -// main/files/var32.gno:4:10: use of untyped nil in variable declaration; main/files/var32.gno:4:6: declared and not used: t +// main/var32.gno:4:10: use of untyped nil in variable declaration; main/var32.gno:4:6: declared and not used: t diff --git a/gnovm/tests/files/var33.gno b/gnovm/tests/files/var33.gno index 4fb1ac5f45f..5198b817d97 100644 --- a/gnovm/tests/files/var33.gno +++ b/gnovm/tests/files/var33.gno @@ -9,4 +9,4 @@ func main() { // pass // TypeCheckError: -// main/files/var33.gno:4:6: declared and not used: t +// main/var33.gno:4:6: declared and not used: t diff --git a/gnovm/tests/files/var34.gno b/gnovm/tests/files/var34.gno index e6e3a35870d..c69881cfb2c 100644 --- a/gnovm/tests/files/var34.gno +++ b/gnovm/tests/files/var34.gno @@ -7,7 +7,7 @@ func main() { } // Error: -// main/files/var34.gno:6:6: f (no value) used as value +// main/var34.gno:6:6-13: f (no value) used as value // TypeCheckError: -// main/files/var34.gno:6:10: f() (no value) used as value; main/files/var34.gno:6:6: declared and not used: t +// main/var34.gno:6:10: f() (no value) used as value; main/var34.gno:6:6: declared and not used: t diff --git a/gnovm/tests/files/var34b.gno b/gnovm/tests/files/var34b.gno index d3175fa531f..b7ddb487a48 100644 --- a/gnovm/tests/files/var34b.gno +++ b/gnovm/tests/files/var34b.gno @@ -8,7 +8,7 @@ func main() { } // Error: -// main/files/var34b.gno:7:2: f (no value) used as value +// main/var34b.gno:7:2-9: f (no value) used as value // TypeCheckError: -// main/files/var34b.gno:7:6: f() (no value) used as value; main/files/var34b.gno:6:6: declared and not used: a +// main/var34b.gno:7:6: f() (no value) used as value; main/var34b.gno:6:6: declared and not used: a diff --git a/gnovm/tests/files/var34c.gno b/gnovm/tests/files/var34c.gno index e1e6376d278..fc01fcc90c7 100644 --- a/gnovm/tests/files/var34c.gno +++ b/gnovm/tests/files/var34c.gno @@ -7,7 +7,7 @@ func main() { } // Error: -// main/files/var34c.gno:6:6: f (no value) used as value +// main/var34c.gno:6:6-23: f (no value) used as value // TypeCheckError: -// main/files/var34c.gno:6:17: f() (no value) used as value; main/files/var34c.gno:6:6: declared and not used: a; main/files/var34c.gno:6:9: declared and not used: b +// main/var34c.gno:6:17: f() (no value) used as value; main/var34c.gno:6:6: declared and not used: a; main/var34c.gno:6:9: declared and not used: b diff --git a/gnovm/tests/files/var35.gno b/gnovm/tests/files/var35.gno index 5f8a1fbfa85..68ff04034ed 100644 --- a/gnovm/tests/files/var35.gno +++ b/gnovm/tests/files/var35.gno @@ -5,7 +5,7 @@ func main() { } // Error: -// main/files/var35.gno:4:6: cannot use nil as int value in variable declaration +// main/var35.gno:4:6-17: cannot use nil as int value in variable declaration // TypeCheckError: -// main/files/var35.gno:4:14: cannot use nil as int value in variable declaration; main/files/var35.gno:4:6: declared and not used: i +// main/var35.gno:4:14: cannot use nil as int value in variable declaration; main/var35.gno:4:6: declared and not used: i diff --git a/gnovm/tests/files/zrealm_crossrealm22.gno b/gnovm/tests/files/zrealm_crossrealm22.gno index 3c1789b9ed1..9f8e9da3bb8 100644 --- a/gnovm/tests/files/zrealm_crossrealm22.gno +++ b/gnovm/tests/files/zrealm_crossrealm22.gno @@ -97,10 +97,19 @@ func main() { // "@type": "/gno.RefNode", // "BlockNode": null, // "Location": { -// "Column": "35", -// "File": "files/zrealm_crossrealm22.gno", -// "Line": "13", -// "PkgPath": "gno.land/r/crossrealm_test" +// "File": "zrealm_crossrealm22.gno", +// "PkgPath": "gno.land/r/crossrealm_test", +// "Span": { +// "End": { +// "Column": "71", +// "Line": "13" +// }, +// "Num": "0", +// "Pos": { +// "Column": "35", +// "Line": "13" +// } +// } // } // }, // "Type": { @@ -136,7 +145,7 @@ func main() { // + }, // + "V": { // + "@type": "/gno.RefValue", -// + "Hash": "496beec28378b765d658286561b08be89e32efee", +// + "Hash": "95bd5e4ce205cb541fd5e0ef755457f33b725dc7", // + "ObjectID": "1712ac7adcfdc8e58a67e5615e20fb312394c4df:36" // } // } @@ -203,7 +212,7 @@ func main() { // }, // "V": { // "@type": "/gno.RefValue", -// - "Hash": "496beec28378b765d658286561b08be89e32efee", +// - "Hash": "95bd5e4ce205cb541fd5e0ef755457f33b725dc7", // - "ObjectID": "1712ac7adcfdc8e58a67e5615e20fb312394c4df:36" // + "Escaped": true, // + "ObjectID": "0edc46caf30c00efd87b6c272673239eafbd051e:7" @@ -279,10 +288,19 @@ func main() { // "@type": "/gno.RefNode", // "BlockNode": null, // "Location": { -// "Column": "62", // "File": "crossrealm.gno", -// "Line": "26", -// "PkgPath": "gno.land/r/demo/tests/crossrealm_b" +// "PkgPath": "gno.land/r/demo/tests/crossrealm_b", +// "Span": { +// "End": { +// "Column": "102", +// "Line": "26" +// }, +// "Num": "0", +// "Pos": { +// "Column": "62", +// "Line": "26" +// } +// } // } // }, // "Type": { @@ -308,7 +326,7 @@ func main() { // "@type": "/gno.RefValue", // - "Escaped": true, // - "ObjectID": "0edc46caf30c00efd87b6c272673239eafbd051e:7" -// + "Hash": "6a8bf31929a4f73151f3b404c376f279bacd9c81", +// + "Hash": "a43fc472719083cebcd120f2d1232bd77c87801f", // + "ObjectID": "1712ac7adcfdc8e58a67e5615e20fb312394c4df:38" // } // } diff --git a/gnovm/tests/files/zrealm_crossrealm28.gno b/gnovm/tests/files/zrealm_crossrealm28.gno index 17ee77d4059..17cdbe46a64 100644 --- a/gnovm/tests/files/zrealm_crossrealm28.gno +++ b/gnovm/tests/files/zrealm_crossrealm28.gno @@ -52,7 +52,7 @@ func main() { // - }, // - "V": { // - "@type": "/gno.RefValue", -// - "Hash": "5b8e03f7f8b6fe2399fb8f4a27dd5a1a49518df8", +// - "Hash": "47596878835b82fc5bcd8469e6d3f9b90e545e45", // - "ObjectID": "0edc46caf30c00efd87b6c272673239eafbd051e:16" // + "@type": "/gno.PrimitiveType", // + "value": "32" diff --git a/gnovm/tests/files/zrealm_natbind0.gno b/gnovm/tests/files/zrealm_natbind0.gno index e12f8014119..45b8410e609 100644 --- a/gnovm/tests/files/zrealm_natbind0.gno +++ b/gnovm/tests/files/zrealm_natbind0.gno @@ -44,16 +44,16 @@ func main() { // "V": { // "@type": "/gno.RefValue", // "Escaped": true, -// - "ObjectID": "a7f5397443359ea76c50be82c77f1f893a060925:36" -// + "ObjectID": "a7f5397443359ea76c50be82c77f1f893a060925:33" +// - "ObjectID": "a7f5397443359ea76c50be82c77f1f893a060925:39" +// + "ObjectID": "a7f5397443359ea76c50be82c77f1f893a060925:36" // } // } // } -// u[a7f5397443359ea76c50be82c77f1f893a060925:33]= +// u[a7f5397443359ea76c50be82c77f1f893a060925:36]= // @@ -8,9 +8,10 @@ // "NativePkg": "std", // "ObjectInfo": { -// "ID": "a7f5397443359ea76c50be82c77f1f893a060925:33", +// "ID": "a7f5397443359ea76c50be82c77f1f893a060925:36", // - "ModTime": "0", // + "IsEscaped": true, // + "ModTime": "6", @@ -63,7 +63,7 @@ func main() { // }, // "Parent": { // "@type": "/gno.RefValue", -// u[a7f5397443359ea76c50be82c77f1f893a060925:36]= +// u[a7f5397443359ea76c50be82c77f1f893a060925:39]= // @@ -11,7 +11,7 @@ // "IsEscaped": true, // "ModTime": "6", diff --git a/gnovm/tests/files/zrealm_panic.gno b/gnovm/tests/files/zrealm_panic.gno index 12078b33a80..f94f9ade1f6 100644 --- a/gnovm/tests/files/zrealm_panic.gno +++ b/gnovm/tests/files/zrealm_panic.gno @@ -20,6 +20,6 @@ func main() { // Stacktrace: // panic: panic // ms.Panic() -// gno.land/r/test/files/zrealm_panic.gno:7 +// gno.land/r/test/zrealm_panic.gno:7 // main() -// gno.land/r/test/files/zrealm_panic.gno:14 +// gno.land/r/test/zrealm_panic.gno:14 diff --git a/gnovm/tests/integ/init/gno.mod b/gnovm/tests/integ/init/gno.mod index 28c7e51b750..71278f21b8f 100644 --- a/gnovm/tests/integ/init/gno.mod +++ b/gnovm/tests/integ/init/gno.mod @@ -1 +1,3 @@ module gno.land/r/demo/init + +gno 0.9 diff --git a/gnovm/tests/stdlibs/fmt/fmt_test.gno b/gnovm/tests/stdlibs/fmt/fmt_test.gno index 8220ebf9b4c..bcfcf8bb882 100644 --- a/gnovm/tests/stdlibs/fmt/fmt_test.gno +++ b/gnovm/tests/stdlibs/fmt/fmt_test.gno @@ -628,7 +628,7 @@ var fmtTests = []struct { // go syntax {"%#v", A{1, 2, "a", []int{1, 2}}, `fmt_test.A{i:1, j:0x2, s:"a", x:[]int{1, 2}}`}, {"%#v", new(byte), "(*uint8)(0xPTR)"}, - {"%#v", TestFmtInterface, "(func(*testing.T))(0xPTR)"}, + {"%#v", TestFmtInterface, "(func(*testing/base.T))(0xPTR)"}, {"%#v", uint64(1<<64 - 1), "0xffffffffffffffff"}, {"%#v", 1000000000, "1000000000"}, {"%#v", map[string]int{"a": 1}, `map[string]int{"a":1}`}, @@ -1328,7 +1328,7 @@ func TestStructPrinter(t *testing.T) { }{ {"%v", "{abc def 123}"}, {"%+v", "{a:abc b:def c:123}"}, - {"%#v", `fmt_test[fmt_test/fmt_test.gno:1315:1].T{a:"abc", b:"def", c:123}`}, + {"%#v", `fmt_test[fmt_test/fmt_test.gno:1315:1-1344:2].T{a:"abc", b:"def", c:123}`}, } for _, tt := range tests { out := fmt.Sprintf(tt.fmt, s) @@ -1591,7 +1591,7 @@ func TestNilDoesNotBecomeTyped(t *testing.T) { var a *A = nil var b B = B{} got := fmt.Sprintf(hideFromVet("%s %s %s %s %s"), nil, a, nil, b, nil) - const expect = "%!s() %!s(*fmt_test[fmt_test/fmt_test.gno:1588:1].A=) %!s() {} %!s()" + const expect = "%!s() %!s(*fmt_test[fmt_test/fmt_test.gno:1588:1-1598:2].A=) %!s() {} %!s()" if got != expect { t.Errorf("expected:\n\t%q\ngot:\n\t%q", expect, got) } diff --git a/gnovm/tests/stdlibs/generated.go b/gnovm/tests/stdlibs/generated.go index d263a3a1863..c6ba02b90c2 100644 --- a/gnovm/tests/stdlibs/generated.go +++ b/gnovm/tests/stdlibs/generated.go @@ -11,6 +11,7 @@ import ( testlibs_os "github.com/gnolang/gno/gnovm/tests/stdlibs/os" testlibs_std "github.com/gnolang/gno/gnovm/tests/stdlibs/std" testlibs_testing "github.com/gnolang/gno/gnovm/tests/stdlibs/testing" + testlibs_testing_base "github.com/gnolang/gno/gnovm/tests/stdlibs/testing/base" testlibs_unicode "github.com/gnolang/gno/gnovm/tests/stdlibs/unicode" ) @@ -667,6 +668,88 @@ var nativeFuncs = [...]NativeFunc{ )) }, }, + { + "testing/base", + "unixNano", + []gno.FieldTypeExpr{}, + []gno.FieldTypeExpr{ + {NameExpr: *gno.Nx("r0"), Type: gno.X("int64")}, + }, + false, + func(m *gno.Machine) { + r0 := testlibs_testing_base.X_unixNano() + + m.PushValue(gno.Go2GnoValue( + m.Alloc, + m.Store, + reflect.ValueOf(&r0).Elem(), + )) + }, + }, + { + "testing/base", + "matchString", + []gno.FieldTypeExpr{ + {NameExpr: *gno.Nx("p0"), Type: gno.X("string")}, + {NameExpr: *gno.Nx("p1"), Type: gno.X("string")}, + }, + []gno.FieldTypeExpr{ + {NameExpr: *gno.Nx("r0"), Type: gno.X("bool")}, + {NameExpr: *gno.Nx("r1"), Type: gno.X("string")}, + }, + false, + func(m *gno.Machine) { + b := m.LastBlock() + var ( + p0 string + rp0 = reflect.ValueOf(&p0).Elem() + p1 string + rp1 = reflect.ValueOf(&p1).Elem() + ) + + tv0 := b.GetPointerTo(nil, gno.NewValuePathBlock(1, 0, "")).TV + tv0.DeepFill(m.Store) + gno.Gno2GoValue(tv0, rp0) + tv1 := b.GetPointerTo(nil, gno.NewValuePathBlock(1, 1, "")).TV + tv1.DeepFill(m.Store) + gno.Gno2GoValue(tv1, rp1) + + r0, r1 := testlibs_testing_base.X_matchString(p0, p1) + + m.PushValue(gno.Go2GnoValue( + m.Alloc, + m.Store, + reflect.ValueOf(&r0).Elem(), + )) + m.PushValue(gno.Go2GnoValue( + m.Alloc, + m.Store, + reflect.ValueOf(&r1).Elem(), + )) + }, + }, + { + "testing/base", + "recoverWithStacktrace", + []gno.FieldTypeExpr{}, + []gno.FieldTypeExpr{ + {NameExpr: *gno.Nx("r0"), Type: gno.AnyT()}, + {NameExpr: *gno.Nx("r1"), Type: gno.X("string")}, + }, + true, + func(m *gno.Machine) { + r0, r1 := testlibs_testing_base.X_recoverWithStacktrace( + m, + ) + + m.PushValue(r0) + m.PushValue(gno.Go2GnoValue( + m.Alloc, + m.Store, + reflect.ValueOf(&r1).Elem(), + )) + }, + }, { "unicode", "IsPrint", diff --git a/gnovm/tests/stdlibs/testing/base/native_testing.gno b/gnovm/tests/stdlibs/testing/base/native_testing.gno new file mode 100644 index 00000000000..12bda0836e8 --- /dev/null +++ b/gnovm/tests/stdlibs/testing/base/native_testing.gno @@ -0,0 +1,7 @@ +package base + +func unixNano() int64 + +func matchString(pat, str string) (bool, string) + +func recoverWithStacktrace() (interface{}, string) diff --git a/gnovm/tests/stdlibs/testing/base/native_testing.go b/gnovm/tests/stdlibs/testing/base/native_testing.go new file mode 100644 index 00000000000..c627c46b33e --- /dev/null +++ b/gnovm/tests/stdlibs/testing/base/native_testing.go @@ -0,0 +1,28 @@ +package base + +import ( + "regexp" + "time" + + "github.com/gnolang/gno/gnovm/pkg/gnolang" +) + +func X_unixNano() int64 { + return time.Now().UnixNano() +} + +func X_matchString(pat, str string) (bool, string) { + matchRe, err := regexp.Compile(pat) + if err != nil { + return false, err.Error() + } + return matchRe.MatchString(str), "" +} + +func X_recoverWithStacktrace(m *gnolang.Machine) (gnolang.TypedValue, string) { + exception := m.Recover() + if exception == nil { + return gnolang.TypedValue{}, "" + } + return exception.Value, exception.Stacktrace.String() +} diff --git a/misc/genstd/package_sort.go b/misc/genstd/package_sort.go index 575f56d9506..daf3bd366b4 100644 --- a/misc/genstd/package_sort.go +++ b/misc/genstd/package_sort.go @@ -37,7 +37,8 @@ func sortPackages(pkgs []*pkgData) []string { if slices.Contains(res, imp) { continue } - if pkg.importPath == "testing" && + if (pkg.importPath == "testing" || + pkg.importPath == "testing/base") && slices.Contains(nativeInjections, imp) { continue } diff --git a/tm2/pkg/colors/cmd/modcolor/modcolor.go b/tm2/pkg/colors/cmd/modcolor/modcolor.go new file mode 100644 index 00000000000..aa6d0c6f679 --- /dev/null +++ b/tm2/pkg/colors/cmd/modcolor/modcolor.go @@ -0,0 +1,36 @@ +package main + +import ( + "bufio" + "flag" + "fmt" + "io" + "os" + + "github.com/gnolang/gno/tm2/pkg/colors" +) + +var ( + order = []colors.Color{colors.None, colors.Gray, colors.Cyan, colors.Blue, colors.Green, colors.Yellow, colors.Red, colors.Magenta} + modPtr = flag.Int("mod", 2, "modulo number of lines; maximum 8") +) + +func main() { + flag.Parse() + if *modPtr < 2 || 8 < *modPtr { + panic("--mod must be between 2 and 8") + } + + mod := *modPtr + rin := bufio.NewReader(os.Stdin) + for i := 0; ; i++ { + line, err := rin.ReadString('\n') + if err == io.EOF { + return + } else if err != nil { + panic(err) + } + color := order[i%mod] + fmt.Println(color(line[:len(line)-1])) + } +} diff --git a/tm2/pkg/colors/colors.go b/tm2/pkg/colors/colors.go index 4cecf38640a..05a74f5b44e 100644 --- a/tm2/pkg/colors/colors.go +++ b/tm2/pkg/colors/colors.go @@ -68,6 +68,10 @@ func Red(args ...any) string { return treatAll(ANSIFgRed, args...) } +func RedBg(args ...any) string { + return treatAll(ANSIBgRed, args...) +} + func Green(args ...any) string { return treatAll(ANSIFgGreen, args...) } diff --git a/tm2/pkg/std/memfile.go b/tm2/pkg/std/memfile.go index a5fb811caca..7db6946222c 100644 --- a/tm2/pkg/std/memfile.go +++ b/tm2/pkg/std/memfile.go @@ -2,99 +2,251 @@ package std import ( "fmt" + "io/ioutil" + "path/filepath" "regexp" + "slices" "sort" "strings" ) +// XXX rename to mempackage.go + +const ( + fileNameLimit = 256 + pkgNameLimit = 256 + pkgPathLimit = 256 +) + +var ( + // See also gnovm/pkg/gnolang/mempackage.go. + // NOTE: DO NOT MODIFY without a pre/post ADR and discussions with core GnoVM and gno.land teams. + reFileName = regexp.MustCompile(`^(([a-z0-9_\-]+|[A-Z0-9_\-]+)(\.[a-z0-9_]+)*\.[a-z0-9_]{1,7}|LICENSE|README)$`) + rePkgName = regexp.MustCompile(`^[a-z][a-z0-9_]*$`) + rePkgPathURL = regexp.MustCompile(`^([a-z0-9-]+\.)*[a-z0-9-]+\.[a-z]{2,}(\/[a-z0-9\-_]+)+$`) + rePkgPathStd = regexp.MustCompile(`^([a-z][a-z0-9_]*\/)*[a-z][a-z0-9_]+$`) +) + +//---------------------------------------- +// MemFile + +// A MemFile is the simplest representation of a "file". +// +// File Name must contain a single dot and extension. +// File Name may be ALLCAPS.xxx or lowercase.xxx; extensions lowercase. +// e.g. OK: README.md, readme.md, readme.txt, READ.me +// e.g. NOT OK: Readme.md, readme.MD, README, .readme +// File Body can be any string. +// +// NOTE: It doesn't have owners or timestamps. Keep this as is for portability. +// Not even date created, ownership, or other attributes. Just a name, and a +// body. This keeps things portable, easy to hash (otherwise need to manage +// e.g. the encoding and portability of timestamps). type MemFile struct { Name string `json:"name" yaml:"name"` Body string `json:"body" yaml:"body"` } +func (mfile *MemFile) ValidateBasic() error { + if len(mfile.Name) == 0 { + return fmt.Errorf("name cannot be empty") + } + if len(mfile.Name) > fileNameLimit { + return fmt.Errorf("name length %d exceeds limit %d", len(mfile.Name), fileNameLimit) + } + if !reFileName.MatchString(mfile.Name) { + return fmt.Errorf("invalid file name %q", mfile.Name) + } + return nil +} + +// Print file to stdout. +func (mfile *MemFile) Print() error { + fmt.Printf("MemFile[%q]:\n", mfile.Name) + fmt.Println(mfile.Body) + return nil +} + +//---------------------------------------- +// MemPackage + // MemPackage represents the information and files of a package which will be // stored in memory. It will generally be initialized by package gnolang's // ReadMemPackage. +// Note: a package does not support subfolders. // -// NOTE: in the future, a MemPackage may represent -// updates/additional-files for an existing package. +// NOTE: in the future, a MemPackage may represent updates/additional-files for +// an existing package. type MemPackage struct { - Name string `json:"name" yaml:"name"` // package name as declared by `package` - Path string `json:"path" yaml:"path"` // import path - Files []*MemFile `json:"files" yaml:"files"` + Name string `json:"name" yaml:"name"` // package name as declared by `package` + Path string `json:"path" yaml:"path"` // import path + Files []*MemFile `json:"files" yaml:"files"` // plain file system files. +} + +// Package Name must be lower_case, can have digits & underscores. +// Package Path must be "a.valid.url/path" or a "simple/path". +// An empty MemPackager is invalid. +func (mpkg *MemPackage) ValidateBasic() error { + // add assertion that MemPkg contains at least 1 file + if len(mpkg.Files) <= 0 { + return fmt.Errorf("no files found within package %q", mpkg.Name) + } + if len(mpkg.Name) > pkgNameLimit { + return fmt.Errorf("name length %d exceeds limit %d", len(mpkg.Name), pkgNameLimit) + } + if len(mpkg.Path) > pkgPathLimit { + return fmt.Errorf("path length %d exceeds limit %d", len(mpkg.Path), pkgPathLimit) + } + if !rePkgName.MatchString(mpkg.Name) { + return fmt.Errorf("invalid package name %q", mpkg.Name) + } + if true && // none of these match... + !rePkgPathURL.MatchString(mpkg.Path) && + !rePkgPathStd.MatchString(mpkg.Path) { + return fmt.Errorf("invalid package path %q", mpkg.Path) + } + + // enforce sorting files based on Go conventions for predictability + sorted := sort.SliceIsSorted( + mpkg.Files, + func(i, j int) bool { + return mpkg.Files[i].Name < mpkg.Files[j].Name + }, + ) + if !sorted { + for i := 0; i < len(mpkg.Files); i++ { + fmt.Println("memfile", i, ":", mpkg.Files[i].Name) + } + return fmt.Errorf("mempackage %q has unsorted files", mpkg.Path) + } + + // unique filenames + if err := mpkg.Uniq(); err != nil { + return err + } + + // validate files + for _, mfile := range mpkg.Files { + if err := mfile.ValidateBasic(); err != nil { + return fmt.Errorf("invalid file in package: %w", err) + } + } + return nil } -func (mempkg *MemPackage) GetFile(name string) *MemFile { - for _, memFile := range mempkg.Files { - if memFile.Name == name { - return memFile +// Returns an error if lowercase(file.Name) are not unique. +func (mpkg *MemPackage) Uniq() error { + uniq := make(map[string]struct{}, len(mpkg.Files)) + for _, mfile := range mpkg.Files { + lname := strings.ToLower(mfile.Name) + if _, exists := uniq[lname]; exists { + return fmt.Errorf("duplicate file name %q", lname) } + uniq[lname] = struct{}{} } return nil } -func (mempkg *MemPackage) IsEmpty() bool { - return mempkg.Name == "" || len(mempkg.Files) == 0 +// Sort files; a MemPackage with unordered files is in valid. +func (mpkg *MemPackage) Sort() { + slices.SortFunc(mpkg.Files, func(a, b *MemFile) int { + return strings.Compare(a.Name, b.Name) + }) } -const pathLengthLimit = 256 +// Return the named file or none if it doesn't exist. +func (mpkg *MemPackage) GetFile(name string) *MemFile { + for _, mfile := range mpkg.Files { + if mfile.Name == name { + return mfile + } + } + return nil +} -var ( - rePkgName = regexp.MustCompile(`^[a-z][a-z0-9_]*$`) - rePkgOrRlmPath = regexp.MustCompile(`^([a-zA-Z0-9-]+\.)*[a-zA-Z0-9-]+\.[a-zA-Z]{2,}\/(?:p|r)(?:\/_?[a-z]+[a-z0-9_]*)+$`) - reFileName = regexp.MustCompile(`^([a-zA-Z0-9_]*\.[a-z0-9_\.]*|LICENSE|README)$`) -) +// Adds a file to the package without validation. +func (mpkg *MemPackage) AddFile(mfile *MemFile) { + mpkg.Files = append(mpkg.Files, mfile) +} -// path must not contain any dots after the first domain component. -// file names must contain dots. -// NOTE: this is to prevent conflicts with nested paths. -func (mempkg *MemPackage) Validate() error { - // add assertion that MemPkg contains at least 1 file - if len(mempkg.Files) <= 0 { - return fmt.Errorf("no files found within package %q", mempkg.Name) +// Creates a new MemFile and adds without validation. +func (mpkg *MemPackage) NewFile(name string, body string) (mfile *MemFile) { + mfile = &MemFile{ + Name: name, + Body: body, } + mpkg.AddFile(mfile) + return +} - if len(mempkg.Path) > pathLengthLimit { - return fmt.Errorf("path length %d exceeds limit %d", len(mempkg.Path), pathLengthLimit) +// Writes to existing file or creates a new one. +func (mpkg *MemPackage) SetFile(name string, body string) *MemFile { + for _, mfile := range mpkg.Files { + if mfile.Name == name { + mfile.Body = body + return mfile + } } + return mpkg.NewFile(name, body) +} - if !rePkgName.MatchString(mempkg.Name) { - return fmt.Errorf("invalid package name %q, failed to match %q", mempkg.Name, rePkgName) +// Removes an existing file and returns it or nil. +func (mpkg *MemPackage) DeleteFile(name string) *MemFile { + for i, mfile := range mpkg.Files { + if mfile.Name == name { + mpkg.Files = append(mpkg.Files[:i], mpkg.Files[i+1:]...) + return mfile + } } + return nil +} - if !rePkgOrRlmPath.MatchString(mempkg.Path) { - return fmt.Errorf("invalid package/realm path %q, failed to match %q", mempkg.Path, rePkgOrRlmPath) - } - // enforce sorting files based on Go conventions for predictability - sorted := sort.SliceIsSorted( - mempkg.Files, - func(i, j int) bool { - return mempkg.Files[i].Name < mempkg.Files[j].Name - }, - ) - if !sorted { - return fmt.Errorf("mempackage %q has unsorted files", mempkg.Path) - } +// Returns true if it has no files. +func (mpkg *MemPackage) IsEmpty() bool { + return len(mpkg.Files) == 0 +} - var prev string - for i, file := range mempkg.Files { - if !reFileName.MatchString(file.Name) { - return fmt.Errorf("invalid file name %q, failed to match %q", file.Name, reFileName) - } - if i > 0 && prev == file.Name { - return fmt.Errorf("duplicate file name %q", file.Name) +// Returns true if zero. +func (mpkg *MemPackage) IsZero() bool { + return mpkg.Name == "" && len(mpkg.Files) == 0 +} + +// Write all files into dir. +func (mpkg *MemPackage) WriteTo(dir string) error { + // fmt.Printf("writing mempackage to %q:\n", dir) + for _, mfile := range mpkg.Files { + // fmt.Printf(" - %s (%d bytes)\n", mfile.Name, len(mfile.Body)) + fpath := filepath.Join(dir, mfile.Name) + err := ioutil.WriteFile(fpath, []byte(mfile.Body), 0o644) + if err != nil { + return err } - prev = file.Name } + return nil +} +// Print all files to stdout. +func (mpkg *MemPackage) Print() error { + fmt.Printf("MemPackage[%q %s]:\n", mpkg.Path, mpkg.Name) + for _, mfile := range mpkg.Files { + mfile.Print() + } return nil } +// Return a list of all file names. +func (mpkg *MemPackage) FileNames() (fnames []string) { + for _, mfile := range mpkg.Files { + fnames = append(fnames, mfile.Name) + } + return +} + const licenseName = "LICENSE" -// Splits a path into the dirpath and filename. -func SplitFilepath(filepath string) (dirpath string, filename string) { - parts := strings.Split(filepath, "/") +// Splits a path into the dir and filename. +func SplitFilepath(fpath string) (dir string, filename string) { + parts := strings.Split(fpath, "/") if len(parts) == 1 { return parts[0], "" } diff --git a/tm2/pkg/std/memfile_test.go b/tm2/pkg/std/memfile_test.go index 71b0dad8423..c2e73dd9b0f 100644 --- a/tm2/pkg/std/memfile_test.go +++ b/tm2/pkg/std/memfile_test.go @@ -261,7 +261,7 @@ func TestMemPackage_Validate(t *testing.T) { t.Run(tc.name, func(t *testing.T) { t.Parallel() - err := tc.mpkg.Validate() + err := tc.mpkg.ValidateBasic() if tc.errContains != "" { assert.ErrorContains(t, err, tc.errContains) } else {