[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 <iant@golang.org>
This commit is contained in:
Ian Lance Taylor 2020-06-30 16:44:43 -07:00
parent 08b9fd164c
commit 938e96e732
3 changed files with 50 additions and 2 deletions

View File

@ -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{

View File

@ -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
}

29
test/gen/g039.go2 Normal file
View File

@ -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)