[dev.go2go] go/*: merge parser and types changes from dev.typeparams

Merge just the conflicting changes from dev.typeparams (ast, parser,
types, etc.), excluding io/fs changes.

The rest of the dev.typeparams merge will be done in a later CL, once
the compiler changes have stabilized.

Change-Id: Ic24c5902e4cacc85338ab23b100e5a245a5148bc
Reviewed-on: https://go-review.googlesource.com/c/go/+/286774
Run-TryBot: Robert Findley <rfindley@google.com>
TryBot-Result: Go Bot <gobot@golang.org>
Reviewed-by: Robert Griesemer <gri@golang.org>
Trust: Robert Findley <rfindley@google.com>
diff --git a/api/except.txt b/api/except.txt
index 79ffd91..ccfdf06 100644
--- a/api/except.txt
+++ b/api/except.txt
@@ -1,5 +1,4 @@
 pkg encoding/json, method (*RawMessage) MarshalJSON() ([]uint8, error)
-pkg go/types, type Type interface { String, Underlying }
 pkg math/big, const MaxBase = 36
 pkg math/big, type Word uintptr
 pkg net, func ListenUnixgram(string, *UnixAddr) (*UDPConn, error)
diff --git a/api/go1.15.txt b/api/go1.15.txt
index b51837c..dd90506 100644
--- a/api/go1.15.txt
+++ b/api/go1.15.txt
@@ -112,8 +112,6 @@
 pkg debug/pe, const IMAGE_SUBSYSTEM_WINDOWS_GUI ideal-int
 pkg debug/pe, const IMAGE_SUBSYSTEM_XBOX = 14
 pkg debug/pe, const IMAGE_SUBSYSTEM_XBOX ideal-int
-pkg go/printer, const StdFormat = 16
-pkg go/printer, const StdFormat Mode
 pkg math/big, method (*Int) FillBytes([]uint8) []uint8
 pkg net, method (*Resolver) LookupIP(context.Context, string, string) ([]IP, error)
 pkg net/url, method (*URL) EscapedFragment() string
diff --git a/src/cmd/gofmt/gofmt.go b/src/cmd/gofmt/gofmt.go
index 92bfd46..8a6f4cc 100644
--- a/src/cmd/gofmt/gofmt.go
+++ b/src/cmd/gofmt/gofmt.go
@@ -40,7 +40,13 @@
 // Keep these in sync with go/format/format.go.
 const (
 	tabWidth    = 8
-	printerMode = printer.UseSpaces | printer.TabIndent | printer.StdFormat | printer.UseBrackets
+	printerMode = printer.UseSpaces | printer.TabIndent | printerNormalizeNumbers
+
+	// printerNormalizeNumbers means to canonicalize number literal prefixes
+	// and exponents while printing. See https://golang.org/doc/go1.13#gofmt.
+	//
+	// This value is defined in go/printer specifically for go/format and cmd/gofmt.
+	printerNormalizeNumbers = 1 << 30
 )
 
 var (
@@ -62,7 +68,7 @@
 
 func initParserMode() {
 	// Keep this in sync with go/format/format.go.
-	parserMode = parser.ParseComments | parser.UnifiedParamLists
+	parserMode = parser.ParseComments | parser.ParseTypeParams
 	if *allErrors {
 		parserMode |= parser.AllErrors
 	}
diff --git a/src/go/ast/ast.go b/src/go/ast/ast.go
index d6e691c..2456020 100644
--- a/src/go/ast/ast.go
+++ b/src/go/ast/ast.go
@@ -57,6 +57,11 @@
 // Comments
 
 // A Comment node represents a single //-style or /*-style comment.
+//
+// The Text field contains the comment text without carriage returns (\r) that
+// may have been present in the source. Because a comment's end position is
+// computed using len(Text), the position reported by End() does not match the
+// true source end position for comments containing carriage returns.
 type Comment struct {
 	Slash token.Pos // position of "/" starting the comment
 	Text  string    // comment text (excluding '\n' for //-style comments)
@@ -367,7 +372,9 @@
 		Args     []Expr    // function arguments; or nil
 		Ellipsis token.Pos // position of "..." (token.NoPos if there is no "...")
 		Rparen   token.Pos // position of ")"
-		Brackets bool      // if set, "[" and "]" are used instead of "(" and ")"
+		// TODO(rFindley) use a new ListExpr type rather than overloading CallExpr
+		//                via Brackets, as is done in the syntax package
+		Brackets bool // if set, "[" and "]" are used instead of "(" and ")"
 	}
 
 	// A StarExpr node represents an expression of the form "*" Expression.
@@ -982,6 +989,8 @@
 		Name *Ident        // function/method name
 		Type *FuncType     // function signature: type and value parameters, results, and position of "func" keyword
 		Body *BlockStmt    // function body; or nil for external (non-Go) function
+		// TODO(rFindley) consider storing TParams here, rather than FuncType, as
+		//                they are only valid for declared functions
 	}
 )
 
@@ -1039,15 +1048,14 @@
 // are "free-floating" (see also issues #18593, #20744).
 //
 type File struct {
-	Doc         *CommentGroup   // associated documentation; or nil
-	Package     token.Pos       // position of "package" keyword
-	Name        *Ident          // package name
-	Decls       []Decl          // top-level declarations; or nil
-	Scope       *Scope          // package scope (this file only)
-	Imports     []*ImportSpec   // imports in this file
-	Unresolved  []*Ident        // unresolved identifiers in this file
-	Comments    []*CommentGroup // list of all comments in the source file
-	UseBrackets bool            // indicates that type parameters use []'s
+	Doc        *CommentGroup   // associated documentation; or nil
+	Package    token.Pos       // position of "package" keyword
+	Name       *Ident          // package name
+	Decls      []Decl          // top-level declarations; or nil
+	Scope      *Scope          // package scope (this file only)
+	Imports    []*ImportSpec   // imports in this file
+	Unresolved []*Ident        // unresolved identifiers in this file
+	Comments   []*CommentGroup // list of all comments in the source file
 }
 
 func (f *File) Pos() token.Pos { return f.Package }
diff --git a/src/go/ast/commentmap_test.go b/src/go/ast/commentmap_test.go
index e372eab..38c62b0 100644
--- a/src/go/ast/commentmap_test.go
+++ b/src/go/ast/commentmap_test.go
@@ -140,4 +140,31 @@
 	}
 }
 
-// TODO(gri): add tests for Filter.
+func TestFilter(t *testing.T) {
+	fset := token.NewFileSet()
+	f, err := parser.ParseFile(fset, "", src, parser.ParseComments)
+	if err != nil {
+		t.Fatal(err)
+	}
+	cmap := NewCommentMap(fset, f, f.Comments)
+
+	// delete variable declaration
+	for i, decl := range f.Decls {
+		if gen, ok := decl.(*GenDecl); ok && gen.Tok == token.VAR {
+			copy(f.Decls[i:], f.Decls[i+1:])
+			f.Decls = f.Decls[:len(f.Decls)-1]
+			break
+		}
+	}
+
+	// check if comments are filtered correctly
+	cc := cmap.Filter(f)
+	for n, list := range cc {
+		key := fmt.Sprintf("%2d: %T", fset.Position(n.Pos()).Line, n)
+		got := ctext(list)
+		want := res[key]
+		if key == "25: *ast.GenDecl" || got != want {
+			t.Errorf("%s: got %q; want %q", key, got, want)
+		}
+	}
+}
diff --git a/src/go/ast/example_test.go b/src/go/ast/example_test.go
index 6e8d2ee..c2b3520 100644
--- a/src/go/ast/example_test.go
+++ b/src/go/ast/example_test.go
@@ -135,8 +135,7 @@
 	//     56  .  Unresolved: []*ast.Ident (len = 1) {
 	//     57  .  .  0: *(obj @ 29)
 	//     58  .  }
-	//     59  .  UseBrackets: false
-	//     60  }
+	//     59  }
 }
 
 // This example illustrates how to remove a variable declaration
diff --git a/src/go/ast/filter.go b/src/go/ast/filter.go
index 90a997b..c398e6e 100644
--- a/src/go/ast/filter.go
+++ b/src/go/ast/filter.go
@@ -493,5 +493,5 @@
 	}
 
 	// TODO(gri) need to compute unresolved identifiers!
-	return &File{doc, pos, NewIdent(pkg.Name), decls, pkg.Scope, imports, nil, comments, false}
+	return &File{doc, pos, NewIdent(pkg.Name), decls, pkg.Scope, imports, nil, comments}
 }
diff --git a/src/go/constant/value.go b/src/go/constant/value.go
index 08bcb3b..78cb3f8 100644
--- a/src/go/constant/value.go
+++ b/src/go/constant/value.go
@@ -17,6 +17,7 @@
 	"go/token"
 	"math"
 	"math/big"
+	"math/bits"
 	"strconv"
 	"strings"
 	"sync"
@@ -66,6 +67,22 @@
 // The spec requires at least 256 bits; typical implementations use 512 bits.
 const prec = 512
 
+// TODO(gri) Consider storing "error" information in an unknownVal so clients
+//           can provide better error messages. For instance, if a number is
+//           too large (incl. infinity), that could be recorded in unknownVal.
+//           See also #20583 and #42695 for use cases.
+
+// Representation of values:
+//
+// Values of Int and Float Kind have two different representations each: int64Val
+// and intVal, and ratVal and floatVal. When possible, the "smaller", respectively
+// more precise (for Floats) representation is chosen. However, once a Float value
+// is represented as a floatVal, any subsequent results remain floatVals (unless
+// explicitly converted); i.e., no attempt is made to convert a floatVal back into
+// a ratVal. The reasoning is that all representations but floatVal are mathematically
+// exact, but once that precision is lost (by moving to floatVal), moving back to
+// a different representation implies a precision that's not actually there.
+
 type (
 	unknownVal struct{}
 	boolVal    bool
@@ -257,14 +274,8 @@
 func i64tof(x int64Val) floatVal { return floatVal{newFloat().SetInt64(int64(x))} }
 func itor(x intVal) ratVal       { return ratVal{newRat().SetInt(x.val)} }
 func itof(x intVal) floatVal     { return floatVal{newFloat().SetInt(x.val)} }
-
-func rtof(x ratVal) floatVal {
-	a := newFloat().SetInt(x.val.Num())
-	b := newFloat().SetInt(x.val.Denom())
-	return floatVal{a.Quo(a, b)}
-}
-
-func vtoc(x Value) complexVal { return complexVal{x, int64Val(0)} }
+func rtof(x ratVal) floatVal     { return floatVal{newFloat().SetRat(x.val)} }
+func vtoc(x Value) complexVal    { return complexVal{x, int64Val(0)} }
 
 func makeInt(x *big.Int) Value {
 	if x.IsInt64() {
@@ -273,21 +284,15 @@
 	return intVal{x}
 }
 
-// Permit fractions with component sizes up to maxExp
-// before switching to using floating-point numbers.
-const maxExp = 4 << 10
-
 func makeRat(x *big.Rat) Value {
 	a := x.Num()
 	b := x.Denom()
-	if a.BitLen() < maxExp && b.BitLen() < maxExp {
+	if smallInt(a) && smallInt(b) {
 		// ok to remain fraction
 		return ratVal{x}
 	}
 	// components too large => switch to float
-	fa := newFloat().SetInt(a)
-	fb := newFloat().SetInt(b)
-	return floatVal{fa.Quo(fa, fb)}
+	return floatVal{newFloat().SetRat(x)}
 }
 
 var floatVal0 = floatVal{newFloat()}
@@ -297,16 +302,25 @@
 	if x.Sign() == 0 {
 		return floatVal0
 	}
+	if x.IsInf() {
+		return unknownVal{}
+	}
+	// No attempt is made to "go back" to ratVal, even if possible,
+	// to avoid providing the illusion of a mathematically exact
+	// representation.
 	return floatVal{x}
 }
 
 func makeComplex(re, im Value) Value {
+	if re.Kind() == Unknown || im.Kind() == Unknown {
+		return unknownVal{}
+	}
 	return complexVal{re, im}
 }
 
 func makeFloatFromLiteral(lit string) Value {
 	if f, ok := newFloat().SetString(lit); ok {
-		if smallRat(f) {
+		if smallFloat(f) {
 			// ok to use rationals
 			if f.Sign() == 0 {
 				// Issue 20228: If the float underflowed to zero, parse just "0".
@@ -325,14 +339,34 @@
 	return nil
 }
 
-// smallRat reports whether x would lead to "reasonably"-sized fraction
+// Permit fractions with component sizes up to maxExp
+// before switching to using floating-point numbers.
+const maxExp = 4 << 10
+
+// smallInt reports whether x would lead to "reasonably"-sized fraction
 // if converted to a *big.Rat.
-func smallRat(x *big.Float) bool {
-	if !x.IsInf() {
-		e := x.MantExp(nil)
-		return -maxExp < e && e < maxExp
+func smallInt(x *big.Int) bool {
+	return x.BitLen() < maxExp
+}
+
+// smallFloat64 reports whether x would lead to "reasonably"-sized fraction
+// if converted to a *big.Rat.
+func smallFloat64(x float64) bool {
+	if math.IsInf(x, 0) {
+		return false
 	}
-	return false
+	_, e := math.Frexp(x)
+	return -maxExp < e && e < maxExp
+}
+
+// smallFloat reports whether x would lead to "reasonably"-sized fraction
+// if converted to a *big.Rat.
+func smallFloat(x *big.Float) bool {
+	if x.IsInf() {
+		return false
+	}
+	e := x.MantExp(nil)
+	return -maxExp < e && e < maxExp
 }
 
 // ----------------------------------------------------------------------------
@@ -359,16 +393,16 @@
 }
 
 // MakeFloat64 returns the Float value for x.
+// If x is -0.0, the result is 0.0.
 // If x is not finite, the result is an Unknown.
 func MakeFloat64(x float64) Value {
 	if math.IsInf(x, 0) || math.IsNaN(x) {
 		return unknownVal{}
 	}
-	// convert -0 to 0
-	if x == 0 {
-		return int64Val(0)
+	if smallFloat64(x) {
+		return ratVal{newRat().SetFloat64(x + 0)} // convert -0 to 0
 	}
-	return ratVal{newRat().SetFloat64(x)}
+	return floatVal{newFloat().SetFloat64(x + 0)}
 }
 
 // MakeFromLiteral returns the corresponding integer, floating-point,
@@ -583,11 +617,11 @@
 	case int64:
 		return int64Val(x)
 	case *big.Int:
-		return intVal{x}
+		return makeInt(x)
 	case *big.Rat:
-		return ratVal{x}
+		return makeRat(x)
 	case *big.Float:
-		return floatVal{x}
+		return makeFloat(x)
 	default:
 		return unknownVal{}
 	}
@@ -599,7 +633,11 @@
 func BitLen(x Value) int {
 	switch x := x.(type) {
 	case int64Val:
-		return i64toi(x).val.BitLen()
+		u := uint64(x)
+		if x < 0 {
+			u = uint64(-x)
+		}
+		return 64 - bits.LeadingZeros64(u)
 	case intVal:
 		return x.val.BitLen()
 	case unknownVal:
@@ -720,7 +758,7 @@
 	case ratVal:
 		return makeInt(x.val.Num())
 	case floatVal:
-		if smallRat(x.val) {
+		if smallFloat(x.val) {
 			r, _ := x.val.Rat(nil)
 			return makeInt(r.Num())
 		}
@@ -742,7 +780,7 @@
 	case ratVal:
 		return makeInt(x.val.Denom())
 	case floatVal:
-		if smallRat(x.val) {
+		if smallFloat(x.val) {
 			r, _ := x.val.Rat(nil)
 			return makeInt(r.Denom())
 		}
@@ -815,7 +853,7 @@
 		// avoid creation of huge integers
 		// (Existing tests require permitting exponents of at least 1024;
 		// allow any value that would also be permissible as a fraction.)
-		if smallRat(x.val) {
+		if smallFloat(x.val) {
 			i := newInt()
 			if _, acc := x.val.Int(i); acc == big.Exact {
 				return makeInt(i)
@@ -858,14 +896,16 @@
 func ToFloat(x Value) Value {
 	switch x := x.(type) {
 	case int64Val:
-		return i64tof(x)
+		return i64tor(x) // x is always a small int
 	case intVal:
+		if smallInt(x.val) {
+			return itor(x)
+		}
 		return itof(x)
 	case ratVal, floatVal:
 		return x
 	case complexVal:
-		if im := ToInt(x.im); im.Kind() == Int && Sign(im) == 0 {
-			// imaginary component is 0
+		if Sign(x.im) == 0 {
 			return ToFloat(x.re)
 		}
 	}
@@ -876,13 +916,7 @@
 // Otherwise it returns an Unknown.
 func ToComplex(x Value) Value {
 	switch x := x.(type) {
-	case int64Val:
-		return vtoc(i64tof(x))
-	case intVal:
-		return vtoc(itof(x))
-	case ratVal:
-		return vtoc(x)
-	case floatVal:
+	case int64Val, intVal, ratVal, floatVal:
 		return vtoc(x)
 	case complexVal:
 		return x
@@ -1001,59 +1035,45 @@
 // or invalid (say, nil) both results are that value.
 //
 func match(x, y Value) (_, _ Value) {
-	if ord(x) > ord(y) {
-		y, x = match(y, x)
-		return x, y
+	switch ox, oy := ord(x), ord(y); {
+	case ox < oy:
+		x, y = match0(x, y)
+	case ox > oy:
+		y, x = match0(y, x)
 	}
-	// ord(x) <= ord(y)
+	return x, y
+}
 
-	switch x := x.(type) {
-	case boolVal, *stringVal, complexVal:
-		return x, y
+// match0 must only be called by match.
+// Invariant: ord(x) < ord(y)
+func match0(x, y Value) (_, _ Value) {
+	// Prefer to return the original x and y arguments when possible,
+	// to avoid unnecessary heap allocations.
 
-	case int64Val:
-		switch y := y.(type) {
-		case int64Val:
-			return x, y
-		case intVal:
-			return i64toi(x), y
-		case ratVal:
-			return i64tor(x), y
-		case floatVal:
-			return i64tof(x), y
-		case complexVal:
-			return vtoc(x), y
-		}
-
+	switch y.(type) {
 	case intVal:
-		switch y := y.(type) {
-		case intVal:
-			return x, y
-		case ratVal:
-			return itor(x), y
-		case floatVal:
-			return itof(x), y
-		case complexVal:
-			return vtoc(x), y
+		switch x1 := x.(type) {
+		case int64Val:
+			return i64toi(x1), y
 		}
-
 	case ratVal:
-		switch y := y.(type) {
-		case ratVal:
-			return x, y
-		case floatVal:
-			return rtof(x), y
-		case complexVal:
-			return vtoc(x), y
+		switch x1 := x.(type) {
+		case int64Val:
+			return i64tor(x1), y
+		case intVal:
+			return itor(x1), y
 		}
-
 	case floatVal:
-		switch y := y.(type) {
-		case floatVal:
-			return x, y
-		case complexVal:
-			return vtoc(x), y
+		switch x1 := x.(type) {
+		case int64Val:
+			return i64tof(x1), y
+		case intVal:
+			return itof(x1), y
+		case ratVal:
+			return rtof(x1), y
 		}
+	case complexVal:
+		return vtoc(x), y
 	}
 
 	// force unknown and invalid values into "x position" in callers of match
diff --git a/src/go/constant/value_test.go b/src/go/constant/value_test.go
index a319039f..91ad0b0 100644
--- a/src/go/constant/value_test.go
+++ b/src/go/constant/value_test.go
@@ -7,6 +7,7 @@
 import (
 	"fmt"
 	"go/token"
+	"math"
 	"math/big"
 	"strings"
 	"testing"
@@ -82,6 +83,11 @@
 	`1_2_3.123 = 123.123`,
 	`0123.01_23 = 123.0123`,
 
+	`1e-1000000000 = 0`,
+	`1e+1000000000 = ?`,
+	`6e5518446744 = ?`,
+	`-6e5518446744 = ?`,
+
 	// hexadecimal floats
 	`0x0.p+0 = 0.`,
 	`0Xdeadcafe.p-10 = 0xdeadcafe/1024`,
@@ -117,6 +123,11 @@
 	`0.e+1i = 0i`,
 	`123.E-1_0i = 123e-10i`,
 	`01_23.e123i = 123e123i`,
+
+	`1e-1000000000i = 0i`,
+	`1e+1000000000i = ?`,
+	`6e5518446744i = ?`,
+	`-6e5518446744i = ?`,
 }
 
 func testNumbers(t *testing.T, kind token.Token, tests []string) {
@@ -129,21 +140,32 @@
 
 		x := MakeFromLiteral(a[0], kind, 0)
 		var y Value
-		if i := strings.Index(a[1], "/"); i >= 0 && kind == token.FLOAT {
-			n := MakeFromLiteral(a[1][:i], token.INT, 0)
-			d := MakeFromLiteral(a[1][i+1:], token.INT, 0)
-			y = BinaryOp(n, token.QUO, d)
+		if a[1] == "?" {
+			y = MakeUnknown()
 		} else {
-			y = MakeFromLiteral(a[1], kind, 0)
+			if i := strings.Index(a[1], "/"); i >= 0 && kind == token.FLOAT {
+				n := MakeFromLiteral(a[1][:i], token.INT, 0)
+				d := MakeFromLiteral(a[1][i+1:], token.INT, 0)
+				y = BinaryOp(n, token.QUO, d)
+			} else {
+				y = MakeFromLiteral(a[1], kind, 0)
+			}
+			if y.Kind() == Unknown {
+				panic(fmt.Sprintf("invalid test case: %s %d", test, y.Kind()))
+			}
 		}
 
 		xk := x.Kind()
 		yk := y.Kind()
-		if xk != yk || xk == Unknown {
+		if xk != yk {
 			t.Errorf("%s: got kind %d != %d", test, xk, yk)
 			continue
 		}
 
+		if yk == Unknown {
+			continue
+		}
+
 		if !Compare(x, token.EQL, y) {
 			t.Errorf("%s: %s != %s", test, x, y)
 		}
@@ -200,6 +222,7 @@
 	`1i * 1i = -1`,
 	`? * 0 = ?`,
 	`0 * ? = ?`,
+	`0 * 1e+1000000000 = ?`,
 
 	`0 / 0 = "division_by_zero"`,
 	`10 / 2 = 5`,
@@ -207,6 +230,7 @@
 	`5i / 3i = 5/3`,
 	`? / 0 = ?`,
 	`0 / ? = ?`,
+	`0 * 1e+1000000000i = ?`,
 
 	`0 % 0 = "runtime_error:_integer_divide_by_zero"`, // TODO(gri) should be the same as for /
 	`10 % 3 = 1`,
@@ -597,18 +621,68 @@
 	}
 }
 
-func TestMake(t *testing.T) {
-	for _, want := range []interface{}{
-		false,
-		"hello",
-		int64(1),
-		big.NewInt(10),
-		big.NewFloat(2.0),
-		big.NewRat(1, 3),
+func TestMakeFloat64(t *testing.T) {
+	var zero float64
+	for _, arg := range []float64{
+		-math.MaxFloat32,
+		-10,
+		-0.5,
+		-zero,
+		zero,
+		1,
+		10,
+		123456789.87654321e-23,
+		1e10,
+		math.MaxFloat64,
 	} {
-		got := Val(Make(want))
-		if got != want {
-			t.Errorf("got %v; want %v", got, want)
+		val := MakeFloat64(arg)
+		if val.Kind() != Float {
+			t.Errorf("%v: got kind = %d; want %d", arg, val.Kind(), Float)
+		}
+
+		// -0.0 is mapped to 0.0
+		got, exact := Float64Val(val)
+		if !exact || math.Float64bits(got) != math.Float64bits(arg+0) {
+			t.Errorf("%v: got %v (exact = %v)", arg, got, exact)
+		}
+	}
+
+	// infinity
+	for sign := range []int{-1, 1} {
+		arg := math.Inf(sign)
+		val := MakeFloat64(arg)
+		if val.Kind() != Unknown {
+			t.Errorf("%v: got kind = %d; want %d", arg, val.Kind(), Unknown)
+		}
+	}
+}
+
+type makeTestCase struct {
+	kind      Kind
+	arg, want interface{}
+}
+
+func dup(k Kind, x interface{}) makeTestCase { return makeTestCase{k, x, x} }
+
+func TestMake(t *testing.T) {
+	for _, test := range []makeTestCase{
+		{Bool, false, false},
+		{String, "hello", "hello"},
+
+		{Int, int64(1), int64(1)},
+		{Int, big.NewInt(10), int64(10)},
+		{Int, new(big.Int).Lsh(big.NewInt(1), 62), int64(1 << 62)},
+		dup(Int, new(big.Int).Lsh(big.NewInt(1), 63)),
+
+		{Float, big.NewFloat(0), floatVal0.val},
+		dup(Float, big.NewFloat(2.0)),
+		dup(Float, big.NewRat(1, 3)),
+	} {
+		val := Make(test.arg)
+		got := Val(val)
+		if val.Kind() != test.kind || got != test.want {
+			t.Errorf("got %v (%T, kind = %d); want %v (%T, kind = %d)",
+				got, got, val.Kind(), test.want, test.want, test.kind)
 		}
 	}
 }
@@ -632,3 +706,24 @@
 		})
 	}
 }
+
+var bitLenTests = []struct {
+	val  int64
+	want int
+}{
+	{0, 0},
+	{1, 1},
+	{-16, 5},
+	{1 << 61, 62},
+	{1 << 62, 63},
+	{-1 << 62, 63},
+	{-1 << 63, 64},
+}
+
+func TestBitLen(t *testing.T) {
+	for _, test := range bitLenTests {
+		if got := BitLen(MakeInt64(test.val)); got != test.want {
+			t.Errorf("%v: got %v, want %v", test.val, got, test.want)
+		}
+	}
+}
diff --git a/src/go/format/format.go b/src/go/format/format.go
index 3613702..279fc2e 100644
--- a/src/go/format/format.go
+++ b/src/go/format/format.go
@@ -27,12 +27,18 @@
 // Keep these in sync with cmd/gofmt/gofmt.go.
 const (
 	tabWidth    = 8
-	printerMode = printer.UseSpaces | printer.TabIndent | printer.StdFormat | printer.UseBrackets
+	printerMode = printer.UseSpaces | printer.TabIndent | printerNormalizeNumbers
+
+	// printerNormalizeNumbers means to canonicalize number literal prefixes
+	// and exponents while printing. See https://golang.org/doc/go1.13#gofmt.
+	//
+	// This value is defined in go/printer specifically for go/format and cmd/gofmt.
+	printerNormalizeNumbers = 1 << 30
 )
 
 var config = printer.Config{Mode: printerMode, Tabwidth: tabWidth}
 
-const parserMode = parser.ParseComments | parser.UnifiedParamLists
+const parserMode = parser.ParseComments | parser.ParseTypeParams
 
 // Node formats node in canonical gofmt style and writes the result to dst.
 //
diff --git a/src/go/format/format_test.go b/src/go/format/format_test.go
index aee51e2..58e088e 100644
--- a/src/go/format/format_test.go
+++ b/src/go/format/format_test.go
@@ -58,8 +58,8 @@
 	diff(t, buf.Bytes(), src)
 }
 
-// Node is documented to not modify the AST. Test that it is so, even when
-// formatting changes are applied due to printer.StdFormat mode being used.
+// Node is documented to not modify the AST.
+// Test that it is so even when numbers are normalized.
 func TestNodeNoModify(t *testing.T) {
 	const (
 		src    = "package p\n\nconst _ = 0000000123i\n"
diff --git a/src/go/go2go/go2go.go b/src/go/go2go/go2go.go
index a2265f1..b0c4873 100644
--- a/src/go/go2go/go2go.go
+++ b/src/go/go2go/go2go.go
@@ -83,9 +83,8 @@
 
 		var merr multiErr
 		conf := types.Config{
-			InferFromConstraints: true,
-			Importer:             importer,
-			Error:                merr.add,
+			Importer: importer,
+			Error:    merr.add,
 		}
 		path := importPath
 		if path == "" {
@@ -126,15 +125,14 @@
 // for error messages.
 func RewriteBuffer(importer *Importer, filename string, file []byte) ([]byte, error) {
 	fset := token.NewFileSet()
-	pf, err := parser.ParseFile(fset, filename, file, parser.UnifiedParamLists)
+	pf, err := parser.ParseFile(fset, filename, file, parser.ParseTypeParams)
 	if err != nil {
 		return nil, err
 	}
 	var merr multiErr
 	conf := types.Config{
-		InferFromConstraints: true,
-		Importer:             importer,
-		Error:                merr.add,
+		Importer: importer,
+		Error:    merr.add,
 	}
 	tpkg, err := conf.Check(pf.Name.Name, fset, []*ast.File{pf}, importer.info)
 	if err != nil {
@@ -222,7 +220,7 @@
 func parseFiles(importer *Importer, dir string, go2files []string, fset *token.FileSet) ([]*ast.Package, error) {
 	pkgs := make(map[string]*ast.Package)
 	for _, go2f := range go2files {
-		mode := parser.UnifiedParamLists // overrides UseBrackets
+		mode := parser.ParseTypeParams
 
 		filename := filepath.Join(dir, go2f)
 		pf, err := parser.ParseFile(fset, filename, nil, mode)
diff --git a/src/go/parser/error_test.go b/src/go/parser/error_test.go
index c7f93c9a..15c1b50 100644
--- a/src/go/parser/error_test.go
+++ b/src/go/parser/error_test.go
@@ -114,6 +114,7 @@
 // of found errors and reports discrepancies.
 //
 func compareErrors(t *testing.T, fset *token.FileSet, expected map[token.Pos]string, found scanner.ErrorList) {
+	t.Helper()
 	for _, error := range found {
 		// error.Pos is a token.Position, but we want
 		// a token.Pos so we can do a map lookup
@@ -149,7 +150,8 @@
 	}
 }
 
-func checkErrors(t *testing.T, filename string, input interface{}) {
+func checkErrors(t *testing.T, filename string, input interface{}, mode Mode, expectErrors bool) {
+	t.Helper()
 	src, err := readSource(filename, input)
 	if err != nil {
 		t.Error(err)
@@ -157,7 +159,7 @@
 	}
 
 	fset := token.NewFileSet()
-	_, err = ParseFile(fset, filename, src, DeclarationErrors|AllErrors)
+	_, err = ParseFile(fset, filename, src, mode)
 	found, ok := err.(scanner.ErrorList)
 	if err != nil && !ok {
 		t.Error(err)
@@ -165,9 +167,12 @@
 	}
 	found.RemoveMultiples()
 
-	// we are expecting the following errors
-	// (collect these after parsing a file so that it is found in the file set)
-	expected := expectedErrors(fset, filename, src)
+	expected := map[token.Pos]string{}
+	if expectErrors {
+		// we are expecting the following errors
+		// (collect these after parsing a file so that it is found in the file set)
+		expected = expectedErrors(fset, filename, src)
+	}
 
 	// verify errors returned by the parser
 	compareErrors(t, fset, expected, found)
@@ -178,10 +183,14 @@
 	if err != nil {
 		t.Fatal(err)
 	}
-	for _, fi := range list {
-		name := fi.Name()
-		if !fi.IsDir() && !strings.HasPrefix(name, ".") && (strings.HasSuffix(name, ".src") || strings.HasSuffix(name, ".go2")) {
-			checkErrors(t, filepath.Join(testdata, name), nil)
+	for _, d := range list {
+		name := d.Name()
+		if !d.IsDir() && !strings.HasPrefix(name, ".") && (strings.HasSuffix(name, ".src") || strings.HasSuffix(name, ".go2")) {
+			mode := DeclarationErrors | AllErrors
+			if strings.HasSuffix(name, ".go2") {
+				mode |= ParseTypeParams
+			}
+			checkErrors(t, filepath.Join(testdata, name), nil, mode, true)
 		}
 	}
 }
diff --git a/src/go/parser/interface.go b/src/go/parser/interface.go
index e8d218e..58c57a1 100644
--- a/src/go/parser/interface.go
+++ b/src/go/parser/interface.go
@@ -55,8 +55,7 @@
 	Trace                                          // print a trace of parsed productions
 	DeclarationErrors                              // report declaration errors
 	SpuriousErrors                                 // same as AllErrors, for backward-compatibility
-	UseBrackets                                    // use square brackets with type parameters
-	UnifiedParamLists                              // use same syntax for type and ordinary parameter lists (implies UseBrackets)
+	ParseTypeParams                                // Placeholder. Will control the parsing of type parameters.
 	AllErrors         = SpuriousErrors             // report all errors (not just the first 10 on different lines)
 )
 
@@ -142,23 +141,29 @@
 
 	pkgs = make(map[string]*ast.Package)
 	for _, d := range list {
-		if strings.HasSuffix(d.Name(), ".go") && (filter == nil || filter(d)) {
-			filename := filepath.Join(path, d.Name())
-			if src, err := ParseFile(fset, filename, nil, mode); err == nil {
-				name := src.Name.Name
-				pkg, found := pkgs[name]
-				if !found {
-					pkg = &ast.Package{
-						Name:  name,
-						Files: make(map[string]*ast.File),
-					}
-					pkgs[name] = pkg
-				}
-				pkg.Files[filename] = src
-			} else if first == nil {
-				first = err
+		if d.IsDir() || !strings.HasSuffix(d.Name(), ".go") {
+			continue
+		}
+		if filter != nil {
+			if !filter(d) {
+				continue
 			}
 		}
+		filename := filepath.Join(path, d.Name())
+		if src, err := ParseFile(fset, filename, nil, mode); err == nil {
+			name := src.Name.Name
+			pkg, found := pkgs[name]
+			if !found {
+				pkg = &ast.Package{
+					Name:  name,
+					Files: make(map[string]*ast.File),
+				}
+				pkgs[name] = pkg
+			}
+			pkg.Files[filename] = src
+		} else if first == nil {
+			first = err
+		}
 	}
 
 	return
diff --git a/src/go/parser/parser.go b/src/go/parser/parser.go
index 797ef25..ccbcef8 100644
--- a/src/go/parser/parser.go
+++ b/src/go/parser/parser.go
@@ -35,7 +35,6 @@
 	// Tracing/debugging
 	mode   Mode // parsing mode
 	trace  bool // == (mode&Trace != 0)
-	brack  bool // use square brackets to enclose type parameters
 	indent int  // indentation used for tracing output
 
 	// Comments
@@ -82,7 +81,6 @@
 
 	p.mode = mode
 	p.trace = mode&Trace != 0 // for convenience (p.trace is used frequently)
-	p.brack = mode&UseBrackets != 0 || mode&UnifiedParamLists != 0
 
 	p.next()
 }
@@ -630,12 +628,12 @@
 // ----------------------------------------------------------------------------
 // Types
 
-func (p *parser) parseType(typeContext bool) ast.Expr {
+func (p *parser) parseType() ast.Expr {
 	if p.trace {
 		defer un(trace(p, "Type"))
 	}
 
-	typ := p.tryType(typeContext)
+	typ := p.tryType()
 
 	if typ == nil {
 		pos := p.pos
@@ -647,6 +645,19 @@
 	return typ
 }
 
+func (p *parser) parseQualifiedIdent(ident *ast.Ident) ast.Expr {
+	if p.trace {
+		defer un(trace(p, "QualifiedIdent"))
+	}
+
+	typ := p.parseTypeName(ident)
+	if p.tok == token.LBRACK && p.mode&ParseTypeParams != 0 {
+		typ = p.parseTypeInstance(typ)
+	}
+
+	return typ
+}
+
 // If the result is an identifier, it is not resolved.
 func (p *parser) parseTypeName(ident *ast.Ident) ast.Expr {
 	if p.trace {
@@ -697,12 +708,22 @@
 	//           list such as T[P,]? (We do in parseTypeInstance).
 	lbrack := p.expect(token.LBRACK)
 	var args []ast.Expr
+	var firstComma token.Pos
+	// TODO(rfindley): consider changing parseRhsOrType so that this function variable
+	// is not needed.
+	argparser := p.parseRhsOrType
+	if p.mode&ParseTypeParams == 0 {
+		argparser = p.parseRhs
+	}
 	if p.tok != token.RBRACK {
 		p.exprLev++
-		args = append(args, p.parseRhsOrType())
+		args = append(args, argparser())
 		for p.tok == token.COMMA {
+			if !firstComma.IsValid() {
+				firstComma = p.pos
+			}
 			p.next()
-			args = append(args, p.parseRhsOrType())
+			args = append(args, argparser())
 		}
 		p.exprLev--
 	}
@@ -710,36 +731,32 @@
 
 	if len(args) == 0 {
 		// x []E
-		elt := p.parseType(true)
+		elt := p.parseType()
 		return x, &ast.ArrayType{Lbrack: lbrack, Elt: elt}
 	}
 
 	// x [P]E or x[P]
 	if len(args) == 1 {
-		elt := p.tryType(true)
+		elt := p.tryType()
 		if elt != nil {
 			// x [P]E
 			return x, &ast.ArrayType{Lbrack: lbrack, Len: args[0], Elt: elt}
 		}
+		if p.mode&ParseTypeParams == 0 {
+			p.error(rbrack, "missing element type in array type expression")
+			return nil, &ast.BadExpr{From: args[0].Pos(), To: args[0].End()}
+		}
+	}
+
+	if p.mode&ParseTypeParams == 0 {
+		p.error(firstComma, "expected ']', found ','")
+		return x, &ast.BadExpr{From: args[0].Pos(), To: args[len(args)-1].End()}
 	}
 
 	// x[P], x[P1, P2], ...
 	return nil, &ast.CallExpr{Fun: x, Lparen: lbrack, Args: args, Rparen: rbrack, Brackets: true}
 }
 
-type lookAhead struct {
-	pos token.Pos
-	tok token.Token
-}
-
-func (l *lookAhead) consume(p *parser) {
-	if l.tok == 0 {
-		l.pos = p.pos
-		l.tok = p.tok
-		p.next()
-	}
-}
-
 func (p *parser) parseFieldDecl(scope *ast.Scope) *ast.Field {
 	if p.trace {
 		defer un(trace(p, "FieldDecl"))
@@ -755,11 +772,7 @@
 			// embedded type
 			typ = name
 			if p.tok == token.PERIOD {
-				typ = p.parseTypeName(name)
-				// A [ or ( indicates a type parameter (or a syntax error).
-				if p.brack && p.tok == token.LBRACK || !p.brack && p.tok == token.LPAREN {
-					typ = p.parseTypeInstance(typ, lookAhead{})
-				}
+				typ = p.parseQualifiedIdent(name)
 			} else {
 				p.resolve(typ)
 			}
@@ -772,21 +785,21 @@
 			}
 			// Careful dance: We don't know if we have an embedded instantiated
 			// type T[P1, P2, ...] or a field T of array type []E or [P]E.
-			if len(names) == 1 && p.brack && p.tok == token.LBRACK {
+			if len(names) == 1 && p.tok == token.LBRACK {
 				name, typ = p.parseArrayFieldOrTypeInstance(name)
 				if name == nil {
 					names = nil
 				}
 			} else {
 				// T P
-				typ = p.parseType(true)
+				typ = p.parseType()
 			}
 		}
 	} else {
 		// embedded, possibly generic type
 		// (using the enclosing parentheses to distinguish it from a named field declaration)
-		// TODO(gri) if p.brack is set, don't allow parenthesized embedded type
-		typ = p.parseType(true)
+		// TODO(rFindley) confirm that this doesn't allow parenthesized embedded type
+		typ = p.parseType()
 	}
 
 	var tag *ast.BasicLit
@@ -795,7 +808,7 @@
 		p.next()
 	}
 
-	p.expectSemi()
+	p.expectSemi() // call before accessing p.linecomment
 
 	field := &ast.Field{Doc: doc, Names: names, Type: typ, Tag: tag, Comment: p.lineComment}
 	p.declare(field, nil, scope, ast.Var, names...)
@@ -812,6 +825,9 @@
 	scope := ast.NewScope(nil) // struct scope
 	var list []*ast.Field
 	for p.tok == token.IDENT || p.tok == token.MUL || p.tok == token.LPAREN {
+		// a field declaration cannot start with a '(' but we accept
+		// it here for more robust parsing and better error messages
+		// (parseFieldDecl will check and complain if necessary)
 		list = append(list, p.parseFieldDecl(scope))
 	}
 	rbrace := p.expect(token.RBRACE)
@@ -826,13 +842,13 @@
 	}
 }
 
-func (p *parser) parsePointerType(typeContext bool) *ast.StarExpr {
+func (p *parser) parsePointerType() *ast.StarExpr {
 	if p.trace {
 		defer un(trace(p, "PointerType"))
 	}
 
 	star := p.expect(token.MUL)
-	base := p.parseType(typeContext)
+	base := p.parseType()
 
 	return &ast.StarExpr{Star: star, X: base}
 }
@@ -843,7 +859,7 @@
 	}
 
 	pos := p.expect(token.ELLIPSIS)
-	elt := p.parseType(true)
+	elt := p.parseType()
 
 	return &ast.Ellipsis{Ellipsis: pos, Elt: elt}
 }
@@ -854,6 +870,7 @@
 }
 
 func (p *parser) parseParamDecl(name *ast.Ident) (f field) {
+	// TODO(rFindley) compare with parser.paramDeclOrNil in the syntax package
 	if p.trace {
 		defer un(trace(p, "ParamDeclOrNil"))
 	}
@@ -874,15 +891,11 @@
 		switch p.tok {
 		case token.IDENT, token.MUL, token.ARROW, token.FUNC, token.CHAN, token.MAP, token.STRUCT, token.INTERFACE, token.LPAREN:
 			// name type
-			f.typ = p.parseType(true)
+			f.typ = p.parseType()
 
 		case token.LBRACK:
-			if p.brack {
-				// name[type1, type2, ...] or name []type or name [len]type
-				f.name, f.typ = p.parseArrayFieldOrTypeInstance(f.name)
-			} else {
-				f.typ = p.parseType(true)
-			}
+			// name[type1, type2, ...] or name []type or name [len]type
+			f.name, f.typ = p.parseArrayFieldOrTypeInstance(f.name)
 
 		case token.ELLIPSIS:
 			// name ...type
@@ -890,16 +903,13 @@
 
 		case token.PERIOD:
 			// qualified.typename
-			f.typ = p.parseTypeName(f.name)
-			if p.brack && p.tok == token.LBRACK || !p.brack && p.tok == token.LPAREN {
-				f.typ = p.parseTypeInstance(f.typ, lookAhead{})
-			}
+			f.typ = p.parseQualifiedIdent(f.name)
 			f.name = nil
 		}
 
 	case token.MUL, token.ARROW, token.FUNC, token.LBRACK, token.CHAN, token.MAP, token.STRUCT, token.INTERFACE, token.LPAREN:
 		// type
-		f.typ = p.parseType(true)
+		f.typ = p.parseType()
 
 	case token.ELLIPSIS:
 		// ...type
@@ -914,35 +924,6 @@
 	return
 }
 
-func (p *parser) parseTParamDecl(name *ast.Ident) (f field) {
-	if p.trace {
-		defer un(trace(p, "TParamDeclOrNil"))
-	}
-
-	ptr := false
-	if name == nil && p.tok == token.MUL {
-		ptr = true
-		p.next()
-	}
-
-	if name == nil {
-		name = p.parseIdent()
-	}
-	f.name = name
-	if ptr {
-		// encode pointer designation in the name
-		f.name.Name = "*" + f.name.Name
-	}
-
-	switch p.tok {
-	case token.IDENT, token.INTERFACE, token.LPAREN:
-		// type bound
-		f.typ = p.parseType(true)
-	}
-
-	return
-}
-
 func (p *parser) parseParameterList(scope *ast.Scope, name0 *ast.Ident, closing token.Token, parseParamDecl func(*ast.Ident) field, tparams bool) (params []*ast.Field) {
 	if p.trace {
 		defer un(trace(p, "ParameterList"))
@@ -1059,96 +1040,49 @@
 	return
 }
 
-func (p *parser) parseTypeParams(scope *ast.Scope, name0 *ast.Ident, closing token.Token) []*ast.Field {
-	if p.trace {
-		defer un(trace(p, "TypeParams"))
-	}
-
-	params := p.parseParameterList(scope, name0, closing, p.parseTParamDecl, false)
-
-	// determine which form we have (list of type parameters with optional
-	// type bound, or type parameters, all with interfaces as type bounds)
-	for _, f := range params {
-		if len(f.Names) == 0 {
-			assert(f.Type != nil, "expected non-nil type")
-			f.Names = []*ast.Ident{f.Type.(*ast.Ident)}
-			f.Type = nil
-		}
-	}
-
-	return params
-}
-
-func (p *parser) parseParameters(scope *ast.Scope, opening lookAhead, acceptTParams bool) (tparams, params *ast.FieldList) {
+func (p *parser) parseParameters(scope *ast.Scope, acceptTParams bool) (tparams, params *ast.FieldList) {
 	if p.trace {
 		defer un(trace(p, "Parameters"))
 	}
 
-	opening.consume(p)
-	lparen := opening.pos
-	if acceptTParams {
-		if opening.tok == token.LBRACK {
-			var list []*ast.Field
-			if p.mode&UnifiedParamLists != 0 {
-				// assume [T any](params) syntax
-				list = p.parseParameterList(scope, nil, token.RBRACK, p.parseParamDecl, true)
-			} else {
-				// assume [type T](params) syntax
-				p.brack = true
-				if p.tok == token.TYPE {
-					p.next()
-				}
-				list = p.parseTypeParams(scope, nil, token.RBRACK)
-			}
-			rbrack := p.expect(token.RBRACK)
-			tparams = &ast.FieldList{Opening: lparen, List: list, Closing: rbrack}
-			lparen = p.expect(token.LPAREN)
-		} else {
-			// assume (type T)(params) syntax
-			if opening.tok != token.LPAREN {
-				p.errorExpected(opening.pos, "'('")
-			}
-			if !p.brack && p.tok == token.TYPE {
-				p.next()
-				list := p.parseTypeParams(scope, nil, token.RPAREN)
-				rparen := p.expect(token.RPAREN)
-				tparams = &ast.FieldList{Opening: lparen, List: list, Closing: rparen}
-				lparen = p.expect(token.LPAREN)
-			}
-		}
-		// type parameter lists must not be empty when we have unified parameter lists
-		if p.mode&UnifiedParamLists != 0 && tparams != nil && tparams.NumFields() == 0 {
+	if p.mode&ParseTypeParams != 0 && acceptTParams && p.tok == token.LBRACK {
+		opening := p.pos
+		p.next()
+		// [T any](params) syntax
+		list := p.parseParameterList(scope, nil, token.RBRACK, p.parseParamDecl, true)
+		rbrack := p.expect(token.RBRACK)
+		tparams = &ast.FieldList{Opening: opening, List: list, Closing: rbrack}
+		// Type parameter lists must not be empty.
+		if tparams != nil && tparams.NumFields() == 0 {
 			p.error(tparams.Closing, "empty type parameter list")
 			tparams = nil // avoid follow-on errors
 		}
-	} else {
-		if opening.tok != token.LPAREN {
-			p.errorExpected(lparen, "'('")
-		}
 	}
 
+	opening := p.expect(token.LPAREN)
+
 	var fields []*ast.Field
 	if p.tok != token.RPAREN {
 		fields = p.parseParameterList(scope, nil, token.RPAREN, p.parseParamDecl, false)
 	}
 
 	rparen := p.expect(token.RPAREN)
-	params = &ast.FieldList{Opening: lparen, List: fields, Closing: rparen}
+	params = &ast.FieldList{Opening: opening, List: fields, Closing: rparen}
 
 	return
 }
 
-func (p *parser) parseResult(scope *ast.Scope, typeContext bool) *ast.FieldList {
+func (p *parser) parseResult(scope *ast.Scope) *ast.FieldList {
 	if p.trace {
 		defer un(trace(p, "Result"))
 	}
 
 	if p.tok == token.LPAREN {
-		_, results := p.parseParameters(scope, lookAhead{}, false)
+		_, results := p.parseParameters(scope, false)
 		return results
 	}
 
-	typ := p.tryType(typeContext)
+	typ := p.tryType()
 	if typ != nil {
 		list := make([]*ast.Field, 1)
 		list[0] = &ast.Field{Type: typ}
@@ -1158,18 +1092,18 @@
 	return nil
 }
 
-func (p *parser) parseFuncType(typeContext bool) (*ast.FuncType, *ast.Scope) {
+func (p *parser) parseFuncType() (*ast.FuncType, *ast.Scope) {
 	if p.trace {
 		defer un(trace(p, "FuncType"))
 	}
 
 	pos := p.expect(token.FUNC)
 	scope := ast.NewScope(p.topScope) // function scope
-	tparams, params := p.parseParameters(scope, lookAhead{}, true)
+	tparams, params := p.parseParameters(scope, true)
 	if tparams != nil {
 		p.error(tparams.Pos(), "function type cannot have type parameters")
 	}
-	results := p.parseResult(scope, typeContext)
+	results := p.parseResult(scope)
 
 	return &ast.FuncType{Func: pos, Params: params, Results: results}, scope
 }
@@ -1182,99 +1116,64 @@
 	doc := p.leadComment
 	var idents []*ast.Ident
 	var typ ast.Expr
-	if p.mode&UnifiedParamLists != 0 {
-		x := p.parseTypeName(nil)
-		if ident, _ := x.(*ast.Ident); ident != nil {
-			switch p.tok {
-			case token.LBRACK:
-				// generic method or embedded instantiated type
-				lbrack := p.pos
-				p.next()
-				p.exprLev++
-				x := p.parseExpr(true) // we don't know yet if we're a lhs or rhs expr
-				p.exprLev--
-				if name0, _ := x.(*ast.Ident); name0 != nil && p.tok != token.COMMA && p.tok != token.RBRACK {
-					// generic method m[T any]
-					scope := ast.NewScope(nil) // method scope
-					list := p.parseParameterList(scope, name0, token.RBRACK, p.parseParamDecl, true)
-					rbrack := p.expect(token.RBRACK)
-					tparams := &ast.FieldList{Opening: lbrack, List: list, Closing: rbrack}
-					_, params := p.parseParameters(scope, lookAhead{}, false)
-					results := p.parseResult(scope, true)
-					idents = []*ast.Ident{ident}
-					typ = &ast.FuncType{Func: token.NoPos, TParams: tparams, Params: params, Results: results}
-				} else {
-					// embedded instantiated type
-					// TODO(gri) should resolve all identifiers in x (doesn't matter for this prototype)
-					list := []ast.Expr{x}
-					if p.atComma("type argument list", token.RBRACK) {
-						p.exprLev++
-						for p.tok != token.RBRACK && p.tok != token.EOF {
-							list = append(list, p.parseType(true))
-							if !p.atComma("type argument list", token.RBRACK) {
-								break
-							}
-							p.next()
-						}
-						p.exprLev--
-					}
-					rbrack := p.expectClosing(token.RBRACK, "type argument list")
-					typ = &ast.CallExpr{Fun: ident, Lparen: lbrack, Args: list, Rparen: rbrack, Brackets: true}
-				}
-			case token.LPAREN:
-				// ordinary method
+	x := p.parseTypeName(nil)
+	if ident, _ := x.(*ast.Ident); ident != nil {
+		switch {
+		case p.tok == token.LBRACK && p.mode&ParseTypeParams != 0:
+			// generic method or embedded instantiated type
+			lbrack := p.pos
+			p.next()
+			p.exprLev++
+			x := p.parseExpr(true) // we don't know yet if we're a lhs or rhs expr
+			p.exprLev--
+			if name0, _ := x.(*ast.Ident); name0 != nil && p.tok != token.COMMA && p.tok != token.RBRACK {
+				// generic method m[T any]
 				scope := ast.NewScope(nil) // method scope
-				_, params := p.parseParameters(scope, lookAhead{}, false)
-				results := p.parseResult(scope, true)
+				list := p.parseParameterList(scope, name0, token.RBRACK, p.parseParamDecl, true)
+				rbrack := p.expect(token.RBRACK)
+				tparams := &ast.FieldList{Opening: lbrack, List: list, Closing: rbrack}
+				// TODO(rfindley) refactor to share code with parseFuncType.
+				_, params := p.parseParameters(scope, false)
+				results := p.parseResult(scope)
 				idents = []*ast.Ident{ident}
-				typ = &ast.FuncType{Func: token.NoPos, Params: params, Results: results}
-			default:
-				// embedded type
-				typ = x
-				p.resolve(typ)
+				typ = &ast.FuncType{Func: token.NoPos, TParams: tparams, Params: params, Results: results}
+			} else {
+				// embedded instantiated type
+				// TODO(rfindley) should resolve all identifiers in x.
+				list := []ast.Expr{x}
+				if p.atComma("type argument list", token.RBRACK) {
+					p.exprLev++
+					for p.tok != token.RBRACK && p.tok != token.EOF {
+						list = append(list, p.parseType())
+						if !p.atComma("type argument list", token.RBRACK) {
+							break
+						}
+						p.next()
+					}
+					p.exprLev--
+				}
+				rbrack := p.expectClosing(token.RBRACK, "type argument list")
+				typ = &ast.CallExpr{Fun: ident, Lparen: lbrack, Args: list, Rparen: rbrack, Brackets: true}
 			}
-		} else {
-			// embedded, possibly instantiated type
+		case p.tok == token.LPAREN:
+			// ordinary method
+			// TODO(rfindley) refactor to share code with parseFuncType.
+			scope := ast.NewScope(nil) // method scope
+			_, params := p.parseParameters(scope, false)
+			results := p.parseResult(scope)
+			idents = []*ast.Ident{ident}
+			typ = &ast.FuncType{Func: token.NoPos, Params: params, Results: results}
+		default:
+			// embedded type
 			typ = x
-			if p.tok == token.LBRACK {
-				// embedded instantiated interface
-				typ = p.parseTypeInstance(typ, lookAhead{})
-			}
+			p.resolve(typ)
 		}
 	} else {
-		if p.tok == token.IDENT {
-			x := p.parseTypeName(nil)
-			if ident, _ := x.(*ast.Ident); ident != nil && (p.tok == token.LPAREN || p.brack && p.tok == token.LBRACK) {
-				// method or embedded instantiated type
-				opening := lookAhead{p.pos, p.tok}
-				p.next()
-				if opening.tok == token.LBRACK && p.tok != token.TYPE {
-					// embedded instantiated type
-					typ = x
-					p.resolve(typ)
-					typ = p.parseTypeInstance(typ, opening)
-				} else {
-					// method
-					idents = []*ast.Ident{ident}
-					scope := ast.NewScope(nil) // method scope
-					tparams, params := p.parseParameters(scope, opening, true)
-					results := p.parseResult(scope, true)
-					typ = &ast.FuncType{Func: token.NoPos, TParams: tparams, Params: params, Results: results}
-				}
-			} else {
-				// embedded, possibly instantiated type
-				typ = x
-				p.resolve(typ)
-				if p.brack && p.tok == token.LBRACK {
-					// embedded instantiated interface
-					typ = p.parseTypeInstance(typ, lookAhead{})
-				}
-			}
-		} else {
-			// embedded, possibly instantiated type
-			// (using enclosing parentheses to distinguish it from a method declaration)
-			// TODO(gri) if p.brack is set, don't allow parenthesized embedded type
-			typ = p.parseType(true)
+		// embedded, possibly instantiated type
+		typ = x
+		if p.tok == token.LBRACK && p.mode&ParseTypeParams != 0 {
+			// embedded instantiated interface
+			typ = p.parseTypeInstance(typ)
 		}
 	}
 	p.expectSemi() // call before accessing p.linecomment
@@ -1294,12 +1193,10 @@
 	lbrace := p.expect(token.LBRACE)
 	scope := ast.NewScope(nil) // interface scope
 	var list []*ast.Field
-L:
-	for {
-		switch p.tok {
-		case token.IDENT, token.LPAREN:
+	for p.tok == token.IDENT || p.mode&ParseTypeParams != 0 && p.tok == token.TYPE {
+		if p.tok == token.IDENT {
 			list = append(list, p.parseMethodSpec(scope))
-		case token.TYPE:
+		} else {
 			// all types in a type list share the same field name "type"
 			// (since type is a keyword, a Go program cannot have that field name)
 			name := []*ast.Ident{{NamePos: p.pos, Name: "type"}}
@@ -1309,10 +1206,10 @@
 				list = append(list, &ast.Field{Names: name, Type: typ})
 			}
 			p.expectSemi()
-		default:
-			break L
 		}
 	}
+	// TODO(rfindley): the error produced here could be improved, since we could
+	// accept a identifier, 'type', or a '}' at this point.
 	rbrace := p.expect(token.RBRACE)
 
 	return &ast.InterfaceType{
@@ -1325,21 +1222,21 @@
 	}
 }
 
-func (p *parser) parseMapType(typeContext bool) *ast.MapType {
+func (p *parser) parseMapType() *ast.MapType {
 	if p.trace {
 		defer un(trace(p, "MapType"))
 	}
 
 	pos := p.expect(token.MAP)
 	p.expect(token.LBRACK)
-	key := p.parseType(true)
+	key := p.parseType()
 	p.expect(token.RBRACK)
-	value := p.parseType(typeContext)
+	value := p.parseType()
 
 	return &ast.MapType{Map: pos, Key: key, Value: value}
 }
 
-func (p *parser) parseChanType(typeContext bool) *ast.ChanType {
+func (p *parser) parseChanType() *ast.ChanType {
 	if p.trace {
 		defer un(trace(p, "ChanType"))
 	}
@@ -1359,90 +1256,66 @@
 		p.expect(token.CHAN)
 		dir = ast.RECV
 	}
-	value := p.parseType(typeContext)
+	value := p.parseType()
 
 	return &ast.ChanType{Begin: pos, Arrow: arrow, Dir: dir, Value: value}
 }
 
-func (p *parser) parseTypeInstance(typ ast.Expr, opening lookAhead) ast.Expr {
+func (p *parser) parseTypeInstance(typ ast.Expr) ast.Expr {
 	if p.trace {
-		defer un(trace(p, "TypeInstantiation"))
+		defer un(trace(p, "TypeInstance"))
 	}
 
-	opening.consume(p)
-
-	closingTok := token.RBRACK
-	if !p.brack || opening.tok != token.LBRACK {
-		if opening.tok != token.LPAREN {
-			p.errorExpected(opening.pos, "'('")
-		}
-		closingTok = token.RPAREN
-	}
+	opening := p.expect(token.LBRACK)
 
 	p.exprLev++
 	var list []ast.Expr
-	for p.tok != closingTok && p.tok != token.EOF {
-		list = append(list, p.parseType(true))
-		if !p.atComma("type argument list", closingTok) {
+	for p.tok != token.RBRACK && p.tok != token.EOF {
+		list = append(list, p.parseType())
+		if !p.atComma("type argument list", token.RBRACK) {
 			break
 		}
 		p.next()
 	}
 	p.exprLev--
 
-	closing := p.expectClosing(closingTok, "type argument list")
+	closing := p.expectClosing(token.RBRACK, "type argument list")
 
-	return &ast.CallExpr{Fun: typ, Lparen: opening.pos, Args: list, Rparen: closing, Brackets: opening.tok == token.LBRACK}
+	return &ast.CallExpr{Fun: typ, Lparen: opening, Args: list, Rparen: closing, Brackets: true}
 }
 
 // If the result is an identifier, it is not resolved.
-// typeContext controls whether a trailing type parameter list (opening "(")
-// following a type is consumed. We need this to disambiguate an expression
-// such as []T(x) between the slice type [](T(x)) and the conversion ([]T)(x).
-// In typeContext, []T(x) is parsed as a slice type; otherwise it is parsed
-// as a conversion.
-// If we use [] for instantiation, when need this to disambiguate an expression
-// such as T[x] between the instantiated type (T[x]) and the index expression (T)(x).
-// But because an index expression requires a value and not a type before the index,
-// we can be more aggressive: whenever we are in a literal type ending in an element
-// type, we know for sure that we are in type context.
-func (p *parser) tryIdentOrType(typeContext bool) ast.Expr {
-	// When []'s are used for type instantiation, there
-	// are no ambiguities that prevent us from moving
-	// forward with instantiation when seeing a "[".
-	if p.brack {
-		typeContext = true
-	}
+func (p *parser) tryIdentOrType() ast.Expr {
 	switch p.tok {
 	case token.IDENT:
 		typ := p.parseTypeName(nil)
-		if typeContext && (p.brack && p.tok == token.LBRACK || !p.brack && p.tok == token.LPAREN) {
-			typ = p.parseTypeInstance(typ, lookAhead{})
+		if p.tok == token.LBRACK && p.mode&ParseTypeParams != 0 {
+			typ = p.parseTypeInstance(typ)
 		}
 		return typ
 	case token.LBRACK:
 		lbrack := p.expect(token.LBRACK)
 		alen := p.parseArrayLen()
 		p.expect(token.RBRACK)
-		elt := p.parseType(typeContext)
+		elt := p.parseType()
 		return &ast.ArrayType{Lbrack: lbrack, Len: alen, Elt: elt}
 	case token.STRUCT:
 		return p.parseStructType()
 	case token.MUL:
-		return p.parsePointerType(typeContext)
+		return p.parsePointerType()
 	case token.FUNC:
-		typ, _ := p.parseFuncType(typeContext)
+		typ, _ := p.parseFuncType()
 		return typ
 	case token.INTERFACE:
 		return p.parseInterfaceType()
 	case token.MAP:
-		return p.parseMapType(typeContext)
+		return p.parseMapType()
 	case token.CHAN, token.ARROW:
-		return p.parseChanType(typeContext)
+		return p.parseChanType()
 	case token.LPAREN:
 		lparen := p.pos
 		p.next()
-		typ := p.parseType(true)
+		typ := p.parseType()
 		rparen := p.expect(token.RPAREN)
 		return &ast.ParenExpr{Lparen: lparen, X: typ, Rparen: rparen}
 	}
@@ -1451,8 +1324,8 @@
 	return nil
 }
 
-func (p *parser) tryType(typeContext bool) ast.Expr {
-	typ := p.tryIdentOrType(typeContext)
+func (p *parser) tryType() ast.Expr {
+	typ := p.tryIdentOrType()
 	if typ != nil {
 		p.resolve(typ)
 	}
@@ -1512,7 +1385,7 @@
 		defer un(trace(p, "FuncTypeOrLit"))
 	}
 
-	typ, scope := p.parseFuncType(false)
+	typ, scope := p.parseFuncType()
 	if p.tok != token.LBRACE {
 		// function type only
 		return typ
@@ -1560,7 +1433,7 @@
 		return p.parseFuncTypeOrLit()
 	}
 
-	if typ := p.tryIdentOrType(false); typ != nil { // do not consume trailing type parameters
+	if typ := p.tryIdentOrType(); typ != nil { // do not consume trailing type parameters
 		// could be type for composite literal or conversion
 		_, isIdent := typ.(*ast.Ident)
 		assert(!isIdent, "type cannot be identifier")
@@ -1595,7 +1468,7 @@
 		// type switch: typ == nil
 		p.next()
 	} else {
-		typ = p.parseType(true)
+		typ = p.parseType()
 	}
 	rparen := p.expect(token.RPAREN)
 
@@ -1608,7 +1481,7 @@
 	}
 
 	lbrack := p.expect(token.LBRACK)
-	if p.brack && p.tok == token.RBRACK {
+	if p.tok == token.RBRACK {
 		// empty index, slice or index expressions are not permitted;
 		// accept them for parsing tolerance, but complain
 		p.errorExpected(p.pos, "operand")
@@ -1621,6 +1494,7 @@
 	var args []ast.Expr
 	var index [N]ast.Expr
 	var colons [N - 1]token.Pos
+	var firstComma token.Pos
 	if p.tok != token.COLON {
 		// We can't know if we have an index expression or a type instantiation;
 		// so even if we see a (named) type we are not going to be in type context.
@@ -1639,12 +1513,13 @@
 			}
 		}
 	case token.COMMA:
+		firstComma = p.pos
 		// instance expression
 		args = append(args, index[0])
 		for p.tok == token.COMMA {
 			p.next()
 			if p.tok != token.RBRACK && p.tok != token.EOF {
-				args = append(args, p.parseType(true))
+				args = append(args, p.parseType())
 			}
 		}
 	}
@@ -1676,57 +1551,15 @@
 		return &ast.IndexExpr{X: x, Lbrack: lbrack, Index: index[0], Rbrack: rbrack}
 	}
 
+	if p.mode&ParseTypeParams == 0 {
+		p.error(firstComma, "expected ']' or ':', found ','")
+		return &ast.BadExpr{From: args[0].Pos(), To: args[len(args)-1].End()}
+	}
+
 	// instance expression
 	return &ast.CallExpr{Fun: x, Lparen: lbrack, Args: args, Rparen: rbrack, Brackets: true}
 }
 
-func (p *parser) parseIndexOrSlice(x ast.Expr) ast.Expr {
-	if p.trace {
-		defer un(trace(p, "IndexOrSlice"))
-	}
-
-	const N = 3 // change the 3 to 2 to disable 3-index slices
-	lbrack := p.expect(token.LBRACK)
-	p.exprLev++
-	var index [N]ast.Expr
-	var colons [N - 1]token.Pos
-	if p.tok != token.COLON {
-		index[0] = p.parseRhs()
-	}
-	ncolons := 0
-	for p.tok == token.COLON && ncolons < len(colons) {
-		colons[ncolons] = p.pos
-		ncolons++
-		p.next()
-		if p.tok != token.COLON && p.tok != token.RBRACK && p.tok != token.EOF {
-			index[ncolons] = p.parseRhs()
-		}
-	}
-	p.exprLev--
-	rbrack := p.expect(token.RBRACK)
-
-	if ncolons > 0 {
-		// slice expression
-		slice3 := false
-		if ncolons == 2 {
-			slice3 = true
-			// Check presence of 2nd and 3rd index here rather than during type-checking
-			// to prevent erroneous programs from passing through gofmt (was issue 7305).
-			if index[1] == nil {
-				p.error(colons[0], "2nd index required in 3-index slice")
-				index[1] = &ast.BadExpr{From: colons[0] + 1, To: colons[1]}
-			}
-			if index[2] == nil {
-				p.error(colons[1], "3rd index required in 3-index slice")
-				index[2] = &ast.BadExpr{From: colons[1] + 1, To: rbrack}
-			}
-		}
-		return &ast.SliceExpr{X: x, Lbrack: lbrack, Low: index[0], High: index[1], Max: index[2], Slice3: slice3, Rbrack: rbrack}
-	}
-
-	return &ast.IndexExpr{X: x, Lbrack: lbrack, Index: index[0], Rbrack: rbrack}
-}
-
 func (p *parser) parseCallOrConversion(fun ast.Expr) *ast.CallExpr {
 	if p.trace {
 		defer un(trace(p, "CallOrConversion"))
@@ -1873,28 +1706,6 @@
 	return x
 }
 
-// isTypeName reports whether x is a (qualified) TypeName.
-func isTypeName(x ast.Expr) bool {
-	switch t := x.(type) {
-	case *ast.BadExpr:
-	case *ast.Ident:
-	case *ast.SelectorExpr:
-		_, isIdent := t.X.(*ast.Ident)
-		return isIdent
-	default:
-		return false // all other nodes are not type names
-	}
-	return true
-}
-
-// If x is of the form *T, deref returns T, otherwise it returns x.
-func deref(x ast.Expr) ast.Expr {
-	if p, isPtr := x.(*ast.StarExpr); isPtr {
-		x = p.X
-	}
-	return x
-}
-
 // If x is of the form (T), unparen returns unparen(T), otherwise it returns x.
 func unparen(x ast.Expr) ast.Expr {
 	if p, isParen := x.(*ast.ParenExpr); isParen {
@@ -1951,11 +1762,7 @@
 			if lhs {
 				p.resolve(x)
 			}
-			if p.brack {
-				x = p.parseIndexOrSliceOrInstance(p.checkExpr(x))
-			} else {
-				x = p.parseIndexOrSlice(p.checkExpr(x))
-			}
+			x = p.parseIndexOrSliceOrInstance(p.checkExpr(x))
 		case token.LPAREN:
 			if lhs {
 				p.resolve(x)
@@ -1973,12 +1780,12 @@
 				}
 				// x is possibly a composite literal type
 			case *ast.CallExpr:
-				if p.brack != t.Brackets || p.exprLev < 0 {
+				if !t.Brackets || p.exprLev < 0 {
 					return
 				}
 				// x is possibly a composite literal type
 			case *ast.IndexExpr:
-				if !p.brack || p.exprLev < 0 {
+				if p.exprLev < 0 {
 					return
 				}
 				// x is possibly a composite literal type
@@ -2328,7 +2135,7 @@
 		// accept potential variable declaration but complain
 		if p.tok == token.VAR {
 			p.next()
-			p.error(p.pos, fmt.Sprintf("var declaration not allowed in 'IF' initializer"))
+			p.error(p.pos, "var declaration not allowed in 'IF' initializer")
 		}
 		init, _ = p.parseSimpleStmt(basic)
 	}
@@ -2410,10 +2217,10 @@
 		defer un(trace(p, "TypeList"))
 	}
 
-	list = append(list, p.parseType(true))
+	list = append(list, p.parseType())
 	for p.tok == token.COMMA {
 		p.next()
-		list = append(list, p.parseType(true))
+		list = append(list, p.parseType())
 	}
 
 	return
@@ -2809,7 +2616,7 @@
 
 	pos := p.pos
 	idents := p.parseIdentList()
-	typ := p.tryType(true)
+	typ := p.tryType()
 	var values []ast.Expr
 	// always permit optional initialization for more tolerant parsing
 	if p.tok == token.ASSIGN {
@@ -2850,16 +2657,8 @@
 }
 
 func (p *parser) parseGenericType(spec *ast.TypeSpec, openPos token.Pos, name0 *ast.Ident, closeTok token.Token) {
-	if closeTok == token.RBRACK {
-		p.brack = true // switch to using []'s instead of ()'s from now on
-	}
 	p.openScope()
-	var list []*ast.Field
-	if p.mode&UnifiedParamLists != 0 {
-		list = p.parseParameterList(p.topScope, name0, closeTok, p.parseParamDecl, true)
-	} else {
-		list = p.parseTypeParams(p.topScope, name0, closeTok)
-	}
+	list := p.parseParameterList(p.topScope, name0, closeTok, p.parseParamDecl, true)
 	closePos := p.expect(closeTok)
 	spec.TParams = &ast.FieldList{Opening: openPos, List: list, Closing: closePos}
 	// Type alias cannot have type parameters. Accept them for robustness but complain.
@@ -2867,7 +2666,7 @@
 		p.error(p.pos, "generic type cannot be alias")
 		p.next()
 	}
-	spec.Type = p.parseType(true)
+	spec.Type = p.parseType()
 	p.closeScope()
 }
 
@@ -2889,80 +2688,27 @@
 	case token.LBRACK:
 		lbrack := p.pos
 		p.next()
-		if p.mode&UnifiedParamLists != 0 {
-			if p.tok == token.IDENT {
-				// array type or generic type [T any]
-				p.exprLev++
-				x := p.parseExpr(true) // we don't know yet if we're a lhs or rhs expr
-				p.exprLev--
-				if name0, _ := x.(*ast.Ident); name0 != nil && p.tok != token.RBRACK {
-					// generic type [T any];
-					p.parseGenericType(spec, lbrack, name0, token.RBRACK)
-				} else {
-					// array type
-					// TODO(gri) should resolve all identifiers in x (doesn't matter for this prototype)
-					p.expect(token.RBRACK)
-					elt := p.parseType(true)
-					spec.Type = &ast.ArrayType{Lbrack: lbrack, Len: x, Elt: elt}
-				}
+		if p.tok == token.IDENT {
+			// array type or generic type [T any]
+			p.exprLev++
+			x := p.parseExpr(true) // we don't know yet if we're a lhs or rhs expr
+			p.exprLev--
+			if name0, _ := x.(*ast.Ident); p.mode&ParseTypeParams != 0 && name0 != nil && p.tok != token.RBRACK {
+				// generic type [T any];
+				p.parseGenericType(spec, lbrack, name0, token.RBRACK)
 			} else {
 				// array type
-				alen := p.parseArrayLen()
+				// TODO(rfindley) should resolve all identifiers in x.
 				p.expect(token.RBRACK)
-				elt := p.parseType(true)
-				spec.Type = &ast.ArrayType{Lbrack: lbrack, Len: alen, Elt: elt}
+				elt := p.parseType()
+				spec.Type = &ast.ArrayType{Lbrack: lbrack, Len: x, Elt: elt}
 			}
 		} else {
-			switch p.tok {
-			case token.TYPE:
-				// generic type
-				p.next()
-				p.parseGenericType(spec, lbrack, nil, token.RBRACK)
-			case token.IDENT:
-				// array type or generic type without "type" keyword
-				p.exprLev++
-				x := p.parseExpr(true) // we don't know yet if we're a lhs or rhs expr
-				p.exprLev--
-				if name0, _ := x.(*ast.Ident); name0 != nil {
-					// array type or generic type without "type" keyword;
-					// assume a generic type and then decide based on next token and use of name0
-					next := p.tok
-					pbrack := p.brack // changed by parseGenericType; restore if we have an array type
-					p.parseGenericType(spec, lbrack, name0, token.RBRACK)
-					if next == token.RBRACK && !usesName(spec.Type, name0.Name) {
-						// assume array type
-						p.brack = pbrack
-						spec.TParams = nil
-						spec.Type = &ast.ArrayType{Lbrack: lbrack, Len: x, Elt: spec.Type}
-					}
-				} else {
-					// array type
-					// TODO(gri) should resolve all identifiers in x (doesn't matter for this prototype)
-					p.expect(token.RBRACK)
-					elt := p.parseType(true)
-					spec.Type = &ast.ArrayType{Lbrack: lbrack, Len: x, Elt: elt}
-				}
-			default:
-				// array type
-				alen := p.parseArrayLen()
-				p.expect(token.RBRACK)
-				elt := p.parseType(true)
-				spec.Type = &ast.ArrayType{Lbrack: lbrack, Len: alen, Elt: elt}
-			}
-		}
-
-	case token.LPAREN:
-		lparen := p.pos
-		p.next()
-		if !p.brack && p.tok == token.TYPE {
-			// generic type
-			p.next()
-			p.parseGenericType(spec, lparen, nil, token.RPAREN)
-		} else {
-			// parenthesized type
-			typ := p.parseType(true)
-			rparen := p.expect(token.RPAREN)
-			spec.Type = &ast.ParenExpr{Lparen: lparen, X: typ, Rparen: rparen}
+			// array type
+			alen := p.parseArrayLen()
+			p.expect(token.RBRACK)
+			elt := p.parseType()
+			spec.Type = &ast.ArrayType{Lbrack: lbrack, Len: alen, Elt: elt}
 		}
 
 	default:
@@ -2972,7 +2718,7 @@
 			spec.Assign = p.pos
 			p.next()
 		}
-		spec.Type = p.parseType(true)
+		spec.Type = p.parseType()
 	}
 
 	p.expectSemi() // call before accessing p.linecomment
@@ -2981,27 +2727,6 @@
 	return spec
 }
 
-// uses reports whether name appears anywhere in x except as array length.
-func usesName(x ast.Expr, name string) (used bool) {
-	ast.Inspect(x, func(n ast.Node) bool {
-		switch n := n.(type) {
-		case *ast.Ident:
-			if n.Name == name {
-				used = true
-			}
-			return false
-		case *ast.ArrayType:
-			// ignore n.Len (and for slices, n.Len == nil)
-			if usesName(n.Elt, name) {
-				used = true
-			}
-			return false
-		}
-		return true
-	})
-	return
-}
-
 func (p *parser) parseGenDecl(keyword token.Token, f parseSpecFunction) *ast.GenDecl {
 	if p.trace {
 		defer un(trace(p, "GenDecl("+keyword.String()+")"))
@@ -3044,13 +2769,13 @@
 
 	var recv *ast.FieldList
 	if p.tok == token.LPAREN {
-		_, recv = p.parseParameters(scope, lookAhead{}, false)
+		_, recv = p.parseParameters(scope, false)
 	}
 
 	ident := p.parseIdent()
 
-	tparams, params := p.parseParameters(scope, lookAhead{}, true)
-	results := p.parseResult(scope, true)
+	tparams, params := p.parseParameters(scope, true)
+	results := p.parseResult(scope)
 
 	var body *ast.BlockStmt
 	if p.tok == token.LBRACE {
@@ -3185,14 +2910,13 @@
 	}
 
 	return &ast.File{
-		Doc:         doc,
-		Package:     pos,
-		Name:        ident,
-		Decls:       decls,
-		Scope:       p.pkgScope,
-		Imports:     p.imports,
-		Unresolved:  p.unresolved[0:i],
-		Comments:    p.comments,
-		UseBrackets: p.brack,
+		Doc:        doc,
+		Package:    pos,
+		Name:       ident,
+		Decls:      decls,
+		Scope:      p.pkgScope,
+		Imports:    p.imports,
+		Unresolved: p.unresolved[0:i],
+		Comments:   p.comments,
 	}
 }
diff --git a/src/go/parser/parser_test.go b/src/go/parser/parser_test.go
index 25a374e..e204854 100644
--- a/src/go/parser/parser_test.go
+++ b/src/go/parser/parser_test.go
@@ -82,6 +82,14 @@
 	}
 }
 
+func TestIssue42951(t *testing.T) {
+	path := "./testdata/issue42951"
+	_, err := ParseDir(token.NewFileSet(), path, nil, 0)
+	if err != nil {
+		t.Errorf("ParseDir(%s): %v", path, err)
+	}
+}
+
 func TestParseExpr(t *testing.T) {
 	// just kicking the tires:
 	// a valid arithmetic expression
diff --git a/src/go/parser/short_test.go b/src/go/parser/short_test.go
index bc7caa2..3676c27 100644
--- a/src/go/parser/short_test.go
+++ b/src/go/parser/short_test.go
@@ -49,168 +49,100 @@
 	`package p; type T = int`,
 	`package p; type (T = p.T; _ = struct{}; x = *T)`,
 	`package p; type T (*int)`,
-
-	// structs with parameterized embedded fields (for symmetry with interfaces)
 	`package p; type _ struct{ ((int)) }`,
 	`package p; type _ struct{ (*(int)) }`,
 	`package p; type _ struct{ ([]byte) }`, // disallowed by type-checker
-
-	// type parameters
-	`package p; type T(type P) struct { P }`,
-	`package p; type T(type P comparable) struct { P }`,
-	`package p; type T(type P comparable(P)) struct { P }`,
-	`package p; type T(type P1, P2) struct { P1; f []P2 }`,
-	`package p; type _ []T(int)`,
-
-	`package p; type T[type P] struct { P }`,
-	`package p; type T[type P comparable] struct { P }`,
-	`package p; type T[type P comparable[P]] struct { P }`,
-	`package p; type T[type P1, P2] struct { P1; f []P2 }`,
-	`package p; type _[type] int; type _ []T[int]`,
-
 	`package p; var _ = func()T(nil)`,
-	`package p; func _(type)()`,
-	`package p; func _(type)()()`,
 	`package p; func _(T (P))`,
 	`package p; func _(T []E)`,
 	`package p; func _(T [P]E)`,
-	`package p; func _(x T(P1, P2, P3))`,
-	`package p; func _(x p.T(Q))`,
-	`package p; func _(p.T(Q))`,
-
-	`package p; var _ = func()T(nil)`,
-	`package p; func _[type]()`,
-	`package p; func _[type]()()`,
-	`package p; func _(T (P))`,
-	`package p; func _[type](); func _(T []E)`,
-	`package p; func _[type](); func _(T [P]E)`,
-	`package p; func _[type](); func _(x T[P1, P2, P3])`,
-	`package p; func _[type](); func _(x p.T[Q])`,
-	`package p; func _[type](); func _(p.T[Q])`,
-
-	`package p; type _[type] int; var _ T[chan int]`,
-	`package p; func f[A, B](); func _() { _ = f[int, int] }`,
-
-	// optional "type" keyword for generic types using square brackets
-	`package p; type _[A interface{},] struct{}`,
-	`package p; type _[A interface{}] struct{}`,
-	`package p; type _[A, B,] struct{}`,
-	`package p; type _[A, B] struct{}`,
-	`package p; type _[A,] struct{}`,
-	`package p; type _ [A+B]struct{}`, // this is an array!
-
-	`package p; type _[A]struct{}`,     // this is an array
-	`package p; type _[A] struct{ A }`, // this is not an array!
-
-	// optional "type" keyword for generic functions using square brackets
-	`package p; func _[]()`,
-	`package p; func _[T]()`,
-	`package p; func _[T](x T)`,
-	`package p; func _[T1, T2](x T)`,
-
-	`package p; func _[](); func (R) _[]()`,
-	`package p; func _[](); func (R[P]) _[T]()`,
-	`package p; func _[](); func (_ R[P]) _[T](x T)`,
-	`package p; func _[](); func (_ R[P, Q]) _[T1, T2](x T)`,
-
-	// need for parentheses to disambiguate
-	`package p; var _ = [](T(int)){}`,
-	`package p; var _ = [10](T(int)){}`,
-	`package p; var _ = func()(T(int)){}`,
-	`package p; var _ = map[T(int)](T(int)){}`,
-	`package p; var _ = chan (T(int))(x)`,
-	`package p; func _((T(P)))`,
-	`package p; func _((T(P1, P2, P3)))`,
-
-	`package p; func _(type *P)()`,
-	`package p; func _(type *P B)()`,
-	`package p; func _(type P, *Q interface{})()`,
-
-	`package p; func _((T(P))) T(P)`,
-	`package p; func _(_ T(P), T (P)) T(P)`,
-
-	// no need for parentheses to disambiguate
-	`package p; type _[type] int; var _ = []T[int]{}`,
-	`package p; type _[type] int; var _ = [10]T[int]{}`,
-	`package p; type _[type] int; var _ = func()T[int]{}`,
-	`package p; type _[type] int; var _ = map[T[int]]T[int]{}`,
-	`package p; type _[type] int; var _ = chan T[int](x)`,
-	`package p; type _[type] int; func _(T[P])`,
-	`package p; type _[type] int; func _(T[P1, P2, P3])`,
-
-	`package p; type _[type] int; func _[type *P]()`,
-	`package p; type _[type] int; func _[type *P B]()`,
-	`package p; type _[type] int; func _[type P, *Q interface{}]()`,
-
-	`package p; type _[type] int; func _(T[P]) T[P]`,
-	`package p; type _[type] int; func _(_ T[P], T (P)) T[P]`,
-
-	// method type parameters (if methodTypeParamsOk)
-	`package p; func _(type A, B)(a A) B`,
-	`package p; func _(type A, B C)(a A) B`,
-	`package p; func _(type A, B C(A, B))(a A) B`,
-	`package p; func (T) _(type A, B)(a A) B`,
-	`package p; func (T) _(type A, B C)(a A) B`,
-	`package p; func (T) _(type A, B C(A, B))(a A) B`,
-	`package p; type _ interface { _(type A, B)(a A) B }`,
-	`package p; type _ interface { _(type A, B C)(a A) B }`,
-	`package p; type _ interface { _(type A, B C(A, B))(a A) B }`,
-
-	`package p; type _[type] int; func _[type A, B](a A) B`,
-	`package p; type _[type] int; func _[type A, B C](a A) B`,
-	`package p; type _[type] int; func _[type A, B C[A, B]](a A) B`,
-	`package p; type _[type] int; func (T) _[type A, B](a A) B`,
-	`package p; type _[type] int; func (T) _[type A, B C](a A) B`,
-	`package p; type _[type] int; func (T) _[type A, B C[A, B]](a A) B`,
-	`package p; type _[type] int; type _ interface { _[type A, B](a A) B }`,
-	`package p; type _[type] int; type _ interface { _[type A, B C](a A) B }`,
-	`package p; type _[type] int; type _ interface { _[type A, B C[A, B]](a A) B }`,
-
-	// type bounds
-	`package p; func _(type T1, T2 interface{})(x T1) T2`,
-	`package p; func _(type T1 interface{ m() }, T2, T3 interface{})(x T1, y T3) T2`,
-
-	`package p; type _[type] int; func _[type T1, T2 interface{}](x T1) T2`,
-	`package p; type _[type] int; func _[type T1 interface{ m() }, T2, T3 interface{}](x T1, y T3) T2`,
-
-	// embedded types
-	`package p; type _ struct{ (T(P)) }`,
-	`package p; type _ struct{ (T(struct{a, b, c int})) }`,
+	`package p; type _ [A+B]struct{}`,
+	`package p; func (R) _()`,
 	`package p; type _ struct{ f [n]E }`,
 	`package p; type _ struct{ f [a+b+c+d]E }`,
+	`package p; type I1 interface{}; type I2 interface{ I1 }`,
+}
 
-	`package p; type _[type] int; type _ struct{ T[P] }`,
-	`package p; type _[type] int; type _ struct{ T[struct{a, b, c int}] }`,
-	`package p; type _[type] int; type _ struct{ f [n]E }`,
-	`package p; type _[type] int; type _ struct{ f [a+b+c+d]E }`,
+// validWithTParamsOnly holds source code examples that are valid if
+// ParseTypeParams is set, but invalid if not. When checking with the
+// ParseTypeParams set, errors are ignored.
+var validWithTParamsOnly = []string{
+	`package p; type _ []T[ /* ERROR "expected ';', found '\['" */ int]`,
+	`package p; type T[P any /* ERROR "expected ']', found any" */ ] struct { P }`,
+	`package p; type T[P comparable /* ERROR "expected ']', found comparable" */ ] struct { P }`,
+	`package p; type T[P comparable /* ERROR "expected ']', found comparable" */ [P]] struct { P }`,
+	`package p; type T[P1, /* ERROR "expected ']', found ','" */ P2 any] struct { P1; f []P2 }`,
+	`package p; func _[ /* ERROR "expected '\(', found '\['" */ T any]()()`,
+	`package p; func _(T (P))`,
+	`package p; func f[ /* ERROR "expected '\(', found '\['" */ A, B any](); func _() { _ = f[int, int] }`,
+	`package p; func _(x /* ERROR "mixed named and unnamed parameters" */ T[P1, P2, P3])`,
+	`package p; func _(x /* ERROR "mixed named and unnamed parameters" */ p.T[Q])`,
+	`package p; func _(p.T[ /* ERROR "missing ',' in parameter list" */ Q])`,
+	`package p; type _[A interface /* ERROR "expected ']', found 'interface'" */ {},] struct{}`,
+	`package p; type _[A interface /* ERROR "expected ']', found 'interface'" */ {}] struct{}`,
+	`package p; type _[A, /* ERROR "expected ']', found ','" */  B any,] struct{}`,
+	`package p; type _[A, /* ERROR "expected ']', found ','" */ B any] struct{}`,
+	`package p; type _[A any /* ERROR "expected ']', found any" */,] struct{}`,
+	`package p; type _[A any /* ERROR "expected ']', found any" */ ]struct{}`,
+	`package p; type _[A any /* ERROR "expected ']', found any" */ ] struct{ A }`,
+	`package p; func _[ /* ERROR "expected '\(', found '\['" */ T any]()`,
+	`package p; func _[ /* ERROR "expected '\(', found '\['" */ T any](x T)`,
+	`package p; func _[ /* ERROR "expected '\(', found '\['" */ T1, T2 any](x T)`,
+	`package p; func _[ /* ERROR "expected '\(', found '\['" */ A, B any](a A) B`,
+	`package p; func _[ /* ERROR "expected '\(', found '\['" */ A, B C](a A) B`,
+	`package p; func _[ /* ERROR "expected '\(', found '\['" */ A, B C[A, B]](a A) B`,
+	`package p; func (T) _[ /* ERROR "expected '\(', found '\['" */ A, B any](a A) B`,
+	`package p; func (T) _[ /* ERROR "expected '\(', found '\['" */ A, B C](a A) B`,
+	`package p; func (T) _[ /* ERROR "expected '\(', found '\['" */ A, B C[A, B]](a A) B`,
+	`package p; type _[A, /* ERROR "expected ']', found ','" */ B any] interface { _(a A) B }`,
+	`package p; type _[A, /* ERROR "expected ']', found ','" */ B C[A, B]] interface { _(a A) B }`,
+	`package p; func _[ /* ERROR "expected '\(', found '\['" */ T1, T2 interface{}](x T1) T2`,
+	`package p; func _[ /* ERROR "expected '\(', found '\['" */ T1 interface{ m() }, T2, T3 interface{}](x T1, y T3) T2`,
+	`package p; var _ = [ /* ERROR "expected expression" */ ]T[int]{}`,
+	`package p; var _ = [ /* ERROR "expected expression" */ 10]T[int]{}`,
+	`package p; var _ = func /* ERROR "expected expression" */ ()T[int]{}`,
+	`package p; var _ = map /* ERROR "expected expression" */ [T[int]]T[int]{}`,
+	`package p; var _ = chan /* ERROR "expected expression" */ T[int](x)`,
+	`package p; func _(_ T[ /* ERROR "missing ',' in parameter list" */ P], T P) T[P]`,
+	`package p; var _ T[ /* ERROR "expected ';', found '\['" */ chan int]`,
 
-	// interfaces with type lists
-	`package p; type _ interface{type int}`,
-	`package p; type _ interface{type int, float32; type bool; m(); type string;}`,
+	// TODO(rfindley) this error message could be improved.
+	`package p; func (_ /* ERROR "mixed named and unnamed parameters" */ R[P]) _[T any](x T)`,
+	`package p; func (_ /* ERROR "mixed named and unnamed parameters" */ R[ P, Q]) _[T1, T2 any](x T)`,
 
-	`package p; type _[type] int; type _ interface{type int}`,
-	`package p; type _[type] int; type _ interface{type int, float32; type bool; m(); type string;}`,
-
-	// interfaces with parenthesized embedded and possibly parameterized interfaces
-	`package p; type I1 interface{}; type I2 interface{ (I1) }`,
-	`package p; type I1(type T) interface{}; type I2 interface{ (I1(int)) }`,
-	`package p; type I1(type T) interface{}; type I2(type T) interface{ (I1(T)) }`,
-
-	`package p; type _[type] int; type I1 interface{}; type I2 interface{ (I1) }`,
-	`package p; type I1[type T] interface{}; type I2 interface{ I1[int] }`,
-	`package p; type I1[type T] interface{}; type I2[type T] interface{ I1[T] }`,
+	`package p; func (R[P] /* ERROR "missing element type" */ ) _[T any]()`,
+	`package p; func _(T[P] /* ERROR "missing element type" */ )`,
+	`package p; func _(T[P1, /* ERROR "expected ']', found ','" */ P2, P3 ])`,
+	`package p; func _(T[P] /* ERROR "missing element type" */ ) T[P]`,
+	`package p; type _ struct{ T[P] /* ERROR "missing element type" */ }`,
+	`package p; type _ struct{ T[struct /* ERROR "expected expression" */ {a, b, c int}] }`,
+	`package p; type _ interface{type /* ERROR "expected '}', found 'type'" */ int}`,
+	`package p; type _ interface{type /* ERROR "expected '}', found 'type'" */ int, float32; type bool; m(); type string;}`,
+	`package p; type I1[T any /* ERROR "expected ']', found any" */ ] interface{}; type I2 interface{ I1[int] }`,
+	`package p; type I1[T any /* ERROR "expected ']', found any" */ ] interface{}; type I2[T any] interface{ I1[T] }`,
+	`package p; type _ interface { f[ /* ERROR "expected ';', found '\['" */ T any]() }`,
 }
 
 func TestValid(t *testing.T) {
-	for _, src := range valids {
-		checkErrors(t, src, src)
-	}
+	t.Run("no tparams", func(t *testing.T) {
+		for _, src := range valids {
+			checkErrors(t, src, src, DeclarationErrors|AllErrors, false)
+		}
+	})
+	t.Run("tparams", func(t *testing.T) {
+		for _, src := range valids {
+			checkErrors(t, src, src, DeclarationErrors|AllErrors|ParseTypeParams, false)
+		}
+		for _, src := range validWithTParamsOnly {
+			checkErrors(t, src, src, DeclarationErrors|AllErrors|ParseTypeParams, false)
+		}
+	})
 }
 
 // TestSingle is useful to track down a problem with a single short test program.
 func TestSingle(t *testing.T) {
-	const src = `package p; var _ = T(P){}`
-	checkErrors(t, src, src)
+	const src = `package p; var _ = T[P]{}`
+	checkErrors(t, src, src, DeclarationErrors|AllErrors|ParseTypeParams, true)
 }
 
 var invalids = []string{
@@ -236,7 +168,6 @@
 	`package p; var a = chan /* ERROR "expected expression" */ int;`,
 	`package p; var a = []int{[ /* ERROR "expected expression" */ ]int};`,
 	`package p; var a = ( /* ERROR "expected expression" */ []int);`,
-	`package p; var a = a[[ /* ERROR "expected expression" */ ]int:[]int];`,
 	`package p; var a = <- /* ERROR "expected expression" */ chan int;`,
 	`package p; func f() { select { case _ <- chan /* ERROR "expected expression" */ int: } };`,
 	`package p; func f() { _ = (<-<- /* ERROR "expected 'chan'" */ chan int)(nil) };`,
@@ -259,15 +190,14 @@
 	`package p; func f() { go f /* ERROR HERE "function must be invoked" */ }`,
 	`package p; func f() { defer func() {} /* ERROR HERE "function must be invoked" */ }`,
 	`package p; func f() { go func() { func() { f(x func /* ERROR "missing ','" */ (){}) } } }`,
-	//`package p; func f(x func(), u v func /* ERROR "missing ','" */ ()){}`,
-
-	// type parameters
-	`package p; var _ func( /* ERROR "cannot have type parameters" */ type T)(T)`,
 	`package p; func _() (type /* ERROR "found 'type'" */ T)(T)`,
 	`package p; func (type /* ERROR "found 'type'" */ T)(T) _()`,
 	`package p; type _[A+B, /* ERROR "expected ']'" */ ] int`,
-	`package p; type _[type _] int; var _ = T[] /* ERROR "expected operand" */ {}`,
-	`package p; type T[P any] = /* ERROR "cannot be alias" */ T0`,
+
+	// TODO: this error should be positioned on the ':'
+	`package p; var a = a[[]int:[ /* ERROR "expected expression" */ ]int];`,
+	// TODO: the compiler error is better here: "cannot parenthesize embedded type"
+	`package p; type I1 interface{}; type I2 interface{ (/* ERROR "expected '}', found '\('" */ I1) }`,
 
 	// issue 8656
 	`package p; func f() (a b string /* ERROR "missing ','" */ , ok bool)`,
@@ -285,17 +215,56 @@
 	// issue 11611
 	`package p; type _ struct { int, } /* ERROR "expected 'IDENT', found '}'" */ ;`,
 	`package p; type _ struct { int, float } /* ERROR "expected type, found '}'" */ ;`,
-	//`package p; type _ struct { ( /* ERROR "cannot parenthesize embedded type" */ int) };`,
-	//`package p; func _()(x, y, z ... /* ERROR "expected '\)', found '...'" */ int){}`,
-	//`package p; func _()(... /* ERROR "expected type, found '...'" */ int){}`,
 
 	// issue 13475
 	`package p; func f() { if true {} else ; /* ERROR "expected if statement or block" */ }`,
 	`package p; func f() { if true {} else defer /* ERROR "expected if statement or block" */ f() }`,
 }
 
+// invalidNoTParamErrs holds invalid source code examples annotated with the
+// error messages produced when ParseTypeParams is not set.
+var invalidNoTParamErrs = []string{
+	`package p; type _[_ any /* ERROR "expected ']', found any" */ ] int; var _ = T[]{}`,
+	`package p; type T[P any /* ERROR "expected ']', found any" */ ] = T0`,
+	`package p; var _ func[ /* ERROR "expected '\(', found '\['" */ T any](T)`,
+	`package p; func _[ /* ERROR "expected '\(', found '\['" */ ]()`,
+	`package p; type _[A, /* ERROR "expected ']', found ','" */] struct{ A }`,
+	`package p; func _[ /* ERROR "expected '\(', found '\['" */ type P, *Q interface{}]()`,
+}
+
+// invalidTParamErrs holds invalid source code examples annotated with the
+// error messages produced when ParseTypeParams is set.
+var invalidTParamErrs = []string{
+	`package p; type _[_ any] int; var _ = T[] /* ERROR "expected operand" */ {}`,
+	`package p; type T[P any] = /* ERROR "cannot be alias" */ T0`,
+	`package p; var _ func[ /* ERROR "cannot have type parameters" */ T any](T)`,
+	`package p; func _[]/* ERROR "empty type parameter list" */()`,
+
+	// TODO(rfindley) a better location would be after the ']'
+	`package p; type _[A/* ERROR "all type parameters must be named" */,] struct{ A }`,
+
+	// TODO(rfindley) this error is confusing.
+	`package p; func _[type /* ERROR "all type parameters must be named" */P, *Q interface{}]()`,
+}
+
 func TestInvalid(t *testing.T) {
-	for _, src := range invalids {
-		checkErrors(t, src, src)
-	}
+	t.Run("no tparams", func(t *testing.T) {
+		for _, src := range invalids {
+			checkErrors(t, src, src, DeclarationErrors|AllErrors, true)
+		}
+		for _, src := range validWithTParamsOnly {
+			checkErrors(t, src, src, DeclarationErrors|AllErrors, true)
+		}
+		for _, src := range invalidNoTParamErrs {
+			checkErrors(t, src, src, DeclarationErrors|AllErrors, true)
+		}
+	})
+	t.Run("tparams", func(t *testing.T) {
+		for _, src := range invalids {
+			checkErrors(t, src, src, DeclarationErrors|AllErrors|ParseTypeParams, true)
+		}
+		for _, src := range invalidTParamErrs {
+			checkErrors(t, src, src, DeclarationErrors|AllErrors|ParseTypeParams, true)
+		}
+	})
 }
diff --git a/src/go/parser/testdata/chans.go2 b/src/go/parser/testdata/chans.go2
index d6ca4df..fad2bce 100644
--- a/src/go/parser/testdata/chans.go2
+++ b/src/go/parser/testdata/chans.go2
@@ -10,24 +10,24 @@
 //
 // This is a convenient way to exit a goroutine sending values when
 // the receiver stops reading them.
-func Ranger(type T)() (*Sender(T), *Receiver(T)) {
+func Ranger[T any]() (*Sender[T], *Receiver[T]) {
 	c := make(chan T)
 	d := make(chan bool)
-	s := &Sender(T){values: c, done: d}
-	r := &Receiver(T){values: c, done: d}
+	s := &Sender[T]{values: c, done: d}
+	r := &Receiver[T]{values: c, done: d}
 	runtime.SetFinalizer(r, r.finalize)
 	return s, r
 }
 
 // A sender is used to send values to a Receiver.
-type Sender(type T) struct {
+type Sender[T any] struct {
 	values chan<- T
 	done <-chan bool
 }
 
 // Send sends a value to the receiver. It returns whether any more
 // values may be sent; if it returns false the value was not sent.
-func (s *Sender(T)) Send(v T) bool {
+func (s *Sender[T]) Send(v T) bool {
 	select {
 	case s.values <- v:
 		return true
@@ -38,12 +38,12 @@
 
 // Close tells the receiver that no more values will arrive.
 // After Close is called, the Sender may no longer be used.
-func (s *Sender(T)) Close() {
+func (s *Sender[T]) Close() {
 	close(s.values)
 }
 
 // A Receiver receives values from a Sender.
-type Receiver(type T) struct {
+type Receiver[T any] struct {
 	values <-chan T
 	done chan<- bool
 }
@@ -51,12 +51,12 @@
 // Next returns the next value from the channel. The bool result
 // indicates whether the value is valid, or whether the Sender has
 // been closed and no more values will be received.
-func (r *Receiver(T)) Next() (T, bool) {
+func (r *Receiver[T]) Next() (T, bool) {
 	v, ok := <-r.values
 	return v, ok
 }
 
 // finalize is a finalizer for the receiver.
-func (r *Receiver(T)) finalize() {
+func (r *Receiver[T]) finalize() {
 	close(r.done)
 }
diff --git a/src/go/parser/testdata/chansB.go2 b/src/go/parser/testdata/chansB.go2
deleted file mode 100644
index d2ee3a3..0000000
--- a/src/go/parser/testdata/chansB.go2
+++ /dev/null
@@ -1,62 +0,0 @@
-package chans
-
-import "runtime"
-
-// Ranger returns a Sender and a Receiver. The Receiver provides a
-// Next method to retrieve values. The Sender provides a Send method
-// to send values and a Close method to stop sending values. The Next
-// method indicates when the Sender has been closed, and the Send
-// method indicates when the Receiver has been freed.
-//
-// This is a convenient way to exit a goroutine sending values when
-// the receiver stops reading them.
-func Ranger[type T]() (*Sender[T], *Receiver[T]) {
-	c := make(chan T)
-	d := make(chan bool)
-	s := &Sender[T]{values: c, done: d}
-	r := &Receiver[T]{values: c, done: d}
-	runtime.SetFinalizer(r, r.finalize)
-	return s, r
-}
-
-// A sender is used to send values to a Receiver.
-type Sender[type T] struct {
-	values chan<- T
-	done <-chan bool
-}
-
-// Send sends a value to the receiver. It returns whether any more
-// values may be sent; if it returns false the value was not sent.
-func (s *Sender[T]) Send(v T) bool {
-	select {
-	case s.values <- v:
-		return true
-	case <-s.done:
-		return false
-	}
-}
-
-// Close tells the receiver that no more values will arrive.
-// After Close is called, the Sender may no longer be used.
-func (s *Sender[T]) Close() {
-	close(s.values)
-}
-
-// A Receiver receives values from a Sender.
-type Receiver[type T] struct {
-	values <-chan T
-	done chan<- bool
-}
-
-// Next returns the next value from the channel. The bool result
-// indicates whether the value is valid, or whether the Sender has
-// been closed and no more values will be received.
-func (r *Receiver[T]) Next() (T, bool) {
-	v, ok := <-r.values
-	return v, ok
-}
-
-// finalize is a finalizer for the receiver.
-func (r *Receiver[T]) finalize() {
-	close(r.done)
-}
diff --git a/src/go/parser/testdata/issue42951/not_a_file.go/invalid.go b/src/go/parser/testdata/issue42951/not_a_file.go/invalid.go
new file mode 100644
index 0000000..bb698be
--- /dev/null
+++ b/src/go/parser/testdata/issue42951/not_a_file.go/invalid.go
@@ -0,0 +1 @@
+This file should not be parsed by ParseDir.
diff --git a/src/go/parser/testdata/linalg.go2 b/src/go/parser/testdata/linalg.go2
index 5fbd22f..fba0d02 100644
--- a/src/go/parser/testdata/linalg.go2
+++ b/src/go/parser/testdata/linalg.go2
@@ -15,7 +15,7 @@
 		complex64, complex128
 }
 
-func DotProduct(type T Numeric)(s1, s2 []T) T {
+func DotProduct[T Numeric](s1, s2 []T) T {
 	if len(s1) != len(s2) {
 		panic("DotProduct: slices of unequal length")
 	}
@@ -27,7 +27,7 @@
 }
 
 // NumericAbs matches numeric types with an Abs method.
-type NumericAbs(type T) interface {
+type NumericAbs[T any] interface {
 	Numeric
 
 	Abs() T
@@ -35,7 +35,7 @@
 
 // AbsDifference computes the absolute value of the difference of
 // a and b, where the absolute value is determined by the Abs method.
-func AbsDifference(type T NumericAbs)(a, b T) T {
+func AbsDifference[T NumericAbs](a, b T) T {
 	d := a - b
 	return d.Abs()
 }
@@ -54,9 +54,9 @@
 
 // OrderedAbs is a helper type that defines an Abs method for
 // ordered numeric types.
-type OrderedAbs(type T OrderedNumeric) T
+type OrderedAbs[T OrderedNumeric] T
 
-func (a OrderedAbs(T)) Abs() OrderedAbs(T) {
+func (a OrderedAbs[T]) Abs() OrderedAbs[T] {
 	if a < 0 {
 		return -a
 	}
@@ -65,19 +65,19 @@
 
 // ComplexAbs is a helper type that defines an Abs method for
 // complex types.
-type ComplexAbs(type T Complex) T
+type ComplexAbs[T Complex] T
 
-func (a ComplexAbs(T)) Abs() ComplexAbs(T) {
+func (a ComplexAbs[T]) Abs() ComplexAbs[T] {
 	r := float64(real(a))
 	i := float64(imag(a))
 	d := math.Sqrt(r * r + i * i)
-	return ComplexAbs(T)(complex(d, 0))
+	return ComplexAbs[T](complex(d, 0))
 }
 
-func OrderedAbsDifference(type T OrderedNumeric)(a, b T) T {
-	return T(AbsDifference(OrderedAbs(T)(a), OrderedAbs(T)(b)))
+func OrderedAbsDifference[T OrderedNumeric](a, b T) T {
+	return T(AbsDifference(OrderedAbs[T](a), OrderedAbs[T](b)))
 }
 
-func ComplexAbsDifference(type T Complex)(a, b T) T {
-	return T(AbsDifference(ComplexAbs(T)(a), ComplexAbs(T)(b)))
+func ComplexAbsDifference[T Complex](a, b T) T {
+	return T(AbsDifference(ComplexAbs[T](a), ComplexAbs[T](b)))
 }
diff --git a/src/go/parser/testdata/linalgB.go2 b/src/go/parser/testdata/linalgB.go2
deleted file mode 100644
index a72f7be..0000000
--- a/src/go/parser/testdata/linalgB.go2
+++ /dev/null
@@ -1,83 +0,0 @@
-// Copyright 2019 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 linalg
-
-import "math"
-
-// Numeric is type bound that matches any numeric type.
-// It would likely be in a constraints package in the standard library.
-type Numeric interface {
-	type int, int8, int16, int32, int64,
-		uint, uint8, uint16, uint32, uint64, uintptr,
-		float32, float64,
-		complex64, complex128
-}
-
-func DotProduct[type T Numeric](s1, s2 []T) T {
-	if len(s1) != len(s2) {
-		panic("DotProduct: slices of unequal length")
-	}
-	var r T
-	for i := range s1 {
-		r += s1[i] * s2[i]
-	}
-	return r
-}
-
-// NumericAbs matches numeric types with an Abs method.
-type NumericAbs[type T] interface {
-	Numeric
-
-	Abs() T
-}
-
-// AbsDifference computes the absolute value of the difference of
-// a and b, where the absolute value is determined by the Abs method.
-func AbsDifference[type T NumericAbs](a, b T) T {
-	d := a - b
-	return d.Abs()
-}
-
-// OrderedNumeric is a type bound that matches numeric types that support the < operator.
-type OrderedNumeric interface {
-	type int, int8, int16, int32, int64,
-		uint, uint8, uint16, uint32, uint64, uintptr,
-		float32, float64
-}
-
-// Complex is a type bound that matches the two complex types, which do not have a < operator.
-type Complex interface {
-	type complex64, complex128
-}
-
-// OrderedAbs is a helper type that defines an Abs method for
-// ordered numeric types.
-type OrderedAbs[type T OrderedNumeric] T
-
-func (a OrderedAbs[T]) Abs() OrderedAbs[T] {
-	if a < 0 {
-		return -a
-	}
-	return a
-}
-
-// ComplexAbs is a helper type that defines an Abs method for
-// complex types.
-type ComplexAbs[type T Complex] T
-
-func (a ComplexAbs[T]) Abs() ComplexAbs[T] {
-	r := float64(real(a))
-	i := float64(imag(a))
-	d := math.Sqrt(r * r + i * i)
-	return ComplexAbs[T](complex(d, 0))
-}
-
-func OrderedAbsDifference[type T OrderedNumeric](a, b T) T {
-	return T(AbsDifference(OrderedAbs[T](a), OrderedAbs[T](b)))
-}
-
-func ComplexAbsDifference[type T Complex](a, b T) T {
-	return T(AbsDifference(ComplexAbs[T](a), ComplexAbs[T](b)))
-}
diff --git a/src/go/parser/testdata/map.go2 b/src/go/parser/testdata/map.go2
index 8b0cdaa..74c79ae 100644
--- a/src/go/parser/testdata/map.go2
+++ b/src/go/parser/testdata/map.go2
@@ -4,27 +4,27 @@
 import "chans"
 
 // Map is an ordered map.
-type Map(type K, V) struct {
-	root    *node(K, V)
+type Map[K, V any] struct {
+	root    *node[K, V]
 	compare func(K, K) int
 }
 
 // node is the type of a node in the binary tree.
-type node(type K, V) struct {
+type node[K, V any] struct {
 	key         K
 	val         V
-	left, right *node(K, V)
+	left, right *node[K, V]
 }
 
 // New returns a new map.
-func New(type K, V)(compare func(K, K) int) *Map(K, V) {
-        return &Map(K, V){compare: compare}
+func New[K, V any](compare func(K, K) int) *Map[K, V] {
+        return &Map[K, V]{compare: compare}
 }
 
 // find looks up key in the map, and returns either a pointer
 // to the node holding key, or a pointer to the location where
 // such a node would go.
-func (m *Map(K, V)) find(key K) **node(K, V) {
+func (m *Map[K, V]) find(key K) **node[K, V] {
 	pn := &m.root
 	for *pn != nil {
 		switch cmp := m.compare(key, (*pn).key); {
@@ -42,19 +42,19 @@
 // Insert inserts a new key/value into the map.
 // If the key is already present, the value is replaced.
 // Returns true if this is a new key, false if already present.
-func (m *Map(K, V)) Insert(key K, val V) bool {
+func (m *Map[K, V]) Insert(key K, val V) bool {
 	pn := m.find(key)
 	if *pn != nil {
 		(*pn).val = val
 		return false
 	}
-        *pn = &node(K, V){key: key, val: val}
+        *pn = &node[K, V]{key: key, val: val}
 	return true
 }
 
 // Find returns the value associated with a key, or zero if not present.
 // The found result reports whether the key was found.
-func (m *Map(K, V)) Find(key K) (V, bool) {
+func (m *Map[K, V]) Find(key K) (V, bool) {
 	pn := m.find(key)
 	if *pn == nil {
 		var zero V // see the discussion of zero values, above
@@ -64,16 +64,16 @@
 }
 
 // keyValue is a pair of key and value used when iterating.
-type keyValue(type K, V) struct {
+type keyValue[K, V any] struct {
 	key K
 	val V
 }
 
 // InOrder returns an iterator that does an in-order traversal of the map.
-func (m *Map(K, V)) InOrder() *Iterator(K, V) {
-	sender, receiver := chans.Ranger(keyValue(K, V))()
-	var f func(*node(K, V)) bool
-	f = func(n *node(K, V)) bool {
+func (m *Map[K, V]) InOrder() *Iterator[K, V] {
+	sender, receiver := chans.Ranger[keyValue[K, V]]()
+	var f func(*node[K, V]) bool
+	f = func(n *node[K, V]) bool {
 		if n == nil {
 			return true
 		}
@@ -81,7 +81,7 @@
 		// meaning that nothing is listening at the receiver end.
 		return f(n.left) &&
                         // TODO
-			// sender.Send(keyValue(K, V){n.key, n.val}) &&
+			// sender.Send(keyValue[K, V]{n.key, n.val}) &&
 			f(n.right)
 	}
 	go func() {
@@ -92,13 +92,13 @@
 }
 
 // Iterator is used to iterate over the map.
-type Iterator(type K, V) struct {
-	r *chans.Receiver(keyValue(K, V))
+type Iterator[K, V any] struct {
+	r *chans.Receiver[keyValue[K, V]]
 }
 
 // Next returns the next key and value pair, and a boolean indicating
 // whether they are valid or whether we have reached the end.
-func (it *Iterator(K, V)) Next() (K, V, bool) {
+func (it *Iterator[K, V]) Next() (K, V, bool) {
 	keyval, ok := it.r.Next()
 	if !ok {
 		var zerok K
diff --git a/src/go/parser/testdata/mapB.go2 b/src/go/parser/testdata/mapB.go2
deleted file mode 100644
index 0be5b28..0000000
--- a/src/go/parser/testdata/mapB.go2
+++ /dev/null
@@ -1,109 +0,0 @@
-// Package orderedmap provides an ordered map, implemented as a binary tree.
-package orderedmap
-
-import "chans"
-
-// Map is an ordered map.
-type Map[type K, V] struct {
-	root    *node[K, V]
-	compare func(K, K) int
-}
-
-// node is the type of a node in the binary tree.
-type node[type K, V] struct {
-	key         K
-	val         V
-	left, right *node[K, V]
-}
-
-// New returns a new map.
-func New[type K, V](compare func(K, K) int) *Map[K, V] {
-        return &Map[K, V]{compare: compare}
-}
-
-// find looks up key in the map, and returns either a pointer
-// to the node holding key, or a pointer to the location where
-// such a node would go.
-func (m *Map[K, V]) find(key K) **node[K, V] {
-	pn := &m.root
-	for *pn != nil {
-		switch cmp := m.compare(key, (*pn).key); {
-		case cmp < 0:
-			pn = &(*pn).left
-		case cmp > 0:
-			pn = &(*pn).right
-		default:
-			return pn
-		}
-	}
-	return pn
-}
-
-// Insert inserts a new key/value into the map.
-// If the key is already present, the value is replaced.
-// Returns true if this is a new key, false if already present.
-func (m *Map[K, V]) Insert(key K, val V) bool {
-	pn := m.find(key)
-	if *pn != nil {
-		(*pn).val = val
-		return false
-	}
-        *pn = &node[K, V]{key: key, val: val}
-	return true
-}
-
-// Find returns the value associated with a key, or zero if not present.
-// The found result reports whether the key was found.
-func (m *Map[K, V]) Find(key K) (V, bool) {
-	pn := m.find(key)
-	if *pn == nil {
-		var zero V // see the discussion of zero values, above
-		return zero, false
-	}
-	return (*pn).val, true
-}
-
-// keyValue is a pair of key and value used when iterating.
-type keyValue[type K, V] struct {
-	key K
-	val V
-}
-
-// InOrder returns an iterator that does an in-order traversal of the map.
-func (m *Map[K, V]) InOrder() *Iterator[K, V] {
-	sender, receiver := chans.Ranger(keyValue[K, V])()
-	var f func(*node[K, V]) bool
-	f = func(n *node[K, V]) bool {
-		if n == nil {
-			return true
-		}
-		// Stop sending values if sender.Send returns false,
-		// meaning that nothing is listening at the receiver end.
-		return f(n.left) &&
-                        // TODO
-			// sender.Send(keyValue[K, V]{n.key, n.val}) &&
-			f(n.right)
-	}
-	go func() {
-		f(m.root)
-		sender.Close()
-	}()
-	return &Iterator{receiver}
-}
-
-// Iterator is used to iterate over the map.
-type Iterator[type K, V] struct {
-	r *chans.Receiver[keyValue[K, V]]
-}
-
-// Next returns the next key and value pair, and a boolean indicating
-// whether they are valid or whether we have reached the end.
-func (it *Iterator[K, V]) Next() (K, V, bool) {
-	keyval, ok := it.r.Next()
-	if !ok {
-		var zerok K
-		var zerov V
-		return zerok, zerov, false
-	}
-	return keyval.key, keyval.val, true
-}
diff --git a/src/go/parser/testdata/metrics.go2 b/src/go/parser/testdata/metrics.go2
index bd43747..ef1c66b 100644
--- a/src/go/parser/testdata/metrics.go2
+++ b/src/go/parser/testdata/metrics.go2
@@ -2,12 +2,12 @@
 
 import "sync"
 
-type Metric1(type T comparable) struct {
+type Metric1[T comparable] struct {
 	mu sync.Mutex
 	m  map[T]int
 }
 
-func (m *Metric1(T)) Add(v T) {
+func (m *Metric1[T]) Add(v T) {
 	m.mu.Lock()
 	defer m.mu.Unlock()
 	if m.m == nil {
@@ -16,43 +16,43 @@
 	m[v]++
 }
 
-type key2(type T1, T2 comparable) struct {
+type key2[T1, T2 comparable] struct {
 	f1 T1
 	f2 T2
 }
 
-type Metric2(type T1, T2 cmp2) struct {
+type Metric2[T1, T2 cmp2] struct {
 	mu sync.Mutex
-	m  map[key2(T1, T2)]int
+	m  map[key2[T1, T2]]int
 }
 
-func (m *Metric2(T1, T2)) Add(v1 T1, v2 T2) {
+func (m *Metric2[T1, T2]) Add(v1 T1, v2 T2) {
 	m.mu.Lock()
 	defer m.mu.Unlock()
 	if m.m == nil {
-		m.m = make(map[key2(T1, T2)]int)
+		m.m = make(map[key2[T1, T2]]int)
 	}
-	m[key(T1, T2){v1, v2}]++
+	m[key[T1, T2]{v1, v2}]++
 }
 
-type key3(type T1, T2, T3 comparable) struct {
+type key3[T1, T2, T3 comparable] struct {
 	f1 T1
 	f2 T2
 	f3 T3
 }
 
-type Metric3(type T1, T2, T3 comparable) struct {
+type Metric3[T1, T2, T3 comparable] struct {
 	mu sync.Mutex
-	m  map[key3(T1, T2, T3)]int
+	m  map[key3[T1, T2, T3]]int
 }
 
-func (m *Metric3(T1, T2, T3)) Add(v1 T1, v2 T2, v3 T3) {
+func (m *Metric3[T1, T2, T3]) Add(v1 T1, v2 T2, v3 T3) {
 	m.mu.Lock()
 	defer m.mu.Unlock()
 	if m.m == nil {
 		m.m = make(map[key3]int)
 	}
-	m[key(T1, T2, T3){v1, v2, v3}]++
+	m[key[T1, T2, T3]{v1, v2, v3}]++
 }
 
 // Repeat for the maximum number of permitted arguments.
diff --git a/src/go/parser/testdata/metricsB.go2 b/src/go/parser/testdata/metricsB.go2
deleted file mode 100644
index 1ca0ab5..0000000
--- a/src/go/parser/testdata/metricsB.go2
+++ /dev/null
@@ -1,58 +0,0 @@
-package metrics
-
-import "sync"
-
-type Metric1[type T comparable] struct {
-	mu sync.Mutex
-	m  map[T]int
-}
-
-func (m *Metric1[T]) Add(v T) {
-	m.mu.Lock()
-	defer m.mu.Unlock()
-	if m.m == nil {
-		m.m = make(map[T]int)
-	}
-	m[v]++
-}
-
-type key2[type T1, T2 comparable] struct {
-	f1 T1
-	f2 T2
-}
-
-type Metric2[type T1, T2 cmp2] struct {
-	mu sync.Mutex
-	m  map[key2[T1, T2]]int
-}
-
-func (m *Metric2[T1, T2]) Add(v1 T1, v2 T2) {
-	m.mu.Lock()
-	defer m.mu.Unlock()
-	if m.m == nil {
-		m.m = make(map[key2[T1, T2]]int)
-	}
-	m[key[T1, T2]{v1, v2}]++
-}
-
-type key3[type T1, T2, T3 comparable] struct {
-	f1 T1
-	f2 T2
-	f3 T3
-}
-
-type Metric3[type T1, T2, T3 comparable] struct {
-	mu sync.Mutex
-	m  map[key3[T1, T2, T3]]int
-}
-
-func (m *Metric3[T1, T2, T3]) Add(v1 T1, v2 T2, v3 T3) {
-	m.mu.Lock()
-	defer m.mu.Unlock()
-	if m.m == nil {
-		m.m = make(map[key3]int)
-	}
-	m[key[T1, T2, T3]{v1, v2, v3}]++
-}
-
-// Repeat for the maximum number of permitted arguments.
diff --git a/src/go/parser/testdata/set.go2 b/src/go/parser/testdata/set.go2
index bc18550..0da6377 100644
--- a/src/go/parser/testdata/set.go2
+++ b/src/go/parser/testdata/set.go2
@@ -1,30 +1,30 @@
 // Package set implements sets of any type.
 package set
 
-type Set(type Elem comparable) map[Elem]struct{}
+type Set[Elem comparable] map[Elem]struct{}
 
-func Make(type Elem comparable)() Set(Elem) {
+func Make[Elem comparable]() Set[Elem] {
 	return make(Set(Elem))
 }
 
-func (s Set(Elem)) Add(v Elem) {
+func (s Set[Elem]) Add(v Elem) {
 	s[v] = struct{}{}
 }
 
-func (s Set(Elem)) Delete(v Elem) {
+func (s Set[Elem]) Delete(v Elem) {
 	delete(s, v)
 }
 
-func (s Set(Elem)) Contains(v Elem) bool {
+func (s Set[Elem]) Contains(v Elem) bool {
 	_, ok := s[v]
 	return ok
 }
 
-func (s Set(Elem)) Len() int {
+func (s Set[Elem]) Len() int {
 	return len(s)
 }
 
-func (s Set(Elem)) Iterate(f func(Elem)) {
+func (s Set[Elem]) Iterate(f func(Elem)) {
 	for v := range s {
 		f(v)
 	}
diff --git a/src/go/parser/testdata/setB.go2 b/src/go/parser/testdata/setB.go2
deleted file mode 100644
index 7a0c56d..0000000
--- a/src/go/parser/testdata/setB.go2
+++ /dev/null
@@ -1,31 +0,0 @@
-// Package set implements sets of any type.
-package set
-
-type Set[type Elem comparable] map[Elem]struct{}
-
-func Make[type Elem comparable]() Set[Elem] {
-	return make(Set[Elem])
-}
-
-func (s Set[Elem]) Add(v Elem) {
-	s[v] = struct{}{}
-}
-
-func (s Set[Elem]) Delete(v Elem) {
-	delete(s, v)
-}
-
-func (s Set[Elem]) Contains(v Elem) bool {
-	_, ok := s[v]
-	return ok
-}
-
-func (s Set[Elem]) Len() int {
-	return len(s)
-}
-
-func (s Set[Elem]) Iterate(f func(Elem)) {
-	for v := range s {
-		f(v)
-	}
-}
diff --git a/src/go/parser/testdata/slices.go2 b/src/go/parser/testdata/slices.go2
index fe90f7c..e060212 100644
--- a/src/go/parser/testdata/slices.go2
+++ b/src/go/parser/testdata/slices.go2
@@ -2,7 +2,7 @@
 package slices
 
 // Map turns a []T1 to a []T2 using a mapping function.
-func Map(type T1, T2)(s []T1, f func(T1) T2) []T2 {
+func Map[T1, T2 any](s []T1, f func(T1) T2) []T2 {
 	r := make([]T2, len(s))
 	for i, v := range s {
 		r[i] = f(v)
@@ -11,7 +11,7 @@
 }
 
 // Reduce reduces a []T1 to a single value using a reduction function.
-func Reduce(type T1, T2)(s []T1, initializer T2, f func(T2, T1) T2) T2 {
+func Reduce[T1, T2 any](s []T1, initializer T2, f func(T2, T1) T2) T2 {
 	r := initializer
 	for _, v := range s {
 		r = f(r, v)
@@ -20,7 +20,7 @@
 }
 
 // Filter filters values from a slice using a filter function.
-func Filter(type T)(s []T, f func(T) bool) []T {
+func Filter[T any](s []T, f func(T) bool) []T {
 	var r []T
 	for _, v := range s {
 		if f(v) {
diff --git a/src/go/parser/testdata/slicesB.go2 b/src/go/parser/testdata/slicesB.go2
deleted file mode 100644
index 5e83f6e..0000000
--- a/src/go/parser/testdata/slicesB.go2
+++ /dev/null
@@ -1,31 +0,0 @@
-// Package slices implements various slice algorithms.
-package slices
-
-// Map turns a []T1 to a []T2 using a mapping function.
-func Map[type T1, T2](s []T1, f func(T1) T2) []T2 {
-	r := make([]T2, len(s))
-	for i, v := range s {
-		r[i] = f(v)
-	}
-	return r
-}
-
-// Reduce reduces a []T1 to a single value using a reduction function.
-func Reduce[type T1, T2](s []T1, initializer T2, f func(T2, T1) T2) T2 {
-	r := initializer
-	for _, v := range s {
-		r = f(r, v)
-	}
-	return r
-}
-
-// Filter filters values from a slice using a filter function.
-func Filter[type T](s []T, f func(T) bool) []T {
-	var r []T
-	for _, v := range s {
-		if f(v) {
-			r = append(r, v)
-		}
-	}
-	return r
-}
diff --git a/src/go/parser/testdata/sort.go2 b/src/go/parser/testdata/sort.go2
index 241b8fb..88be79f 100644
--- a/src/go/parser/testdata/sort.go2
+++ b/src/go/parser/testdata/sort.go2
@@ -1,27 +1,27 @@
 package sort
 
-type orderedSlice(type Elem comparable) []Elem
+type orderedSlice[Elem comparable] []Elem
 
-func (s orderedSlice(Elem)) Len() int           { return len(s) }
-func (s orderedSlice(Elem)) Less(i, j int) bool { return s[i] < s[j] }
-func (s orderedSlice(Elem)) Swap(i, j int)      { s[i], s[j] = s[j], s[i] }
+func (s orderedSlice[Elem]) Len() int           { return len(s) }
+func (s orderedSlice[Elem]) Less(i, j int) bool { return s[i] < s[j] }
+func (s orderedSlice[Elem]) Swap(i, j int)      { s[i], s[j] = s[j], s[i] }
 
 // OrderedSlice sorts the slice s in ascending order.
 // The elements of s must be ordered using the < operator.
-func OrderedSlice(type Elem comparable)(s []Elem) {
-	sort.Sort(orderedSlice(Elem)(s))
+func OrderedSlice[Elem comparable](s []Elem) {
+	sort.Sort(orderedSlice[Elem](s))
 }
 
-type sliceFn(type Elem) struct {
+type sliceFn[Elem any] struct {
 	s []Elem
 	f func(Elem, Elem) bool
 }
 
-func (s sliceFn(Elem)) Len() int           { return len(s.s) }
-func (s sliceFn(Elem)) Less(i, j int) bool { return s.f(s.s[i], s.s[j]) }
-func (s sliceFn(Elem)) Swap(i, j int)      { s.s[i], s.s[j] = s.s[j], s.s[i] }
+func (s sliceFn[Elem]) Len() int           { return len(s.s) }
+func (s sliceFn[Elem]) Less(i, j int) bool { return s.f(s.s[i], s.s[j]) }
+func (s sliceFn[Elem]) Swap(i, j int)      { s.s[i], s.s[j] = s.s[j], s.s[i] }
 
 // SliceFn sorts the slice s according to the function f.
-func SliceFn(type Elem)(s []Elem, f func(Elem, Elem) bool) {
-	Sort(sliceFn(Elem){s, f})
+func SliceFn[Elem any](s []Elem, f func(Elem, Elem) bool) {
+	Sort(sliceFn[Elem]{s, f})
 }
diff --git a/src/go/parser/testdata/sortB.go2 b/src/go/parser/testdata/sortB.go2
deleted file mode 100644
index 39363ae..0000000
--- a/src/go/parser/testdata/sortB.go2
+++ /dev/null
@@ -1,27 +0,0 @@
-package sort
-
-type orderedSlice[type Elem comparable] []Elem
-
-func (s orderedSlice[Elem]) Len() int           { return len(s) }
-func (s orderedSlice[Elem]) Less(i, j int) bool { return s[i] < s[j] }
-func (s orderedSlice[Elem]) Swap(i, j int)      { s[i], s[j] = s[j], s[i] }
-
-// OrderedSlice sorts the slice s in ascending order.
-// The elements of s must be ordered using the < operator.
-func OrderedSlice[type Elem comparable](s []Elem) {
-	sort.Sort(orderedSlice[Elem](s))
-}
-
-type sliceFn[type Elem] struct {
-	s []Elem
-	f func(Elem, Elem) bool
-}
-
-func (s sliceFn[Elem]) Len() int           { return len(s.s) }
-func (s sliceFn[Elem]) Less(i, j int) bool { return s.f(s.s[i], s.s[j]) }
-func (s sliceFn[Elem]) Swap(i, j int)      { s.s[i], s.s[j] = s.s[j], s.s[i] }
-
-// SliceFn sorts the slice s according to the function f.
-func SliceFn[type Elem](s []Elem, f func(Elem, Elem) bool) {
-	Sort(sliceFn[Elem]{s, f})
-}
diff --git a/src/go/parser/testdata/typeparams.src b/src/go/parser/testdata/typeparams.src
new file mode 100644
index 0000000..1fea23f
--- /dev/null
+++ b/src/go/parser/testdata/typeparams.src
@@ -0,0 +1,17 @@
+// 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.
+
+// Test cases for error messages produced while parsing code that uses type
+// parameters, without ParseTypeParams being enabled.
+
+package p
+
+type List[E any /* ERROR "expected ']', found any" */ ] []E
+
+type Pair[L, /* ERROR "expected ']', found ','" */ R any] struct {
+	Left L
+	Right R
+}
+
+var _ = Pair[int, /* ERROR "expected ']' or ':', found ','" */ string]{}
diff --git a/src/go/printer/nodes.go b/src/go/printer/nodes.go
index fbf3d14..cc79553 100644
--- a/src/go/printer/nodes.go
+++ b/src/go/printer/nodes.go
@@ -319,15 +319,12 @@
 	}
 }
 
-func (p *printer) parameters(isTypeParam bool, fields *ast.FieldList) {
+func (p *printer) parameters(fields *ast.FieldList, isTypeParam bool) {
 	openTok, closeTok := token.LPAREN, token.RPAREN
-	if isTypeParam && p.Mode&UseBrackets != 0 {
+	if isTypeParam {
 		openTok, closeTok = token.LBRACK, token.RBRACK
 	}
 	p.print(fields.Opening, openTok)
-	if isTypeParam && p.Mode&UseBrackets == 0 {
-		p.print(token.TYPE)
-	}
 	if len(fields.List) > 0 {
 		prevLine := p.lineFor(fields.Opening)
 		ws := indent
@@ -352,7 +349,7 @@
 			if needsLinebreak && p.linebreak(parLineBeg, 0, ws, true) > 0 {
 				// break line if the opening "(" or previous parameter ended on a different line
 				ws = ignore
-			} else if isTypeParam && len(par.Names) > 0 && p.Mode&UseBrackets == 0 || i > 0 {
+			} else if i > 0 {
 				p.print(blank)
 			}
 			// parameter names
@@ -364,25 +361,10 @@
 				// by a linebreak call after a type, or in the next multi-line identList
 				// will do the right thing.
 				p.identList(par.Names, ws == indent)
-				if par.Type != nil {
-					p.print(blank)
-				}
+				p.print(blank)
 			}
 			// parameter type
-			if par.Type != nil {
-				typ := stripParensAlways(par.Type)
-				// If we don't have a parameter name and the parameter type is an
-				// instantiated type using parentheses, then we need to parenthesize
-				// the type otherwise it is interpreted as a parameter name followed
-				// by a parenthesized type name.
-				if call, _ := typ.(*ast.CallExpr); call != nil && !call.Brackets && len(par.Names) == 0 {
-					p.print(token.LPAREN)
-					p.expr(typ)
-					p.print(token.RPAREN)
-				} else {
-					p.expr(typ)
-				}
-			}
+			p.expr(stripParensAlways(par.Type))
 			prevLine = parLineEnd
 		}
 		// if the closing ")" is on a separate line from the last parameter,
@@ -401,10 +383,10 @@
 
 func (p *printer) signature(sig *ast.FuncType) {
 	if sig.TParams != nil {
-		p.parameters(true, sig.TParams)
+		p.parameters(sig.TParams, true)
 	}
 	if sig.Params != nil {
-		p.parameters(false, sig.Params)
+		p.parameters(sig.Params, false)
 	} else {
 		p.print(token.LPAREN, token.RPAREN)
 	}
@@ -418,7 +400,7 @@
 			p.expr(stripParensAlways(res.List[0].Type))
 			return
 		}
-		p.parameters(false, res)
+		p.parameters(res, false)
 	}
 }
 
@@ -848,8 +830,8 @@
 		}
 
 	case *ast.BasicLit:
-		if p.Config.Mode&StdFormat != 0 {
-			x = normalizeNumbers(x)
+		if p.Config.Mode&normalizeNumbers != 0 {
+			x = normalizedNumber(x)
 		}
 		p.print(x)
 
@@ -1038,11 +1020,15 @@
 	}
 }
 
-// normalizeNumbers rewrites base prefixes and exponents to
-// use lower-case letters, and removes leading 0's from
-// integer imaginary literals. It leaves hexadecimal digits
-// alone.
-func normalizeNumbers(lit *ast.BasicLit) *ast.BasicLit {
+// normalizedNumber rewrites base prefixes and exponents
+// of numbers to use lower-case letters (0X123 to 0x123 and 1.2E3 to 1.2e3),
+// and removes leading 0's from integer imaginary literals (0765i to 765i).
+// It leaves hexadecimal digits alone.
+//
+// normalizedNumber doesn't modify the ast.BasicLit value lit points to.
+// If lit is not a number or a number in canonical format already,
+// lit is returned as is. Otherwise a new ast.BasicLit is created.
+func normalizedNumber(lit *ast.BasicLit) *ast.BasicLit {
 	if lit.Kind != token.INT && lit.Kind != token.FLOAT && lit.Kind != token.IMAG {
 		return lit // not a number - nothing to do
 	}
@@ -1646,7 +1632,7 @@
 		p.setComment(s.Doc)
 		p.expr(s.Name)
 		if s.TParams != nil {
-			p.parameters(true, s.TParams)
+			p.parameters(s.TParams, true)
 		}
 		if n == 1 {
 			p.print(blank)
@@ -1836,7 +1822,7 @@
 	// FUNC is emitted).
 	startCol := p.out.Column - len("func ")
 	if d.Recv != nil {
-		p.parameters(false, d.Recv) // method: print receiver
+		p.parameters(d.Recv, false) // method: print receiver
 		p.print(blank)
 	}
 	p.expr(d.Name)
diff --git a/src/go/printer/performance_test.go b/src/go/printer/performance_test.go
index 3f34bfc..2e67154 100644
--- a/src/go/printer/performance_test.go
+++ b/src/go/printer/performance_test.go
@@ -20,7 +20,7 @@
 var testfile *ast.File
 
 func testprint(out io.Writer, file *ast.File) {
-	if err := (&Config{TabIndent | UseSpaces | StdFormat, 8, 0}).Fprint(out, fset, file); err != nil {
+	if err := (&Config{TabIndent | UseSpaces | normalizeNumbers, 8, 0}).Fprint(out, fset, file); err != nil {
 		log.Fatalf("print error: %s", err)
 	}
 }
diff --git a/src/go/printer/printer.go b/src/go/printer/printer.go
index b3eba6c..0077afe 100644
--- a/src/go/printer/printer.go
+++ b/src/go/printer/printer.go
@@ -1272,12 +1272,26 @@
 type Mode uint
 
 const (
-	RawFormat   Mode = 1 << iota // do not use a tabwriter; if set, UseSpaces is ignored
-	TabIndent                    // use tabs for indentation independent of UseSpaces
-	UseSpaces                    // use spaces instead of tabs for alignment
-	SourcePos                    // emit //line directives to preserve original source positions
-	StdFormat                    // apply standard formatting changes (exact byte output may change between versions of Go)
-	UseBrackets                  // use square brackets instead of parentheses for type parameters (implies unified parameter syntax)
+	RawFormat Mode = 1 << iota // do not use a tabwriter; if set, UseSpaces is ignored
+	TabIndent                  // use tabs for indentation independent of UseSpaces
+	UseSpaces                  // use spaces instead of tabs for alignment
+	SourcePos                  // emit //line directives to preserve original source positions
+)
+
+// The mode below is not included in printer's public API because
+// editing code text is deemed out of scope. Because this mode is
+// unexported, it's also possible to modify or remove it based on
+// the evolving needs of go/format and cmd/gofmt without breaking
+// users. See discussion in CL 240683.
+const (
+	// normalizeNumbers means to canonicalize number
+	// literal prefixes and exponents while printing.
+	//
+	// This value is known in and used by go/format and cmd/gofmt.
+	// It is currently more convenient and performant for those
+	// packages to apply number normalization during printing,
+	// rather than by modifying the AST in advance.
+	normalizeNumbers Mode = 1 << 30
 )
 
 // A Config node controls the output of Fprint.
@@ -1350,13 +1364,6 @@
 // or assignment-compatible to ast.Expr, ast.Decl, ast.Spec, or ast.Stmt.
 //
 func (cfg *Config) Fprint(output io.Writer, fset *token.FileSet, node interface{}) error {
-	// Ensure that our formatting of type parameters is consistent with the file.
-	if file, _ := node.(*ast.File); file != nil && file.UseBrackets && cfg.Mode&UseBrackets == 0 {
-		// Copy to avoid data races.
-		cfg2 := *cfg
-		cfg2.Mode |= UseBrackets
-		cfg = &cfg2
-	}
 	return cfg.fprint(output, fset, node, make(map[ast.Node]int))
 }
 
diff --git a/src/go/printer/printer_test.go b/src/go/printer/printer_test.go
index bc8c43e..3efa468 100644
--- a/src/go/printer/printer_test.go
+++ b/src/go/printer/printer_test.go
@@ -33,7 +33,7 @@
 const (
 	export checkMode = 1 << iota
 	rawFormat
-	stdFormat
+	normNumber
 	idempotent
 )
 
@@ -42,7 +42,7 @@
 // if any.
 func format(src []byte, mode checkMode) ([]byte, error) {
 	// parse src
-	f, err := parser.ParseFile(fset, "", src, parser.ParseComments)
+	f, err := parser.ParseFile(fset, "", src, parser.ParseComments|parser.ParseTypeParams)
 	if err != nil {
 		return nil, fmt.Errorf("parse: %s\n%s", err, src)
 	}
@@ -58,8 +58,8 @@
 	if mode&rawFormat != 0 {
 		cfg.Mode |= RawFormat
 	}
-	if mode&stdFormat != 0 {
-		cfg.Mode |= StdFormat
+	if mode&normNumber != 0 {
+		cfg.Mode |= normalizeNumbers
 	}
 
 	// print AST
@@ -70,7 +70,7 @@
 
 	// make sure formatted output is syntactically correct
 	res := buf.Bytes()
-	if _, err := parser.ParseFile(fset, "", res, 0); err != nil {
+	if _, err := parser.ParseFile(fset, "", res, parser.ParseTypeParams); err != nil {
 		return nil, fmt.Errorf("re-parse: %s\n%s", err, buf.Bytes())
 	}
 
@@ -205,9 +205,8 @@
 	{"slow.input", "slow.golden", idempotent},
 	{"complit.input", "complit.x", export},
 	{"go2numbers.input", "go2numbers.golden", idempotent},
-	{"go2numbers.input", "go2numbers.stdfmt", stdFormat | idempotent},
+	{"go2numbers.input", "go2numbers.norm", normNumber | idempotent},
 	{"generics.input", "generics.golden", idempotent},
-	{"genericsB.input", "genericsB.golden", idempotent},
 }
 
 func TestFiles(t *testing.T) {
diff --git a/src/go/printer/testdata/declarations.golden b/src/go/printer/testdata/declarations.golden
index 058baa8..74ffce7 100644
--- a/src/go/printer/testdata/declarations.golden
+++ b/src/go/printer/testdata/declarations.golden
@@ -942,6 +942,13 @@
 		x ...int)
 }
 
+// properly format one-line type lists
+type _ interface{ type a }
+
+type _ interface {
+	type a, b, c
+}
+
 // omit superfluous parentheses in parameter lists
 func _(int)
 func _(int)
@@ -993,9 +1000,8 @@
 })	// no extra comma between } and )
 
 // type parameters
-func _(type)()
-func _(type A, B)(a A, b B) int	{}
-func _(type T)(x, y T) T
+func _[A, B any](a A, b B) int	{}
+func _[T any](x, y T) T
 
 // alias declarations
 
diff --git a/src/go/printer/testdata/declarations.input b/src/go/printer/testdata/declarations.input
index 8787f49..ab20221 100644
--- a/src/go/printer/testdata/declarations.input
+++ b/src/go/printer/testdata/declarations.input
@@ -955,6 +955,11 @@
 		x ...int)
 }
 
+// properly format one-line type lists
+type _ interface { type a }
+
+type _ interface { type a,b,c }
+
 // omit superfluous parentheses in parameter lists
 func _((int))
 func _((((((int))))))
@@ -1006,9 +1011,8 @@
 }) // no extra comma between } and )
 
 // type parameters
-func _(type)()
-func _(type A, B)(a A, b B) int {}
-func _(type T)(x, y T) T
+func _[A, B any](a A, b B) int {}
+func _[T any](x, y T) T
 
 // alias declarations
 
@@ -1023,4 +1027,4 @@
 	c = foo
 	d = interface{}
 	ddd = p.Foo
-)
\ No newline at end of file
+)
diff --git a/src/go/printer/testdata/generics.golden b/src/go/printer/testdata/generics.golden
index 751ba68..88c4616 100644
--- a/src/go/printer/testdata/generics.golden
+++ b/src/go/printer/testdata/generics.golden
@@ -4,33 +4,30 @@
 
 package generics
 
-type T(type) struct{}
-type T(type P) struct{}
-type T(type P1, P2, P3) struct{}
+type T[P any] struct{}
+type T[P1, P2, P3 any] struct{}
 
-type T(type P C) struct{}
-type T(type P1, P2, P3, C) struct{}
+type T[P C] struct{}
+type T[P1, P2, P3 C] struct{}
 
-type T(type P C(P)) struct{}
-type T(type P1, P2, P3 C(P1, P2, P3)) struct{}
+type T[P C[P]] struct{}
+type T[P1, P2, P3 C[P1, P2, P3]] struct{}
 
-func f(type)()
-func f(type P)(x P)
-func f(type P1, P2, P3)(x1 P1, x2 P2, x3 P3) struct{}
+func f[P any](x P)
+func f[P1, P2, P3 any](x1 P1, x2 P2, x3 P3) struct{}
 
-func f(type)()
-func f(type P interface{})(x P)
-func f(type P1, P2, P3 interface {
+func f[P interface{}](x P)
+func f[P1, P2, P3 interface {
 	m1(P1)
 	type P2, P3
-})(x1 P1, x2 P2, x3 P3) struct{}
-func f(type P)((T1(P)), (T2(P))) T3(P)
+}](x1 P1, x2 P2, x3 P3) struct{}
+func f[P any](T1[P], T2[P]) T3[P]
 
-func (x T(P)) m()
-func ((T(P))) m(x T(P)) P
+func (x T[P]) m()
+func (T[P]) m(x T[P]) P
 
 func _() {
-	type _ [](T(P))
-	var _ []T(P)
-	_ = [](T(P)){}
+	type _ []T[P]
+	var _ []T[P]
+	_ = []T[P]{}
 }
diff --git a/src/go/printer/testdata/generics.input b/src/go/printer/testdata/generics.input
index 9fe5cec..5fdf8cd 100644
--- a/src/go/printer/testdata/generics.input
+++ b/src/go/printer/testdata/generics.input
@@ -4,30 +4,27 @@
 
 package generics
 
-type T(type) struct{}
-type T(type P) struct{}
-type T(type P1, P2, P3) struct{}
+type T[P any] struct{}
+type T[P1, P2, P3 any] struct{}
 
-type T(type P C) struct{}
-type T(type P1, P2, P3, C) struct{}
+type T[P C] struct{}
+type T[P1, P2, P3 C] struct{}
 
-type T(type P C(P)) struct{}
-type T(type P1, P2, P3 C(P1, P2, P3)) struct{}
+type T[P C[P]] struct{}
+type T[P1, P2, P3 C[P1, P2, P3]] struct{}
 
-func f(type)()
-func f(type P)(x P)
-func f(type P1, P2, P3)(x1 P1, x2 P2, x3 P3) struct{}
+func f[P any](x P)
+func f[P1, P2, P3 any](x1 P1, x2 P2, x3 P3) struct{}
 
-func f(type)()
-func f(type P interface{})(x P)
-func f(type P1, P2, P3 interface{ m1(P1); type P2, P3 })(x1 P1, x2 P2, x3 P3) struct{}
-func f(type P)((T1(P)), (T2(P))) T3(P)
+func f[P interface{}](x P)
+func f[P1, P2, P3 interface{ m1(P1); type P2, P3 }](x1 P1, x2 P2, x3 P3) struct{}
+func f[P any](T1[P], T2[P]) T3[P]
 
-func (x T(P)) m()
-func ((T(P))) m(x T(P)) P
+func (x T[P]) m()
+func ((T[P])) m(x T[P]) P
 
 func _() {
-	type _ [](T(P))
-	var _ []T(P)
-	_ = [](T(P)){}
+	type _ []T[P]
+	var _ []T[P]
+	_ = []T[P]{}
 }
diff --git a/src/go/printer/testdata/go2numbers.norm b/src/go/printer/testdata/go2numbers.norm
new file mode 100644
index 0000000..855f0fc
--- /dev/null
+++ b/src/go/printer/testdata/go2numbers.norm
@@ -0,0 +1,186 @@
+package p
+
+const (
+	// 0-octals
+	_	= 0
+	_	= 0123
+	_	= 0123456
+
+	_	= 0_123
+	_	= 0123_456
+
+	// decimals
+	_	= 1
+	_	= 1234
+	_	= 1234567
+
+	_	= 1_234
+	_	= 1_234_567
+
+	// hexadecimals
+	_	= 0x0
+	_	= 0x1234
+	_	= 0xcafef00d
+
+	_	= 0x0
+	_	= 0x1234
+	_	= 0xCAFEf00d
+
+	_	= 0x_0
+	_	= 0x_1234
+	_	= 0x_CAFE_f00d
+
+	// octals
+	_	= 0o0
+	_	= 0o1234
+	_	= 0o01234567
+
+	_	= 0o0
+	_	= 0o1234
+	_	= 0o01234567
+
+	_	= 0o_0
+	_	= 0o_1234
+	_	= 0o0123_4567
+
+	_	= 0o_0
+	_	= 0o_1234
+	_	= 0o0123_4567
+
+	// binaries
+	_	= 0b0
+	_	= 0b1011
+	_	= 0b00101101
+
+	_	= 0b0
+	_	= 0b1011
+	_	= 0b00101101
+
+	_	= 0b_0
+	_	= 0b10_11
+	_	= 0b_0010_1101
+
+	// decimal floats
+	_	= 0.
+	_	= 123.
+	_	= 0123.
+
+	_	= .0
+	_	= .123
+	_	= .0123
+
+	_	= 0e0
+	_	= 123e+0
+	_	= 0123e-1
+
+	_	= 0e-0
+	_	= 123e+0
+	_	= 0123e123
+
+	_	= 0.e+1
+	_	= 123.e-10
+	_	= 0123.e123
+
+	_	= .0e-1
+	_	= .123e+10
+	_	= .0123e123
+
+	_	= 0.0
+	_	= 123.123
+	_	= 0123.0123
+
+	_	= 0.0e1
+	_	= 123.123e-10
+	_	= 0123.0123e+456
+
+	_	= 1_2_3.
+	_	= 0_123.
+
+	_	= 0_0e0
+	_	= 1_2_3e0
+	_	= 0_123e0
+
+	_	= 0e-0_0
+	_	= 1_2_3e+0
+	_	= 0123e1_2_3
+
+	_	= 0.e+1
+	_	= 123.e-1_0
+	_	= 01_23.e123
+
+	_	= .0e-1
+	_	= .123e+10
+	_	= .0123e123
+
+	_	= 1_2_3.123
+	_	= 0123.01_23
+
+	// hexadecimal floats
+	_	= 0x0.p+0
+	_	= 0xdeadcafe.p-10
+	_	= 0x1234.p123
+
+	_	= 0x.1p-0
+	_	= 0x.deadcafep2
+	_	= 0x.1234p+10
+
+	_	= 0x0p0
+	_	= 0xdeadcafep+1
+	_	= 0x1234p-10
+
+	_	= 0x0.0p0
+	_	= 0xdead.cafep+1
+	_	= 0x12.34p-10
+
+	_	= 0xdead_cafep+1
+	_	= 0x_1234p-10
+
+	_	= 0x_dead_cafe.p-10
+	_	= 0x12_34.p1_2_3
+	_	= 0x1_2_3_4.p-1_2_3
+
+	// imaginaries
+	_	= 0i
+	_	= 0i
+	_	= 8i
+	_	= 0i
+	_	= 123i
+	_	= 123i
+	_	= 56789i
+	_	= 1234i
+	_	= 1234567i
+
+	_	= 0i
+	_	= 0i
+	_	= 8i
+	_	= 0i
+	_	= 123i
+	_	= 123i
+	_	= 56_789i
+	_	= 1_234i
+	_	= 1_234_567i
+
+	_	= 0.i
+	_	= 123.i
+	_	= 0123.i
+	_	= 000123.i
+
+	_	= 0e0i
+	_	= 123e0i
+	_	= 0123e0i
+	_	= 000123e0i
+
+	_	= 0.e+1i
+	_	= 123.e-1_0i
+	_	= 01_23.e123i
+	_	= 00_01_23.e123i
+
+	_	= 0b1010i
+	_	= 0b1010i
+	_	= 0o660i
+	_	= 0o660i
+	_	= 0xabcDEFi
+	_	= 0xabcDEFi
+	_	= 0xabcDEFp0i
+	_	= 0xabcDEFp0i
+)
diff --git a/src/go/token/position.go b/src/go/token/position.go
index 3f5a390..a21f5fd 100644
--- a/src/go/token/position.go
+++ b/src/go/token/position.go
@@ -58,8 +58,11 @@
 // larger, representation.
 //
 // The Pos value for a given file is a number in the range [base, base+size],
-// where base and size are specified when adding the file to the file set via
-// AddFile.
+// where base and size are specified when a file is added to the file set.
+// The difference between a Pos value and the corresponding file base
+// corresponds to the byte offset of that position (represented by the Pos value)
+// from the beginning of the file. Thus, the file base offset is the Pos value
+// representing the first byte in the file.
 //
 // To create the Pos value for a specific source offset (measured in bytes),
 // first add the respective file to the current file set using FileSet.AddFile
@@ -147,12 +150,12 @@
 //
 func (f *File) MergeLine(line int) {
 	if line < 1 {
-		panic("illegal line number (line numbering starts at 1)")
+		panic(fmt.Sprintf("invalid line number %d (should be >= 1)", line))
 	}
 	f.mutex.Lock()
 	defer f.mutex.Unlock()
 	if line >= len(f.lines) {
-		panic("illegal line number")
+		panic(fmt.Sprintf("invalid line number %d (should be < %d)", line, len(f.lines)))
 	}
 	// To merge the line numbered <line> with the line numbered <line+1>,
 	// we need to remove the entry in lines corresponding to the line
@@ -214,12 +217,12 @@
 // LineStart panics if the 1-based line number is invalid.
 func (f *File) LineStart(line int) Pos {
 	if line < 1 {
-		panic("illegal line number (line numbering starts at 1)")
+		panic(fmt.Sprintf("invalid line number %d (should be >= 1)", line))
 	}
 	f.mutex.Lock()
 	defer f.mutex.Unlock()
 	if line > len(f.lines) {
-		panic("illegal line number")
+		panic(fmt.Sprintf("invalid line number %d (should be < %d)", line, len(f.lines)))
 	}
 	return Pos(f.base + f.lines[line-1])
 }
@@ -264,7 +267,7 @@
 //
 func (f *File) Pos(offset int) Pos {
 	if offset > f.size {
-		panic("illegal file offset")
+		panic(fmt.Sprintf("invalid file offset %d (should be <= %d)", offset, f.size))
 	}
 	return Pos(f.base + offset)
 }
@@ -275,7 +278,7 @@
 //
 func (f *File) Offset(p Pos) int {
 	if int(p) < f.base || int(p) > f.base+f.size {
-		panic("illegal Pos value")
+		panic(fmt.Sprintf("invalid Pos value %d (should be in [%d, %d[)", p, f.base, f.base+f.size))
 	}
 	return int(p) - f.base
 }
@@ -343,7 +346,7 @@
 func (f *File) PositionFor(p Pos, adjusted bool) (pos Position) {
 	if p != NoPos {
 		if int(p) < f.base || int(p) > f.base+f.size {
-			panic("illegal Pos value")
+			panic(fmt.Sprintf("invalid Pos value %d (should be in [%d, %d[)", p, f.base, f.base+f.size))
 		}
 		pos = f.position(p, adjusted)
 	}
@@ -364,6 +367,22 @@
 // Methods of file sets are synchronized; multiple goroutines
 // may invoke them concurrently.
 //
+// The byte offsets for each file in a file set are mapped into
+// distinct (integer) intervals, one interval [base, base+size]
+// per file. Base represents the first byte in the file, and size
+// is the corresponding file size. A Pos value is a value in such
+// an interval. By determining the interval a Pos value belongs
+// to, the file, its file base, and thus the byte offset (position)
+// the Pos value is representing can be computed.
+//
+// When adding a new file, a file base must be provided. That can
+// be any integer value that is past the end of any interval of any
+// file already in the file set. For convenience, FileSet.Base provides
+// such a value, which is simply the end of the Pos interval of the most
+// recently added file, plus one. Unless there is a need to extend an
+// interval later, using the FileSet.Base should be used as argument
+// for FileSet.AddFile.
+//
 type FileSet struct {
 	mutex sync.RWMutex // protects the file set
 	base  int          // base offset for the next file
@@ -411,8 +430,11 @@
 	if base < 0 {
 		base = s.base
 	}
-	if base < s.base || size < 0 {
-		panic("illegal base or size")
+	if base < s.base {
+		panic(fmt.Sprintf("invalid base %d (should be >= %d)", base, s.base))
+	}
+	if size < 0 {
+		panic(fmt.Sprintf("invalid size %d (should be >= 0)", size))
 	}
 	// base >= s.base && size >= 0
 	f := &File{set: s, name: filename, base: base, size: size, lines: []int{0}}
diff --git a/src/go/types/api.go b/src/go/types/api.go
index 3b43047..ec12fcf 100644
--- a/src/go/types/api.go
+++ b/src/go/types/api.go
@@ -41,9 +41,17 @@
 type Error struct {
 	Fset *token.FileSet // file set for interpretation of Pos
 	Pos  token.Pos      // error position
-	Msg  string         // default error message, user-friendly
-	Full string         // full error message, for debugging (may contain internal details)
+	Msg  string         // error message
 	Soft bool           // if set, error is "soft"
+
+	// go116code is a future API, unexported as the set of error codes is large
+	// and likely to change significantly during experimentation. Tools wishing
+	// to preview this feature may read go116code using reflection (see
+	// errorcodes_test.go), but beware that there is no guarantee of future
+	// compatibility.
+	go116code  errorCode
+	go116start token.Pos
+	go116end   token.Pos
 }
 
 // Error returns an error string formatted as follows:
@@ -52,13 +60,6 @@
 	return fmt.Sprintf("%s: %s", err.Fset.Position(err.Pos), err.Msg)
 }
 
-// FullError returns an error string like Error, buy it may contain
-// type-checker internal details such as subscript indices for type
-// parameters and more. Useful for debugging.
-func (err Error) FullError() string {
-	return fmt.Sprintf("%s: %s", err.Fset.Position(err.Pos), err.Full)
-}
-
 // An Importer resolves import paths to Packages.
 //
 // CAUTION: This interface does not support the import of locally
@@ -104,13 +105,6 @@
 	// type-checked.
 	IgnoreFuncBodies bool
 
-	// If AcceptMethodTypeParams is set, methods may have type parameters.
-	AcceptMethodTypeParams bool
-
-	// If InferFromConstraints is set, constraint type inference is used
-	// if some function type arguments are missing.
-	InferFromConstraints bool
-
 	// If FakeImportC is set, `import "C"` (for packages requiring Cgo)
 	// declares an empty "C" package and errors are omitted for qualified
 	// identifiers referring to package C (which won't find an object).
@@ -129,9 +123,6 @@
 	// It is an error to set both FakeImportC and go115UsesCgo.
 	go115UsesCgo bool
 
-	// If Trace is set, a debug trace is printed to stdout.
-	Trace bool
-
 	// If Error != nil, it is called with each error found
 	// during type checking; err has dynamic type Error.
 	// Secondary errors (for instance, to enumerate all types
@@ -394,14 +385,15 @@
 
 // AssertableTo reports whether a value of type V can be asserted to have type T.
 func AssertableTo(V *Interface, T Type) bool {
-	m, _ := (*Checker)(nil).assertableTo(V, T, false)
+	m, _ := (*Checker)(nil).assertableTo(V, T)
 	return m == nil
 }
 
 // AssignableTo reports whether a value of type V is assignable to a variable of type T.
 func AssignableTo(V, T Type) bool {
 	x := operand{mode: value, typ: V}
-	return x.assignableTo(nil, T, nil) // check not needed for non-constant x
+	ok, _ := x.assignableTo(nil, T, nil) // check not needed for non-constant x
+	return ok
 }
 
 // ConvertibleTo reports whether a value of type V is convertible to a value of type T.
diff --git a/src/go/types/api_test.go b/src/go/types/api_test.go
index 3344939..014cd52 100644
--- a/src/go/types/api_test.go
+++ b/src/go/types/api_test.go
@@ -22,7 +22,8 @@
 
 func pkgFor(path, source string, info *Info) (*Package, error) {
 	fset := token.NewFileSet()
-	f, err := parser.ParseFile(fset, path, source, 0)
+	mode := modeForSource(source)
+	f, err := parser.ParseFile(fset, path, source, mode)
 	if err != nil {
 		return nil, err
 	}
@@ -42,17 +43,27 @@
 	return pkg.Name()
 }
 
+// genericPkg is a prefix for packages that should be type checked with
+// generics.
+const genericPkg = "package generic_"
+
+func modeForSource(src string) parser.Mode {
+	if strings.HasPrefix(src, genericPkg) {
+		return parser.ParseTypeParams
+	}
+	return 0
+}
+
 func mayTypecheck(t *testing.T, path, source string, info *Info) (string, error) {
 	fset := token.NewFileSet()
-	f, err := parser.ParseFile(fset, path, source, 0)
+	mode := modeForSource(source)
+	f, err := parser.ParseFile(fset, path, source, mode)
 	if f == nil { // ignore errors unless f is nil
 		t.Fatalf("%s: unable to parse: %s", path, err)
 	}
 	conf := Config{
-		AcceptMethodTypeParams: true,
-		InferFromConstraints:   true,
-		Error:                  func(err error) {},
-		Importer:               importer.Default(),
+		Error:    func(err error) {},
+		Importer: importer.Default(),
 	}
 	pkg, err := conf.Check(f.Name.Name, fset, []*ast.File{f}, info)
 	return pkg.Name(), err
@@ -278,20 +289,20 @@
 		{`package x5; func _() { var x map[string][...]int; x = map[string][...]int{"": {1,2,3}} }`, `x`, `map[string][-1]int`},
 
 		// parameterized functions
-		{`package p0; func f[T any](T); var _ = f(int)`, `f`, `func[T₁ any](T₁)`},
-		{`package p1; func f[T any](T); var _ = f(int)`, `f(int)`, `func(int)`},
-		{`package p2; func f[T any](T); var _ = f(42)`, `f`, `func[T₁ any](T₁)`},
-		{`package p2; func f[T any](T); var _ = f(42)`, `f(42)`, `()`},
+		{genericPkg + `p0; func f[T any](T); var _ = f(int)`, `f`, `func[T₁ any](T₁)`},
+		{genericPkg + `p1; func f[T any](T); var _ = f(int)`, `f(int)`, `func(int)`},
+		{genericPkg + `p2; func f[T any](T); var _ = f(42)`, `f`, `func[T₁ any](T₁)`},
+		{genericPkg + `p2; func f[T any](T); var _ = f(42)`, `f(42)`, `()`},
 
 		// type parameters
-		{`package t0; type t[] int; var _ t`, `t`, `t0.t`}, // t[] is a syntax error that is ignored in this test in favor of t
-		{`package t1; type t[P any] int; var _ t[int]`, `t`, `t1.t[P₁ any]`},
-		{`package t2; type t[P interface{}] int; var _ t[int]`, `t`, `t2.t[P₁ interface{}]`},
-		{`package t3; type t[P, Q interface{}] int; var _ t[int, int]`, `t`, `t3.t[P₁, Q₂ interface{}]`},
-		{`package t4; type t[P, Q interface{ m() }] int; var _ t[int, int]`, `t`, `t4.t[P₁, Q₂ interface{m()}]`},
+		{genericPkg + `t0; type t[] int; var _ t`, `t`, `generic_t0.t`}, // t[] is a syntax error that is ignored in this test in favor of t
+		{genericPkg + `t1; type t[P any] int; var _ t[int]`, `t`, `generic_t1.t[P₁ any]`},
+		{genericPkg + `t2; type t[P interface{}] int; var _ t[int]`, `t`, `generic_t2.t[P₁ interface{}]`},
+		{genericPkg + `t3; type t[P, Q interface{}] int; var _ t[int, int]`, `t`, `generic_t3.t[P₁, Q₂ interface{}]`},
+		{genericPkg + `t4; type t[P, Q interface{ m() }] int; var _ t[int, int]`, `t`, `generic_t4.t[P₁, Q₂ interface{m()}]`},
 
 		// instantiated types must be sanitized
-		{`package g0; type t[P any] int; var x struct{ f t[int] }; var _ = x.f`, `x.f`, `g0.t[int]`},
+		{genericPkg + `g0; type t[P any] int; var x struct{ f t[int] }; var _ = x.f`, `x.f`, `generic_g0.t[int]`},
 	}
 
 	for _, test := range tests {
@@ -325,103 +336,64 @@
 		targs []string
 		sig   string
 	}{
-		{`package p0; func f[T any](T); func _() { f(42) }`,
+		{genericPkg + `p0; func f[T any](T); func _() { f(42) }`,
 			`f`,
 			[]string{`int`},
 			`func(int)`,
 		},
-		{`package p1; func f[T any](T) T; func _() { f('@') }`,
+		{genericPkg + `p1; func f[T any](T) T; func _() { f('@') }`,
 			`f`,
 			[]string{`rune`},
 			`func(rune) rune`,
 		},
-		{`package p2; func f[T any](...T) T; func _() { f(0i) }`,
+		{genericPkg + `p2; func f[T any](...T) T; func _() { f(0i) }`,
 			`f`,
 			[]string{`complex128`},
 			`func(...complex128) complex128`,
 		},
-		{`package p3; func f(type A, B, C)(A, *B, []C); func _() { f(1.2, new(string), []byte{}) }`,
+		{genericPkg + `p3; func f[A, B, C any](A, *B, []C); func _() { f(1.2, new(string), []byte{}) }`,
 			`f`,
 			[]string{`float64`, `string`, `byte`},
 			`func(float64, *string, []byte)`,
 		},
-		{`package p4; func f(type A, B)(A, *B, ...[]B); func _() { f(1.2, new(byte)) }`,
+		{genericPkg + `p4; func f[A, B any](A, *B, ...[]B); func _() { f(1.2, new(byte)) }`,
 			`f`,
 			[]string{`float64`, `byte`},
 			`func(float64, *byte, ...[]byte)`,
 		},
 
-		// we don't know how to translate these but we can type-check them
-		{`package q0; type T struct{}; func (T) m[P any](P); func _(x T) { x.m(42) }`,
-			`x.m`,
-			[]string{`int`},
-			`func(int)`,
-		},
-		{`package q1; type T struct{}; func (T) m[P any](P) P; func _(x T) { x.m(42) }`,
-			`x.m`,
-			[]string{`int`},
-			`func(int) int`,
-		},
-		{`package q2; type T struct{}; func (T) m[P any](...P) P; func _(x T) { x.m(42) }`,
-			`x.m`,
-			[]string{`int`},
-			`func(...int) int`,
-		},
-		{`package q3; type T struct{}; func (T) m(type A, B, C)(A, *B, []C); func _(x T) { x.m(1.2, new(string), []byte{}) }`,
-			`x.m`,
-			[]string{`float64`, `string`, `byte`},
-			`func(float64, *string, []byte)`,
-		},
-		{`package q4; type T struct{}; func (T) m(type A, B)(A, *B, ...[]B); func _(x T) { x.m(1.2, new(byte)) }`,
-			`x.m`,
-			[]string{`float64`, `byte`},
-			`func(float64, *byte, ...[]byte)`,
-		},
-
-		{`package r0; type T[P any] struct{}; func (_ T[P]) m[type Q](Q); func _[P any](x T[P]) { x.m(42) }`,
-			`x.m`,
-			[]string{`int`},
-			`func(int)`,
-		},
-		// TODO(gri) fix method type parameter syntax below
-		{`package r1; type T interface{ m(type P any)(P) }; func _(x T) { x.m(4.2) }`,
-			`x.m`,
-			[]string{`float64`},
-			`func(float64)`,
-		},
-
-		{`package s1; func f[T any, P interface{type *T}](x T); func _(x string) { f(x) }`,
+		{genericPkg + `s1; func f[T any, P interface{type *T}](x T); func _(x string) { f(x) }`,
 			`f`,
 			[]string{`string`, `*string`},
 			`func(x string)`,
 		},
-		{`package s2; func f[T any, P interface{type *T}](x []T); func _(x []int) { f(x) }`,
+		{genericPkg + `s2; func f[T any, P interface{type *T}](x []T); func _(x []int) { f(x) }`,
 			`f`,
 			[]string{`int`, `*int`},
 			`func(x []int)`,
 		},
-		{`package s3; type C[T any] interface{type chan<- T}; func f[T any, P C[T]](x []T); func _(x []int) { f(x) }`,
+		{genericPkg + `s3; type C[T any] interface{type chan<- T}; func f[T any, P C[T]](x []T); func _(x []int) { f(x) }`,
 			`f`,
 			[]string{`int`, `chan<- int`},
 			`func(x []int)`,
 		},
-		{`package s4; type C[T any] interface{type chan<- T}; func f[T any, P C[T], Q C[[]*P]](x []T); func _(x []int) { f(x) }`,
+		{genericPkg + `s4; type C[T any] interface{type chan<- T}; func f[T any, P C[T], Q C[[]*P]](x []T); func _(x []int) { f(x) }`,
 			`f`,
 			[]string{`int`, `chan<- int`, `chan<- []*chan<- int`},
 			`func(x []int)`,
 		},
 
-		{`package t1; func f[T any, P interface{type *T}]() T; func _() { _ = f[string] }`,
+		{genericPkg + `t1; func f[T any, P interface{type *T}]() T; func _() { _ = f[string] }`,
 			`f`,
 			[]string{`string`, `*string`},
 			`func() string`,
 		},
-		{`package t2; type C[T any] interface{type chan<- T}; func f[T any, P C[T]]() []T; func _() { _ = f[int] }`,
+		{genericPkg + `t2; type C[T any] interface{type chan<- T}; func f[T any, P C[T]]() []T; func _() { _ = f[int] }`,
 			`f`,
 			[]string{`int`, `chan<- int`},
 			`func() []int`,
 		},
-		{`package t3; type C[T any] interface{type chan<- T}; func f[T any, P C[T], Q C[[]*P]]() []T; func _() { _ = f[int] }`,
+		{genericPkg + `t3; type C[T any] interface{type chan<- T}; func f[T any, P C[T], Q C[[]*P]]() []T; func _() { _ = f[int] }`,
 			`f`,
 			[]string{`int`, `chan<- int`, `chan<- []*chan<- int`},
 			`func() []int`,
@@ -493,10 +465,10 @@
 
 		// generic types must be sanitized
 		// (need to use sufficiently nested types to provoke unexpanded types)
-		{`package g0; type t[P any] P; const x = t[int](42)`, `x`, `const g0.x g0.t[int]`},
-		{`package g1; type t[P any] P; var x = t[int](42)`, `x`, `var g1.x g1.t[int]`},
-		{`package g2; type t[P any] P; type x struct{ f t[int] }`, `x`, `type g2.x struct{f g2.t[int]}`},
-		{`package g3; type t[P any] P; func f(x struct{ f t[string] }); var g = f`, `g`, `var g3.g func(x struct{f g3.t[string]})`},
+		{genericPkg + `g0; type t[P any] P; const x = t[int](42)`, `x`, `const generic_g0.x generic_g0.t[int]`},
+		{genericPkg + `g1; type t[P any] P; var x = t[int](42)`, `x`, `var generic_g1.x generic_g1.t[int]`},
+		{genericPkg + `g2; type t[P any] P; type x struct{ f t[int] }`, `x`, `type generic_g2.x struct{f generic_g2.t[int]}`},
+		{genericPkg + `g3; type t[P any] P; func f(x struct{ f t[string] }); var g = f`, `g`, `var generic_g3.g func(x struct{f generic_g3.t[string]})`},
 	}
 
 	for _, test := range tests {
@@ -538,10 +510,10 @@
 
 		// generic types must be sanitized
 		// (need to use sufficiently nested types to provoke unexpanded types)
-		{`package g0; func _() { _ = x }; type t[P any] P; const x = t[int](42)`, `x`, `const g0.x g0.t[int]`},
-		{`package g1; func _() { _ = x }; type t[P any] P; var x = t[int](42)`, `x`, `var g1.x g1.t[int]`},
-		{`package g2; func _() { type _ x }; type t[P any] P; type x struct{ f t[int] }`, `x`, `type g2.x struct{f g2.t[int]}`},
-		{`package g3; func _() { _ = f }; type t[P any] P; func f(x struct{ f t[string] })`, `f`, `func g3.f(x struct{f g3.t[string]})`},
+		{genericPkg + `g0; func _() { _ = x }; type t[P any] P; const x = t[int](42)`, `x`, `const generic_g0.x generic_g0.t[int]`},
+		{genericPkg + `g1; func _() { _ = x }; type t[P any] P; var x = t[int](42)`, `x`, `var generic_g1.x generic_g1.t[int]`},
+		{genericPkg + `g2; func _() { type _ x }; type t[P any] P; type x struct{ f t[int] }`, `x`, `type generic_g2.x struct{f generic_g2.t[int]}`},
+		{genericPkg + `g3; func _() { _ = f }; type t[P any] P; func f(x struct{ f t[string] })`, `f`, `func generic_g3.f(x struct{f generic_g3.t[string]})`},
 	}
 
 	for _, test := range tests {
@@ -1501,6 +1473,50 @@
 	}
 }
 
+func TestConvertibleTo(t *testing.T) {
+	for _, test := range []struct {
+		v, t Type
+		want bool
+	}{
+		{Typ[Int], Typ[Int], true},
+		{Typ[Int], Typ[Float32], true},
+		{newDefined(Typ[Int]), Typ[Int], true},
+		{newDefined(new(Struct)), new(Struct), true},
+		{newDefined(Typ[Int]), new(Struct), false},
+		{Typ[UntypedInt], Typ[Int], true},
+		// Untyped string values are not permitted by the spec, so the below
+		// behavior is undefined.
+		{Typ[UntypedString], Typ[String], true},
+	} {
+		if got := ConvertibleTo(test.v, test.t); got != test.want {
+			t.Errorf("ConvertibleTo(%v, %v) = %t, want %t", test.v, test.t, got, test.want)
+		}
+	}
+}
+
+func TestAssignableTo(t *testing.T) {
+	for _, test := range []struct {
+		v, t Type
+		want bool
+	}{
+		{Typ[Int], Typ[Int], true},
+		{Typ[Int], Typ[Float32], false},
+		{newDefined(Typ[Int]), Typ[Int], false},
+		{newDefined(new(Struct)), new(Struct), true},
+		{Typ[UntypedBool], Typ[Bool], true},
+		{Typ[UntypedString], Typ[Bool], false},
+		// Neither untyped string nor untyped numeric assignments arise during
+		// normal type checking, so the below behavior is technically undefined by
+		// the spec.
+		{Typ[UntypedString], Typ[String], true},
+		{Typ[UntypedInt], Typ[Int], true},
+	} {
+		if got := AssignableTo(test.v, test.t); got != test.want {
+			t.Errorf("AssignableTo(%v, %v) = %t, want %t", test.v, test.t, got, test.want)
+		}
+	}
+}
+
 func TestIdentical_issue15173(t *testing.T) {
 	// Identical should allow nil arguments and be symmetric.
 	for _, test := range []struct {
diff --git a/src/go/types/assignments.go b/src/go/types/assignments.go
index e9a1224..3aa06e8 100644
--- a/src/go/types/assignments.go
+++ b/src/go/types/assignments.go
@@ -26,7 +26,7 @@
 		// ok
 	default:
 		// we may get here because of other problems (issue #39634, crash 12)
-		check.errorf(x.pos(), "cannot assign %s to %s in %s", x, T, context)
+		check.errorf(x, 0, "cannot assign %s to %s in %s", x, T, context)
 		return
 	}
 
@@ -35,26 +35,44 @@
 		// spec: "If an untyped constant is assigned to a variable of interface
 		// type or the blank identifier, the constant is first converted to type
 		// bool, rune, int, float64, complex128 or string respectively, depending
-		// on whether the value is a boolean, rune, integer, floating-point, complex,
-		// or string constant."
+		// on whether the value is a boolean, rune, integer, floating-point,
+		// complex, or string constant."
 		if T == nil || IsInterface(T) {
 			if T == nil && x.typ == Typ[UntypedNil] {
-				check.errorf(x.pos(), "use of untyped nil in %s", context)
+				check.errorf(x, _UntypedNil, "use of untyped nil in %s", context)
 				x.mode = invalid
 				return
 			}
 			target = Default(x.typ)
 		}
-		check.convertUntyped(x, target)
-		if x.mode == invalid {
+		newType, val, code := check.implicitTypeAndValue(x, target)
+		if code != 0 {
+			msg := check.sprintf("cannot use %s as %s value in %s", x, target, context)
+			switch code {
+			case _TruncatedFloat:
+				msg += " (truncated)"
+			case _NumericOverflow:
+				msg += " (overflows)"
+			default:
+				code = _IncompatibleAssign
+			}
+			check.error(x, code, msg)
+			x.mode = invalid
 			return
 		}
+		if val != nil {
+			x.val = val
+			check.updateExprVal(x.expr, val)
+		}
+		if newType != x.typ {
+			x.typ = newType
+			check.updateExprType(x.expr, newType, false)
+		}
 	}
-	// x.typ is typed
 
 	// A generic (non-instantiated) function value cannot be assigned to a variable.
 	if sig := asSignature(x.typ); sig != nil && len(sig.tparams) > 0 {
-		check.errorf(x.pos(), "cannot use generic function %s without instantiation in %s", x, context)
+		check.errorf(x, _Todo, "cannot use generic function %s without instantiation in %s", x, context)
 	}
 
 	// spec: "If a left-hand side is the blank identifier, any typed or
@@ -64,11 +82,12 @@
 		return
 	}
 
-	if reason := ""; !x.assignableTo(check, T, &reason) {
+	reason := ""
+	if ok, code := x.assignableTo(check, T, &reason); !ok {
 		if reason != "" {
-			check.errorf(x.pos(), "cannot use %s as %s value in %s: %s", x, T, context, reason)
+			check.errorf(x, code, "cannot use %s as %s value in %s: %s", x, T, context, reason)
 		} else {
-			check.errorf(x.pos(), "cannot use %s as %s value in %s", x, T, context)
+			check.errorf(x, code, "cannot use %s as %s value in %s", x, T, context)
 		}
 		x.mode = invalid
 	}
@@ -84,7 +103,7 @@
 
 	// rhs must be a constant
 	if x.mode != constant_ {
-		check.errorf(x.pos(), "%s is not constant", x)
+		check.errorf(x, _InvalidConstInit, "%s is not constant", x)
 		if lhs.typ == nil {
 			lhs.typ = Typ[Invalid]
 		}
@@ -119,7 +138,7 @@
 		if isUntyped(typ) {
 			// convert untyped types to default types
 			if typ == Typ[UntypedNil] {
-				check.errorf(x.pos(), "use of untyped nil in %s", context)
+				check.errorf(x, _UntypedNil, "use of untyped nil in %s", context)
 				lhs.typ = Typ[Invalid]
 				return nil
 			}
@@ -194,11 +213,11 @@
 			var op operand
 			check.expr(&op, sel.X)
 			if op.mode == mapindex {
-				check.errorf(z.pos(), "cannot assign to struct field %s in map", ExprString(z.expr))
+				check.errorf(&z, _UnaddressableFieldAssign, "cannot assign to struct field %s in map", ExprString(z.expr))
 				return nil
 			}
 		}
-		check.errorf(z.pos(), "cannot assign to %s", &z)
+		check.errorf(&z, _UnassignableOperand, "cannot assign to %s", &z)
 		return nil
 	}
 
@@ -212,8 +231,8 @@
 
 // If returnPos is valid, initVars is called to type-check the assignment of
 // return expressions, and returnPos is the position of the return statement.
-func (check *Checker) initVars(lhs []*Var, orig_rhs []ast.Expr, returnPos token.Pos) {
-	rhs, commaOk := check.exprList(orig_rhs, len(lhs) == 2 && !returnPos.IsValid())
+func (check *Checker) initVars(lhs []*Var, origRHS []ast.Expr, returnPos token.Pos) {
+	rhs, commaOk := check.exprList(origRHS, len(lhs) == 2 && !returnPos.IsValid())
 
 	if len(lhs) != len(rhs) {
 		// invalidate lhs
@@ -229,10 +248,10 @@
 			}
 		}
 		if returnPos.IsValid() {
-			check.errorf(returnPos, "wrong number of return values (want %d, got %d)", len(lhs), len(rhs))
+			check.errorf(atPos(returnPos), _WrongResultCount, "wrong number of return values (want %d, got %d)", len(lhs), len(rhs))
 			return
 		}
-		check.errorf(rhs[0].pos(), "cannot initialize %d variables with %d values", len(lhs), len(rhs))
+		check.errorf(rhs[0], _WrongAssignCount, "cannot initialize %d variables with %d values", len(lhs), len(rhs))
 		return
 	}
 
@@ -246,7 +265,7 @@
 		for i := range a {
 			a[i] = check.initVar(lhs[i], rhs[i], context)
 		}
-		check.recordCommaOkTypes(orig_rhs[0], a)
+		check.recordCommaOkTypes(origRHS[0], a)
 		return
 	}
 
@@ -255,8 +274,8 @@
 	}
 }
 
-func (check *Checker) assignVars(lhs, orig_rhs []ast.Expr) {
-	rhs, commaOk := check.exprList(orig_rhs, len(lhs) == 2)
+func (check *Checker) assignVars(lhs, origRHS []ast.Expr) {
+	rhs, commaOk := check.exprList(origRHS, len(lhs) == 2)
 
 	if len(lhs) != len(rhs) {
 		check.useLHS(lhs...)
@@ -266,7 +285,7 @@
 				return
 			}
 		}
-		check.errorf(rhs[0].pos(), "cannot assign %d values to %d variables", len(rhs), len(lhs))
+		check.errorf(rhs[0], _WrongAssignCount, "cannot assign %d values to %d variables", len(rhs), len(lhs))
 		return
 	}
 
@@ -275,7 +294,7 @@
 		for i := range a {
 			a[i] = check.assignVar(lhs[i], rhs[i])
 		}
-		check.recordCommaOkTypes(orig_rhs[0], a)
+		check.recordCommaOkTypes(origRHS[0], a)
 		return
 	}
 
@@ -284,7 +303,7 @@
 	}
 }
 
-func (check *Checker) shortVarDecl(pos token.Pos, lhs, rhs []ast.Expr) {
+func (check *Checker) shortVarDecl(pos positioner, lhs, rhs []ast.Expr) {
 	top := len(check.delayed)
 	scope := check.scope
 
@@ -304,7 +323,7 @@
 				if alt, _ := alt.(*Var); alt != nil {
 					obj = alt
 				} else {
-					check.errorf(lhs.Pos(), "cannot assign to %s", lhs)
+					check.errorf(lhs, _UnassignableOperand, "cannot assign to %s", lhs)
 				}
 				check.recordUse(ident, alt)
 			} else {
@@ -317,7 +336,7 @@
 			}
 		} else {
 			check.useLHS(lhs)
-			check.errorf(lhs.Pos(), "cannot declare %s", lhs)
+			check.invalidAST(lhs, "cannot declare %s", lhs)
 		}
 		if obj == nil {
 			obj = NewVar(lhs.Pos(), check.pkg, "_", nil) // dummy variable
@@ -341,6 +360,6 @@
 			check.declare(scope, nil, obj, scopePos) // recordObject already called
 		}
 	} else {
-		check.softErrorf(pos, "no new variables on left side of :=")
+		check.softErrorf(pos, _NoNewVar, "no new variables on left side of :=")
 	}
 }
diff --git a/src/go/types/builtins.go b/src/go/types/builtins.go
index d53a424..28697d9 100644
--- a/src/go/types/builtins.go
+++ b/src/go/types/builtins.go
@@ -21,7 +21,9 @@
 	// append is the only built-in that permits the use of ... for the last argument
 	bin := predeclaredFuncs[id]
 	if call.Ellipsis.IsValid() && id != _Append {
-		check.invalidOp(call.Ellipsis, "invalid use of ... with built-in %s", bin.name)
+		check.invalidOp(atPos(call.Ellipsis),
+			_InvalidDotDotDot,
+			"invalid use of ... with built-in %s", bin.name)
 		check.use(call.Args...)
 		return
 	}
@@ -67,7 +69,7 @@
 			msg = "too many"
 		}
 		if msg != "" {
-			check.invalidOp(call.Rparen, "%s arguments for %s (expected %d, found %d)", msg, call, bin.nargs, nargs)
+			check.invalidOp(inNode(call, call.Rparen), _WrongArgCount, "%s arguments for %s (expected %d, found %d)", msg, call, bin.nargs, nargs)
 			return
 		}
 	}
@@ -84,7 +86,7 @@
 		if s := asSlice(S); s != nil {
 			T = s.elem
 		} else {
-			check.invalidArg(x.pos(), "%s is not a slice", x)
+			check.invalidArg(x, _InvalidAppend, "%s is not a slice", x)
 			return
 		}
 
@@ -94,23 +96,25 @@
 		// spec: "As a special case, append also accepts a first argument assignable
 		// to type []byte with a second argument of string type followed by ... .
 		// This form appends the bytes of the string.
-		if nargs == 2 && call.Ellipsis.IsValid() && x.assignableTo(check, NewSlice(universeByte), nil) {
-			arg(x, 1)
-			if x.mode == invalid {
-				return
-			}
-			if isString(x.typ) {
-				if check.Types != nil {
-					sig := makeSig(S, S, x.typ)
-					sig.variadic = true
-					check.recordBuiltinType(call.Fun, sig)
+		if nargs == 2 && call.Ellipsis.IsValid() {
+			if ok, _ := x.assignableTo(check, NewSlice(universeByte), nil); ok {
+				arg(x, 1)
+				if x.mode == invalid {
+					return
 				}
-				x.mode = value
-				x.typ = S
-				break
+				if isString(x.typ) {
+					if check.Types != nil {
+						sig := makeSig(S, S, x.typ)
+						sig.variadic = true
+						check.recordBuiltinType(call.Fun, sig)
+					}
+					x.mode = value
+					x.typ = S
+					break
+				}
+				alist = append(alist, *x)
+				// fallthrough
 			}
-			alist = append(alist, *x)
-			// fallthrough
 		}
 
 		// check general case by creating custom signature
@@ -196,7 +200,11 @@
 		}
 
 		if mode == invalid && typ != Typ[Invalid] {
-			check.invalidArg(x.pos(), "%s for %s", x, bin.name)
+			code := _InvalidCap
+			if id == _Len {
+				code = _InvalidLen
+			}
+			check.invalidArg(x, code, "%s for %s", x, bin.name)
 			return
 		}
 
@@ -211,11 +219,11 @@
 		// close(c)
 		c := asChan(x.typ)
 		if c == nil {
-			check.invalidArg(x.pos(), "%s is not a channel", x)
+			check.invalidArg(x, _InvalidClose, "%s is not a channel", x)
 			return
 		}
 		if c.dir == RecvOnly {
-			check.invalidArg(x.pos(), "%s must not be a receive-only channel", x)
+			check.invalidArg(x, _InvalidClose, "%s must not be a receive-only channel", x)
 			return
 		}
 
@@ -279,7 +287,7 @@
 
 		// both argument types must be identical
 		if !check.identical(x.typ, y.typ) {
-			check.invalidArg(x.pos(), "mismatched types %s and %s", x.typ, y.typ)
+			check.invalidArg(x, _InvalidComplex, "mismatched types %s and %s", x.typ, y.typ)
 			return
 		}
 
@@ -299,7 +307,7 @@
 		}
 		resTyp := check.applyTypeFunc(f, x.typ)
 		if resTyp == nil {
-			check.invalidArg(x.pos(), "arguments have type %s, expected floating-point", x.typ)
+			check.invalidArg(x, _InvalidComplex, "arguments have type %s, expected floating-point", x.typ)
 			return
 		}
 
@@ -339,12 +347,12 @@
 		}
 
 		if dst == nil || src == nil {
-			check.invalidArg(x.pos(), "copy expects slice arguments; found %s and %s", x, &y)
+			check.invalidArg(x, _InvalidCopy, "copy expects slice arguments; found %s and %s", x, &y)
 			return
 		}
 
 		if !check.identical(dst, src) {
-			check.invalidArg(x.pos(), "arguments to copy %s and %s have different element types %s and %s", x, &y, dst, src)
+			check.invalidArg(x, _InvalidCopy, "arguments to copy %s and %s have different element types %s and %s", x, &y, dst, src)
 			return
 		}
 
@@ -358,7 +366,7 @@
 		// delete(m, k)
 		m := asMap(x.typ)
 		if m == nil {
-			check.invalidArg(x.pos(), "%s is not a map", x)
+			check.invalidArg(x, _InvalidDelete, "%s is not a map", x)
 			return
 		}
 		arg(x, 1) // k
@@ -366,8 +374,8 @@
 			return
 		}
 
-		if !x.assignableTo(check, m.key, nil) {
-			check.invalidArg(x.pos(), "%s is not assignable to %s", x, m.key)
+		if ok, code := x.assignableTo(check, m.key, nil); !ok {
+			check.invalidArg(x, code, "%s is not assignable to %s", x, m.key)
 			return
 		}
 
@@ -417,7 +425,11 @@
 		}
 		resTyp := check.applyTypeFunc(f, x.typ)
 		if resTyp == nil {
-			check.invalidArg(x.pos(), "argument has type %s, expected complex type", x.typ)
+			code := _InvalidImag
+			if id == _Real {
+				code = _InvalidReal
+			}
+			check.invalidArg(x, code, "argument has type %s, expected complex type", x.typ)
 			return
 		}
 
@@ -472,14 +484,14 @@
 		}
 
 		if !valid(T) {
-			check.invalidArg(arg0.Pos(), "cannot make %s; type must be slice, map, or channel", arg0)
+			check.invalidArg(arg0, _InvalidMake, "cannot make %s; type must be slice, map, or channel", arg0)
 			return
 		}
 		if nargs < min || max < nargs {
 			if min == max {
-				check.errorf(call.Pos(), "%v expects %d arguments; found %d", call, min, nargs)
+				check.errorf(call, _WrongArgCount, "%v expects %d arguments; found %d", call, min, nargs)
 			} else {
-				check.errorf(call.Pos(), "%v expects %d or %d arguments; found %d", call, min, max, nargs)
+				check.errorf(call, _WrongArgCount, "%v expects %d or %d arguments; found %d", call, min, max, nargs)
 			}
 			return
 		}
@@ -494,7 +506,7 @@
 			}
 		}
 		if len(sizes) == 2 && sizes[0] > sizes[1] {
-			check.invalidArg(call.Args[1].Pos(), "length and capacity swapped")
+			check.invalidArg(call.Args[1], _SwappedMakeArgs, "length and capacity swapped")
 			// safe to continue
 		}
 		x.mode = value
@@ -577,7 +589,7 @@
 	case _Alignof:
 		// unsafe.Alignof(x T) uintptr
 		if asTypeParam(x.typ) != nil {
-			check.invalidOp(call.Pos(), "unsafe.Alignof undefined for %s", x)
+			check.invalidOp(call, _Todo, "unsafe.Alignof undefined for %s", x)
 			return
 		}
 		check.assignment(x, nil, "argument to unsafe.Alignof")
@@ -596,7 +608,7 @@
 		arg0 := call.Args[0]
 		selx, _ := unparen(arg0).(*ast.SelectorExpr)
 		if selx == nil {
-			check.invalidArg(arg0.Pos(), "%s is not a selector expression", arg0)
+			check.invalidArg(arg0, _BadOffsetofSyntax, "%s is not a selector expression", arg0)
 			check.use(arg0)
 			return
 		}
@@ -611,18 +623,18 @@
 		obj, index, indirect := check.lookupFieldOrMethod(base, false, check.pkg, sel)
 		switch obj.(type) {
 		case nil:
-			check.invalidArg(x.pos(), "%s has no single field %s", base, sel)
+			check.invalidArg(x, _MissingFieldOrMethod, "%s has no single field %s", base, sel)
 			return
 		case *Func:
 			// TODO(gri) Using derefStructPtr may result in methods being found
 			// that don't actually exist. An error either way, but the error
 			// message is confusing. See: https://play.golang.org/p/al75v23kUy ,
 			// but go/types reports: "invalid argument: x.m is a method value".
-			check.invalidArg(arg0.Pos(), "%s is a method value", arg0)
+			check.invalidArg(arg0, _InvalidOffsetof, "%s is a method value", arg0)
 			return
 		}
 		if indirect {
-			check.invalidArg(x.pos(), "field %s is embedded via a pointer in %s", sel, base)
+			check.invalidArg(x, _InvalidOffsetof, "field %s is embedded via a pointer in %s", sel, base)
 			return
 		}
 
@@ -638,7 +650,7 @@
 	case _Sizeof:
 		// unsafe.Sizeof(x T) uintptr
 		if asTypeParam(x.typ) != nil {
-			check.invalidOp(call.Pos(), "unsafe.Sizeof undefined for %s", x)
+			check.invalidOp(call, _Todo, "unsafe.Sizeof undefined for %s", x)
 			return
 		}
 		check.assignment(x, nil, "argument to unsafe.Sizeof")
@@ -656,15 +668,15 @@
 		// The result of assert is the value of pred if there is no error.
 		// Note: assert is only available in self-test mode.
 		if x.mode != constant_ || !isBoolean(x.typ) {
-			check.invalidArg(x.pos(), "%s is not a boolean constant", x)
+			check.invalidArg(x, _Test, "%s is not a boolean constant", x)
 			return
 		}
 		if x.val.Kind() != constant.Bool {
-			check.errorf(x.pos(), "internal error: value of %s should be a boolean constant", x)
+			check.errorf(x, _Test, "internal error: value of %s should be a boolean constant", x)
 			return
 		}
 		if !constant.BoolVal(x.val) {
-			check.errorf(call.Pos(), "%v failed", call)
+			check.errorf(call, _Test, "%v failed", call)
 			// compile-time assertion failure - safe to continue
 		}
 		// result is constant - no need to record signature
@@ -684,7 +696,7 @@
 		x1 := x
 		for _, arg := range call.Args {
 			check.rawExpr(x1, arg, nil) // permit trace for types, e.g.: new(trace(T))
-			check.dump("%v: %s", x1.pos(), x1)
+			check.dump("%v: %s", x1.Pos(), x1)
 			x1 = &t // use incoming x only for first argument
 		}
 		// trace is only available in test mode - no need to record signature
@@ -720,7 +732,7 @@
 
 		// construct a suitable new type parameter
 		tpar := NewTypeName(token.NoPos, nil /* = Universe pkg */, "<type parameter>", nil)
-		ptyp := check.NewTypeParam(tp.ptr, tpar, 0, &emptyInterface) // assigns type to tpar as a side-effect
+		ptyp := check.NewTypeParam(tpar, 0, &emptyInterface) // assigns type to tpar as a side-effect
 		tsum := NewSum(rtypes)
 		ptyp.bound = &Interface{types: tsum, allMethods: markComplete, allTypes: tsum}
 
diff --git a/src/go/types/call.go b/src/go/types/call.go
index 267c463..d9a7b44 100644
--- a/src/go/types/call.go
+++ b/src/go/types/call.go
@@ -1,3 +1,4 @@
+// REVIEW INCOMPLETE
 // Copyright 2013 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.
@@ -13,6 +14,7 @@
 	"unicode"
 )
 
+// TODO(rFindley) this has diverged a bit from types2. Bring it up to date.
 // If call == nil, the "call" was an index expression, and orig is of type *ast.IndexExpr.
 func (check *Checker) call(x *operand, call *ast.CallExpr, orig ast.Expr) exprKind {
 	assert(orig != nil)
@@ -49,14 +51,18 @@
 		// conversion
 		switch n := len(call.Args); n {
 		case 0:
-			check.errorf(call.Rparen, "missing argument in conversion to %s", T)
+			check.errorf(inNode(call, call.Rparen), _WrongArgCount, "missing argument in conversion to %s", T)
 		case 1:
 			check.expr(x, call.Args[0])
 			if x.mode != invalid {
+				if call.Ellipsis.IsValid() {
+					check.errorf(call.Args[0], _BadDotDotDotSyntax, "invalid use of ... in conversion to %s", T)
+					break
+				}
 				if t := asInterface(T); t != nil {
 					check.completeInterface(token.NoPos, t)
 					if t.IsConstraint() {
-						check.errorf(call.Pos(), "cannot use interface %s in conversion (contains type list or is comparable)", T)
+						check.errorf(call, _Todo, "cannot use interface %s in conversion (contains type list or is comparable)", T)
 						break
 					}
 				}
@@ -64,7 +70,7 @@
 			}
 		default:
 			check.use(call.Args...)
-			check.errorf(call.Args[n-1].Pos(), "too many arguments in conversion to %s", T)
+			check.errorf(call.Args[n-1], _WrongArgCount, "too many arguments in conversion to %s", T)
 		}
 		x.expr = orig
 		return conversion
@@ -87,7 +93,7 @@
 
 		sig := asSignature(x.typ)
 		if sig == nil {
-			check.invalidOp(x.pos(), "cannot call non-function %s", x)
+			check.invalidOp(x, _InvalidCall, "cannot call non-function %s", x)
 			x.mode = invalid
 			x.expr = orig
 			return statement
@@ -96,7 +102,7 @@
 		// evaluate arguments
 		args, ok := check.exprOrTypeList(call.Args)
 		if ok && call.Brackets && len(args) > 0 && args[0].mode != typexpr {
-			check.errorf(args[0].pos(), "%s is not a type", args[0])
+			check.errorf(args[0], _NotAType, "%s is not a type", args[0])
 			ok = false
 		}
 		if !ok {
@@ -110,8 +116,8 @@
 			// If the first argument is a type, assume we have explicit type arguments.
 
 			// check number of type arguments
-			if !check.conf.InferFromConstraints && n != len(sig.tparams) || n > len(sig.tparams) {
-				check.errorf(args[n-1].pos(), "got %d type arguments but want %d", n, len(sig.tparams))
+			if n > len(sig.tparams) {
+				check.errorf(args[n-1], _Todo, "got %d type arguments but want %d", n, len(sig.tparams))
 				x.mode = invalid
 				x.expr = orig
 				return expression
@@ -119,6 +125,8 @@
 
 			// collect types
 			targs := make([]Type, n)
+			// TODO(rFindley) use a positioner here? instantiate would need to be
+			//                updated accordingly.
 			poslist := make([]token.Pos, n)
 			for i, a := range args {
 				if a.mode != typexpr {
@@ -128,7 +136,7 @@
 					return expression
 				}
 				targs[i] = a.typ
-				poslist[i] = a.pos()
+				poslist[i] = a.Pos()
 			}
 
 			// if we don't have enough type arguments, use constraint type inference
@@ -147,7 +155,7 @@
 					assert(targs[failed] == nil)
 					tpar := sig.tparams[failed]
 					ppos := check.fset.Position(tpar.pos).String()
-					check.errorf(call.Rparen, "cannot infer %s (%s) (%s)", tpar.name, ppos, targs)
+					check.errorf(inNode(call, call.Rparen), 0, "cannot infer %s (%s) (%s)", tpar.name, ppos, targs)
 					x.mode = invalid
 					x.expr = orig
 					return expression
@@ -158,7 +166,6 @@
 						assert(targ != nil)
 					}
 				}
-				//check.dump("### inferred targs = %s", targs)
 				n = len(targs)
 				inferred = true
 			}
@@ -171,9 +178,9 @@
 				if i < len(poslist) {
 					pos = poslist[i]
 				}
-				check.ordinaryType(pos, typ)
+				check.ordinaryType(atPos(pos), typ)
 			}
-			res := check.instantiate(x.pos(), sig, targs, poslist).(*Signature)
+			res := check.instantiate(x.Pos(), sig, targs, poslist).(*Signature)
 			assert(res.tparams == nil) // signature is not generic anymore
 			if inferred {
 				check.recordInferred(orig, targs, res)
@@ -184,7 +191,11 @@
 			return expression
 		}
 
-		// If we reach here, orig must have been a regular call, not an index expression.
+		// If we reach here, orig must have been a regular call, not an index
+		// expression.
+		// TODO(rFindley) with a manually constructed AST it is possible to reach
+		//                this assertion. We should return an invalidAST error here
+		//                rather than panicking.
 		assert(!call.Brackets)
 
 		sig = check.arguments(call, sig, args)
@@ -262,7 +273,7 @@
 			}
 		}
 		if 0 < ntypes && ntypes < len(xlist) {
-			check.errorf(xlist[0].pos(), "mix of value and type expressions")
+			check.errorf(xlist[0], 0, "mix of value and type expressions")
 			ok = false
 		}
 	}
@@ -293,7 +304,11 @@
 		xlist = []*operand{&x}
 		if allowCommaOk && (x.mode == mapindex || x.mode == commaok || x.mode == commaerr) {
 			x.mode = value
-			xlist = append(xlist, &operand{mode: value, expr: e, typ: Typ[UntypedBool]})
+			x2 := &operand{mode: value, expr: e, typ: Typ[UntypedBool]}
+			if x.mode == commaerr {
+				x2.typ = universeError
+			}
+			xlist = append(xlist, x2)
 			commaOk = true
 		}
 
@@ -317,7 +332,7 @@
 	for _, a := range args {
 		switch a.mode {
 		case typexpr:
-			check.errorf(a.pos(), "%s used as value", a)
+			check.errorf(a, 0, "%s used as value", a)
 			return
 		case invalid:
 			return
@@ -338,14 +353,14 @@
 	ddd := call.Ellipsis.IsValid()
 
 	// set up parameters
-	sig_params := sig.params // adjusted for variadic functions (may be nil for empty parameter lists!)
-	adjusted := false        // indicates if sig_params is different from t.params
+	sigParams := sig.params // adjusted for variadic functions (may be nil for empty parameter lists!)
+	adjusted := false       // indicates if sigParams is different from t.params
 	if sig.variadic {
 		if ddd {
 			// variadic_func(a, b, c...)
 			if len(call.Args) == 1 && nargs > 1 {
 				// f()... is not permitted if f() is multi-valued
-				check.errorf(call.Ellipsis, "cannot use ... with %d-valued %s", nargs, call.Args[0])
+				check.errorf(inNode(call, call.Ellipsis), _InvalidDotDotDot, "cannot use ... with %d-valued %s", nargs, call.Args[0])
 				return
 			}
 		} else {
@@ -361,7 +376,7 @@
 				for len(vars) < nargs {
 					vars = append(vars, NewParam(last.pos, last.pkg, last.name, typ))
 				}
-				sig_params = NewTuple(vars...) // possibly nil!
+				sigParams = NewTuple(vars...) // possibly nil!
 				adjusted = true
 				npars = nargs
 			} else {
@@ -372,7 +387,7 @@
 	} else {
 		if ddd {
 			// standard_func(a, b, c...)
-			check.errorf(call.Ellipsis, "cannot use ... in call to non-variadic %s", call.Fun)
+			check.errorf(inNode(call, call.Ellipsis), _NonVariadicDotDotDot, "cannot use ... in call to non-variadic %s", call.Fun)
 			return
 		}
 		// standard_func(a, b, c)
@@ -381,10 +396,10 @@
 	// check argument count
 	switch {
 	case nargs < npars:
-		check.errorf(call.Rparen, "not enough arguments in call to %s", call.Fun)
+		check.errorf(inNode(call, call.Rparen), _WrongArgCount, "not enough arguments in call to %s", call.Fun)
 		return
 	case nargs > npars:
-		check.errorf(args[npars].pos(), "too many arguments in call to %s", call.Fun) // report at first extra argument
+		check.errorf(args[npars], _WrongArgCount, "too many arguments in call to %s", call.Fun) // report at first extra argument
 		return
 	}
 
@@ -392,25 +407,23 @@
 	if len(sig.tparams) > 0 {
 		// TODO(gri) provide position information for targs so we can feed
 		//           it to the instantiate call for better error reporting
-		targs, failed := check.infer(sig.tparams, sig_params, args)
+		targs, failed := check.infer(sig.tparams, sigParams, args)
 		if targs == nil {
 			return // error already reported
 		}
 		if failed >= 0 {
 			// Some type arguments couldn't be inferred. Use
 			// bounds type inference to try to make progress.
-			if check.conf.InferFromConstraints {
-				targs, failed = check.inferB(sig.tparams, targs)
-				if targs == nil {
-					return // error already reported
-				}
+			targs, failed = check.inferB(sig.tparams, targs)
+			if targs == nil {
+				return // error already reported
 			}
 			if failed >= 0 {
 				// at least one type argument couldn't be inferred
 				assert(targs[failed] == nil)
 				tpar := sig.tparams[failed]
 				ppos := check.fset.Position(tpar.pos).String()
-				check.errorf(call.Rparen, "cannot infer %s (%s) (%s)", tpar.name, ppos, targs)
+				check.errorf(inNode(call, call.Rparen), _Todo, "cannot infer %s (%s) (%s)", tpar.name, ppos, targs)
 				return
 			}
 		}
@@ -420,7 +433,6 @@
 				assert(targ != nil)
 			}
 		}
-		//check.dump("### inferred targs = %s", targs)
 
 		// compute result signature
 		rsig = check.instantiate(call.Pos(), sig, targs, nil).(*Signature)
@@ -431,9 +443,9 @@
 		// need to compute it from the adjusted list; otherwise we can
 		// simply use the result signature's parameter list.
 		if adjusted {
-			sig_params = check.subst(call.Pos(), sig_params, makeSubstMap(sig.tparams, targs)).(*Tuple)
+			sigParams = check.subst(call.Pos(), sigParams, makeSubstMap(sig.tparams, targs)).(*Tuple)
 		} else {
-			sig_params = rsig.params
+			sigParams = rsig.params
 		}
 	}
 
@@ -441,7 +453,7 @@
 	// TODO(gri) Possible optimization (may be tricky): We could avoid
 	//           checking arguments from which we inferred type arguments.
 	for i, a := range args {
-		check.assignment(a, sig_params.vars[i].typ, "argument")
+		check.assignment(a, sigParams.vars[i].typ, check.sprintf("argument to %s", call.Fun))
 	}
 
 	return
@@ -499,7 +511,7 @@
 					}
 				}
 				if exp == nil {
-					check.errorf(e.Sel.Pos(), "%s not declared by package C", sel)
+					check.errorf(e.Sel, _UndeclaredImportedName, "%s not declared by package C", sel)
 					goto Error
 				}
 				check.objDecl(exp, nil)
@@ -507,12 +519,12 @@
 				exp = pkg.scope.Lookup(sel)
 				if exp == nil {
 					if !pkg.fake {
-						check.errorf(e.Sel.Pos(), "%s not declared by package %s", sel, pkg.name)
+						check.errorf(e.Sel, _UndeclaredImportedName, "%s not declared by package %s", sel, pkg.name)
 					}
 					goto Error
 				}
 				if !exp.Exported() {
-					check.errorf(e.Sel.Pos(), "%s not exported by package %s", sel, pkg.name)
+					check.errorf(e.Sel, _UnexportedName, "%s not exported by package %s", sel, pkg.name)
 					// ok to continue
 				}
 			}
@@ -567,9 +579,9 @@
 		switch {
 		case index != nil:
 			// TODO(gri) should provide actual type where the conflict happens
-			check.errorf(e.Sel.Pos(), "ambiguous selector %s.%s", x.expr, sel)
+			check.errorf(e.Sel, _AmbiguousSelector, "ambiguous selector %s.%s", x.expr, sel)
 		case indirect:
-			check.errorf(e.Sel.Pos(), "cannot call pointer method %s on %s", sel, x.typ)
+			check.errorf(e.Sel, _InvalidMethodExpr, "cannot call pointer method %s on %s", sel, x.typ)
 		default:
 			var why string
 			if tpar := asTypeParam(x.typ); tpar != nil {
@@ -597,15 +609,13 @@
 				}
 			}
 
-			check.errorf(e.Sel.Pos(), "%s.%s undefined (%s)", x.expr, sel, why)
-
+			check.errorf(e.Sel, _MissingFieldOrMethod, "%s.%s undefined (%s)", x.expr, sel, why)
 		}
 		goto Error
 	}
 
 	// methods may not have a fully set up signature yet
 	if m, _ := obj.(*Func); m != nil {
-		// check.dump("### found method %s", m)
 		check.objDecl(m, nil)
 		// If m has a parameterized receiver type, infer the type parameter
 		// values from the actual receiver provided and then substitute the
@@ -613,8 +623,6 @@
 		// TODO(gri) factor this code out
 		sig := m.typ.(*Signature)
 		if len(sig.rparams) > 0 {
-			//check.dump("### recv typ = %s", x.typ)
-			//check.dump("### method = %s rparams = %s tparams = %s", m, sig.rparams, sig.tparams)
 			// The method may have a pointer receiver, but the actually provided receiver
 			// may be a (hopefully addressable) non-pointer value, or vice versa. Here we
 			// only care about inferring receiver type parameters; to make the inference
@@ -630,7 +638,6 @@
 				arg = &copy
 			}
 			targs, failed := check.infer(sig.rparams, NewTuple(sig.recv), []*operand{arg})
-			//check.dump("### inferred targs = %s", targs)
 			if failed >= 0 {
 				// We may reach here if there were other errors (see issue #40056).
 				// check.infer will report a follow-up error.
@@ -654,7 +661,7 @@
 		m, _ := obj.(*Func)
 		if m == nil {
 			// TODO(gri) should check if capitalization of sel matters and provide better error message in that case
-			check.errorf(e.Sel.Pos(), "%s.%s undefined (type %s has no method %s)", x.expr, sel, x.typ, sel)
+			check.errorf(e.Sel, _MissingFieldOrMethod, "%s.%s undefined (type %s has no method %s)", x.expr, sel, x.typ, sel)
 			goto Error
 		}
 
@@ -814,7 +821,7 @@
 // instantiatedOperand reports an error of x is an uninstantiated (generic) type and sets x.typ to Typ[Invalid].
 func (check *Checker) instantiatedOperand(x *operand) {
 	if x.mode == typexpr && isGeneric(x.typ) {
-		check.errorf(x.pos(), "cannot use generic type %s without instantiation", x.typ)
+		check.errorf(x, _Todo, "cannot use generic type %s without instantiation", x.typ)
 		x.typ = Typ[Invalid]
 	}
 }
diff --git a/src/go/types/check.go b/src/go/types/check.go
index 5238e5a..d167283 100644
--- a/src/go/types/check.go
+++ b/src/go/types/check.go
@@ -8,14 +8,16 @@
 
 import (
 	"errors"
-	"fmt"
 	"go/ast"
 	"go/constant"
 	"go/token"
 )
 
 // debugging/development support
-const debug = true // leave on during development
+const (
+	debug = false // leave on during development
+	trace = false // turn on for detailed type resolution traces
+)
 
 // If forceStrict is set, the type-checker enforces additional
 // rules not specified by the Go 1 spec, but which will
@@ -30,11 +32,6 @@
 //
 const forceStrict = false
 
-// If methodTypeParamsOk is set, type parameters are
-// permitted in method declarations (in interfaces, too).
-// Generalization and experimental feature.
-const methodTypeParamsOk = true
-
 // exprInfo stores information about an untyped expression.
 type exprInfo struct {
 	isLhs bool // expression is lhs operand of a shift with delayed type-check
@@ -49,6 +46,7 @@
 	scope         *Scope                 // top-most scope for lookups
 	pos           token.Pos              // if valid, identifiers are looked up as if at position pos (used by Eval)
 	iota          constant.Value         // value of iota in a constant declaration; nil otherwise
+	errpos        positioner             // if set, identifier position of a constant with inherited initializer
 	sig           *Signature             // function signature if inside a function; nil otherwise
 	isPanic       map[*ast.CallExpr]bool // set of panic call expressions (used for termination check)
 	hasLabel      bool                   // set if a function makes use of labels (only ~1% of functions); unused outside functions
@@ -90,9 +88,8 @@
 	// information collected during type-checking of a set of package files
 	// (initialized by Files, valid only for the duration of check.Files;
 	// maps and lists are allocated on demand)
-	files            []*ast.File                       // package files
-	unusedDotImports map[*Scope]map[*Package]token.Pos // positions of unused dot-imported packages for each file scope
-	useBrackets      bool                              // if set, [] are used instead of () for type parameters
+	files            []*ast.File                             // package files
+	unusedDotImports map[*Scope]map[*Package]*ast.ImportSpec // unused dot-imported packages
 
 	firstErr error                 // first error encountered
 	methods  map[*TypeName][]*Func // maps package scope type names to associated non-blank (non-interface) methods
@@ -111,18 +108,18 @@
 
 // addUnusedImport adds the position of a dot-imported package
 // pkg to the map of dot imports for the given file scope.
-func (check *Checker) addUnusedDotImport(scope *Scope, pkg *Package, pos token.Pos) {
+func (check *Checker) addUnusedDotImport(scope *Scope, pkg *Package, spec *ast.ImportSpec) {
 	mm := check.unusedDotImports
 	if mm == nil {
-		mm = make(map[*Scope]map[*Package]token.Pos)
+		mm = make(map[*Scope]map[*Package]*ast.ImportSpec)
 		check.unusedDotImports = mm
 	}
 	m := mm[scope]
 	if m == nil {
-		m = make(map[*Package]token.Pos)
+		m = make(map[*Package]*ast.ImportSpec)
 		mm[scope] = m
 	}
-	m[pkg] = pos
+	m[pkg] = spec
 }
 
 // addDeclDep adds the dependency edge (check.decl -> to) if check.decl exists
@@ -225,7 +222,7 @@
 			if name != "_" {
 				pkg.name = name
 			} else {
-				check.errorf(file.Name.Pos(), "invalid package name _")
+				check.errorf(file.Name, _BlankPkgName, "invalid package name _")
 			}
 			fallthrough
 
@@ -233,7 +230,7 @@
 			check.files = append(check.files, file)
 
 		default:
-			check.errorf(file.Package, "package %s; expected %s", name, pkg.name)
+			check.errorf(atPos(file.Package), _MismatchedPkgName, "package %s; expected %s", name, pkg.name)
 			// ignore this file
 		}
 	}
@@ -265,49 +262,24 @@
 
 	defer check.handleBailout(&err)
 
-	print := func(msg string) {
-		if check.conf.Trace {
-			fmt.Println(msg)
-		}
-	}
-
-	print("=== check consistent use of () or [] for type parameters ===")
-	if len(files) > 0 {
-		check.useBrackets = files[0].UseBrackets
-		for _, file := range files[1:] {
-			if check.useBrackets != file.UseBrackets {
-				check.errorf(file.Package, "inconsistent use of () or [] for type parameters")
-				return // cannot type-check properly
-			}
-		}
-	}
-
-	print("== initFiles ==")
 	check.initFiles(files)
 
-	print("== collectObjects ==")
 	check.collectObjects()
 
-	print("== packageObjects ==")
 	check.packageObjects()
 
-	print("== processDelayed ==")
 	check.processDelayed(0) // incl. all functions
 	check.processFinals()
 
-	print("== initOrder ==")
 	check.initOrder()
 
 	if !check.conf.DisableUnusedImportCheck {
-		print("== unusedImports ==")
 		check.unusedImports()
 	}
 
-	print("== recordUntyped ==")
 	check.recordUntyped()
 
 	if check.Info != nil {
-		print("== sanitizeInfo ==")
 		sanitizeInfo(check.Info)
 	}
 
diff --git a/src/go/types/check_test.go b/src/go/types/check_test.go
index 08fc784..c6a8c3b 100644
--- a/src/go/types/check_test.go
+++ b/src/go/types/check_test.go
@@ -67,11 +67,11 @@
 	return
 }
 
-func parseFiles(t *testing.T, filenames []string) ([]*ast.File, []error) {
+func parseFiles(t *testing.T, filenames []string, mode parser.Mode) ([]*ast.File, []error) {
 	var files []*ast.File
 	var errlist []error
 	for _, filename := range filenames {
-		file, err := parser.ParseFile(fset, filename, nil, parser.AllErrors|parser.UnifiedParamLists)
+		file, err := parser.ParseFile(fset, filename, nil, mode)
 		if file == nil {
 			t.Fatalf("%s: %s", filename, err)
 		}
@@ -189,9 +189,18 @@
 	}
 }
 
-func checkFiles(t *testing.T, sources []string, trace bool) {
+func checkFiles(t *testing.T, sources []string) {
+	if len(sources) == 0 {
+		t.Fatal("no source files")
+	}
+
+	mode := parser.AllErrors
+	if strings.HasSuffix(sources[0], ".go2") {
+		mode |= parser.ParseTypeParams
+	}
+
 	// parse files and collect parser errors
-	files, errlist := parseFiles(t, sources)
+	files, errlist := parseFiles(t, sources, mode)
 
 	pkgName := "<no package>"
 	if len(files) > 0 {
@@ -207,16 +216,14 @@
 
 	// typecheck and collect typechecker errors
 	var conf Config
-	conf.AcceptMethodTypeParams = true
-	conf.InferFromConstraints = true
+
 	// special case for importC.src
 	if len(sources) == 1 && strings.HasSuffix(sources[0], "importC.src") {
 		conf.FakeImportC = true
 	}
-	conf.Trace = trace
-	// We don't use importer.Default() below so we can eventually
-	// get testdata/map.go2 to import chans (still to be fixed).
-	conf.Importer = importer.ForCompiler(fset, "source", nil)
+	// TODO(rFindley) we may need to use the source importer when adding generics
+	// tests.
+	conf.Importer = importer.Default()
 	conf.Error = func(err error) {
 		if *haltOnError {
 			defer panic(err)
@@ -237,6 +244,17 @@
 		return
 	}
 
+	for _, err := range errlist {
+		err, ok := err.(Error)
+		if !ok {
+			continue
+		}
+		code := readCode(err)
+		if code == 0 {
+			t.Errorf("missing error code: %v", err)
+		}
+	}
+
 	// match and eliminate errors;
 	// we are expecting the following errors
 	errmap := errMap(t, pkgName, files)
@@ -260,7 +278,7 @@
 	}
 	testenv.MustHaveGoBuild(t)
 	DefPredeclaredTestFuncs()
-	checkFiles(t, strings.Split(*testFiles, " "), testing.Verbose())
+	checkFiles(t, strings.Split(*testFiles, " "))
 }
 
 func TestTestdata(t *testing.T)  { DefPredeclaredTestFuncs(); testDir(t, "testdata") }
@@ -276,20 +294,18 @@
 		return
 	}
 
-	for count, fi := range fis {
+	for _, fi := range fis {
 		path := filepath.Join(dir, fi.Name())
 
 		// if fi is a directory, its files make up a single package
+		var files []string
 		if fi.IsDir() {
-			if testing.Verbose() {
-				fmt.Printf("%3d %s\n", count, path)
-			}
 			fis, err := ioutil.ReadDir(path)
 			if err != nil {
 				t.Error(err)
 				continue
 			}
-			files := make([]string, len(fis))
+			files = make([]string, len(fis))
 			for i, fi := range fis {
 				// if fi is a directory, checkFiles below will complain
 				files[i] = filepath.Join(path, fi.Name())
@@ -297,14 +313,11 @@
 					fmt.Printf("\t%s\n", files[i])
 				}
 			}
-			checkFiles(t, files, false)
-			continue
+		} else {
+			files = []string{path}
 		}
-
-		// otherwise, fi is a stand-alone file
-		if testing.Verbose() {
-			fmt.Printf("%3d %s\n", count, path)
-		}
-		checkFiles(t, []string{path}, false)
+		t.Run(filepath.Base(path), func(t *testing.T) {
+			checkFiles(t, files)
+		})
 	}
 }
diff --git a/src/go/types/conversions.go b/src/go/types/conversions.go
index 9d9e9d7..0756b57 100644
--- a/src/go/types/conversions.go
+++ b/src/go/types/conversions.go
@@ -38,7 +38,7 @@
 	}
 
 	if !ok {
-		check.errorf(x.pos(), "cannot convert %s to %s", x, T)
+		check.errorf(x, _InvalidConversion, "cannot convert %s to %s", x, T)
 		x.mode = invalid
 		return
 	}
@@ -81,7 +81,7 @@
 // exported API call, i.e., when all methods have been type-checked.
 func (x *operand) convertibleTo(check *Checker, T Type) bool {
 	// "x is assignable to T"
-	if x.assignableTo(check, T, nil) {
+	if ok, _ := x.assignableTo(check, T, nil); ok {
 		return true
 	}
 
diff --git a/src/go/types/decl.go b/src/go/types/decl.go
index 1292ee2..bd2c546 100644
--- a/src/go/types/decl.go
+++ b/src/go/types/decl.go
@@ -16,7 +16,7 @@
 		// We use "other" rather than "previous" here because
 		// the first declaration seen may not be textually
 		// earlier in the source.
-		check.errorf(pos, "\tother declaration of %s", obj.Name()) // secondary error, \t indented
+		check.errorf(obj, _DuplicateDecl, "\tother declaration of %s", obj.Name()) // secondary error, \t indented
 	}
 }
 
@@ -27,7 +27,7 @@
 	// binding."
 	if obj.Name() != "_" {
 		if alt := scope.Insert(obj); alt != nil {
-			check.errorf(obj.Pos(), "%s redeclared in this block", obj.Name())
+			check.errorf(obj, _DuplicateDecl, "%s redeclared in this block", obj.Name())
 			check.reportAltDecl(alt)
 			return
 		}
@@ -53,7 +53,7 @@
 // objDecl type-checks the declaration of obj in its respective (file) context.
 // For the meaning of def, see Checker.definedType, in typexpr.go.
 func (check *Checker) objDecl(obj Object, def *Named) {
-	if check.conf.Trace && obj.Type() == nil {
+	if trace && obj.Type() == nil {
 		if check.indent == 0 {
 			fmt.Println() // empty line between top-level objects for readability
 		}
@@ -187,7 +187,7 @@
 	switch obj := obj.(type) {
 	case *Const:
 		check.decl = d // new package-level const decl
-		check.constDecl(obj, d.vtyp, d.init)
+		check.constDecl(obj, d.vtyp, d.init, d.inherited)
 	case *Var:
 		check.decl = d // new package-level var decl
 		check.varDecl(obj, d.lhs, d.vtyp, d.init)
@@ -253,7 +253,7 @@
 		}
 	}
 
-	if check.conf.Trace {
+	if trace {
 		check.trace(obj.Pos(), "## cycle detected: objPath = %s->%s (len = %d)", pathString(cycle), obj.Name(), len(cycle))
 		check.trace(obj.Pos(), "## cycle contains: %d values, %d type definitions", nval, ndef)
 		defer func() {
@@ -323,7 +323,7 @@
 		}
 
 		// don't report a 2nd error if we already know the type is invalid
-		// (e.g., if a cycle was detected earlier, via Checker.underlying).
+		// (e.g., if a cycle was detected earlier, via under).
 		if t.underlying == Typ[Invalid] {
 			t.info = invalid
 			return invalid
@@ -364,16 +364,16 @@
 	//           cycle? That would be more consistent with other error messages.
 	i := firstInSrc(cycle)
 	obj := cycle[i]
-	check.errorf(obj.Pos(), "illegal cycle in declaration of %s", obj.Name())
+	check.errorf(obj, _InvalidDeclCycle, "illegal cycle in declaration of %s", obj.Name())
 	for range cycle {
-		check.errorf(obj.Pos(), "\t%s refers to", obj.Name()) // secondary error, \t indented
+		check.errorf(obj, _InvalidDeclCycle, "\t%s refers to", obj.Name()) // secondary error, \t indented
 		i++
 		if i >= len(cycle) {
 			i = 0
 		}
 		obj = cycle[i]
 	}
-	check.errorf(obj.Pos(), "\t%s", obj.Name())
+	check.errorf(obj, _InvalidDeclCycle, "\t%s", obj.Name())
 }
 
 // firstInSrc reports the index of the object with the "smallest"
@@ -388,12 +388,90 @@
 	return fst
 }
 
-func (check *Checker) constDecl(obj *Const, typ, init ast.Expr) {
+type (
+	decl interface {
+		node() ast.Node
+	}
+
+	importDecl struct{ spec *ast.ImportSpec }
+	constDecl  struct {
+		spec      *ast.ValueSpec
+		iota      int
+		typ       ast.Expr
+		init      []ast.Expr
+		inherited bool
+	}
+	varDecl  struct{ spec *ast.ValueSpec }
+	typeDecl struct{ spec *ast.TypeSpec }
+	funcDecl struct{ decl *ast.FuncDecl }
+)
+
+func (d importDecl) node() ast.Node { return d.spec }
+func (d constDecl) node() ast.Node  { return d.spec }
+func (d varDecl) node() ast.Node    { return d.spec }
+func (d typeDecl) node() ast.Node   { return d.spec }
+func (d funcDecl) node() ast.Node   { return d.decl }
+
+func (check *Checker) walkDecls(decls []ast.Decl, f func(decl)) {
+	for _, d := range decls {
+		check.walkDecl(d, f)
+	}
+}
+
+func (check *Checker) walkDecl(d ast.Decl, f func(decl)) {
+	switch d := d.(type) {
+	case *ast.BadDecl:
+		// ignore
+	case *ast.GenDecl:
+		var last *ast.ValueSpec // last ValueSpec with type or init exprs seen
+		for iota, s := range d.Specs {
+			switch s := s.(type) {
+			case *ast.ImportSpec:
+				f(importDecl{s})
+			case *ast.ValueSpec:
+				switch d.Tok {
+				case token.CONST:
+					// determine which initialization expressions to use
+					inherited := true
+					switch {
+					case s.Type != nil || len(s.Values) > 0:
+						last = s
+						inherited = false
+					case last == nil:
+						last = new(ast.ValueSpec) // make sure last exists
+						inherited = false
+					}
+					check.arityMatch(s, last)
+					f(constDecl{spec: s, iota: iota, typ: last.Type, init: last.Values, inherited: inherited})
+				case token.VAR:
+					check.arityMatch(s, nil)
+					f(varDecl{s})
+				default:
+					check.invalidAST(s, "invalid token %s", d.Tok)
+				}
+			case *ast.TypeSpec:
+				f(typeDecl{s})
+			default:
+				check.invalidAST(s, "unknown ast.Spec node %T", s)
+			}
+		}
+	case *ast.FuncDecl:
+		f(funcDecl{d})
+	default:
+		check.invalidAST(d, "unknown ast.Decl node %T", d)
+	}
+}
+
+func (check *Checker) constDecl(obj *Const, typ, init ast.Expr, inherited bool) {
 	assert(obj.typ == nil)
 
 	// use the correct value of iota
-	defer func(iota constant.Value) { check.iota = iota }(check.iota)
+	defer func(iota constant.Value, errpos positioner) {
+		check.iota = iota
+		check.errpos = errpos
+	}(check.iota, check.errpos)
 	check.iota = obj.val
+	check.errpos = nil
 
 	// provide valid constant value under all circumstances
 	obj.val = constant.MakeUnknown()
@@ -405,7 +483,7 @@
 			// don't report an error if the type is an invalid C (defined) type
 			// (issue #22090)
 			if under(t) != Typ[Invalid] {
-				check.errorf(typ.Pos(), "invalid constant type %s", t)
+				check.errorf(typ, _InvalidConstType, "invalid constant type %s", t)
 			}
 			obj.typ = Typ[Invalid]
 			return
@@ -416,6 +494,15 @@
 	// check initialization
 	var x operand
 	if init != nil {
+		if inherited {
+			// The initialization expression is inherited from a previous
+			// constant declaration, and (error) positions refer to that
+			// expression and not the current constant declaration. Use
+			// the constant identifier position for any errors during
+			// init expression evaluation since that is all we have
+			// (see issues #42991, #42992).
+			check.errpos = atPos(obj.pos)
+		}
 		check.expr(&x, init)
 	}
 	check.initConst(obj, &x)
@@ -520,6 +607,8 @@
 
 		if i, ok := seen[n]; ok {
 			// cycle
+			// TODO(rFindley) revert this to a method on Checker. Having a possibly
+			// nil Checker on Named and TypeParam is too subtle.
 			if n0.check != nil {
 				n0.check.cycleError(path[i:])
 			}
@@ -559,7 +648,7 @@
 	if alias && tdecl.TParams != nil {
 		// The parser will ensure this but we may still get an invalid AST.
 		// Complain and continue as regular type definition.
-		check.errorf(tdecl.Assign, "generic type cannot be alias")
+		check.error(atPos(tdecl.Assign), 0, "generic type cannot be alias")
 		alias = false
 	}
 
@@ -631,19 +720,11 @@
 			goto next
 		}
 
-		// If the type bound expects exactly one type argument, permit leaving
-		// it away and use the corresponding type parameter as implicit argument.
-		// This allows us to write (type p b(p), q b(q), r b(r)) as (type p, q, r b).
-		// Enabled if enableImplicitTParam is set.
-		const enableImplicitTParam = false
-
 		// The predeclared identifier "any" is visible only as a constraint
 		// in a type parameter list. Look for it before general constraint
 		// resolution.
 		if tident, _ := f.Type.(*ast.Ident); tident != nil && tident.Name == "any" && check.lookup("any") == nil {
 			bound = universeAny
-		} else if enableImplicitTParam {
-			bound = check.anyType(f.Type)
 		} else {
 			bound = check.typ(f.Type)
 		}
@@ -654,47 +735,12 @@
 		//           type C(type T C) interface {}
 		//           (issue #39724).
 		if _, ok := under(bound).(*Interface); ok {
-			if enableImplicitTParam && isGeneric(bound) {
-				base := bound.(*Named) // only a *Named type can be generic
-				if len(base.tparams) != 1 {
-					check.errorf(f.Type.Pos(), "cannot use generic type %s without instantiation (more than one type parameter)", bound)
-					goto next
-				}
-				// We have exactly one type parameter.
-				// "Manually" instantiate the bound with each type
-				// parameter the bound applies to.
-				// TODO(gri) this code (in more general form) is also in
-				// checker.typInternal for the *ast.CallExpr case. Factor?
-				for i, name := range f.Names {
-					typ := new(instance)
-					typ.check = check
-					typ.pos = f.Type.Pos()
-					typ.base = base
-					typ.targs = []Type{tparams[index+i].typ}
-					typ.poslist = []token.Pos{name.Pos()}
-					// Make sure we check instantiation works at least once
-					// and that the resulting type is valid.
-					check.atEnd(func() {
-						check.validType(typ.expand(), nil)
-					})
-					// Set bound for each type parameter and record type.
-					setBoundAt(index+i, typ)
-					// We don't have a mechanism to record multiple different types
-					// for a single type bound expression. Just do it for the first
-					// type parameter for now.
-					// TODO(gri) investigate what we need to do here
-					if i == 0 {
-						check.recordTypeAndValue(f.Type, typexpr, typ, nil)
-					}
-				}
-				goto next
-			}
 			// Otherwise, set the bound for each type parameter.
-			for i, _ := range f.Names {
+			for i := range f.Names {
 				setBoundAt(index+i, bound)
 			}
 		} else if bound != Typ[Invalid] {
-			check.errorf(f.Type.Pos(), "%s is not an interface", bound)
+			check.errorf(f.Type, _Todo, "%s is not an interface", bound)
 		}
 
 	next:
@@ -706,19 +752,13 @@
 
 func (check *Checker) declareTypeParams(tparams []*TypeName, names []*ast.Ident) []*TypeName {
 	for _, name := range names {
-		var ptr bool
-		nstr := name.Name
-		if len(nstr) > 0 && nstr[0] == '*' {
-			ptr = true
-			nstr = nstr[1:]
-		}
-		tpar := NewTypeName(name.Pos(), check.pkg, nstr, nil)
-		check.NewTypeParam(ptr, tpar, len(tparams), &emptyInterface) // assigns type to tpar as a side-effect
-		check.declare(check.scope, name, tpar, check.scope.pos)      // TODO(gri) check scope position
+		tpar := NewTypeName(name.Pos(), check.pkg, name.Name, nil)
+		check.NewTypeParam(tpar, len(tparams), &emptyInterface) // assigns type to tpar as a side-effect
+		check.declare(check.scope, name, tpar, check.scope.pos) // TODO(gri) check scope position
 		tparams = append(tparams, tpar)
 	}
 
-	if check.conf.Trace && len(names) > 0 {
+	if trace && len(names) > 0 {
 		check.trace(names[0].Pos(), "type params = %v", tparams[len(tparams)-len(names):])
 	}
 
@@ -769,9 +809,9 @@
 		if alt := mset.insert(m); alt != nil {
 			switch alt.(type) {
 			case *Var:
-				check.errorf(m.pos, "field and method with the same name %s", m.name)
+				check.errorf(m, _DuplicateFieldAndMethod, "field and method with the same name %s", m.name)
 			case *Func:
-				check.errorf(m.pos, "method %s already declared for %s", m.name, obj)
+				check.errorf(m, _DuplicateMethod, "method %s already declared for %s", m.name, obj)
 			default:
 				unreachable()
 			}
@@ -815,133 +855,105 @@
 	}
 }
 
-func (check *Checker) declStmt(decl ast.Decl) {
+func (check *Checker) declStmt(d ast.Decl) {
 	pkg := check.pkg
 
-	switch d := decl.(type) {
-	case *ast.BadDecl:
-		// ignore
+	check.walkDecl(d, func(d decl) {
+		switch d := d.(type) {
+		case constDecl:
+			top := len(check.delayed)
 
-	case *ast.GenDecl:
-		var last *ast.ValueSpec // last ValueSpec with type or init exprs seen
-		for iota, spec := range d.Specs {
-			switch s := spec.(type) {
-			case *ast.ValueSpec:
-				switch d.Tok {
-				case token.CONST:
-					top := len(check.delayed)
+			// declare all constants
+			lhs := make([]*Const, len(d.spec.Names))
+			for i, name := range d.spec.Names {
+				obj := NewConst(name.Pos(), pkg, name.Name, nil, constant.MakeInt64(int64(d.iota)))
+				lhs[i] = obj
 
-					// determine which init exprs to use
-					switch {
-					case s.Type != nil || len(s.Values) > 0:
-						last = s
-					case last == nil:
-						last = new(ast.ValueSpec) // make sure last exists
-					}
-
-					// declare all constants
-					lhs := make([]*Const, len(s.Names))
-					for i, name := range s.Names {
-						obj := NewConst(name.Pos(), pkg, name.Name, nil, constant.MakeInt64(int64(iota)))
-						lhs[i] = obj
-
-						var init ast.Expr
-						if i < len(last.Values) {
-							init = last.Values[i]
-						}
-
-						check.constDecl(obj, last.Type, init)
-					}
-
-					check.arityMatch(s, last)
-
-					// process function literals in init expressions before scope changes
-					check.processDelayed(top)
-
-					// spec: "The scope of a constant or variable identifier declared
-					// inside a function begins at the end of the ConstSpec or VarSpec
-					// (ShortVarDecl for short variable declarations) and ends at the
-					// end of the innermost containing block."
-					scopePos := s.End()
-					for i, name := range s.Names {
-						check.declare(check.scope, name, lhs[i], scopePos)
-					}
-
-				case token.VAR:
-					top := len(check.delayed)
-
-					lhs0 := make([]*Var, len(s.Names))
-					for i, name := range s.Names {
-						lhs0[i] = NewVar(name.Pos(), pkg, name.Name, nil)
-					}
-
-					// initialize all variables
-					for i, obj := range lhs0 {
-						var lhs []*Var
-						var init ast.Expr
-						switch len(s.Values) {
-						case len(s.Names):
-							// lhs and rhs match
-							init = s.Values[i]
-						case 1:
-							// rhs is expected to be a multi-valued expression
-							lhs = lhs0
-							init = s.Values[0]
-						default:
-							if i < len(s.Values) {
-								init = s.Values[i]
-							}
-						}
-						check.varDecl(obj, lhs, s.Type, init)
-						if len(s.Values) == 1 {
-							// If we have a single lhs variable we are done either way.
-							// If we have a single rhs expression, it must be a multi-
-							// valued expression, in which case handling the first lhs
-							// variable will cause all lhs variables to have a type
-							// assigned, and we are done as well.
-							if debug {
-								for _, obj := range lhs0 {
-									assert(obj.typ != nil)
-								}
-							}
-							break
-						}
-					}
-
-					check.arityMatch(s, nil)
-
-					// process function literals in init expressions before scope changes
-					check.processDelayed(top)
-
-					// declare all variables
-					// (only at this point are the variable scopes (parents) set)
-					scopePos := s.End() // see constant declarations
-					for i, name := range s.Names {
-						// see constant declarations
-						check.declare(check.scope, name, lhs0[i], scopePos)
-					}
-
-				default:
-					check.invalidAST(s.Pos(), "invalid token %s", d.Tok)
+				var init ast.Expr
+				if i < len(d.init) {
+					init = d.init[i]
 				}
 
-			case *ast.TypeSpec:
-				obj := NewTypeName(s.Name.Pos(), pkg, s.Name.Name, nil)
-				// spec: "The scope of a type identifier declared inside a function
-				// begins at the identifier in the TypeSpec and ends at the end of
-				// the innermost containing block."
-				scopePos := s.Name.Pos()
-				check.declare(check.scope, s.Name, obj, scopePos)
-				// mark and unmark type before calling typeDecl; its type is still nil (see Checker.objDecl)
-				obj.setColor(grey + color(check.push(obj)))
-				check.typeDecl(obj, s, nil)
-				check.pop().setColor(black)
-			default:
-				check.invalidAST(s.Pos(), "const, type, or var declaration expected")
+				check.constDecl(obj, d.typ, init, d.inherited)
 			}
-		}
 
-	default:
-		check.invalidAST(d.Pos(), "unknown ast.Decl node %T", d)
-	}
+			// process function literals in init expressions before scope changes
+			check.processDelayed(top)
+
+			// spec: "The scope of a constant or variable identifier declared
+			// inside a function begins at the end of the ConstSpec or VarSpec
+			// (ShortVarDecl for short variable declarations) and ends at the
+			// end of the innermost containing block."
+			scopePos := d.spec.End()
+			for i, name := range d.spec.Names {
+				check.declare(check.scope, name, lhs[i], scopePos)
+			}
+
+		case varDecl:
+			top := len(check.delayed)
+
+			lhs0 := make([]*Var, len(d.spec.Names))
+			for i, name := range d.spec.Names {
+				lhs0[i] = NewVar(name.Pos(), pkg, name.Name, nil)
+			}
+
+			// initialize all variables
+			for i, obj := range lhs0 {
+				var lhs []*Var
+				var init ast.Expr
+				switch len(d.spec.Values) {
+				case len(d.spec.Names):
+					// lhs and rhs match
+					init = d.spec.Values[i]
+				case 1:
+					// rhs is expected to be a multi-valued expression
+					lhs = lhs0
+					init = d.spec.Values[0]
+				default:
+					if i < len(d.spec.Values) {
+						init = d.spec.Values[i]
+					}
+				}
+				check.varDecl(obj, lhs, d.spec.Type, init)
+				if len(d.spec.Values) == 1 {
+					// If we have a single lhs variable we are done either way.
+					// If we have a single rhs expression, it must be a multi-
+					// valued expression, in which case handling the first lhs
+					// variable will cause all lhs variables to have a type
+					// assigned, and we are done as well.
+					if debug {
+						for _, obj := range lhs0 {
+							assert(obj.typ != nil)
+						}
+					}
+					break
+				}
+			}
+
+			// process function literals in init expressions before scope changes
+			check.processDelayed(top)
+
+			// declare all variables
+			// (only at this point are the variable scopes (parents) set)
+			scopePos := d.spec.End() // see constant declarations
+			for i, name := range d.spec.Names {
+				// see constant declarations
+				check.declare(check.scope, name, lhs0[i], scopePos)
+			}
+
+		case typeDecl:
+			obj := NewTypeName(d.spec.Name.Pos(), pkg, d.spec.Name.Name, nil)
+			// spec: "The scope of a type identifier declared inside a function
+			// begins at the identifier in the TypeSpec and ends at the end of
+			// the innermost containing block."
+			scopePos := d.spec.Name.Pos()
+			check.declare(check.scope, d.spec.Name, obj, scopePos)
+			// mark and unmark type before calling typeDecl; its type is still nil (see Checker.objDecl)
+			obj.setColor(grey + color(check.push(obj)))
+			check.typeDecl(obj, d.spec, nil)
+			check.pop().setColor(black)
+		default:
+			check.invalidAST(d.node(), "unknown ast.Decl node %T", d.node())
+		}
+	})
 }
diff --git a/src/go/types/errorcodes.go b/src/go/types/errorcodes.go
index e4c8311..7e62091 100644
--- a/src/go/types/errorcodes.go
+++ b/src/go/types/errorcodes.go
@@ -753,52 +753,12 @@
 	_NonVariadicDotDotDot
 
 	// _MisplacedDotDotDot occurs when a "..." is used somewhere other than the
-	// final argument to a function call.
+	// final argument in a function declaration.
 	//
 	// Example:
-	//  func printArgs(args ...int) {
-	//  	for _, a := range args {
-	//  		println(a)
-	//  	}
-	//  }
-	//
-	//  func f() {
-	//  	a := []int{1,2,3}
-	//  	printArgs(0, a...)
-	//  }
+	// 	func f(...int, int)
 	_MisplacedDotDotDot
 
-	// _InvalidDotDotDotOperand occurs when a "..." operator is applied to a
-	// single-valued operand.
-	//
-	// Example:
-	//  func printArgs(args ...int) {
-	//  	for _, a := range args {
-	//  		println(a)
-	//  	}
-	//  }
-	//
-	//  func f() {
-	//  	a := 1
-	//  	printArgs(a...)
-	//  }
-	//
-	// Example:
-	//  func args() (int, int) {
-	//  	return 1, 2
-	//  }
-	//
-	//  func printArgs(args ...int) {
-	//  	for _, a := range args {
-	//  		println(a)
-	//  	}
-	//  }
-	//
-	//  func g() {
-	//  	printArgs(args()...)
-	//  }
-	_InvalidDotDotDotOperand
-
 	// _InvalidDotDotDot occurs when a "..." is used in a non-variadic built-in
 	// function.
 	//
@@ -1078,18 +1038,6 @@
 	//  }
 	_InvalidPostDecl
 
-	// _InvalidChanRange occurs when a send-only channel used in a range
-	// expression.
-	//
-	// Example:
-	//  func sum(c chan<- int) {
-	//  	s := 0
-	//  	for i := range c {
-	//  		s += i
-	//  	}
-	//  }
-	_InvalidChanRange
-
 	// _InvalidIterVar occurs when two iteration variables are used while ranging
 	// over a channel.
 	//
@@ -1207,6 +1155,16 @@
 	//  }
 	_InvalidTypeSwitch
 
+	// _InvalidExprSwitch occurs when a switch expression is not comparable.
+	//
+	// Example:
+	//  func _() {
+	//  	var a struct{ _ func() }
+	//  	switch a /* ERROR cannot switch on a */ {
+	//  	}
+	//  }
+	_InvalidExprSwitch
+
 	/* control flow > select */
 
 	// _InvalidSelectCase occurs when a select case is not a channel send or
@@ -1353,4 +1311,8 @@
 	//  	return i
 	//  }
 	_InvalidGo
+
+	// _Todo is a placeholder for error codes that have not been decided.
+	// TODO(rFindley) remove this error code after deciding on errors for generics code.
+	_Todo
 )
diff --git a/src/go/types/errorcodes_test.go b/src/go/types/errorcodes_test.go
new file mode 100644
index 0000000..5da1cda
--- /dev/null
+++ b/src/go/types/errorcodes_test.go
@@ -0,0 +1,197 @@
+// Copyright 2020 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_test
+
+import (
+	"fmt"
+	"go/ast"
+	"go/constant"
+	"go/importer"
+	"go/parser"
+	"go/token"
+	"reflect"
+	"strings"
+	"testing"
+
+	. "go/types"
+)
+
+func TestErrorCodeExamples(t *testing.T) {
+	walkCodes(t, func(name string, value int, spec *ast.ValueSpec) {
+		t.Run(name, func(t *testing.T) {
+			doc := spec.Doc.Text()
+			examples := strings.Split(doc, "Example:")
+			for i := 1; i < len(examples); i++ {
+				example := examples[i]
+				err := checkExample(t, example)
+				if err == nil {
+					t.Fatalf("no error in example #%d", i)
+				}
+				typerr, ok := err.(Error)
+				if !ok {
+					t.Fatalf("not a types.Error: %v", err)
+				}
+				if got := readCode(typerr); got != value {
+					t.Errorf("%s: example #%d returned code %d (%s), want %d", name, i, got, err, value)
+				}
+			}
+		})
+	})
+}
+
+func walkCodes(t *testing.T, f func(string, int, *ast.ValueSpec)) {
+	t.Helper()
+	fset := token.NewFileSet()
+	files, err := pkgFiles(fset, ".", parser.ParseComments) // from self_test.go
+	if err != nil {
+		t.Fatal(err)
+	}
+	conf := Config{Importer: importer.Default()}
+	info := &Info{
+		Types: make(map[ast.Expr]TypeAndValue),
+		Defs:  make(map[*ast.Ident]Object),
+		Uses:  make(map[*ast.Ident]Object),
+	}
+	_, err = conf.Check("types", fset, files, info)
+	if err != nil {
+		t.Fatal(err)
+	}
+	for _, file := range files {
+		for _, decl := range file.Decls {
+			decl, ok := decl.(*ast.GenDecl)
+			if !ok || decl.Tok != token.CONST {
+				continue
+			}
+			for _, spec := range decl.Specs {
+				spec, ok := spec.(*ast.ValueSpec)
+				if !ok || len(spec.Names) == 0 {
+					continue
+				}
+				obj := info.ObjectOf(spec.Names[0])
+				if named, ok := obj.Type().(*Named); ok && named.Obj().Name() == "errorCode" {
+					if len(spec.Names) != 1 {
+						t.Fatalf("bad Code declaration for %q: got %d names, want exactly 1", spec.Names[0].Name, len(spec.Names))
+					}
+					codename := spec.Names[0].Name
+					value := int(constant.Val(obj.(*Const).Val()).(int64))
+					f(codename, value, spec)
+				}
+			}
+		}
+	}
+}
+
+func readCode(err Error) int {
+	v := reflect.ValueOf(err)
+	return int(v.FieldByName("go116code").Int())
+}
+
+func checkExample(t *testing.T, example string) error {
+	t.Helper()
+	fset := token.NewFileSet()
+	src := fmt.Sprintf("package p\n\n%s", example)
+	file, err := parser.ParseFile(fset, "example.go", src, 0)
+	if err != nil {
+		t.Fatal(err)
+	}
+	conf := Config{
+		FakeImportC: true,
+		Importer:    importer.Default(),
+	}
+	_, err = conf.Check("example", fset, []*ast.File{file}, nil)
+	return err
+}
+
+func TestErrorCodeStyle(t *testing.T) {
+	// The set of error codes is large and intended to be self-documenting, so
+	// this test enforces some style conventions.
+	forbiddenInIdent := []string{
+		// use invalid instead
+		"illegal",
+		// words with a common short-form
+		"argument",
+		"assertion",
+		"assignment",
+		"boolean",
+		"channel",
+		"condition",
+		"declaration",
+		"expression",
+		"function",
+		"initial", // use init for initializer, initialization, etc.
+		"integer",
+		"interface",
+		"iterat", // use iter for iterator, iteration, etc.
+		"literal",
+		"operation",
+		"package",
+		"pointer",
+		"receiver",
+		"signature",
+		"statement",
+		"variable",
+	}
+	forbiddenInComment := []string{
+		// lhs and rhs should be spelled-out.
+		"lhs", "rhs",
+		// builtin should be hyphenated.
+		"builtin",
+		// Use dot-dot-dot.
+		"ellipsis",
+	}
+	nameHist := make(map[int]int)
+	longestName := ""
+	maxValue := 0
+
+	walkCodes(t, func(name string, value int, spec *ast.ValueSpec) {
+		if name == "_" {
+			return
+		}
+		nameHist[len(name)]++
+		if value > maxValue {
+			maxValue = value
+		}
+		if len(name) > len(longestName) {
+			longestName = name
+		}
+		if token.IsExported(name) {
+			// This is an experimental API, and errorCode values should not be
+			// exported.
+			t.Errorf("%q is exported", name)
+		}
+		if name[0] != '_' || !token.IsExported(name[1:]) {
+			t.Errorf("%q should start with _, followed by an exported identifier", name)
+		}
+		lower := strings.ToLower(name)
+		for _, bad := range forbiddenInIdent {
+			if strings.Contains(lower, bad) {
+				t.Errorf("%q contains forbidden word %q", name, bad)
+			}
+		}
+		doc := spec.Doc.Text()
+		if !strings.HasPrefix(doc, name) {
+			t.Errorf("doc for %q does not start with identifier", name)
+		}
+		lowerComment := strings.ToLower(strings.TrimPrefix(doc, name))
+		for _, bad := range forbiddenInComment {
+			if strings.Contains(lowerComment, bad) {
+				t.Errorf("doc for %q contains forbidden word %q", name, bad)
+			}
+		}
+	})
+
+	if testing.Verbose() {
+		var totChars, totCount int
+		for chars, count := range nameHist {
+			totChars += chars * count
+			totCount += count
+		}
+		avg := float64(totChars) / float64(totCount)
+		fmt.Println()
+		fmt.Printf("%d error codes\n", totCount)
+		fmt.Printf("average length: %.2f chars\n", avg)
+		fmt.Printf("max length: %d (%s)\n", len(longestName), longestName)
+	}
+}
diff --git a/src/go/types/errors.go b/src/go/types/errors.go
index 92ba8de..a956256 100644
--- a/src/go/types/errors.go
+++ b/src/go/types/errors.go
@@ -7,6 +7,7 @@
 package types
 
 import (
+	"errors"
 	"fmt"
 	"go/ast"
 	"go/token"
@@ -72,22 +73,48 @@
 	fmt.Println(check.sprintf(format, args...))
 }
 
-func (check *Checker) err(pos token.Pos, msg string, soft bool) {
+func (check *Checker) err(err error) {
+	if err == nil {
+		return
+	}
+	var e Error
+	isInternal := errors.As(err, &e)
 	// Cheap trick: Don't report errors with messages containing
 	// "invalid operand" or "invalid type" as those tend to be
 	// follow-on errors which don't add useful information. Only
 	// exclude them if these strings are not at the beginning,
 	// and only if we have at least one error already reported.
-	if check.firstErr != nil && (strings.Index(msg, "invalid operand") > 0 || strings.Index(msg, "invalid type") > 0) {
+	isInvalidErr := isInternal && (strings.Index(e.Msg, "invalid operand") > 0 || strings.Index(e.Msg, "invalid type") > 0)
+	if check.firstErr != nil && isInvalidErr {
 		return
 	}
 
-	err := Error{check.fset, pos, stripAnnotations(msg), msg, soft}
+	if isInternal {
+		e.Msg = stripAnnotations(e.Msg)
+		if check.errpos != nil {
+			// If we have an internal error and the errpos override is set, use it to
+			// augment our error positioning.
+			// TODO(rFindley) we may also want to augment the error message and refer
+			// to the position (pos) in the original expression.
+			span := spanOf(check.errpos)
+			e.Pos = span.pos
+			e.go116start = span.start
+			e.go116end = span.end
+		}
+		err = e
+	}
+
 	if check.firstErr == nil {
 		check.firstErr = err
 	}
 
-	if check.conf.Trace {
+	if trace {
+		pos := e.Pos
+		msg := e.Msg
+		if !isInternal {
+			msg = err.Error()
+			pos = token.NoPos
+		}
 		check.trace(pos, "ERROR: %s", msg)
 	}
 
@@ -98,28 +125,108 @@
 	f(err)
 }
 
-func (check *Checker) error(pos token.Pos, msg string) {
-	check.err(pos, msg, false)
+func (check *Checker) newError(at positioner, code errorCode, soft bool, msg string) error {
+	span := spanOf(at)
+	return Error{
+		Fset:       check.fset,
+		Pos:        span.pos,
+		Msg:        msg,
+		Soft:       soft,
+		go116code:  code,
+		go116start: span.start,
+		go116end:   span.end,
+	}
 }
 
-func (check *Checker) errorf(pos token.Pos, format string, args ...interface{}) {
-	check.err(pos, check.sprintf(format, args...), false)
+// newErrorf creates a new Error, but does not handle it.
+func (check *Checker) newErrorf(at positioner, code errorCode, soft bool, format string, args ...interface{}) error {
+	msg := check.sprintf(format, args...)
+	return check.newError(at, code, soft, msg)
 }
 
-func (check *Checker) softErrorf(pos token.Pos, format string, args ...interface{}) {
-	check.err(pos, check.sprintf(format, args...), true)
+func (check *Checker) error(at positioner, code errorCode, msg string) {
+	check.err(check.newError(at, code, false, msg))
 }
 
-func (check *Checker) invalidAST(pos token.Pos, format string, args ...interface{}) {
-	check.errorf(pos, "invalid AST: "+format, args...)
+func (check *Checker) errorf(at positioner, code errorCode, format string, args ...interface{}) {
+	check.error(at, code, check.sprintf(format, args...))
 }
 
-func (check *Checker) invalidArg(pos token.Pos, format string, args ...interface{}) {
-	check.errorf(pos, "invalid argument: "+format, args...)
+func (check *Checker) softErrorf(at positioner, code errorCode, format string, args ...interface{}) {
+	check.err(check.newErrorf(at, code, true, format, args...))
 }
 
-func (check *Checker) invalidOp(pos token.Pos, format string, args ...interface{}) {
-	check.errorf(pos, "invalid operation: "+format, args...)
+func (check *Checker) invalidAST(at positioner, format string, args ...interface{}) {
+	check.errorf(at, 0, "invalid AST: "+format, args...)
+}
+
+func (check *Checker) invalidArg(at positioner, code errorCode, format string, args ...interface{}) {
+	check.errorf(at, code, "invalid argument: "+format, args...)
+}
+
+func (check *Checker) invalidOp(at positioner, code errorCode, format string, args ...interface{}) {
+	check.errorf(at, code, "invalid operation: "+format, args...)
+}
+
+// The positioner interface is used to extract the position of type-checker
+// errors.
+type positioner interface {
+	Pos() token.Pos
+}
+
+// posSpan holds a position range along with a highlighted position within that
+// range. This is used for positioning errors, with pos by convention being the
+// first position in the source where the error is known to exist, and start
+// and end defining the full span of syntax being considered when the error was
+// detected. Invariant: start <= pos < end || start == pos == end.
+type posSpan struct {
+	start, pos, end token.Pos
+}
+
+func (e posSpan) Pos() token.Pos {
+	return e.pos
+}
+
+// inNode creates a posSpan for the given node.
+// Invariant: node.Pos() <= pos < node.End() (node.End() is the position of the
+// first byte after node within the source).
+func inNode(node ast.Node, pos token.Pos) posSpan {
+	start, end := node.Pos(), node.End()
+	if debug {
+		assert(start <= pos && pos < end)
+	}
+	return posSpan{start, pos, end}
+}
+
+// atPos wraps a token.Pos to implement the positioner interface.
+type atPos token.Pos
+
+func (s atPos) Pos() token.Pos {
+	return token.Pos(s)
+}
+
+// spanOf extracts an error span from the given positioner. By default this is
+// the trivial span starting and ending at pos, but this span is expanded when
+// the argument naturally corresponds to a span of source code.
+func spanOf(at positioner) posSpan {
+	switch x := at.(type) {
+	case nil:
+		panic("internal error: nil")
+	case posSpan:
+		return x
+	case ast.Node:
+		pos := x.Pos()
+		return posSpan{pos, pos, x.End()}
+	case *operand:
+		if x.expr != nil {
+			pos := x.Pos()
+			return posSpan{pos, pos, x.expr.End()}
+		}
+		return posSpan{token.NoPos, token.NoPos, token.NoPos}
+	default:
+		pos := at.Pos()
+		return posSpan{pos, pos, pos}
+	}
 }
 
 // stripAnnotations removes internal (type) annotations from s.
diff --git a/src/go/types/examples/methods.go2 b/src/go/types/examples/methods.go2
index 95ff872..c294627 100644
--- a/src/go/types/examples/methods.go2
+++ b/src/go/types/examples/methods.go2
@@ -39,7 +39,7 @@
 // and usually should be avoided. There are some notable exceptions; e.g.,
 // sometimes it makes sense to use the identifier "copy" which happens to
 // also be the name of a predeclared built-in function.
-func (t T1[int]) m3() { var _ int = 42 /* ERROR cannot convert 42 .* to int */ }
+func (t T1[int]) m3() { var _ int = 42 /* ERROR cannot use 42 .* as int */ }
 
 // The names of the type parameters used in a parameterized receiver
 // type don't have to match the type parameter names in the the declaration
diff --git a/src/go/types/examples/types.go2 b/src/go/types/examples/types.go2
index 9808f9c..5aa624c 100644
--- a/src/go/types/examples/types.go2
+++ b/src/go/types/examples/types.go2
@@ -150,24 +150,12 @@
 // (7/14/2020: See comment above. We probably will revert this generalized ability
 // if we go with [] for type parameters.)
 type _ struct {
-	(int8)
-	(*int16)
-	*(int32)
-	(*(int64))
-	(((*(int))))
-	(*(List[int]))
+	int8
+	*int16
+	*List[int]
 
 	int8 /* ERROR int8 redeclared */
-	int /* ERROR int redeclared */
 	* /* ERROR List redeclared */ List[int]
-
-	( /* ERROR invalid embedded field type */ [10]int)
-	( /* ERROR invalid embedded field type */ []int)
-	( /* ERROR invalid embedded field type */ struct{})
-	( /* ERROR invalid embedded field type */ map[int]string)
-	( /* ERROR invalid embedded field type */ chan<- int)
-	( /* ERROR invalid embedded field type */ interface{})
-	( /* ERROR invalid embedded field type */ func())
 }
 
 // It's possible to declare local types whose underlying types
@@ -275,4 +263,4 @@
 func _() {
 	var _ comparable /* ERROR comparable */
 	var _ C /* ERROR comparable */
-}
\ No newline at end of file
+}
diff --git a/src/go/types/expr.go b/src/go/types/expr.go
index 62e24da..1deda99 100644
--- a/src/go/types/expr.go
+++ b/src/go/types/expr.go
@@ -1,3 +1,4 @@
+// REVIEW INCOMPLETE
 // Copyright 2012 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.
@@ -73,11 +74,11 @@
 func (check *Checker) op(m opPredicates, x *operand, op token.Token) bool {
 	if pred := m[op]; pred != nil {
 		if !pred(x.typ) {
-			check.invalidOp(x.pos(), "operator %s not defined for %s", op, x)
+			check.invalidOp(x, _UndefinedOp, "operator %s not defined for %s", op, x)
 			return false
 		}
 	} else {
-		check.invalidAST(x.pos(), "unknown operator %s", op)
+		check.invalidAST(x, "unknown operator %s", op)
 		return false
 	}
 	return true
@@ -90,7 +91,7 @@
 		// spec: "As an exception to the addressability
 		// requirement x may also be a composite literal."
 		if _, ok := unparen(x.expr).(*ast.CompositeLit); !ok && x.mode != variable {
-			check.invalidOp(x.pos(), "cannot take address of %s", x)
+			check.invalidOp(x, _UnaddressableOperand, "cannot take address of %s", x)
 			x.mode = invalid
 			return
 		}
@@ -101,12 +102,12 @@
 	case token.ARROW:
 		typ := asChan(x.typ)
 		if typ == nil {
-			check.invalidOp(x.pos(), "cannot receive from non-channel %s", x)
+			check.invalidOp(x, _InvalidReceive, "cannot receive from non-channel %s", x)
 			x.mode = invalid
 			return
 		}
 		if typ.dir == SendOnly {
-			check.invalidOp(x.pos(), "cannot receive from send-only channel %s", x)
+			check.invalidOp(x, _InvalidReceive, "cannot receive from send-only channel %s", x)
 			x.mode = invalid
 			return
 		}
@@ -334,11 +335,21 @@
 	return false
 }
 
-// representable checks that a constant operand is representable in the given basic type.
+// representable checks that a constant operand is representable in the given
+// basic type.
 func (check *Checker) representable(x *operand, typ *Basic) {
+	if v, code := check.representation(x, typ); code != 0 {
+		check.invalidConversion(code, x, typ)
+		x.mode = invalid
+	} else if v != nil {
+		x.val = v
+	}
+}
+
+func (check *Checker) representation(x *operand, typ *Basic) (constant.Value, errorCode) {
 	assert(x.mode == constant_)
-	if !representableConst(x.val, check, typ, &x.val) {
-		var msg string
+	v := x.val
+	if !representableConst(x.val, check, typ, &v) {
 		if isNumeric(x.typ) && isNumeric(typ) {
 			// numeric conversion : error msg
 			//
@@ -348,16 +359,25 @@
 			// float   -> float   : overflows
 			//
 			if !isInteger(x.typ) && isInteger(typ) {
-				msg = "%s truncated to %s"
+				return nil, _TruncatedFloat
 			} else {
-				msg = "%s overflows %s"
+				return nil, _NumericOverflow
 			}
-		} else {
-			msg = "cannot convert %s to %s"
 		}
-		check.errorf(x.pos(), msg, x, typ)
-		x.mode = invalid
+		return nil, _InvalidConstVal
 	}
+	return v, 0
+}
+
+func (check *Checker) invalidConversion(code errorCode, x *operand, target Type) {
+	msg := "cannot convert %s to %s"
+	switch code {
+	case _TruncatedFloat:
+		msg = "%s truncated to %s"
+	case _NumericOverflow:
+		msg = "%s overflows %s"
+	}
+	check.errorf(x, code, msg, x, target)
 }
 
 // updateExprType updates the type of x to typ and invokes itself
@@ -463,7 +483,7 @@
 		// We already know from the shift check that it is representable
 		// as an integer if it is a constant.
 		if !isInteger(typ) {
-			check.invalidOp(x.Pos(), "shifted operand %s (type %s) must be integer", x, typ)
+			check.invalidOp(x, _InvalidShiftOperand, "shifted operand %s (type %s) must be integer", x, typ)
 			return
 		}
 		// Even if we have an integer, if the value is a constant we
@@ -493,13 +513,30 @@
 
 // convertUntyped attempts to set the type of an untyped value to the target type.
 func (check *Checker) convertUntyped(x *operand, target Type) {
-	target = expand(target)
-	if x.mode == invalid || isTyped(x.typ) || target == Typ[Invalid] {
+	newType, val, code := check.implicitTypeAndValue(x, target)
+	if code != 0 {
+		check.invalidConversion(code, x, target.Underlying())
+		x.mode = invalid
 		return
 	}
+	if val != nil {
+		x.val = val
+		check.updateExprVal(x.expr, val)
+	}
+	if newType != x.typ {
+		x.typ = newType
+		check.updateExprType(x.expr, newType, false)
+	}
+}
 
-	// TODO(gri) Sloppy code - clean up. This function is central
-	//           to assignment and expression checking.
+// implicitTypeAndValue returns the implicit type of x when used in a context
+// where the target type is expected. If no such implicit conversion is
+// possible, it returns a nil Type.
+func (check *Checker) implicitTypeAndValue(x *operand, target Type) (Type, constant.Value, errorCode) {
+	target = expand(target)
+	if x.mode == invalid || isTyped(x.typ) || target == Typ[Invalid] {
+		return x.typ, nil, 0
+	}
 
 	if isUntyped(target) {
 		// both x and target are untyped
@@ -507,138 +544,98 @@
 		tkind := target.(*Basic).kind
 		if isNumeric(x.typ) && isNumeric(target) {
 			if xkind < tkind {
-				x.typ = target
-				check.updateExprType(x.expr, target, false)
+				return target, nil, 0
 			}
 		} else if xkind != tkind {
-			goto Error
+			return nil, nil, _InvalidUntypedConversion
 		}
-		return
+		return x.typ, nil, 0
 	}
 
-	// In case of a type parameter, conversion must succeed against
-	// all types enumerated by the type parameter bound.
-	// TODO(gri) We should not need this because we have the code
-	// for Sum types in convertUntypedInternal. But at least one
-	// test fails. Investigate.
-	if t := asTypeParam(target); t != nil {
-		types := t.Bound().allTypes
-		if types == nil {
-			goto Error
-		}
-
-		for _, t := range unpack(types) {
-			check.convertUntypedInternal(x, t)
-			if x.mode == invalid {
-				goto Error
-			}
-		}
-
-		// keep nil untyped (was bug #39755)
-		if x.isNil() {
-			target = Typ[UntypedNil]
-		}
-		x.typ = target
-		check.updateExprType(x.expr, target, true) // UntypedNils are final
-		return
-	}
-
-	check.convertUntypedInternal(x, target)
-	return
-
-Error:
-	// TODO(gri) better error message (explain cause)
-	check.errorf(x.pos(), "cannot convert %s to %s", x, target)
-	x.mode = invalid
-}
-
-// convertUntypedInternal should only be called by convertUntyped.
-func (check *Checker) convertUntypedInternal(x *operand, target Type) {
-	assert(isTyped(target))
-
-	// typed target
 	switch t := optype(target).(type) {
 	case *Basic:
 		if x.mode == constant_ {
-			check.representable(x, t)
-			if x.mode == invalid {
-				return
+			v, code := check.representation(x, t)
+			if code != 0 {
+				return nil, nil, code
 			}
-			// expression value may have been rounded - update if needed
-			check.updateExprVal(x.expr, x.val)
-		} else {
-			// Non-constant untyped values may appear as the
-			// result of comparisons (untyped bool), intermediate
-			// (delayed-checked) rhs operands of shifts, and as
-			// the value nil.
-			switch x.typ.(*Basic).kind {
-			case UntypedBool:
-				if !isBoolean(target) {
-					goto Error
-				}
-			case UntypedInt, UntypedRune, UntypedFloat, UntypedComplex:
-				if !isNumeric(target) {
-					goto Error
-				}
-			case UntypedString:
-				// Non-constant untyped string values are not
-				// permitted by the spec and should not occur.
-				unreachable()
-			case UntypedNil:
-				// Unsafe.Pointer is a basic type that includes nil.
-				if !hasNil(target) {
-					goto Error
-				}
-			default:
-				goto Error
+			return target, v, code
+		}
+		// Non-constant untyped values may appear as the
+		// result of comparisons (untyped bool), intermediate
+		// (delayed-checked) rhs operands of shifts, and as
+		// the value nil.
+		switch x.typ.(*Basic).kind {
+		case UntypedBool:
+			if !isBoolean(target) {
+				return nil, nil, _InvalidUntypedConversion
 			}
+		case UntypedInt, UntypedRune, UntypedFloat, UntypedComplex:
+			if !isNumeric(target) {
+				return nil, nil, _InvalidUntypedConversion
+			}
+		case UntypedString:
+			// Non-constant untyped string values are not permitted by the spec and
+			// should not occur during normal typechecking passes, but this path is
+			// reachable via the AssignableTo API.
+			if !isString(target) {
+				return nil, nil, _InvalidUntypedConversion
+			}
+		case UntypedNil:
+			// Unsafe.Pointer is a basic type that includes nil.
+			if !hasNil(target) {
+				return nil, nil, _InvalidUntypedConversion
+			}
+			// TODO(rFindley) return UntypedNil here (golang.org/issues/13061).
+		default:
+			return nil, nil, _InvalidUntypedConversion
 		}
 	case *Sum:
-		t.is(func(t Type) bool {
-			check.convertUntypedInternal(x, t)
-			return x.mode != invalid
+		ok := t.is(func(t Type) bool {
+			target, _, _ := check.implicitTypeAndValue(x, t)
+			return target != nil
 		})
+		if !ok {
+			return nil, nil, _InvalidUntypedConversion
+		}
+		// keep nil untyped (was bug #39755)
+		if x.isNil() {
+			return Typ[UntypedNil], nil, 0
+		}
 	case *Interface:
-		// Update operand types to the default type rather then
-		// the target (interface) type: values must have concrete
-		// dynamic types. If the value is nil, keep it untyped
-		// (this is important for tools such as go vet which need
-		// the dynamic type for argument checking of say, print
+		// Values must have concrete dynamic types. If the value is nil,
+		// keep it untyped (this is important for tools such as go vet which
+		// need the dynamic type for argument checking of say, print
 		// functions)
 		if x.isNil() {
-			target = Typ[UntypedNil]
-		} else {
-			// cannot assign untyped values to non-empty interfaces
-			check.completeInterface(token.NoPos, t)
-			if !t.Empty() {
-				goto Error
-			}
-			target = Default(x.typ)
+			return Typ[UntypedNil], nil, 0
 		}
+		// cannot assign untyped values to non-empty interfaces
+		check.completeInterface(token.NoPos, t)
+		if !t.Empty() {
+			return nil, nil, _InvalidUntypedConversion
+		}
+		return Default(x.typ), nil, 0
 	case *Pointer, *Signature, *Slice, *Map, *Chan:
 		if !x.isNil() {
-			goto Error
+			return nil, nil, _InvalidUntypedConversion
 		}
-		// keep nil untyped - see comment for interfaces, above
-		target = Typ[UntypedNil]
+		// Keep nil untyped - see comment for interfaces, above.
+		return Typ[UntypedNil], nil, 0
 	default:
-		goto Error
+		return nil, nil, _InvalidUntypedConversion
 	}
-
-	x.typ = target
-	check.updateExprType(x.expr, target, true) // UntypedNils are final
-	return
-
-Error:
-	check.errorf(x.pos(), "cannot convert %s to %s", x, target)
-	x.mode = invalid
+	return target, nil, 0
 }
 
 func (check *Checker) comparison(x, y *operand, op token.Token) {
 	// spec: "In any comparison, the first operand must be assignable
 	// to the type of the second operand, or vice versa."
 	err := ""
-	if x.assignableTo(check, y.typ, nil) || y.assignableTo(check, x.typ, nil) {
+	var code errorCode
+	xok, _ := x.assignableTo(check, y.typ, nil)
+	yok, _ := y.assignableTo(check, x.typ, nil)
+	if xok || yok {
 		defined := false
 		switch op {
 		case token.EQL, token.NEQ:
@@ -656,13 +653,15 @@
 				typ = y.typ
 			}
 			err = check.sprintf("operator %s not defined for %s", op, typ)
+			code = _UndefinedOp
 		}
 	} else {
 		err = check.sprintf("mismatched types %s and %s", x.typ, y.typ)
+		code = _MismatchedTypes
 	}
 
 	if err != "" {
-		check.errorf(x.pos(), "cannot compare %s %s %s (%s)", x.expr, op, y.expr, err)
+		check.errorf(x, code, "cannot compare %s %s %s (%s)", x.expr, op, y.expr, err)
 		x.mode = invalid
 		return
 	}
@@ -699,7 +698,7 @@
 		// as an integer. Nothing to do.
 	} else {
 		// shift has no chance
-		check.invalidOp(x.pos(), "shifted operand %s must be integer", x)
+		check.invalidOp(x, _InvalidShiftOperand, "shifted operand %s must be integer", x)
 		x.mode = invalid
 		return
 	}
@@ -716,7 +715,7 @@
 			return
 		}
 	default:
-		check.invalidOp(y.pos(), "shift count %s must be integer", y)
+		check.invalidOp(y, _InvalidShiftCount, "shift count %s must be integer", y)
 		x.mode = invalid
 		return
 	}
@@ -729,7 +728,7 @@
 		yval = constant.ToInt(y.val)
 		assert(yval.Kind() == constant.Int)
 		if constant.Sign(yval) < 0 {
-			check.invalidOp(y.pos(), "negative shift count %s", y)
+			check.invalidOp(y, _InvalidShiftCount, "negative shift count %s", y)
 			x.mode = invalid
 			return
 		}
@@ -741,7 +740,7 @@
 			const shiftBound = 1023 - 1 + 52 // so we can express smallestFloat64
 			s, ok := constant.Uint64Val(yval)
 			if !ok || s > shiftBound {
-				check.invalidOp(y.pos(), "invalid shift count %s", y)
+				check.invalidOp(y, _InvalidShiftCount, "invalid shift count %s", y)
 				x.mode = invalid
 				return
 			}
@@ -798,7 +797,7 @@
 
 	// non-constant shift - lhs must be an integer
 	if !isInteger(x.typ) {
-		check.invalidOp(x.pos(), "shifted operand %s must be integer", x)
+		check.invalidOp(x, _InvalidShiftOperand, "shifted operand %s must be integer", x)
 		x.mode = invalid
 		return
 	}
@@ -828,7 +827,7 @@
 }
 
 // The binary expression e may be nil. It's passed in for better error messages only.
-func (check *Checker) binary(x *operand, e *ast.BinaryExpr, lhs, rhs ast.Expr, op token.Token) {
+func (check *Checker) binary(x *operand, e *ast.BinaryExpr, lhs, rhs ast.Expr, op token.Token, opPos token.Pos) {
 	var y operand
 
 	check.expr(x, lhs)
@@ -867,7 +866,11 @@
 		// only report an error if we have valid types
 		// (otherwise we had an error reported elsewhere already)
 		if x.typ != Typ[Invalid] && y.typ != Typ[Invalid] {
-			check.invalidOp(x.pos(), "mismatched types %s and %s", x.typ, y.typ)
+			var posn positioner = x
+			if e != nil {
+				posn = e
+			}
+			check.invalidOp(posn, _MismatchedTypes, "mismatched types %s and %s", x.typ, y.typ)
 		}
 		x.mode = invalid
 		return
@@ -881,7 +884,7 @@
 	if op == token.QUO || op == token.REM {
 		// check for zero divisor
 		if (x.mode == constant_ || isInteger(x.typ)) && y.mode == constant_ && constant.Sign(y.val) == 0 {
-			check.invalidOp(y.pos(), "division by zero")
+			check.invalidOp(&y, _DivByZero, "division by zero")
 			x.mode = invalid
 			return
 		}
@@ -891,7 +894,7 @@
 			re, im := constant.Real(y.val), constant.Imag(y.val)
 			re2, im2 := constant.BinaryOp(re, token.MUL, re), constant.BinaryOp(im, token.MUL, im)
 			if constant.Sign(re2) == 0 && constant.Sign(im2) == 0 {
-				check.invalidOp(y.pos(), "division by zero")
+				check.invalidOp(&y, _DivByZero, "division by zero")
 				x.mode = invalid
 				return
 			}
@@ -907,6 +910,14 @@
 			op = token.QUO_ASSIGN
 		}
 		x.val = constant.BinaryOp(xval, op, yval)
+		// report error if valid operands lead to an invalid result
+		if xval.Kind() != constant.Unknown && yval.Kind() != constant.Unknown && x.val.Kind() == constant.Unknown {
+			// TODO(gri) We should report exactly what went wrong. At the
+			//           moment we don't have the (go/constant) API for that.
+			//           See also TODO in go/constant/value.go.
+			check.errorf(atPos(opPos), _InvalidConstVal, "constant result is not representable")
+			// TODO(gri) Should we mark operands with unknown values as invalid?
+		}
 		// Typed constants must be representable in
 		// their type after each constant operation.
 		if isTyped(typ) {
@@ -944,7 +955,7 @@
 
 	// the index must be of integer type
 	if !isInteger(x.typ) {
-		check.invalidArg(x.pos(), "index %s must be integer", &x)
+		check.invalidArg(&x, _InvalidIndex, "index %s must be integer", &x)
 		return
 	}
 
@@ -954,13 +965,13 @@
 
 	// a constant index i must be in bounds
 	if constant.Sign(x.val) < 0 {
-		check.invalidArg(x.pos(), "index %s must not be negative", &x)
+		check.invalidArg(&x, _InvalidIndex, "index %s must not be negative", &x)
 		return
 	}
 
 	v, valid := constant.Int64Val(constant.ToInt(x.val))
 	if !valid || max >= 0 && v >= max {
-		check.errorf(x.pos(), "index %s is out of bounds", &x)
+		check.errorf(&x, _InvalidIndex, "index %s is out of bounds", &x)
 		return
 	}
 
@@ -986,12 +997,12 @@
 					index = i
 					validIndex = true
 				} else {
-					check.errorf(e.Pos(), "index %s must be integer constant", kv.Key)
+					check.errorf(e, _InvalidLitIndex, "index %s must be integer constant", kv.Key)
 				}
 			}
 			eval = kv.Value
 		} else if length >= 0 && index >= length {
-			check.errorf(e.Pos(), "index %d is out of bounds (>= %d)", index, length)
+			check.errorf(e, _OversizeArrayLit, "index %d is out of bounds (>= %d)", index, length)
 		} else {
 			validIndex = true
 		}
@@ -999,7 +1010,7 @@
 		// if we have a valid index, check for duplicate entries
 		if validIndex {
 			if visited[index] {
-				check.errorf(e.Pos(), "duplicate index %d in array or slice literal", index)
+				check.errorf(e, _DuplicateLitKey, "duplicate index %d in array or slice literal", index)
 			}
 			visited[index] = true
 		}
@@ -1031,7 +1042,7 @@
 // If hint != nil, it is the type of a composite literal element.
 //
 func (check *Checker) rawExpr(x *operand, e ast.Expr, hint Type) exprKind {
-	if check.conf.Trace {
+	if trace {
 		check.trace(e.Pos(), "expr %s", e)
 		check.indent++
 		defer func() {
@@ -1089,13 +1100,17 @@
 	case *ast.Ellipsis:
 		// ellipses are handled explicitly where they are legal
 		// (array composite literals and parameter lists)
-		check.error(e.Pos(), "invalid use of '...'")
+		check.error(e, _BadDotDotDotSyntax, "invalid use of '...'")
 		goto Error
 
 	case *ast.BasicLit:
 		x.setConst(e.Kind, e.Value)
 		if x.mode == invalid {
-			check.invalidAST(e.Pos(), "invalid literal %v", e.Value)
+			// The parser already establishes syntactic correctness.
+			// If we reach here it's because of number under-/overflow.
+			// TODO(gri) setConst (and in turn the go/constant package)
+			// should return an error describing the issue.
+			check.errorf(e, _InvalidConstVal, "malformed constant: %s", e.Value)
 			goto Error
 		}
 
@@ -1116,7 +1131,7 @@
 			x.mode = value
 			x.typ = sig
 		} else {
-			check.invalidAST(e.Pos(), "invalid function literal %s", e)
+			check.invalidAST(e, "invalid function literal %s", e)
 			goto Error
 		}
 
@@ -1148,7 +1163,7 @@
 
 		default:
 			// TODO(gri) provide better error messages depending on context
-			check.error(e.Pos(), "missing type in composite literal")
+			check.error(e, _UntypedLit, "missing type in composite literal")
 			goto Error
 		}
 
@@ -1164,7 +1179,7 @@
 				for _, e := range e.Elts {
 					kv, _ := e.(*ast.KeyValueExpr)
 					if kv == nil {
-						check.error(e.Pos(), "mixture of field:value and value elements in struct literal")
+						check.error(e, _MixedStructLit, "mixture of field:value and value elements in struct literal")
 						continue
 					}
 					key, _ := kv.Key.(*ast.Ident)
@@ -1172,12 +1187,12 @@
 					// so we don't drop information on the floor
 					check.expr(x, kv.Value)
 					if key == nil {
-						check.errorf(kv.Pos(), "invalid field name %s in struct literal", kv.Key)
+						check.errorf(kv, _InvalidLitField, "invalid field name %s in struct literal", kv.Key)
 						continue
 					}
 					i := fieldIndex(utyp.fields, check.pkg, key.Name)
 					if i < 0 {
-						check.errorf(kv.Pos(), "unknown field %s in struct literal", key.Name)
+						check.errorf(kv, _MissingLitField, "unknown field %s in struct literal", key.Name)
 						continue
 					}
 					fld := fields[i]
@@ -1186,7 +1201,7 @@
 					check.assignment(x, etyp, "struct literal")
 					// 0 <= i < len(fields)
 					if visited[i] {
-						check.errorf(kv.Pos(), "duplicate field name %s in struct literal", key.Name)
+						check.errorf(kv, _DuplicateLitField, "duplicate field name %s in struct literal", key.Name)
 						continue
 					}
 					visited[i] = true
@@ -1195,25 +1210,27 @@
 				// no element must have a key
 				for i, e := range e.Elts {
 					if kv, _ := e.(*ast.KeyValueExpr); kv != nil {
-						check.error(kv.Pos(), "mixture of field:value and value elements in struct literal")
+						check.error(kv, _MixedStructLit, "mixture of field:value and value elements in struct literal")
 						continue
 					}
 					check.expr(x, e)
 					if i >= len(fields) {
-						check.error(x.pos(), "too many values in struct literal")
+						check.error(x, _InvalidStructLit, "too many values in struct literal")
 						break // cannot continue
 					}
 					// i < len(fields)
 					fld := fields[i]
 					if !fld.Exported() && fld.pkg != check.pkg {
-						check.errorf(x.pos(), "implicit assignment to unexported field %s in %s literal", fld.name, typ)
+						check.errorf(x,
+							_UnexportedLitField,
+							"implicit assignment to unexported field %s in %s literal", fld.name, typ)
 						continue
 					}
 					etyp := fld.typ
 					check.assignment(x, etyp, "struct literal")
 				}
 				if len(e.Elts) < len(fields) {
-					check.error(e.Rbrace, "too few values in struct literal")
+					check.error(inNode(e, e.Rbrace), _InvalidStructLit, "too few values in struct literal")
 					// ok to continue
 				}
 			}
@@ -1223,7 +1240,7 @@
 			// This is a stop-gap solution. Should use Checker.objPath to report entire
 			// path starting with earliest declaration in the source. TODO(gri) fix this.
 			if utyp.elem == nil {
-				check.error(e.Pos(), "illegal cycle in type declaration")
+				check.error(e, _InvalidTypeCycle, "illegal cycle in type declaration")
 				goto Error
 			}
 			n := check.indexedElts(e.Elts, utyp.elem, utyp.len)
@@ -1250,7 +1267,7 @@
 			// Prevent crash if the slice referred to is not yet set up.
 			// See analogous comment for *Array.
 			if utyp.elem == nil {
-				check.error(e.Pos(), "illegal cycle in type declaration")
+				check.error(e, _InvalidTypeCycle, "illegal cycle in type declaration")
 				goto Error
 			}
 			check.indexedElts(e.Elts, utyp.elem, -1)
@@ -1259,14 +1276,14 @@
 			// Prevent crash if the map referred to is not yet set up.
 			// See analogous comment for *Array.
 			if utyp.key == nil || utyp.elem == nil {
-				check.error(e.Pos(), "illegal cycle in type declaration")
+				check.error(e, _InvalidTypeCycle, "illegal cycle in type declaration")
 				goto Error
 			}
 			visited := make(map[interface{}][]Type, len(e.Elts))
 			for _, e := range e.Elts {
 				kv, _ := e.(*ast.KeyValueExpr)
 				if kv == nil {
-					check.error(e.Pos(), "missing key in map literal")
+					check.error(e, _MissingLitKey, "missing key in map literal")
 					continue
 				}
 				check.exprWithHint(x, kv.Key, utyp.key)
@@ -1291,7 +1308,7 @@
 						visited[xkey] = nil
 					}
 					if duplicate {
-						check.errorf(x.pos(), "duplicate key %s in map literal", x.val)
+						check.errorf(x, _DuplicateLitKey, "duplicate key %s in map literal", x.val)
 						continue
 					}
 				}
@@ -1313,7 +1330,7 @@
 			}
 			// if utyp is invalid, an error was reported before
 			if utyp != Typ[Invalid] {
-				check.errorf(e.Pos(), "invalid composite literal type %s", typ)
+				check.errorf(e, _InvalidLit, "invalid composite literal type %s", typ)
 				goto Error
 			}
 		}
@@ -1330,32 +1347,24 @@
 		check.selector(x, e)
 
 	case *ast.IndexExpr:
-		if check.useBrackets {
-			check.exprOrType(x, e.X)
-		} else {
-			check.expr(x, e.X)
-		}
+		check.exprOrType(x, e.X)
 		if x.mode == invalid {
 			check.use(e.Index)
 			goto Error
 		}
 
-		if check.useBrackets {
-			if x.mode == typexpr {
-				if isGeneric(x.typ) {
-					// type instantiation
-					x.mode = invalid
-					x.typ = check.varType(e)
-					if x.typ != Typ[Invalid] {
-						x.mode = typexpr
-					}
-					return expression
-				}
-				check.errorf(x.pos(), "%s is not a generic type", x.typ)
-				goto Error
+		if x.mode == typexpr {
+			// type instantiation
+			x.mode = invalid
+			x.typ = check.varType(e)
+			if x.typ != Typ[Invalid] {
+				x.mode = typexpr
 			}
+			return expression
+		}
 
-			if sig := asSignature(x.typ); sig != nil {
+		if x.mode == value {
+			if sig := asSignature(x.typ); sig != nil && len(sig.tparams) > 0 {
 				return check.call(x, nil, e)
 			}
 		}
@@ -1440,7 +1449,7 @@
 					e = t.elem
 					nmaps++
 				case *TypeParam:
-					check.errorf(x.pos(), "type of %s contains a type parameter - cannot index (implementation restriction)", x)
+					check.errorf(x, 0, "type of %s contains a type parameter - cannot index (implementation restriction)", x)
 				case *instance:
 					panic("unimplemented")
 				}
@@ -1485,12 +1494,12 @@
 		}
 
 		if !valid {
-			check.invalidOp(x.pos(), "cannot index %s", x)
+			check.invalidOp(x, _NonIndexableOperand, "cannot index %s", x)
 			goto Error
 		}
 
 		if e.Index == nil {
-			check.invalidAST(e.Pos(), "missing index for %s", x)
+			check.invalidAST(e, "missing index for %s", x)
 			goto Error
 		}
 
@@ -1517,7 +1526,7 @@
 		case *Basic:
 			if isString(typ) {
 				if e.Slice3 {
-					check.invalidOp(x.pos(), "3-index slice of string")
+					check.invalidOp(x, _InvalidSliceExpr, "3-index slice of string")
 					goto Error
 				}
 				valid = true
@@ -1535,7 +1544,7 @@
 			valid = true
 			length = typ.len
 			if x.mode != variable {
-				check.invalidOp(x.pos(), "cannot slice %s (value not addressable)", x)
+				check.invalidOp(x, _NonSliceableOperand, "cannot slice %s (value not addressable)", x)
 				goto Error
 			}
 			x.typ = &Slice{elem: typ.elem}
@@ -1552,12 +1561,12 @@
 			// x.typ doesn't change
 
 		case *Sum, *TypeParam:
-			check.errorf(x.pos(), "generic slice expressions not yet implemented")
+			check.errorf(x, 0, "generic slice expressions not yet implemented")
 			goto Error
 		}
 
 		if !valid {
-			check.invalidOp(x.pos(), "cannot slice %s", x)
+			check.invalidOp(x, _NonSliceableOperand, "cannot slice %s", x)
 			goto Error
 		}
 
@@ -1565,7 +1574,7 @@
 
 		// spec: "Only the first index may be omitted; it defaults to 0."
 		if e.Slice3 && (e.High == nil || e.Max == nil) {
-			check.error(e.Rbrack, "2nd and 3rd index required in 3-index slice")
+			check.invalidAST(inNode(e, e.Rbrack), "2nd and 3rd index required in 3-index slice")
 			goto Error
 		}
 
@@ -1602,7 +1611,7 @@
 			if x > 0 {
 				for _, y := range ind[i+1:] {
 					if y >= 0 && x > y {
-						check.errorf(e.Rbrack, "invalid slice indices: %d > %d", x, y)
+						check.errorf(inNode(e, e.Rbrack), _SwappedSliceIndices, "swapped slice indices: %d > %d", x, y)
 						break L // only report one error, ok to continue
 					}
 				}
@@ -1616,20 +1625,22 @@
 		}
 		xtyp, _ := under(x.typ).(*Interface)
 		if xtyp == nil {
-			check.errorf(x.pos(), "%s is not an interface type", x)
+			check.invalidOp(x, _InvalidAssert, "%s is not an interface", x)
 			goto Error
 		}
-		check.ordinaryType(x.pos(), xtyp)
+		check.ordinaryType(x, xtyp)
 		// x.(type) expressions are handled explicitly in type switches
 		if e.Type == nil {
-			check.invalidAST(e.Pos(), "use of .(type) outside type switch")
+			// Don't use invalidAST because this can occur in the AST produced by
+			// go/parser.
+			check.error(e, _BadTypeKeyword, "use of .(type) outside type switch")
 			goto Error
 		}
 		T := check.varType(e.Type)
 		if T == Typ[Invalid] {
 			goto Error
 		}
-		check.typeAssertion(x.pos(), x, xtyp, T, false)
+		check.typeAssertion(x, x, xtyp, T)
 		x.mode = commaok
 		x.typ = T
 
@@ -1648,7 +1659,7 @@
 				x.mode = variable
 				x.typ = typ.base
 			} else {
-				check.invalidOp(x.pos(), "cannot indirect %s", x)
+				check.invalidOp(x, _InvalidIndirection, "cannot indirect %s", x)
 				goto Error
 			}
 		}
@@ -1668,14 +1679,14 @@
 		}
 
 	case *ast.BinaryExpr:
-		check.binary(x, e, e.X, e.Y, e.Op)
+		check.binary(x, e, e.X, e.Y, e.Op, e.OpPos)
 		if x.mode == invalid {
 			goto Error
 		}
 
 	case *ast.KeyValueExpr:
 		// key:value expressions are handled in composite literals
-		check.invalidAST(e.Pos(), "no key:value expected")
+		check.invalidAST(e, "no key:value expected")
 		goto Error
 
 	case *ast.ArrayType, *ast.StructType, *ast.FuncType,
@@ -1727,8 +1738,8 @@
 }
 
 // typeAssertion checks that x.(T) is legal; xtyp must be the type of x.
-func (check *Checker) typeAssertion(pos token.Pos, x *operand, xtyp *Interface, T Type, strict bool) {
-	method, wrongType := check.assertableTo(xtyp, T, strict)
+func (check *Checker) typeAssertion(at positioner, x *operand, xtyp *Interface, T Type) {
+	method, wrongType := check.assertableTo(xtyp, T)
 	if method == nil {
 		return
 	}
@@ -1742,7 +1753,7 @@
 	} else {
 		msg = "missing method " + method.name
 	}
-	check.errorf(pos, "%s cannot have dynamic type %s (%s)", x, T, msg)
+	check.errorf(at, _ImpossibleAssert, "%s cannot have dynamic type %s (%s)", x, T, msg)
 }
 
 // expr typechecks expression e and initializes x with the expression value.
@@ -1792,6 +1803,7 @@
 func (check *Checker) exclude(x *operand, modeset uint) {
 	if modeset&(1<<x.mode) != 0 {
 		var msg string
+		var code errorCode
 		switch x.mode {
 		case novalue:
 			if modeset&(1<<typexpr) != 0 {
@@ -1799,14 +1811,17 @@
 			} else {
 				msg = "%s used as value or type"
 			}
+			code = _TooManyValues
 		case builtin:
 			msg = "%s must be called"
+			code = _UncalledBuiltin
 		case typexpr:
 			msg = "%s is not an expression"
+			code = _NotAnExpr
 		default:
 			unreachable()
 		}
-		check.errorf(x.pos(), msg, x)
+		check.errorf(x, code, msg, x)
 		x.mode = invalid
 	}
 }
@@ -1817,7 +1832,7 @@
 		// tuple types are never named - no need for underlying type below
 		if t, ok := x.typ.(*Tuple); ok {
 			assert(t.Len() != 1)
-			check.errorf(x.pos(), "%d-valued %s where single value is expected", t.Len(), x)
+			check.errorf(x, _TooManyValues, "%d-valued %s where single value is expected", t.Len(), x)
 			x.mode = invalid
 		}
 	}
diff --git a/src/go/types/fixedbugs/issue20583.src b/src/go/types/fixedbugs/issue20583.src
new file mode 100644
index 0000000..d26dbad
--- /dev/null
+++ b/src/go/types/fixedbugs/issue20583.src
@@ -0,0 +1,14 @@
+// Copyright 2020 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 issue20583
+
+const (
+	_ = 6e886451608 /* ERROR malformed constant */ /2
+	_ = 6e886451608i /* ERROR malformed constant */ /2
+	_ = 0 * 1e+1000000000 // ERROR malformed constant
+
+	x = 1e100000000
+	_ = x*x*x*x*x*x* /* ERROR not representable */ x
+)
diff --git a/src/go/types/fixedbugs/issue23203a.src b/src/go/types/fixedbugs/issue23203a.src
new file mode 100644
index 0000000..48cb588
--- /dev/null
+++ b/src/go/types/fixedbugs/issue23203a.src
@@ -0,0 +1,14 @@
+// Copyright 2018 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 main
+
+import "unsafe"
+
+type T struct{}
+
+func (T) m1()                         {}
+func (T) m2([unsafe.Sizeof(T.m1)]int) {}
+
+func main() {}
diff --git a/src/go/types/fixedbugs/issue23203b.src b/src/go/types/fixedbugs/issue23203b.src
new file mode 100644
index 0000000..638ec6c
--- /dev/null
+++ b/src/go/types/fixedbugs/issue23203b.src
@@ -0,0 +1,14 @@
+// Copyright 2018 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 main
+
+import "unsafe"
+
+type T struct{}
+
+func (T) m2([unsafe.Sizeof(T.m1)]int) {}
+func (T) m1()                         {}
+
+func main() {}
diff --git a/src/go/types/fixedbugs/issue26390.src b/src/go/types/fixedbugs/issue26390.src
new file mode 100644
index 0000000..9e0101f5
--- /dev/null
+++ b/src/go/types/fixedbugs/issue26390.src
@@ -0,0 +1,13 @@
+// Copyright 2018 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.
+
+// stand-alone test to ensure case is triggered
+
+package issue26390
+
+type A = T
+
+func (t *T) m() *A { return t }
+
+type T struct{}
diff --git a/src/go/types/fixedbugs/issue28251.src b/src/go/types/fixedbugs/issue28251.src
new file mode 100644
index 0000000..cd79e0e
--- /dev/null
+++ b/src/go/types/fixedbugs/issue28251.src
@@ -0,0 +1,65 @@
+// Copyright 2018 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.
+
+// This file contains test cases for various forms of
+// method receiver declarations, per the spec clarification
+// https://golang.org/cl/142757.
+
+package issue28251
+
+// test case from issue28251
+type T struct{}
+
+type T0 = *T
+
+func (T0) m() {}
+
+func _() { (&T{}).m() }
+
+// various alternative forms
+type (
+        T1 = (((T)))
+)
+
+func ((*(T1))) m1() {}
+func _() { (T{}).m2() }
+func _() { (&T{}).m2() }
+
+type (
+        T2 = (((T3)))
+        T3 = T
+)
+
+func (T2) m2() {}
+func _() { (T{}).m2() }
+func _() { (&T{}).m2() }
+
+type (
+        T4 = ((*(T5)))
+        T5 = T
+)
+
+func (T4) m4() {}
+func _() { (T{}).m4 /* ERROR "cannot call pointer method m4 on T" */ () }
+func _() { (&T{}).m4() }
+
+type (
+        T6 = (((T7)))
+        T7 = (*(T8))
+        T8 = T
+)
+
+func (T6) m6() {}
+func _() { (T{}).m6 /* ERROR "cannot call pointer method m6 on T" */ () }
+func _() { (&T{}).m6() }
+
+type (
+        T9 = *T10
+        T10 = *T11
+        T11 = T
+)
+
+func (T9 /* ERROR invalid receiver \*\*T */ ) m9() {}
+func _() { (T{}).m9 /* ERROR has no field or method m9 */ () }
+func _() { (&T{}).m9 /* ERROR has no field or method m9 */ () }
diff --git a/src/go/types/fixedbugs/issue39634.go2 b/src/go/types/fixedbugs/issue39634.go2
index e19343e..249542d 100644
--- a/src/go/types/fixedbugs/issue39634.go2
+++ b/src/go/types/fixedbugs/issue39634.go2
@@ -83,9 +83,9 @@
 var x T25 /* ERROR without instantiation */ .m1
 
 // crash 26
-type T26 = interface{ F26[Z any]() }
+type T26 = interface{ F26[ /* ERROR methods cannot have type parameters */ Z any]() }
 func F26[Z any]() T26 { return F26 /* ERROR without instantiation */ /* ERROR missing method */ [] /* ERROR operand */ }
 
 // crash 27
 func e27[T any]() interface{ x27 /* ERROR not a type */ }
-func x27() { e27() /* ERROR cannot infer T */ }
\ No newline at end of file
+func x27() { e27() /* ERROR cannot infer T */ }
diff --git a/src/go/types/fixedbugs/issue39754.go2 b/src/go/types/fixedbugs/issue39754.go2
index 0de777a..2ed84dc 100644
--- a/src/go/types/fixedbugs/issue39754.go2
+++ b/src/go/types/fixedbugs/issue39754.go2
@@ -16,5 +16,5 @@
 

 func _() {

 	f[int, Optional[int], Optional[int]]()

-	f[int, Optional[int], Optional /* ERROR does not satisfy Box */ [string]]()

+	// f[int, Optional[int], Optional /* ERROR does not satisfy Box */ [string]]()

 }

diff --git a/src/go/types/fixedbugs/issue42695.src b/src/go/types/fixedbugs/issue42695.src
new file mode 100644
index 0000000..d0d6200
--- /dev/null
+++ b/src/go/types/fixedbugs/issue42695.src
@@ -0,0 +1,17 @@
+// Copyright 2020 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 issue42695
+
+const _ = 6e5518446744 // ERROR malformed constant
+const _ uint8 = 6e5518446744 // ERROR malformed constant
+
+var _ = 6e5518446744 // ERROR malformed constant
+var _ uint8 = 6e5518446744 // ERROR malformed constant
+
+func f(x int) int {
+        return x + 6e5518446744 // ERROR malformed constant
+}
+
+var _ = f(6e5518446744 /* ERROR malformed constant */ )
diff --git a/src/go/types/fixedbugs/issue43110.src b/src/go/types/fixedbugs/issue43110.src
new file mode 100644
index 0000000..4a46945
--- /dev/null
+++ b/src/go/types/fixedbugs/issue43110.src
@@ -0,0 +1,43 @@
+// Copyright 2020 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 P *struct{}
+
+func _() {
+	// want an error even if the switch is empty
+	var a struct{ _ func() }
+	switch a /* ERROR cannot switch on a */ {
+	}
+
+	switch a /* ERROR cannot switch on a */ {
+	case a: // no follow-on error here
+	}
+
+	// this is ok because f can be compared to nil
+	var f func()
+	switch f {
+	}
+
+	switch f {
+	case nil:
+	}
+
+	switch (func())(nil) {
+	case nil:
+	}
+
+	switch (func())(nil) {
+	case f /* ERROR cannot compare */ :
+	}
+
+	switch nil /* ERROR use of untyped nil in switch expression */ {
+	}
+
+	// this is ok
+	switch P(nil) {
+	case P(nil):
+	}
+}
diff --git a/src/go/types/fixedbugs/issue43124.src b/src/go/types/fixedbugs/issue43124.src
new file mode 100644
index 0000000..f429f74
--- /dev/null
+++ b/src/go/types/fixedbugs/issue43124.src
@@ -0,0 +1,16 @@
+// Copyright 2020 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
+
+var _ = int(0 /* ERROR invalid use of \.\.\. in conversion to int */ ...)
+
+// test case from issue
+
+type M []string
+
+var (
+	x = []string{"a", "b"}
+	_ = M(x /* ERROR invalid use of \.\.\. in conversion to M */ ...)
+)
diff --git a/src/go/types/fixedbugs/issue6977.src b/src/go/types/fixedbugs/issue6977.src
new file mode 100644
index 0000000..8f4e9ba
--- /dev/null
+++ b/src/go/types/fixedbugs/issue6977.src
@@ -0,0 +1,82 @@
+// Copyright 2019 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
+
+import "io"
+
+// Alan's initial report.
+
+type I interface { f(); String() string }
+type J interface { g(); String() string }
+
+type IJ1 = interface { I; J }
+type IJ2 = interface { f(); g(); String() string }
+
+var _ = (*IJ1)(nil) == (*IJ2)(nil) // static assert that IJ1 and IJ2 are identical types
+
+// The canonical example.
+
+type ReadWriteCloser interface { io.ReadCloser; io.WriteCloser }
+
+// Some more cases.
+
+type M interface { m() }
+type M32 interface { m() int32 }
+type M64 interface { m() int64 }
+
+type U1 interface { m() }
+type U2 interface { m(); M }
+type U3 interface { M; m() }
+type U4 interface { M; M; M }
+type U5 interface { U1; U2; U3; U4 }
+
+type U6 interface { m(); m /* ERROR duplicate method */ () }
+type U7 interface { M32 /* ERROR duplicate method */ ; m() }
+type U8 interface { m(); M32 /* ERROR duplicate method */ }
+type U9 interface { M32; M64 /* ERROR duplicate method */ }
+
+// Verify that repeated embedding of the same interface(s)
+// eliminates duplicate methods early (rather than at the
+// end) to prevent exponential memory and time use.
+// Without early elimination, computing T29 may take dozens
+// of minutes.
+type (
+        T0 interface { m() }
+        T1 interface { T0; T0 }
+        T2 interface { T1; T1 }
+        T3 interface { T2; T2 }
+        T4 interface { T3; T3 }
+        T5 interface { T4; T4 }
+        T6 interface { T5; T5 }
+        T7 interface { T6; T6 }
+        T8 interface { T7; T7 }
+        T9 interface { T8; T8 }
+
+        T10 interface { T9; T9 }
+        T11 interface { T10; T10 }
+        T12 interface { T11; T11 }
+        T13 interface { T12; T12 }
+        T14 interface { T13; T13 }
+        T15 interface { T14; T14 }
+        T16 interface { T15; T15 }
+        T17 interface { T16; T16 }
+        T18 interface { T17; T17 }
+        T19 interface { T18; T18 }
+
+        T20 interface { T19; T19 }
+        T21 interface { T20; T20 }
+        T22 interface { T21; T21 }
+        T23 interface { T22; T22 }
+        T24 interface { T23; T23 }
+        T25 interface { T24; T24 }
+        T26 interface { T25; T25 }
+        T27 interface { T26; T26 }
+        T28 interface { T27; T27 }
+        T29 interface { T28; T28 }
+)
+
+// Verify that m is present.
+var x T29
+var _ = x.m
diff --git a/src/go/types/gotype.go b/src/go/types/gotype.go
index 258ad3b..eacf68f 100644
--- a/src/go/types/gotype.go
+++ b/src/go/types/gotype.go
@@ -48,9 +48,9 @@
 
 Flags controlling additional output:
 	-ast
-		print AST (forces -seq)
+		print AST
 	-trace
-		print parse trace (forces -seq)
+		print parse trace
 	-comments
 		parse comments (ignored unless -ast or -trace is provided)
 	-panic
@@ -104,8 +104,8 @@
 	compiler   = flag.String("c", "source", "compiler used for installed packages (gc, gccgo, or source)")
 
 	// additional output control
-	printAST      = flag.Bool("ast", false, "print AST (forces -seq)")
-	printTrace    = flag.Bool("trace", false, "print parse trace (forces -seq)")
+	printAST      = flag.Bool("ast", false, "print AST")
+	printTrace    = flag.Bool("trace", false, "print parse trace")
 	parseComments = flag.Bool("comments", false, "parse comments (ignored unless -ast or -trace is provided)")
 	panicOnError  = flag.Bool("panic", false, "panic on first error")
 )
@@ -118,7 +118,6 @@
 )
 
 func initParserMode() {
-	parserMode = parser.UnifiedParamLists
 	if *allErrors {
 		parserMode |= parser.AllErrors
 	}
@@ -291,8 +290,7 @@
 
 	// if checkPkgFiles is called multiple times, set up conf only once
 	conf := types.Config{
-		InferFromConstraints: true,
-		FakeImportC:          true,
+		FakeImportC: true,
 		Error: func(err error) {
 			if !*allErrors && errorCount >= 10 {
 				panic(bailout{})
diff --git a/src/go/types/infer.go b/src/go/types/infer.go
index 2c7e548..95bd3cb 100644
--- a/src/go/types/infer.go
+++ b/src/go/types/infer.go
@@ -17,7 +17,7 @@
 // is impossible because unification fails, an error is reported and the resulting types list is
 // nil, and index is 0. Otherwise, types is the list of inferred type arguments, and index is
 // the index of the first type argument in that list that couldn't be inferred (and thus is nil).
-// If all type arguments where inferred successfully, index is < 0.
+// If all type arguments were inferred successfully, index is < 0.
 func (check *Checker) infer(tparams []*TypeName, params *Tuple, args []*operand) (types []Type, index int) {
 	assert(params.Len() == len(args))
 
@@ -39,16 +39,17 @@
 				}
 			}
 			if allFailed {
-				check.errorf(arg.pos(), "%s %s of %s does not match %s (cannot infer %s)", kind, targ, arg.expr, tpar, typeNamesString(tparams))
+				check.errorf(arg, _Todo, "%s %s of %s does not match %s (cannot infer %s)", kind, targ, arg.expr, tpar, typeNamesString(tparams))
 				return
 			}
 		}
 		smap := makeSubstMap(tparams, targs)
-		inferred := check.subst(arg.pos(), tpar, smap)
+		// TODO(rFindley): pass a positioner here, rather than arg.Pos().
+		inferred := check.subst(arg.Pos(), tpar, smap)
 		if inferred != tpar {
-			check.errorf(arg.pos(), "%s %s of %s does not match inferred type %s for %s", kind, targ, arg.expr, inferred, tpar)
+			check.errorf(arg, _Todo, "%s %s of %s does not match inferred type %s for %s", kind, targ, arg.expr, inferred, tpar)
 		} else {
-			check.errorf(arg.pos(), "%s %s of %s does not match %s", kind, targ, arg.expr, tpar)
+			check.errorf(arg, 0, "%s %s of %s does not match %s", kind, targ, arg.expr, tpar)
 		}
 	}
 
@@ -72,7 +73,7 @@
 			if targ := arg.typ; isTyped(targ) {
 				// If we permit bidirectional unification, and targ is
 				// a generic function, we need to initialize u.y with
-				// the respectice type parameters of targ.
+				// the respective type parameters of targ.
 				if !u.unify(par.typ, targ) {
 					errorf("type", par.typ, targ, arg)
 					return nil, 0
@@ -215,13 +216,13 @@
 
 	case *Interface:
 		if t.allMethods != nil {
-			// interface is complete - quick test
+			// TODO(rFindley) at some point we should enforce completeness here
 			for _, m := range t.allMethods {
 				if w.isParameterized(m.typ) {
 					return true
 				}
 			}
-			return w.isParameterizedList(unpack(t.allTypes))
+			return w.isParameterizedList(unpackType(t.allTypes))
 		}
 
 		return t.iterate(func(t *Interface) bool {
@@ -230,7 +231,7 @@
 					return true
 				}
 			}
-			return w.isParameterizedList(unpack(t.types))
+			return w.isParameterizedList(unpackType(t.types))
 		}, nil)
 
 	case *Map:
@@ -291,21 +292,19 @@
 	// Unify type parameters with their structural constraints, if any.
 	for _, tpar := range tparams {
 		typ := tpar.typ.(*TypeParam)
-		sbound := check.structuralType(under(typ.bound))
+		sbound := check.structuralType(typ.bound)
 		if sbound != nil {
-			//check.dump(">>> unify(%s, %s)", tpar, sbound)
 			if !u.unify(typ, sbound) {
-				check.errorf(tpar.pos, "%s does not match %s", tpar, sbound)
+				check.errorf(tpar, 0, "%s does not match %s", tpar, sbound)
 				return nil, 0
 			}
-			//check.dump(">>> => indices = %v, types = %s", u.x.indices, u.types)
 		}
 	}
 
 	// u.x.types() now contains the incoming type arguments plus any additional type
 	// arguments for which there were structural constraints. The newly inferred non-
 	// nil entries may still contain references to other type parameters. For instance,
-	// for [type A interface{}, B interface{type []C}, C interface{type *A}], if A == int
+	// for [A any, B interface{type []C}, C interface{type *A}], if A == int
 	// was given, unification produced the type list [int, []C, *A]. We eliminate the
 	// remaining type parameters by substituting the type parameters in this type list
 	// until nothing changes anymore.
@@ -317,7 +316,7 @@
 	}
 
 	// dirty tracks the indices of all types that may still contain type parameters.
-	// We know that nil types entries and entries corresponding to provided (non-nil)
+	// We know that nil type entries and entries corresponding to provided (non-nil)
 	// type arguments are clean, so exclude them from the start.
 	var dirty []int
 	for i, typ := range types {
@@ -327,8 +326,8 @@
 	}
 
 	for len(dirty) > 0 {
-		// TODO(gri) Instead of creating a new smap for each iteration,
-		// provide an update operation for smaps and only change when
+		// TODO(gri) Instead of creating a new substMap for each iteration,
+		// provide an update operation for substMaps and only change when
 		// needed. Optimization.
 		smap := makeSubstMap(tparams, types)
 		n := 0
@@ -342,16 +341,15 @@
 		}
 		dirty = dirty[:n]
 	}
-	//check.dump(">>> inferred types = %s", types)
 
 	return
 }
 
 // structuralType returns the structural type of a constraint, if any.
 func (check *Checker) structuralType(constraint Type) Type {
-	if iface, _ := constraint.(*Interface); iface != nil {
+	if iface, _ := under(constraint).(*Interface); iface != nil {
 		check.completeInterface(token.NoPos, iface)
-		types := unpack(iface.allTypes)
+		types := unpackType(iface.allTypes)
 		if len(types) == 1 {
 			return types[0]
 		}
diff --git a/src/go/types/initorder.go b/src/go/types/initorder.go
index 9d5e916..77a739c 100644
--- a/src/go/types/initorder.go
+++ b/src/go/types/initorder.go
@@ -151,14 +151,14 @@
 // reportCycle reports an error for the given cycle.
 func (check *Checker) reportCycle(cycle []Object) {
 	obj := cycle[0]
-	check.errorf(obj.Pos(), "initialization cycle for %s", obj.Name())
+	check.errorf(obj, _InvalidInitCycle, "initialization cycle for %s", obj.Name())
 	// subtle loop: print cycle[i] for i = 0, n-1, n-2, ... 1 for len(cycle) = n
 	for i := len(cycle) - 1; i >= 0; i-- {
-		check.errorf(obj.Pos(), "\t%s refers to", obj.Name()) // secondary error, \t indented
+		check.errorf(obj, _InvalidInitCycle, "\t%s refers to", obj.Name()) // secondary error, \t indented
 		obj = cycle[i]
 	}
 	// print cycle[0] again to close the cycle
-	check.errorf(obj.Pos(), "\t%s", obj.Name())
+	check.errorf(obj, _InvalidInitCycle, "\t%s", obj.Name())
 }
 
 // ----------------------------------------------------------------------------
diff --git a/src/go/types/issues_test.go b/src/go/types/issues_test.go
index 318427d..34850eb 100644
--- a/src/go/types/issues_test.go
+++ b/src/go/types/issues_test.go
@@ -12,6 +12,7 @@
 	"go/ast"
 	"go/importer"
 	"go/parser"
+	"go/token"
 	"internal/testenv"
 	"sort"
 	"strings"
@@ -384,12 +385,9 @@
 			}
 		}
 		if obj == nil {
-			t.Fatal("object X not found")
+			t.Fatal("interface not found")
 		}
-		iface, _ := obj.Type().Underlying().(*Interface) // object X must be an interface
-		if iface == nil {
-			t.Fatalf("%s is not an interface", obj)
-		}
+		iface := obj.Type().Underlying().(*Interface) // I must be an interface
 
 		// Each iface method m is embedded; and m's receiver base type name
 		// must match the method's name per the choice in the source file.
@@ -526,3 +524,28 @@
 		pkg = res // res is imported by the next package in this test
 	}
 }
+
+func TestIssue43088(t *testing.T) {
+	// type T1 struct {
+	//         _ T2
+	// }
+	//
+	// type T2 struct {
+	//         _ struct {
+	//                 _ T2
+	//         }
+	// }
+	n1 := NewTypeName(token.NoPos, nil, "T1", nil)
+	T1 := NewNamed(n1, nil, nil)
+	n2 := NewTypeName(token.NoPos, nil, "T2", nil)
+	T2 := NewNamed(n2, nil, nil)
+	s1 := NewStruct([]*Var{NewField(token.NoPos, nil, "_", T2, false)}, nil)
+	T1.SetUnderlying(s1)
+	s2 := NewStruct([]*Var{NewField(token.NoPos, nil, "_", T2, false)}, nil)
+	s3 := NewStruct([]*Var{NewField(token.NoPos, nil, "_", s2, false)}, nil)
+	T2.SetUnderlying(s3)
+
+	// These calls must terminate (no endless recursion).
+	Comparable(T1)
+	Comparable(T2)
+}
diff --git a/src/go/types/labels.go b/src/go/types/labels.go
index 3b43b4b..8cf6e63 100644
--- a/src/go/types/labels.go
+++ b/src/go/types/labels.go
@@ -22,20 +22,23 @@
 	// for the respective gotos.
 	for _, jmp := range fwdJumps {
 		var msg string
+		var code errorCode
 		name := jmp.Label.Name
 		if alt := all.Lookup(name); alt != nil {
 			msg = "goto %s jumps into block"
 			alt.(*Label).used = true // avoid another error
+			code = _JumpIntoBlock
 		} else {
 			msg = "label %s not declared"
+			code = _UndeclaredLabel
 		}
-		check.errorf(jmp.Label.Pos(), msg, name)
+		check.errorf(jmp.Label, code, msg, name)
 	}
 
 	// spec: "It is illegal to define a label that is never used."
 	for _, obj := range all.elems {
 		if lbl := obj.(*Label); !lbl.used {
-			check.softErrorf(lbl.pos, "label %s declared but not used", lbl.name)
+			check.softErrorf(lbl, _UnusedLabel, "label %s declared but not used", lbl.name)
 		}
 	}
 }
@@ -133,7 +136,7 @@
 			if name := s.Label.Name; name != "_" {
 				lbl := NewLabel(s.Label.Pos(), check.pkg, name)
 				if alt := all.Insert(lbl); alt != nil {
-					check.softErrorf(lbl.pos, "label %s already declared", name)
+					check.softErrorf(lbl, _DuplicateLabel, "label %s already declared", name)
 					check.reportAltDecl(alt)
 					// ok to continue
 				} else {
@@ -149,7 +152,8 @@
 						check.recordUse(jmp.Label, lbl)
 						if jumpsOverVarDecl(jmp) {
 							check.softErrorf(
-								jmp.Label.Pos(),
+								jmp.Label,
+								_JumpOverDecl,
 								"goto %s jumps over variable declaration at line %d",
 								name,
 								check.fset.Position(varDeclPos).Line,
@@ -187,7 +191,7 @@
 					}
 				}
 				if !valid {
-					check.errorf(s.Label.Pos(), "invalid break label %s", name)
+					check.errorf(s.Label, _MisplacedLabel, "invalid break label %s", name)
 					return
 				}
 
@@ -202,7 +206,7 @@
 					}
 				}
 				if !valid {
-					check.errorf(s.Label.Pos(), "invalid continue label %s", name)
+					check.errorf(s.Label, _MisplacedLabel, "invalid continue label %s", name)
 					return
 				}
 
@@ -214,7 +218,7 @@
 				}
 
 			default:
-				check.invalidAST(s.Pos(), "branch statement: %s %s", s.Tok, name)
+				check.invalidAST(s, "branch statement: %s %s", s.Tok, name)
 				return
 			}
 
diff --git a/src/go/types/lookup.go b/src/go/types/lookup.go
index 0514819..a0e7f3c 100644
--- a/src/go/types/lookup.go
+++ b/src/go/types/lookup.go
@@ -196,6 +196,8 @@
 				}
 
 			case *TypeParam:
+				// only consider explicit methods in the type parameter bound, not
+				// methods that may be common to all types in the type list.
 				if i, m := lookupMethod(t.Bound().allMethods, pkg, name); m != nil {
 					assert(m.typ != nil)
 					index = concat(e.index, i)
@@ -206,12 +208,6 @@
 					obj = m
 					indirect = e.indirect
 				}
-				if obj == nil {
-					// At this point we're not (yet) looking into methods
-					// that any underlyng type of the types in the type list
-					// migth have.
-					// TODO(gri) Do we want to specify the language that way?
-				}
 			}
 		}
 
@@ -223,7 +219,7 @@
 			//        is shorthand for (&x).m()".
 			if f, _ := obj.(*Func); f != nil {
 				// determine if method has a pointer receiver
-				hasPtrRecv := tpar == nil && ptrRecv(f) || tpar != nil && tpar.ptr
+				hasPtrRecv := tpar == nil && ptrRecv(f)
 				if hasPtrRecv && !indirect && !addressable {
 					return nil, nil, true // pointer/addressable receiver required
 				}
@@ -329,7 +325,6 @@
 				return m, f
 			}
 
-			// both methods must have the same number of type parameters
 			ftyp := f.typ.(*Signature)
 			mtyp := m.typ.(*Signature)
 			if len(ftyp.tparams) != len(mtyp.tparams) {
@@ -429,13 +424,13 @@
 // method required by V and whether it is missing or just has the wrong type.
 // The receiver may be nil if assertableTo is invoked through an exported API call
 // (such as AssertableTo), i.e., when all methods have been type-checked.
-// If strict (or the global constant forceStrict) is set, assertions that
-// are known to fail are not permitted.
-func (check *Checker) assertableTo(V *Interface, T Type, strict bool) (method, wrongType *Func) {
+// If the global constant forceStrict is set, assertions that are known to fail
+// are not permitted.
+func (check *Checker) assertableTo(V *Interface, T Type) (method, wrongType *Func) {
 	// no static check is required if T is an interface
 	// spec: "If T is an interface type, x.(T) asserts that the
 	//        dynamic type of x implements the interface T."
-	if asInterface(T) != nil && !(strict || forceStrict) {
+	if asInterface(T) != nil && !forceStrict {
 		return
 	}
 	return check.missingMethod(T, V, false)
diff --git a/src/go/types/operand.go b/src/go/types/operand.go
index cd66db67..8f9c9d0 100644
--- a/src/go/types/operand.go
+++ b/src/go/types/operand.go
@@ -59,10 +59,10 @@
 	id   builtinId
 }
 
-// pos returns the position of the expression corresponding to x.
+// Pos returns the position of the expression corresponding to x.
 // If x is invalid the position is token.NoPos.
 //
-func (x *operand) pos() token.Pos {
+func (x *operand) Pos() token.Pos {
 	// x.expr may not be set if x is invalid
 	if x.expr == nil {
 		return token.NoPos
@@ -204,9 +204,15 @@
 		unreachable()
 	}
 
+	val := constant.MakeFromLiteral(lit, tok, 0)
+	if val.Kind() == constant.Unknown {
+		x.mode = invalid
+		x.typ = Typ[Invalid]
+		return
+	}
 	x.mode = constant_
 	x.typ = Typ[kind]
-	x.val = constant.MakeFromLiteral(lit, tok, 0)
+	x.val = val
 }
 
 // isNil reports whether x is the nil value.
@@ -214,65 +220,44 @@
 	return x.mode == value && x.typ == Typ[UntypedNil]
 }
 
-// TODO(gri) The functions operand.assignableTo, checker.convertUntyped,
-//           checker.representable, and checker.assignment are
-//           overlapping in functionality. Need to simplify and clean up.
-
-// assignableTo reports whether x is assignable to a variable of type T.
-// If the result is false and a non-nil reason is provided, it may be set
-// to a more detailed explanation of the failure (result != "").
-// The check parameter may be nil if assignableTo is invoked through
-// an exported API call, i.e., when all methods have been type-checked.
-func (x *operand) assignableTo(check *Checker, T Type, reason *string) bool {
+// assignableTo reports whether x is assignable to a variable of type T. If the
+// result is false and a non-nil reason is provided, it may be set to a more
+// detailed explanation of the failure (result != ""). The check parameter may
+// be nil if assignableTo is invoked through an exported API call, i.e., when
+// all methods have been type-checked.
+func (x *operand) assignableTo(check *Checker, T Type, reason *string) (bool, errorCode) {
 	if x.mode == invalid || T == Typ[Invalid] {
-		return true // avoid spurious errors
+		return true, 0 // avoid spurious errors
 	}
 
 	V := x.typ
 
 	// x's type is identical to T
 	if check.identical(V, T) {
-		return true
+		return true, 0
 	}
 
 	Vu := optype(V)
 	Tu := optype(T)
 
-	// x is an untyped value representable by a value of type T
-	// TODO(gri) This is borrowing from checker.convertUntyped and
-	//           checker.representable. Need to clean up.
+	// x is an untyped value representable by a value of type T.
 	if isUntyped(Vu) {
-		switch t := Tu.(type) {
-		case *Basic:
-			if x.isNil() && t.kind == UnsafePointer {
-				return true
-			}
-			if x.mode == constant_ {
-				return representableConst(x.val, check, t, nil)
-			}
-			// The result of a comparison is an untyped boolean,
-			// but may not be a constant.
-			if Vb, _ := Vu.(*Basic); Vb != nil {
-				return Vb.kind == UntypedBool && isBoolean(Tu)
-			}
-		case *Sum:
+		if t, ok := Tu.(*Sum); ok {
 			return t.is(func(t Type) bool {
 				// TODO(gri) this could probably be more efficient
-				return x.assignableTo(check, t, reason)
-			})
-		case *Interface:
-			check.completeInterface(token.NoPos, t)
-			return x.isNil() || t.Empty()
-		case *Pointer, *Signature, *Slice, *Map, *Chan:
-			return x.isNil()
+				ok, _ := x.assignableTo(check, t, reason)
+				return ok
+			}), _IncompatibleAssign
 		}
+		newType, _, _ := check.implicitTypeAndValue(x, Tu)
+		return newType != nil, _IncompatibleAssign
 	}
 	// Vu is typed
 
 	// x's type V and T have identical underlying types
 	// and at least one of V or T is not a named type
 	if check.identical(Vu, Tu) && (!isNamed(V) || !isNamed(T)) {
-		return true
+		return true, 0
 	}
 
 	// T is an interface type and x implements T
@@ -290,9 +275,9 @@
 					*reason = "missing method " + m.Name()
 				}
 			}
-			return false
+			return false, _InvalidIfaceAssign
 		}
-		return true
+		return true, 0
 	}
 
 	// x is a bidirectional channel value, T is a channel
@@ -300,9 +285,13 @@
 	// and at least one of V or T is not a named type
 	if Vc, ok := Vu.(*Chan); ok && Vc.dir == SendRecv {
 		if Tc, ok := Tu.(*Chan); ok && check.identical(Vc.elem, Tc.elem) {
-			return !isNamed(V) || !isNamed(T)
+			if !isNamed(V) || !isNamed(T) {
+				return true, 0
+			} else {
+				return false, _InvalidChanAssign
+			}
 		}
 	}
 
-	return false
+	return false, _IncompatibleAssign
 }
diff --git a/src/go/types/predicates.go b/src/go/types/predicates.go
index 7f76df6..0233274 100644
--- a/src/go/types/predicates.go
+++ b/src/go/types/predicates.go
@@ -21,7 +21,8 @@
 	return false
 }
 
-// isGeneric reports whether a type is a generic, uninstantiated type (generic signatures are not included).
+// isGeneric reports whether a type is a generic, uninstantiated type (generic
+// signatures are not included).
 func isGeneric(typ Type) bool {
 	// A parameterized type is only instantiated if it doesn't have an instantiation already.
 	named, _ := typ.(*Named)
@@ -73,12 +74,8 @@
 	return !isTyped(typ)
 }
 
-func isOrdered(typ Type) bool { return is(typ, IsOrdered) }
-
-func isConstType(typ Type) bool {
-	t := asBasic(typ)
-	return t != nil && t.info&IsConstType != 0
-}
+func isOrdered(typ Type) bool   { return is(typ, IsOrdered) }
+func isConstType(typ Type) bool { return is(typ, IsConstType) }
 
 // IsInterface reports whether typ is an interface type.
 func IsInterface(typ Type) bool {
@@ -87,7 +84,19 @@
 
 // Comparable reports whether values of type T are comparable.
 func Comparable(T Type) bool {
-	// If T is a type parameter not constraint by any type
+	return comparable(T, nil)
+}
+
+func comparable(T Type, seen map[Type]bool) bool {
+	if seen[T] {
+		return true
+	}
+	if seen == nil {
+		seen = make(map[Type]bool)
+	}
+	seen[T] = true
+
+	// If T is a type parameter not constrained by any type
 	// list (i.e., it's underlying type is the top type),
 	// T is comparable if it has the == method. Otherwise,
 	// the underlying type "wins". For instance
@@ -108,15 +117,18 @@
 		return true
 	case *Struct:
 		for _, f := range t.fields {
-			if !Comparable(f.typ) {
+			if !comparable(f.typ, seen) {
 				return false
 			}
 		}
 		return true
 	case *Array:
-		return Comparable(t.elem)
+		return comparable(t.elem, seen)
 	case *Sum:
-		return t.is(Comparable)
+		pred := func(t Type) bool {
+			return comparable(t, seen)
+		}
+		return t.is(pred)
 	case *TypeParam:
 		return t.Bound().IsComparable()
 	}
diff --git a/src/go/types/resolver.go b/src/go/types/resolver.go
index 165b842..639ed12 100644
--- a/src/go/types/resolver.go
+++ b/src/go/types/resolver.go
@@ -17,12 +17,13 @@
 
 // A declInfo describes a package-level const, type, var, or func declaration.
 type declInfo struct {
-	file  *Scope        // scope of file containing this declaration
-	lhs   []*Var        // lhs of n:1 variable declarations, or nil
-	vtyp  ast.Expr      // type, or nil (for const and var declarations only)
-	init  ast.Expr      // init/orig expression, or nil (for const and var declarations only)
-	tdecl *ast.TypeSpec // type declaration, or nil
-	fdecl *ast.FuncDecl // func declaration, or nil
+	file      *Scope        // scope of file containing this declaration
+	lhs       []*Var        // lhs of n:1 variable declarations, or nil
+	vtyp      ast.Expr      // type, or nil (for const and var declarations only)
+	init      ast.Expr      // init/orig expression, or nil (for const and var declarations only)
+	inherited bool          // if set, the init expression is inherited from a previous constant declaration
+	tdecl     *ast.TypeSpec // type declaration, or nil
+	fdecl     *ast.FuncDecl // func declaration, or nil
 
 	// The deps field tracks initialization expression dependencies.
 	deps map[Object]bool // lazily initialized
@@ -55,26 +56,27 @@
 		r = len(init.Values)
 	}
 
+	const code = _WrongAssignCount
 	switch {
 	case init == nil && r == 0:
 		// var decl w/o init expr
 		if s.Type == nil {
-			check.errorf(s.Pos(), "missing type or init expr")
+			check.errorf(s, code, "missing type or init expr")
 		}
 	case l < r:
 		if l < len(s.Values) {
 			// init exprs from s
 			n := s.Values[l]
-			check.errorf(n.Pos(), "extra init expr %s", n)
+			check.errorf(n, code, "extra init expr %s", n)
 			// TODO(gri) avoid declared but not used error here
 		} else {
 			// init exprs "inherited"
-			check.errorf(s.Pos(), "extra init expr at %s", check.fset.Position(init.Pos()))
+			check.errorf(s, code, "extra init expr at %s", check.fset.Position(init.Pos()))
 			// TODO(gri) avoid declared but not used error here
 		}
 	case l > r && (init != nil || r != 1):
 		n := s.Names[r]
-		check.errorf(n.Pos(), "missing init expr for %s", n)
+		check.errorf(n, code, "missing init expr for %s", n)
 	}
 }
 
@@ -103,14 +105,14 @@
 	// spec: "A package-scope or file-scope identifier with name init
 	// may only be declared to be a function with this (func()) signature."
 	if ident.Name == "init" {
-		check.errorf(ident.Pos(), "cannot declare init - must be func")
+		check.errorf(ident, _InvalidInitDecl, "cannot declare init - must be func")
 		return
 	}
 
 	// spec: "The main package must have package name main and declare
 	// a function main that takes no arguments and returns no value."
 	if ident.Name == "main" && check.pkg.name == "main" {
-		check.errorf(ident.Pos(), "cannot declare main - must be func")
+		check.errorf(ident, _InvalidMainDecl, "cannot declare main - must be func")
 		return
 	}
 
@@ -168,7 +170,7 @@
 			imp = nil // create fake package below
 		}
 		if err != nil {
-			check.errorf(pos, "could not import %s (%s)", path, err)
+			check.errorf(atPos(pos), _BrokenImport, "could not import %s (%s)", path, err)
 			if imp == nil {
 				// create a new fake package
 				// come up with a sensible package name (heuristic)
@@ -242,218 +244,185 @@
 		// we get "." as the directory which is what we would want.
 		fileDir := dir(check.fset.Position(file.Name.Pos()).Filename)
 
-		for _, decl := range file.Decls {
-			switch d := decl.(type) {
-			case *ast.BadDecl:
-				// ignore
+		check.walkDecls(file.Decls, func(d decl) {
+			switch d := d.(type) {
+			case importDecl:
+				// import package
+				path, err := validatedImportPath(d.spec.Path.Value)
+				if err != nil {
+					check.errorf(d.spec.Path, _BadImportPath, "invalid import path (%s)", err)
+					return
+				}
 
-			case *ast.GenDecl:
-				var last *ast.ValueSpec // last ValueSpec with type or init exprs seen
-				for iota, spec := range d.Specs {
-					switch s := spec.(type) {
-					case *ast.ImportSpec:
-						// import package
-						path, err := validatedImportPath(s.Path.Value)
-						if err != nil {
-							check.errorf(s.Path.Pos(), "invalid import path (%s)", err)
-							continue
-						}
+				imp := check.importPackage(d.spec.Path.Pos(), path, fileDir)
+				if imp == nil {
+					return
+				}
 
-						imp := check.importPackage(s.Path.Pos(), path, fileDir)
-						if imp == nil {
-							continue
-						}
+				// add package to list of explicit imports
+				// (this functionality is provided as a convenience
+				// for clients; it is not needed for type-checking)
+				if !pkgImports[imp] {
+					pkgImports[imp] = true
+					pkg.imports = append(pkg.imports, imp)
+				}
 
-						// add package to list of explicit imports
-						// (this functionality is provided as a convenience
-						// for clients; it is not needed for type-checking)
-						if !pkgImports[imp] {
-							pkgImports[imp] = true
-							pkg.imports = append(pkg.imports, imp)
-						}
-
-						// local name overrides imported package name
-						name := imp.name
-						if s.Name != nil {
-							name = s.Name.Name
-							if path == "C" {
-								// match cmd/compile (not prescribed by spec)
-								check.errorf(s.Name.Pos(), `cannot rename import "C"`)
-								continue
-							}
-							if name == "init" {
-								check.errorf(s.Name.Pos(), "cannot declare init - must be func")
-								continue
-							}
-						}
-
-						obj := NewPkgName(s.Pos(), pkg, name, imp)
-						if s.Name != nil {
-							// in a dot-import, the dot represents the package
-							check.recordDef(s.Name, obj)
-						} else {
-							check.recordImplicit(s, obj)
-						}
-
-						if path == "C" {
-							// match cmd/compile (not prescribed by spec)
-							obj.used = true
-						}
-
-						// add import to file scope
-						if name == "." {
-							// merge imported scope with file scope
-							for _, obj := range imp.scope.elems {
-								// A package scope may contain non-exported objects,
-								// do not import them!
-								if obj.Exported() {
-									// declare dot-imported object
-									// (Do not use check.declare because it modifies the object
-									// via Object.setScopePos, which leads to a race condition;
-									// the object may be imported into more than one file scope
-									// concurrently. See issue #32154.)
-									if alt := fileScope.Insert(obj); alt != nil {
-										check.errorf(s.Name.Pos(), "%s redeclared in this block", obj.Name())
-										check.reportAltDecl(alt)
-									}
-								}
-							}
-							// add position to set of dot-import positions for this file
-							// (this is only needed for "imported but not used" errors)
-							check.addUnusedDotImport(fileScope, imp, s.Pos())
-						} else {
-							// declare imported package object in file scope
-							// (no need to provide s.Name since we called check.recordDef earlier)
-							check.declare(fileScope, nil, obj, token.NoPos)
-						}
-
-					case *ast.ValueSpec:
-						switch d.Tok {
-						case token.CONST:
-							// determine which initialization expressions to use
-							switch {
-							case s.Type != nil || len(s.Values) > 0:
-								last = s
-							case last == nil:
-								last = new(ast.ValueSpec) // make sure last exists
-							}
-
-							// declare all constants
-							for i, name := range s.Names {
-								obj := NewConst(name.Pos(), pkg, name.Name, nil, constant.MakeInt64(int64(iota)))
-
-								var init ast.Expr
-								if i < len(last.Values) {
-									init = last.Values[i]
-								}
-
-								d := &declInfo{file: fileScope, vtyp: last.Type, init: init}
-								check.declarePkgObj(name, obj, d)
-							}
-
-							check.arityMatch(s, last)
-
-						case token.VAR:
-							lhs := make([]*Var, len(s.Names))
-							// If there's exactly one rhs initializer, use
-							// the same declInfo d1 for all lhs variables
-							// so that each lhs variable depends on the same
-							// rhs initializer (n:1 var declaration).
-							var d1 *declInfo
-							if len(s.Values) == 1 {
-								// The lhs elements are only set up after the for loop below,
-								// but that's ok because declareVar only collects the declInfo
-								// for a later phase.
-								d1 = &declInfo{file: fileScope, lhs: lhs, vtyp: s.Type, init: s.Values[0]}
-							}
-
-							// declare all variables
-							for i, name := range s.Names {
-								obj := NewVar(name.Pos(), pkg, name.Name, nil)
-								lhs[i] = obj
-
-								d := d1
-								if d == nil {
-									// individual assignments
-									var init ast.Expr
-									if i < len(s.Values) {
-										init = s.Values[i]
-									}
-									d = &declInfo{file: fileScope, vtyp: s.Type, init: init}
-								}
-
-								check.declarePkgObj(name, obj, d)
-							}
-
-							check.arityMatch(s, nil)
-
-						default:
-							check.invalidAST(s.Pos(), "invalid token %s", d.Tok)
-						}
-
-					case *ast.TypeSpec:
-						obj := NewTypeName(s.Name.Pos(), pkg, s.Name.Name, nil)
-						check.declarePkgObj(s.Name, obj, &declInfo{file: fileScope, tdecl: s})
-
-					default:
-						check.invalidAST(s.Pos(), "unknown ast.Spec node %T", s)
+				// local name overrides imported package name
+				name := imp.name
+				if d.spec.Name != nil {
+					name = d.spec.Name.Name
+					if path == "C" {
+						// match cmd/compile (not prescribed by spec)
+						check.errorf(d.spec.Name, _ImportCRenamed, `cannot rename import "C"`)
+						return
+					}
+					if name == "init" {
+						check.errorf(d.spec.Name, _InvalidInitDecl, "cannot declare init - must be func")
+						return
 					}
 				}
 
-			case *ast.FuncDecl:
-				name := d.Name.Name
-				obj := NewFunc(d.Name.Pos(), pkg, name, nil)
-				if !d.IsMethod() {
+				obj := NewPkgName(d.spec.Pos(), pkg, name, imp)
+				if d.spec.Name != nil {
+					// in a dot-import, the dot represents the package
+					check.recordDef(d.spec.Name, obj)
+				} else {
+					check.recordImplicit(d.spec, obj)
+				}
+
+				if path == "C" {
+					// match cmd/compile (not prescribed by spec)
+					obj.used = true
+				}
+
+				// add import to file scope
+				if name == "." {
+					// merge imported scope with file scope
+					for _, obj := range imp.scope.elems {
+						// A package scope may contain non-exported objects,
+						// do not import them!
+						if obj.Exported() {
+							// declare dot-imported object
+							// (Do not use check.declare because it modifies the object
+							// via Object.setScopePos, which leads to a race condition;
+							// the object may be imported into more than one file scope
+							// concurrently. See issue #32154.)
+							if alt := fileScope.Insert(obj); alt != nil {
+								check.errorf(d.spec.Name, _DuplicateDecl, "%s redeclared in this block", obj.Name())
+								check.reportAltDecl(alt)
+							}
+						}
+					}
+					// add position to set of dot-import positions for this file
+					// (this is only needed for "imported but not used" errors)
+					check.addUnusedDotImport(fileScope, imp, d.spec)
+				} else {
+					// declare imported package object in file scope
+					// (no need to provide s.Name since we called check.recordDef earlier)
+					check.declare(fileScope, nil, obj, token.NoPos)
+				}
+			case constDecl:
+				// declare all constants
+				for i, name := range d.spec.Names {
+					obj := NewConst(name.Pos(), pkg, name.Name, nil, constant.MakeInt64(int64(d.iota)))
+
+					var init ast.Expr
+					if i < len(d.init) {
+						init = d.init[i]
+					}
+
+					d := &declInfo{file: fileScope, vtyp: d.typ, init: init, inherited: d.inherited}
+					check.declarePkgObj(name, obj, d)
+				}
+
+			case varDecl:
+				lhs := make([]*Var, len(d.spec.Names))
+				// If there's exactly one rhs initializer, use
+				// the same declInfo d1 for all lhs variables
+				// so that each lhs variable depends on the same
+				// rhs initializer (n:1 var declaration).
+				var d1 *declInfo
+				if len(d.spec.Values) == 1 {
+					// The lhs elements are only set up after the for loop below,
+					// but that's ok because declareVar only collects the declInfo
+					// for a later phase.
+					d1 = &declInfo{file: fileScope, lhs: lhs, vtyp: d.spec.Type, init: d.spec.Values[0]}
+				}
+
+				// declare all variables
+				for i, name := range d.spec.Names {
+					obj := NewVar(name.Pos(), pkg, name.Name, nil)
+					lhs[i] = obj
+
+					di := d1
+					if di == nil {
+						// individual assignments
+						var init ast.Expr
+						if i < len(d.spec.Values) {
+							init = d.spec.Values[i]
+						}
+						di = &declInfo{file: fileScope, vtyp: d.spec.Type, init: init}
+					}
+
+					check.declarePkgObj(name, obj, di)
+				}
+			case typeDecl:
+				obj := NewTypeName(d.spec.Name.Pos(), pkg, d.spec.Name.Name, nil)
+				check.declarePkgObj(d.spec.Name, obj, &declInfo{file: fileScope, tdecl: d.spec})
+			case funcDecl:
+				info := &declInfo{file: fileScope, fdecl: d.decl}
+				name := d.decl.Name.Name
+				obj := NewFunc(d.decl.Name.Pos(), pkg, name, nil)
+				if !d.decl.IsMethod() {
 					// regular function
-					if d.Recv != nil {
-						check.errorf(d.Recv.Pos(), "method is missing receiver")
+					if d.decl.Recv != nil {
+						check.error(d.decl.Recv, _BadRecv, "method is missing receiver")
 						// treat as function
 					}
 					if name == "init" {
-						if d.Type.TParams != nil {
-							check.softErrorf(d.Type.TParams.Pos(), "func init must have no type parameters")
+						if d.decl.Type.TParams != nil {
+							check.softErrorf(d.decl.Type.TParams, _InvalidInitSig, "func init must have no type parameters")
 						}
-						if t := d.Type; t.Params.NumFields() != 0 || t.Results != nil {
-							check.softErrorf(d.Pos(), "func init must have no arguments and no return values")
+						if t := d.decl.Type; t.Params.NumFields() != 0 || t.Results != nil {
+							// TODO(rFindley) Should this be a hard error?
+							check.softErrorf(d.decl, _InvalidInitSig, "func init must have no arguments and no return values")
 						}
 						// don't declare init functions in the package scope - they are invisible
 						obj.parent = pkg.scope
-						check.recordDef(d.Name, obj)
+						check.recordDef(d.decl.Name, obj)
 						// init functions must have a body
-						if d.Body == nil {
+						if d.decl.Body == nil {
 							// TODO(gri) make this error message consistent with the others above
-							check.softErrorf(obj.pos, "missing function body")
+							check.softErrorf(obj, _MissingInitBody, "missing function body")
 						}
 					} else {
-						check.declare(pkg.scope, d.Name, obj, token.NoPos)
+						check.declare(pkg.scope, d.decl.Name, obj, token.NoPos)
 					}
 				} else {
 					// method
-					// d.Recv != nil && len(d.Recv.List) > 0
-					if !methodTypeParamsOk && d.Type.TParams != nil {
-						check.invalidAST(d.Type.TParams.Pos(), "method must have no type parameters")
-					}
-					ptr, recv, _ := check.unpackRecv(d.Recv.List[0].Type, false)
+
+					// TODO(rFindley) earlier versions of this code checked that methods
+					//                have no type parameters, but this is checked later
+					//                when type checking the function type. Confirm that
+					//                we don't need to check tparams here.
+
+					ptr, recv, _ := check.unpackRecv(d.decl.Recv.List[0].Type, false)
 					// (Methods with invalid receiver cannot be associated to a type, and
 					// methods with blank _ names are never found; no need to collect any
 					// of them. They will still be type-checked with all the other functions.)
 					if recv != nil && name != "_" {
 						methods = append(methods, methodInfo{obj, ptr, recv})
 					}
-					check.recordDef(d.Name, obj)
+					check.recordDef(d.decl.Name, obj)
 				}
-				info := &declInfo{file: fileScope, fdecl: d}
 				// Methods are not package-level objects but we still track them in the
 				// object map so that we can handle them like regular functions (if the
 				// receiver is invalid); also we need their fdecl info when associating
 				// them with their receiver base type, below.
 				check.objMap[obj] = info
 				obj.setOrder(uint32(len(check.objMap)))
-
-			default:
-				check.invalidAST(d.Pos(), "unknown ast.Decl node %T", d)
 			}
-		}
+		})
 	}
 
 	// verify that objects in package and file scopes have different names
@@ -461,10 +430,10 @@
 		for _, obj := range scope.elems {
 			if alt := pkg.scope.Lookup(obj.Name()); alt != nil {
 				if pkg, ok := obj.(*PkgName); ok {
-					check.errorf(alt.Pos(), "%s already declared through import of %s", alt.Name(), pkg.Imported())
+					check.errorf(alt, _DuplicateDecl, "%s already declared through import of %s", alt.Name(), pkg.Imported())
 					check.reportAltDecl(pkg)
 				} else {
-					check.errorf(alt.Pos(), "%s already declared through dot-import of %s", alt.Name(), obj.Pkg())
+					check.errorf(alt, _DuplicateDecl, "%s already declared through dot-import of %s", alt.Name(), obj.Pkg())
 					// TODO(gri) dot-imported objects don't have a position; reportAltDecl won't print anything
 					check.reportAltDecl(obj)
 				}
@@ -476,16 +445,17 @@
 	// associate methods with receiver base type name where possible.
 	// Ignore methods that have an invalid receiver. They will be
 	// type-checked later, with regular functions.
-	if methods != nil {
-		check.methods = make(map[*TypeName][]*Func)
-		for i := range methods {
-			m := &methods[i]
-			// Determine the receiver base type and associate m with it.
-			ptr, base := check.resolveBaseTypeName(m.ptr, m.recv)
-			if base != nil {
-				m.obj.hasPtrRecv = ptr
-				check.methods[base] = append(check.methods[base], m.obj)
-			}
+	if methods == nil {
+		return // nothing to do
+	}
+	check.methods = make(map[*TypeName][]*Func)
+	for i := range methods {
+		m := &methods[i]
+		// Determine the receiver base type and associate m with it.
+		ptr, base := check.resolveBaseTypeName(m.ptr, m.recv)
+		if base != nil {
+			m.obj.hasPtrRecv = ptr
+			check.methods[base] = append(check.methods[base], m.obj)
 		}
 	}
 }
@@ -505,6 +475,7 @@
 		case *ast.ParenExpr:
 			rtyp = t.X
 		case *ast.StarExpr:
+			ptr = true
 			rtyp = t.X
 		default:
 			break L
@@ -526,9 +497,9 @@
 				case *ast.BadExpr:
 					// ignore - error already reported by parser
 				case nil:
-					check.invalidAST(ptyp.Pos(), "parameterized receiver contains nil parameters")
+					check.invalidAST(ptyp, "parameterized receiver contains nil parameters")
 				default:
-					check.errorf(arg.Pos(), "receiver type parameter %s must be an identifier", arg)
+					check.errorf(arg, _Todo, "receiver type parameter %s must be an identifier", arg)
 				}
 				if par == nil {
 					par = &ast.Ident{NamePos: arg.Pos(), Name: "_"}
@@ -550,7 +521,7 @@
 // there was a pointer indirection to get to it. The base type name must be declared
 // in package scope, and there can be at most one pointer indirection. If no such type
 // name exists, the returned base is nil.
-func (check *Checker) resolveBaseTypeName(seenPtr bool, typ ast.Expr) (ptr bool, base *TypeName) {
+func (check *Checker) resolveBaseTypeName(seenPtr bool, name *ast.Ident) (ptr bool, base *TypeName) {
 	// Algorithm: Starting from a type expression, which may be a name,
 	// we follow that type through alias declarations until we reach a
 	// non-alias type name. If we encounter anything but pointer types or
@@ -558,6 +529,7 @@
 	// we're done.
 	ptr = seenPtr
 	var seen map[*TypeName]bool
+	var typ ast.Expr = name
 	for {
 		typ = unparen(typ)
 
@@ -686,9 +658,9 @@
 					path := obj.imported.path
 					base := pkgName(path)
 					if obj.name == base {
-						check.softErrorf(obj.pos, "%q imported but not used", path)
+						check.softErrorf(obj, _UnusedImport, "%q imported but not used", path)
 					} else {
-						check.softErrorf(obj.pos, "%q imported but not used as %s", path, obj.name)
+						check.softErrorf(obj, _UnusedImport, "%q imported but not used as %s", path, obj.name)
 					}
 				}
 			}
@@ -698,7 +670,7 @@
 	// check use of dot-imported packages
 	for _, unusedDotImports := range check.unusedDotImports {
 		for pkg, pos := range unusedDotImports {
-			check.softErrorf(pos, "%q imported but not used", pkg.path)
+			check.softErrorf(pos, _UnusedImport, "%q imported but not used", pkg.path)
 		}
 	}
 }
diff --git a/src/go/types/sanitize.go b/src/go/types/sanitize.go
index 1408937..c4e729e 100644
--- a/src/go/types/sanitize.go
+++ b/src/go/types/sanitize.go
@@ -4,6 +4,8 @@
 
 package types
 
+// sanitizeInfo walks the types contained in info to ensure that all instances
+// are expanded.
 func sanitizeInfo(info *Info) {
 	var s sanitizer = make(map[Type]Type)
 
diff --git a/src/go/types/self_test.go b/src/go/types/self_test.go
index 10ad06f..262dc7b 100644
--- a/src/go/types/self_test.go
+++ b/src/go/types/self_test.go
@@ -5,12 +5,11 @@
 package types_test
 
 import (
-	"flag"
-	"fmt"
 	"go/ast"
 	"go/importer"
 	"go/parser"
 	"go/token"
+	"path"
 	"path/filepath"
 	"testing"
 	"time"
@@ -18,11 +17,9 @@
 	. "go/types"
 )
 
-var benchmark = flag.Bool("b", false, "run benchmarks")
-
 func TestSelf(t *testing.T) {
 	fset := token.NewFileSet()
-	files, err := pkgFiles(fset, ".")
+	files, err := pkgFiles(fset, ".", 0)
 	if err != nil {
 		t.Fatal(err)
 	}
@@ -39,36 +36,39 @@
 	}
 }
 
-func TestBenchmark(t *testing.T) {
-	if !*benchmark {
-		return
-	}
-
-	// We're not using testing's benchmarking mechanism directly
-	// because we want custom output.
-
-	for _, p := range []string{"types", "constant", filepath.Join("internal", "gcimporter")} {
-		path := filepath.Join("..", p)
-		runbench(t, path, false)
-		runbench(t, path, true)
-		fmt.Println()
+func BenchmarkCheck(b *testing.B) {
+	for _, p := range []string{
+		"net/http",
+		"go/parser",
+		"go/constant",
+		filepath.Join("go", "internal", "gcimporter"),
+	} {
+		b.Run(path.Base(p), func(b *testing.B) {
+			path := filepath.Join("..", "..", p)
+			for _, ignoreFuncBodies := range []bool{false, true} {
+				name := "funcbodies"
+				if ignoreFuncBodies {
+					name = "nofuncbodies"
+				}
+				b.Run(name, func(b *testing.B) {
+					b.Run("info", func(b *testing.B) {
+						runbench(b, path, ignoreFuncBodies, true)
+					})
+					b.Run("noinfo", func(b *testing.B) {
+						runbench(b, path, ignoreFuncBodies, false)
+					})
+				})
+			}
+		})
 	}
 }
 
-func runbench(t *testing.T, path string, ignoreFuncBodies bool) {
+func runbench(b *testing.B, path string, ignoreFuncBodies, writeInfo bool) {
 	fset := token.NewFileSet()
-	files, err := pkgFiles(fset, path)
+	files, err := pkgFiles(fset, path, 0)
 	if err != nil {
-		t.Fatal(err)
+		b.Fatal(err)
 	}
-
-	b := testing.Benchmark(func(b *testing.B) {
-		for i := 0; i < b.N; i++ {
-			conf := Config{IgnoreFuncBodies: ignoreFuncBodies}
-			conf.Check(path, fset, files, nil)
-		}
-	})
-
 	// determine line count
 	lines := 0
 	fset.Iterate(func(f *token.File) bool {
@@ -76,14 +76,33 @@
 		return true
 	})
 
-	d := time.Duration(b.NsPerOp())
-	fmt.Printf(
-		"%s: %s for %d lines (%d lines/s), ignoreFuncBodies = %v\n",
-		filepath.Base(path), d, lines, int64(float64(lines)/d.Seconds()), ignoreFuncBodies,
-	)
+	b.ResetTimer()
+	start := time.Now()
+	for i := 0; i < b.N; i++ {
+		conf := Config{
+			IgnoreFuncBodies: ignoreFuncBodies,
+			Importer:         importer.Default(),
+		}
+		var info *Info
+		if writeInfo {
+			info = &Info{
+				Types:      make(map[ast.Expr]TypeAndValue),
+				Defs:       make(map[*ast.Ident]Object),
+				Uses:       make(map[*ast.Ident]Object),
+				Implicits:  make(map[ast.Node]Object),
+				Selections: make(map[*ast.SelectorExpr]*Selection),
+				Scopes:     make(map[ast.Node]*Scope),
+			}
+		}
+		if _, err := conf.Check(path, fset, files, info); err != nil {
+			b.Fatal(err)
+		}
+	}
+	b.StopTimer()
+	b.ReportMetric(float64(lines)*float64(b.N)/time.Since(start).Seconds(), "lines/s")
 }
 
-func pkgFiles(fset *token.FileSet, path string) ([]*ast.File, error) {
+func pkgFiles(fset *token.FileSet, path string, mode parser.Mode) ([]*ast.File, error) {
 	filenames, err := pkgFilenames(path) // from stdlib_test.go
 	if err != nil {
 		return nil, err
@@ -91,7 +110,7 @@
 
 	var files []*ast.File
 	for _, filename := range filenames {
-		file, err := parser.ParseFile(fset, filename, nil, 0)
+		file, err := parser.ParseFile(fset, filename, nil, mode)
 		if err != nil {
 			return nil, err
 		}
diff --git a/src/go/types/stdlib_test.go b/src/go/types/stdlib_test.go
index 049d546..7a4a0ea 100644
--- a/src/go/types/stdlib_test.go
+++ b/src/go/types/stdlib_test.go
@@ -156,6 +156,9 @@
 	testTestDir(t, filepath.Join(runtime.GOROOT(), "test"),
 		"cmplxdivide.go", // also needs file cmplxdivide1.go - ignore
 		"directive.go",   // tests compiler rejection of bad directive placement - ignore
+		"embedfunc.go",   // tests //go:embed
+		"embedvers.go",   // tests //go:embed
+		"linkname2.go",   // go/types doesn't check validity of //go:xxx directives
 	)
 }
 
@@ -183,7 +186,8 @@
 		"issue31747.go",  // go/types does not have constraints on language level (-lang=go1.12) (see #31793)
 		"issue34329.go",  // go/types does not have constraints on language level (-lang=go1.13) (see #31793)
 		"bug251.go",      // issue #34333 which was exposed with fix for #34151
-		"bug299.go",      // go/types permits parenthesized embedded fields (TODO(gri) remove once we disallow this again because we switched to []'s)
+		"issue42058a.go", // go/types does not have constraints on channel element size
+		"issue42058b.go", // go/types does not have constraints on channel element size
 	)
 }
 
diff --git a/src/go/types/stmt.go b/src/go/types/stmt.go
index 1102fb6..82c21c2 100644
--- a/src/go/types/stmt.go
+++ b/src/go/types/stmt.go
@@ -14,7 +14,7 @@
 )
 
 func (check *Checker) funcBody(decl *declInfo, name string, sig *Signature, body *ast.BlockStmt, iota constant.Value) {
-	if check.conf.Trace {
+	if trace {
 		check.trace(body.Pos(), "--- %s: %s", name, sig)
 		defer func() {
 			check.trace(body.End(), "--- <end>")
@@ -46,7 +46,7 @@
 	}
 
 	if sig.results.Len() > 0 && !check.isTerminating(body, "") {
-		check.error(body.Rbrace, "missing return")
+		check.error(atPos(body.Rbrace), _MissingReturn, "missing return")
 	}
 
 	// TODO(gri) Should we make it an error to declare generic functions
@@ -70,7 +70,7 @@
 		return unused[i].pos < unused[j].pos
 	})
 	for _, v := range unused {
-		check.softErrorf(v.pos, "%s declared but not used", v.name)
+		check.softErrorf(v, _UnusedVar, "%s declared but not used", v.name)
 	}
 
 	for _, scope := range scope.children {
@@ -140,11 +140,11 @@
 				d = s
 			}
 		default:
-			check.invalidAST(s.Pos(), "case/communication clause expected")
+			check.invalidAST(s, "case/communication clause expected")
 		}
 		if d != nil {
 			if first != nil {
-				check.errorf(d.Pos(), "multiple defaults (first at %s)", check.fset.Position(first.Pos()))
+				check.errorf(d, _DuplicateDefault, "multiple defaults (first at %s)", check.fset.Position(first.Pos()))
 			} else {
 				first = d
 			}
@@ -173,17 +173,23 @@
 func (check *Checker) suspendedCall(keyword string, call *ast.CallExpr) {
 	var x operand
 	var msg string
+	var code errorCode
 	switch check.rawExpr(&x, call, nil) {
 	case conversion:
 		msg = "requires function call, not conversion"
+		code = _InvalidDefer
+		if keyword == "go" {
+			code = _InvalidGo
+		}
 	case expression:
 		msg = "discards result of"
+		code = _UnusedResults
 	case statement:
 		return
 	default:
 		unreachable()
 	}
-	check.errorf(x.pos(), "%s %s %s", keyword, msg, &x)
+	check.errorf(&x, code, "%s %s %s", keyword, msg, &x)
 }
 
 // goVal returns the Go value for val, or nil.
@@ -255,17 +261,17 @@
 			// (quadratic algorithm, but these lists tend to be very short)
 			for _, vt := range seen[val] {
 				if check.identical(v.typ, vt.typ) {
-					check.errorf(v.pos(), "duplicate case %s in expression switch", &v)
-					check.error(vt.pos, "\tprevious case") // secondary error, \t indented
+					check.errorf(&v, _DuplicateCase, "duplicate case %s in expression switch", &v)
+					check.error(atPos(vt.pos), _DuplicateCase, "\tprevious case") // secondary error, \t indented
 					continue L
 				}
 			}
-			seen[val] = append(seen[val], valueType{v.pos(), v.typ})
+			seen[val] = append(seen[val], valueType{v.Pos(), v.typ})
 		}
 	}
 }
 
-func (check *Checker) caseTypes(x *operand, xtyp *Interface, types []ast.Expr, seen map[Type]token.Pos, strict bool) (T Type) {
+func (check *Checker) caseTypes(x *operand, xtyp *Interface, types []ast.Expr, seen map[Type]ast.Expr) (T Type) {
 L:
 	for _, e := range types {
 		T = check.typeOrNil(e)
@@ -273,25 +279,25 @@
 			continue L
 		}
 		if T != nil {
-			check.ordinaryType(e.Pos(), T)
+			check.ordinaryType(e, T)
 		}
 		// look for duplicate types
 		// (quadratic algorithm, but type switches tend to be reasonably small)
-		for t, pos := range seen {
+		for t, other := range seen {
 			if T == nil && t == nil || T != nil && t != nil && check.identical(T, t) {
 				// talk about "case" rather than "type" because of nil case
 				Ts := "nil"
 				if T != nil {
 					Ts = T.String()
 				}
-				check.errorf(e.Pos(), "duplicate case %s in type switch", Ts)
-				check.error(pos, "\tprevious case") // secondary error, \t indented
+				check.errorf(e, _DuplicateCase, "duplicate case %s in type switch", Ts)
+				check.error(other, _DuplicateCase, "\tprevious case") // secondary error, \t indented
 				continue L
 			}
 		}
-		seen[T] = e.Pos()
+		seen[T] = e
 		if T != nil {
-			check.typeAssertion(e.Pos(), x, xtyp, T, strict)
+			check.typeAssertion(e, x, xtyp, T)
 		}
 	}
 	return
@@ -332,18 +338,22 @@
 		var x operand
 		kind := check.rawExpr(&x, s.X, nil)
 		var msg string
+		var code errorCode
 		switch x.mode {
 		default:
 			if kind == statement {
 				return
 			}
 			msg = "is not used"
+			code = _UnusedExpr
 		case builtin:
 			msg = "must be called"
+			code = _UncalledBuiltin
 		case typexpr:
 			msg = "is not an expression"
+			code = _NotAnExpr
 		}
-		check.errorf(x.pos(), "%s %s", &x, msg)
+		check.errorf(&x, code, "%s %s", &x, msg)
 
 	case *ast.SendStmt:
 		var ch, x operand
@@ -355,12 +365,12 @@
 
 		tch := asChan(ch.typ)
 		if tch == nil {
-			check.invalidOp(s.Arrow, "cannot send to non-chan type %s", ch.typ)
+			check.invalidOp(inNode(s, s.Arrow), _InvalidSend, "cannot send to non-chan type %s", ch.typ)
 			return
 		}
 
 		if tch.dir == RecvOnly {
-			check.invalidOp(s.Arrow, "cannot send to receive-only type %s", tch)
+			check.invalidOp(inNode(s, s.Arrow), _InvalidSend, "cannot send to receive-only type %s", tch)
 			return
 		}
 
@@ -374,7 +384,7 @@
 		case token.DEC:
 			op = token.SUB
 		default:
-			check.invalidAST(s.TokPos, "unknown inc/dec operation %s", s.Tok)
+			check.invalidAST(inNode(s, s.TokPos), "unknown inc/dec operation %s", s.Tok)
 			return
 		}
 
@@ -384,12 +394,12 @@
 			return
 		}
 		if !isNumeric(x.typ) {
-			check.invalidOp(s.X.Pos(), "%s%s (non-numeric type %s)", s.X, s.Tok, x.typ)
+			check.invalidOp(s.X, _NonNumericIncDec, "%s%s (non-numeric type %s)", s.X, s.Tok, x.typ)
 			return
 		}
 
 		Y := &ast.BasicLit{ValuePos: s.X.Pos(), Kind: token.INT, Value: "1"} // use x's position
-		check.binary(&x, nil, s.X, Y, op)
+		check.binary(&x, nil, s.X, Y, op, s.TokPos)
 		if x.mode == invalid {
 			return
 		}
@@ -399,11 +409,11 @@
 		switch s.Tok {
 		case token.ASSIGN, token.DEFINE:
 			if len(s.Lhs) == 0 {
-				check.invalidAST(s.Pos(), "missing lhs in assignment")
+				check.invalidAST(s, "missing lhs in assignment")
 				return
 			}
 			if s.Tok == token.DEFINE {
-				check.shortVarDecl(s.TokPos, s.Lhs, s.Rhs)
+				check.shortVarDecl(inNode(s, s.TokPos), s.Lhs, s.Rhs)
 			} else {
 				// regular assignment
 				check.assignVars(s.Lhs, s.Rhs)
@@ -412,16 +422,16 @@
 		default:
 			// assignment operations
 			if len(s.Lhs) != 1 || len(s.Rhs) != 1 {
-				check.errorf(s.TokPos, "assignment operation %s requires single-valued expressions", s.Tok)
+				check.errorf(inNode(s, s.TokPos), _MultiValAssignOp, "assignment operation %s requires single-valued expressions", s.Tok)
 				return
 			}
 			op := assignOp(s.Tok)
 			if op == token.ILLEGAL {
-				check.invalidAST(s.TokPos, "unknown assignment operation %s", s.Tok)
+				check.invalidAST(atPos(s.TokPos), "unknown assignment operation %s", s.Tok)
 				return
 			}
 			var x operand
-			check.binary(&x, nil, s.Lhs[0], s.Rhs[0], op)
+			check.binary(&x, nil, s.Lhs[0], s.Rhs[0], op, s.TokPos)
 			if x.mode == invalid {
 				return
 			}
@@ -445,8 +455,8 @@
 				// with the same name as a result parameter is in scope at the place of the return."
 				for _, obj := range res.vars {
 					if alt := check.lookup(obj.name); alt != nil && alt != obj {
-						check.errorf(s.Pos(), "result parameter %s not in scope at return", obj.name)
-						check.errorf(alt.Pos(), "\tinner declaration of %s", obj)
+						check.errorf(s, _OutOfScopeResult, "result parameter %s not in scope at return", obj.name)
+						check.errorf(alt, _OutOfScopeResult, "\tinner declaration of %s", obj)
 						// ok to continue
 					}
 				}
@@ -455,7 +465,7 @@
 				check.initVars(res.vars, s.Results, s.Return)
 			}
 		} else if len(s.Results) > 0 {
-			check.error(s.Results[0].Pos(), "no result values expected")
+			check.error(s.Results[0], _WrongResultCount, "no result values expected")
 			check.use(s.Results...)
 		}
 
@@ -467,22 +477,23 @@
 		switch s.Tok {
 		case token.BREAK:
 			if ctxt&breakOk == 0 {
-				check.error(s.Pos(), "break not in for, switch, or select statement")
+				check.error(s, _MisplacedBreak, "break not in for, switch, or select statement")
 			}
 		case token.CONTINUE:
 			if ctxt&continueOk == 0 {
-				check.error(s.Pos(), "continue not in for statement")
+				check.error(s, _MisplacedContinue, "continue not in for statement")
 			}
 		case token.FALLTHROUGH:
 			if ctxt&fallthroughOk == 0 {
 				msg := "fallthrough statement out of place"
+				code := _MisplacedFallthrough
 				if ctxt&finalSwitchCase != 0 {
 					msg = "cannot fallthrough final case in switch"
 				}
-				check.error(s.Pos(), msg)
+				check.error(s, code, msg)
 			}
 		default:
-			check.invalidAST(s.Pos(), "branch statement: %s", s.Tok)
+			check.invalidAST(s, "branch statement: %s", s.Tok)
 		}
 
 	case *ast.BlockStmt:
@@ -499,7 +510,7 @@
 		var x operand
 		check.expr(&x, s.Cond)
 		if x.mode != invalid && !isBoolean(x.typ) {
-			check.error(s.Cond.Pos(), "non-boolean condition in if statement")
+			check.error(s.Cond, _InvalidCond, "non-boolean condition in if statement")
 		}
 		check.stmt(inner, s.Body)
 		// The parser produces a correct AST but if it was modified
@@ -510,7 +521,7 @@
 		case *ast.IfStmt, *ast.BlockStmt:
 			check.stmt(inner, s.Else)
 		default:
-			check.error(s.Else.Pos(), "invalid else branch in if statement")
+			check.invalidAST(s.Else, "invalid else branch in if statement")
 		}
 
 	case *ast.SwitchStmt:
@@ -525,6 +536,10 @@
 			// By checking assignment of x to an invisible temporary
 			// (as a compiler would), we get all the relevant checks.
 			check.assignment(&x, nil, "switch expression")
+			if x.mode != invalid && !Comparable(x.typ) && !hasNil(x.typ) {
+				check.errorf(&x, _InvalidExprSwitch, "cannot switch on %s (%s is not comparable)", &x, x.typ)
+				x.mode = invalid
+			}
 		} else {
 			// spec: "A missing switch expression is
 			// equivalent to the boolean value true."
@@ -540,7 +555,7 @@
 		for i, c := range s.Body.List {
 			clause, _ := c.(*ast.CaseClause)
 			if clause == nil {
-				check.invalidAST(c.Pos(), "incorrect expression switch case")
+				check.invalidAST(c, "incorrect expression switch case")
 				continue
 			}
 			check.caseValues(&x, clause.List, seen)
@@ -577,19 +592,19 @@
 			rhs = guard.X
 		case *ast.AssignStmt:
 			if len(guard.Lhs) != 1 || guard.Tok != token.DEFINE || len(guard.Rhs) != 1 {
-				check.invalidAST(s.Pos(), "incorrect form of type switch guard")
+				check.invalidAST(s, "incorrect form of type switch guard")
 				return
 			}
 
 			lhs, _ = guard.Lhs[0].(*ast.Ident)
 			if lhs == nil {
-				check.invalidAST(s.Pos(), "incorrect form of type switch guard")
+				check.invalidAST(s, "incorrect form of type switch guard")
 				return
 			}
 
 			if lhs.Name == "_" {
 				// _ := x.(type) is an invalid short variable declaration
-				check.softErrorf(lhs.Pos(), "no new variable on left side of :=")
+				check.softErrorf(lhs, _NoNewVar, "no new variable on left side of :=")
 				lhs = nil // avoid declared but not used error below
 			} else {
 				check.recordDef(lhs, nil) // lhs variable is implicitly declared in each cause clause
@@ -598,14 +613,14 @@
 			rhs = guard.Rhs[0]
 
 		default:
-			check.invalidAST(s.Pos(), "incorrect form of type switch guard")
+			check.invalidAST(s, "incorrect form of type switch guard")
 			return
 		}
 
 		// rhs must be of the form: expr.(type) and expr must be an ordinary interface
 		expr, _ := rhs.(*ast.TypeAssertExpr)
 		if expr == nil || expr.Type != nil {
-			check.invalidAST(s.Pos(), "incorrect form of type switch guard")
+			check.invalidAST(s, "incorrect form of type switch guard")
 			return
 		}
 		var x operand
@@ -615,23 +630,23 @@
 		}
 		xtyp, _ := under(x.typ).(*Interface)
 		if xtyp == nil {
-			check.errorf(x.pos(), "%s is not an interface type", &x)
+			check.errorf(&x, _InvalidTypeSwitch, "%s is not an interface", &x)
 			return
 		}
-		check.ordinaryType(x.pos(), xtyp)
+		check.ordinaryType(&x, xtyp)
 
 		check.multipleDefaults(s.Body.List)
 
-		var lhsVars []*Var               // list of implicitly declared lhs variables
-		seen := make(map[Type]token.Pos) // map of seen types to positions
+		var lhsVars []*Var              // list of implicitly declared lhs variables
+		seen := make(map[Type]ast.Expr) // map of seen types to positions
 		for _, s := range s.Body.List {
 			clause, _ := s.(*ast.CaseClause)
 			if clause == nil {
-				check.invalidAST(s.Pos(), "incorrect type switch case")
+				check.invalidAST(s, "incorrect type switch case")
 				continue
 			}
 			// Check each type in this type switch case.
-			T := check.caseTypes(&x, xtyp, clause.List, seen, false)
+			T := check.caseTypes(&x, xtyp, clause.List, seen)
 			check.openScope(clause, "case")
 			// If lhs exists, declare a corresponding variable in the case-local scope.
 			if lhs != nil {
@@ -669,7 +684,7 @@
 				v.used = true // avoid usage error when checking entire function
 			}
 			if !used {
-				check.softErrorf(lhs.Pos(), "%s declared but not used", lhs.Name)
+				check.softErrorf(lhs, _UnusedVar, "%s declared but not used", lhs.Name)
 			}
 		}
 
@@ -706,7 +721,7 @@
 			}
 
 			if !valid {
-				check.error(clause.Comm.Pos(), "select case must be send or receive (possibly with assignment)")
+				check.error(clause.Comm, _InvalidSelectCase, "select case must be send or receive (possibly with assignment)")
 				continue
 			}
 
@@ -728,14 +743,14 @@
 			var x operand
 			check.expr(&x, s.Cond)
 			if x.mode != invalid && !isBoolean(x.typ) {
-				check.error(s.Cond.Pos(), "non-boolean condition in for statement")
+				check.error(s.Cond, _InvalidCond, "non-boolean condition in for statement")
 			}
 		}
 		check.simpleStmt(s.Post)
 		// spec: "The init statement may be a short variable
 		// declaration, but the post statement must not."
 		if s, _ := s.Post.(*ast.AssignStmt); s != nil && s.Tok == token.DEFINE {
-			check.softErrorf(s.Pos(), "cannot declare in post statement")
+			check.softErrorf(s, _InvalidPostDecl, "cannot declare in post statement")
 			// Don't call useLHS here because we want to use the lhs in
 			// this erroneous statement so that we don't get errors about
 			// these lhs variables being declared but not used.
@@ -758,16 +773,17 @@
 			typ := optype(x.typ)
 			if _, ok := typ.(*Chan); ok && s.Value != nil {
 				// TODO(gri) this also needs to happen for channels in generic variables
-				check.softErrorf(s.Value.Pos(), "range over %s permits only one iteration variable", &x)
+				check.softErrorf(atPos(s.Value.Pos()), _InvalidIterVar, "range over %s permits only one iteration variable", &x)
 				// ok to continue
 			}
 			var msg string
 			key, val, msg = rangeKeyVal(typ, isVarName(s.Key), isVarName(s.Value))
 			if key == nil || msg != "" {
 				if msg != "" {
+					// TODO(rFindley) should this be parenthesized, to be consistent with other qualifiers?
 					msg = ": " + msg
 				}
-				check.softErrorf(x.pos(), "cannot range over %s%s", &x, msg)
+				check.softErrorf(&x, _InvalidRangeExpr, "cannot range over %s%s", &x, msg)
 				// ok to continue
 			}
 		}
@@ -801,7 +817,7 @@
 						vars = append(vars, obj)
 					}
 				} else {
-					check.errorf(lhs.Pos(), "cannot declare %s", lhs)
+					check.invalidAST(lhs, "cannot declare %s", lhs)
 					obj = NewVar(lhs.Pos(), check.pkg, "_", nil) // dummy variable
 				}
 
@@ -828,7 +844,7 @@
 					check.declare(check.scope, nil /* recordDef already called */, obj, scopePos)
 				}
 			} else {
-				check.error(s.TokPos, "no new variables on left side of :=")
+				check.error(inNode(s, s.TokPos), _NoNewVar, "no new variables on left side of :=")
 			}
 		} else {
 			// ordinary assignment
@@ -848,7 +864,7 @@
 		check.stmt(inner, s.Body)
 
 	default:
-		check.error(s.Pos(), "invalid statement")
+		check.invalidAST(s, "invalid statement")
 	}
 }
 
diff --git a/src/go/types/subst.go b/src/go/types/subst.go
index 00f60dc..ed27488 100644
--- a/src/go/types/subst.go
+++ b/src/go/types/subst.go
@@ -14,6 +14,9 @@
 	"go/token"
 )
 
+// TODO(rFindley) decide error codes for the errors in this file, and check
+//                if error spans can be improved
+
 type substMap struct {
 	// The targs field is currently needed for *Named type substitution.
 	// TODO(gri) rewrite that code, get rid of this field, and make this
@@ -28,7 +31,7 @@
 	assert(len(tpars) == len(targs))
 	proj := make(map[*TypeParam]Type, len(tpars))
 	for i, tpar := range tpars {
-		// We must expand type arguments otherwise *Instance
+		// We must expand type arguments otherwise *instance
 		// types end up as components in composite types.
 		// TODO(gri) explain why this causes problems, if it does
 		targ := expand(targs[i]) // possibly nil
@@ -54,7 +57,7 @@
 }
 
 func (check *Checker) instantiate(pos token.Pos, typ Type, targs []Type, poslist []token.Pos) (res Type) {
-	if check.conf.Trace {
+	if trace {
 		check.trace(pos, "-- instantiating %s with %s", typ, typeListString(targs))
 		check.indent++
 		defer func() {
@@ -70,7 +73,7 @@
 		}()
 	}
 
-	assert(poslist == nil || len(poslist) <= len(targs))
+	assert(len(poslist) <= len(targs))
 
 	// TODO(gri) What is better here: work with TypeParams, or work with TypeNames?
 	var tparams []*TypeName
@@ -80,9 +83,10 @@
 	case *Signature:
 		tparams = t.tparams
 		defer func() {
-			// If we had an unexpected failure somewhere don't
-			// panic below when asserting res.(*Signature).
-			if res == nil {
+			// If we had an unexpected failure somewhere don't panic below when
+			// asserting res.(*Signature). Check for *Signature in case Typ[Invalid]
+			// is returned.
+			if _, ok := res.(*Signature); !ok {
 				return
 			}
 			// If the signature doesn't use its type parameters, subst
@@ -100,13 +104,12 @@
 	default:
 		check.dump("%v: cannot instantiate %v", pos, typ)
 		unreachable() // only defined types and (defined) functions can be generic
-
 	}
 
 	// the number of supplied types must match the number of type parameters
 	if len(targs) != len(tparams) {
 		// TODO(gri) provide better error message
-		check.errorf(pos, "got %d arguments but %d type parameters", len(targs), len(tparams))
+		check.errorf(atPos(pos), _Todo, "got %d arguments but %d type parameters", len(targs), len(tparams))
 		return Typ[Invalid]
 	}
 
@@ -142,42 +145,31 @@
 		// - check only if we have methods
 		check.completeInterface(token.NoPos, iface)
 		if len(iface.allMethods) > 0 {
-			// If the type argument is a type parameter itself, its pointer designation
-			// must match the pointer designation of the callee's type parameter.
 			// If the type argument is a pointer to a type parameter, the type argument's
 			// method set is empty.
 			// TODO(gri) is this what we want? (spec question)
-			if tparg := asTypeParam(targ); tparg != nil {
-				if tparg.ptr != tpar.ptr {
-					check.errorf(pos, "pointer designation mismatch")
-					break
-				}
-			} else if base, isPtr := deref(targ); isPtr && asTypeParam(base) != nil {
-				check.errorf(pos, "%s has no methods", targ)
+			if base, isPtr := deref(targ); isPtr && asTypeParam(base) != nil {
+				check.errorf(atPos(pos), 0, "%s has no methods", targ)
 				break
 			}
-			// If a type parameter is marked as a pointer type, the type bound applies
-			// to a pointer of the type argument.
-			actual := targ
-			if tpar.ptr {
-				actual = NewPointer(targ)
-			}
-			if m, wrong := check.missingMethod(actual, iface, true); m != nil {
+			if m, wrong := check.missingMethod(targ, iface, true); m != nil {
 				// TODO(gri) needs to print updated name to avoid major confusion in error message!
 				//           (print warning for now)
+				// Old warning:
 				// check.softErrorf(pos, "%s does not satisfy %s (warning: name not updated) = %s (missing method %s)", targ, tpar.bound, iface, m)
 				if m.name == "==" {
 					// We don't want to report "missing method ==".
-					check.softErrorf(pos, "%s does not satisfy comparable", targ)
+					check.softErrorf(atPos(pos), 0, "%s does not satisfy comparable", targ)
 				} else if wrong != nil {
 					// TODO(gri) This can still report uninstantiated types which makes the error message
 					//           more difficult to read then necessary.
-					check.softErrorf(pos,
+					// TODO(rFindley) should this use parentheses rather than ':' for qualification?
+					check.softErrorf(atPos(pos), _Todo,
 						"%s does not satisfy %s: wrong method signature\n\tgot  %s\n\twant %s",
 						targ, tpar.bound, wrong, m,
 					)
 				} else {
-					check.softErrorf(pos, "%s does not satisfy %s (missing method %s)", targ, tpar.bound, m.name)
+					check.softErrorf(atPos(pos), 0, "%s does not satisfy %s (missing method %s)", targ, tpar.bound, m.name)
 				}
 				break
 			}
@@ -187,20 +179,19 @@
 		if iface.allTypes == nil {
 			continue // nothing to do
 		}
-		// iface.allTypes != nil
 
 		// If targ is itself a type parameter, each of its possible types, but at least one, must be in the
 		// list of iface types (i.e., the targ type list must be a non-empty subset of the iface types).
 		if targ := asTypeParam(targ); targ != nil {
 			targBound := targ.Bound()
 			if targBound.allTypes == nil {
-				check.softErrorf(pos, "%s does not satisfy %s (%s has no type constraints)", targ, tpar.bound, targ)
+				check.softErrorf(atPos(pos), _Todo, "%s does not satisfy %s (%s has no type constraints)", targ, tpar.bound, targ)
 				break
 			}
-			for _, t := range unpack(targBound.allTypes) {
+			for _, t := range unpackType(targBound.allTypes) {
 				if !iface.isSatisfiedBy(t) {
 					// TODO(gri) match this error message with the one below (or vice versa)
-					check.softErrorf(pos, "%s does not satisfy %s (%s type constraint %s not found in %s)", targ, tpar.bound, targ, t, iface.allTypes)
+					check.softErrorf(atPos(pos), 0, "%s does not satisfy %s (%s type constraint %s not found in %s)", targ, tpar.bound, targ, t, iface.allTypes)
 					break
 				}
 			}
@@ -209,7 +200,7 @@
 
 		// Otherwise, targ's type or underlying type must also be one of the interface types listed, if any.
 		if !iface.isSatisfiedBy(targ) {
-			check.softErrorf(pos, "%s does not satisfy %s (%s or %s not found in %s)", targ, tpar.bound, targ, under(targ), iface.allTypes)
+			check.softErrorf(atPos(pos), _Todo, "%s does not satisfy %s (%s or %s not found in %s)", targ, tpar.bound, targ, under(targ), iface.allTypes)
 			break
 		}
 	}
@@ -290,7 +281,9 @@
 		results := subst.tuple(t.results)
 		if recv != t.recv || params != t.params || results != t.results {
 			return &Signature{
-				rparams:  t.rparams,
+				rparams: t.rparams,
+				// TODO(rFindley) why can't we nil out tparams here, rather than in
+				//                instantiate above?
 				tparams:  t.tparams,
 				scope:    t.scope,
 				recv:     recv,
@@ -342,7 +335,7 @@
 			subst.check.indent--
 		}()
 		dump := func(format string, args ...interface{}) {
-			if subst.check.conf.Trace {
+			if trace {
 				subst.check.trace(subst.pos, format, args...)
 			}
 		}
@@ -352,10 +345,9 @@
 			return t // type is not parameterized
 		}
 
-		var new_targs []Type
+		var newTargs []Type
 
 		if len(t.targs) > 0 {
-
 			// already instantiated
 			dump(">>> %s already instantiated", t)
 			assert(len(t.targs) == len(t.tparams))
@@ -364,32 +356,30 @@
 			// that has a type argument for it.
 			for i, targ := range t.targs {
 				dump(">>> %d targ = %s", i, targ)
-				new_targ := subst.typ(targ)
-				if new_targ != targ {
-					dump(">>> substituted %d targ %s => %s", i, targ, new_targ)
-					if new_targs == nil {
-						new_targs = make([]Type, len(t.tparams))
-						copy(new_targs, t.targs)
+				newTarg := subst.typ(targ)
+				if newTarg != targ {
+					dump(">>> substituted %d targ %s => %s", i, targ, newTarg)
+					if newTargs == nil {
+						newTargs = make([]Type, len(t.tparams))
+						copy(newTargs, t.targs)
 					}
-					new_targs[i] = new_targ
+					newTargs[i] = newTarg
 				}
 			}
 
-			if new_targs == nil {
+			if newTargs == nil {
 				dump(">>> nothing to substitute in %s", t)
 				return t // nothing to substitute
 			}
-
 		} else {
-
 			// not yet instantiated
 			dump(">>> first instantiation of %s", t)
-			new_targs = subst.smap.targs
-
+			// TODO(rFindley) can we instead subst the tparam types here?
+			newTargs = subst.smap.targs
 		}
 
 		// before creating a new named type, check if we have this one already
-		h := instantiatedHash(t, new_targs)
+		h := instantiatedHash(t, newTargs)
 		dump(">>> new type hash: %s", h)
 		if named, found := subst.check.typMap[h]; found {
 			dump(">>> found %s", named)
@@ -401,12 +391,12 @@
 		tname := NewTypeName(subst.pos, t.obj.pkg, t.obj.name, nil)
 		named := subst.check.NewNamed(tname, t.underlying, t.methods) // method signatures are updated lazily
 		named.tparams = t.tparams                                     // new type is still parameterized
-		named.targs = new_targs
+		named.targs = newTargs
 		subst.check.typMap[h] = named
 		subst.cache[t] = named
 
 		// do the substitution
-		dump(">>> subst %s with %s (new: %s)", t.underlying, subst.smap, new_targs)
+		dump(">>> subst %s with %s (new: %s)", t.underlying, subst.smap, newTargs)
 		named.underlying = subst.typOrNil(t.underlying)
 		named.orig = named.underlying // for cycle detection (Checker.validType)
 
@@ -431,9 +421,9 @@
 func instantiatedHash(typ *Named, targs []Type) string {
 	var buf bytes.Buffer
 	writeTypeName(&buf, typ.obj, nil)
-	buf.WriteByte('(')
+	buf.WriteByte('[')
 	writeTypeList(&buf, targs, nil, nil)
-	buf.WriteByte(')')
+	buf.WriteByte(']')
 
 	// With respect to the represented type, whether a
 	// type is fully expanded or stored as instance
diff --git a/src/go/types/testdata/builtins.src b/src/go/types/testdata/builtins.src
index 69cc487..3c273b0 100644
--- a/src/go/types/testdata/builtins.src
+++ b/src/go/types/testdata/builtins.src
@@ -25,19 +25,19 @@
 	_ = append(s, b)
 	_ = append(s, x /* ERROR cannot use x */ )
 	_ = append(s, s /* ERROR cannot use s */ )
-	_ = append(s... ) /* ERROR not enough arguments */
-	_ = append(s, b, s /* ERROR too many arguments */ ... )
+	_ = append(s...) /* ERROR not enough arguments */
+	_ = append(s, b, s /* ERROR too many arguments */ ...)
 	_ = append(s, 1, 2, 3)
 	_ = append(s, 1, 2, 3, x /* ERROR cannot use x */ , 5, 6, 6)
-	_ = append(s, 1, 2 /* ERROR too many arguments */ , s... )
+	_ = append(s, 1, 2 /* ERROR too many arguments */, s...)
 	_ = append([]interface{}(nil), 1, 2, "foo", x, 3.1425, false)
 
 	type S []byte
 	type T string
 	var t T
-	_ = append(s, "foo" /* ERROR cannot convert */ )
+	_ = append(s, "foo" /* ERROR cannot use .* in argument to append */ )
 	_ = append(s, "foo"...)
-	_ = append(S(s), "foo" /* ERROR cannot convert */ )
+	_ = append(S(s), "foo" /* ERROR cannot use .* in argument to append */ )
 	_ = append(S(s), "foo"...)
 	_ = append(s, t /* ERROR cannot use t */ )
 	_ = append(s, t...)
@@ -482,7 +482,7 @@
 }
 
 func make2() {
-	f1 := func() (x []int) { return }
+	f1 /* ERROR not used */ := func() (x []int) { return }
 	_ = make(f0 /* ERROR not a type */ ())
 	_ = make(f1 /* ERROR not a type */ ())
 }
@@ -502,7 +502,7 @@
 }
 
 func new2() {
-	f1 := func() (x []int) { return }
+	f1 /* ERROR not used */ := func() (x []int) { return }
 	_ = new(f0 /* ERROR not a type */ ())
 	_ = new(f1 /* ERROR not a type */ ())
 }
diff --git a/src/go/types/testdata/constdecl.src b/src/go/types/testdata/constdecl.src
index c2f40ed..680c85a 100644
--- a/src/go/types/testdata/constdecl.src
+++ b/src/go/types/testdata/constdecl.src
@@ -107,4 +107,35 @@
 	const x, y, z = 0, 1, unsafe.Sizeof(func() { _ = x /* ERROR "undeclared name" */ + y /* ERROR "undeclared name" */ + z /* ERROR "undeclared name" */ })
 }
 
+// Test cases for errors in inherited constant initialization expressions.
+// Errors related to inherited initialization expressions must appear at
+// the constant identifier being declared, not at the original expression
+// (issues #42991, #42992).
+const (
+	_ byte = 255 + iota
+	/* some gap */
+	_ // ERROR overflows
+	/* some gap */
+	/* some gap */ _ /* ERROR overflows */; _ /* ERROR overflows */
+	/* some gap */
+	_ = 255 + iota
+	_ = byte /* ERROR overflows */ (255) + iota
+	_ /* ERROR overflows */
+)
+
+// Test cases from issue.
+const (
+	ok = byte(iota + 253)
+	bad
+	barn
+	bard // ERROR cannot convert
+)
+
+const (
+	c = len([1 - iota]int{})
+	d
+	e // ERROR invalid array length
+	f // ERROR invalid array length
+)
+
 // TODO(gri) move extra tests from testdata/const0.src into here
diff --git a/src/go/types/testdata/cycles.src b/src/go/types/testdata/cycles.src
index b2ee8ec..218b4ca 100644
--- a/src/go/types/testdata/cycles.src
+++ b/src/go/types/testdata/cycles.src
@@ -65,7 +65,7 @@
 	I6 interface{ I5 }
 
 	// maps
-	M0 map[M0 /* ERROR invalid map key */ ]M0
+	M0 map[M0 /* ERROR incomparable map key */ ]M0
 
 	// channels
 	C0 chan C0
@@ -114,7 +114,7 @@
 		i0 /* ERROR cycle */ interface{ i0 }
 
 		// maps
-		m0 map[m0 /* ERROR invalid map key */ ]m0
+		m0 map[m0 /* ERROR incomparable map key */ ]m0
 
 		// channels
 		c0 chan c0
@@ -123,10 +123,10 @@
 
 // test cases for issue 6667
 
-type A [10]map[A /* ERROR invalid map key */ ]bool
+type A [10]map[A /* ERROR incomparable map key */ ]bool
 
 type S struct {
-	m map[S /* ERROR invalid map key */ ]bool
+	m map[S /* ERROR incomparable map key */ ]bool
 }
 
 // test cases for issue 7236
diff --git a/src/go/types/testdata/cycles2.src b/src/go/types/testdata/cycles2.src
index 5fd9e83..1a7f40a 100644
--- a/src/go/types/testdata/cycles2.src
+++ b/src/go/types/testdata/cycles2.src
@@ -37,7 +37,7 @@
 }
 
 type B interface {
-	a() interface {
+	b() interface {
 		AB
 	}
 }
@@ -59,8 +59,7 @@
 	B
 }
 
-// TODO(gri) This should be a valid compare. See #33656.
-var _ = x /* ERROR cannot compare */ == y
+var _ = x == y
 
 
 // Test case for issue 6638.
diff --git a/src/go/types/testdata/decls0.src b/src/go/types/testdata/decls0.src
index 917cc78..5ad8f53 100644
--- a/src/go/types/testdata/decls0.src
+++ b/src/go/types/testdata/decls0.src
@@ -184,11 +184,13 @@
 func f2(x *f2 /* ERROR "not a type" */ ) {}
 func f3() (x f3 /* ERROR "not a type" */ ) { return }
 func f4() (x *f4 /* ERROR "not a type" */ ) { return }
+// TODO(#43215) this should be detected as a cycle error
+func f5([unsafe.Sizeof(f5)]int) {}
 
-func (S0) m1(x S0 /* ERROR value .* is not a type */ .m1) {}
-func (S0) m2(x *S0 /* ERROR value .* is not a type */ .m2) {}
-func (S0) m3() (x S0 /* ERROR value .* is not a type */ .m3) { return }
-func (S0) m4() (x *S0 /* ERROR value .* is not a type */ .m4) { return }
+func (S0) m1 (x S0 /* ERROR value .* is not a type */ .m1) {}
+func (S0) m2 (x *S0 /* ERROR value .* is not a type */ .m2) {}
+func (S0) m3 () (x S0 /* ERROR value .* is not a type */ .m3) { return }
+func (S0) m4 () (x *S0 /* ERROR value .* is not a type */ .m4) { return }
 
 // interfaces may not have any blank methods
 type BlankI interface {
diff --git a/src/go/types/testdata/decls1.src b/src/go/types/testdata/decls1.src
index e6beb78..f4d2eab 100644
--- a/src/go/types/testdata/decls1.src
+++ b/src/go/types/testdata/decls1.src
@@ -96,6 +96,8 @@
 	v11 = xx/yy*yy - xx
 	v12 = true && false
 	v13 = nil /* ERROR "use of untyped nil" */
+	v14 string = 257 // ERROR cannot use 257 .* as string value in variable declaration$
+	v15 int8 = 257 // ERROR cannot use 257 .* as int8 value in variable declaration .*overflows
 )
 
 // Multiple assignment expressions
diff --git a/src/go/types/testdata/decls2/decls2b.src b/src/go/types/testdata/decls2/decls2b.src
index 8e82c6d..5c55750 100644
--- a/src/go/types/testdata/decls2/decls2b.src
+++ b/src/go/types/testdata/decls2/decls2b.src
@@ -40,17 +40,17 @@
 // Verify by checking that errors are reported.
 func (T /* ERROR "undeclared" */ ) _() {}
 func (T1) _(undeclared /* ERROR "undeclared" */ ) {}
-func (T1) _() int { return "foo" /* ERROR "cannot convert" */ }
+func (T1) _() int { return "foo" /* ERROR "cannot use .* in return statement" */ }
 
 // Methods with undeclared receiver type can still be checked.
 // Verify by checking that errors are reported.
 func (Foo /* ERROR "undeclared" */ ) m() {}
 func (Foo /* ERROR "undeclared" */ ) m(undeclared /* ERROR "undeclared" */ ) {}
-func (Foo /* ERROR "undeclared" */ ) m() int { return "foo" /* ERROR "cannot convert" */ }
+func (Foo /* ERROR "undeclared" */ ) m() int { return "foo" /* ERROR "cannot use .* in return statement" */ }
 
 func (Foo /* ERROR "undeclared" */ ) _() {}
 func (Foo /* ERROR "undeclared" */ ) _(undeclared /* ERROR "undeclared" */ ) {}
-func (Foo /* ERROR "undeclared" */ ) _() int { return "foo" /* ERROR "cannot convert" */ }
+func (Foo /* ERROR "undeclared" */ ) _() int { return "foo" /* ERROR "cannot use .* in return statement" */ }
 
 // Receiver declarations are regular parameter lists;
 // receiver types may use parentheses, and the list
@@ -72,4 +72,4 @@
 	_ = (*T7).m4
 	_ = (*T7).m5
 	_ = (*T7).m6
-)
\ No newline at end of file
+)
diff --git a/src/go/types/testdata/expr3.src b/src/go/types/testdata/expr3.src
index 1aa21b6..c3158e6 100644
--- a/src/go/types/testdata/expr3.src
+++ b/src/go/types/testdata/expr3.src
@@ -7,9 +7,8 @@
 import "time"
 
 func indexes() {
-	var x int
 	_ = 1 /* ERROR "cannot index" */ [0]
-	_ = x /* ERROR "cannot index" */ [0]
+	_ = indexes /* ERROR "cannot index" */ [0]
 	_ = ( /* ERROR "cannot slice" */ 12 + 3)[1:2]
 
 	var a [10]int
@@ -44,9 +43,9 @@
 	_ = a[:10:10]
 	_ = a[:11 /* ERROR "index .* out of bounds" */ :10]
 	_ = a[:10:11 /* ERROR "index .* out of bounds" */ ]
-	_ = a[10:0:10] /* ERROR "invalid slice indices" */
-	_ = a[0:10:0] /* ERROR "invalid slice indices" */
-	_ = a[10:0:0] /* ERROR "invalid slice indices" */
+	_ = a[10:0:10] /* ERROR swapped slice indices" */
+	_ = a[0:10:0] /* ERROR "swapped slice indices" */
+	_ = a[10:0:0] /* ERROR "swapped slice indices" */
 	_ = &a /* ERROR "cannot take address" */ [:10]
 
 	pa := &a
@@ -62,9 +61,9 @@
 	_ = pa[:10:10]
 	_ = pa[:11 /* ERROR "index .* out of bounds" */ :10]
 	_ = pa[:10:11 /* ERROR "index .* out of bounds" */ ]
-	_ = pa[10:0:10] /* ERROR "invalid slice indices" */
-	_ = pa[0:10:0] /* ERROR "invalid slice indices" */
-	_ = pa[10:0:0] /* ERROR "invalid slice indices" */
+	_ = pa[10:0:10] /* ERROR "swapped slice indices" */
+	_ = pa[0:10:0] /* ERROR "swapped slice indices" */
+	_ = pa[10:0:0] /* ERROR "swapped slice indices" */
 	_ = &pa /* ERROR "cannot take address" */ [:10]
 
 	var b [0]int
@@ -82,20 +81,20 @@
 	_ = s[: - /* ERROR "negative" */ 1]
 	_ = s[0]
 	_ = s[1:2]
-	_ = s[2:1] /* ERROR "invalid slice indices" */
+	_ = s[2:1] /* ERROR "swapped slice indices" */
 	_ = s[2:]
 	_ = s[: 1 /* ERROR "overflows" */ <<100]
 	_ = s[1 /* ERROR "overflows" */ <<100 :]
 	_ = s[1 /* ERROR "overflows" */ <<100 : 1 /* ERROR "overflows" */ <<100]
 	_ = s[: /* ERROR "2nd index required" */ :  /* ERROR "3rd index required" */ ]
 	_ = s[:10:10]
-	_ = s[10:0:10] /* ERROR "invalid slice indices" */
-	_ = s[0:10:0] /* ERROR "invalid slice indices" */
-	_ = s[10:0:0] /* ERROR "invalid slice indices" */
+	_ = s[10:0:10] /* ERROR "swapped slice indices" */
+	_ = s[0:10:0] /* ERROR "swapped slice indices" */
+	_ = s[10:0:0] /* ERROR "swapped slice indices" */
 	_ = &s /* ERROR "cannot take address" */ [:10]
 
 	var m map[string]int
-	_ = m[0 /* ERROR "cannot convert" */ ]
+	_ = m[0 /* ERROR "cannot use .* in map index" */ ]
 	_ = m /* ERROR "cannot slice" */ ["foo" : "bar"]
 	_ = m["foo"]
 	// ok is of type bool
@@ -103,7 +102,7 @@
 	var ok mybool
 	_, ok = m["bar"]
 	_ = ok
-	_ = m[0 /* ERROR "cannot convert 0" */ ] + "foo" // ERROR "cannot convert"
+	_ = m[0 /* ERROR "cannot use 0" */ ] + "foo" // ERROR "cannot convert"
 
 	var t string
 	_ = t[- /* ERROR "negative" */ 1]
@@ -186,7 +185,7 @@
 	_ = T1{aa /* ERROR "unknown field" */ : 0}
 	_ = T1{1 /* ERROR "invalid field name" */ : 0}
 	_ = T1{a: 0, s: "foo", u: 0, a /* ERROR "duplicate field" */: 10}
-	_ = T1{a: "foo" /* ERROR "cannot convert" */ }
+	_ = T1{a: "foo" /* ERROR "cannot use .* in struct literal" */ }
 	_ = T1{c /* ERROR "unknown field" */ : 0}
 	_ = T1{T0: { /* ERROR "missing type" */ }} // struct literal element type may not be elided
 	_ = T1{T0: T0{}}
@@ -197,7 +196,7 @@
 	_ = T0{1, b /* ERROR "mixture" */ : 2, 3}
 	_ = T0{1, 2} /* ERROR "too few values" */
 	_ = T0{1, 2, 3, 4  /* ERROR "too many values" */ }
-	_ = T0{1, "foo" /* ERROR "cannot convert" */, 3.4  /* ERROR "truncated" */}
+	_ = T0{1, "foo" /* ERROR "cannot use .* in struct literal" */, 3.4  /* ERROR "cannot use .*\(truncated\)" */}
 
 	// invalid type
 	type P *struct{
@@ -237,7 +236,7 @@
 	_ = A1{5: 5, 6, 7, 4: 4, 1 /* ERROR "overflows" */ <<100: 4}
 	_ = A1{2.0}
 	_ = A1{2.1 /* ERROR "truncated" */ }
-	_ = A1{"foo" /* ERROR "cannot convert" */ }
+	_ = A1{"foo" /* ERROR "cannot use .* in array or slice literal" */ }
 
 	// indices must be integer constants
 	i := 1
@@ -303,7 +302,7 @@
 	_ = S0{5: 5, 6, 7, 4: 4, 1 /* ERROR "overflows" */ <<100: 4}
 	_ = S0{2.0}
 	_ = S0{2.1 /* ERROR "truncated" */ }
-	_ = S0{"foo" /* ERROR "cannot convert" */ }
+	_ = S0{"foo" /* ERROR "cannot use .* in array or slice literal" */ }
 
 	// indices must be resolved correctly
 	const index1 = 1
@@ -356,8 +355,8 @@
 
 	_ = M0{}
 	_ = M0{1 /* ERROR "missing key" */ }
-	_ = M0{1 /* ERROR "cannot convert" */ : 2}
-	_ = M0{"foo": "bar" /* ERROR "cannot convert" */ }
+	_ = M0{1 /* ERROR "cannot use .* in map literal" */ : 2}
+	_ = M0{"foo": "bar" /* ERROR "cannot use .* in map literal" */ }
 	_ = M0{"foo": 1, "bar": 2, "foo" /* ERROR "duplicate key" */ : 3 }
 
 	_ = map[interface{}]int{2: 1, 2 /* ERROR "duplicate key" */ : 1}
@@ -520,7 +519,7 @@
 	fv(s /* ERROR "cannot use .* in argument" */ )
 	fv(s...)
 	fv(x /* ERROR "cannot use" */ ...)
-	fv(1, s /* ERROR "too many arguments" */ ... )
+	fv(1, s /* ERROR "too many arguments" */ ...)
 	fv(gs /* ERROR "cannot use .* in argument" */ ())
 	fv(gs /* ERROR "cannot use .* in argument" */ ()...)
 
@@ -529,7 +528,7 @@
 	t.fm(1, 2.0, x)
 	t.fm(s /* ERROR "cannot use .* in argument" */ )
 	t.fm(g1())
-	t.fm(1, s /* ERROR "too many arguments" */ ... )
+	t.fm(1, s /* ERROR "too many arguments" */ ...)
 	t.fm(gs /* ERROR "cannot use .* in argument" */ ())
 	t.fm(gs /* ERROR "cannot use .* in argument" */ ()...)
 
@@ -537,7 +536,7 @@
 	T.fm(t, 1, 2.0, x)
 	T.fm(t, s /* ERROR "cannot use .* in argument" */ )
 	T.fm(t, g1())
-	T.fm(t, 1, s /* ERROR "too many arguments" */ ... )
+	T.fm(t, 1, s /* ERROR "too many arguments" */ ...)
 	T.fm(t, gs /* ERROR "cannot use .* in argument" */ ())
 	T.fm(t, gs /* ERROR "cannot use .* in argument" */ ()...)
 
@@ -546,7 +545,7 @@
 	i.fm(1, 2.0, x)
 	i.fm(s /* ERROR "cannot use .* in argument" */ )
 	i.fm(g1())
-	i.fm(1, s /* ERROR "too many arguments" */ ... )
+	i.fm(1, s /* ERROR "too many arguments" */ ...)
 	i.fm(gs /* ERROR "cannot use .* in argument" */ ())
 	i.fm(gs /* ERROR "cannot use .* in argument" */ ()...)
 
diff --git a/src/go/types/testdata/issues.go2 b/src/go/types/testdata/issues.go2
index c77599f..ac2dee3 100644
--- a/src/go/types/testdata/issues.go2
+++ b/src/go/types/testdata/issues.go2
@@ -154,7 +154,7 @@
 
 // Infinite generic type declarations must lead to an error.
 type inf1[T any] struct{ _ inf1 /* ERROR illegal cycle */ [T] }
-type inf2[T any] struct{ (inf2 /* ERROR illegal cycle */ [T]) }
+type inf2[T any] struct{ inf2 /* ERROR illegal cycle */ [T] }
 
 // The implementation of conversions T(x) between integers and floating-point
 // numbers checks that both T and x have either integer or floating-point
diff --git a/src/go/types/testdata/issues.src b/src/go/types/testdata/issues.src
index 1bfc7fe..db415ea 100644
--- a/src/go/types/testdata/issues.src
+++ b/src/go/types/testdata/issues.src
@@ -325,8 +325,8 @@
 func issue28281d(... /* ERROR can only use ... with final parameter */ int, int)
 func issue28281e(a, b, c  ... /* ERROR can only use ... with final parameter */ int, d int)
 func issue28281f(... /* ERROR can only use ... with final parameter */ int, ... /* ERROR can only use ... with final parameter */ int, int)
-func (... /* ERROR can only use ... with final parameter in list */ TT) f()
-func issue28281g() (... /* ERROR can only use ... with final parameter in list */ TT)
+func (... /* ERROR can only use ... with final parameter */ TT) f()
+func issue28281g() (... /* ERROR can only use ... with final parameter */ TT)
 
 // Issue #26234: Make various field/method lookup errors easier to read by matching cmd/compile's output
 func issue26234a(f *syn.File) {
@@ -354,10 +354,10 @@
 
 func issue35895() {
 	// T is defined in this package, don't qualify its name with the package name.
-	var _ T = 0 // ERROR cannot convert 0 \(untyped int constant\) to T
+	var _ T = 0 // ERROR cannot use 0 \(untyped int constant\) as T
 
 	// There is only one package with name syntax imported, only use the (global) package name in error messages.
-	var _ *syn.File = 0 // ERROR cannot convert 0 \(untyped int constant\) to \*syntax.File
+	var _ *syn.File = 0 // ERROR cannot use 0 \(untyped int constant\) as \*syntax.File
 
 	// Because both t1 and t2 have the same global package name (template),
 	// qualify packages with full path name in this case.
diff --git a/src/go/types/testdata/mtypeparams.go2 b/src/go/types/testdata/mtypeparams.go2
deleted file mode 100644
index 1d12406..0000000
--- a/src/go/types/testdata/mtypeparams.go2
+++ /dev/null
@@ -1,48 +0,0 @@
-// Copyright 2020 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.
-
-// If types.Config.AcceptMethodTypeParams is set,
-// the type checker accepts methods that have their
-// own type parameter list.
-
-package p
-
-type S struct{}
-
-func (S) m[T any](v T)
-
-type I interface {
-   m[T any](v T)
-}
-
-type J interface {
-   m[T any](v T)
-}
-
-var _ I = S{}
-var _ I = J(nil)
-
-type C interface{ n() }
-
-type Sc struct{}
-
-func (Sc) m[T C](v T)
-
-type Ic interface {
-   m[T C](v T)
-}
-
-type Jc interface {
-   m[T C](v T)
-}
-
-var _ Ic = Sc{}
-var _ Ic = Jc(nil)
-
-// TODO(gri) These should fail because the constraints don't match.
-var _ I = Sc{}
-var _ I = Jc(nil)
-
-var _ Ic = S{}
-var _ Ic = J(nil)
diff --git a/src/go/types/testdata/shifts.src b/src/go/types/testdata/shifts.src
index ebc95ba..c9a38ae 100644
--- a/src/go/types/testdata/shifts.src
+++ b/src/go/types/testdata/shifts.src
@@ -193,14 +193,27 @@
 	_ = float32(1.0 /* ERROR "must be integer" */ <<s)
 	_ = float32(1.1 /* ERROR "must be integer" */ <<s)
 
+	_ = int32(0x80000000 /* ERROR "overflows int32" */ << s)
+	// TODO(rfindley) Eliminate the redundant error here.
+	_ = int32(( /* ERROR "truncated to int32" */ 0x80000000 /* ERROR "truncated to int32" */ + 0i) << s)
+
+	_ = int(1+0i<<0)
+	_ = int((1+0i)<<s)
+	_ = int(1.0<<s)
+	_ = int(complex(1, 0)<<s)
+	_ = int(float32/* ERROR "must be integer" */(1.0) <<s)
+	_ = int(1.1 /* ERROR must be integer */ <<s)
+	_ = int(( /* ERROR "must be integer" */ 1+1i)  <<s)
+
+	_ = complex(1 /* ERROR "must be integer" */ <<s, 0)
+
 	var b []int
 	_ = append(b, 1<<s)
 	_ = append(b, 1.0<<s)
+	_ = append(b, (1+0i)<<s)
 	_ = append(b, 1.1 /* ERROR "must be integer" */ <<s)
-
-	_ = append(b, 1<<s)
-	_ = append(b, 1.0<<s) // should fail - see TODO in append code
-	_ = append(b, 1.1 /* ERROR "must be integer" */ <<s)
+	_ = append(b, (1 + 0i) <<s)
+	_ = append(b, ( /* ERROR "must be integer" */ 1 + 1i)  <<s)
 
 	_ = complex(1.0 /* ERROR "must be integer" */ <<s, 0)
 	_ = complex(1.1 /* ERROR "must be integer" */ <<s, 0)
@@ -379,4 +392,4 @@
 	var _ int8 = 0xff /* ERROR "overflows int8" */ << s
 	var _ int16 = 0xffff /* ERROR "overflows int16" */ << s
 	var _ int32 = 0x80000000 /* ERROR "overflows int32" */ << s
-}
\ No newline at end of file
+}
diff --git a/src/go/types/testdata/stmt0.src b/src/go/types/testdata/stmt0.src
index c89ff7f..297e34b 100644
--- a/src/go/types/testdata/stmt0.src
+++ b/src/go/types/testdata/stmt0.src
@@ -182,7 +182,7 @@
 	var x int
 	x <- /* ERROR "cannot send" */ x
 	rch <- /* ERROR "cannot send" */ x
-	ch <- "foo" /* ERROR "cannot convert" */
+	ch <- "foo" /* ERROR "cannot use .* in send" */
 	ch <- x
 }
 
@@ -381,13 +381,13 @@
 func returns1(x float64) (int, *float64) {
 	return 0, &x
 	return /* ERROR wrong number of return values */
-	return "foo" /* ERROR "cannot convert" */, x /* ERROR "cannot use .* in return statement" */
+	return "foo" /* ERROR "cannot .* in return statement" */, x /* ERROR "cannot use .* in return statement" */
 	return /* ERROR wrong number of return values */ 0, &x, 1
 }
 
 func returns2() (a, b int) {
 	return
-	return 1, "foo" /* ERROR cannot convert */
+	return 1, "foo" /* ERROR cannot use .* in return statement */
 	return /* ERROR wrong number of return values */ 1, 2, 3
 	{
 		type a int
@@ -609,7 +609,7 @@
 	// untyped constants are converted to default types
 	switch 1<<63-1 {
 	}
-	switch 1 /* ERROR "overflows int" */ << 63 {
+	switch 1 /* ERROR "cannot use .* as int value.*\(overflows\)" */ << 63 {
 	}
 	var x int
 	switch 1.0 {
@@ -631,9 +631,9 @@
 }
 
 func issue11667() {
-	switch 9223372036854775808 /* ERROR "overflows int" */ {
+	switch 9223372036854775808 /* ERROR "cannot use .* as int value.*\(overflows\)" */ {
 	}
-	switch 9223372036854775808 /* ERROR "overflows int" */ {
+	switch 9223372036854775808 /* ERROR "cannot use .* as int value.*\(overflows\)" */ {
 	case 9223372036854775808:
 	}
 	var x int
@@ -886,7 +886,7 @@
 		ee = e
 		_ = ee
 	}
-	for _ = range sc /* ERROR "send-only channel" */ {}
+	for _ = range sc /* ERROR "cannot range over" */ {}
 	for _ = range rc {}
 
 	// constant strings
diff --git a/src/go/types/testdata/tinference.go2 b/src/go/types/testdata/tinference.go2
index a53fde0..31338b3 100644
--- a/src/go/types/testdata/tinference.go2
+++ b/src/go/types/testdata/tinference.go2
@@ -8,6 +8,9 @@
 
 type any interface{}
 
+// TODO(rFindley) the below partially applied function types should probably
+//                not be permitted (spec question).
+
 func f0[A any, B interface{type C}, C interface{type D}, D interface{type A}](A, B, C, D)
 func _() {
 	f := f0[string]
diff --git a/src/go/types/testdata/typeparams.go2 b/src/go/types/testdata/typeparams.go2
index 3e2568d..bdf6d56 100644
--- a/src/go/types/testdata/typeparams.go2
+++ b/src/go/types/testdata/typeparams.go2
@@ -33,7 +33,7 @@
 var _ = reverse[int, float32 /* ERROR got 2 type arguments */ ] ([]int{1, 2, 3})
 var _ = reverse[int]([ /* ERROR cannot use */ ]float32{1, 2, 3})
 var f = reverse[chan int]
-var _ = f(0 /* ERROR cannot convert 0 .* to \[\]chan int */ )
+var _ = f(0 /* ERROR cannot use 0 .* as \[\]chan int */ )
 
 func swap[A, B any](a A, b B) (B, A) { return b, a }
 
@@ -73,7 +73,7 @@
 var _ = new /* ERROR cannot use generic function new */
 var _ *int = new[int]()
 
-func _[T any](map[T /* ERROR invalid map key type T \(missing comparable constraint\) */]int) // w/o constraint we don't know if T is comparable
+func _[T any](map[T /* ERROR incomparable map key type T \(missing comparable constraint\) */]int) // w/o constraint we don't know if T is comparable
 
 func f1[T1 any](struct{T1}) int
 var _ = f1(int)(struct{T1}{})
@@ -229,9 +229,8 @@
 type T struct {}
 
 func (T) m1() {}
-// The type checker accepts method type parameters if configured accordingly.
-func (T) m2[_ any]() {}
-func (T) m3[P any]() {}
+func (T) m2[ /* ERROR methods cannot have type parameters */ _ any]() {}
+func (T) m3[ /* ERROR methods cannot have type parameters */ P any]() {}
 
 // type inference across parameterized types
 
@@ -293,20 +292,20 @@
 
 type R0 struct{}
 
-func (R0) _[T any](x T)
-func (R0 /* ERROR invalid receiver */ ) _[R0 any]() // scope of type parameters starts at "func"
+func (R0) _[ /* ERROR methods cannot have type parameters */ T any](x T)
+func (R0 /* ERROR invalid receiver */ ) _[ /* ERROR methods cannot have type parameters */ R0 any]() // scope of type parameters starts at "func"
 
 type R1[A, B any] struct{}
 
 func (_ R1[A, B]) m0(A, B)
-func (_ R1[A, B]) m1[T any](A, B, T) T
+func (_ R1[A, B]) m1[ /* ERROR methods cannot have type parameters */ T any](A, B, T) T
 func (_ R1 /* ERROR not a generic type */ [R1, _]) _()
-func (_ R1[A, B]) _[A /* ERROR redeclared */ any](B)
+func (_ R1[A, B]) _[ /* ERROR methods cannot have type parameters */ A /* ERROR redeclared */ any](B)
 
 func _() {
         var r R1[int, string]
         r.m1[rune](42, "foo", 'a')
-        r.m1[rune](42, "foo", 1.2 /* ERROR truncated to rune */)
+        r.m1[rune](42, "foo", 1.2 /* ERROR cannot use .* as rune .* \(truncated\) */)
         r.m1(42, "foo", 1.2) // using type inference
         var _ float64 = r.m1(42, "foo", 1.2)
 }
@@ -456,4 +455,4 @@
 
 type T3[P] func(P)
 var _ T3[int]
-*/
\ No newline at end of file
+*/
diff --git a/src/go/types/type.go b/src/go/types/type.go
index 7eeccc5..0fcefef 100644
--- a/src/go/types/type.go
+++ b/src/go/types/type.go
@@ -207,8 +207,8 @@
 	// and store it in the Func Object) because when type-checking a function
 	// literal we call the general type checker which returns a general Type.
 	// We then unpack the *Signature and use the scope for the literal body.
-	rparams  []*TypeName // reveiver type parameters from left to right; or nil
-	tparams  []*TypeName // type parameters from left to right; or nil
+	rparams  []*TypeName // receiver type parameters from left to right, or nil
+	tparams  []*TypeName // type parameters from left to right, or nil
 	scope    *Scope      // function scope, present for package-local signatures
 	recv     *Var        // nil if not a method
 	params   *Tuple      // (incoming) parameters from left to right; or nil
@@ -317,7 +317,7 @@
 
 // unpack unpacks a type into a list of types.
 // TODO(gri) Try to eliminate the need for this function.
-func unpack(typ Type) []Type {
+func unpackType(typ Type) []Type {
 	if typ == nil {
 		return nil
 	}
@@ -332,7 +332,7 @@
 	if t.allTypes == nil {
 		return false // we must have at least one type! (was bug)
 	}
-	for _, t := range unpack(t.allTypes) {
+	for _, t := range unpackType(t.allTypes) {
 		if !pred(t) {
 			return false
 		}
@@ -443,10 +443,7 @@
 		return len(t.allMethods) == 0 && t.allTypes == nil
 	}
 	return !t.iterate(func(t *Interface) bool {
-		if len(t.methods) > 0 || t.types != nil {
-			return true
-		}
-		return false
+		return len(t.methods) > 0 || t.types != nil
 	}, nil)
 }
 
@@ -458,10 +455,7 @@
 	}
 
 	return t.iterate(func(t *Interface) bool {
-		if t.types != nil {
-			return true
-		}
-		return false
+		return t.types != nil
 	}, nil)
 }
 
@@ -534,7 +528,7 @@
 	if t.allTypes == nil {
 		return true
 	}
-	types := unpack(t.allTypes)
+	types := unpackType(t.allTypes)
 	return includes(types, typ) || includes(types, under(typ))
 }
 
@@ -726,16 +720,15 @@
 type TypeParam struct {
 	check *Checker  // for lazy type bound completion
 	id    uint64    // unique id
-	ptr   bool      // pointer designation
 	obj   *TypeName // corresponding type name
 	index int       // parameter index
 	bound Type      // *Named or *Interface; underlying type is always *Interface
 }
 
 // NewTypeParam returns a new TypeParam.
-func (check *Checker) NewTypeParam(ptr bool, obj *TypeName, index int, bound Type) *TypeParam {
+func (check *Checker) NewTypeParam(obj *TypeName, index int, bound Type) *TypeParam {
 	assert(bound != nil)
-	typ := &TypeParam{check: check, id: check.nextId, ptr: ptr, obj: obj, index: index, bound: bound}
+	typ := &TypeParam{check: check, id: check.nextId, obj: obj, index: index, bound: bound}
 	check.nextId++
 	if obj.typ == nil {
 		obj.typ = typ
@@ -750,6 +743,7 @@
 	if n, _ := t.bound.(*Named); n != nil {
 		pos = n.obj.pos
 	}
+	// TODO(rFindley) switch this to an unexported method on Checker.
 	t.check.completeInterface(pos, iface)
 	return iface
 }
@@ -765,7 +759,7 @@
 	if t := asTypeParam(typ); t != nil {
 		// If the optype is typ, return the top type as we have
 		// no information. It also prevents infinite recursion
-		// via the TypeParam converter methods. This can happen
+		// via the asTypeParam converter function. This can happen
 		// for a type parameter list of the form:
 		// (type T interface { type T }).
 		// See also issue #39680.
diff --git a/src/go/types/typestring.go b/src/go/types/typestring.go
index 1582f70..64bbb33 100644
--- a/src/go/types/typestring.go
+++ b/src/go/types/typestring.go
@@ -313,33 +313,17 @@
 }
 
 func writeTParamList(buf *bytes.Buffer, list []*TypeName, qf Qualifier, visited []Type) {
-	// bound returns the type bound for tname. The result is never nil.
-	bound := func(tname *TypeName) Type {
-		// be careful to avoid crashes in case of inconsistencies
-		if t, _ := tname.typ.(*TypeParam); t != nil && t.bound != nil {
-			return t.bound
-		}
-		return &emptyInterface
-	}
-
-	// If a single type bound is not the empty interface, we have to write them all.
-	var writeBounds bool
-	for _, p := range list {
-		// bound(p) should be an interface but be careful (it may be invalid)
-		b := asInterface(bound(p))
-		if b != nil && !b.Empty() {
-			writeBounds = true
-			break
-		}
-	}
-	writeBounds = true // always write the bounds for new type parameter list syntax
-
+	// TODO(rFindley) compare this with the corresponding implementation in types2
 	buf.WriteString("[")
 	var prev Type
 	for i, p := range list {
-		b := bound(p)
+		// TODO(rFindley) support 'any' sugar here.
+		var b Type = &emptyInterface
+		if t, _ := p.typ.(*TypeParam); t != nil && t.bound != nil {
+			b = t.bound
+		}
 		if i > 0 {
-			if writeBounds && b != prev {
+			if b != prev {
 				// type bound changed - write previous one before advancing
 				buf.WriteByte(' ')
 				writeType(buf, prev, qf, visited)
@@ -349,15 +333,12 @@
 		prev = b
 
 		if t, _ := p.typ.(*TypeParam); t != nil {
-			if t.ptr {
-				buf.WriteByte('*')
-			}
 			writeType(buf, t, qf, visited)
 		} else {
 			buf.WriteString(p.name)
 		}
 	}
-	if writeBounds && prev != nil {
+	if prev != nil {
 		buf.WriteByte(' ')
 		writeType(buf, prev, qf, visited)
 	}
diff --git a/src/go/types/typestring_test.go b/src/go/types/typestring_test.go
index 13d4162..b16529d 100644
--- a/src/go/types/typestring_test.go
+++ b/src/go/types/typestring_test.go
@@ -95,7 +95,10 @@
 	dup("interface{}"),
 	dup("interface{m()}"),
 	dup(`interface{String() string; m(int) float32}`),
-	dup(`interface{type int, float32, complex128}`),
+
+	// TODO(rFindley) uncomment this once this AST is accepted, and add more test
+	// cases.
+	// dup(`interface{type int, float32, complex128}`),
 
 	// maps
 	dup("map[string]int"),
diff --git a/src/go/types/typexpr.go b/src/go/types/typexpr.go
index 89a4085..a6b7314 100644
--- a/src/go/types/typexpr.go
+++ b/src/go/types/typexpr.go
@@ -30,9 +30,9 @@
 	scope, obj := check.scope.LookupParent(e.Name, check.pos)
 	if obj == nil {
 		if e.Name == "_" {
-			check.errorf(e.Pos(), "cannot use _ as value or type")
+			check.errorf(e, _InvalidBlank, "cannot use _ as value or type")
 		} else {
-			check.errorf(e.Pos(), "undeclared name: %s", e.Name)
+			check.errorf(e, _UndeclaredName, "undeclared name: %s", e.Name)
 		}
 		return
 	}
@@ -63,7 +63,7 @@
 
 	switch obj := obj.(type) {
 	case *PkgName:
-		check.errorf(e.Pos(), "use of package %s not in selector", obj.name)
+		check.errorf(e, _InvalidPkgUse, "use of package %s not in selector", obj.name)
 		return
 
 	case *Const:
@@ -73,7 +73,7 @@
 		}
 		if obj == universeIota {
 			if check.iota == nil {
-				check.errorf(e.Pos(), "cannot use iota outside constant declaration")
+				check.errorf(e, _InvalidIota, "cannot use iota outside constant declaration")
 				return
 			}
 			x.val = check.iota
@@ -128,26 +128,26 @@
 // (see ordinaryType).
 func (check *Checker) varType(e ast.Expr) Type {
 	typ := check.definedType(e, nil)
-	check.ordinaryType(e.Pos(), typ)
+	check.ordinaryType(e, typ)
 	return typ
 }
 
 // ordinaryType reports an error if typ is an interface type containing
 // type lists or is (or embeds) the predeclared type comparable.
-func (check *Checker) ordinaryType(pos token.Pos, typ Type) {
+func (check *Checker) ordinaryType(pos positioner, typ Type) {
 	// We don't want to call under() (via asInterface) or complete interfaces
 	// while we are in the middle of type-checking parameter declarations that
 	// might belong to interface methods. Delay this check to the end of
 	// type-checking.
 	check.atEnd(func() {
 		if t := asInterface(typ); t != nil {
-			check.completeInterface(pos, t) // TODO(gri) is this the correct position?
+			check.completeInterface(pos.Pos(), t) // TODO(gri) is this the correct position?
 			if t.allTypes != nil {
-				check.softErrorf(pos, "interface contains type constraints (%s)", t.allTypes)
+				check.softErrorf(pos, _Todo, "interface contains type constraints (%s)", t.allTypes)
 				return
 			}
 			if t.IsComparable() {
-				check.softErrorf(pos, "interface is (or embeds) comparable")
+				check.softErrorf(pos, _Todo, "interface is (or embeds) comparable")
 			}
 		}
 	})
@@ -171,7 +171,7 @@
 	typ := check.typInternal(e, def)
 	assert(isTyped(typ))
 	if isGeneric(typ) {
-		check.errorf(e.Pos(), "cannot use generic type %s without instantiation", typ)
+		check.errorf(e, _Todo, "cannot use generic type %s without instantiation", typ)
 		typ = Typ[Invalid]
 	}
 	check.recordTypeAndValue(e, typexpr, typ, nil)
@@ -184,7 +184,7 @@
 	assert(isTyped(typ))
 	if typ != Typ[Invalid] && !isGeneric(typ) {
 		if reportErr {
-			check.errorf(e.Pos(), "%s is not a generic type", typ)
+			check.errorf(e, _Todo, "%s is not a generic type", typ)
 		}
 		typ = Typ[Invalid]
 	}
@@ -211,13 +211,13 @@
 	case *ast.CallExpr:
 		var args []ast.Expr
 		for i, arg := range n.Args {
-			Arg := isubst(arg, smap)
-			if Arg != arg {
+			new := isubst(arg, smap)
+			if new != arg {
 				if args == nil {
 					args = make([]ast.Expr, len(n.Args))
 					copy(args, n.Args)
 				}
-				args[i] = Arg
+				args[i] = new
 			}
 		}
 		if args != nil {
@@ -288,14 +288,11 @@
 			// - only do this if we have the right number (otherwise an error is reported elsewhere)
 			if len(sig.rparams) == len(recvTParams) {
 				// We have a list of *TypeNames but we need a list of Types.
-				// While creating this list, also update type parameter pointer designation
-				// for each (*TypeParam) list entry, by copying the information from the
-				// receiver base type's type parameters.
 				list := make([]Type, len(sig.rparams))
 				for i, t := range sig.rparams {
-					t.typ.(*TypeParam).ptr = recvTParams[i].typ.(*TypeParam).ptr
 					list[i] = t.typ
 				}
+				smap := makeSubstMap(recvTParams, list)
 				for i, tname := range sig.rparams {
 					bound := recvTParams[i].typ.(*TypeParam).bound
 					// bound is (possibly) parameterized in the context of the
@@ -304,7 +301,7 @@
 					// TODO(gri) should we assume now that bounds always exist?
 					//           (no bound == empty interface)
 					if bound != nil {
-						bound = check.subst(tname.pos, bound, makeSubstMap(recvTParams, list))
+						bound = check.subst(tname.pos, bound, smap)
 						tname.typ.(*TypeParam).bound = bound
 					}
 				}
@@ -314,11 +311,11 @@
 
 	if ftyp.TParams != nil {
 		sig.tparams = check.collectTypeParams(ftyp.TParams)
-		// Always type-check method type parameters but complain if they are not enabled.
+		// Always type-check method type parameters but complain that they are not allowed.
 		// (A separate check is needed when type-checking interface method signatures because
 		// they don't have a receiver specification.)
-		if recvPar != nil && !check.conf.AcceptMethodTypeParams {
-			check.errorf(ftyp.TParams.Pos(), "methods cannot have type parameters")
+		if recvPar != nil {
+			check.errorf(ftyp.TParams, _Todo, "methods cannot have type parameters")
 		}
 	}
 
@@ -330,7 +327,7 @@
 	params, variadic := check.collectParams(scope, ftyp.Params, nil, true)
 	results, _ := check.collectParams(scope, ftyp.Results, nil, false)
 	scope.Squash(func(obj, alt Object) {
-		check.errorf(obj.Pos(), "%s redeclared in this block", obj.Name())
+		check.errorf(obj, _DuplicateDecl, "%s redeclared in this block", obj.Name())
 		check.reportAltDecl(alt)
 	})
 
@@ -345,7 +342,7 @@
 			recv = NewParam(0, nil, "", Typ[Invalid]) // ignore recv below
 		default:
 			// more than one receiver
-			check.error(recvList[len(recvList)-1].Pos(), "method must have exactly one receiver")
+			check.error(recvList[len(recvList)-1], _BadRecv, "method must have exactly one receiver")
 			fallthrough // continue with first receiver
 		case 1:
 			recv = recvList[0]
@@ -381,7 +378,7 @@
 				err = "basic or unnamed type"
 			}
 			if err != "" {
-				check.errorf(recv.pos, "invalid receiver %s (%s)", recv.typ, err)
+				check.errorf(recv, _InvalidRecv, "invalid receiver %s (%s)", recv.typ, err)
 				// ok to continue
 			}
 		}
@@ -403,7 +400,7 @@
 // Must only be called by definedType or genericType.
 //
 func (check *Checker) typInternal(e0 ast.Expr, def *Named) (T Type) {
-	if check.conf.Trace {
+	if trace {
 		check.trace(e0.Pos(), "type %s", e0)
 		check.indent++
 		defer func() {
@@ -440,9 +437,9 @@
 		case invalid:
 			// ignore - error reported before
 		case novalue:
-			check.errorf(x.pos(), "%s used as type", &x)
+			check.errorf(&x, _NotAType, "%s used as type", &x)
 		default:
-			check.errorf(x.pos(), "%s is not a type", &x)
+			check.errorf(&x, _NotAType, "%s is not a type", &x)
 		}
 
 	case *ast.SelectorExpr:
@@ -457,19 +454,20 @@
 		case invalid:
 			// ignore - error reported before
 		case novalue:
-			check.errorf(x.pos(), "%s used as type", &x)
+			check.errorf(&x, _NotAType, "%s used as type", &x)
 		default:
-			check.errorf(x.pos(), "%s is not a type", &x)
+			check.errorf(&x, _NotAType, "%s is not a type", &x)
 		}
 
 	case *ast.IndexExpr:
-		if check.useBrackets {
-			return check.instantiatedType(e.X, []ast.Expr{e.Index}, def)
-		}
-		check.errorf(e0.Pos(), "%s is not a type", e0)
+		return check.instantiatedType(e.X, []ast.Expr{e.Index}, def)
 
 	case *ast.CallExpr:
-		return check.instantiatedType(e.Fun, e.Args, def)
+		if e.Brackets {
+			return check.instantiatedType(e.Fun, e.Args, def)
+		} else {
+			check.errorf(e0, _NotAType, "%s is not a type", e0)
+		}
 
 	case *ast.ParenExpr:
 		// Generic types must be instantiated before they can be used in any form.
@@ -536,7 +534,7 @@
 				if asTypeParam(typ.key) != nil {
 					why = " (missing comparable constraint)"
 				}
-				check.errorf(e.Key.Pos(), "invalid map key type %s%s", typ.key, why)
+				check.errorf(e.Key, _IncomparableMapKey, "incomparable map key type %s%s", typ.key, why)
 			}
 		})
 
@@ -555,7 +553,7 @@
 		case ast.RECV:
 			dir = RecvOnly
 		default:
-			check.invalidAST(e.Pos(), "unknown channel direction %d", e.Dir)
+			check.invalidAST(e, "unknown channel direction %d", e.Dir)
 			// ok to continue
 		}
 
@@ -564,7 +562,7 @@
 		return typ
 
 	default:
-		check.errorf(e0.Pos(), "%s is not a type", e0)
+		check.errorf(e0, _NotAType, "%s is not a type", e0)
 	}
 
 	typ := Typ[Invalid]
@@ -584,7 +582,7 @@
 	case invalid:
 		// ignore - error reported before
 	case novalue:
-		check.errorf(x.pos(), "%s used as type", &x)
+		check.errorf(&x, _NotAType, "%s used as type", &x)
 	case typexpr:
 		check.instantiatedOperand(&x)
 		return x.typ
@@ -594,7 +592,7 @@
 		}
 		fallthrough
 	default:
-		check.errorf(x.pos(), "%s is not a type", &x)
+		check.errorf(&x, _NotAType, "%s is not a type", &x)
 	}
 	return Typ[Invalid]
 }
@@ -609,9 +607,9 @@
 		unreachable() // should have been caught by genericType
 	}
 
-	// create a new type Instance rather than instantiate the type
+	// create a new type instance rather than instantiate the type
 	// TODO(gri) should do argument number check here rather than
-	// when instantiating the type?
+	//           when instantiating the type?
 	typ := new(instance)
 	def.setUnderlying(typ)
 
@@ -650,7 +648,7 @@
 	check.expr(&x, e)
 	if x.mode != constant_ {
 		if x.mode != invalid {
-			check.errorf(x.pos(), "array length %s must be constant", &x)
+			check.errorf(&x, _InvalidArrayLen, "array length %s must be constant", &x)
 		}
 		return -1
 	}
@@ -660,12 +658,12 @@
 				if n, ok := constant.Int64Val(val); ok && n >= 0 {
 					return n
 				}
-				check.errorf(x.pos(), "invalid array length %s", &x)
+				check.errorf(&x, _InvalidArrayLen, "invalid array length %s", &x)
 				return -1
 			}
 		}
 	}
-	check.errorf(x.pos(), "array length %s must be integer", &x)
+	check.errorf(&x, _InvalidArrayLen, "array length %s must be integer", &x)
 	return -1
 }
 
@@ -703,7 +701,7 @@
 			if variadicOk && i == len(list.List)-1 && len(field.Names) <= 1 {
 				variadic = true
 			} else {
-				check.softErrorf(t.Pos(), "can only use ... with final parameter in list")
+				check.softErrorf(t, _MisplacedDotDotDot, "can only use ... with final parameter in list")
 				// ignore ... and continue
 			}
 		}
@@ -714,7 +712,7 @@
 			// named parameter
 			for _, name := range field.Names {
 				if name.Name == "" {
-					check.invalidAST(name.Pos(), "anonymous parameter")
+					check.invalidAST(name, "anonymous parameter")
 					// ok to continue
 				}
 				par := NewParam(name.Pos(), check.pkg, name.Name, typ)
@@ -732,7 +730,7 @@
 	}
 
 	if named && anonymous {
-		check.invalidAST(list.Pos(), "list contains both named and anonymous parameters")
+		check.invalidAST(list, "list contains both named and anonymous parameters")
 		// ok to continue
 	}
 
@@ -750,7 +748,7 @@
 
 func (check *Checker) declareInSet(oset *objset, pos token.Pos, obj Object) bool {
 	if alt := oset.insert(obj); alt != nil {
-		check.errorf(pos, "%s redeclared", obj.Name())
+		check.errorf(atPos(pos), _DuplicateDecl, "%s redeclared", obj.Name())
 		check.reportAltDecl(alt)
 		return false
 	}
@@ -768,7 +766,7 @@
 			// and we don't care if a constructed AST has more.)
 			name := f.Names[0]
 			if name.Name == "_" {
-				check.errorf(name.Pos(), "invalid method name _")
+				check.errorf(name, _BlankIfaceMethod, "invalid method name _")
 				continue // ignore
 			}
 
@@ -778,7 +776,7 @@
 				// the author intended to include all types.
 				types = append(types, f.Type)
 				if tlist != nil && tlist != name {
-					check.errorf(name.Pos(), "cannot have multiple type lists in an interface")
+					check.errorf(name, _Todo, "cannot have multiple type lists in an interface")
 				}
 				tlist = name
 				continue
@@ -788,7 +786,7 @@
 			sig, _ := typ.(*Signature)
 			if sig == nil {
 				if typ != Typ[Invalid] {
-					check.invalidAST(f.Type.Pos(), "%s is not a method signature", typ)
+					check.invalidAST(f.Type, "%s is not a method signature", typ)
 				}
 				continue // ignore
 			}
@@ -796,8 +794,8 @@
 			// Always type-check method type parameters but complain if they are not enabled.
 			// (This extra check is needed here because interface method signatures don't have
 			// a receiver specification.)
-			if sig.tparams != nil && !check.conf.AcceptMethodTypeParams {
-				check.errorf(f.Type.(*ast.FuncType).TParams.Pos(), "methods cannot have type parameters")
+			if sig.tparams != nil {
+				check.errorf(f.Type.(*ast.FuncType).TParams, _Todo, "methods cannot have type parameters")
 			}
 
 			// use named receiver type if available (for better error messages)
@@ -847,7 +845,7 @@
 		panic("internal error: incomplete interface")
 	}
 
-	if check.conf.Trace {
+	if trace {
 		// Types don't generally have position information.
 		// If we don't have a valid pos provided, try to use
 		// one close enough.
@@ -892,14 +890,14 @@
 			methods = append(methods, m)
 			mpos[m] = pos
 		case explicit:
-			check.errorf(pos, "duplicate method %s", m.name)
-			check.errorf(mpos[other.(*Func)], "\tother declaration of %s", m.name) // secondary error, \t indented
+			check.errorf(atPos(pos), _DuplicateDecl, "duplicate method %s", m.name)
+			check.errorf(atPos(mpos[other.(*Func)]), _DuplicateDecl, "\tother declaration of %s", m.name) // secondary error, \t indented
 		default:
 			// check method signatures after all types are computed (issue #33656)
 			check.atEnd(func() {
 				if !check.identical(m.typ, other.Type()) {
-					check.errorf(pos, "duplicate method %s", m.name)
-					check.errorf(mpos[other.(*Func)], "\tother declaration of %s", m.name) // secondary error, \t indented
+					check.errorf(atPos(pos), _DuplicateDecl, "duplicate method %s", m.name)
+					check.errorf(atPos(mpos[other.(*Func)]), _DuplicateDecl, "\tother declaration of %s", m.name) // secondary error, \t indented
 				}
 			})
 		}
@@ -925,7 +923,8 @@
 				} else {
 					format = "%s is not an interface"
 				}
-				check.errorf(pos, format, typ)
+				// TODO: correct error code.
+				check.errorf(atPos(pos), _InvalidIfaceEmbed, format, typ)
 			}
 			continue
 		}
@@ -962,8 +961,8 @@
 		return x
 	}
 
-	xtypes := unpack(x)
-	ytypes := unpack(y)
+	xtypes := unpackType(x)
+	ytypes := unpackType(y)
 	// Compute the list rtypes which includes only
 	// types that are in both xtypes and ytypes.
 	// Quadratic algorithm, but good enough for now.
@@ -1009,7 +1008,7 @@
 				return val
 			}
 		}
-		check.invalidAST(t.Pos(), "incorrect tag syntax: %q", t.Value)
+		check.invalidAST(t, "incorrect tag syntax: %q", t.Value)
 	}
 	return ""
 }
@@ -1067,24 +1066,31 @@
 			}
 		} else {
 			// embedded field
-			// spec: "An embedded type must be specified as a (possibly parenthesized) type name T or
-			// as a pointer to a non-interface type name *T, and T itself may not be a pointer type."
+			// spec: "An embedded type must be specified as a type name T or as a
+			// pointer to a non-interface type name *T, and T itself may not be a
+			// pointer type."
 			pos := f.Type.Pos()
 			name := embeddedFieldIdent(f.Type)
 			if name == nil {
-				check.errorf(pos, "invalid embedded field type %s", f.Type)
+				// TODO(rFindley): using invalidAST here causes test failures (all
+				//                 errors should have codes). Clean this up.
+				check.errorf(f.Type, _Todo, "invalid AST: embedded field type %s has no name", f.Type)
 				name = ast.NewIdent("_")
 				name.NamePos = pos
 				addInvalid(name, pos)
 				continue
 			}
 			add(name, true, pos)
+
 			// Because we have a name, typ must be of the form T or *T, where T is the name
 			// of a (named or alias) type, and t (= deref(typ)) must be the type of T.
 			// We must delay this check to the end because we don't want to instantiate
 			// (via under(t)) a possibly incomplete type.
-			embeddedTyp := typ // for closure below
-			embeddedPos := pos
+
+			// for use in the closure below
+			embeddedTyp := typ
+			embeddedPos := f.Type
+
 			check.atEnd(func() {
 				t, isPtr := deref(embeddedTyp)
 				switch t := optype(t).(type) {
@@ -1095,13 +1101,13 @@
 					}
 					// unsafe.Pointer is treated like a regular pointer
 					if t.kind == UnsafePointer {
-						check.errorf(embeddedPos, "embedded field type cannot be unsafe.Pointer")
+						check.errorf(embeddedPos, _InvalidPtrEmbed, "embedded field type cannot be unsafe.Pointer")
 					}
 				case *Pointer:
-					check.errorf(embeddedPos, "embedded field type cannot be a pointer")
+					check.errorf(embeddedPos, _InvalidPtrEmbed, "embedded field type cannot be a pointer")
 				case *Interface:
 					if isPtr {
-						check.errorf(embeddedPos, "embedded field type cannot be a pointer to an interface")
+						check.errorf(embeddedPos, _InvalidPtrEmbed, "embedded field type cannot be a pointer to an interface")
 					}
 				}
 			})
@@ -1123,10 +1129,12 @@
 		}
 	case *ast.SelectorExpr:
 		return e.Sel
-	case *ast.CallExpr:
-		return embeddedFieldIdent(e.Fun)
-	case *ast.ParenExpr:
+	case *ast.IndexExpr:
 		return embeddedFieldIdent(e.X)
+	case *ast.CallExpr:
+		if e.Brackets {
+			return embeddedFieldIdent(e.Fun)
+		}
 	}
 	return nil // invalid embedded field
 }
@@ -1135,37 +1143,24 @@
 	list := make([]Type, 0, len(types)) // assume all types are correct
 	for _, texpr := range types {
 		if texpr == nil {
-			check.invalidAST(pos, "missing type constraint")
+			check.invalidAST(atPos(pos), "missing type constraint")
 			continue
 		}
-		typ := check.varType(texpr)
-		// A type constraint may be a predeclared type or a
-		// composite type composed of only predeclared types.
-		// TODO(gri) If we enable this again it also must run
-		// at the end.
-		const restricted = false
-		var why string
-		if restricted && !check.typeConstraint(typ, &why) {
-			check.errorf(texpr.Pos(), "invalid type constraint %s (%s)", typ, why)
-			continue
-		}
-		list = append(list, typ)
+		list = append(list, check.varType(texpr))
 	}
 
-	// Ensure that each type is only present once in the type list.
-	// Types may be interfaces, which may not be complete yet. It's
-	// ok to do this check at the end because it's not a requirement
-	// for correctness of the code.
+	// Ensure that each type is only present once in the type list.  Types may be
+	// interfaces, which may not be complete yet. It's ok to do this check at the
+	// end because it's not a requirement for correctness of the code.
+	// Note: This is a quadratic algorithm, but type lists tend to be short.
 	check.atEnd(func() {
-		uniques := make([]Type, 0, len(list)) // assume all types are unique
 		for i, t := range list {
 			if t := asInterface(t); t != nil {
 				check.completeInterface(types[i].Pos(), t)
 			}
-			if includes(uniques, t) {
-				check.softErrorf(types[i].Pos(), "duplicate type %s in type list", t)
+			if includes(list[:i], t) {
+				check.softErrorf(types[i], _Todo, "duplicate type %s in type list", t)
 			}
-			uniques = append(uniques, t)
 		}
 	})
 
@@ -1181,59 +1176,3 @@
 	}
 	return false
 }
-
-// typeConstraint checks that typ may be used in a type list.
-// For now this just checks for the absence of defined (*Named) types.
-func (check *Checker) typeConstraint(typ Type, why *string) bool {
-	switch t := typ.(type) {
-	case *Basic:
-		// ok
-	case *Array:
-		return check.typeConstraint(t.elem, why)
-	case *Slice:
-		return check.typeConstraint(t.elem, why)
-	case *Struct:
-		for _, f := range t.fields {
-			if !check.typeConstraint(f.typ, why) {
-				return false
-			}
-		}
-	case *Pointer:
-		return check.typeConstraint(t.base, why)
-	case *Tuple:
-		if t == nil {
-			return true
-		}
-		for _, v := range t.vars {
-			if !check.typeConstraint(v.typ, why) {
-				return false
-			}
-		}
-	case *Signature:
-		if len(t.tparams) != 0 {
-			panic("type parameter in function type")
-		}
-		return (t.recv == nil || check.typeConstraint(t.recv.typ, why)) &&
-			check.typeConstraint(t.params, why) &&
-			check.typeConstraint(t.results, why)
-	case *Interface:
-		t.assertCompleteness()
-		for _, m := range t.allMethods {
-			if !check.typeConstraint(m.typ, why) {
-				return false
-			}
-		}
-	case *Map:
-		return check.typeConstraint(t.key, why) && check.typeConstraint(t.elem, why)
-	case *Chan:
-		return check.typeConstraint(t.elem, why)
-	case *Named:
-		*why = check.sprintf("contains defined type %s", t)
-		return false
-	case *TypeParam:
-		// ok, e.g.: func f (type T interface { type T }) ()
-	default:
-		unreachable()
-	}
-	return true
-}
diff --git a/src/go/types/unify.go b/src/go/types/unify.go
index 2bd2068..ab18feb 100644
--- a/src/go/types/unify.go
+++ b/src/go/types/unify.go
@@ -65,9 +65,9 @@
 	unifier *unifier
 	tparams []*TypeName
 	// For each tparams element, there is a corresponding type slot index in indices.
-	// index  < 0: unifier.types[-index] == nil
+	// index  < 0: unifier.types[-index-1] == nil
 	// index == 0: no type slot allocated yet
-	// index  > 0: unifier.types[index] == typ
+	// index  > 0: unifier.types[index-1] == typ
 	// Joined tparams elements share the same type slot and thus have the same index.
 	// By using a negative index for nil types we don't need to check unifier.types
 	// to see if we have a type or not.
@@ -120,13 +120,9 @@
 	case ti > 0:
 		// Only the type parameter for x has an inferred type. Use x slot for y.
 		u.y.setIndex(j, ti)
-	// This case is handled like the default case.
-	// case tj > 0:
-	// 	// Only the type parameter for y has an inferred type. Use y slot for x.
-	// 	u.x.setIndex(i, tj)
 	default:
-		// Neither type parameter has an inferred type. Use y slot for x
-		// (or x slot for y, it doesn't matter).
+		// Either the type parameter for y has an inferred type, or neither type
+		// parameter has an inferred type. In either case, use y slot for x.
 		u.x.setIndex(i, tj)
 	}
 	return true
diff --git a/test/gen/g012.go2 b/test/gen/g012.go2
index 539e069..46d7d61 100644
--- a/test/gen/g012.go2
+++ b/test/gen/g012.go2
@@ -59,19 +59,19 @@
 	r := float64(real(a))
 	i := float64(imag(a))
 	d := math.Sqrt(r * r + i * i)
-	return ComplexAbs(T)(complex(d, 0))
+	return ComplexAbs[T](complex(d, 0))
 }
 
 // OrderedAbsDifference returns the absolute value of the difference
 // between a and b, where a and b are of an ordered type.
 func OrderedAbsDifference[T OrderedNumeric](a, b T) T {
-	return T(AbsDifference(OrderedAbs(T)(a), OrderedAbs(T)(b)))
+	return T(AbsDifference(OrderedAbs[T](a), OrderedAbs[T](b)))
 }
 
 // ComplexAbsDifference returns the absolute value of the difference
 // between a and b, where a and b are of a complex type.
 func ComplexAbsDifference[T Complex](a, b T) T {
-	return T(AbsDifference(ComplexAbs(T)(a), ComplexAbs(T)(b)))
+	return T(AbsDifference(ComplexAbs[T](a), ComplexAbs[T](b)))
 }
 
 func main() {