Skip to content

Commit 6cf6bf1

Browse files
committed
[dev.go2go] go/types: report inferred type when a type argument doesn't match
Fixes #39725. Change-Id: I48248283ae0eb635d489d8661512f32b98700c1a Reviewed-on: https://go-review.googlesource.com/c/go/+/240523 Reviewed-by: Robert Griesemer <[email protected]>
1 parent 938e96e commit 6cf6bf1

File tree

4 files changed

+52
-19
lines changed

4 files changed

+52
-19
lines changed

src/go/types/check_test.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -126,10 +126,11 @@ var tests = [][]string{
126126
// TODO(gri) Eliminate the need to enumerate these tests here.
127127
// Should just traverse that directory.
128128
{"fixedbugs/issue39664.go2"},
129-
{"fixedbugs/issue39693.go2"},
130129
{"fixedbugs/issue39680.go2"},
130+
{"fixedbugs/issue39693.go2"},
131131
{"fixedbugs/issue39711.go2"},
132132
{"fixedbugs/issue39723.go2"},
133+
{"fixedbugs/issue39725.go2"},
133134
{"fixedbugs/issue39754.go2"},
134135
{"fixedbugs/issue39755.go2"},
135136
{"fixedbugs/issue39768.go2"},

src/go/types/fixedbugs/issue39725.go2

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
// Copyright 2020 The Go Authors. All rights reserved.
2+
// Use of this source code is governed by a BSD-style
3+
// license that can be found in the LICENSE file.
4+
5+
package p
6+
7+
func f1(type T1, T2)(T1, T2, struct{a T1; b T2})
8+
func _() {
9+
f1(42, string("foo"), struct /* ERROR does not match inferred type struct\{a int; b string\} */ {a, b int}{})
10+
}
11+
12+
// simplified test case from issue
13+
func f2(type T)(_ []T, _ func(T))
14+
func _() {
15+
f2([]string{}, func /* ERROR does not match inferred type func\(string\) */ (f []byte) {})
16+
}

src/go/types/infer.go

Lines changed: 17 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -20,13 +20,14 @@ func (check *Checker) infer(pos token.Pos, tparams []*TypeName, params *Tuple, a
2020

2121
errorf := func(kind string, tpar, targ Type, arg *operand) {
2222
// provide a better error message if we can
23-
if tpar, _ := tpar.(*TypeParam); tpar != nil {
24-
if inferred := u.x.at(tpar.index); inferred != nil {
25-
check.errorf(arg.pos(), "%s %s of %s does not match inferred type %s for %s", kind, targ, arg.expr, inferred, tpar)
26-
return
27-
}
23+
targs, _ := u.x.types()
24+
smap := makeSubstMap(tparams, targs)
25+
inferred := check.subst(arg.pos(), tpar, smap)
26+
if inferred != tpar {
27+
check.errorf(arg.pos(), "%s %s of %s does not match inferred type %s for %s", kind, targ, arg.expr, inferred, tpar)
28+
} else {
29+
check.errorf(arg.pos(), "%s %s of %s does not match %s", kind, targ, arg.expr, tpar)
2830
}
29-
check.errorf(arg.pos(), "%s %s of %s does not match %s", kind, targ, arg.expr, tpar)
3031
}
3132

3233
// Terminology: generic parameter = function parameter with a type-parameterized type
@@ -96,24 +97,22 @@ func (check *Checker) infer(pos token.Pos, tparams []*TypeName, params *Tuple, a
9697

9798
// Collect type arguments and check if they all have been determined.
9899
// TODO(gri) consider moving this outside this function and then we won't need to pass in pos
99-
var targs []Type // lazily allocated
100-
for i, tpar := range tparams {
101-
targ := u.x.at(i)
102-
if targ == nil {
103-
ppos := check.fset.Position(tpar.pos).String()
104-
check.errorf(pos, "cannot infer %s (%s)", tpar.name, ppos)
105-
return nil
106-
}
107-
if targs == nil {
108-
targs = make([]Type, len(tparams))
109-
}
110-
targs[i] = targ
100+
targs, failed := u.x.types()
101+
if failed >= 0 {
102+
tpar := tparams[failed]
103+
ppos := check.fset.Position(tpar.pos).String()
104+
check.errorf(pos, "cannot infer %s (%s)", tpar.name, ppos)
105+
return nil
111106
}
112107

113108
return targs
114109
}
115110

116111
// IsParameterized reports whether typ contains any type parameters.
112+
// TODO(gri) This is not strictly correct. We only want the free
113+
// type parameters for a given type. (At the moment, the only way
114+
// to mix free and bound type parameters is through method type parameters
115+
// on parameterized receiver types - need to investigate.)
117116
func IsParameterized(typ Type) bool {
118117
return isParameterized(typ, make(map[Type]bool))
119118
}

src/go/types/unify.go

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,23 @@ func (d *typeDesc) at(i int) Type {
6464
return nil
6565
}
6666

67+
// types returns the list of inferred types (via unification) for the type parameters
68+
// described by d, and an index. If all types were inferred, the returned index is < 0.
69+
// Otherwise, it is the index of the first type parameter which couldn't be inferred
70+
// and for which list[index] is nil.
71+
func (d *typeDesc) types() (list []Type, index int) {
72+
list = make([]Type, len(d.tparams))
73+
index = -1
74+
for i := range d.tparams {
75+
t := d.at(i)
76+
list[i] = t
77+
if index < 0 && t == nil {
78+
index = i
79+
}
80+
}
81+
return
82+
}
83+
6784
// set sets the type typ inferred (via unification) for the i'th type parameter; typ must not be nil.
6885
// The index i must be a valid type parameter index: 0 <= i < len(d.tparams).
6986
func (d *typeDesc) set(i int, typ Type) {

0 commit comments

Comments
 (0)