[dev.go2go] all: merge dev.typeparams (dc122c7) into dev.go2go

This merge resolved all conflicts by taking the dev.typeparams copy. The
only additional changes were to delete exprstring.go,
exprstring_test.go, methodset.go, and walk.go, which had been deleted
from dev.typeparams but were not present in the merge base.

go/build/deps_test.go was updated to allow go2go dependencies.

Change-Id: I2d6da3c1e44a4da888ee71165d5cb3702fec5f88
diff --git a/README.go2go.md b/README.go2go.md
new file mode 100644
index 0000000..6930889
--- /dev/null
+++ b/README.go2go.md
@@ -0,0 +1,36 @@
+# dev.go2go branch
+
+This branch contains a type checker and a translation tool for
+experimentation with generics in Go.
+This implements the [generics design draft](https://go.googlesource.com/proposal/+/refs/heads/master/design/go2draft-type-parameters.md).
+
+You can build this branch [as
+usual](https://golang.org/doc/install/source).
+You can then use the new `go2go` tool.
+Write your generic code in a file with the extension `.go2` instead of
+`.go`.
+Run it using `go tool go2go run x.go2`.
+There are some sample packages in `cmd/go2go/testdata/go2path/src`.
+You can see the full documentation for the tool by running `go doc
+cmd/go2go`.
+
+The `go2go` tool will look for `.go2` files using the environment variable `GO2PATH`.
+You can find some useful packages that you might want to experiment with by
+setting `GO2PATH=$GOROOT/src/cmd/go2go/testdata/go2path`.
+
+If you find bugs in the updated type checker or in the translation
+tool, they should be filed in the [standard Go issue
+tracker](https://golang.org/issue).
+Please start the issue title with `cmd/go2go`.
+Note that the issue tracker should only be used for reporting bugs in
+the tools, not for discussion of changes to the language.
+
+Unlike typical dev branches, we do not intend any eventual merge of
+this code into the master branch.
+We will update it for bug fixes and change to the generic design
+draft.
+If a generics language proposal is accepted, it will be implemented in
+the standard compiler, not via a translation tool.
+The necessary changes to the go/* packages (go/ast, go/parser, and so
+forth) may re-use code from this prototype but will follow the usual
+code review process.
diff --git a/src/cmd/compile/internal/types2/NOTES b/src/cmd/compile/internal/types2/NOTES
new file mode 100644
index 0000000..446b6b6
--- /dev/null
+++ b/src/cmd/compile/internal/types2/NOTES
@@ -0,0 +1,183 @@
+This file serves as a notebook/implementation log.
+
+----------------------------------------------------------------------------------------------------
+TODO (implementation issues)
+
+- report a better error when a type is not in a type list (investigate)
+- better error message when we need parentheses around a parameterized function parameter type
+- review handling of fields of instantiated generic types (do we need to make them non-parameterized,
+  similar to what we did for the embedded interfaces created by contract embedding?)
+- use []*TypeParam for tparams in subst? (unclear)
+- should we use nil instead of &emptyInterface for no type bounds (as an optimization)?
+- TBD: in prose, should we use "generic" or "parameterized" (try to be consistent)
+
+----------------------------------------------------------------------------------------------------
+KNOWN ISSUES
+
+- type parameter constraints are ignored when checking if a parameterized method implements the
+  matching method in an interface
+- iteration over generic variables doesn't report certain channel errors (see TODOs in code)
+- cannot handle mutually recursive parameterized interfaces using themselves as type bounds
+  example: type B(type P B(P)) interface{ m() } (need to delay all checking after seting up declarations)
+- invoking a method of a parameterized embedded type doesn't work (cannot properly determine receiver yet)
+- pointer designation is incorrectly handled when checking type list constraint satisfaction
+
+----------------------------------------------------------------------------------------------------
+OBSERVATIONS
+
+- 2/20/2020: Because we permit parenthesized types anywhere for consistency, also in parameter lists (mea
+  culpa), we have parsing ambiguities when using instantiated types in parameter lists w/o argument names.
+  We could disallow the use of parentheses at the top level of type literals and then we might not have
+  this problem. This is not a backward-compatible change but perhaps worthwhile investigating. Specifically,
+  will this always work (look specifically at channel types where we need parentheses for disambiguation
+  and possibly function types). File a proposal?
+
+- 6/3/2020: Observation: gofmt already removes superflous parentheses around types in parameter lists,
+  so in gofmt'ed code there won't be any such parentheses. Thus we can perhaps make the suggested language
+  change above without too many problems.
+
+- 2/21/2020: We do need top-level parentheses around types in certain situations such as conversions
+  or composite literals. We could disallow parentheses around types in parameter lists only, but that
+  seems quite a bit less elegant.
+
+- 6/13/2020: When comparing against the type list of an interface (to see if the interface is satisfied),
+  we must either recompute the underlying types of the type list entries after the interface was instantiated,
+  or we must compute the underlying type of each entry before comparing. (A type list may contain type
+  parameters which may be substituted with defined types when the interface is instantiated.) With the
+  latter approach (which is what's implemented now), we could relax some of the constraints that we have
+  on type lists entries: We could allow any type and just say that for interface satisfaction we always
+  look at the underlying types.
+
+----------------------------------------------------------------------------------------------------
+OPEN QUESTIONS
+
+- Parsing _ = [](a(int)){} requires parentheses around `(a(int))` - should the parser be smarter in
+  these cases? Another example: []a(b, c){} This cannot be a conversion. Could fix such cases by re-
+  associating the AST when we see a {. Need to be careful, and need to take into account additional
+  complexity of spec.
+- For len/cap(x) where x is of type parameter type and the bound contains arrays only, should the
+  result be a constant? (right now it is not). What are the implications for alternative, non-
+  monomorphizing implementation methods?
+- Confirm that it's ok to use inference in missingMethod to compare parameterized methods.
+
+----------------------------------------------------------------------------------------------------
+DESIGN/IMPLEMENTATION
+
+- 11/19/2019: For type parameters with interface bounds to work, the scope of all type parameters in
+  a type parameter list starts at the "type" keyword. This makes all type parameters visible for all
+  type parameter bounds (interfaces that may be parameterized with the type parameters).
+
+- 12/4/2019: do not allow parenthesized generic uninstantiated types (unless instantiated implicitly)
+  In other words: generic types must always be instantiated before they can be used in any form
+  More generally: Only permit type instantiation T(x) in type context, when the type is a named type.
+  Do not permit it in general in type context: e.g., disallow []T(x) because we consider that a
+  conversion, in general. Same for ([]T)(x).
+
+- 12/12/2019: represent type bounds always as (possibly unnamed) interfaces
+  (contracts are user syntactic sugar)
+
+- 12/19/2019: Type parameters don't act like type aliases. For instance:
+
+        func f(type T1, T2)(x T1) T2 { return x }
+
+  is not valid, no matter how T1 and T2 are instantiated (but if T1 and T2 were type aliases with
+  both of them having type int, the return x would be valid). In fact, the type parameters act more
+  like named types with the methods described by their type bound. But type parameters are never
+  interfaces. To determine: Given a type parameter P, is P == underlying(P) (like for basic types),
+  or is the the underlying type of P something else (like for defined types). Is there an observable
+  difference?
+
+- 12/19/2019: Rewrote contract handling: they are now treated as Objects (rather than Types) throughout.
+
+- 12/20/2019: Decided to start moving type parameters to types (from TypeName to Named), need to do the
+  same for Func. This make more sense as in general any type (conceptually even literal types) could
+  have type parameters. It's a property of the type, not the type name. It also simplified the code.
+
+- 12/20/2019: Type parameters may be part of type lists in contracts/interfaces. It just falls out
+  naturally. Added test cases.
+
+- 12/23/2019: Decision: Type parameters and ordinary (value) parameters are in the same block, notably
+  the function block. The scope of type parameters starts at the 'type' keyword; the scope of ordinary
+  parameters starts with the (opening '{' of the) function body. Both scopes end with the closing '}'
+  of the function body (i.e., the end of the function block).
+
+- 1/2/2020: Implementation decision: contracts can only be declared at the package level.
+
+- 1/6/2020: Experimental: First steps towards permitting type parameters in methods as a generalization.
+  Type-checking problems ooccurring from this are likely to highlight general problematic areas.
+  First consequence: Scope of type parameters starts at "func" keyword which means that receiver type
+  name cannot be a type parameter name declared later (or by the receiver type specification). This
+  seems reasonable and should help avoid confusion which is possible otherwise.
+
+- 1/7/2020: We distinguish embedded instantiated (parameterized) interfaces from methods by enclosing
+  the embedded interfaces in parentheses (the design draft recommends this change). Since this opens
+  the possibility for any parenthesized type (that is an interface), we can also allow (parenthesized)
+  interface literals as it is simpler to permit those than forbid them.
+
+- 1/7/2020: The current implementation permits empty type parameter lists as in: "func f(type)(x int)"
+  but we cannot call such a function as "f()(1)"; the empty type argument list causes problems.
+  Document that we allow empty type parameter list declarations, but not empty actual type parameter
+  lists. (We could allow them for types, but that doesn't seem consistent and probably is confusing).
+
+- 2/19/2020: We accept parenthesized embedded struct fields so we can distinguish between a named
+  field with a parenthesized type foo (T) and an embedded parameterized type (foo(T)), similarly
+  to interace embedding.
+
+- 2/19/2020: Permit parentheses around embedded contracts for symmetry with embedding in structs
+  and interfaces.
+
+- 2/20/2020: Receiver type parameters must always be provided in the receiver parameter list of
+  a method, even if they are not used by the method. Since the receiver acts like an implicit
+  declaration of those type parameters, they may be blank, as with any other declaration.
+
+- 3/20/2020: Local type declarations with an underlying type that is a type parameter lose the
+  methods declared with the type parameter bound. But they don't lose the properties of the
+  underlying type, i.e., the properties of the type parameter bound's type list.
+  This is something to consider if we were contemplating moving to a methods-only approach
+  (no type lists), even though local type declarations are exceedingly rare if they exist at
+  all in the wild.
+
+- 3/24/2020: Implemented initial support for bidirection type unification which could make
+  type inference more powerful if we decided to go that route. Specifically, this would
+  permit type inference for the type parameters of a generic function argument. Given:
+  func h(f func(int)); func g(type T)(T); one could allow the call: h(g) and the type argument
+  T of g would be inferred to be int. While not hard to implement, this would be a special case
+  of the rule that all generic types/functions must be instantiated before they are used except
+  for function calls where the type arguments can be inferred from the actual arguments.
+  Decided that for now we leave things as is, since it's not clear the extra complexity is
+  worth the (probably small) convenience.
+
+- 3/25/2020: We can probably simplify the contract syntax again and only permit one of three
+  possible constraint entries: 1) an embedded contract, 2) a type parameter followed by a
+  method signature, and 3) a type parameter followed by a type list. This is what the type
+  checker currently supports and the printer can print. (The parser still accepts a list of
+  method signatures or types, freely mixed.)
+
+- 4/24/2020: Permit omission of explicit type bound instantiation if the type bound is an
+  interface that applies to exactly one type parameter and the type bound expects exactly
+  one type argument. This makes parameterized interface type bounds easier to use in a common
+  case.
+
+- 5/?/2020: Relaxed above syntactic sugar and permit omission of explicit type bound instantiation
+  in any case where the type bound only accepts a single type parameter.
+  We may not want to permit this in the first version as this is something we can always add later.
+
+- 6/3/2020: A function type parameter acts like a named type. If its type bound has a type list
+  that type list determines the underlying type of the type parameter. If the bound doesn't have
+  a type list, the underlying type of a type parameter is itself. (We may decide that in this
+  latter case there may no underlying type at all which would perhaps more consistent. But this
+  is not clear cut.)
+
+- 6/6/2020: The underlying type of a type parameter must _always_ be itself, otherwise a declaration
+  such as: type T(type P interface{type int}) P would have an underlying type int which is wrong.
+
+- 6/7/2020: Introduced the notion of an operational type which is used when determining what
+  operations are supported by a value of a given type. The operational type of a type parameter
+  is determined by its type bound. The operational type of any other type is its underlying
+  type. This approach appears to complete the picture about the nature of type parameters.
+
+- 6/7/2020: Removed support for contracts to match the latest design draft.
+
+- 6/15/2020: Disabled check that types in type lists must only contain basic types or composite types
+  composed of basic types. It is not needed since we always must recompute the underlying types
+  after a (possible) instantiation anyway (see observation from 6/3/2020).
diff --git a/src/cmd/compile/internal/types2/README b/src/cmd/compile/internal/types2/README
new file mode 100644
index 0000000..8a0c56a
--- /dev/null
+++ b/src/cmd/compile/internal/types2/README
@@ -0,0 +1,68 @@
+This version of go/types is part of the prototype that implements the
+extended Go language as outlined by the latest generics draft design.
+
+DISCLAIMER
+
+This code is based on the std/library's go/types package but it has
+been modified heavily. Please bear in mind that:
+
+- This is a prototype. Expect bugs, incomplete parts, and suboptimal
+  and (gulp) possibly ugly code.
+
+- While all the major aspects of the generics design draft have been
+  implemented, parts are missing, especially around the operations permitted
+  on operands of generic types. In such cases, the result is most often
+  an error reporting that a certain operation is not permitted even though
+  it should be according to the draft design.
+
+- As prototyping continues, expect refinement and possibly divergence
+  from the most recent draft design published.
+
+EXAMPLE CODE
+
+For tests and example code (with detailed comments) look for files
+with suffix .go2 in the testdata and examples subdirectories.
+
+(The suffix .go2 is solely to distinguish them from regular Go code and
+to prevent gofmt from touching them. We expect a proper implementation to
+keep using .go .)
+
+RUNNING THE TYPE-CHECKER
+
+The type-checker is automatically run as part of the go2go tool.
+To experiment with generic code, it is recommened to use that tool.
+
+But the type-checker can also be run stand-alone on source code if
+so desired. There are two primary ways:
+
+1) By building the gotype tool in this source directory:
+
+      go build gotype.go
+
+   and then running the resulting binary on some input files
+
+      ./gotype <package files>
+
+   (Make sure to use the correct go tool when building.)
+
+2) By using the type-checker's TestCheck test function which
+   accepts a list of user provided files:
+
+      go test -run Check$ -errlist -files <package files>
+
+   For instance:
+
+      go test -run Check$ -files examples/types.go2
+
+   TestCheck will match any type errors against ERROR comments
+   in the source files and complain about discrepancies.
+   To report the errors instead, use:
+
+      go test -run Check$ -errlist -files examples/types.go2
+
+   To see a trace of the type checker progress, use the -v flag:
+
+      go test -v -run Check$ -errlist -files examples/types.go2
+
+   (When playing with this code, sometimes go vet gets in the
+   way, so it can be helpful to also provide -vet off.)
diff --git a/src/cmd/go2go/doc.go b/src/cmd/go2go/doc.go
new file mode 100644
index 0000000..c78fd9d
--- /dev/null
+++ b/src/cmd/go2go/doc.go
@@ -0,0 +1,61 @@
+// Copyright 2020 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// go2go is a command for trying out generic Go code.
+// It supports a small number of commands similar to cmd/go.
+//
+// Usage:
+//
+//	go2go [options] <command> [arguments]
+//
+// Commands:
+//
+//      build      translate and then run "go build packages"
+//      run        translate and then run a list of files
+//      test       translate and then run "go test packages"
+//      translate  translate .go2 files into .go files for listed packages
+//
+// A package is expected to contain .go2 files but no .go files.
+//
+// Non-local imported packages will be first looked up using the GO2PATH
+// environment variable, which should point to a GOPATH-like directory.
+// For example, import "x" will first look for GO2PATHDIR/src/x,
+// for each colon-separated component in GO2PATH. If not found in GO2PATH,
+// imports will be looked up in the usual way. If an import includes
+// .go2 files, they will be translated into .go files.
+//
+// There is a sample GO2PATH in cmd/go2go/testdata/go2path. It provides
+// several packages that serve as examples of using generics, and may
+// be useful in experimenting with your own generic code.
+//
+// Translation into standard Go requires generating Go code with mangled names.
+// The mangled names will always include Odia (Oriya) digits, such as ୦ and ୮.
+// Do not use Oriya digits in identifiers in your own code.
+//
+// Because this tool generates Go files, and because instantiated types
+// and functions need to refer to the types with which they are instantiated,
+// using function-local types as type arguments is not supported.
+// Similarly, function-local parameterized types do not work.
+// These are deficiencies of the tool, they will work as expected in
+// any complete implementation.
+//
+// Similarly, generic function and type bodies that refer to unexported,
+// non-generic, names can't be instantiated by different packages.
+//
+// Because this tool generates Go files, and because it generates type
+// and function instantiations alongside other code in the package that
+// instantiates those functions and types, and because those instantiatations
+// may refer to names in packages imported by the original generic code,
+// this tool will add imports as necessary to support the instantiations.
+// Therefore, packages that use generic code must not use top level
+// definitions whose names are the same as the names of packages imported
+// by the generic code. For example, don't write, in package scope,
+//
+//     var strings = []string{"a", "b"}
+//
+// because if the generic code imports "strings", the variable name will
+// conflict with the package name, even if your code doesn't import "strings".
+// This is a deficiency of the tool, it will not be a deficiency in
+// any complete implementation.
+package main
diff --git a/src/cmd/go2go/go2go_test.go b/src/cmd/go2go/go2go_test.go
new file mode 100644
index 0000000..296fa3e
--- /dev/null
+++ b/src/cmd/go2go/go2go_test.go
@@ -0,0 +1,323 @@
+// Copyright 2020 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main_test
+
+import (
+	"fmt"
+	"internal/testenv"
+	"io/ioutil"
+	"os"
+	"os/exec"
+	"path/filepath"
+	"reflect"
+	"runtime"
+	"sort"
+	"strings"
+	"sync"
+	"testing"
+)
+
+func TestMain(m *testing.M) {
+	os.Exit(testMain(m))
+}
+
+func testMain(m *testing.M) int {
+	dir, err := ioutil.TempDir("", "go2gotest")
+	if err != nil {
+		fmt.Fprintln(os.Stderr, err)
+		os.Exit(1)
+	}
+	defer os.RemoveAll(dir)
+	testTempDir = dir
+
+	return m.Run()
+}
+
+// testTempDir is a temporary directory the tests can use.
+var testTempDir string
+
+// testGo2go is the version of cmd/go2go run by the tests.
+var testGo2go string
+
+// testGo2goOnce ensures that testGo2go is built only once.
+var testGo2goOnce sync.Once
+
+// testGo2goErr is an error that occurred when building testGo2go.
+// In the normal case this is nil.
+var testGo2goErr error
+
+// buildGo2go builds an up-to-date version of cmd/go2go.
+// This is not run from TestMain because it's simpler if it has a *testing.T.
+func buildGo2go(t *testing.T) {
+	t.Helper()
+	testenv.MustHaveGoBuild(t)
+	testGo2goOnce.Do(func() {
+		testGo2go = filepath.Join(testTempDir, "go2go.exe")
+		t.Logf("running [go build -o %s]", testGo2go)
+		out, err := exec.Command(testenv.GoToolPath(t), "build", "-o", testGo2go).CombinedOutput()
+		if len(out) > 0 {
+			t.Logf("%s", out)
+		}
+		testGo2goErr = err
+	})
+	if testGo2goErr != nil {
+		t.Fatal("failed to build testgo2go program:", testGo2goErr)
+	}
+}
+
+func TestGO2PATH(t *testing.T) {
+	t.Parallel()
+	buildGo2go(t)
+
+	copyFile := func(path string, info os.FileInfo, err error) error {
+		if err != nil {
+			t.Fatal(err)
+		}
+		newPath := filepath.Join(testTempDir, path)
+		if info.IsDir() {
+			if err := os.MkdirAll(newPath, 0o755); err != nil {
+				t.Fatal(err)
+			}
+			return nil
+		}
+		data, err := ioutil.ReadFile(path)
+		if err != nil {
+			t.Fatal(err)
+		}
+		if err := ioutil.WriteFile(newPath, data, 0o444); err != nil {
+			t.Fatal(err)
+		}
+		return nil
+	}
+
+	if err := filepath.Walk("testdata/go2path/src", copyFile); err != nil {
+		t.Fatal(err)
+	}
+
+	d, err := os.Open(filepath.Join(testTempDir, "testdata/go2path/src"))
+	if err != nil {
+		t.Fatal(err)
+	}
+	defer d.Close()
+	dirs, err := d.Readdirnames(-1)
+	if err != nil {
+		t.Fatal(err)
+	}
+	sort.Strings(dirs)
+
+	for _, dir := range dirs {
+		t.Run(dir, func(t *testing.T) {
+			cmd := exec.Command(testGo2go, "test")
+			cmd.Dir = filepath.Join(testTempDir, "testdata", "go2path", "src", dir)
+			cmd.Env = append(os.Environ(), "GO2PATH="+filepath.Join(testTempDir, "testdata", "go2path"))
+			t.Logf("running [%s test] in %s", testGo2go, cmd.Dir)
+			out, err := cmd.CombinedOutput()
+			if len(out) > 0 {
+				t.Log(dir)
+				t.Logf("%s", out)
+			}
+			if err != nil {
+				t.Errorf("error testing %s: %v", dir, err)
+			}
+		})
+	}
+}
+
+type testFile struct {
+	name, contents string
+}
+
+type testFiles []testFile
+
+func (tfs testFiles) create(t *testing.T, gopath string) {
+	t.Helper()
+	for _, tf := range tfs {
+		fn := filepath.Join(gopath, "src", tf.name)
+		if err := os.MkdirAll(filepath.Dir(fn), 0o755); err != nil {
+			t.Fatal(err)
+		}
+		if err := ioutil.WriteFile(fn, []byte(tf.contents), 0o444); err != nil {
+			t.Fatal(err)
+		}
+	}
+}
+
+func TestGO2PATHEqGOPATH(t *testing.T) {
+	t.Parallel()
+	buildGo2go(t)
+
+	gopath := t.TempDir()
+	testFiles{
+		{
+			"pkg/p.go",
+			`package pkg; func F() {}`,
+		},
+		{
+			"cmd/cmd.go2",
+			`package main; import "pkg"; func main() { pkg.F() }`,
+		},
+	}.create(t, gopath)
+
+	t.Log("go2go build")
+	cmdDir := filepath.Join(gopath, "src", "cmd")
+	cmd := exec.Command(testGo2go, "build")
+	cmd.Dir = cmdDir
+	cmd.Env = append(os.Environ(),
+		"GOPATH="+gopath,
+		"GO2PATH="+gopath,
+		"GO111MODULE=off",
+	)
+	out, err := cmd.CombinedOutput()
+	if len(out) > 0 {
+		t.Logf("%s", out)
+	}
+	if err != nil {
+		t.Fatalf(`error running "go2go build": %v`, err)
+	}
+
+	t.Log("./cmd")
+	cmdName := "./cmd"
+	if runtime.GOOS == "windows" {
+		cmdName += ".exe"
+	}
+	cmd = exec.Command(cmdName)
+	cmd.Dir = cmdDir
+	out, err = cmd.CombinedOutput()
+	if err != nil {
+		t.Fatalf("error running %q: %v", cmdName, err)
+	}
+	if len(out) != 0 {
+		t.Errorf("unexpected output: %q", out)
+	}
+}
+
+const buildSource = `
+package main
+
+import "fmt"
+
+func PrintSlice[Elem any](s []Elem) {
+	for _, v := range s {
+		fmt.Println(v)
+	}
+}
+
+func main() {
+	PrintSlice([]string{"hello", "world"})
+}
+`
+
+func TestBuild(t *testing.T) {
+	t.Parallel()
+	buildGo2go(t)
+
+	gopath := t.TempDir()
+	testFiles{
+		{
+			"hello/hello.go2",
+			buildSource,
+		},
+	}.create(t, gopath)
+
+	t.Log("go2go build")
+	dir := filepath.Join(gopath, "src", "hello")
+	cmd := exec.Command(testGo2go, "build")
+	cmd.Dir = dir
+	out, err := cmd.CombinedOutput()
+	if len(out) > 0 {
+		t.Logf("%s", out)
+	}
+	if err != nil {
+		t.Fatalf(`error running "go2go build": %v`, err)
+	}
+
+	runHello(t, dir)
+}
+
+func runHello(t *testing.T, dir string) {
+	cmdName := "./hello"
+	if runtime.GOOS == "windows" {
+		cmdName += ".exe"
+	}
+	cmd := exec.Command(cmdName)
+	cmd.Dir = dir
+	out, err := cmd.CombinedOutput()
+	t.Log("./hello")
+	if len(out) > 0 {
+		t.Logf("%s", out)
+	}
+	if err != nil {
+		t.Fatalf("error running hello: %v", err)
+	}
+	got := strings.Split(strings.TrimSpace(string(out)), "\n")
+	want := []string{"hello", "world"}
+	if !reflect.DeepEqual(got, want) {
+		t.Errorf("hello output %v, want %v", got, want)
+	}
+}
+
+func TestBuildPackage(t *testing.T) {
+	t.Parallel()
+	buildGo2go(t)
+
+	gopath := t.TempDir()
+	testFiles{
+		{
+			"cmd/hello/hello.go2",
+			buildSource,
+		},
+	}.create(t, gopath)
+
+	t.Log("go2go build")
+	cmd := exec.Command(testGo2go, "build", "cmd/hello")
+	cmd.Dir = gopath
+	cmd.Env = append(os.Environ(),
+		"GO2PATH="+gopath,
+	)
+	out, err := cmd.CombinedOutput()
+	if len(out) > 0 {
+		t.Logf("%s", out)
+	}
+	if err != nil {
+		t.Fatalf(`error running "go2go build": %v`, err)
+	}
+
+	runHello(t, gopath)
+}
+
+func TestTransitiveGo1(t *testing.T) {
+	t.Parallel()
+	buildGo2go(t)
+
+	gopath := t.TempDir()
+	testFiles{
+		{
+			"a/a.go2",
+			`package a; func ident[T any](v T) T { return v }; func F1(v int) int { return ident(v) }`,
+		},
+		{
+			"b/b.go",
+			`package b; import "a"; func F2(v int) int { return a.F1(v) }`,
+		},
+		{
+			"c/c.go2",
+			`package main; import ("fmt"; "b"); func main() { fmt.Println(b.F2(42)) }`,
+		},
+	}.create(t, gopath)
+
+	t.Log("go2go build")
+	cmd := exec.Command(testGo2go, "build", "c")
+	cmd.Dir = gopath
+	cmd.Env = append(os.Environ(),
+		"GO2PATH="+gopath,
+	)
+	out, err := cmd.CombinedOutput()
+	if len(out) > 0 {
+		t.Logf("%s", out)
+	}
+	if err != nil {
+		t.Fatalf(`error running "go2go build": %v`, err)
+	}
+}
diff --git a/src/cmd/go2go/main.go b/src/cmd/go2go/main.go
new file mode 100644
index 0000000..a354361
--- /dev/null
+++ b/src/cmd/go2go/main.go
@@ -0,0 +1,185 @@
+// Copyright 2020 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import (
+	"flag"
+	"fmt"
+	"go/go2go"
+	"io/ioutil"
+	"log"
+	"os"
+	"os/exec"
+	"path/filepath"
+	"runtime"
+	"strings"
+)
+
+var gotool = filepath.Join(runtime.GOROOT(), "bin", "go")
+
+var cmds = map[string]bool{
+	"build":     true,
+	"run":       true,
+	"test":      true,
+	"translate": true,
+}
+
+func main() {
+	flag.Usage = usage
+	flag.Parse()
+
+	args := flag.Args()
+	if len(args) < 1 {
+		usage()
+	}
+
+	if !cmds[args[0]] {
+		usage()
+	}
+
+	importerTmpdir, err := ioutil.TempDir("", "go2go")
+	if err != nil {
+		log.Fatal(err)
+	}
+	defer os.RemoveAll(importerTmpdir)
+
+	importer := go2go.NewImporter(importerTmpdir)
+
+	var rundir string
+	if args[0] == "run" {
+		tmpdir := copyToTmpdir(args[1:])
+		defer os.RemoveAll(tmpdir)
+		translate(importer, tmpdir)
+		nargs := []string{"run"}
+		for _, arg := range args[1:] {
+			base := filepath.Base(arg)
+			f := strings.TrimSuffix(base, ".go2") + ".go"
+			nargs = append(nargs, f)
+		}
+		args = nargs
+		rundir = tmpdir
+	} else if args[0] == "translate" && isGo2Files(args[1:]...) {
+		for _, arg := range args[1:] {
+			translateFile(importer, arg)
+		}
+	} else {
+		for _, dir := range expandPackages(args[1:]) {
+			translate(importer, dir)
+		}
+	}
+
+	if args[0] != "translate" {
+		cmd := exec.Command(gotool, args...)
+		cmd.Stdin = os.Stdin
+		cmd.Stdout = os.Stdout
+		cmd.Stderr = os.Stderr
+		cmd.Dir = rundir
+		gopath := importerTmpdir
+		if go2path := os.Getenv("GO2PATH"); go2path != "" {
+			gopath += string(os.PathListSeparator) + go2path
+		}
+		if oldGopath := os.Getenv("GOPATH"); oldGopath != "" {
+			gopath += string(os.PathListSeparator) + oldGopath
+		}
+		cmd.Env = append(os.Environ(),
+			"GOPATH="+gopath,
+			"GO111MODULE=off",
+		)
+		if err := cmd.Run(); err != nil {
+			die(fmt.Sprintf("%s %v failed: %v", gotool, args, err))
+		}
+	}
+}
+
+// isGo2Files reports whether the arguments are a list of .go2 files.
+func isGo2Files(args ...string) bool {
+	for _, arg := range args {
+		if filepath.Ext(arg) != ".go2" {
+			return false
+		}
+	}
+	return true
+}
+
+// expandPackages returns a list of directories expanded from packages.
+func expandPackages(pkgs []string) []string {
+	if len(pkgs) == 0 {
+		return []string{"."}
+	}
+	go2path := os.Getenv("GO2PATH")
+	var dirs []string
+pkgloop:
+	for _, pkg := range pkgs {
+		if go2path != "" {
+			for _, pd := range strings.Split(go2path, string(os.PathListSeparator)) {
+				d := filepath.Join(pd, "src", pkg)
+				if fi, err := os.Stat(d); err == nil && fi.IsDir() {
+					dirs = append(dirs, d)
+					continue pkgloop
+				}
+			}
+		}
+
+		cmd := exec.Command(gotool, "list", "-f", "{{.Dir}}", pkg)
+		cmd.Stderr = os.Stderr
+		if go2path != "" {
+			gopath := go2path
+			if oldGopath := os.Getenv("GOPATH"); oldGopath != "" {
+				gopath += string(os.PathListSeparator) + oldGopath
+			}
+			cmd.Env = append(os.Environ(),
+				"GOPATH="+gopath,
+				"GO111MODULE=off",
+			)
+		}
+		out, err := cmd.Output()
+		if err != nil {
+			die(fmt.Sprintf("%s list %q failed: %v", gotool, pkg, err))
+		}
+		dirs = append(dirs, strings.Split(string(out), "\n")...)
+	}
+	return dirs
+}
+
+// copyToTmpdir copies files into a temporary directory.
+func copyToTmpdir(files []string) string {
+	if len(files) == 0 {
+		die("no files to run")
+	}
+	tmpdir, err := ioutil.TempDir("", "go2go-run")
+	if err != nil {
+		die(err.Error())
+	}
+	for _, file := range files {
+		data, err := ioutil.ReadFile(file)
+		if err != nil {
+			die(err.Error())
+		}
+		if err := ioutil.WriteFile(filepath.Join(tmpdir, filepath.Base(file)), data, 0444); err != nil {
+			die(err.Error())
+		}
+	}
+	return tmpdir
+}
+
+// usage reports a usage message and exits with failure.
+func usage() {
+	fmt.Fprint(os.Stderr, `Usage: go2go <command> [arguments]
+
+The commands are:
+
+	build      translate and build packages
+	run        translate and run list of files
+	test       translate and test packages
+	translate  translate .go2 files into .go files
+`)
+	os.Exit(2)
+}
+
+// die reports an error and exits.
+func die(msg string) {
+	fmt.Fprintln(os.Stderr, msg)
+	os.Exit(1)
+}
diff --git a/src/cmd/go2go/testdata/go2path/src/alg/alg.go2 b/src/cmd/go2go/testdata/go2path/src/alg/alg.go2
new file mode 100644
index 0000000..c2e48bf
--- /dev/null
+++ b/src/cmd/go2go/testdata/go2path/src/alg/alg.go2
@@ -0,0 +1,24 @@
+// Copyright 2020 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package alg provides basic algorithms.
+package alg
+
+import "constraints"
+
+// Max returns the maximum of two values of some ordered type.
+func Max[T constraints.Ordered](a, b T) T {
+	if a < b {
+		return b
+	}
+	return a
+}
+
+// Min returns the minimum of two values of some ordered type.
+func Min[T constraints.Ordered](a, b T) T {
+	if a < b {
+		return a
+	}
+	return b
+}
diff --git a/src/cmd/go2go/testdata/go2path/src/chans/chans.go2 b/src/cmd/go2go/testdata/go2path/src/chans/chans.go2
new file mode 100644
index 0000000..c5369ab
--- /dev/null
+++ b/src/cmd/go2go/testdata/go2path/src/chans/chans.go2
@@ -0,0 +1,215 @@
+// Copyright 2020 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package chans provides utility functions for working with channels.
+package chans
+
+import (
+	"context"
+	"runtime"
+)
+
+// ReadAll reads from c until the channel is closed or the context is
+// canceled, returning all the values read.
+func ReadAll[Elem any](ctx context.Context, c <-chan Elem) []Elem {
+	var r []Elem
+	for {
+		select {
+		case <-ctx.Done():
+			return r
+		case v, ok := <-c:
+			if !ok {
+				return r
+			}
+			r = append(r, v)
+		}
+	}
+}
+
+// Merge merges two channels into a single channel.
+// This will leave a goroutine running until either both channels are closed
+// or the context is canceled, at which point the returned channel is closed.
+func Merge[Elem any](ctx context.Context, c1, c2 <-chan Elem) <-chan Elem {
+	r := make(chan Elem)
+	go func(ctx context.Context, c1, c2 <-chan Elem, r chan<- Elem) {
+		defer close(r)
+		for c1 != nil || c2 != nil {
+			select {
+			case <-ctx.Done():
+				return
+			case v1, ok := <-c1:
+				if ok {
+					r <- v1
+				} else {
+					c1 = nil
+				}
+			case v2, ok := <-c2:
+				if ok {
+					r <- v2
+				} else {
+					c2 = nil
+				}
+			}
+		}
+	}(ctx, c1, c2, r)
+	return r
+}
+
+// Filter calls f on each value read from c. If f returns true the value
+// is sent on the returned channel. This will leave a goroutine running
+// until c is closed or the context is canceled, at which point the
+// returned channel is closed.
+func Filter[Elem any](ctx context.Context, c <-chan Elem, f func(Elem) bool) <-chan Elem {
+	r := make(chan Elem)
+	go func(ctx context.Context, c <-chan Elem, f func(Elem) bool, r chan<- Elem) {
+		defer close(r)
+		for {
+			select {
+			case <-ctx.Done():
+				return
+			case v, ok := <-c:
+				if !ok {
+					return
+				}
+				if f(v) {
+					r <- v
+				}
+			}
+		}
+	}(ctx, c, f, r)
+	return r
+}
+
+// Sink returns a channel that discards all values sent to it.
+// This will leave a goroutine running until the context is canceled
+// or the returned channel is closed.
+func Sink[Elem any](ctx context.Context) chan<- Elem {
+	r := make(chan Elem)
+	go func(ctx context.Context, r <-chan Elem) {
+		for {
+			select {
+			case <-ctx.Done():
+				return
+			case _, ok := <-r:
+				if !ok {
+					return
+				}
+			}
+		}
+	}(ctx, r)
+	return r
+}
+
+// An Exclusive is a value that may only be used by a single goroutine
+// at a time. This is implemented using channels rather than a mutex.
+type Exclusive[Val any] struct {
+	c chan Val
+}
+
+// MakeExclusive makes an initialized exclusive value.
+func MakeExclusive[Val any](initial Val) *Exclusive[Val] {
+	r := &Exclusive[Val]{
+		c: make(chan Val, 1),
+	}
+	r.c <- initial
+	return r
+}
+
+// Acquire acquires the exclusive value for private use.
+// It must be released using the Release method.
+func (e *Exclusive[Val]) Acquire() Val {
+	return <-e.c
+}
+
+// TryAcquire attempts to acquire the value. The ok result reports whether
+// the value was acquired. If the value is acquired, it must be released
+// using the Release method.
+func (e *Exclusive[Val]) TryAcquire() (v Val, ok bool) {
+	select {
+	case r := <-e.c:
+		return r, true
+	default:
+		return v, false
+	}
+}
+
+// Release updates and releases the value.
+// This method panics if the value has not been acquired.
+func (e *Exclusive[Val]) Release(v Val) {
+	select {
+	case e.c <- v:
+	default:
+		panic("Exclusive Release without Acquire")
+	}
+}
+
+// Ranger returns a Sender and a Receiver. The Receiver provides a
+// Next method to retrieve values. The Sender provides a Send method
+// to send values and a Close method to stop sending values. The Next
+// method indicates when the Sender has been closed, and the Send
+// method indicates when the Receiver has been freed.
+//
+// This is a convenient way to exit a goroutine sending values when
+// the receiver stops reading them.
+func Ranger[Elem any]() (*Sender[Elem], *Receiver[Elem]) {
+	c := make(chan Elem)
+	d := make(chan struct{})
+	s := &Sender[Elem]{
+		values: c,
+		done:   d,
+	}
+	r := &Receiver[Elem] {
+		values: c,
+		done:   d,
+	}
+	runtime.SetFinalizer(r, (*Receiver[Elem]).finalize)
+	return s, r
+}
+
+// A Sender is used to send values to a Receiver.
+type Sender[Elem any] struct {
+	values chan<- Elem
+	done   <-chan struct{}
+}
+
+// Send sends a value to the receiver. It reports whether the value was sent.
+// The value will not be sent if the context is closed or the receiver
+// is freed.
+func (s *Sender[Elem]) Send(ctx context.Context, v Elem) bool {
+	select {
+	case <-ctx.Done():
+		return false
+	case s.values <- v:
+		return true
+	case <-s.done:
+		return false
+	}
+}
+
+// Close tells the receiver that no more values will arrive.
+// After Close is called, the Sender may no longer be used.
+func (s *Sender[Elem]) Close() {
+	close(s.values)
+}
+
+// A Receiver receives values from a Sender.
+type Receiver[Elem any] struct {
+	values <-chan Elem
+	done   chan<- struct{}
+}
+
+// Next returns the next value from the channel. The bool result indicates
+// whether the value is valid.
+func (r *Receiver[Elem]) Next(ctx context.Context) (v Elem, ok bool) {
+	select {
+	case <-ctx.Done():
+	case v, ok = <-r.values:
+	}
+	return v, ok
+}
+
+// finalize is a finalizer for the receiver.
+func (r *Receiver[Elem]) finalize() {
+	close(r.done)
+}
diff --git a/src/cmd/go2go/testdata/go2path/src/chans/chans_test.go2 b/src/cmd/go2go/testdata/go2path/src/chans/chans_test.go2
new file mode 100644
index 0000000..8bafbc9
--- /dev/null
+++ b/src/cmd/go2go/testdata/go2path/src/chans/chans_test.go2
@@ -0,0 +1,180 @@
+// Copyright 2020 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package chans
+
+import (
+	"context"
+	"runtime"
+	"sort"
+	"sync"
+	"testing"
+	"time"
+
+	"slices"
+)
+
+func TestReadAll(t *testing.T) {
+	c := make(chan int)
+	go func() {
+		c <- 4
+		c <- 2
+		c <- 5
+		close(c)
+	}()
+	got := ReadAll(context.Background(), c)
+	want := []int{4, 2, 5}
+	if !slices.Equal(got, want) {
+		t.Errorf("ReadAll returned %v, want %v", got, want)
+	}
+}
+
+func TestMerge(t *testing.T) {
+	c1 := make(chan int)
+	c2 := make(chan int)
+	go func() {
+		c1 <- 1
+		c1 <- 3
+		c1 <- 5
+		close(c1)
+	}()
+	go func() {
+		c2 <- 2
+		c2 <- 4
+		c2 <- 6
+		close(c2)
+	}()
+	ctx := context.Background()
+	got := ReadAll(ctx, Merge(ctx, c1, c2))
+	sort.Ints(got)
+	want := []int{1, 2, 3, 4, 5, 6}
+	if !slices.Equal(got, want) {
+		t.Errorf("Merge returned %v, want %v", got, want)
+	}
+}
+
+func TestFilter(t *testing.T) {
+	c := make(chan int)
+	go func() {
+		c <- 1
+		c <- 2
+		c <- 3
+		close(c)
+	}()
+	even := func(i int) bool { return i%2 == 0 }
+	ctx := context.Background()
+	got := ReadAll(ctx, Filter(ctx, c, even))
+	want := []int{2}
+	if !slices.Equal(got, want) {
+		t.Errorf("Filter returned %v, want %v", got, want)
+	}
+}
+
+func TestSink(t *testing.T) {
+	c := Sink(int)(context.Background())
+	after := time.NewTimer(time.Minute)
+	defer after.Stop()
+	send := func(v int) {
+		select {
+		case c <- v:
+		case <-after.C:
+			t.Error("timed out sending to Sink")
+		}
+	}
+	send(1)
+	send(2)
+	send(3)
+	close(c)
+}
+
+func TestExclusive(t *testing.T) {
+	val := 0
+	ex := MakeExclusive(&val)
+
+	var wg sync.WaitGroup
+	f := func() {
+		defer wg.Done()
+		for i := 0; i < 10; i++ {
+			p := ex.Acquire()
+			(*p)++
+			ex.Release(p)
+		}
+	}
+
+	wg.Add(2)
+	go f()
+	go f()
+
+	wg.Wait()
+	if val != 20 {
+		t.Errorf("after Acquire/Release loop got %d, want 20", val)
+	}
+}
+
+func TestExclusiveTry(t *testing.T) {
+	s := ""
+	ex := MakeExclusive(&s)
+	p, ok := ex.TryAcquire()
+	if !ok {
+		t.Fatalf("TryAcquire failed")
+	}
+	*p = "a"
+
+	var wg sync.WaitGroup
+	wg.Add(1)
+	go func() {
+		defer wg.Done()
+		_, ok := ex.TryAcquire()
+		if ok {
+			t.Errorf("TryAcquire succeeded unexpectedly")
+		}
+	}()
+	wg.Wait()
+
+	ex.Release(p)
+
+	p, ok = ex.TryAcquire()
+	if !ok {
+		t.Errorf("TryAcquire failed")
+	}
+}
+
+func TestRanger(t *testing.T) {
+	s, r := Ranger(int)()
+
+	ctx := context.Background()
+	go func() {
+		// Receive one value then exit.
+		v, ok := r.Next(ctx)
+		if !ok {
+			t.Errorf("did not receive any values")
+		} else if v != 1 {
+			t.Errorf("received %d, want 1", v)
+		}
+	}()
+
+	c1 := make(chan bool)
+	c2 := make(chan bool)
+	go func() {
+		defer close(c2)
+		if !s.Send(ctx, 1) {
+			t.Errorf("Send failed unexpectedly")
+		}
+		close(c1)
+		if s.Send(ctx, 2) {
+			t.Errorf("Send succeeded unexpectedly")
+		}
+	}()
+
+	<-c1
+
+	// Force a garbage collection to try to get the finalizers to run.
+	runtime.GC()
+
+	select {
+	case <-c2:
+	case <-time.After(time.Minute):
+		t.Error("Ranger Send should have failed, but timed out")
+	}
+}
diff --git a/src/cmd/go2go/testdata/go2path/src/constraints/constraints.go2 b/src/cmd/go2go/testdata/go2path/src/constraints/constraints.go2
new file mode 100644
index 0000000..ee757c4
--- /dev/null
+++ b/src/cmd/go2go/testdata/go2path/src/constraints/constraints.go2
@@ -0,0 +1,31 @@
+// Copyright 2020 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package constraints defines some useful type constraints.
+package constraints
+
+// Ordered permits any ordered type: any type that supports
+// the operations <, <=, >=, >, as well as == and !=.
+type Ordered interface {
+	type int, int8, int16, int32, int64,
+		uint, uint8, uint16, uint32, uint64, uintptr,
+		float32, float64,
+		string
+}
+
+// Integer permits any integer type.
+type Integer interface {
+	type int, int8, int16, int32, int64,
+		uint, uint8, uint16, uint32, uint64, uintptr
+}
+
+// Signed permits any signed integer type.
+type Signed interface {
+	type int, int8, int16, int32, int64
+}
+
+// Unsigned permits any unsigned integer type.
+type Unsigned interface {
+	type uint, uint8, uint16, uint32, uint64, uintptr
+}
diff --git a/src/cmd/go2go/testdata/go2path/src/graph/graph.go2 b/src/cmd/go2go/testdata/go2path/src/graph/graph.go2
new file mode 100644
index 0000000..ed90281
--- /dev/null
+++ b/src/cmd/go2go/testdata/go2path/src/graph/graph.go2
@@ -0,0 +1,72 @@
+// Copyright 2020 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package graph implements general purpose graph algorithms.
+package graph
+
+import "errors"
+
+// A Graph is a collection of nodes. A node may have an arbitrary number
+// of edges. An edge connects two nodes. Both nodes and edges must be
+// comparable. This is an undirected simple graph.
+type Graph[Node NodeC[Edge], Edge EdgeC[Node]] struct {
+	nodes []Node
+}
+
+// NodeC is the contraints on a node in a graph, given the Edge type.
+type NodeC[Edge any] interface {
+	comparable
+	Edges() []Edge
+}
+
+// Edgec is the constraints on an edge in a graph, given the Node type.
+type EdgeC[Node any] interface {
+	comparable
+	Nodes() (a, b Node)
+}
+
+// New creates a new Graph from a collection of Nodes.
+func New[Node NodeC[Edge], Edge EdgeC[Node]](nodes []Node) *Graph[Node, Edge] {
+	return &Graph[Node, Edge]{nodes: nodes}
+}
+
+// nodePath holds the path to a node during ShortestPath.
+// This should ideally be a type defined inside ShortestPath,
+// but the translator tool doesn't support that.
+type nodePath[Node NodeC[Edge], Edge EdgeC[Node]] struct {
+	node Node
+	path []Edge
+}
+
+// ShortestPath returns the shortest path between two nodes,
+// as an ordered list of edges. If there are multiple shortest paths,
+// which one is returned is unpredictable.
+func (g *Graph[Node, Edge]) ShortestPath(from, to Node) ([]Edge, error) {
+	visited := make(map[Node]bool)
+	visited[from] = true
+	workqueue := []nodePath[Node, Edge]{nodePath[Node, Edge]{from, nil}}
+	for len(workqueue) > 0 {
+		current := workqueue
+		workqueue = nil
+		for _, np := range current {
+			edges := np.node.Edges()
+			for _, edge := range edges {
+				a, b := edge.Nodes()
+				if a == np.node {
+					a = b
+				}
+				if !visited[a] {
+					ve := append([]Edge(nil), np.path...)
+					ve = append(ve, edge)
+					if a == to {
+						return ve, nil
+					}
+					workqueue = append(workqueue, nodePath[Node, Edge]{a, ve})
+					visited[a] = true
+				}
+			}
+		}
+	}
+	return nil, errors.New("no path")
+}
diff --git a/src/cmd/go2go/testdata/go2path/src/graph/graph_test.go2 b/src/cmd/go2go/testdata/go2path/src/graph/graph_test.go2
new file mode 100644
index 0000000..c36fc52
--- /dev/null
+++ b/src/cmd/go2go/testdata/go2path/src/graph/graph_test.go2
@@ -0,0 +1,143 @@
+// Copyright 2020 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package graph
+
+import (
+	"fmt"
+	"testing"
+
+	"slices"
+)
+
+type direction int
+
+const (
+	north direction = iota
+	ne
+	east
+	se
+	south
+	sw
+	west
+	nw
+	up
+	down
+)
+
+func (dir direction) String() string {
+	strs := map[direction]string{
+		north: "north",
+		ne:    "ne",
+		east:  "east",
+		se:    "se",
+		south: "south",
+		sw:    "sw",
+		west:  "west",
+		nw:    "nw",
+		up:    "up",
+		down:  "down",
+	}
+	if str, ok := strs[dir]; ok {
+		return str
+	}
+	return fmt.Sprintf("direction %d", dir)
+}
+
+type mazeRoom struct {
+	index int
+	exits [10]int
+}
+
+type mazeEdge struct {
+	from, to int
+	dir      direction
+}
+
+// Edges returns the exits from the room.
+func (m mazeRoom) Edges() []mazeEdge {
+	var r []mazeEdge
+	for i, exit := range m.exits {
+		if exit != 0 {
+			r = append(r, mazeEdge{
+				from: m.index,
+				to:   exit,
+				dir:  direction(i),
+			})
+		}
+	}
+	return r
+}
+
+// Nodes returns the rooms connected by an edge.
+func (e mazeEdge) Nodes() (mazeRoom, mazeRoom) {
+	m1, ok := zork[e.from]
+	if !ok {
+		panic("bad edge")
+	}
+	m2, ok := zork[e.to]
+	if !ok {
+		panic("bad edge")
+	}
+	return m1, m2
+}
+
+// The first maze in Zork. Room indexes based on original Fortran data file.
+// You are in a maze of twisty little passages, all alike.
+var zork = map[int]mazeRoom{
+	11: {exits: [10]int{north: 11, south: 12, east: 14}}, // west to Troll Room
+	12: {exits: [10]int{south: 11, north: 14, east: 13}},
+	13: {exits: [10]int{west: 12, north: 14, up: 16}},
+	14: {exits: [10]int{west: 13, north: 11, east: 15}},
+	15: {exits: [10]int{south: 14}},                   // Dead End
+	16: {exits: [10]int{east: 17, north: 13, sw: 18}}, // skeleton, etc.
+	17: {exits: [10]int{west: 16}},                    // Dead End
+	18: {exits: [10]int{down: 16, east: 19, west: 18, up: 22}},
+	19: {exits: [10]int{up: 29, west: 18, ne: 15, east: 20, south: 30}},
+	20: {exits: [10]int{ne: 19, west: 20, se: 21}},
+	21: {exits: [10]int{north: 20}}, // Dead End
+	22: {exits: [10]int{north: 18, east: 24, down: 23, south: 28, west: 26, nw: 22}},
+	23: {exits: [10]int{east: 22, west: 28, up: 24}},
+	24: {exits: [10]int{ne: 25, down: 23, nw: 28, sw: 26}},
+	25: {exits: [10]int{sw: 24}}, // Grating room (up to Clearing)
+	26: {exits: [10]int{west: 16, sw: 24, east: 28, up: 22, north: 27}},
+	27: {exits: [10]int{south: 26}}, // Dead End
+	28: {exits: [10]int{east: 22, down: 26, south: 23, west: 24}},
+	29: {exits: [10]int{west: 30, nw: 29, ne: 19, south: 19}},
+	30: {exits: [10]int{west: 29, south: 19}}, // ne to Cyclops Room
+}
+
+func TestShortestPath(t *testing.T) {
+	// The Zork maze is not a proper undirected simple graph,
+	// as there are some one way paths (e.g., 19 -> 15),
+	// but for this test that doesn't matter.
+
+	// Set the index field in the map. Simpler than doing it in the
+	// composite literal.
+	for k := range zork {
+		r := zork[k]
+		r.index = k
+		zork[k] = r
+	}
+
+	var nodes []mazeRoom
+	for idx, room := range zork {
+		mridx := room
+		mridx.index = idx
+		nodes = append(nodes, mridx)
+	}
+	g := New[mazeRoom, mazeEdge](nodes)
+	path, err := g.ShortestPath(zork[11], zork[30])
+	if err != nil {
+		t.Fatal(err)
+	}
+	var steps []direction
+	for _, edge := range path {
+		steps = append(steps, edge.dir)
+	}
+	want := []direction{east, west, up, sw, east, south}
+	if !slices.Equal(steps, want) {
+		t.Errorf("ShortestPath returned %v, want %v", steps, want)
+	}
+}
diff --git a/src/cmd/go2go/testdata/go2path/src/gsort/gsort.go2 b/src/cmd/go2go/testdata/go2path/src/gsort/gsort.go2
new file mode 100644
index 0000000..5d4301a
--- /dev/null
+++ b/src/cmd/go2go/testdata/go2path/src/gsort/gsort.go2
@@ -0,0 +1,51 @@
+// Copyright 2020 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package gsort provides primitives for sorting slices of any type.
+package gsort
+
+import (
+	"sort"
+
+	"constraints"
+)
+
+// orderedSlice is a slice of values of some ordered type.
+type orderedSlice[Elem constraints.Ordered] []Elem
+
+// orderedSlice implements sort.Interface.
+
+func (s orderedSlice[Elem]) Len() int           { return len(s) }
+func (s orderedSlice[Elem]) Less(i, j int) bool {
+	if s[i] < s[j] {
+		return true
+	}
+	isNaN := func(f Elem) bool { return f != f }
+	if isNaN(s[i]) && !isNaN(s[j]) {
+		return true
+	}
+	return false
+}
+func (s orderedSlice[Elem]) Swap(i, j int)      { s[i], s[j] = s[j], s[i] }
+
+// OrderedSlice sorts a slice of any ordered type in ascending order.
+func OrderedSlice[Elem constraints.Ordered](s []Elem) {
+	sort.Sort(orderedSlice[Elem](s))
+}
+
+// sliceFn implements sort.Interface for a slice of any type with an
+// explicit less-than function.
+type sliceFn[Elem any] struct {
+	s    []Elem
+	less func(Elem, Elem) bool
+}
+
+func (s sliceFn[Elem]) Len() int           { return len(s.s) }
+func (s sliceFn[Elem]) Less(i, j int) bool { return s.less(s.s[i], s.s[j]) }
+func (s sliceFn[Elem]) Swap(i, j int)      { s.s[i], s.s[j] = s.s[j], s.s[i] }
+
+// SliceFn sorts a slice of any type according to a less-than function.
+func SliceFn[Elem any](s []Elem, less func(Elem, Elem) bool) {
+	sort.Sort(sliceFn[Elem]{s, less})
+}
diff --git a/src/cmd/go2go/testdata/go2path/src/gsort/gsort_test.go2 b/src/cmd/go2go/testdata/go2path/src/gsort/gsort_test.go2
new file mode 100644
index 0000000..a7bb157
--- /dev/null
+++ b/src/cmd/go2go/testdata/go2path/src/gsort/gsort_test.go2
@@ -0,0 +1,92 @@
+// Copyright 2020 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package gsort
+
+import (
+	"math"
+	"sort"
+	"testing"
+
+	"constraints"
+	"slices"
+)
+
+// Test data copied from the standard library sort package.
+
+var ints = []int{74, 59, 238, -784, 9845, 959, 905, 0, 0, 42, 7586, -5467984, 7586}
+var float64s = []float64{74.3, 59.0, math.Inf(1), 238.2, -784.0, 2.3, math.NaN(), math.NaN(), math.Inf(-1), 9845.768, -959.7485, 905, 7.8, 7.8}
+var strs = []string{"", "Hello", "foo", "bar", "foo", "f00", "%*&^*&^&", "***"}
+
+func TestSortOrderedInts(t *testing.T) {
+	testOrdered(t, ints, sort.Ints)
+}
+
+func TestSortOrderedFloat64s(t *testing.T) {
+	testOrdered(t, float64s, sort.Float64s)
+}
+
+func TestSortOrderedStrings(t *testing.T) {
+	testOrdered(t, strs, sort.Strings)
+}
+
+func testOrdered[Elem constraints.Ordered](t *testing.T, s []Elem, sorter func([]Elem)) {
+	s1 := make([]Elem, len(s))
+	copy(s1, s)
+	s2 := make([]Elem, len(s))
+	copy(s2, s)
+	OrderedSlice(s1)
+	sorter(s2)
+	if !slices.Equal(s1, s2) {
+		t.Fatalf("got %v, want %v", s1, s2)
+	}
+	for i := len(s1) - 1; i > 0; i-- {
+		if s1[i] < s1[i-1] {
+			t.Fatalf("element %d (%v) < element %d (%v)", i, s1[i], i - 1, s1[i - 1])
+		}
+	}
+}
+
+var slicesToSort = [][]int {
+	[]int{1, 2},
+	[]int{3, 2, 1},
+	[]int{1},
+	[]int{1, 3},
+	[]int{1, 2, 3},
+}
+
+var sortedSlices = [][]int {
+	[]int{1},
+	[]int{1, 2},
+	[]int{1, 3},
+	[]int{1, 2, 3},
+	[]int{3, 2, 1},
+}
+
+func sorter(s1, s2 []int) bool {
+	switch {
+	case len(s1) < len(s2):
+		return true
+	case len(s1) > len(s2):
+		return false
+	}
+	for i := range s1 {
+		switch {
+		case s1[i] < s2[i]:
+			return true
+		case s1[i] > s2[i]:
+			return false
+		}
+	}
+	return false
+}
+
+func TestSortSliceFn(t *testing.T) {
+	c := make([][]int, len(slicesToSort))
+	copy(c, slicesToSort)
+	SliceFn(c, sorter)
+	if !slices.EqualFn(c, sortedSlices, func(a, b []int) bool { return slices.Equal(int)(a, b) }) {
+		t.Errorf("got %v, want %v", c, sortedSlices)
+	}
+}
diff --git a/src/cmd/go2go/testdata/go2path/src/list/list.go2 b/src/cmd/go2go/testdata/go2path/src/list/list.go2
new file mode 100644
index 0000000..2740fd4
--- /dev/null
+++ b/src/cmd/go2go/testdata/go2path/src/list/list.go2
@@ -0,0 +1,244 @@
+// Copyright 2020 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package list provides a doubly linked list of some element type.
+package list
+
+// FIXME: This should probably be in container/list,
+// perhaps with different type names.
+
+// Element is an element of a linked list.
+type Element[TElem any] struct {
+	// Next and previous pointers in the doubly-linked list of elements.
+	// To simplify the implementation, internally a list l is implemented
+	// as a ring, such that &l.root is both the next element of the last
+	// list element (l.Back()) and the previous element of the first list
+	// element (l.Front()).
+	next, prev *Element[TElem]
+
+	// The list to which this element belongs.
+	list *List[TElem]
+
+	// The value stored with this element.
+	Value TElem
+}
+
+// Next returns the next list element or nil.
+func (e *Element[TElem]) Next() *Element[TElem] {
+	if p := e.next; e.list != nil && p != &e.list.root {
+		return p
+	}
+	return nil
+}
+
+// Prev returns the previous list element or nil.
+func (e *Element[TElem]) Prev() *Element[TElem] {
+	if p := e.prev; e.list != nil && p != &e.list.root {
+		return p
+	}
+	return nil
+}
+
+// List represents a doubly linked list.
+// The zero value for List is an empty list ready to use.
+type List[TElem any] struct {
+	root Element[TElem] // sentinel list element, only &root, root.prev, and root.next are used
+	len  int     // current list length excluding (this) sentinel element
+}
+
+// Init initializes or clears list l.
+func (l *List[TElem]) Init() *List[TElem] {
+	l.root.next = &l.root
+	l.root.prev = &l.root
+	l.len = 0
+	return l
+}
+
+// New returns an initialized list.
+func New[TElem any]() *List[TElem] { return new(List[TElem]).Init() }
+
+// Len returns the number of elements of list l.
+// The complexity is O(1).
+func (l *List[TElem]) Len() int { return l.len }
+
+// Front returns the first element of list l or nil if the list is empty.
+func (l *List[TElem]) Front() *Element[TElem] {
+	if l.len == 0 {
+		return nil
+	}
+	return l.root.next
+}
+
+// Back returns the last element of list l or nil if the list is empty.
+func (l *List[TElem]) Back() *Element[TElem] {
+	if l.len == 0 {
+		return nil
+	}
+	return l.root.prev
+}
+
+// lazyInit lazily initializes a zero List value.
+func (l *List[TElem]) lazyInit() {
+	if l.root.next == nil {
+		l.Init()
+	}
+}
+
+// insert inserts e after at, increments l.len, and returns e.
+func (l *List[TElem]) insert(e, at *Element[TElem]) *Element[TElem] {
+	e.prev = at
+	e.next = at.next
+	e.prev.next = e
+	e.next.prev = e
+	e.list = l
+	l.len++
+	return e
+}
+
+// insertValue is a convenience wrapper for insert(&Element[TElem]{Value: v}, at).
+func (l *List[TElem]) insertValue(v TElem, at *Element[TElem]) *Element[TElem] {
+	return l.insert(&Element[TElem]{Value: v}, at)
+}
+
+// remove removes e from its list, decrements l.len, and returns e.
+func (l *List[TElem]) remove(e *Element[TElem]) *Element[TElem] {
+	e.prev.next = e.next
+	e.next.prev = e.prev
+	e.next = nil // avoid memory leaks
+	e.prev = nil // avoid memory leaks
+	e.list = nil
+	l.len--
+	return e
+}
+
+// move moves e to next to at and returns e.
+func (l *List[TElem]) move(e, at *Element[TElem]) *Element[TElem] {
+	if e == at {
+		return e
+	}
+	e.prev.next = e.next
+	e.next.prev = e.prev
+
+	e.prev = at
+	e.next = at.next
+	e.prev.next = e
+	e.next.prev = e
+
+	return e
+}
+
+// Remove removes e from l if e is an element of list l.
+// It returns the element value e.Value.
+// The element must not be nil.
+func (l *List[TElem]) Remove(e *Element[TElem]) TElem {
+	if e.list == l {
+		// if e.list == l, l must have been initialized when e was inserted
+		// in l or l == nil (e is a zero Element) and l.remove will crash
+		l.remove(e)
+	}
+	return e.Value
+}
+
+// PushFront inserts a new element e with value v at the front of list l and returns e.
+func (l *List[TElem]) PushFront(v TElem) *Element[TElem] {
+	l.lazyInit()
+	return l.insertValue(v, &l.root)
+}
+
+// PushBack inserts a new element e with value v at the back of list l and returns e.
+func (l *List[TElem]) PushBack(v TElem) *Element[TElem] {
+	l.lazyInit()
+	return l.insertValue(v, l.root.prev)
+}
+
+// InsertBefore inserts a new element e with value v immediately before mark and returns e.
+// If mark is not an element of l, the list is not modified.
+// The mark must not be nil.
+func (l *List[TElem]) InsertBefore(v TElem, mark *Element[TElem]) *Element[TElem] {
+	if mark.list != l {
+		return nil
+	}
+	// see comment in List.Remove about initialization of l
+	return l.insertValue(v, mark.prev)
+}
+
+// InsertAfter inserts a new element e with value v immediately after mark and returns e.
+// If mark is not an element of l, the list is not modified.
+// The mark must not be nil.
+func (l *List[TElem]) InsertAfter(v TElem, mark *Element[TElem]) *Element[TElem] {
+	if mark.list != l {
+		return nil
+	}
+	// see comment in List.Remove about initialization of l
+	return l.insertValue(v, mark)
+}
+
+// MoveToFront moves element e to the front of list l.
+// If e is not an element of l, the list is not modified.
+// The element must not be nil.
+func (l *List[TElem]) MoveToFront(e *Element[TElem]) {
+	if e.list != l || l.root.next == e {
+		return
+	}
+	// see comment in List.Remove about initialization of l
+	l.move(e, &l.root)
+}
+
+// MoveToBack moves element e to the back of list l.
+// If e is not an element of l, the list is not modified.
+// The element must not be nil.
+func (l *List[TElem]) MoveToBack(e *Element[TElem]) {
+	if e.list != l || l.root.prev == e {
+		return
+	}
+	// see comment in List.Remove about initialization of l
+	l.move(e, l.root.prev)
+}
+
+// MoveBefore moves element e to its new position before mark.
+// If e or mark is not an element of l, or e == mark, the list is not modified.
+// The element and mark must not be nil.
+func (l *List[TElem]) MoveBefore(e, mark *Element[TElem]) {
+	if e.list != l || e == mark || mark.list != l {
+		return
+	}
+	l.move(e, mark.prev)
+}
+
+// MoveAfter moves element e to its new position after mark.
+// If e or mark is not an element of l, or e == mark, the list is not modified.
+// The element and mark must not be nil.
+func (l *List[TElem]) MoveAfter(e, mark *Element[TElem]) {
+	if e.list != l || e == mark || mark.list != l {
+		return
+	}
+	l.move(e, mark)
+}
+
+// PushBackList inserts a copy of an other list at the back of list l.
+// The lists l and other may be the same. They must not be nil.
+func (l *List[TElem]) PushBackList(other *List[TElem]) {
+	l.lazyInit()
+	for i, e := other.Len(), other.Front(); i > 0; i, e = i-1, e.Next() {
+		l.insertValue(e.Value, l.root.prev)
+	}
+}
+
+// PushFrontList inserts a copy of an other list at the front of list l.
+// The lists l and other may be the same. They must not be nil.
+func (l *List[TElem]) PushFrontList(other *List[TElem]) {
+	l.lazyInit()
+	for i, e := other.Len(), other.Back(); i > 0; i, e = i-1, e.Prev() {
+		l.insertValue(e.Value, &l.root)
+	}
+}
+
+// Transform runs a transform function on a list returning a new list.
+func Transform[TElem1, TElem2 any](lst *List[TElem1], f func(TElem1) TElem2) *List[TElem2] {
+	ret := New[TElem2]()
+	for p := lst.Front(); p != nil; p = p.Next() {
+		ret.PushBack(f(p.Value))
+	}
+	return ret
+}
diff --git a/src/cmd/go2go/testdata/go2path/src/list/list_test.go2 b/src/cmd/go2go/testdata/go2path/src/list/list_test.go2
new file mode 100644
index 0000000..0671c76
--- /dev/null
+++ b/src/cmd/go2go/testdata/go2path/src/list/list_test.go2
@@ -0,0 +1,354 @@
+// Copyright 2020 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package list
+
+import (
+	"strconv"
+	"testing"
+)
+
+func checkListLen[TElem any](t *testing.T, l *List[TElem], len int) bool {
+	if n := l.Len(); n != len {
+		t.Errorf("l.Len() = %d, want %d", n, len)
+		return false
+	}
+	return true
+}
+
+func checkListPointers[TElem any](t *testing.T, l *List[TElem], es []*Element[TElem]) {
+	root := &l.root
+
+	if !checkListLen(t, l, len(es)) {
+		return
+	}
+
+	// zero length lists must be the zero value or properly initialized (sentinel circle)
+	if len(es) == 0 {
+		if l.root.next != nil && l.root.next != root || l.root.prev != nil && l.root.prev != root {
+			t.Errorf("l.root.next = %p, l.root.prev = %p; both should both be nil or %p", l.root.next, l.root.prev, root)
+		}
+		return
+	}
+	// len(es) > 0
+
+	// check internal and external prev/next connections
+	for i, e := range es {
+		prev := root
+		Prev := (*Element[TElem])(nil)
+		if i > 0 {
+			prev = es[i-1]
+			Prev = prev
+		}
+		if p := e.prev; p != prev {
+			t.Errorf("elt[%d](%p).prev = %p, want %p", i, e, p, prev)
+		}
+		if p := e.Prev(); p != Prev {
+			t.Errorf("elt[%d](%p).Prev() = %p, want %p", i, e, p, Prev)
+		}
+
+		next := root
+		Next := (*Element[TElem])(nil)
+		if i < len(es)-1 {
+			next = es[i+1]
+			Next = next
+		}
+		if n := e.next; n != next {
+			t.Errorf("elt[%d](%p).next = %p, want %p", i, e, n, next)
+		}
+		if n := e.Next(); n != Next {
+			t.Errorf("elt[%d](%p).Next() = %p, want %p", i, e, n, Next)
+		}
+	}
+}
+
+func TestList(t *testing.T) {
+	l := New(string)()
+	checkListPointers(t, l, []*(Element[string]){})
+
+	// Single element list
+	e := l.PushFront("a")
+	checkListPointers(t, l, []*(Element[string]){e})
+	l.MoveToFront(e)
+	checkListPointers(t, l, []*(Element[string]){e})
+	l.MoveToBack(e)
+	checkListPointers(t, l, []*(Element[string]){e})
+	l.Remove(e)
+	checkListPointers(t, l, []*(Element[string]){})
+
+	// Bigger list
+	l2 := New[int]()
+	e2 := l2.PushFront(2)
+	e1 := l2.PushFront(1)
+	e3 := l2.PushBack(3)
+	e4 := l2.PushBack(600)
+	checkListPointers(t, l2, []*(Element[int]){e1, e2, e3, e4})
+
+	l2.Remove(e2)
+	checkListPointers(t, l2, []*(Element[int]){e1, e3, e4})
+
+	l2.MoveToFront(e3) // move from middle
+	checkListPointers(t, l2, []*(Element[int]){e3, e1, e4})
+
+	l2.MoveToFront(e1)
+	l2.MoveToBack(e3) // move from middle
+	checkListPointers(t, l2, []*(Element[int]){e1, e4, e3})
+
+	l2.MoveToFront(e3) // move from back
+	checkListPointers(t, l2, []*(Element[int]){e3, e1, e4})
+	l2.MoveToFront(e3) // should be no-op
+	checkListPointers(t, l2, []*(Element[int]){e3, e1, e4})
+
+	l2.MoveToBack(e3) // move from front
+	checkListPointers(t, l2, []*(Element[int]){e1, e4, e3})
+	l2.MoveToBack(e3) // should be no-op
+	checkListPointers(t, l2, []*(Element[int]){e1, e4, e3})
+
+	e2 = l2.InsertBefore(2, e1) // insert before front
+	checkListPointers(t, l2, []*(Element[int]){e2, e1, e4, e3})
+	l2.Remove(e2)
+	e2 = l2.InsertBefore(2, e4) // insert before middle
+	checkListPointers(t, l2, []*(Element[int]){e1, e2, e4, e3})
+	l2.Remove(e2)
+	e2 = l2.InsertBefore(2, e3) // insert before back
+	checkListPointers(t, l2, []*(Element[int]){e1, e4, e2, e3})
+	l2.Remove(e2)
+
+	e2 = l2.InsertAfter(2, e1) // insert after front
+	checkListPointers(t, l2, []*(Element[int]){e1, e2, e4, e3})
+	l2.Remove(e2)
+	e2 = l2.InsertAfter(2, e4) // insert after middle
+	checkListPointers(t, l2, []*(Element[int]){e1, e4, e2, e3})
+	l2.Remove(e2)
+	e2 = l2.InsertAfter(2, e3) // insert after back
+	checkListPointers(t, l2, []*(Element[int]){e1, e4, e3, e2})
+	l2.Remove(e2)
+
+	// Check standard iteration.
+	sum := 0
+	for e := l2.Front(); e != nil; e = e.Next() {
+		sum += e.Value
+	}
+	if sum != 604 {
+		t.Errorf("sum over l = %d, want 604", sum)
+	}
+
+	// Clear all elements by iterating
+	var next *Element[int]
+	for e := l2.Front(); e != nil; e = next {
+		next = e.Next()
+		l2.Remove(e)
+	}
+	checkListPointers(t, l2, []*(Element[int]){})
+}
+
+func checkList[TElem comparable](t *testing.T, l *List[TElem], es []interface{}) {
+	if !checkListLen(t, l, len(es)) {
+		return
+	}
+
+	i := 0
+	for e := l.Front(); e != nil; e = e.Next() {
+		le := e.Value
+		if le != es[i] {
+			t.Errorf("elt[%d].Value = %v, want %v", i, le, es[i])
+		}
+		i++
+	}
+}
+
+func TestExtending(t *testing.T) {
+	l1 := New[int]()
+	l2 := New[int]()
+
+	l1.PushBack(1)
+	l1.PushBack(2)
+	l1.PushBack(3)
+
+	l2.PushBack(4)
+	l2.PushBack(5)
+
+	l3 := New[int]()
+	l3.PushBackList(l1)
+	checkList(t, l3, []interface{}{1, 2, 3})
+	l3.PushBackList(l2)
+	checkList(t, l3, []interface{}{1, 2, 3, 4, 5})
+
+	l3 = New[int]()
+	l3.PushFrontList(l2)
+	checkList(t, l3, []interface{}{4, 5})
+	l3.PushFrontList(l1)
+	checkList(t, l3, []interface{}{1, 2, 3, 4, 5})
+
+	checkList(t, l1, []interface{}{1, 2, 3})
+	checkList(t, l2, []interface{}{4, 5})
+
+	l3 = New[int]()
+	l3.PushBackList(l1)
+	checkList(t, l3, []interface{}{1, 2, 3})
+	l3.PushBackList(l3)
+	checkList(t, l3, []interface{}{1, 2, 3, 1, 2, 3})
+
+	l3 = New[int]()
+	l3.PushFrontList(l1)
+	checkList(t, l3, []interface{}{1, 2, 3})
+	l3.PushFrontList(l3)
+	checkList(t, l3, []interface{}{1, 2, 3, 1, 2, 3})
+
+	l3 = New[int]()
+	l1.PushBackList(l3)
+	checkList(t, l1, []interface{}{1, 2, 3})
+	l1.PushFrontList(l3)
+	checkList(t, l1, []interface{}{1, 2, 3})
+}
+
+func TestRemove(t *testing.T) {
+	l := New[int]()
+	e1 := l.PushBack(1)
+	e2 := l.PushBack(2)
+	checkListPointers(t, l, []*(Element[int]){e1, e2})
+	e := l.Front()
+	l.Remove(e)
+	checkListPointers(t, l, []*(Element[int]){e2})
+	l.Remove(e)
+	checkListPointers(t, l, []*(Element[int]){e2})
+}
+
+func TestIssue4103(t *testing.T) {
+	l1 := New[int]()
+	l1.PushBack(1)
+	l1.PushBack(2)
+
+	l2 := New[int]()
+	l2.PushBack(3)
+	l2.PushBack(4)
+
+	e := l1.Front()
+	l2.Remove(e) // l2 should not change because e is not an element of l2
+	if n := l2.Len(); n != 2 {
+		t.Errorf("l2.Len() = %d, want 2", n)
+	}
+
+	l1.InsertBefore(8, e)
+	if n := l1.Len(); n != 3 {
+		t.Errorf("l1.Len() = %d, want 3", n)
+	}
+}
+
+func TestIssue6349(t *testing.T) {
+	l := New[int]()
+	l.PushBack(1)
+	l.PushBack(2)
+
+	e := l.Front()
+	l.Remove(e)
+	if e.Value != 1 {
+		t.Errorf("e.value = %d, want 1", e.Value)
+	}
+	if e.Next() != nil {
+		t.Errorf("e.Next() != nil")
+	}
+	if e.Prev() != nil {
+		t.Errorf("e.Prev() != nil")
+	}
+}
+
+func TestMove(t *testing.T) {
+	l := New[int]()
+	e1 := l.PushBack(1)
+	e2 := l.PushBack(2)
+	e3 := l.PushBack(3)
+	e4 := l.PushBack(4)
+
+	l.MoveAfter(e3, e3)
+	checkListPointers(t, l, []*(Element[int]){e1, e2, e3, e4})
+	l.MoveBefore(e2, e2)
+	checkListPointers(t, l, []*(Element[int]){e1, e2, e3, e4})
+
+	l.MoveAfter(e3, e2)
+	checkListPointers(t, l, []*(Element[int]){e1, e2, e3, e4})
+	l.MoveBefore(e2, e3)
+	checkListPointers(t, l, []*(Element[int]){e1, e2, e3, e4})
+
+	l.MoveBefore(e2, e4)
+	checkListPointers(t, l, []*(Element[int]){e1, e3, e2, e4})
+	e2, e3 = e3, e2
+
+	l.MoveBefore(e4, e1)
+	checkListPointers(t, l, []*(Element[int]){e4, e1, e2, e3})
+	e1, e2, e3, e4 = e4, e1, e2, e3
+
+	l.MoveAfter(e4, e1)
+	checkListPointers(t, l, []*(Element[int]){e1, e4, e2, e3})
+	e2, e3, e4 = e4, e2, e3
+
+	l.MoveAfter(e2, e3)
+	checkListPointers(t, l, []*(Element[int]){e1, e3, e2, e4})
+	e2, e3 = e3, e2
+}
+
+// Test PushFront, PushBack, PushFrontList, PushBackList with uninitialized List
+func TestZeroList(t *testing.T) {
+	var l1 = new(List[int])
+	l1.PushFront(1)
+	checkList(t, l1, []interface{}{1})
+
+	var l2 = new(List[int])
+	l2.PushBack(1)
+	checkList(t, l2, []interface{}{1})
+
+	var l3 = new(List[int])
+	l3.PushFrontList(l1)
+	checkList(t, l3, []interface{}{1})
+
+	var l4 = new(List[int])
+	l4.PushBackList(l2)
+	checkList(t, l4, []interface{}{1})
+}
+
+// Test that a list l is not modified when calling InsertBefore with a mark that is not an element of l.
+func TestInsertBeforeUnknownMark(t *testing.T) {
+	var l List[int]
+	l.PushBack(1)
+	l.PushBack(2)
+	l.PushBack(3)
+	l.InsertBefore(1, new(Element[int]))
+	checkList(t, &l, []interface{}{1, 2, 3})
+}
+
+// Test that a list l is not modified when calling InsertAfter with a mark that is not an element of l.
+func TestInsertAfterUnknownMark(t *testing.T) {
+	var l List[int]
+	l.PushBack(1)
+	l.PushBack(2)
+	l.PushBack(3)
+	l.InsertAfter(1, new(Element[int]))
+	checkList(t, &l, []interface{}{1, 2, 3})
+}
+
+// Test that a list l is not modified when calling MoveAfter or MoveBefore with a mark that is not an element of l.
+func TestMoveUnknownMark(t *testing.T) {
+	var l1 List[int]
+	e1 := l1.PushBack(1)
+
+	var l2 List[int]
+	e2 := l2.PushBack(2)
+
+	l1.MoveAfter(e1, e2)
+	checkList(t, &l1, []interface{}{1})
+	checkList(t, &l2, []interface{}{2})
+
+	l1.MoveBefore(e1, e2)
+	checkList(t, &l1, []interface{}{1})
+	checkList(t, &l2, []interface{}{2})
+}
+
+// Test the Transform function.
+func TestTransform(t *testing.T) {
+	l1 := New[int]()
+	l1.PushBack(1)
+	l1.PushBack(2)
+	l2 := Transform(l1, strconv.Itoa)
+	checkList(t, l2, []interface{}{"1", "2"})
+}
diff --git a/src/cmd/go2go/testdata/go2path/src/maps/maps.go2 b/src/cmd/go2go/testdata/go2path/src/maps/maps.go2
new file mode 100644
index 0000000..77e9898
--- /dev/null
+++ b/src/cmd/go2go/testdata/go2path/src/maps/maps.go2
@@ -0,0 +1,91 @@
+// Copyright 2020 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package maps implements simple functions to manipulate maps in various ways.
+package maps
+
+// Keys returns the keys of the map m.
+// The keys will be an indeterminate order.
+func Keys[K comparable, V any](m map[K]V) []K {
+	r := make([]K, 0, len(m))
+	for k := range m {
+		r = append(r, k)
+	}
+	return r
+}
+
+// Values returns the values of the map m.
+// The values will be in an indeterminate order.
+func Values[K comparable, V any](m map[K]V) []V {
+	r := make([]V, 0, len(m))
+	for _, v := range m {
+		r = append(r, v)
+	}
+	return r
+}
+
+// Equal reports whether two maps contain the same key/value pairs.
+// Values are compared using ==.
+func Equal[K, V comparable](m1, m2 map[K]V) bool {
+	if len(m1) != len(m2) {
+		return false
+	}
+	for k, v1 := range m1 {
+		if v2, ok := m2[k]; !ok || v1 != v2 {
+			return false
+		}
+	}
+	return true
+}
+
+// Copy returns a copy of m.
+func Copy[K comparable, V any](m map[K]V) map[K]V {
+	r := make(map[K]V, len(m))
+	for k, v := range m {
+		r[k] = v
+	}
+	return r
+}
+
+// Add adds all key/value pairs in m2 to m1. Keys in m2 that are already
+// present in m1 will be overwritten with the value in m2.
+func Add[K comparable, V any](m1, m2 map[K]V) {
+	for k, v := range m2 {
+		m1[k] = v
+	}
+}
+
+// Sub removes all keys in m2 from m1. Keys in m2 that are not present
+// in m1 are ignored. The values in m2 are ignored.
+func Sub[K comparable, V any](m1, m2 map[K]V) {
+	for k := range m2 {
+		delete(m1, k)
+	}
+}
+
+// Intersect removes all keys from m1 that are not present in m2.
+// Keys in m2 that are not in m1 are ignored. The values in m2 are ignored.
+func Intersect[K comparable, V any](m1, m2 map[K]V) {
+	for k := range m1 {
+		if _, ok := m2[k]; !ok {
+			delete(m1, k)
+		}
+	}
+}
+
+// Filter deletes any key/value pairs from m for which f returns false.
+func Filter[K comparable, V any](m map[K]V, f func(K, V) bool) {
+	for k, v := range m {
+		if !f(k, v) {
+			delete(m, k)
+		}
+	}
+}
+
+// TransformValues applies f to each value in m. The keys remain unchanged.
+func TransformValues[K comparable, V any](m map[K]V, f func(V) V) {
+	for k, v := range m {
+		m[k] = f(v)
+	}
+}
diff --git a/src/cmd/go2go/testdata/go2path/src/maps/maps_test.go2 b/src/cmd/go2go/testdata/go2path/src/maps/maps_test.go2
new file mode 100644
index 0000000..5a3aa44
--- /dev/null
+++ b/src/cmd/go2go/testdata/go2path/src/maps/maps_test.go2
@@ -0,0 +1,145 @@
+// Copyright 2020 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package maps
+
+import (
+	"math"
+	"sort"
+	"testing"
+
+	"slices"
+)
+
+var m1 = map[int]int{1: 2, 2: 4, 4: 8, 8: 16}
+var m2 = map[int]string{1: "2", 2: "4", 4: "8", 8: "16"}
+
+func TestKeys(t *testing.T) {
+	want := []int{1, 2, 4, 8}
+
+	got1 := Keys(m1)
+	sort.Ints(got1)
+	if !slices.Equal(got1, want) {
+		t.Errorf("Keys(%v) = %v, want %v", m1, got1, want)
+	}
+
+	got2 := Keys(m2)
+	sort.Ints(got2)
+	if !slices.Equal(got2, want) {
+		t.Errorf("Keys(%v) = %v, want %v", m2, got2, want)
+	}
+}
+
+func TestValues(t *testing.T) {
+	got1 := Values(m1)
+	want1 := []int{2, 4, 8, 16}
+	sort.Ints(got1)
+	if !slices.Equal(got1, want1) {
+		t.Errorf("Values(%v) = %v, want %v", m1, got1, want1)
+	}
+
+	got2 := Values(m2)
+	want2 := []string{"16", "2", "4", "8"}
+	sort.Strings(got2)
+	if !slices.Equal(got2, want2) {
+		t.Errorf("Values(%v) = %v, want %v", m2, got2, want2)
+	}
+}
+
+func TestEqual(t *testing.T) {
+	if !Equal(m1, m1) {
+		t.Errorf("Equal(%v, %v) = false, want true", m1, m1)
+	}
+	if Equal(m1, nil) {
+		t.Errorf("Equal(%v, nil) = true, want false", m1)
+	}
+	if Equal(nil, m1) {
+		t.Errorf("Equal(nil, %v) = true, want false", m1)
+	}
+	if !Equal(int, int)(nil, nil) {
+		t.Error("Equal(nil, nil) = false, want true")
+	}
+	if ms := map[int]int{1: 2}; Equal(m1, ms) {
+		t.Errorf("Equal(%v, %v) = true, want false", m1, ms)
+	}
+
+	// Comparing NaN for equality is expected to fail.
+	mf := map[int]float64{1: 0, 2: math.NaN()}
+	if Equal(mf, mf) {
+		t.Errorf("Equal(%v, %v) = true, want false", mf, mf)
+	}
+}
+
+func TestCopy(t *testing.T) {
+	m2 := Copy(m1)
+	if !Equal(m1, m2) {
+		t.Errorf("Copy(%v) = %v, want %v", m1, m2, m1)
+	}
+	m2[16] = 32
+	if Equal(m1, m2) {
+		t.Errorf("Equal(%v, %v) = true, want false", m1, m2)
+	}
+}
+
+func TestAdd(t *testing.T) {
+	mc := Copy(m1)
+	Add(mc, mc)
+	if !Equal(mc, m1) {
+		t.Errorf("Add(%v, %v) = %v, want %v", m1, m1, mc, m1)
+	}
+	Add(mc, map[int]int{16: 32})
+	want := map[int]int{1: 2, 2: 4, 4: 8, 8: 16, 16: 32}
+	if !Equal(mc, want) {
+		t.Errorf("Add result = %v, want %v", mc, want)
+	}
+}
+
+func TestSub(t *testing.T) {
+	mc := Copy(m1)
+	Sub(mc, mc)
+	if len(mc) > 0 {
+		t.Errorf("Sub(%v, %v) = %v, want empty map", m1, m1, mc)
+	}
+	mc = Copy(m1)
+	Sub(mc, map[int]int{1: 0})
+	want := map[int]int{2: 4, 4: 8, 8: 16}
+	if !Equal(mc, want) {
+		t.Errorf("Sub result = %v, want %v", mc, want)
+	}
+}
+
+func TestIntersect(t *testing.T) {
+	mc := Copy(m1)
+	Intersect(mc, mc)
+	if !Equal(mc, m1) {
+		t.Errorf("Intersect(%v, %v) = %v, want %v", m1, m1, mc, m1)
+	}
+	Intersect(mc, map[int]int{1: 0, 2: 0})
+	want := map[int]int{1: 2, 2: 4}
+	if !Equal(mc, want) {
+		t.Errorf("Intersect result = %v, want %v", mc, want)
+	}
+}
+
+func TestFilter(t *testing.T) {
+	mc := Copy(m1)
+	Filter(mc, func(int, int) bool { return true })
+	if !Equal(mc, m1) {
+		t.Errorf("Filter(%v, true) = %v, want %v", m1, mc, m1)
+	}
+	Filter(mc, func(k, v int) bool { return k < 3 })
+	want := map[int]int{1: 2, 2: 4}
+	if !Equal(mc, want) {
+		t.Errorf("Filter result = %v, want %v", mc, want)
+	}
+}
+
+func TestTransformValues(t *testing.T) {
+	mc := Copy(m1)
+	TransformValues(mc, func(i int) int { return i / 2 })
+	want := map[int]int{1: 1, 2: 2, 4: 4, 8: 8}
+	if !Equal(mc, want) {
+		t.Errorf("TransformValues result = %v, want %v", mc, want)
+	}
+}
diff --git a/src/cmd/go2go/testdata/go2path/src/metrics/metrics.go2 b/src/cmd/go2go/testdata/go2path/src/metrics/metrics.go2
new file mode 100644
index 0000000..0467fd6
--- /dev/null
+++ b/src/cmd/go2go/testdata/go2path/src/metrics/metrics.go2
@@ -0,0 +1,117 @@
+// Copyright 2020 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package metrics provides tracking arbitrary metrics composed of
+// values of comparable types.
+package metrics
+
+import (
+	"sync"
+
+	"maps"
+)
+
+// Metric1 tracks metrics of values of some type.
+type Metric1[T comparable] struct {
+	mu sync.Mutex
+	m  map[T]int
+}
+
+// Add adds another instance of some value.
+func (m *Metric1[T]) Add(v T) {
+	m.mu.Lock()
+	defer m.mu.Unlock()
+	if m.m == nil {
+		m.m = make(map[T]int)
+	}
+	m.m[v]++
+}
+
+// Count returns the number of instances we've seen of v.
+func (m *Metric1[T]) Count(v T) int {
+	m.mu.Lock()
+	defer m.mu.Unlock()
+	return m.m[v]
+}
+
+// Metrics returns all the values we've seen, in an indeterminate order.
+func (m *Metric1[T]) Metrics() []T {
+	return maps.Keys(m.m)
+}
+
+type key2[T1, T2 comparable] struct {
+	f1 T1
+	f2 T2
+}
+
+// Metric2 tracks metrics of pairs of values.
+type Metric2[T1, T2 comparable] struct {
+	mu sync.Mutex
+	m  map[key2[T1, T2]]int
+}
+
+// Add adds another instance of some pair of values.
+func (m *Metric2[T1, T2]) Add(v1 T1, v2 T2) {
+	m.mu.Lock()
+	defer m.mu.Unlock()
+	if m.m == nil {
+		m.m = make(map[key2[T1, T2]]int)
+	}
+	m.m[key2[T1, T2]{v1, v2}]++
+}
+
+// Count returns the number of instances we've seen of v1/v2.
+func (m *Metric2[T1, T2]) Count(v1 T1, v2 T2) int {
+	m.mu.Lock()
+	defer m.mu.Unlock()
+	return m.m[key2[T1, T2]{v1, v2}]
+}
+
+// Metrics returns all the values we've seen, in an indeterminate order.
+func (m *Metric2[T1, T2]) Metrics() (r1 []T1, r2 []T2) {
+	for _, k := range maps.Keys(m.m) {
+		r1 = append(r1, k.f1)
+		r2 = append(r2, k.f2)
+	}
+	return r1, r2
+}
+
+type key3[T1, T2, T3 comparable] struct {
+	f1 T1
+	f2 T2
+	f3 T3
+}
+
+// Metric3 tracks metrics of triplets of values.
+type Metric3[T1, T2, T3 comparable] struct {
+	mu sync.Mutex
+	m  map[key3[T1, T2, T3]]int
+}
+
+// Add adds another instance of some triplet of values.
+func (m *Metric3[T1, T2, T3]) Add(v1 T1, v2 T2, v3 T3) {
+	m.mu.Lock()
+	defer m.mu.Unlock()
+	if m.m == nil {
+		m.m = make(map[key3[T1, T2, T3]]int)
+	}
+	m.m[key3[T1, T2, T3]{v1, v2, v3}]++
+}
+
+// Count returns the number of instances we've seen of v1/v2/v3.
+func (m *Metric3[T1, T2, T3]) Count(v1 T1, v2 T2, v3 T3) int {
+	m.mu.Lock()
+	defer m.mu.Unlock()
+	return m.m[key3[T1, T2, T3]{v1, v2, v3}]
+}
+
+// Metrics returns all the values we've seen, in an indeterminate order.
+func (m *Metric3[T1, T2, T3]) Metrics() (r1 []T1, r2 []T2, r3 []T3) {
+	for k := range m.m {
+		r1 = append(r1, k.f1)
+		r2 = append(r2, k.f2)
+		r3 = append(r3, k.f3)
+	}
+	return r1, r2, r3
+}
diff --git a/src/cmd/go2go/testdata/go2path/src/metrics/metrics_test.go2 b/src/cmd/go2go/testdata/go2path/src/metrics/metrics_test.go2
new file mode 100644
index 0000000..1fbf4b8
--- /dev/null
+++ b/src/cmd/go2go/testdata/go2path/src/metrics/metrics_test.go2
@@ -0,0 +1,57 @@
+// Copyright 2020 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package metrics
+
+import (
+	"sort"
+	"testing"
+
+	"slices"
+)
+
+type S struct{ a, b, c string }
+
+func TestMetrics(t *testing.T) {
+	m1 := Metric1[string]{}
+	if got := m1.Count("a"); got != 0 {
+		t.Errorf("Count(%q) = %d, want 0", "a", got)
+	}
+	m1.Add("a")
+	m1.Add("a")
+	if got := m1.Count("a"); got != 2 {
+		t.Errorf("Count(%q) = %d, want 2", "a", got)
+	}
+	if got, want := m1.Metrics(), []string{"a"}; !slices.Equal(got, want) {
+		t.Errorf("Metrics = %v, want %v", got, want)
+	}
+
+	m2 := Metric2[int, float64]{}
+	m2.Add(1, 1)
+	m2.Add(2, 2)
+	m2.Add(3, 3)
+	m2.Add(3, 3)
+	k1, k2 := m2.Metrics()
+
+	sort.Ints(k1)
+	w1 := []int{1, 2, 3}
+	if !slices.Equal(k1, w1) {
+		t.Errorf("Metric2.Metrics first slice = %v, want %v", k1, w1)
+	}
+
+	sort.Float64s(k2)
+	w2 := []float64{1, 2, 3}
+	if !slices.Equal(k2, w2) {
+		t.Errorf("Metric2.Metrics first slice = %v, want %v", k2, w2)
+	}
+
+	m3 := Metric3[string, S, S]{}
+	m3.Add("a", S{"d", "e", "f"}, S{"g", "h", "i"})
+	m3.Add("a", S{"d", "e", "f"}, S{"g", "h", "i"})
+	m3.Add("a", S{"d", "e", "f"}, S{"g", "h", "i"})
+	m3.Add("b", S{"d", "e", "f"}, S{"g", "h", "i"})
+	if got := m3.Count("a", S{"d", "e", "f"}, S{"g", "h", "i"}); got != 3 {
+		t.Errorf("Count(%v, %v, %v) = %d, want 3", "a", S{"d", "e", "f"}, S{"g", "h", "i"}, got)
+	}
+}
diff --git a/src/cmd/go2go/testdata/go2path/src/orderedmap/orderedmap.go2 b/src/cmd/go2go/testdata/go2path/src/orderedmap/orderedmap.go2
new file mode 100644
index 0000000..e1ea5dc
--- /dev/null
+++ b/src/cmd/go2go/testdata/go2path/src/orderedmap/orderedmap.go2
@@ -0,0 +1,136 @@
+// Copyright 2020 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package orderedmap provides an ordered map, implemented as a binary tree.
+package orderedmap
+
+// FIXME: This should probably be container/orderedmap.
+
+import (
+	"context"
+
+	"chans"
+	"constraints"
+)
+
+// Map is an ordered map.
+type Map[K, V any] struct {
+	root    *node[K, V]
+	compare func(K, K) int
+}
+
+// node is the type of a node in the binary tree.
+type node[K, V any] struct {
+	key         K
+	val         V
+	left, right *node[K, V]
+}
+
+// New returns a new map. It takes a comparison function that compares two
+// keys and returns < 0 if the first is less, == 0 if they are equal,
+// > 0 if the first is greater.
+func New[K, V any](compare func(K, K) int) *Map[K, V] {
+	return &Map[K, V]{compare: compare}
+}
+
+// NewOrdered returns a new map whose key is an ordered type.
+// This is like New, but does not require providing a compare function.
+// The map compare function uses the obvious key ordering.
+func NewOrdered[K constraints.Ordered, V any]() *Map[K, V] {
+	return New[K, V](func(k1, k2 K) int {
+		switch {
+		case k1 < k2:
+			return -1
+		case k1 == k2:
+			return 0
+		default:
+			return 1
+		}
+	})
+}
+
+// find looks up key in the map, returning either a pointer to the slot of the
+// node holding key, or a pointer to the slot where should a node would go.
+func (m *Map[K, V]) find(key K) **node[K, V] {
+	pn := &m.root
+	for *pn != nil {
+		switch cmp := m.compare(key, (*pn).key); {
+		case cmp < 0:
+			pn = &(*pn).left
+		case cmp > 0:
+			pn = &(*pn).right
+		default:
+			return pn
+		}
+	}
+	return pn
+}
+
+// Insert inserts a new key/value into the map.
+// If the key is already present, the value is replaced.
+// Reports whether this is a new key.
+func (m *Map[K, V]) Insert(key K, val V) bool {
+	pn := m.find(key)
+	if *pn != nil {
+		(*pn).val = val
+		return false
+	}
+	*pn = &node[K, V]{key: key, val: val}
+	return true
+}
+
+// Find returns the value associated with a key, or the zero value
+// if not present. The found result reports whether the key was found.
+func (m *Map[K, V]) Find(key K) (V, bool) {
+	pn := m.find(key)
+	if *pn == nil {
+		var zero V
+		return zero, false
+	}
+	return (*pn).val, true
+}
+
+// keyValue is a pair of key and value used while iterating.
+type keyValue[K, V any] struct {
+	key K
+	val V
+}
+
+// iterate returns an iterator that traverses the map.
+func (m *Map[K, V]) Iterate() *Iterator[K, V] {
+	sender, receiver := chans.Ranger(keyValue[K, V])()
+	var f func(*node[K, V]) bool
+	f = func(n *node[K, V]) bool {
+		if n == nil {
+			return true
+		}
+		// Stop the traversal if Send fails, which means that
+		// nothing is listening to the receiver.
+		return f(n.left) &&
+			sender.Send(context.Background(), keyValue[K, V]{n.key, n.val}) &&
+			f(n.right)
+	}
+	go func() {
+		f(m.root)
+		sender.Close()
+	}()
+	return &Iterator[K, V]{receiver}
+}
+
+// Iterator is used to iterate over the map.
+type Iterator[K, V any] struct {
+	r *chans.Receiver[keyValue[K, V]]
+}
+
+// Next returns the next key and value pair, and a boolean that reports
+// whether they are valid. If not valid, we have reached the end of the map.
+func (it *Iterator[K, V]) Next() (K, V, bool) {
+	keyval, ok := it.r.Next(context.Background())
+	if !ok {
+		var zerok K
+		var zerov V
+		return zerok, zerov, false
+	}
+	return keyval.key, keyval.val, true
+}
diff --git a/src/cmd/go2go/testdata/go2path/src/orderedmap/orderedmap_test.go2 b/src/cmd/go2go/testdata/go2path/src/orderedmap/orderedmap_test.go2
new file mode 100644
index 0000000..dd7306b
--- /dev/null
+++ b/src/cmd/go2go/testdata/go2path/src/orderedmap/orderedmap_test.go2
@@ -0,0 +1,63 @@
+// Copyright 2020 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package orderedmap
+
+import (
+	"bytes"
+	"testing"
+
+	"slices"
+)
+
+func TestMap(t *testing.T) {
+	m := New[[]byte, int](bytes.Compare)
+
+	if _, found := m.Find([]byte("a")); found {
+		t.Errorf("unexpectedly found %q in empty map", []byte("a"))
+	}
+	if !m.Insert([]byte("a"), 'a') {
+		t.Errorf("key %q unexpectedly already present", []byte("a"))
+	}
+	if !m.Insert([]byte("c"), 'c') {
+		t.Errorf("key %q unexpectedly already present", []byte("c"))
+	}
+	if !m.Insert([]byte("b"), 'b') {
+		t.Errorf("key %q unexpectedly already present", []byte("b"))
+	}
+	if m.Insert([]byte("c"), 'x') {
+		t.Errorf("key %q unexpectedly not present", []byte("c"))
+	}
+
+	if v, found := m.Find([]byte("a")); !found {
+		t.Errorf("did not find %q", []byte("a"))
+	} else if v != 'a' {
+		t.Errorf("key %q returned wrong value %c, expected %c", []byte("a"), v, 'a')
+	}
+	if v, found := m.Find([]byte("c")); !found {
+		t.Errorf("did not find %q", []byte("c"))
+	} else if v != 'x' {
+		t.Errorf("key %q returned wrong value %c, expected %c", []byte("c"), v, 'x')
+	}
+
+	if _, found := m.Find([]byte("d")); found {
+		t.Errorf("unexpectedly found %q", []byte("d"))
+	}
+
+	gather := func(it *Iterator[[]byte, int]) []int {
+		var r []int
+		for {
+			_, v, ok := it.Next()
+			if !ok {
+				return r
+			}
+			r = append(r, v)
+		}
+	}
+	got := gather(m.Iterate())
+	want := []int{'a', 'b', 'x'}
+	if !slices.Equal(got, want) {
+		t.Errorf("Iterate returned %v, want %v", got, want)
+	}
+}
diff --git a/src/cmd/go2go/testdata/go2path/src/sets/sets.go2 b/src/cmd/go2go/testdata/go2path/src/sets/sets.go2
new file mode 100644
index 0000000..539a98c
--- /dev/null
+++ b/src/cmd/go2go/testdata/go2path/src/sets/sets.go2
@@ -0,0 +1,111 @@
+// Copyright 2020 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package sets implements sets of any type.
+package sets
+
+// A Set is a set of elements of some type.
+type Set[Elem comparable] struct {
+	m map[Elem]struct{}
+}
+
+// Make makes a new set.
+func Make[Elem comparable]() Set[Elem] {
+	return Set[Elem]{m: make(map[Elem]struct{})}
+}
+
+// Add adds an element to a set.
+func (s Set[Elem]) Add(v Elem) {
+	s.m[v] = struct{}{}
+}
+
+// Delete removes an element from a set. If the element is not present
+// in the set, this does nothing.
+func (s Set[Elem]) Delete(v Elem) {
+	delete(s.m, v)
+}
+
+// Contains reports whether v is in the set.
+func (s Set[Elem]) Contains(v Elem) bool {
+	_, ok := s.m[v]
+	return ok
+}
+
+// Len returns the number of elements in the set.
+func (s Set[Elem]) Len() int {
+	return len(s.m)
+}
+
+// Values returns the values in the set.
+// The values will be in an indeterminate order.
+func (s Set[Elem]) Values() []Elem {
+	r := make([]Elem, 0, len(s.m))
+	for v := range s.m {
+		r = append(r, v)
+	}
+	return r
+}
+
+// Equal reports whether two sets contain the same elements.
+func Equal[Elem comparable](s1, s2 Set[Elem]) bool {
+	if len(s1.m) != len(s2.m) {
+		return false
+	}
+	for v1 := range s1.m {
+		if !s2.Contains(v1) {
+			return false
+		}
+	}
+	return true
+}
+
+// Copy returns a copy of s.
+func (s Set[Elem]) Copy() Set[Elem] {
+	r := Set[Elem]{m: make(map[Elem]struct{}, len(s.m))}
+	for v := range s.m {
+		r.m[v] = struct{}{}
+	}
+	return r
+}
+
+// AddSet adds all the elements of s2 to s.
+func (s Set[Elem]) AddSet(s2 Set[Elem]) {
+	for v := range s2.m {
+		s.m[v] = struct{}{}
+	}
+}
+
+// SubSet removes all elements in s2 from s.
+// Values in s2 that are not in s are ignored.
+func (s Set[Elem]) SubSet(s2 Set[Elem]) {
+	for v := range s2.m {
+		delete(s.m, v)
+	}
+}
+
+// Intersect removes all elements from s that are not present in s2.
+// Values in s2 that are not in s are ignored.
+func (s Set[Elem]) Intersect(s2 Set[Elem]) {
+	for v := range s.m {
+		if !s2.Contains(v) {
+			delete(s.m, v)
+		}
+	}
+}
+
+// Iterate calls f on every element in the set.
+func (s Set[Elem]) Iterate(f func(Elem)) {
+	for v := range s.m {
+		f(v)
+	}
+}
+
+// Filter deletes any elements from s for which f returns false.
+func (s Set[Elem]) Filter(f func(Elem) bool) {
+	for v := range s.m {
+		if !f(v) {
+			delete(s.m, v)
+		}
+	}
+}
diff --git a/src/cmd/go2go/testdata/go2path/src/sets/sets_test.go2 b/src/cmd/go2go/testdata/go2path/src/sets/sets_test.go2
new file mode 100644
index 0000000..6994d9d
--- /dev/null
+++ b/src/cmd/go2go/testdata/go2path/src/sets/sets_test.go2
@@ -0,0 +1,146 @@
+// Copyright 2020 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package sets
+
+import (
+	"sort"
+	"testing"
+
+	"slices"
+)
+
+func TestSet(t *testing.T) {
+	s1 := Make[int]()
+	if got := s1.Len(); got != 0 {
+		t.Errorf("Len of empty set = %d, want 0", got)
+	}
+	s1.Add(1)
+	s1.Add(1)
+	s1.Add(1)
+	if got := s1.Len(); got != 1 {
+		t.Errorf("(%v).Len() == %d, want 1", s1, got)
+	}
+	s1.Add(2)
+	s1.Add(3)
+	s1.Add(4)
+	if got := s1.Len(); got != 4 {
+		t.Errorf("(%v).Len() == %d, want 4", s1, got)
+	}
+	if !s1.Contains(1) {
+		t.Errorf("(%v).Contains(1) == false, want true", s1)
+	}
+	if s1.Contains(5) {
+		t.Errorf("(%v).Contains(5) == true, want false", s1)
+	}
+	vals := s1.Values()
+	sort.Ints(vals)
+	w1 := []int{1, 2, 3, 4}
+	if !slices.Equal(vals,  w1) {
+		t.Errorf("(%v).Values() == %v, want %v", s1, vals, w1)
+	}
+}
+
+func TestEqual(t *testing.T) {
+	s1 := Make[string]()
+	s2 := Make[string]()
+	if !Equal(s1, s2) {
+		t.Errorf("Equal(%v, %v) = false, want true", s1, s2)
+	}
+	s1.Add("hello")
+	s1.Add("world")
+	if got := s1.Len(); got != 2 {
+		t.Errorf("(%v).Len() == %d, want 2", s1, got)
+	}
+	if Equal(s1, s2) {
+		t.Errorf("Equal(%v, %v) = true, want false", s1, s2)
+	}
+}
+
+func TestCopy(t *testing.T) {
+	s1 := Make[float64]()
+	s1.Add(0)
+	s2 := s1.Copy()
+	if !Equal(s1, s2) {
+		t.Errorf("Equal(%v, %v) = false, want true", s1, s2)
+	}
+	s1.Add(1)
+	if Equal(s1, s2) {
+		t.Errorf("Equal(%v, %v) = true, want false", s1, s2)
+	}
+}
+
+func TestAddSet(t *testing.T) {
+	s1 := Make[int]()
+	s1.Add(1)
+	s1.Add(2)
+	s2 := Make[int]()
+	s2.Add(2)
+	s2.Add(3)
+	s1.AddSet(s2)
+	if got := s1.Len(); got != 3 {
+		t.Errorf("(%v).Len() == %d, want 3", s1, got)
+	}
+	s2.Add(1)
+	if !Equal(s1, s2) {
+		t.Errorf("Equal(%v, %v) = false, want true", s1, s2)
+	}
+}
+
+func TestSubSet(t *testing.T) {
+	s1 := Make[int]()
+	s1.Add(1)
+	s1.Add(2)
+	s2 := Make[int]()
+	s2.Add(2)
+	s2.Add(3)
+	s1.SubSet(s2)
+	if got := s1.Len(); got != 1 {
+		t.Errorf("(%v).Len() == %d, want 1", s1, got)
+	}
+	if vals, want := s1.Values(), []int{1}; !slices.Equal(vals, want) {
+		t.Errorf("after SubSet got %v, want %v", vals, want)
+	}
+}
+
+func TestIntersect(t *testing.T) {
+	s1 := Make[int]()
+	s1.Add(1)
+	s1.Add(2)
+	s2 := Make[int]()
+	s2.Add(2)
+	s2.Add(3)
+	s1.Intersect(s2)
+	if got := s1.Len(); got != 1 {
+		t.Errorf("(%v).Len() == %d, want 1", s1, got)
+	}
+	if vals, want := s1.Values(), []int{2}; !slices.Equal(vals, want) {
+		t.Errorf("after Intersect got %v, want %v", vals, want)
+	}
+}
+
+func TestIterate(t *testing.T) {
+	s1 := Make[int]()
+	s1.Add(1)
+	s1.Add(2)
+	s1.Add(3)
+	s1.Add(4)
+	tot := 0
+	s1.Iterate(func(i int) { tot += i })
+	if tot != 10 {
+		t.Errorf("total of %v == %d, want 10", s1, tot)
+	}
+}
+
+func TestFilter(t *testing.T) {
+	s1 := Make[int]()
+	s1.Add(1)
+	s1.Add(2)
+	s1.Add(3)
+	s1.Filter(func(v int) bool { return v%2 == 0 })
+	if vals, want := s1.Values(), []int{2}; !slices.Equal(vals, want) {
+		t.Errorf("after Filter got %v, want %v", vals, want)
+	}
+
+}
diff --git a/src/cmd/go2go/testdata/go2path/src/slices/slices.go2 b/src/cmd/go2go/testdata/go2path/src/slices/slices.go2
new file mode 100644
index 0000000..990ad43
--- /dev/null
+++ b/src/cmd/go2go/testdata/go2path/src/slices/slices.go2
@@ -0,0 +1,125 @@
+// Copyright 2020 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package slices provides functions for basic operations on
+// slices of any element type.
+package slices
+
+import (
+	"alg"
+	"constraints"
+)
+
+// Equal reports whether two slices are equal: the same length and all
+// elements equal. All floating point NaNs are considered equal.
+func Equal[Elem comparable](s1, s2 []Elem) bool {
+	if len(s1) != len(s2) {
+		return false
+	}
+	for i, v1 := range s1 {
+		v2 := s2[i]
+		if v1 != v2 {
+			isNaN := func(f Elem) bool { return f != f }
+			if !isNaN(v1) || !isNaN(v2) {
+				return false
+			}
+		}
+	}
+	return true
+}
+
+// EqualFn reports whether two slices are equal using a comparision
+// function on each element.
+func EqualFn[Elem any](s1, s2 []Elem, eq func(Elem, Elem) bool) bool {
+	if len(s1) != len(s2) {
+		return false
+	}
+	for i, v1 := range s1 {
+		v2 := s2[i]
+		if !eq(v1, v2) {
+			return false
+		}
+	}
+	return true
+}
+
+// Map turns a []Elem1 to a []Elem2 using a mapping function.
+func Map[Elem1, Elem2 any](s []Elem1, f func(Elem1) Elem2) []Elem2 {
+	r := make([]Elem2, len(s))
+	for i, v := range s {
+		r[i] = f(v)
+	}
+	return r
+}
+
+// Reduce reduces a []Elem1 to a single value of type Elem2 using
+// a reduction function.
+func Reduce[Elem1, Elem2 any](s []Elem1, initializer Elem2, f func(Elem2, Elem1) Elem2) Elem2 {
+	r := initializer
+	for _, v := range s {
+		r = f(r, v)
+	}
+	return r
+}
+
+// Filter filters values from a slice using a filter function.
+func Filter[Elem any](s []Elem, f func(Elem) bool) []Elem {
+	var r []Elem
+	for _, v := range s {
+		if f(v) {
+			r = append(r, v)
+		}
+	}
+	return r
+}
+
+// Max returns the maximum element in a slice of some ordered type.
+// If the slice is empty it returns the zero value of the element type.
+func Max[Elem constraints.Ordered](s []Elem) Elem {
+	if len(s) == 0 {
+		var zero Elem
+		return zero
+	}
+	return Reduce(s[1:], s[0], alg.Max(Elem))
+}
+
+// Min returns the minimum element in a slice of some ordered type.
+// If the slice is empty it returns the zero value of the element type.
+func Min[Elem constraints.Ordered](s []Elem) Elem {
+	if len(s) == 0 {
+		var zero Elem
+		return zero
+	}
+	return Reduce(s[1:], s[0], alg.Min(Elem))
+}
+
+// Append adds values to the end of a slice, returning a new slice.
+// This is like the predeclared append function; it's an example
+// of how to write it using generics. We used to write code like
+// this before append was added to the language, but we had to write
+// a separate copy for each type.
+func Append[T any](s []T, t ...T) []T {
+	lens := len(s)
+	tot := lens + len(t)
+	if tot <= cap(s) {
+		s = s[:tot]
+	} else {
+		news := make([]T, tot, tot + tot/2)
+		Copy(news, s)
+		s = news
+	}
+	Copy(s[lens:tot], t)
+	return s
+}
+
+// Copy copies values from t to s, stopping when either slice is full,
+// returning the number of values copied. This is like the predeclared
+// copy function; it's an example of how to write it using generics.
+func Copy[T any](s, t []T) int {
+	i := 0
+	for ; i < len(s) && i < len(t); i++ {
+		s[i] = t[i]
+	}
+	return i
+}
diff --git a/src/cmd/go2go/testdata/go2path/src/slices/slices_test.go2 b/src/cmd/go2go/testdata/go2path/src/slices/slices_test.go2
new file mode 100644
index 0000000..c90474a
--- /dev/null
+++ b/src/cmd/go2go/testdata/go2path/src/slices/slices_test.go2
@@ -0,0 +1,164 @@
+// Copyright 2020 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package slices
+
+import (
+	"math"
+	"strings"
+	"testing"
+
+	"constraints"
+)
+
+func TestEqual(t *testing.T) {
+	s1 := []int{1, 2, 3}
+	if !Equal(s1, s1) {
+		t.Errorf("Equal(%v, %v) = false, want true", s1, s1)
+	}
+	s2 := []int{1, 2, 3}
+	if !Equal(s1, s2) {
+		t.Errorf("Equal(%v, %v) = false, want true", s1, s2)
+	}
+	s2 = append(s2, 4)
+	if Equal(s1, s2) {
+		t.Errorf("Equal(%v, %v) = true, want false", s1, s2)
+	}
+
+	s3 := []float64{1, 2, math.NaN()}
+	if !Equal(s3, s3) {
+		t.Errorf("Equal(%v, %v) = false, want true", s3, s3)
+	}
+
+	if Equal(s1, nil) {
+		t.Errorf("Equal(%v, nil) = true, want false", s1)
+	}
+	if Equal(nil, s1) {
+		t.Errorf("Equal(nil, %v) = true, want false", s1)
+	}
+	if !Equal(s1[:0], nil) {
+		t.Errorf("Equal(%v, nil = false, want true", s1[:0])
+	}
+}
+
+func offByOne[Elem constraints.Integer](a, b Elem) bool {
+	return a == b + 1 || a == b - 1
+}
+
+func TestEqualFn(t *testing.T) {
+	s1 := []int{1, 2, 3}
+	s2 := []int{2, 3, 4}
+	if EqualFn(s1, s1, offByOne(int)) {
+		t.Errorf("EqualFn(%v, %v, offByOne) = true, want false", s1, s1)
+	}
+	if !EqualFn(s1, s2, offByOne(int)) {
+		t.Errorf("EqualFn(%v, %v, offByOne) = false, want true", s1, s2)
+	}
+
+	s3 := []string{"a", "b", "c"}
+	s4 := []string{"A", "B", "C"}
+	if !EqualFn(s3, s4, strings.EqualFold) {
+		t.Errorf("EqualFn(%v, %v, strings.EqualFold) = false, want true", s3, s4)
+	}
+
+	if !EqualFn(s1[:0], nil, offByOne(int)) {
+		t.Errorf("EqualFn(%v, nil, offByOne) = false, want true", s1[:0])
+	}
+}
+
+func TestMap(t *testing.T) {
+	s1 := []int{1, 2, 3}
+	s2 := Map(s1, func(i int) float64 { return float64(i) * 2.5 })
+	if want := []float64{2.5, 5, 7.5}; !Equal(s2, want) {
+		t.Errorf("Map(%v, ...) = %v, want %v", s1, s2, want)
+	}
+
+	s3 := []string{"Hello", "World"}
+	s4 := Map(s3, strings.ToLower)
+	if want := []string{"hello", "world"}; !Equal(s4, want) {
+		t.Errorf("Map(%v, strings.ToLower) = %v, want %v", s3, s4, want)
+	}
+
+	s5 := Map(nil, func(i int) int { return i })
+	if len(s5) != 0 {
+		t.Errorf("Map(nil, identity) = %v, want empty slice", s5)
+	}
+}
+
+func TestReduce(t *testing.T) {
+	s1 := []int{1, 2, 3}
+	r := Reduce(s1, 0, func(f float64, i int) float64 { return float64(i) * 2.5 + f })
+	if want := 15.0; r != want {
+		t.Errorf("Reduce(%v, 0, ...) = %v, want %v", s1, r, want)
+	}
+
+	if got := Reduce(nil, 0, func(i, j int) int { return i + j}); got != 0 {
+		t.Errorf("Reduce(nil, 0, add) = %v, want 0", got)
+	}
+}
+
+func TestFilter(t *testing.T) {
+	s1 := []int{1, 2, 3}
+	s2 := Filter(s1, func(i int) bool { return i%2 == 0 })
+	if want := []int{2}; !Equal(s2, want) {
+		t.Errorf("Filter(%v, even) = %v, want %v", s1, s2, want)
+	}
+
+	if s3 := Filter(s1[:0], func(i int) bool { return true }); len(s3) > 0 {
+		t.Errorf("Filter(%v, identity) = %v, want empty slice", s1[:0], s3)
+	}
+}
+
+func TestMax(t *testing.T) {
+	s1 := []int{1, 2, 3, -5}
+	if got, want := Max(s1), 3; got != want {
+		t.Errorf("Max(%v) = %d, want %d", s1, got, want)
+	}
+
+	s2 := []string{"aaa", "a", "aa", "aaaa"}
+	if got, want := Max(s2), "aaaa"; got != want {
+		t.Errorf("Max(%v) = %q, want %q", s2, got, want)
+	}
+
+	if got, want := Max(s2[:0]), ""; got != want {
+		t.Errorf("Max(%v) = %q, want %q", s2[:0], got, want)
+	}
+}
+
+func TestMin(t *testing.T) {
+	s1 := []int{1, 2, 3, -5}
+	if got, want := Min(s1), -5; got != want {
+		t.Errorf("Min(%v) = %d, want %d", s1, got, want)
+	}
+
+	s2 := []string{"aaa", "a", "aa", "aaaa"}
+	if got, want := Min(s2), "a"; got != want {
+		t.Errorf("Min(%v) = %q, want %q", s2, got, want)
+	}
+
+	if got, want := Min(s2[:0]), ""; got != want {
+		t.Errorf("Min(%v) = %q, want %q", s2[:0], got, want)
+	}
+}
+
+func TestAppend(t *testing.T) {
+	s := []int{1, 2, 3}
+	s = Append(s, 4, 5, 6)
+	want := []int{1, 2, 3, 4, 5, 6}
+	if !Equal(s, want) {
+		t.Errorf("after Append got %v, want %v", s, want)
+	}
+}
+
+func TestCopy(t *testing.T) {
+	s1 := []int{1, 2, 3}
+	s2 := []int{4, 5}
+	if got := Copy(s1, s2); got != 2 {
+		t.Errorf("Copy returned %d, want 2", got)
+	}
+	want := []int{4, 5, 3}
+	if !Equal(s1, want) {
+		t.Errorf("after Copy got %v, want %v", s1, want)
+	}
+}
diff --git a/src/cmd/go2go/translate.go b/src/cmd/go2go/translate.go
new file mode 100644
index 0000000..a74fd4c
--- /dev/null
+++ b/src/cmd/go2go/translate.go
@@ -0,0 +1,33 @@
+// Copyright 2020 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import (
+	"go/go2go"
+	"io/ioutil"
+	"strings"
+)
+
+// translate writes .go files for all .go2 files in dir.
+func translate(importer *go2go.Importer, dir string) {
+	if err := go2go.Rewrite(importer, dir); err != nil {
+		die(err.Error())
+	}
+}
+
+// translateFile translates one .go2 file into a .go file.
+func translateFile(importer *go2go.Importer, file string) {
+	data, err := ioutil.ReadFile(file)
+	if err != nil {
+		die(err.Error())
+	}
+	out, err := go2go.RewriteBuffer(importer, file, data)
+	if err != nil {
+		die(err.Error())
+	}
+	if err := ioutil.WriteFile(strings.TrimSuffix(file, ".go2")+".go", out, 0644); err != nil {
+		die(err.Error())
+	}
+}
diff --git a/src/cmd/gofmt/gofmt.go b/src/cmd/gofmt/gofmt.go
index 2793c2c..a43cda1 100644
--- a/src/cmd/gofmt/gofmt.go
+++ b/src/cmd/gofmt/gofmt.go
@@ -67,7 +67,8 @@
 }
 
 func initParserMode() {
-	parserMode = parser.ParseComments
+	// Keep this in sync with go/format/format.go.
+	parserMode = parser.ParseComments | parser.ParseTypeParams
 	if *allErrors {
 		parserMode |= parser.AllErrors
 	}
diff --git a/src/go/build/deps_test.go b/src/go/build/deps_test.go
index c97c668..322765c 100644
--- a/src/go/build/deps_test.go
+++ b/src/go/build/deps_test.go
@@ -514,6 +514,9 @@
 
 	FMT, container/heap, math/rand
 	< internal/trace;
+
+	# go2go: a package that should only exist on the dev.go2go branch
+	go/build, go/importer, go/printer, go/types, log < go/go2go;
 `
 
 // listStdPkgs returns the same list of packages as "go list std".
diff --git a/src/go/format/format.go b/src/go/format/format.go
index a603d96..279fc2e 100644
--- a/src/go/format/format.go
+++ b/src/go/format/format.go
@@ -38,7 +38,7 @@
 
 var config = printer.Config{Mode: printerMode, Tabwidth: tabWidth}
 
-const parserMode = parser.ParseComments
+const parserMode = parser.ParseComments | parser.ParseTypeParams
 
 // Node formats node in canonical gofmt style and writes the result to dst.
 //
diff --git a/src/go/go2go/go2go.go b/src/go/go2go/go2go.go
new file mode 100644
index 0000000..b0c4873
--- /dev/null
+++ b/src/go/go2go/go2go.go
@@ -0,0 +1,272 @@
+// Copyright 2020 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package go2go rewrites polymorphic code into non-polymorphic code.
+package go2go
+
+import (
+	"bytes"
+	"fmt"
+	"go/ast"
+	"go/parser"
+	"go/token"
+	"go/types"
+	"io"
+	"os"
+	"path/filepath"
+	"sort"
+	"strings"
+)
+
+// rewritePrefix is what we put at the start of each newly generated .go file.
+const rewritePrefix = "// Code generated by go2go; DO NOT EDIT.\n\n"
+
+// Rewrite rewrites the contents of a single directory.
+// It looks for all files with the extension .go2, and parses
+// them as a single package. It writes out a .go file with any
+// polymorphic code rewritten into normal code.
+func Rewrite(importer *Importer, dir string) error {
+	_, err := rewriteToPkgs(importer, "", dir)
+	return err
+}
+
+// rewriteToPkgs rewrites the contents of a single directory,
+// and returns the types.Packages that it computes.
+func rewriteToPkgs(importer *Importer, importPath, dir string) ([]*types.Package, error) {
+	go2files, gofiles, err := go2Files(dir)
+	if err != nil {
+		return nil, err
+	}
+
+	if err := checkAndRemoveGofiles(dir, gofiles); err != nil {
+		return nil, err
+	}
+
+	return rewriteFilesInPath(importer, importPath, dir, go2files)
+}
+
+// namedAST holds a file name and the AST parsed from that file.
+type namedAST struct {
+	name string
+	ast  *ast.File
+}
+
+// RewriteFiles rewrites a set of .go2 files in dir.
+func RewriteFiles(importer *Importer, dir string, go2files []string) ([]*types.Package, error) {
+	return rewriteFilesInPath(importer, "", dir, go2files)
+}
+
+// rewriteFilesInPath rewrites a set of .go2 files in dir for importPath.
+func rewriteFilesInPath(importer *Importer, importPath, dir string, go2files []string) ([]*types.Package, error) {
+	fset := token.NewFileSet()
+	pkgs, err := parseFiles(importer, dir, go2files, fset)
+	if err != nil {
+		return nil, err
+	}
+
+	var rpkgs []*types.Package
+	var tpkgs [][]namedAST
+	for _, pkg := range pkgs {
+		pkgfiles := make([]namedAST, 0, len(pkg.Files))
+		for n, f := range pkg.Files {
+			pkgfiles = append(pkgfiles, namedAST{n, f})
+		}
+		sort.Slice(pkgfiles, func(i, j int) bool {
+			return pkgfiles[i].name < pkgfiles[j].name
+		})
+
+		asts := make([]*ast.File, 0, len(pkgfiles))
+		for _, a := range pkgfiles {
+			asts = append(asts, a.ast)
+		}
+
+		var merr multiErr
+		conf := types.Config{
+			Importer: importer,
+			Error:    merr.add,
+		}
+		path := importPath
+		if path == "" {
+			path = pkg.Name
+		}
+		tpkg, err := conf.Check(path, fset, asts, importer.info)
+		if err != nil {
+			return nil, fmt.Errorf("type checking failed for %s\n%v", pkg.Name, merr)
+		}
+
+		importer.record(pkg.Name, pkgfiles, importPath, tpkg, asts)
+
+		rpkgs = append(rpkgs, tpkg)
+		tpkgs = append(tpkgs, pkgfiles)
+	}
+
+	for i, tpkg := range tpkgs {
+		addImportable := 0
+		for j, pkgfile := range tpkg {
+			if !strings.HasSuffix(pkgfile.name, "_test.go2") {
+				addImportable = j
+				break
+			}
+		}
+
+		for j, pkgfile := range tpkg {
+			if err := rewriteFile(dir, fset, importer, importPath, rpkgs[i], pkgfile.name, pkgfile.ast, j == addImportable); err != nil {
+				return nil, err
+			}
+		}
+	}
+
+	return rpkgs, nil
+}
+
+// RewriteBuffer rewrites the contents of a single file, in a buffer.
+// It returns a modified buffer. The filename parameter is only used
+// for error messages.
+func RewriteBuffer(importer *Importer, filename string, file []byte) ([]byte, error) {
+	fset := token.NewFileSet()
+	pf, err := parser.ParseFile(fset, filename, file, parser.ParseTypeParams)
+	if err != nil {
+		return nil, err
+	}
+	var merr multiErr
+	conf := types.Config{
+		Importer: importer,
+		Error:    merr.add,
+	}
+	tpkg, err := conf.Check(pf.Name.Name, fset, []*ast.File{pf}, importer.info)
+	if err != nil {
+		return nil, fmt.Errorf("type checking failed for %s\n%v", pf.Name.Name, merr)
+	}
+	importer.addIDs(pf)
+	if err := rewriteAST(fset, importer, "", tpkg, pf, true); err != nil {
+		return nil, err
+	}
+	var buf bytes.Buffer
+	fmt.Fprintln(&buf, rewritePrefix)
+	if err := config.Fprint(&buf, fset, pf); err != nil {
+		return nil, err
+	}
+	return buf.Bytes(), nil
+}
+
+// go2Files returns the list of files in dir with a .go2 extension
+// and a list of files with a .go extension.
+// This returns an error if it finds any .go files that do not start
+// with rewritePrefix.
+func go2Files(dir string) (go2files []string, gofiles []string, err error) {
+	f, err := os.Open(dir)
+	if err != nil {
+		return nil, nil, err
+	}
+	defer f.Close()
+
+	files, err := f.Readdirnames(0)
+	if err != nil {
+		return nil, nil, fmt.Errorf("reading directory %s: %w", dir, err)
+
+	}
+
+	go2files = make([]string, 0, len(files))
+	gofiles = make([]string, 0, len(files))
+	for _, f := range files {
+		switch filepath.Ext(f) {
+		case ".go2":
+			go2files = append(go2files, f)
+		case ".go":
+			gofiles = append(gofiles, f)
+		}
+	}
+
+	return go2files, gofiles, nil
+}
+
+// checkAndRemoveGofiles looks through all the .go files.
+// Any .go file that starts with rewritePrefix is removed.
+// Any other .go file is reported as an error.
+// This is intended to make it harder for go2go to break a
+// traditional Go package.
+func checkAndRemoveGofiles(dir string, gofiles []string) error {
+	for _, f := range gofiles {
+		if err := checkGoFile(dir, f); err != nil {
+			return err
+		}
+		if err := os.Remove(filepath.Join(dir, f)); err != nil {
+			return err
+		}
+	}
+	return nil
+}
+
+// checkGofile reports an error if the file does not start with rewritePrefix.
+func checkGoFile(dir, f string) error {
+	o, err := os.Open(filepath.Join(dir, f))
+	if err != nil {
+		return err
+	}
+	defer o.Close()
+	var buf [100]byte
+	n, err := o.Read(buf[:])
+	if n > 0 && !strings.HasPrefix(string(buf[:n]), rewritePrefix) {
+		return fmt.Errorf("Go file %s was not created by go2go", f)
+	}
+	if err != nil && err != io.EOF {
+		return err
+	}
+	return nil
+}
+
+// parseFiles parses a list of .go2 files.
+func parseFiles(importer *Importer, dir string, go2files []string, fset *token.FileSet) ([]*ast.Package, error) {
+	pkgs := make(map[string]*ast.Package)
+	for _, go2f := range go2files {
+		mode := parser.ParseTypeParams
+
+		filename := filepath.Join(dir, go2f)
+		pf, err := parser.ParseFile(fset, filename, nil, mode)
+		if err != nil {
+			return nil, err
+		}
+
+		name := pf.Name.Name
+		pkg, ok := pkgs[name]
+		if !ok {
+			pkg = &ast.Package{
+				Name:  name,
+				Files: make(map[string]*ast.File),
+			}
+			pkgs[name] = pkg
+		}
+		pkg.Files[filename] = pf
+	}
+
+	rpkgs := make([]*ast.Package, 0, len(pkgs))
+	for _, pkg := range pkgs {
+		rpkgs = append(rpkgs, pkg)
+	}
+	sort.Slice(rpkgs, func(i, j int) bool {
+		return rpkgs[i].Name < rpkgs[j].Name
+	})
+
+	return rpkgs, nil
+}
+
+// multiErr is an error value that accumulates type checking errors.
+type multiErr []error
+
+// The add methods adds another error to a multiErr.
+func (m *multiErr) add(err error) {
+	*m = append(*m, err)
+}
+
+// The Error method returns the accumulated errors.
+func (m multiErr) Error() string {
+	if len(m) == 0 {
+		return "internal error: empty multiErr"
+	}
+	var sb strings.Builder
+	for _, e := range m {
+		fmt.Fprintln(&sb, e)
+	}
+	return sb.String()
+}
diff --git a/src/go/go2go/importer.go b/src/go/go2go/importer.go
new file mode 100644
index 0000000..6c92730
--- /dev/null
+++ b/src/go/go2go/importer.go
@@ -0,0 +1,414 @@
+// Copyright 2020 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package go2go
+
+import (
+	"fmt"
+	"go/ast"
+	"go/build"
+	"go/importer"
+	"go/parser"
+	"go/token"
+	"go/types"
+	"internal/goroot"
+	"io/ioutil"
+	"log"
+	"os"
+	"os/exec"
+	"path/filepath"
+	"runtime"
+	"sort"
+	"strings"
+)
+
+// Importer implements the types.ImporterFrom interface.
+// It looks for Go2 packages using GO2PATH.
+// Imported Go2 packages are rewritten to normal Go packages.
+// This type also tracks references across imported packages.
+type Importer struct {
+	// The default importer, for Go1 packages.
+	defaultImporter types.ImporterFrom
+
+	// Temporary directory used to rewrite packages.
+	tmpdir string
+
+	// Aggregated info from go/types.
+	info *types.Info
+
+	// Map from import path to directory holding rewritten files.
+	translated map[string]string
+
+	// Map from import path to package information.
+	packages map[string]*types.Package
+
+	// Map from import path to list of import paths that it imports.
+	imports map[string][]string
+
+	// Map from Object to AST function declaration for
+	// parameterized functions.
+	idToFunc map[types.Object]*ast.FuncDecl
+
+	// Map from Object to AST type definition for parameterized types.
+	idToTypeSpec map[types.Object]*ast.TypeSpec
+
+	// Map from a Package to the instantiations we've created
+	// for that package. This doesn't really belong here,
+	// since it doesn't deal with import information,
+	// but Importer is a useful common location to store the data.
+	instantiations map[*types.Package]*instantiations
+}
+
+var _ types.ImporterFrom = &Importer{}
+
+// NewImporter returns a new Importer.
+// The tmpdir will become a GOPATH with translated files.
+func NewImporter(tmpdir string) *Importer {
+	info := &types.Info{
+		Types:    make(map[ast.Expr]types.TypeAndValue),
+		Inferred: make(map[ast.Expr]types.Inferred),
+		Defs:     make(map[*ast.Ident]types.Object),
+		Uses:     make(map[*ast.Ident]types.Object),
+	}
+	return &Importer{
+		defaultImporter: importer.Default().(types.ImporterFrom),
+		tmpdir:          tmpdir,
+		info:            info,
+		translated:      make(map[string]string),
+		packages:        make(map[string]*types.Package),
+		imports:         make(map[string][]string),
+		idToFunc:        make(map[types.Object]*ast.FuncDecl),
+		idToTypeSpec:    make(map[types.Object]*ast.TypeSpec),
+		instantiations:  make(map[*types.Package]*instantiations),
+	}
+}
+
+// Import should never be called. This is the old API; current code
+// uses ImportFrom. This method still needs to be defined in order
+// to implement the interface.
+func (imp *Importer) Import(path string) (*types.Package, error) {
+	log.Fatal("unexpected call to Import method")
+	return nil, nil
+}
+
+// ImportFrom looks for a Go2 package, and if not found tries the
+// default importer.
+func (imp *Importer) ImportFrom(importPath, dir string, mode types.ImportMode) (*types.Package, error) {
+	if build.IsLocalImport(importPath) {
+		return imp.localImport(importPath, dir)
+	}
+
+	if imp.translated[importPath] != "" {
+		tpkg, ok := imp.packages[importPath]
+		if !ok {
+			return nil, fmt.Errorf("circular import when processing %q", importPath)
+		}
+		return tpkg, nil
+	}
+
+	var pdir string
+	if go2path := os.Getenv("GO2PATH"); go2path != "" {
+		pdir = imp.findFromPath(go2path, importPath)
+	}
+	if pdir == "" {
+		bpkg, err := build.Import(importPath, dir, build.FindOnly)
+		if err != nil {
+			return nil, err
+		}
+		pdir = bpkg.Dir
+	}
+
+	// If the directory holds .go2 files, we need to translate them.
+	fdir, err := os.Open(pdir)
+	if err != nil {
+		return nil, err
+	}
+	defer fdir.Close()
+	names, err := fdir.Readdirnames(-1)
+	if err != nil {
+		return nil, err
+	}
+	var gofiles, go2files []string
+	for _, name := range names {
+		switch filepath.Ext(name) {
+		case ".go":
+			gofiles = append(gofiles, name)
+		case ".go2":
+			go2files = append(go2files, name)
+		}
+	}
+
+	if len(go2files) == 0 {
+		return imp.importGo1Package(importPath, dir, mode, pdir, gofiles)
+	}
+
+	if len(gofiles) > 0 {
+		for _, gofile := range gofiles {
+			if err := checkGoFile(pdir, gofile); err != nil {
+				return nil, err
+			}
+		}
+	}
+
+	tdir := filepath.Join(imp.tmpdir, "src", importPath)
+	if err := os.MkdirAll(tdir, 0755); err != nil {
+		return nil, err
+	}
+	for _, name := range go2files {
+		data, err := ioutil.ReadFile(filepath.Join(pdir, name))
+		if err != nil {
+			return nil, err
+		}
+		if err := ioutil.WriteFile(filepath.Join(tdir, name), data, 0644); err != nil {
+			return nil, err
+		}
+	}
+
+	imp.translated[importPath] = tdir
+
+	tpkgs, err := rewriteToPkgs(imp, importPath, tdir)
+	if err != nil {
+		return nil, err
+	}
+
+	switch len(tpkgs) {
+	case 1:
+		return tpkgs[0], nil
+	case 2:
+		if strings.HasSuffix(tpkgs[0].Name(), "_test") {
+			return tpkgs[1], nil
+		} else if strings.HasSuffix(tpkgs[1].Name(), "_test") {
+			return tpkgs[0], nil
+		}
+	}
+
+	return nil, fmt.Errorf("unexpected number of packages (%d) for %q (directory %q)", len(tpkgs), importPath, pdir)
+}
+
+// findFromPath looks for a directory under gopath.
+func (imp *Importer) findFromPath(gopath, dir string) string {
+	if filepath.IsAbs(dir) || build.IsLocalImport(dir) {
+		return ""
+	}
+	for _, pd := range strings.Split(gopath, string(os.PathListSeparator)) {
+		d := filepath.Join(pd, "src", dir)
+		if fi, err := os.Stat(d); err == nil && fi.IsDir() {
+			return d
+		}
+	}
+	return ""
+}
+
+// importGo1Package handles importing a package with .go files rather
+// than .go2 files. The default importer can do this if the package
+// has been installed, but not otherwise. Installing the package using
+// "go install" won't work if the Go 1 package depends on a Go 2 package.
+// So use the default importer for a package in the standard library,
+// and otherwise use go/types.
+func (imp *Importer) importGo1Package(importPath, dir string, mode types.ImportMode, pdir string, gofiles []string) (*types.Package, error) {
+	if goroot.IsStandardPackage(runtime.GOROOT(), "gc", importPath) {
+		return imp.defaultImporter.ImportFrom(importPath, dir, mode)
+	}
+
+	if len(gofiles) == 0 {
+		return nil, fmt.Errorf("importing %q: no Go files in %s", importPath, pdir)
+	}
+
+	fset := token.NewFileSet()
+	filter := func(fi os.FileInfo) bool {
+		return !strings.HasSuffix(fi.Name(), "_test.go")
+	}
+	pkgs, err := parser.ParseDir(fset, pdir, filter, 0)
+	if err != nil {
+		return nil, err
+	}
+	if len(pkgs) > 1 {
+		return nil, fmt.Errorf("importing %q: multiple Go packages in %s", importPath, pdir)
+	}
+
+	var apkg *ast.Package
+	for _, apkg = range pkgs {
+		break
+	}
+
+	var asts []*ast.File
+	for _, f := range apkg.Files {
+		asts = append(asts, f)
+	}
+	sort.Slice(asts, func(i, j int) bool {
+		return asts[i].Name.Name < asts[j].Name.Name
+	})
+
+	var merr multiErr
+	conf := types.Config{
+		Importer: imp,
+		Error:    merr.add,
+	}
+	tpkg, err := conf.Check(importPath, fset, asts, imp.info)
+	if err != nil {
+		return nil, merr
+	}
+
+	return tpkg, nil
+}
+
+// installGo1Package runs "go install" to install a package.
+// This is used for Go 1 packages, because the default
+// importer looks at .a files, not sources.
+// This is best effort; we don't report an error.
+func (imp *Importer) installGo1Package(dir string) {
+	gotool := filepath.Join(runtime.GOROOT(), "bin", "go")
+	cmd := exec.Command(gotool, "install")
+	cmd.Dir = dir
+	cmd.Run()
+}
+
+// Register registers a package under an import path.
+// This is for tests that use directives like //compiledir.
+func (imp *Importer) Register(importPath string, tpkgs []*types.Package) error {
+	switch len(tpkgs) {
+	case 1:
+		imp.packages[importPath] = tpkgs[0]
+		return nil
+	case 2:
+		if strings.HasSuffix(tpkgs[0].Name(), "_test") {
+			imp.packages[importPath] = tpkgs[1]
+			return nil
+		} else if strings.HasSuffix(tpkgs[1].Name(), "_test") {
+			imp.packages[importPath] = tpkgs[0]
+			return nil
+		}
+	}
+	return fmt.Errorf("unexpected number of packages (%d) for %q", len(tpkgs), importPath)
+}
+
+// localImport handles a local import such as
+//     import "./a"
+// This is for tests that use directives like //compiledir.
+func (imp *Importer) localImport(importPath, dir string) (*types.Package, error) {
+	tpkg, ok := imp.packages[strings.TrimPrefix(importPath, "./")]
+	if !ok {
+		return nil, fmt.Errorf("cannot find local import %q", importPath)
+	}
+	return tpkg, nil
+}
+
+// record records information for a package, for use when working
+// with packages that import this one.
+func (imp *Importer) record(pkgName string, pkgfiles []namedAST, importPath string, tpkg *types.Package, asts []*ast.File) {
+	if !strings.HasSuffix(pkgName, "_test") {
+		if importPath != "" {
+			imp.packages[importPath] = tpkg
+		}
+		imp.imports[importPath] = imp.collectImports(asts)
+	}
+	for _, nast := range pkgfiles {
+		imp.addIDs(nast.ast)
+	}
+}
+
+// collectImports returns all the imports paths imported by any of the ASTs.
+func (imp *Importer) collectImports(asts []*ast.File) []string {
+	m := make(map[string]bool)
+	for _, a := range asts {
+		for _, decl := range a.Decls {
+			gen, ok := decl.(*ast.GenDecl)
+			if !ok || gen.Tok != token.IMPORT {
+				continue
+			}
+			for _, spec := range gen.Specs {
+				imp := spec.(*ast.ImportSpec)
+				if imp.Name != nil {
+					// We don't try to handle import aliases.
+					continue
+				}
+				path := strings.TrimPrefix(strings.TrimSuffix(imp.Path.Value, `"`), `"`)
+				m[path] = true
+			}
+		}
+	}
+	s := make([]string, 0, len(m))
+	for p := range m {
+		s = append(s, p)
+	}
+	sort.Strings(s)
+	return s
+}
+
+// addIDs finds IDs for generic functions and types and adds them to a map.
+func (imp *Importer) addIDs(f *ast.File) {
+	for _, decl := range f.Decls {
+		switch decl := decl.(type) {
+		case *ast.FuncDecl:
+			if isParameterizedFuncDecl(decl, imp.info) {
+				obj, ok := imp.info.Defs[decl.Name]
+				if !ok {
+					panic(fmt.Sprintf("no types.Object for %q", decl.Name.Name))
+				}
+				imp.idToFunc[obj] = decl
+			}
+		case *ast.GenDecl:
+			if decl.Tok == token.TYPE {
+				for _, s := range decl.Specs {
+					ts := s.(*ast.TypeSpec)
+					obj, ok := imp.info.Defs[ts.Name]
+					if !ok {
+						panic(fmt.Sprintf("no types.Object for %q", ts.Name.Name))
+					}
+					imp.idToTypeSpec[obj] = ts
+				}
+			}
+		}
+	}
+}
+
+// lookupPackage looks up a package by path.
+func (imp *Importer) lookupPackage(path string) (*types.Package, bool) {
+	pkg, ok := imp.packages[strings.TrimPrefix(path, "./")]
+	return pkg, ok
+}
+
+// lookupFunc looks up a function by Object.
+func (imp *Importer) lookupFunc(obj types.Object) (*ast.FuncDecl, bool) {
+	decl, ok := imp.idToFunc[obj]
+	return decl, ok
+}
+
+// lookupTypeSpec looks up a type by Object.
+func (imp *Importer) lookupTypeSpec(obj types.Object) (*ast.TypeSpec, bool) {
+	ts, ok := imp.idToTypeSpec[obj]
+	return ts, ok
+}
+
+// transitiveImports returns all the transitive imports of an import path.
+func (imp *Importer) transitiveImports(path string) []string {
+	return imp.gatherTransitiveImports(path, make(map[string]bool))
+}
+
+// gatherTransitiveImports returns all the transitive imports of an import path,
+// using a map to avoid duplicate work.
+func (imp *Importer) gatherTransitiveImports(path string, m map[string]bool) []string {
+	imports := imp.imports[path]
+	if len(imports) == 0 {
+		return nil
+	}
+	var r []string
+	for _, im := range imports {
+		r = append(r, im)
+		if !m[im] {
+			m[im] = true
+			r = append(r, imp.gatherTransitiveImports(im, m)...)
+		}
+	}
+	dup := make(map[string]bool)
+	for _, p := range r {
+		dup[p] = true
+	}
+	r = make([]string, 0, len(dup))
+	for p := range dup {
+		r = append(r, p)
+	}
+	sort.Strings(r)
+	return r
+}
diff --git a/src/go/go2go/instantiate.go b/src/go/go2go/instantiate.go
new file mode 100644
index 0000000..e9566cb
--- /dev/null
+++ b/src/go/go2go/instantiate.go
@@ -0,0 +1,980 @@
+// Copyright 2020 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package go2go
+
+import (
+	"fmt"
+	"go/ast"
+	"go/token"
+	"go/types"
+)
+
+// typeArgs holds type arguments for the function that we are instantiating.
+// We can look them up either with a types.Object associated with an ast.Ident,
+// or with a types.TypeParam.
+type typeArgs struct {
+	types []types.Type // type arguments in order
+	toAST map[types.Object]ast.Expr
+	toTyp map[*types.TypeParam]types.Type
+}
+
+// newTypeArgs returns a new typeArgs value.
+func newTypeArgs(typeTypes []types.Type) *typeArgs {
+	return &typeArgs{
+		types: typeTypes,
+		toAST: make(map[types.Object]ast.Expr),
+		toTyp: make(map[*types.TypeParam]types.Type),
+	}
+}
+
+// typeArgsFromFields builds mappings from a list of type parameters
+// expressed as ast.Field values.
+func typeArgsFromFields(t *translator, astTypes []ast.Expr, typeTypes []types.Type, tparams []*ast.Field) *typeArgs {
+	ta := newTypeArgs(typeTypes)
+	i := 0
+	for _, tf := range tparams {
+		for _, tn := range tf.Names {
+			obj, ok := t.importer.info.Defs[tn]
+			if !ok {
+				panic(fmt.Sprintf("no object for type parameter %q", tn))
+			}
+			objType := obj.Type()
+			objParam, ok := objType.(*types.TypeParam)
+			if !ok {
+				panic(fmt.Sprintf("%v is not a TypeParam", objParam))
+			}
+			ta.add(obj, objParam, astTypes[i], typeTypes[i])
+			i++
+		}
+	}
+	return ta
+}
+
+// typeArgsFromExprs builds mappings from a list of type parameters
+// expressed as ast.Expr values.
+func typeArgsFromExprs(t *translator, astTypes []ast.Expr, typeTypes []types.Type, tparams []ast.Expr) *typeArgs {
+	ta := newTypeArgs(typeTypes)
+	for i, ti := range tparams {
+		obj, ok := t.importer.info.Defs[ti.(*ast.Ident)]
+		if !ok {
+			panic(fmt.Sprintf("no object for type parameter %q", ti))
+		}
+		objType := obj.Type()
+		objParam, ok := objType.(*types.TypeParam)
+		if !ok {
+			panic(fmt.Sprintf("%v is not a TypeParam", objParam))
+		}
+		ta.add(obj, objParam, astTypes[i], typeTypes[i])
+	}
+	return ta
+}
+
+// add adds mappings for obj to ast and typ.
+func (ta *typeArgs) add(obj types.Object, objParam *types.TypeParam, ast ast.Expr, typ types.Type) {
+	ta.toAST[obj] = ast
+	ta.toTyp[objParam] = typ
+}
+
+// ast returns the AST for obj, and reports whether it exists.
+func (ta *typeArgs) ast(obj types.Object) (ast.Expr, bool) {
+	e, ok := ta.toAST[obj]
+	return e, ok
+}
+
+// typ returns the Type for param, and reports whether it exists.
+func (ta *typeArgs) typ(param *types.TypeParam) (types.Type, bool) {
+	t, ok := ta.toTyp[param]
+	return t, ok
+}
+
+// instantiateFunction creates a new instantiation of a function.
+func (t *translator) instantiateFunction(qid qualifiedIdent, astTypes []ast.Expr, typeTypes []types.Type) (*ast.Ident, error) {
+	name, err := t.instantiatedName(qid, typeTypes)
+	if err != nil {
+		return nil, err
+	}
+
+	decl, err := t.findFuncDecl(qid)
+	if err != nil {
+		return nil, err
+	}
+
+	ta := typeArgsFromFields(t, astTypes, typeTypes, decl.Type.TParams.List)
+
+	instIdent := ast.NewIdent(name)
+
+	newDecl := &ast.FuncDecl{
+		Doc:  decl.Doc,
+		Recv: t.instantiateFieldList(ta, decl.Recv),
+		Name: instIdent,
+		Type: t.instantiateExpr(ta, decl.Type).(*ast.FuncType),
+		Body: t.instantiateBlockStmt(ta, decl.Body),
+	}
+	t.newDecls = append(t.newDecls, newDecl)
+
+	return instIdent, nil
+}
+
+// findFuncDecl looks for the FuncDecl for qid.
+func (t *translator) findFuncDecl(qid qualifiedIdent) (*ast.FuncDecl, error) {
+	obj := t.findTypesObject(qid)
+	if obj == nil {
+		return nil, fmt.Errorf("could not find Object for %q", qid)
+	}
+	decl, ok := t.importer.lookupFunc(obj)
+	if !ok {
+		return nil, fmt.Errorf("could not find function body for %q", qid)
+	}
+	return decl, nil
+}
+
+// findTypesObject looks up the types.Object for qid.
+// It returns nil if the ID is not found.
+func (t *translator) findTypesObject(qid qualifiedIdent) types.Object {
+	if qid.pkg == nil {
+		if obj := t.importer.info.ObjectOf(qid.ident); obj != nil {
+			// Ignore an embedded struct field.
+			// We want the type, not the field.
+			if _, ok := obj.(*types.Var); !ok {
+				return obj
+			}
+		}
+		return t.tpkg.Scope().Lookup(qid.ident.Name)
+	} else {
+		return qid.pkg.Scope().Lookup(qid.ident.Name)
+	}
+}
+
+// instantiateType creates a new instantiation of a type.
+func (t *translator) instantiateTypeDecl(qid qualifiedIdent, typ *types.Named, astTypes []ast.Expr, typeTypes []types.Type, instIdent *ast.Ident) (types.Type, error) {
+	spec, err := t.findTypeSpec(qid)
+	if err != nil {
+		return nil, err
+	}
+
+	ta := typeArgsFromFields(t, astTypes, typeTypes, spec.TParams.List)
+
+	newSpec := &ast.TypeSpec{
+		Doc:     spec.Doc,
+		Name:    instIdent,
+		Assign:  spec.Assign,
+		Type:    t.instantiateExpr(ta, spec.Type),
+		Comment: spec.Comment,
+	}
+	newDecl := &ast.GenDecl{
+		Tok:   token.TYPE,
+		Specs: []ast.Spec{newSpec},
+	}
+	t.newDecls = append(t.newDecls, newDecl)
+
+	// If typ already has type arguments, then they should be correct.
+	// If it doesn't, we want to use typeTypes.
+	typeWithTargs := typ
+	if len(typ.TArgs()) == 0 {
+		typeWithTargs = t.updateTArgs(typ, typeTypes)
+	}
+
+	instType := t.instantiateType(ta, typeWithTargs)
+
+	t.setType(instIdent, instType)
+
+	nm := typ.NumMethods()
+	for i := 0; i < nm; i++ {
+		method := typ.Method(i)
+		mast, ok := t.importer.lookupFunc(method)
+		if !ok {
+			panic(fmt.Sprintf("no AST for method %v", method))
+		}
+		rtyp := mast.Recv.List[0].Type
+		newRtype := ast.Expr(ast.NewIdent(instIdent.Name))
+		if p, ok := rtyp.(*ast.StarExpr); ok {
+			rtyp = p.X
+			newRtype = &ast.StarExpr{
+				X: newRtype,
+			}
+		}
+		var tparams []ast.Expr
+		switch rtyp := rtyp.(type) {
+		case *ast.CallExpr:
+			tparams = rtyp.Args
+		case *ast.IndexExpr:
+			tparams = []ast.Expr{rtyp.Index}
+		default:
+			panic("unexpected AST type")
+		}
+		ta := typeArgsFromExprs(t, astTypes, typeTypes, tparams)
+		var names []*ast.Ident
+		if mnames := mast.Recv.List[0].Names; len(mnames) > 0 {
+			names = []*ast.Ident{mnames[0]}
+		}
+		newDecl := &ast.FuncDecl{
+			Doc: mast.Doc,
+			Recv: &ast.FieldList{
+				Opening: mast.Recv.Opening,
+				List: []*ast.Field{
+					{
+						Doc:     mast.Recv.List[0].Doc,
+						Names:   names,
+						Type:    newRtype,
+						Comment: mast.Recv.List[0].Comment,
+					},
+				},
+				Closing: mast.Recv.Closing,
+			},
+			Name: mast.Name,
+			Type: t.instantiateExpr(ta, mast.Type).(*ast.FuncType),
+			Body: t.instantiateBlockStmt(ta, mast.Body),
+		}
+		t.newDecls = append(t.newDecls, newDecl)
+	}
+
+	return instType, nil
+}
+
+// findTypeSpec looks for the TypeSpec for qid.
+func (t *translator) findTypeSpec(qid qualifiedIdent) (*ast.TypeSpec, error) {
+	obj := t.findTypesObject(qid)
+	if obj == nil {
+		return nil, fmt.Errorf("could not find Object for %q", qid)
+	}
+	spec, ok := t.importer.lookupTypeSpec(obj)
+	if !ok {
+		return nil, fmt.Errorf("could not find type spec for %q", qid)
+	}
+
+	if spec.Assign != token.NoPos {
+		// This is a type alias that we need to resolve.
+		typ := t.lookupType(spec.Type)
+		if typ != nil {
+			if named, ok := typ.(*types.Named); ok {
+				if s, ok := t.importer.lookupTypeSpec(named.Obj()); ok {
+					spec = s
+				}
+			}
+		}
+	}
+
+	if spec.TParams == nil {
+		return nil, fmt.Errorf("found type spec for %q but it has no type parameters", qid)
+	}
+
+	return spec, nil
+}
+
+// instantiateDecl instantiates a declaration.
+func (t *translator) instantiateDecl(ta *typeArgs, d ast.Decl) ast.Decl {
+	switch d := d.(type) {
+	case nil:
+		return nil
+	case *ast.GenDecl:
+		if len(d.Specs) == 0 {
+			return d
+		}
+		nspecs := make([]ast.Spec, len(d.Specs))
+		changed := false
+		for i, s := range d.Specs {
+			ns := t.instantiateSpec(ta, s)
+			if ns != s {
+				changed = true
+			}
+			nspecs[i] = ns
+		}
+		if !changed {
+			return d
+		}
+		return &ast.GenDecl{
+			Doc:    d.Doc,
+			TokPos: d.TokPos,
+			Tok:    d.Tok,
+			Lparen: d.Lparen,
+			Specs:  nspecs,
+			Rparen: d.Rparen,
+		}
+	default:
+		panic(fmt.Sprintf("unimplemented Decl %T", d))
+	}
+}
+
+// instantiateSpec instantiates a spec node.
+func (t *translator) instantiateSpec(ta *typeArgs, s ast.Spec) ast.Spec {
+	switch s := s.(type) {
+	case nil:
+		return nil
+	case *ast.ValueSpec:
+		typ := t.instantiateExpr(ta, s.Type)
+		values, changed := t.instantiateExprList(ta, s.Values)
+		if typ == s.Type && !changed {
+			return s
+		}
+		return &ast.ValueSpec{
+			Doc:     s.Doc,
+			Names:   s.Names,
+			Type:    typ,
+			Values:  values,
+			Comment: s.Comment,
+		}
+	case *ast.TypeSpec:
+		if s.TParams != nil {
+			t.err = fmt.Errorf("%s: go2go tool does not support local parameterized types", t.fset.Position(s.Pos()))
+			return nil
+		}
+		typ := t.instantiateExpr(ta, s.Type)
+		if typ == s.Type {
+			return s
+		}
+		return &ast.TypeSpec{
+			Doc:     s.Doc,
+			Name:    s.Name,
+			Assign:  s.Assign,
+			Type:    typ,
+			Comment: s.Comment,
+		}
+	default:
+		panic(fmt.Sprintf("unimplemented Spec %T", s))
+	}
+}
+
+// instantiateStmt instantiates a statement.
+func (t *translator) instantiateStmt(ta *typeArgs, s ast.Stmt) ast.Stmt {
+	switch s := s.(type) {
+	case nil:
+		return nil
+	case *ast.DeclStmt:
+		decl := t.instantiateDecl(ta, s.Decl)
+		if decl == s.Decl {
+			return s
+		}
+		return &ast.DeclStmt{
+			Decl: decl,
+		}
+	case *ast.EmptyStmt:
+		return s
+	case *ast.LabeledStmt:
+		stmt := t.instantiateStmt(ta, s.Stmt)
+		if stmt == s.Stmt {
+			return s
+		}
+		return &ast.LabeledStmt{
+			Label: s.Label,
+			Colon: s.Colon,
+			Stmt:  stmt,
+		}
+	case *ast.ExprStmt:
+		x := t.instantiateExpr(ta, s.X)
+		if x == s.X {
+			return s
+		}
+		return &ast.ExprStmt{
+			X: x,
+		}
+	case *ast.SendStmt:
+		ch := t.instantiateExpr(ta, s.Chan)
+		value := t.instantiateExpr(ta, s.Value)
+		if ch == s.Chan && value == s.Value {
+			return s
+		}
+		return &ast.SendStmt{
+			Chan:  ch,
+			Arrow: s.Arrow,
+			Value: value,
+		}
+	case *ast.IncDecStmt:
+		x := t.instantiateExpr(ta, s.X)
+		if x == s.X {
+			return s
+		}
+		return &ast.IncDecStmt{
+			X:      x,
+			TokPos: s.TokPos,
+			Tok:    s.Tok,
+		}
+	case *ast.AssignStmt:
+		lhs, lchanged := t.instantiateExprList(ta, s.Lhs)
+		rhs, rchanged := t.instantiateExprList(ta, s.Rhs)
+		if !lchanged && !rchanged {
+			return s
+		}
+		return &ast.AssignStmt{
+			Lhs:    lhs,
+			TokPos: s.TokPos,
+			Tok:    s.Tok,
+			Rhs:    rhs,
+		}
+	case *ast.GoStmt:
+		call := t.instantiateExpr(ta, s.Call).(*ast.CallExpr)
+		if call == s.Call {
+			return s
+		}
+		return &ast.GoStmt{
+			Go:   s.Go,
+			Call: call,
+		}
+	case *ast.DeferStmt:
+		call := t.instantiateExpr(ta, s.Call).(*ast.CallExpr)
+		if call == s.Call {
+			return s
+		}
+		return &ast.DeferStmt{
+			Defer: s.Defer,
+			Call:  call,
+		}
+	case *ast.ReturnStmt:
+		results, changed := t.instantiateExprList(ta, s.Results)
+		if !changed {
+			return s
+		}
+		return &ast.ReturnStmt{
+			Return:  s.Return,
+			Results: results,
+		}
+	case *ast.BranchStmt:
+		return s
+	case *ast.BlockStmt:
+		return t.instantiateBlockStmt(ta, s)
+	case *ast.IfStmt:
+		init := t.instantiateStmt(ta, s.Init)
+		cond := t.instantiateExpr(ta, s.Cond)
+		body := t.instantiateBlockStmt(ta, s.Body)
+		els := t.instantiateStmt(ta, s.Else)
+		if init == s.Init && cond == s.Cond && body == s.Body && els == s.Else {
+			return s
+		}
+		return &ast.IfStmt{
+			If:   s.If,
+			Init: init,
+			Cond: cond,
+			Body: body,
+			Else: els,
+		}
+	case *ast.CaseClause:
+		list, listChanged := t.instantiateExprList(ta, s.List)
+		body, bodyChanged := t.instantiateStmtList(ta, s.Body)
+		if !listChanged && !bodyChanged {
+			return s
+		}
+		return &ast.CaseClause{
+			Case:  s.Case,
+			List:  list,
+			Colon: s.Colon,
+			Body:  body,
+		}
+	case *ast.SwitchStmt:
+		init := t.instantiateStmt(ta, s.Init)
+		tag := t.instantiateExpr(ta, s.Tag)
+		body := t.instantiateBlockStmt(ta, s.Body)
+		if init == s.Init && tag == s.Tag && body == s.Body {
+			return s
+		}
+		return &ast.SwitchStmt{
+			Switch: s.Switch,
+			Init:   init,
+			Tag:    tag,
+			Body:   body,
+		}
+	case *ast.TypeSwitchStmt:
+		init := t.instantiateStmt(ta, s.Init)
+		assign := t.instantiateStmt(ta, s.Assign)
+		body := t.instantiateBlockStmt(ta, s.Body)
+		if init == s.Init && assign == s.Assign && body == s.Body {
+			return s
+		}
+		return &ast.TypeSwitchStmt{
+			Switch: s.Switch,
+			Init:   init,
+			Assign: assign,
+			Body:   body,
+		}
+	case *ast.CommClause:
+		comm := t.instantiateStmt(ta, s.Comm)
+		body, bodyChanged := t.instantiateStmtList(ta, s.Body)
+		if comm == s.Comm && !bodyChanged {
+			return s
+		}
+		return &ast.CommClause{
+			Case:  s.Case,
+			Comm:  comm,
+			Colon: s.Colon,
+			Body:  body,
+		}
+	case *ast.SelectStmt:
+		body := t.instantiateBlockStmt(ta, s.Body)
+		if body == s.Body {
+			return s
+		}
+		return &ast.SelectStmt{
+			Select: s.Select,
+			Body:   body,
+		}
+	case *ast.ForStmt:
+		init := t.instantiateStmt(ta, s.Init)
+		cond := t.instantiateExpr(ta, s.Cond)
+		post := t.instantiateStmt(ta, s.Post)
+		body := t.instantiateBlockStmt(ta, s.Body)
+		if init == s.Init && cond == s.Cond && post == s.Post && body == s.Body {
+			return s
+		}
+		return &ast.ForStmt{
+			For:  s.For,
+			Init: init,
+			Cond: cond,
+			Post: post,
+			Body: body,
+		}
+	case *ast.RangeStmt:
+		key := t.instantiateExpr(ta, s.Key)
+		value := t.instantiateExpr(ta, s.Value)
+		x := t.instantiateExpr(ta, s.X)
+		body := t.instantiateBlockStmt(ta, s.Body)
+		if key == s.Key && value == s.Value && x == s.X && body == s.Body {
+			return s
+		}
+		return &ast.RangeStmt{
+			For:    s.For,
+			Key:    key,
+			Value:  value,
+			TokPos: s.TokPos,
+			Tok:    s.Tok,
+			X:      x,
+			Body:   body,
+		}
+	default:
+		panic(fmt.Sprintf("unimplemented Stmt %T", s))
+	}
+}
+
+// instantiateBlockStmt instantiates a BlockStmt.
+func (t *translator) instantiateBlockStmt(ta *typeArgs, pbs *ast.BlockStmt) *ast.BlockStmt {
+	if pbs == nil {
+		return nil
+	}
+	changed := false
+	stmts := make([]ast.Stmt, len(pbs.List))
+	for i, s := range pbs.List {
+		is := t.instantiateStmt(ta, s)
+		stmts[i] = is
+		if is != s {
+			changed = true
+		}
+	}
+	if !changed {
+		return pbs
+	}
+	return &ast.BlockStmt{
+		Lbrace: pbs.Lbrace,
+		List:   stmts,
+		Rbrace: pbs.Rbrace,
+	}
+}
+
+// instantiateStmtList instantiates a statement list.
+func (t *translator) instantiateStmtList(ta *typeArgs, sl []ast.Stmt) ([]ast.Stmt, bool) {
+	nsl := make([]ast.Stmt, len(sl))
+	changed := false
+	for i, s := range sl {
+		ns := t.instantiateStmt(ta, s)
+		if ns != s {
+			changed = true
+		}
+		nsl[i] = ns
+	}
+	if !changed {
+		return sl, false
+	}
+	return nsl, true
+}
+
+// instantiateFieldList instantiates a field list.
+func (t *translator) instantiateFieldList(ta *typeArgs, fl *ast.FieldList) *ast.FieldList {
+	if fl == nil {
+		return nil
+	}
+	nfl := make([]*ast.Field, len(fl.List))
+	changed := false
+	for i, f := range fl.List {
+		nf := t.instantiateField(ta, f)
+		if nf != f {
+			changed = true
+		}
+		nfl[i] = nf
+	}
+	if !changed {
+		return fl
+	}
+	return &ast.FieldList{
+		Opening: fl.Opening,
+		List:    nfl,
+		Closing: fl.Closing,
+	}
+}
+
+// instantiateField instantiates a field.
+func (t *translator) instantiateField(ta *typeArgs, f *ast.Field) *ast.Field {
+	typ := t.instantiateExpr(ta, f.Type)
+	if typ == f.Type {
+		return f
+	}
+	return &ast.Field{
+		Doc:     f.Doc,
+		Names:   f.Names,
+		Type:    typ,
+		Tag:     f.Tag,
+		Comment: f.Comment,
+	}
+}
+
+// instantiateExpr instantiates an expression.
+func (t *translator) instantiateExpr(ta *typeArgs, e ast.Expr) ast.Expr {
+	var r ast.Expr
+	switch e := e.(type) {
+	case nil:
+		return nil
+	case *ast.Ident:
+		obj := t.importer.info.ObjectOf(e)
+		if obj != nil {
+			if typ, ok := ta.ast(obj); ok {
+				return typ
+			}
+		}
+		return e
+	case *ast.Ellipsis:
+		elt := t.instantiateExpr(ta, e.Elt)
+		if elt == e.Elt {
+			return e
+		}
+		return &ast.Ellipsis{
+			Ellipsis: e.Ellipsis,
+			Elt:      elt,
+		}
+	case *ast.BasicLit:
+		return e
+	case *ast.FuncLit:
+		typ := t.instantiateExpr(ta, e.Type).(*ast.FuncType)
+		body := t.instantiateBlockStmt(ta, e.Body)
+		if typ == e.Type && body == e.Body {
+			return e
+		}
+		return &ast.FuncLit{
+			Type: typ,
+			Body: body,
+		}
+	case *ast.CompositeLit:
+		typ := t.instantiateExpr(ta, e.Type)
+		elts, changed := t.instantiateExprList(ta, e.Elts)
+		if typ == e.Type && !changed {
+			return e
+		}
+		return &ast.CompositeLit{
+			Type:       typ,
+			Lbrace:     e.Lbrace,
+			Elts:       elts,
+			Rbrace:     e.Rbrace,
+			Incomplete: e.Incomplete,
+		}
+	case *ast.ParenExpr:
+		x := t.instantiateExpr(ta, e.X)
+		if x == e.X {
+			return e
+		}
+		return &ast.ParenExpr{
+			Lparen: e.Lparen,
+			X:      x,
+			Rparen: e.Rparen,
+		}
+	case *ast.SelectorExpr:
+		x := t.instantiateExpr(ta, e.X)
+
+		// If this is a reference to an instantiated embedded field,
+		// we may need to instantiate it. The actual instantiation
+		// is at the end of the function, as long as we create a
+		// a new SelectorExpr when needed.
+		instantiate := false
+		obj := t.importer.info.ObjectOf(e.Sel)
+		if obj != nil {
+			if f, ok := obj.(*types.Var); ok && f.Embedded() {
+				if named, ok := f.Type().(*types.Named); ok && len(named.TArgs()) > 0 && obj.Name() == named.Obj().Name() {
+					instantiate = true
+				}
+			}
+		}
+
+		if x == e.X && !instantiate {
+			return e
+		}
+		r = &ast.SelectorExpr{
+			X:   x,
+			Sel: e.Sel,
+		}
+	case *ast.IndexExpr:
+		x := t.instantiateExpr(ta, e.X)
+		index := t.instantiateExpr(ta, e.Index)
+		origInferred, haveInferred := t.importer.info.Inferred[e]
+		var newInferred types.Inferred
+		inferredChanged := false
+		if haveInferred {
+			for _, typ := range origInferred.Targs {
+				nt := t.instantiateType(ta, typ)
+				newInferred.Targs = append(newInferred.Targs, nt)
+				if nt != typ {
+					inferredChanged = true
+				}
+			}
+		}
+		if x == e.X && index == e.Index && !inferredChanged {
+			return e
+		}
+		r = &ast.IndexExpr{
+			X:      x,
+			Lbrack: e.Lbrack,
+			Index:  index,
+			Rbrack: e.Rbrack,
+		}
+		if haveInferred {
+			t.importer.info.Inferred[r] = newInferred
+		}
+	case *ast.SliceExpr:
+		x := t.instantiateExpr(ta, e.X)
+		low := t.instantiateExpr(ta, e.Low)
+		high := t.instantiateExpr(ta, e.High)
+		max := t.instantiateExpr(ta, e.Max)
+		if x == e.X && low == e.Low && high == e.High && max == e.Max {
+			return e
+		}
+		r = &ast.SliceExpr{
+			X:      x,
+			Lbrack: e.Lbrack,
+			Low:    low,
+			High:   high,
+			Max:    max,
+			Slice3: e.Slice3,
+			Rbrack: e.Rbrack,
+		}
+	case *ast.TypeAssertExpr:
+		x := t.instantiateExpr(ta, e.X)
+		typ := t.instantiateExpr(ta, e.Type)
+		if x == e.X && typ == e.Type {
+			return e
+		}
+		r = &ast.TypeAssertExpr{
+			X:      x,
+			Lparen: e.Lparen,
+			Type:   typ,
+			Rparen: e.Rparen,
+		}
+	case *ast.CallExpr:
+		fun := t.instantiateExpr(ta, e.Fun)
+		args, argsChanged := t.instantiateExprList(ta, e.Args)
+		origInferred, haveInferred := t.importer.info.Inferred[e]
+		var newInferred types.Inferred
+		inferredChanged := false
+		if haveInferred {
+			for _, typ := range origInferred.Targs {
+				nt := t.instantiateType(ta, typ)
+				newInferred.Targs = append(newInferred.Targs, nt)
+				if nt != typ {
+					inferredChanged = true
+				}
+			}
+			newInferred.Sig = t.instantiateType(ta, origInferred.Sig).(*types.Signature)
+			if newInferred.Sig != origInferred.Sig {
+				inferredChanged = true
+			}
+		}
+		if fun == e.Fun && !argsChanged && !inferredChanged {
+			return e
+		}
+		r = &ast.CallExpr{
+			Fun:      fun,
+			Lparen:   e.Lparen,
+			Args:     args,
+			Ellipsis: e.Ellipsis,
+			Rparen:   e.Rparen,
+		}
+		if haveInferred {
+			t.importer.info.Inferred[r] = newInferred
+		}
+	case *ast.StarExpr:
+		x := t.instantiateExpr(ta, e.X)
+		if x == e.X {
+			return e
+		}
+		r = &ast.StarExpr{
+			Star: e.Star,
+			X:    x,
+		}
+	case *ast.UnaryExpr:
+		x := t.instantiateExpr(ta, e.X)
+		if x == e.X {
+			return e
+		}
+		r = &ast.UnaryExpr{
+			OpPos: e.OpPos,
+			Op:    e.Op,
+			X:     x,
+		}
+	case *ast.BinaryExpr:
+		x := t.instantiateExpr(ta, e.X)
+		y := t.instantiateExpr(ta, e.Y)
+		if x == e.X && y == e.Y {
+			return e
+		}
+		r = &ast.BinaryExpr{
+			X:     x,
+			OpPos: e.OpPos,
+			Op:    e.Op,
+			Y:     y,
+		}
+	case *ast.KeyValueExpr:
+		key := t.instantiateExpr(ta, e.Key)
+		value := t.instantiateExpr(ta, e.Value)
+		if key == e.Key && value == e.Value {
+			return e
+		}
+		r = &ast.KeyValueExpr{
+			Key:   key,
+			Colon: e.Colon,
+			Value: value,
+		}
+	case *ast.ArrayType:
+		ln := t.instantiateExpr(ta, e.Len)
+		elt := t.instantiateExpr(ta, e.Elt)
+		if ln == e.Len && elt == e.Elt {
+			return e
+		}
+		r = &ast.ArrayType{
+			Lbrack: e.Lbrack,
+			Len:    ln,
+			Elt:    elt,
+		}
+	case *ast.StructType:
+		fields := e.Fields.List
+		newFields := make([]*ast.Field, 0, len(fields))
+		changed := false
+		for _, f := range fields {
+			newFields = append(newFields, f)
+			if len(f.Names) > 0 {
+				continue
+			}
+			isPtr := false
+			ftyp := f.Type
+			if star, ok := ftyp.(*ast.StarExpr); ok {
+				ftyp = star.X
+				isPtr = true
+			}
+			id, ok := ftyp.(*ast.Ident)
+			if !ok {
+				continue
+			}
+			typ := t.lookupType(id)
+			if typ == nil {
+				continue
+			}
+			typeParam, ok := typ.(*types.TypeParam)
+			if !ok {
+				continue
+			}
+			instType := t.instantiateType(ta, typeParam)
+			if isPtr {
+				instType = types.NewPointer(instType)
+			}
+			newField := &ast.Field{
+				Doc:     f.Doc,
+				Names:   []*ast.Ident{id},
+				Type:    t.typeToAST(instType),
+				Tag:     f.Tag,
+				Comment: f.Comment,
+			}
+			newFields[len(newFields)-1] = newField
+			changed = true
+		}
+		fl := e.Fields
+		if changed {
+			fl = &ast.FieldList{
+				Opening: fl.Opening,
+				List:    newFields,
+				Closing: fl.Closing,
+			}
+		}
+		newFl := t.instantiateFieldList(ta, fl)
+		if !changed && newFl == fl {
+			return e
+		}
+		r = &ast.StructType{
+			Struct:     e.Struct,
+			Fields:     newFl,
+			Incomplete: e.Incomplete,
+		}
+	case *ast.FuncType:
+		params := t.instantiateFieldList(ta, e.Params)
+		results := t.instantiateFieldList(ta, e.Results)
+		if e.TParams == nil && params == e.Params && results == e.Results {
+			return e
+		}
+		r = &ast.FuncType{
+			Func:    e.Func,
+			TParams: nil,
+			Params:  params,
+			Results: results,
+		}
+	case *ast.InterfaceType:
+		eMethods, eTypes := splitFieldList(e.Methods)
+		methods := t.instantiateFieldList(ta, eMethods)
+		types, typesChanged := t.instantiateExprList(ta, eTypes)
+		if methods == e.Methods && !typesChanged {
+			return e
+		}
+		r = &ast.InterfaceType{
+			Interface:  e.Interface,
+			Methods:    mergeFieldList(methods, types),
+			Incomplete: e.Incomplete,
+		}
+	case *ast.MapType:
+		key := t.instantiateExpr(ta, e.Key)
+		value := t.instantiateExpr(ta, e.Value)
+		if key == e.Key && value == e.Value {
+			return e
+		}
+		r = &ast.MapType{
+			Map:   e.Map,
+			Key:   key,
+			Value: value,
+		}
+	case *ast.ChanType:
+		value := t.instantiateExpr(ta, e.Value)
+		if value == e.Value {
+			return e
+		}
+		r = &ast.ChanType{
+			Begin: e.Begin,
+			Arrow: e.Arrow,
+			Dir:   e.Dir,
+			Value: value,
+		}
+	default:
+		panic(fmt.Sprintf("unimplemented Expr %T", e))
+	}
+
+	if et := t.lookupType(e); et != nil {
+		t.setType(r, t.instantiateType(ta, et))
+	}
+
+	return r
+}
+
+// instantiateExprList instantiates an expression list.
+func (t *translator) instantiateExprList(ta *typeArgs, el []ast.Expr) ([]ast.Expr, bool) {
+	nel := make([]ast.Expr, len(el))
+	changed := false
+	for i, e := range el {
+		ne := t.instantiateExpr(ta, e)
+		if ne != e {
+			changed = true
+		}
+		nel[i] = ne
+	}
+	if !changed {
+		return el, false
+	}
+	return nel, true
+}
diff --git a/src/go/go2go/names.go b/src/go/go2go/names.go
new file mode 100644
index 0000000..ec3bef2
--- /dev/null
+++ b/src/go/go2go/names.go
@@ -0,0 +1,75 @@
+// Copyright 2020 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package go2go
+
+import (
+	"fmt"
+	"go/types"
+	"strings"
+	"unicode"
+)
+
+// We use Oriya digit zero as a separator.
+// Do not use this character in your own identifiers.
+const nameSep = '୦'
+
+// We use Oriya digit eight to introduce a special character code.
+// Do not use this character in your own identifiers.
+const nameIntro = '୮'
+
+var nameCodes = map[rune]int{
+	' ':       0,
+	'*':       1,
+	';':       2,
+	',':       3,
+	'{':       4,
+	'}':       5,
+	'[':       6,
+	']':       7,
+	'(':       8,
+	')':       9,
+	'.':       10,
+	'<':       11,
+	'-':       12,
+	'/':       13,
+	nameSep:   14,
+	nameIntro: 15,
+}
+
+// instantiatedName returns the name of a newly instantiated function.
+func (t *translator) instantiatedName(qid qualifiedIdent, types []types.Type) (string, error) {
+	var sb strings.Builder
+	fmt.Fprintf(&sb, "instantiate%c", nameSep)
+	if qid.pkg != nil {
+		fmt.Fprintf(&sb, qid.pkg.Name())
+	}
+	fmt.Fprintf(&sb, "%c%s", nameSep, qid.ident.Name)
+	for _, typ := range types {
+		sb.WriteRune(nameSep)
+		s := t.withoutTags(typ).String()
+
+		// We have to uniquely translate s into a valid Go identifier.
+		// This is not possible in general but we assume that
+		// identifiers will not contain nameSep or nameIntro.
+		for _, r := range s {
+			if (unicode.IsLetter(r) || unicode.IsDigit(r) || r == '_') && r != nameSep && r != nameIntro {
+				sb.WriteRune(r)
+			} else {
+				code, ok := nameCodes[r]
+				if !ok {
+					panic(fmt.Sprintf("%s: unexpected type string character %q in %q", t.fset.Position(qid.ident.Pos()), r, s))
+				}
+				fmt.Fprintf(&sb, "%c%x", nameIntro, code)
+			}
+		}
+	}
+	return sb.String(), nil
+}
+
+// importableName returns a name that we define in each package, so that
+// we have something to import to avoid an unused package error.
+func (t *translator) importableName() string {
+	return "Importable" + string(nameSep)
+}
diff --git a/src/go/go2go/rewrite.go b/src/go/go2go/rewrite.go
new file mode 100644
index 0000000..89a00e0
--- /dev/null
+++ b/src/go/go2go/rewrite.go
@@ -0,0 +1,1288 @@
+// Copyright 2020 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package go2go
+
+import (
+	"bufio"
+	"fmt"
+	"go/ast"
+	"go/printer"
+	"go/token"
+	"go/types"
+	"os"
+	"path/filepath"
+	"sort"
+	"strconv"
+	"strings"
+)
+
+var config = printer.Config{
+	Mode:     printer.UseSpaces | printer.TabIndent | printer.SourcePos,
+	Tabwidth: 8,
+}
+
+// isParameterizedFuncDecl reports whether fd is a parameterized function.
+func isParameterizedFuncDecl(fd *ast.FuncDecl, info *types.Info) bool {
+	if fd.Type.TParams != nil && len(fd.Type.TParams.List) > 0 {
+		return true
+	}
+	if fd.Recv != nil {
+		rtyp := info.TypeOf(fd.Recv.List[0].Type)
+		if rtyp == nil {
+			// Already instantiated.
+			return false
+		}
+		if p, ok := rtyp.(*types.Pointer); ok {
+			rtyp = p.Elem()
+		}
+		if named, ok := rtyp.(*types.Named); ok {
+			if named.TParams() != nil {
+				return true
+			}
+		}
+	}
+	return false
+}
+
+// isTranslatableType reports whether a type spec can be translated to Go1.
+// This is false if the type spec relies on any features that use generics.
+func isTranslatableType(s ast.Spec, info *types.Info) bool {
+	if isParameterizedTypeDecl(s, info) {
+		return false
+	}
+	if isTypeBound(s, info) {
+		return false
+	}
+	if embedsComparable(s, info) {
+		return false
+	}
+	return true
+}
+
+// isParameterizedTypeDecl reports whether s is a parameterized type.
+func isParameterizedTypeDecl(s ast.Spec, info *types.Info) bool {
+	ts := s.(*ast.TypeSpec)
+	if ts.TParams != nil && len(ts.TParams.List) > 0 {
+		return true
+	}
+	if ts.Assign == token.NoPos {
+		return false
+	}
+
+	// This is a type alias. Try to resolve it.
+	typ := info.TypeOf(ts.Type)
+	if typ == nil {
+		return false
+	}
+	named, ok := typ.(*types.Named)
+	if !ok {
+		return false
+	}
+	return len(named.TParams()) > 0 && len(named.TArgs()) == 0
+}
+
+// isTypeBound reports whether s is an interface type that includes a
+// type bound or that embeds an interface that must be a type bound.
+func isTypeBound(s ast.Spec, info *types.Info) bool {
+	typ := info.TypeOf(s.(*ast.TypeSpec).Type)
+	if typ == nil {
+		return false
+	}
+	if iface, ok := typ.Underlying().(*types.Interface); ok {
+		if iface.HasTypeList() {
+			return true
+		}
+	}
+	return false
+}
+
+// embedsComparable reports whether s is an interface type that embeds
+// the predeclared type "comparable", directly or indirectly.
+func embedsComparable(s ast.Spec, info *types.Info) bool {
+	typ := info.TypeOf(s.(*ast.TypeSpec).Type)
+	return typeEmbedsComparable(typ)
+}
+
+// typeEmbedsComparable reports whether typ is an interface type
+// that embeds the predeclared type "comparable", directly or indirectly.
+// This is like embedsComparable, but for a types.Type.
+func typeEmbedsComparable(typ types.Type) bool {
+	if typ == nil {
+		return false
+	}
+	iface, ok := typ.Underlying().(*types.Interface)
+	if !ok {
+		return false
+	}
+	n := iface.NumEmbeddeds()
+	if n == 0 {
+		return false
+	}
+	comparable := types.Universe.Lookup("comparable")
+	for i := 0; i < n; i++ {
+		et := iface.EmbeddedType(i)
+		if named, ok := et.(*types.Named); ok && named.Obj() == comparable {
+			return true
+		}
+		if typeEmbedsComparable(et) {
+			return true
+		}
+	}
+	return false
+}
+
+// A translator is used to translate a file from generic Go to Go 1.
+type translator struct {
+	fset         *token.FileSet
+	importer     *Importer
+	tpkg         *types.Package
+	types        map[ast.Expr]types.Type
+	newDecls     []ast.Decl
+	typePackages map[*types.Package]bool
+
+	// typeDepth tracks recursive type instantiations.
+	typeDepth int
+
+	// err is set if we have seen an error during this translation.
+	// This is used by the rewrite methods.
+	err error
+}
+
+// instantiations tracks all function and type instantiations for a package.
+type instantiations struct {
+	funcInstantiations map[string][]*funcInstantiation
+	typeInstantiations map[types.Type][]*typeInstantiation
+}
+
+// A funcInstantiation is a single instantiation of a function.
+type funcInstantiation struct {
+	types []types.Type
+	decl  *ast.Ident
+}
+
+// A typeInstantiation is a single instantiation of a type.
+type typeInstantiation struct {
+	types      []types.Type
+	decl       *ast.Ident
+	typ        types.Type
+	inProgress bool
+}
+
+// funcInstantiations fetches the function instantiations defined in
+// the current package, given a generic function name.
+func (t *translator) funcInstantiations(key string) []*funcInstantiation {
+	insts := t.importer.instantiations[t.tpkg]
+	if insts == nil {
+		return nil
+	}
+	return insts.funcInstantiations[key]
+}
+
+// addFuncInstantiation adds a new function instantiation.
+func (t *translator) addFuncInstantiation(key string, inst *funcInstantiation) {
+	insts := t.pkgInstantiations()
+	insts.funcInstantiations[key] = append(insts.funcInstantiations[key], inst)
+}
+
+// typeInstantiations fetches the type instantiations defined in
+// the current package, given a generic type.
+func (t *translator) typeInstantiations(typ types.Type) []*typeInstantiation {
+	insts := t.importer.instantiations[t.tpkg]
+	if insts == nil {
+		return nil
+	}
+	return insts.typeInstantiations[typ]
+}
+
+// addTypeInstantiations adds a new type instantiation.
+func (t *translator) addTypeInstantiation(typ types.Type, inst *typeInstantiation) {
+	insts := t.pkgInstantiations()
+	insts.typeInstantiations[typ] = append(insts.typeInstantiations[typ], inst)
+}
+
+// pkgInstantiations returns the instantiations structure for the current
+// package, creating it if necessary.
+func (t *translator) pkgInstantiations() *instantiations {
+	insts := t.importer.instantiations[t.tpkg]
+	if insts == nil {
+		insts = &instantiations{
+			funcInstantiations: make(map[string][]*funcInstantiation),
+			typeInstantiations: make(map[types.Type][]*typeInstantiation),
+		}
+		t.importer.instantiations[t.tpkg] = insts
+	}
+	return insts
+}
+
+// rewrite rewrites the contents of one file.
+func rewriteFile(dir string, fset *token.FileSet, importer *Importer, importPath string, tpkg *types.Package, filename string, file *ast.File, addImportableName bool) (err error) {
+	if err := rewriteAST(fset, importer, importPath, tpkg, file, addImportableName); err != nil {
+		return err
+	}
+
+	filename = filepath.Base(filename)
+	goFile := strings.TrimSuffix(filename, filepath.Ext(filename)) + ".go"
+	o, err := os.Create(filepath.Join(dir, goFile))
+	if err != nil {
+		return err
+	}
+	defer func() {
+		if closeErr := o.Close(); err == nil {
+			err = closeErr
+		}
+	}()
+
+	w := bufio.NewWriter(o)
+	defer func() {
+		if flushErr := w.Flush(); err == nil {
+			err = flushErr
+		}
+	}()
+	fmt.Fprintln(w, rewritePrefix)
+
+	return config.Fprint(w, fset, file)
+}
+
+// rewriteAST rewrites the AST for a file.
+func rewriteAST(fset *token.FileSet, importer *Importer, importPath string, tpkg *types.Package, file *ast.File, addImportableName bool) (err error) {
+	t := translator{
+		fset:         fset,
+		importer:     importer,
+		tpkg:         tpkg,
+		types:        make(map[ast.Expr]types.Type),
+		typePackages: make(map[*types.Package]bool),
+	}
+	t.translate(file)
+
+	// Add all the transitive imports. This is more than we need,
+	// but we're not trying to be elegant here.
+	imps := make(map[string]bool)
+
+	for _, p := range importer.transitiveImports(importPath) {
+		imps[p] = true
+	}
+	for pkg := range t.typePackages {
+		if pkg != t.tpkg {
+			imps[pkg.Path()] = true
+		}
+	}
+
+	decls := make([]ast.Decl, 0, len(file.Decls))
+	var specs []ast.Spec
+	for _, decl := range file.Decls {
+		gen, ok := decl.(*ast.GenDecl)
+		if !ok || gen.Tok != token.IMPORT {
+			decls = append(decls, decl)
+			continue
+		}
+		for _, spec := range gen.Specs {
+			imp := spec.(*ast.ImportSpec)
+			if imp.Name != nil {
+				specs = append(specs, imp)
+			}
+			// We picked up Go 2 imports above, but we still
+			// need to pick up Go 1 imports here.
+			path, err := strconv.Unquote(imp.Path.Value)
+			if err != nil || imps[path] {
+				continue
+			}
+			if imp.Name == nil {
+				// If Name != nil we are keeping the spec.
+				// Don't add the import again here,
+				// only if it is needed elsewhere.
+				imps[path] = true
+			}
+			for _, p := range importer.transitiveImports(path) {
+				imps[p] = true
+			}
+		}
+	}
+	file.Decls = decls
+
+	// If we have a ./ import, let it override a standard import
+	// we may have added due to t.typePackages.
+	for path := range imps {
+		if strings.HasPrefix(path, "./") {
+			delete(imps, strings.TrimPrefix(path, "./"))
+		}
+	}
+
+	paths := make([]string, 0, len(imps))
+	for p := range imps {
+		paths = append(paths, p)
+	}
+	sort.Strings(paths)
+
+	for _, p := range paths {
+		specs = append(specs, ast.Spec(&ast.ImportSpec{
+			Path: &ast.BasicLit{
+				Kind:  token.STRING,
+				Value: strconv.Quote(p),
+			},
+		}))
+	}
+	if len(specs) > 0 {
+		first := &ast.GenDecl{
+			Tok:   token.IMPORT,
+			Specs: specs,
+		}
+		file.Decls = append([]ast.Decl{first}, file.Decls...)
+	}
+
+	// Add a name that other packages can reference to avoid an error
+	// about an unused package.
+	if addImportableName {
+		file.Decls = append(file.Decls,
+			&ast.GenDecl{
+				Tok: token.TYPE,
+				Specs: []ast.Spec{
+					&ast.TypeSpec{
+						Name: ast.NewIdent(t.importableName()),
+						Type: ast.NewIdent("int"),
+					},
+				},
+			})
+	}
+
+	// Add a reference for each imported package to avoid an error
+	// about an unused package.
+	for _, decl := range file.Decls {
+		gen, ok := decl.(*ast.GenDecl)
+		if !ok || gen.Tok != token.IMPORT {
+			continue
+		}
+		for _, spec := range gen.Specs {
+			imp := spec.(*ast.ImportSpec)
+			if imp.Name != nil && imp.Name.Name == "_" {
+				continue
+			}
+			path := strings.TrimPrefix(strings.TrimSuffix(imp.Path.Value, `"`), `"`)
+			var pname string
+
+			var tok token.Token
+			var importableName string
+			if pkg, ok := importer.lookupPackage(path); ok {
+				tok = token.TYPE
+				importableName = t.importableName()
+				pname = pkg.Name()
+			} else {
+				fileDir := filepath.Dir(fset.Position(file.Name.Pos()).Filename)
+				pkg, err := importer.ImportFrom(path, fileDir, 0)
+				if err != nil {
+					return err
+				}
+				scope := pkg.Scope()
+				pname = pkg.Name()
+				names := scope.Names()
+			nameLoop:
+				for _, name := range names {
+					if !token.IsExported(name) {
+						continue
+					}
+					obj := scope.Lookup(name)
+					switch obj.(type) {
+					case *types.TypeName:
+						tok = token.TYPE
+						importableName = name
+						break nameLoop
+					case *types.Var, *types.Func:
+						tok = token.VAR
+						importableName = name
+						break nameLoop
+					case *types.Const:
+						tok = token.CONST
+						importableName = name
+						break nameLoop
+					}
+				}
+				if importableName == "" {
+					return fmt.Errorf("can't find any importable name in package %q", path)
+				}
+			}
+
+			var name string
+			if imp.Name != nil {
+				name = imp.Name.Name
+			} else {
+				name = pname
+			}
+			var spec ast.Spec
+			switch tok {
+			case token.CONST, token.VAR:
+				spec = &ast.ValueSpec{
+					Names: []*ast.Ident{
+						ast.NewIdent("_"),
+					},
+					Values: []ast.Expr{
+						&ast.SelectorExpr{
+							X:   ast.NewIdent(name),
+							Sel: ast.NewIdent(importableName),
+						},
+					},
+				}
+			case token.TYPE:
+				spec = &ast.TypeSpec{
+					Name: ast.NewIdent("_"),
+					Type: &ast.SelectorExpr{
+						X:   ast.NewIdent(name),
+						Sel: ast.NewIdent(importableName),
+					},
+				}
+			default:
+				panic("can't happen")
+			}
+			file.Decls = append(file.Decls,
+				&ast.GenDecl{
+					Tok:   tok,
+					Specs: []ast.Spec{spec},
+				})
+		}
+	}
+
+	return t.err
+}
+
+// translate translates the AST for a file from generic Go to Go 1.
+func (t *translator) translate(file *ast.File) {
+	declsToDo := file.Decls
+	file.Decls = nil
+	c := 0
+	for len(declsToDo) > 0 {
+		if c > 50 {
+			var sb strings.Builder
+			printer.Fprint(&sb, t.fset, declsToDo[0])
+			t.err = fmt.Errorf("looping while expanding %v", &sb)
+			return
+		}
+		c++
+
+		newDecls := make([]ast.Decl, 0, len(declsToDo))
+		for i, decl := range declsToDo {
+			switch decl := decl.(type) {
+			case *ast.FuncDecl:
+				if !isParameterizedFuncDecl(decl, t.importer.info) {
+					t.translateFuncDecl(&declsToDo[i])
+					newDecls = append(newDecls, decl)
+				}
+			case *ast.GenDecl:
+				switch decl.Tok {
+				case token.TYPE:
+					newSpecs := make([]ast.Spec, 0, len(decl.Specs))
+					for j := range decl.Specs {
+						if isTranslatableType(decl.Specs[j], t.importer.info) {
+							t.translateTypeSpec(&decl.Specs[j])
+							newSpecs = append(newSpecs, decl.Specs[j])
+						}
+					}
+					if len(newSpecs) == 0 {
+						decl = nil
+					} else {
+						decl.Specs = newSpecs
+					}
+				case token.VAR, token.CONST:
+					for j := range decl.Specs {
+						t.translateValueSpec(&decl.Specs[j])
+					}
+				}
+				if decl != nil {
+					newDecls = append(newDecls, decl)
+				}
+			default:
+				newDecls = append(newDecls, decl)
+			}
+		}
+		file.Decls = append(file.Decls, newDecls...)
+		declsToDo = t.newDecls
+		t.newDecls = nil
+	}
+}
+
+// translateTypeSpec translates a type from generic Go to Go 1.
+func (t *translator) translateTypeSpec(ps *ast.Spec) {
+	ts := (*ps).(*ast.TypeSpec)
+	if ts.TParams != nil && len(ts.TParams.List) > 0 {
+		t.err = fmt.Errorf("%s: go2go tool does not support parameterized type here", t.fset.Position((*ps).Pos()))
+		return
+	}
+	t.translateExpr(&ts.Type)
+}
+
+// translateValueSpec translates a variable or constant from generic Go to Go 1.
+func (t *translator) translateValueSpec(ps *ast.Spec) {
+	vs := (*ps).(*ast.ValueSpec)
+	t.translateExpr(&vs.Type)
+	for i := range vs.Values {
+		t.translateExpr(&vs.Values[i])
+	}
+}
+
+// translateFuncDecl translates a function from generic Go to Go 1.
+func (t *translator) translateFuncDecl(pd *ast.Decl) {
+	if t.err != nil {
+		return
+	}
+	fd := (*pd).(*ast.FuncDecl)
+	if fd.Type.TParams != nil {
+		if len(fd.Type.TParams.List) > 0 {
+			panic("parameterized function")
+		}
+		fd.Type.TParams = nil
+	}
+	if fd.Recv != nil {
+		t.translateFieldList(fd.Recv)
+	}
+	t.translateFieldList(fd.Type.Params)
+	t.translateFieldList(fd.Type.Results)
+	t.translateBlockStmt(fd.Body)
+}
+
+// translateBlockStmt translates a block statement from generic Go to Go 1.
+func (t *translator) translateBlockStmt(pbs *ast.BlockStmt) {
+	if pbs == nil {
+		return
+	}
+	for i := range pbs.List {
+		t.translateStmt(&pbs.List[i])
+	}
+}
+
+// translateStmt translates a statement from generic Go to Go 1.
+func (t *translator) translateStmt(ps *ast.Stmt) {
+	if t.err != nil {
+		return
+	}
+	if *ps == nil {
+		return
+	}
+	switch s := (*ps).(type) {
+	case *ast.DeclStmt:
+		d := s.Decl.(*ast.GenDecl)
+		switch d.Tok {
+		case token.TYPE:
+			for i := range d.Specs {
+				t.translateTypeSpec(&d.Specs[i])
+			}
+		case token.CONST, token.VAR:
+			for i := range d.Specs {
+				t.translateValueSpec(&d.Specs[i])
+			}
+		default:
+			panic(fmt.Sprintf("unknown decl type %v", d.Tok))
+		}
+	case *ast.EmptyStmt:
+	case *ast.LabeledStmt:
+		t.translateStmt(&s.Stmt)
+	case *ast.ExprStmt:
+		t.translateExpr(&s.X)
+	case *ast.SendStmt:
+		t.translateExpr(&s.Chan)
+		t.translateExpr(&s.Value)
+	case *ast.IncDecStmt:
+		t.translateExpr(&s.X)
+	case *ast.AssignStmt:
+		t.translateExprList(s.Lhs)
+		t.translateExprList(s.Rhs)
+	case *ast.GoStmt:
+		e := ast.Expr(s.Call)
+		t.translateExpr(&e)
+		s.Call = e.(*ast.CallExpr)
+	case *ast.DeferStmt:
+		e := ast.Expr(s.Call)
+		t.translateExpr(&e)
+		s.Call = e.(*ast.CallExpr)
+	case *ast.ReturnStmt:
+		t.translateExprList(s.Results)
+	case *ast.BranchStmt:
+	case *ast.BlockStmt:
+		t.translateBlockStmt(s)
+	case *ast.IfStmt:
+		t.translateStmt(&s.Init)
+		t.translateExpr(&s.Cond)
+		t.translateBlockStmt(s.Body)
+		t.translateStmt(&s.Else)
+	case *ast.CaseClause:
+		t.translateExprList(s.List)
+		t.translateStmtList(s.Body)
+	case *ast.SwitchStmt:
+		t.translateStmt(&s.Init)
+		t.translateExpr(&s.Tag)
+		t.translateBlockStmt(s.Body)
+	case *ast.TypeSwitchStmt:
+		t.translateStmt(&s.Init)
+		t.translateStmt(&s.Assign)
+		t.translateBlockStmt(s.Body)
+	case *ast.CommClause:
+		t.translateStmt(&s.Comm)
+		t.translateStmtList(s.Body)
+	case *ast.SelectStmt:
+		t.translateBlockStmt(s.Body)
+	case *ast.ForStmt:
+		t.translateStmt(&s.Init)
+		t.translateExpr(&s.Cond)
+		t.translateStmt(&s.Post)
+		t.translateBlockStmt(s.Body)
+	case *ast.RangeStmt:
+		t.translateExpr(&s.Key)
+		t.translateExpr(&s.Value)
+		t.translateExpr(&s.X)
+		t.translateBlockStmt(s.Body)
+	default:
+		panic(fmt.Sprintf("unimplemented Stmt %T", s))
+	}
+}
+
+// translateStmtList translates a list of statements generic Go to Go 1.
+func (t *translator) translateStmtList(sl []ast.Stmt) {
+	for i := range sl {
+		t.translateStmt(&sl[i])
+	}
+}
+
+// translateExpr translates an expression from generic Go to Go 1.
+func (t *translator) translateExpr(pe *ast.Expr) {
+	if t.err != nil {
+		return
+	}
+	if *pe == nil {
+		return
+	}
+	switch e := (*pe).(type) {
+	case *ast.Ident:
+		t.translateIdent(pe)
+	case *ast.Ellipsis:
+		t.translateExpr(&e.Elt)
+	case *ast.BasicLit:
+	case *ast.FuncLit:
+		t.translateFieldList(e.Type.TParams)
+		t.translateFieldList(e.Type.Params)
+		t.translateFieldList(e.Type.Results)
+		t.translateBlockStmt(e.Body)
+	case *ast.CompositeLit:
+		t.translateExpr(&e.Type)
+		t.translateExprList(e.Elts)
+	case *ast.ParenExpr:
+		t.translateExpr(&e.X)
+	case *ast.SelectorExpr:
+		t.translateSelectorExpr(pe)
+	case *ast.IndexExpr:
+		if ftyp, ok := t.lookupType(e.X).(*types.Signature); ok && len(ftyp.TParams()) > 0 {
+			t.translateFunctionInstantiation(pe)
+		} else if ntyp, ok := t.lookupType(e.X).(*types.Named); ok && len(ntyp.TParams()) > 0 && len(ntyp.TArgs()) == 0 {
+			t.translateTypeInstantiation(pe)
+		}
+		t.translateExpr(&e.X)
+		t.translateExpr(&e.Index)
+	case *ast.SliceExpr:
+		t.translateExpr(&e.X)
+		t.translateExpr(&e.Low)
+		t.translateExpr(&e.High)
+		t.translateExpr(&e.Max)
+	case *ast.TypeAssertExpr:
+		t.translateExpr(&e.X)
+		t.translateExpr(&e.Type)
+	case *ast.CallExpr:
+		if ftyp, ok := t.lookupType(e.Fun).(*types.Signature); ok && len(ftyp.TParams()) > 0 {
+			t.translateFunctionInstantiation(pe)
+		} else if ntyp, ok := t.lookupType(e.Fun).(*types.Named); ok && len(ntyp.TParams()) > 0 && len(ntyp.TArgs()) == 0 {
+			t.translateTypeInstantiation(pe)
+		}
+		t.translateExprList(e.Args)
+		t.translateExpr(&e.Fun)
+	case *ast.StarExpr:
+		t.translateExpr(&e.X)
+	case *ast.UnaryExpr:
+		t.translateExpr(&e.X)
+	case *ast.BinaryExpr:
+		t.translateExpr(&e.X)
+		t.translateExpr(&e.Y)
+	case *ast.KeyValueExpr:
+		t.translateExpr(&e.Key)
+		t.translateExpr(&e.Value)
+	case *ast.ArrayType:
+		t.translateExpr(&e.Len)
+		t.translateExpr(&e.Elt)
+	case *ast.StructType:
+		t.translateFieldList(e.Fields)
+	case *ast.FuncType:
+		t.translateFieldList(e.TParams)
+		t.translateFieldList(e.Params)
+		t.translateFieldList(e.Results)
+	case *ast.InterfaceType:
+		methods, types := splitFieldList(e.Methods)
+		t.translateFieldList(methods)
+		t.translateExprList(types)
+	case *ast.MapType:
+		t.translateExpr(&e.Key)
+		t.translateExpr(&e.Value)
+	case *ast.ChanType:
+		t.translateExpr(&e.Value)
+	default:
+		panic(fmt.Sprintf("unimplemented Expr %T", e))
+	}
+}
+
+// translateIdent translates a simple identifier generic Go to Go 1.
+// These are usually fine as is, but a reference
+// to a non-generic name in another package may need a package qualifier.
+func (t *translator) translateIdent(pe *ast.Expr) {
+	e := (*pe).(*ast.Ident)
+	obj := t.importer.info.ObjectOf(e)
+	if obj == nil {
+		return
+	}
+	if named, ok := obj.Type().(*types.Named); ok && len(named.TParams()) > 0 {
+		// A generic function that will be instantiated locally.
+		return
+	}
+	ipkg := obj.Pkg()
+	if ipkg == nil || ipkg == t.tpkg {
+		// We don't need a package qualifier if it's defined
+		// in the current package.
+		return
+	}
+	if obj.Parent() != ipkg.Scope() {
+		// We only need a package qualifier if it's defined in
+		// package scope.
+		return
+	}
+
+	// Add package qualifier.
+	*pe = &ast.SelectorExpr{
+		X:   ast.NewIdent(ipkg.Name()),
+		Sel: e,
+	}
+}
+
+// translateSelectorExpr translates a selector expression
+// from generic Go to Go 1.
+func (t *translator) translateSelectorExpr(pe *ast.Expr) {
+	e := (*pe).(*ast.SelectorExpr)
+
+	t.translateExpr(&e.X)
+
+	obj := t.importer.info.ObjectOf(e.Sel)
+	if obj == nil {
+		return
+	}
+
+	// Handle references to promoted fields and methods,
+	// if they go through an embedded instantiated field.
+	// We have to add a reference to the field we inserted.
+	if xType := t.lookupType(e.X); xType != nil {
+		if ptr := types.AsPointer(xType); ptr != nil {
+			xType = ptr.Elem()
+		}
+		fobj, indexes, _ := types.LookupFieldOrMethod(xType, true, obj.Pkg(), obj.Name())
+		if fobj != nil && len(indexes) > 1 {
+			for _, index := range indexes[:len(indexes)-1] {
+				xf := types.AsStruct(xType).Field(index)
+				// This must be an embedded type.
+				// If the field name is the one we expect,
+				// don't mention it explicitly,
+				// because it might not be exported.
+				if xf.Name() == types.TypeString(xf.Type(), relativeTo(xf.Pkg())) {
+					continue
+				}
+				e.X = &ast.SelectorExpr{
+					X:   e.X,
+					Sel: ast.NewIdent(xf.Name()),
+				}
+				xType = xf.Type()
+				if ptr := types.AsPointer(xType); ptr != nil {
+					xType = ptr.Elem()
+				}
+			}
+		}
+	}
+
+	// Handle references to instantiated embedded fields.
+	// We have to rewrite the name to the name used in
+	// the translated struct definition.
+	if f, ok := obj.(*types.Var); ok && f.Embedded() {
+		typ := t.lookupType(e)
+		if typ == nil {
+			typ = f.Type()
+		}
+		if pt := types.AsPointer(typ); pt != nil {
+			typ = pt.Elem()
+		}
+		named, ok := typ.(*types.Named)
+		if !ok || len(named.TArgs()) == 0 {
+			return
+		}
+		if obj.Name() != named.Obj().Name() {
+			return
+		}
+		_, id := t.lookupInstantiatedType(named)
+		*pe = &ast.SelectorExpr{
+			X:   e.X,
+			Sel: id,
+		}
+	}
+}
+
+// TODO(iant) refactor code and get rid of this?
+func splitFieldList(fl *ast.FieldList) (methods *ast.FieldList, types []ast.Expr) {
+	if fl == nil {
+		return
+	}
+	var mfields []*ast.Field
+	for _, f := range fl.List {
+		if len(f.Names) > 0 && f.Names[0].Name == "type" {
+			// type list type
+			types = append(types, f.Type)
+		} else {
+			mfields = append(mfields, f)
+		}
+	}
+	copy := *fl
+	copy.List = mfields
+	methods = &copy
+	return
+}
+
+// TODO(iant) refactor code and get rid of this?
+func mergeFieldList(methods *ast.FieldList, types []ast.Expr) (fl *ast.FieldList) {
+	fl = methods
+	if len(types) == 0 {
+		return
+	}
+	if fl == nil {
+		fl = new(ast.FieldList)
+	}
+	name := []*ast.Ident{ast.NewIdent("type")}
+	for _, typ := range types {
+		fl.List = append(fl.List, &ast.Field{Names: name, Type: typ})
+	}
+	return
+}
+
+// translateExprList translate an expression list generic Go to Go 1.
+func (t *translator) translateExprList(el []ast.Expr) {
+	for i := range el {
+		t.translateExpr(&el[i])
+	}
+}
+
+// translateFieldList translates a field list generic Go to Go 1.
+func (t *translator) translateFieldList(fl *ast.FieldList) {
+	if fl == nil {
+		return
+	}
+	for _, f := range fl.List {
+		t.translateField(f)
+	}
+}
+
+// translateField translates a field generic Go to Go 1.
+func (t *translator) translateField(f *ast.Field) {
+	t.translateExpr(&f.Type)
+}
+
+// translateFunctionInstantiation translates an instantiated function
+// to Go 1.
+func (t *translator) translateFunctionInstantiation(pe *ast.Expr) {
+	expr := *pe
+	qid := t.instantiatedIdent(expr)
+	argList, typeList, typeArgs := t.instantiationTypes(expr)
+	if t.err != nil {
+		return
+	}
+
+	var instIdent *ast.Ident
+	key := qid.String()
+	insts := t.funcInstantiations(key)
+	for _, inst := range insts {
+		if t.sameTypes(typeList, inst.types) {
+			instIdent = inst.decl
+			break
+		}
+	}
+
+	if instIdent == nil {
+		var err error
+		instIdent, err = t.instantiateFunction(qid, argList, typeList)
+		if err != nil {
+			t.err = err
+			return
+		}
+
+		n := &funcInstantiation{
+			types: typeList,
+			decl:  instIdent,
+		}
+		t.addFuncInstantiation(key, n)
+	}
+
+	if typeArgs {
+		*pe = instIdent
+	} else {
+		switch e := expr.(type) {
+		case *ast.CallExpr:
+			newCall := *e
+			newCall.Fun = instIdent
+			*pe = &newCall
+		case *ast.IndexExpr:
+			*pe = instIdent
+		default:
+			panic("unexpected AST type")
+		}
+	}
+}
+
+// translateTypeInstantiation translates an instantiated type to Go 1.
+func (t *translator) translateTypeInstantiation(pe *ast.Expr) {
+	expr := *pe
+	qid := t.instantiatedIdent(expr)
+	typ := t.lookupType(qid.ident).(*types.Named)
+	argList, typeList, typeArgs := t.instantiationTypes(expr)
+	if t.err != nil {
+		return
+	}
+	if !typeArgs {
+		panic("no type arguments for type")
+	}
+
+	var seen *typeInstantiation
+	key := t.typeWithoutArgs(typ)
+	for _, inst := range t.typeInstantiations(key) {
+		if t.sameTypes(typeList, inst.types) {
+			if inst.inProgress {
+				panic(fmt.Sprintf("%s: circular type instantiation", t.fset.Position((*pe).Pos())))
+			}
+			if inst.decl == nil {
+				// This can happen if we've instantiated
+				// the type in instantiateType.
+				seen = inst
+				break
+			}
+			*pe = inst.decl
+			return
+		}
+	}
+
+	name, err := t.instantiatedName(qid, typeList)
+	if err != nil {
+		t.err = err
+		return
+	}
+	instIdent := ast.NewIdent(name)
+
+	if seen != nil {
+		seen.decl = instIdent
+		seen.inProgress = true
+	} else {
+		seen = &typeInstantiation{
+			types:      typeList,
+			decl:       instIdent,
+			typ:        nil,
+			inProgress: true,
+		}
+		t.addTypeInstantiation(key, seen)
+	}
+
+	defer func() {
+		seen.inProgress = false
+	}()
+
+	instType, err := t.instantiateTypeDecl(qid, typ, argList, typeList, instIdent)
+	if err != nil {
+		t.err = err
+		return
+	}
+
+	if seen.typ == nil {
+		seen.typ = instType
+	}
+
+	*pe = instIdent
+}
+
+// instantiatedIdent returns the qualified identifer that is being
+// instantiated.
+func (t *translator) instantiatedIdent(x ast.Expr) qualifiedIdent {
+	var fun ast.Expr
+	switch x := x.(type) {
+	case *ast.CallExpr:
+		fun = x.Fun
+	case *ast.IndexExpr:
+		fun = x.X
+	default:
+		panic(fmt.Sprintf("unexpected AST %T", x))
+	}
+
+	switch fun := fun.(type) {
+	case *ast.Ident:
+		if obj := t.importer.info.ObjectOf(fun); obj != nil && obj.Pkg() != t.tpkg {
+			return qualifiedIdent{pkg: obj.Pkg(), ident: fun}
+		}
+		return qualifiedIdent{ident: fun}
+	case *ast.SelectorExpr:
+		pkgname, ok := fun.X.(*ast.Ident)
+		if !ok {
+			break
+		}
+		pkgobj, ok := t.importer.info.Uses[pkgname]
+		if !ok {
+			break
+		}
+		pn, ok := pkgobj.(*types.PkgName)
+		if !ok {
+			break
+		}
+		return qualifiedIdent{pkg: pn.Imported(), ident: fun.Sel}
+	}
+	panic(fmt.Sprintf("instantiated object %T %v is not an identifier", fun, fun))
+}
+
+// instantiationTypes returns the type arguments of an instantiation.
+// It also returns the AST arguments if they are present.
+// The typeArgs result reports whether the AST arguments are types.
+func (t *translator) instantiationTypes(x ast.Expr) (argList []ast.Expr, typeList []types.Type, typeArgs bool) {
+	var args []ast.Expr
+	switch x := x.(type) {
+	case *ast.CallExpr:
+		args = x.Args
+	case *ast.IndexExpr:
+		args = []ast.Expr{x.Index}
+	default:
+		panic("unexpected AST type")
+	}
+	inferred, haveInferred := t.importer.info.Inferred[x]
+
+	if !haveInferred {
+		argList = args
+		typeList = make([]types.Type, 0, len(argList))
+		for _, arg := range argList {
+			if id, ok := arg.(*ast.Ident); ok && id.Name == "_" {
+				t.err = fmt.Errorf("%s: go2go tool does not support using _ here", t.fset.Position(arg.Pos()))
+				return
+			}
+			if at := t.lookupType(arg); at == nil {
+				panic(fmt.Sprintf("%s: no type found for %T %v", t.fset.Position(arg.Pos()), arg, arg))
+			} else {
+				typeList = append(typeList, at)
+			}
+		}
+		typeArgs = true
+	} else {
+		typeList, argList = t.typeListToASTList(inferred.Targs)
+	}
+
+	// Instantiating with a locally defined type won't work.
+	// Check that here.
+	for _, typ := range typeList {
+		if named, ok := typ.(*types.Named); ok && named.Obj().Pkg() != nil {
+			if scope := named.Obj().Parent(); scope != nil && scope != named.Obj().Pkg().Scope() {
+				t.err = fmt.Errorf("%s: go2go tool does not support using locally defined type as type argument", t.fset.Position(x.Pos()))
+				return
+			}
+		}
+	}
+
+	return
+}
+
+// lookupInstantiatedType looks for an existing instantiation of an
+// instantiated type.
+func (t *translator) lookupInstantiatedType(typ *types.Named) (types.Type, *ast.Ident) {
+	copyType := func(typ *types.Named, newName string) types.Type {
+		nm := typ.NumMethods()
+		methods := make([]*types.Func, 0, nm)
+		for i := 0; i < nm; i++ {
+			methods = append(methods, typ.Method(i))
+		}
+		obj := typ.Obj()
+		obj = types.NewTypeName(obj.Pos(), obj.Pkg(), newName, nil)
+		nt := types.NewNamed(obj, typ.Underlying(), methods)
+		nt.SetTArgs(typ.TArgs())
+		return nt
+	}
+
+	targs := typ.TArgs()
+	key := t.typeWithoutArgs(typ)
+	var seen *typeInstantiation
+	for _, inst := range t.typeInstantiations(key) {
+		if t.sameTypes(targs, inst.types) {
+			if inst.inProgress {
+				panic(fmt.Sprintf("instantiation for %v in progress", typ))
+			}
+			if inst.decl == nil {
+				// This can happen if we've instantiated
+				// the type in instantiateType.
+				seen = inst
+				break
+			}
+			if inst.typ == nil {
+				panic(fmt.Sprintf("no type for instantiation entry for %v", typ))
+			}
+			if instNamed, ok := inst.typ.(*types.Named); ok {
+				return copyType(instNamed, inst.decl.Name), inst.decl
+			}
+			return inst.typ, inst.decl
+		}
+	}
+
+	typeList, argList := t.typeListToASTList(targs)
+
+	qid := qualifiedIdent{ident: ast.NewIdent(typ.Obj().Name())}
+	if typPkg := typ.Obj().Pkg(); typPkg != t.tpkg {
+		qid.pkg = typPkg
+	}
+
+	name, err := t.instantiatedName(qid, typeList)
+	if err != nil {
+		t.err = err
+		return nil, nil
+	}
+	instIdent := ast.NewIdent(name)
+
+	if seen != nil {
+		seen.decl = instIdent
+		seen.inProgress = true
+	} else {
+		seen = &typeInstantiation{
+			types:      targs,
+			decl:       instIdent,
+			typ:        nil,
+			inProgress: true,
+		}
+		t.addTypeInstantiation(key, seen)
+	}
+
+	defer func() {
+		seen.inProgress = false
+	}()
+
+	instType, err := t.instantiateTypeDecl(qid, typ, argList, typeList, instIdent)
+	if err != nil {
+		t.err = err
+		return nil, nil
+	}
+
+	if seen.typ == nil {
+		seen.typ = instType
+	} else {
+		instType = seen.typ
+	}
+
+	if instNamed, ok := instType.(*types.Named); ok {
+		return copyType(instNamed, instIdent.Name), instIdent
+	}
+	return instType, instIdent
+}
+
+// typeWithoutArgs takes a named type with arguments and returns the
+// same type without arguments.
+func (t *translator) typeWithoutArgs(typ *types.Named) *types.Named {
+	if len(typ.TArgs()) == 0 {
+		return typ
+	}
+	name := typ.Obj().Name()
+	fields := strings.Split(name, ".")
+	if len(fields) > 2 {
+		panic(fmt.Sprintf("unparseable instantiated name %q", name))
+	}
+	if len(fields) > 1 {
+		name = fields[1]
+	}
+
+	tpkg := typ.Obj().Pkg()
+	if tpkg == nil {
+		panic(fmt.Sprintf("can't find package for %s", name))
+	}
+	nobj := tpkg.Scope().Lookup(name)
+	if nobj == nil {
+		panic(fmt.Sprintf("can't find %q in scope of package %q", name, tpkg.Name()))
+	}
+	return nobj.Type().(*types.Named)
+}
+
+// typeListToASTList returns an AST list for a type list,
+// as well as an updated type list.
+func (t *translator) typeListToASTList(typeList []types.Type) ([]types.Type, []ast.Expr) {
+	argList := make([]ast.Expr, 0, len(typeList))
+	for _, typ := range typeList {
+		argList = append(argList, t.typeToAST(typ))
+
+		// This inferred type may introduce a reference to
+		// packages that we don't otherwise import, and that
+		// package name may wind up in arg. Record all packages
+		// seen in inferred types so that we add import
+		// statements for them, just in case.
+		t.addTypePackages(typ)
+	}
+	return typeList, argList
+}
+
+// relativeTo is like types.RelativeTo, but returns just the package name,
+// not the package path.
+func relativeTo(pkg *types.Package) types.Qualifier {
+	return func(other *types.Package) string {
+		if pkg == other {
+			return "" // same package; unqualified
+		}
+		return other.Name()
+	}
+}
+
+// sameTypes reports whether two type slices are the same.
+func (t *translator) sameTypes(a, b []types.Type) bool {
+	if len(a) != len(b) {
+		return false
+	}
+	for i, x := range a {
+		if !t.sameType(x, b[i]) {
+			return false
+		}
+	}
+	return true
+}
+
+// sameType reports whether two types are the same.
+// We have to check type arguments ourselves.
+func (t *translator) sameType(a, b types.Type) bool {
+	if types.IdenticalIgnoreTags(a, b) {
+		return true
+	}
+	if ap, bp := types.AsPointer(a), types.AsPointer(b); ap != nil && bp != nil {
+		a = ap.Elem()
+		b = bp.Elem()
+	}
+	an, ok := a.(*types.Named)
+	if !ok {
+		return false
+	}
+	bn, ok := b.(*types.Named)
+	if !ok {
+		return false
+	}
+	if an.Obj().Name() != bn.Obj().Name() {
+		return false
+	}
+	if len(an.TArgs()) == 0 || len(an.TArgs()) != len(bn.TArgs()) {
+		return false
+	}
+	for i, typ := range an.TArgs() {
+		if !t.sameType(typ, bn.TArgs()[i]) {
+			return false
+		}
+	}
+	return true
+}
+
+// qualifiedIdent is an identifier possibly qualified with a package.
+type qualifiedIdent struct {
+	pkg   *types.Package // identifier's package; nil for current package
+	ident *ast.Ident
+}
+
+// String returns a printable name for qid.
+func (qid qualifiedIdent) String() string {
+	if qid.pkg == nil {
+		return qid.ident.Name
+	}
+	return qid.pkg.Path() + "." + qid.ident.Name
+}
diff --git a/src/go/go2go/types.go b/src/go/go2go/types.go
new file mode 100644
index 0000000..4af92ce
--- /dev/null
+++ b/src/go/go2go/types.go
@@ -0,0 +1,626 @@
+// Copyright 2020 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package go2go
+
+import (
+	"fmt"
+	"go/ast"
+	"go/token"
+	"go/types"
+	"strconv"
+	"strings"
+)
+
+// lookupType returns the types.Type for an AST expression.
+// Returns nil if the type is not known.
+func (t *translator) lookupType(e ast.Expr) types.Type {
+	if typ := t.importer.info.TypeOf(e); typ != nil {
+		return typ
+	}
+	if typ, ok := t.types[e]; ok {
+		return typ
+	}
+	return nil
+}
+
+// setType records the type for an AST expression. This is only used for
+// AST expressions created during function instantiation.
+// Uninstantiated AST expressions will be listed in t.importer.info.Types.
+func (t *translator) setType(e ast.Expr, nt types.Type) {
+	if ot, ok := t.importer.info.Types[e]; ok {
+		if !t.sameType(ot.Type, nt) {
+			panic("expression type changed")
+		}
+		return
+	}
+	if ot, ok := t.types[e]; ok {
+		if !t.sameType(ot, nt) {
+			panic("expression type changed")
+		}
+		return
+	}
+	t.types[e] = nt
+}
+
+// instantiateType instantiates typ using ta.
+func (t *translator) instantiateType(ta *typeArgs, typ types.Type) types.Type {
+	if t.err != nil {
+		return nil
+	}
+
+	t.typeDepth++
+	defer func() { t.typeDepth-- }()
+	if t.typeDepth > 25 {
+		t.err = fmt.Errorf("looping while instantiating %v %v", typ, ta.types)
+		return nil
+	}
+
+	var inProgress *typeInstantiation
+	for _, inst := range t.typeInstantiations(typ) {
+		if t.sameTypes(ta.types, inst.types) {
+			if inst.typ == nil {
+				inProgress = inst
+				break
+			}
+			return inst.typ
+		}
+	}
+
+	ityp := t.doInstantiateType(ta, typ)
+	if inProgress != nil {
+		if inProgress.typ == nil {
+			inProgress.typ = ityp
+		} else {
+			ityp = inProgress.typ
+		}
+	} else {
+		typinst := &typeInstantiation{
+			types: ta.types,
+			typ:   ityp,
+		}
+		t.addTypeInstantiation(typ, typinst)
+	}
+
+	return ityp
+}
+
+// doInstantiateType does the work of instantiating typ using ta.
+// This should only be called from instantiateType.
+func (t *translator) doInstantiateType(ta *typeArgs, typ types.Type) types.Type {
+	switch typ := typ.(type) {
+	case *types.Basic:
+		return typ
+	case *types.Array:
+		elem := typ.Elem()
+		instElem := t.instantiateType(ta, elem)
+		if elem == instElem {
+			return typ
+		}
+		return types.NewArray(instElem, typ.Len())
+	case *types.Slice:
+		elem := typ.Elem()
+		instElem := t.instantiateType(ta, elem)
+		if elem == instElem {
+			return typ
+		}
+		return types.NewSlice(instElem)
+	case *types.Struct:
+		n := typ.NumFields()
+		fields := make([]*types.Var, n)
+		changed := false
+		tags := make([]string, n)
+		hasTag := false
+		for i := 0; i < n; i++ {
+			v := typ.Field(i)
+			instType := t.instantiateType(ta, v.Type())
+			if v.Type() != instType {
+				changed = true
+			}
+			fields[i] = types.NewVar(v.Pos(), v.Pkg(), v.Name(), instType)
+
+			tag := typ.Tag(i)
+			if tag != "" {
+				tags[i] = tag
+				hasTag = true
+			}
+		}
+		if !changed {
+			return typ
+		}
+		if !hasTag {
+			tags = nil
+		}
+		return types.NewStruct(fields, tags)
+	case *types.Pointer:
+		elem := typ.Elem()
+		instElem := t.instantiateType(ta, elem)
+		if elem == instElem {
+			return typ
+		}
+		return types.NewPointer(instElem)
+	case *types.Tuple:
+		return t.instantiateTypeTuple(ta, typ)
+	case *types.Signature:
+		params := t.instantiateTypeTuple(ta, typ.Params())
+		results := t.instantiateTypeTuple(ta, typ.Results())
+		if params == typ.Params() && results == typ.Results() {
+			return typ
+		}
+		r := types.NewSignature(typ.Recv(), params, results, typ.Variadic())
+		if tparams := typ.TParams(); tparams != nil {
+			r.SetTParams(tparams)
+		}
+		return r
+	case *types.Interface:
+		nm := typ.NumExplicitMethods()
+		methods := make([]*types.Func, nm)
+		changed := false
+		for i := 0; i < nm; i++ {
+			m := typ.ExplicitMethod(i)
+			instSig := t.instantiateType(ta, m.Type()).(*types.Signature)
+			if instSig != m.Type() {
+				m = types.NewFunc(m.Pos(), m.Pkg(), m.Name(), instSig)
+				changed = true
+			}
+			methods[i] = m
+		}
+		ne := typ.NumEmbeddeds()
+		embeddeds := make([]types.Type, ne)
+		for i := 0; i < ne; i++ {
+			e := typ.EmbeddedType(i)
+			instE := t.instantiateType(ta, e)
+			if e != instE {
+				changed = true
+			}
+			embeddeds[i] = instE
+		}
+		if !changed {
+			return typ
+		}
+		return types.NewInterfaceType(methods, embeddeds)
+	case *types.Map:
+		key := t.instantiateType(ta, typ.Key())
+		elem := t.instantiateType(ta, typ.Elem())
+		if key == typ.Key() && elem == typ.Elem() {
+			return typ
+		}
+		return types.NewMap(key, elem)
+	case *types.Chan:
+		elem := t.instantiateType(ta, typ.Elem())
+		if elem == typ.Elem() {
+			return typ
+		}
+		return types.NewChan(typ.Dir(), elem)
+	case *types.Named:
+		targs := typ.TArgs()
+		targsChanged := false
+		if len(targs) > 0 {
+			newTargs := make([]types.Type, 0, len(targs))
+			for _, targ := range targs {
+				newTarg := t.instantiateType(ta, targ)
+				if newTarg != targ {
+					targsChanged = true
+				}
+				newTargs = append(newTargs, newTarg)
+			}
+			targs = newTargs
+		}
+		if targsChanged {
+			return t.updateTArgs(typ, targs)
+		}
+		return typ
+	case *types.TypeParam:
+		if instType, ok := ta.typ(typ); ok {
+			return instType
+		}
+		return typ
+	default:
+		panic(fmt.Sprintf("unimplemented Type %T", typ))
+	}
+}
+
+// setTargs returns a new named type with updated type arguments.
+func (t *translator) updateTArgs(typ *types.Named, targs []types.Type) *types.Named {
+	nm := typ.NumMethods()
+	methods := make([]*types.Func, 0, nm)
+	for i := 0; i < nm; i++ {
+		methods = append(methods, typ.Method(i))
+	}
+	obj := typ.Obj()
+	obj = types.NewTypeName(obj.Pos(), obj.Pkg(), obj.Name(), nil)
+	nt := types.NewNamed(obj, typ.Underlying(), methods)
+	nt.SetTArgs(targs)
+	return nt
+}
+
+// instantiateTypeTuple instantiates a types.Tuple.
+func (t *translator) instantiateTypeTuple(ta *typeArgs, tuple *types.Tuple) *types.Tuple {
+	if tuple == nil {
+		return nil
+	}
+	l := tuple.Len()
+	instTypes := make([]types.Type, l)
+	changed := false
+	for i := 0; i < l; i++ {
+		typ := tuple.At(i).Type()
+		instType := t.instantiateType(ta, typ)
+		if typ != instType {
+			changed = true
+		}
+		instTypes[i] = instType
+	}
+	if !changed {
+		return tuple
+	}
+	vars := make([]*types.Var, l)
+	for i := 0; i < l; i++ {
+		v := tuple.At(i)
+		vars[i] = types.NewVar(v.Pos(), v.Pkg(), v.Name(), instTypes[i])
+	}
+	return types.NewTuple(vars...)
+}
+
+// addTypePackages adds all packages mentioned in typ to t.typePackages.
+func (t *translator) addTypePackages(typ types.Type) {
+	switch typ := typ.(type) {
+	case *types.Basic:
+	case *types.Array:
+		t.addTypePackages(typ.Elem())
+	case *types.Slice:
+		t.addTypePackages(typ.Elem())
+	case *types.Struct:
+		n := typ.NumFields()
+		for i := 0; i < n; i++ {
+			t.addTypePackages(typ.Field(i).Type())
+		}
+	case *types.Pointer:
+		t.addTypePackages(typ.Elem())
+	case *types.Tuple:
+		n := typ.Len()
+		for i := 0; i < n; i++ {
+			t.addTypePackages(typ.At(i).Type())
+		}
+	case *types.Signature:
+		// We'll have seen typ.Recv elsewhere.
+		t.addTypePackages(typ.Params())
+		t.addTypePackages(typ.Results())
+	case *types.Interface:
+		nm := typ.NumExplicitMethods()
+		for i := 0; i < nm; i++ {
+			t.addTypePackages(typ.ExplicitMethod(i).Type())
+		}
+		ne := typ.NumEmbeddeds()
+		for i := 0; i < ne; i++ {
+			t.addTypePackages(typ.EmbeddedType(i))
+		}
+	case *types.Map:
+		t.addTypePackages(typ.Key())
+		t.addTypePackages(typ.Elem())
+	case *types.Chan:
+		t.addTypePackages(typ.Elem())
+	case *types.Named:
+		// This is the point of this whole method.
+		if typ.Obj().Pkg() != nil {
+			t.typePackages[typ.Obj().Pkg()] = true
+		}
+	case *types.TypeParam:
+	default:
+		panic(fmt.Sprintf("unimplemented Type %T", typ))
+	}
+}
+
+// withoutTags returns a type with no struct tags. If typ has no
+// struct tags anyhow, this just returns typ.
+func (t *translator) withoutTags(typ types.Type) types.Type {
+	switch typ := typ.(type) {
+	case *types.Basic:
+		return typ
+	case *types.Array:
+		elem := typ.Elem()
+		elemNoTags := t.withoutTags(elem)
+		if elem == elemNoTags {
+			return typ
+		}
+		return types.NewArray(elemNoTags, typ.Len())
+	case *types.Slice:
+		elem := typ.Elem()
+		elemNoTags := t.withoutTags(elem)
+		if elem == elemNoTags {
+			return typ
+		}
+		return types.NewSlice(elemNoTags)
+	case *types.Struct:
+		n := typ.NumFields()
+		fields := make([]*types.Var, n)
+		changed := false
+		hasTag := false
+		for i := 0; i < n; i++ {
+			v := typ.Field(i)
+			typeNoTags := t.withoutTags(v.Type())
+			if v.Type() != typeNoTags {
+				changed = true
+			}
+			fields[i] = types.NewVar(v.Pos(), v.Pkg(), v.Name(), typeNoTags)
+			if typ.Tag(i) != "" {
+				hasTag = true
+			}
+		}
+		if !changed && !hasTag {
+			return typ
+		}
+		return types.NewStruct(fields, nil)
+	case *types.Pointer:
+		elem := typ.Elem()
+		elemNoTags := t.withoutTags(elem)
+		if elem == elemNoTags {
+			return typ
+		}
+		return types.NewPointer(elemNoTags)
+	case *types.Tuple:
+		return t.tupleWithoutTags(typ)
+	case *types.Signature:
+		params := t.tupleWithoutTags(typ.Params())
+		results := t.tupleWithoutTags(typ.Results())
+		if params == typ.Params() && results == typ.Results() {
+			return typ
+		}
+		r := types.NewSignature(typ.Recv(), params, results, typ.Variadic())
+		if tparams := typ.TParams(); tparams != nil {
+			r.SetTParams(tparams)
+		}
+		return r
+	case *types.Interface:
+		nm := typ.NumExplicitMethods()
+		methods := make([]*types.Func, nm)
+		changed := false
+		for i := 0; i < nm; i++ {
+			m := typ.ExplicitMethod(i)
+			sigNoTags := t.withoutTags(m.Type()).(*types.Signature)
+			if sigNoTags != m.Type() {
+				m = types.NewFunc(m.Pos(), m.Pkg(), m.Name(), sigNoTags)
+				changed = true
+			}
+			methods[i] = m
+		}
+		ne := typ.NumEmbeddeds()
+		embeddeds := make([]types.Type, ne)
+		for i := 0; i < ne; i++ {
+			e := typ.EmbeddedType(i)
+			eNoTags := t.withoutTags(e)
+			if e != eNoTags {
+				changed = true
+			}
+			embeddeds[i] = eNoTags
+		}
+		if !changed {
+			return typ
+		}
+		return types.NewInterfaceType(methods, embeddeds)
+	case *types.Map:
+		key := t.withoutTags(typ.Key())
+		elem := t.withoutTags(typ.Elem())
+		if key == typ.Key() && elem == typ.Elem() {
+			return typ
+		}
+		return types.NewMap(key, elem)
+	case *types.Chan:
+		elem := t.withoutTags(typ.Elem())
+		if elem == typ.Elem() {
+			return typ
+		}
+		return types.NewChan(typ.Dir(), elem)
+	case *types.Named:
+		targs := typ.TArgs()
+		targsChanged := false
+		if len(targs) > 0 {
+			newTargs := make([]types.Type, 0, len(targs))
+			for _, targ := range targs {
+				newTarg := t.withoutTags(targ)
+				if newTarg != targ {
+					targsChanged = true
+				}
+				newTargs = append(newTargs, newTarg)
+			}
+			targs = newTargs
+		}
+		if targsChanged {
+			return t.updateTArgs(typ, targs)
+		}
+		return typ
+	case *types.TypeParam:
+		return typ
+	default:
+		panic(fmt.Sprintf("unimplemented Type %T", typ))
+	}
+}
+
+// tupleWithoutTags returns a tuple with all struct tag removed.
+func (t *translator) tupleWithoutTags(tuple *types.Tuple) *types.Tuple {
+	if tuple == nil {
+		return nil
+	}
+	l := tuple.Len()
+	typesNoTags := make([]types.Type, l)
+	changed := false
+	for i := 0; i < l; i++ {
+		typ := tuple.At(i).Type()
+		typNoTags := t.withoutTags(typ)
+		if typ != typNoTags {
+			changed = true
+		}
+		typesNoTags[i] = typNoTags
+	}
+	if !changed {
+		return tuple
+	}
+	vars := make([]*types.Var, l)
+	for i := 0; i < l; i++ {
+		v := tuple.At(i)
+		vars[i] = types.NewVar(v.Pos(), v.Pkg(), v.Name(), typesNoTags[i])
+	}
+	return types.NewTuple(vars...)
+}
+
+// typeToAST converts a types.Type to an ast.Expr.
+func (t *translator) typeToAST(typ types.Type) ast.Expr {
+	var r ast.Expr
+	switch typ := typ.(type) {
+	case *types.Basic:
+		r = ast.NewIdent(typ.Name())
+	case *types.Array:
+		r = &ast.ArrayType{
+			Len: &ast.BasicLit{
+				Kind:  token.INT,
+				Value: strconv.FormatInt(typ.Len(), 10),
+			},
+			Elt: t.typeToAST(typ.Elem()),
+		}
+	case *types.Slice:
+		r = &ast.ArrayType{
+			Elt: t.typeToAST(typ.Elem()),
+		}
+	case *types.Struct:
+		var fields []*ast.Field
+		n := typ.NumFields()
+		for i := 0; i < n; i++ {
+			tf := typ.Field(i)
+			var names []*ast.Ident
+			if !tf.Embedded() {
+				names = []*ast.Ident{
+					ast.NewIdent(tf.Name()),
+				}
+			}
+			var atag *ast.BasicLit
+			if tag := typ.Tag(i); tag != "" {
+				atag = &ast.BasicLit{
+					Kind:  token.STRING,
+					Value: strconv.Quote(tag),
+				}
+			}
+			af := &ast.Field{
+				Names: names,
+				Type:  t.typeToAST(tf.Type()),
+				Tag:   atag,
+			}
+			fields = append(fields, af)
+		}
+		r = &ast.StructType{
+			Fields: &ast.FieldList{
+				List: fields,
+			},
+		}
+	case *types.Pointer:
+		r = &ast.StarExpr{
+			X: t.typeToAST(typ.Elem()),
+		}
+	case *types.Tuple:
+		// We should only see this in a types.Signature,
+		// where we handle it specially, since there is
+		// no ast.Expr that can represent this.
+		panic("unexpected types.Tuple")
+	case *types.Signature:
+		if len(typ.TParams()) > 0 {
+			// We should only see type parameters for
+			// a package scope function declaration.
+			panic("unexpected type parameters")
+		}
+		r = &ast.FuncType{
+			Params:  t.tupleToFieldList(typ.Params()),
+			Results: t.tupleToFieldList(typ.Params()),
+		}
+	case *types.Interface:
+		var methods []*ast.Field
+		nm := typ.NumExplicitMethods()
+		for i := 0; i < nm; i++ {
+			m := typ.ExplicitMethod(i)
+			f := &ast.Field{
+				Names: []*ast.Ident{
+					ast.NewIdent(m.Name()),
+				},
+				Type: t.typeToAST(m.Type()),
+			}
+			methods = append(methods, f)
+		}
+		ne := typ.NumEmbeddeds()
+		for i := 0; i < ne; i++ {
+			e := typ.EmbeddedType(i)
+			f := &ast.Field{
+				Type: t.typeToAST(e),
+			}
+			methods = append(methods, f)
+		}
+		r = &ast.InterfaceType{
+			Methods: &ast.FieldList{
+				List: methods,
+			},
+		}
+	case *types.Map:
+		r = &ast.MapType{
+			Key:   t.typeToAST(typ.Key()),
+			Value: t.typeToAST(typ.Elem()),
+		}
+	case *types.Chan:
+		var dir ast.ChanDir
+		switch typ.Dir() {
+		case types.SendRecv:
+			dir = ast.SEND | ast.RECV
+		case types.SendOnly:
+			dir = ast.SEND
+		case types.RecvOnly:
+			dir = ast.RECV
+		default:
+			panic("unsupported channel direction")
+		}
+		r = &ast.ChanType{
+			Dir:   dir,
+			Value: t.typeToAST(typ.Elem()),
+		}
+	case *types.Named:
+		if len(typ.TArgs()) > 0 {
+			_, id := t.lookupInstantiatedType(typ)
+			r = id
+		} else {
+			var sb strings.Builder
+			tn := typ.Obj()
+			if tn.Pkg() != nil && tn.Pkg() != t.tpkg {
+				sb.WriteString(tn.Pkg().Name())
+				sb.WriteByte('.')
+			}
+			sb.WriteString(tn.Name())
+			r = ast.NewIdent(sb.String())
+		}
+	case *types.TypeParam:
+		// This should have been instantiated already.
+		panic("unexpected type parameter")
+	default:
+		panic(fmt.Sprintf("unimplemented Type %T", typ))
+	}
+
+	t.setType(r, typ)
+	return r
+}
+
+// tupleToFieldList converts a tupes.Tuple to a ast.FieldList.
+func (t *translator) tupleToFieldList(tuple *types.Tuple) *ast.FieldList {
+	var fields []*ast.Field
+	n := tuple.Len()
+	for i := 0; i < n; i++ {
+		v := tuple.At(i)
+		var names []*ast.Ident
+		if v.Name() != "" {
+			names = []*ast.Ident{
+				ast.NewIdent(v.Name()),
+			}
+		}
+		f := &ast.Field{
+			Names: names,
+			Type:  t.typeToAST(v.Type()),
+		}
+		fields = append(fields, f)
+	}
+	return &ast.FieldList{
+		List: fields,
+	}
+}
diff --git a/src/go/internal/gcimporter/gcimporter_test.go b/src/go/internal/gcimporter/gcimporter_test.go
index 3c76aaf..b86d0bd 100644
--- a/src/go/internal/gcimporter/gcimporter_test.go
+++ b/src/go/internal/gcimporter/gcimporter_test.go
@@ -264,7 +264,8 @@
 	{"io.Reader", "type Reader interface{Read(p []byte) (n int, err error)}"},
 	{"io.ReadWriter", "type ReadWriter interface{Reader; Writer}"},
 	{"go/ast.Node", "type Node interface{End() go/token.Pos; Pos() go/token.Pos}"},
-	{"go/types.Type", "type Type interface{String() string; Underlying() Type}"},
+	// go/types.Type has grown much larger - excluded for now
+	// {"go/types.Type", "type Type interface{String() string; Underlying() Type}"},
 }
 
 func TestImportedTypes(t *testing.T) {
diff --git a/src/go/printer/testdata/genericsB.golden b/src/go/printer/testdata/genericsB.golden
new file mode 100644
index 0000000..5f09934
--- /dev/null
+++ b/src/go/printer/testdata/genericsB.golden
@@ -0,0 +1,33 @@
+// Copyright 2020 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package generics
+
+type T[P any] struct{}
+type T[P1, P2, P3 any] struct{}
+
+type T[P C] struct{}
+type T[P1, P2, P3, C] struct{}
+
+type T[P C[P]] struct{}
+type T[P1, P2, P3 C[P1, P2, P3]] struct{}
+
+func f[P any](x P)
+func f[P1, P2, P3 any](x1 P1, x2 P2, x3 P3) struct{}
+
+func f[P interface{}](x P)
+func f[P1, P2, P3 interface {
+	m1(P1)
+	type P2, P3
+}](x1 P1, x2 P2, x3 P3) struct{}
+func f[P any](T1[P], T2[P]) T3[P]
+
+func (x T[P]) m()
+func (T[P]) m(x T[P]) P
+
+func _() {
+	type _ []T[P]
+	var _ []T[P]
+	_ = []T[P]{}
+}
diff --git a/src/go/printer/testdata/genericsB.input b/src/go/printer/testdata/genericsB.input
new file mode 100644
index 0000000..f137c21
--- /dev/null
+++ b/src/go/printer/testdata/genericsB.input
@@ -0,0 +1,30 @@
+// Copyright 2020 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package generics
+
+type T[P any] struct{}
+type T[P1, P2, P3 any] struct{}
+
+type T[P C] struct{}
+type T[P1, P2, P3, C] struct{}
+
+type T[P C[P]] struct{}
+type T[P1, P2, P3 C[P1, P2, P3]] struct{}
+
+func f[P any](x P)
+func f[P1, P2, P3 any](x1 P1, x2 P2, x3 P3) struct{}
+
+func f[P interface{}](x P)
+func f[P1, P2, P3 interface{ m1(P1); type P2, P3 }](x1 P1, x2 P2, x3 P3) struct{}
+func f[P any](T1[P], T2[P]) T3[P]
+
+func (x T[P]) m()
+func ((T[P])) m(x T[P]) P
+
+func _() {
+	type _ []T[P]
+	var _ []T[P]
+	_ = []T[P]{}
+}
diff --git a/src/go/types/NOTES b/src/go/types/NOTES
new file mode 100644
index 0000000..d9a5c6f
--- /dev/null
+++ b/src/go/types/NOTES
@@ -0,0 +1,182 @@
+This file serves as a notebook/implementation log.
+
+----------------------------------------------------------------------------------------------------
+TODO (implementation issues)
+
+- report a better error when a type is not in a type list (investigate)
+- better error message when we need parentheses around a parameterized function parameter type
+- review handling of fields of instantiated generic types (do we need to make them non-parameterized?)
+- use []*TypeParam for tparams in subst? (unclear)
+- should we use nil instead of &emptyInterface for no type bounds (as an optimization)?
+- TBD: in prose, should we use "generic" or "parameterized" (try to be consistent)
+
+----------------------------------------------------------------------------------------------------
+KNOWN ISSUES
+
+- type parameter constraints are ignored when checking if a parameterized method implements the
+  matching method in an interface
+- iteration over generic variables doesn't report certain channel errors (see TODOs in code)
+- cannot handle mutually recursive parameterized interfaces using themselves as type bounds
+  example: type B(type P B(P)) interface{ m() } (need to delay all checking after seting up declarations)
+- invoking a method of a parameterized embedded type doesn't work (cannot properly determine receiver yet)
+- pointer designation is incorrectly handled when checking type list constraint satisfaction
+
+----------------------------------------------------------------------------------------------------
+OBSERVATIONS
+
+- 2/20/2020: Because we permit parenthesized types anywhere for consistency, also in parameter lists (mea
+  culpa), we have parsing ambiguities when using instantiated types in parameter lists w/o argument names.
+  We could disallow the use of parentheses at the top level of type literals and then we might not have
+  this problem. This is not a backward-compatible change but perhaps worthwhile investigating. Specifically,
+  will this always work (look specifically at channel types where we need parentheses for disambiguation
+  and possibly function types).
+
+- 6/3/2020: Observation: gofmt already removes superflous parentheses around types in parameter lists,
+  so in gofmt'ed code there won't be any such parentheses. Thus we can perhaps make the suggested language
+  change above without too many problems.
+
+- 2/21/2020: We do need top-level parentheses around types in certain situations such as conversions
+  or composite literals. We could disallow parentheses around types in parameter lists only, but that
+  seems quite a bit less elegant.
+
+- 6/13/2020: When comparing against the type list of an interface (to see if the interface is satisfied),
+  we must either recompute the underlying types of the type list entries after the interface was instantiated,
+  or we must compute the underlying type of each entry before comparing. (A type list may contain type
+  parameters which may be substituted with defined types when the interface is instantiated.) With the
+  latter approach (which is what's implemented now), we could relax some of the constraints that we have
+  on type lists entries: We could allow any type and just say that for interface satisfaction we always
+  look at the underlying types.
+
+----------------------------------------------------------------------------------------------------
+OPEN QUESTIONS
+
+- Parsing _ = [](a(int)){} requires parentheses around `(a(int))` - should the parser be smarter in
+  these cases? Another example: []a(b, c){} This cannot be a conversion. Could fix such cases by re-
+  associating the AST when we see a {. Need to be careful, and need to take into account additional
+  complexity of spec.
+- For len/cap(x) where x is of type parameter type and the bound contains arrays only, should the
+  result be a constant? (right now it is not). What are the implications for alternative, non-
+  monomorphizing implementation methods?
+- Confirm that it's ok to use inference in missingMethod to compare parameterized methods.
+
+----------------------------------------------------------------------------------------------------
+DESIGN/IMPLEMENTATION
+
+- 11/19/2019: For type parameters with interface bounds to work, the scope of all type parameters in
+  a type parameter list starts at the "type" keyword. This makes all type parameters visible for all
+  type parameter bounds (interfaces that may be parameterized with the type parameters).
+
+- 12/4/2019: do not allow parenthesized generic uninstantiated types (unless instantiated implicitly)
+  In other words: generic types must always be instantiated before they can be used in any form
+  More generally: Only permit type instantiation T(x) in type context, when the type is a named type.
+  Do not permit it in general in type context: e.g., disallow []T(x) because we consider that a
+  conversion, in general. Same for ([]T)(x).
+
+- 12/12/2019: represent type bounds always as (possibly unnamed) interfaces
+  (contracts are user syntactic sugar)
+
+- 12/19/2019: Type parameters don't act like type aliases. For instance:
+
+        func f(type T1, T2)(x T1) T2 { return x }
+
+  is not valid, no matter how T1 and T2 are instantiated (but if T1 and T2 were type aliases with
+  both of them having type int, the return x would be valid). In fact, the type parameters act more
+  like named types with the methods described by their type bound. But type parameters are never
+  interfaces. To determine: Given a type parameter P, is P == underlying(P) (like for basic types),
+  or is the the underlying type of P something else (like for defined types). Is there an observable
+  difference?
+
+- 12/19/2019: Rewrote contract handling: they are now treated as Objects (rather than Types) throughout.
+
+- 12/20/2019: Decided to start moving type parameters to types (from TypeName to Named), need to do the
+  same for Func. This make more sense as in general any type (conceptually even literal types) could
+  have type parameters. It's a property of the type, not the type name. It also simplified the code.
+
+- 12/20/2019: Type parameters may be part of type lists in contracts/interfaces. It just falls out
+  naturally. Added test cases.
+
+- 12/23/2019: Decision: Type parameters and ordinary (value) parameters are in the same block, notably
+  the function block. The scope of type parameters starts at the 'type' keyword; the scope of ordinary
+  parameters starts with the (opening '{' of the) function body. Both scopes end with the closing '}'
+  of the function body (i.e., the end of the function block).
+
+- 1/2/2020: Implementation decision: contracts can only be declared at the package level.
+
+- 1/6/2020: Experimental: First steps towards permitting type parameters in methods as a generalization.
+  Type-checking problems ooccurring from this are likely to highlight general problematic areas.
+  First consequence: Scope of type parameters starts at "func" keyword which means that receiver type
+  name cannot be a type parameter name declared later (or by the receiver type specification). This
+  seems reasonable and should help avoid confusion which is possible otherwise.
+
+- 1/7/2020: We distinguish embedded instantiated (parameterized) interfaces from methods by enclosing
+  the embedded interfaces in parentheses (the design draft recommends this change). Since this opens
+  the possibility for any parenthesized type (that is an interface), we can also allow (parenthesized)
+  interface literals as it is simpler to permit those than forbid them.
+
+- 1/7/2020: The current implementation permits empty type parameter lists as in: "func f(type)(x int)"
+  but we cannot call such a function as "f()(1)"; the empty type argument list causes problems.
+  Document that we allow empty type parameter list declarations, but not empty actual type parameter
+  lists. (We could allow them for types, but that doesn't seem consistent and probably is confusing).
+
+- 2/19/2020: We accept parenthesized embedded struct fields so we can distinguish between a named
+  field with a parenthesized type foo (T) and an embedded parameterized type (foo(T)), similarly
+  to interace embedding.
+
+- 2/19/2020: Permit parentheses around embedded contracts for symmetry with embedding in structs
+  and interfaces.
+
+- 2/20/2020: Receiver type parameters must always be provided in the receiver parameter list of
+  a method, even if they are not used by the method. Since the receiver acts like an implicit
+  declaration of those type parameters, they may be blank, as with any other declaration.
+
+- 3/20/2020: Local type declarations with an underlying type that is a type parameter lose the
+  methods declared with the type parameter bound. But they don't lose the properties of the
+  underlying type, i.e., the properties of the type parameter bound's type list.
+  This is something to consider if we were contemplating moving to a methods-only approach
+  (no type lists), even though local type declarations are exceedingly rare if they exist at
+  all in the wild.
+
+- 3/24/2020: Implemented initial support for bidirection type unification which could make
+  type inference more powerful if we decided to go that route. Specifically, this would
+  permit type inference for the type parameters of a generic function argument. Given:
+  func h(f func(int)); func g(type T)(T); one could allow the call: h(g) and the type argument
+  T of g would be inferred to be int. While not hard to implement, this would be a special case
+  of the rule that all generic types/functions must be instantiated before they are used except
+  for function calls where the type arguments can be inferred from the actual arguments.
+  Decided that for now we leave things as is, since it's not clear the extra complexity is
+  worth the (probably small) convenience.
+
+- 3/25/2020: We can probably simplify the contract syntax again and only permit one of three
+  possible constraint entries: 1) an embedded contract, 2) a type parameter followed by a
+  method signature, and 3) a type parameter followed by a type list. This is what the type
+  checker currently supports and the printer can print. (The parser still accepts a list of
+  method signatures or types, freely mixed.)
+
+- 4/24/2020: Permit omission of explicit type bound instantiation if the type bound is an
+  interface that applies to exactly one type parameter and the type bound expects exactly
+  one type argument. This makes parameterized interface type bounds easier to use in a common
+  case.
+
+- 5/?/2020: Relaxed above syntactic sugar and permit omission of explicit type bound instantiation
+  in any case where the type bound only accepts a single type parameter.
+  We may not want to permit this in the first version as this is something we can always add later.
+
+- 6/3/2020: A function type parameter acts like a named type. If its type bound has a type list
+  that type list determines the underlying type of the type parameter. If the bound doesn't have
+  a type list, the underlying type of a type parameter is itself. (We may decide that in this
+  latter case there may no underlying type at all which would perhaps more consistent. But this
+  is not clear cut.)
+
+- 6/6/2020: The underlying type of a type parameter must _always_ be itself, otherwise a declaration
+  such as: type T(type P interface{type int}) P would have an underlying type int which is wrong.
+
+- 6/7/2020: Introduced the notion of an operational type which is used when determining what
+  operations are supported by a value of a given type. The operational type of a type parameter
+  is determined by its type bound. The operational type of any other type is its underlying
+  type. This approach appears to complete the picture about the nature of type parameters.
+
+- 6/7/2020: Removed support for contracts to match the latest design draft.
+
+- 6/15/2020: Disabled check that types in type lists must only contain basic types or composite types
+  composed of basic types. It is not needed since we always must recompute the underlying types
+  after a (possible) instantiation anyway (see observation from 6/3/2020).
diff --git a/src/go/types/README b/src/go/types/README
new file mode 100644
index 0000000..8a0c56a
--- /dev/null
+++ b/src/go/types/README
@@ -0,0 +1,68 @@
+This version of go/types is part of the prototype that implements the
+extended Go language as outlined by the latest generics draft design.
+
+DISCLAIMER
+
+This code is based on the std/library's go/types package but it has
+been modified heavily. Please bear in mind that:
+
+- This is a prototype. Expect bugs, incomplete parts, and suboptimal
+  and (gulp) possibly ugly code.
+
+- While all the major aspects of the generics design draft have been
+  implemented, parts are missing, especially around the operations permitted
+  on operands of generic types. In such cases, the result is most often
+  an error reporting that a certain operation is not permitted even though
+  it should be according to the draft design.
+
+- As prototyping continues, expect refinement and possibly divergence
+  from the most recent draft design published.
+
+EXAMPLE CODE
+
+For tests and example code (with detailed comments) look for files
+with suffix .go2 in the testdata and examples subdirectories.
+
+(The suffix .go2 is solely to distinguish them from regular Go code and
+to prevent gofmt from touching them. We expect a proper implementation to
+keep using .go .)
+
+RUNNING THE TYPE-CHECKER
+
+The type-checker is automatically run as part of the go2go tool.
+To experiment with generic code, it is recommened to use that tool.
+
+But the type-checker can also be run stand-alone on source code if
+so desired. There are two primary ways:
+
+1) By building the gotype tool in this source directory:
+
+      go build gotype.go
+
+   and then running the resulting binary on some input files
+
+      ./gotype <package files>
+
+   (Make sure to use the correct go tool when building.)
+
+2) By using the type-checker's TestCheck test function which
+   accepts a list of user provided files:
+
+      go test -run Check$ -errlist -files <package files>
+
+   For instance:
+
+      go test -run Check$ -files examples/types.go2
+
+   TestCheck will match any type errors against ERROR comments
+   in the source files and complain about discrepancies.
+   To report the errors instead, use:
+
+      go test -run Check$ -errlist -files examples/types.go2
+
+   To see a trace of the type checker progress, use the -v flag:
+
+      go test -v -run Check$ -errlist -files examples/types.go2
+
+   (When playing with this code, sometimes go vet gets in the
+   way, so it can be helpful to also provide -vet off.)
diff --git a/src/go/types/errors_test.go b/src/go/types/errors_test.go
new file mode 100644
index 0000000..fdbe07c
--- /dev/null
+++ b/src/go/types/errors_test.go
@@ -0,0 +1,25 @@
+// Copyright 2020 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package types
+
+import "testing"
+
+func TestStripAnnotations(t *testing.T) {
+	for _, test := range []struct {
+		in, want string
+	}{
+		{"", ""},
+		{"   ", "   "},
+		{"foo", "foo"},
+		{"foo₀", "foo"},
+		{"foo(T₀)", "foo(T)"},
+		{"#foo(T₀)", "foo(T)"},
+	} {
+		got := stripAnnotations(test.in)
+		if got != test.want {
+			t.Errorf("%q: got %q; want %q", test.in, got, test.want)
+		}
+	}
+}
diff --git a/test/gen/err001.go2 b/test/gen/err001.go2
new file mode 100644
index 0000000..24b865f
--- /dev/null
+++ b/test/gen/err001.go2
@@ -0,0 +1,64 @@
+// errorcheck
+
+// Copyright 2020 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package p
+
+func F1[T comparable]() {}
+func F2() { F1[[]int]() } // ERROR "\[\]int does not satisfy comparable$"
+
+type C interface {
+	M()
+}
+
+func F3[T C]() {}
+func F4() { F3[int]() } // ERROR "int does not satisfy C.*method M"
+
+func F5[T any]() { F3[T]() } // ERROR "T does not satisfy C.*method M"
+
+type signed interface {
+	type int, int8, int16, int32, int64
+}
+
+type integer interface {
+	type int, int8, int16, int32, int64,
+		uint, uint8, uint16, uint32, uint64, uintptr
+}
+
+func F6[T signed](a T) bool { return a < 0 }
+func F7[T any](a T) bool { return F6(a) } // ERROR "T does not satisfy signed.*T has no type constraints"
+func F8[T integer](a T) bool { return F6(a) } // ERROR "T does not satisfy signed.*T type constraint uint not found in"
+func F9(a uint) bool { return F6(a) } // ERROR "uint does not satisfy signed.*uint not found in"
+
+type MyInt int
+type MyUint uint
+
+func F10(a MyInt) bool { return F6(a) }
+func F11(a MyUint) bool { return F6(a) } // ERROR "MyUint does not satisfy signed.*uint not found in"
+
+type C2 interface {
+	C
+	signed
+}
+
+func F20[T C2](a T) bool {
+	a.M()
+	return a < 0
+}
+
+func (MyInt) M() {}
+
+func (MyUint) M() {}
+
+type S struct {}
+func (S) M() {}
+
+func F21() bool { return F20(MyInt(0)) }
+func F22() bool { return F20(0) } // ERROR "int does not satisfy C2.*(missing method M)"
+func F23[T any](a T) bool { return F20(a) } // ERROR "T does not satisfy C2.*(missing method M)"
+func F24[T integer](a T) bool { return F20(a) } // ERROR "T does not satisfy C2.*(missing method M)"
+func F25(a uint) bool { return F20(a) } // ERROR "uint does not satisfy C2.*(missing method M)"
+func F26(a MyUint) bool { return F20(a) } // ERROR "MyUint does not satisfy C2.*uint not found in"
+func F27(a S) bool { return F20(a) } // ERROR "S does not satisfy C2.*struct{} not found in"
diff --git a/test/gen/err002.dir/a.go2 b/test/gen/err002.dir/a.go2
new file mode 100644
index 0000000..de3ef43
--- /dev/null
+++ b/test/gen/err002.dir/a.go2
@@ -0,0 +1,9 @@
+// Copyright 2020 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package a
+
+type C interface {
+	M()
+}
diff --git a/test/gen/err002.dir/b.go2 b/test/gen/err002.dir/b.go2
new file mode 100644
index 0000000..b738a4e
--- /dev/null
+++ b/test/gen/err002.dir/b.go2
@@ -0,0 +1,10 @@
+// Copyright 2020 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package b
+
+import "./a"
+
+func F1[T a.C]() {}
+func F2() { F1(int)() } // ERROR "int does not satisfy a.C.*method M"
diff --git a/test/gen/err002.go2 b/test/gen/err002.go2
new file mode 100644
index 0000000..c04e67c
--- /dev/null
+++ b/test/gen/err002.go2
@@ -0,0 +1,7 @@
+// errorcheckdir
+
+// Copyright 2020 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package ignored
diff --git a/test/gen/err003.go2 b/test/gen/err003.go2
new file mode 100644
index 0000000..36e9e63
--- /dev/null
+++ b/test/gen/err003.go2
@@ -0,0 +1,29 @@
+// errorcheck
+
+// Copyright 2020 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package p
+
+type Setter interface {
+	Set(string)
+}
+
+func FromStrings[T Setter](s []string) []T {
+	result := make([]T, len(s))
+	for i, v := range s {
+		result[i].Set(v)
+	}
+	return result
+}
+
+type Settable int
+
+func (p *Settable) Set(s string) {
+	*p = 0
+}
+
+func F() {
+	FromStrings[Settable]([]string{"1"}) // ERROR "Settable does not satisfy Setter"
+}
diff --git a/test/gen/err004.go2 b/test/gen/err004.go2
new file mode 100644
index 0000000..e4846ae
--- /dev/null
+++ b/test/gen/err004.go2
@@ -0,0 +1,11 @@
+// errorcheck
+
+// Copyright 2020 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package p
+
+func F() {
+     type t[T any] T // ERROR "parameterized type"
+}
diff --git a/test/gen/err005.go2 b/test/gen/err005.go2
new file mode 100644
index 0000000..257a719
--- /dev/null
+++ b/test/gen/err005.go2
@@ -0,0 +1,15 @@
+// errorcheck
+
+// Copyright 2020 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Issue 39738.
+package p
+
+func F1[T any]() {}
+
+func F2() {
+     type s struct{}
+     F1[s]() // ERROR "locally defined type"
+}
diff --git a/test/gen/err006.go2 b/test/gen/err006.go2
new file mode 100644
index 0000000..6881c13
--- /dev/null
+++ b/test/gen/err006.go2
@@ -0,0 +1,16 @@
+// errorcheck
+
+// Copyright 2020 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Issue 39743.
+package p
+
+type S[T any] struct{}
+
+func (s S[_]) M() {}	// ERROR "_"
+
+func F() {
+	S[int]{}.M()
+}
diff --git a/test/gen/g001.go2 b/test/gen/g001.go2
new file mode 100644
index 0000000..cb0170e
--- /dev/null
+++ b/test/gen/g001.go2
@@ -0,0 +1,23 @@
+// run
+
+// Copyright 2020 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import "fmt"
+
+func Print[T any](s []T) {
+	for _, v := range s {
+		fmt.Println(v)
+	}
+}
+
+func PrintInts(s []int) {
+	Print[int](s)
+}
+
+func main() {
+	PrintInts([]int{1, 2})
+}
diff --git a/test/gen/g001.out b/test/gen/g001.out
new file mode 100644
index 0000000..1191247
--- /dev/null
+++ b/test/gen/g001.out
@@ -0,0 +1,2 @@
+1
+2
diff --git a/test/gen/g002.go2 b/test/gen/g002.go2
new file mode 100644
index 0000000..29f0b9f
--- /dev/null
+++ b/test/gen/g002.go2
@@ -0,0 +1,27 @@
+// run
+
+// Copyright 2020 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import "fmt"
+
+func Print1[T any](s []T) {
+	for _, v := range s {
+		fmt.Println(v)
+	}
+}
+
+func Print2[T any](s []T) {
+	Print1(T)(s)
+}
+
+func PrintInts(s []int) {
+	Print2(int)(s)
+}
+
+func main() {
+	PrintInts([]int{1, 2})
+}
diff --git a/test/gen/g002.out b/test/gen/g002.out
new file mode 100644
index 0000000..1191247
--- /dev/null
+++ b/test/gen/g002.out
@@ -0,0 +1,2 @@
+1
+2
diff --git a/test/gen/g003.go2 b/test/gen/g003.go2
new file mode 100644
index 0000000..813ed92
--- /dev/null
+++ b/test/gen/g003.go2
@@ -0,0 +1,32 @@
+// run
+
+// Copyright 2020 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import (
+	"fmt"
+	"unsafe"
+)
+
+type Pair[F1, F2 any] struct {
+	f1 F1
+	f2 F2
+}
+
+func main() {
+	p := Pair[int32, int64]{1, 2}
+	if got, want := unsafe.Sizeof(p.f1), uintptr(4); got != want {
+		panic(fmt.Sprintf("unexpected f1 size == %d want %d", got, want))
+	}
+	if got, want := unsafe.Sizeof(p.f2), uintptr(8); got != want {
+		panic(fmt.Sprintf("unexpected f2 size == %d want %d", got, want))
+	}
+	type MyPair struct { f1 int32; f2 int64 }
+	mp := MyPair(p)
+	if mp.f1 != 1 || mp.f2 != 2 {
+		panic(fmt.Sprintf("mp == %#v want %#v", mp, MyPair{1, 2}))
+	}
+}
diff --git a/test/gen/g004.go2 b/test/gen/g004.go2
new file mode 100644
index 0000000..940d6e3
--- /dev/null
+++ b/test/gen/g004.go2
@@ -0,0 +1,39 @@
+// run
+
+// Copyright 2020 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import "fmt"
+
+type Value[T any] struct {
+	val T
+}
+
+func (v *Value[T]) Get() T {
+	return v.val
+}
+
+func (v *Value[T]) Set(val T) {
+	v.val = val
+}
+
+func main() {
+	var v1 Value[int]
+	v1.Set(1)
+	if got, want := v1.Get(), 1; got != want {
+		panic(fmt.Sprintf("Get() == %d, want %d", got, want))
+	}
+	v1.Set(2)
+	if got, want := v1.Get(), 2; got != want {
+		panic(fmt.Sprintf("Get() == %d, want %d", got, want))
+	}
+
+	var v2 Value[string]
+	v2.Set("a")
+	if got, want := v2.Get(), "a"; got != want {
+		panic(fmt.Sprintf("Get() == %q, want %q", got, want))
+	}
+}
diff --git a/test/gen/g005.dir/a.go2 b/test/gen/g005.dir/a.go2
new file mode 100644
index 0000000..098d876
--- /dev/null
+++ b/test/gen/g005.dir/a.go2
@@ -0,0 +1,30 @@
+// Copyright 2020 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package a
+
+type Stack[E any] []E
+
+func (s *Stack[E]) Push(e E) {
+	*s = append(*s, e)
+}
+
+func (s *Stack[E]) Pop() (E, bool) {
+	l := len(*s)
+	if l == 0 {
+		var zero E
+		return zero, false
+	}
+	r := (*s)[l - 1]
+	*s = (*s)[:l - 1]
+	return r, true
+}
+
+func (s *Stack[E]) IsEmpty() bool {
+	return len(*s) == 0
+}
+
+func (s *Stack[E]) Len() int {
+	return len(*s)
+}
diff --git a/test/gen/g005.dir/b.go2 b/test/gen/g005.dir/b.go2
new file mode 100644
index 0000000..8523323
--- /dev/null
+++ b/test/gen/g005.dir/b.go2
@@ -0,0 +1,31 @@
+// Copyright 2020 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import "./a"
+
+func main() {
+	var s a.Stack[string]
+	s.Push("hi")
+	s.Push("bye")
+	if s.IsEmpty() {
+		panic("unexpected IsEmpty")
+	}
+	if s.Len() != 2 {
+		panic("bad Len")
+	}
+	if v, ok := s.Pop(); !ok || v != "bye" {
+		panic("bad Pop 1")
+	}
+	if v, ok := s.Pop(); !ok || v != "hi" {
+		panic("bad Pop 2")
+	}
+	if !s.IsEmpty() {
+		panic("expected IsEmpty")
+	}
+	if s.Len() != 0 {
+		panic("bad Len 2")
+	}
+}
diff --git a/test/gen/g005.go2 b/test/gen/g005.go2
new file mode 100644
index 0000000..4a7d9e1
--- /dev/null
+++ b/test/gen/g005.go2
@@ -0,0 +1,7 @@
+// rundir
+
+// Copyright 2020 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package ignored
diff --git a/test/gen/g006.go2 b/test/gen/g006.go2
new file mode 100644
index 0000000..8171e2a
--- /dev/null
+++ b/test/gen/g006.go2
@@ -0,0 +1,96 @@
+// run
+
+// Copyright 2020 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import (
+	"fmt"
+	"math"
+	"os"
+	"sort"
+)
+
+type Ordered interface {
+	type int, int8, int16, int32, int64,
+		uint, uint8, uint16, uint32, uint64, uintptr,
+		float32, float64,
+		string
+}
+
+type orderedSlice[Elem Ordered] []Elem
+
+func (s orderedSlice[Elem]) Len() int           { return len(s) }
+func (s orderedSlice[Elem]) Less(i, j int) bool {
+	if s[i] < s[j] {
+		return true
+	}
+	isNaN := func(f Elem) bool { return f != f }
+	if isNaN(s[i]) && !isNaN(s[j]) {
+		return true
+	}
+	return false
+}
+func (s orderedSlice[Elem]) Swap(i, j int)      { s[i], s[j] = s[j], s[i] }
+
+func OrderedSlice[Elem Ordered](s []Elem) {
+	sort.Sort(orderedSlice[Elem](s))
+}
+
+var ints = []int{74, 59, 238, -784, 9845, 959, 905, 0, 0, 42, 7586, -5467984, 7586}
+var float64s = []float64{74.3, 59.0, math.Inf(1), 238.2, -784.0, 2.3, math.NaN(), math.NaN(), math.Inf(-1), 9845.768, -959.7485, 905, 7.8, 7.8}
+var strings = []string{"", "Hello", "foo", "bar", "foo", "f00", "%*&^*&^&", "***"}
+
+func TestSortOrderedInts() bool {
+	return testOrdered("ints", ints, sort.Ints)
+}
+
+func TestSortOrderedFloat64s() bool {
+	return testOrdered("float64s", float64s, sort.Float64s)
+}
+
+func TestSortOrderedStrings() bool {
+	return testOrdered("strings", strings, sort.Strings)
+}
+
+func testOrdered[Elem Ordered](name string, s []Elem, sorter func([]Elem)) bool {
+	s1 := make([]Elem, len(s))
+	copy(s1, s)
+	s2 := make([]Elem, len(s))
+	copy(s2, s)
+	OrderedSlice(s1)
+	sorter(s2)
+	ok := true
+	if !sliceEq(s1, s2) {
+		fmt.Printf("%s: got %v, want %v", name, s1, s2)
+		ok = false
+	}
+	for i := len(s1) - 1; i > 0; i-- {
+		if s1[i] < s1[i-1] {
+			fmt.Printf("%s: element %d (%v) < element %d (%v)", name, i, s1[i], i - 1, s1[i - 1])
+			ok = false
+		}
+	}
+	return ok
+}
+
+func sliceEq[Elem Ordered](s1, s2 []Elem) bool {
+	for i, v1 := range s1 {
+		v2 := s2[i]
+		if v1 != v2 {
+			isNaN := func(f Elem) bool { return f != f }
+			if !isNaN(v1) || !isNaN(v2) {
+				return false
+			}
+		}
+	}
+	return true
+}
+
+func main() {
+	if !TestSortOrderedInts() || !TestSortOrderedFloat64s() || !TestSortOrderedStrings() {
+		os.Exit(1)
+	}
+}
diff --git a/test/gen/g007.go2 b/test/gen/g007.go2
new file mode 100644
index 0000000..57f7ee2
--- /dev/null
+++ b/test/gen/g007.go2
@@ -0,0 +1,20 @@
+// compile
+
+// Copyright 2020 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Using a type literal based on a type parameter as a type argument
+// in a result.
+
+package p
+
+type S[T any] struct {
+	f T
+}
+
+func SliceS[T any]() S[[]T] {
+	return S[[]T]{nil}
+}
+
+var V = SliceS[int]()
diff --git a/test/gen/g008.go2 b/test/gen/g008.go2
new file mode 100644
index 0000000..94afbff
--- /dev/null
+++ b/test/gen/g008.go2
@@ -0,0 +1,41 @@
+// run
+
+// Copyright 2020 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+type Setter interface {
+	Set(string)
+}
+
+func FromStrings[T Setter](s []string) []T {
+	result := make([]T, len(s))
+	for i, v := range s {
+		result[i].Set(v)
+	}
+	return result
+}
+
+type Settable int
+
+func (p *Settable) Set(s string) {
+	*p = 0
+}
+
+func F() {
+	defer func() {
+		if recover() == nil {
+			panic("did not panic as expected")
+		}
+	}()
+	// This should type check but should panic at run time,
+	// because it will make a slice of *Settable and then call
+	// Set on a nil value.
+	FromStrings(*Settable)([]string{"1"})
+}
+
+func main() {
+	F()
+}
diff --git a/test/gen/g009.go2 b/test/gen/g009.go2
new file mode 100644
index 0000000..aa5a8fd
--- /dev/null
+++ b/test/gen/g009.go2
@@ -0,0 +1,43 @@
+// run
+
+// Copyright 2020 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import (
+	"log"
+	"strconv"
+)
+
+type Setter2[B any] interface {
+	Set(string)
+	type *B
+}
+
+func FromStrings2[T any, PT Setter2[T]](s []string) []T {
+	result := make([]T, len(s))
+	for i, v := range s {
+		p := PT(&result[i])
+		p.Set(v)
+	}
+	return result
+}
+
+type Settable int
+
+func (p *Settable) Set(s string) {
+	i, err := strconv.Atoi(s)
+	if err != nil {
+		log.Fatal(err)
+	}
+	*p = Settable(i)
+}
+
+func main() {
+	s := FromStrings2[Settable, *Settable]([]string{"1"})
+	if len(s) != 1 || s[0] != 1 {
+		log.Fatalf("got %v, want %v", s, []int{1})
+	}
+}
diff --git a/test/gen/g010.go2 b/test/gen/g010.go2
new file mode 100644
index 0000000..0c4bf98
--- /dev/null
+++ b/test/gen/g010.go2
@@ -0,0 +1,38 @@
+// run
+
+// Copyright 2020 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import (
+	"log"
+	"strconv"
+)
+
+func FromStrings3[T any](s []string, set func(*T, string)) []T {
+	results := make([]T, len(s))
+	for i, v := range s {
+		set(&results[i], v)
+	}
+	return results
+}
+
+type Settable int
+
+func (p *Settable) Set(s string) {
+	i, err := strconv.Atoi(s)
+	if err != nil {
+		log.Fatal(err)
+	}
+	*p = Settable(i)
+}
+
+func main() {
+	s := FromStrings3[Settable]([]string{"1"},
+		func(p *Settable, s string) { p.Set(s) })
+	if len(s) != 1 || s[0] != 1 {
+		log.Fatalf("got %v, want %v", s, []int{1})
+	}
+}
diff --git a/test/gen/g011.go2 b/test/gen/g011.go2
new file mode 100644
index 0000000..2ca4660
--- /dev/null
+++ b/test/gen/g011.go2
@@ -0,0 +1,46 @@
+// run
+
+// Copyright 2020 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import (
+	"log"
+	"strconv"
+)
+
+type Setter[B any] interface {
+	Set(string)
+	type *B
+}
+
+func FromStrings[T any, PT Setter[T]](s []string) []T {
+	result := make([]T, len(s))
+	for i, v := range s {
+		// The type of &result[i] is *T which is in the type list
+		// of Setter, so we can convert it to PT.
+		p := PT(&result[i])
+		// PT has a Set method.
+		p.Set(v)
+	}
+	return result
+}
+
+type Settable int
+
+func (p *Settable) Set(s string) {
+	i, err := strconv.Atoi(s)
+	if err != nil {
+		log.Fatal(err)
+	}
+	*p = Settable(i)
+}
+
+func main() {
+	s := FromStrings[Settable, *Settable]([]string{"1"})
+	if len(s) != 1 || s[0] != 1 {
+		log.Fatalf("got %v, want %v", s, []int{1})
+	}
+}
diff --git a/test/gen/g012.go2 b/test/gen/g012.go2
new file mode 100644
index 0000000..46d7d61
--- /dev/null
+++ b/test/gen/g012.go2
@@ -0,0 +1,90 @@
+// run
+
+// Copyright 2020 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import "math"
+
+type Numeric interface {
+	type int, int8, int16, int32, int64,
+		uint, uint8, uint16, uint32, uint64, uintptr,
+		float32, float64,
+		complex64, complex128
+}
+
+// NumericAbs matches numeric types with an Abs method.
+type NumericAbs[T any] interface {
+	Numeric
+	Abs() T
+}
+
+// AbsDifference computes the absolute value of the difference of
+// a and b, where the absolute value is determined by the Abs method.
+func AbsDifference[T NumericAbs[T]](a, b T) T {
+	d := a - b
+	return d.Abs()
+}
+
+// OrderedNumeric matches numeric types that support the < operator.
+type OrderedNumeric interface {
+	type int, int8, int16, int32, int64,
+		uint, uint8, uint16, uint32, uint64, uintptr,
+		float32, float64
+}
+
+// Complex matches the two complex types, which do not have a < operator.
+type Complex interface {
+	type complex64, complex128
+}
+
+// OrderedAbs is a helper type that defines an Abs method for
+// ordered numeric types.
+type OrderedAbs[T OrderedNumeric] T
+
+func (a OrderedAbs[T]) Abs() OrderedAbs[T] {
+	if a < 0 {
+		return -a
+	}
+	return a
+}
+
+// ComplexAbs is a helper type that defines an Abs method for
+// complex types.
+type ComplexAbs[T Complex] T
+
+func (a ComplexAbs[T]) Abs() ComplexAbs[T] {
+	r := float64(real(a))
+	i := float64(imag(a))
+	d := math.Sqrt(r * r + i * i)
+	return ComplexAbs[T](complex(d, 0))
+}
+
+// OrderedAbsDifference returns the absolute value of the difference
+// between a and b, where a and b are of an ordered type.
+func OrderedAbsDifference[T OrderedNumeric](a, b T) T {
+	return T(AbsDifference(OrderedAbs[T](a), OrderedAbs[T](b)))
+}
+
+// ComplexAbsDifference returns the absolute value of the difference
+// between a and b, where a and b are of a complex type.
+func ComplexAbsDifference[T Complex](a, b T) T {
+	return T(AbsDifference(ComplexAbs[T](a), ComplexAbs[T](b)))
+}
+
+func main() {
+	if d := OrderedAbsDifference(1.0, -2.0); d != 3 {
+		panic(d)
+	}
+	if d := OrderedAbsDifference(-1.0, 2.0); d != 3 {
+		panic(d)
+	}
+	if d := ComplexAbsDifference(5.0 + 2.0i, 2.0 - 2.0i); d != 5 {
+		panic(d)
+	}
+	if d := ComplexAbsDifference(2.0 - 2.0i, 5.0 + 2.0i); d != 5 {
+		panic(d)
+	}
+}
diff --git a/test/gen/g013.go2 b/test/gen/g013.go2
new file mode 100644
index 0000000..4a57a53
--- /dev/null
+++ b/test/gen/g013.go2
@@ -0,0 +1,48 @@
+// run
+
+// Copyright 2020 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+type Gen[A any] func() (A, bool)
+
+func combine[T1, T2, T any](g1 Gen[T1], g2 Gen[T2], join func(T1, T2) T) Gen[T] {
+    return func() (T, bool) {
+        var t T
+        t1, ok := g1()
+        if !ok {
+            return t, false
+        }
+        t2, ok := g2()
+        if !ok {
+            return t, false
+        }
+        return join(t1, t2), true
+    }
+}
+
+type Pair[A, B any] struct {
+	A A
+	B B
+}
+
+func NewPair[A, B any](a A, b B) Pair[A, B] { return Pair[A, B]{a, b} }
+
+func Combine2[A, B any](ga Gen[A], gb Gen[B]) Gen[Pair[A, B]] {
+    return combine(ga, gb, NewPair(A, B))
+}
+
+func main() {
+	var g1 Gen[int] = func() (int, bool) { return 3, true }
+	var g2 Gen[string] = func() (string, bool) { return "x", false }
+	gc := combine(g1, g2, NewPair[int, string])
+	gc2 := Combine2(g1, g2)
+	if got, ok := gc(); ok {
+		panic(got)
+	}
+	if got2, ok := gc2(); ok {
+		panic(got2)
+	}
+}
diff --git a/test/gen/g014.go2 b/test/gen/g014.go2
new file mode 100644
index 0000000..e9d1d4d
--- /dev/null
+++ b/test/gen/g014.go2
@@ -0,0 +1,44 @@
+// run
+
+// Copyright 2020 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+type T[A any] struct {
+	V A
+}
+
+type S1 struct {
+	T[int]
+	V string
+}
+
+type Tint = T[int]
+type Tbool = T[bool]
+
+type S2 struct {
+	Tint
+	Tbool
+	V string
+}
+
+type S3 struct {
+	*T[int]
+}
+
+func main() {
+	var s1 S1
+	if s1.T.V != 0 {
+		panic(s1)
+	}
+	var s2 S2
+	if s2.Tint.V != 0 || s2.Tbool.V {
+		panic(s2)
+	}
+	var s3 S3
+	if s3.T != nil {
+		panic(s3)
+	}
+}
diff --git a/test/gen/g015.go2 b/test/gen/g015.go2
new file mode 100644
index 0000000..71d1328
--- /dev/null
+++ b/test/gen/g015.go2
@@ -0,0 +1,17 @@
+// compile
+
+// Copyright 2020 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package p
+
+func F1[T any](x T) {}
+
+func F2(c <-chan int) {
+	F1(c)
+}
+
+func F3(c chan <- int) {
+	F1(c)
+}
diff --git a/test/gen/g016.go2 b/test/gen/g016.go2
new file mode 100644
index 0000000..0508687
--- /dev/null
+++ b/test/gen/g016.go2
@@ -0,0 +1,92 @@
+// run
+
+// Copyright 2020 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import "fmt"
+
+type Any interface{}
+
+type Function[a, b any] interface {
+	Apply(x a) b
+}
+
+type incr struct{ n int }
+
+func (this incr) Apply(x int) int {
+	return x + this.n
+}
+
+type pos struct{}
+
+func (this pos) Apply(x int) bool {
+	return x > 0
+}
+
+type compose[a, b, c any] struct {
+	f Function[a, b]
+	g Function[b, c]
+}
+
+func (this compose[a, b, c]) Apply(x a) c {
+	return this.g.Apply(this.f.Apply(x))
+}
+
+type Eq[a any] interface {
+	Equal(a) bool
+}
+
+type Int int
+
+func (this Int) Equal(that int) bool {
+	return int(this) == that
+}
+
+type List[a any] interface {
+	Match(casenil Function[Nil[a], Any], casecons Function[Cons[a], Any]) Any
+}
+
+type Nil[a any] struct{}
+
+func (xs Nil[a]) Match(casenil Function[Nil[a], Any], casecons Function[Cons[a], Any]) Any {
+	return casenil.Apply(xs)
+}
+
+type Cons[a any] struct {
+	Head a
+	Tail List[a]
+}
+
+func (xs Cons[a]) Match(casenil Function[Nil[a], Any], casecons Function[Cons[a], Any]) Any {
+	return casecons.Apply(xs)
+}
+
+type mapNil[a, b any] struct{}
+
+func (m mapNil[a, b]) Apply(_ Nil[a]) Any {
+	return Nil[b]{}
+}
+
+type mapCons[a, b any] struct {
+	f Function[a, b]
+}
+
+func (m mapCons[a, b]) Apply(xs Cons[a]) Any {
+	return Cons[b]{m.f.Apply(xs.Head), Map[a, b](m.f, xs.Tail)}
+}
+
+func Map[a, b any](f Function[a, b], xs List[a]) List[b] {
+	return xs.Match(mapNil[a, b]{}, mapCons[a, b]{f}).(List[b])
+}
+
+func main() {
+	var xs List[int] = Cons[int]{3, Cons[int]{6, Nil[int]{}}}
+	var ys List[int] = Map[int, int](incr{-5}, xs)
+	var xz List[bool] = Map[int, bool](pos{}, ys)
+	if fmt.Sprint(xz) != "{false {true {}}}" {
+		panic(xz)
+	}
+}
diff --git a/test/gen/g017.go2 b/test/gen/g017.go2
new file mode 100644
index 0000000..1becc9c
--- /dev/null
+++ b/test/gen/g017.go2
@@ -0,0 +1,24 @@
+// run
+
+// Copyright 2020 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+type Recv <-chan int
+
+type sliceOf[E any] interface {
+	type []E
+}
+
+func Append[S sliceOf[T], T any](s S, t ...T) S {
+	return append(s, t...)
+}
+
+func main() {
+	a := Append([]Recv{nil}, Recv(nil))
+	if len(a) != 2 || a[0] != nil || a[1] != nil {
+		panic(a)
+	}
+}
diff --git a/test/gen/g018.go2 b/test/gen/g018.go2
new file mode 100644
index 0000000..a02566c
--- /dev/null
+++ b/test/gen/g018.go2
@@ -0,0 +1,27 @@
+// compile
+
+// Copyright 2020 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package p
+
+type I1 interface {
+	comparable
+}
+
+type I2 interface {
+	I1
+}
+
+type I3 I2
+
+type I4 interface {
+	type int
+}
+
+type I5 interface {
+	I4
+}
+
+type I6 I5
diff --git a/test/gen/g019.go2 b/test/gen/g019.go2
new file mode 100644
index 0000000..5ca57c9
--- /dev/null
+++ b/test/gen/g019.go2
@@ -0,0 +1,24 @@
+// compile
+
+// Copyright 2020 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Issue 39662.
+package p
+
+type S1 struct{}
+func (*S1) M() {}
+
+type S2 struct{}
+func (S2) M() {}
+
+func F1[T interface{ M() }](t T) {
+	_ = T.M
+}
+
+func F2() {
+	F1(&S1{})
+	F1(S2{})
+	F1(&S2{})
+}
diff --git a/test/gen/g020.go2 b/test/gen/g020.go2
new file mode 100644
index 0000000..420035d
--- /dev/null
+++ b/test/gen/g020.go2
@@ -0,0 +1,23 @@
+// compile
+
+// Copyright 2020 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Issue 39653.
+package p
+
+type E struct{}
+
+type N[T any] struct {
+	i int
+	n T
+}
+
+func F1[T any](i int, n T) N[T] {
+	return N[T]{i: i, n: n}
+}
+
+func F2() {
+	F1(1, F1(2, F1(3, E{})))
+}
diff --git a/test/gen/g021.go2 b/test/gen/g021.go2
new file mode 100644
index 0000000..8b025bc
--- /dev/null
+++ b/test/gen/g021.go2
@@ -0,0 +1,50 @@
+// run
+
+// Copyright 2020 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import "sync"
+
+// A Lockable is a value that may be safely simultaneously accessed
+// from multiple goroutines via the Get and Set methods.
+type Lockable[T any] struct {
+	T
+	mu sync.Mutex
+}
+
+// Get returns the value stored in a Lockable.
+func (l *Lockable[T]) Get() T {
+	l.mu.Lock()
+	defer l.mu.Unlock()
+	return l.T
+}
+
+// Set sets the value in a Lockable.
+func (l *Lockable[T]) Set(v T) {
+	l.mu.Lock()
+	defer l.mu.Unlock()
+	l.T = v
+}
+
+func main() {
+	sl := Lockable[string]{T: "a"}
+	if got := sl.Get(); got != "a" {
+		panic(got)
+	}
+	sl.Set("b")
+	if got := sl.Get(); got != "b" {
+		panic(got)
+	}
+
+	il := Lockable[int]{T: 1}
+	if got := il.Get(); got != 1 {
+		panic(got)
+	}
+	il.Set(2)
+	if got := il.Get(); got != 2 {
+		panic(got)
+	}
+}
diff --git a/test/gen/g022.go2 b/test/gen/g022.go2
new file mode 100644
index 0000000..ce5977d
--- /dev/null
+++ b/test/gen/g022.go2
@@ -0,0 +1,11 @@
+// compile
+
+// Copyright 2020 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package p
+
+type F[T any] func(T) error
+
+type instF = F[int]
diff --git a/test/gen/g023.go2 b/test/gen/g023.go2
new file mode 100644
index 0000000..f2affee
--- /dev/null
+++ b/test/gen/g023.go2
@@ -0,0 +1,17 @@
+// compile
+
+// Copyright 2020 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package p
+
+import "net/url"
+
+type S[T any] struct {
+	f T
+}
+
+func F() S[url.Error] {
+	return S[url.Error]{}
+}
diff --git a/test/gen/g024.go2 b/test/gen/g024.go2
new file mode 100644
index 0000000..6ae53af
--- /dev/null
+++ b/test/gen/g024.go2
@@ -0,0 +1,23 @@
+// compile
+
+// Copyright 2020 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Issue 39672
+package p
+
+type S[T any] T
+
+func (r S[T]) M()
+
+func F() {
+	var x S[int]
+	_ = x
+}
+
+func G[T any](v T)
+
+func F2() {
+	G(0)
+}
diff --git a/test/gen/g025.go2 b/test/gen/g025.go2
new file mode 100644
index 0000000..0e6d5bd
--- /dev/null
+++ b/test/gen/g025.go2
@@ -0,0 +1,29 @@
+// compile
+
+// Copyright 2020 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Issue 39692
+package p
+
+type S1[T1, T2 any] struct {
+	f1 T1
+	f2 T2
+}
+
+type S2[T1, T2 any] struct {
+	f1 T1
+	f2 T2
+}
+
+func F1[T any](v T) T {
+	return v
+}
+
+func F() {
+	_ = S2[int, S1[S1[int, int], S1[int, int]]]{
+		f1: 0,
+		f2: S1[S1[int, int], S1[int, int]]{},
+	}
+}
diff --git a/test/gen/g026.go2 b/test/gen/g026.go2
new file mode 100644
index 0000000..0122307
--- /dev/null
+++ b/test/gen/g026.go2
@@ -0,0 +1,16 @@
+// run
+
+// Copyright 2020 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Issue 39625.
+package main
+
+import "io/ioutil"
+
+func F[T1, T2 any](f func(T1) (T2, error)) {}
+
+func main() {
+	F(ioutil.ReadAll)
+}
diff --git a/test/gen/g027.go2 b/test/gen/g027.go2
new file mode 100644
index 0000000..b268df0
--- /dev/null
+++ b/test/gen/g027.go2
@@ -0,0 +1,34 @@
+// compile
+
+// Copyright 2020 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Issue 39678, 39881.
+package p
+
+type B[T any] struct {
+	T
+}
+
+type C struct {
+	F int
+}
+
+type BC B[C]
+
+func F(s BC) {
+	s.F = 7
+}
+
+type Pair[T, U any] struct {
+	T
+	U
+}
+
+func (p Pair[T, U]) M() {
+	_, _ = p.T, p.U
+}
+
+var V1 Pair[Pair[int, int], int]
+var V2 Pair[struct { p Pair[int, int] }, int]
diff --git a/test/gen/g028.go2 b/test/gen/g028.go2
new file mode 100644
index 0000000..8d263d0
--- /dev/null
+++ b/test/gen/g028.go2
@@ -0,0 +1,14 @@
+// compile
+
+// Copyright 2020 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Issue 39688.
+package p
+
+type S[T any] T
+
+func (*S[T]) M() {}
+
+var V S[int]
diff --git a/test/gen/g029.go2 b/test/gen/g029.go2
new file mode 100644
index 0000000..94072b7
--- /dev/null
+++ b/test/gen/g029.go2
@@ -0,0 +1,16 @@
+// compile
+
+// Copyright 2020 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Issue 39741.
+package p
+
+func F[T any]() {
+	type S struct{}
+}
+
+func G() {
+	F[int]()
+}
diff --git a/test/gen/g030.dir/a.go2 b/test/gen/g030.dir/a.go2
new file mode 100644
index 0000000..e32797c
--- /dev/null
+++ b/test/gen/g030.dir/a.go2
@@ -0,0 +1,20 @@
+// Copyright 2020 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+func Len[T any](s []T) int {
+	return len(s)
+}
+
+func F1(s []int) int {
+	return Len(s)
+}
+
+func main() {
+	got := F1(nil) + F2(nil)
+	if got != 0 {
+		panic(got)
+	}
+}
diff --git a/test/gen/g030.dir/b.go2 b/test/gen/g030.dir/b.go2
new file mode 100644
index 0000000..4f3ddc7
--- /dev/null
+++ b/test/gen/g030.dir/b.go2
@@ -0,0 +1,9 @@
+// Copyright 2020 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+func F2(s []int) int {
+	return Len(s)
+}
diff --git a/test/gen/g030.go2 b/test/gen/g030.go2
new file mode 100644
index 0000000..4a7d9e1
--- /dev/null
+++ b/test/gen/g030.go2
@@ -0,0 +1,7 @@
+// rundir
+
+// Copyright 2020 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package ignored
diff --git a/test/gen/g031.go2 b/test/gen/g031.go2
new file mode 100644
index 0000000..c2e5ff5
--- /dev/null
+++ b/test/gen/g031.go2
@@ -0,0 +1,14 @@
+// compile
+
+// Copyright 2020 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Issue 39737.
+package p
+
+func F1[T any]() {}
+
+func F2() {
+	F1(struct { F string `json:"f"` })()
+}
diff --git a/test/gen/g032.go2 b/test/gen/g032.go2
new file mode 100644
index 0000000..1901b86
--- /dev/null
+++ b/test/gen/g032.go2
@@ -0,0 +1,16 @@
+// compile
+
+// Copyright 2020 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Issue 39744.
+package p
+
+import "net/http"
+
+func F1[T any](f func() T) { f() }
+
+func F2() {
+	F1(func() *http.Request { return nil })
+}
diff --git a/test/gen/g033.dir/a.go2 b/test/gen/g033.dir/a.go2
new file mode 100644
index 0000000..1048354
--- /dev/null
+++ b/test/gen/g033.dir/a.go2
@@ -0,0 +1,9 @@
+// Copyright 2020 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package a
+
+type S[T any] struct {
+	F T
+}
diff --git a/test/gen/g033.dir/b.go2 b/test/gen/g033.dir/b.go2
new file mode 100644
index 0000000..19c656d
--- /dev/null
+++ b/test/gen/g033.dir/b.go2
@@ -0,0 +1,16 @@
+// Copyright 2020 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import "./a"
+
+type S = a.S
+
+func main() {
+	var s S[int]
+	if s.F != 0 {
+		panic(s.F)
+	}
+}
diff --git a/test/gen/g033.go2 b/test/gen/g033.go2
new file mode 100644
index 0000000..4a7d9e1
--- /dev/null
+++ b/test/gen/g033.go2
@@ -0,0 +1,7 @@
+// rundir
+
+// Copyright 2020 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package ignored
diff --git a/test/gen/g034.go2 b/test/gen/g034.go2
new file mode 100644
index 0000000..83a1cc2
--- /dev/null
+++ b/test/gen/g034.go2
@@ -0,0 +1,20 @@
+// compile
+
+// Copyright 2020 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package p
+
+type I interface{}
+
+type S[T any] struct {
+	*T
+}
+
+func F() {
+	v := S[I]{}
+	if v.T != nil {
+		panic(v)
+	}
+}
diff --git a/test/gen/g035.dir/a.go2 b/test/gen/g035.dir/a.go2
new file mode 100644
index 0000000..04d848d
--- /dev/null
+++ b/test/gen/g035.dir/a.go2
@@ -0,0 +1,9 @@
+// Copyright 2020 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package a
+
+type S[T any] struct {
+	f T
+}
diff --git a/test/gen/g035.dir/b.go2 b/test/gen/g035.dir/b.go2
new file mode 100644
index 0000000..c4a4846
--- /dev/null
+++ b/test/gen/g035.dir/b.go2
@@ -0,0 +1,20 @@
+// Copyright 2020 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import "./a"
+
+type S = a.S
+
+func F1[T any](T) {}
+
+func F2() { F1(S[string]{}) }
+
+func F3() { F1[S[string]](S[string]{}) }
+
+func main() {
+	F2()
+	F3()
+}
diff --git a/test/gen/g035.go2 b/test/gen/g035.go2
new file mode 100644
index 0000000..4a7d9e1
--- /dev/null
+++ b/test/gen/g035.go2
@@ -0,0 +1,7 @@
+// rundir
+
+// Copyright 2020 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package ignored
diff --git a/test/gen/g036.dir/a.go2 b/test/gen/g036.dir/a.go2
new file mode 100644
index 0000000..2ec4445
--- /dev/null
+++ b/test/gen/g036.dir/a.go2
@@ -0,0 +1,13 @@
+// Copyright 2020 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package a
+
+type S[T any] struct {
+	F T
+}
+
+func NewS[T any](v T) S[T] {
+	return S[T]{F: v}
+}
diff --git a/test/gen/g036.dir/b.go2 b/test/gen/g036.dir/b.go2
new file mode 100644
index 0000000..46bb989
--- /dev/null
+++ b/test/gen/g036.dir/b.go2
@@ -0,0 +1,23 @@
+// Copyright 2020 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import "./a"
+
+type S[T any] struct {
+	F T
+}
+
+func NewS[T any](v T) S[T] {
+	return S[T]{F: v}
+}
+
+func main() {
+	v1 := a.NewS(0)
+	v2 := NewS(0)
+	if v1.F != v2.F {
+		panic(v1)
+	}
+}
diff --git a/test/gen/g036.go2 b/test/gen/g036.go2
new file mode 100644
index 0000000..4a7d9e1
--- /dev/null
+++ b/test/gen/g036.go2
@@ -0,0 +1,7 @@
+// rundir
+
+// Copyright 2020 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package ignored
diff --git a/test/gen/g037.dir/a.go2 b/test/gen/g037.dir/a.go2
new file mode 100644
index 0000000..b49ab07
--- /dev/null
+++ b/test/gen/g037.dir/a.go2
@@ -0,0 +1,11 @@
+// Copyright 2020 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package a
+
+func F() {}
+
+func G[T any]() {
+	F()
+}
diff --git a/test/gen/g037.dir/b.go2 b/test/gen/g037.dir/b.go2
new file mode 100644
index 0000000..dc18c7a
--- /dev/null
+++ b/test/gen/g037.dir/b.go2
@@ -0,0 +1,11 @@
+// Copyright 2020 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import "./a"
+
+func main() {
+	a.G[int]()
+}
diff --git a/test/gen/g037.go2 b/test/gen/g037.go2
new file mode 100644
index 0000000..4a7d9e1
--- /dev/null
+++ b/test/gen/g037.go2
@@ -0,0 +1,7 @@
+// rundir
+
+// Copyright 2020 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package ignored
diff --git a/test/gen/g038.go2 b/test/gen/g038.go2
new file mode 100644
index 0000000..2c08e93
--- /dev/null
+++ b/test/gen/g038.go2
@@ -0,0 +1,15 @@
+// compile
+
+// Copyright 2020 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+func F[T comparable](a T) bool {
+	return a == a
+}
+
+func G() {
+	F(error(nil))
+}
diff --git a/test/gen/g039.go2 b/test/gen/g039.go2
new file mode 100644
index 0000000..b829a45
--- /dev/null
+++ b/test/gen/g039.go2
@@ -0,0 +1,29 @@
+// compile
+
+// Copyright 2020 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package p
+
+type top[T, T2 any] struct {
+	p *parent[T, T2]
+}
+
+type parent[T, T2 any] struct {
+	child[T, T2]
+}
+
+type child[T, T2 any] struct {
+	T2
+}
+
+func (d *top[T, T2]) foo() *T {
+	return d.p.child.foo()
+}
+
+func (rb *child[T, T2]) foo() *T {
+	return nil
+}
+
+var V top[int, int]
diff --git a/test/gen/g040.go2 b/test/gen/g040.go2
new file mode 100644
index 0000000..6942f3b
--- /dev/null
+++ b/test/gen/g040.go2
@@ -0,0 +1,19 @@
+// compile
+
+// Copyright 2020 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package p
+
+type S1[T any] struct{}
+
+type S2[K comparable] struct{}
+
+type S3[K comparable] struct {
+	f map[K]*S1[*S2[K]]
+}
+
+var V = S3[int]{
+	f: make(map[int]*S1[*S2[int]]),
+}
diff --git a/test/gen/g041.go2 b/test/gen/g041.go2
new file mode 100644
index 0000000..69d7b8e
--- /dev/null
+++ b/test/gen/g041.go2
@@ -0,0 +1,12 @@
+// errorcheck
+
+// Copyright 2020 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Issue 40015.
+package p
+
+func F1[](s []int) {} // ERROR "empty type parameter list"
+
+func F2() { F1([]int{1, 2}) }
diff --git a/test/gen/g042.go2 b/test/gen/g042.go2
new file mode 100644
index 0000000..b594ab7
--- /dev/null
+++ b/test/gen/g042.go2
@@ -0,0 +1,18 @@
+// compile
+
+// Copyright 2020 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Issue 40318
+package p
+
+import (
+	crand "crypto/rand"
+	"math/rand"
+)
+
+func F() {
+	_ = crand.Reader
+	_ = rand.Source(nil)
+}
diff --git a/test/gen/g043.go2 b/test/gen/g043.go2
new file mode 100644
index 0000000..ecc81ee
--- /dev/null
+++ b/test/gen/g043.go2
@@ -0,0 +1,38 @@
+// compile
+
+// Copyright 2020 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Issue 40859.
+package main
+
+import (
+	"fmt"
+)
+
+type Number interface {
+	type int, int8, int16, int32, int64, uint, uint8, uint16, uint32, uint64, uintptr, float32, float64
+}
+
+type MySlice []int
+
+type SC[E any] interface {
+	type []E
+}
+
+func DoubleDefined[S SC[E], E Number](s S) S {
+	r := make(S, len(s))
+	for i, v := range s {
+		r[i] = v + v
+	}
+	return r
+}
+
+func main() {
+	// Expicit types work fine
+	fmt.Println(DoubleDefined[MySlice, int](MySlice{1}))
+
+	// Constraint type inference does not work?
+	fmt.Println(DoubleDefined(MySlice{1}))
+}
diff --git a/test/gen/g044.go2 b/test/gen/g044.go2
new file mode 100644
index 0000000..bc3ec32
--- /dev/null
+++ b/test/gen/g044.go2
@@ -0,0 +1,50 @@
+// run
+
+// Copyright 2020 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Issue 41216.
+
+package main
+
+func main() {
+	ps := FromStrings2[X]([]string{"x", "y"})
+	if len(ps) != 2 || ps[0] != (X{"x"}) || ps[1] != (X{"y"}) {
+		panic(ps)
+	}
+}
+
+type X struct {
+	s string
+}
+
+func (x *X) Set(s string) {
+	x.s = s
+}
+
+// Setter2 is a type constraint that requires that the type
+// implement a Set method that sets the value from a string,
+// and also requires that the type be a pointer to its type parameter.
+type Setter2[B any] interface {
+	Set(string)
+	type *B
+}
+
+// FromStrings2 takes a slice of strings and returns a slice of T,
+// calling the Set method to set each returned value.
+//
+// We use two different type parameters so that we can return
+// a slice of type T but call methods on *T aka PT.
+// The Setter2 constraint ensures that PT is a pointer to T.
+func FromStrings2[T any, PT Setter2[T]](s []string) []T {
+	result := make([]T, len(s))
+	for i, v := range s {
+		// The type of &result[i] is *T which is in the type list
+		// of Setter2, so we can convert it to PT.
+		p := PT(&result[i])
+		// PT has a Set method.
+		p.Set(v)
+	}
+	return result
+}
diff --git a/test/run.go b/test/run.go
index 30cab82..bae51c1 100644
--- a/test/run.go
+++ b/test/run.go
@@ -12,6 +12,7 @@
 	"errors"
 	"flag"
 	"fmt"
+	"go/go2go"
 	"hash/fnv"
 	"io"
 	"io/fs"
@@ -23,6 +24,7 @@
 	"path/filepath"
 	"regexp"
 	"runtime"
+	"runtime/debug"
 	"sort"
 	"strconv"
 	"strings"
@@ -54,6 +56,13 @@
 	return os.Getenv("GO_BUILDER_NAME") == "linux-amd64"
 }
 
+type fileType int
+
+const (
+	go1Files fileType = iota
+	go2Files
+)
+
 var (
 	goos, goarch string
 
@@ -109,7 +118,7 @@
 				for _, baseGoFile := range goFiles(arg) {
 					tests = append(tests, startTest(arg, baseGoFile))
 				}
-			} else if strings.HasSuffix(arg, ".go") {
+			} else if strings.HasSuffix(arg, ".go") || strings.HasSuffix(arg, ".go2") {
 				dir, file := filepath.Split(arg)
 				tests = append(tests, startTest(dir, file))
 			} else {
@@ -204,7 +213,7 @@
 	}
 	names := []string{}
 	for _, name := range dirnames {
-		if !strings.HasPrefix(name, ".") && strings.HasSuffix(name, ".go") && shardMatch(name) {
+		if !strings.HasPrefix(name, ".") && (strings.HasSuffix(name, ".go") || strings.HasSuffix(name, ".go2")) && shardMatch(name) {
 			names = append(names, name)
 		}
 	}
@@ -224,7 +233,43 @@
 	return runcmd(cmd...)
 }
 
-func compileInDir(runcmd runCmd, dir string, flags []string, localImports bool, names ...string) (out []byte, err error) {
+func compileInDir(runcmd runCmd, dir string, ft fileType, importer *go2go.Importer, flags []string, localImports bool, names ...string) (out []byte, err error) {
+	gofiles := names
+	if ft == go2Files {
+		defer func() {
+			if r := recover(); r != nil {
+				if err == nil {
+					err = fmt.Errorf("panic: %v", r)
+				}
+				fmt.Fprintf(os.Stderr, "%s", debug.Stack())
+			}
+		}()
+		tpkgs, err := go2go.RewriteFiles(importer, dir, names)
+		if err != nil {
+			// The error returned by RewriteFiles is similar
+			// to the output of the compiler, so return it
+			// as a []byte, without the first line.
+			errStr := go2Error(err.Error())
+			return []byte(errStr), err
+		}
+		if err := importer.Register(tpkgs[0].Path(), tpkgs); err != nil {
+			return nil, err
+		}
+
+		gofiles = make([]string, len(names))
+		for i, name := range names {
+			gofiles[i] = strings.TrimSuffix(name, ".go2") + ".go"
+		}
+
+		if !*keep {
+			defer func() {
+				for _, name := range gofiles {
+					os.Remove(filepath.Join(dir, name))
+				}
+			}()
+		}
+	}
+
 	cmd := []string{goTool(), "tool", "compile", "-e"}
 	if localImports {
 		// Set relative path for local imports and import search path to current dir.
@@ -234,14 +279,25 @@
 	if *linkshared {
 		cmd = append(cmd, "-dynlink", "-installsuffix=dynlink")
 	}
-	for _, name := range names {
+	for _, name := range gofiles {
 		cmd = append(cmd, filepath.Join(dir, name))
 	}
 	return runcmd(cmd...)
 }
 
+// go2Error takes an error returned by go/go2go and strips the prefix,
+// to make it look more like an error from "go tool compile".
+func go2Error(s string) string {
+	fields := strings.SplitN(s, "\n", 2)
+	if len(fields) > 1 && strings.HasPrefix(fields[0], "type checking failed for") {
+		return fields[1]
+	}
+	return s
+}
+
 func linkFile(runcmd runCmd, goname string, ldflags []string) (err error) {
-	pfile := strings.Replace(goname, ".go", ".o", -1)
+	pfile := strings.Replace(goname, ".go2", ".o", -1)
+	pfile = strings.Replace(pfile, ".go", ".o", -1)
 	cmd := []string{goTool(), "tool", "link", "-w", "-o", "a.exe", "-L", "."}
 	if *linkshared {
 		cmd = append(cmd, "-linkshared", "-installsuffix=dynlink")
@@ -313,13 +369,22 @@
 	return filepath.Join(t.dir, strings.Replace(t.gofile, ".go", ".dir", -1))
 }
 
-func goDirFiles(longdir string) (filter []os.FileInfo, err error) {
+func goDirFiles(longdir string, ft fileType) (filter []os.FileInfo, err error) {
 	files, dirErr := ioutil.ReadDir(longdir)
 	if dirErr != nil {
 		return nil, dirErr
 	}
+	var ext string
+	switch ft {
+	case go1Files:
+		ext = ".go"
+	case go2Files:
+		ext = ".go2"
+	default:
+		log.Fatalf("invalid file type %v", ft)
+	}
 	for _, gofile := range files {
-		if filepath.Ext(gofile.Name()) == ".go" {
+		if filepath.Ext(gofile.Name()) == ext {
 			filter = append(filter, gofile)
 		}
 	}
@@ -342,8 +407,8 @@
 
 // If singlefilepkgs is set, each file is considered a separate package
 // even if the package names are the same.
-func goDirPackages(longdir string, singlefilepkgs bool) ([][]string, error) {
-	files, err := goDirFiles(longdir)
+func goDirPackages(longdir string, singlefilepkgs bool, ft fileType) ([][]string, error) {
+	files, err := goDirFiles(longdir, ft)
 	if err != nil {
 		return nil, err
 	}
@@ -597,6 +662,48 @@
 		defer os.RemoveAll(t.tempDir)
 	}
 
+	ft := go1Files
+	var importer *go2go.Importer
+	if strings.HasSuffix(t.gofile, ".go2") {
+		defer func() {
+			if r := recover(); r != nil {
+				if t.err == nil {
+					t.err = fmt.Errorf("panic: %v", r)
+				}
+				fmt.Fprintf(os.Stderr, "%s", debug.Stack())
+			}
+		}()
+		importer = go2go.NewImporter(t.dir)
+		go2Bytes, err := go2go.RewriteBuffer(importer, t.gofile, srcBytes)
+		if err != nil {
+			if !wantError {
+				t.err = err
+				return
+			}
+			if action != "errorcheck" {
+				t.err = fmt.Errorf("%s not supported for .go2 files", action)
+				return
+			}
+			errStr := go2Error(err.Error())
+			long := filepath.Join(cwd, t.goFileName())
+			if *updateErrors {
+				t.updateErrors(errStr, long)
+			}
+			t.err = t.errorCheck(errStr, false, long, t.gofile)
+			return
+		}
+		srcBytes = go2Bytes
+		t.gofile = strings.TrimSuffix(t.gofile, ".go2") + ".go"
+		ft = go2Files
+		if err := ioutil.WriteFile(filepath.Join(t.dir, t.gofile), srcBytes, 0644); err != nil {
+			t.err = err
+			return
+		}
+		if !*keep {
+			defer os.Remove(filepath.Join(t.dir, t.gofile))
+		}
+	}
+
 	err = ioutil.WriteFile(filepath.Join(t.tempDir, t.gofile), srcBytes, 0644)
 	if err != nil {
 		log.Fatal(err)
@@ -817,13 +924,13 @@
 	case "compiledir":
 		// Compile all files in the directory as packages in lexicographic order.
 		longdir := filepath.Join(cwd, t.goDirName())
-		pkgs, err := goDirPackages(longdir, singlefilepkgs)
+		pkgs, err := goDirPackages(longdir, singlefilepkgs, ft)
 		if err != nil {
 			t.err = err
 			return
 		}
 		for _, gofiles := range pkgs {
-			_, t.err = compileInDir(runcmd, longdir, flags, localImports, gofiles...)
+			_, t.err = compileInDir(runcmd, longdir, ft, importer, flags, localImports, gofiles...)
 			if t.err != nil {
 				return
 			}
@@ -834,7 +941,7 @@
 		// If errorcheckdir and wantError, compilation of the last package must fail.
 		// If errorcheckandrundir and wantError, compilation of the package prior the last must fail.
 		longdir := filepath.Join(cwd, t.goDirName())
-		pkgs, err := goDirPackages(longdir, singlefilepkgs)
+		pkgs, err := goDirPackages(longdir, singlefilepkgs, ft)
 		if err != nil {
 			t.err = err
 			return
@@ -846,7 +953,7 @@
 			errPkg--
 		}
 		for i, gofiles := range pkgs {
-			out, err := compileInDir(runcmd, longdir, flags, localImports, gofiles...)
+			out, err := compileInDir(runcmd, longdir, ft, importer, flags, localImports, gofiles...)
 			if i == errPkg {
 				if wantError && err == nil {
 					t.err = fmt.Errorf("compilation succeeded unexpectedly\n%s", out)
@@ -879,7 +986,7 @@
 		// Link as if the last file is the main package, run it.
 		// Verify the expected output.
 		longdir := filepath.Join(cwd, t.goDirName())
-		pkgs, err := goDirPackages(longdir, singlefilepkgs)
+		pkgs, err := goDirPackages(longdir, singlefilepkgs, ft)
 		if err != nil {
 			t.err = err
 			return
@@ -905,7 +1012,7 @@
 				}
 				pflags = append(pflags, "-p", pkgname)
 			}
-			_, err := compileInDir(runcmd, longdir, pflags, localImports, gofiles...)
+			_, err := compileInDir(runcmd, longdir, ft, importer, pflags, localImports, gofiles...)
 			// Allow this package compilation fail based on conditions below;
 			// its errors were checked in previous case.
 			if err != nil && !(wantError && action == "errorcheckandrundir" && i == len(pkgs)-2) {