go/types: correct result type for append (bug fix)

Rewrote existing code to prevent similar mistakes.

R=adonovan
CC=golang-dev
https://golang.org/cl/7129046
diff --git a/src/pkg/go/types/builtins.go b/src/pkg/go/types/builtins.go
index aabb2e66..3875a3c 100644
--- a/src/pkg/go/types/builtins.go
+++ b/src/pkg/go/types/builtins.go
@@ -21,8 +21,7 @@
 	id := bin.id
 
 	// declare before goto's
-	var arg0 ast.Expr
-	var typ0 Type
+	var arg0 ast.Expr // first argument, if present
 
 	// check argument count
 	n := len(args)
@@ -42,31 +41,24 @@
 	if n > 0 {
 		arg0 = args[0]
 		switch id {
-		case _Make, _New:
-			// argument must be a type
-			typ0 = check.typ(arg0, false)
-			if typ0 == Typ[Invalid] {
-				goto Error
-			}
-		case _Trace:
-			// _Trace implementation does the work
+		case _Make, _New, _Trace:
+			// respective cases below do the work
 		default:
 			// argument must be an expression
 			check.expr(x, arg0, nil, iota)
 			if x.mode == invalid {
 				goto Error
 			}
-			typ0 = underlying(x.typ)
 		}
 	}
 
 	switch id {
 	case _Append:
-		s, ok := typ0.(*Slice)
-		if !ok {
+		if _, ok := underlying(x.typ).(*Slice); !ok {
 			check.invalidArg(x.pos(), "%s is not a typed slice", x)
 			goto Error
 		}
+		resultTyp := x.typ
 		for _, arg := range args[1:] {
 			check.expr(x, arg, nil, iota)
 			if x.mode == invalid {
@@ -75,12 +67,12 @@
 			// TODO(gri) check assignability
 		}
 		x.mode = value
-		x.typ = s
+		x.typ = resultTyp
 
 	case _Cap, _Len:
 		mode := invalid
 		var val interface{}
-		switch typ := implicitDeref(typ0).(type) {
+		switch typ := implicitDeref(underlying(x.typ)).(type) {
 		case *Basic:
 			if isString(typ) && id == _Len {
 				if x.mode == constant {
@@ -116,7 +108,7 @@
 		x.val = val
 
 	case _Close:
-		ch, ok := typ0.(*Chan)
+		ch, ok := underlying(x.typ).(*Chan)
 		if !ok {
 			check.invalidArg(x.pos(), "%s is not a channel", x)
 			goto Error
@@ -182,7 +174,7 @@
 		}
 
 		var dst, src Type
-		if t, ok := typ0.(*Slice); ok {
+		if t, ok := underlying(x.typ).(*Slice); ok {
 			dst = t.Elt
 		}
 		switch t := underlying(y.typ).(type) {
@@ -208,7 +200,7 @@
 		x.typ = Typ[Int]
 
 	case _Delete:
-		m, ok := typ0.(*Map)
+		m, ok := underlying(x.typ).(*Map)
 		if !ok {
 			check.invalidArg(x.pos(), "%s is not a map", x)
 			goto Error
@@ -224,7 +216,7 @@
 		x.mode = novalue
 
 	case _Imag, _Real:
-		if !isComplex(typ0) {
+		if !isComplex(x.typ) {
 			check.invalidArg(x.pos(), "%s must be a complex number", x)
 			goto Error
 		}
@@ -242,7 +234,7 @@
 			x.mode = value
 		}
 		k := Invalid
-		switch typ0.(*Basic).Kind {
+		switch underlying(x.typ).(*Basic).Kind {
 		case Complex64:
 			k = Float32
 		case Complex128:
@@ -255,8 +247,12 @@
 		x.typ = Typ[k]
 
 	case _Make:
+		resultTyp := check.typ(arg0, false)
+		if resultTyp == Typ[Invalid] {
+			goto Error
+		}
 		var min int // minimum number of arguments
-		switch underlying(typ0).(type) {
+		switch underlying(resultTyp).(type) {
 		case *Slice:
 			min = 2
 		case *Map, *Chan:
@@ -291,11 +287,15 @@
 			// safe to continue
 		}
 		x.mode = variable
-		x.typ = typ0
+		x.typ = resultTyp
 
 	case _New:
+		resultTyp := check.typ(arg0, false)
+		if resultTyp == Typ[Invalid] {
+			goto Error
+		}
 		x.mode = variable
-		x.typ = &Pointer{Base: typ0}
+		x.typ = &Pointer{Base: resultTyp}
 
 	case _Panic, _Print, _Println:
 		for _, arg := range args[1:] {
@@ -329,14 +329,14 @@
 
 	case _Sizeof:
 		x.mode = constant
+		x.val = sizeof(check.ctxt, x.typ)
 		x.typ = Typ[Uintptr]
-		x.val = sizeof(check.ctxt, typ0)
 
 	case _Assert:
 		// assert(pred) causes a typechecker error if pred is false.
 		// The result of assert is the value of pred if there is no error.
 		// Note: assert is only available in self-test mode.
-		if x.mode != constant || !isBoolean(typ0) {
+		if x.mode != constant || !isBoolean(x.typ) {
 			check.invalidArg(x.pos(), "%s is not a boolean constant", x)
 			goto Error
 		}