go.exp/go/types: better error messages for failing shifts

When updating expression trees with the final type,
use the default type for untyped values since that
is the type of the values materialized at run-time.

As a result, error messages due to delayed operand
checking for non-constant untyped shift operands
become better (they refer to a materialized rather
an untyped type).

R=adonovan
CC=golang-dev
https://golang.org/cl/7842044
diff --git a/go/types/builtins.go b/go/types/builtins.go
index 220be08..0cfd2a2 100644
--- a/go/types/builtins.go
+++ b/go/types/builtins.go
@@ -173,9 +173,16 @@
 			goto Error
 		}
 
-		// arguments have final type
-		check.updateExprType(args[0], typ, true)
-		check.updateExprType(args[1], typ, true)
+		if x.mode != constant {
+			// The arguments have now their final types, which at run-
+			// time will be materialized. Update the expression trees.
+			// If the current types are untyped, the materialized type
+			// is the respective default type.
+			// (If the result is constant, the arguments are never
+			// materialized and there is nothing to do.)
+			check.updateExprType(args[0], defaultType(typ), true)
+			check.updateExprType(args[1], defaultType(typ), true)
+		}
 
 	case _Copy:
 		var y operand
diff --git a/go/types/conversions.go b/go/types/conversions.go
index f75568e..0f6dca1 100644
--- a/go/types/conversions.go
+++ b/go/types/conversions.go
@@ -60,7 +60,9 @@
 		x.mode = value
 	}
 
-	// the conversion argument types are final
+	// the conversion argument types are final; for now we just use x.typ
+	// TODO(gri) What should the type used here be? The spec is unclear.
+	//           See also disabled test cases in testdata/shifts.src, shifts8().
 	check.updateExprType(x.expr, x.typ, true)
 
 	check.conversions[conv] = true // for cap/len checking
diff --git a/go/types/expr.go b/go/types/expr.go
index 5ccd75f..7b9bedf 100644
--- a/go/types/expr.go
+++ b/go/types/expr.go
@@ -531,17 +531,20 @@
 
 	if x.mode == constant && y.mode == constant {
 		x.val = compareConst(x.val, y.val, op)
+		// The operands are never materialized; no need to update
+		// their types.
 	} else {
 		x.mode = value
+		// The operands have now their final types, which at run-
+		// time will be materialized. Update the expression trees.
+		// If the current types are untyped, the materialized type
+		// is the respective default type.
+		check.updateExprType(x.expr, defaultType(x.typ), true)
+		check.updateExprType(y.expr, defaultType(y.typ), true)
 	}
 
-	// The result type of a comparison is always boolean and
-	// independent of the argument types. They have now their
-	// final types (untyped or typed): update the respective
-	// expression trees.
-	check.updateExprType(x.expr, x.typ, true)
-	check.updateExprType(y.expr, y.typ, true)
-
+	// spec: "Comparison operators compare two operands and yield
+	//        an untyped boolean value."
 	x.typ = Typ[UntypedBool]
 }
 
diff --git a/go/types/testdata/shifts.src b/go/types/testdata/shifts.src
index 49496e5..c6d49e1 100644
--- a/go/types/testdata/shifts.src
+++ b/go/types/testdata/shifts.src
@@ -40,6 +40,8 @@
 		o = 1<<s == 2<<s   // 1 and 2 have type int; o == true if ints are 32bits in size
 		p = 1<<s == 1<<33  // illegal if ints are 32bits in size: 1 has type int, but 1<<33 overflows int
 		u = 1.0 /* ERROR "must be integer" */ <<s         // illegal: 1.0 has type float64, cannot shift
+		u1 = 1.0 /* ERROR "must be integer" */ <<s != 0   // illegal: 1.0 has type float64, cannot shift
+		u2 = 1 /* ERROR "must be integer" */ <<s != 1.0   // illegal: 1 has type float64, cannot shift
 		v float32 = 1 /* ERROR "must be integer" */ <<s   // illegal: 1 has type float32, cannot shift
 		w int64 = 1.0<<33  // 1.0<<33 is a constant shift expression
 	)
@@ -195,6 +197,31 @@
 }
 
 func shifts8() {
+	// shift examples from shift discussion: better error messages
+	var s uint
+	_ = 1.0 /* ERROR "shifted operand 1.0 \(type float64\) must be integer" */ <<s == 1
+	_ = 1.0 /* ERROR "shifted operand 1.0 \(type float64\) must be integer" */ <<s == 1.0
+	_ = 1 /* ERROR "shifted operand 1 \(type float64\) must be integer" */ <<s == 1.0
+	_ = 1 /* ERROR "shifted operand 1 \(type float64\) must be integer" */ <<s + 1.0 == 1
+	_ = 1 /* ERROR "shifted operand 1 \(type float64\) must be integer" */ <<s + 1.1 == 1
+	_ = 1 /* ERROR "shifted operand 1 \(type float64\) must be integer" */ <<s + 1 == 1.0
+
+	// additional cases
+	_ = complex(1.0 /* ERROR "shifted operand 1.0 \(type float64\) must be integer" */ <<s, 1)
+	_ = complex(1.0, 1 /* ERROR "shifted operand 1 \(type float64\) must be integer" */ <<s)
+
+	// TODO(gri): enable tests using conversions (the spec is unclear)
+	// _ = int(1.<<s)
+	// _ = int(1.1<<s)
+	// _ = float32(1<<s)
+	// _ = float32(1.<<s)
+	// _ = float32(1.1<<s)
+	// _ = complex64(1<<s)
+	// _ = complex64(1.<<s)
+	// _ = complex64(1.1<<s)
+}
+
+func shifts9() {
 	// various originally failing snippets of code from the std library
 	// from src/pkg/compress/lzw/reader.go:90
 	{