diff --git a/src/go/go2go/importer.go b/src/go/go2go/importer.go index c2efa56a11..8f2a35dd2e 100644 --- a/src/go/go2go/importer.go +++ b/src/go/go2go/importer.go @@ -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), } } diff --git a/src/go/go2go/rewrite.go b/src/go/go2go/rewrite.go index 9c7fe51bc2..388cb58f7b 100644 --- a/src/go/go2go/rewrite.go +++ b/src/go/go2go/rewrite.go @@ -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() { diff --git a/src/go/go2go/types.go b/src/go/go2go/types.go index 7a94ab8fbc..0257b39545 100644 --- a/src/go/go2go/types.go +++ b/src/go/go2go/types.go @@ -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 diff --git a/test/gen/g030.dir/a.go2 b/test/gen/g030.dir/a.go2 new file mode 100644 index 0000000000..b1cf82e2fc --- /dev/null +++ b/test/gen/g030.dir/a.go2 @@ -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) + } +} diff --git a/test/gen/g030.dir/b.go2 b/test/gen/g030.dir/b.go2 new file mode 100644 index 0000000000..4f3ddc773f --- /dev/null +++ b/test/gen/g030.dir/b.go2 @@ -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) +} diff --git a/test/gen/g030.go2 b/test/gen/g030.go2 new file mode 100644 index 0000000000..4a7d9e185b --- /dev/null +++ b/test/gen/g030.go2 @@ -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