From 9840dbbef855381fb0ee86e533c6b9583a6348a3 Mon Sep 17 00:00:00 2001 From: Ian Lance Taylor Date: Wed, 17 Jun 2020 16:20:01 -0700 Subject: [PATCH] [dev.go2go] go/go2go: instantiate embedded type parameters Turn an embedded type parameter into a regular field with the type parameter as the name and the type argument as the type. Fixes #39671 Change-Id: I0050499b90feb5085cac4452d53fa0dc6f614c48 Reviewed-on: https://go-review.googlesource.com/c/go/+/238621 Reviewed-by: Ian Lance Taylor --- src/go/go2go/instantiate.go | 46 +++++++++++++++++++++++++++++++--- test/gen/g021.go2 | 50 +++++++++++++++++++++++++++++++++++++ 2 files changed, 93 insertions(+), 3 deletions(-) create mode 100644 test/gen/g021.go2 diff --git a/src/go/go2go/instantiate.go b/src/go/go2go/instantiate.go index 507c002200..72ee90219c 100644 --- a/src/go/go2go/instantiate.go +++ b/src/go/go2go/instantiate.go @@ -766,13 +766,53 @@ func (t *translator) instantiateExpr(ta *typeArgs, e ast.Expr) ast.Expr { Elt: elt, } case *ast.StructType: - fields := t.instantiateFieldList(ta, e.Fields) - if fields == e.Fields { + fields := e.Fields.List + newFields := make([]*ast.Field, 0, len(fields)) + changed := false + for _, f := range fields { + newFields = append(newFields, f) + if len(f.Names) > 0 { + continue + } + id, ok := f.Type.(*ast.Ident) + if !ok { + continue + } + typ := t.lookupType(id) + if typ == nil { + continue + } + typeParam, ok := typ.(*types.TypeParam) + if !ok { + continue + } + instType := t.instantiateType(ta, typeParam) + str := types.TypeString(instType, types.RelativeTo(t.tpkg)) + newField := &ast.Field{ + Doc: f.Doc, + Names: []*ast.Ident{id}, + Type: ast.NewIdent(str), + Tag: f.Tag, + Comment: f.Comment, + } + newFields[len(newFields)-1] = newField + changed = true + } + fl := e.Fields + if changed { + fl = &ast.FieldList{ + Opening: fl.Opening, + List: newFields, + Closing: fl.Closing, + } + } + newFl := t.instantiateFieldList(ta, fl) + if !changed && newFl == fl { return e } r = &ast.StructType{ Struct: e.Struct, - Fields: fields, + Fields: newFl, Incomplete: e.Incomplete, } case *ast.FuncType: diff --git a/test/gen/g021.go2 b/test/gen/g021.go2 new file mode 100644 index 0000000000..ab7efcf870 --- /dev/null +++ b/test/gen/g021.go2 @@ -0,0 +1,50 @@ +// run + +// 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 + +import "sync" + +// A Lockable is a value that may be safely simultaneously accessed +// from multiple goroutines via the Get and Set methods. +type Lockable(type T) struct { + T + mu sync.Mutex +} + +// Get returns the value stored in a Lockable. +func (l *Lockable(T)) Get() T { + l.mu.Lock() + defer l.mu.Unlock() + return l.T +} + +// Set sets the value in a Lockable. +func (l *Lockable(T)) Set(v T) { + l.mu.Lock() + defer l.mu.Unlock() + l.T = v +} + +func main() { + sl := Lockable(string){T: "a"} + if got := sl.Get(); got != "a" { + panic(got) + } + sl.Set("b") + if got := sl.Get(); got != "b" { + panic(got) + } + + il := Lockable(int){T: 1} + if got := il.Get(); got != 1 { + panic(got) + } + il.Set(2) + if got := il.Get(); got != 2 { + panic(got) + } +}