cmd/compile: add Key, FieldSlice, and SetFields helpers

Allows safely eliminating more direct uses of Type's Type and Down
fields.

Passes toolstash -cmp.

Change-Id: I5c17fe541a0473c3cd2978d8314c4ab759079a61
Reviewed-on: https://go-review.googlesource.com/20541
Run-TryBot: Matthew Dempsky <mdempsky@google.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
diff --git a/src/cmd/compile/internal/gc/align.go b/src/cmd/compile/internal/gc/align.go
index 2dc3f41..cabb0a9 100644
--- a/src/cmd/compile/internal/gc/align.go
+++ b/src/cmd/compile/internal/gc/align.go
@@ -223,7 +223,7 @@
 		w = int64(Widthptr)
 
 		checkwidth(t.Type)
-		checkwidth(t.Down)
+		checkwidth(t.Key())
 
 	case TFORW: // should have been filled in
 		if !t.Broke {
diff --git a/src/cmd/compile/internal/gc/bexport.go b/src/cmd/compile/internal/gc/bexport.go
index 6bb14de..67b0f97 100644
--- a/src/cmd/compile/internal/gc/bexport.go
+++ b/src/cmd/compile/internal/gc/bexport.go
@@ -534,8 +534,8 @@
 
 	case TMAP:
 		p.tag(mapTag)
-		p.typ(t.Down) // key
-		p.typ(t.Type) // val
+		p.typ(t.Key()) // key
+		p.typ(t.Type)  // val
 
 	case TCHAN:
 		p.tag(chanTag)
diff --git a/src/cmd/compile/internal/gc/dcl.go b/src/cmd/compile/internal/gc/dcl.go
index 6f02914..8c9906c 100644
--- a/src/cmd/compile/internal/gc/dcl.go
+++ b/src/cmd/compile/internal/gc/dcl.go
@@ -827,12 +827,11 @@
 		Fatalf("struct expected")
 	}
 
-	tp := &t.Type
+	var fields []*Type
 	for _, n := range l {
-		f := structfield(n)
-		*tp = f
-		tp = &f.Down
+		fields = append(fields, structfield(n))
 	}
+	t.SetFields(fields)
 
 	for f, it := IterFields(t); f != nil && !t.Broke; f = it.Next() {
 		if f.Broke {
@@ -849,14 +848,12 @@
 }
 
 func tofunargs(l []*Node) *Type {
-	var f *Type
-
 	t := typ(TSTRUCT)
 	t.Funarg = true
 
-	tp := &t.Type
+	var fields []*Type
 	for _, n := range l {
-		f = structfield(n)
+		f := structfield(n)
 		f.Funarg = true
 
 		// esc.go needs to find f given a PPARAM to add the tag.
@@ -864,9 +861,9 @@
 			n.Left.Name.Param.Field = f
 		}
 
-		*tp = f
-		tp = &f.Down
+		fields = append(fields, f)
 	}
+	t.SetFields(fields)
 
 	for f, it := IterFields(t); f != nil && !t.Broke; f = it.Next() {
 		if f.Broke {
@@ -955,7 +952,7 @@
 		Fatalf("interface expected")
 	}
 
-	tp := &t.Type
+	var fields []*Type
 	for _, n := range l {
 		f := interfacefield(n)
 
@@ -969,14 +966,13 @@
 				if f.Sym != nil {
 					f.Nname = newname(f.Sym)
 				}
-				*tp = f
-				tp = &f.Down
+				fields = append(fields, f)
 			}
 		} else {
-			*tp = f
-			tp = &f.Down
+			fields = append(fields, f)
 		}
 	}
+	t.SetFields(fields)
 
 	for f, it := IterFields(t); f != nil && !t.Broke; f = it.Next() {
 		if f.Broke {
diff --git a/src/cmd/compile/internal/gc/fmt.go b/src/cmd/compile/internal/gc/fmt.go
index 6d7a50a..4597ceb 100644
--- a/src/cmd/compile/internal/gc/fmt.go
+++ b/src/cmd/compile/internal/gc/fmt.go
@@ -580,7 +580,7 @@
 		return fmt.Sprintf("chan %v", t.Type)
 
 	case TMAP:
-		return fmt.Sprintf("map[%v]%v", t.Down, t.Type)
+		return fmt.Sprintf("map[%v]%v", t.Key(), t.Type)
 
 	case TINTER:
 		var buf bytes.Buffer
@@ -645,15 +645,15 @@
 			// Format the bucket struct for map[x]y as map.bucket[x]y.
 			// This avoids a recursive print that generates very long names.
 			if t.Map.Bucket == t {
-				return fmt.Sprintf("map.bucket[%v]%v", t.Map.Down, t.Map.Type)
+				return fmt.Sprintf("map.bucket[%v]%v", t.Map.Key(), t.Map.Type)
 			}
 
 			if t.Map.Hmap == t {
-				return fmt.Sprintf("map.hdr[%v]%v", t.Map.Down, t.Map.Type)
+				return fmt.Sprintf("map.hdr[%v]%v", t.Map.Key(), t.Map.Type)
 			}
 
 			if t.Map.Hiter == t {
-				return fmt.Sprintf("map.iter[%v]%v", t.Map.Down, t.Map.Type)
+				return fmt.Sprintf("map.iter[%v]%v", t.Map.Key(), t.Map.Type)
 			}
 
 			Yyerror("unknown internal map type")
diff --git a/src/cmd/compile/internal/gc/range.go b/src/cmd/compile/internal/gc/range.go
index d4df16b..1459b7a 100644
--- a/src/cmd/compile/internal/gc/range.go
+++ b/src/cmd/compile/internal/gc/range.go
@@ -56,7 +56,7 @@
 		t2 = t.Type
 
 	case TMAP:
-		t1 = t.Down
+		t1 = t.Key()
 		t2 = t.Type
 
 	case TCHAN:
@@ -228,12 +228,12 @@
 		hit := prealloc[n]
 		hit.Type = th
 		n.Left = nil
-		keyname := newname(th.Type.Sym)      // depends on layout of iterator struct.  See reflect.go:hiter
-		valname := newname(th.Type.Down.Sym) // ditto
+		keyname := newname(th.Field(0).Sym) // depends on layout of iterator struct.  See reflect.go:hiter
+		valname := newname(th.Field(1).Sym) // ditto
 
 		fn := syslook("mapiterinit")
 
-		substArgTypes(&fn, t.Down, t.Type, th)
+		substArgTypes(&fn, t.Key(), t.Type, th)
 		init = append(init, mkcall1(fn, nil, nil, typename(t), ha, Nod(OADDR, hit, nil)))
 		n.Left = Nod(ONE, Nod(ODOT, hit, keyname), nodnil())
 
diff --git a/src/cmd/compile/internal/gc/reflect.go b/src/cmd/compile/internal/gc/reflect.go
index 306f7c7..b9cc215 100644
--- a/src/cmd/compile/internal/gc/reflect.go
+++ b/src/cmd/compile/internal/gc/reflect.go
@@ -75,7 +75,7 @@
 	}
 
 	bucket := typ(TSTRUCT)
-	keytype := t.Down
+	keytype := t.Key()
 	valtype := t.Type
 	dowidth(keytype)
 	dowidth(valtype)
@@ -119,7 +119,7 @@
 	// so if the struct needs 64-bit padding (because a key or value does)
 	// then it would end with an extra 32-bit padding field.
 	// Preempt that by emitting the padding here.
-	if int(t.Type.Align) > Widthptr || int(t.Down.Align) > Widthptr {
+	if int(t.Type.Align) > Widthptr || int(t.Key().Align) > Widthptr {
 		field = append(field, makefield("pad", Types[TUINTPTR]))
 	}
 
@@ -130,7 +130,7 @@
 	// the type of the overflow field to uintptr in this case.
 	// See comment on hmap.overflow in ../../../../runtime/hashmap.go.
 	otyp := Ptrto(bucket)
-	if !haspointers(t.Type) && !haspointers(t.Down) && t.Type.Width <= MAXKEYSIZE && t.Down.Width <= MAXVALSIZE {
+	if !haspointers(t.Type) && !haspointers(t.Key()) && t.Type.Width <= MAXVALSIZE && t.Key().Width <= MAXKEYSIZE {
 		otyp = Types[TUINTPTR]
 	}
 	ovf := makefield("overflow", otyp)
@@ -139,11 +139,7 @@
 	// link up fields
 	bucket.Noalg = true
 	bucket.Local = t.Local
-	bucket.Type = field[0]
-	for n := int32(0); n < int32(len(field)-1); n++ {
-		field[n].Down = field[n+1]
-	}
-	field[len(field)-1].Down = nil
+	bucket.SetFields(field[:])
 	dowidth(bucket)
 
 	// Double-check that overflow field is final memory in struct,
@@ -179,11 +175,7 @@
 	h := typ(TSTRUCT)
 	h.Noalg = true
 	h.Local = t.Local
-	h.Type = field[0]
-	for n := int32(0); n < int32(len(field)-1); n++ {
-		field[n].Down = field[n+1]
-	}
-	field[len(field)-1].Down = nil
+	h.SetFields(field[:])
 	dowidth(h)
 	t.Hmap = h
 	h.Map = t
@@ -212,8 +204,7 @@
 	// }
 	// must match ../../../../runtime/hashmap.go:hiter.
 	var field [12]*Type
-	field[0] = makefield("key", Ptrto(t.Down))
-
+	field[0] = makefield("key", Ptrto(t.Key()))
 	field[1] = makefield("val", Ptrto(t.Type))
 	field[2] = makefield("t", Ptrto(Types[TUINT8]))
 	field[3] = makefield("h", Ptrto(hmap(t)))
@@ -228,13 +219,8 @@
 
 	// build iterator struct holding the above fields
 	i := typ(TSTRUCT)
-
 	i.Noalg = true
-	i.Type = field[0]
-	for n := int32(0); n < int32(len(field)-1); n++ {
-		field[n].Down = field[n+1]
-	}
-	field[len(field)-1].Down = nil
+	i.SetFields(field[:])
 	dowidth(i)
 	if i.Width != int64(12*Widthptr) {
 		Yyerror("hash_iter size not correct %d %d", i.Width, 12*Widthptr)
@@ -1124,8 +1110,7 @@
 
 	// ../../../../runtime/type.go:/mapType
 	case TMAP:
-		s1 := dtypesym(t.Down)
-
+		s1 := dtypesym(t.Key())
 		s2 := dtypesym(t.Type)
 		s3 := dtypesym(mapbucket(t))
 		s4 := dtypesym(hmap(t))
@@ -1134,11 +1119,11 @@
 		ot = dsymptr(s, ot, s2, 0)
 		ot = dsymptr(s, ot, s3, 0)
 		ot = dsymptr(s, ot, s4, 0)
-		if t.Down.Width > MAXKEYSIZE {
+		if t.Key().Width > MAXKEYSIZE {
 			ot = duint8(s, ot, uint8(Widthptr))
 			ot = duint8(s, ot, 1) // indirect
 		} else {
-			ot = duint8(s, ot, uint8(t.Down.Width))
+			ot = duint8(s, ot, uint8(t.Key().Width))
 			ot = duint8(s, ot, 0) // not indirect
 		}
 
@@ -1151,8 +1136,8 @@
 		}
 
 		ot = duint16(s, ot, uint16(mapbucket(t).Width))
-		ot = duint8(s, ot, uint8(obj.Bool2int(isreflexive(t.Down))))
-		ot = duint8(s, ot, uint8(obj.Bool2int(needkeyupdate(t.Down))))
+		ot = duint8(s, ot, uint8(obj.Bool2int(isreflexive(t.Key()))))
+		ot = duint8(s, ot, uint8(obj.Bool2int(needkeyupdate(t.Key()))))
 		ot = dextratype(s, ot, t, 0)
 
 	case TPTR32, TPTR64:
diff --git a/src/cmd/compile/internal/gc/sinit.go b/src/cmd/compile/internal/gc/sinit.go
index 6edfe53..3b0d269 100644
--- a/src/cmd/compile/internal/gc/sinit.go
+++ b/src/cmd/compile/internal/gc/sinit.go
@@ -979,7 +979,7 @@
 		// build list of var[c] = expr.
 		// use temporary so that mapassign1 can have addressable key, val.
 		if key == nil {
-			key = temp(var_.Type.Down)
+			key = temp(var_.Type.Key())
 			val = temp(var_.Type.Type)
 		}
 
diff --git a/src/cmd/compile/internal/gc/subr.go b/src/cmd/compile/internal/gc/subr.go
index 6c68165..96fca94 100644
--- a/src/cmd/compile/internal/gc/subr.go
+++ b/src/cmd/compile/internal/gc/subr.go
@@ -417,23 +417,9 @@
 }
 
 func sortinter(t *Type) *Type {
-	if t.Type == nil || t.Type.Down == nil {
-		return t
-	}
-
-	var a []*Type
-	for f, it := IterFields(t); f != nil; f = it.Next() {
-		a = append(a, f)
-	}
-	sort.Sort(methcmp(a))
-
-	n := len(a) // n > 0 due to initial conditions.
-	for i := 0; i < n-1; i++ {
-		a[i].Down = a[i+1]
-	}
-	a[n-1].Down = nil
-
-	t.Type = a[0]
+	s := t.FieldSlice()
+	sort.Sort(methcmp(s))
+	t.SetFields(s)
 	return t
 }
 
@@ -740,12 +726,9 @@
 
 	switch t1.Etype {
 	case TINTER, TSTRUCT:
-		t1 = t1.Type
-		t2 = t2.Type
-		for ; t1 != nil && t2 != nil; t1, t2 = t1.Down, t2.Down {
-			if t1.Etype != TFIELD || t2.Etype != TFIELD {
-				Fatalf("struct/interface missing field: %v %v", t1, t2)
-			}
+		t1, i1 := IterFields(t1)
+		t2, i2 := IterFields(t2)
+		for ; t1 != nil && t2 != nil; t1, t2 = i1.Next(), i2.Next() {
 			if t1.Sym != t2.Sym || t1.Embedded != t2.Embedded || !eqtype1(t1.Type, t2.Type, assumedEqual) || !eqnote(t1.Note, t2.Note) {
 				return false
 			}
@@ -782,9 +765,14 @@
 		if t1.Chan != t2.Chan {
 			return false
 		}
+
+	case TMAP:
+		if !eqtype1(t1.Key(), t2.Key(), assumedEqual) {
+			return false
+		}
 	}
 
-	return eqtype1(t1.Down, t2.Down, assumedEqual) && eqtype1(t1.Type, t2.Type, assumedEqual)
+	return eqtype1(t1.Type, t2.Type, assumedEqual)
 }
 
 // Are t1 and t2 equal struct types when field names are ignored?
@@ -795,8 +783,8 @@
 		return false
 	}
 
-	t1 = t1.Type
-	t2 = t2.Type
+	t1, i1 := IterFields(t1)
+	t2, i2 := IterFields(t2)
 	for {
 		if !Eqtype(t1, t2) {
 			return false
@@ -804,8 +792,8 @@
 		if t1 == nil {
 			return true
 		}
-		t1 = t1.Down
-		t2 = t2.Down
+		t1 = i1.Next()
+		t2 = i2.Next()
 	}
 }
 
@@ -2635,13 +2623,13 @@
 		TUNSAFEPTR:
 		return true
 
-		// Array of 1 direct iface type can be direct.
 	case TARRAY:
+		// Array of 1 direct iface type can be direct.
 		return t.Bound == 1 && isdirectiface(t.Type)
 
-		// Struct with 1 field of direct iface type can be direct.
 	case TSTRUCT:
-		return t.Type != nil && t.Type.Down == nil && isdirectiface(t.Type.Type)
+		// Struct with 1 field of direct iface type can be direct.
+		return countfield(t) == 1 && isdirectiface(t.Field(0).Type)
 	}
 
 	return false
diff --git a/src/cmd/compile/internal/gc/type.go b/src/cmd/compile/internal/gc/type.go
index ec06407..e5e12f0 100644
--- a/src/cmd/compile/internal/gc/type.go
+++ b/src/cmd/compile/internal/gc/type.go
@@ -274,6 +274,12 @@
 	(*Type).Recvs, (*Type).Params, (*Type).Results,
 }
 
+// Key returns the key type of map type t.
+func (t *Type) Key() *Type {
+	t.wantEtype(TMAP)
+	return t.Down
+}
+
 // Field returns the i'th field/method of struct/interface type t.
 func (t *Type) Field(i int) *Type {
 	// TODO: store fields in a slice so we can
@@ -294,6 +300,29 @@
 	panic("not enough fields")
 }
 
+// FieldSlice returns a slice of containing all fields/methods of
+// struct/interface type t.
+func (t *Type) FieldSlice() []*Type {
+	var s []*Type
+	for f, it := IterFields(t); f != nil; f = it.Next() {
+		s = append(s, f)
+	}
+	return s
+}
+
+// SetFields sets struct/interface type t's fields/methods to fields.
+func (t *Type) SetFields(fields []*Type) {
+	if t.Etype != TSTRUCT && t.Etype != TINTER {
+		Fatalf("SetFields: type %v does not have fields", t)
+	}
+	var next *Type
+	for i := len(fields) - 1; i >= 0; i-- {
+		fields[i].Down = next
+		next = fields[i]
+	}
+	t.Type = next
+}
+
 func (t *Type) Size() int64 {
 	dowidth(t)
 	return t.Width
diff --git a/src/cmd/compile/internal/gc/typecheck.go b/src/cmd/compile/internal/gc/typecheck.go
index fe2560e..7840878 100644
--- a/src/cmd/compile/internal/gc/typecheck.go
+++ b/src/cmd/compile/internal/gc/typecheck.go
@@ -1021,9 +1021,9 @@
 
 		case TMAP:
 			n.Etype = 0
-			defaultlit(&n.Right, t.Down)
+			defaultlit(&n.Right, t.Key())
 			if n.Right.Type != nil {
-				n.Right = assignconv(n.Right, t.Down, "map index")
+				n.Right = assignconv(n.Right, t.Key(), "map index")
 			}
 			n.Type = t.Type
 			n.Op = OINDEXMAP
@@ -1460,9 +1460,9 @@
 				return
 			}
 
-			t = n.List.First().Type.Type
-			l = t.Nname
-			r = t.Down.Nname
+			t = n.List.First().Type
+			l = t.Field(0).Nname
+			r = t.Field(1).Nname
 		} else {
 			if !twoarg(n) {
 				n.Type = nil
@@ -1575,7 +1575,7 @@
 			return
 		}
 
-		args.SetIndex(1, assignconv(r, l.Type.Down, "delete"))
+		args.SetIndex(1, assignconv(r, l.Type.Key(), "delete"))
 		break OpSwitch
 
 	case OAPPEND:
@@ -3028,10 +3028,10 @@
 			}
 
 			r = l.Left
-			pushtype(r, t.Down)
+			pushtype(r, t.Key())
 			typecheck(&r, Erv)
-			defaultlit(&r, t.Down)
-			l.Left = assignconv(r, t.Down, "map key")
+			defaultlit(&r, t.Key())
+			l.Left = assignconv(r, t.Key(), "map key")
 			if l.Left.Op != OCONV {
 				keydup(l.Left, hash)
 			}
diff --git a/src/cmd/compile/internal/gc/unsafe.go b/src/cmd/compile/internal/gc/unsafe.go
index 99e0ac8..7cac851 100644
--- a/src/cmd/compile/internal/gc/unsafe.go
+++ b/src/cmd/compile/internal/gc/unsafe.go
@@ -104,19 +104,21 @@
 			goto bad
 		}
 
+		var f [2]*Type
+		f[0] = typ(TFIELD)
+		f[0].Type = Types[TUINT8]
+		f[1] = typ(TFIELD)
+		f[1].Type = tr
+
 		// make struct { byte; T; }
 		t := typ(TSTRUCT)
-
-		t.Type = typ(TFIELD)
-		t.Type.Type = Types[TUINT8]
-		t.Type.Down = typ(TFIELD)
-		t.Type.Down.Type = tr
+		t.SetFields(f[:])
 
 		// compute struct widths
 		dowidth(t)
 
 		// the offset of T is its required alignment
-		v = t.Type.Down.Width
+		v = t.Field(1).Width
 
 		goto yes
 	}
diff --git a/src/cmd/compile/internal/gc/walk.go b/src/cmd/compile/internal/gc/walk.go
index 3c397df..be0d5ff 100644
--- a/src/cmd/compile/internal/gc/walk.go
+++ b/src/cmd/compile/internal/gc/walk.go
@@ -840,7 +840,7 @@
 		t := r.Left.Type
 		p := ""
 		if t.Type.Width <= 128 { // Check ../../runtime/hashmap.go:maxValueSize before changing.
-			switch algtype(t.Down) {
+			switch algtype(t.Key()) {
 			case AMEM32:
 				p = "mapaccess2_fast32"
 			case AMEM64:
@@ -876,7 +876,7 @@
 		// the boolean result of i.(T) is now untyped so we make it the
 		// same type as the variable on the lhs.
 		if !isblank(n.List.Second()) {
-			r.Type.Type.Down.Type = n.List.Second().Type
+			r.Type.Field(1).Type = n.List.Second().Type
 		}
 		n.Rlist.Set1(r)
 		n.Op = OAS2FUNC
@@ -1247,7 +1247,7 @@
 		t := n.Left.Type
 		p := ""
 		if t.Type.Width <= 128 { // Check ../../runtime/hashmap.go:maxValueSize before changing.
-			switch algtype(t.Down) {
+			switch algtype(t.Key()) {
 			case AMEM32:
 				p = "mapaccess1_fast32"
 			case AMEM64:
@@ -1439,7 +1439,7 @@
 		}
 
 		fn := syslook("makemap")
-		substArgTypes(&fn, hmap(t), mapbucket(t), t.Down, t.Type)
+		substArgTypes(&fn, hmap(t), mapbucket(t), t.Key(), t.Type)
 		n = mkcall1(fn, n.Type, init, typename(n.Type), conv(n.Left, Types[TINT64]), a, r)
 
 	case OMAKESLICE:
@@ -2690,7 +2690,7 @@
 		Fatalf("mapfn %v", t)
 	}
 	fn := syslook(name)
-	substArgTypes(&fn, t.Down, t.Type, t.Down, t.Type)
+	substArgTypes(&fn, t.Key(), t.Type, t.Key(), t.Type)
 	return fn
 }
 
@@ -2699,7 +2699,7 @@
 		Fatalf("mapfn %v", t)
 	}
 	fn := syslook(name)
-	substArgTypes(&fn, t.Down, t.Type, t.Down)
+	substArgTypes(&fn, t.Key(), t.Type, t.Key())
 	return fn
 }