Skip to content

Commit 10ea225

Browse files
[dev.go2go] go/go2go: translate types to AST
We were relying on calling typeString and treating that as an AST ident, with special handling for instantiated types, but that fails if there is an instantiated type within a type literal. Fixes #39881 Change-Id: I793fe359868d8d73e830aa8dc67cf52de99355a8 Reviewed-on: https://go-review.googlesource.com/c/go/+/240197 Reviewed-by: Ian Lance Taylor <[email protected]>
1 parent 93014c5 commit 10ea225

File tree

4 files changed

+186
-21
lines changed

4 files changed

+186
-21
lines changed

src/go/go2go/instantiate.go

+1-2
Original file line numberDiff line numberDiff line change
@@ -841,11 +841,10 @@ func (t *translator) instantiateExpr(ta *typeArgs, e ast.Expr) ast.Expr {
841841
if isPtr {
842842
instType = types.NewPointer(instType)
843843
}
844-
str := types.TypeString(instType, relativeTo(t.tpkg))
845844
newField := &ast.Field{
846845
Doc: f.Doc,
847846
Names: []*ast.Ident{id},
848-
Type: ast.NewIdent(str),
847+
Type: t.typeToAST(instType),
849848
Tag: f.Tag,
850849
Comment: f.Comment,
851850
}

src/go/go2go/rewrite.go

+5-16
Original file line numberDiff line numberDiff line change
@@ -771,6 +771,10 @@ func (t *translator) translateSelectorExpr(pe *ast.Expr) {
771771
if fobj != nil && len(indexes) > 1 {
772772
for _, index := range indexes[:len(indexes)-1] {
773773
xf := xType.Struct().Field(index)
774+
// This must be an embedded type.
775+
// If the field name is the one we expect,
776+
// don't mention it explicitly,
777+
// because it might not be exported.
774778
if xf.Name() == types.TypeString(xf.Type(), relativeTo(xf.Pkg())) {
775779
continue
776780
}
@@ -1168,22 +1172,7 @@ func (t *translator) typeWithoutArgs(typ *types.Named) *types.Named {
11681172
func (t *translator) typeListToASTList(typeList []types.Type) ([]types.Type, []ast.Expr) {
11691173
argList := make([]ast.Expr, 0, len(typeList))
11701174
for _, typ := range typeList {
1171-
str := types.TypeString(typ, relativeTo(t.tpkg))
1172-
arg := ast.NewIdent("(" + str + ")")
1173-
if named, ok := typ.(*types.Named); ok {
1174-
if len(named.TArgs()) > 0 {
1175-
var narg *ast.Ident
1176-
_, narg = t.lookupInstantiatedType(named)
1177-
if t.err != nil {
1178-
return nil, nil
1179-
}
1180-
if narg != nil {
1181-
arg = ast.NewIdent(narg.Name)
1182-
}
1183-
}
1184-
}
1185-
argList = append(argList, arg)
1186-
t.setType(arg, typ)
1175+
argList = append(argList, t.typeToAST(typ))
11871176

11881177
// This inferred type may introduce a reference to
11891178
// packages that we don't otherwise import, and that

src/go/go2go/types.go

+167-2
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,10 @@ package go2go
77
import (
88
"fmt"
99
"go/ast"
10+
"go/token"
1011
"go/types"
12+
"strconv"
13+
"strings"
1114
)
1215

1316
// lookupType returns the types.Type for an AST expression.
@@ -27,13 +30,13 @@ func (t *translator) lookupType(e ast.Expr) types.Type {
2730
// Uninstantiated AST expressions will be listed in t.importer.info.Types.
2831
func (t *translator) setType(e ast.Expr, nt types.Type) {
2932
if ot, ok := t.importer.info.Types[e]; ok {
30-
if !types.IdenticalIgnoreTags(ot.Type, nt) {
33+
if !t.sameType(ot.Type, nt) {
3134
panic("expression type changed")
3235
}
3336
return
3437
}
3538
if ot, ok := t.types[e]; ok {
36-
if !types.IdenticalIgnoreTags(ot, nt) {
39+
if !t.sameType(ot, nt) {
3740
panic("expression type changed")
3841
}
3942
return
@@ -459,3 +462,165 @@ func (t *translator) tupleWithoutTags(tuple *types.Tuple) *types.Tuple {
459462
}
460463
return types.NewTuple(vars...)
461464
}
465+
466+
// typeToAST converts a types.Type to an ast.Expr.
467+
func (t *translator) typeToAST(typ types.Type) ast.Expr {
468+
var r ast.Expr
469+
switch typ := typ.(type) {
470+
case *types.Basic:
471+
r = ast.NewIdent(typ.Name())
472+
case *types.Array:
473+
r = &ast.ArrayType{
474+
Len: &ast.BasicLit{
475+
Kind: token.INT,
476+
Value: strconv.FormatInt(typ.Len(), 10),
477+
},
478+
Elt: t.typeToAST(typ.Elem()),
479+
}
480+
case *types.Slice:
481+
r = &ast.ArrayType{
482+
Elt: t.typeToAST(typ.Elem()),
483+
}
484+
case *types.Struct:
485+
var fields []*ast.Field
486+
n := typ.NumFields()
487+
for i := 0; i < n; i++ {
488+
tf := typ.Field(i)
489+
var names []*ast.Ident
490+
if !tf.Embedded() {
491+
names = []*ast.Ident{
492+
ast.NewIdent(tf.Name()),
493+
}
494+
}
495+
var atag *ast.BasicLit
496+
if tag := typ.Tag(i); tag != "" {
497+
atag = &ast.BasicLit{
498+
Kind: token.STRING,
499+
Value: strconv.Quote(tag),
500+
}
501+
}
502+
af := &ast.Field{
503+
Names: names,
504+
Type: t.typeToAST(tf.Type()),
505+
Tag: atag,
506+
}
507+
fields = append(fields, af)
508+
}
509+
r = &ast.StructType{
510+
Fields: &ast.FieldList{
511+
List: fields,
512+
},
513+
}
514+
case *types.Pointer:
515+
r = &ast.StarExpr{
516+
X: t.typeToAST(typ.Elem()),
517+
}
518+
case *types.Tuple:
519+
// We should only see this in a types.Signature,
520+
// where we handle it specially, since there is
521+
// no ast.Expr that can represent this.
522+
panic("unexpected types.Tuple")
523+
case *types.Signature:
524+
if len(typ.TParams()) > 0 {
525+
// We should only see type parameters for
526+
// a package scope function declaration.
527+
panic("unexpected type parameters")
528+
}
529+
r = &ast.FuncType{
530+
Params: t.tupleToFieldList(typ.Params()),
531+
Results: t.tupleToFieldList(typ.Params()),
532+
}
533+
case *types.Interface:
534+
var methods []*ast.Field
535+
nm := typ.NumExplicitMethods()
536+
for i := 0; i < nm; i++ {
537+
m := typ.ExplicitMethod(i)
538+
f := &ast.Field{
539+
Names: []*ast.Ident{
540+
ast.NewIdent(m.Name()),
541+
},
542+
Type: t.typeToAST(m.Type()),
543+
}
544+
methods = append(methods, f)
545+
}
546+
ne := typ.NumEmbeddeds()
547+
for i := 0; i < ne; i++ {
548+
e := typ.EmbeddedType(i)
549+
f := &ast.Field{
550+
Type: t.typeToAST(e),
551+
}
552+
methods = append(methods, f)
553+
}
554+
r = &ast.InterfaceType{
555+
Methods: &ast.FieldList{
556+
List: methods,
557+
},
558+
}
559+
case *types.Map:
560+
r = &ast.MapType{
561+
Key: t.typeToAST(typ.Key()),
562+
Value: t.typeToAST(typ.Elem()),
563+
}
564+
case *types.Chan:
565+
var dir ast.ChanDir
566+
switch typ.Dir() {
567+
case types.SendRecv:
568+
dir = ast.SEND | ast.RECV
569+
case types.SendOnly:
570+
dir = ast.SEND
571+
case types.RecvOnly:
572+
dir = ast.RECV
573+
default:
574+
panic("unsupported channel direction")
575+
}
576+
r = &ast.ChanType{
577+
Dir: dir,
578+
Value: t.typeToAST(typ.Elem()),
579+
}
580+
case *types.Named:
581+
if len(typ.TArgs()) > 0 {
582+
_, id := t.lookupInstantiatedType(typ)
583+
r = id
584+
} else {
585+
var sb strings.Builder
586+
tn := typ.Obj()
587+
if tn.Pkg() != nil && tn.Pkg() != t.tpkg {
588+
sb.WriteString(tn.Pkg().Name())
589+
sb.WriteByte('.')
590+
}
591+
sb.WriteString(tn.Name())
592+
r = ast.NewIdent(sb.String())
593+
}
594+
case *types.TypeParam:
595+
// This should have been instantiated already.
596+
panic("unexpected type parameter")
597+
default:
598+
panic(fmt.Sprintf("unimplemented Type %T", typ))
599+
}
600+
601+
t.setType(r, typ)
602+
return r
603+
}
604+
605+
// tupleToFieldList converts a tupes.Tuple to a ast.FieldList.
606+
func (t *translator) tupleToFieldList(tuple *types.Tuple) *ast.FieldList {
607+
var fields []*ast.Field
608+
n := tuple.Len()
609+
for i := 0; i < n; i++ {
610+
v := tuple.At(i)
611+
var names []*ast.Ident
612+
if v.Name() != "" {
613+
names = []*ast.Ident{
614+
ast.NewIdent(v.Name()),
615+
}
616+
}
617+
f := &ast.Field{
618+
Names: names,
619+
Type: t.typeToAST(v.Type()),
620+
}
621+
fields = append(fields, f)
622+
}
623+
return &ast.FieldList{
624+
List: fields,
625+
}
626+
}

test/gen/g027.go2

+13-1
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
// Use of this source code is governed by a BSD-style
55
// license that can be found in the LICENSE file.
66

7-
// Issue 39678.
7+
// Issue 39678, 39881.
88
package p
99

1010
type B(type T) struct {
@@ -20,3 +20,15 @@ type BC B(C)
2020
func F(s BC) {
2121
s.F = 7
2222
}
23+
24+
type Pair(type T, U) struct {
25+
T
26+
U
27+
}
28+
29+
func (p Pair(T, U)) M() {
30+
_, _ = p.T, p.U
31+
}
32+
33+
var V1 Pair(Pair(int, int), int)
34+
var V2 Pair(struct { p Pair(int, int) }, int)

0 commit comments

Comments
 (0)