| 219 | return nil |
| 220 | } |
| 221 | func (validator) apply(s *state, vx, vy reflect.Value) { |
| 222 | // Implies missing slice element or map entry. |
| 223 | if !vx.IsValid() || !vy.IsValid() { |
| 224 | s.report(vx.IsValid() == vy.IsValid(), 0) |
| 225 | return |
| 226 | } |
| 227 | |
| 228 | // Unable to Interface implies unexported field without visibility access. |
| 229 | if !vx.CanInterface() || !vy.CanInterface() { |
| 230 | help := "consider using a custom Comparer; if you control the implementation of type, you can also consider using an Exporter, AllowUnexported, or cmpopts.IgnoreUnexported" |
| 231 | var name string |
| 232 | if t := s.curPath.Index(-2).Type(); t.Name() != "" { |
| 233 | // Named type with unexported fields. |
| 234 | name = fmt.Sprintf("%q.%v", t.PkgPath(), t.Name()) // e.g., "path/to/package".MyType |
| 235 | isProtoMessage := func(t reflect.Type) bool { |
| 236 | m, ok := reflect.PointerTo(t).MethodByName("ProtoReflect") |
| 237 | return ok && m.Type.NumIn() == 1 && m.Type.NumOut() == 1 && |
| 238 | m.Type.Out(0).PkgPath() == "google.golang.org/protobuf/reflect/protoreflect" && |
| 239 | m.Type.Out(0).Name() == "Message" |
| 240 | } |
| 241 | if isProtoMessage(t) { |
| 242 | help = `consider using "google.golang.org/protobuf/testing/protocmp".Transform to compare proto.Message types` |
| 243 | } else if _, ok := reflect.New(t).Interface().(error); ok { |
| 244 | help = "consider using cmpopts.EquateErrors to compare error values" |
| 245 | } else if t.Comparable() { |
| 246 | help = "consider using cmpopts.EquateComparable to compare comparable Go types" |
| 247 | } |
| 248 | } else { |
| 249 | // Unnamed type with unexported fields. Derive PkgPath from field. |
| 250 | var pkgPath string |
| 251 | for i := 0; i < t.NumField() && pkgPath == ""; i++ { |
| 252 | pkgPath = t.Field(i).PkgPath |
| 253 | } |
| 254 | name = fmt.Sprintf("%q.(%v)", pkgPath, t.String()) // e.g., "path/to/package".(struct { a int }) |
| 255 | } |
| 256 | panic(fmt.Sprintf("cannot handle unexported field at %#v:\n\t%v\n%s", s.curPath, name, help)) |
| 257 | } |
| 258 | |
| 259 | panic("not reachable") |
| 260 | } |
| 261 | |
| 262 | // identRx represents a valid identifier according to the Go specification. |
| 263 | const identRx = `[_\p{L}][_\p{L}\p{N}]*` |