diff --git a/gnovm/pkg/gnolang/preprocess.go b/gnovm/pkg/gnolang/preprocess.go index 459910505b9..88c5c2f1da4 100644 --- a/gnovm/pkg/gnolang/preprocess.go +++ b/gnovm/pkg/gnolang/preprocess.go @@ -2477,7 +2477,7 @@ func checkOrConvertType(store Store, last BlockNode, x *Expr, t Type, autoNative // convert type if isUntyped(xt) { // convert if x is untyped literal if t == nil { - t = defaultTypeOf(xt) + t = defaultTypeOf(xt, nil) } // Push type into expr if qualifying binary expr. if bx, ok := (*x).(*BinaryExpr); ok { diff --git a/gnovm/pkg/gnolang/types.go b/gnovm/pkg/gnolang/types.go index fcfcd7d9d37..86b3d588eda 100644 --- a/gnovm/pkg/gnolang/types.go +++ b/gnovm/pkg/gnolang/types.go @@ -1203,8 +1203,8 @@ func (ft *FuncType) Specify(store Store, argTVs []TypedValue, isVarg bool) *Func continue } else if vargt == nil { vargt = varg.T - } else if isUntyped(varg.T) && vargt.TypeID() == defaultTypeOf(varg.T).TypeID() { - vargt = defaultTypeOf(varg.T) + } else if isUntyped(varg.T) && vargt.TypeID() == defaultTypeOf(varg.T, varg.V).TypeID() { + vargt = defaultTypeOf(varg.T, varg.V) } else if vargt.TypeID() != varg.T.TypeID() { panic(fmt.Sprintf( "incompatible varg types: expected %v, got %s", @@ -2281,14 +2281,23 @@ func isDataByte(t Type) bool { // TODO move untyped const stuff to preprocess.go. // TODO associate with ConvertTo() in documentation. -func defaultTypeOf(t Type) Type { +func defaultTypeOf(t Type, v Value) Type { switch t { case UntypedBoolType: return BoolType case UntypedRuneType: return Int32Type case UntypedBigintType: - return IntType + typeVal := IntType + if bigintValue, ok := v.(BigintValue); ok { + if bigintValue.V != nil && bigintValue.V.Sign() == 1 && !bigintValue.V.IsInt64() { + // Use an unsigned type if the value is positive and we know + // it won't fit in an int64. + typeVal = Uint64Type + } + } + + return typeVal case UntypedBigdecType: return Float64Type case UntypedStringType: @@ -2514,7 +2523,7 @@ func specifyType(store Store, lookup map[Name]Type, tmpl Type, spec Type, specTy return // ok } else { if isUntyped(spec) { - spec = defaultTypeOf(spec) + spec = defaultTypeOf(spec, nil) } lookup[ct.Generic] = spec return // ok diff --git a/gnovm/pkg/gnolang/values.go b/gnovm/pkg/gnolang/values.go index b0996b98b6f..d8d4bc58bc3 100644 --- a/gnovm/pkg/gnolang/values.go +++ b/gnovm/pkg/gnolang/values.go @@ -1594,7 +1594,7 @@ func (tv *TypedValue) Assign(alloc *Allocator, tv2 TypedValue, cu bool) { } *tv = tv2.Copy(alloc) if cu && isUntyped(tv.T) { - ConvertUntypedTo(tv, defaultTypeOf(tv.T)) + ConvertUntypedTo(tv, defaultTypeOf(tv.T, tv.V)) } } diff --git a/gnovm/pkg/gnolang/values_conversions.go b/gnovm/pkg/gnolang/values_conversions.go index b4888878c7a..edaa8883819 100644 --- a/gnovm/pkg/gnolang/values_conversions.go +++ b/gnovm/pkg/gnolang/values_conversions.go @@ -926,7 +926,7 @@ func ConvertUntypedTo(tv *TypedValue, t Type) { } // general case if t == nil { - t = defaultTypeOf(tv.T) + t = defaultTypeOf(tv.T, tv.V) } switch tv.T { case UntypedBoolType: diff --git a/gnovm/tests/files/bigint1.gno b/gnovm/tests/files/bigint1.gno new file mode 100644 index 00000000000..01032e27b3f --- /dev/null +++ b/gnovm/tests/files/bigint1.gno @@ -0,0 +1,14 @@ +package main + +import ( + "math" +) + +func main() { + println(float64(math.MaxUint32)) + println(float64(math.MaxUint64)) +} + +// Output: +// 4.294967295e+09 +// 1.8446744073709552e+19