Skip to content

Commit 8337ca0

Browse files
griesemergopherbot
authored andcommitted
go/types, types2: rename generic function arguments
For correct inference, if the same generic function is provided more than once as an argument to another function, the argument function's type parameters must be unique for each argument so that the type parameters can be correctly inferred. Example: func f(func(int), func(string)) {} func g[P any](P) {} func _() { f(g, g) } Here the type parameter P for the first g argument resolves to int and the type parameter P for the second g argument resolves to string. Fixes #59956. For #59338. Change-Id: I10ce0ea08c2033722dd7c7c976b2a5448b2ee2d8 Reviewed-on: https://go-review.googlesource.com/c/go/+/492516 Reviewed-by: Robert Griesemer <gri@google.com> TryBot-Result: Gopher Robot <gobot@golang.org> Reviewed-by: Robert Findley <rfindley@google.com> Run-TryBot: Robert Griesemer <gri@google.com> Auto-Submit: Robert Griesemer <gri@google.com>
1 parent 8dea635 commit 8337ca0

File tree

6 files changed

+82
-7
lines changed

6 files changed

+82
-7
lines changed

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

+7
Original file line numberDiff line numberDiff line change
@@ -583,6 +583,13 @@ type T[P any] []P
583583
{`h`, []string{`int`}, `func([]int, *float32)`},
584584
},
585585
},
586+
{`package issue59956; func f(func(int), func(string), func(bool)) {}; func g[P any](P) {}; func _() { f(g, g, g) }`,
587+
[]testInst{
588+
{`g`, []string{`int`}, `func(int)`},
589+
{`g`, []string{`string`}, `func(string)`},
590+
{`g`, []string{`bool`}, `func(bool)`},
591+
},
592+
},
586593
}
587594

588595
for _, test := range tests {

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

+9-2
Original file line numberDiff line numberDiff line change
@@ -500,8 +500,15 @@ func (check *Checker) arguments(call *syntax.CallExpr, sig *Signature, targs []T
500500
for i, arg := range args {
501501
// generic arguments cannot have a defined (*Named) type - no need for underlying type below
502502
if asig, _ := arg.typ.(*Signature); asig != nil && asig.TypeParams().Len() > 0 {
503-
// TODO(gri) need to also rename type parameters for cases like f(g, g)
504-
tparams = append(tparams, asig.TypeParams().list()...)
503+
// Rename type parameters for cases like f(g, g); this gives each
504+
// generic function argument a unique type identity (go.dev/issues/59956).
505+
// TODO(gri) Consider only doing this if a function argument appears
506+
// multiple times, which is rare (possible optimization).
507+
atparams, tmp := check.renameTParams(call.Pos(), asig.TypeParams().list(), asig)
508+
asig = tmp.(*Signature)
509+
asig.tparams = &TypeParamList{atparams} // renameTParams doesn't touch associated type parameters
510+
arg.typ = asig // new type identity for the function argument
511+
tparams = append(tparams, atparams...)
505512
genericArgs = append(genericArgs, i)
506513
}
507514
}

src/go/types/api_test.go

+7
Original file line numberDiff line numberDiff line change
@@ -583,6 +583,13 @@ type T[P any] []P
583583
{`h`, []string{`int`}, `func([]int, *float32)`},
584584
},
585585
},
586+
{`package issue59956; func f(func(int), func(string), func(bool)) {}; func g[P any](P) {}; func _() { f(g, g, g) }`,
587+
[]testInst{
588+
{`g`, []string{`int`}, `func(int)`},
589+
{`g`, []string{`string`}, `func(string)`},
590+
{`g`, []string{`bool`}, `func(bool)`},
591+
},
592+
},
586593
}
587594

588595
for _, test := range tests {

src/go/types/call.go

+9-2
Original file line numberDiff line numberDiff line change
@@ -503,8 +503,15 @@ func (check *Checker) arguments(call *ast.CallExpr, sig *Signature, targs []Type
503503
for i, arg := range args {
504504
// generic arguments cannot have a defined (*Named) type - no need for underlying type below
505505
if asig, _ := arg.typ.(*Signature); asig != nil && asig.TypeParams().Len() > 0 {
506-
// TODO(gri) need to also rename type parameters for cases like f(g, g)
507-
tparams = append(tparams, asig.TypeParams().list()...)
506+
// Rename type parameters for cases like f(g, g); this gives each
507+
// generic function argument a unique type identity (go.dev/issues/59956).
508+
// TODO(gri) Consider only doing this if a function argument appears
509+
// multiple times, which is rare (possible optimization).
510+
atparams, tmp := check.renameTParams(call.Pos(), asig.TypeParams().list(), asig)
511+
asig = tmp.(*Signature)
512+
asig.tparams = &TypeParamList{atparams} // renameTParams doesn't touch associated type parameters
513+
arg.typ = asig // new type identity for the function argument
514+
tparams = append(tparams, atparams...)
508515
genericArgs = append(genericArgs, i)
509516
}
510517
}

src/internal/types/testdata/examples/inference2.go

+1-3
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,5 @@ func _() {
8888
g2(f4)
8989
g4(f6)
9090
g5(f6, f7)
91-
92-
// TODO(gri) this should work (requires type parameter renaming for f1)
93-
g6(f1, f1 /* ERROR "type func[P any](P) of f1 does not match func(string)" */)
91+
g6(f1, f1)
9492
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
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 f1(func(int))
10+
func f2(func(int), func(string))
11+
func f3(func(int), func(string), func(float32))
12+
13+
func g1[P any](P) {}
14+
15+
func _() {
16+
f1(g1)
17+
f2(g1, g1)
18+
f3(g1, g1, g1)
19+
}
20+
21+
// More complex examples
22+
23+
func g2[P any](P, P) {}
24+
func h3[P any](func(P), func(P), func() P) {}
25+
func h4[P, Q any](func(P), func(P, Q), func() Q, func(P, Q)) {}
26+
27+
func r1() int { return 0 }
28+
29+
func _() {
30+
h3(g1, g1, r1)
31+
h4(g1, g2, r1, g2)
32+
}
33+
34+
// Variadic cases
35+
36+
func f(func(int))
37+
func g[P any](P) {}
38+
39+
func d[P any](...func(P)) {}
40+
41+
func _() {
42+
d /* ERROR "cannot infer P" */ ()
43+
d(f)
44+
d(f, g)
45+
d(f, g, g)
46+
d /* ERROR "cannot infer P" */ (g, g, g)
47+
d(g, g, f)
48+
d(g, f, g, f)
49+
}

0 commit comments

Comments
 (0)