go/types, types2: better error message for some inference failures

For a unification failure involving a constraint, rather than just
reporting (for instance)

        S does not match []E

now report the inferred type for the type parameter, use spec
terminology when referring to the constraint, and print the
constraint in full:

        S (type func()) does not satisfy ~[]E

There's more we can do, but this is better than what we had.

For #60542.

Change-Id: I033369fa0dfc475f0ec0da0582e8cbefb109f3cf
Reviewed-on: https://go-review.googlesource.com/c/go/+/499639
Reviewed-by: Robert Griesemer <gri@google.com>
Run-TryBot: Robert Griesemer <gri@google.com>
Auto-Submit: Robert Griesemer <gri@google.com>
TryBot-Result: Gopher Robot <gobot@golang.org>
Reviewed-by: Robert Findley <rfindley@google.com>
This commit is contained in:
Robert Griesemer 2023-05-31 15:15:13 -07:00 committed by Gopher Robot
parent fdd9911d1a
commit 1079a5c08a
7 changed files with 41 additions and 17 deletions

View File

@ -231,7 +231,10 @@ func (check *Checker) infer(pos syntax.Pos, tparams []*TypeParam, targs []Type,
// 2) If the core type doesn't have a tilde, we also must unify tx
// with the core type.
if !u.unify(tx, core.typ, 0) {
check.errorf(pos, CannotInferTypeArgs, "%s does not match %s", tpar, core.typ)
// TODO(gri) Type parameters that appear in the constraint and
// for which we have type arguments inferred should
// use those type arguments for a better error message.
check.errorf(pos, CannotInferTypeArgs, "%s (type %s) does not satisfy %s", tpar, tx, tpar.Constraint())
return nil
}
case single && !core.tilde:
@ -249,7 +252,8 @@ func (check *Checker) infer(pos syntax.Pos, tparams []*TypeParam, targs []Type,
var cause string
constraint := tpar.iface()
if m, _ := check.missingMethod(tx, constraint, true, func(x, y Type) bool { return u.unify(x, y, 0) }, &cause); m != nil {
check.errorf(pos, CannotInferTypeArgs, "%s does not satisfy %s %s", tx, constraint, cause)
// TODO(gri) better error message (see TODO above)
check.errorf(pos, CannotInferTypeArgs, "%s (type %s) does not satisfy %s %s", tpar, tx, tpar.Constraint(), cause)
return nil
}
}

View File

@ -233,7 +233,10 @@ func (check *Checker) infer(posn positioner, tparams []*TypeParam, targs []Type,
// 2) If the core type doesn't have a tilde, we also must unify tx
// with the core type.
if !u.unify(tx, core.typ, 0) {
check.errorf(posn, CannotInferTypeArgs, "%s does not match %s", tpar, core.typ)
// TODO(gri) Type parameters that appear in the constraint and
// for which we have type arguments inferred should
// use those type arguments for a better error message.
check.errorf(posn, CannotInferTypeArgs, "%s (type %s) does not satisfy %s", tpar, tx, tpar.Constraint())
return nil
}
case single && !core.tilde:
@ -251,7 +254,8 @@ func (check *Checker) infer(posn positioner, tparams []*TypeParam, targs []Type,
var cause string
constraint := tpar.iface()
if m, _ := check.missingMethod(tx, constraint, true, func(x, y Type) bool { return u.unify(x, y, 0) }, &cause); m != nil {
check.errorf(posn, CannotInferTypeArgs, "%s does not satisfy %s %s", tx, constraint, cause)
// TODO(gri) better error message (see TODO above)
check.errorf(posn, CannotInferTypeArgs, "%s (type %s) does not satisfy %s %s", tpar, tx, tpar.Constraint(), cause)
return nil
}
}

View File

@ -99,7 +99,7 @@ func _() {
// last.
related2(1.2, []float64{})
related2(1.0, []int{})
related2 /* ERROR "Slice does not match []Elem" */ (float64(1.0), []int{}) // TODO(gri) better error message
related2 /* ERROR "Slice (type []int) does not satisfy interface{[]Elem}" */ (float64(1.0), []int{}) // TODO(gri) better error message
}
type List[P any] []P
@ -117,7 +117,11 @@ func _() {
related3 /* ERROR "cannot infer Slice" */ [int]()
}
func wantsMethods[P interface{ m1(Q); m2() R }, Q, R any](P) {}
func wantsMethods[P interface {
m1(Q)
m2() R
}, Q, R any](P) {
}
type hasMethods1 struct{}
@ -129,12 +133,12 @@ type hasMethods2 struct{}
func (*hasMethods2) m1(int)
func (*hasMethods2) m2() string
type hasMethods3 interface{
type hasMethods3 interface {
m1(float64)
m2() complex128
}
type hasMethods4 interface{
type hasMethods4 interface {
m1()
}
@ -144,11 +148,11 @@ func _() {
// signatures.
wantsMethods(hasMethods1{})
wantsMethods(&hasMethods1{})
wantsMethods /* ERROR "hasMethods2 does not satisfy interface{m1(Q); m2() R} (method m1 has pointer receiver)" */ (hasMethods2{})
wantsMethods /* ERROR "P (type hasMethods2) does not satisfy interface{m1(Q); m2() R} (method m1 has pointer receiver)" */ (hasMethods2{})
wantsMethods(&hasMethods2{})
wantsMethods(hasMethods3(nil))
wantsMethods /* ERROR "any does not satisfy interface{m1(Q); m2() R} (missing method m1)" */ (any(nil))
wantsMethods /* ERROR "hasMethods4 does not satisfy interface{m1(Q); m2() R} (wrong type for method m1)" */ (hasMethods4(nil))
wantsMethods /* ERROR "P (type any) does not satisfy interface{m1(Q); m2() R} (missing method m1)" */ (any(nil))
wantsMethods /* ERROR "P (type hasMethods4) does not satisfy interface{m1(Q); m2() R} (wrong type for method m1)" */ (hasMethods4(nil))
}
// "Reverse" type inference is not yet permitted.

View File

@ -9,5 +9,5 @@ func app[S interface{ ~[]T }, T any](s S, e T) S {
}
func _() {
_ = app /* ERROR "S does not match []T" */ [int] // TODO(gri) better error message
_ = app /* ERROR "S (type int) does not satisfy interface{~[]T}" */ [int] // TODO(gri) better error message
}

View File

@ -7,9 +7,9 @@ package p
func f[P int](P) {}
func _() {
_ = f[int]
_ = f[[ /* ERROR "[]int does not satisfy int" */ ]int]
_ = f[int]
_ = f[[ /* ERROR "[]int does not satisfy int ([]int missing in int)" */ ]int]
f(0)
f /* ERROR "P does not match int" */ ([]int{}) // TODO(gri) better error message
f(0)
f /* ERROR "P (type []int) does not satisfy int" */ ([]int{}) // TODO(gri) better error message
}

View File

@ -49,6 +49,6 @@ func f[T interface{comparable; []byte|string}](x T) {
}
func _(s []byte) {
f /* ERROR "T does not match string" */ (s) // TODO(gri) better error message (T's type set only contains string!)
f /* ERROR "T (type []byte) does not satisfy interface{comparable; []byte | string}" */ (s) // TODO(gri) better error message (T's type set only contains string!)
_ = f[[ /* ERROR "does not satisfy" */ ]byte]
}

View File

@ -0,0 +1,12 @@
// Copyright 2023 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 Clip[S ~[]E, E any](s S) S {
return s
}
var versions func()
var _ = Clip /* ERROR "S (type func()) does not satisfy ~[]E" */ (versions)