--- /dev/null
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package test
+
+import (
+ "internal/goexperiment"
+ "internal/testenv"
+ "io/ioutil"
+ "os"
+ "os/exec"
+ "path/filepath"
+ "regexp"
+ "testing"
+)
+
+// TestInst tests that only one instantiation of Sort is created, even though generic
+// Sort is used for multiple pointer types across two packages.
+func TestInst(t *testing.T) {
+ if goexperiment.Unified {
+ t.Skip("unified currently does stenciling, not dictionaries")
+ }
+ testenv.MustHaveGoBuild(t)
+ testenv.MustHaveGoRun(t)
+
+ var tmpdir string
+ var err error
+ tmpdir, err = ioutil.TempDir("", "TestDict")
+ if err != nil {
+ t.Fatalf("Failed to create temporary directory: %v", err)
+ }
+ defer os.RemoveAll(tmpdir)
+
+ // Build ptrsort.go, which uses package mysort.
+ var output []byte
+ filename := "ptrsort.go"
+ exename := "ptrsort"
+ outname := "ptrsort.out"
+ gotool := testenv.GoToolPath(t)
+ dest := filepath.Join(tmpdir, exename)
+ cmd := exec.Command(gotool, "build", "-o", dest, filepath.Join("testdata", filename))
+ if output, err = cmd.CombinedOutput(); err != nil {
+ t.Fatalf("Failed: %v:\nOutput: %s\n", err, output)
+ }
+
+ // Test that there is exactly one shape-based instantiation of Sort in
+ // the executable.
+ cmd = exec.Command(gotool, "tool", "nm", dest)
+ if output, err = cmd.CombinedOutput(); err != nil {
+ t.Fatalf("Failed: %v:\nOut: %s\n", err, output)
+ }
+ re := regexp.MustCompile(`\bSort\[.*shape.*\]`)
+ r := re.FindAllIndex(output, -1)
+ if len(r) != 1 {
+ t.Fatalf("Wanted 1 instantiations of Sort function, got %d\n", len(r))
+ }
+
+ // Actually run the test and make sure output is correct.
+ cmd = exec.Command(gotool, "run", filepath.Join("testdata", filename))
+ if output, err = cmd.CombinedOutput(); err != nil {
+ t.Fatalf("Failed: %v:\nOut: %s\n", err, output)
+ }
+ out, err := ioutil.ReadFile(filepath.Join("testdata", outname))
+ if err != nil {
+ t.Fatalf("Could not find %s\n", outname)
+ }
+ if string(out) != string(output) {
+ t.Fatalf("Wanted output %v, got %v\n", string(out), string(output))
+ }
+}
--- /dev/null
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Generic sort function, tested with two different pointer types.
+
+package mysort
+
+import (
+ "fmt"
+)
+
+type LessConstraint[T any] interface {
+ Less(T) bool
+}
+
+//go:noinline
+func Sort[T LessConstraint[T]](x []T) {
+ n := len(x)
+ for i := 1; i < n; i++ {
+ for j := i; j > 0 && x[j].Less(x[j-1]); j-- {
+ x[j], x[j-1] = x[j-1], x[j]
+ }
+ }
+}
+
+type MyInt struct {
+ Value int
+}
+
+func (a *MyInt) Less(b *MyInt) bool {
+ return a.Value < b.Value
+}
+
+//go:noinline
+func F() {
+ sl1 := []*MyInt{&MyInt{4}, &MyInt{3}, &MyInt{8}, &MyInt{7}}
+ Sort(sl1)
+ fmt.Printf("%v %v %v %v\n", sl1[0], sl1[1], sl1[2], sl1[3])
+}
--- /dev/null
+package main
+
+// Test generic sort function with two different pointer types in different packages,
+// make sure only one instantiation is created.
+
+import (
+ "fmt"
+
+ "./mysort"
+)
+
+type MyString struct {
+ string
+}
+
+func (a *MyString) Less(b *MyString) bool {
+ return a.string < b.string
+}
+
+func main() {
+ mysort.F()
+
+ sl1 := []*mysort.MyInt{{7}, {1}, {4}, {6}}
+ mysort.Sort(sl1)
+ fmt.Printf("%v %v %v %v\n", sl1[0], sl1[1], sl1[2], sl1[3])
+
+ sl2 := []*MyString{{"when"}, {"in"}, {"the"}, {"course"}, {"of"}}
+ mysort.Sort(sl2)
+ fmt.Printf("%v %v %v %v %v\n", sl2[0], sl2[1], sl2[2], sl2[3], sl2[4])
+}
--- /dev/null
+// run -gcflags=-G=3
+
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Test wrappers/interfaces for generic type embedding another generic type.
+
+package main
+
+import "fmt"
+
+type A[T any] struct {
+ B[T]
+}
+
+type B[T any] struct {
+ val T
+}
+
+func (b *B[T]) get() T {
+ return b.val
+}
+
+type getter[T any] interface {
+ get() T
+}
+
+//go:noinline
+func doGet[T any](i getter[T]) T {
+ return i.get()
+}
+
+//go:noline
+func doGet2[T any](i interface{}) T {
+ i2 := i.(getter[T])
+ return i2.get()
+}
+
+func main() {
+ a := A[int]{B: B[int]{3}}
+ var i getter[int] = &a
+
+ if got, want := doGet(i), 3; got != want {
+ panic(fmt.Sprintf("got %v, want %v", got, want))
+ }
+
+ as := A[string]{B: B[string]{"abc"}}
+ if got, want := doGet2[string](&as), "abc"; got != want {
+ panic(fmt.Sprintf("got %v, want %v", got, want))
+ }
+}