all: refactor extensions, add proto.GetExtension etc.

Change protoiface.ExtensionDescV1 to implement protoreflect.ExtensionType.

ExtensionDescV1's Name field conflicts with the Descriptor Name method,
so change the protoreflect.{Message,Enum,Extension}Type types to no
longer implement the corresponding Descriptor interface. This also leads
to a clearer distinction between the two types.

Introduce a protoreflect.ExtensionTypeDescriptor type which bridges
between ExtensionType and ExtensionDescriptor.

Add extension accessor functions to the proto package:
proto.{Has,Clear,Get,Set}Extension. These functions take a
protoreflect.ExtensionType parameter, which allows writing the
same function call using either the old or new API:

  proto.GetExtension(message, somepb.E_ExtensionFoo)

Fixes golang/protobuf#908

Change-Id: Ibc65d12a46666297849114fd3aefbc4a597d9f08
Reviewed-on: https://go-review.googlesource.com/c/protobuf/+/189199
Reviewed-by: Joe Tsai <thebrokentoaster@gmail.com>
diff --git a/internal/impl/legacy_extension.go b/internal/impl/legacy_extension.go
index aaf8fcc..2da4d71 100644
--- a/internal/impl/legacy_extension.go
+++ b/internal/impl/legacy_extension.go
@@ -5,11 +5,9 @@
 package impl
 
 import (
-	"fmt"
 	"reflect"
 	"sync"
 
-	"google.golang.org/protobuf/internal/descfmt"
 	ptag "google.golang.org/protobuf/internal/encoding/tag"
 	"google.golang.org/protobuf/internal/filedesc"
 	pref "google.golang.org/protobuf/reflect/protoreflect"
@@ -62,8 +60,9 @@
 	}
 
 	// Determine the parent type if possible.
+	xd := xt.Descriptor()
 	var parent piface.MessageV1
-	messageName := xt.ContainingMessage().FullName()
+	messageName := xd.ContainingMessage().FullName()
 	if mt, _ := preg.GlobalTypes.FindMessageByName(messageName); mt != nil {
 		// Create a new parent message and unwrap it if possible.
 		mv := mt.New().Interface()
@@ -94,7 +93,7 @@
 	// Reconstruct the legacy enum full name, which is an odd mixture of the
 	// proto package name with the Go type name.
 	var enumName string
-	if xt.Kind() == pref.EnumKind {
+	if xd.Kind() == pref.EnumKind {
 		// Derive Go type name.
 		t := extType
 		if t.Kind() == reflect.Ptr || t.Kind() == reflect.Slice {
@@ -105,7 +104,7 @@
 		// Derive the proto package name.
 		// For legacy enums, obtain the proto package from the raw descriptor.
 		var protoPkg string
-		if fd := xt.Enum().ParentFile(); fd != nil {
+		if fd := xd.Enum().ParentFile(); fd != nil {
 			protoPkg = string(fd.Package())
 		}
 		if ed, ok := reflect.Zero(t).Interface().(enumV1); ok && protoPkg == "" {
@@ -120,7 +119,7 @@
 
 	// Derive the proto file that the extension was declared within.
 	var filename string
-	if fd := xt.ParentFile(); fd != nil {
+	if fd := xd.ParentFile(); fd != nil {
 		filename = fd.Path()
 	}
 
@@ -129,9 +128,9 @@
 		Type:          xt,
 		ExtendedType:  parent,
 		ExtensionType: reflect.Zero(extType).Interface(),
-		Field:         int32(xt.Number()),
-		Name:          string(xt.FullName()),
-		Tag:           ptag.Marshal(xt, enumName),
+		Field:         int32(xd.Number()),
+		Name:          string(xd.FullName()),
+		Tag:           ptag.Marshal(xd, enumName),
 		Filename:      filename,
 	}
 	if d, ok := legacyExtensionDescCache.LoadOrStore(xt, d); ok {
@@ -217,15 +216,16 @@
 //
 // This is exported for testing purposes.
 func LegacyExtensionTypeOf(xd pref.ExtensionDescriptor, t reflect.Type) pref.ExtensionType {
-	return &legacyExtensionType{
-		ExtensionDescriptor: xd,
-		typ:                 t,
-		conv:                NewConverter(t, xd),
+	xt := &legacyExtensionType{
+		typ:  t,
+		conv: NewConverter(t, xd),
 	}
+	xt.desc = &extDesc{xd, xt}
+	return xt
 }
 
 type legacyExtensionType struct {
-	pref.ExtensionDescriptor
+	desc pref.ExtensionTypeDescriptor
 	typ  reflect.Type
 	conv Converter
 }
@@ -239,5 +239,12 @@
 func (x *legacyExtensionType) InterfaceOf(v pref.Value) interface{} {
 	return x.conv.GoValueOf(v).Interface()
 }
-func (x *legacyExtensionType) Descriptor() pref.ExtensionDescriptor { return x.ExtensionDescriptor }
-func (x *legacyExtensionType) Format(s fmt.State, r rune)           { descfmt.FormatDesc(s, r, x) }
+func (x *legacyExtensionType) Descriptor() pref.ExtensionTypeDescriptor { return x.desc }
+
+type extDesc struct {
+	pref.ExtensionDescriptor
+	xt *legacyExtensionType
+}
+
+func (t *extDesc) Type() pref.ExtensionType             { return t.xt }
+func (t *extDesc) Descriptor() pref.ExtensionDescriptor { return t.ExtensionDescriptor }