]> Cypherpunks.ru repositories - gostls13.git/commitdiff
[dev.typeparams] merge master (2f0da6d) into dev.typeparams
authorRob Findley <rfindley@google.com>
Wed, 17 Feb 2021 21:34:00 +0000 (16:34 -0500)
committerRob Findley <rfindley@google.com>
Thu, 18 Feb 2021 01:04:03 +0000 (20:04 -0500)
This was a mostly clean merge, with the exception of codereview.cfg and
changes in src/go/types.

codereview.cfg for dev.typeparams is preserved in this CL. It should be
deleted before merging back to master.

The go/types changes were merged manually. For the most part this
involved taking the union of patches, with the following exceptions:
 + declInfo.aliasPos is removed, as it is not necessary in
   dev.typeparams where we have access to the full TypeSpec.
 + Checker.overflow is updated to use the asBasic converter.
 + A TODO is added to errorcodes.go to ensure that go1.16 error codes
   are preserved.

Change-Id: If9595196852e2163e27a9478df1e7b2c3704947d

17 files changed:
1  2 
src/cmd/dist/test.go
src/go/types/api.go
src/go/types/assignments.go
src/go/types/builtins.go
src/go/types/check.go
src/go/types/check_test.go
src/go/types/decl.go
src/go/types/errorcodes.go
src/go/types/eval_test.go
src/go/types/expr.go
src/go/types/predicates.go
src/go/types/resolver.go
src/go/types/testdata/builtins.src
src/go/types/testdata/stmt0.src
src/go/types/type.go
src/go/types/typexpr.go
test/run.go

diff --combined src/cmd/dist/test.go
index 2b1f82246ab3508315a9a3fe64326303b2d7840f,4f081c9f888987ca37e32ac1af5d46ef28533bf3..a22397aa16b298f9a0934fb82aeb235e573025b6
@@@ -309,24 -309,14 +309,24 @@@ var 
        benchMatches []string
  )
  
 -func (t *tester) registerStdTest(pkg string) {
 -      testName := "go_test:" + pkg
 +func (t *tester) registerStdTest(pkg string, useG3 bool) {
 +      heading := "Testing packages."
 +      testPrefix := "go_test:"
 +      gcflags := gogcflags
 +      if useG3 {
 +              heading = "Testing packages with -G=3."
 +              testPrefix = "go_test_g3:"
 +              gcflags += " -G=3"
 +      }
 +
 +      testName := testPrefix + pkg
        if t.runRx == nil || t.runRx.MatchString(testName) == t.runRxWant {
                stdMatches = append(stdMatches, pkg)
        }
 +
        t.tests = append(t.tests, distTest{
                name:    testName,
 -              heading: "Testing packages.",
 +              heading: heading,
                fn: func(dt *distTest) error {
                        if ranGoTest {
                                return nil
                                "-short=" + short(),
                                t.tags(),
                                t.timeout(timeoutSec),
 -                              "-gcflags=all=" + gogcflags,
 +                              "-gcflags=all=" + gcflags,
                        }
                        if t.race {
                                args = append(args, "-race")
@@@ -418,10 -408,7 +418,10 @@@ func (t *tester) registerTests() 
        if len(t.runNames) > 0 {
                for _, name := range t.runNames {
                        if strings.HasPrefix(name, "go_test:") {
 -                              t.registerStdTest(strings.TrimPrefix(name, "go_test:"))
 +                              t.registerStdTest(strings.TrimPrefix(name, "go_test:"), false)
 +                      }
 +                      if strings.HasPrefix(name, "go_test_g3:") {
 +                              t.registerStdTest(strings.TrimPrefix(name, "go_test_g3:"), true)
                        }
                        if strings.HasPrefix(name, "go_test_bench:") {
                                t.registerRaceBenchTest(strings.TrimPrefix(name, "go_test_bench:"))
                        fatalf("Error running go list std cmd: %v:\n%s", err, cmd.Stderr)
                }
                pkgs := strings.Fields(string(all))
 +              if false {
 +                      // Disable -G=3 option for standard tests for now, since
 +                      // they are flaky on the builder.
 +                      for _, pkg := range pkgs {
 +                              t.registerStdTest(pkg, true /* -G=3 flag */)
 +                      }
 +              }
                for _, pkg := range pkgs {
 -                      t.registerStdTest(pkg)
 +                      t.registerStdTest(pkg, false)
                }
                if t.race {
                        for _, pkg := range pkgs {
                }
        }
  
-       // Doc tests only run on builders.
-       // They find problems approximately never.
-       if goos != "js" && goos != "android" && !t.iOS() && os.Getenv("GO_BUILDER_NAME") != "" {
-               t.registerTest("doc_progs", "../doc/progs", "go", "run", "run.go")
-               t.registerTest("wiki", "../doc/articles/wiki", t.goTest(), ".")
-               t.registerTest("codewalk", "../doc/codewalk", t.goTest(), "codewalk_test.go")
-       }
        if goos != "android" && !t.iOS() {
                // There are no tests in this directory, only benchmarks.
                // Check that the test binary builds but don't bother running it.
diff --combined src/go/types/api.go
index ec12fcf3804c3e898223635030d30551d16e3c58,b5bbb2d97dc7ee383f6abcea5e0e220570e18ff5..09ac65b81f1117a00946dbb92713989e5ef26964
@@@ -101,6 -101,13 +101,13 @@@ type ImporterFrom interface 
  // A Config specifies the configuration for type checking.
  // The zero value for Config is a ready-to-use default configuration.
  type Config struct {
+       // GoVersion describes the accepted Go language version. The string
+       // must follow the format "go%d.%d" (e.g. "go1.12") or it must be
+       // empty; an empty string indicates the latest language version.
+       // If the format is invalid, invoking the type checker will cause a
+       // panic.
+       GoVersion string
        // If IgnoreFuncBodies is set, function bodies are not
        // type-checked.
        IgnoreFuncBodies bool
@@@ -177,12 -184,6 +184,12 @@@ type Info struct 
        // qualified identifiers are collected in the Uses map.
        Types map[ast.Expr]TypeAndValue
  
 +      // Inferred maps calls of parameterized functions that use
 +      // type inference to the inferred type arguments and signature
 +      // of the function called. The recorded "call" expression may be
 +      // an *ast.CallExpr (as in f(x)), or an *ast.IndexExpr (s in f[T]).
 +      Inferred map[ast.Expr]Inferred
 +
        // Defs maps identifiers to the objects they define (including
        // package names, dots "." of dot-imports, and blank "_" identifiers).
        // For identifiers that do not denote objects (e.g., the package name
@@@ -339,13 -340,6 +346,13 @@@ func (tv TypeAndValue) HasOk() bool 
        return tv.mode == commaok || tv.mode == mapindex
  }
  
 +// Inferred reports the inferred type arguments and signature
 +// for a parameterized function call that uses type inference.
 +type Inferred struct {
 +      Targs []Type
 +      Sig   *Signature
 +}
 +
  // An Initializer describes a package-level variable, or a list of variables in case
  // of a multi-valued initialization expression, and the corresponding initialization
  // expression.
index ee7dd962146bb73892b81009075af3a148c74ce6,616564b567d7315d4723c5ed3f7ddb46b7a35a8f..3aa06e8939fca76084b0217202c4f2eb8c4b4509
@@@ -7,6 -7,7 +7,6 @@@
  package types
  
  import (
 -      "errors"
        "go/ast"
        "go/token"
  )
@@@ -25,9 -26,7 +25,9 @@@ func (check *Checker) assignment(x *ope
        case constant_, variable, mapindex, value, commaok, commaerr:
                // ok
        default:
 -              unreachable()
 +              // we may get here because of other problems (issue #39634, crash 12)
 +              check.errorf(x, 0, "cannot assign %s to %s in %s", x, T, context)
 +              return
        }
  
        if isUntyped(x.typ) {
                        }
                        target = Default(x.typ)
                }
 -              if err := check.canConvertUntyped(x, target); err != nil {
 +              newType, val, code := check.implicitTypeAndValue(x, target)
 +              if code != 0 {
                        msg := check.sprintf("cannot use %s as %s value in %s", x, target, context)
 -                      code := _IncompatibleAssign
 -                      var ierr Error
 -                      if errors.As(err, &ierr) {
 -                              // Preserve these inner errors, as they are informative.
 -                              switch ierr.go116code {
 -                              case _TruncatedFloat:
 -                                      msg += " (truncated)"
 -                                      code = ierr.go116code
 -                              case _NumericOverflow:
 -                                      msg += " (overflows)"
 -                                      code = ierr.go116code
 -                              }
 +                      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)
 +              }
 +      }
 +
 +      // 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, _Todo, "cannot use generic function %s without instantiation in %s", x, context)
        }
 -      // x.typ is typed
  
        // spec: "If a left-hand side is the blank identifier, any typed or
        // non-constant value except for the predeclared identifier nil may
@@@ -129,7 -120,6 +129,6 @@@ func (check *Checker) initVar(lhs *Var
                if lhs.typ == nil {
                        lhs.typ = Typ[Invalid]
                }
-               lhs.used = true
                return nil
        }
  
  
  func (check *Checker) assignVar(lhs ast.Expr, x *operand) Type {
        if x.mode == invalid || x.typ == Typ[Invalid] {
 +              check.useLHS(lhs)
                return nil
        }
  
  
  // 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, rhs []ast.Expr, returnPos token.Pos) {
 -      l := len(lhs)
 -      get, r, commaOk := unpack(func(x *operand, i int) { check.multiExpr(x, rhs[i]) }, len(rhs), l == 2 && !returnPos.IsValid())
 -      if get == nil || l != r {
 -              // invalidate lhs and use rhs
 +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
                for _, obj := range lhs {
                        if obj.typ == nil {
                                obj.typ = Typ[Invalid]
                        }
                }
 -              if get == nil {
 -                      return // error reported by unpack
 +              // don't report an error if we already reported one
 +              for _, x := range rhs {
 +                      if x.mode == invalid {
 +                              return
 +                      }
                }
 -              check.useGetter(get, r)
                if returnPos.IsValid() {
 -                      check.errorf(atPos(returnPos), _WrongResultCount, "wrong number of return values (want %d, got %d)", l, r)
 +                      check.errorf(atPos(returnPos), _WrongResultCount, "wrong number of return values (want %d, got %d)", len(lhs), len(rhs))
                        return
                }
 -              check.errorf(rhs[0], _WrongAssignCount, "cannot initialize %d variables with %d values", l, r)
 +              check.errorf(rhs[0], _WrongAssignCount, "cannot initialize %d variables with %d values", len(lhs), len(rhs))
                return
        }
  
                context = "return statement"
        }
  
 -      var x operand
        if commaOk {
                var a [2]Type
                for i := range a {
 -                      get(&x, i)
 -                      a[i] = check.initVar(lhs[i], &x, context)
 +                      a[i] = check.initVar(lhs[i], rhs[i], context)
                }
 -              check.recordCommaOkTypes(rhs[0], a)
 +              check.recordCommaOkTypes(origRHS[0], a)
                return
        }
  
        for i, lhs := range lhs {
 -              get(&x, i)
 -              check.initVar(lhs, &x, context)
 +              check.initVar(lhs, rhs[i], context)
        }
  }
  
 -func (check *Checker) assignVars(lhs, rhs []ast.Expr) {
 -      l := len(lhs)
 -      get, r, commaOk := unpack(func(x *operand, i int) { check.multiExpr(x, rhs[i]) }, len(rhs), l == 2)
 -      if get == nil {
 +func (check *Checker) assignVars(lhs, origRHS []ast.Expr) {
 +      rhs, commaOk := check.exprList(origRHS, len(lhs) == 2)
 +
 +      if len(lhs) != len(rhs) {
                check.useLHS(lhs...)
 -              return // error reported by unpack
 -      }
 -      if l != r {
 -              check.useGetter(get, r)
 -              check.errorf(rhs[0], _WrongAssignCount, "cannot assign %d values to %d variables", r, l)
 +              // don't report an error if we already reported one
 +              for _, x := range rhs {
 +                      if x.mode == invalid {
 +                              return
 +                      }
 +              }
 +              check.errorf(rhs[0], _WrongAssignCount, "cannot assign %d values to %d variables", len(rhs), len(lhs))
                return
        }
  
 -      var x operand
        if commaOk {
                var a [2]Type
                for i := range a {
 -                      get(&x, i)
 -                      a[i] = check.assignVar(lhs[i], &x)
 +                      a[i] = check.assignVar(lhs[i], rhs[i])
                }
 -              check.recordCommaOkTypes(rhs[0], a)
 +              check.recordCommaOkTypes(origRHS[0], a)
                return
        }
  
        for i, lhs := range lhs {
 -              get(&x, i)
 -              check.assignVar(lhs, &x)
 +              check.assignVar(lhs, rhs[i])
        }
  }
  
diff --combined src/go/types/builtins.go
index 28697d90870a72eb4a937d3a71286f90236a4863,078ed4488d11b3aded9e8df7a050c65e6dbd70e8..d45cd9b2781b32495bf578bf6e661df3f7863f72
@@@ -31,8 -31,8 +31,8 @@@ func (check *Checker) builtin(x *operan
        // For len(x) and cap(x) we need to know if x contains any function calls or
        // receive operations. Save/restore current setting and set hasCallOrRecv to
        // false for the evaluation of x so that we can check it afterwards.
 -      // Note: We must do this _before_ calling unpack because unpack evaluates the
 -      //       first argument before we even call arg(x, 0)!
 +      // Note: We must do this _before_ calling exprList because exprList evaluates
 +      //       all arguments.
        if id == _Len || id == _Cap {
                defer func(b bool) {
                        check.hasCallOrRecv = b
        }
  
        // determine actual arguments
 -      var arg getter
 +      var arg func(*operand, int) // TODO(gri) remove use of arg getter in favor of using xlist directly
        nargs := len(call.Args)
        switch id {
        default:
                // make argument getter
 -              arg, nargs, _ = unpack(func(x *operand, i int) { check.multiExpr(x, call.Args[i]) }, nargs, false)
 -              if arg == nil {
 -                      return
 -              }
 +              xlist, _ := check.exprList(call.Args, false)
 +              arg = func(x *operand, i int) { *x = *xlist[i]; x.typ = expand(x.typ) }
 +              nargs = len(xlist)
                // evaluate first argument, if present
                if nargs > 0 {
                        arg(x, 0)
@@@ -83,7 -84,7 +83,7 @@@
                // of S and the respective parameter passing rules apply."
                S := x.typ
                var T Type
 -              if s, _ := S.Underlying().(*Slice); s != nil {
 +              if s := asSlice(S); s != nil {
                        T = s.elem
                } else {
                        check.invalidArg(x, _InvalidAppend, "%s is not a slice", x)
                // check general case by creating custom signature
                sig := makeSig(S, S, NewSlice(T)) // []T required for variadic signature
                sig.variadic = true
 -              check.arguments(x, call, sig, func(x *operand, i int) {
 -                      // only evaluate arguments that have not been evaluated before
 -                      if i < len(alist) {
 -                              *x = alist[i]
 -                              return
 -                      }
 -                      arg(x, i)
 -              }, nargs)
 +              var xlist []*operand
 +              // convert []operand to []*operand
 +              for i := range alist {
 +                      xlist = append(xlist, &alist[i])
 +              }
 +              for i := len(alist); i < nargs; i++ {
 +                      var x operand
 +                      arg(&x, i)
 +                      xlist = append(xlist, &x)
 +              }
 +              check.arguments(call, sig, xlist) // discard result (we know the result type)
                // ok to continue even if check.arguments reported errors
  
                x.mode = value
                mode := invalid
                var typ Type
                var val constant.Value
 -              switch typ = implicitArrayDeref(x.typ.Underlying()); t := typ.(type) {
 +              switch typ = implicitArrayDeref(optype(x.typ)); t := typ.(type) {
                case *Basic:
                        if isString(t) && id == _Len {
                                if x.mode == constant_ {
                        if id == _Len {
                                mode = value
                        }
 +
 +              case *Sum:
 +                      if t.is(func(t Type) bool {
 +                              switch t := under(t).(type) {
 +                              case *Basic:
 +                                      if isString(t) && id == _Len {
 +                                              return true
 +                                      }
 +                              case *Array, *Slice, *Chan:
 +                                      return true
 +                              case *Map:
 +                                      if id == _Len {
 +                                              return true
 +                                      }
 +                              }
 +                              return false
 +                      }) {
 +                              mode = value
 +                      }
                }
  
                if mode == invalid && typ != Typ[Invalid] {
  
        case _Close:
                // close(c)
 -              c, _ := x.typ.Underlying().(*Chan)
 +              c := asChan(x.typ)
                if c == nil {
                        check.invalidArg(x, _InvalidClose, "%s is not a channel", x)
                        return
                }
  
                // the argument types must be of floating-point type
 -              if !isFloat(x.typ) {
 +              f := func(x Type) Type {
 +                      if t := asBasic(x); t != nil {
 +                              switch t.kind {
 +                              case Float32:
 +                                      return Typ[Complex64]
 +                              case Float64:
 +                                      return Typ[Complex128]
 +                              case UntypedFloat:
 +                                      return Typ[UntypedComplex]
 +                              }
 +                      }
 +                      return nil
 +              }
 +              resTyp := check.applyTypeFunc(f, x.typ)
 +              if resTyp == nil {
                        check.invalidArg(x, _InvalidComplex, "arguments have type %s, expected floating-point", x.typ)
                        return
                }
                        x.mode = value
                }
  
 -              // determine result type
 -              var res BasicKind
 -              switch x.typ.Underlying().(*Basic).kind {
 -              case Float32:
 -                      res = Complex64
 -              case Float64:
 -                      res = Complex128
 -              case UntypedFloat:
 -                      res = UntypedComplex
 -              default:
 -                      unreachable()
 -              }
 -              resTyp := Typ[res]
 -
                if check.Types != nil && x.mode != constant_ {
                        check.recordBuiltinType(call.Fun, makeSig(resTyp, x.typ, x.typ))
                }
        case _Copy:
                // copy(x, y []T) int
                var dst Type
 -              if t, _ := x.typ.Underlying().(*Slice); t != nil {
 +              if t := asSlice(x.typ); t != nil {
                        dst = t.elem
                }
  
                        return
                }
                var src Type
 -              switch t := y.typ.Underlying().(type) {
 +              switch t := optype(y.typ).(type) {
                case *Basic:
                        if isString(y.typ) {
                                src = universeByte
  
        case _Delete:
                // delete(m, k)
 -              m, _ := x.typ.Underlying().(*Map)
 +              m := asMap(x.typ)
                if m == nil {
                        check.invalidArg(x, _InvalidDelete, "%s is not a map", x)
                        return
                        return
                }
  
-               if ok, code := x.assignableTo(check, m.key, nil); !ok {
-                       check.invalidArg(x, code, "%s is not assignable to %s", x, m.key)
+               check.assignment(x, m.key, "argument to delete")
+               if x.mode == invalid {
                        return
                }
  
                }
  
                // the argument must be of complex type
 -              if !isComplex(x.typ) {
 +              f := func(x Type) Type {
 +                      if t := asBasic(x); t != nil {
 +                              switch t.kind {
 +                              case Complex64:
 +                                      return Typ[Float32]
 +                              case Complex128:
 +                                      return Typ[Float64]
 +                              case UntypedComplex:
 +                                      return Typ[UntypedFloat]
 +                              }
 +                      }
 +                      return nil
 +              }
 +              resTyp := check.applyTypeFunc(f, x.typ)
 +              if resTyp == nil {
                        code := _InvalidImag
                        if id == _Real {
                                code = _InvalidReal
                        x.mode = value
                }
  
 -              // determine result type
 -              var res BasicKind
 -              switch x.typ.Underlying().(*Basic).kind {
 -              case Complex64:
 -                      res = Float32
 -              case Complex128:
 -                      res = Float64
 -              case UntypedComplex:
 -                      res = UntypedFloat
 -              default:
 -                      unreachable()
 -              }
 -              resTyp := Typ[res]
 -
                if check.Types != nil && x.mode != constant_ {
                        check.recordBuiltinType(call.Fun, makeSig(resTyp, x.typ))
                }
                // make(T, n, m)
                // (no argument evaluated yet)
                arg0 := call.Args[0]
 -              T := check.typ(arg0)
 +              T := check.varType(arg0)
                if T == Typ[Invalid] {
                        return
                }
  
 -              var min int // minimum number of arguments
 -              switch T.Underlying().(type) {
 -              case *Slice:
 -                      min = 2
 -              case *Map, *Chan:
 -                      min = 1
 -              default:
 +              min, max := -1, 10
 +              var valid func(t Type) bool
 +              valid = func(t Type) bool {
 +                      var m int
 +                      switch t := optype(t).(type) {
 +                      case *Slice:
 +                              m = 2
 +                      case *Map, *Chan:
 +                              m = 1
 +                      case *Sum:
 +                              return t.is(valid)
 +                      default:
 +                              return false
 +                      }
 +                      if m > min {
 +                              min = m
 +                      }
 +                      if m+1 < max {
 +                              max = m + 1
 +                      }
 +                      return true
 +              }
 +
 +              if !valid(T) {
                        check.invalidArg(arg0, _InvalidMake, "cannot make %s; type must be slice, map, or channel", arg0)
                        return
                }
 -              if nargs < min || min+1 < nargs {
 -                      check.errorf(call, _WrongArgCount, "%v expects %d or %d arguments; found %d", call, min, min+1, nargs)
 +              if nargs < min || max < nargs {
 +                      if min == max {
 +                              check.errorf(call, _WrongArgCount, "%v expects %d arguments; found %d", call, min, nargs)
 +                      } else {
 +                              check.errorf(call, _WrongArgCount, "%v expects %d or %d arguments; found %d", call, min, max, nargs)
 +                      }
                        return
                }
 +
                types := []Type{T}
                var sizes []int64 // constant integer arguments, if any
                for _, arg := range call.Args[1:] {
        case _New:
                // new(T)
                // (no argument evaluated yet)
 -              T := check.typ(call.Args[0])
 +              T := check.varType(call.Args[0])
                if T == Typ[Invalid] {
                        return
                }
  
        case _Alignof:
                // unsafe.Alignof(x T) uintptr
 +              if asTypeParam(x.typ) != nil {
 +                      check.invalidOp(call, _Todo, "unsafe.Alignof undefined for %s", x)
 +                      return
 +              }
                check.assignment(x, nil, "argument to unsafe.Alignof")
                if x.mode == invalid {
                        return
  
        case _Sizeof:
                // unsafe.Sizeof(x T) uintptr
 +              if asTypeParam(x.typ) != nil {
 +                      check.invalidOp(call, _Todo, "unsafe.Sizeof undefined for %s", x)
 +                      return
 +              }
                check.assignment(x, nil, "argument to unsafe.Sizeof")
                if x.mode == invalid {
                        return
        return true
  }
  
 +// applyTypeFunc applies f to x. If x is a type parameter,
 +// the result is a type parameter constrained by an new
 +// interface bound. The type bounds for that interface
 +// are computed by applying f to each of the type bounds
 +// of x. If any of these applications of f return nil,
 +// applyTypeFunc returns nil.
 +// If x is not a type parameter, the result is f(x).
 +func (check *Checker) applyTypeFunc(f func(Type) Type, x Type) Type {
 +      if tp := asTypeParam(x); tp != nil {
 +              // Test if t satisfies the requirements for the argument
 +              // type and collect possible result types at the same time.
 +              var rtypes []Type
 +              if !tp.Bound().is(func(x Type) bool {
 +                      if r := f(x); r != nil {
 +                              rtypes = append(rtypes, r)
 +                              return true
 +                      }
 +                      return false
 +              }) {
 +                      return nil
 +              }
 +
 +              // construct a suitable new type parameter
 +              tpar := NewTypeName(token.NoPos, nil /* = Universe pkg */, "<type parameter>", nil)
 +              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}
 +
 +              return ptyp
 +      }
 +
 +      return f(x)
 +}
 +
  // makeSig makes a signature for the given argument and result types.
  // Default types are used for untyped arguments, and res may be nil.
  func makeSig(res Type, args ...Type) *Signature {
  //
  func implicitArrayDeref(typ Type) Type {
        if p, ok := typ.(*Pointer); ok {
 -              if a, ok := p.base.Underlying().(*Array); ok {
 +              if a := asArray(p.base); a != nil {
                        return a
                }
        }
diff --combined src/go/types/check.go
index d1672837b8d9d9b678edf595662eb407bd707070,3bc8ee067c2b1b516e98bbcfbc447b91c712fc9c..57c6a2e7b89ff059a31acccf2fc64dee5540ec6c
@@@ -8,6 -8,7 +8,7 @@@ package type
  
  import (
        "errors"
+       "fmt"
        "go/ast"
        "go/constant"
        "go/token"
@@@ -19,18 -20,18 +20,18 @@@ const 
        trace = false // turn on for detailed type resolution traces
  )
  
 -// If Strict is set, the type-checker enforces additional
 +// If forceStrict is set, the type-checker enforces additional
  // rules not specified by the Go 1 spec, but which will
  // catch guaranteed run-time errors if the respective
  // code is executed. In other words, programs passing in
 -// Strict mode are Go 1 compliant, but not all Go 1 programs
 -// will pass in Strict mode. The additional rules are:
 +// strict mode are Go 1 compliant, but not all Go 1 programs
 +// will pass in strict mode. The additional rules are:
  //
  // - A type assertion x.(T) where T is an interface type
  //   is invalid if any (statically known) method that exists
  //   for both x and T have different signatures.
  //
 -const strict = false
 +const forceStrict = false
  
  // exprInfo stores information about an untyped expression.
  type exprInfo struct {
@@@ -69,6 -70,12 +70,12 @@@ type importKey struct 
        path, dir string
  }
  
+ // A dotImportKey describes a dot-imported object in the given scope.
+ type dotImportKey struct {
+       scope *Scope
+       obj   Object
+ }
  // A Checker maintains the state of the type checker.
  // It must be created with NewChecker.
  type Checker struct {
        fset *token.FileSet
        pkg  *Package
        *Info
-       nextId uint64                     // unique Id for type parameters (first valid Id is 1)
-       objMap map[Object]*declInfo       // maps package-level objects and (non-interface) methods to declaration info
-       impMap map[importKey]*Package     // maps (import path, source directory) to (complete or fake) package
-       posMap map[*Interface][]token.Pos // maps interface types to lists of embedded interface positions
-       typMap map[string]*Named          // maps an instantiated named type hash to a *Named type
-       pkgCnt map[string]int             // counts number of imported packages with a given name (for better error messages)
+       version version                    // accepted language version
++      nextId  uint64                     // unique Id for type parameters (first valid Id is 1)
+       objMap  map[Object]*declInfo       // maps package-level objects and (non-interface) methods to declaration info
+       impMap  map[importKey]*Package     // maps (import path, source directory) to (complete or fake) package
+       posMap  map[*Interface][]token.Pos // maps interface types to lists of embedded interface positions
++      typMap  map[string]*Named          // maps an instantiated named type hash to a *Named type
+       pkgCnt  map[string]int             // counts number of imported packages with a given name (for better error messages)
  
        // 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]*ast.ImportSpec // unused dot-imported packages
+       files        []*ast.File               // package files
+       imports      []*PkgName                // list of imported packages
+       dotImportMap map[dotImportKey]*PkgName // maps dot-imported objects to the package they were dot-imported through
  
        firstErr error                 // first error encountered
        methods  map[*TypeName][]*Func // maps package scope type names to associated non-blank (non-interface) methods
        indent int // indentation for tracing
  }
  
- // 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, spec *ast.ImportSpec) {
-       mm := check.unusedDotImports
-       if mm == nil {
-               mm = make(map[*Scope]map[*Package]*ast.ImportSpec)
-               check.unusedDotImports = mm
-       }
-       m := mm[scope]
-       if m == nil {
-               m = make(map[*Package]*ast.ImportSpec)
-               mm[scope] = m
-       }
-       m[pkg] = spec
- }
  // addDeclDep adds the dependency edge (check.decl -> to) if check.decl exists
  func (check *Checker) addDeclDep(to Object) {
        from := check.decl
@@@ -187,17 -178,21 +180,23 @@@ func NewChecker(conf *Config, fset *tok
                info = new(Info)
        }
  
+       version, err := parseGoVersion(conf.GoVersion)
+       if err != nil {
+               panic(fmt.Sprintf("invalid Go version %q (%v)", conf.GoVersion, err))
+       }
        return &Checker{
-               conf:   conf,
-               fset:   fset,
-               pkg:    pkg,
-               Info:   info,
-               nextId: 1,
-               objMap: make(map[Object]*declInfo),
-               impMap: make(map[importKey]*Package),
-               posMap: make(map[*Interface][]token.Pos),
-               typMap: make(map[string]*Named),
-               pkgCnt: make(map[string]int),
+               conf:    conf,
+               fset:    fset,
+               pkg:     pkg,
+               Info:    info,
+               version: version,
++              nextId:  1,
+               objMap:  make(map[Object]*declInfo),
+               impMap:  make(map[importKey]*Package),
+               posMap:  make(map[*Interface][]token.Pos),
++              typMap:  make(map[string]*Named),
+               pkgCnt:  make(map[string]int),
        }
  }
  
  func (check *Checker) initFiles(files []*ast.File) {
        // start with a clean slate (check.Files may be called multiple times)
        check.files = nil
-       check.unusedDotImports = nil
+       check.imports = nil
+       check.dotImportMap = nil
  
        check.firstErr = nil
        check.methods = nil
@@@ -276,14 -272,16 +276,20 @@@ func (check *Checker) checkFiles(files 
        if !check.conf.DisableUnusedImportCheck {
                check.unusedImports()
        }
+       // no longer needed - release memory
+       check.imports = nil
+       check.dotImportMap = nil
  
        check.recordUntyped()
  
 +      if check.Info != nil {
 +              sanitizeInfo(check.Info)
 +      }
 +
        check.pkg.complete = true
+       // TODO(rFindley) There's more memory we should release at this point.
        return
  }
  
@@@ -385,14 -383,6 +391,14 @@@ func (check *Checker) recordCommaOkType
        }
  }
  
 +func (check *Checker) recordInferred(call ast.Expr, targs []Type, sig *Signature) {
 +      assert(call != nil)
 +      assert(sig != nil)
 +      if m := check.Inferred; m != nil {
 +              m[call] = Inferred{targs, sig}
 +      }
 +}
 +
  func (check *Checker) recordDef(id *ast.Ident, obj Object) {
        assert(id != nil)
        if m := check.Defs; m != nil {
index 51eae052f375c564a273324bdf61fa7079f38801,ca7d926ca903990bf941af6371a7a6d86cd9b2d8..c92855b3d8004c4ca6e95679e9656ca753704649
@@@ -47,7 -47,8 +47,8 @@@ import 
  var (
        haltOnError = flag.Bool("halt", false, "halt on error")
        listErrors  = flag.Bool("errlist", false, "list errors")
-       testFiles   = flag.String("files", "", "space-separated list of test files")
+       testFiles   = flag.String("files", "", "comma-separated list of test files")
+       goVersion   = flag.String("lang", "", "Go language version (e.g. \"go1.12\"")
  )
  
  var fset = token.NewFileSet()
@@@ -68,11 -69,11 +69,11 @@@ func splitError(err error) (pos, msg st
        return
  }
  
- func parseFiles(t *testing.T, filenames []string, mode parser.Mode) ([]*ast.File, []error) {
 -func parseFiles(t *testing.T, filenames []string, srcs [][]byte) ([]*ast.File, []error) {
++func parseFiles(t *testing.T, filenames []string, srcs [][]byte, mode parser.Mode) ([]*ast.File, []error) {
        var files []*ast.File
        var errlist []error
-       for _, filename := range filenames {
-               file, err := parser.ParseFile(fset, filename, nil, mode)
+       for i, filename := range filenames {
 -              file, err := parser.ParseFile(fset, filename, srcs[i], parser.AllErrors)
++              file, err := parser.ParseFile(fset, filename, srcs[i], mode)
                if file == nil {
                        t.Fatalf("%s: %s", filename, err)
                }
@@@ -101,19 -102,17 +102,17 @@@ var errRx = regexp.MustCompile(`^ *ERRO
  // errMap collects the regular expressions of ERROR comments found
  // in files and returns them as a map of error positions to error messages.
  //
- func errMap(t *testing.T, testname string, files []*ast.File) map[string][]string {
+ // srcs must be a slice of the same length as files, containing the original
+ // source for the parsed AST.
+ func errMap(t *testing.T, files []*ast.File, srcs [][]byte) map[string][]string {
        // map of position strings to lists of error message patterns
        errmap := make(map[string][]string)
  
-       for _, file := range files {
-               filename := fset.Position(file.Package).Filename
-               src, err := os.ReadFile(filename)
-               if err != nil {
-                       t.Fatalf("%s: could not read %s", testname, filename)
-               }
+       for i, file := range files {
+               tok := fset.File(file.Package)
+               src := srcs[i]
                var s scanner.Scanner
-               s.Init(fset.AddFile(filename, -1, len(src)), src, nil, scanner.ScanComments)
+               s.Init(tok, src, nil, scanner.ScanComments)
                var prev token.Pos // position of last non-comment, non-semicolon token
                var here token.Pos // position immediately after the token at position prev
  
@@@ -190,24 -189,38 +189,43 @@@ func eliminate(t *testing.T, errmap map
        }
  }
  
- func checkFiles(t *testing.T, sources []string) {
-       if len(sources) == 0 {
+ // goVersionRx matches a Go version string using '_', e.g. "go1_12".
+ var goVersionRx = regexp.MustCompile(`^go[1-9][0-9]*_(0|[1-9][0-9]*)$`)
+ // asGoVersion returns a regular Go language version string
+ // if s is a Go version string using '_' rather than '.' to
+ // separate the major and minor version numbers (e.g. "go1_12").
+ // Otherwise it returns the empty string.
+ func asGoVersion(s string) string {
+       if goVersionRx.MatchString(s) {
+               return strings.Replace(s, "_", ".", 1)
+       }
+       return ""
+ }
+ func checkFiles(t *testing.T, goVersion string, filenames []string, srcs [][]byte) {
+       if len(filenames) == 0 {
                t.Fatal("no source files")
        }
  
-       if strings.HasSuffix(sources[0], ".go2") {
 +      mode := parser.AllErrors
++      if strings.HasSuffix(filenames[0], ".go2") {
 +              mode |= parser.ParseTypeParams
 +      }
 +
        // parse files and collect parser errors
-       files, errlist := parseFiles(t, sources, mode)
 -      files, errlist := parseFiles(t, filenames, srcs)
++      files, errlist := parseFiles(t, filenames, srcs, mode)
  
        pkgName := "<no package>"
        if len(files) > 0 {
                pkgName = files[0].Name.Name
        }
  
+       // if no Go version is given, consider the package name
+       if goVersion == "" {
+               goVersion = asGoVersion(pkgName)
+       }
        if *listErrors && len(errlist) > 0 {
                t.Errorf("--- %s:", pkgName)
                for _, err := range errlist {
  
        // typecheck and collect typechecker errors
        var conf Config
+       conf.GoVersion = goVersion
  
        // special case for importC.src
-       if len(sources) == 1 && strings.HasSuffix(sources[0], "importC.src") {
-               conf.FakeImportC = true
+       if len(filenames) == 1 {
+               if strings.HasSuffix(filenames[0], "importC.src") {
+                       conf.FakeImportC = true
+               }
        }
-       // 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 {
  
        // match and eliminate errors;
        // we are expecting the following errors
-       errmap := errMap(t, pkgName, files)
+       errmap := errMap(t, files, srcs)
        eliminate(t, errmap, errlist)
  
        // there should be no expected errors left
  }
  
  // TestCheck is for manual testing of selected input files, provided with -files.
+ // The accepted Go language version can be controlled with the -lang flag.
  func TestCheck(t *testing.T) {
        if *testFiles == "" {
                return
        }
        testenv.MustHaveGoBuild(t)
        DefPredeclaredTestFuncs()
-       checkFiles(t, strings.Split(*testFiles, " "))
+       testPkg(t, strings.Split(*testFiles, ","), *goVersion)
+ }
+ func TestLongConstants(t *testing.T) {
+       format := "package longconst\n\nconst _ = %s\nconst _ = %s // ERROR excessively long constant"
+       src := fmt.Sprintf(format, strings.Repeat("1", 9999), strings.Repeat("1", 10001))
+       checkFiles(t, "", []string{"longconst.go"}, [][]byte{[]byte(src)})
  }
  
  func TestTestdata(t *testing.T)  { DefPredeclaredTestFuncs(); testDir(t, "testdata") }
 +func TestExamples(t *testing.T)  { testDir(t, "examples") }
  func TestFixedbugs(t *testing.T) { testDir(t, "fixedbugs") }
  
  func testDir(t *testing.T, dir string) {
                path := filepath.Join(dir, fi.Name())
  
                // if fi is a directory, its files make up a single package
-               var files []string
+               var filenames []string
                if fi.IsDir() {
                        fis, err := ioutil.ReadDir(path)
                        if err != nil {
                                t.Error(err)
                                continue
                        }
-                       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())
-                               if testing.Verbose() {
-                                       fmt.Printf("\t%s\n", files[i])
-                               }
+                       for _, fi := range fis {
+                               filenames = append(filenames, filepath.Join(path, fi.Name()))
                        }
                } else {
-                       files = []string{path}
+                       filenames = []string{path}
                }
                t.Run(filepath.Base(path), func(t *testing.T) {
-                       checkFiles(t, files)
+                       testPkg(t, filenames, "")
                })
        }
  }
+ func testPkg(t *testing.T, filenames []string, goVersion string) {
+       srcs := make([][]byte, len(filenames))
+       for i, filename := range filenames {
+               src, err := os.ReadFile(filename)
+               if err != nil {
+                       t.Fatalf("could not read %s: %v", filename, err)
+               }
+               srcs[i] = src
+       }
+       checkFiles(t, goVersion, filenames, srcs)
+ }
diff --combined src/go/types/decl.go
index f2e68bbd5c3fe38e08f978b4e7f74b9bd50e6573,6462edbd75e3e63eac8f25653eb1e3fdaea4b2ad..c97b1a66bb975aed9b2068fe3f1e9f7e5dad6bbf
@@@ -5,7 -5,6 +5,7 @@@
  package types
  
  import (
 +      "fmt"
        "go/ast"
        "go/constant"
        "go/token"
@@@ -53,10 -52,7 +53,10 @@@ func pathString(path []Object) string 
  // 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 trace {
 +      if trace && obj.Type() == nil {
 +              if check.indent == 0 {
 +                      fmt.Println() // empty line between top-level objects for readability
 +              }
                check.trace(obj.Pos(), "-- checking %s (%s, objPath = %s)", obj, obj.color(), pathString(check.objPath))
                check.indent++
                defer func() {
        switch obj := obj.(type) {
        case *Const:
                check.decl = d // new package-level const decl
 -              check.constDecl(obj, d.typ, d.init, d.inherited)
 +              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.typ, d.init)
 +              check.varDecl(obj, d.lhs, d.vtyp, d.init)
        case *TypeName:
                // invalid recursive types are detected via path
 -              check.typeDecl(obj, d.typ, def, d.aliasPos)
 +              check.typeDecl(obj, d.tdecl, def)
 +              check.collectMethods(obj) // methods can only be added to top-level types
        case *Func:
                // functions may be recursive - no need to track dependencies
                check.funcDecl(obj, d)
@@@ -239,7 -234,7 +239,7 @@@ func (check *Checker) cycle(obj Object
                        // this information explicitly in the object.
                        var alias bool
                        if d := check.objMap[obj]; d != nil {
 -                              alias = d.aliasPos.IsValid() // package-level object
 +                              alias = d.tdecl.Assign.IsValid() // package-level object
                        } else {
                                alias = obj.IsAlias() // function local object
                        }
@@@ -323,7 -318,7 +323,7 @@@ func (check *Checker) validType(typ Typ
                }
  
                // 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
                                if tn == t.obj {
                                        check.cycleError(path[i:])
                                        t.info = invalid
 -                                      t.underlying = Typ[Invalid]
                                        return t.info
                                }
                        }
                        panic("internal error: cycle start not found")
                }
                return t.info
 +
 +      case *instance:
 +              return check.validType(t.expand(), path)
        }
  
        return valid
@@@ -482,7 -475,7 +482,7 @@@ func (check *Checker) constDecl(obj *Co
                if !isConstType(t) {
                        // don't report an error if the type is an invalid C (defined) type
                        // (issue #22090)
 -                      if t.Underlying() != Typ[Invalid] {
 +                      if under(t) != Typ[Invalid] {
                                check.errorf(typ, _InvalidConstType, "invalid constant type %s", t)
                        }
                        obj.typ = Typ[Invalid]
  func (check *Checker) varDecl(obj *Var, lhs []*Var, typ, init ast.Expr) {
        assert(obj.typ == nil)
  
-       // If we have undefined variable types due to errors,
-       // mark variables as used to avoid follow-on errors.
-       // Matches compiler behavior.
-       defer func() {
-               if obj.typ == Typ[Invalid] {
-                       obj.used = true
-               }
-               for _, lhs := range lhs {
-                       if lhs.typ == Typ[Invalid] {
-                               lhs.used = true
-                       }
-               }
-       }()
        // determine type, if any
        if typ != nil {
 -              obj.typ = check.typ(typ)
 +              obj.typ = check.varType(typ)
                // We cannot spread the type to all lhs variables if there
                // are more than one since that would mark them as checked
                // (see Checker.objDecl) and the assignment of init exprs,
        check.initVars(lhs, []ast.Expr{init}, token.NoPos)
  }
  
 -// underlying returns the underlying type of typ; possibly by following
 -// forward chains of named types. Such chains only exist while named types
 -// are incomplete. If an underlying type is found, resolve the chain by
 -// setting the underlying type for each defined type in the chain before
 -// returning it.
 -//
 -// If no underlying type is found, a cycle error is reported and Typ[Invalid]
 -// is used as underlying type for each defined type in the chain and returned
 -// as result.
 -func (check *Checker) underlying(typ Type) Type {
 -      // If typ is not a defined type, its underlying type is itself.
 -      n0, _ := typ.(*Named)
 -      if n0 == nil {
 -              return typ // nothing to do
 +// under returns the expanded underlying type of n0; possibly by following
 +// forward chains of named types. If an underlying type is found, resolve
 +// the chain by setting the underlying type for each defined type in the
 +// chain before returning it. If no underlying type is found or a cycle
 +// is detected, the result is Typ[Invalid]. If a cycle is detected and
 +// n0.check != nil, the cycle is reported.
 +func (n0 *Named) under() Type {
 +      u := n0.underlying
 +      if u == nil {
 +              return Typ[Invalid]
        }
  
        // If the underlying type of a defined type is not a defined
        // type, then that is the desired underlying type.
 -      typ = n0.underlying
 -      n, _ := typ.(*Named)
 +      n := asNamed(u)
        if n == nil {
 -              return typ // common case
 +              return u // common case
        }
  
        // Otherwise, follow the forward chain.
        seen := map[*Named]int{n0: 0}
        path := []Object{n0.obj}
        for {
 -              typ = n.underlying
 -              n1, _ := typ.(*Named)
 +              u = n.underlying
 +              if u == nil {
 +                      u = Typ[Invalid]
 +                      break
 +              }
 +              n1 := asNamed(u)
                if n1 == nil {
                        break // end of chain
                }
  
                if i, ok := seen[n]; ok {
                        // cycle
 -                      check.cycleError(path[i:])
 -                      typ = Typ[Invalid]
 +                      // 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:])
 +                      }
 +                      u = Typ[Invalid]
                        break
                }
        }
                // We should never have to update the underlying type of an imported type;
                // those underlying types should have been resolved during the import.
                // Also, doing so would lead to a race condition (was issue #31749).
 -              if n.obj.pkg != check.pkg {
 +              // Do this check always, not just in debug more (it's cheap).
 +              if n0.check != nil && n.obj.pkg != n0.check.pkg {
                        panic("internal error: imported type with unresolved underlying type")
                }
 -              n.underlying = typ
 +              n.underlying = u
        }
  
 -      return typ
 +      return u
  }
  
  func (n *Named) setUnderlying(typ Type) {
        }
  }
  
 -func (check *Checker) typeDecl(obj *TypeName, typ ast.Expr, def *Named, aliasPos token.Pos) {
 +func (check *Checker) typeDecl(obj *TypeName, tdecl *ast.TypeSpec, def *Named) {
        assert(obj.typ == nil)
  
        check.later(func() {
                check.validType(obj.typ, nil)
        })
  
 -      if aliasPos.IsValid() {
 +      alias := tdecl.Assign.IsValid()
 +      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.error(atPos(tdecl.Assign), 0, "generic type cannot be alias")
 +              alias = false
 +      }
 +
 +      if alias {
 +              // type alias declaration
+               if !check.allowVersion(obj.pkg, 1, 9) {
 -                      check.errorf(atPos(aliasPos), _BadDecl, "type aliases requires go1.9 or later")
++                      check.errorf(atPos(tdecl.Assign), _BadDecl, "type aliases requires go1.9 or later")
+               }
  
                obj.typ = Typ[Invalid]
 -              obj.typ = check.typ(typ)
 +              obj.typ = check.anyType(tdecl.Type)
  
        } else {
 +              // defined type declaration
  
 -              named := &Named{obj: obj}
 +              named := &Named{check: check, obj: obj}
                def.setUnderlying(named)
                obj.typ = named // make sure recursive type declarations terminate
  
 +              if tdecl.TParams != nil {
 +                      check.openScope(tdecl, "type parameters")
 +                      defer check.closeScope()
 +                      named.tparams = check.collectTypeParams(tdecl.TParams)
 +              }
 +
                // determine underlying type of named
 -              named.orig = check.definedType(typ, named)
 +              named.orig = check.definedType(tdecl.Type, named)
  
                // The underlying type of named may be itself a named type that is
                // incomplete:
                // and which has as its underlying type the named type B.
                // Determine the (final, unnamed) underlying type by resolving
                // any forward chain.
 -              named.underlying = check.underlying(named)
 +              // TODO(gri) Investigate if we can just use named.origin here
 +              //           and rely on lazy computation of the underlying type.
 +              named.underlying = under(named)
 +      }
 +
 +}
 +
 +func (check *Checker) collectTypeParams(list *ast.FieldList) (tparams []*TypeName) {
 +      // Type parameter lists should not be empty. The parser will
 +      // complain but we still may get an incorrect AST: ignore it.
 +      if list.NumFields() == 0 {
 +              return
 +      }
 +
 +      // Declare type parameters up-front, with empty interface as type bound.
 +      // The scope of type parameters starts at the beginning of the type parameter
 +      // list (so we can have mutually recursive parameterized interfaces).
 +      for _, f := range list.List {
 +              tparams = check.declareTypeParams(tparams, f.Names)
 +      }
  
 +      setBoundAt := func(at int, bound Type) {
 +              assert(IsInterface(bound))
 +              tparams[at].typ.(*TypeParam).bound = bound
        }
  
 -      // TODO(rFindley): move to the callsite, as this is only needed for top-level
 -      //                 decls.
 -      check.addMethodDecls(obj)
 +      index := 0
 +      var bound Type
 +      for _, f := range list.List {
 +              if f.Type == nil {
 +                      goto next
 +              }
 +
 +              // 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 {
 +                      bound = check.typ(f.Type)
 +              }
 +
 +              // type bound must be an interface
 +              // TODO(gri) We should delay the interface check because
 +              //           we may not have a complete interface yet:
 +              //           type C(type T C) interface {}
 +              //           (issue #39724).
 +              if _, ok := under(bound).(*Interface); ok {
 +                      // Otherwise, set the bound for each type parameter.
 +                      for i := range f.Names {
 +                              setBoundAt(index+i, bound)
 +                      }
 +              } else if bound != Typ[Invalid] {
 +                      check.errorf(f.Type, _Todo, "%s is not an interface", bound)
 +              }
 +
 +      next:
 +              index += len(f.Names)
 +      }
 +
 +      return
  }
  
 -// TODO(rFindley): rename to collectMethods, to be consistent with types2.
 -func (check *Checker) addMethodDecls(obj *TypeName) {
 +func (check *Checker) declareTypeParams(tparams []*TypeName, names []*ast.Ident) []*TypeName {
 +      for _, name := range names {
 +              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 trace && len(names) > 0 {
 +              check.trace(names[0].Pos(), "type params = %v", tparams[len(tparams)-len(names):])
 +      }
 +
 +      return tparams
 +}
 +
 +func (check *Checker) collectMethods(obj *TypeName) {
        // get associated methods
        // (Checker.collectObjects only collects methods with non-blank names;
        // Checker.resolveBaseTypeName ensures that obj is not an alias name
                return
        }
        delete(check.methods, obj)
 -      assert(!check.objMap[obj].aliasPos.IsValid()) // don't use TypeName.IsAlias (requires fully set up object)
 +      assert(!check.objMap[obj].tdecl.Assign.IsValid()) // don't use TypeName.IsAlias (requires fully set up object)
  
        // use an objset to check for name conflicts
        var mset objset
  
        // spec: "If the base type is a struct type, the non-blank method
        // and field names must be distinct."
 -      base, _ := obj.typ.(*Named) // shouldn't fail but be conservative
 +      base := asNamed(obj.typ) // shouldn't fail but be conservative
        if base != nil {
                if t, _ := base.underlying.(*Struct); t != nil {
                        for _, fld := range t.fields {
@@@ -847,18 -741,16 +836,18 @@@ func (check *Checker) funcDecl(obj *Fun
  
        sig := new(Signature)
        obj.typ = sig // guard against cycles
 +
 +      // Avoid cycle error when referring to method while type-checking the signature.
 +      // This avoids a nuisance in the best case (non-parameterized receiver type) and
 +      // since the method is not a type, we get an error. If we have a parameterized
 +      // receiver type, instantiating the receiver type leads to the instantiation of
 +      // its methods, and we don't want a cycle error in that case.
 +      // TODO(gri) review if this is correct and/or whether we still need this?
 +      saved := obj.color_
 +      obj.color_ = black
        fdecl := decl.fdecl
        check.funcType(sig, fdecl.Recv, fdecl.Type)
 -      if sig.recv == nil {
 -              if obj.name == "init" && (sig.params.Len() > 0 || sig.results.Len() > 0) {
 -                      check.errorf(fdecl, _InvalidInitDecl, "func init must have no arguments and no return values")
 -              } else if obj.name == "main" && check.pkg.name == "main" && (sig.params.Len() > 0 || sig.results.Len() > 0) {
 -                      check.errorf(fdecl, _InvalidMainDecl, "func main must have no arguments and no return values")
 -              }
 -              // ok to continue
 -      }
 +      obj.color_ = saved
  
        // function body must be type-checked after global declarations
        // (functions implemented elsewhere have no body)
@@@ -964,7 -856,7 +953,7 @@@ func (check *Checker) declStmt(d ast.De
                        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.Type, nil, d.spec.Assign)
 +                      check.typeDecl(obj, d.spec, nil)
                        check.pop().setColor(black)
                default:
                        check.invalidAST(d.node(), "unknown ast.Decl node %T", d.node())
index 2837019bf5ec39dd56b77a23c634e7aadec4353f,ac28c3bd13443d65e3db53b41086a92e5751f315..1e39aed07d619cc59b5a8dcbe5d6022f95a515de
@@@ -6,6 -6,6 +6,9 @@@ package type
  
  type errorCode int
  
++// TODO(rFindley): ensure that existing error codes do not change in the
++//                 dev.typeparams branch.
++
  // This file defines the error codes that can be produced during type-checking.
  // Collectively, these codes provide an identifier that may be used to
  // implement special handling for certain types of errors.
@@@ -756,12 -756,52 +759,12 @@@ const 
        _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.
        //
        //  }
        _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.
        //
        //  }
        _InvalidGo
  
+       // _BadDecl occurs when a declaration has invalid syntax.
+       _BadDecl
++
 +      // _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
  )
index 33dfbefe19c7a38e9ec4beb556910c9624cbb703,3a97ac0471620fe3a835dadfdab3ad1425e830cb..41d3a61b89528ed7e8c4445585982f8efc593bd0
@@@ -76,7 -76,7 +76,7 @@@ func TestEvalArith(t *testing.T) 
                `false == false`,
                `12345678 + 87654321 == 99999999`,
                `10 * 20 == 200`,
-               `(1<<1000)*2 >> 100 == 2<<900`,
+               `(1<<500)*2 >> 100 == 2<<400`,
                `"foo" + "bar" == "foobar"`,
                `"abc" <= "bcd"`,
                `len([10]struct{}{}) == 2*5`,
@@@ -155,9 -155,9 +155,9 @@@ func TestEvalPos(t *testing.T) 
                import "io"
                type R = io.Reader
                func _() {
 -                      /* interface{R}.Read => , func(interface{io.Reader}, p []byte) (n int, err error) */
 +                      /* interface{R}.Read => , func(interface{io.Reader}, p []byte) (n int, err error) */
                        _ = func() {
 -                              /* interface{io.Writer}.Write => , func(interface{io.Writer}, p []byte) (n int, err error) */
 +                              /* interface{io.Writer}.Write => , func(interface{io.Writer}, p []byte) (n int, err error) */
                                type io interface {} // must not shadow io in line above
                        }
                        type R interface {} // must not shadow R in first line of this function body
diff --combined src/go/types/expr.go
index 0d9540245502a26b80798eb28787aa631748d250,aec3172327877b0e6905bc7a1d462b5907229b0c..45cf8c6b417ce082662d7365d68755cfb600296f
@@@ -1,4 -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.
@@@ -59,16 -58,11 +59,16 @@@ the type (and constant value, if any) i
  
  type opPredicates map[token.Token]func(Type) bool
  
 -var unaryOpPredicates = opPredicates{
 -      token.ADD: isNumeric,
 -      token.SUB: isNumeric,
 -      token.XOR: isInteger,
 -      token.NOT: isBoolean,
 +var unaryOpPredicates opPredicates
 +
 +func init() {
 +      // Setting unaryOpPredicates in init avoids declaration cycles.
 +      unaryOpPredicates = opPredicates{
 +              token.ADD: isNumeric,
 +              token.SUB: isNumeric,
 +              token.XOR: isInteger,
 +              token.NOT: isBoolean,
 +      }
  }
  
  func (check *Checker) op(m opPredicates, x *operand, op token.Token) bool {
        return true
  }
  
 -      if typ, ok := x.typ.Underlying().(*Basic); ok && isTyped(typ) {
+ // overflow checks that the constant x is representable by its type.
+ // For untyped constants, it checks that the value doesn't become
+ // arbitrarily large.
+ func (check *Checker) overflow(x *operand, op token.Token, opPos token.Pos) {
+       assert(x.mode == constant_)
+       if 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")
+               return
+       }
+       // Typed constants must be representable in
+       // their type after each constant operation.
++      if typ := asBasic(x.typ); typ != nil && isTyped(typ) {
+               check.representable(x, typ)
+               return
+       }
+       // Untyped integer values must not grow arbitrarily.
+       const prec = 512 // 512 is the constant precision
+       if x.val.Kind() == constant.Int && constant.BitLen(x.val) > prec {
+               check.errorf(atPos(opPos), _InvalidConstVal, "constant %s overflow", opName(x.expr))
+               x.val = constant.MakeUnknown()
+       }
+ }
+ // opName returns the name of an operation, or the empty string.
+ // For now, only operations that might overflow are handled.
+ // TODO(gri) Expand this to a general mechanism giving names to
+ //           nodes?
+ func opName(e ast.Expr) string {
+       switch e := e.(type) {
+       case *ast.BinaryExpr:
+               if int(e.Op) < len(op2str2) {
+                       return op2str2[e.Op]
+               }
+       case *ast.UnaryExpr:
+               if int(e.Op) < len(op2str1) {
+                       return op2str1[e.Op]
+               }
+       }
+       return ""
+ }
+ var op2str1 = [...]string{
+       token.XOR: "bitwise complement",
+ }
+ // This is only used for operations that may cause overflow.
+ var op2str2 = [...]string{
+       token.ADD: "addition",
+       token.SUB: "subtraction",
+       token.XOR: "bitwise XOR",
+       token.MUL: "multiplication",
+       token.SHL: "shift",
+ }
  // The unary expression e may be nil. It's passed in for better error messages only.
- func (check *Checker) unary(x *operand, e *ast.UnaryExpr, op token.Token) {
-       switch op {
+ func (check *Checker) unary(x *operand, e *ast.UnaryExpr) {
+       check.expr(x, e.X)
+       if x.mode == invalid {
+               return
+       }
+       switch e.Op {
        case token.AND:
                // 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 {
+               if _, ok := unparen(e.X).(*ast.CompositeLit); !ok && x.mode != variable {
                        check.invalidOp(x, _UnaddressableOperand, "cannot take address of %s", x)
                        x.mode = invalid
                        return
                return
  
        case token.ARROW:
 -              typ, ok := x.typ.Underlying().(*Chan)
 -              if !ok {
 +              typ := asChan(x.typ)
 +              if typ == nil {
                        check.invalidOp(x, _InvalidReceive, "cannot receive from non-channel %s", x)
                        x.mode = invalid
                        return
                return
        }
  
-       if !check.op(unaryOpPredicates, x, op) {
+       if !check.op(unaryOpPredicates, x, e.Op) {
                x.mode = invalid
                return
        }
  
        if x.mode == constant_ {
+               if x.val.Kind() == constant.Unknown {
+                       // nothing to do (and don't cause an error below in the overflow check)
+                       return
+               }
 +              typ := asBasic(x.typ)
                var prec uint
 -              if isUnsigned(x.typ) {
 -                      prec = uint(check.conf.sizeof(x.typ) * 8)
 +              if isUnsigned(typ) {
 +                      prec = uint(check.conf.sizeof(typ) * 8)
                }
-               x.val = constant.UnaryOp(op, x.val, prec)
-               // Typed constants must be representable in
-               // their type after each constant operation.
-               if isTyped(typ) {
-                       if e != nil {
-                               x.expr = e // for better error message
-                       }
-                       check.representable(x, typ)
-               }
+               x.val = constant.UnaryOp(e.Op, x.val, prec)
+               x.expr = e
+               check.overflow(x, e.Op, x.Pos())
                return
        }
  
@@@ -338,18 -393,17 +400,18 @@@ func representableConst(x constant.Valu
  // representable checks that a constant operand is representable in the given
  // basic type.
  func (check *Checker) representable(x *operand, typ *Basic) {
 -      if err := check.isRepresentable(x, typ); err != nil {
 +      if v, code := check.representation(x, typ); code != 0 {
 +              check.invalidConversion(code, x, typ)
                x.mode = invalid
 -              check.err(err)
 +      } else if v != nil {
 +              x.val = v
        }
  }
  
 -func (check *Checker) isRepresentable(x *operand, typ *Basic) error {
 +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
 -              var code errorCode
 +      v := x.val
 +      if !representableConst(x.val, check, typ, &v) {
                if isNumeric(x.typ) && isNumeric(typ) {
                        // numeric conversion : error msg
                        //
                        // float   -> float   : overflows
                        //
                        if !isInteger(x.typ) && isInteger(typ) {
 -                              msg = "%s truncated to %s"
 -                              code = _TruncatedFloat
 +                              return nil, _TruncatedFloat
                        } else {
 -                              msg = "%s overflows %s"
 -                              code = _NumericOverflow
 +                              return nil, _NumericOverflow
                        }
 -              } else {
 -                      msg = "cannot convert %s to %s"
 -                      code = _InvalidConstVal
                }
 -              return check.newErrorf(x, code, false, msg, x, typ)
 +              return nil, _InvalidConstVal
        }
 -      return nil
 +      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
@@@ -469,7 -517,7 +531,7 @@@ func (check *Checker) updateExprType(x 
        // If the new type is not final and still untyped, just
        // update the recorded type.
        if !final && isUntyped(typ) {
 -              old.typ = typ.Underlying().(*Basic)
 +              old.typ = asBasic(typ)
                check.untyped[x] = old
                return
        }
@@@ -513,29 -561,15 +575,29 @@@ func (check *Checker) updateExprVal(x a
  
  // convertUntyped attempts to set the type of an untyped value to the target type.
  func (check *Checker) convertUntyped(x *operand, target Type) {
 -      if err := check.canConvertUntyped(x, target); err != nil {
 +      newType, val, code := check.implicitTypeAndValue(x, target)
 +      if code != 0 {
 +              check.invalidConversion(code, x, target.Underlying())
                x.mode = invalid
 -              check.err(err)
 +              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)
        }
  }
  
 -func (check *Checker) canConvertUntyped(x *operand, target Type) error {
 +// 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 nil
 +              return x.typ, nil, 0
        }
  
        if isUntyped(target) {
                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 {
 -                      return check.newErrorf(x, _InvalidUntypedConversion, false, "cannot convert %s to %s", x, target)
 +                      return nil, nil, _InvalidUntypedConversion
                }
 -              return nil
 +              return x.typ, nil, 0
        }
  
 -      if t, ok := target.Underlying().(*Basic); ok && x.mode == constant_ {
 -              if err := check.isRepresentable(x, t); err != nil {
 -                      return err
 -              }
 -              // Expression value may have been rounded - update if needed.
 -              check.updateExprVal(x.expr, x.val)
 -      } else {
 -              newTarget := check.implicitType(x, target)
 -              if newTarget == nil {
 -                      return check.newErrorf(x, _InvalidUntypedConversion, false, "cannot convert %s to %s", x, target)
 -              }
 -              target = newTarget
 -      }
 -      x.typ = target
 -      // Even though implicitType can return UntypedNil, this value is final: the
 -      // predeclared identifier nil has no type.
 -      check.updateExprType(x.expr, target, true)
 -      return nil
 -}
 -
 -// implicitType 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 nil.
 -func (check *Checker) implicitType(x *operand, target Type) Type {
 -      assert(isUntyped(x.typ))
 -      switch t := target.Underlying().(type) {
 +      switch t := optype(target).(type) {
        case *Basic:
 -              assert(x.mode != constant_)
 +              if x.mode == constant_ {
 +                      v, code := check.representation(x, t)
 +                      if code != 0 {
 +                              return nil, nil, code
 +                      }
 +                      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
                switch x.typ.(*Basic).kind {
                case UntypedBool:
                        if !isBoolean(target) {
 -                              return nil
 +                              return nil, nil, _InvalidUntypedConversion
                        }
                case UntypedInt, UntypedRune, UntypedFloat, UntypedComplex:
                        if !isNumeric(target) {
 -                              return nil
 +                              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
 +                              return nil, nil, _InvalidUntypedConversion
                        }
                case UntypedNil:
                        // Unsafe.Pointer is a basic type that includes nil.
                        if !hasNil(target) {
 -                              return nil
 +                              return nil, nil, _InvalidUntypedConversion
                        }
                        // Preserve the type of nil as UntypedNil: see #13061.
 -                      return Typ[UntypedNil]
 +                      return Typ[UntypedNil], nil, 0
                default:
 -                      return nil
 +                      return nil, nil, _InvalidUntypedConversion
 +              }
 +      case *Sum:
 +              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:
                // Values must have concrete dynamic types. If the value is nil,
                // need the dynamic type for argument checking of say, print
                // functions)
                if x.isNil() {
 -                      return Typ[UntypedNil]
 +                      return Typ[UntypedNil], nil, 0
                }
                // cannot assign untyped values to non-empty interfaces
 -              check.completeInterface(t)
 +              check.completeInterface(token.NoPos, t)
                if !t.Empty() {
 -                      return nil
 +                      return nil, nil, _InvalidUntypedConversion
                }
 -              return Default(x.typ)
 +              return Default(x.typ), nil, 0
        case *Pointer, *Signature, *Slice, *Map, *Chan:
                if !x.isNil() {
 -                      return nil
 +                      return nil, nil, _InvalidUntypedConversion
                }
                // Keep nil untyped - see comment for interfaces, above.
 -              return Typ[UntypedNil]
 +              return Typ[UntypedNil], nil, 0
        default:
 -              return nil
 +              return nil, nil, _InvalidUntypedConversion
        }
 -      return target
 +      return target, nil, 0
  }
  
  func (check *Checker) comparison(x, y *operand, op token.Token) {
        x.typ = Typ[UntypedBool]
  }
  
- func (check *Checker) shift(x, y *operand, e *ast.BinaryExpr, op token.Token) {
-       untypedx := isUntyped(x.typ)
+ // If e != nil, it must be the shift expression; it may be nil for non-constant shifts.
+ func (check *Checker) shift(x, y *operand, e ast.Expr, op token.Token) {
+       // TODO(gri) This function seems overly complex. Revisit.
  
        var xval constant.Value
        if x.mode == constant_ {
                xval = constant.ToInt(x.val)
        }
  
-       if isInteger(x.typ) || untypedx && xval != nil && xval.Kind() == constant.Int {
+       if isInteger(x.typ) || isUntyped(x.typ) && xval != nil && xval.Kind() == constant.Int {
                // The lhs is of integer type or an untyped constant representable
                // as an integer. Nothing to do.
        } else {
  
        // spec: "The right operand in a shift expression must have integer type
        // or be an untyped constant representable by a value of type uint."
-       switch {
-       case isInteger(y.typ):
-               // nothing to do
-       case isUntyped(y.typ):
+       // Provide a good error message for negative shift counts.
+       if y.mode == constant_ {
+               yval := constant.ToInt(y.val) // consider -1, 1.0, but not -1.1
+               if yval.Kind() == constant.Int && constant.Sign(yval) < 0 {
+                       check.invalidOp(y, _InvalidShiftCount, "negative shift count %s", y)
+                       x.mode = invalid
+                       return
+               }
+       }
+       // Caution: Check for isUntyped first because isInteger includes untyped
+       //          integers (was bug #43697).
+       if isUntyped(y.typ) {
                check.convertUntyped(y, Typ[Uint])
                if y.mode == invalid {
                        x.mode = invalid
                        return
                }
-       default:
+       } else if !isInteger(y.typ) {
                check.invalidOp(y, _InvalidShiftCount, "shift count %s must be integer", y)
                x.mode = invalid
                return
+       } else if !isUnsigned(y.typ) && !check.allowVersion(check.pkg, 1, 13) {
+               check.invalidOp(y, _InvalidShiftCount, "signed shift count %s requires go1.13 or later", y)
+               x.mode = invalid
+               return
        }
  
        var yval constant.Value
  
        if x.mode == constant_ {
                if y.mode == constant_ {
+                       // if either x or y has an unknown value, the result is unknown
+                       if x.val.Kind() == constant.Unknown || y.val.Kind() == constant.Unknown {
+                               x.val = constant.MakeUnknown()
+                               // ensure the correct type - see comment below
+                               if !isInteger(x.typ) {
+                                       x.typ = Typ[UntypedInt]
+                               }
+                               return
+                       }
                        // rhs must be within reasonable bounds in constant shifts
-                       const shiftBound = 1023 - 1 + 52 // so we can express smallestFloat64
+                       const shiftBound = 1023 - 1 + 52 // so we can express smallestFloat64 (see issue #44057)
                        s, ok := constant.Uint64Val(yval)
                        if !ok || s > shiftBound {
                                check.invalidOp(y, _InvalidShiftCount, "invalid shift count %s", y)
                        }
                        // x is a constant so xval != nil and it must be of Int kind.
                        x.val = constant.Shift(xval, op, uint(s))
-                       // Typed constants must be representable in
-                       // their type after each constant operation.
-                       if isTyped(x.typ) {
-                               if e != nil {
-                                       x.expr = e // for better error message
-                               }
-                               check.representable(x, asBasic(x.typ))
+                       x.expr = e
+                       opPos := x.Pos()
+                       if b, _ := e.(*ast.BinaryExpr); b != nil {
+                               opPos = b.OpPos
                        }
+                       check.overflow(x, op, opPos)
                        return
                }
  
                // non-constant shift with constant lhs
-               if untypedx {
+               if isUntyped(x.typ) {
                        // spec: "If the left operand of a non-constant shift
                        // expression is an untyped constant, the type of the
                        // constant is what it would be if the shift expression
        x.mode = value
  }
  
 -var binaryOpPredicates = opPredicates{
 -      token.ADD: func(typ Type) bool { return isNumeric(typ) || isString(typ) },
 -      token.SUB: isNumeric,
 -      token.MUL: isNumeric,
 -      token.QUO: isNumeric,
 -      token.REM: isInteger,
 +var binaryOpPredicates opPredicates
 +
 +func init() {
 +      // Setting binaryOpPredicates in init avoids declaration cycles.
 +      binaryOpPredicates = opPredicates{
 +              token.ADD: isNumericOrString,
 +              token.SUB: isNumeric,
 +              token.MUL: isNumeric,
 +              token.QUO: isNumeric,
 +              token.REM: isInteger,
  
 -      token.AND:     isInteger,
 -      token.OR:      isInteger,
 -      token.XOR:     isInteger,
 -      token.AND_NOT: isInteger,
 +              token.AND:     isInteger,
 +              token.OR:      isInteger,
 +              token.XOR:     isInteger,
 +              token.AND_NOT: isInteger,
  
 -      token.LAND: isBoolean,
 -      token.LOR:  isBoolean,
 +              token.LAND: isBoolean,
 +              token.LOR:  isBoolean,
 +      }
  }
  
- // 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, opPos token.Pos) {
+ // If e != nil, it must be the binary expression; it may be nil for non-constant expressions
+ // (when invoked for an assignment operation where the binary expression is implicit).
+ func (check *Checker) binary(x *operand, e ast.Expr, lhs, rhs ast.Expr, op token.Token, opPos token.Pos) {
        var y operand
  
        check.expr(x, lhs)
        }
  
        if x.mode == constant_ && y.mode == constant_ {
-               xval := x.val
-               yval := y.val
+               // if either x or y has an unknown value, the result is unknown
+               if x.val.Kind() == constant.Unknown || y.val.Kind() == constant.Unknown {
+                       x.val = constant.MakeUnknown()
+                       // x.typ is unchanged
+                       return
+               }
 +              typ := asBasic(x.typ)
                // force integer division of integer operands
 -              if op == token.QUO && isInteger(x.typ) {
 +              if op == token.QUO && isInteger(typ) {
                        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) {
-                       if e != nil {
-                               x.expr = e // for better error message
-                       }
-                       check.representable(x, typ)
-               }
+               x.val = constant.BinaryOp(x.val, op, y.val)
+               x.expr = e
+               check.overflow(x, op, opPos)
                return
        }
  
@@@ -1044,7 -1093,7 +1119,7 @@@ const 
  //
  func (check *Checker) rawExpr(x *operand, e ast.Expr, hint Type) exprKind {
        if trace {
 -              check.trace(e.Pos(), "%s", e)
 +              check.trace(e.Pos(), "expr %s", e)
                check.indent++
                defer func() {
                        check.indent--
@@@ -1105,6 -1154,24 +1180,24 @@@ func (check *Checker) exprInternal(x *o
                goto Error
  
        case *ast.BasicLit:
+               switch e.Kind {
+               case token.INT, token.FLOAT, token.IMAG:
+                       check.langCompat(e)
+                       // The max. mantissa precision for untyped numeric values
+                       // is 512 bits, or 4048 bits for each of the two integer
+                       // parts of a fraction for floating-point numbers that are
+                       // represented accurately in the go/constant package.
+                       // Constant literals that are longer than this many bits
+                       // are not meaningful; and excessively long constants may
+                       // consume a lot of space and time for a useless conversion.
+                       // Cap constant length with a generous upper limit that also
+                       // allows for separators between all digits.
+                       const limit = 10000
+                       if len(e.Value) > limit {
+                               check.errorf(e, _InvalidConstVal, "excessively long constant: %s... (%d chars)", e.Value[:10], len(e.Value))
+                               goto Error
+                       }
+               }
                x.setConst(e.Kind, e.Value)
                if x.mode == invalid {
                        // The parser already establishes syntactic correctness.
                                        // We have an "open" [...]T array type.
                                        // Create a new ArrayType with unknown length (-1)
                                        // and finish setting it up after analyzing the literal.
 -                                      typ = &Array{len: -1, elem: check.typ(atyp.Elt)}
 +                                      typ = &Array{len: -1, elem: check.varType(atyp.Elt)}
                                        base = typ
                                        break
                                }
                case hint != nil:
                        // no composite literal type present - use hint (element type of enclosing type)
                        typ = hint
 -                      base, _ = deref(typ.Underlying()) // *T implies &T{}
 +                      base, _ = deref(under(typ)) // *T implies &T{}
  
                default:
                        // TODO(gri) provide better error messages depending on context
                        goto Error
                }
  
 -              switch utyp := base.Underlying().(type) {
 +              switch utyp := optype(base).(type) {
                case *Struct:
                        if len(e.Elts) == 0 {
                                break
                                        duplicate := false
                                        // if the key is of interface type, the type is also significant when checking for duplicates
                                        xkey := keyVal(x.val)
 -                                      if _, ok := utyp.key.Underlying().(*Interface); ok {
 +                                      if asInterface(utyp.key) != nil {
                                                for _, vtyp := range visited[xkey] {
                                                        if check.identical(vtyp, x.typ) {
                                                                duplicate = true
                check.selector(x, e)
  
        case *ast.IndexExpr:
 -              check.expr(x, e.X)
 +              check.exprOrType(x, e.X)
                if x.mode == invalid {
                        check.use(e.Index)
                        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 x.mode == value {
 +                      if sig := asSignature(x.typ); sig != nil && len(sig.tparams) > 0 {
 +                              return check.call(x, nil, e)
 +                      }
 +              }
 +
                valid := false
                length := int64(-1) // valid if >= 0
 -              switch typ := x.typ.Underlying().(type) {
 +              switch typ := optype(x.typ).(type) {
                case *Basic:
                        if isString(typ) {
                                valid = true
                        x.typ = typ.elem
  
                case *Pointer:
 -                      if typ, _ := typ.base.Underlying().(*Array); typ != nil {
 +                      if typ := asArray(typ.base); typ != nil {
                                valid = true
                                length = typ.len
                                x.mode = variable
                        x.typ = typ.elem
                        x.expr = e
                        return expression
 +
 +              case *Sum:
 +                      // A sum type can be indexed if all of the sum's types
 +                      // support indexing and have the same index and element
 +                      // type. Special rules apply for maps in the sum type.
 +                      var tkey, telem Type // key is for map types only
 +                      nmaps := 0           // number of map types in sum type
 +                      if typ.is(func(t Type) bool {
 +                              var e Type
 +                              switch t := under(t).(type) {
 +                              case *Basic:
 +                                      if isString(t) {
 +                                              e = universeByte
 +                                      }
 +                              case *Array:
 +                                      e = t.elem
 +                              case *Pointer:
 +                                      if t := asArray(t.base); t != nil {
 +                                              e = t.elem
 +                                      }
 +                              case *Slice:
 +                                      e = t.elem
 +                              case *Map:
 +                                      // If there are multiple maps in the sum type,
 +                                      // they must have identical key types.
 +                                      // TODO(gri) We may be able to relax this rule
 +                                      // but it becomes complicated very quickly.
 +                                      if tkey != nil && !Identical(t.key, tkey) {
 +                                              return false
 +                                      }
 +                                      tkey = t.key
 +                                      e = t.elem
 +                                      nmaps++
 +                              case *TypeParam:
 +                                      check.errorf(x, 0, "type of %s contains a type parameter - cannot index (implementation restriction)", x)
 +                              case *instance:
 +                                      panic("unimplemented")
 +                              }
 +                              if e == nil || telem != nil && !Identical(e, telem) {
 +                                      return false
 +                              }
 +                              telem = e
 +                              return true
 +                      }) {
 +                              // If there are maps, the index expression must be assignable
 +                              // to the map key type (as for simple map index expressions).
 +                              if nmaps > 0 {
 +                                      var key operand
 +                                      check.expr(&key, e.Index)
 +                                      check.assignment(&key, tkey, "map index")
 +                                      // ok to continue even if indexing failed - map element type is known
 +
 +                                      // If there are only maps, we are done.
 +                                      if nmaps == len(typ.types) {
 +                                              x.mode = mapindex
 +                                              x.typ = telem
 +                                              x.expr = e
 +                                              return expression
 +                                      }
 +
 +                                      // Otherwise we have mix of maps and other types. For
 +                                      // now we require that the map key be an integer type.
 +                                      // TODO(gri) This is probably not good enough.
 +                                      valid = isInteger(tkey)
 +                                      // avoid 2nd indexing error if indexing failed above
 +                                      if !valid && key.mode == invalid {
 +                                              goto Error
 +                                      }
 +                                      x.mode = value // map index expressions are not addressable
 +                              } else {
 +                                      // no maps
 +                                      valid = true
 +                                      x.mode = variable
 +                              }
 +                              x.typ = telem
 +                      }
                }
  
                if !valid {
                        goto Error
                }
  
 +              // In pathological (invalid) cases (e.g.: type T1 [][[]T1{}[0][0]]T0)
 +              // the element type may be accessed before it's set. Make sure we have
 +              // a valid type.
 +              if x.typ == nil {
 +                      x.typ = Typ[Invalid]
 +              }
 +
                check.index(e.Index, length)
                // ok to continue
  
  
                valid := false
                length := int64(-1) // valid if >= 0
 -              switch typ := x.typ.Underlying().(type) {
 +              switch typ := optype(x.typ).(type) {
                case *Basic:
                        if isString(typ) {
                                if e.Slice3 {
                        x.typ = &Slice{elem: typ.elem}
  
                case *Pointer:
 -                      if typ, _ := typ.base.Underlying().(*Array); typ != nil {
 +                      if typ := asArray(typ.base); typ != nil {
                                valid = true
                                length = typ.len
                                x.typ = &Slice{elem: typ.elem}
                case *Slice:
                        valid = true
                        // x.typ doesn't change
 +
 +              case *Sum, *TypeParam:
 +                      check.errorf(x, 0, "generic slice expressions not yet implemented")
 +                      goto Error
                }
  
                if !valid {
                if x.mode == invalid {
                        goto Error
                }
 -              xtyp, _ := x.typ.Underlying().(*Interface)
 +              xtyp, _ := under(x.typ).(*Interface)
                if xtyp == nil {
                        check.invalidOp(x, _InvalidAssert, "%s is not an interface", x)
                        goto Error
                }
 +              check.ordinaryType(x, xtyp)
                // x.(type) expressions are handled explicitly in type switches
                if e.Type == nil {
                        // Don't use invalidAST because this can occur in the AST produced by
                        check.error(e, _BadTypeKeyword, "use of .(type) outside type switch")
                        goto Error
                }
 -              T := check.typ(e.Type)
 +              T := check.varType(e.Type)
                if T == Typ[Invalid] {
                        goto Error
                }
                x.typ = T
  
        case *ast.CallExpr:
 -              return check.call(x, e)
 +              return check.call(x, e, e)
  
        case *ast.StarExpr:
                check.exprOrType(x, e.X)
                case typexpr:
                        x.typ = &Pointer{base: x.typ}
                default:
 -                      if typ, ok := x.typ.Underlying().(*Pointer); ok {
 +                      if typ := asPointer(x.typ); typ != nil {
                                x.mode = variable
                                x.typ = typ.base
                        } else {
                }
  
        case *ast.UnaryExpr:
-               check.expr(x, e.X)
-               if x.mode == invalid {
-                       goto Error
-               }
-               check.unary(x, e, e.Op)
+               check.unary(x, e)
                if x.mode == invalid {
                        goto Error
                }
@@@ -1757,26 -1716,46 +1846,26 @@@ func (check *Checker) typeAssertion(at 
        check.errorf(at, _ImpossibleAssert, "%s cannot have dynamic type %s (%s)", x, T, msg)
  }
  
 -func (check *Checker) singleValue(x *operand) {
 -      if x.mode == value {
 -              // 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, _TooManyValues, "%d-valued %s where single value is expected", t.Len(), x)
 -                      x.mode = invalid
 -              }
 -      }
 -}
 -
  // expr typechecks expression e and initializes x with the expression value.
  // The result must be a single value.
  // If an error occurred, x.mode is set to invalid.
  //
  func (check *Checker) expr(x *operand, e ast.Expr) {
 -      check.multiExpr(x, e)
 +      check.rawExpr(x, e, nil)
 +      check.exclude(x, 1<<novalue|1<<builtin|1<<typexpr)
        check.singleValue(x)
  }
  
 -// multiExpr is like expr but the result may be a multi-value.
 +// multiExpr is like expr but the result may also be a multi-value.
  func (check *Checker) multiExpr(x *operand, e ast.Expr) {
        check.rawExpr(x, e, nil)
 -      var msg string
 -      var code errorCode
 -      switch x.mode {
 -      default:
 -              return
 -      case novalue:
 -              msg = "%s used as value"
 -              code = _TooManyValues
 -      case builtin:
 -              msg = "%s must be called"
 -              code = _UncalledBuiltin
 -      case typexpr:
 -              msg = "%s is not an expression"
 -              code = _NotAnExpr
 -      }
 -      check.errorf(x, code, msg, x)
 -      x.mode = invalid
 +      check.exclude(x, 1<<novalue|1<<builtin|1<<typexpr)
 +}
 +
 +// multiExprOrType is like multiExpr but the result may also be a type.
 +func (check *Checker) multiExprOrType(x *operand, e ast.Expr) {
 +      check.rawExpr(x, e, nil)
 +      check.exclude(x, 1<<novalue|1<<builtin)
  }
  
  // exprWithHint typechecks expression e and initializes x with the expression value;
  func (check *Checker) exprWithHint(x *operand, e ast.Expr, hint Type) {
        assert(hint != nil)
        check.rawExpr(x, e, hint)
 +      check.exclude(x, 1<<novalue|1<<builtin|1<<typexpr)
        check.singleValue(x)
 -      var msg string
 -      var code errorCode
 -      switch x.mode {
 -      default:
 -              return
 -      case novalue:
 -              msg = "%s used as value"
 -              code = _TooManyValues
 -      case builtin:
 -              msg = "%s must be called"
 -              code = _UncalledBuiltin
 -      case typexpr:
 -              msg = "%s is not an expression"
 -              code = _NotAnExpr
 -      }
 -      check.errorf(x, code, msg, x)
 -      x.mode = invalid
  }
  
  // exprOrType typechecks expression or type e and initializes x with the expression value or type.
  //
  func (check *Checker) exprOrType(x *operand, e ast.Expr) {
        check.rawExpr(x, e, nil)
 +      check.exclude(x, 1<<novalue)
        check.singleValue(x)
 -      if x.mode == novalue {
 -              check.errorf(x, _NotAnExpr, "%s used as value or type", x)
 +}
 +
 +// exclude reports an error if x.mode is in modeset and sets x.mode to invalid.
 +// The modeset may contain any of 1<<novalue, 1<<builtin, 1<<typexpr.
 +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 {
 +                              msg = "%s used as value"
 +                      } 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, code, msg, x)
                x.mode = invalid
        }
  }
 +
 +// singleValue reports an error if x describes a tuple and sets x.mode to invalid.
 +func (check *Checker) singleValue(x *operand) {
 +      if x.mode == value {
 +              // 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, _TooManyValues, "%d-valued %s where single value is expected", t.Len(), x)
 +                      x.mode = invalid
 +              }
 +      }
 +}
index 023327496713611ecdf27ea3cffbae36f80caf4f,954a7ca987a8f554c79264dae3b6da8905405db2..7a99c1ff99750b5288ea3cb1cb9752b41a50eca2
@@@ -6,80 -6,73 +6,79 @@@
  
  package types
  
-       "sort"
 +import (
 +      "go/token"
 +)
 +
 +// isNamed reports whether typ has a name.
 +// isNamed may be called with types that are not fully set up.
  func isNamed(typ Type) bool {
 -      if _, ok := typ.(*Basic); ok {
 -              return ok
 +      switch typ.(type) {
 +      case *Basic, *Named, *TypeParam, *instance:
 +              return true
        }
 -      _, ok := typ.(*Named)
 -      return ok
 -}
 -
 -func isBoolean(typ Type) bool {
 -      t, ok := typ.Underlying().(*Basic)
 -      return ok && t.info&IsBoolean != 0
 -}
 -
 -func isInteger(typ Type) bool {
 -      t, ok := typ.Underlying().(*Basic)
 -      return ok && t.info&IsInteger != 0
 -}
 -
 -func isUnsigned(typ Type) bool {
 -      t, ok := typ.Underlying().(*Basic)
 -      return ok && t.info&IsUnsigned != 0
 -}
 -
 -func isFloat(typ Type) bool {
 -      t, ok := typ.Underlying().(*Basic)
 -      return ok && t.info&IsFloat != 0
 -}
 -
 -func isComplex(typ Type) bool {
 -      t, ok := typ.Underlying().(*Basic)
 -      return ok && t.info&IsComplex != 0
 +      return false
  }
  
 -func isNumeric(typ Type) bool {
 -      t, ok := typ.Underlying().(*Basic)
 -      return ok && t.info&IsNumeric != 0
 +// 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)
 +      return named != nil && named.obj != nil && named.tparams != nil && named.targs == nil
  }
  
 -func isString(typ Type) bool {
 -      t, ok := typ.Underlying().(*Basic)
 -      return ok && t.info&IsString != 0
 +func is(typ Type, what BasicInfo) bool {
 +      switch t := optype(typ).(type) {
 +      case *Basic:
 +              return t.info&what != 0
 +      case *Sum:
 +              return t.is(func(typ Type) bool { return is(typ, what) })
 +      }
 +      return false
  }
  
 +func isBoolean(typ Type) bool  { return is(typ, IsBoolean) }
 +func isInteger(typ Type) bool  { return is(typ, IsInteger) }
 +func isUnsigned(typ Type) bool { return is(typ, IsUnsigned) }
 +func isFloat(typ Type) bool    { return is(typ, IsFloat) }
 +func isComplex(typ Type) bool  { return is(typ, IsComplex) }
 +func isNumeric(typ Type) bool  { return is(typ, IsNumeric) }
 +func isString(typ Type) bool   { return is(typ, IsString) }
 +
 +// Note that if typ is a type parameter, isInteger(typ) || isFloat(typ) does not
 +// produce the expected result because a type list that contains both an integer
 +// and a floating-point type is neither (all) integers, nor (all) floats.
 +// Use isIntegerOrFloat instead.
 +func isIntegerOrFloat(typ Type) bool { return is(typ, IsInteger|IsFloat) }
 +
 +// isNumericOrString is the equivalent of isIntegerOrFloat for isNumeric(typ) || isString(typ).
 +func isNumericOrString(typ Type) bool { return is(typ, IsNumeric|IsString) }
 +
 +// isTyped reports whether typ is typed; i.e., not an untyped
 +// constant or boolean. isTyped may be called with types that
 +// are not fully set up.
  func isTyped(typ Type) bool {
 -      t, ok := typ.Underlying().(*Basic)
 -      return !ok || t.info&IsUntyped == 0
 +      // isTyped is called with types that are not fully
 +      // set up. Must not call asBasic()!
 +      // A *Named or *instance type is always typed, so
 +      // we only need to check if we have a true *Basic
 +      // type.
 +      t, _ := typ.(*Basic)
 +      return t == nil || t.info&IsUntyped == 0
  }
  
 +// isUntyped(typ) is the same as !isTyped(typ).
  func isUntyped(typ Type) bool {
 -      t, ok := typ.Underlying().(*Basic)
 -      return ok && t.info&IsUntyped != 0
 -}
 -
 -func isOrdered(typ Type) bool {
 -      t, ok := typ.Underlying().(*Basic)
 -      return ok && t.info&IsOrdered != 0
 +      return !isTyped(typ)
  }
  
 -func isConstType(typ Type) bool {
 -      t, ok := typ.Underlying().(*Basic)
 -      return ok && 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 {
 -      _, ok := typ.Underlying().(*Interface)
 -      return ok
 +      return asInterface(typ) != nil
  }
  
  // Comparable reports whether values of type T are comparable.
@@@ -96,19 -89,7 +95,19 @@@ func comparable(T Type, seen map[Type]b
        }
        seen[T] = true
  
 -      switch t := T.Underlying().(type) {
 +      // 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
 +      //
 +      //     interface{ comparable; type []byte }
 +      //
 +      // is not comparable because []byte is not comparable.
 +      if t := asTypeParam(T); t != nil && optype(t) == theTop {
 +              return t.Bound().IsComparable()
 +      }
 +
 +      switch t := optype(T).(type) {
        case *Basic:
                // assume invalid types to be comparable
                // to avoid follow-up errors
                return true
        case *Array:
                return comparable(t.elem, seen)
 +      case *Sum:
 +              pred := func(t Type) bool {
 +                      return comparable(t, seen)
 +              }
 +              return t.is(pred)
 +      case *TypeParam:
 +              return t.Bound().IsComparable()
        }
        return false
  }
  
  // hasNil reports whether a type includes the nil value.
  func hasNil(typ Type) bool {
 -      switch t := typ.Underlying().(type) {
 +      switch t := optype(typ).(type) {
        case *Basic:
                return t.kind == UnsafePointer
        case *Slice, *Pointer, *Signature, *Interface, *Map, *Chan:
                return true
 +      case *Sum:
 +              return t.is(hasNil)
        }
        return false
  }
@@@ -170,12 -142,7 +169,12 @@@ func (p *ifacePair) identical(q *ifaceP
        return p.x == q.x && p.y == q.y || p.x == q.y && p.y == q.x
  }
  
 +// For changes to this code the corresponding changes should be made to unifier.nify.
  func (check *Checker) identical0(x, y Type, cmpTags bool, p *ifacePair) bool {
 +      // types must be expanded for comparison
 +      x = expandf(x)
 +      y = expandf(y)
 +
        if x == y {
                return true
        }
                // and result values, corresponding parameter and result types are identical,
                // and either both functions are variadic or neither is. Parameter and result
                // names are not required to match.
 +              // Generic functions must also have matching type parameter lists, but for the
 +              // parameter names.
                if y, ok := y.(*Signature); ok {
                        return x.variadic == y.variadic &&
 +                              check.identicalTParams(x.tparams, y.tparams, cmpTags, p) &&
                                check.identical0(x.params, y.params, cmpTags, p) &&
                                check.identical0(x.results, y.results, cmpTags, p)
                }
  
 +      case *Sum:
 +              // Two sum types are identical if they contain the same types.
 +              // (Sum types always consist of at least two types. Also, the
 +              // the set (list) of types in a sum type consists of unique
 +              // types - each type appears exactly once. Thus, two sum types
 +              // must contain the same number of types to have chance of
 +              // being equal.
 +              if y, ok := y.(*Sum); ok && len(x.types) == len(y.types) {
 +                      // Every type in x.types must be in y.types.
 +                      // Quadratic algorithm, but probably good enough for now.
 +                      // TODO(gri) we need a fast quick type ID/hash for all types.
 +              L:
 +                      for _, x := range x.types {
 +                              for _, y := range y.types {
 +                                      if Identical(x, y) {
 +                                              continue L // x is in y.types
 +                                      }
 +                              }
 +                              return false // x is not in y.types
 +                      }
 +                      return true
 +              }
 +
        case *Interface:
                // Two interface types are identical if they have the same set of methods with
                // the same names and identical function types. Lower-case method names from
                        // that case, interfaces are expected to be complete and lazy completion
                        // here is not needed.
                        if check != nil {
 -                              check.completeInterface(x)
 -                              check.completeInterface(y)
 +                              check.completeInterface(token.NoPos, x)
 +                              check.completeInterface(token.NoPos, y)
                        }
                        a := x.allMethods
                        b := y.allMethods
                                        p = p.prev
                                }
                                if debug {
-                                       assert(sort.IsSorted(byUniqueMethodName(a)))
-                                       assert(sort.IsSorted(byUniqueMethodName(b)))
+                                       assertSortedMethods(a)
+                                       assertSortedMethods(b)
                                }
                                for i, f := range a {
                                        g := b[i]
                // Two named types are identical if their type names originate
                // in the same type declaration.
                if y, ok := y.(*Named); ok {
 +                      // TODO(gri) Why is x == y not sufficient? And if it is,
 +                      //           we can just return false here because x == y
 +                      //           is caught in the very beginning of this function.
                        return x.obj == y.obj
                }
  
 +      case *TypeParam:
 +              // nothing to do (x and y being equal is caught in the very beginning of this function)
 +
 +      // case *instance:
 +      //      unreachable since types are expanded
 +
 +      case *bottom, *top:
 +              // Either both types are theBottom, or both are theTop in which
 +              // case the initial x == y check will have caught them. Otherwise
 +              // they are not identical.
 +
        case nil:
 +              // avoid a crash in case of nil type
  
        default:
                unreachable()
        return false
  }
  
 +func (check *Checker) identicalTParams(x, y []*TypeName, cmpTags bool, p *ifacePair) bool {
 +      if len(x) != len(y) {
 +              return false
 +      }
 +      for i, x := range x {
 +              y := y[i]
 +              if !check.identical0(x.typ.(*TypeParam).bound, y.typ.(*TypeParam).bound, cmpTags, p) {
 +                      return false
 +              }
 +      }
 +      return true
 +}
 +
  // Default returns the default "typed" type for an "untyped" type;
  // it returns the incoming type for all other types. The default type
  // for untyped nil is untyped nil.
diff --combined src/go/types/resolver.go
index 4f09237692837c3fb81275e7e9149feb0653bede,e4411592e82a0ae6c77ce570d8106a7828ceb155..36f9a45cca2b6d5f27d2fc4dccf48a7540eb348f
@@@ -19,11 -19,11 +19,11 @@@ import 
  type declInfo struct {
        file      *Scope        // scope of file containing this declaration
        lhs       []*Var        // lhs of n:1 variable declarations, or nil
 -      typ       ast.Expr      // type, or nil
 -      init      ast.Expr      // init/orig expression, 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
 -      aliasPos  token.Pos     // If valid, the decl is a type alias and aliasPos is the position of '='.
  
        // The deps field tracks initialization expression dependencies.
        deps map[Object]bool // lazily initialized
@@@ -216,13 -216,7 +216,13 @@@ func (check *Checker) collectObjects() 
                pkgImports[imp] = true
        }
  
 -      var methods []*Func // list of methods with non-blank _ names
 +      type methodInfo struct {
 +              obj  *Func      // method
 +              ptr  bool       // true if pointer receiver
 +              recv *ast.Ident // receiver type name
 +      }
 +      var methods []methodInfo // collected methods with valid receivers and non-blank _ names
 +      var fileScopes []*Scope
        for fileNo, file := range check.files {
                // The package identifier denotes the current package,
                // but there is no corresponding package object.
                        pos, end = token.Pos(f.Base()), token.Pos(f.Base()+f.Size())
                }
                fileScope := NewScope(check.pkg.scope, pos, end, check.filename(fileNo))
 +              fileScopes = append(fileScopes, fileScope)
                check.recordScope(file, fileScope)
  
                // determine file directory, necessary to resolve imports
                                        return
                                }
  
-                               // 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 d.spec.Name != nil {
                                                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
-                                       }
                                }
  
-                               obj := NewPkgName(d.spec.Pos(), pkg, name, imp)
+                               if name == "init" {
+                                       check.errorf(d.spec.Name, _InvalidInitDecl, "cannot import package as init - init must be a func")
+                                       return
+                               }
+                               // 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)
+                               }
+                               pkgName := 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)
+                                       check.recordDef(d.spec.Name, pkgName)
                                } else {
-                                       check.recordImplicit(d.spec, obj)
+                                       check.recordImplicit(d.spec, pkgName)
                                }
  
                                if path == "C" {
                                        // match cmd/compile (not prescribed by spec)
-                                       obj.used = true
+                                       pkgName.used = true
                                }
  
                                // add import to file scope
+                               check.imports = append(check.imports, pkgName)
                                if name == "." {
+                                       // dot-import
+                                       if check.dotImportMap == nil {
+                                               check.dotImportMap = make(map[dotImportKey]*PkgName)
+                                       }
                                        // merge imported scope with file scope
                                        for _, obj := range imp.scope.elems {
                                                // A package scope may contain non-exported objects,
                                                        if alt := fileScope.Insert(obj); alt != nil {
                                                                check.errorf(d.spec.Name, _DuplicateDecl, "%s redeclared in this block", obj.Name())
                                                                check.reportAltDecl(alt)
+                                                       } else {
+                                                               check.dotImportMap[dotImportKey{fileScope, obj}] = pkgName
                                                        }
                                                }
                                        }
-                                       // 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)
+                                       check.declare(fileScope, nil, pkgName, token.NoPos)
                                }
                        case constDecl:
                                // declare all constants
                                                init = d.init[i]
                                        }
  
 -                                      d := &declInfo{file: fileScope, typ: d.typ, init: init, inherited: d.inherited}
 +                                      d := &declInfo{file: fileScope, vtyp: d.typ, init: init, inherited: d.inherited}
                                        check.declarePkgObj(name, obj, d)
                                }
  
                                        // 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, typ: d.spec.Type, init: d.spec.Values[0]}
 +                                      d1 = &declInfo{file: fileScope, lhs: lhs, vtyp: d.spec.Type, init: d.spec.Values[0]}
                                }
  
                                // declare all variables
                                                if i < len(d.spec.Values) {
                                                        init = d.spec.Values[i]
                                                }
 -                                              di = &declInfo{file: fileScope, typ: d.spec.Type, init: init}
 +                                              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, typ: d.spec.Type, aliasPos: d.spec.Assign})
 +                              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.Recv == nil {
 +                              if !d.decl.IsMethod() {
                                        // regular function
 +                                      if d.decl.Recv != nil {
 +                                              check.error(d.decl.Recv, _BadRecv, "method is missing receiver")
 +                                              // treat as function
 +                                      }
 +                                      if name == "init" || (name == "main" && check.pkg.name == "main") {
 +                                              code := _InvalidInitDecl
 +                                              if name == "main" {
 +                                                      code = _InvalidMainDecl
 +                                              }
 +                                              if d.decl.Type.TParams != nil {
 +                                                      check.softErrorf(d.decl.Type.TParams, code, "func %s must have no type parameters", name)
 +                                              }
 +                                              if t := d.decl.Type; t.Params.NumFields() != 0 || t.Results != nil {
 +                                                      // TODO(rFindley) Should this be a hard error?
 +                                                      check.softErrorf(d.decl, code, "func %s must have no arguments and no return values", name)
 +                                              }
 +                                      }
                                        if name == "init" {
                                                // don't declare init functions in the package scope - they are invisible
                                                obj.parent = pkg.scope
                                                check.recordDef(d.decl.Name, obj)
                                                // init functions must have a body
                                                if d.decl.Body == nil {
 +                                                      // TODO(gri) make this error message consistent with the others above
                                                        check.softErrorf(obj, _MissingInitBody, "missing function body")
                                                }
                                        } else {
                                        }
                                } else {
                                        // method
 -                                      // (Methods with blank _ names are never found; no need to collect
 -                                      // them for later type association. They will still be type-checked
 -                                      // with all the other functions.)
 -                                      if name != "_" {
 -                                              methods = append(methods, obj)
 +
 +                                      // 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.decl.Name, obj)
                                }
        }
  
        // verify that objects in package and file scopes have different names
 -      for _, scope := range check.pkg.scope.children /* file scopes */ {
 +      for _, scope := range fileScopes {
                for _, obj := range scope.elems {
                        if alt := pkg.scope.Lookup(obj.Name()); alt != nil {
                                if pkg, ok := obj.(*PkgName); ok {
                return // nothing to do
        }
        check.methods = make(map[*TypeName][]*Func)
 -      for _, f := range methods {
 -              fdecl := check.objMap[f].fdecl
 -              if list := fdecl.Recv.List; len(list) > 0 {
 -                      // f is a method.
 -                      // Determine the receiver base type and associate f with it.
 -                      ptr, base := check.resolveBaseTypeName(list[0].Type)
 -                      if base != nil {
 -                              f.hasPtrRecv = ptr
 -                              check.methods[base] = append(check.methods[base], f)
 +      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)
 +              }
 +      }
 +}
 +
 +// unpackRecv unpacks a receiver type and returns its components: ptr indicates whether
 +// rtyp is a pointer receiver, rname is the receiver type name, and tparams are its
 +// type parameters, if any. The type parameters are only unpacked if unpackParams is
 +// set. If rname is nil, the receiver is unusable (i.e., the source has a bug which we
 +// cannot easily work around).
 +func (check *Checker) unpackRecv(rtyp ast.Expr, unpackParams bool) (ptr bool, rname *ast.Ident, tparams []*ast.Ident) {
 +L: // unpack receiver type
 +      // This accepts invalid receivers such as ***T and does not
 +      // work for other invalid receivers, but we don't care. The
 +      // validity of receiver expressions is checked elsewhere.
 +      for {
 +              switch t := rtyp.(type) {
 +              case *ast.ParenExpr:
 +                      rtyp = t.X
 +              case *ast.StarExpr:
 +                      ptr = true
 +                      rtyp = t.X
 +              default:
 +                      break L
 +              }
 +      }
 +
 +      // unpack type parameters, if any
 +      switch ptyp := rtyp.(type) {
 +      case *ast.IndexExpr:
 +              panic("unimplemented")
 +      case *ast.CallExpr:
 +              rtyp = ptyp.Fun
 +              if unpackParams {
 +                      for _, arg := range ptyp.Args {
 +                              var par *ast.Ident
 +                              switch arg := arg.(type) {
 +                              case *ast.Ident:
 +                                      par = arg
 +                              case *ast.BadExpr:
 +                                      // ignore - error already reported by parser
 +                              case nil:
 +                                      check.invalidAST(ptyp, "parameterized receiver contains nil parameters")
 +                              default:
 +                                      check.errorf(arg, _Todo, "receiver type parameter %s must be an identifier", arg)
 +                              }
 +                              if par == nil {
 +                                      par = &ast.Ident{NamePos: arg.Pos(), Name: "_"}
 +                              }
 +                              tparams = append(tparams, par)
                        }
                }
        }
 +
 +      // unpack receiver name
 +      if name, _ := rtyp.(*ast.Ident); name != nil {
 +              rname = name
 +      }
 +
 +      return
  }
  
  // resolveBaseTypeName returns the non-alias base type name for typ, and whether
  // 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(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
        // parentheses we're done. If we encounter more than one pointer type
        // we're done.
 +      ptr = seenPtr
        var seen map[*TypeName]bool
 +      var typ ast.Expr = name
        for {
                typ = unparen(typ)
  
  
                // we're done if tdecl defined tname as a new type
                // (rather than an alias)
 -              tdecl := check.objMap[tname] // must exist for objects in package scope
 -              if !tdecl.aliasPos.IsValid() {
 +              tdecl := check.objMap[tname].tdecl // must exist for objects in package scope
 +              if !tdecl.Assign.IsValid() {
                        return ptr, tname
                }
  
                // otherwise, continue resolving
 -              typ = tdecl.typ
 +              typ = tdecl.Type
                if seen == nil {
                        seen = make(map[*TypeName]bool)
                }
@@@ -603,7 -520,7 +608,7 @@@ func (check *Checker) packageObjects() 
        // add new methods to already type-checked types (from a prior Checker.Files call)
        for _, obj := range objList {
                if obj, _ := obj.(*TypeName); obj != nil && obj.typ != nil {
 -                      check.addMethodDecls(obj)
 +                      check.collectMethods(obj)
                }
        }
  
        // phase 1
        for _, obj := range objList {
                // If we have a type alias, collect it for the 2nd phase.
 -              if tname, _ := obj.(*TypeName); tname != nil && check.objMap[tname].aliasPos.IsValid() {
 +              if tname, _ := obj.(*TypeName); tname != nil && check.objMap[tname].tdecl.Assign.IsValid() {
                        aliasList = append(aliasList, tname)
                        continue
                }
@@@ -654,39 -571,30 +659,30 @@@ func (check *Checker) unusedImports() 
        // any of its exported identifiers. To import a package solely for its side-effects
        // (initialization), use the blank identifier as explicit package name."
  
-       // check use of regular imported packages
-       for _, scope := range check.pkg.scope.children /* file scopes */ {
-               for _, obj := range scope.elems {
-                       if obj, ok := obj.(*PkgName); ok {
-                               // Unused "blank imports" are automatically ignored
-                               // since _ identifiers are not entered into scopes.
-                               if !obj.used {
-                                       path := obj.imported.path
-                                       base := pkgName(path)
-                                       if obj.name == base {
-                                               check.softErrorf(obj, _UnusedImport, "%q imported but not used", path)
-                                       } else {
-                                               check.softErrorf(obj, _UnusedImport, "%q imported but not used as %s", path, obj.name)
-                                       }
-                               }
-                       }
-               }
-       }
-       // check use of dot-imported packages
-       for _, unusedDotImports := range check.unusedDotImports {
-               for pkg, pos := range unusedDotImports {
-                       check.softErrorf(pos, _UnusedImport, "%q imported but not used", pkg.path)
+       for _, obj := range check.imports {
+               if !obj.used && obj.name != "_" {
+                       check.errorUnusedPkg(obj)
                }
        }
  }
  
- // pkgName returns the package name (last element) of an import path.
- func pkgName(path string) string {
-       if i := strings.LastIndex(path, "/"); i >= 0 {
-               path = path[i+1:]
+ func (check *Checker) errorUnusedPkg(obj *PkgName) {
+       // If the package was imported with a name other than the final
+       // import path element, show it explicitly in the error message.
+       // Note that this handles both renamed imports and imports of
+       // packages containing unconventional package declarations.
+       // Note that this uses / always, even on Windows, because Go import
+       // paths always use forward slashes.
+       path := obj.imported.path
+       elem := path
+       if i := strings.LastIndex(elem, "/"); i >= 0 {
+               elem = elem[i+1:]
+       }
+       if obj.name == "" || obj.name == "." || obj.name == elem {
+               check.softErrorf(obj, _UnusedImport, "%q imported but not used", path)
+       } else {
+               check.softErrorf(obj, _UnusedImport, "%q imported but not used as %s", path, obj.name)
        }
-       return path
  }
  
  // dir makes a good-faith attempt to return the directory
index 3c273b07664be47bee134e2882bf40964cbfbb5c,6ee28f13b4291fb19c161981f1772b13ff1093a5..370752891407beef0f7d828a128144617c4796c9
@@@ -25,11 -25,11 +25,11 @@@ func append1() 
        _ = append(s, b)
        _ = append(s, x /* ERROR cannot use x */ )
        _ = append(s, s /* ERROR cannot use s */ )
 -      _ = append(s... /* ERROR can only use ... with matching parameter */ )
 -      _ = append(s, b, s... /* ERROR can only use ... with matching parameter */ )
 +      _ = 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, s... /* ERROR can only use ... with matching parameter */ )
 +      _ = append(s, 1, 2 /* ERROR too many arguments */, s...)
        _ = append([]interface{}(nil), 1, 2, "foo", x, 3.1425, false)
  
        type S []byte
@@@ -283,7 -283,7 +283,7 @@@ func delete1() 
        delete() // ERROR not enough arguments
        delete(1) // ERROR not enough arguments
        delete(1, 2, 3) // ERROR too many arguments
-       delete(m, 0 /* ERROR not assignable */)
+       delete(m, 0 /* ERROR cannot use */)
        delete(m, s)
        _ = delete /* ERROR used as value */ (m, s)
  
@@@ -514,7 -514,7 +514,7 @@@ func panic1() 
        panic("foo")
        panic(false)
        panic(1<<10)
-       panic(1 /* ERROR overflows */ <<1000)
+       panic(1 << /* ERROR constant shift overflow */ 1000)
        _ = panic /* ERROR used as value */ (0)
  
        var s []byte
@@@ -538,7 -538,7 +538,7 @@@ func print1() 
        print(2.718281828)
        print(false)
        print(1<<10)
-       print(1 /* ERROR overflows */ <<1000)
+       print(1 << /* ERROR constant shift overflow */ 1000)
        println(nil /* ERROR untyped nil */ )
  
        var s []int
@@@ -564,7 -564,7 +564,7 @@@ func println1() 
        println(2.718281828)
        println(false)
        println(1<<10)
-       println(1 /* ERROR overflows */ <<1000)
+       println(1 << /* ERROR constant shift overflow */ 1000)
        println(nil /* ERROR untyped nil */ )
  
        var s []int
@@@ -695,7 -695,7 +695,7 @@@ func Alignof1() 
        _ = unsafe.Alignof(42)
        _ = unsafe.Alignof(new(struct{}))
        _ = unsafe.Alignof(1<<10)
-       _ = unsafe.Alignof(1 /* ERROR overflows */ <<1000)
+       _ = unsafe.Alignof(1 << /* ERROR constant shift overflow */ 1000)
        _ = unsafe.Alignof(nil /* ERROR "untyped nil */ )
        unsafe /* ERROR not used */ .Alignof(x)
  
@@@ -783,7 -783,7 +783,7 @@@ func Sizeof1() 
        _ = unsafe.Sizeof(42)
        _ = unsafe.Sizeof(new(complex128))
        _ = unsafe.Sizeof(1<<10)
-       _ = unsafe.Sizeof(1 /* ERROR overflows */ <<1000)
+       _ = unsafe.Sizeof(1 << /* ERROR constant shift overflow */ 1000)
        _ = unsafe.Sizeof(nil /* ERROR untyped nil */ )
        unsafe /* ERROR not used */ .Sizeof(x)
  
index 297e34be421ccc26a9d31c174142da0cf8ea0cad,de8f936a617ae106e57dd60bf37eabf6ab0178de..2602d7dacf4daa450a67c235a07041b701d78ad9
@@@ -86,11 -86,11 +86,11 @@@ func assignments1() 
  
        g := func(int, bool){}
        var m map[int]int
 -      g(m[0]) /* ERROR "too few arguments" */
 +      g(m[0]) /* ERROR "not enough arguments" */
  
        // assignments to _
        _ = nil /* ERROR "use of untyped nil" */
-       _ = 1 /* ERROR overflow */ <<1000
+       _ = 1  << /* ERROR constant shift overflow */ 1000
        (_) = 0
  }
  
@@@ -886,7 -886,7 +886,7 @@@ func rangeloops1() 
                ee = e
                _ = ee
        }
 -      for _ = range sc /* ERROR "cannot range over send-only channel" */ {}
 +      for _ = range sc /* ERROR "cannot range over" */ {}
        for _ = range rc {}
  
        // constant strings
diff --combined src/go/types/type.go
index 0fcefefb7348b0018c0e7be05281b2b1f1e7817f,66e194e967920ecb66ec4bc0a16f1c7ef2711d57..21892c9270d0dab06bf7652e0224baa7692bac82
@@@ -4,18 -4,10 +4,17 @@@
  
  package types
  
-       "sort"
 +import (
 +      "fmt"
 +      "go/token"
 +)
 +
  // A Type represents a type of Go.
  // All types implement the Type interface.
  type Type interface {
 -      // Underlying returns the underlying type of a type.
 +      // Underlying returns the underlying type of a type
 +      // w/o following forwarding chains. Only used by
 +      // client packages (here for backward-compatibility).
        Underlying() Type
  
        // String returns a string representation of a type.
@@@ -104,7 -96,7 +103,7 @@@ type Array struct 
  
  // NewArray returns a new array type for the given element type and length.
  // A negative length indicates an unknown length.
 -func NewArray(elem Type, len int64) *Array { return &Array{len, elem} }
 +func NewArray(elem Type, len int64) *Array { return &Array{len: len, elem: elem} }
  
  // Len returns the length of array a.
  // A negative result indicates an unknown length.
@@@ -119,7 -111,7 +118,7 @@@ type Slice struct 
  }
  
  // NewSlice returns a new slice type for the given element type.
 -func NewSlice(elem Type) *Slice { return &Slice{elem} }
 +func NewSlice(elem Type) *Slice { return &Slice{elem: elem} }
  
  // Elem returns the element type of slice s.
  func (s *Slice) Elem() Type { return s.elem }
@@@ -182,10 -174,8 +181,10 @@@ type Tuple struct 
  // NewTuple returns a new tuple for the given variables.
  func NewTuple(x ...*Var) *Tuple {
        if len(x) > 0 {
 -              return &Tuple{x}
 +              return &Tuple{vars: x}
        }
 +      // TODO(gri) Don't represent empty tuples with a (*Tuple)(nil) pointer;
 +      //           it's too subtle and causes problems.
        return nil
  }
  
@@@ -207,13 -197,11 +206,13 @@@ type Signature struct 
        // 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.
 -      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
 -      results  *Tuple // (outgoing) results from left to right; or nil
 -      variadic bool   // true if the last parameter's type is of the form ...T (or string, for append built-in only)
 +      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
 +      results  *Tuple      // (outgoing) results from left to right; or nil
 +      variadic bool        // true if the last parameter's type is of the form ...T (or string, for append built-in only)
  }
  
  // NewSignature returns a new function type for the given receiver, parameters,
@@@ -230,7 -218,7 +229,7 @@@ func NewSignature(recv *Var, params, re
                        panic("types.NewSignature: variadic parameter must be of unnamed slice type")
                }
        }
 -      return &Signature{nil, recv, params, results, variadic}
 +      return &Signature{recv: recv, params: params, results: results, variadic: variadic}
  }
  
  // Recv returns the receiver of signature s (if a method), or nil if a
  // contain methods whose receiver type is a different interface.
  func (s *Signature) Recv() *Var { return s.recv }
  
 +// TParams returns the type parameters of signature s, or nil.
 +func (s *Signature) TParams() []*TypeName { return s.tparams }
 +
 +// SetTParams sets the type parameters of signature s.
 +func (s *Signature) SetTParams(tparams []*TypeName) { s.tparams = tparams }
 +
  // Params returns the parameters of signature s, or nil.
  func (s *Signature) Params() *Tuple { return s.params }
  
@@@ -256,88 -238,12 +255,88 @@@ func (s *Signature) Results() *Tuple { 
  // Variadic reports whether the signature s is variadic.
  func (s *Signature) Variadic() bool { return s.variadic }
  
 +// A Sum represents a set of possible types.
 +// Sums are currently used to represent type lists of interfaces
 +// and thus the underlying types of type parameters; they are not
 +// first class types of Go.
 +type Sum struct {
 +      types []Type // types are unique
 +}
 +
 +// NewSum returns a new Sum type consisting of the provided
 +// types if there are more than one. If there is exactly one
 +// type, it returns that type. If the list of types is empty
 +// the result is nil.
 +func NewSum(types []Type) Type {
 +      if len(types) == 0 {
 +              return nil
 +      }
 +
 +      // What should happen if types contains a sum type?
 +      // Do we flatten the types list? For now we check
 +      // and panic. This should not be possible for the
 +      // current use case of type lists.
 +      // TODO(gri) Come up with the rules for sum types.
 +      for _, t := range types {
 +              if _, ok := t.(*Sum); ok {
 +                      panic("sum type contains sum type - unimplemented")
 +              }
 +      }
 +
 +      if len(types) == 1 {
 +              return types[0]
 +      }
 +      return &Sum{types: types}
 +}
 +
 +// is reports whether all types in t satisfy pred.
 +func (s *Sum) is(pred func(Type) bool) bool {
 +      if s == nil {
 +              return false
 +      }
 +      for _, t := range s.types {
 +              if !pred(t) {
 +                      return false
 +              }
 +      }
 +      return true
 +}
 +
  // An Interface represents an interface type.
  type Interface struct {
        methods   []*Func // ordered list of explicitly declared methods
 +      types     Type    // (possibly a Sum) type declared with a type list (TODO(gri) need better field name)
        embeddeds []Type  // ordered list of explicitly embedded types
  
        allMethods []*Func // ordered list of methods declared with or embedded in this interface (TODO(gri): replace with mset)
 +      allTypes   Type    // intersection of all embedded and locally declared types  (TODO(gri) need better field name)
 +
 +      obj Object // type declaration defining this interface; or nil (for better error messages)
 +}
 +
 +// unpack unpacks a type into a list of types.
 +// TODO(gri) Try to eliminate the need for this function.
 +func unpackType(typ Type) []Type {
 +      if typ == nil {
 +              return nil
 +      }
 +      if sum := asSum(typ); sum != nil {
 +              return sum.types
 +      }
 +      return []Type{typ}
 +}
 +
 +// is reports whether interface t represents types that all satisfy pred.
 +func (t *Interface) is(pred func(Type) bool) bool {
 +      if t.allTypes == nil {
 +              return false // we must have at least one type! (was bug)
 +      }
 +      for _, t := range unpackType(t.allTypes) {
 +              if !pred(t) {
 +                      return false
 +              }
 +      }
 +      return true
  }
  
  // emptyInterface represents the empty (completed) interface
@@@ -393,8 -299,8 +392,8 @@@ func NewInterfaceType(methods []*Func, 
        }
  
        // sort for API stability
-       sort.Sort(byUniqueMethodName(methods))
-       sort.Stable(byUniqueTypeName(embeddeds))
+       sortMethods(methods)
+       sortTypes(embeddeds)
  
        typ.methods = methods
        typ.embeddeds = embeddeds
@@@ -436,101 -342,8 +435,101 @@@ func (t *Interface) assertCompleteness(
  func (t *Interface) Method(i int) *Func { t.assertCompleteness(); return t.allMethods[i] }
  
  // Empty reports whether t is the empty interface.
 -// The interface must have been completed.
 -func (t *Interface) Empty() bool { t.assertCompleteness(); return len(t.allMethods) == 0 }
 +func (t *Interface) Empty() bool {
 +      if t.allMethods != nil {
 +              // interface is complete - quick test
 +              // A non-nil allTypes may still be empty and represents the bottom type.
 +              return len(t.allMethods) == 0 && t.allTypes == nil
 +      }
 +      return !t.iterate(func(t *Interface) bool {
 +              return len(t.methods) > 0 || t.types != nil
 +      }, nil)
 +}
 +
 +// HasTypeList reports whether interface t has a type list, possibly from an embedded type.
 +func (t *Interface) HasTypeList() bool {
 +      if t.allMethods != nil {
 +              // interface is complete - quick test
 +              return t.allTypes != nil
 +      }
 +
 +      return t.iterate(func(t *Interface) bool {
 +              return t.types != nil
 +      }, nil)
 +}
 +
 +// IsComparable reports whether interface t is or embeds the predeclared interface "comparable".
 +func (t *Interface) IsComparable() bool {
 +      if t.allMethods != nil {
 +              // interface is complete - quick test
 +              _, m := lookupMethod(t.allMethods, nil, "==")
 +              return m != nil
 +      }
 +
 +      return t.iterate(func(t *Interface) bool {
 +              _, m := lookupMethod(t.methods, nil, "==")
 +              return m != nil
 +      }, nil)
 +}
 +
 +// IsConstraint reports t.HasTypeList() || t.IsComparable().
 +func (t *Interface) IsConstraint() bool {
 +      if t.allMethods != nil {
 +              // interface is complete - quick test
 +              if t.allTypes != nil {
 +                      return true
 +              }
 +              _, m := lookupMethod(t.allMethods, nil, "==")
 +              return m != nil
 +      }
 +
 +      return t.iterate(func(t *Interface) bool {
 +              if t.types != nil {
 +                      return true
 +              }
 +              _, m := lookupMethod(t.methods, nil, "==")
 +              return m != nil
 +      }, nil)
 +}
 +
 +// iterate calls f with t and then with any embedded interface of t, recursively, until f returns true.
 +// iterate reports whether any call to f returned true.
 +func (t *Interface) iterate(f func(*Interface) bool, seen map[*Interface]bool) bool {
 +      if f(t) {
 +              return true
 +      }
 +      for _, e := range t.embeddeds {
 +              // e should be an interface but be careful (it may be invalid)
 +              if e := asInterface(e); e != nil {
 +                      // Cyclic interfaces such as "type E interface { E }" are not permitted
 +                      // but they are still constructed and we need to detect such cycles.
 +                      if seen[e] {
 +                              continue
 +                      }
 +                      if seen == nil {
 +                              seen = make(map[*Interface]bool)
 +                      }
 +                      seen[e] = true
 +                      if e.iterate(f, seen) {
 +                              return true
 +                      }
 +              }
 +      }
 +      return false
 +}
 +
 +// isSatisfiedBy reports whether interface t's type list is satisfied by the type typ.
 +// If the the type list is empty (absent), typ trivially satisfies the interface.
 +// TODO(gri) This is not a great name. Eventually, we should have a more comprehensive
 +//           "implements" predicate.
 +func (t *Interface) isSatisfiedBy(typ Type) bool {
 +      t.Complete()
 +      if t.allTypes == nil {
 +              return true
 +      }
 +      types := unpackType(t.allTypes)
 +      return includes(types, typ) || includes(types, under(typ))
 +}
  
  // Complete computes the interface's method set. It must be called by users of
  // NewInterfaceType and NewInterface after the interface's embedded types are
@@@ -564,22 -377,12 +563,22 @@@ func (t *Interface) Complete() *Interfa
                addMethod(m, true)
        }
  
 +      allTypes := t.types
 +
        for _, typ := range t.embeddeds {
 -              typ := typ.Underlying().(*Interface)
 -              typ.Complete()
 -              for _, m := range typ.allMethods {
 +              utyp := under(typ)
 +              etyp := asInterface(utyp)
 +              if etyp == nil {
 +                      if utyp != Typ[Invalid] {
 +                              panic(fmt.Sprintf("%s is not an interface", typ))
 +                      }
 +                      continue
 +              }
 +              etyp.Complete()
 +              for _, m := range etyp.allMethods {
                        addMethod(m, false)
                }
 +              allTypes = intersect(allTypes, etyp.allTypes)
        }
  
        for i := 0; i < len(todo); i += 2 {
        }
  
        if methods != nil {
-               sort.Sort(byUniqueMethodName(methods))
+               sortMethods(methods)
                t.allMethods = methods
        }
 +      t.allTypes = allTypes
  
        return t
  }
@@@ -606,7 -408,7 +605,7 @@@ type Map struct 
  
  // NewMap returns a new map for the given key and element types.
  func NewMap(key, elem Type) *Map {
 -      return &Map{key, elem}
 +      return &Map{key: key, elem: elem}
  }
  
  // Key returns the key type of map m.
@@@ -633,7 -435,7 +632,7 @@@ const 
  
  // NewChan returns a new channel type for the given direction and element type.
  func NewChan(dir ChanDir, elem Type) *Chan {
 -      return &Chan{dir, elem}
 +      return &Chan{dir: dir, elem: elem}
  }
  
  // Dir returns the direction of channel c.
@@@ -642,16 -444,13 +641,16 @@@ func (c *Chan) Dir() ChanDir { return c
  // Elem returns the element type of channel c.
  func (c *Chan) Elem() Type { return c.elem }
  
 -// A Named represents a named type.
 +// A Named represents a named (defined) type.
  type Named struct {
 -      info       typeInfo  // for cycle detection
 -      obj        *TypeName // corresponding declared object
 -      orig       Type      // type (on RHS of declaration) this *Named type is derived of (for cycle reporting)
 -      underlying Type      // possibly a *Named during setup; never a *Named once set up completely
 -      methods    []*Func   // methods declared for this type (not the method set of this type); signatures are type-checked lazily
 +      check      *Checker    // for Named.under implementation
 +      info       typeInfo    // for cycle detection
 +      obj        *TypeName   // corresponding declared object
 +      orig       Type        // type (on RHS of declaration) this *Named type is derived of (for cycle reporting)
 +      underlying Type        // possibly a *Named during setup; never a *Named once set up completely
 +      tparams    []*TypeName // type parameters, or nil
 +      targs      []Type      // type arguments (after instantiation), or nil
 +      methods    []*Func     // methods declared for this type (not the method set of this type); signatures are type-checked lazily
  }
  
  // NewNamed returns a new named type for the given type name, underlying type, and associated methods.
@@@ -668,30 -467,9 +667,30 @@@ func NewNamed(obj *TypeName, underlyin
        return typ
  }
  
 +func (check *Checker) NewNamed(obj *TypeName, underlying Type, methods []*Func) *Named {
 +      typ := &Named{check: check, obj: obj, orig: underlying, underlying: underlying, methods: methods}
 +      if obj.typ == nil {
 +              obj.typ = typ
 +      }
 +      return typ
 +}
 +
  // Obj returns the type name for the named type t.
  func (t *Named) Obj() *TypeName { return t.obj }
  
 +// TODO(gri) Come up with a better representation and API to distinguish
 +//           between parameterized instantiated and non-instantiated types.
 +
 +// TParams returns the type parameters of the named type t, or nil.
 +// The result is non-nil for an (originally) parameterized type even if it is instantiated.
 +func (t *Named) TParams() []*TypeName { return t.tparams }
 +
 +// TArgs returns the type arguments after instantiation of the named type t, or nil if not instantiated.
 +func (t *Named) TArgs() []Type { return t.targs }
 +
 +// SetTArgs sets the type arguments of Named.
 +func (t *Named) SetTArgs(args []Type) { t.targs = args }
 +
  // NumMethods returns the number of explicit methods whose receiver is named type t.
  func (t *Named) NumMethods() int { return len(t.methods) }
  
@@@ -716,261 -494,28 +715,261 @@@ func (t *Named) AddMethod(m *Func) 
        }
  }
  
 -// Implementations for Type methods.
 +// A TypeParam represents a type parameter type.
 +type TypeParam struct {
 +      check *Checker  // for lazy type bound completion
 +      id    uint64    // unique id
 +      obj   *TypeName // corresponding type name
 +      index int       // parameter index
 +      bound Type      // *Named or *Interface; underlying type is always *Interface
 +}
  
 -func (b *Basic) Underlying() Type     { return b }
 -func (a *Array) Underlying() Type     { return a }
 -func (s *Slice) Underlying() Type     { return s }
 -func (s *Struct) Underlying() Type    { return s }
 -func (p *Pointer) Underlying() Type   { return p }
 +// NewTypeParam returns a new TypeParam.
 +func (check *Checker) NewTypeParam(obj *TypeName, index int, bound Type) *TypeParam {
 +      assert(bound != nil)
 +      typ := &TypeParam{check: check, id: check.nextId, obj: obj, index: index, bound: bound}
 +      check.nextId++
 +      if obj.typ == nil {
 +              obj.typ = typ
 +      }
 +      return typ
 +}
 +
 +func (t *TypeParam) Bound() *Interface {
 +      iface := asInterface(t.bound)
 +      // use the type bound position if we have one
 +      pos := token.NoPos
 +      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
 +}
 +
 +// optype returns a type's operational type. Except for
 +// type parameters, the operational type is the same
 +// as the underlying type (as returned by under). For
 +// Type parameters, the operational type is determined
 +// by the corresponding type bound's type list. The
 +// result may be the bottom or top type, but it is never
 +// the incoming type parameter.
 +func optype(typ Type) Type {
 +      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 asTypeParam converter function. This can happen
 +              // for a type parameter list of the form:
 +              // (type T interface { type T }).
 +              // See also issue #39680.
 +              if u := t.Bound().allTypes; u != nil && u != typ {
 +                      // u != typ and u is a type parameter => under(u) != typ, so this is ok
 +                      return under(u)
 +              }
 +              return theTop
 +      }
 +      return under(typ)
 +}
 +
 +// An instance represents an instantiated generic type syntactically
 +// (without expanding the instantiation). Type instances appear only
 +// during type-checking and are replaced by their fully instantiated
 +// (expanded) types before the end of type-checking.
 +type instance struct {
 +      check   *Checker    // for lazy instantiation
 +      pos     token.Pos   // position of type instantiation; for error reporting only
 +      base    *Named      // parameterized type to be instantiated
 +      targs   []Type      // type arguments
 +      poslist []token.Pos // position of each targ; for error reporting only
 +      value   Type        // base(targs...) after instantiation or Typ[Invalid]; nil if not yet set
 +}
 +
 +// expand returns the instantiated (= expanded) type of t.
 +// The result is either an instantiated *Named type, or
 +// Typ[Invalid] if there was an error.
 +func (t *instance) expand() Type {
 +      v := t.value
 +      if v == nil {
 +              v = t.check.instantiate(t.pos, t.base, t.targs, t.poslist)
 +              if v == nil {
 +                      v = Typ[Invalid]
 +              }
 +              t.value = v
 +      }
 +      // After instantiation we must have an invalid or a *Named type.
 +      if debug && v != Typ[Invalid] {
 +              _ = v.(*Named)
 +      }
 +      return v
 +}
 +
 +// expand expands a type instance into its instantiated
 +// type and leaves all other types alone. expand does
 +// not recurse.
 +func expand(typ Type) Type {
 +      if t, _ := typ.(*instance); t != nil {
 +              return t.expand()
 +      }
 +      return typ
 +}
 +
 +// expandf is set to expand.
 +// Call expandf when calling expand causes compile-time cycle error.
 +var expandf func(Type) Type
 +
 +func init() { expandf = expand }
 +
 +// bottom represents the bottom of the type lattice.
 +// It is the underlying type of a type parameter that
 +// cannot be satisfied by any type, usually because
 +// the intersection of type constraints left nothing).
 +type bottom struct{}
 +
 +// theBottom is the singleton bottom type.
 +var theBottom = &bottom{}
 +
 +// top represents the top of the type lattice.
 +// It is the underlying type of a type parameter that
 +// can be satisfied by any type (ignoring methods),
 +// usually because the type constraint has no type
 +// list.
 +type top struct{}
 +
 +// theTop is the singleton top type.
 +var theTop = &top{}
 +
 +// Type-specific implementations of Underlying.
 +func (t *Basic) Underlying() Type     { return t }
 +func (t *Array) Underlying() Type     { return t }
 +func (t *Slice) Underlying() Type     { return t }
 +func (t *Struct) Underlying() Type    { return t }
 +func (t *Pointer) Underlying() Type   { return t }
  func (t *Tuple) Underlying() Type     { return t }
 -func (s *Signature) Underlying() Type { return s }
 +func (t *Signature) Underlying() Type { return t }
 +func (t *Sum) Underlying() Type       { return t }
  func (t *Interface) Underlying() Type { return t }
 -func (m *Map) Underlying() Type       { return m }
 -func (c *Chan) Underlying() Type      { return c }
 +func (t *Map) Underlying() Type       { return t }
 +func (t *Chan) Underlying() Type      { return t }
  func (t *Named) Underlying() Type     { return t.underlying }
 -
 -func (b *Basic) String() string     { return TypeString(b, nil) }
 -func (a *Array) String() string     { return TypeString(a, nil) }
 -func (s *Slice) String() string     { return TypeString(s, nil) }
 -func (s *Struct) String() string    { return TypeString(s, nil) }
 -func (p *Pointer) String() string   { return TypeString(p, nil) }
 +func (t *TypeParam) Underlying() Type { return t }
 +func (t *instance) Underlying() Type  { return t }
 +func (t *bottom) Underlying() Type    { return t }
 +func (t *top) Underlying() Type       { return t }
 +
 +// Type-specific implementations of String.
 +func (t *Basic) String() string     { return TypeString(t, nil) }
 +func (t *Array) String() string     { return TypeString(t, nil) }
 +func (t *Slice) String() string     { return TypeString(t, nil) }
 +func (t *Struct) String() string    { return TypeString(t, nil) }
 +func (t *Pointer) String() string   { return TypeString(t, nil) }
  func (t *Tuple) String() string     { return TypeString(t, nil) }
 -func (s *Signature) String() string { return TypeString(s, nil) }
 +func (t *Signature) String() string { return TypeString(t, nil) }
 +func (t *Sum) String() string       { return TypeString(t, nil) }
  func (t *Interface) String() string { return TypeString(t, nil) }
 -func (m *Map) String() string       { return TypeString(m, nil) }
 -func (c *Chan) String() string      { return TypeString(c, nil) }
 +func (t *Map) String() string       { return TypeString(t, nil) }
 +func (t *Chan) String() string      { return TypeString(t, nil) }
  func (t *Named) String() string     { return TypeString(t, nil) }
 +func (t *TypeParam) String() string { return TypeString(t, nil) }
 +func (t *instance) String() string  { return TypeString(t, nil) }
 +func (t *bottom) String() string    { return TypeString(t, nil) }
 +func (t *top) String() string       { return TypeString(t, nil) }
 +
 +// under returns the true expanded underlying type.
 +// If it doesn't exist, the result is Typ[Invalid].
 +// under must only be called when a type is known
 +// to be fully set up.
 +func under(t Type) Type {
 +      // TODO(gri) is this correct for *Sum?
 +      if n := asNamed(t); n != nil {
 +              return n.under()
 +      }
 +      return t
 +}
 +
 +// Converters
 +//
 +// A converter must only be called when a type is
 +// known to be fully set up. A converter returns
 +// a type's operational type (see comment for optype)
 +// or nil if the type argument is not of the
 +// respective type.
 +
 +func asBasic(t Type) *Basic {
 +      op, _ := optype(t).(*Basic)
 +      return op
 +}
 +
 +func asArray(t Type) *Array {
 +      op, _ := optype(t).(*Array)
 +      return op
 +}
 +
 +func asSlice(t Type) *Slice {
 +      op, _ := optype(t).(*Slice)
 +      return op
 +}
 +
 +// TODO (rFindley) delete this on the dev.typeparams branch. This is only
 +// exported in the prototype for legacy compatibility.
 +func AsStruct(t Type) *Struct {
 +      return asStruct(t)
 +}
 +
 +func asStruct(t Type) *Struct {
 +      op, _ := optype(t).(*Struct)
 +      return op
 +}
 +
 +// TODO(rFindley) delete this on the dev.typeparams branch (see ToStruct).
 +func AsPointer(t Type) *Pointer {
 +      return asPointer(t)
 +}
 +
 +func asPointer(t Type) *Pointer {
 +      op, _ := optype(t).(*Pointer)
 +      return op
 +}
 +
 +func asTuple(t Type) *Tuple {
 +      op, _ := optype(t).(*Tuple)
 +      return op
 +}
 +
 +func asSignature(t Type) *Signature {
 +      op, _ := optype(t).(*Signature)
 +      return op
 +}
 +
 +func asSum(t Type) *Sum {
 +      op, _ := optype(t).(*Sum)
 +      return op
 +}
 +
 +func asInterface(t Type) *Interface {
 +      op, _ := optype(t).(*Interface)
 +      return op
 +}
 +
 +func asMap(t Type) *Map {
 +      op, _ := optype(t).(*Map)
 +      return op
 +}
 +
 +func asChan(t Type) *Chan {
 +      op, _ := optype(t).(*Chan)
 +      return op
 +}
 +
 +// If the argument to asNamed and asTypeParam is of the respective types
 +// (possibly after expanding an instance type), these methods return that type.
 +// Otherwise the result is nil.
 +
 +func asNamed(t Type) *Named {
 +      e, _ := expand(t).(*Named)
 +      return e
 +}
 +
 +func asTypeParam(t Type) *TypeParam {
 +      u, _ := under(t).(*TypeParam)
 +      return u
 +}
diff --combined src/go/types/typexpr.go
index bca0a6664f3ca9c012f11af8c223a933387bc111,b9249494fa16d0159d65f7e1c8213d8c3e5ae8a7..503f9c71aca63501fc2798e5219aa4d2a6b78eec
@@@ -7,13 -7,11 +7,13 @@@
  package types
  
  import (
 +      "fmt"
        "go/ast"
        "go/constant"
        "go/token"
        "sort"
        "strconv"
 +      "strings"
  )
  
  // ident type-checks identifier e and initializes x with the value or type of e.
@@@ -53,12 -51,12 +53,12 @@@ func (check *Checker) ident(x *operand
        }
        assert(typ != nil)
  
-       // The object may be dot-imported: If so, remove its package from
-       // the map of unused dot imports for the respective file scope.
+       // The object may have been dot-imported.
+       // If so, mark the respective package as used.
        // (This code is only needed for dot-imports. Without them,
        // we only have to mark variables, see *Var case below).
-       if pkg := obj.Pkg(); pkg != check.pkg && pkg != nil {
-               delete(check.unusedDotImports[scope], pkg)
+       if pkgName := check.dotImportMap[dotImportKey{scope, obj}]; pkgName != nil {
+               pkgName.used = true
        }
  
        switch obj := obj.(type) {
  }
  
  // typ type-checks the type expression e and returns its type, or Typ[Invalid].
 +// The type must not be an (uninstantiated) generic type.
  func (check *Checker) typ(e ast.Expr) Type {
        return check.definedType(e, nil)
  }
  
 +// varType type-checks the type expression e and returns its type, or Typ[Invalid].
 +// The type must not be an (uninstantiated) generic type and it must be ordinary
 +// (see ordinaryType).
 +func (check *Checker) varType(e ast.Expr) Type {
 +      typ := check.definedType(e, nil)
 +      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 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.Pos(), t) // TODO(gri) is this the correct position?
 +                      if t.allTypes != nil {
 +                              check.softErrorf(pos, _Todo, "interface contains type constraints (%s)", t.allTypes)
 +                              return
 +                      }
 +                      if t.IsComparable() {
 +                              check.softErrorf(pos, _Todo, "interface is (or embeds) comparable")
 +                      }
 +              }
 +      })
 +}
 +
 +// anyType type-checks the type expression e and returns its type, or Typ[Invalid].
 +// The type may be generic or instantiated.
 +func (check *Checker) anyType(e ast.Expr) Type {
 +      typ := check.typInternal(e, nil)
 +      assert(isTyped(typ))
 +      check.recordTypeAndValue(e, typexpr, typ, nil)
 +      return typ
 +}
 +
  // definedType is like typ but also accepts a type name def.
  // If def != nil, e is the type specification for the defined type def, declared
  // in a type declaration, and def.underlying will be set to the type of e before
  // any components of e are type-checked.
  //
 -func (check *Checker) definedType(e ast.Expr, def *Named) (T Type) {
 -      if trace {
 -              check.trace(e.Pos(), "%s", e)
 -              check.indent++
 -              defer func() {
 -                      check.indent--
 -                      check.trace(e.Pos(), "=> %s", T)
 -              }()
 +func (check *Checker) definedType(e ast.Expr, def *Named) Type {
 +      typ := check.typInternal(e, def)
 +      assert(isTyped(typ))
 +      if isGeneric(typ) {
 +              check.errorf(e, _Todo, "cannot use generic type %s without instantiation", typ)
 +              typ = Typ[Invalid]
        }
 +      check.recordTypeAndValue(e, typexpr, typ, nil)
 +      return typ
 +}
  
 -      T = check.typInternal(e, def)
 -      assert(isTyped(T))
 -      check.recordTypeAndValue(e, typexpr, T, nil)
 +// genericType is like typ but the type must be an (uninstantiated) generic type.
 +func (check *Checker) genericType(e ast.Expr, reportErr bool) Type {
 +      typ := check.typInternal(e, nil)
 +      assert(isTyped(typ))
 +      if typ != Typ[Invalid] && !isGeneric(typ) {
 +              if reportErr {
 +                      check.errorf(e, _Todo, "%s is not a generic type", typ)
 +              }
 +              typ = Typ[Invalid]
 +      }
 +      // TODO(gri) what is the correct call below?
 +      check.recordTypeAndValue(e, typexpr, typ, nil)
 +      return typ
 +}
  
 -      return
 +// isubst returns an x with identifiers substituted per the substitution map smap.
 +// isubst only handles the case of (valid) method receiver type expressions correctly.
 +func isubst(x ast.Expr, smap map[*ast.Ident]*ast.Ident) ast.Expr {
 +      switch n := x.(type) {
 +      case *ast.Ident:
 +              if alt := smap[n]; alt != nil {
 +                      return alt
 +              }
 +      case *ast.StarExpr:
 +              X := isubst(n.X, smap)
 +              if X != n.X {
 +                      new := *n
 +                      new.X = X
 +                      return &new
 +              }
 +      case *ast.CallExpr:
 +              var args []ast.Expr
 +              for i, arg := range n.Args {
 +                      new := isubst(arg, smap)
 +                      if new != arg {
 +                              if args == nil {
 +                                      args = make([]ast.Expr, len(n.Args))
 +                                      copy(args, n.Args)
 +                              }
 +                              args[i] = new
 +                      }
 +              }
 +              if args != nil {
 +                      new := *n
 +                      new.Args = args
 +                      return &new
 +              }
 +      case *ast.ParenExpr:
 +              return isubst(n.X, smap) // no need to keep parentheses
 +      default:
 +              // Other receiver type expressions are invalid.
 +              // It's fine to ignore those here as they will
 +              // be checked elsewhere.
 +      }
 +      return x
  }
  
  // funcType type-checks a function or method type.
  func (check *Checker) funcType(sig *Signature, recvPar *ast.FieldList, ftyp *ast.FuncType) {
 -      scope := NewScope(check.scope, token.NoPos, token.NoPos, "function")
 -      scope.isFunc = true
 -      check.recordScope(ftyp, scope)
 +      check.openScope(ftyp, "function")
 +      check.scope.isFunc = true
 +      check.recordScope(ftyp, check.scope)
 +      sig.scope = check.scope
 +      defer check.closeScope()
 +
 +      var recvTyp ast.Expr // rewritten receiver type; valid if != nil
 +      if recvPar != nil && len(recvPar.List) > 0 {
 +              // collect generic receiver type parameters, if any
 +              // - a receiver type parameter is like any other type parameter, except that it is declared implicitly
 +              // - the receiver specification acts as local declaration for its type parameters, which may be blank
 +              _, rname, rparams := check.unpackRecv(recvPar.List[0].Type, true)
 +              if len(rparams) > 0 {
 +                      // Blank identifiers don't get declared and regular type-checking of the instantiated
 +                      // parameterized receiver type expression fails in Checker.collectParams of receiver.
 +                      // Identify blank type parameters and substitute each with a unique new identifier named
 +                      // "n_" (where n is the parameter index) and which cannot conflict with any user-defined
 +                      // name.
 +                      var smap map[*ast.Ident]*ast.Ident // substitution map from "_" to "n_" identifiers
 +                      for i, p := range rparams {
 +                              if p.Name == "_" {
 +                                      new := *p
 +                                      new.Name = fmt.Sprintf("%d_", i)
 +                                      rparams[i] = &new // use n_ identifier instead of _ so it can be looked up
 +                                      if smap == nil {
 +                                              smap = make(map[*ast.Ident]*ast.Ident)
 +                                      }
 +                                      smap[p] = &new
 +                              }
 +                      }
 +                      if smap != nil {
 +                              // blank identifiers were found => use rewritten receiver type
 +                              recvTyp = isubst(recvPar.List[0].Type, smap)
 +                      }
 +                      sig.rparams = check.declareTypeParams(nil, rparams)
 +                      // determine receiver type to get its type parameters
 +                      // and the respective type parameter bounds
 +                      var recvTParams []*TypeName
 +                      if rname != nil {
 +                              // recv should be a Named type (otherwise an error is reported elsewhere)
 +                              // Also: Don't report an error via genericType since it will be reported
 +                              //       again when we type-check the signature.
 +                              // TODO(gri) maybe the receiver should be marked as invalid instead?
 +                              if recv := asNamed(check.genericType(rname, false)); recv != nil {
 +                                      recvTParams = recv.tparams
 +                              }
 +                      }
 +                      // provide type parameter bounds
 +                      // - 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.
 +                              list := make([]Type, len(sig.rparams))
 +                              for i, t := range sig.rparams {
 +                                      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
 +                                      // receiver type declaration. Substitute parameters for the
 +                                      // current context.
 +                                      // TODO(gri) should we assume now that bounds always exist?
 +                                      //           (no bound == empty interface)
 +                                      if bound != nil {
 +                                              bound = check.subst(tname.pos, bound, smap)
 +                                              tname.typ.(*TypeParam).bound = bound
 +                                      }
 +                              }
 +                      }
 +              }
 +      }
 +
 +      if ftyp.TParams != nil {
 +              sig.tparams = check.collectTypeParams(ftyp.TParams)
 +              // 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.errorf(ftyp.TParams, _Todo, "methods cannot have type parameters")
 +              }
 +      }
  
 -      recvList, _ := check.collectParams(scope, recvPar, false)
 -      params, variadic := check.collectParams(scope, ftyp.Params, true)
 -      results, _ := check.collectParams(scope, ftyp.Results, false)
 +      // Value (non-type) parameters' scope starts in the function body. Use a temporary scope for their
 +      // declarations and then squash that scope into the parent scope (and report any redeclarations at
 +      // that time).
 +      scope := NewScope(check.scope, token.NoPos, token.NoPos, "function body (temp. scope)")
 +      recvList, _ := check.collectParams(scope, recvPar, recvTyp, false) // use rewritten receiver type, if any
 +      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, _DuplicateDecl, "%s redeclared in this block", obj.Name())
 +              check.reportAltDecl(alt)
 +      })
  
        if recvPar != nil {
                // recv parameter list present (may be empty)
                var recv *Var
                switch len(recvList) {
                case 0:
 -                      check.error(recvPar, _BadRecv, "method is missing receiver")
 +                      // error reported by resolver
                        recv = NewParam(0, nil, "", Typ[Invalid]) // ignore recv below
                default:
                        // more than one receiver
                case 1:
                        recv = recvList[0]
                }
 +
 +              // TODO(gri) We should delay rtyp expansion to when we actually need the
 +              //           receiver; thus all checks here should be delayed to later.
 +              rtyp, _ := deref(recv.typ)
 +              rtyp = expand(rtyp)
 +
                // spec: "The receiver type must be of the form T or *T where T is a type name."
                // (ignore invalid types - error was reported before)
 -              if t, _ := deref(recv.typ); t != Typ[Invalid] {
 +              if t := rtyp; t != Typ[Invalid] {
                        var err string
 -                      if T, _ := t.(*Named); T != nil {
 +                      if T := asNamed(t); T != nil {
                                // spec: "The type denoted by T is called the receiver base type; it must not
                                // be a pointer or interface type and it must be declared in the same package
                                // as the method."
                                if T.obj.pkg != check.pkg {
                                        err = "type not defined in this package"
                                } else {
 -                                      // TODO(gri) This is not correct if the underlying type is unknown yet.
 -                                      switch u := T.underlying.(type) {
 +                                      switch u := optype(T).(type) {
                                        case *Basic:
                                                // unsafe.Pointer is treated like a regular pointer
                                                if u.kind == UnsafePointer {
                sig.recv = recv
        }
  
 -      sig.scope = scope
        sig.params = NewTuple(params...)
        sig.results = NewTuple(results...)
        sig.variadic = variadic
  }
  
 +// goTypeName returns the Go type name for typ and
 +// removes any occurences of "types." from that name.
 +func goTypeName(typ Type) string {
 +      return strings.ReplaceAll(fmt.Sprintf("%T", typ), "types.", "")
 +}
 +
  // typInternal drives type checking of types.
 -// Must only be called by definedType.
 +// Must only be called by definedType or genericType.
  //
 -func (check *Checker) typInternal(e ast.Expr, def *Named) Type {
 -      switch e := e.(type) {
 +func (check *Checker) typInternal(e0 ast.Expr, def *Named) (T Type) {
 +      if trace {
 +              check.trace(e0.Pos(), "type %s", e0)
 +              check.indent++
 +              defer func() {
 +                      check.indent--
 +                      var under Type
 +                      if T != nil {
 +                              // Calling under() here may lead to endless instantiations.
 +                              // Test case: type T[P any] *T[P]
 +                              // TODO(gri) investigate if that's a bug or to be expected
 +                              // (see also analogous comment in Checker.instantiate).
 +                              under = T.Underlying()
 +                      }
 +                      if T == under {
 +                              check.trace(e0.Pos(), "=> %s // %s", T, goTypeName(T))
 +                      } else {
 +                              check.trace(e0.Pos(), "=> %s (under = %s) // %s", T, under, goTypeName(T))
 +                      }
 +              }()
 +      }
 +
 +      switch e := e0.(type) {
        case *ast.BadExpr:
                // ignore - error reported before
  
                        check.errorf(&x, _NotAType, "%s is not a type", &x)
                }
  
 +      case *ast.IndexExpr:
 +              return check.instantiatedType(e.X, []ast.Expr{e.Index}, def)
 +
 +      case *ast.CallExpr:
 +              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.
 +              // Consequently, generic types cannot be parenthesized.
                return check.definedType(e.X, def)
  
        case *ast.ArrayType:
                        typ := new(Array)
                        def.setUnderlying(typ)
                        typ.len = check.arrayLength(e.Len)
 -                      typ.elem = check.typ(e.Elt)
 -                      return typ
 -
 -              } else {
 -                      typ := new(Slice)
 -                      def.setUnderlying(typ)
 -                      typ.elem = check.typ(e.Elt)
 +                      typ.elem = check.varType(e.Elt)
                        return typ
                }
  
 +              typ := new(Slice)
 +              def.setUnderlying(typ)
 +              typ.elem = check.varType(e.Elt)
 +              return typ
 +
 +      case *ast.Ellipsis:
 +              // dots are handled explicitly where they are legal
 +              // (array composite literals and parameter lists)
 +              check.error(e, _InvalidDotDotDot, "invalid use of '...'")
 +              check.use(e.Elt)
 +
        case *ast.StructType:
                typ := new(Struct)
                def.setUnderlying(typ)
        case *ast.StarExpr:
                typ := new(Pointer)
                def.setUnderlying(typ)
 -              typ.base = check.typ(e.X)
 +              typ.base = check.varType(e.X)
                return typ
  
        case *ast.FuncType:
        case *ast.InterfaceType:
                typ := new(Interface)
                def.setUnderlying(typ)
 +              if def != nil {
 +                      typ.obj = def.obj
 +              }
                check.interfaceType(typ, e, def)
                return typ
  
                typ := new(Map)
                def.setUnderlying(typ)
  
 -              typ.key = check.typ(e.Key)
 -              typ.elem = check.typ(e.Value)
 +              typ.key = check.varType(e.Key)
 +              typ.elem = check.varType(e.Value)
  
                // spec: "The comparison operators == and != must be fully defined
                // for operands of the key type; thus the key type must not be a
                // it is safe to continue in any case (was issue 6667).
                check.atEnd(func() {
                        if !Comparable(typ.key) {
 -                              check.errorf(e.Key, _IncomparableMapKey, "incomparable map key type %s", typ.key)
 +                              var why string
 +                              if asTypeParam(typ.key) != nil {
 +                                      why = " (missing comparable constraint)"
 +                              }
 +                              check.errorf(e.Key, _IncomparableMapKey, "incomparable map key type %s%s", typ.key, why)
                        }
                })
  
                }
  
                typ.dir = dir
 -              typ.elem = check.typ(e.Value)
 +              typ.elem = check.varType(e.Value)
                return typ
  
        default:
 -              check.errorf(e, _NotAType, "%s is not a type", e)
 +              check.errorf(e0, _NotAType, "%s is not a type", e0)
        }
  
        typ := Typ[Invalid]
  }
  
  // typeOrNil type-checks the type expression (or nil value) e
 -// and returns the typ of e, or nil.
 -// If e is neither a type nor nil, typOrNil returns Typ[Invalid].
 -//
 -func (check *Checker) typOrNil(e ast.Expr) Type {
 +// and returns the type of e, or nil. If e is a type, it must
 +// not be an (uninstantiated) generic type.
 +// If e is neither a type nor nil, typeOrNil returns Typ[Invalid].
 +// TODO(gri) should we also disallow non-var types?
 +func (check *Checker) typeOrNil(e ast.Expr) Type {
        var x operand
        check.rawExpr(&x, e, nil)
        switch x.mode {
        case novalue:
                check.errorf(&x, _NotAType, "%s used as type", &x)
        case typexpr:
 +              check.instantiatedOperand(&x)
                return x.typ
        case value:
                if x.isNil() {
        return Typ[Invalid]
  }
  
 +func (check *Checker) instantiatedType(x ast.Expr, targs []ast.Expr, def *Named) Type {
 +      b := check.genericType(x, true) // TODO(gri) what about cycles?
 +      if b == Typ[Invalid] {
 +              return b // error already reported
 +      }
 +      base := asNamed(b)
 +      if base == nil {
 +              unreachable() // should have been caught by genericType
 +      }
 +
 +      // create a new type instance rather than instantiate the type
 +      // TODO(gri) should do argument number check here rather than
 +      //           when instantiating the type?
 +      typ := new(instance)
 +      def.setUnderlying(typ)
 +
 +      typ.check = check
 +      typ.pos = x.Pos()
 +      typ.base = base
 +
 +      // evaluate arguments (always)
 +      typ.targs = check.typeList(targs)
 +      if typ.targs == nil {
 +              def.setUnderlying(Typ[Invalid]) // avoid later errors due to lazy instantiation
 +              return Typ[Invalid]
 +      }
 +
 +      // determine argument positions (for error reporting)
 +      typ.poslist = make([]token.Pos, len(targs))
 +      for i, arg := range targs {
 +              typ.poslist[i] = arg.Pos()
 +      }
 +
 +      // make sure we check instantiation works at least once
 +      // and that the resulting type is valid
 +      check.atEnd(func() {
 +              t := typ.expand()
 +              check.validType(t, nil)
 +      })
 +
 +      return typ
 +}
 +
  // arrayLength type-checks the array length expression e
  // and returns the constant length >= 0, or a value < 0
  // to indicate an error (and thus an unknown length).
@@@ -673,25 -394,7 +673,25 @@@ func (check *Checker) arrayLength(e ast
        return -1
  }
  
 -func (check *Checker) collectParams(scope *Scope, list *ast.FieldList, variadicOk bool) (params []*Var, variadic bool) {
 +// typeList provides the list of types corresponding to the incoming expression list.
 +// If an error occured, the result is nil, but all list elements were type-checked.
 +func (check *Checker) typeList(list []ast.Expr) []Type {
 +      res := make([]Type, len(list)) // res != nil even if len(list) == 0
 +      for i, x := range list {
 +              t := check.varType(x)
 +              if t == Typ[Invalid] {
 +                      res = nil
 +              }
 +              if res != nil {
 +                      res[i] = t
 +              }
 +      }
 +      return res
 +}
 +
 +// collectParams declares the parameters of list in scope and returns the corresponding
 +// variable list. If type0 != nil, it is used instead of the the first type in list.
 +func (check *Checker) collectParams(scope *Scope, list *ast.FieldList, type0 ast.Expr, variadicOk bool) (params []*Var, variadic bool) {
        if list == nil {
                return
        }
        var named, anonymous bool
        for i, field := range list.List {
                ftype := field.Type
 +              if i == 0 && type0 != nil {
 +                      ftype = type0
 +              }
                if t, _ := ftype.(*ast.Ellipsis); t != nil {
                        ftype = t.Elt
                        if variadicOk && i == len(list.List)-1 && len(field.Names) <= 1 {
                                // ignore ... and continue
                        }
                }
 -              typ := check.typ(ftype)
 +              typ := check.varType(ftype)
                // The parser ensures that f.Tag is nil and we don't
                // care if a constructed AST contains a non-nil tag.
                if len(field.Names) > 0 {
@@@ -762,12 -462,9 +762,12 @@@ func (check *Checker) declareInSet(ose
  }
  
  func (check *Checker) interfaceType(ityp *Interface, iface *ast.InterfaceType, def *Named) {
 +      var tlist *ast.Ident // "type" name of first entry in a type list declaration
 +      var types []ast.Expr
        for _, f := range iface.Methods.List {
                if len(f.Names) > 0 {
 -                      // We have a method with name f.Names[0].
 +                      // We have a method with name f.Names[0], or a type
 +                      // of a type list (name.Name == "type").
                        // (The parser ensures that there's only one method
                        // and we don't care if a constructed AST has more.)
                        name := f.Names[0]
                                continue // ignore
                        }
  
 +                      if name.Name == "type" {
 +                              // Always collect all type list entries, even from
 +                              // different type lists, under the assumption that
 +                              // the author intended to include all types.
 +                              types = append(types, f.Type)
 +                              if tlist != nil && tlist != name {
 +                                      check.errorf(name, _Todo, "cannot have multiple type lists in an interface")
 +                              }
 +                              tlist = name
 +                              continue
 +                      }
 +
                        typ := check.typ(f.Type)
                        sig, _ := typ.(*Signature)
                        if sig == nil {
                                continue // ignore
                        }
  
 +                      // 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.errorf(f.Type.(*ast.FuncType).TParams, _Todo, "methods cannot have type parameters")
 +                      }
 +
                        // use named receiver type if available (for better error messages)
                        var recvTyp Type = ityp
                        if def != nil {
                        check.recordDef(name, m)
                        ityp.methods = append(ityp.methods, m)
                } else {
 -                      // We have an embedded interface and f.Type is its
 -                      // (possibly qualified) embedded type name. Collect
 -                      // it if it's a valid interface.
 -                      typ := check.typ(f.Type)
 -
 -                      utyp := check.underlying(typ)
 -                      if _, ok := utyp.(*Interface); !ok {
 -                              if utyp != Typ[Invalid] {
 -                                      check.errorf(f.Type, _InvalidIfaceEmbed, "%s is not an interface", typ)
 -                              }
 -                              continue
 -                      }
 -
 -                      ityp.embeddeds = append(ityp.embeddeds, typ)
 +                      // We have an embedded type. completeInterface will
 +                      // eventually verify that we have an interface.
 +                      ityp.embeddeds = append(ityp.embeddeds, check.typ(f.Type))
                        check.posMap[ityp] = append(check.posMap[ityp], f.Type.Pos())
                }
        }
  
 -      if len(ityp.methods) == 0 && len(ityp.embeddeds) == 0 {
 +      // type constraints
 +      ityp.types = NewSum(check.collectTypeConstraints(iface.Pos(), types))
 +
 +      if len(ityp.methods) == 0 && ityp.types == nil && len(ityp.embeddeds) == 0 {
                // empty interface
                ityp.allMethods = markComplete
                return
        }
  
        // sort for API stability
-       sort.Sort(byUniqueMethodName(ityp.methods))
-       sort.Stable(byUniqueTypeName(ityp.embeddeds))
+       sortMethods(ityp.methods)
+       sortTypes(ityp.embeddeds)
  
 -      check.later(func() { check.completeInterface(ityp) })
 +      check.later(func() { check.completeInterface(iface.Pos(), ityp) })
  }
  
 -func (check *Checker) completeInterface(ityp *Interface) {
 +func (check *Checker) completeInterface(pos token.Pos, ityp *Interface) {
        if ityp.allMethods != nil {
                return
        }
        }
  
        if trace {
 -              check.trace(token.NoPos, "complete %s", ityp)
 +              // Types don't generally have position information.
 +              // If we don't have a valid pos provided, try to use
 +              // one close enough.
 +              if !pos.IsValid() && len(ityp.methods) > 0 {
 +                      pos = ityp.methods[0].pos
 +              }
 +
 +              check.trace(pos, "complete %s", ityp)
                check.indent++
                defer func() {
                        check.indent--
 -                      check.trace(token.NoPos, "=> %s", ityp)
 +                      check.trace(pos, "=> %s (methods = %v, types = %v)", ityp, ityp.allMethods, ityp.allTypes)
                }()
        }
  
                        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)
+                       // We have a duplicate method name in an embedded (not explicitly declared) method.
+                       // Check method signatures after all types are computed (issue #33656).
+                       // If we're pre-go1.14 (overlapping embeddings are not permitted), report that
+                       // error here as well (even though we could do it eagerly) because it's the same
+                       // error message.
                        check.atEnd(func() {
-                               if !check.identical(m.typ, other.Type()) {
+                               if !check.allowVersion(m.pkg, 1, 14) || !check.identical(m.typ, other.Type()) {
                                        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
                                }
                addMethod(m.pos, m, true)
        }
  
 +      // collect types
 +      allTypes := ityp.types
 +
        posList := check.posMap[ityp]
        for i, typ := range ityp.embeddeds {
                pos := posList[i] // embedding position
 -              typ, ok := check.underlying(typ).(*Interface)
 -              if !ok {
 -                      // An error was reported when collecting the embedded types.
 -                      // Ignore it.
 +              utyp := under(typ)
 +              etyp := asInterface(utyp)
 +              if etyp == nil {
 +                      if utyp != Typ[Invalid] {
 +                              var format string
 +                              if _, ok := utyp.(*TypeParam); ok {
 +                                      format = "%s is a type parameter, not an interface"
 +                              } else {
 +                                      format = "%s is not an interface"
 +                              }
 +                              // TODO: correct error code.
 +                              check.errorf(atPos(pos), _InvalidIfaceEmbed, format, typ)
 +                      }
                        continue
                }
 -              check.completeInterface(typ)
 -              for _, m := range typ.allMethods {
 +              check.completeInterface(pos, etyp)
 +              for _, m := range etyp.allMethods {
                        addMethod(pos, m, false) // use embedding position pos rather than m.pos
                }
 +              allTypes = intersect(allTypes, etyp.allTypes)
        }
  
        if methods != nil {
                sort.Sort(byUniqueMethodName(methods))
                ityp.allMethods = methods
        }
 +      ityp.allTypes = allTypes
 +}
 +
 +// intersect computes the intersection of the types x and y.
 +// Note: A incomming nil type stands for the top type. A top
 +// type result is returned as nil.
 +func intersect(x, y Type) (r Type) {
 +      defer func() {
 +              if r == theTop {
 +                      r = nil
 +              }
 +      }()
 +
 +      switch {
 +      case x == theBottom || y == theBottom:
 +              return theBottom
 +      case x == nil || x == theTop:
 +              return y
 +      case y == nil || x == theTop:
 +              return x
 +      }
 +
 +      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.
 +      // TODO(gri) fix this
 +      var rtypes []Type
 +      for _, x := range xtypes {
 +              if includes(ytypes, x) {
 +                      rtypes = append(rtypes, x)
 +              }
 +      }
 +
 +      if rtypes == nil {
 +              return theBottom
 +      }
 +      return NewSum(rtypes)
  }
  
+ func sortTypes(list []Type) {
+       sort.Stable(byUniqueTypeName(list))
+ }
  // byUniqueTypeName named type lists can be sorted by their unique type names.
  type byUniqueTypeName []Type
  
@@@ -994,12 -629,25 +1002,25 @@@ func (a byUniqueTypeName) Less(i, j int
  func (a byUniqueTypeName) Swap(i, j int)      { a[i], a[j] = a[j], a[i] }
  
  func sortName(t Type) string {
 -      if named, _ := t.(*Named); named != nil {
 +      if named := asNamed(t); named != nil {
                return named.obj.Id()
        }
        return ""
  }
  
+ func sortMethods(list []*Func) {
+       sort.Sort(byUniqueMethodName(list))
+ }
+ func assertSortedMethods(list []*Func) {
+       if !debug {
+               panic("internal error: assertSortedMethods called outside debug mode")
+       }
+       if !sort.IsSorted(byUniqueMethodName(list)) {
+               panic("internal error: methods not sorted")
+       }
+ }
  // byUniqueMethodName method lists can be sorted by their unique method names.
  type byUniqueMethodName []*Func
  
@@@ -1063,7 -711,7 +1084,7 @@@ func (check *Checker) structType(styp *
        }
  
        for _, f := range list.List {
 -              typ = check.typ(f.Type)
 +              typ = check.varType(f.Type)
                tag = check.tag(f.Tag)
                if len(f.Names) > 0 {
                        // named fields
                        }
                } else {
                        // embedded field
 -                      // 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."
 +                      // 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.invalidAST(f.Type, "embedded field type %s has no name", 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
                        }
 -                      t, isPtr := deref(typ)
 +                      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.
 -                      switch t := t.Underlying().(type) {
 -                      case *Basic:
 -                              if t == Typ[Invalid] {
 -                                      // error was reported before
 -                                      addInvalid(name, pos)
 -                                      continue
 -                              }
 -
 -                              // unsafe.Pointer is treated like a regular pointer
 -                              if t.kind == UnsafePointer {
 -                                      check.errorf(f.Type, _InvalidPtrEmbed, "embedded field type cannot be unsafe.Pointer")
 -                                      addInvalid(name, pos)
 -                                      continue
 -                              }
 +                      // We must delay this check to the end because we don't want to instantiate
 +                      // (via under(t)) a possibly incomplete type.
  
 -                      case *Pointer:
 -                              check.errorf(f.Type, _InvalidPtrEmbed, "embedded field type cannot be a pointer")
 -                              addInvalid(name, pos)
 -                              continue
 +                      // for use in the closure below
 +                      embeddedTyp := typ
 +                      embeddedPos := f.Type
  
 -                      case *Interface:
 -                              if isPtr {
 -                                      check.errorf(f.Type, _InvalidPtrEmbed, "embedded field type cannot be a pointer to an interface")
 -                                      addInvalid(name, pos)
 -                                      continue
 +                      check.atEnd(func() {
 +                              t, isPtr := deref(embeddedTyp)
 +                              switch t := optype(t).(type) {
 +                              case *Basic:
 +                                      if t == Typ[Invalid] {
 +                                              // error was reported before
 +                                              return
 +                                      }
 +                                      // unsafe.Pointer is treated like a regular pointer
 +                                      if t.kind == UnsafePointer {
 +                                              check.errorf(embeddedPos, _InvalidPtrEmbed, "embedded field type cannot be unsafe.Pointer")
 +                                      }
 +                              case *Pointer:
 +                                      check.errorf(embeddedPos, _InvalidPtrEmbed, "embedded field type cannot be a pointer")
 +                              case *Interface:
 +                                      if isPtr {
 +                                              check.errorf(embeddedPos, _InvalidPtrEmbed, "embedded field type cannot be a pointer to an interface")
 +                                      }
                                }
 -                      }
 -                      add(name, true, pos)
 +                      })
                }
        }
  
@@@ -1135,50 -780,6 +1156,50 @@@ func embeddedFieldIdent(e ast.Expr) *as
                }
        case *ast.SelectorExpr:
                return e.Sel
 +      case *ast.IndexExpr:
 +              return embeddedFieldIdent(e.X)
 +      case *ast.CallExpr:
 +              if e.Brackets {
 +                      return embeddedFieldIdent(e.Fun)
 +              }
        }
        return nil // invalid embedded field
  }
 +
 +func (check *Checker) collectTypeConstraints(pos token.Pos, types []ast.Expr) []Type {
 +      list := make([]Type, 0, len(types)) // assume all types are correct
 +      for _, texpr := range types {
 +              if texpr == nil {
 +                      check.invalidAST(atPos(pos), "missing type constraint")
 +                      continue
 +              }
 +              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.
 +      // Note: This is a quadratic algorithm, but type lists tend to be short.
 +      check.atEnd(func() {
 +              for i, t := range list {
 +                      if t := asInterface(t); t != nil {
 +                              check.completeInterface(types[i].Pos(), t)
 +                      }
 +                      if includes(list[:i], t) {
 +                              check.softErrorf(types[i], _Todo, "duplicate type %s in type list", t)
 +                      }
 +              }
 +      })
 +
 +      return list
 +}
 +
 +// includes reports whether typ is in list.
 +func includes(list []Type, typ Type) bool {
 +      for _, e := range list {
 +              if Identical(typ, e) {
 +                      return true
 +              }
 +      }
 +      return false
 +}
diff --combined test/run.go
index 3ff5d9c1e03c7620dcf76e5774c5074006fb2a44,dba4d16d63e6ed3cce2d64c7a04b69e610c0ab18..657632643ead6bd33c34751962cd439f809e9531
@@@ -59,7 -59,7 +59,7 @@@ var 
  
        // dirs are the directories to look for *.go files in.
        // TODO(bradfitz): just use all directories?
 -      dirs = []string{".", "ken", "chan", "interface", "syntax", "dwarf", "fixedbugs", "codegen", "runtime", "abi"}
 +      dirs = []string{".", "ken", "chan", "interface", "syntax", "dwarf", "fixedbugs", "codegen", "runtime", "abi", "typeparam"}
  
        // ratec controls the max number of tests running at a time.
        ratec chan bool
@@@ -749,66 -749,7 +749,66 @@@ func (t *test) run() 
                        t.updateErrors(string(out), long)
                }
                t.err = t.errorCheck(string(out), wantAuto, long, t.gofile)
 -              return
 +              if t.err != nil {
 +                      return // don't hide error if run below succeeds
 +              }
 +
 +              // The following is temporary scaffolding to get types2 typechecker
 +              // up and running against the existing test cases. The explicitly
 +              // listed files don't pass yet, usually because the error messages
 +              // are slightly different (this list is not complete). Any errorcheck
 +              // tests that require output from analysis phases past intial type-
 +              // checking are also excluded since these phases are not running yet.
 +              // We can get rid of this code once types2 is fully plugged in.
 +
 +              // For now we're done when we can't handle the file or some of the flags.
 +              // The first goal is to eliminate the excluded list; the second goal is to
 +              // eliminate the flag list.
 +
 +              // Excluded files.
 +              filename := strings.Replace(t.goFileName(), "\\", "/", -1) // goFileName() uses \ on Windows
 +              if excluded[filename] {
 +                      if *verbose {
 +                              fmt.Printf("excl\t%s\n", filename)
 +                      }
 +                      return // cannot handle file yet
 +              }
 +
 +              // Excluded flags.
 +              for _, flag := range flags {
 +                      for _, pattern := range []string{
 +                              "-m",
 +                      } {
 +                              if strings.Contains(flag, pattern) {
 +                                      if *verbose {
 +                                              fmt.Printf("excl\t%s\t%s\n", filename, flags)
 +                                      }
 +                                      return // cannot handle flag
 +                              }
 +                      }
 +              }
 +
 +              // Run errorcheck again with -G option (new typechecker).
 +              cmdline = []string{goTool(), "tool", "compile", "-G=3", "-C", "-e", "-o", "a.o"}
 +              // No need to add -dynlink even if linkshared if we're just checking for errors...
 +              cmdline = append(cmdline, flags...)
 +              cmdline = append(cmdline, long)
 +              out, err = runcmd(cmdline...)
 +              if wantError {
 +                      if err == nil {
 +                              t.err = fmt.Errorf("compilation succeeded unexpectedly\n%s", out)
 +                              return
 +                      }
 +              } else {
 +                      if err != nil {
 +                              t.err = err
 +                              return
 +                      }
 +              }
 +              if *updateErrors {
 +                      t.updateErrors(string(out), long)
 +              }
 +              t.err = t.errorCheck(string(out), wantAuto, long, t.gofile)
  
        case "compile":
                // Compile Go file.
                if *linkshared {
                        cmd = append(cmd, "-linkshared")
                }
+               cmd = append(cmd, flags...)
                cmd = append(cmd, ".")
                out, err := runcmd(cmd...)
                if err != nil {
@@@ -1913,67 -1855,3 +1914,67 @@@ func overlayDir(dstRoot, srcRoot string
                return err
        })
  }
 +
 +// List of files that the compiler cannot errorcheck with the new typechecker (compiler -G option).
 +// Temporary scaffolding until we pass all the tests at which point this map can be removed.
 +var excluded = map[string]bool{
 +      "complit1.go":     true, // types2 reports extra errors
 +      "const2.go":       true, // types2 not run after syntax errors
 +      "ddd1.go":         true, // issue #42987
 +      "directive.go":    true, // misplaced compiler directive checks
 +      "float_lit3.go":   true, // types2 reports extra errors
 +      "import1.go":      true, // types2 reports extra errors
 +      "import5.go":      true, // issue #42988
 +      "import6.go":      true, // issue #43109
 +      "initializerr.go": true, // types2 reports extra errors
 +      "linkname2.go":    true, // error reported by noder (not running for types2 errorcheck test)
 +      "notinheap.go":    true, // types2 doesn't report errors about conversions that are invalid due to //go:notinheap
 +      "shift1.go":       true, // issue #42989
 +      "typecheck.go":    true, // invalid function is not causing errors when called
 +      "writebarrier.go": true, // correct diagnostics, but different lines (probably irgen's fault)
 +
 +      "fixedbugs/bug176.go":    true, // types2 reports all errors (pref: types2)
 +      "fixedbugs/bug193.go":    true, // types2 bug: shift error not reported (fixed in go/types)
 +      "fixedbugs/bug195.go":    true, // types2 reports slightly different (but correct) bugs
 +      "fixedbugs/bug228.go":    true, // types2 not run after syntax errors
 +      "fixedbugs/bug231.go":    true, // types2 bug? (same error reported twice)
 +      "fixedbugs/bug255.go":    true, // types2 reports extra errors
 +      "fixedbugs/bug351.go":    true, // types2 reports extra errors
 +      "fixedbugs/bug374.go":    true, // types2 reports extra errors
 +      "fixedbugs/bug385_32.go": true, // types2 doesn't produce missing error "type .* too large" (32-bit specific)
 +      "fixedbugs/bug388.go":    true, // types2 not run due to syntax errors
 +      "fixedbugs/bug412.go":    true, // types2 produces a follow-on error
 +
 +      "fixedbugs/issue11590.go":  true, // types2 doesn't report a follow-on error (pref: types2)
 +      "fixedbugs/issue11610.go":  true, // types2 not run after syntax errors
 +      "fixedbugs/issue11614.go":  true, // types2 reports an extra error
 +      "fixedbugs/issue13415.go":  true, // declared but not used conflict
 +      "fixedbugs/issue14520.go":  true, // missing import path error by types2
 +      "fixedbugs/issue16428.go":  true, // types2 reports two instead of one error
 +      "fixedbugs/issue17038.go":  true, // types2 doesn't report a follow-on error (pref: types2)
 +      "fixedbugs/issue17645.go":  true, // multiple errors on same line
 +      "fixedbugs/issue18331.go":  true, // missing error about misuse of //go:noescape (irgen needs code from noder)
 +      "fixedbugs/issue18393.go":  true, // types2 not run after syntax errors
 +      "fixedbugs/issue19012.go":  true, // multiple errors on same line
 +      "fixedbugs/issue20233.go":  true, // types2 reports two instead of one error (pref: compiler)
 +      "fixedbugs/issue20245.go":  true, // types2 reports two instead of one error (pref: compiler)
 +      "fixedbugs/issue20250.go":  true, // correct diagnostics, but different lines (probably irgen's fault)
 +      "fixedbugs/issue21979.go":  true, // types2 doesn't report a follow-on error (pref: types2)
 +      "fixedbugs/issue23732.go":  true, // types2 reports different (but ok) line numbers
 +      "fixedbugs/issue25958.go":  true, // types2 doesn't report a follow-on error (pref: types2)
 +      "fixedbugs/issue28079b.go": true, // types2 reports follow-on errors
 +      "fixedbugs/issue28268.go":  true, // types2 reports follow-on errors
 +      "fixedbugs/issue33460.go":  true, // types2 reports alternative positions in separate error
 +      "fixedbugs/issue41575.go":  true, // types2 reports alternative positions in separate error
 +      "fixedbugs/issue42058a.go": true, // types2 doesn't report "channel element type too large"
 +      "fixedbugs/issue42058b.go": true, // types2 doesn't report "channel element type too large"
 +      "fixedbugs/issue4232.go":   true, // types2 reports (correct) extra errors
 +      "fixedbugs/issue4452.go":   true, // types2 reports (correct) extra errors
 +      "fixedbugs/issue5609.go":   true, // types2 needs a better error message
 +      "fixedbugs/issue6889.go":   true, // types2 can handle this without constant overflow
 +      "fixedbugs/issue7525.go":   true, // types2 reports init cycle error on different line - ok otherwise
 +      "fixedbugs/issue7525b.go":  true, // types2 reports init cycle error on different line - ok otherwise
 +      "fixedbugs/issue7525c.go":  true, // types2 reports init cycle error on different line - ok otherwise
 +      "fixedbugs/issue7525d.go":  true, // types2 reports init cycle error on different line - ok otherwise
 +      "fixedbugs/issue7525e.go":  true, // types2 reports init cycle error on different line - ok otherwise
 +}