Skip to content

fix(gnovm): allow type-switch with sole case nil: (preprocess single-case branch must tag-type-only when ct is nil) - #5766

Merged
ltzmaxwell merged 11 commits into
masterfrom
fix/typeswitch1
Aug 24, 2026
Merged

fix(gnovm): allow type-switch with sole case nil: (preprocess single-case branch must tag-type-only when ct is nil)#5766
ltzmaxwell merged 11 commits into
masterfrom
fix/typeswitch1

Conversation

@ltzmaxwell

Copy link
Copy Markdown
Contributor
  • Before: a type-switch whose sole case was case nil: (e.g. switch xx := x.(type) { case nil: ... }) panicked at preprocess with name xx not declared because the single-case shortcut registered the switch var with anyValue(ct) where ct == nil; after: the sole-nil form is accepted and xx is bound to the tag's static type, matching Go.
  • preprocess1's *TypeSwitchStmt branch in gnovm/pkg/gnolang/preprocess.go now gates the len(n.Cases) == 1 define-with-case-type shortcut on ct != nil, so a nil ct falls through to the same tag-type define used for multi-case switches.
  • New filetest gnovm/tests/files/typeswitch1.gno mirrors gocorpus's typeswitch1 (sole case nil: alongside mixed multi-type cases) and exercises both the xx := x.(type) and bare xx.(type) shapes.

@Gno2D2

Gno2D2 commented Jun 2, 2026

Copy link
Copy Markdown
Collaborator

🛠 PR Checks Summary

All Automated Checks passed. ✅

Manual Checks (for Reviewers):
  • IGNORE the bot requirements for this PR (force green CI check)
Read More

🤖 This bot helps streamline PR reviews by verifying automated checks and providing guidance for contributors and reviewers.

✅ Automated Checks (for Contributors):

No automated checks match this pull request.

☑️ Contributor Actions:
  1. Fix any issues flagged by automated checks.
  2. Follow the Contributor Checklist to ensure your PR is ready for review.
    • Add new tests, or document why they are unnecessary.
    • Provide clear examples/screenshots, if necessary.
    • Update documentation, if required.
    • Ensure no breaking changes, or include BREAKING CHANGE notes.
    • Link related issues/PRs, where applicable.
☑️ Reviewer Actions:
  1. Complete manual checks for the PR, including the guidelines and additional checks if applicable.
📚 Resources:
Debug
Manual Checks
**IGNORE** the bot requirements for this PR (force green CI check)

If

🟢 Condition met
└── 🟢 On every pull request

Can be checked by

  • Any user with comment edit permission

@codecov

codecov Bot commented Jun 2, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.

📢 Thoughts on this report? Let us know!

Reserve() remains the legitimate entry point for nil-typed placeholder slots; Define() is for real bindings only. Catches the type-switch `case nil:` class of bug at the offending caller instead of as a confusing downstream "name not declared" panic.
@thehowl thehowl added the a/vm GnoVM, Security, Runtime team label Jun 11, 2026

@notJoon notJoon left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The change look good. I left a minor suggestion; please take a look and feel free to apply them.

not necessary, but I think it would be good to have a test that distinguishes between an interface containing a nil value and one with no dynamic type at all.

for example:

// PATH: gnovm/tests/files/typeswitch2.gno

package main

type S struct{}

func classify(x any) {
	switch v := x.(type) {
	case nil:
		println("nil", v == nil)
	case *S:
		println("*S", v == nil)
	default:
		panic("unexpected type")
	}
}

func main() {
	classify(nil)
	classify((*S)(nil))
	classify(&S{})
}

// Output:
// nil true
// *S true
// *S false

https://go.dev/play/p/hOcVkHTayGI

nil has no dynamic type, so it enters case nil. In contrast, (*S)(nil) still has the dynamic type *S even though the underlying pointer value is nil, so it enters case *S. and I confirmed that this passes on my side.

Since this change adds support for case nil, testing this boundary as well would help ensure the behavior is robust and the intent is clear.

Comment thread gnovm/tests/files/typeswitch1.gno Outdated
Comment thread gnovm/tests/files/typeswitch1.gno Outdated
Comment thread gnovm/tests/files/typeswitch1.gno Outdated
ltzmaxwell and others added 4 commits August 21, 2026 11:15
Co-authored-by: Lee ByeongJun <lbj199874@gmail.com>
Co-authored-by: Lee ByeongJun <lbj199874@gmail.com>
Co-authored-by: Lee ByeongJun <lbj199874@gmail.com>
@ltzmaxwell

ltzmaxwell commented Aug 21, 2026

Copy link
Copy Markdown
Contributor Author

Added the suggested typeswitch2.gno filetest in 47d220b — good boundary to pin down: nil (no dynamic type) enters case nil, while (*S)(nil) keeps dynamic type *S and enters case *S with a nil underlying value. Passes locally. Thanks @notJoon!

@ltzmaxwell
ltzmaxwell merged commit add66f2 into master Aug 24, 2026
91 of 92 checks passed
@ltzmaxwell
ltzmaxwell deleted the fix/typeswitch1 branch August 24, 2026 14:40
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

a/vm GnoVM, Security, Runtime team 📦 🤖 gnovm Issues or PRs gnovm related

Projects

Development

Successfully merging this pull request may close these issues.

5 participants