You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
On macOS arm64, a bare (uncast) integer literal that does not fit in 32 bits is truncated to its low 32 bits when it is compared against an i64inside assert. The comparison yields the wrong answer, and assert's own diagnostic prints the literal as a different number than the one written in the source:
assert get_plain() == -123456789012345
left value: get_plain() = -123456789012345
right value: -123456789012345 = 2045911175
2045911175 is exactly -123456789012345 & 0xFFFFFFFF.
The same comparison written in a plain if evaluates correctly on the same platform, so this appears specific to the code assert generates rather than to comparison codegen in general.
The same file passes on ubuntu-latest (x86_64), so identical source produces different results per architecture.
Possibly related: V's checker rejects the very same literal when it is bound rather than compared —
constc=-123456789012345// error: overflow in implicit type `int`, use explicit type casting insteady:=-123456789012345// error: overflow in implicit type `int`, use explicit type casting instead
so the literal is being typed as int in those positions and correctly diagnosed, while the assert comparison position silently accepts it and then truncates. Promoting the literal to the other operand's type (or raising the same overflow error) in that position would presumably fix it.
Reproduction Steps
probe/literal_test.v:
fnget() !i64 {
returni64(-123456789012345)
}
fnget_plain() i64 {
returni64(-123456789012345)
}
// FAILS on macOS arm64fntest_unwrap_eq_bare_literal() ! {
assertget()!==-123456789012345
}
// FAILS on macOS arm64fntest_plain_eq_bare_literal() {
assertget_plain() ==-123456789012345
}
// PASSES — same comparison outside of assertfntest_if_comparison() {
muthit:=falseifget_plain() ==-123456789012345 {
hit=true
}
assert hit, 'if-comparison against bare literal did not match'
}
// PASSES — explicit cast on both sides (the workaround)fntest_unwrap_eq_cast_literal() ! {
assertget()!==i64(-123456789012345)
}
All four tests pass. -123456789012345 is representable as i64, the left operand is i64, and the same literal compares correctly in a plain if on the same machine — so the assert comparison should agree.
(Alternatively, if a bare literal in this position is genuinely meant to be int, it should raise the same overflow in implicit type int error the checker already raises for const c = -123456789012345, rather than silently truncating.)
Current Behavior
macOS arm64:
FAIL 21.020 ms probe/literal_test.v
V panic: Assertion failed...
probe/literal_test.v:16: fn test_unwrap_eq_bare_literal
assert get()! == -123456789012345
right value: -123456789012345 = 2045911175
V panic: Assertion failed...
probe/literal_test.v:21: fn test_plain_eq_bare_literal
assert get_plain() == -123456789012345
left value: get_plain() = -123456789012345
right value: -123456789012345 = 2045911175
Summary for all V _test.v files: 1 failed, 1 total.
test_if_comparison and test_unwrap_eq_cast_literal pass.
In the assert comparison position, infer the untyped integer literal from the other operand's type (here i64) instead of defaulting it to int. If defaulting to int is intended, apply the existing overflow in implicit type int check there too so it fails loudly at compile time instead of silently truncating at runtime.
Additional Information/Context
Found while building a protobuf library for V, where test vectors compare decoded i64/sint64 values against literals. Real impact is limited by the workaround (cast both sides), but it is easy to hit and fails only on Apple Silicon, so it presents as a mysterious platform-specific test failure.
Reproduced on three separate CI runs over three days (2026-08-05, 2026-08-08 ×2), each against a freshly downloaded refs/heads/master tarball.
Not reproducible on x86_64 Linux with either gcc 16.1.1 or clang 22.1.4.
V version
V 0.5.2, built from https://codeload.github.com/vlang/v/legacy.tar.gz/refs/heads/master on 2026-08-08 (installed by vlang/setup-v@v1; the tarball has no .git, so v version reports a bare V 0.5.2 with no commit hash).
Locally on Linux (where it does not reproduce): V 0.5.2 e65ec29e8738bfc1875d722161b9babae372eb86.
Local machine where it also does not reproduce (v doctor):
V full version | V 0.5.2 e65ec29e8738bfc1875d722161b9babae372eb86
OS | linux, "Bazzite" (Fedora Atomic)
Processor | 12 cpus, 64bit, little endian, AMD Ryzen 5 3600 6-Core Processor
cc version | cc (GCC) 16.1.1 20260515 (Red Hat 16.1.1-2)
clang version | Homebrew clang version 22.1.4
glibc version | ldd (GNU libc) 2.43
Note
You can use the 👍 reaction to increase the issue's priority for developers.
Please note that only the 👍 reaction to the issue itself counts as a vote.
Other reactions and those to comments will not be taken into account.
Describe the bug
On macOS arm64, a bare (uncast) integer literal that does not fit in 32 bits is truncated to its low 32 bits when it is compared against an
i64insideassert. The comparison yields the wrong answer, andassert's own diagnostic prints the literal as a different number than the one written in the source:2045911175is exactly-123456789012345 & 0xFFFFFFFF.The same comparison written in a plain
ifevaluates correctly on the same platform, so this appears specific to the codeassertgenerates rather than to comparison codegen in general.The same file passes on
ubuntu-latest(x86_64), so identical source produces different results per architecture.Possibly related: V's checker rejects the very same literal when it is bound rather than compared —
so the literal is being typed as
intin those positions and correctly diagnosed, while theassertcomparison position silently accepts it and then truncates. Promoting the literal to the other operand's type (or raising the same overflow error) in that position would presumably fix it.Reproduction Steps
probe/literal_test.v:v test probe/Runnable branch, with a CI workflow that runs it on macos-latest and ubuntu-latest side by side:
https://github.com/we-be/protobuf.v/blob/probe-i64-literal/probe/literal_test.v
Expected Behavior
All four tests pass.
-123456789012345is representable asi64, the left operand isi64, and the same literal compares correctly in a plainifon the same machine — so theassertcomparison should agree.(Alternatively, if a bare literal in this position is genuinely meant to be
int, it should raise the sameoverflow in implicit type interror the checker already raises forconst c = -123456789012345, rather than silently truncating.)Current Behavior
macOS arm64:
test_if_comparisonandtest_unwrap_eq_cast_literalpass.ubuntu-latest x86_64: all four pass.
CI run showing both platforms on the same commit:
https://github.com/we-be/protobuf.v/actions/runs/31235511455
Possible Solution
In the
assertcomparison position, infer the untyped integer literal from the other operand's type (herei64) instead of defaulting it toint. If defaulting tointis intended, apply the existingoverflow in implicit type intcheck there too so it fails loudly at compile time instead of silently truncating at runtime.Additional Information/Context
i64/sint64values against literals. Real impact is limited by the workaround (cast both sides), but it is easy to hit and fails only on Apple Silicon, so it presents as a mysterious platform-specific test failure.refs/heads/mastertarball.V version
V 0.5.2, built from
https://codeload.github.com/vlang/v/legacy.tar.gz/refs/heads/masteron 2026-08-08 (installed byvlang/setup-v@v1; the tarball has no.git, sov versionreports a bareV 0.5.2with no commit hash).Locally on Linux (where it does not reproduce):
V 0.5.2 e65ec29e8738bfc1875d722161b9babae372eb86.Environment details (OS name and version, etc.)
Failing platform — GitHub Actions
macos-latest:Passing platform — GitHub Actions
ubuntu-latest:Local machine where it also does not reproduce (
v doctor):Note
You can use the 👍 reaction to increase the issue's priority for developers.
Please note that only the 👍 reaction to the issue itself counts as a vote.
Other reactions and those to comments will not be taken into account.