cmd/compile: add missing shape check in (*Tsubster).tinter

Add a missing shape check in (*Tsubster).tinter when substituting on a
generic type which is an empty interface, analogous to same check in
(*Tsubster).tstruct. Empty structs/interfaces that have rparams (i.e.
are a generic type or a shape type) need to get a new type of their
rparams - they will be different even though they don't have any
fields/methods. Without this shape check, we were not correctly
completing the Token[int] type during substitution in the example in the
issue. This issue only happens for a generic type which is an empty
interface (i.e. doesn't actually use the type param, hence quite unusual).

Added the test case already created by Keith.

Fixes #50841

Change-Id: Ia985b9f52c0e87ed0647b46373e44c51cb748ba4
Reviewed-on: https://go-review.googlesource.com/c/go/+/381175
Trust: Dan Scales <danscales@google.com>
Run-TryBot: Dan Scales <danscales@google.com>
TryBot-Result: Gopher Robot <gobot@golang.org>
Reviewed-by: Keith Randall <khr@golang.org>
This commit is contained in:
Dan Scales 2022-01-26 17:58:08 -08:00
parent f4aa021985
commit a991d9dc27
4 changed files with 47 additions and 7 deletions

View file

@ -1326,9 +1326,9 @@ func (ts *Tsubster) typ1(t *types.Type) *types.Type {
func (ts *Tsubster) tstruct(t *types.Type, force bool) *types.Type {
if t.NumFields() == 0 {
if t.HasTParam() || t.HasShape() {
// For an empty struct, we need to return a new type,
// since it may now be fully instantiated (HasTParam
// becomes false).
// For an empty struct, we need to return a new type, if
// substituting from a generic type or shape type, since it
// will change HasTParam/HasShape flags.
return types.NewStruct(t.Pkg(), nil)
}
return t
@ -1387,10 +1387,10 @@ func (ts *Tsubster) tstruct(t *types.Type, force bool) *types.Type {
// tinter substitutes type params in types of the methods of an interface type.
func (ts *Tsubster) tinter(t *types.Type, force bool) *types.Type {
if t.Methods().Len() == 0 {
if t.HasTParam() {
// For an empty interface, we need to return a new type,
// since it may now be fully instantiated (HasTParam
// becomes false).
if t.HasTParam() || t.HasShape() {
// For an empty interface, we need to return a new type, if
// substituting from a generic type or shape type, since
// since it will change HasTParam/HasShape flags.
return types.NewInterface(t.Pkg(), nil, false)
}
return t

View file

@ -0,0 +1,22 @@
// Copyright 2022 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 a
func Marshal[foobar any]() {
_ = NewEncoder[foobar]()
}
func NewEncoder[foobar any]() *Encoder[foobar] {
return nil
}
type Encoder[foobar any] struct {
}
func (e *Encoder[foobar]) EncodeToken(t Token[foobar]) {
}
type Token[foobar any] any

View file

@ -0,0 +1,11 @@
// Copyright 2022 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 b
import "a"
func F() {
a.Marshal[int]()
}

View file

@ -0,0 +1,7 @@
// compiledir -G=3
// Copyright 2022 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 ignored