[dev.cmdgo] all: merge master (67f7e16) into dev.cmdgo

Merge List:

+ 2021-08-27 67f7e16bcc encoding/gob: optimize decoding of []byte
+ 2021-08-27 2c60a99f72 cmd/compile/internal/syntax: make valid type parameter list in presence of errors
+ 2021-08-27 d350a66532 cmd/compile: eagerly CalcStructSize for synthetic ABI types
+ 2021-08-27 d7e2e2ec2b cmd/compile: delay fillinMethods to deal with mutually-recursive types
+ 2021-08-27 c927599783 cmd/compile: eliminate repetitive code
+ 2021-08-27 62f88b6dc8 cmd/compile: add types.RecalcSize
+ 2021-08-27 e7eee5e265 cmd/compile: remove ssagen/pgen_test.go
+ 2021-08-27 f153b6739b cmd/compile: use typecheck.InitUniverse in unit tests
+ 2021-08-26 967a8017f7 cmd/compile: move types init code into package types
+ 2021-08-26 af80af22b5 cmd/compile/internal/types2: do not declare new methods on instantiated types
+ 2021-08-26 03db2c2413 cmd/compile/internal/types2: implement TypeList.String (debugging support)
+ 2021-08-26 c9e05fdcf7 cmd/compile: fix reference to generic type needed by crawler
+ 2021-08-26 eb6a07fcf9 cmd/compile: unexport Type.Vargen
+ 2021-08-26 3836983779 cmd/compile/internal/types: unexport Type.Extra
+ 2021-08-26 1f8d4562de cmd/compile: change typecheck.iscmp into ir.Op.IsCmp

Change-Id: I95c040a0e984a13a3b12c50458148007221ee300
diff --git a/src/cmd/compile/internal/abi/abiutils.go b/src/cmd/compile/internal/abi/abiutils.go
index d657ddc..24f34b8 100644
--- a/src/cmd/compile/internal/abi/abiutils.go
+++ b/src/cmd/compile/internal/abi/abiutils.go
@@ -722,14 +722,17 @@
 			types.NewField(nxp, fname("len"), ui),
 			types.NewField(nxp, fname("cap"), ui),
 		})
+		types.CalcStructSize(synthSlice)
 		synthString = types.NewStruct(types.NoPkg, []*types.Field{
 			types.NewField(nxp, fname("data"), unsp),
 			types.NewField(nxp, fname("len"), ui),
 		})
+		types.CalcStructSize(synthString)
 		synthIface = types.NewStruct(types.NoPkg, []*types.Field{
 			types.NewField(nxp, fname("f1"), unsp),
 			types.NewField(nxp, fname("f2"), unsp),
 		})
+		types.CalcStructSize(synthIface)
 	})
 }
 
diff --git a/src/cmd/compile/internal/gc/main.go b/src/cmd/compile/internal/gc/main.go
index 9660ef9d..8a365f8 100644
--- a/src/cmd/compile/internal/gc/main.go
+++ b/src/cmd/compile/internal/gc/main.go
@@ -84,7 +84,7 @@
 	types.BuiltinPkg.Prefix = "go.builtin"            // not go%2ebuiltin
 
 	// pseudo-package, accessed by import "unsafe"
-	ir.Pkgs.Unsafe = types.NewPkg("unsafe", "unsafe")
+	types.UnsafePkg = types.NewPkg("unsafe", "unsafe")
 
 	// Pseudo-package that contains the compiler's builtin
 	// declarations for package runtime. These are declared in a
diff --git a/src/cmd/compile/internal/ir/node.go b/src/cmd/compile/internal/ir/node.go
index f071cb7..8784f9e 100644
--- a/src/cmd/compile/internal/ir/node.go
+++ b/src/cmd/compile/internal/ir/node.go
@@ -334,6 +334,16 @@
 	OEND
 )
 
+// IsCmp reports whether op is a comparison operation (==, !=, <, <=,
+// >, or >=).
+func (op Op) IsCmp() bool {
+	switch op {
+	case OEQ, ONE, OLT, OLE, OGT, OGE:
+		return true
+	}
+	return false
+}
+
 // Nodes is a pointer to a slice of *Node.
 // For fields that are not used in most nodes, this is used instead of
 // a slice to save space.
diff --git a/src/cmd/compile/internal/ir/scc.go b/src/cmd/compile/internal/ir/scc.go
index 2cfceaa..a42951c 100644
--- a/src/cmd/compile/internal/ir/scc.go
+++ b/src/cmd/compile/internal/ir/scc.go
@@ -116,12 +116,11 @@
 		var i int
 		for i = len(v.stack) - 1; i >= 0; i-- {
 			x := v.stack[i]
+			v.nodeID[x] = ^uint32(0)
 			if x == n {
 				break
 			}
-			v.nodeID[x] = ^uint32(0)
 		}
-		v.nodeID[n] = ^uint32(0)
 		block := v.stack[i:]
 		// Run escape analysis on this set of functions.
 		v.stack = v.stack[:i]
diff --git a/src/cmd/compile/internal/ir/symtab.go b/src/cmd/compile/internal/ir/symtab.go
index 61727fb..1e82618 100644
--- a/src/cmd/compile/internal/ir/symtab.go
+++ b/src/cmd/compile/internal/ir/symtab.go
@@ -68,5 +68,4 @@
 	Go      *types.Pkg
 	Itab    *types.Pkg
 	Runtime *types.Pkg
-	Unsafe  *types.Pkg
 }
diff --git a/src/cmd/compile/internal/noder/decl.go b/src/cmd/compile/internal/noder/decl.go
index b23dd47..54a13b4 100644
--- a/src/cmd/compile/internal/noder/decl.go
+++ b/src/cmd/compile/internal/noder/decl.go
@@ -154,8 +154,7 @@
 	name, obj := g.def(decl.Name)
 	ntyp, otyp := name.Type(), obj.Type()
 	if ir.CurFunc != nil {
-		typecheck.TypeGen++
-		ntyp.Vargen = typecheck.TypeGen
+		ntyp.SetVargen()
 	}
 
 	pragmas := g.pragmaFlags(decl.Pragma, typePragmas)
diff --git a/src/cmd/compile/internal/noder/func.go b/src/cmd/compile/internal/noder/func.go
index 7021381..6077b34 100644
--- a/src/cmd/compile/internal/noder/func.go
+++ b/src/cmd/compile/internal/noder/func.go
@@ -37,8 +37,7 @@
 	// calculated its size, including parameter offsets. Now that we've
 	// created the parameter Names, force a recalculation to ensure
 	// their offsets are correct.
-	typ.Align = 0
-	types.CalcSize(typ)
+	types.RecalcSize(typ)
 
 	if block != nil {
 		typecheck.DeclContext = ir.PAUTO
diff --git a/src/cmd/compile/internal/noder/import.go b/src/cmd/compile/internal/noder/import.go
index 48f0e48..c26340c 100644
--- a/src/cmd/compile/internal/noder/import.go
+++ b/src/cmd/compile/internal/noder/import.go
@@ -198,7 +198,7 @@
 		return nil
 	}
 
-	if pkg != ir.Pkgs.Unsafe && pkg.Height >= myheight {
+	if pkg != types.UnsafePkg && pkg.Height >= myheight {
 		myheight = pkg.Height + 1
 	}
 	return pkg
@@ -231,7 +231,7 @@
 	}
 
 	if path == "unsafe" {
-		pkg1, pkg2 = ir.Pkgs.Unsafe, types2.Unsafe
+		pkg1, pkg2 = types.UnsafePkg, types2.Unsafe
 
 		// TODO(mdempsky): Investigate if this actually matters. Why would
 		// the linker or runtime care whether a package imported unsafe?
diff --git a/src/cmd/compile/internal/noder/irgen.go b/src/cmd/compile/internal/noder/irgen.go
index 29882eb..d53c254 100644
--- a/src/cmd/compile/internal/noder/irgen.go
+++ b/src/cmd/compile/internal/noder/irgen.go
@@ -149,6 +149,9 @@
 	// statements yet.
 	exprStmtOK bool
 
+	// types which we need to finish, by doing g.fillinMethods.
+	typesToFinalize []*typeDelayInfo
+
 	// Fully-instantiated generic types whose methods should be instantiated
 	instTypeList []*types.Type
 
@@ -184,6 +187,11 @@
 	off   int
 }
 
+type typeDelayInfo struct {
+	typ  *types2.Named
+	ntyp *types.Type
+}
+
 func (g *irgen) generate(noders []*noder) {
 	types.LocalPkg.Name = g.self.Name()
 	types.LocalPkg.Height = g.self.Height()
diff --git a/src/cmd/compile/internal/noder/noder.go b/src/cmd/compile/internal/noder/noder.go
index e1b485b..61a7f8a 100644
--- a/src/cmd/compile/internal/noder/noder.go
+++ b/src/cmd/compile/internal/noder/noder.go
@@ -384,7 +384,7 @@
 		return
 	}
 
-	if ipkg == ir.Pkgs.Unsafe {
+	if ipkg == types.UnsafePkg {
 		p.importedUnsafe = true
 	}
 	if ipkg.Path == "embed" {
diff --git a/src/cmd/compile/internal/noder/reader.go b/src/cmd/compile/internal/noder/reader.go
index 985453a..e7a9d96 100644
--- a/src/cmd/compile/internal/noder/reader.go
+++ b/src/cmd/compile/internal/noder/reader.go
@@ -428,7 +428,7 @@
 		pos := r.pos()
 		pkg, sym := r.selector()
 		tpkg = pkg
-		mtyp := r.signature(pkg, typecheck.FakeRecv())
+		mtyp := r.signature(pkg, types.FakeRecv())
 		methods[i] = types.NewField(pos, sym, mtyp)
 	}
 	for i := range embeddeds {
@@ -540,7 +540,7 @@
 	if tag == objStub {
 		assert(!sym.IsBlank())
 		switch sym.Pkg {
-		case types.BuiltinPkg, ir.Pkgs.Unsafe:
+		case types.BuiltinPkg, types.UnsafePkg:
 			return sym.Def.(ir.Node)
 		}
 		if pri, ok := objReader[sym]; ok {
diff --git a/src/cmd/compile/internal/noder/stencil.go b/src/cmd/compile/internal/noder/stencil.go
index b3ff4b8..0c6bb51 100644
--- a/src/cmd/compile/internal/noder/stencil.go
+++ b/src/cmd/compile/internal/noder/stencil.go
@@ -903,7 +903,7 @@
 		ir.EditChildren(m, edit)
 
 		m.SetTypecheck(1)
-		if typecheck.IsCmp(x.Op()) {
+		if x.Op().IsCmp() {
 			transformCompare(m.(*ir.BinaryExpr))
 		} else {
 			switch x.Op() {
diff --git a/src/cmd/compile/internal/noder/types.go b/src/cmd/compile/internal/noder/types.go
index c9f7c2b..e00a3a5 100644
--- a/src/cmd/compile/internal/noder/types.go
+++ b/src/cmd/compile/internal/noder/types.go
@@ -22,7 +22,7 @@
 	case g.self:
 		return types.LocalPkg
 	case types2.Unsafe:
-		return ir.Pkgs.Unsafe
+		return types.UnsafePkg
 	}
 	return types.NewPkg(pkg.Path(), pkg.Name())
 }
@@ -35,6 +35,16 @@
 	types.DeferCheckSize()
 	res := g.typ1(typ)
 	types.ResumeCheckSize()
+
+	// Finish up any types on typesToFinalize, now that we are at the top of a
+	// fully-defined (possibly recursive) type. fillinMethods could create more
+	// types to finalize.
+	for len(g.typesToFinalize) > 0 {
+		l := len(g.typesToFinalize)
+		info := g.typesToFinalize[l-1]
+		g.typesToFinalize = g.typesToFinalize[:l-1]
+		g.fillinMethods(info.typ, info.ntyp)
+	}
 	return res
 }
 
@@ -118,9 +128,14 @@
 				return s.Def.Type()
 			}
 
+			// Make sure the base generic type exists in type1 (it may
+			// not yet if we are referecing an imported generic type, as
+			// opposed to a generic type declared in this package).
+			_ = g.obj(typ.Orig().Obj())
+
 			// Create a forwarding type first and put it in the g.typs
 			// map, in order to deal with recursive generic types
-			// (including via method signatures).. Set up the extra
+			// (including via method signatures). Set up the extra
 			// ntyp information (Def, RParams, which may set
 			// HasTParam) before translating the underlying type
 			// itself, so we handle recursion correctly.
@@ -146,10 +161,19 @@
 			ntyp.SetRParams(rparams)
 			//fmt.Printf("Saw new type %v %v\n", instName, ntyp.HasTParam())
 
-			ntyp.SetUnderlying(g.typ1(typ.Underlying()))
-			g.fillinMethods(typ, ntyp)
 			// Save the symbol for the base generic type.
 			ntyp.OrigSym = g.pkg(typ.Obj().Pkg()).Lookup(typ.Obj().Name())
+			ntyp.SetUnderlying(g.typ1(typ.Underlying()))
+			if typ.NumMethods() != 0 {
+				// Save a delayed call to g.fillinMethods() (once
+				// potentially recursive types have been fully
+				// resolved).
+				g.typesToFinalize = append(g.typesToFinalize,
+					&typeDelayInfo{
+						typ:  typ,
+						ntyp: ntyp,
+					})
+			}
 			return ntyp
 		}
 		obj := g.obj(typ.Obj())
@@ -201,7 +225,7 @@
 		methods := make([]*types.Field, typ.NumExplicitMethods())
 		for i := range methods {
 			m := typ.ExplicitMethod(i)
-			mtyp := g.signature(typecheck.FakeRecv(), m.Type().(*types2.Signature))
+			mtyp := g.signature(types.FakeRecv(), m.Type().(*types2.Signature))
 			methods[i] = types.NewField(g.pos(m), g.selector(m), mtyp)
 		}
 
@@ -261,76 +285,75 @@
 	}
 }
 
-// fillinMethods fills in the method name nodes and types for a defined type. This
-// is needed for later typechecking when looking up methods of instantiated types,
-// and for actually generating the methods for instantiated types.
+// fillinMethods fills in the method name nodes and types for a defined type with at
+// least one method. This is needed for later typechecking when looking up methods of
+// instantiated types, and for actually generating the methods for instantiated
+// types.
 func (g *irgen) fillinMethods(typ *types2.Named, ntyp *types.Type) {
-	if typ.NumMethods() != 0 {
-		targs2 := typ.TArgs()
-		targs := make([]*types.Type, targs2.Len())
-		for i := range targs {
-			targs[i] = g.typ1(targs2.At(i))
-		}
+	targs2 := typ.TArgs()
+	targs := make([]*types.Type, targs2.Len())
+	for i := range targs {
+		targs[i] = g.typ1(targs2.At(i))
+	}
 
-		methods := make([]*types.Field, typ.NumMethods())
-		for i := range methods {
-			m := typ.Method(i)
-			recvType := deref2(types2.AsSignature(m.Type()).Recv().Type())
-			var meth *ir.Name
-			if m.Pkg() != g.self {
-				// Imported methods cannot be loaded by name (what
-				// g.obj() does) - they must be loaded via their
-				// type.
-				meth = g.obj(recvType.(*types2.Named).Obj()).Type().Methods().Index(i).Nname.(*ir.Name)
+	methods := make([]*types.Field, typ.NumMethods())
+	for i := range methods {
+		m := typ.Method(i)
+		recvType := deref2(types2.AsSignature(m.Type()).Recv().Type())
+		var meth *ir.Name
+		if m.Pkg() != g.self {
+			// Imported methods cannot be loaded by name (what
+			// g.obj() does) - they must be loaded via their
+			// type.
+			meth = g.obj(recvType.(*types2.Named).Obj()).Type().Methods().Index(i).Nname.(*ir.Name)
+		} else {
+			meth = g.obj(m)
+		}
+		if recvType != types2.Type(typ) {
+			// Unfortunately, meth is the type of the method of the
+			// generic type, so we have to do a substitution to get
+			// the name/type of the method of the instantiated type,
+			// using m.Type().RParams() and typ.TArgs()
+			inst2 := instTypeName2("", typ.TArgs())
+			name := meth.Sym().Name
+			i1 := strings.Index(name, "[")
+			i2 := strings.Index(name[i1:], "]")
+			assert(i1 >= 0 && i2 >= 0)
+			// Generate the name of the instantiated method.
+			name = name[0:i1] + inst2 + name[i1+i2+1:]
+			newsym := meth.Sym().Pkg.Lookup(name)
+			var meth2 *ir.Name
+			if newsym.Def != nil {
+				meth2 = newsym.Def.(*ir.Name)
 			} else {
-				meth = g.obj(m)
-			}
-			if recvType != types2.Type(typ) {
-				// Unfortunately, meth is the type of the method of the
-				// generic type, so we have to do a substitution to get
-				// the name/type of the method of the instantiated type,
-				// using m.Type().RParams() and typ.TArgs()
-				inst2 := instTypeName2("", typ.TArgs())
-				name := meth.Sym().Name
-				i1 := strings.Index(name, "[")
-				i2 := strings.Index(name[i1:], "]")
-				assert(i1 >= 0 && i2 >= 0)
-				// Generate the name of the instantiated method.
-				name = name[0:i1] + inst2 + name[i1+i2+1:]
-				newsym := meth.Sym().Pkg.Lookup(name)
-				var meth2 *ir.Name
-				if newsym.Def != nil {
-					meth2 = newsym.Def.(*ir.Name)
-				} else {
-					meth2 = ir.NewNameAt(meth.Pos(), newsym)
-					rparams := types2.AsSignature(m.Type()).RParams()
-					tparams := make([]*types.Type, rparams.Len())
-					for i := range tparams {
-						tparams[i] = g.typ1(rparams.At(i))
-					}
-					assert(len(tparams) == len(targs))
-					ts := typecheck.Tsubster{
-						Tparams: tparams,
-						Targs:   targs,
-					}
-					// Do the substitution of the type
-					meth2.SetType(ts.Typ(meth.Type()))
-					// Add any new fully instantiated types
-					// seen during the substitution to
-					// g.instTypeList.
-					g.instTypeList = append(g.instTypeList, ts.InstTypeList...)
-					newsym.Def = meth2
+				meth2 = ir.NewNameAt(meth.Pos(), newsym)
+				rparams := types2.AsSignature(m.Type()).RParams()
+				tparams := make([]*types.Type, rparams.Len())
+				for i := range tparams {
+					tparams[i] = g.typ1(rparams.At(i))
 				}
-				meth = meth2
+				assert(len(tparams) == len(targs))
+				ts := typecheck.Tsubster{
+					Tparams: tparams,
+					Targs:   targs,
+				}
+				// Do the substitution of the type
+				meth2.SetType(ts.Typ(meth.Type()))
+				// Add any new fully instantiated types
+				// seen during the substitution to
+				// g.instTypeList.
+				g.instTypeList = append(g.instTypeList, ts.InstTypeList...)
+				newsym.Def = meth2
 			}
-			methods[i] = types.NewField(meth.Pos(), g.selector(m), meth.Type())
-			methods[i].Nname = meth
+			meth = meth2
 		}
-		ntyp.Methods().Set(methods)
-		if !ntyp.HasTParam() && !ntyp.HasShape() {
-			// Generate all the methods for a new fully-instantiated type.
-			g.instTypeList = append(g.instTypeList, ntyp)
-		}
+		methods[i] = types.NewField(meth.Pos(), g.selector(m), meth.Type())
+		methods[i].Nname = meth
+	}
+	ntyp.Methods().Set(methods)
+	if !ntyp.HasTParam() && !ntyp.HasShape() {
+		// Generate all the methods for a new fully-instantiated type.
+		g.instTypeList = append(g.instTypeList, ntyp)
 	}
 }
 
diff --git a/src/cmd/compile/internal/reflectdata/reflect.go b/src/cmd/compile/internal/reflectdata/reflect.go
index 9b9efe0..ca48db0 100644
--- a/src/cmd/compile/internal/reflectdata/reflect.go
+++ b/src/cmd/compile/internal/reflectdata/reflect.go
@@ -927,7 +927,7 @@
 
 func writeType(t *types.Type) *obj.LSym {
 	t = formalType(t)
-	if t.IsUntyped() {
+	if t.IsUntyped() || t.HasTParam() {
 		base.Fatalf("writeType %v", t)
 	}
 
@@ -1726,7 +1726,7 @@
 		// Local defined type; our responsibility.
 		return true
 
-	case base.Ctxt.Pkgpath == "runtime" && (sym.Pkg == types.BuiltinPkg || sym.Pkg == ir.Pkgs.Unsafe):
+	case base.Ctxt.Pkgpath == "runtime" && (sym.Pkg == types.BuiltinPkg || sym.Pkg == types.UnsafePkg):
 		// Package runtime is responsible for including code for builtin
 		// types (predeclared and package unsafe).
 		return true
diff --git a/src/cmd/compile/internal/ssa/export_test.go b/src/cmd/compile/internal/ssa/export_test.go
index 6d3c0f3..c4e87ec 100644
--- a/src/cmd/compile/internal/ssa/export_test.go
+++ b/src/cmd/compile/internal/ssa/export_test.go
@@ -5,14 +5,16 @@
 package ssa
 
 import (
+	"testing"
+
 	"cmd/compile/internal/ir"
+	"cmd/compile/internal/typecheck"
 	"cmd/compile/internal/types"
 	"cmd/internal/obj"
 	"cmd/internal/obj/arm64"
 	"cmd/internal/obj/s390x"
 	"cmd/internal/obj/x86"
 	"cmd/internal/src"
-	"testing"
 )
 
 var CheckFunc = checkFunc
@@ -104,33 +106,12 @@
 var testTypes Types
 
 func init() {
-	// Initialize just enough of the universe and the types package to make our tests function.
-	// TODO(josharian): move universe initialization to the types package,
-	// so this test setup can share it.
+	// TODO(mdempsky): Push into types.InitUniverse or typecheck.InitUniverse.
+	types.PtrSize = 8
+	types.RegSize = 8
+	types.MaxWidth = 1 << 50
 
-	for _, typ := range [...]struct {
-		width int64
-		et    types.Kind
-	}{
-		{1, types.TINT8},
-		{1, types.TUINT8},
-		{1, types.TBOOL},
-		{2, types.TINT16},
-		{2, types.TUINT16},
-		{4, types.TINT32},
-		{4, types.TUINT32},
-		{4, types.TFLOAT32},
-		{4, types.TFLOAT64},
-		{8, types.TUINT64},
-		{8, types.TINT64},
-		{8, types.TINT},
-		{8, types.TUINTPTR},
-	} {
-		t := types.New(typ.et)
-		t.Width = typ.width
-		t.Align = uint8(typ.width)
-		types.Types[typ.et] = t
-	}
+	typecheck.InitUniverse()
 	testTypes.SetTypPtrs()
 }
 
diff --git a/src/cmd/compile/internal/ssagen/pgen.go b/src/cmd/compile/internal/ssagen/pgen.go
index 93157bf..0ddf11b 100644
--- a/src/cmd/compile/internal/ssagen/pgen.go
+++ b/src/cmd/compile/internal/ssagen/pgen.go
@@ -75,7 +75,22 @@
 // allocate space. In particular, it excludes arguments and results, which are in
 // the callers frame.
 func needAlloc(n *ir.Name) bool {
-	return n.Class == ir.PAUTO || n.Class == ir.PPARAMOUT && n.IsOutputParamInRegisters()
+	if n.Op() != ir.ONAME {
+		base.FatalfAt(n.Pos(), "%v has unexpected Op %v", n, n.Op())
+	}
+
+	switch n.Class {
+	case ir.PAUTO:
+		return true
+	case ir.PPARAM:
+		return false
+	case ir.PPARAMOUT:
+		return n.IsOutputParamInRegisters()
+
+	default:
+		base.FatalfAt(n.Pos(), "%v has unexpected Class %v", n, n.Class)
+		return false
+	}
 }
 
 func (s *ssafn) AllocFrame(f *ssa.Func) {
diff --git a/src/cmd/compile/internal/ssagen/pgen_test.go b/src/cmd/compile/internal/ssagen/pgen_test.go
deleted file mode 100644
index 69ed8ad..0000000
--- a/src/cmd/compile/internal/ssagen/pgen_test.go
+++ /dev/null
@@ -1,209 +0,0 @@
-// Copyright 2015 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package ssagen
-
-import (
-	"reflect"
-	"sort"
-	"testing"
-
-	"cmd/compile/internal/ir"
-	"cmd/compile/internal/typecheck"
-	"cmd/compile/internal/types"
-	"cmd/internal/src"
-)
-
-func typeWithoutPointers() *types.Type {
-	return types.NewStruct(types.NoPkg, []*types.Field{
-		types.NewField(src.NoXPos, nil, types.New(types.TINT)),
-	})
-}
-
-func typeWithPointers() *types.Type {
-	return types.NewStruct(types.NoPkg, []*types.Field{
-		types.NewField(src.NoXPos, nil, types.NewPtr(types.New(types.TINT))),
-	})
-}
-
-func markUsed(n *ir.Name) *ir.Name {
-	n.SetUsed(true)
-	return n
-}
-
-func markNeedZero(n *ir.Name) *ir.Name {
-	n.SetNeedzero(true)
-	return n
-}
-
-// Test all code paths for cmpstackvarlt.
-func TestCmpstackvar(t *testing.T) {
-	nod := func(xoffset int64, t *types.Type, s *types.Sym, cl ir.Class) *ir.Name {
-		if s == nil {
-			s = &types.Sym{Name: "."}
-		}
-		n := typecheck.NewName(s)
-		n.SetType(t)
-		n.SetFrameOffset(xoffset)
-		n.Class = cl
-		return n
-	}
-	testdata := []struct {
-		a, b *ir.Name
-		lt   bool
-	}{
-		{
-			nod(0, nil, nil, ir.PAUTO),
-			nod(0, nil, nil, ir.PFUNC),
-			false,
-		},
-		{
-			nod(0, nil, nil, ir.PFUNC),
-			nod(0, nil, nil, ir.PAUTO),
-			true,
-		},
-		{
-			nod(0, nil, nil, ir.PFUNC),
-			nod(10, nil, nil, ir.PFUNC),
-			true,
-		},
-		{
-			nod(20, nil, nil, ir.PFUNC),
-			nod(10, nil, nil, ir.PFUNC),
-			false,
-		},
-		{
-			nod(10, nil, nil, ir.PFUNC),
-			nod(10, nil, nil, ir.PFUNC),
-			false,
-		},
-		{
-			nod(10, nil, nil, ir.PPARAM),
-			nod(20, nil, nil, ir.PPARAMOUT),
-			true,
-		},
-		{
-			nod(10, nil, nil, ir.PPARAMOUT),
-			nod(20, nil, nil, ir.PPARAM),
-			true,
-		},
-		{
-			markUsed(nod(0, nil, nil, ir.PAUTO)),
-			nod(0, nil, nil, ir.PAUTO),
-			true,
-		},
-		{
-			nod(0, nil, nil, ir.PAUTO),
-			markUsed(nod(0, nil, nil, ir.PAUTO)),
-			false,
-		},
-		{
-			nod(0, typeWithoutPointers(), nil, ir.PAUTO),
-			nod(0, typeWithPointers(), nil, ir.PAUTO),
-			false,
-		},
-		{
-			nod(0, typeWithPointers(), nil, ir.PAUTO),
-			nod(0, typeWithoutPointers(), nil, ir.PAUTO),
-			true,
-		},
-		{
-			markNeedZero(nod(0, &types.Type{}, nil, ir.PAUTO)),
-			nod(0, &types.Type{}, nil, ir.PAUTO),
-			true,
-		},
-		{
-			nod(0, &types.Type{}, nil, ir.PAUTO),
-			markNeedZero(nod(0, &types.Type{}, nil, ir.PAUTO)),
-			false,
-		},
-		{
-			nod(0, &types.Type{Width: 1}, nil, ir.PAUTO),
-			nod(0, &types.Type{Width: 2}, nil, ir.PAUTO),
-			false,
-		},
-		{
-			nod(0, &types.Type{Width: 2}, nil, ir.PAUTO),
-			nod(0, &types.Type{Width: 1}, nil, ir.PAUTO),
-			true,
-		},
-		{
-			nod(0, &types.Type{}, &types.Sym{Name: "abc"}, ir.PAUTO),
-			nod(0, &types.Type{}, &types.Sym{Name: "xyz"}, ir.PAUTO),
-			true,
-		},
-		{
-			nod(0, &types.Type{}, &types.Sym{Name: "abc"}, ir.PAUTO),
-			nod(0, &types.Type{}, &types.Sym{Name: "abc"}, ir.PAUTO),
-			false,
-		},
-		{
-			nod(0, &types.Type{}, &types.Sym{Name: "xyz"}, ir.PAUTO),
-			nod(0, &types.Type{}, &types.Sym{Name: "abc"}, ir.PAUTO),
-			false,
-		},
-	}
-	for _, d := range testdata {
-		got := cmpstackvarlt(d.a, d.b)
-		if got != d.lt {
-			t.Errorf("want %v < %v", d.a, d.b)
-		}
-		// If we expect a < b to be true, check that b < a is false.
-		if d.lt && cmpstackvarlt(d.b, d.a) {
-			t.Errorf("unexpected %v < %v", d.b, d.a)
-		}
-	}
-}
-
-func TestStackvarSort(t *testing.T) {
-	nod := func(xoffset int64, t *types.Type, s *types.Sym, cl ir.Class) *ir.Name {
-		n := typecheck.NewName(s)
-		n.SetType(t)
-		n.SetFrameOffset(xoffset)
-		n.Class = cl
-		return n
-	}
-	inp := []*ir.Name{
-		nod(0, &types.Type{}, &types.Sym{}, ir.PFUNC),
-		nod(0, &types.Type{}, &types.Sym{}, ir.PAUTO),
-		nod(0, &types.Type{}, &types.Sym{}, ir.PFUNC),
-		nod(10, &types.Type{}, &types.Sym{}, ir.PFUNC),
-		nod(20, &types.Type{}, &types.Sym{}, ir.PFUNC),
-		markUsed(nod(0, &types.Type{}, &types.Sym{}, ir.PAUTO)),
-		nod(0, typeWithoutPointers(), &types.Sym{}, ir.PAUTO),
-		nod(0, &types.Type{}, &types.Sym{}, ir.PAUTO),
-		markNeedZero(nod(0, &types.Type{}, &types.Sym{}, ir.PAUTO)),
-		nod(0, &types.Type{Width: 1}, &types.Sym{}, ir.PAUTO),
-		nod(0, &types.Type{Width: 2}, &types.Sym{}, ir.PAUTO),
-		nod(0, &types.Type{}, &types.Sym{Name: "abc"}, ir.PAUTO),
-		nod(0, &types.Type{}, &types.Sym{Name: "xyz"}, ir.PAUTO),
-	}
-	want := []*ir.Name{
-		nod(0, &types.Type{}, &types.Sym{}, ir.PFUNC),
-		nod(0, &types.Type{}, &types.Sym{}, ir.PFUNC),
-		nod(10, &types.Type{}, &types.Sym{}, ir.PFUNC),
-		nod(20, &types.Type{}, &types.Sym{}, ir.PFUNC),
-		markUsed(nod(0, &types.Type{}, &types.Sym{}, ir.PAUTO)),
-		markNeedZero(nod(0, &types.Type{}, &types.Sym{}, ir.PAUTO)),
-		nod(0, &types.Type{Width: 2}, &types.Sym{}, ir.PAUTO),
-		nod(0, &types.Type{Width: 1}, &types.Sym{}, ir.PAUTO),
-		nod(0, &types.Type{}, &types.Sym{}, ir.PAUTO),
-		nod(0, &types.Type{}, &types.Sym{}, ir.PAUTO),
-		nod(0, &types.Type{}, &types.Sym{Name: "abc"}, ir.PAUTO),
-		nod(0, &types.Type{}, &types.Sym{Name: "xyz"}, ir.PAUTO),
-		nod(0, typeWithoutPointers(), &types.Sym{}, ir.PAUTO),
-	}
-	sort.Sort(byStackVar(inp))
-	if !reflect.DeepEqual(want, inp) {
-		t.Error("sort failed")
-		for i := range inp {
-			g := inp[i]
-			w := want[i]
-			eq := reflect.DeepEqual(w, g)
-			if !eq {
-				t.Log(i, w, g)
-			}
-		}
-	}
-}
diff --git a/src/cmd/compile/internal/syntax/dumper_test.go b/src/cmd/compile/internal/syntax/dumper_test.go
index 22680dc..033283a 100644
--- a/src/cmd/compile/internal/syntax/dumper_test.go
+++ b/src/cmd/compile/internal/syntax/dumper_test.go
@@ -13,11 +13,7 @@
 		t.Skip("skipping test in short mode")
 	}
 
-	// provide a no-op error handler so parsing doesn't stop after first error
-	ast, err := ParseFile(*src_, func(error) {}, nil, CheckBranches)
-	if err != nil {
-		t.Error(err)
-	}
+	ast, _ := ParseFile(*src_, func(err error) { t.Error(err) }, nil, CheckBranches|AllowGenerics)
 
 	if ast != nil {
 		Fdump(testOut(), ast)
diff --git a/src/cmd/compile/internal/syntax/parser.go b/src/cmd/compile/internal/syntax/parser.go
index fd97279..3d1ca9d 100644
--- a/src/cmd/compile/internal/syntax/parser.go
+++ b/src/cmd/compile/internal/syntax/parser.go
@@ -1924,7 +1924,7 @@
 	}
 
 	// distribute parameter types (len(list) > 0)
-	if named == 0 {
+	if named == 0 && !requireNames {
 		// all unnamed => found names are named types
 		for _, par := range list {
 			if typ := par.Name; typ != nil {
@@ -1932,9 +1932,6 @@
 				par.Name = nil
 			}
 		}
-		if requireNames {
-			p.syntaxErrorAt(list[0].Type.Pos(), "type parameters must be named")
-		}
 	} else if named != len(list) {
 		// some named => all must have names and types
 		var pos Pos // left-most error position (or unknown)
diff --git a/src/cmd/compile/internal/syntax/printer_test.go b/src/cmd/compile/internal/syntax/printer_test.go
index ec4b1de..638e6d4 100644
--- a/src/cmd/compile/internal/syntax/printer_test.go
+++ b/src/cmd/compile/internal/syntax/printer_test.go
@@ -18,11 +18,7 @@
 		t.Skip("skipping test in short mode")
 	}
 
-	// provide a no-op error handler so parsing doesn't stop after first error
-	ast, err := ParseFile(*src_, func(error) {}, nil, 0)
-	if err != nil {
-		t.Error(err)
-	}
+	ast, _ := ParseFile(*src_, func(err error) { t.Error(err) }, nil, AllowGenerics)
 
 	if ast != nil {
 		Fprint(testOut(), ast, LineForm)
diff --git a/src/cmd/compile/internal/typecheck/dcl.go b/src/cmd/compile/internal/typecheck/dcl.go
index 472d8d2..76fc6de 100644
--- a/src/cmd/compile/internal/typecheck/dcl.go
+++ b/src/cmd/compile/internal/typecheck/dcl.go
@@ -314,13 +314,6 @@
 	}
 }
 
-// TODO(mdempsky): Move to package types.
-func FakeRecv() *types.Field {
-	return types.NewField(src.NoXPos, nil, types.FakeRecvType())
-}
-
-var fakeRecvField = FakeRecv
-
 var funcStack []funcStackEnt // stack of previous values of ir.CurFunc/DeclContext
 
 type funcStackEnt struct {
diff --git a/src/cmd/compile/internal/typecheck/expr.go b/src/cmd/compile/internal/typecheck/expr.go
index 7e974df..d83bc65 100644
--- a/src/cmd/compile/internal/typecheck/expr.go
+++ b/src/cmd/compile/internal/typecheck/expr.go
@@ -77,10 +77,6 @@
 	return l, r, t
 }
 
-func IsCmp(op ir.Op) bool {
-	return iscmp[op]
-}
-
 // tcArith typechecks operands of a binary arithmetic expression.
 // The result of tcArith MUST be assigned back to original operands,
 // t is the type of the expression, and should be set by the caller. e.g:
@@ -96,7 +92,7 @@
 		t = r.Type()
 	}
 	aop := ir.OXXX
-	if iscmp[n.Op()] && t.Kind() != types.TIDEAL && !types.Identical(l.Type(), r.Type()) {
+	if n.Op().IsCmp() && t.Kind() != types.TIDEAL && !types.Identical(l.Type(), r.Type()) {
 		// comparison is okay as long as one side is
 		// assignable to the other.  convert so they have
 		// the same type.
diff --git a/src/cmd/compile/internal/typecheck/iexport.go b/src/cmd/compile/internal/typecheck/iexport.go
index 75d6115..82006c3 100644
--- a/src/cmd/compile/internal/typecheck/iexport.go
+++ b/src/cmd/compile/internal/typecheck/iexport.go
@@ -430,7 +430,7 @@
 	}
 
 	// Don't export predeclared declarations.
-	if n.Sym().Pkg == types.BuiltinPkg || n.Sym().Pkg == ir.Pkgs.Unsafe {
+	if n.Sym().Pkg == types.BuiltinPkg || n.Sym().Pkg == types.UnsafePkg {
 		return
 	}
 
@@ -905,7 +905,7 @@
 	// type orderedAbs[T any] T
 	if t.IsTypeParam() && t.Underlying() == t {
 		assert(base.Flag.G > 0)
-		if s.Pkg == types.BuiltinPkg || s.Pkg == ir.Pkgs.Unsafe {
+		if s.Pkg == types.BuiltinPkg || s.Pkg == types.UnsafePkg {
 			base.Fatalf("builtin type missing from typIndex: %v", t)
 		}
 		// Write out the first use of a type param as a qualified ident.
@@ -916,7 +916,7 @@
 	}
 
 	if s != nil {
-		if s.Pkg == types.BuiltinPkg || s.Pkg == ir.Pkgs.Unsafe {
+		if s.Pkg == types.BuiltinPkg || s.Pkg == types.UnsafePkg {
 			base.Fatalf("builtin type missing from typIndex: %v", t)
 		}
 
diff --git a/src/cmd/compile/internal/typecheck/iimport.go b/src/cmd/compile/internal/typecheck/iimport.go
index a1a3ac3..87ad5d1 100644
--- a/src/cmd/compile/internal/typecheck/iimport.go
+++ b/src/cmd/compile/internal/typecheck/iimport.go
@@ -607,7 +607,7 @@
 	case exoticTypeRecv:
 		var rcvr *types.Field
 		if r.bool() { // isFakeRecv
-			rcvr = fakeRecvField()
+			rcvr = types.FakeRecv()
 		} else {
 			rcvr = r.exoticParam()
 		}
@@ -793,7 +793,7 @@
 		for i := range methods {
 			pos := r.pos()
 			sym := r.selector()
-			typ := r.signature(fakeRecvField(), nil)
+			typ := r.signature(types.FakeRecv(), nil)
 
 			methods[i] = types.NewField(pos, sym, typ)
 		}
diff --git a/src/cmd/compile/internal/typecheck/typecheck.go b/src/cmd/compile/internal/typecheck/typecheck.go
index db1b11c..404af5b 100644
--- a/src/cmd/compile/internal/typecheck/typecheck.go
+++ b/src/cmd/compile/internal/typecheck/typecheck.go
@@ -1736,11 +1736,6 @@
 	mapqueue = nil
 }
 
-// TypeGen tracks the number of function-scoped defined types that
-// have been declared. It's used to generate unique linker symbols for
-// their runtime type descriptors.
-var TypeGen int32
-
 func typecheckdeftype(n *ir.Name) {
 	if base.EnableTrace && base.Flag.LowerT {
 		defer tracePrint("typecheckdeftype", n)(nil)
@@ -1748,8 +1743,7 @@
 
 	t := types.NewNamed(n)
 	if n.Curfn != nil {
-		TypeGen++
-		t.Vargen = TypeGen
+		t.SetVargen()
 	}
 
 	if n.Pragma()&ir.NotInHeap != 0 {
diff --git a/src/cmd/compile/internal/typecheck/universe.go b/src/cmd/compile/internal/typecheck/universe.go
index 54f3c89..ebe338e 100644
--- a/src/cmd/compile/internal/typecheck/universe.go
+++ b/src/cmd/compile/internal/typecheck/universe.go
@@ -29,37 +29,6 @@
 	okforarith [types.NTYPE]bool
 )
 
-var basicTypes = [...]struct {
-	name  string
-	etype types.Kind
-}{
-	{"int8", types.TINT8},
-	{"int16", types.TINT16},
-	{"int32", types.TINT32},
-	{"int64", types.TINT64},
-	{"uint8", types.TUINT8},
-	{"uint16", types.TUINT16},
-	{"uint32", types.TUINT32},
-	{"uint64", types.TUINT64},
-	{"float32", types.TFLOAT32},
-	{"float64", types.TFLOAT64},
-	{"complex64", types.TCOMPLEX64},
-	{"complex128", types.TCOMPLEX128},
-	{"bool", types.TBOOL},
-	{"string", types.TSTRING},
-}
-
-var typedefs = [...]struct {
-	name     string
-	etype    types.Kind
-	sameas32 types.Kind
-	sameas64 types.Kind
-}{
-	{"int", types.TINT, types.TINT32, types.TINT64},
-	{"uint", types.TUINT, types.TUINT32, types.TUINT64},
-	{"uintptr", types.TUINTPTR, types.TUINT32, types.TUINT64},
-}
-
 var builtinFuncs = [...]struct {
 	name string
 	op   ir.Op
@@ -94,86 +63,12 @@
 
 // InitUniverse initializes the universe block.
 func InitUniverse() {
-	if types.PtrSize == 0 {
-		base.Fatalf("typeinit before betypeinit")
-	}
-
-	types.SlicePtrOffset = 0
-	types.SliceLenOffset = types.Rnd(types.SlicePtrOffset+int64(types.PtrSize), int64(types.PtrSize))
-	types.SliceCapOffset = types.Rnd(types.SliceLenOffset+int64(types.PtrSize), int64(types.PtrSize))
-	types.SliceSize = types.Rnd(types.SliceCapOffset+int64(types.PtrSize), int64(types.PtrSize))
-
-	// string is same as slice wo the cap
-	types.StringSize = types.Rnd(types.SliceLenOffset+int64(types.PtrSize), int64(types.PtrSize))
-
-	for et := types.Kind(0); et < types.NTYPE; et++ {
-		types.SimType[et] = et
-	}
-
-	types.Types[types.TANY] = types.New(types.TANY)
-	types.Types[types.TINTER] = types.NewInterface(types.LocalPkg, nil)
-
-	defBasic := func(kind types.Kind, pkg *types.Pkg, name string) *types.Type {
-		sym := pkg.Lookup(name)
+	types.InitTypes(func(sym *types.Sym, typ *types.Type) types.Object {
 		n := ir.NewDeclNameAt(src.NoXPos, ir.OTYPE, sym)
-		t := types.NewBasic(kind, n)
-		n.SetType(t)
+		n.SetType(typ)
 		sym.Def = n
-		if kind != types.TANY {
-			types.CalcSize(t)
-		}
-		return t
-	}
-
-	for _, s := range &basicTypes {
-		types.Types[s.etype] = defBasic(s.etype, types.BuiltinPkg, s.name)
-	}
-
-	for _, s := range &typedefs {
-		sameas := s.sameas32
-		if types.PtrSize == 8 {
-			sameas = s.sameas64
-		}
-		types.SimType[s.etype] = sameas
-
-		types.Types[s.etype] = defBasic(s.etype, types.BuiltinPkg, s.name)
-	}
-
-	// We create separate byte and rune types for better error messages
-	// rather than just creating type alias *types.Sym's for the uint8 and
-	// int32 types. Hence, (bytetype|runtype).Sym.isAlias() is false.
-	// TODO(gri) Should we get rid of this special case (at the cost
-	// of less informative error messages involving bytes and runes)?
-	// (Alternatively, we could introduce an OTALIAS node representing
-	// type aliases, albeit at the cost of having to deal with it everywhere).
-	types.ByteType = defBasic(types.TUINT8, types.BuiltinPkg, "byte")
-	types.RuneType = defBasic(types.TINT32, types.BuiltinPkg, "rune")
-
-	// error type
-	s := types.BuiltinPkg.Lookup("error")
-	n := ir.NewDeclNameAt(src.NoXPos, ir.OTYPE, s)
-	types.ErrorType = types.NewNamed(n)
-	types.ErrorType.SetUnderlying(makeErrorInterface())
-	n.SetType(types.ErrorType)
-	s.Def = n
-	types.CalcSize(types.ErrorType)
-
-	// comparable type (interface)
-	s = types.BuiltinPkg.Lookup("comparable")
-	n = ir.NewDeclNameAt(src.NoXPos, ir.OTYPE, s)
-	types.ComparableType = types.NewNamed(n)
-	types.ComparableType.SetUnderlying(makeComparableInterface())
-	n.SetType(types.ComparableType)
-	s.Def = n
-	types.CalcSize(types.ComparableType)
-
-	types.Types[types.TUNSAFEPTR] = defBasic(types.TUNSAFEPTR, ir.Pkgs.Unsafe, "Pointer")
-
-	// simple aliases
-	types.SimType[types.TMAP] = types.TPTR
-	types.SimType[types.TCHAN] = types.TPTR
-	types.SimType[types.TFUNC] = types.TPTR
-	types.SimType[types.TUNSAFEPTR] = types.TPTR
+		return n
+	})
 
 	for _, s := range &builtinFuncs {
 		s2 := types.BuiltinPkg.Lookup(s.name)
@@ -183,13 +78,13 @@
 	}
 
 	for _, s := range &unsafeFuncs {
-		s2 := ir.Pkgs.Unsafe.Lookup(s.name)
+		s2 := types.UnsafePkg.Lookup(s.name)
 		def := NewName(s2)
 		def.BuiltinOp = s.op
 		s2.Def = def
 	}
 
-	s = types.BuiltinPkg.Lookup("true")
+	s := types.BuiltinPkg.Lookup("true")
 	s.Def = ir.NewConstAt(src.NoXPos, s, types.UntypedBool, constant.MakeBool(true))
 
 	s = types.BuiltinPkg.Lookup("false")
@@ -219,19 +114,6 @@
 	s = types.BuiltinPkg.Lookup("iota")
 	s.Def = ir.NewIota(base.Pos, s)
 
-	for et := types.TINT8; et <= types.TUINT64; et++ {
-		types.IsInt[et] = true
-	}
-	types.IsInt[types.TINT] = true
-	types.IsInt[types.TUINT] = true
-	types.IsInt[types.TUINTPTR] = true
-
-	types.IsFloat[types.TFLOAT32] = true
-	types.IsFloat[types.TFLOAT64] = true
-
-	types.IsComplex[types.TCOMPLEX64] = true
-	types.IsComplex[types.TCOMPLEX128] = true
-
 	// initialize okfor
 	for et := types.Kind(0); et < types.NTYPE; et++ {
 		if types.IsInt[et] || et == types.TIDEAL {
@@ -329,28 +211,6 @@
 	// special
 	okfor[ir.OCAP] = okforcap[:]
 	okfor[ir.OLEN] = okforlen[:]
-
-	// comparison
-	iscmp[ir.OLT] = true
-	iscmp[ir.OGT] = true
-	iscmp[ir.OGE] = true
-	iscmp[ir.OLE] = true
-	iscmp[ir.OEQ] = true
-	iscmp[ir.ONE] = true
-}
-
-func makeErrorInterface() *types.Type {
-	sig := types.NewSignature(types.NoPkg, fakeRecvField(), nil, nil, []*types.Field{
-		types.NewField(src.NoXPos, nil, types.Types[types.TSTRING]),
-	})
-	method := types.NewField(src.NoXPos, Lookup("Error"), sig)
-	return types.NewInterface(types.NoPkg, []*types.Field{method})
-}
-
-func makeComparableInterface() *types.Type {
-	sig := types.NewSignature(types.NoPkg, fakeRecvField(), nil, nil, nil)
-	method := types.NewField(src.NoXPos, Lookup("=="), sig)
-	return types.NewInterface(types.NoPkg, []*types.Field{method})
 }
 
 // DeclareUniverse makes the universe block visible within the current package.
diff --git a/src/cmd/compile/internal/types/fmt.go b/src/cmd/compile/internal/types/fmt.go
index 0824f6d..2f81c7b 100644
--- a/src/cmd/compile/internal/types/fmt.go
+++ b/src/cmd/compile/internal/types/fmt.go
@@ -23,6 +23,9 @@
 // LocalPkg is the package being compiled.
 var LocalPkg *Pkg
 
+// UnsafePkg is package unsafe.
+var UnsafePkg *Pkg
+
 // BlankSym is the blank (_) symbol.
 var BlankSym *Sym
 
@@ -298,7 +301,7 @@
 		return
 	}
 	if t.Kind() == TSSA {
-		b.WriteString(t.Extra.(string))
+		b.WriteString(t.extra.(string))
 		return
 	}
 	if t.Kind() == TTUPLE {
@@ -309,7 +312,7 @@
 	}
 
 	if t.Kind() == TRESULTS {
-		tys := t.Extra.(*Results).Types
+		tys := t.extra.(*Results).Types
 		for i, et := range tys {
 			if i > 0 {
 				b.WriteByte(',')
@@ -361,8 +364,8 @@
 		// output too. It seems like it should, but that mode is currently
 		// used in string representation used by reflection, which is
 		// user-visible and doesn't expect this.
-		if mode == fmtTypeID && t.Vargen != 0 {
-			fmt.Fprintf(b, "·%d", t.Vargen)
+		if mode == fmtTypeID && t.vargen != 0 {
+			fmt.Fprintf(b, "·%d", t.vargen)
 		}
 		return
 	}
diff --git a/src/cmd/compile/internal/types/size.go b/src/cmd/compile/internal/types/size.go
index 89391ad..2546f0e 100644
--- a/src/cmd/compile/internal/types/size.go
+++ b/src/cmd/compile/internal/types/size.go
@@ -526,7 +526,7 @@
 		w = calcStructOffset(t1, t1.Recvs(), 0, 0)
 		w = calcStructOffset(t1, t1.Params(), w, RegSize)
 		w = calcStructOffset(t1, t1.Results(), w, RegSize)
-		t1.Extra.(*Func).Argwid = w
+		t1.extra.(*Func).Argwid = w
 		if w%int64(RegSize) != 0 {
 			base.Warn("bad type %v %d\n", t1, w)
 		}
@@ -562,6 +562,14 @@
 	s.Width = calcStructOffset(s, s, 0, 1) // sets align
 }
 
+// RecalcSize is like CalcSize, but recalculates t's size even if it
+// has already been calculated before. It does not recalculate other
+// types.
+func RecalcSize(t *Type) {
+	t.Align = 0
+	CalcSize(t)
+}
+
 // when a type's width should be known, we call CheckSize
 // to compute it.  during a declaration like
 //
diff --git a/src/cmd/compile/internal/types/type.go b/src/cmd/compile/internal/types/type.go
index 875b0ba..e84e89f 100644
--- a/src/cmd/compile/internal/types/type.go
+++ b/src/cmd/compile/internal/types/type.go
@@ -139,7 +139,7 @@
 
 // A Type represents a Go type.
 type Type struct {
-	// Extra contains extra etype-specific fields.
+	// extra contains extra etype-specific fields.
 	// As an optimization, those etype-specific structs which contain exactly
 	// one pointer-shaped field are stored as values rather than pointers when possible.
 	//
@@ -156,7 +156,7 @@
 	// TSLICE: Slice
 	// TSSA: string
 	// TTYPEPARAM:  *Typeparam
-	Extra interface{}
+	extra interface{}
 
 	// Width is the width of this Type in bytes.
 	Width int64 // valid if Align > 0
@@ -178,7 +178,7 @@
 	}
 
 	sym    *Sym  // symbol containing name, for named types
-	Vargen int32 // unique name for OTYPE/ONAME
+	vargen int32 // unique name for OTYPE/ONAME
 
 	kind  Kind  // kind of type
 	Align uint8 // the required alignment of this type, in bytes (0 means Width and Align have not yet been computed)
@@ -325,11 +325,11 @@
 func (t *Type) Pkg() *Pkg {
 	switch t.kind {
 	case TFUNC:
-		return t.Extra.(*Func).pkg
+		return t.extra.(*Func).pkg
 	case TSTRUCT:
-		return t.Extra.(*Struct).pkg
+		return t.extra.(*Struct).pkg
 	case TINTER:
-		return t.Extra.(*Interface).pkg
+		return t.extra.(*Interface).pkg
 	default:
 		base.Fatalf("Pkg: unexpected kind: %v", t)
 		return nil
@@ -349,7 +349,7 @@
 // MapType returns t's extra map-specific fields.
 func (t *Type) MapType() *Map {
 	t.wantEtype(TMAP)
-	return t.Extra.(*Map)
+	return t.extra.(*Map)
 }
 
 // Forward contains Type fields specific to forward types.
@@ -361,7 +361,7 @@
 // ForwardType returns t's extra forward-type-specific fields.
 func (t *Type) ForwardType() *Forward {
 	t.wantEtype(TFORW)
-	return t.Extra.(*Forward)
+	return t.extra.(*Forward)
 }
 
 // Func contains Type fields specific to func types.
@@ -382,7 +382,7 @@
 // FuncType returns t's extra func-specific fields.
 func (t *Type) FuncType() *Func {
 	t.wantEtype(TFUNC)
-	return t.Extra.(*Func)
+	return t.extra.(*Func)
 }
 
 // StructType contains Type fields specific to struct types.
@@ -411,7 +411,7 @@
 // StructType returns t's extra struct-specific fields.
 func (t *Type) StructType() *Struct {
 	t.wantEtype(TSTRUCT)
-	return t.Extra.(*Struct)
+	return t.extra.(*Struct)
 }
 
 // Interface contains Type fields specific to interface types.
@@ -455,7 +455,7 @@
 // ChanType returns t's extra channel-specific fields.
 func (t *Type) ChanType() *Chan {
 	t.wantEtype(TCHAN)
-	return t.Extra.(*Chan)
+	return t.extra.(*Chan)
 }
 
 type Tuple struct {
@@ -590,31 +590,31 @@
 	// TODO(josharian): lazily initialize some of these?
 	switch t.kind {
 	case TMAP:
-		t.Extra = new(Map)
+		t.extra = new(Map)
 	case TFORW:
-		t.Extra = new(Forward)
+		t.extra = new(Forward)
 	case TFUNC:
-		t.Extra = new(Func)
+		t.extra = new(Func)
 	case TSTRUCT:
-		t.Extra = new(Struct)
+		t.extra = new(Struct)
 	case TINTER:
-		t.Extra = new(Interface)
+		t.extra = new(Interface)
 	case TPTR:
-		t.Extra = Ptr{}
+		t.extra = Ptr{}
 	case TCHANARGS:
-		t.Extra = ChanArgs{}
+		t.extra = ChanArgs{}
 	case TFUNCARGS:
-		t.Extra = FuncArgs{}
+		t.extra = FuncArgs{}
 	case TCHAN:
-		t.Extra = new(Chan)
+		t.extra = new(Chan)
 	case TTUPLE:
-		t.Extra = new(Tuple)
+		t.extra = new(Tuple)
 	case TRESULTS:
-		t.Extra = new(Results)
+		t.extra = new(Results)
 	case TTYPEPARAM:
-		t.Extra = new(Typeparam)
+		t.extra = new(Typeparam)
 	case TUNION:
-		t.Extra = new(Union)
+		t.extra = new(Union)
 	}
 	return t
 }
@@ -625,7 +625,7 @@
 		base.Fatalf("NewArray: invalid bound %v", bound)
 	}
 	t := New(TARRAY)
-	t.Extra = &Array{Elem: elem, Bound: bound}
+	t.extra = &Array{Elem: elem, Bound: bound}
 	t.SetNotInHeap(elem.NotInHeap())
 	if elem.HasTParam() {
 		t.SetHasTParam(true)
@@ -646,7 +646,7 @@
 	}
 
 	t := New(TSLICE)
-	t.Extra = Slice{Elem: elem}
+	t.extra = Slice{Elem: elem}
 	elem.cache.slice = t
 	if elem.HasTParam() {
 		t.SetHasTParam(true)
@@ -674,8 +674,8 @@
 
 func NewTuple(t1, t2 *Type) *Type {
 	t := New(TTUPLE)
-	t.Extra.(*Tuple).first = t1
-	t.Extra.(*Tuple).second = t2
+	t.extra.(*Tuple).first = t1
+	t.extra.(*Tuple).second = t2
 	if t1.HasTParam() || t2.HasTParam() {
 		t.SetHasTParam(true)
 	}
@@ -687,7 +687,7 @@
 
 func newResults(types []*Type) *Type {
 	t := New(TRESULTS)
-	t.Extra.(*Results).Types = types
+	t.extra.(*Results).Types = types
 	return t
 }
 
@@ -700,7 +700,7 @@
 
 func newSSA(name string) *Type {
 	t := New(TSSA)
-	t.Extra = name
+	t.extra = name
 	return t
 }
 
@@ -747,7 +747,7 @@
 	}
 
 	t := New(TPTR)
-	t.Extra = Ptr{Elem: elem}
+	t.extra = Ptr{Elem: elem}
 	t.Width = int64(PtrSize)
 	t.Align = uint8(PtrSize)
 	if NewPtrCacheEnabled {
@@ -765,14 +765,14 @@
 // NewChanArgs returns a new TCHANARGS type for channel type c.
 func NewChanArgs(c *Type) *Type {
 	t := New(TCHANARGS)
-	t.Extra = ChanArgs{T: c}
+	t.extra = ChanArgs{T: c}
 	return t
 }
 
 // NewFuncArgs returns a new TFUNCARGS type for func type f.
 func NewFuncArgs(f *Type) *Type {
 	t := New(TFUNCARGS)
-	t.Extra = FuncArgs{T: f}
+	t.extra = FuncArgs{T: f}
 	return t
 }
 
@@ -811,28 +811,28 @@
 		elem := SubstAny(t.Elem(), types)
 		if elem != t.Elem() {
 			t = t.copy()
-			t.Extra = Ptr{Elem: elem}
+			t.extra = Ptr{Elem: elem}
 		}
 
 	case TARRAY:
 		elem := SubstAny(t.Elem(), types)
 		if elem != t.Elem() {
 			t = t.copy()
-			t.Extra.(*Array).Elem = elem
+			t.extra.(*Array).Elem = elem
 		}
 
 	case TSLICE:
 		elem := SubstAny(t.Elem(), types)
 		if elem != t.Elem() {
 			t = t.copy()
-			t.Extra = Slice{Elem: elem}
+			t.extra = Slice{Elem: elem}
 		}
 
 	case TCHAN:
 		elem := SubstAny(t.Elem(), types)
 		if elem != t.Elem() {
 			t = t.copy()
-			t.Extra.(*Chan).Elem = elem
+			t.extra.(*Chan).Elem = elem
 		}
 
 	case TMAP:
@@ -840,8 +840,8 @@
 		elem := SubstAny(t.Elem(), types)
 		if key != t.Key() || elem != t.Elem() {
 			t = t.copy()
-			t.Extra.(*Map).Key = key
-			t.Extra.(*Map).Elem = elem
+			t.extra.(*Map).Key = key
+			t.extra.(*Map).Elem = elem
 		}
 
 	case TFUNC:
@@ -882,26 +882,26 @@
 	// copy any *T Extra fields, to avoid aliasing
 	switch t.kind {
 	case TMAP:
-		x := *t.Extra.(*Map)
-		nt.Extra = &x
+		x := *t.extra.(*Map)
+		nt.extra = &x
 	case TFORW:
-		x := *t.Extra.(*Forward)
-		nt.Extra = &x
+		x := *t.extra.(*Forward)
+		nt.extra = &x
 	case TFUNC:
-		x := *t.Extra.(*Func)
-		nt.Extra = &x
+		x := *t.extra.(*Func)
+		nt.extra = &x
 	case TSTRUCT:
-		x := *t.Extra.(*Struct)
-		nt.Extra = &x
+		x := *t.extra.(*Struct)
+		nt.extra = &x
 	case TINTER:
-		x := *t.Extra.(*Interface)
-		nt.Extra = &x
+		x := *t.extra.(*Interface)
+		nt.extra = &x
 	case TCHAN:
-		x := *t.Extra.(*Chan)
-		nt.Extra = &x
+		x := *t.extra.(*Chan)
+		nt.extra = &x
 	case TARRAY:
-		x := *t.Extra.(*Array)
-		nt.Extra = &x
+		x := *t.extra.(*Array)
+		nt.extra = &x
 	case TTYPEPARAM:
 		base.Fatalf("typeparam types cannot be copied")
 	case TTUPLE, TSSA, TRESULTS:
@@ -970,7 +970,7 @@
 // Key returns the key type of map type t.
 func (t *Type) Key() *Type {
 	t.wantEtype(TMAP)
-	return t.Extra.(*Map).Key
+	return t.extra.(*Map).Key
 }
 
 // Elem returns the type of elements of t.
@@ -978,15 +978,15 @@
 func (t *Type) Elem() *Type {
 	switch t.kind {
 	case TPTR:
-		return t.Extra.(Ptr).Elem
+		return t.extra.(Ptr).Elem
 	case TARRAY:
-		return t.Extra.(*Array).Elem
+		return t.extra.(*Array).Elem
 	case TSLICE:
-		return t.Extra.(Slice).Elem
+		return t.extra.(Slice).Elem
 	case TCHAN:
-		return t.Extra.(*Chan).Elem
+		return t.extra.(*Chan).Elem
 	case TMAP:
-		return t.Extra.(*Map).Elem
+		return t.extra.(*Map).Elem
 	}
 	base.Fatalf("Type.Elem %s", t.kind)
 	return nil
@@ -995,18 +995,18 @@
 // ChanArgs returns the channel type for TCHANARGS type t.
 func (t *Type) ChanArgs() *Type {
 	t.wantEtype(TCHANARGS)
-	return t.Extra.(ChanArgs).T
+	return t.extra.(ChanArgs).T
 }
 
 // FuncArgs returns the func type for TFUNCARGS type t.
 func (t *Type) FuncArgs() *Type {
 	t.wantEtype(TFUNCARGS)
-	return t.Extra.(FuncArgs).T
+	return t.extra.(FuncArgs).T
 }
 
 // IsFuncArgStruct reports whether t is a struct representing function parameters or results.
 func (t *Type) IsFuncArgStruct() bool {
-	return t.kind == TSTRUCT && t.Extra.(*Struct).Funarg != FunargNone
+	return t.kind == TSTRUCT && t.extra.(*Struct).Funarg != FunargNone
 }
 
 // Methods returns a pointer to the base methods (excluding embedding) for type t.
@@ -1037,7 +1037,7 @@
 // Fields returns the fields of struct type t.
 func (t *Type) Fields() *Fields {
 	t.wantEtype(TSTRUCT)
-	return &t.Extra.(*Struct).fields
+	return &t.extra.(*Struct).fields
 }
 
 // Field returns the i'th field of struct type t.
@@ -1091,7 +1091,7 @@
 // It includes the receiver, parameters, and results.
 func (t *Type) ArgWidth() int64 {
 	t.wantEtype(TFUNC)
-	return t.Extra.(*Func).Argwid
+	return t.extra.(*Func).Argwid
 }
 
 func (t *Type) Size() int64 {
@@ -1221,8 +1221,8 @@
 
 	if x.sym != nil {
 		// Syms non-nil, if vargens match then equal.
-		if t.Vargen != x.Vargen {
-			return cmpForNe(t.Vargen < x.Vargen)
+		if t.vargen != x.vargen {
+			return cmpForNe(t.vargen < x.vargen)
 		}
 		return CMPeq
 	}
@@ -1234,8 +1234,8 @@
 		return CMPeq
 
 	case TSSA:
-		tname := t.Extra.(string)
-		xname := x.Extra.(string)
+		tname := t.extra.(string)
+		xname := x.extra.(string)
 		// desire fast sorting, not pretty sorting.
 		if len(tname) == len(xname) {
 			if tname == xname {
@@ -1252,16 +1252,16 @@
 		return CMPlt
 
 	case TTUPLE:
-		xtup := x.Extra.(*Tuple)
-		ttup := t.Extra.(*Tuple)
+		xtup := x.extra.(*Tuple)
+		ttup := t.extra.(*Tuple)
 		if c := ttup.first.Compare(xtup.first); c != CMPeq {
 			return c
 		}
 		return ttup.second.Compare(xtup.second)
 
 	case TRESULTS:
-		xResults := x.Extra.(*Results)
-		tResults := t.Extra.(*Results)
+		xResults := x.extra.(*Results)
+		tResults := t.extra.(*Results)
 		xl, tl := len(xResults.Types), len(tResults.Types)
 		if tl != xl {
 			if tl < xl {
@@ -1548,7 +1548,7 @@
 
 func (t *Type) NumFields() int {
 	if t.kind == TRESULTS {
-		return len(t.Extra.(*Results).Types)
+		return len(t.extra.(*Results).Types)
 	}
 	return t.Fields().Len()
 }
@@ -1556,15 +1556,15 @@
 	if t.kind == TTUPLE {
 		switch i {
 		case 0:
-			return t.Extra.(*Tuple).first
+			return t.extra.(*Tuple).first
 		case 1:
-			return t.Extra.(*Tuple).second
+			return t.extra.(*Tuple).second
 		default:
 			panic("bad tuple index")
 		}
 	}
 	if t.kind == TRESULTS {
-		return t.Extra.(*Results).Types[i]
+		return t.extra.(*Results).Types[i]
 	}
 	return t.Field(i).Type
 }
@@ -1577,7 +1577,7 @@
 
 func (t *Type) NumElem() int64 {
 	t.wantEtype(TARRAY)
-	return t.Extra.(*Array).Bound
+	return t.extra.(*Array).Bound
 }
 
 type componentsIncludeBlankFields bool
@@ -1639,15 +1639,15 @@
 // The direction will be one of Crecv, Csend, or Cboth.
 func (t *Type) ChanDir() ChanDir {
 	t.wantEtype(TCHAN)
-	return t.Extra.(*Chan).Dir
+	return t.extra.(*Chan).Dir
 }
 
 func (t *Type) IsMemory() bool {
-	if t == TypeMem || t.kind == TTUPLE && t.Extra.(*Tuple).second == TypeMem {
+	if t == TypeMem || t.kind == TTUPLE && t.extra.(*Tuple).second == TypeMem {
 		return true
 	}
 	if t.kind == TRESULTS {
-		if types := t.Extra.(*Results).Types; len(types) > 0 && types[len(types)-1] == TypeMem {
+		if types := t.extra.(*Results).Types; len(types) > 0 && types[len(types)-1] == TypeMem {
 			return true
 		}
 	}
@@ -1699,11 +1699,11 @@
 		return !t.Elem().NotInHeap()
 
 	case TTUPLE:
-		ttup := t.Extra.(*Tuple)
+		ttup := t.extra.(*Tuple)
 		return ttup.first.HasPointers() || ttup.second.HasPointers()
 
 	case TRESULTS:
-		types := t.Extra.(*Results).Types
+		types := t.extra.(*Results).Types
 		for _, et := range types {
 			if et.HasPointers() {
 				return true
@@ -1738,6 +1738,10 @@
 	return recvType
 }
 
+func FakeRecv() *Field {
+	return NewField(src.NoXPos, nil, FakeRecvType())
+}
+
 var (
 	// TSSA types. HasPointers assumes these are pointer-free.
 	TypeInvalid   = newSSA("invalid")
@@ -1768,6 +1772,25 @@
 	return nil
 }
 
+// typeGen tracks the number of function-scoped defined types that
+// have been declared. It's used to generate unique linker symbols for
+// their runtime type descriptors.
+var typeGen int32
+
+// SetVargen assigns a unique generation number to type t, which must
+// be a defined type declared within function scope. The generation
+// number is used to distinguish it from other similarly spelled
+// defined types from the same package.
+//
+// TODO(mdempsky): Come up with a better solution.
+func (t *Type) SetVargen() {
+	base.Assertf(t.Sym() != nil, "SetVargen on anonymous type %v", t)
+	base.Assertf(t.vargen == 0, "type %v already has Vargen %v", t, t.vargen)
+
+	typeGen++
+	t.vargen = typeGen
+}
+
 // SetUnderlying sets the underlying type. SetUnderlying automatically updates any
 // types that were waiting for this type to be completed.
 func (t *Type) SetUnderlying(underlying *Type) {
@@ -1781,7 +1804,7 @@
 
 	// TODO(mdempsky): Fix Type rekinding.
 	t.kind = underlying.kind
-	t.Extra = underlying.Extra
+	t.extra = underlying.extra
 	t.Width = underlying.Width
 	t.Align = underlying.Align
 	t.underlying = underlying.underlying
@@ -1865,7 +1888,7 @@
 	if anyBroke(methods) {
 		t.SetBroke(true)
 	}
-	t.Extra.(*Interface).pkg = pkg
+	t.extra.(*Interface).pkg = pkg
 	return t
 }
 
@@ -1874,7 +1897,7 @@
 func NewTypeParam(sym *Sym, index int) *Type {
 	t := New(TTYPEPARAM)
 	t.sym = sym
-	t.Extra.(*Typeparam).index = index
+	t.extra.(*Typeparam).index = index
 	t.SetHasTParam(true)
 	return t
 }
@@ -1882,25 +1905,25 @@
 // Index returns the index of the type param within its param list.
 func (t *Type) Index() int {
 	t.wantEtype(TTYPEPARAM)
-	return t.Extra.(*Typeparam).index
+	return t.extra.(*Typeparam).index
 }
 
 // SetIndex sets the index of the type param within its param list.
 func (t *Type) SetIndex(i int) {
 	t.wantEtype(TTYPEPARAM)
-	t.Extra.(*Typeparam).index = i
+	t.extra.(*Typeparam).index = i
 }
 
 // SetBound sets the bound of a typeparam.
 func (t *Type) SetBound(bound *Type) {
 	t.wantEtype(TTYPEPARAM)
-	t.Extra.(*Typeparam).bound = bound
+	t.extra.(*Typeparam).bound = bound
 }
 
 // Bound returns the bound of a typeparam.
 func (t *Type) Bound() *Type {
 	t.wantEtype(TTYPEPARAM)
-	return t.Extra.(*Typeparam).bound
+	return t.extra.(*Typeparam).bound
 }
 
 // NewUnion returns a new union with the specified set of terms (types). If
@@ -1910,8 +1933,8 @@
 	if len(terms) != len(tildes) {
 		base.Fatalf("Mismatched terms and tildes for NewUnion")
 	}
-	t.Extra.(*Union).terms = terms
-	t.Extra.(*Union).tildes = tildes
+	t.extra.(*Union).terms = terms
+	t.extra.(*Union).tildes = tildes
 	nt := len(terms)
 	for i := 0; i < nt; i++ {
 		if terms[i].HasTParam() {
@@ -1927,14 +1950,14 @@
 // NumTerms returns the number of terms in a union type.
 func (t *Type) NumTerms() int {
 	t.wantEtype(TUNION)
-	return len(t.Extra.(*Union).terms)
+	return len(t.extra.(*Union).terms)
 }
 
 // Term returns ith term of a union type as (term, tilde). If tilde is true, term
 // represents ~T, rather than just T.
 func (t *Type) Term(i int) (*Type, bool) {
 	t.wantEtype(TUNION)
-	u := t.Extra.(*Union)
+	u := t.extra.(*Union)
 	return u.terms[i], u.tildes[i]
 }
 
@@ -1995,7 +2018,7 @@
 	if anyBroke(fields) {
 		t.SetBroke(true)
 	}
-	t.Extra.(*Struct).pkg = pkg
+	t.extra.(*Struct).pkg = pkg
 	if fieldsHasTParam(fields) {
 		t.SetHasTParam(true)
 	}
diff --git a/src/cmd/compile/internal/types/type_test.go b/src/cmd/compile/internal/types/type_test.go
index fe3f380..1fd05b3 100644
--- a/src/cmd/compile/internal/types/type_test.go
+++ b/src/cmd/compile/internal/types/type_test.go
@@ -2,26 +2,25 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-package types_test
+package types
 
 import (
-	"cmd/compile/internal/types"
 	"testing"
 )
 
 func TestSSACompare(t *testing.T) {
-	a := []*types.Type{
-		types.TypeInvalid,
-		types.TypeMem,
-		types.TypeFlags,
-		types.TypeVoid,
-		types.TypeInt128,
+	a := []*Type{
+		TypeInvalid,
+		TypeMem,
+		TypeFlags,
+		TypeVoid,
+		TypeInt128,
 	}
 	for _, x := range a {
 		for _, y := range a {
 			c := x.Compare(y)
-			if x == y && c != types.CMPeq || x != y && c == types.CMPeq {
-				t.Errorf("%s compare %s == %d\n", x.Extra, y.Extra, c)
+			if x == y && c != CMPeq || x != y && c == CMPeq {
+				t.Errorf("%s compare %s == %d\n", x.extra, y.extra, c)
 			}
 		}
 	}
diff --git a/src/cmd/compile/internal/types/universe.go b/src/cmd/compile/internal/types/universe.go
new file mode 100644
index 0000000..abceecd
--- /dev/null
+++ b/src/cmd/compile/internal/types/universe.go
@@ -0,0 +1,144 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package types
+
+import (
+	"cmd/compile/internal/base"
+	"cmd/internal/src"
+)
+
+var basicTypes = [...]struct {
+	name  string
+	etype Kind
+}{
+	{"int8", TINT8},
+	{"int16", TINT16},
+	{"int32", TINT32},
+	{"int64", TINT64},
+	{"uint8", TUINT8},
+	{"uint16", TUINT16},
+	{"uint32", TUINT32},
+	{"uint64", TUINT64},
+	{"float32", TFLOAT32},
+	{"float64", TFLOAT64},
+	{"complex64", TCOMPLEX64},
+	{"complex128", TCOMPLEX128},
+	{"bool", TBOOL},
+	{"string", TSTRING},
+}
+
+var typedefs = [...]struct {
+	name     string
+	etype    Kind
+	sameas32 Kind
+	sameas64 Kind
+}{
+	{"int", TINT, TINT32, TINT64},
+	{"uint", TUINT, TUINT32, TUINT64},
+	{"uintptr", TUINTPTR, TUINT32, TUINT64},
+}
+
+func InitTypes(defTypeName func(sym *Sym, typ *Type) Object) {
+	if PtrSize == 0 {
+		base.Fatalf("typeinit before betypeinit")
+	}
+
+	SlicePtrOffset = 0
+	SliceLenOffset = Rnd(SlicePtrOffset+int64(PtrSize), int64(PtrSize))
+	SliceCapOffset = Rnd(SliceLenOffset+int64(PtrSize), int64(PtrSize))
+	SliceSize = Rnd(SliceCapOffset+int64(PtrSize), int64(PtrSize))
+
+	// string is same as slice wo the cap
+	StringSize = Rnd(SliceLenOffset+int64(PtrSize), int64(PtrSize))
+
+	for et := Kind(0); et < NTYPE; et++ {
+		SimType[et] = et
+	}
+
+	Types[TANY] = New(TANY)
+	Types[TINTER] = NewInterface(LocalPkg, nil)
+
+	defBasic := func(kind Kind, pkg *Pkg, name string) *Type {
+		typ := New(kind)
+		obj := defTypeName(pkg.Lookup(name), typ)
+		typ.sym = obj.Sym()
+		typ.nod = obj
+		if kind != TANY {
+			CheckSize(typ)
+		}
+		return typ
+	}
+
+	for _, s := range &basicTypes {
+		Types[s.etype] = defBasic(s.etype, BuiltinPkg, s.name)
+	}
+
+	for _, s := range &typedefs {
+		sameas := s.sameas32
+		if PtrSize == 8 {
+			sameas = s.sameas64
+		}
+		SimType[s.etype] = sameas
+
+		Types[s.etype] = defBasic(s.etype, BuiltinPkg, s.name)
+	}
+
+	// We create separate byte and rune types for better error messages
+	// rather than just creating type alias *Sym's for the uint8 and
+	// int32  Hence, (bytetype|runtype).Sym.isAlias() is false.
+	// TODO(gri) Should we get rid of this special case (at the cost
+	// of less informative error messages involving bytes and runes)?
+	// (Alternatively, we could introduce an OTALIAS node representing
+	// type aliases, albeit at the cost of having to deal with it everywhere).
+	ByteType = defBasic(TUINT8, BuiltinPkg, "byte")
+	RuneType = defBasic(TINT32, BuiltinPkg, "rune")
+
+	// error type
+	DeferCheckSize()
+	ErrorType = defBasic(TFORW, BuiltinPkg, "error")
+	ErrorType.SetUnderlying(makeErrorInterface())
+	ResumeCheckSize()
+
+	// comparable type (interface)
+	DeferCheckSize()
+	ComparableType = defBasic(TFORW, BuiltinPkg, "comparable")
+	ComparableType.SetUnderlying(makeComparableInterface())
+	ResumeCheckSize()
+
+	Types[TUNSAFEPTR] = defBasic(TUNSAFEPTR, UnsafePkg, "Pointer")
+
+	// simple aliases
+	SimType[TMAP] = TPTR
+	SimType[TCHAN] = TPTR
+	SimType[TFUNC] = TPTR
+	SimType[TUNSAFEPTR] = TPTR
+
+	for et := TINT8; et <= TUINT64; et++ {
+		IsInt[et] = true
+	}
+	IsInt[TINT] = true
+	IsInt[TUINT] = true
+	IsInt[TUINTPTR] = true
+
+	IsFloat[TFLOAT32] = true
+	IsFloat[TFLOAT64] = true
+
+	IsComplex[TCOMPLEX64] = true
+	IsComplex[TCOMPLEX128] = true
+}
+
+func makeErrorInterface() *Type {
+	sig := NewSignature(NoPkg, FakeRecv(), nil, nil, []*Field{
+		NewField(src.NoXPos, nil, Types[TSTRING]),
+	})
+	method := NewField(src.NoXPos, LocalPkg.Lookup("Error"), sig)
+	return NewInterface(NoPkg, []*Field{method})
+}
+
+func makeComparableInterface() *Type {
+	sig := NewSignature(NoPkg, FakeRecv(), nil, nil, nil)
+	method := NewField(src.NoXPos, LocalPkg.Lookup("=="), sig)
+	return NewInterface(NoPkg, []*Field{method})
+}
diff --git a/src/cmd/compile/internal/types2/instantiate.go b/src/cmd/compile/internal/types2/instantiate.go
index f9cde24..4113d24 100644
--- a/src/cmd/compile/internal/types2/instantiate.go
+++ b/src/cmd/compile/internal/types2/instantiate.go
@@ -75,7 +75,7 @@
 func (check *Checker) instantiate(pos syntax.Pos, typ Type, targs []Type, posList []syntax.Pos) (res Type) {
 	assert(check != nil)
 	if check.conf.Trace {
-		check.trace(pos, "-- instantiating %s with %s", typ, typeListString(targs))
+		check.trace(pos, "-- instantiating %s with %s", typ, NewTypeList(targs))
 		check.indent++
 		defer func() {
 			check.indent--
diff --git a/src/cmd/compile/internal/types2/signature.go b/src/cmd/compile/internal/types2/signature.go
index d28e7b8..ddad1f0 100644
--- a/src/cmd/compile/internal/types2/signature.go
+++ b/src/cmd/compile/internal/types2/signature.go
@@ -132,7 +132,7 @@
 				// Also: Don't report an error via genericType since it will be reported
 				//       again when we type-check the signature.
 				// TODO(gri) maybe the receiver should be marked as invalid instead?
-				if recv := asNamed(check.genericType(rname, false)); recv != nil {
+				if recv, _ := check.genericType(rname, false).(*Named); recv != nil {
 					recvTParams = recv.TParams().list()
 				}
 			}
@@ -211,6 +211,12 @@
 			switch T := rtyp.(type) {
 			case *Named:
 				T.expand(nil)
+				// The receiver type may be an instantiated type referred to
+				// by an alias (which cannot have receiver parameters for now).
+				if T.TArgs() != nil && sig.RParams() == nil {
+					check.errorf(recv.pos, "cannot define methods on instantiated type %s", recv.typ)
+					break
+				}
 				// spec: "The type denoted by T is called the receiver base type; it must not
 				// be a pointer or interface type and it must be declared in the same package
 				// as the method."
diff --git a/src/cmd/compile/internal/types2/subst.go b/src/cmd/compile/internal/types2/subst.go
index ff8dd13..7c33e7a 100644
--- a/src/cmd/compile/internal/types2/subst.go
+++ b/src/cmd/compile/internal/types2/subst.go
@@ -281,12 +281,6 @@
 	return string(res[:i])
 }
 
-func typeListString(list []Type) string {
-	var buf bytes.Buffer
-	writeTypeList(&buf, list, nil, nil)
-	return buf.String()
-}
-
 // typOrNil is like typ but if the argument is nil it is replaced with Typ[Invalid].
 // A nil type may appear in pathological cases such as type T[P any] []func(_ T([]_))
 // where an array/slice element is accessed before it is set up.
diff --git a/src/cmd/compile/internal/types2/testdata/fixedbugs/issue47968.go2 b/src/cmd/compile/internal/types2/testdata/fixedbugs/issue47968.go2
new file mode 100644
index 0000000..bbbe680
--- /dev/null
+++ b/src/cmd/compile/internal/types2/testdata/fixedbugs/issue47968.go2
@@ -0,0 +1,21 @@
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package p
+
+type T[P any] struct{}
+
+func (T[P]) m1()
+
+type A1 = T
+
+func (A1[P]) m2() {}
+
+type A2 = T[int]
+
+func (A2 /* ERROR cannot define methods on instantiated type T\[int\] */) m3()   {}
+func (_ /* ERROR cannot define methods on instantiated type T\[int\] */ A2) m4() {}
+
+func (T[int]) m5()                                     {} // int is the type parameter name, not an instantiation
+func (T[* /* ERROR must be an identifier */ int]) m6() {} // syntax error
diff --git a/src/cmd/compile/internal/types2/testdata/fixedbugs/issue47996.go2 b/src/cmd/compile/internal/types2/testdata/fixedbugs/issue47996.go2
new file mode 100644
index 0000000..56e9094
--- /dev/null
+++ b/src/cmd/compile/internal/types2/testdata/fixedbugs/issue47996.go2
@@ -0,0 +1,8 @@
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package p
+
+// don't crash
+func T /* ERROR missing */ [P /* ERROR named */ ] m /* ERROR m */ () /* ERROR \) */ { /* ERROR { */ } /* ERROR } */
diff --git a/src/cmd/compile/internal/types2/typelists.go b/src/cmd/compile/internal/types2/typelists.go
index 3258a5e..c3befb0 100644
--- a/src/cmd/compile/internal/types2/typelists.go
+++ b/src/cmd/compile/internal/types2/typelists.go
@@ -4,6 +4,8 @@
 
 package types2
 
+import "bytes"
+
 // TParamList holds a list of type parameters.
 type TParamList struct{ tparams []*TypeParam }
 
@@ -52,6 +54,17 @@
 	return l.types
 }
 
+func (l *TypeList) String() string {
+	if l == nil || len(l.types) == 0 {
+		return "[]"
+	}
+	var buf bytes.Buffer
+	buf.WriteByte('[')
+	writeTypeList(&buf, l.types, nil, nil)
+	buf.WriteByte(']')
+	return buf.String()
+}
+
 // ----------------------------------------------------------------------------
 // Implementation
 
diff --git a/src/encoding/gob/decode.go b/src/encoding/gob/decode.go
index d2f6c74..4ef9ef7 100644
--- a/src/encoding/gob/decode.go
+++ b/src/encoding/gob/decode.go
@@ -376,7 +376,7 @@
 	if value.Cap() < n {
 		value.Set(reflect.MakeSlice(value.Type(), n, n))
 	} else {
-		value.Set(value.Slice(0, n))
+		value.SetLen(n)
 	}
 	if _, err := state.b.Read(value.Bytes()); err != nil {
 		errorf("error decoding []byte: %s", err)
diff --git a/src/encoding/gob/timing_test.go b/src/encoding/gob/timing_test.go
index 3478bd2..ceb21c4 100644
--- a/src/encoding/gob/timing_test.go
+++ b/src/encoding/gob/timing_test.go
@@ -280,6 +280,14 @@
 	benchmarkDecodeSlice(b, a)
 }
 
+func BenchmarkDecodeBytesSlice(b *testing.B) {
+	a := make([][]byte, 1000)
+	for i := range a {
+		a[i] = []byte("now is the time")
+	}
+	benchmarkDecodeSlice(b, a)
+}
+
 func BenchmarkDecodeInterfaceSlice(b *testing.B) {
 	a := make([]interface{}, 1000)
 	for i := range a {
diff --git a/test/typeparam/issue47514c.dir/a.go b/test/typeparam/issue47514c.dir/a.go
new file mode 100644
index 0000000..782b1d2
--- /dev/null
+++ b/test/typeparam/issue47514c.dir/a.go
@@ -0,0 +1,5 @@
+package a
+
+type Doer[T any] interface {
+	Do() T
+}
diff --git a/test/typeparam/issue47514c.dir/main.go b/test/typeparam/issue47514c.dir/main.go
new file mode 100644
index 0000000..bc1166f
--- /dev/null
+++ b/test/typeparam/issue47514c.dir/main.go
@@ -0,0 +1,10 @@
+package main
+
+import "a"
+
+func Do[T any](doer a.Doer[T]) {
+	doer.Do()
+}
+
+func main() {
+}
diff --git a/test/typeparam/issue47514c.go b/test/typeparam/issue47514c.go
new file mode 100644
index 0000000..76930e5
--- /dev/null
+++ b/test/typeparam/issue47514c.go
@@ -0,0 +1,7 @@
+// rundir -G=3
+
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package ignored
diff --git a/test/typeparam/issue47710.go b/test/typeparam/issue47710.go
new file mode 100644
index 0000000..0882cb4
--- /dev/null
+++ b/test/typeparam/issue47710.go
@@ -0,0 +1,19 @@
+// compile -G=3
+
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package p
+
+type FooType[t any] interface {
+	Foo(BarType[t])
+}
+type BarType[t any] interface {
+	Int(IntType[t]) FooType[int]
+}
+
+type IntType[t any] int
+
+func (n IntType[t]) Foo(BarType[t]) {}
+func (n IntType[_]) String()    {}