[dev.typeparams] cmd/compile: make sure types added to the dictionary are instantiated correctly

Make sure the instantiating types are the type parameters of the containing
function (or types derived from those).

The one exception is the argument of a OFUNCINST, whose type
parameters are those of the declaration site of the function or method
being instantiated. We skip those types.

Change-Id: I4b3ff22eb8a81a76476930cf8ed2a7dd6489d8b8
Reviewed-on: https://go-review.googlesource.com/c/go/+/336352
Trust: Keith Randall <khr@golang.org>
Trust: Dan Scales <danscales@google.com>
Run-TryBot: Keith Randall <khr@golang.org>
TryBot-Result: Go Bot <gobot@golang.org>
Reviewed-by: Dan Scales <danscales@google.com>
This commit is contained in:
Keith Randall 2021-07-21 19:17:20 -07:00
parent 73162a54c2
commit 5cb84f0604

View file

@ -22,6 +22,9 @@ import (
"strconv"
)
// Enable extra consistency checks.
const doubleCheck = true
func assert(p bool) {
base.Assert(p)
}
@ -1820,7 +1823,6 @@ func (g *irgen) getGfInfo(gn *ir.Name) *gfInfo {
ir.Visit(n1, visitFunc)
}
}
addType(&info, n, n.Type())
}
@ -1847,9 +1849,17 @@ func addType(info *gfInfo, n ir.Node, t *types.Type) {
if t.IsTypeParam() && t.Underlying() == t {
return
}
if !parameterizedBy(t, info.tparams) {
if t.Kind() == types.TFUNC && n != nil &&
(t.Recv() != nil ||
n.Op() == ir.ONAME && n.Name().Class == ir.PFUNC) {
// Don't use the type of a named generic function or method,
// since that is parameterized by other typeparams.
// (They all come from arguments of a FUNCINST node.)
return
}
if doubleCheck && !parameterizedBy(t, info.tparams) {
base.Fatalf("adding type with invalid parameters %+v", t)
}
if t.Kind() == types.TSTRUCT && t.IsFuncArgStruct() {
// Multiple return values are not a relevant new type (?).
return
@ -1872,13 +1882,25 @@ func parameterizedBy1(t *types.Type, params []*types.Type, visited map[*types.Ty
return true
}
visited[t] = true
if t.Sym() != nil && len(t.RParams()) > 0 {
// This defined type is instantiated. Check the instantiating types.
for _, r := range t.RParams() {
if !parameterizedBy1(r, params, visited) {
return false
}
}
return true
}
switch t.Kind() {
case types.TTYPEPARAM:
// Check if t is one of the allowed parameters in scope.
for _, p := range params {
if p == t {
return true
}
}
// Couldn't find t in the list of allowed parameters.
return false
case types.TARRAY, types.TPTR, types.TSLICE, types.TCHAN:
@ -1888,10 +1910,7 @@ func parameterizedBy1(t *types.Type, params []*types.Type, visited map[*types.Ty
return parameterizedBy1(t.Key(), params, visited) && parameterizedBy1(t.Elem(), params, visited)
case types.TFUNC:
if t.NumTParams() > 0 {
return false
}
return parameterizedBy1(t.Recvs(), params, visited) && parameterizedBy1(t.Params(), params, visited) && parameterizedBy1(t.Results(), params, visited)
return parameterizedBy1(t.TParams(), params, visited) && parameterizedBy1(t.Recvs(), params, visited) && parameterizedBy1(t.Params(), params, visited) && parameterizedBy1(t.Results(), params, visited)
case types.TSTRUCT:
for _, f := range t.Fields().Slice() {