Skip to content

Commit 277fca7

Browse files
committed
gopls/internal/golang/completion: don't make unnecessary conversions for generic functions
Type conversions introduced by CL 618675 are necessary only when function results are generic (e.g. `func New[T any](v ...T) Set[T]`). This CL adds an additional check to prevent unnecessary conversions. It also fixes cases where accepting a completion item would result in a compile error, like this: ``` func sort(s []int) { slices.SortFunc(s, func(a, b int) int { // compile error: cannot use interface cmp.Ordered in conversion return cmp.Compare(cmp.Ordered(a)) }) } ```
1 parent c212c4a commit 277fca7

File tree

3 files changed

+84
-1
lines changed

3 files changed

+84
-1
lines changed

gopls/internal/golang/completion/completion.go

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2419,7 +2419,9 @@ Nodes:
24192419
return inf
24202420
}
24212421

2422-
if sig.TypeParams().Len() > 0 {
2422+
// Inference is necessary only when function results are generic.
2423+
var free typeparams.Free
2424+
if free.Has(sig.Results()) {
24232425
targs := c.getTypeArgs(node)
24242426
res := inferExpectedResultTypes(c, i)
24252427
substs := reverseInferTypeArgs(sig, targs, res)

gopls/internal/golang/implementation.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -773,6 +773,9 @@ func unify(x, y types.Type, unifier map[*types.TypeParam]types.Type) bool {
773773

774774
// typeParams yields all the free type parameters within t that are relevant for
775775
// unification.
776+
//
777+
// Note: this function is tailored for the specific needs of the unification algorithm.
778+
// Don't try to use it for other purposes, see [typeparams.Free] instead.
776779
func typeParams(t types.Type) iter.Seq[*types.TypeParam] {
777780

778781
return func(yield func(*types.TypeParam) bool) {
Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
-- flags --
2+
-ignore_extra_diags
3+
4+
-- declarations.go --
5+
package x
6+
7+
import (
8+
"cmp"
9+
"io"
10+
"os"
11+
)
12+
13+
var File *os.File
14+
15+
func A[T cmp.Ordered](T) int { return 0 }
16+
17+
func B[T comparable](T) int { return 0 }
18+
19+
func C[T int | string](T) int { return 0 }
20+
21+
func D[T io.Reader](T) int { return 0 }
22+
23+
-- a.go --
24+
package x
25+
26+
func _(i int) {
27+
i = A(File.Nam) //@acceptcompletion(re"Nam()", "Name", A)
28+
}
29+
30+
-- @A/a.go --
31+
package x
32+
33+
func _(i int) {
34+
i = A(File.Name()) //@acceptcompletion(re"Nam()", "Name", A)
35+
}
36+
37+
-- b.go --
38+
package x
39+
40+
func _(i int) {
41+
i = B(File.Nam) //@acceptcompletion(re"Nam()", "Name", B)
42+
}
43+
44+
-- @B/b.go --
45+
package x
46+
47+
func _(i int) {
48+
i = B(File.Name()) //@acceptcompletion(re"Nam()", "Name", B)
49+
}
50+
51+
-- c.go --
52+
package x
53+
54+
func _(i int) {
55+
i = C(File.Nam) //@acceptcompletion(re"Nam()", "Name", C)
56+
}
57+
58+
-- @C/c.go --
59+
package x
60+
61+
func _(i int) {
62+
i = C(File.Name()) //@acceptcompletion(re"Nam()", "Name", C)
63+
}
64+
65+
-- d.go --
66+
package x
67+
68+
func _(i int) {
69+
i = D(Fil) //@acceptcompletion(re"Fil()", "File", D)
70+
}
71+
72+
-- @D/d.go --
73+
package x
74+
75+
func _(i int) {
76+
i = D(File) //@acceptcompletion(re"Fil()", "File", D)
77+
}
78+

0 commit comments

Comments
 (0)