From 63c5b4353d50020e9bedd354c54f5cdf99437878 Mon Sep 17 00:00:00 2001 From: "Randall C. O'Reilly" Date: Sun, 25 Oct 2026 10:16:51 +0100 Subject: [PATCH] fix(builtin): wrap a uint64 converted to int in generic code A conversion to a type parameter whose type argument is int did not wrap a uint64 beyond the int range, so T(u) for u = 1<<64 - 7 gave 18446744073709552000 instead of -7, as the non-generic int(u) does. Signed-off-by: Randall C. O'Reilly --- gs/builtin/builtin.ts | 3 ++- .../generic_typeparam_conversion/expected.log | 2 ++ .../generic_typeparam_conversion.go | 9 ++++++++ .../generic_typeparam_conversion.gs.ts | 22 +++++++++++++++++++ 4 files changed, 35 insertions(+), 1 deletion(-) diff --git a/gs/builtin/builtin.ts b/gs/builtin/builtin.ts index 228bfc72d..cfa2831b9 100644 --- a/gs/builtin/builtin.ts +++ b/gs/builtin/builtin.ts @@ -894,7 +894,8 @@ export function genericConvert( case 'rune': return int(value, 32) as T case 'int': - return int(value) as T + // int is 64 bits, so a uint64 beyond its range wraps as in Go. + return int(value, 64) as T case 'uint8': case 'byte': return uint(value, 8) as T diff --git a/tests/tests/generic_typeparam_conversion/expected.log b/tests/tests/generic_typeparam_conversion/expected.log index 4df8258fb..f5b0ec566 100644 --- a/tests/tests/generic_typeparam_conversion/expected.log +++ b/tests/tests/generic_typeparam_conversion/expected.log @@ -6,3 +6,5 @@ 10 wide 16 7 44 +-7 -7 -7 +-1 diff --git a/tests/tests/generic_typeparam_conversion/generic_typeparam_conversion.go b/tests/tests/generic_typeparam_conversion/generic_typeparam_conversion.go index f5256033a..cceb07a23 100644 --- a/tests/tests/generic_typeparam_conversion/generic_typeparam_conversion.go +++ b/tests/tests/generic_typeparam_conversion/generic_typeparam_conversion.go @@ -48,6 +48,12 @@ func toWide[T, E EnumConstraint](e E) T { return T(e) } +// fromUint64 converts a uint64 to a type parameter, which wraps a value +// beyond the range of the type. +func fromUint64[T Integer](u uint64) T { + return T(u) +} + // fromConst converts a constant and a basic value to a type parameter. func fromConst[T Integer](i int) (T, T) { return T(7), T(i) @@ -64,4 +70,7 @@ func main() { println(int64(a) + int64(b)) c, d := fromConst[uint8](300) println(c, d) + u := uint64(1<<64 - 7) + println(fromUint64[int](u), fromUint64[int64](u), fromUint64[int32](u)) + println(fromUint64[int](u) % 3) } diff --git a/tests/tests/generic_typeparam_conversion/generic_typeparam_conversion.gs.ts b/tests/tests/generic_typeparam_conversion/generic_typeparam_conversion.gs.ts index 2377b951e..f6226be2b 100644 --- a/tests/tests/generic_typeparam_conversion/generic_typeparam_conversion.gs.ts +++ b/tests/tests/generic_typeparam_conversion/generic_typeparam_conversion.gs.ts @@ -115,6 +115,10 @@ export function toWide(__typeArgs: $.GenericTypeArgs | undefined, e: any): any { return $.genericConvert(__typeArgs, "T", e) } +export function fromUint64(__typeArgs: $.GenericTypeArgs | undefined, u: bigint): any { + return $.genericConvert(__typeArgs, "T", u) +} + export function fromConst(__typeArgs: $.GenericTypeArgs | undefined, i: number): [any, any] { return [$.genericConvert(__typeArgs, "T", 7), $.genericConvert(__typeArgs, "T", i)] } @@ -135,6 +139,9 @@ export async function main(): globalThis.Promise { let c: number = (__goscriptTuple1[0] as number) let d: number = (__goscriptTuple1[1] as number) await $.println(c, d) + let u = 18446744073709551609n + await $.println(fromUint64(__goscriptStatic4(), u), fromUint64(__goscriptStatic5(), u), fromUint64(__goscriptStatic6(), u)) + await $.println(fromUint64(__goscriptStatic4(), u) % 3) } var __goscriptStatic0$value: any @@ -157,6 +164,21 @@ function __goscriptStatic3(): any { return __goscriptStatic3$value ??= ({[$.genericTypeArgsMarker]: $.genericTypeArgsBrand, T: { type: /* @__PURE__ */ $.basicType("uint8"), zero: () => 0 }}) } +var __goscriptStatic4$value: any +function __goscriptStatic4(): any { + return __goscriptStatic4$value ??= ({[$.genericTypeArgsMarker]: $.genericTypeArgsBrand, T: { type: /* @__PURE__ */ $.basicType("int"), zero: () => 0 }}) +} + +var __goscriptStatic5$value: any +function __goscriptStatic5(): any { + return __goscriptStatic5$value ??= ({[$.genericTypeArgsMarker]: $.genericTypeArgsBrand, T: { type: /* @__PURE__ */ $.basicType("int64"), zero: () => 0n }}) +} + +var __goscriptStatic6$value: any +function __goscriptStatic6(): any { + return __goscriptStatic6$value ??= ({[$.genericTypeArgsMarker]: $.genericTypeArgsBrand, T: { type: /* @__PURE__ */ $.basicType("int32"), zero: () => 0 }}) +} + if ($.isMainScript(import.meta)) { await main() }