go/internal/gcimporter: update iimport.go to support type parameters

This CL pulls in the latest changes from go/internal/gcimporter, while
avoiding breaking the build on older go versions. To help maintain
compatibility with older Go versions while minimizing the diff with the
standard library importer, the internal/typeparams package was
significantly expanded.

I decided to use type aliases in the internal/typeparams package on Go
version >= go1.18, and placeholder types on Go version < go1.18. This
reduces the amount of copying needed in the APIs, though it might not be
the best decision if we ever decide to export this package.
Documentation was also updated to be more concise and specific to the Go
version being used.

In order to actually fix the x/tools Trybot for packages using generics
in the standard library, we need to switch from the 'typeparams' build
constraint to the 'go1.18' build constraint. This means if we make any
additional API changes in go/types we'll have to submit them with a
broken x/tools Trybot and then immediately fix the x/tools build.

Change-Id: Ifa0b1c37b89dc549ee295fa3a959f03deda86e56
Reviewed-on: https://go-review.googlesource.com/c/tools/+/349949
Trust: Robert Findley <rfindley@google.com>
Run-TryBot: Robert Findley <rfindley@google.com>
gopls-CI: kokoro <noreply+kokoro@google.com>
TryBot-Result: Go Bot <gobot@golang.org>
Reviewed-by: Robert Griesemer <gri@golang.org>
diff --git a/go/internal/gcimporter/bimport.go b/go/internal/gcimporter/bimport.go
index e9f73d1..b023120 100644
--- a/go/internal/gcimporter/bimport.go
+++ b/go/internal/gcimporter/bimport.go
@@ -1029,6 +1029,7 @@
 			// used internally by gc; never used by this package or in .a files
 			anyType{},
 		}
+		predecl = append(predecl, additionalPredeclared()...)
 	})
 	return predecl
 }
diff --git a/go/internal/gcimporter/iimport.go b/go/internal/gcimporter/iimport.go
index 8ed8bc6..869c132 100644
--- a/go/internal/gcimporter/iimport.go
+++ b/go/internal/gcimporter/iimport.go
@@ -18,6 +18,8 @@
 	"go/types"
 	"io"
 	"sort"
+
+	"golang.org/x/tools/internal/typeparams"
 )
 
 type intReader struct {
@@ -41,6 +43,21 @@
 	return i
 }
 
+// Keep this in sync with constants in iexport.go.
+const (
+	iexportVersionGo1_11 = 0
+	iexportVersionPosCol = 1
+	// TODO: before release, change this back to 2.
+	iexportVersionGenerics = iexportVersionPosCol
+
+	iexportVersionCurrent = iexportVersionGenerics
+)
+
+type ident struct {
+	pkg  string
+	name string
+}
+
 const predeclReserved = 32
 
 type itag uint64
@@ -56,6 +73,9 @@
 	signatureType
 	structType
 	interfaceType
+	typeParamType
+	instType
+	unionType
 )
 
 // IImportData imports a package from the serialized package data
@@ -101,9 +121,13 @@
 
 	version = int64(r.uint64())
 	switch version {
-	case currentVersion, 0:
+	case /* iexportVersionGenerics, */ iexportVersionPosCol, iexportVersionGo1_11:
 	default:
-		errorf("unknown iexport format version %d", version)
+		if version > iexportVersionGenerics {
+			errorf("unstable iexport format version %d, just rebuild compiler and std library", version)
+		} else {
+			errorf("unknown iexport format version %d", version)
+		}
 	}
 
 	sLen := int64(r.uint64())
@@ -115,8 +139,9 @@
 	r.Seek(sLen+dLen, io.SeekCurrent)
 
 	p := iimporter{
-		ipath:   path,
-		version: int(version),
+		exportVersion: version,
+		ipath:         path,
+		version:       int(version),
 
 		stringData:  stringData,
 		stringCache: make(map[uint64]string),
@@ -125,6 +150,9 @@
 		declData: declData,
 		pkgIndex: make(map[*types.Package]map[string]uint64),
 		typCache: make(map[uint64]types.Type),
+		// Separate map for typeparams, keyed by their package and unique
+		// name (name with subscript).
+		tparamIndex: make(map[ident]types.Type),
 
 		fake: fakeFileSet{
 			fset:  fset,
@@ -216,16 +244,18 @@
 }
 
 type iimporter struct {
-	ipath   string
-	version int
+	exportVersion int64
+	ipath         string
+	version       int
 
 	stringData  []byte
 	stringCache map[uint64]string
 	pkgCache    map[uint64]*types.Package
 
-	declData []byte
-	pkgIndex map[*types.Package]map[string]uint64
-	typCache map[uint64]types.Type
+	declData    []byte
+	pkgIndex    map[*types.Package]map[string]uint64
+	typCache    map[uint64]types.Type
+	tparamIndex map[ident]types.Type
 
 	fake          fakeFileSet
 	interfaceList []*types.Interface
@@ -315,17 +345,27 @@
 
 		r.declare(types.NewConst(pos, r.currPkg, name, typ, val))
 
-	case 'F':
+	case 'F', 'G':
+		var tparams []*typeparams.TypeParam
+		if tag == 'G' {
+			tparams = r.tparamList()
+		}
 		sig := r.signature(nil)
-
+		typeparams.SetForSignature(sig, tparams)
 		r.declare(types.NewFunc(pos, r.currPkg, name, sig))
 
-	case 'T':
+	case 'T', 'U':
 		// Types can be recursive. We need to setup a stub
 		// declaration before recursing.
 		obj := types.NewTypeName(pos, r.currPkg, name, nil)
 		named := types.NewNamed(obj, nil, nil)
+		// Declare obj before calling r.tparamList, so the new type name is recognized
+		// if used in the constraint of one of its own typeparams (see #48280).
 		r.declare(obj)
+		if tag == 'U' {
+			tparams := r.tparamList()
+			typeparams.SetForNamed(named, tparams)
+		}
 
 		underlying := r.p.typAt(r.uint64(), named).Underlying()
 		named.SetUnderlying(underlying)
@@ -337,10 +377,46 @@
 				recv := r.param()
 				msig := r.signature(recv)
 
+				// If the receiver has any targs, set those as the
+				// rparams of the method (since those are the
+				// typeparams being used in the method sig/body).
+				targs := typeparams.NamedTypeArgs(baseType(msig.Recv().Type()))
+				if len(targs) > 0 {
+					rparams := make([]*typeparams.TypeParam, len(targs))
+					for i := range rparams {
+						rparams[i], _ = targs[i].(*typeparams.TypeParam)
+					}
+					typeparams.SetRecvTypeParams(msig, rparams)
+				}
+
 				named.AddMethod(types.NewFunc(mpos, r.currPkg, mname, msig))
 			}
 		}
 
+	case 'P':
+		// We need to "declare" a typeparam in order to have a name that
+		// can be referenced recursively (if needed) in the type param's
+		// bound.
+		if r.p.exportVersion < iexportVersionGenerics {
+			errorf("unexpected type param type")
+		}
+		name0, sub := parseSubscript(name)
+		tn := types.NewTypeName(pos, r.currPkg, name0, nil)
+		t := typeparams.NewTypeParam(tn, nil)
+		if sub == 0 {
+			errorf("missing subscript")
+		}
+
+		// TODO(rfindley): can we use a different, stable ID?
+		// t.SetId(sub)
+
+		// To handle recursive references to the typeparam within its
+		// bound, save the partial type in tparamIndex before reading the bounds.
+		id := ident{r.currPkg.Name(), name}
+		r.p.tparamIndex[id] = t
+
+		typeparams.SetTypeParamConstraint(t, r.typ())
+
 	case 'V':
 		typ := r.typ()
 
@@ -618,6 +694,49 @@
 		typ := newInterface(methods, embeddeds)
 		r.p.interfaceList = append(r.p.interfaceList, typ)
 		return typ
+
+	case typeParamType:
+		if r.p.exportVersion < iexportVersionGenerics {
+			errorf("unexpected type param type")
+		}
+		pkg, name := r.qualifiedIdent()
+		id := ident{pkg.Name(), name}
+		if t, ok := r.p.tparamIndex[id]; ok {
+			// We're already in the process of importing this typeparam.
+			return t
+		}
+		// Otherwise, import the definition of the typeparam now.
+		r.p.doDecl(pkg, name)
+		return r.p.tparamIndex[id]
+
+	case instType:
+		if r.p.exportVersion < iexportVersionGenerics {
+			errorf("unexpected instantiation type")
+		}
+		// pos does not matter for instances: they are positioned on the original
+		// type.
+		_ = r.pos()
+		len := r.uint64()
+		targs := make([]types.Type, len)
+		for i := range targs {
+			targs[i] = r.typ()
+		}
+		baseType := r.typ()
+		// The imported instantiated type doesn't include any methods, so
+		// we must always use the methods of the base (orig) type.
+		// TODO provide a non-nil *Environment
+		t, _ := typeparams.Instantiate(nil, baseType, targs, false)
+		return t
+
+	case unionType:
+		if r.p.exportVersion < iexportVersionGenerics {
+			errorf("unexpected instantiation type")
+		}
+		terms := make([]*typeparams.Term, r.uint64())
+		for i := range terms {
+			terms[i] = typeparams.NewTerm(r.bool(), r.typ())
+		}
+		return typeparams.NewUnion(terms)
 	}
 }
 
@@ -632,6 +751,20 @@
 	return types.NewSignature(recv, params, results, variadic)
 }
 
+func (r *importReader) tparamList() []*typeparams.TypeParam {
+	n := r.uint64()
+	if n == 0 {
+		return nil
+	}
+	xs := make([]*typeparams.TypeParam, n)
+	for i := range xs {
+		// Note: the standard library importer is tolerant of nil types here,
+		// though would panic in SetTypeParams.
+		xs[i] = r.typ().(*typeparams.TypeParam)
+	}
+	return xs
+}
+
 func (r *importReader) paramList() *types.Tuple {
 	xs := make([]*types.Var, r.uint64())
 	for i := range xs {
@@ -674,3 +807,33 @@
 	}
 	return x
 }
+
+func baseType(typ types.Type) *types.Named {
+	// pointer receivers are never types.Named types
+	if p, _ := typ.(*types.Pointer); p != nil {
+		typ = p.Elem()
+	}
+	// receiver base types are always (possibly generic) types.Named types
+	n, _ := typ.(*types.Named)
+	return n
+}
+
+func parseSubscript(name string) (string, uint64) {
+	// Extract the subscript value from the type param name. We export
+	// and import the subscript value, so that all type params have
+	// unique names.
+	sub := uint64(0)
+	startsub := -1
+	for i, r := range name {
+		if '₀' <= r && r < '₀'+10 {
+			if startsub == -1 {
+				startsub = i
+			}
+			sub = sub*10 + uint64(r-'₀')
+		}
+	}
+	if startsub >= 0 {
+		name = name[:startsub]
+	}
+	return name, sub
+}
diff --git a/go/internal/gcimporter/support_go117.go b/go/internal/gcimporter/support_go117.go
new file mode 100644
index 0000000..e6403e1
--- /dev/null
+++ b/go/internal/gcimporter/support_go117.go
@@ -0,0 +1,14 @@
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+//go:build !go1.18
+// +build !go1.18
+
+package gcimporter
+
+import "go/types"
+
+func additionalPredeclared() []types.Type {
+	return nil
+}
diff --git a/go/internal/gcimporter/support_go118.go b/go/internal/gcimporter/support_go118.go
new file mode 100644
index 0000000..a5c7485
--- /dev/null
+++ b/go/internal/gcimporter/support_go118.go
@@ -0,0 +1,18 @@
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+//go:build go1.18
+// +build go1.18
+
+package gcimporter
+
+import "go/types"
+
+// additionalPredeclared returns additional predeclared types in go.1.18.
+func additionalPredeclared() []types.Type {
+	return []types.Type{
+		// comparable
+		types.Universe.Lookup("comparable").Type(),
+	}
+}
diff --git a/internal/lsp/source/hover.go b/internal/lsp/source/hover.go
index 56666d3..a2c731a 100644
--- a/internal/lsp/source/hover.go
+++ b/internal/lsp/source/hover.go
@@ -406,7 +406,7 @@
 func objectString(obj types.Object, qf types.Qualifier, inferred *types.Signature) string {
 	// If the signature type was inferred, prefer the preferred signature with a
 	// comment showing the generic signature.
-	if sig, _ := obj.Type().(*types.Signature); sig != nil && len(typeparams.ForSignature(sig)) > 0 && inferred != nil {
+	if sig, _ := obj.Type().(*types.Signature); sig != nil && typeparams.ForSignature(sig).Len() > 0 && inferred != nil {
 		obj2 := types.NewFunc(obj.Pos(), obj.Pkg(), obj.Name(), inferred)
 		str := types.ObjectString(obj2, qf)
 		// Try to avoid overly long lines.
diff --git a/internal/lsp/source/identifier.go b/internal/lsp/source/identifier.go
index 155f7c4..2bc3431 100644
--- a/internal/lsp/source/identifier.go
+++ b/internal/lsp/source/identifier.go
@@ -377,7 +377,7 @@
 			// If the IndexExpr is fully instantiated, we consider that 'inference' for
 			// gopls' purposes.
 			sig, _ := info.TypeOf(e).(*types.Signature)
-			if sig != nil && len(typeparams.ForSignature(sig)) == 0 {
+			if sig != nil && typeparams.ForSignature(sig).Len() == 0 {
 				return sig
 			}
 			_, sig = typeparams.GetInferred(info, e)
diff --git a/internal/lsp/testdata/summary_generics.txt.golden b/internal/lsp/testdata/summary_go1.18.txt.golden
similarity index 97%
rename from internal/lsp/testdata/summary_generics.txt.golden
rename to internal/lsp/testdata/summary_go1.18.txt.golden
index f93110a..aaeb262 100644
--- a/internal/lsp/testdata/summary_generics.txt.golden
+++ b/internal/lsp/testdata/summary_go1.18.txt.golden
@@ -20,7 +20,7 @@
 TypeDefinitionsCount = 18
 HighlightsCount = 69
 ReferencesCount = 27
-RenamesCount = 37
+RenamesCount = 41
 PrepareRenamesCount = 7
 SymbolsCount = 5
 WorkspaceSymbolsCount = 20
diff --git a/internal/lsp/tests/tests.go b/internal/lsp/tests/tests.go
index 5d6af9e..13da559 100644
--- a/internal/lsp/tests/tests.go
+++ b/internal/lsp/tests/tests.go
@@ -47,7 +47,7 @@
 
 func init() {
 	if typeparams.Enabled {
-		summaryFile = "summary_generics.txt"
+		summaryFile = "summary_go1.18.txt"
 	}
 }
 
diff --git a/internal/typeparams/enabled_go117.go b/internal/typeparams/enabled_go117.go
new file mode 100644
index 0000000..1821239
--- /dev/null
+++ b/internal/typeparams/enabled_go117.go
@@ -0,0 +1,12 @@
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+//go:build !go1.18
+// +build !go1.18
+
+package typeparams
+
+// Enabled reports whether type parameters are enabled in the current build
+// environment.
+const Enabled = false
diff --git a/internal/typeparams/enabled_go118.go b/internal/typeparams/enabled_go118.go
new file mode 100644
index 0000000..d671488
--- /dev/null
+++ b/internal/typeparams/enabled_go118.go
@@ -0,0 +1,15 @@
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+//go:build go1.18
+// +build go1.18
+
+package typeparams
+
+// Note: this constant is in a separate file as this is the only acceptable
+// diff between the <1.18 API of this package and the 1.18 API.
+
+// Enabled reports whether type parameters are enabled in the current build
+// environment.
+const Enabled = true
diff --git a/internal/typeparams/notypeparams.go b/internal/typeparams/notypeparams.go
deleted file mode 100644
index e975e47..0000000
--- a/internal/typeparams/notypeparams.go
+++ /dev/null
@@ -1,93 +0,0 @@
-// Copyright 2021 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-//go:build !typeparams || !go1.18
-// +build !typeparams !go1.18
-
-package typeparams
-
-import (
-	"go/ast"
-	"go/types"
-)
-
-// NOTE: doc comments must be kept in sync with typeparams.go.
-
-// Enabled reports whether type parameters are enabled in the current build
-// environment.
-const Enabled = false
-
-// GetIndexExprData extracts data from AST nodes that represent index
-// expressions.
-//
-// For an ast.IndexExpr, the resulting IndexExprData will have exactly one
-// index expression. For an ast.MultiIndexExpr (go1.18+), it may have a
-// variable number of index expressions.
-//
-// For nodes that don't represent index expressions, GetIndexExprData returns
-// nil.
-func GetIndexExprData(n ast.Node) *IndexExprData {
-	if e, _ := n.(*ast.IndexExpr); e != nil {
-		return &IndexExprData{
-			X:       e.X,
-			Lbrack:  e.Lbrack,
-			Indices: []ast.Expr{e.Index},
-			Rbrack:  e.Rbrack,
-		}
-	}
-	return nil
-}
-
-// ForTypeDecl extracts the (possibly nil) type parameter node list from n.
-func ForTypeDecl(*ast.TypeSpec) *ast.FieldList {
-	return nil
-}
-
-// ForFuncDecl extracts the (possibly nil) type parameter node list from n.
-func ForFuncDecl(*ast.FuncDecl) *ast.FieldList {
-	return nil
-}
-
-// ForSignature extracts the (possibly empty) type parameter object list from
-// sig.
-func ForSignature(*types.Signature) []*types.TypeName {
-	return nil
-}
-
-// IsComparable reports if iface is the comparable interface.
-func IsComparable(*types.Interface) bool {
-	return false
-}
-
-// IsConstraint reports whether iface may only be used as a type parameter
-// constraint (i.e. has a type set or is the comparable interface).
-func IsConstraint(*types.Interface) bool {
-	return false
-}
-
-// ForNamed extracts the (possibly empty) type parameter object list from
-// named.
-func ForNamed(*types.Named) []*types.TypeName {
-	return nil
-}
-
-// NamedTArgs extracts the (possibly empty) type argument list from named.
-func NamedTArgs(*types.Named) []types.Type {
-	return nil
-}
-
-// InitInferred initializes info to record inferred type information.
-func InitInferred(*types.Info) {
-}
-
-// GetInferred extracts inferred type information from info for e.
-//
-// The expression e may have an inferred type if it is an *ast.IndexExpr
-// representing partial instantiation of a generic function type for which type
-// arguments have been inferred using constraint type inference, or if it is an
-// *ast.CallExpr for which type type arguments have be inferred using both
-// constraint type inference and function argument inference.
-func GetInferred(*types.Info, ast.Expr) ([]types.Type, *types.Signature) {
-	return nil, nil
-}
diff --git a/internal/typeparams/typeparams.go b/internal/typeparams/typeparams.go
deleted file mode 100644
index 12a4e60..0000000
--- a/internal/typeparams/typeparams.go
+++ /dev/null
@@ -1,134 +0,0 @@
-// Copyright 2021 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-//go:build typeparams && go1.18
-// +build typeparams,go1.18
-
-package typeparams
-
-import (
-	"go/ast"
-	"go/types"
-)
-
-// NOTE: doc comments must be kept in sync with notypeparams.go.
-
-// Enabled reports whether type parameters are enabled in the current build
-// environment.
-const Enabled = true
-
-// GetIndexExprData extracts data from AST nodes that represent index
-// expressions.
-//
-// For an ast.IndexExpr, the resulting IndexExprData will have exactly one
-// index expression. For an ast.IndexListExpr (go1.18+), it may have a
-// variable number of index expressions.
-//
-// For nodes that don't represent index expressions, GetIndexExprData returns
-// nil.
-func GetIndexExprData(n ast.Node) *IndexExprData {
-	switch e := n.(type) {
-	case *ast.IndexExpr:
-		return &IndexExprData{
-			X:       e.X,
-			Lbrack:  e.Lbrack,
-			Indices: []ast.Expr{e.Index},
-			Rbrack:  e.Rbrack,
-		}
-	case *ast.IndexListExpr:
-		return (*IndexExprData)(e)
-	}
-	return nil
-}
-
-// ForTypeDecl extracts the (possibly nil) type parameter node list from n.
-func ForTypeDecl(n *ast.TypeSpec) *ast.FieldList {
-	return n.TypeParams
-}
-
-// ForFuncDecl extracts the (possibly nil) type parameter node list from n.
-func ForFuncDecl(n *ast.FuncDecl) *ast.FieldList {
-	if n.Type != nil {
-		return n.Type.TypeParams
-	}
-	return nil
-}
-
-// ForSignature extracts the (possibly empty) type parameter object list from
-// sig.
-func ForSignature(sig *types.Signature) []*types.TypeName {
-	return tparamsSlice(sig.TypeParams())
-}
-
-// IsComparable reports if iface is the comparable interface.
-func IsComparable(iface *types.Interface) bool {
-	return iface.IsComparable()
-}
-
-// IsConstraint reports whether iface may only be used as a type parameter
-// constraint (i.e. has a type set or is the comparable interface).
-func IsConstraint(iface *types.Interface) bool {
-	return iface.IsConstraint()
-}
-
-// ForNamed extracts the (possibly empty) type parameter object list from
-// named.
-func ForNamed(named *types.Named) []*types.TypeName {
-	return tparamsSlice(named.TypeParams())
-}
-
-func tparamsSlice(tparams *types.TypeParamList) []*types.TypeName {
-	length := tparams.Len()
-	if length == 0 {
-		return nil
-	}
-
-	result := make([]*types.TypeName, length)
-	for i := 0; i < length; i++ {
-		result[i] = tparams.At(i).Obj()
-	}
-
-	return result
-}
-
-// NamedTArgs extracts the (possibly empty) type argument list from named.
-func NamedTArgs(named *types.Named) []types.Type {
-	targs := named.TypeArgs()
-	numArgs := targs.Len()
-
-	typs := make([]types.Type, numArgs)
-	for i := 0; i < numArgs; i++ {
-		typs[i] = targs.At(i)
-	}
-
-	return typs
-}
-
-// InitInferred initializes info to record inferred type information.
-func InitInferred(info *types.Info) {
-	info.Inferred = make(map[ast.Expr]types.Inferred)
-}
-
-// GetInferred extracts inferred type information from info for e.
-//
-// The expression e may have an inferred type if it is an *ast.IndexExpr
-// representing partial instantiation of a generic function type for which type
-// arguments have been inferred using constraint type inference, or if it is an
-// *ast.CallExpr for which type type arguments have be inferred using both
-// constraint type inference and function argument inference.
-func GetInferred(info *types.Info, e ast.Expr) ([]types.Type, *types.Signature) {
-	if info.Inferred == nil {
-		return nil, nil
-	}
-	inf := info.Inferred[e]
-
-	length := inf.TArgs.Len()
-
-	typs := make([]types.Type, length)
-	for i := 0; i < length; i++ {
-		typs[i] = inf.TArgs.At(i)
-	}
-
-	return typs, inf.Sig
-}
diff --git a/internal/typeparams/typeparams_go117.go b/internal/typeparams/typeparams_go117.go
new file mode 100644
index 0000000..d015ee1
--- /dev/null
+++ b/internal/typeparams/typeparams_go117.go
@@ -0,0 +1,164 @@
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+//go:build !go1.18
+// +build !go1.18
+
+package typeparams
+
+import (
+	"go/ast"
+	"go/types"
+)
+
+func unsupported() {
+	panic("type parameters are unsupported at this go version")
+}
+
+// GetIndexExprData extracts data from *ast.IndexExpr nodes.
+// For other nodes, GetIndexExprData returns nil.
+func GetIndexExprData(n ast.Node) *IndexExprData {
+	if e, _ := n.(*ast.IndexExpr); e != nil {
+		return &IndexExprData{
+			X:       e.X,
+			Lbrack:  e.Lbrack,
+			Indices: []ast.Expr{e.Index},
+			Rbrack:  e.Rbrack,
+		}
+	}
+	return nil
+}
+
+// ForTypeDecl returns an empty field list, as type parameters on not supported
+// at this Go version.
+func ForTypeDecl(*ast.TypeSpec) *ast.FieldList {
+	return nil
+}
+
+// ForFuncDecl returns an empty field list, as type parameters are not
+// supported at this Go version.
+func ForFuncDecl(*ast.FuncDecl) *ast.FieldList {
+	return nil
+}
+
+// TypeParam is a placeholder type, as type parameters are not supported at
+// this Go version. Its methods panic on use.
+type TypeParam struct{ types.Type }
+
+// TypeParamList is a placeholder for an empty type parameter list.
+type TypeParamList struct{}
+
+func (*TypeParamList) Len() int          { return 0 }
+func (*TypeParamList) At(int) *TypeParam { unsupported(); return nil }
+
+// TypeList is a placeholder for an empty type list.
+type TypeList struct{}
+
+func (*TypeList) Len() int          { return 0 }
+func (*TypeList) At(int) types.Type { unsupported(); return nil }
+
+// NewTypeParam is unsupported at this Go version, and panics.
+func NewTypeParam(name *types.TypeName, constraint types.Type) *TypeParam {
+	unsupported()
+	return nil
+}
+
+// SetTypeParamConstraint is unsupported at this Go version, and panics.
+func SetTypeParamConstraint(tparam *TypeParam, constraint types.Type) {
+	unsupported()
+}
+
+// ForSignature returns an empty slice.
+func ForSignature(*types.Signature) *TypeParamList {
+	return nil
+}
+
+// SetForSignature panics if tparams is non-empty.
+func SetForSignature(_ *types.Signature, tparams []*TypeParam) {
+	if len(tparams) > 0 {
+		unsupported()
+	}
+}
+
+// RecvTypeParams returns a nil slice.
+func RecvTypeParams(sig *types.Signature) *TypeParamList {
+	return nil
+}
+
+// SetRecvTypeParams panics if rparams is non-empty.
+func SetRecvTypeParams(sig *types.Signature, rparams []*TypeParam) {
+	if len(rparams) > 0 {
+		unsupported()
+	}
+}
+
+// IsComparable returns false, as no interfaces are type-restricted at this Go
+// version.
+func IsComparable(*types.Interface) bool {
+	return false
+}
+
+// IsConstraint returns false, as no interfaces are type-restricted at this Go
+// version.
+func IsConstraint(*types.Interface) bool {
+	return false
+}
+
+// ForNamed returns an empty type parameter list, as type parameters are not
+// supported at this Go version.
+func ForNamed(*types.Named) *TypeParamList {
+	return nil
+}
+
+// SetForNamed panics if tparams is non-empty.
+func SetForNamed(_ *types.Named, tparams []*TypeParam) {
+	if len(tparams) > 0 {
+		unsupported()
+	}
+}
+
+// NamedTypeArgs extracts the (possibly empty) type argument list from named.
+func NamedTypeArgs(*types.Named) []types.Type {
+	return nil
+}
+
+// Term is a placeholder type, as type parameters are not supported at this Go
+// version. Its methods panic on use.
+type Term struct{ types.Type }
+
+// NewTerm is unsupported at this Go version, and panics.
+func NewTerm(tilde bool, typ types.Type) *Term {
+	unsupported()
+	return nil
+}
+
+// Union is a placeholder type, as type parameters are not supported at this Go
+// version. Its methods panic on use.
+type Union struct{ types.Type }
+
+// NewUnion is unsupported at this Go version, and panics.
+func NewUnion(terms []*Term) *Union {
+	unsupported()
+	return nil
+}
+
+// InitInferred is a noop at this Go version.
+func InitInferred(*types.Info) {
+}
+
+// GetInferred returns nothing, as type parameters are not supported at this Go
+// version.
+func GetInferred(*types.Info, ast.Expr) ([]types.Type, *types.Signature) {
+	return nil, nil
+}
+
+// Environment is a placeholder type, as type parameters are not supported at
+// this Go version.
+type Environment struct{}
+
+// Instantiate is unsupported on this Go version, and panics.
+func Instantiate(env *Environment, typ types.Type, targs []types.Type, validate bool) (types.Type, error) {
+	unsupported()
+	return nil, nil
+}
diff --git a/internal/typeparams/typeparams_go118.go b/internal/typeparams/typeparams_go118.go
new file mode 100644
index 0000000..3e808e7
--- /dev/null
+++ b/internal/typeparams/typeparams_go118.go
@@ -0,0 +1,176 @@
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+//go:build go1.18
+// +build go1.18
+
+package typeparams
+
+import (
+	"go/ast"
+	"go/types"
+)
+
+// GetIndexExprData extracts data from AST nodes that represent index
+// expressions.
+//
+// For an ast.IndexExpr, the resulting IndexExprData will have exactly one
+// index expression. For an ast.IndexListExpr (go1.18+), it may have a
+// variable number of index expressions.
+//
+// For nodes that don't represent index expressions, GetIndexExprData returns
+// nil.
+func GetIndexExprData(n ast.Node) *IndexExprData {
+	switch e := n.(type) {
+	case *ast.IndexExpr:
+		return &IndexExprData{
+			X:       e.X,
+			Lbrack:  e.Lbrack,
+			Indices: []ast.Expr{e.Index},
+			Rbrack:  e.Rbrack,
+		}
+	case *ast.IndexListExpr:
+		return (*IndexExprData)(e)
+	}
+	return nil
+}
+
+// ForTypeDecl returns n.TypeParams.
+func ForTypeDecl(n *ast.TypeSpec) *ast.FieldList {
+	return n.TypeParams
+}
+
+// ForFuncDecl returns n.Type.TypeParams.
+func ForFuncDecl(n *ast.FuncDecl) *ast.FieldList {
+	if n.Type != nil {
+		return n.Type.TypeParams
+	}
+	return nil
+}
+
+// TypeParam is an alias for types.TypeParam
+type TypeParam = types.TypeParam
+
+// TypeParamList is an alias for types.TypeParamList
+type TypeParamList = types.TypeParamList
+
+// TypeList is an alias for types.TypeList
+type TypeList = types.TypeList
+
+// NewTypeParam calls types.NewTypeParam.
+func NewTypeParam(name *types.TypeName, constraint types.Type) *TypeParam {
+	return types.NewTypeParam(name, constraint)
+}
+
+// SetTypeParamConstraint calls tparam.SetConstraint(constraint).
+func SetTypeParamConstraint(tparam *TypeParam, constraint types.Type) {
+	tparam.SetConstraint(constraint)
+}
+
+// ForSignature returns sig.TypeParams()
+func ForSignature(sig *types.Signature) *TypeParamList {
+	return sig.TypeParams()
+}
+
+// SetForSignature calls sig.SetTypeParams(tparams)
+func SetForSignature(sig *types.Signature, tparams []*TypeParam) {
+	sig.SetTypeParams(tparams)
+}
+
+// RecvTypeParams returns sig.RecvTypeParams().
+func RecvTypeParams(sig *types.Signature) *TypeParamList {
+	return sig.RecvTypeParams()
+}
+
+// SetRecvTypeParams calls sig.SetRecvTypeParams(rparams).
+func SetRecvTypeParams(sig *types.Signature, rparams []*TypeParam) {
+	sig.SetRecvTypeParams(rparams)
+}
+
+// IsComparable calls iface.IsComparable().
+func IsComparable(iface *types.Interface) bool {
+	return iface.IsComparable()
+}
+
+// IsConstraint calls iface.IsConstraint().
+func IsConstraint(iface *types.Interface) bool {
+	return iface.IsConstraint()
+}
+
+// ForNamed extracts the (possibly empty) type parameter object list from
+// named.
+func ForNamed(named *types.Named) *TypeParamList {
+	return named.TypeParams()
+}
+
+// SetForNamed sets the type params tparams on n. Each tparam must be of
+// dynamic type *types.TypeParam.
+func SetForNamed(n *types.Named, tparams []*TypeParam) {
+	n.SetTypeParams(tparams)
+}
+
+// NamedTypeArgs extracts the (possibly empty) type argument list from named.
+func NamedTypeArgs(named *types.Named) []types.Type {
+	targs := named.TypeArgs()
+	numArgs := targs.Len()
+
+	typs := make([]types.Type, numArgs)
+	for i := 0; i < numArgs; i++ {
+		typs[i] = targs.At(i)
+	}
+
+	return typs
+}
+
+// Term is an alias for types.Term.
+type Term = types.Term
+
+// NewTerm calls types.NewTerm.
+func NewTerm(tilde bool, typ types.Type) *Term {
+	return types.NewTerm(tilde, typ)
+}
+
+// Union is an alias for types.Union
+type Union = types.Union
+
+// NewUnion calls types.NewUnion.
+func NewUnion(terms []*Term) *Union {
+	return types.NewUnion(terms)
+}
+
+// InitInferred initializes info to record inferred type information.
+func InitInferred(info *types.Info) {
+	info.Inferred = make(map[ast.Expr]types.Inferred)
+}
+
+// GetInferred extracts inferred type information from info for e.
+//
+// The expression e may have an inferred type if it is an *ast.IndexExpr
+// representing partial instantiation of a generic function type for which type
+// arguments have been inferred using constraint type inference, or if it is an
+// *ast.CallExpr for which type type arguments have be inferred using both
+// constraint type inference and function argument inference.
+func GetInferred(info *types.Info, e ast.Expr) ([]types.Type, *types.Signature) {
+	if info.Inferred == nil {
+		return nil, nil
+	}
+	inf := info.Inferred[e]
+
+	length := inf.TArgs.Len()
+
+	typs := make([]types.Type, length)
+	for i := 0; i < length; i++ {
+		typs[i] = inf.TArgs.At(i)
+	}
+
+	return typs, inf.Sig
+}
+
+// Environment is an alias for types.Environment.
+type Environment = types.Environment
+
+// Instantiate calls types.Instantiate.
+func Instantiate(env *Environment, typ types.Type, targs []types.Type, validate bool) (types.Type, error) {
+	return types.Instantiate(env, typ, targs, validate)
+}
diff --git a/internal/typeparams/typeparams_test.go b/internal/typeparams/typeparams_test.go
new file mode 100644
index 0000000..9302ad7
--- /dev/null
+++ b/internal/typeparams/typeparams_test.go
@@ -0,0 +1,54 @@
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+//go:build go1.18
+// +build go1.18
+
+package typeparams_test
+
+import (
+	"go/ast"
+	"go/importer"
+	"go/parser"
+	"go/token"
+	"go/types"
+	"testing"
+
+	"golang.org/x/tools/internal/apidiff"
+	"golang.org/x/tools/internal/testenv"
+)
+
+func TestAPIConsistency(t *testing.T) {
+	testenv.NeedsGoBuild(t) // This is a lie. We actually need the source code.
+
+	// The packages below exclude enabled_*.go, as typeparams.Enabled is
+	// permitted to change between versions.
+	old := typeCheck(t, []string{"common.go", "typeparams_go117.go"})
+	new := typeCheck(t, []string{"common.go", "typeparams_go118.go"})
+
+	report := apidiff.Changes(old, new)
+	if len(report.Changes) > 0 {
+		t.Errorf("API diff:\n%s", report)
+	}
+}
+
+func typeCheck(t *testing.T, filenames []string) *types.Package {
+	fset := token.NewFileSet()
+	var files []*ast.File
+	for _, name := range filenames {
+		f, err := parser.ParseFile(fset, name, nil, 0)
+		if err != nil {
+			t.Fatal(err)
+		}
+		files = append(files, f)
+	}
+	conf := types.Config{
+		Importer: importer.Default(),
+	}
+	pkg, err := conf.Check("", fset, files, nil)
+	if err != nil {
+		t.Fatal(err)
+	}
+	return pkg
+}