go/internal/gcimporter: add support for exporting the 1.18 export format

This CL adds support for the Go 1.18 export format to iexport.go. This
support is based on cmd/compile/internal/typecheck/iexport.go, though
with a different types API and adjusted to build at Go versions below
1.18.

Specifically, this CL adds support for both column details in positions,
and generic types and functions. Along the way, some minor adjustments
are made to aid in debugging and testing.

Notably, after this CL the export data version produced by
go/gcexportdata will depend on the Go version used to build.

As part of this change, TestIExportData_stdlib is unskipped for Go 1.18.

Fixes golang/go#48392

Change-Id: I1b218e0acd4864de5c7b89706192273bc7850ffa
Reviewed-on: https://go-review.googlesource.com/c/tools/+/351029
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: Matthew Dempsky <mdempsky@google.com>
diff --git a/go/internal/gcimporter/bexport_test.go b/go/internal/gcimporter/bexport_test.go
index 702278e..116a009 100644
--- a/go/internal/gcimporter/bexport_test.go
+++ b/go/internal/gcimporter/bexport_test.go
@@ -21,6 +21,7 @@
 	"golang.org/x/tools/go/buildutil"
 	"golang.org/x/tools/go/internal/gcimporter"
 	"golang.org/x/tools/go/loader"
+	"golang.org/x/tools/internal/typeparams"
 )
 
 var isRace = false
@@ -230,9 +231,14 @@
 		}
 	case *types.Named:
 		y := y.(*types.Named)
-		if x.String() != y.String() {
+		xOrig := typeparams.NamedTypeOrigin(x)
+		yOrig := typeparams.NamedTypeOrigin(y)
+		if sanitizeName(xOrig.String()) != sanitizeName(yOrig.String()) {
 			return fmt.Errorf("unequal named types: %s vs %s", x, y)
 		}
+		if err := equalTypeArgs(typeparams.NamedTypeArgs(x), typeparams.NamedTypeArgs(y)); err != nil {
+			return fmt.Errorf("type arguments: %s", err)
+		}
 	case *types.Pointer:
 		y := y.(*types.Pointer)
 		if err := equalType(x.Elem(), y.Elem()); err != nil {
@@ -262,6 +268,12 @@
 			// 	return fmt.Errorf("receiver: %s", err)
 			// }
 		}
+		if err := equalTypeParams(typeparams.ForSignature(x), typeparams.ForSignature(y)); err != nil {
+			return fmt.Errorf("type params: %s", err)
+		}
+		if err := equalTypeParams(typeparams.RecvTypeParams(x), typeparams.RecvTypeParams(y)); err != nil {
+			return fmt.Errorf("recv type params: %s", err)
+		}
 	case *types.Slice:
 		y := y.(*types.Slice)
 		if err := equalType(x.Elem(), y.Elem()); err != nil {
@@ -297,10 +309,63 @@
 				return fmt.Errorf("tuple element %d: %s", i, err)
 			}
 		}
+	case *typeparams.TypeParam:
+		y := y.(*typeparams.TypeParam)
+		if sanitizeName(x.String()) != sanitizeName(y.String()) {
+			return fmt.Errorf("unequal named types: %s vs %s", x, y)
+		}
+		// For now, just compare constraints by type string to short-circuit
+		// cycles.
+		xc := sanitizeName(x.Constraint().String())
+		yc := sanitizeName(y.Constraint().String())
+		if xc != yc {
+			return fmt.Errorf("unequal constraints: %s vs %s", xc, yc)
+		}
+
+	default:
+		panic(fmt.Sprintf("unexpected %T type", x))
 	}
 	return nil
 }
 
+func equalTypeArgs(x, y *typeparams.TypeList) error {
+	if x.Len() != y.Len() {
+		return fmt.Errorf("unequal lengths: %d vs %d", x.Len(), y.Len())
+	}
+	for i := 0; i < x.Len(); i++ {
+		if err := equalType(x.At(i), y.At(i)); err != nil {
+			return fmt.Errorf("type %d: %s", i, err)
+		}
+	}
+	return nil
+}
+
+func equalTypeParams(x, y *typeparams.TypeParamList) error {
+	if x.Len() != y.Len() {
+		return fmt.Errorf("unequal lengths: %d vs %d", x.Len(), y.Len())
+	}
+	for i := 0; i < x.Len(); i++ {
+		if err := equalType(x.At(i), y.At(i)); err != nil {
+			return fmt.Errorf("type parameter %d: %s", i, err)
+		}
+	}
+	return nil
+}
+
+// sanitizeName removes type parameter debugging markers from an object
+// or type string, to normalize it for comparison.
+// TODO(rfindley): remove once this is no longer necessary.
+func sanitizeName(name string) string {
+	var runes []rune
+	for _, r := range name {
+		if '₀' <= r && r < '₀'+10 {
+			continue // trim type parameter subscripts
+		}
+		runes = append(runes, r)
+	}
+	return string(runes)
+}
+
 // TestVeryLongFile tests the position of an import object declared in
 // a very long input file.  Line numbers greater than maxlines are
 // reported as line 1, not garbage or token.NoPos.