Skip to content

Commit 13201d5

Browse files
griesemergopherbot
authored andcommitted
go/types, types2: consider generic functions in inference simplify step
After type arguments for all type parameters have been determined, the type arguments are "simplified" by substituting any type parameters that might occur in them with their corresponding type arguments until all type parameters have been removed. If in this process a (formerly) generic function signature becomes non-generic, make sure to nil out its (declared) type parameters. Fixes #59953. For #59338. Change-Id: Ie16bffd7b0a8baed18e76e5532cdfaecd26e4278 Reviewed-on: https://go-review.googlesource.com/c/go/+/491797 Reviewed-by: Robert Findley <[email protected]> TryBot-Result: Gopher Robot <[email protected]> Reviewed-by: Robert Griesemer <[email protected]> Run-TryBot: Robert Griesemer <[email protected]> Auto-Submit: Robert Griesemer <[email protected]>
1 parent 60c724c commit 13201d5

File tree

3 files changed

+51
-0
lines changed

3 files changed

+51
-0
lines changed

src/cmd/compile/internal/types2/infer.go

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -349,6 +349,9 @@ func (check *Checker) infer(pos syntax.Pos, tparams []*TypeParam, targs []Type,
349349
}
350350

351351
for len(dirty) > 0 {
352+
if traceInference {
353+
u.tracef("-- simplify %s ➞ %s", tparams, inferred)
354+
}
352355
// TODO(gri) Instead of creating a new substMap for each iteration,
353356
// provide an update operation for substMaps and only change when
354357
// needed. Optimization.
@@ -357,6 +360,21 @@ func (check *Checker) infer(pos syntax.Pos, tparams []*TypeParam, targs []Type,
357360
for _, index := range dirty {
358361
t0 := inferred[index]
359362
if t1 := check.subst(nopos, t0, smap, nil, check.context()); t1 != t0 {
363+
// t0 was simplified to t1.
364+
// If t0 was a generic function, but the simplifed signature t1 does
365+
// not contain any type parameters anymore, the function is not generic
366+
// anymore. Remove it's type parameters. (go.dev/issue/59953)
367+
// Note that if t0 was a signature, t1 must be a signature, and t1
368+
// can only be a generic signature if it originated from a generic
369+
// function argument. Those signatures are never defined types and
370+
// thus there is no need to call under below.
371+
// TODO(gri) Consider doing this in Checker.subst.
372+
// Then this would fall out automatically here and also
373+
// in instantiation (where we also explicitly nil out
374+
// type parameters). See the *Signature TODO in subst.
375+
if sig, _ := t1.(*Signature); sig != nil && sig.TypeParams().Len() > 0 && !isParameterized(tparams, sig) {
376+
sig.tparams = nil
377+
}
360378
inferred[index] = t1
361379
dirty[n] = index
362380
n++
@@ -462,6 +480,8 @@ func typeParamsString(list []*TypeParam) string {
462480
}
463481

464482
// isParameterized reports whether typ contains any of the type parameters of tparams.
483+
// If typ is a generic function, isParameterized ignores the type parameter declarations;
484+
// it only considers the signature proper (incoming and result parameters).
465485
func isParameterized(tparams []*TypeParam, typ Type) bool {
466486
w := tpWalker{
467487
tparams: tparams,

src/go/types/infer.go

Lines changed: 20 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
// -reverseTypeInference
2+
3+
// Copyright 2023 The Go Authors. All rights reserved.
4+
// Use of this source code is governed by a BSD-style
5+
// license that can be found in the LICENSE file.
6+
7+
package p
8+
9+
func _() { f(g) }
10+
func f[P any](P) {}
11+
func g[Q int](Q) {}

0 commit comments

Comments
 (0)