mirror of
https://github.com/golang/go
synced 2024-11-22 14:34:45 -07:00
[dev.typeparams] cmd/compile: add test for number of instantiations
Add a test for a generic sort function, operating on several different pointer types (across two packages), so they should all share the same shape-based instantiation. Actually check that only one instantiation of Sort is created using 'go tool nm', and also check that the output is correct. In order to do the test on the executable using 'go nm', added this as a 'go test' in cmd/compile/internal/test. Added the genembed.go test that I meant to include with a previous CL. Change-Id: I9962913c2f1809484c2b1dfef3b07e4c8770731c Reviewed-on: https://go-review.googlesource.com/c/go/+/354696 Trust: Dan Scales <danscales@google.com> Run-TryBot: Dan Scales <danscales@google.com> TryBot-Result: Go Bot <gobot@golang.org> Reviewed-by: Keith Randall <khr@golang.org> Reviewed-by: Matthew Dempsky <mdempsky@google.com>
This commit is contained in:
parent
d032b2b2c8
commit
ac6d706a05
71
src/cmd/compile/internal/test/inst_test.go
Normal file
71
src/cmd/compile/internal/test/inst_test.go
Normal file
@ -0,0 +1,71 @@
|
||||
// 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))
|
||||
}
|
||||
}
|
40
src/cmd/compile/internal/test/testdata/mysort/mysort.go
vendored
Normal file
40
src/cmd/compile/internal/test/testdata/mysort/mysort.go
vendored
Normal file
@ -0,0 +1,40 @@
|
||||
// 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])
|
||||
}
|
30
src/cmd/compile/internal/test/testdata/ptrsort.go
vendored
Normal file
30
src/cmd/compile/internal/test/testdata/ptrsort.go
vendored
Normal file
@ -0,0 +1,30 @@
|
||||
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])
|
||||
}
|
3
src/cmd/compile/internal/test/testdata/ptrsort.out
vendored
Normal file
3
src/cmd/compile/internal/test/testdata/ptrsort.out
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
&{3} &{4} &{7} &{8}
|
||||
&{1} &{4} &{6} &{7}
|
||||
&{course} &{in} &{of} &{the} &{when}
|
52
test/typeparam/genembed.go
Normal file
52
test/typeparam/genembed.go
Normal file
@ -0,0 +1,52 @@
|
||||
// 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))
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user