[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 <gri@golang.org>
This commit is contained in:
Robert Griesemer 2020-06-30 17:28:22 -07:00
parent 938e96e732
commit 6cf6bf162c
4 changed files with 52 additions and 19 deletions

View File

@ -126,10 +126,11 @@ var tests = [][]string{
// TODO(gri) Eliminate the need to enumerate these tests here.
// Should just traverse that directory.
{"fixedbugs/issue39664.go2"},
{"fixedbugs/issue39693.go2"},
{"fixedbugs/issue39680.go2"},
{"fixedbugs/issue39693.go2"},
{"fixedbugs/issue39711.go2"},
{"fixedbugs/issue39723.go2"},
{"fixedbugs/issue39725.go2"},
{"fixedbugs/issue39754.go2"},
{"fixedbugs/issue39755.go2"},
{"fixedbugs/issue39768.go2"},

View File

@ -0,0 +1,16 @@
// Copyright 2020 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package p
func f1(type T1, T2)(T1, T2, struct{a T1; b T2})
func _() {
f1(42, string("foo"), struct /* ERROR does not match inferred type struct\{a int; b string\} */ {a, b int}{})
}
// simplified test case from issue
func f2(type T)(_ []T, _ func(T))
func _() {
f2([]string{}, func /* ERROR does not match inferred type func\(string\) */ (f []byte) {})
}

View File

@ -20,13 +20,14 @@ func (check *Checker) infer(pos token.Pos, tparams []*TypeName, params *Tuple, a
errorf := func(kind string, tpar, targ Type, arg *operand) {
// provide a better error message if we can
if tpar, _ := tpar.(*TypeParam); tpar != nil {
if inferred := u.x.at(tpar.index); inferred != nil {
check.errorf(arg.pos(), "%s %s of %s does not match inferred type %s for %s", kind, targ, arg.expr, inferred, tpar)
return
}
targs, _ := u.x.types()
smap := makeSubstMap(tparams, targs)
inferred := check.subst(arg.pos(), tpar, smap)
if inferred != tpar {
check.errorf(arg.pos(), "%s %s of %s does not match inferred type %s for %s", kind, targ, arg.expr, inferred, tpar)
} else {
check.errorf(arg.pos(), "%s %s of %s does not match %s", kind, targ, arg.expr, tpar)
}
check.errorf(arg.pos(), "%s %s of %s does not match %s", kind, targ, arg.expr, tpar)
}
// 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
// Collect type arguments and check if they all have been determined.
// TODO(gri) consider moving this outside this function and then we won't need to pass in pos
var targs []Type // lazily allocated
for i, tpar := range tparams {
targ := u.x.at(i)
if targ == nil {
ppos := check.fset.Position(tpar.pos).String()
check.errorf(pos, "cannot infer %s (%s)", tpar.name, ppos)
return nil
}
if targs == nil {
targs = make([]Type, len(tparams))
}
targs[i] = targ
targs, failed := u.x.types()
if failed >= 0 {
tpar := tparams[failed]
ppos := check.fset.Position(tpar.pos).String()
check.errorf(pos, "cannot infer %s (%s)", tpar.name, ppos)
return nil
}
return targs
}
// IsParameterized reports whether typ contains any type parameters.
// TODO(gri) This is not strictly correct. We only want the free
// type parameters for a given type. (At the moment, the only way
// to mix free and bound type parameters is through method type parameters
// on parameterized receiver types - need to investigate.)
func IsParameterized(typ Type) bool {
return isParameterized(typ, make(map[Type]bool))
}

View File

@ -64,6 +64,23 @@ func (d *typeDesc) at(i int) Type {
return nil
}
// types returns the list of inferred types (via unification) for the type parameters
// described by d, and an index. If all types were inferred, the returned index is < 0.
// Otherwise, it is the index of the first type parameter which couldn't be inferred
// and for which list[index] is nil.
func (d *typeDesc) types() (list []Type, index int) {
list = make([]Type, len(d.tparams))
index = -1
for i := range d.tparams {
t := d.at(i)
list[i] = t
if index < 0 && t == nil {
index = i
}
}
return
}
// set sets the type typ inferred (via unification) for the i'th type parameter; typ must not be nil.
// The index i must be a valid type parameter index: 0 <= i < len(d.tparams).
func (d *typeDesc) set(i int, typ Type) {