mirror of https://github.com/golang/go.git
go/internal/gcimporter: port CL 431495 to tools, add tests
Changes to the export format need to be ported here too; added the tests that check for this bug. Notable changes to the copypasta -- there were name clashes between locally defined types and some new imports, resolved with import renaming. Change-Id: Ie7149595f65e91581e963ae4fe871d29fb98f4c0 Reviewed-on: https://go-review.googlesource.com/c/tools/+/444235 Run-TryBot: David Chase <drchase@google.com> Reviewed-by: Matthew Dempsky <mdempsky@google.com>
This commit is contained in:
parent
d476af7108
commit
2dcdbd43ac
|
|
@ -10,8 +10,12 @@ package gcimporter
|
|||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"go/ast"
|
||||
"go/build"
|
||||
"go/constant"
|
||||
goimporter "go/importer"
|
||||
goparser "go/parser"
|
||||
"go/token"
|
||||
"go/types"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
|
|
@ -156,6 +160,129 @@ func TestImportTestdata(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func TestImportTypeparamTests(t *testing.T) {
|
||||
testenv.NeedsGo1Point(t, 18) // requires generics
|
||||
|
||||
// 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)
|
||||
}
|
||||
|
||||
var skip map[string]string
|
||||
if !unifiedIR {
|
||||
// The Go 1.18 frontend still fails several cases.
|
||||
skip = map[string]string{
|
||||
"equal.go": "inconsistent embedded sorting", // TODO(rfindley): investigate this.
|
||||
"nested.go": "fails to compile", // TODO(rfindley): investigate this.
|
||||
"issue47631.go": "can not handle local type declarations",
|
||||
"issue55101.go": "fails to compile",
|
||||
}
|
||||
}
|
||||
|
||||
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 && 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 := goparser.ParseFile(fset, filename, src, 0)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
config := types.Config{
|
||||
Importer: goimporter.Default(),
|
||||
}
|
||||
pkg, err := config.Check("", fset, []*ast.File{f}, nil)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
return pkg
|
||||
}
|
||||
|
||||
func TestVersionHandling(t *testing.T) {
|
||||
if debug {
|
||||
t.Skip("TestVersionHandling panics in debug mode")
|
||||
|
|
|
|||
|
|
@ -21,3 +21,17 @@ func additionalPredeclared() []types.Type {
|
|||
types.Universe.Lookup("any").Type(),
|
||||
}
|
||||
}
|
||||
|
||||
// See cmd/compile/internal/types.SplitVargenSuffix.
|
||||
func splitVargenSuffix(name string) (base, suffix string) {
|
||||
i := len(name)
|
||||
for i > 0 && name[i-1] >= '0' && name[i-1] <= '9' {
|
||||
i--
|
||||
}
|
||||
const dot = "·"
|
||||
if i >= len(dot) && name[i-len(dot):i] == dot {
|
||||
i -= len(dot)
|
||||
return name[:i], name[i:]
|
||||
}
|
||||
return name, ""
|
||||
}
|
||||
|
|
|
|||
|
|
@ -490,6 +490,11 @@ func (pr *pkgReader) objIdx(idx pkgbits.Index) (*types.Package, string) {
|
|||
return objPkg, objName
|
||||
}
|
||||
|
||||
// Ignore local types promoted to global scope (#55110).
|
||||
if _, suffix := splitVargenSuffix(objName); suffix != "" {
|
||||
return objPkg, objName
|
||||
}
|
||||
|
||||
if objPkg.Scope().Lookup(objName) == nil {
|
||||
dict := pr.objDictIdx(idx)
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue