Skip to content

for range <int> compiles but crashes at runtime (should be a typecheck error given Go 1.17 baseline) #4680

@omarsy

Description

@omarsy

Summary
The following program compiles in Gno but panics at runtime:

package main

func main() {
	for range 1000 {
	}
}

Since Gno targets Go 1.17 semantics, range over an integer should be rejected at type-check time. “Range over int” only became valid Go syntax in Go 1.22; before that, it must be a compile-time error like:
cannot range over 1000 (type untyped int) (or equivalent). ([tip.golang.org][1]

Steps to Reproduce

  1. Create main.gno:

    package main
    
    func main() {
    	for range 1000 {
    	}
    }
  2. Build/run with Gno.

  3. Observe a runtime panic.

Expected Behavior

  • The program should fail to compile with a typecheck error, because ranging over integers isn’t supported in Go 1.17.

Actual Behavior

  • The program builds and then panics at runtime.

  • Runtime output / panic trace:

testing.tRunner.func1.2({0x100f1aaa0, 0x1400035c318})
       /Users/ghost/go/pkg/mod/golang.org/[email protected]/src/testing/testing.go:1734 +0x1ac
testing.tRunner.func1()
       /Users/ghost/go/pkg/mod/golang.org/[email protected]/src/testing/testing.go:1737 +0x334
panic({0x100f1aaa0?, 0x1400035c318?})
       /Users/ghost/go/pkg/mod/golang.org/[email protected]/src/runtime/panic.go:792 +0x124
github.com/gnolang/gno/gnovm/pkg/gnolang.(*bodyStmt).LastStmt(...)
       /Users/ghost/Documents/projects/gno/gnovm/pkg/gnolang/nodes.go:1013
github.com/gnolang/gno/gnovm/pkg/gnolang.(*Machine).Stacktrace(0x1400020a588)
       /Users/ghost/Documents/projects/gno/gnovm/pkg/gnolang/machine.go:421 +0x4f0
github.com/gnolang/gno/gnovm/pkg/test.(*TestOptions).runTest.func1()
       /Users/ghost/Documents/projects/gno/gnovm/pkg/test/filetest.go:312 +0x2a8
panic({0x100e12ee0?, 0x1400004abc0?})
       /Users/ghost/go/pkg/mod/golang.org/[email protected]/src/runtime/panic.go:792 +0x124
github.com/gnolang/gno/gnovm/pkg/gnolang.(*Machine).Run.func1()
       /Users/ghost/Documents/projects/gno/gnovm/pkg/gnolang/machine.go:1258 +0x174
panic({0x100e12ee0?, 0x1400004abc0?})
       /Users/ghost/go/pkg/mod/golang.org/[email protected]/src/runtime/panic.go:792 +0x124
github.com/gnolang/gno/gnovm/pkg/gnolang.(*TypedValue).GetLength(0x100f9f5d8?)
       /Users/ghost/Documents/projects/gno/gnovm/pkg/gnolang/values.go:2049 +0x38c
github.com/gnolang/gno/gnovm/pkg/gnolang.(*Machine).doOpExec(0x1400020a588, 0x40?)
       /Users/ghost/Documents/projects/gno/gnovm/pkg/gnolang/op_exec.go:154 +0xf74
github.com/gnolang/gno/gnovm/pkg/gnolang.(*Machine).Run(0x1400020a588, {0x100b11785?, 0x140004be248?})
       /Users/ghost/Documents/projects/gno/gnovm/pkg/gnolang/machine.go:1576 +0x9ec
github.com/gnolang/gno/gnovm/pkg/gnolang.(*Machine).RunStatement(0x1400020a588, {0x100b11785, 0x8}, {0x100fa6e80, 0x140000574a0})
       /Users/ghost/Documents/projects/gno/gnovm/pkg/gnolang/machine.go:922 +0x280
github.com/gnolang/gno/gnovm/pkg/gnolang.(*Machine).runFunc(0x1400020a588, {0x100b11785, 0x8}, {0x100b0d31b, 0x4}, 0x2?)
       /Users/ghost/Documents/projects/gno/gnovm/pkg/gnolang/machine.go:767 +0x3ac
github.com/gnolang/gno/gnovm/pkg/gnolang.(*Machine).RunMain(...)
       /Users/ghost/Documents/projects/gno/gnovm/pkg/gnolang/machine.go:771
github.com/gnolang/gno/gnovm/pkg/test.(*TestOptions).runTest(0x140000cc180, 0x1400020a588, {0x100b0d31b, 0x4}, {0x140001d7160?, 0x100f91540?}, {0x140001f7e00, 0x92, 0x140004a40f0?}, {0x0, ...}, ...)
       /Users/ghost/Documents/projects/gno/gnovm/pkg/test/filetest.go:359 +0xeb0
github.com/gnolang/gno/gnovm/pkg/test.(*TestOptions).runFiletest(0x140000cc180, {0x140001d7160, 0xa}, {0x140001f7e00, 0x92, 0x200}, {0x100fae100, 0x140004a4b40}, 0x1)
       /Users/ghost/Documents/projects/gno/gnovm/pkg/test/filetest.go:82 +0x67c
github.com/gnolang/gno/gnovm/pkg/test.(*TestOptions).RunFiletest(0x14000591f18?, {0x140001d7160?, 0x140004a4000?}, {0x140001f7e00?, 0x0?, 0x10041a763?}, {0x100fae100?, 0x140004a4b40?})
       /Users/ghost/Documents/projects/gno/gnovm/pkg/test/filetest.go:32 +0x88
github.com/gnolang/gno/gnovm/pkg/gnolang_test.TestFiles.func2.4(0x140002b5dc0)
       /Users/ghost/Documents/projects/gno/gnovm/pkg/gnolang/files_test.go:109 +0xc0
testing.tRunner(0x140002b5dc0, 0x140003debd0)
       /Users/ghost/go/pkg/mod/golang.org/[email protected]/src/testing/testing.go:1792 +0xe4
created by testing.(*T).Run in goroutine 11
       /Users/ghost/go/pkg/mod/golang.org/[email protected]/src/testing/testing.go:1851 +0x374
FAIL    github.com/gnolang/gno/gnovm/pkg/gnolang 

Analysis

  • Go added “range over integers” (for i := range N { ... }) in Go 1.22 only. Under Go 1.17 semantics, range is limited to arrays, slices, strings, maps, and channels, so range 1000 should be rejected during type checking. Allowing it to pass the checker and then failing at runtime suggests the parser/type checker accepts the construct but the backend can’t execute it. ([tip.golang.org][1], [go.dev][2])

Possible Fixes

  • Enforce a typecheck error when the range expression is of (untyped) integer type under the Go 1.17 rules; or
  • If We intends to adopt Go 1.22 behavior, implement full range-over-int semantics (0..N-1) consistently across the compiler/runtime.

Metadata

Metadata

Assignees

No one assigned

    Labels

    🐞 bugSomething isn't working

    Type

    No type

    Projects

    Status

    Done

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions