From 09852e75acc8228887713e75e9c88dc864978065 Mon Sep 17 00:00:00 2001 From: Robert Griesemer Date: Tue, 28 Feb 2023 15:04:35 -0800 Subject: [PATCH] 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 Reviewed-by: Robert Findley TryBot-Result: Gopher Robot Reviewed-by: Robert Griesemer Auto-Submit: Robert Griesemer --- src/cmd/compile/internal/types2/instantiate.go | 2 +- src/cmd/compile/internal/types2/lookup.go | 14 ++++++++------ src/go/types/instantiate.go | 2 +- src/go/types/lookup.go | 14 ++++++++------ 4 files changed, 18 insertions(+), 14 deletions(-) diff --git a/src/cmd/compile/internal/types2/instantiate.go b/src/cmd/compile/internal/types2/instantiate.go index 9f5eb268ac..7091ef7e49 100644 --- a/src/cmd/compile/internal/types2/instantiate.go +++ b/src/cmd/compile/internal/types2/instantiate.go @@ -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)) } diff --git a/src/cmd/compile/internal/types2/lookup.go b/src/cmd/compile/internal/types2/lookup.go index 0c3b96ff2d..7d34179249 100644 --- a/src/cmd/compile/internal/types2/lookup.go +++ b/src/cmd/compile/internal/types2/lookup.go @@ -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. diff --git a/src/go/types/instantiate.go b/src/go/types/instantiate.go index 11afb7a853..2a9182d5af 100644 --- a/src/go/types/instantiate.go +++ b/src/go/types/instantiate.go @@ -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)) } diff --git a/src/go/types/lookup.go b/src/go/types/lookup.go index 331c308656..f9e297044e 100644 --- a/src/go/types/lookup.go +++ b/src/go/types/lookup.go @@ -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.