all: add ProtoMethods method to protoreflect.Message

Promote the fast-path magic ProtoMethods method to first-class citizen
of the protoreflect.Message interface.

To avoid polluting the protoreflect package with the various types
required by this method, make the necessary protoiface types unnamed and
duplicate them in protoreflect.

Updates golang/protobuf#1022.

Change-Id: I9595bae40b3bc7536d727fb6f99b3bce8f73da87
Reviewed-on: https://go-review.googlesource.com/c/protobuf/+/215718
Reviewed-by: Joe Tsai <joetsai@google.com>
diff --git a/internal/impl/decode.go b/internal/impl/decode.go
index 3e26223..50b0cf1 100644
--- a/internal/impl/decode.go
+++ b/internal/impl/decode.go
@@ -24,7 +24,8 @@
 	// Keep this field's type identical to (proto.UnmarshalOptions).Resolver
 	// to avoid a type conversion on assignment.
 	resolver interface {
-		preg.ExtensionTypeResolver
+		FindExtensionByName(field pref.FullName) (pref.ExtensionType, error)
+		FindExtensionByNumber(message pref.FullName, field pref.FieldNumber) (pref.ExtensionType, error)
 	}
 }
 
diff --git a/internal/testprotos/irregular/irregular.go b/internal/testprotos/irregular/irregular.go
index 4240124..da5c396 100644
--- a/internal/testprotos/irregular/irregular.go
+++ b/internal/testprotos/irregular/irregular.go
@@ -8,6 +8,7 @@
 	"google.golang.org/protobuf/encoding/prototext"
 	"google.golang.org/protobuf/reflect/protodesc"
 	pref "google.golang.org/protobuf/reflect/protoreflect"
+	"google.golang.org/protobuf/runtime/protoiface"
 
 	"google.golang.org/protobuf/types/descriptorpb"
 )
@@ -26,6 +27,7 @@
 func (m *message) New() pref.Message                  { return &message{} }
 func (m *message) Zero() pref.Message                 { return (*message)(nil) }
 func (m *message) Interface() pref.ProtoMessage       { return (*IrregularMessage)(m) }
+func (m *message) ProtoMethods() *protoiface.Methods  { return nil }
 
 var fieldDescS = fileDesc.Messages().Get(0).Fields().Get(0)
 
diff --git a/proto/decode.go b/proto/decode.go
index 03ea7ec..cea434d 100644
--- a/proto/decode.go
+++ b/proto/decode.go
@@ -38,7 +38,8 @@
 	// Resolver is used for looking up types when unmarshaling extension fields.
 	// If nil, this defaults to using protoregistry.GlobalTypes.
 	Resolver interface {
-		protoregistry.ExtensionTypeResolver
+		FindExtensionByName(field protoreflect.FullName) (protoreflect.ExtensionType, error)
+		FindExtensionByNumber(message protoreflect.FullName, field protoreflect.FieldNumber) (protoreflect.ExtensionType, error)
 	}
 }
 
diff --git a/proto/proto_methods.go b/proto/proto_methods.go
index 86dde4a..d8dd604 100644
--- a/proto/proto_methods.go
+++ b/proto/proto_methods.go
@@ -15,8 +15,5 @@
 const hasProtoMethods = true
 
 func protoMethods(m protoreflect.Message) *protoiface.Methods {
-	if x, ok := m.(protoiface.Methoder); ok {
-		return x.ProtoMethods()
-	}
-	return nil
+	return m.ProtoMethods()
 }
diff --git a/reflect/protoreflect/methods.go b/reflect/protoreflect/methods.go
new file mode 100644
index 0000000..171ed6f
--- /dev/null
+++ b/reflect/protoreflect/methods.go
@@ -0,0 +1,44 @@
+// Copyright 2020 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package protoreflect
+
+import (
+	"google.golang.org/protobuf/internal/pragma"
+)
+
+// The following types are used by the fast-path Message.ProtoMethods method.
+//
+// To avoid polluting the public protoreflect API with types used only by
+// low-level implementations, the canonical definitions of these types are
+// in the runtime/protoiface package. The definitions here and in protoiface
+// must be kept in sync.
+type (
+	methods = struct {
+		pragma.NoUnkeyedLiterals
+		Flags         supportFlags
+		Size          func(m Message, opts marshalOptions) int
+		MarshalAppend func(b []byte, m Message, opts marshalOptions) ([]byte, error)
+		Unmarshal     func(b []byte, m Message, opts unmarshalOptions) error
+		IsInitialized func(m Message) error
+	}
+	supportFlags   = uint64
+	marshalOptions = struct {
+		pragma.NoUnkeyedLiterals
+		AllowPartial  bool
+		Deterministic bool
+		UseCachedSize bool
+	}
+
+	unmarshalOptions = struct {
+		pragma.NoUnkeyedLiterals
+		Merge          bool
+		AllowPartial   bool
+		DiscardUnknown bool
+		Resolver       interface {
+			FindExtensionByName(field FullName) (ExtensionType, error)
+			FindExtensionByNumber(message FullName, field FieldNumber) (ExtensionType, error)
+		}
+	}
+)
diff --git a/reflect/protoreflect/value.go b/reflect/protoreflect/value.go
index e37a233..c7da263 100644
--- a/reflect/protoreflect/value.go
+++ b/reflect/protoreflect/value.go
@@ -150,6 +150,14 @@
 	// be preserved in marshaling or other operations.
 	IsValid() bool
 
+	// ProtoMethods returns optional fast-path implementions of various operations.
+	// This method may return nil.
+	//
+	// The returned methods type is identical to
+	// "google.golang.org/protobuf/runtime/protoiface".Methods.
+	// Consult the protoiface package documentation for details.
+	ProtoMethods() *methods
+
 	// TODO: Add method to retrieve ExtensionType by FieldNumber?
 }
 
diff --git a/runtime/protoiface/methods.go b/runtime/protoiface/methods.go
index b7ba129..4b9bb92 100644
--- a/runtime/protoiface/methods.go
+++ b/runtime/protoiface/methods.go
@@ -12,18 +12,10 @@
 import (
 	"google.golang.org/protobuf/internal/pragma"
 	"google.golang.org/protobuf/reflect/protoreflect"
-	"google.golang.org/protobuf/reflect/protoregistry"
 )
 
-// Methoder is an optional interface implemented by protoreflect.Message to
-// provide fast-path implementations of various operations.
-// The returned Methods struct must not be mutated.
-type Methoder interface {
-	ProtoMethods() *Methods // may return nil
-}
-
 // Methods is a set of optional fast-path implementations of various operations.
-type Methods struct {
+type Methods = struct {
 	pragma.NoUnkeyedLiterals
 
 	// Flags indicate support for optional features.
@@ -46,7 +38,7 @@
 	IsInitialized func(m protoreflect.Message) error
 }
 
-type SupportFlags uint64
+type SupportFlags = uint64
 
 const (
 	// SupportMarshalDeterministic reports whether MarshalOptions.Deterministic is supported.
@@ -59,7 +51,7 @@
 // MarshalOptions configure the marshaler.
 //
 // This type is identical to the one in package proto.
-type MarshalOptions struct {
+type MarshalOptions = struct {
 	pragma.NoUnkeyedLiterals
 
 	AllowPartial  bool // must be treated as true by method implementations
@@ -70,13 +62,14 @@
 // UnmarshalOptions configures the unmarshaler.
 //
 // This type is identical to the one in package proto.
-type UnmarshalOptions struct {
+type UnmarshalOptions = struct {
 	pragma.NoUnkeyedLiterals
 
 	Merge          bool // must be treated as true by method implementations
 	AllowPartial   bool // must be treated as true by method implementations
 	DiscardUnknown bool
 	Resolver       interface {
-		protoregistry.ExtensionTypeResolver
+		FindExtensionByName(field protoreflect.FullName) (protoreflect.ExtensionType, error)
+		FindExtensionByNumber(message protoreflect.FullName, field protoreflect.FieldNumber) (protoreflect.ExtensionType, error)
 	}
 }
diff --git a/types/dynamicpb/dynamic.go b/types/dynamicpb/dynamic.go
index 828a2be..4109128 100644
--- a/types/dynamicpb/dynamic.go
+++ b/types/dynamicpb/dynamic.go
@@ -10,7 +10,8 @@
 
 	"google.golang.org/protobuf/internal/errors"
 	pref "google.golang.org/protobuf/reflect/protoreflect"
-	protoimpl "google.golang.org/protobuf/runtime/protoimpl"
+	"google.golang.org/protobuf/runtime/protoiface"
+	"google.golang.org/protobuf/runtime/protoimpl"
 )
 
 // A Message is a dynamically constructed protocol buffer message.
@@ -76,6 +77,12 @@
 	return m
 }
 
+// ProtoMethods is an internal detail of the protoreflect.Message interface.
+// Users should never call this directly.
+func (m *Message) ProtoMethods() *protoiface.Methods {
+	return nil
+}
+
 // Range visits every populated field in undefined order.
 // See protoreflect.Message for details.
 func (m *Message) Range(f func(pref.FieldDescriptor, pref.Value) bool) {