[dev.go2go] go/go2go: avoid multiple identical instantiations

Move tracking of instantiations from translator to Importer,
so that we can track all instantiations within a package
to avoid duplicates.

Fixes #39749

Change-Id: If6cd5bcdc6e19c2d6481e62a6187ddf7f4fac72a
Reviewed-on: https://go-review.googlesource.com/c/go/+/239337
Reviewed-by: Ian Lance Taylor <iant@golang.org>
This commit is contained in:
Ian Lance Taylor 2020-06-22 11:37:03 -07:00
parent 6500ed4790
commit e643c9792f
6 changed files with 118 additions and 27 deletions

View File

@ -52,6 +52,12 @@ type Importer struct {
// Map from Object to AST type definition for parameterized types.
idToTypeSpec map[types.Object]*ast.TypeSpec
// Map from a Package to the instantiations we've created
// for that package. This doesn't really belong here,
// since it doesn't deal with import information,
// but Importer is a useful common location to store the data.
instantiations map[*types.Package]*instantiations
}
var _ types.ImporterFrom = &Importer{}
@ -74,6 +80,7 @@ func NewImporter(tmpdir string) *Importer {
imports: make(map[string][]string),
idToFunc: make(map[types.Object]*ast.FuncDecl),
idToTypeSpec: make(map[types.Object]*ast.TypeSpec),
instantiations: make(map[*types.Package]*instantiations),
}
}

View File

@ -119,14 +119,12 @@ func typeEmbedsComparable(typ types.Type) bool {
// A translator is used to translate a file from Go with contracts to Go 1.
type translator struct {
fset *token.FileSet
importer *Importer
tpkg *types.Package
types map[ast.Expr]types.Type
instantiations map[string][]*instantiation
newDecls []ast.Decl
typeInstantiations map[types.Type][]*typeInstantiation
typePackages map[*types.Package]bool
fset *token.FileSet
importer *Importer
tpkg *types.Package
types map[ast.Expr]types.Type
newDecls []ast.Decl
typePackages map[*types.Package]bool
// typeDepth tracks recursive type instantiations.
typeDepth int
@ -136,8 +134,14 @@ type translator struct {
err error
}
// An instantiation is a single instantiation of a function.
type instantiation struct {
// instantiations tracks all function and type instantiations for a package.
type instantiations struct {
funcInstantiations map[string][]*funcInstantiation
typeInstantiations map[types.Type][]*typeInstantiation
}
// A funcInstantiation is a single instantiation of a function.
type funcInstantiation struct {
types []types.Type
decl *ast.Ident
}
@ -150,6 +154,52 @@ type typeInstantiation struct {
inProgress bool
}
// funcInstantiations fetches the function instantiations defined in
// the current package, given a generic function name.
func (t *translator) funcInstantiations(key string) []*funcInstantiation {
insts := t.importer.instantiations[t.tpkg]
if insts == nil {
return nil
}
return insts.funcInstantiations[key]
}
// addFuncInstantiation adds a new function instantiation.
func (t *translator) addFuncInstantiation(key string, inst *funcInstantiation) {
insts := t.pkgInstantiations()
insts.funcInstantiations[key] = append(insts.funcInstantiations[key], inst)
}
// typeInstantiations fetches the type instantiations defined in
// the current package, given a generic type.
func (t *translator) typeInstantiations(typ types.Type) []*typeInstantiation {
insts := t.importer.instantiations[t.tpkg]
if insts == nil {
return nil
}
return insts.typeInstantiations[typ]
}
// addTypeInstantiations adds a new type instantiation.
func (t *translator) addTypeInstantiation(typ types.Type, inst *typeInstantiation) {
insts := t.pkgInstantiations()
insts.typeInstantiations[typ] = append(insts.typeInstantiations[typ], inst)
}
// pkgInstantiations returns the instantiations structure for the current
// package, creating it if necessary.
func (t *translator) pkgInstantiations() *instantiations {
insts := t.importer.instantiations[t.tpkg]
if insts == nil {
insts = &instantiations{
funcInstantiations: make(map[string][]*funcInstantiation),
typeInstantiations: make(map[types.Type][]*typeInstantiation),
}
t.importer.instantiations[t.tpkg] = insts
}
return insts
}
// rewrite rewrites the contents of one file.
func rewriteFile(dir string, fset *token.FileSet, importer *Importer, importPath string, tpkg *types.Package, filename string, file *ast.File, addImportableName bool) (err error) {
if err := rewriteAST(fset, importer, importPath, tpkg, file, addImportableName); err != nil {
@ -182,13 +232,11 @@ func rewriteFile(dir string, fset *token.FileSet, importer *Importer, importPath
// rewriteAST rewrites the AST for a file.
func rewriteAST(fset *token.FileSet, importer *Importer, importPath string, tpkg *types.Package, file *ast.File, addImportableName bool) (err error) {
t := translator{
fset: fset,
importer: importer,
tpkg: tpkg,
types: make(map[ast.Expr]types.Type),
instantiations: make(map[string][]*instantiation),
typeInstantiations: make(map[types.Type][]*typeInstantiation),
typePackages: make(map[*types.Package]bool),
fset: fset,
importer: importer,
tpkg: tpkg,
types: make(map[ast.Expr]types.Type),
typePackages: make(map[*types.Package]bool),
}
t.translate(file)
@ -771,8 +819,8 @@ func (t *translator) translateFunctionInstantiation(pe *ast.Expr) {
var instIdent *ast.Ident
key := qid.String()
instantiations := t.instantiations[key]
for _, inst := range instantiations {
insts := t.funcInstantiations(key)
for _, inst := range insts {
if t.sameTypes(typeList, inst.types) {
instIdent = inst.decl
break
@ -787,11 +835,11 @@ func (t *translator) translateFunctionInstantiation(pe *ast.Expr) {
return
}
n := &instantiation{
n := &funcInstantiation{
types: typeList,
decl: instIdent,
}
t.instantiations[key] = append(instantiations, n)
t.addFuncInstantiation(key, n)
}
if typeArgs {
@ -815,7 +863,7 @@ func (t *translator) translateTypeInstantiation(pe *ast.Expr) {
var seen *typeInstantiation
key := t.typeWithoutArgs(typ)
for _, inst := range t.typeInstantiations[key] {
for _, inst := range t.typeInstantiations(key) {
if t.sameTypes(typeList, inst.types) {
if inst.inProgress {
panic(fmt.Sprintf("%s: circular type instantiation", t.fset.Position((*pe).Pos())))
@ -848,7 +896,7 @@ func (t *translator) translateTypeInstantiation(pe *ast.Expr) {
typ: nil,
inProgress: true,
}
t.typeInstantiations[key] = append(t.typeInstantiations[key], seen)
t.addTypeInstantiation(key, seen)
}
defer func() {
@ -935,7 +983,7 @@ func (t *translator) lookupInstantiatedType(typ *types.Named) (types.Type, *ast.
targs := typ.TArgs()
key := t.typeWithoutArgs(typ)
var seen *typeInstantiation
for _, inst := range t.typeInstantiations[key] {
for _, inst := range t.typeInstantiations(key) {
if t.sameTypes(targs, inst.types) {
if inst.inProgress {
panic(fmt.Sprintf("instantiation for %v in progress", typ))
@ -980,7 +1028,7 @@ func (t *translator) lookupInstantiatedType(typ *types.Named) (types.Type, *ast.
typ: nil,
inProgress: true,
}
t.typeInstantiations[key] = append(t.typeInstantiations[key], seen)
t.addTypeInstantiation(key, seen)
}
defer func() {

View File

@ -55,7 +55,7 @@ func (t *translator) instantiateType(ta *typeArgs, typ types.Type) types.Type {
}
var inProgress *typeInstantiation
for _, inst := range t.typeInstantiations[typ] {
for _, inst := range t.typeInstantiations(typ) {
if t.sameTypes(ta.types, inst.types) {
if inst.typ == nil {
inProgress = inst
@ -77,7 +77,7 @@ func (t *translator) instantiateType(ta *typeArgs, typ types.Type) types.Type {
types: ta.types,
typ: ityp,
}
t.typeInstantiations[typ] = append(t.typeInstantiations[typ], typinst)
t.addTypeInstantiation(typ, typinst)
}
return ityp

20
test/gen/g030.dir/a.go2 Normal file
View File

@ -0,0 +1,20 @@
// Copyright 2020 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 main
func Len(type T)(s []T) int {
return len(s)
}
func F1(s []int) int {
return Len(s)
}
func main() {
got := F1(nil) + F2(nil)
if got != 0 {
panic(got)
}
}

9
test/gen/g030.dir/b.go2 Normal file
View File

@ -0,0 +1,9 @@
// Copyright 2020 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 main
func F2(s []int) int {
return Len(s)
}

7
test/gen/g030.go2 Normal file
View File

@ -0,0 +1,7 @@
// rundir
// Copyright 2020 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 ignored