cmd/compile: add Type.Elem

This removes almost all direct access to
Type’s heavily overloaded Type field.

Mostly generated by eg, manually checked.

Significant manual changes:

* reflect.go's typPkg used Type indiscriminately.
  Use it only for specific etypes.
* gen.go's visitComponents contained a usage of Type
  with structs. Using Type for structs no longer
  occurs, and the Fatal contained therein has not triggered,
  so it has been axed.
* Scary code in cgen.go's cgen_slice is now explicitly scary.

Passes toolstash -cmp.

Change-Id: I2dbfb3c959da7ae239f964d83898c204affcabc6
Reviewed-on: https://go-review.googlesource.com/21331
Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
Run-TryBot: Josh Bleecher Snyder <josharian@gmail.com>
Reviewed-by: Matthew Dempsky <mdempsky@google.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
diff --git a/src/cmd/compile/internal/gc/alg.go b/src/cmd/compile/internal/gc/alg.go
index ac51561..a017d9c 100644
--- a/src/cmd/compile/internal/gc/alg.go
+++ b/src/cmd/compile/internal/gc/alg.go
@@ -106,7 +106,7 @@
 			return ANOEQ
 		}
 
-		a := algtype1(t.Type, bad)
+		a := algtype1(t.Elem(), bad)
 		switch a {
 		case AMEM:
 			return AMEM
@@ -203,7 +203,7 @@
 		// An array of pure memory would be handled by the
 		// standard algorithm, so the element type must not be
 		// pure memory.
-		hashel := hashfor(t.Type)
+		hashel := hashfor(t.Elem())
 
 		n := Nod(ORANGE, nil, Nod(OIND, np, nil))
 		ni := newname(Lookup("i"))
@@ -519,7 +519,7 @@
 	nx = typecheck(nx, Erv)
 	ny = typecheck(ny, Erv)
 
-	fn, needsize := eqmemfunc(size, nx.Type.Type)
+	fn, needsize := eqmemfunc(size, nx.Type.Elem())
 	call := Nod(OCALL, fn, nil)
 	call.List.Append(nx)
 	call.List.Append(ny)
diff --git a/src/cmd/compile/internal/gc/align.go b/src/cmd/compile/internal/gc/align.go
index 351ca73..fd3fe0d 100644
--- a/src/cmd/compile/internal/gc/align.go
+++ b/src/cmd/compile/internal/gc/align.go
@@ -176,11 +176,11 @@
 
 	case TPTR32:
 		w = 4
-		checkwidth(t.Type)
+		checkwidth(t.Elem())
 
 	case TPTR64:
 		w = 8
-		checkwidth(t.Type)
+		checkwidth(t.Elem())
 
 	case TUNSAFEPTR:
 		w = int64(Widthptr)
@@ -194,7 +194,7 @@
 	case TCHAN: // implemented as pointer
 		w = int64(Widthptr)
 
-		checkwidth(t.Type)
+		checkwidth(t.Elem())
 
 		// make fake type to check later to
 		// trigger channel argument check.
@@ -204,7 +204,7 @@
 	case TCHANARGS:
 		t1 := t.Wrapped()
 		dowidth(t1) // just in case
-		if t1.Type.Width >= 1<<16 {
+		if t1.Elem().Width >= 1<<16 {
 			Yyerror("channel element type too large (>64kB)")
 		}
 		t.Width = 1
@@ -235,23 +235,23 @@
 		t.Align = uint8(Widthptr)
 
 	case TARRAY:
-		if t.Type == nil {
+		if t.Elem() == nil {
 			break
 		}
 		if t.IsArray() {
-			dowidth(t.Type)
-			if t.Type.Width != 0 {
-				cap := (uint64(Thearch.MAXWIDTH) - 1) / uint64(t.Type.Width)
+			dowidth(t.Elem())
+			if t.Elem().Width != 0 {
+				cap := (uint64(Thearch.MAXWIDTH) - 1) / uint64(t.Elem().Width)
 				if uint64(t.Bound) > cap {
 					Yyerror("type %v larger than address space", Tconv(t, FmtLong))
 				}
 			}
 
-			w = t.Bound * t.Type.Width
-			t.Align = t.Type.Align
+			w = t.Bound * t.Elem().Width
+			t.Align = t.Elem().Align
 		} else if t.Bound == -1 {
 			w = int64(sizeof_Array)
-			checkwidth(t.Type)
+			checkwidth(t.Elem())
 			t.Align = uint8(Widthptr)
 		} else if t.isDDDArray() {
 			if !t.Broke {
diff --git a/src/cmd/compile/internal/gc/bexport.go b/src/cmd/compile/internal/gc/bexport.go
index f14f12f..24537ac 100644
--- a/src/cmd/compile/internal/gc/bexport.go
+++ b/src/cmd/compile/internal/gc/bexport.go
@@ -512,7 +512,7 @@
 		} else {
 			p.tag(sliceTag)
 		}
-		p.typ(t.Type)
+		p.typ(t.Elem())
 
 	case TDDDFIELD:
 		// see p.param use of TDDDFIELD
@@ -525,7 +525,7 @@
 
 	case TPTR32, TPTR64: // could use Tptr but these are constants
 		p.tag(pointerTag)
-		p.typ(t.Type)
+		p.typ(t.Elem())
 
 	case TFUNC:
 		p.tag(signatureTag)
@@ -548,7 +548,7 @@
 	case TCHAN:
 		p.tag(chanTag)
 		p.int(int(t.Chan))
-		p.typ(t.Type)
+		p.typ(t.Elem())
 
 	default:
 		Fatalf("exporter: unexpected type: %s (Etype = %d)", Tconv(t, 0), t.Etype)
@@ -636,7 +636,7 @@
 func basetypeName(t *Type) string {
 	s := t.Sym
 	if s == nil && Isptr[t.Etype] {
-		s = t.Type.Sym // deref
+		s = t.Elem().Sym // deref
 	}
 	if s != nil {
 		return s.Name
@@ -666,7 +666,7 @@
 	t := q.Type
 	if q.Isddd {
 		// create a fake type to encode ... just for the p.typ call
-		t = typWrapper(TDDDFIELD, t.Type)
+		t = typWrapper(TDDDFIELD, t.Elem())
 	}
 	p.typ(t)
 	if n > 0 {
diff --git a/src/cmd/compile/internal/gc/cgen.go b/src/cmd/compile/internal/gc/cgen.go
index f6dda21..2effc42 100644
--- a/src/cmd/compile/internal/gc/cgen.go
+++ b/src/cmd/compile/internal/gc/cgen.go
@@ -2214,14 +2214,14 @@
 			return off
 		}
 		if Isconst(n.Right, CTINT) {
-			return off + t.Type.Width*n.Right.Val().U.(*Mpint).Int64()
+			return off + t.Elem().Width*n.Right.Val().U.(*Mpint).Int64()
 		}
 		return +1000 // on stack but not sure exactly where
 
 	case OCALLMETH, OCALLINTER, OCALLFUNC:
 		t := n.Left.Type
 		if Isptr[t.Etype] {
-			t = t.Type
+			t = t.Elem()
 		}
 
 		f := t.Results().Field(0)
@@ -2552,7 +2552,7 @@
 func cgen_callret(n *Node, res *Node) {
 	t := n.Left.Type
 	if t.Etype == TPTR32 || t.Etype == TPTR64 {
-		t = t.Type
+		t = t.Elem()
 	}
 
 	fp := t.Results().Field(0)
@@ -2576,7 +2576,7 @@
 func cgen_aret(n *Node, res *Node) {
 	t := n.Left.Type
 	if Isptr[t.Etype] {
-		t = t.Type
+		t = t.Elem()
 	}
 
 	fp := t.Results().Field(0)
@@ -2865,7 +2865,7 @@
 	Regfree(&rlen)
 
 	fn := syslook("growslice")
-	fn = substArgTypes(fn, res.Type.Type, res.Type.Type)
+	fn = substArgTypes(fn, res.Type.Elem(), res.Type.Elem())
 	Ginscall(fn, 0)
 
 	if Widthptr == 4 && Widthreg == 8 {
@@ -2945,7 +2945,7 @@
 		if i > 0 {
 			Thearch.Gins(Thearch.Optoas(OADD, Types[TUINT]), Nodintconst(int64(i)), &r2)
 		}
-		w := res.Type.Type.Width
+		w := res.Type.Elem().Width
 		if Thearch.AddIndex != nil && Thearch.AddIndex(&r2, w, &r1) {
 			// r1 updated by back end
 		} else if w == 1 {
@@ -2957,7 +2957,7 @@
 		Regfree(&r2)
 
 		r1.Op = OINDREG
-		r1.Type = res.Type.Type
+		r1.Type = res.Type.Elem()
 		cgen_wb(n2, &r1, needwritebarrier(&r1, n2))
 		Regfree(&r1)
 		i++
@@ -3025,7 +3025,7 @@
 			return
 		}
 		if n.Op == OSLICEARR || n.Op == OSLICE3ARR {
-			Nodconst(&xlen, indexRegType, n.Left.Type.Type.Bound)
+			Nodconst(&xlen, indexRegType, n.Left.Type.Elem().Bound)
 			return
 		}
 		if n.Op == OSLICESTR && Isconst(n.Left, CTSTR) {
@@ -3183,7 +3183,7 @@
 	// The func obvious below checks for out-of-order constant indexes.
 	var bound int64 = -1
 	if n.Op == OSLICEARR || n.Op == OSLICE3ARR {
-		bound = n.Left.Type.Type.Bound
+		bound = n.Left.Type.Elem().Bound
 	} else if n.Op == OSLICESTR && Isconst(n.Left, CTSTR) {
 		bound = int64(len(n.Left.Val().U.(string)))
 	}
@@ -3467,7 +3467,17 @@
 			Cgenr(n.Left, &xbase, nil)
 			Cgen_checknil(&xbase)
 		} else {
-			regalloc(&xbase, Ptrto(res.Type.Type), nil)
+			var ptr *Type
+			if n.Op == OSLICESTR {
+				// Yikes! Ptrto(nil)?!
+				// Prior to CL 21331, that's what this code did implicitly.
+				// Now it does it explicitly, to safely preserve old behavior.
+				// This will all be replaced by SSA anyway.
+				ptr = Ptrto(nil)
+			} else {
+				ptr = Ptrto(n.Type.Elem())
+			}
+			regalloc(&xbase, ptr, nil)
 			x.Type = xbase.Type
 			Thearch.Gmove(&x, &xbase)
 			Regfree(&x)
@@ -3490,7 +3500,7 @@
 			if n.Op == OSLICESTR {
 				w = 1 // res is string, elem size is 1 (byte)
 			} else {
-				w = res.Type.Type.Width // res is []T, elem size is T.width
+				w = res.Type.Elem().Width // res is []T, elem size is T.width
 			}
 			if Isconst(&i, CTINT) {
 				ginscon(Thearch.Optoas(OADD, xbase.Type), i.Val().U.(*Mpint).Int64()*w, &xbase)
diff --git a/src/cmd/compile/internal/gc/closure.go b/src/cmd/compile/internal/gc/closure.go
index 194c028..98edb6d 100644
--- a/src/cmd/compile/internal/gc/closure.go
+++ b/src/cmd/compile/internal/gc/closure.go
@@ -490,7 +490,7 @@
 	}
 	basetype := rcvrtype
 	if Isptr[rcvrtype.Etype] {
-		basetype = basetype.Type
+		basetype = basetype.Elem()
 	}
 	if basetype.Etype != TINTER && basetype.Sym == nil {
 		Fatalf("missing base type for %v", rcvrtype)
diff --git a/src/cmd/compile/internal/gc/const.go b/src/cmd/compile/internal/gc/const.go
index 17c67aa..bfd462a 100644
--- a/src/cmd/compile/internal/gc/const.go
+++ b/src/cmd/compile/internal/gc/const.go
@@ -1684,7 +1684,7 @@
 		t := l.Type
 
 		if t != nil && Isptr[t.Etype] {
-			t = t.Type
+			t = t.Elem()
 		}
 		if Isfixedarray(t) && !hascallchan(l) {
 			return true
diff --git a/src/cmd/compile/internal/gc/dcl.go b/src/cmd/compile/internal/gc/dcl.go
index a04fde1..5e23aaa 100644
--- a/src/cmd/compile/internal/gc/dcl.go
+++ b/src/cmd/compile/internal/gc/dcl.go
@@ -716,7 +716,7 @@
 	}
 
 	if t.Sym == nil && Isptr[t.Etype] {
-		t = t.Type
+		t = t.Elem()
 		if t.Etype == TINTER {
 			Yyerror("embedded type cannot be a pointer to interface")
 		}
@@ -1020,7 +1020,7 @@
 	if !Isptr[t.Etype] {
 		return false
 	}
-	t = t.Type
+	t = t.Elem()
 	if t.Sym != nil || t.Etype != TSTRUCT || t.NumFields() != 0 {
 		return false
 	}
@@ -1076,7 +1076,7 @@
 	}
 	s = t.Sym
 	if s == nil && Isptr[t.Etype] {
-		t = t.Type
+		t = t.Elem()
 		if t == nil {
 			goto bad
 		}
@@ -1198,7 +1198,7 @@
 					return
 				}
 
-				t = t.Type
+				t = t.Elem()
 			}
 
 			if t.Broke { // rely on typecheck having complained before
diff --git a/src/cmd/compile/internal/gc/esc.go b/src/cmd/compile/internal/gc/esc.go
index 2820c8a..0e91993 100644
--- a/src/cmd/compile/internal/gc/esc.go
+++ b/src/cmd/compile/internal/gc/esc.go
@@ -640,7 +640,7 @@
 	// "Big" conditions that were scattered around in walk have been gathered here
 	if n.Esc != EscHeap && n.Type != nil &&
 		(n.Type.Width > MaxStackVarSize ||
-			n.Op == ONEW && n.Type.Type.Width >= 1<<16 ||
+			n.Op == ONEW && n.Type.Elem().Width >= 1<<16 ||
 			n.Op == OMAKESLICE && !isSmallMakeSlice(n)) {
 		if Debug['m'] > 2 {
 			Warnl(n.Lineno, "%v is too large for stack", n)
@@ -697,7 +697,7 @@
 			// it is also a dereference, because it is implicitly
 			// dereferenced (see #12588)
 			if Isfixedarray(n.Type) &&
-				!(Isptr[n.Right.Type.Etype] && Eqtype(n.Right.Type.Type, n.Type)) {
+				!(Isptr[n.Right.Type.Etype] && Eqtype(n.Right.Type.Elem(), n.Type)) {
 				escassignNilWhy(e, n.List.Second(), n.Right, "range")
 			} else {
 				escassignDereference(e, n.List.Second(), n.Right, e.stepAssign(nil, n.List.Second(), n.Right, "range-deref"))
@@ -1341,7 +1341,7 @@
 		// This should model our own sloppy use of OIND to encode
 		// decreasing levels of indirection; i.e., "indirecting" an array
 		// might yield the type of an element. To be enhanced...
-		t = t.Type
+		t = t.Elem()
 	}
 	ind.Type = t
 	return ind
@@ -1493,7 +1493,7 @@
 				if n2.Isddd && !n.Isddd {
 					// Introduce ODDDARG node to represent ... allocation.
 					src = Nod(ODDDARG, nil, nil)
-					arr := typArray(n2.Type.Type, int64(len(lls)))
+					arr := typArray(n2.Type.Elem(), int64(len(lls)))
 					src.Type = Ptrto(arr) // make pointer so it will be tracked
 					src.Lineno = n.Lineno
 					e.track(src)
@@ -1555,7 +1555,7 @@
 			// Introduce ODDDARG node to represent ... allocation.
 			src = Nod(ODDDARG, nil, nil)
 			src.Lineno = n.Lineno
-			arr := typArray(t.Type.Type, int64(len(lls)-i))
+			arr := typArray(t.Type.Elem(), int64(len(lls)-i))
 			src.Type = Ptrto(arr) // make pointer so it will be tracked
 			e.track(src)
 			n.Right = src
diff --git a/src/cmd/compile/internal/gc/export.go b/src/cmd/compile/internal/gc/export.go
index d17368a..4363360 100644
--- a/src/cmd/compile/internal/gc/export.go
+++ b/src/cmd/compile/internal/gc/export.go
@@ -150,7 +150,7 @@
 
 		if t != Types[t.Etype] && t != idealbool && t != idealstring {
 			if Isptr[t.Etype] {
-				t = t.Type
+				t = t.Elem()
 			}
 			if t != nil && t.Sym != nil && t.Sym.Def != nil && !exportedsym(t.Sym) {
 				if Debug['E'] != 0 {
@@ -164,7 +164,7 @@
 		t := n.Type
 		if t != Types[n.Type.Etype] && t != idealbool && t != idealstring {
 			if Isptr[t.Etype] {
-				t = t.Type
+				t = t.Elem()
 			}
 			if t != nil && t.Sym != nil && t.Sym.Def != nil && !exportedsym(t.Sym) {
 				if Debug['E'] != 0 {
@@ -205,7 +205,7 @@
 		switch t.Etype {
 		case TARRAY, TCHAN, TPTR32, TPTR64:
 			if t.Sym == nil {
-				t = t.Type
+				t = t.Elem()
 			}
 		}
 		if t != nil && t.Sym != nil && t.Sym.Def != nil && !exportedsym(t.Sym) {
@@ -304,7 +304,7 @@
 		dumpexporttype(t.Val())
 		dumpexporttype(t.Key())
 	case TARRAY, TCHAN, TPTR32, TPTR64:
-		dumpexporttype(t.Type)
+		dumpexporttype(t.Elem())
 	}
 
 	if t.Sym == nil {
diff --git a/src/cmd/compile/internal/gc/fmt.go b/src/cmd/compile/internal/gc/fmt.go
index 79d64a1..4079f5a 100644
--- a/src/cmd/compile/internal/gc/fmt.go
+++ b/src/cmd/compile/internal/gc/fmt.go
@@ -581,32 +581,32 @@
 	switch t.Etype {
 	case TPTR32, TPTR64:
 		if fmtmode == FTypeId && (flag&FmtShort != 0) {
-			return "*" + Tconv(t.Type, FmtShort)
+			return "*" + Tconv(t.Elem(), FmtShort)
 		}
-		return "*" + t.Type.String()
+		return "*" + t.Elem().String()
 
 	case TARRAY:
 		if t.IsArray() {
-			return fmt.Sprintf("[%d]%v", t.Bound, t.Type)
+			return fmt.Sprintf("[%d]%v", t.Bound, t.Elem())
 		}
 		if t.isDDDArray() {
-			return "[...]" + t.Type.String()
+			return "[...]" + t.Elem().String()
 		}
-		return "[]" + t.Type.String()
+		return "[]" + t.Elem().String()
 
 	case TCHAN:
 		switch t.Chan {
 		case Crecv:
-			return "<-chan " + t.Type.String()
+			return "<-chan " + t.Elem().String()
 
 		case Csend:
-			return "chan<- " + t.Type.String()
+			return "chan<- " + t.Elem().String()
 		}
 
-		if t.Type != nil && t.Type.Etype == TCHAN && t.Type.Sym == nil && t.Type.Chan == Crecv {
-			return "chan (" + t.Type.String() + ")"
+		if t.Elem() != nil && t.Elem().Etype == TCHAN && t.Elem().Sym == nil && t.Elem().Chan == Crecv {
+			return "chan (" + t.Elem().String() + ")"
 		}
-		return "chan " + t.Type.String()
+		return "chan " + t.Elem().String()
 
 	case TMAP:
 		return "map[" + t.Key().String() + "]" + t.Val().String()
@@ -736,7 +736,7 @@
 	}
 
 	// Don't know how to handle - fall back to detailed prints.
-	return fmt.Sprintf("%v <%v> %v", Econv(t.Etype), t.Sym, t.Type)
+	return fmt.Sprintf("%v <%v> %v", Econv(t.Etype), t.Sym, t.Elem())
 }
 
 // Statements which may be rendered with a simplestmt as init.
@@ -1185,7 +1185,7 @@
 		if fmtmode == FErr {
 			if n.Right != nil && n.Right.Type != nil && !n.Implicit {
 				if ptrlit {
-					return fmt.Sprintf("&%v literal", n.Right.Type.Type)
+					return fmt.Sprintf("&%v literal", n.Right.Type.Elem())
 				} else {
 					return fmt.Sprintf("%v literal", n.Right.Type)
 				}
@@ -1196,7 +1196,7 @@
 
 		if fmtmode == FExp && ptrlit {
 			// typecheck has overwritten OIND by OTYPE with pointer type.
-			return fmt.Sprintf("(&%v{ %v })", n.Right.Type.Type, Hconv(n.List, FmtComma))
+			return fmt.Sprintf("(&%v{ %v })", n.Right.Type.Elem(), Hconv(n.List, FmtComma))
 		}
 
 		return fmt.Sprintf("(%v{ %v })", n.Right, Hconv(n.List, FmtComma))
@@ -1652,7 +1652,7 @@
 
 	var typ string
 	if f.Isddd {
-		typ = "..." + Tconv(f.Type.Type, 0)
+		typ = "..." + Tconv(f.Type.Elem(), 0)
 	} else {
 		typ = Tconv(f.Type, 0)
 	}
diff --git a/src/cmd/compile/internal/gc/gen.go b/src/cmd/compile/internal/gc/gen.go
index 6a7b64a..5b1abfd 100644
--- a/src/cmd/compile/internal/gc/gen.go
+++ b/src/cmd/compile/internal/gc/gen.go
@@ -1205,35 +1205,24 @@
 
 	case TARRAY:
 		if Isslice(t) {
-			return f(Ptrto(t.Type), startOffset+int64(Array_array)) &&
+			return f(Ptrto(t.Elem()), startOffset+int64(Array_array)) &&
 				f(Types[Simtype[TUINT]], startOffset+int64(Array_nel)) &&
 				f(Types[Simtype[TUINT]], startOffset+int64(Array_cap))
 		}
 
 		// Short-circuit [1e6]struct{}.
-		if t.Type.Width == 0 {
+		if t.Elem().Width == 0 {
 			return true
 		}
 
 		for i := int64(0); i < t.Bound; i++ {
-			if !visitComponents(t.Type, startOffset+i*t.Type.Width, f) {
+			if !visitComponents(t.Elem(), startOffset+i*t.Elem().Width, f) {
 				return false
 			}
 		}
 		return true
 
 	case TSTRUCT:
-		if t.Type != nil && t.Type.Width != 0 {
-			// NOTE(rsc): If this happens, the right thing to do is to say
-			//	startOffset -= t.Type.Width
-			// but I want to see if it does.
-			// The old version of componentgen handled this,
-			// in code introduced in CL 6932045 to fix issue #4518.
-			// But the test case in issue 4518 does not trigger this anymore,
-			// so maybe this complication is no longer needed.
-			Fatalf("struct not at offset 0")
-		}
-
 		for _, field := range t.Fields().Slice() {
 			if !visitComponents(field.Type, startOffset+field.Offset, f) {
 				return false
diff --git a/src/cmd/compile/internal/gc/inl.go b/src/cmd/compile/internal/gc/inl.go
index 4221842..e5b02c4 100644
--- a/src/cmd/compile/internal/gc/inl.go
+++ b/src/cmd/compile/internal/gc/inl.go
@@ -39,7 +39,7 @@
 		rcvr := fn.Type.Recv().Type
 
 		if Isptr[rcvr.Etype] {
-			rcvr = rcvr.Type
+			rcvr = rcvr.Elem()
 		}
 		if rcvr.Sym == nil {
 			Fatalf("receiver with no sym: [%v] %v  (%v)", fn.Sym, Nconv(fn, FmtLong), rcvr)
@@ -747,7 +747,7 @@
 			as.Right = nodnil()
 			as.Right.Type = varargtype
 		} else {
-			vararrtype := typArray(varargtype.Type, int64(varargcount))
+			vararrtype := typArray(varargtype.Elem(), int64(varargcount))
 			as.Right = Nod(OCOMPLIT, nil, typenod(vararrtype))
 			as.Right.List.Set(varargs)
 			as.Right = Nod(OSLICE, as.Right, Nod(OKEY, nil, nil))
@@ -866,7 +866,7 @@
 // when they come from a multiple return call.
 func argvar(t *Type, i int) *Node {
 	n := newname(LookupN("~arg", i))
-	n.Type = t.Type
+	n.Type = t.Elem()
 	n.Class = PAUTO
 	n.Used = true
 	n.Name.Curfn = Curfn // the calling function, not the called one
diff --git a/src/cmd/compile/internal/gc/order.go b/src/cmd/compile/internal/gc/order.go
index 7e953e8..15f1813 100644
--- a/src/cmd/compile/internal/gc/order.go
+++ b/src/cmd/compile/internal/gc/order.go
@@ -591,7 +591,7 @@
 		orderexprlist(n.List, order)
 		n.Rlist.First().Left = orderexpr(n.Rlist.First().Left, order, nil) // arg to recv
 		ch := n.Rlist.First().Left.Type
-		tmp1 := ordertemp(ch.Type, order, haspointers(ch.Type))
+		tmp1 := ordertemp(ch.Elem(), order, haspointers(ch.Elem()))
 		var tmp2 *Node
 		if !isblank(n.List.Second()) {
 			tmp2 = ordertemp(n.List.Second().Type, order, false)
@@ -861,7 +861,7 @@
 							n2.Ninit.Append(tmp2)
 						}
 
-						r.Left = ordertemp(r.Right.Left.Type.Type, order, haspointers(r.Right.Left.Type.Type))
+						r.Left = ordertemp(r.Right.Left.Type.Elem(), order, haspointers(r.Right.Left.Type.Elem()))
 						tmp2 = Nod(OAS, tmp1, r.Left)
 						tmp2 = typecheck(tmp2, Etop)
 						n2.Ninit.Append(tmp2)
@@ -1165,7 +1165,7 @@
 			// Allocate a temporary that will be cleaned up when this statement
 			// completes. We could be more aggressive and try to arrange for it
 			// to be cleaned up when the call completes.
-			prealloc[n] = ordertemp(n.Type.Type, order, false)
+			prealloc[n] = ordertemp(n.Type.Elem(), order, false)
 		}
 
 	case ODOTTYPE, ODOTTYPE2:
diff --git a/src/cmd/compile/internal/gc/parser.go b/src/cmd/compile/internal/gc/parser.go
index 90be801..27ebf9b 100644
--- a/src/cmd/compile/internal/gc/parser.go
+++ b/src/cmd/compile/internal/gc/parser.go
@@ -3154,7 +3154,7 @@
 	} else {
 		s := s2.Sym
 		if s == nil && Isptr[s2.Etype] {
-			s = s2.Type.Sym
+			s = s2.Elem().Sym
 		}
 		pkg := importpkg
 		if s1 != nil {
diff --git a/src/cmd/compile/internal/gc/plive.go b/src/cmd/compile/internal/gc/plive.go
index 652b023..4a977d8 100644
--- a/src/cmd/compile/internal/gc/plive.go
+++ b/src/cmd/compile/internal/gc/plive.go
@@ -932,7 +932,7 @@
 			*xoffset += t.Width
 		} else {
 			for i := int64(0); i < t.Bound; i++ {
-				onebitwalktype1(t.Type, xoffset, bv)
+				onebitwalktype1(t.Elem(), xoffset, bv)
 			}
 		}
 
diff --git a/src/cmd/compile/internal/gc/range.go b/src/cmd/compile/internal/gc/range.go
index 9ff1531..ae1786a 100644
--- a/src/cmd/compile/internal/gc/range.go
+++ b/src/cmd/compile/internal/gc/range.go
@@ -38,8 +38,8 @@
 		}
 	}
 
-	if Isptr[t.Etype] && Isfixedarray(t.Type) {
-		t = t.Type
+	if Isptr[t.Etype] && Isfixedarray(t.Elem()) {
+		t = t.Elem()
 	}
 	n.Type = t
 
@@ -51,7 +51,7 @@
 
 	case TARRAY:
 		t1 = Types[TINT]
-		t2 = t.Type
+		t2 = t.Elem()
 
 	case TMAP:
 		t1 = t.Key()
@@ -63,7 +63,7 @@
 			goto out
 		}
 
-		t1 = t.Type
+		t1 = t.Elem()
 		t2 = nil
 		if n.List.Len() == 2 {
 			toomany = 1
@@ -180,7 +180,7 @@
 		init = append(init, Nod(OAS, hv1, nil))
 		init = append(init, Nod(OAS, hn, Nod(OLEN, ha, nil)))
 		if v2 != nil {
-			hp = temp(Ptrto(n.Type.Type))
+			hp = temp(Ptrto(n.Type.Elem()))
 			tmp := Nod(OINDEX, ha, Nodintconst(0))
 			tmp.Bounded = true
 			init = append(init, Nod(OAS, hp, Nod(OADDR, tmp, nil)))
@@ -206,7 +206,7 @@
 			// Advancing during the increment ensures that the pointer p only points
 			// pass the end of the array during the final "p++; i++; if(i >= len(x)) break;",
 			// after which p is dead, so it cannot confuse the collector.
-			tmp := Nod(OADD, hp, Nodintconst(t.Type.Width))
+			tmp := Nod(OADD, hp, Nodintconst(t.Elem().Width))
 
 			tmp.Type = hp.Type
 			tmp.Typecheck = 1
@@ -260,9 +260,9 @@
 
 		n.Left = nil
 
-		hv1 := temp(t.Type)
+		hv1 := temp(t.Elem())
 		hv1.Typecheck = 1
-		if haspointers(t.Type) {
+		if haspointers(t.Elem()) {
 			init = append(init, Nod(OAS, hv1, nil))
 		}
 		hb := temp(Types[TBOOL])
@@ -353,7 +353,7 @@
 	if !samesafeexpr(stmt.Left.Left, a) || !samesafeexpr(stmt.Left.Right, v1) {
 		return false
 	}
-	elemsize := n.Type.Type.Width
+	elemsize := n.Type.Elem().Width
 	if elemsize <= 0 || !iszero(stmt.Right) {
 		return false
 	}
diff --git a/src/cmd/compile/internal/gc/reflect.go b/src/cmd/compile/internal/gc/reflect.go
index 92f8285..214beec 100644
--- a/src/cmd/compile/internal/gc/reflect.go
+++ b/src/cmd/compile/internal/gc/reflect.go
@@ -306,7 +306,7 @@
 		// method does not apply.
 		this := f.Type.Recv().Type
 
-		if Isptr[this.Etype] && this.Type == t {
+		if Isptr[this.Etype] && this.Elem() == t {
 			continue
 		}
 		if Isptr[this.Etype] && !Isptr[t.Etype] && f.Embedded != 2 && !isifacemethod(f.Type) {
@@ -582,8 +582,13 @@
 
 func typePkg(t *Type) *Pkg {
 	tsym := t.Sym
-	if tsym == nil && t.Type != nil {
-		tsym = t.Type.Sym
+	if tsym == nil {
+		switch t.Etype {
+		case TARRAY, TPTR32, TPTR64, TCHAN:
+			if t.Elem() != nil {
+				tsym = t.Elem().Sym
+			}
+		}
 	}
 	if tsym != nil && t != Types[t.Etype] && t != errortype {
 		return tsym.Pkg
@@ -684,7 +689,7 @@
 			break
 		}
 
-		ret = haspointers(t.Type)
+		ret = haspointers(t.Elem())
 
 	case TSTRUCT:
 		ret = false
@@ -743,7 +748,7 @@
 			return int64(Widthptr)
 		}
 		// haspointers already eliminated t.Bound == 0.
-		return (t.Bound-1)*t.Type.Width + typeptrdata(t.Type)
+		return (t.Bound-1)*t.Elem().Width + typeptrdata(t.Elem())
 
 	case TSTRUCT:
 		// Find the last field that has pointers.
@@ -913,7 +918,7 @@
 }
 
 func typenamesym(t *Type) *Sym {
-	if t == nil || (Isptr[t.Etype] && t.Type == nil) || isideal(t) {
+	if t == nil || (Isptr[t.Etype] && t.Elem() == nil) || isideal(t) {
 		Fatalf("typename %v", t)
 	}
 	s := typesym(t)
@@ -941,7 +946,7 @@
 }
 
 func itabname(t, itype *Type) *Node {
-	if t == nil || (Isptr[t.Etype] && t.Type == nil) || isideal(t) {
+	if t == nil || (Isptr[t.Etype] && t.Elem() == nil) || isideal(t) {
 		Fatalf("itabname %v", t)
 	}
 	s := Pkglookup(Tconv(t, FmtLeft)+","+Tconv(itype, FmtLeft), itabpkg)
@@ -997,7 +1002,7 @@
 		if Isslice(t) {
 			Fatalf("slice can't be a map key: %v", t)
 		}
-		return isreflexive(t.Type)
+		return isreflexive(t.Elem())
 
 	case TSTRUCT:
 		for _, t1 := range t.Fields().Slice() {
@@ -1047,7 +1052,7 @@
 		if Isslice(t) {
 			Fatalf("slice can't be a map key: %v", t)
 		}
-		return needkeyupdate(t.Type)
+		return needkeyupdate(t.Elem())
 
 	case TSTRUCT:
 		for _, t1 := range t.Fields().Slice() {
@@ -1086,8 +1091,8 @@
 	// emit the type structures for int, float, etc.
 	tbase := t
 
-	if Isptr[t.Etype] && t.Sym == nil && t.Type.Sym != nil {
-		tbase = t.Type
+	if Isptr[t.Etype] && t.Sym == nil && t.Elem().Sym != nil {
+		tbase = t.Elem()
 	}
 	dupok := 0
 	if tbase.Sym == nil {
@@ -1116,8 +1121,8 @@
 	case TARRAY:
 		if t.IsArray() {
 			// ../../../../runtime/type.go:/arrayType
-			s1 := dtypesym(t.Type)
-			t2 := typSlice(t.Type)
+			s1 := dtypesym(t.Elem())
+			t2 := typSlice(t.Elem())
 			s2 := dtypesym(t2)
 			ot = dcommontype(s, ot, t)
 			ot = dsymptr(s, ot, s1, 0)
@@ -1125,7 +1130,7 @@
 			ot = duintptr(s, ot, uint64(t.Bound))
 		} else {
 			// ../../../../runtime/type.go:/sliceType
-			s1 := dtypesym(t.Type)
+			s1 := dtypesym(t.Elem())
 
 			ot = dcommontype(s, ot, t)
 			ot = dsymptr(s, ot, s1, 0)
@@ -1134,7 +1139,7 @@
 
 	// ../../../../runtime/type.go:/chanType
 	case TCHAN:
-		s1 := dtypesym(t.Type)
+		s1 := dtypesym(t.Elem())
 
 		ot = dcommontype(s, ot, t)
 		ot = dsymptr(s, ot, s1, 0)
@@ -1246,7 +1251,7 @@
 		ot = dextratype(s, ot, t, 0)
 
 	case TPTR32, TPTR64:
-		if t.Type.Etype == TANY {
+		if t.Elem().Etype == TANY {
 			// ../../../../runtime/type.go:/UnsafePointerType
 			ot = dcommontype(s, ot, t)
 			ot = dextratype(s, ot, t, 0)
@@ -1255,7 +1260,7 @@
 		}
 
 		// ../../../../runtime/type.go:/ptrType
-		s1 := dtypesym(t.Type)
+		s1 := dtypesym(t.Elem())
 
 		ot = dcommontype(s, ot, t)
 		ot = dsymptr(s, ot, s1, 0)
@@ -1639,10 +1644,10 @@
 
 		// Flatten array-of-array-of-array to just a big array by multiplying counts.
 		count := t.Bound
-		elem := t.Type
+		elem := t.Elem()
 		for Isfixedarray(elem) {
 			count *= elem.Bound
-			elem = elem.Type
+			elem = elem.Elem()
 		}
 
 		if !p.w.ShouldRepeat(elem.Width/int64(Widthptr), count) {
diff --git a/src/cmd/compile/internal/gc/sinit.go b/src/cmd/compile/internal/gc/sinit.go
index 0677612..3c06a96 100644
--- a/src/cmd/compile/internal/gc/sinit.go
+++ b/src/cmd/compile/internal/gc/sinit.go
@@ -434,7 +434,7 @@
 		if Isslice(r.Type) {
 			// Init slice.
 			bound := r.Right.Val().U.(*Mpint).Int64()
-			ta := typArray(r.Type.Type, bound)
+			ta := typArray(r.Type.Elem(), bound)
 			a := staticname(ta, 1)
 			inittemps[r] = a
 			n := *l
@@ -1233,7 +1233,7 @@
 			if a.Op != OKEY || !Smallintconst(a.Left) {
 				Fatalf("initplan arraylit")
 			}
-			addvalue(p, n.Type.Type.Width*a.Left.Val().U.(*Mpint).Int64(), a.Right)
+			addvalue(p, n.Type.Elem().Width*a.Left.Val().U.(*Mpint).Int64(), a.Right)
 		}
 
 	case OSTRUCTLIT:
diff --git a/src/cmd/compile/internal/gc/ssa.go b/src/cmd/compile/internal/gc/ssa.go
index 11a478a..b880eda 100644
--- a/src/cmd/compile/internal/gc/ssa.go
+++ b/src/cmd/compile/internal/gc/ssa.go
@@ -1950,11 +1950,11 @@
 			return s.newValue2(ssa.OpLoad, Types[TUINT8], ptr, s.mem())
 		case n.Left.Type.IsSlice():
 			p := s.addr(n, false)
-			return s.newValue2(ssa.OpLoad, n.Left.Type.Type, p, s.mem())
+			return s.newValue2(ssa.OpLoad, n.Left.Type.Elem(), p, s.mem())
 		case n.Left.Type.IsArray():
 			// TODO: fix when we can SSA arrays of length 1.
 			p := s.addr(n, false)
-			return s.newValue2(ssa.OpLoad, n.Left.Type.Type, p, s.mem())
+			return s.newValue2(ssa.OpLoad, n.Left.Type.Elem(), p, s.mem())
 		default:
 			s.Fatalf("bad type for index %v", n.Left.Type)
 			return nil
@@ -2077,7 +2077,7 @@
 		// *(ptr+len+2) = e3
 		// makeslice(ptr,newlen,cap)
 
-		et := n.Type.Type
+		et := n.Type.Elem()
 		pt := Ptrto(et)
 
 		// Evaluate slice
@@ -2672,7 +2672,7 @@
 			if !n.Bounded {
 				s.boundsCheck(i, len)
 			}
-			return s.newValue2(ssa.OpPtrIndex, Ptrto(n.Left.Type.Type), a, i)
+			return s.newValue2(ssa.OpPtrIndex, Ptrto(n.Left.Type.Elem()), a, i)
 		}
 	case OIND:
 		p := s.expr(n.Left)
@@ -3138,7 +3138,7 @@
 	zero := s.constInt(Types[TINT], 0)
 	switch {
 	case t.IsSlice():
-		elemtype = t.Type
+		elemtype = t.Elem()
 		ptrtype = Ptrto(elemtype)
 		ptr = s.newValue1(ssa.OpSlicePtr, ptrtype, v)
 		len = s.newValue1(ssa.OpSliceLen, Types[TINT], v)
@@ -3150,14 +3150,14 @@
 		len = s.newValue1(ssa.OpStringLen, Types[TINT], v)
 		cap = len
 	case t.IsPtr():
-		if !t.Type.IsArray() {
+		if !t.Elem().IsArray() {
 			s.Fatalf("bad ptr to array in slice %v\n", t)
 		}
-		elemtype = t.Type.Type
+		elemtype = t.Elem().Elem()
 		ptrtype = Ptrto(elemtype)
 		s.nilCheck(v)
 		ptr = v
-		len = s.constInt(Types[TINT], t.Type.Bound)
+		len = s.constInt(Types[TINT], t.Elem().Bound)
 		cap = len
 	default:
 		s.Fatalf("bad type in slice %v\n", t)
diff --git a/src/cmd/compile/internal/gc/subr.go b/src/cmd/compile/internal/gc/subr.go
index 31c5ec8..18d35a2 100644
--- a/src/cmd/compile/internal/gc/subr.go
+++ b/src/cmd/compile/internal/gc/subr.go
@@ -565,7 +565,7 @@
 	if !Isptr[t.Etype] {
 		return false
 	}
-	t = t.Type
+	t = t.Elem()
 	if t == nil {
 		return false
 	}
@@ -633,7 +633,7 @@
 		if t.Sym != nil {
 			return nil
 		}
-		t = t.Type
+		t = t.Elem()
 		if t == nil {
 			return nil
 		}
@@ -773,7 +773,7 @@
 		return eqtype1(t1.Val(), t2.Val(), assumedEqual)
 	}
 
-	return eqtype1(t1.Type, t2.Type, assumedEqual)
+	return eqtype1(t1.Elem(), t2.Elem(), assumedEqual)
 }
 
 // Are t1 and t2 equal struct types when field names are ignored?
@@ -886,7 +886,7 @@
 	// src and dst have identical element types, and
 	// either src or dst is not a named type.
 	if src.Etype == TCHAN && src.Chan == Cboth && dst.Etype == TCHAN {
-		if Eqtype(src.Type, dst.Type) && (src.Sym == nil || dst.Sym == nil) {
+		if Eqtype(src.Elem(), dst.Elem()) && (src.Sym == nil || dst.Sym == nil) {
 			return OCONVNOP
 		}
 	}
@@ -960,7 +960,7 @@
 	// 3. src and dst are unnamed pointer types
 	// and their base types have identical underlying types.
 	if Isptr[src.Etype] && Isptr[dst.Etype] && src.Sym == nil && dst.Sym == nil {
-		if Eqtype(src.Type.Orig, dst.Type.Orig) {
+		if Eqtype(src.Elem().Orig, dst.Elem().Orig) {
 			return OCONVNOP
 		}
 	}
@@ -988,10 +988,10 @@
 	}
 
 	if Isslice(src) && dst.Etype == TSTRING {
-		if src.Type.Etype == bytetype.Etype {
+		if src.Elem().Etype == bytetype.Etype {
 			return OARRAYBYTESTR
 		}
-		if src.Type.Etype == runetype.Etype {
+		if src.Elem().Etype == runetype.Etype {
 			return OARRAYRUNESTR
 		}
 	}
@@ -999,10 +999,10 @@
 	// 7. src is a string and dst is []byte or []rune.
 	// String to slice.
 	if src.Etype == TSTRING && Isslice(dst) {
-		if dst.Type.Etype == bytetype.Etype {
+		if dst.Elem().Etype == bytetype.Etype {
 			return OSTRARRAYBYTE
 		}
-		if dst.Type.Etype == runetype.Etype {
+		if dst.Elem().Etype == runetype.Etype {
 			return OSTRARRAYRUNE
 		}
 	}
@@ -1278,9 +1278,9 @@
 
 	// common mistake: *struct and *interface.
 	if tl != nil && tr != nil && Isptr[tl.Etype] && Isptr[tr.Etype] {
-		if tl.Type.Etype == TSTRUCT && tr.Type.Etype == TINTER {
+		if tl.Elem().Etype == TSTRUCT && tr.Elem().Etype == TINTER {
 			fmt_ += "\n\t(*struct vs *interface)"
-		} else if tl.Type.Etype == TINTER && tr.Type.Etype == TSTRUCT {
+		} else if tl.Elem().Etype == TINTER && tr.Elem().Etype == TSTRUCT {
 			fmt_ += "\n\t(*interface vs *struct)"
 		}
 	}
@@ -1445,7 +1445,7 @@
 func lookdot0(s *Sym, t *Type, save **Field, ignorecase bool) int {
 	u := t
 	if Isptr[u.Etype] {
-		u = u.Type
+		u = u.Elem()
 	}
 
 	c := 0
@@ -1501,7 +1501,7 @@
 
 	u = t
 	if Isptr[u.Etype] {
-		u = u.Type
+		u = u.Elem()
 	}
 	if u.Etype != TSTRUCT && u.Etype != TINTER {
 		goto out
@@ -1611,7 +1611,7 @@
 	u := t
 	if Isptr[u.Etype] {
 		followptr = true
-		u = u.Type
+		u = u.Elem()
 	}
 
 	if u.Etype == TINTER {
@@ -1651,7 +1651,7 @@
 	u := t
 	if Isptr[u.Etype] {
 		followptr = true
-		u = u.Type
+		u = u.Elem()
 	}
 
 	if u.Etype != TSTRUCT && u.Etype != TINTER {
@@ -1826,7 +1826,7 @@
 	methodrcvr := method.Type.Recv().Type
 
 	// generate nil pointer check for better error
-	if Isptr[rcvr.Etype] && rcvr.Type == methodrcvr {
+	if Isptr[rcvr.Etype] && rcvr.Elem() == methodrcvr {
 		// generating wrapper from *T to T.
 		n := Nod(OIF, nil, nil)
 
@@ -1837,9 +1837,9 @@
 		var l []*Node
 
 		var v Val
-		v.U = rcvr.Type.Sym.Pkg.Name // package name
+		v.U = rcvr.Elem().Sym.Pkg.Name // package name
 		l = append(l, nodlit(v))
-		v.U = rcvr.Type.Sym.Name // type name
+		v.U = rcvr.Elem().Sym.Name // type name
 		l = append(l, nodlit(v))
 		v.U = method.Sym.Name
 		l = append(l, nodlit(v)) // method name
@@ -1889,7 +1889,7 @@
 	testdclstack()
 
 	// wrappers where T is anonymous (struct or interface) can be duplicated.
-	if rcvr.Etype == TSTRUCT || rcvr.Etype == TINTER || Isptr[rcvr.Etype] && rcvr.Type.Etype == TSTRUCT {
+	if rcvr.Etype == TSTRUCT || rcvr.Etype == TINTER || Isptr[rcvr.Etype] && rcvr.Elem().Etype == TSTRUCT {
 		fn.Func.Dupok = true
 	}
 	fn = typecheck(fn, Etop)
@@ -2273,7 +2273,7 @@
 
 	case TARRAY:
 		// Array of 1 direct iface type can be direct.
-		return t.Bound == 1 && isdirectiface(t.Type)
+		return t.Bound == 1 && isdirectiface(t.Elem())
 
 	case TSTRUCT:
 		// Struct with 1 field of direct iface type can be direct.
diff --git a/src/cmd/compile/internal/gc/type.go b/src/cmd/compile/internal/gc/type.go
index f7bd270..0700d49 100644
--- a/src/cmd/compile/internal/gc/type.go
+++ b/src/cmd/compile/internal/gc/type.go
@@ -503,6 +503,17 @@
 	return t.Type
 }
 
+// Elem returns the type of elements of t.
+// Usable with pointers, channels, arrays, and slices.
+func (t *Type) Elem() *Type {
+	switch t.Etype {
+	case TPTR32, TPTR64, TCHAN, TARRAY:
+	default:
+		Fatalf("Type.Elem %s", t.Etype)
+	}
+	return t.Type
+}
+
 // Wrapped returns the type that pseudo-type t wraps.
 func (t *Type) Wrapped() *Type {
 	switch t.Etype {
@@ -787,7 +798,7 @@
 	}
 
 	// Common element type comparison for TARRAY, TCHAN, TPTR32, and TPTR64.
-	return t.Type.cmp(x.Type)
+	return t.Elem().cmp(x.Elem())
 }
 
 func (t *Type) IsBoolean() bool {
@@ -864,11 +875,9 @@
 }
 
 func (t *Type) ElemType() ssa.Type {
-	switch t.Etype {
-	case TARRAY, TPTR32, TPTR64:
-		return t.Type
-	}
-	panic(fmt.Sprintf("ElemType on invalid type %v", t))
+	// TODO(josharian): If Type ever moves to a shared
+	// internal package, remove this silly wrapper.
+	return t.Elem()
 }
 func (t *Type) PtrTo() ssa.Type {
 	return Ptrto(t)
diff --git a/src/cmd/compile/internal/gc/typecheck.go b/src/cmd/compile/internal/gc/typecheck.go
index b570d2d..b7ea9ac 100644
--- a/src/cmd/compile/internal/gc/typecheck.go
+++ b/src/cmd/compile/internal/gc/typecheck.go
@@ -484,7 +484,7 @@
 		}
 
 		ok |= Erv
-		n.Type = t.Type
+		n.Type = t.Elem()
 		break OpSwitch
 
 	// arithmetic exprs
@@ -864,8 +864,8 @@
 			break OpSwitch
 		}
 
-		if Isptr[t.Etype] && t.Type.Etype != TINTER {
-			t = t.Type
+		if Isptr[t.Etype] && t.Elem().Etype != TINTER {
+			t = t.Elem()
 			if t == nil {
 				n.Type = nil
 				return n
@@ -886,7 +886,7 @@
 			case isnilinter(t):
 				Yyerror("%v undefined (type %v is interface with no methods)", n, n.Left.Type)
 
-			case Isptr[t.Etype] && Isinter(t.Type):
+			case Isptr[t.Etype] && Isinter(t.Elem()):
 				// Pointer to interface is almost always a mistake.
 				Yyerror("%v undefined (type %v is pointer to interface, not interface)", n, n.Left.Type)
 
@@ -989,7 +989,7 @@
 			if t.Etype == TSTRING {
 				n.Type = bytetype
 			} else {
-				n.Type = t.Type
+				n.Type = t.Elem()
 			}
 			why := "string"
 			if t.Etype == TARRAY {
@@ -1052,7 +1052,7 @@
 			return n
 		}
 
-		n.Type = t.Type
+		n.Type = t.Elem()
 		break OpSwitch
 
 	case OSEND:
@@ -1079,13 +1079,13 @@
 			return n
 		}
 
-		n.Right = defaultlit(n.Right, t.Type)
+		n.Right = defaultlit(n.Right, t.Elem())
 		r := n.Right
 		if r.Type == nil {
 			n.Type = nil
 			return n
 		}
-		n.Right = assignconv(r, l.Type.Type, "send")
+		n.Right = assignconv(r, l.Type.Elem(), "send")
 
 		// TODO: more aggressive
 		n.Etype = 0
@@ -1124,9 +1124,9 @@
 		if Istype(t, TSTRING) {
 			n.Type = t
 			n.Op = OSLICESTR
-		} else if Isptr[t.Etype] && Isfixedarray(t.Type) {
-			tp = t.Type
-			n.Type = typSlice(tp.Type)
+		} else if Isptr[t.Etype] && Isfixedarray(t.Elem()) {
+			tp = t.Elem()
+			n.Type = typSlice(tp.Elem())
 			dowidth(n.Type)
 			n.Op = OSLICEARR
 		} else if Isslice(t) {
@@ -1189,9 +1189,9 @@
 		}
 
 		var tp *Type
-		if Isptr[t.Etype] && Isfixedarray(t.Type) {
-			tp = t.Type
-			n.Type = typSlice(tp.Type)
+		if Isptr[t.Etype] && Isfixedarray(t.Elem()) {
+			tp = t.Elem()
+			n.Type = typSlice(tp.Elem())
 			dowidth(n.Type)
 			n.Op = OSLICE3ARR
 		} else if Isslice(t) {
@@ -1622,7 +1622,7 @@
 				return n
 			}
 
-			if Istype(t.Type, TUINT8) && Istype(args.Second().Type, TSTRING) {
+			if Istype(t.Elem(), TUINT8) && Istype(args.Second().Type, TSTRING) {
 				args.SetIndex(1, defaultlit(args.Index(1), Types[TSTRING]))
 				break OpSwitch
 			}
@@ -1634,8 +1634,8 @@
 		if funarg != nil {
 			_, it := IterFields(funarg) // Skip first field
 			for t := it.Next(); t != nil; t = it.Next() {
-				if assignop(t.Type, n.Type.Type, nil) == 0 {
-					Yyerror("cannot append %v value to []%v", t.Type, n.Type.Type)
+				if assignop(t.Type, n.Type.Elem(), nil) == 0 {
+					Yyerror("cannot append %v value to []%v", t.Type, n.Type.Elem())
 				}
 			}
 		} else {
@@ -1644,7 +1644,7 @@
 				if n.Type == nil {
 					continue
 				}
-				as[i] = assignconv(n, t.Type, "append")
+				as[i] = assignconv(n, t.Elem(), "append")
 			}
 		}
 
@@ -1684,7 +1684,7 @@
 
 		// copy([]byte, string)
 		if Isslice(n.Left.Type) && n.Right.Type.Etype == TSTRING {
-			if Eqtype(n.Left.Type.Type, bytetype) {
+			if Eqtype(n.Left.Type.Elem(), bytetype) {
 				break OpSwitch
 			}
 			Yyerror("arguments to copy have different element types: %v and string", Tconv(n.Left.Type, FmtLong))
@@ -1704,7 +1704,7 @@
 			return n
 		}
 
-		if !Eqtype(n.Left.Type.Type, n.Right.Type.Type) {
+		if !Eqtype(n.Left.Type.Elem(), n.Right.Type.Elem()) {
 			Yyerror("arguments to copy have different element types: %v and %v", Tconv(n.Left.Type, FmtLong), Tconv(n.Right.Type, FmtLong))
 			n.Type = nil
 			return n
@@ -1978,7 +1978,7 @@
 		if t.Etype == TSTRING {
 			n.Type = Ptrto(Types[TUINT8])
 		} else {
-			n.Type = Ptrto(t.Type)
+			n.Type = Ptrto(t.Elem())
 		}
 		break OpSwitch
 
@@ -2299,7 +2299,7 @@
 	if t == nil || !Isptr[t.Etype] {
 		return n
 	}
-	t = t.Type
+	t = t.Elem()
 	if t == nil {
 		return n
 	}
@@ -2435,7 +2435,7 @@
 
 func derefall(t *Type) *Type {
 	for t != nil && t.Etype == Tptr {
-		t = t.Type
+		t = t.Elem()
 	}
 	return t
 }
@@ -2506,26 +2506,26 @@
 		dowidth(tt)
 		rcvr := f2.Type.Recv().Type
 		if !Eqtype(rcvr, tt) {
-			if rcvr.Etype == Tptr && Eqtype(rcvr.Type, tt) {
+			if rcvr.Etype == Tptr && Eqtype(rcvr.Elem(), tt) {
 				checklvalue(n.Left, "call pointer method on")
 				n.Left = Nod(OADDR, n.Left, nil)
 				n.Left.Implicit = true
 				n.Left = typecheck(n.Left, Etype|Erv)
-			} else if tt.Etype == Tptr && rcvr.Etype != Tptr && Eqtype(tt.Type, rcvr) {
+			} else if tt.Etype == Tptr && rcvr.Etype != Tptr && Eqtype(tt.Elem(), rcvr) {
 				n.Left = Nod(OIND, n.Left, nil)
 				n.Left.Implicit = true
 				n.Left = typecheck(n.Left, Etype|Erv)
-			} else if tt.Etype == Tptr && tt.Type.Etype == Tptr && Eqtype(derefall(tt), derefall(rcvr)) {
+			} else if tt.Etype == Tptr && tt.Elem().Etype == Tptr && Eqtype(derefall(tt), derefall(rcvr)) {
 				Yyerror("calling method %v with receiver %v requires explicit dereference", n.Sym, Nconv(n.Left, FmtLong))
 				for tt.Etype == Tptr {
 					// Stop one level early for method with pointer receiver.
-					if rcvr.Etype == Tptr && tt.Type.Etype != Tptr {
+					if rcvr.Etype == Tptr && tt.Elem().Etype != Tptr {
 						break
 					}
 					n.Left = Nod(OIND, n.Left, nil)
 					n.Left.Implicit = true
 					n.Left = typecheck(n.Left, Etype|Erv)
-					tt = tt.Type
+					tt = tt.Elem()
 				}
 			} else {
 				Fatalf("method mismatch: %v for %v", rcvr, tt)
@@ -2612,11 +2612,11 @@
 				for _, tl := range tstruct.Fields().Slice() {
 					if tl.Isddd {
 						for ; tn != nil; tn = it.Next() {
-							if assignop(tn.Type, tl.Type.Type, &why) == 0 {
+							if assignop(tn.Type, tl.Type.Elem(), &why) == 0 {
 								if call != nil {
-									Yyerror("cannot use %v as type %v in argument to %v%s", tn.Type, tl.Type.Type, call, why)
+									Yyerror("cannot use %v as type %v in argument to %v%s", tn.Type, tl.Type.Elem(), call, why)
 								} else {
-									Yyerror("cannot use %v as type %v in %s%s", tn.Type, tl.Type.Type, desc(), why)
+									Yyerror("cannot use %v as type %v in %s%s", tn.Type, tl.Type.Elem(), desc(), why)
 								}
 							}
 						}
@@ -2693,7 +2693,7 @@
 				n = nl.Index(i)
 				setlineno(n)
 				if n.Type != nil {
-					nl.SetIndex(i, assignconvfn(n, t.Type, desc))
+					nl.SetIndex(i, assignconvfn(n, t.Elem(), desc))
 				}
 			}
 
@@ -2846,7 +2846,7 @@
 		return true
 
 	case TPTR32, TPTR64:
-		switch t.Type.Etype {
+		switch t.Elem().Etype {
 		case TARRAY, TSTRUCT, TMAP:
 			return true
 		}
@@ -2914,7 +2914,7 @@
 		// For better or worse, we don't allow pointers as the composite literal type,
 		// except when using the &T syntax, which sets implicit on the OIND.
 		if !n.Right.Implicit {
-			Yyerror("invalid pointer type %v for composite literal (use &%v instead)", t, t.Type)
+			Yyerror("invalid pointer type %v for composite literal (use &%v instead)", t, t.Elem())
 			n.Type = nil
 			return n
 		}
@@ -2926,7 +2926,7 @@
 			return n
 		}
 
-		t = t.Type
+		t = t.Elem()
 	}
 
 	var r *Node
@@ -2979,10 +2979,10 @@
 			}
 
 			r = l.Right
-			pushtype(r, t.Type)
+			pushtype(r, t.Elem())
 			r = typecheck(r, Erv)
-			r = defaultlit(r, t.Type)
-			l.Right = assignconv(r, t.Type, "array or slice literal")
+			r = defaultlit(r, t.Elem())
+			l.Right = assignconv(r, t.Elem(), "array or slice literal")
 		}
 
 		if t.isDDDArray() {
@@ -3440,7 +3440,7 @@
 
 	s := n.Left.Val().U.(string)
 	var l []*Node
-	if n.Type.Type.Etype == TUINT8 {
+	if n.Type.Elem().Etype == TUINT8 {
 		// []byte
 		for i := 0; i < len(s); i++ {
 			l = append(l, Nod(OKEY, Nodintconst(int64(i)), Nodintconst(int64(s[0]))))
diff --git a/src/cmd/compile/internal/gc/walk.go b/src/cmd/compile/internal/gc/walk.go
index 7180538..54aa52a 100644
--- a/src/cmd/compile/internal/gc/walk.go
+++ b/src/cmd/compile/internal/gc/walk.go
@@ -365,7 +365,7 @@
 	}
 	t := n.Type
 
-	return Smallintconst(l) && Smallintconst(r) && (t.Type.Width == 0 || r.Val().U.(*Mpint).Int64() < (1<<16)/t.Type.Width)
+	return Smallintconst(l) && Smallintconst(r) && (t.Elem().Width == 0 || r.Val().U.(*Mpint).Int64() < (1<<16)/t.Elem().Width)
 }
 
 // walk the whole tree of the body of an
@@ -518,7 +518,7 @@
 
 	case ODOTPTR:
 		usefield(n)
-		if n.Op == ODOTPTR && n.Left.Type.Type.Width == 0 {
+		if n.Op == ODOTPTR && n.Left.Type.Elem().Width == 0 {
 			// No actual copy will be generated, so emit an explicit nil check.
 			n.Left = cheapexpr(n.Left, init)
 
@@ -542,7 +542,7 @@
 		t := n.Left.Type
 
 		if Isptr[t.Etype] {
-			t = t.Type
+			t = t.Elem()
 		}
 		if Isfixedarray(t) {
 			safeexpr(n.Left, init)
@@ -1155,7 +1155,7 @@
 		}
 		t := n.Left.Type
 		if t != nil && Isptr[t.Etype] {
-			t = t.Type
+			t = t.Elem()
 		}
 		if Isfixedarray(t) {
 			n.Bounded = bounded(r, t.Bound)
@@ -1268,10 +1268,10 @@
 
 	case ONEW:
 		if n.Esc == EscNone {
-			if n.Type.Type.Width >= 1<<16 {
+			if n.Type.Elem().Width >= 1<<16 {
 				Fatalf("large ONEW with EscNone: %v", n)
 			}
-			r := temp(n.Type.Type)
+			r := temp(n.Type.Elem())
 			r = Nod(OAS, r, nil) // zero temp
 			r = typecheck(r, Etop)
 			init.Append(r)
@@ -1279,7 +1279,7 @@
 			r = typecheck(r, Erv)
 			n = r
 		} else {
-			n = callnew(n.Type.Type)
+			n = callnew(n.Type.Elem())
 		}
 
 		// If one argument to the comparison is an empty string,
@@ -1410,7 +1410,7 @@
 			}
 			// var arr [r]T
 			// n = arr[:l]
-			t = aindex(r, t.Type) // [r]T
+			t = aindex(r, t.Elem()) // [r]T
 			var_ := temp(t)
 			a := Nod(OAS, var_, nil) // zero temp
 			a = typecheck(a, Etop)
@@ -1424,7 +1424,7 @@
 			// makeslice(t *Type, nel int64, max int64) (ary []any)
 			fn := syslook("makeslice")
 
-			fn = substArgTypes(fn, t.Type) // any-1
+			fn = substArgTypes(fn, t.Elem()) // any-1
 			n = mkcall1(fn, n.Type, init, typename(n.Type), conv(l, Types[TINT64]), conv(r, Types[TINT64]))
 		}
 
@@ -1538,7 +1538,7 @@
 
 	case OSEND:
 		n1 := n.Right
-		n1 = assignconv(n1, n.Left.Type.Type, "chan send")
+		n1 = assignconv(n1, n.Left.Type.Elem(), "chan send")
 		n1 = walkexpr(n1, init)
 		n1 = Nod(OADDR, n1, nil)
 		n = mkcall1(chanfn("chansend1", 2, n.Left.Type), nil, init, typename(n.Left.Type), n.Left, n1)
@@ -1715,7 +1715,7 @@
 		esc = ddd.Esc
 	}
 
-	tslice := typSlice(l.Type.Type)
+	tslice := typSlice(l.Type.Elem())
 
 	var n *Node
 	if len(lr0) == 0 {
@@ -2633,9 +2633,9 @@
 	default:
 		Fatalf("chanfn %d", n)
 	case 1:
-		fn = substArgTypes(fn, t.Type)
+		fn = substArgTypes(fn, t.Elem())
 	case 2:
-		fn = substArgTypes(fn, t.Type, t.Type)
+		fn = substArgTypes(fn, t.Elem(), t.Elem())
 	}
 	return fn
 }
@@ -2772,7 +2772,7 @@
 
 	// instantiate growslice(Type*, []any, int) []any
 	fn := syslook("growslice")
-	fn = substArgTypes(fn, s.Type.Type, s.Type.Type)
+	fn = substArgTypes(fn, s.Type.Elem(), s.Type.Elem())
 
 	// s = growslice(T, s, n)
 	nif.Nbody.Set1(Nod(OAS, s, mkcall1(fn, s.Type, &nif.Ninit, typename(s.Type), s, nn)))
@@ -2783,7 +2783,7 @@
 	nt.Etype = 1
 	l = append(l, Nod(OAS, s, nt))
 
-	if haspointers(l1.Type.Type) {
+	if haspointers(l1.Type.Elem()) {
 		// copy(s[len(l1):], l2)
 		nptr1 := Nod(OSLICE, s, Nod(OKEY, Nod(OLEN, l1, nil), nil))
 
@@ -2793,7 +2793,7 @@
 		fn = substArgTypes(fn, l1.Type, l2.Type)
 		var ln Nodes
 		ln.Set(l)
-		nt := mkcall1(fn, Types[TINT], &ln, typename(l1.Type.Type), nptr1, nptr2)
+		nt := mkcall1(fn, Types[TINT], &ln, typename(l1.Type.Elem()), nptr1, nptr2)
 		l = append(ln.Slice(), nt)
 	} else if instrumenting {
 		// rely on runtime to instrument copy.
@@ -2811,7 +2811,7 @@
 		fn = substArgTypes(fn, l1.Type, l2.Type)
 		var ln Nodes
 		ln.Set(l)
-		nt := mkcall1(fn, Types[TINT], &ln, nptr1, nptr2, Nodintconst(s.Type.Type.Width))
+		nt := mkcall1(fn, Types[TINT], &ln, nptr1, nptr2, Nodintconst(s.Type.Elem().Width))
 		l = append(ln.Slice(), nt)
 	} else {
 		// memmove(&s[len(l1)], &l2[0], len(l2)*sizeof(T))
@@ -2823,13 +2823,13 @@
 		nptr2 := Nod(OSPTR, l2, nil)
 
 		fn := syslook("memmove")
-		fn = substArgTypes(fn, s.Type.Type, s.Type.Type)
+		fn = substArgTypes(fn, s.Type.Elem(), s.Type.Elem())
 
 		var ln Nodes
 		ln.Set(l)
 		nwid := cheapexpr(conv(Nod(OLEN, l2, nil), Types[TUINTPTR]), &ln)
 
-		nwid = Nod(OMUL, nwid, Nodintconst(s.Type.Type.Width))
+		nwid = Nod(OMUL, nwid, Nodintconst(s.Type.Elem().Width))
 		nt := mkcall1(fn, nil, &ln, nptr1, nptr2, nwid)
 		l = append(ln.Slice(), nt)
 	}
@@ -2883,7 +2883,7 @@
 
 	// Resolve slice type of multi-valued return.
 	if Istype(nsrc.Type, TSTRUCT) {
-		nsrc.Type = nsrc.Type.Type.Type
+		nsrc.Type = nsrc.Type.Elem().Elem()
 	}
 	argc := n.List.Len() - 1
 	if argc < 1 {
@@ -2906,7 +2906,7 @@
 	nx.Left = Nod(OLT, Nod(OSUB, Nod(OCAP, ns, nil), Nod(OLEN, ns, nil)), na)
 
 	fn := syslook("growslice") //   growslice(<type>, old []T, mincap int) (ret []T)
-	fn = substArgTypes(fn, ns.Type.Type, ns.Type.Type)
+	fn = substArgTypes(fn, ns.Type.Elem(), ns.Type.Elem())
 
 	nx.Nbody.Set1(Nod(OAS, ns,
 		mkcall1(fn, ns.Type, &nx.Ninit, typename(ns.Type), ns,
@@ -2949,9 +2949,9 @@
 // Also works if b is a string.
 //
 func copyany(n *Node, init *Nodes, runtimecall bool) *Node {
-	if haspointers(n.Left.Type.Type) {
+	if haspointers(n.Left.Type.Elem()) {
 		fn := writebarrierfn("typedslicecopy", n.Left.Type, n.Right.Type)
-		return mkcall1(fn, n.Type, init, typename(n.Left.Type.Type), n.Left, n.Right)
+		return mkcall1(fn, n.Type, init, typename(n.Left.Type.Elem()), n.Left, n.Right)
 	}
 
 	if runtimecall {
@@ -2962,7 +2962,7 @@
 			fn = syslook("slicecopy")
 		}
 		fn = substArgTypes(fn, n.Left.Type, n.Right.Type)
-		return mkcall1(fn, n.Type, init, n.Left, n.Right, Nodintconst(n.Left.Type.Type.Width))
+		return mkcall1(fn, n.Type, init, n.Left, n.Right, Nodintconst(n.Left.Type.Elem().Width))
 	}
 
 	n.Left = walkexpr(n.Left, init)
@@ -2991,10 +2991,10 @@
 	// Call memmove.
 	fn := syslook("memmove")
 
-	fn = substArgTypes(fn, nl.Type.Type, nl.Type.Type)
+	fn = substArgTypes(fn, nl.Type.Elem(), nl.Type.Elem())
 	nwid := temp(Types[TUINTPTR])
 	l = append(l, Nod(OAS, nwid, conv(nlen, Types[TUINTPTR])))
-	nwid = Nod(OMUL, nwid, Nodintconst(nl.Type.Type.Width))
+	nwid = Nod(OMUL, nwid, Nodintconst(nl.Type.Elem().Width))
 	l = append(l, mkcall1(fn, nil, init, nto, nfrm, nwid))
 
 	typecheckslice(l, Etop)
@@ -3136,7 +3136,7 @@
 	}
 
 	var expr *Node
-	if t.Etype == TARRAY && t.Bound <= 4 && issimple[t.Type.Etype] {
+	if t.Etype == TARRAY && t.Bound <= 4 && issimple[t.Elem().Etype] {
 		// Four or fewer elements of a basic type.
 		// Unroll comparisons.
 		var li *Node
@@ -3773,7 +3773,7 @@
 
 	t := n.Left.Type
 	if Isptr[t.Etype] {
-		t = t.Type
+		t = t.Elem()
 	}
 	field := dotField[typeSym{t.Orig, n.Sym}]
 	if field == nil {
@@ -3785,7 +3785,7 @@
 
 	outer := n.Left.Type
 	if Isptr[outer.Etype] {
-		outer = outer.Type
+		outer = outer.Elem()
 	}
 	if outer.Sym == nil {
 		Yyerror("tracked field must be in named struct type")