diff --git a/src/go/go2go/instantiate.go b/src/go/go2go/instantiate.go index 9cb59ac59e..d21c5fac70 100644 --- a/src/go/go2go/instantiate.go +++ b/src/go/go2go/instantiate.go @@ -14,13 +14,15 @@ import ( // We can look them up either with a types.Object associated with an ast.Ident, // or with a types.TypeParam. type typeArgs struct { + types []types.Type // type arguments in order toAST map[types.Object]ast.Expr toTyp map[*types.TypeParam]types.Type } // newTypeArgs returns a new typeArgs value. -func newTypeArgs() *typeArgs { +func newTypeArgs(typeTypes []types.Type) *typeArgs { return &typeArgs{ + types: typeTypes, toAST: make(map[types.Object]ast.Expr), toTyp: make(map[*types.TypeParam]types.Type), } @@ -56,7 +58,7 @@ func (t *translator) instantiateFunction(fnident *ast.Ident, astTypes []ast.Expr return nil, err } - ta := newTypeArgs() + ta := newTypeArgs(typeTypes) for i, tf := range decl.Type.TParams.List { for _, tn := range tf.Names { obj, ok := t.info.Defs[tn] diff --git a/src/go/go2go/rewrite.go b/src/go/go2go/rewrite.go index bb8448e472..a825e6648d 100644 --- a/src/go/go2go/rewrite.go +++ b/src/go/go2go/rewrite.go @@ -41,11 +41,12 @@ func isParameterizedFuncDecl(fd *ast.FuncDecl) bool { // A translator is used to translate a file from Go with contracts to Go 1. type translator struct { - info *types.Info - types map[ast.Expr]types.Type - idToFunc map[types.Object]*ast.FuncDecl - instantiations map[*ast.Ident][]*instantiation - newDecls []ast.Decl + info *types.Info + types map[ast.Expr]types.Type + idToFunc map[types.Object]*ast.FuncDecl + instantiations map[*ast.Ident][]*instantiation + newDecls []ast.Decl + typeInstantiations map[types.Type][]*typeInstantiation } // An instantiation is a single instantiation of a function. @@ -54,6 +55,12 @@ type instantiation struct { decl *ast.Ident } +// A typeInstantiation is a single instantiation of a type. +type typeInstantiation struct { + types []types.Type + typ types.Type +} + // rewrite rewrites the contents of one file. func rewriteFile(dir string, fset *token.FileSet, info *types.Info, idToFunc map[types.Object]*ast.FuncDecl, filename string, file *ast.File) (err error) { if err := rewriteAST(info, idToFunc, file); err != nil { @@ -86,10 +93,11 @@ func rewriteFile(dir string, fset *token.FileSet, info *types.Info, idToFunc map // rewriteAST rewrites the AST for a file. func rewriteAST(info *types.Info, idToFunc map[types.Object]*ast.FuncDecl, file *ast.File) (err error) { t := translator{ - info: info, - types: make(map[ast.Expr]types.Type), - idToFunc: idToFunc, - instantiations: make(map[*ast.Ident][]*instantiation), + info: info, + types: make(map[ast.Expr]types.Type), + idToFunc: idToFunc, + instantiations: make(map[*ast.Ident][]*instantiation), + typeInstantiations: make(map[types.Type][]*typeInstantiation), } return t.translate(file) } diff --git a/src/go/go2go/types.go b/src/go/go2go/types.go index 60d4c5f865..3aed203578 100644 --- a/src/go/go2go/types.go +++ b/src/go/go2go/types.go @@ -42,6 +42,26 @@ func (t *translator) setType(e ast.Expr, nt types.Type) { // instantiateType instantiates typ using ta. func (t *translator) instantiateType(ta *typeArgs, typ types.Type) types.Type { + if insts, ok := t.typeInstantiations[typ]; ok { + for _, inst := range insts { + if t.sameTypes(ta.types, inst.types) { + return inst.typ + } + } + } + + ityp := t.doInstantiateType(ta, typ) + typinst := &typeInstantiation{ + types: ta.types, + typ: ityp, + } + t.typeInstantiations[typ] = append(t.typeInstantiations[typ], typinst) + return ityp +} + +// doInstantiateType does the work of instantiating typ using ta. +// This should only be called from instantiateType. +func (t *translator) doInstantiateType(ta *typeArgs, typ types.Type) types.Type { switch typ := typ.(type) { case *types.TypeParam: if instType, ok := ta.typ(typ); ok {