cmd/compile: make typecheck set correct untyped type

Passes toolstash-check.

Change-Id: Ie631d8dacb1cc76613e1f50da8422850ac7119a1
Reviewed-on: https://go-review.googlesource.com/c/go/+/255217
Trust: Cuong Manh Le <cuong.manhle.vn@gmail.com>
Run-TryBot: Cuong Manh Le <cuong.manhle.vn@gmail.com>
TryBot-Result: Go Bot <gobot@golang.org>
Reviewed-by: Matthew Dempsky <mdempsky@google.com>
diff --git a/src/cmd/compile/internal/gc/const.go b/src/cmd/compile/internal/gc/const.go
index fe73df9..59b2c56 100644
--- a/src/cmd/compile/internal/gc/const.go
+++ b/src/cmd/compile/internal/gc/const.go
@@ -44,7 +44,7 @@
 		Fatalf("unexpected Ctype for %T", v.U)
 		panic("unreachable")
 	case nil:
-		return 0
+		return CTxxx
 	case *NilVal:
 		return CTNIL
 	case bool:
@@ -261,7 +261,7 @@
 	}
 
 	if t == nil || !okforconst[t.Etype] {
-		t = defaultType(idealkind(n))
+		t = defaultType(n.Type)
 	}
 
 	switch n.Op {
@@ -994,10 +994,8 @@
 		Xoffset: BADWIDTH,
 	}
 	n.SetVal(v)
-	if n.Type.IsUntyped() {
-		// TODO(mdempsky): Make typecheck responsible for setting
-		// the correct untyped type.
-		n.Type = idealType(v.Ctype())
+	if vt := idealType(v.Ctype()); n.Type.IsUntyped() && n.Type != vt {
+		Fatalf("untyped type mismatch, have: %v, want: %v", n.Type, vt)
 	}
 
 	// Check range.
@@ -1056,67 +1054,6 @@
 	return nil
 }
 
-// idealkind returns a constant kind like consttype
-// but for an arbitrary "ideal" (untyped constant) expression.
-func idealkind(n *Node) Ctype {
-	if n == nil || !n.Type.IsUntyped() {
-		return CTxxx
-	}
-
-	switch n.Op {
-	default:
-		return CTxxx
-
-	case OLITERAL:
-		return n.Val().Ctype()
-
-		// numeric kinds.
-	case OADD,
-		OAND,
-		OANDNOT,
-		OBITNOT,
-		ODIV,
-		ONEG,
-		OMOD,
-		OMUL,
-		OSUB,
-		OXOR,
-		OOR,
-		OPLUS:
-		k1 := idealkind(n.Left)
-		k2 := idealkind(n.Right)
-		if k1 > k2 {
-			return k1
-		} else {
-			return k2
-		}
-
-	case OREAL, OIMAG:
-		return CTFLT
-
-	case OCOMPLEX:
-		return CTCPLX
-
-	case OADDSTR:
-		return CTSTR
-
-	case OANDAND,
-		OEQ,
-		OGE,
-		OGT,
-		OLE,
-		OLT,
-		ONE,
-		ONOT,
-		OOROR:
-		return CTBOOL
-
-		// shifts (beware!).
-	case OLSH, ORSH:
-		return idealkind(n.Left)
-	}
-}
-
 // defaultlit on both nodes simultaneously;
 // if they're both ideal going in they better
 // get the same type going out.
@@ -1152,32 +1089,57 @@
 		return l, r
 	}
 
-	k := idealkind(l)
-	if rk := idealkind(r); rk > k {
-		k = rk
+	nn := l
+	if ctype(r.Type) > ctype(l.Type) {
+		nn = r
 	}
-	t := defaultType(k)
+
+	t := defaultType(nn.Type)
 	l = convlit(l, t)
 	r = convlit(r, t)
 	return l, r
 }
 
-func defaultType(k Ctype) *types.Type {
-	switch k {
-	case CTBOOL:
+func ctype(t *types.Type) Ctype {
+	switch t {
+	case types.Idealbool:
+		return CTBOOL
+	case types.Idealstring:
+		return CTSTR
+	case types.Idealint:
+		return CTINT
+	case types.Idealrune:
+		return CTRUNE
+	case types.Idealfloat:
+		return CTFLT
+	case types.Idealcomplex:
+		return CTCPLX
+	}
+	Fatalf("bad type %v", t)
+	panic("unreachable")
+}
+
+func defaultType(t *types.Type) *types.Type {
+	if !t.IsUntyped() {
+		return t
+	}
+
+	switch t {
+	case types.Idealbool:
 		return types.Types[TBOOL]
-	case CTSTR:
+	case types.Idealstring:
 		return types.Types[TSTRING]
-	case CTINT:
+	case types.Idealint:
 		return types.Types[TINT]
-	case CTRUNE:
+	case types.Idealrune:
 		return types.Runetype
-	case CTFLT:
+	case types.Idealfloat:
 		return types.Types[TFLOAT64]
-	case CTCPLX:
+	case types.Idealcomplex:
 		return types.Types[TCOMPLEX128]
 	}
-	Fatalf("bad idealkind: %v", k)
+
+	Fatalf("bad type %v", t)
 	return nil
 }
 
diff --git a/src/cmd/compile/internal/gc/typecheck.go b/src/cmd/compile/internal/gc/typecheck.go
index 834c1a8..274787a 100644
--- a/src/cmd/compile/internal/gc/typecheck.go
+++ b/src/cmd/compile/internal/gc/typecheck.go
@@ -623,6 +623,9 @@
 			// no defaultlit for left
 			// the outer context gives the type
 			n.Type = l.Type
+			if (l.Type == types.Idealfloat || l.Type == types.Idealcomplex) && r.Op == OLITERAL {
+				n.Type = types.Idealint
+			}
 
 			break
 		}
@@ -798,6 +801,20 @@
 		}
 
 		n.Type = t
+		if t.Etype == TIDEAL {
+			switch {
+			case l.Type == types.Idealcomplex || r.Type == types.Idealcomplex:
+				n.Type = types.Idealcomplex
+			case l.Type == types.Idealfloat || r.Type == types.Idealfloat:
+				n.Type = types.Idealfloat
+			case l.Type == types.Idealrune || r.Type == types.Idealrune:
+				n.Type = types.Idealrune
+			case l.Type == types.Idealint || r.Type == types.Idealint:
+				n.Type = types.Idealint
+			default:
+				Fatalf("bad untyped type: %v", t)
+			}
+		}
 
 	case OBITNOT, ONEG, ONOT, OPLUS:
 		ok |= ctxExpr
@@ -1678,7 +1695,7 @@
 		}
 		var why string
 		n.Op = convertop(n.Left.Op == OLITERAL, t, n.Type, &why)
-		if n.Op == 0 {
+		if n.Op == OXXX {
 			if !n.Diag() && !n.Type.Broke() && !n.Left.Diag() {
 				yyerror("cannot convert %L to type %v%s", n.Left, n.Type, why)
 				n.SetDiag(true)