From 938e96e732e41bf93ef8c38579ff4f57bfebcc49 Mon Sep 17 00:00:00 2001 From: Ian Lance Taylor Date: Tue, 30 Jun 2020 16:44:43 -0700 Subject: [PATCH] [dev.go2go] go/go2go: instantiate embedded field when needed If an embedded field is an instantiated type, we need to instantiate it when instantiating the whole type, in case the type arguments themselves need instantiation. Fixes #39953 Change-Id: I80b57456aa4f8e8b2eff82359066c37a9c2a40f5 Reviewed-on: https://go-review.googlesource.com/c/go/+/240522 Reviewed-by: Ian Lance Taylor --- src/go/go2go/instantiate.go | 17 ++++++++++++++++- src/go/go2go/rewrite.go | 6 +++++- test/gen/g039.go2 | 29 +++++++++++++++++++++++++++++ 3 files changed, 50 insertions(+), 2 deletions(-) create mode 100644 test/gen/g039.go2 diff --git a/src/go/go2go/instantiate.go b/src/go/go2go/instantiate.go index 7055c23ded..791f435499 100644 --- a/src/go/go2go/instantiate.go +++ b/src/go/go2go/instantiate.go @@ -676,7 +676,22 @@ func (t *translator) instantiateExpr(ta *typeArgs, e ast.Expr) ast.Expr { } case *ast.SelectorExpr: x := t.instantiateExpr(ta, e.X) - if x == e.X { + + // If this is a reference to an instantiated embedded field, + // we may need to instantiate it. The actual instantiation + // is at the end of the function, as long as we create a + // a new SelectorExpr when needed. + instantiate := false + obj := t.importer.info.ObjectOf(e.Sel) + if obj != nil { + if f, ok := obj.(*types.Var); ok && f.Embedded() { + if named, ok := f.Type().(*types.Named); ok && len(named.TArgs()) > 0 && obj.Name() == named.Obj().Name() { + instantiate = true + } + } + } + + if x == e.X && !instantiate { return e } r = &ast.SelectorExpr{ diff --git a/src/go/go2go/rewrite.go b/src/go/go2go/rewrite.go index 2b3ef7cc3f..bf1e2aecb9 100644 --- a/src/go/go2go/rewrite.go +++ b/src/go/go2go/rewrite.go @@ -794,7 +794,11 @@ func (t *translator) translateSelectorExpr(pe *ast.Expr) { // We have to rewrite the name to the name used in // the translated struct definition. if f, ok := obj.(*types.Var); ok && f.Embedded() { - named, ok := f.Type().(*types.Named) + typ := t.lookupType(e) + if typ == nil { + typ = f.Type() + } + named, ok := typ.(*types.Named) if !ok || len(named.TArgs()) == 0 { return } diff --git a/test/gen/g039.go2 b/test/gen/g039.go2 new file mode 100644 index 0000000000..69ec25ad31 --- /dev/null +++ b/test/gen/g039.go2 @@ -0,0 +1,29 @@ +// compile + +// 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 p + +type top(type T, T2) struct { + p *parent(T, T2) +} + +type parent(type T, T2) struct { + (child(T, T2)) +} + +type child(type T, T2) struct { + T2 +} + +func (d *top(T, T2)) foo() *T { + return d.p.child.foo() +} + +func (rb *child(T, T2)) foo() *T { + return nil +} + +var V top(int, int)