mirror of
https://github.com/golang/go
synced 2024-11-11 17:51:49 -07:00
go/types, types2: refer to type parameter if so for interface pointer errors
Follow-up on comment in CL 376914. Also: - add missing check != nil test in assignableTo - use check.sprintf rather than fmt.Sprintf in missingMethodReason For #48312. Change-Id: Ie209b4101a7f2c279e42a59987d0068079c8b69f Reviewed-on: https://go-review.googlesource.com/c/go/+/377375 Trust: Robert Griesemer <gri@golang.org> Reviewed-by: Robert Findley <rfindley@google.com>
This commit is contained in:
parent
91edf2b7f2
commit
4ceb5a94d8
@ -544,7 +544,7 @@ func (check *Checker) selector(x *operand, e *syntax.SelectorExpr) {
|
||||
|
||||
var why string
|
||||
if isInterfacePtr(x.typ) {
|
||||
why = check.sprintf("type %s is pointer to interface, not interface", x.typ)
|
||||
why = check.interfacePtrError(x.typ)
|
||||
} else {
|
||||
why = check.sprintf("type %s has no field or method %s", x.typ, sel)
|
||||
// Check if capitalization of sel matters and provide better error message in that case.
|
||||
|
@ -7,7 +7,6 @@
|
||||
package types2
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
)
|
||||
|
||||
@ -429,17 +428,17 @@ func (check *Checker) missingMethodReason(V, T Type, m, wrongType *Func) string
|
||||
if wrongType != nil {
|
||||
if Identical(m.typ, wrongType.typ) {
|
||||
if m.Name() == wrongType.Name() {
|
||||
r = fmt.Sprintf("(%s has pointer receiver)", mname)
|
||||
r = check.sprintf("(%s has pointer receiver)", mname)
|
||||
} else {
|
||||
r = fmt.Sprintf("(missing %s)\n\t\thave %s^^%s\n\t\twant %s^^%s",
|
||||
r = check.sprintf("(missing %s)\n\t\thave %s^^%s\n\t\twant %s^^%s",
|
||||
mname, wrongType.Name(), wrongType.typ, m.Name(), m.typ)
|
||||
}
|
||||
} else {
|
||||
if check.conf.CompilerErrorMessages {
|
||||
r = fmt.Sprintf("(wrong type for %s)\n\t\thave %s^^%s\n\t\twant %s^^%s",
|
||||
r = check.sprintf("(wrong type for %s)\n\t\thave %s^^%s\n\t\twant %s^^%s",
|
||||
mname, wrongType.Name(), wrongType.typ, m.Name(), m.typ)
|
||||
} else {
|
||||
r = fmt.Sprintf("(wrong type for %s: have %s, want %s)",
|
||||
r = check.sprintf("(wrong type for %s: have %s, want %s)",
|
||||
mname, wrongType.typ, m.typ)
|
||||
}
|
||||
}
|
||||
@ -450,13 +449,13 @@ func (check *Checker) missingMethodReason(V, T Type, m, wrongType *Func) string
|
||||
r = strings.Replace(r, "^^func", "", -1)
|
||||
} else if IsInterface(T) {
|
||||
if isInterfacePtr(V) {
|
||||
r = fmt.Sprintf("(type %s is pointer to interface, not interface)", V)
|
||||
r = "(" + check.interfacePtrError(V) + ")"
|
||||
}
|
||||
} else if isInterfacePtr(T) {
|
||||
r = fmt.Sprintf("(type %s is pointer to interface, not interface)", T)
|
||||
r = "(" + check.interfacePtrError(T) + ")"
|
||||
}
|
||||
if r == "" {
|
||||
r = fmt.Sprintf("(missing %s)", mname)
|
||||
r = check.sprintf("(missing %s)", mname)
|
||||
}
|
||||
return r
|
||||
}
|
||||
@ -466,6 +465,14 @@ func isInterfacePtr(T Type) bool {
|
||||
return p != nil && IsInterface(p.base)
|
||||
}
|
||||
|
||||
func (check *Checker) interfacePtrError(T Type) string {
|
||||
assert(isInterfacePtr(T))
|
||||
if p, _ := under(T).(*Pointer); isTypeParam(p.base) {
|
||||
return check.sprintf("type %s is pointer to type parameter, not type parameter", T)
|
||||
}
|
||||
return check.sprintf("type %s is pointer to interface, not interface", T)
|
||||
}
|
||||
|
||||
// assertableTo reports whether a value of type V can be asserted to have type T.
|
||||
// It returns (nil, false) as affirmative answer. Otherwise it returns a missing
|
||||
// method required by V and whether it is missing or just has the wrong type.
|
||||
|
@ -292,7 +292,7 @@ func (x *operand) assignableTo(check *Checker, T Type, reason *string) (bool, er
|
||||
if Ti, ok := Tu.(*Interface); ok && Tp == nil {
|
||||
if m, wrongType := check.missingMethod(V, Ti, true); m != nil /* !Implements(V, Ti) */ {
|
||||
if reason != nil {
|
||||
if check.conf.CompilerErrorMessages {
|
||||
if check != nil && check.conf.CompilerErrorMessages {
|
||||
*reason = check.sprintf("%s does not implement %s %s", x.typ, T,
|
||||
check.missingMethodReason(x.typ, T, m, wrongType))
|
||||
} else {
|
||||
|
@ -20,7 +20,7 @@ func _[P interface{ m() }](x P) {
|
||||
x.m()
|
||||
// (&x).m doesn't exist because &x is of type *P
|
||||
// and pointers to type parameters don't have methods
|
||||
(&x).m /* ERROR type \*P is pointer to interface, not interface */ ()
|
||||
(&x).m /* ERROR type \*P is pointer to type parameter, not type parameter */ ()
|
||||
}
|
||||
|
||||
|
||||
|
@ -16,5 +16,5 @@ func _(p P) {
|
||||
}
|
||||
|
||||
func _[P T](p *P) {
|
||||
p.m /* ERROR type \*P is pointer to interface, not interface */ ()
|
||||
p.m /* ERROR type \*P is pointer to type parameter, not type parameter */ ()
|
||||
}
|
||||
|
@ -546,7 +546,7 @@ func (check *Checker) selector(x *operand, e *ast.SelectorExpr) {
|
||||
|
||||
var why string
|
||||
if isInterfacePtr(x.typ) {
|
||||
why = check.sprintf("type %s is pointer to interface, not interface", x.typ)
|
||||
why = check.interfacePtrError(x.typ)
|
||||
} else {
|
||||
why = check.sprintf("type %s has no field or method %s", x.typ, sel)
|
||||
// Check if capitalization of sel matters and provide better error message in that case.
|
||||
|
@ -7,7 +7,6 @@
|
||||
package types
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
)
|
||||
|
||||
@ -403,17 +402,17 @@ func (check *Checker) missingMethodReason(V, T Type, m, wrongType *Func) string
|
||||
if wrongType != nil {
|
||||
if Identical(m.typ, wrongType.typ) {
|
||||
if m.Name() == wrongType.Name() {
|
||||
r = fmt.Sprintf("(%s has pointer receiver)", mname)
|
||||
r = check.sprintf("(%s has pointer receiver)", mname)
|
||||
} else {
|
||||
r = fmt.Sprintf("(missing %s)\n\t\thave %s^^%s\n\t\twant %s^^%s",
|
||||
r = check.sprintf("(missing %s)\n\t\thave %s^^%s\n\t\twant %s^^%s",
|
||||
mname, wrongType.Name(), wrongType.typ, m.Name(), m.typ)
|
||||
}
|
||||
} else {
|
||||
if compilerErrorMessages {
|
||||
r = fmt.Sprintf("(wrong type for %s)\n\t\thave %s^^%s\n\t\twant %s^^%s",
|
||||
r = check.sprintf("(wrong type for %s)\n\t\thave %s^^%s\n\t\twant %s^^%s",
|
||||
mname, wrongType.Name(), wrongType.typ, m.Name(), m.typ)
|
||||
} else {
|
||||
r = fmt.Sprintf("(wrong type for %s: have %s, want %s)",
|
||||
r = check.sprintf("(wrong type for %s: have %s, want %s)",
|
||||
mname, wrongType.typ, m.typ)
|
||||
}
|
||||
}
|
||||
@ -424,13 +423,13 @@ func (check *Checker) missingMethodReason(V, T Type, m, wrongType *Func) string
|
||||
r = strings.Replace(r, "^^func", "", -1)
|
||||
} else if IsInterface(T) {
|
||||
if isInterfacePtr(V) {
|
||||
r = fmt.Sprintf("(type %s is pointer to interface, not interface)", V)
|
||||
r = "(" + check.interfacePtrError(V) + ")"
|
||||
}
|
||||
} else if isInterfacePtr(T) {
|
||||
r = fmt.Sprintf("(type %s is pointer to interface, not interface)", T)
|
||||
r = "(" + check.interfacePtrError(T) + ")"
|
||||
}
|
||||
if r == "" {
|
||||
r = fmt.Sprintf("(missing %s)", mname)
|
||||
r = check.sprintf("(missing %s)", mname)
|
||||
}
|
||||
return r
|
||||
}
|
||||
@ -440,6 +439,14 @@ func isInterfacePtr(T Type) bool {
|
||||
return p != nil && IsInterface(p.base)
|
||||
}
|
||||
|
||||
func (check *Checker) interfacePtrError(T Type) string {
|
||||
assert(isInterfacePtr(T))
|
||||
if p, _ := under(T).(*Pointer); isTypeParam(p.base) {
|
||||
return check.sprintf("type %s is pointer to type parameter, not type parameter", T)
|
||||
}
|
||||
return check.sprintf("type %s is pointer to interface, not interface", T)
|
||||
}
|
||||
|
||||
// assertableTo reports whether a value of type V can be asserted to have type T.
|
||||
// It returns (nil, false) as affirmative answer. Otherwise it returns a missing
|
||||
// method required by V and whether it is missing or just has the wrong type.
|
||||
|
@ -282,7 +282,7 @@ func (x *operand) assignableTo(check *Checker, T Type, reason *string) (bool, er
|
||||
if Ti, ok := Tu.(*Interface); ok && Tp == nil {
|
||||
if m, wrongType := check.missingMethod(V, Ti, true); m != nil /* Implements(V, Ti) */ {
|
||||
if reason != nil {
|
||||
if compilerErrorMessages {
|
||||
if check != nil && compilerErrorMessages {
|
||||
*reason = check.sprintf("%s does not implement %s %s", x.typ, T,
|
||||
check.missingMethodReason(x.typ, T, m, wrongType))
|
||||
} else {
|
||||
|
@ -20,7 +20,7 @@ func _[P interface{ m() }](x P) {
|
||||
x.m()
|
||||
// (&x).m doesn't exist because &x is of type *P
|
||||
// and pointers to type parameters don't have methods
|
||||
(&x).m /* ERROR type \*P is pointer to interface, not interface */ ()
|
||||
(&x).m /* ERROR type \*P is pointer to type parameter, not type parameter */ ()
|
||||
}
|
||||
|
||||
|
||||
|
@ -16,5 +16,5 @@ func _(p P) {
|
||||
}
|
||||
|
||||
func _[P T](p *P) {
|
||||
p.m /* ERROR type \*P is pointer to interface, not interface */ ()
|
||||
p.m /* ERROR type \*P is pointer to type parameter, not type parameter */ ()
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user