diff --git a/internal/gcimporter/gcimporter_test.go b/internal/gcimporter/gcimporter_test.go index 95cc36c4d..1a56af403 100644 --- a/internal/gcimporter/gcimporter_test.go +++ b/internal/gcimporter/gcimporter_test.go @@ -956,6 +956,67 @@ func TestIssue58296(t *testing.T) { } } +func TestIssueAliases(t *testing.T) { + // This package only handles gc export data. + testenv.NeedsGo1Point(t, 24) + needsCompiler(t, "gc") + testenv.NeedsGoBuild(t) // to find stdlib export data in the build cache + testenv.NeedsGoExperiment(t, "aliastypeparams") + + t.Setenv("GODEBUG", fmt.Sprintf("gotypesalias=%d", 1)) + + tmpdir := mktmpdir(t) + defer os.RemoveAll(tmpdir) + testoutdir := filepath.Join(tmpdir, "testdata") + + apkg := filepath.Join(testoutdir, "a") + bpkg := filepath.Join(testoutdir, "b") + cpkg := filepath.Join(testoutdir, "c") + + // compile a, b and c into gc export data. + srcdir := filepath.Join("testdata", "aliases") + compilePkg(t, filepath.Join(srcdir, "a"), "a.go", testoutdir, nil, apkg) + compilePkg(t, filepath.Join(srcdir, "b"), "b.go", testoutdir, map[string]string{apkg: filepath.Join(testoutdir, "a.o")}, bpkg) + compilePkg(t, filepath.Join(srcdir, "c"), "c.go", testoutdir, + map[string]string{apkg: filepath.Join(testoutdir, "a.o"), bpkg: filepath.Join(testoutdir, "b.o")}, + cpkg, + ) + + // import c from gc export data using a and b. + pkg, err := Import(map[string]*types.Package{ + apkg: types.NewPackage(apkg, "a"), + bpkg: types.NewPackage(bpkg, "b"), + }, "./c", testoutdir, nil) + if err != nil { + t.Fatal(err) + } + + // Check c's objects and types. + var objs []string + for _, imp := range pkg.Scope().Names() { + obj := pkg.Scope().Lookup(imp) + s := fmt.Sprintf("%s : %s", obj.Name(), obj.Type()) + s = strings.ReplaceAll(s, testoutdir, "testdata") + objs = append(objs, s) + } + sort.Strings(objs) + + want := strings.Join([]string{ + "S : struct{F int}", + "T : struct{F int}", + "U : testdata/a.A[string]", + "V : testdata/a.A[int]", + "W : testdata/b.B[string]", + "X : testdata/b.B[int]", + "Y : testdata/c.c[string]", + "Z : testdata/c.c[int]", + "c : testdata/c.c", + }, ",") + if got := strings.Join(objs, ","); got != want { + t.Errorf("got imports %v for package c. wanted %v", objs, want) + } +} + // apkg returns the package "a" prefixed by (as a package) testoutdir func apkg(testoutdir string) string { apkg := testoutdir + "/a" diff --git a/internal/gcimporter/iexport_test.go b/internal/gcimporter/iexport_test.go index cd6990764..7e82a5818 100644 --- a/internal/gcimporter/iexport_test.go +++ b/internal/gcimporter/iexport_test.go @@ -517,8 +517,6 @@ type Chained = C[Named] // B[Named, A[Named]] = B[Named, *Named] = []*Named // This means that it can be loaded by go/importer or go/types. // This step is not supported, but it does give test coverage for stdlib. "goroot": func(t *testing.T) *types.Package { - t.Skip("Fix bug in src/internal/gcimporter.IImportData for aliasType then reenable") - // Write indexed export data file contents. // // TODO(taking): Slightly unclear to what extent this step should be supported by go/importer. diff --git a/internal/gcimporter/testdata/aliases/a/a.go b/internal/gcimporter/testdata/aliases/a/a.go new file mode 100644 index 000000000..0558258e1 --- /dev/null +++ b/internal/gcimporter/testdata/aliases/a/a.go @@ -0,0 +1,14 @@ +// Copyright 2024 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 A[T any] = *T + +type B = struct{ F int } + +func F() B { + type a[T any] = struct{ F T } + return a[int]{} +} diff --git a/internal/gcimporter/testdata/aliases/b/b.go b/internal/gcimporter/testdata/aliases/b/b.go new file mode 100644 index 000000000..9a2dbe2ba --- /dev/null +++ b/internal/gcimporter/testdata/aliases/b/b.go @@ -0,0 +1,11 @@ +// Copyright 2024 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" + +type B[S any] = struct { + F a.A[[]S] +} diff --git a/internal/gcimporter/testdata/aliases/c/c.go b/internal/gcimporter/testdata/aliases/c/c.go new file mode 100644 index 000000000..359cee619 --- /dev/null +++ b/internal/gcimporter/testdata/aliases/c/c.go @@ -0,0 +1,26 @@ +// Copyright 2024 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 c + +import ( + "./a" + "./b" +) + +type c[V any] = struct { + G b.B[[3]V] +} + +var S struct{ F int } = a.B{} +var T struct{ F int } = a.F() + +var U a.A[string] = (*string)(nil) +var V a.A[int] = (*int)(nil) + +var W b.B[string] = struct{ F *[]string }{} +var X b.B[int] = struct{ F *[]int }{} + +var Y c[string] = struct{ G struct{ F *[][3]string } }{} +var Z c[int] = struct{ G struct{ F *[][3]int } }{} diff --git a/internal/gcimporter/ureader_yes.go b/internal/gcimporter/ureader_yes.go index 50b4a379e..f0742f540 100644 --- a/internal/gcimporter/ureader_yes.go +++ b/internal/gcimporter/ureader_yes.go @@ -52,8 +52,7 @@ func (pr *pkgReader) later(fn func()) { // See cmd/compile/internal/noder.derivedInfo. type derivedInfo struct { - idx pkgbits.Index - needed bool + idx pkgbits.Index } // See cmd/compile/internal/noder.typeInfo. @@ -110,13 +109,17 @@ func readUnifiedPackage(fset *token.FileSet, ctxt *types.Context, imports map[st r := pr.newReader(pkgbits.RelocMeta, pkgbits.PublicRootIdx, pkgbits.SyncPublic) pkg := r.pkg() - r.Bool() // has init + if r.Version().Has(pkgbits.HasInit) { + r.Bool() + } for i, n := 0, r.Len(); i < n; i++ { // As if r.obj(), but avoiding the Scope.Lookup call, // to avoid eager loading of imports. r.Sync(pkgbits.SyncObject) - assert(!r.Bool()) + if r.Version().Has(pkgbits.DerivedFuncInstance) { + assert(!r.Bool()) + } r.p.objIdx(r.Reloc(pkgbits.RelocObj)) assert(r.Len() == 0) } @@ -165,7 +168,7 @@ type readerDict struct { // tparams is a slice of the constructed TypeParams for the element. tparams []*types.TypeParam - // devived is a slice of types derived from tparams, which may be + // derived is a slice of types derived from tparams, which may be // instantiated while reading the current element. derived []derivedInfo derivedTypes []types.Type // lazily instantiated from derived @@ -471,7 +474,9 @@ func (r *reader) param() *types.Var { func (r *reader) obj() (types.Object, []types.Type) { r.Sync(pkgbits.SyncObject) - assert(!r.Bool()) + if r.Version().Has(pkgbits.DerivedFuncInstance) { + assert(!r.Bool()) + } pkg, name := r.p.objIdx(r.Reloc(pkgbits.RelocObj)) obj := pkgScope(pkg).Lookup(name) @@ -525,8 +530,11 @@ func (pr *pkgReader) objIdx(idx pkgbits.Index) (*types.Package, string) { case pkgbits.ObjAlias: pos := r.pos() + var tparams []*types.TypeParam + if r.Version().Has(pkgbits.AliasTypeParamNames) { + tparams = r.typeParamNames() + } typ := r.typ() - var tparams []*types.TypeParam // TODO(#68778): read type params once pkgbits.V2 is available. declare(aliases.NewAlias(r.p.aliases, pos, objPkg, objName, typ, tparams)) case pkgbits.ObjConst: @@ -633,7 +641,10 @@ func (pr *pkgReader) objDictIdx(idx pkgbits.Index) *readerDict { dict.derived = make([]derivedInfo, r.Len()) dict.derivedTypes = make([]types.Type, len(dict.derived)) for i := range dict.derived { - dict.derived[i] = derivedInfo{r.Reloc(pkgbits.RelocType), r.Bool()} + dict.derived[i] = derivedInfo{idx: r.Reloc(pkgbits.RelocType)} + if r.Version().Has(pkgbits.DerivedInfoNeeded) { + assert(!r.Bool()) + } } pr.retireReader(r)