mirror of
https://github.com/golang/go.git
synced 2025-12-08 06:10:04 +00:00
go/internal/gcimporter: add import tests for type parameters
Add a new test TestImportTypeparamTests that compiles and imports packages contained in test/typeparam, and compares the resulting package scope with the scope produced by type-checking directly. In the process, fix a bug in go/types affecting embedded instances with more than one type argument. This was uncovered by smoketest.go. To enable this new test it was easiest to move gcimporter_test.go to an external test, which required copying the pkgExts variable. Fixes #48101 Change-Id: Ie4d981bf463e886a8d141809805d184dbbf64607 Reviewed-on: https://go-review.googlesource.com/c/go/+/347070 Trust: Robert Findley <rfindley@google.com> Run-TryBot: Robert Findley <rfindley@google.com> TryBot-Result: Go Bot <gobot@golang.org> Reviewed-by: Robert Griesemer <gri@golang.org>
This commit is contained in:
parent
b8420baf46
commit
4fb79569d2
2 changed files with 134 additions and 1 deletions
|
|
@ -2,11 +2,12 @@
|
||||||
// Use of this source code is governed by a BSD-style
|
// Use of this source code is governed by a BSD-style
|
||||||
// license that can be found in the LICENSE file.
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
package gcimporter
|
package gcimporter_test
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"internal/goexperiment"
|
||||||
"internal/testenv"
|
"internal/testenv"
|
||||||
"os"
|
"os"
|
||||||
"os/exec"
|
"os/exec"
|
||||||
|
|
@ -16,8 +17,13 @@ import (
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"go/ast"
|
||||||
|
"go/importer"
|
||||||
|
"go/parser"
|
||||||
"go/token"
|
"go/token"
|
||||||
"go/types"
|
"go/types"
|
||||||
|
|
||||||
|
. "go/internal/gcimporter"
|
||||||
)
|
)
|
||||||
|
|
||||||
// skipSpecialPlatforms causes the test to be skipped for platforms where
|
// skipSpecialPlatforms causes the test to be skipped for platforms where
|
||||||
|
|
@ -63,6 +69,8 @@ func testPath(t *testing.T, path, srcDir string) *types.Package {
|
||||||
|
|
||||||
const maxTime = 30 * time.Second
|
const maxTime = 30 * time.Second
|
||||||
|
|
||||||
|
var pkgExts = [...]string{".a", ".o"} // keep in sync with gcimporter.go
|
||||||
|
|
||||||
func testDir(t *testing.T, dir string, endTime time.Time) (nimports int) {
|
func testDir(t *testing.T, dir string, endTime time.Time) (nimports int) {
|
||||||
dirname := filepath.Join(runtime.GOROOT(), "pkg", runtime.GOOS+"_"+runtime.GOARCH, dir)
|
dirname := filepath.Join(runtime.GOROOT(), "pkg", runtime.GOOS+"_"+runtime.GOARCH, dir)
|
||||||
list, err := os.ReadDir(dirname)
|
list, err := os.ReadDir(dirname)
|
||||||
|
|
@ -134,6 +142,129 @@ func TestImportTestdata(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestImportTypeparamTests(t *testing.T) {
|
||||||
|
// This test doesn't yet work with the unified export format.
|
||||||
|
if goexperiment.Unified {
|
||||||
|
t.Skip("unified export data format is currently unsupported")
|
||||||
|
}
|
||||||
|
|
||||||
|
// This package only handles gc export data.
|
||||||
|
if runtime.Compiler != "gc" {
|
||||||
|
t.Skipf("gc-built packages not available (compiler = %s)", runtime.Compiler)
|
||||||
|
}
|
||||||
|
|
||||||
|
tmpdir := mktmpdir(t)
|
||||||
|
defer os.RemoveAll(tmpdir)
|
||||||
|
|
||||||
|
// Check go files in test/typeparam, except those that fail for a known
|
||||||
|
// reason.
|
||||||
|
rootDir := filepath.Join(runtime.GOROOT(), "test", "typeparam")
|
||||||
|
list, err := os.ReadDir(rootDir)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
skip := map[string]string{
|
||||||
|
"equal.go": "inconsistent embedded sorting", // TODO(rfindley): investigate this.
|
||||||
|
"nested.go": "fails to compile", // TODO(rfindley): investigate this.
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, entry := range list {
|
||||||
|
if entry.IsDir() || !strings.HasSuffix(entry.Name(), ".go") {
|
||||||
|
// For now, only consider standalone go files.
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
t.Run(entry.Name(), func(t *testing.T) {
|
||||||
|
if reason, ok := skip[entry.Name()]; ok {
|
||||||
|
t.Skip(reason)
|
||||||
|
}
|
||||||
|
|
||||||
|
filename := filepath.Join(rootDir, entry.Name())
|
||||||
|
src, err := os.ReadFile(filename)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if !bytes.HasPrefix(src, []byte("// run")) && !bytes.HasPrefix(src, []byte("// compile")) {
|
||||||
|
// We're bypassing the logic of run.go here, so be conservative about
|
||||||
|
// the files we consider in an attempt to make this test more robust to
|
||||||
|
// changes in test/typeparams.
|
||||||
|
t.Skipf("not detected as a run test")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Compile and import, and compare the resulting package with the package
|
||||||
|
// that was type-checked directly.
|
||||||
|
compile(t, rootDir, entry.Name(), filepath.Join(tmpdir, "testdata"))
|
||||||
|
pkgName := strings.TrimSuffix(entry.Name(), ".go")
|
||||||
|
imported := importPkg(t, "./testdata/"+pkgName, tmpdir)
|
||||||
|
checked := checkFile(t, filename, src)
|
||||||
|
|
||||||
|
seen := make(map[string]bool)
|
||||||
|
for _, name := range imported.Scope().Names() {
|
||||||
|
if !token.IsExported(name) {
|
||||||
|
continue // ignore synthetic names like .inittask and .dict.*
|
||||||
|
}
|
||||||
|
seen[name] = true
|
||||||
|
|
||||||
|
importedObj := imported.Scope().Lookup(name)
|
||||||
|
got := types.ObjectString(importedObj, types.RelativeTo(imported))
|
||||||
|
got = sanitizeObjectString(got)
|
||||||
|
|
||||||
|
checkedObj := checked.Scope().Lookup(name)
|
||||||
|
if checkedObj == nil {
|
||||||
|
t.Fatalf("imported object %q was not type-checked", name)
|
||||||
|
}
|
||||||
|
want := types.ObjectString(checkedObj, types.RelativeTo(checked))
|
||||||
|
want = sanitizeObjectString(want)
|
||||||
|
|
||||||
|
if got != want {
|
||||||
|
t.Errorf("imported %q as %q, want %q", name, got, want)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, name := range checked.Scope().Names() {
|
||||||
|
if !token.IsExported(name) || seen[name] {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
t.Errorf("did not import object %q", name)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// sanitizeObjectString removes type parameter debugging markers from an object
|
||||||
|
// string, to normalize it for comparison.
|
||||||
|
// TODO(rfindley): this should not be necessary.
|
||||||
|
func sanitizeObjectString(s string) string {
|
||||||
|
var runes []rune
|
||||||
|
for _, r := range s {
|
||||||
|
if r == '#' {
|
||||||
|
continue // trim instance markers
|
||||||
|
}
|
||||||
|
if '₀' <= r && r < '₀'+10 {
|
||||||
|
continue // trim type parameter subscripts
|
||||||
|
}
|
||||||
|
runes = append(runes, r)
|
||||||
|
}
|
||||||
|
return string(runes)
|
||||||
|
}
|
||||||
|
|
||||||
|
func checkFile(t *testing.T, filename string, src []byte) *types.Package {
|
||||||
|
fset := token.NewFileSet()
|
||||||
|
f, err := parser.ParseFile(fset, filename, src, 0)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
config := types.Config{
|
||||||
|
Importer: importer.Default(),
|
||||||
|
}
|
||||||
|
pkg, err := config.Check("", fset, []*ast.File{f}, nil)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
return pkg
|
||||||
|
}
|
||||||
|
|
||||||
func TestVersionHandling(t *testing.T) {
|
func TestVersionHandling(t *testing.T) {
|
||||||
skipSpecialPlatforms(t)
|
skipSpecialPlatforms(t)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -176,6 +176,8 @@ func embeddedFieldIdent(e ast.Expr) *ast.Ident {
|
||||||
return e.Sel
|
return e.Sel
|
||||||
case *ast.IndexExpr:
|
case *ast.IndexExpr:
|
||||||
return embeddedFieldIdent(e.X)
|
return embeddedFieldIdent(e.X)
|
||||||
|
case *ast.MultiIndexExpr:
|
||||||
|
return embeddedFieldIdent(e.X)
|
||||||
}
|
}
|
||||||
return nil // invalid embedded field
|
return nil // invalid embedded field
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue