cue: fix number output

Ensure that numbers of type float have
a dot in them to retain their type.

Also:
- removes stripping of trailing zeros after
  division.
-  fixes a bug where the type of a resulting
   number is determined using old semantics.
- fixes a blatant typing bug.

Fixes #233

Change-Id: I2cc524923f189bdf8cb25dd72a1667ee2f2097d0
Reviewed-on: https://cue-review.googlesource.com/c/cue/+/4400
Reviewed-by: Marcel van Lohuizen <mpvl@golang.org>
diff --git a/cue/binop.go b/cue/binop.go
index 86dca45..38dcdb1 100644
--- a/cue/binop.go
+++ b/cue/binop.go
@@ -452,10 +452,16 @@
 				case diff == 1:
 					if k&floatKind == 0 {
 						if x.op == opGeq && y.op == opLss {
-							return &numLit{numBase: a.numBase, v: lo}
+							n := *a
+							n.k = k & numKind
+							n.v.Set(&lo)
+							return &n
 						}
 						if x.op == opGtr && y.op == opLeq {
-							return &numLit{numBase: b.numBase, v: hi}
+							n := *b
+							n.k = k & numKind
+							n.v.Set(&hi)
+							return &n
 						}
 					}
 
@@ -1047,7 +1053,6 @@
 			if cond.DivisionByZero() {
 				return ctx.mkErr(src, "division by zero")
 			}
-			_, _, _ = ctx.Reduce(&n.v, &n.v)
 			n.k = floatKind
 		case opIDiv:
 			if y.v.IsZero() {
diff --git a/cue/debug.go b/cue/debug.go
index 17d8f2f..e525c17 100644
--- a/cue/debug.go
+++ b/cue/debug.go
@@ -432,11 +432,7 @@
 		str = str[1 : len(str)-1]
 		writef("'%s'", str)
 	case *numLit:
-		if x.k&intKind != 0 {
-			write(x.v.Text('f')) // also render info
-		} else {
-			write(x.v.Text('g')) // also render info
-		}
+		write(x.String())
 	case *durationLit:
 		write(x.d.String())
 	case *bound:
diff --git a/cue/export.go b/cue/export.go
index 9990072..36fdc83 100644
--- a/cue/export.go
+++ b/cue/export.go
@@ -550,16 +550,11 @@
 		}
 
 	case *numLit:
+		kind := token.FLOAT
 		if x.k&intKind != 0 {
-			return &ast.BasicLit{
-				Kind:  token.INT,
-				Value: x.v.Text('f'),
-			}
+			kind = token.INT
 		}
-		return &ast.BasicLit{
-			Kind:  token.FLOAT,
-			Value: x.v.Text('g'),
-		}
+		return &ast.BasicLit{Kind: kind, Value: x.String()}
 
 	case *durationLit:
 		panic("unimplemented")
diff --git a/cue/go.go b/cue/go.go
index d2a2225..09c1ae6 100644
--- a/cue/go.go
+++ b/cue/go.go
@@ -452,7 +452,7 @@
 }
 
 func toUint(ctx *context, src source, x uint64) evaluated {
-	n := newNum(src, floatKind)
+	n := newNum(src, intKind)
 	n.v.Coeff.SetUint64(x)
 	return n
 }
diff --git a/cue/lit.go b/cue/lit.go
index 57ace1f..325f9e5 100644
--- a/cue/lit.go
+++ b/cue/lit.go
@@ -47,11 +47,6 @@
 	return numInfo{m, k}
 }
 
-func unifyNuminfo(a, b numInfo) numInfo {
-	k := unifyType(a.k, b.k)
-	return numInfo{a.rep | b.rep, k}
-}
-
 func (n numInfo) isValid() bool          { return n.k != bottomKind }
 func (n numInfo) multiplier() multiplier { return n.rep & (hasSeparators - 1) }
 
diff --git a/cue/resolve_test.go b/cue/resolve_test.go
index 26bde55..3733af9 100644
--- a/cue/resolve_test.go
+++ b/cue/resolve_test.go
@@ -137,9 +137,11 @@
 			sum: -1 + +2        // 1
 			div1: 2.0 / 3 * 6   // 4
 			div2: 2 / 3 * 6     // 4
+			div3: 1.00 / 1.00
 			divZero: 1.0 / 0
 			div00: 0 / 0
 			b: 1 != 4
+			add: div1 + 1.0
 
 			idiv00: 0 div 0
 			imod00: 0 mod 0
@@ -166,14 +168,16 @@
 			`sum: 1, ` +
 			`div1: 4.00000000000000000000000, ` +
 			`div2: 4.00000000000000000000000, ` +
+			`div3: 1., ` +
 			`divZero: _|_((1.0 / 0):division by zero), ` +
 			`div00: _|_((0 / 0):division undefined), ` +
 			`b: true, ` +
+			`add: 5.00000000000000000000000, ` +
 			`idiv00: _|_((0 div 0):division by zero), ` +
 			`imod00: _|_((0 mod 0):division by zero), ` +
 			`iquo00: _|_((0 quo 0):division by zero), ` +
 			`irem00: _|_((0 rem 0):division by zero), ` +
-			`v1: 5e+11, ` +
+			`v1: 5.0000000000e+11, ` +
 			`v2: true, ` +
 			`v3: 0.666666666666666666666667, ` +
 			`v5: 0, ` +
@@ -611,9 +615,10 @@
 				v2: 2.0 == 2
 				n1: 1
 				v5: 2.0 / n1
+				v6: 1.0 / 1.0
 				e2: int & 4.0/2.0
 				`,
-		out: `<0>{v1: 5e+11, v2: true, n1: 1, v5: 2, e2: _|_((int & (4.0 / 2.0)):conflicting values int and (4.0 / 2.0) (mismatched types int and float))}`,
+		out: `<0>{v1: 5.0000000000e+11, v2: true, n1: 1, v5: 2.0, v6: 1., e2: _|_((int & (4.0 / 2.0)):conflicting values int and (4.0 / 2.0) (mismatched types int and float))}`,
 	}, {
 		desc: "inequality",
 		in: `
@@ -768,6 +773,7 @@
 	}, {
 		desc: "bound conversions",
 		in: `
+		r0: int & >0.1 &  <=1.9
 		r1: int & >0.1 & <1.9
 		r2: int & >=0.1 & <1.9
 		r3: int & >=-1.9 & <=-0.1
@@ -783,6 +789,7 @@
 		c4: 1.2 & (>=1 & <2 & int)
 		`,
 		out: `<0>{` +
+			`r0: 1, ` +
 			`r1: 1, ` +
 			`r2: 1, ` +
 			`r3: -1, ` +
diff --git a/cue/types.go b/cue/types.go
index 273fd24..c019e11 100644
--- a/cue/types.go
+++ b/cue/types.go
@@ -987,6 +987,7 @@
 func makeInt(v Value, x int64) Value {
 	n := &numLit{numBase: numBase{baseValue: v.path.v.base()}}
 	n.v.SetInt64(x)
+	n.k = intKind
 	return remakeValue(v, n)
 }
 
diff --git a/cue/types_test.go b/cue/types_test.go
index 7718475..c38ab79 100644
--- a/cue/types_test.go
+++ b/cue/types_test.go
@@ -1891,7 +1891,7 @@
 	}, {
 		// Issue #107
 		value: `a: 1.0/1`,
-		json:  `{"a":1}`,
+		json:  `{"a":1.0}`,
 	}, {
 		// Issue #108
 		value: `
diff --git a/cue/value.go b/cue/value.go
index 3d1fbf8..59c0ef1 100644
--- a/cue/value.go
+++ b/cue/value.go
@@ -315,7 +315,7 @@
 	n := &numLit{
 		numBase: numBase{
 			baseValue: a.baseValue,
-			numInfo:   unifyNuminfo(a.numInfo, b.numInfo),
+			numInfo:   numInfo{a.rep | b.rep, k},
 		},
 	}
 	return n
@@ -326,6 +326,17 @@
 	v apd.Decimal
 }
 
+func (n *numLit) String() string {
+	if n.k&intKind != 0 {
+		return n.v.Text('f') // also render info
+	}
+	s := n.v.Text('g')
+	if len(s) == 1 {
+		s += "."
+	}
+	return s // also render info
+}
+
 func parseInt(k kind, s string) *numLit {
 	n := &ast.BasicLit{
 		Kind:  token.INT,