1
0
mirror of https://github.com/golang/go synced 2024-09-30 03:34:51 -06:00

go/types, types2: add predicate to missingMethod signature

This allows us to use missingMethod with different type comparers,
such as the global Identical predicate, or a unifier.

Preparation for the next CL.

Change-Id: I237fd9dd7feb3708847ae6d9a112bcdd0aa1ecb4
Reviewed-on: https://go-review.googlesource.com/c/go/+/472297
Run-TryBot: Robert Griesemer <gri@google.com>
Reviewed-by: Robert Findley <rfindley@google.com>
TryBot-Result: Gopher Robot <gobot@golang.org>
Reviewed-by: Robert Griesemer <gri@google.com>
Auto-Submit: Robert Griesemer <gri@google.com>
This commit is contained in:
Robert Griesemer 2023-02-28 15:04:35 -08:00 committed by Gopher Robot
parent 052a36ccbe
commit 09852e75ac
4 changed files with 18 additions and 14 deletions

View File

@ -241,7 +241,7 @@ func (check *Checker) implements(V, T Type, constraint bool, cause *string) bool
}
// V must implement T's methods, if any.
if m, wrong := check.missingMethod(V, Ti, true); m != nil /* !Implements(V, Ti) */ {
if m, wrong := check.missingMethod(V, Ti, true, Identical); m != nil /* !Implements(V, Ti) */ {
if cause != nil {
*cause = check.sprintf("%s does not %s %s %s", V, verb, T, check.missingMethodCause(V, T, m, wrong))
}

View File

@ -305,20 +305,22 @@ func (l *instanceLookup) add(inst *Named) {
// present in V have matching types (e.g., for a type assertion x.(T) where
// x is of interface type V).
func MissingMethod(V Type, T *Interface, static bool) (method *Func, wrongType bool) {
m, alt := (*Checker)(nil).missingMethod(V, T, static)
m, alt := (*Checker)(nil).missingMethod(V, T, static, Identical)
// Only report a wrong type if the alternative method has the same name as m.
return m, alt != nil && alt.name == m.name // alt != nil implies m != nil
}
// missingMethod is like MissingMethod but accepts a *Checker as receiver.
// missingMethod is like MissingMethod but accepts a *Checker as receiver
// and comparator equivalent for type comparison.
// The receiver may be nil if missingMethod is invoked through an exported
// API call (such as MissingMethod), i.e., when all methods have been type-
// checked.
// The comparator is used to compare signatures.
//
// If a method is missing on T but is found on *T, or if a method is found
// on T when looked up with case-folding, this alternative method is returned
// as the second result.
func (check *Checker) missingMethod(V Type, T *Interface, static bool) (method, alt *Func) {
func (check *Checker) missingMethod(V Type, T *Interface, static bool, equivalent func(x, y Type) bool) (method, alt *Func) {
if T.NumMethods() == 0 {
return
}
@ -336,7 +338,7 @@ func (check *Checker) missingMethod(V Type, T *Interface, static bool) (method,
return m, nil
}
if !Identical(f.typ, m.typ) {
if !equivalent(f.typ, m.typ) {
return m, f
}
}
@ -370,7 +372,7 @@ func (check *Checker) missingMethod(V Type, T *Interface, static bool) (method,
check.objDecl(f, nil)
}
if !found || !Identical(f.typ, m.typ) {
if !found || !equivalent(f.typ, m.typ) {
return m, f
}
}
@ -467,7 +469,7 @@ func (check *Checker) assertableTo(V *Interface, T Type) (method, wrongType *Fun
return
}
// TODO(gri) fix this for generalized interfaces
return check.missingMethod(T, V, false)
return check.missingMethod(T, V, false, Identical)
}
// newAssertableTo reports whether a value of type V can be asserted to have type T.

View File

@ -243,7 +243,7 @@ func (check *Checker) implements(V, T Type, constraint bool, cause *string) bool
}
// V must implement T's methods, if any.
if m, wrong := check.missingMethod(V, Ti, true); m != nil /* !Implements(V, Ti) */ {
if m, wrong := check.missingMethod(V, Ti, true, Identical); m != nil /* !Implements(V, Ti) */ {
if cause != nil {
*cause = check.sprintf("%s does not %s %s %s", V, verb, T, check.missingMethodCause(V, T, m, wrong))
}

View File

@ -307,20 +307,22 @@ func (l *instanceLookup) add(inst *Named) {
// present in V have matching types (e.g., for a type assertion x.(T) where
// x is of interface type V).
func MissingMethod(V Type, T *Interface, static bool) (method *Func, wrongType bool) {
m, alt := (*Checker)(nil).missingMethod(V, T, static)
m, alt := (*Checker)(nil).missingMethod(V, T, static, Identical)
// Only report a wrong type if the alternative method has the same name as m.
return m, alt != nil && alt.name == m.name // alt != nil implies m != nil
}
// missingMethod is like MissingMethod but accepts a *Checker as receiver.
// missingMethod is like MissingMethod but accepts a *Checker as receiver
// and comparator equivalent for type comparison.
// The receiver may be nil if missingMethod is invoked through an exported
// API call (such as MissingMethod), i.e., when all methods have been type-
// checked.
// The comparator is used to compare signatures.
//
// If a method is missing on T but is found on *T, or if a method is found
// on T when looked up with case-folding, this alternative method is returned
// as the second result.
func (check *Checker) missingMethod(V Type, T *Interface, static bool) (method, alt *Func) {
func (check *Checker) missingMethod(V Type, T *Interface, static bool, equivalent func(x, y Type) bool) (method, alt *Func) {
if T.NumMethods() == 0 {
return
}
@ -338,7 +340,7 @@ func (check *Checker) missingMethod(V Type, T *Interface, static bool) (method,
return m, nil
}
if !Identical(f.typ, m.typ) {
if !equivalent(f.typ, m.typ) {
return m, f
}
}
@ -372,7 +374,7 @@ func (check *Checker) missingMethod(V Type, T *Interface, static bool) (method,
check.objDecl(f, nil)
}
if !found || !Identical(f.typ, m.typ) {
if !found || !equivalent(f.typ, m.typ) {
return m, f
}
}
@ -469,7 +471,7 @@ func (check *Checker) assertableTo(V *Interface, T Type) (method, wrongType *Fun
return
}
// TODO(gri) fix this for generalized interfaces
return check.missingMethod(T, V, false)
return check.missingMethod(T, V, false, Identical)
}
// newAssertableTo reports whether a value of type V can be asserted to have type T.