proto, internal/errors: add Error sentinel, errors.Wrap

Add a sentinel proto.Error error which matches all errors returned by
packages in this module.

Document that protoregistry.NotFound is an exact sentinel value for
performance reasons.

Add a Wrap function to the internal/errors package and use it to wrap
errors from outside sources (resolvers). Wrapped errors match
proto.Error.

Fixes golang/protobuf#1021.

Change-Id: I45567df3fd6c8dc9a5caafdb55654827f6fb1941
Reviewed-on: https://go-review.googlesource.com/c/protobuf/+/215338
Reviewed-by: Joe Tsai <joetsai@google.com>
diff --git a/reflect/protodesc/desc_resolve.go b/reflect/protodesc/desc_resolve.go
index 1bf4799..cebb36c 100644
--- a/reflect/protodesc/desc_resolve.go
+++ b/reflect/protodesc/desc_resolve.go
@@ -187,7 +187,7 @@
 			}
 			foundButNotImported = d
 		} else if err != protoregistry.NotFound {
-			return nil, err
+			return nil, errors.Wrap(err, "%q", s)
 		}
 
 		// Continue on at a higher level of scoping.
diff --git a/reflect/protoregistry/registry.go b/reflect/protoregistry/registry.go
index c77f77a..8385c75 100644
--- a/reflect/protoregistry/registry.go
+++ b/reflect/protoregistry/registry.go
@@ -47,6 +47,9 @@
 var GlobalTypes *Types = new(Types)
 
 // NotFound is a sentinel error value to indicate that the type was not found.
+//
+// Since registry lookup can happen in the critical performance path, resolvers
+// must return this exact error value, not an error wrapping it.
 var NotFound = errors.New("not found")
 
 // Files is a registry for looking up or iterating over files and the