all: unify protoV1.ExtensionDesc and proto.ExtensionType

Change protoV1.ExtensionDesc to directly implement ExtensionType
rather than delegating to one.

Unify the previous types protoiface.ExtensionDescV1 and
filetype.Extension in impl.ExtensionInfo. The protoV1.ExtensionDesc
type becomes an alias to ExtensionInfo.

This gives us:

  - Just one implementation of ExtensionType.
  - Generated foopb.E_Ext vars are canonical ExtensionTypes.
  - Generated foopb.E_Ext vars are also v1.ExtensionDescs for backwards
    compatibility.
  - Conversion between legacy and modern representations happens
    transparently when lazily initializing an ExtensionInfo.

Overall, a simplification for users of generated code, since they can
mostly ignore the ExtensionDesc/ExtentionType distinction and use the
same value in either the old or new API.

This is change 3/5 in a series of commits changing protoV1.ExtensionDesc
to directly implement protoreflect.ExtensionType.

1. [v2] Add protoimpl.ExtensionInfo as an alias for
   protoiface.ExtensionDescV1.

2. [v1] Update references to protoimpl.ExtensionInfo to use
   protoiface.ExtensionInfo.

3. [v2] Create protoimpl.ExtensionInfo (an alias to a new type in
   the impl package) and remove protoiface.ExtensionDescV1.

4. [v1] Remove unneeded explicit conversions between ExtensionDesc and
   ExtensionType (since the former now directly implements the latter).

5. [v2] Remove stub conversion functions.

Change-Id: I96ee890541ec11b2412e1a72c9d7b96e4d7f66b4
Reviewed-on: https://go-review.googlesource.com/c/protobuf/+/189563
Reviewed-by: Joe Tsai <thebrokentoaster@gmail.com>
diff --git a/internal/impl/extension.go b/internal/impl/extension.go
new file mode 100644
index 0000000..e7083e5
--- /dev/null
+++ b/internal/impl/extension.go
@@ -0,0 +1,172 @@
+// Copyright 2019 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 impl
+
+import (
+	"reflect"
+	"sync"
+	"sync/atomic"
+
+	pref "google.golang.org/protobuf/reflect/protoreflect"
+	piface "google.golang.org/protobuf/runtime/protoiface"
+)
+
+// ExtensionInfo implements ExtensionType.
+//
+// This type contains a number of exported fields for legacy compatibility.
+// The only non-deprecated use of this type is through the methods of the
+// ExtensionType interface.
+type ExtensionInfo struct {
+	// An ExtensionInfo may exist in several stages of initialization.
+	//
+	// extensionInfoUninitialized: Some or all of the legacy exported
+	// fields may be set, but none of the unexported fields have been
+	// initialized. This is the starting state for an ExtensionInfo
+	// in legacy generated code.
+	//
+	// extensionInfoDescInit: The desc and tdesc fields have been
+	// set, but the descriptor is not otherwise initialized. Legacy
+	// exported fields may or may not be set. This is the starting state
+	// for an ExtensionInfo in new generated code. Calling the Descriptor
+	// method will not trigger lazy initialization, although any other
+	// method will.
+	//
+	// extensionInfoFullInit: The ExtensionInfo is fully initialized.
+	// This state is only entered after lazy initialization is complete.
+	init uint32
+	mu   sync.Mutex
+
+	desc   pref.ExtensionDescriptor
+	tdesc  extensionTypeDescriptor
+	goType reflect.Type
+	conv   Converter
+
+	// TODO: Remove after updating v2 to not set this.
+	Type interface{}
+
+	// ExtendedType is a typed nil-pointer to the parent message type that
+	// is being extended. It is possible for this to be unpopulated in v2
+	// since the message may no longer implement the MessageV1 interface.
+	//
+	// Deprecated: Use the ExtendedType method instead.
+	ExtendedType piface.MessageV1
+
+	// ExtensionType is zero value of the extension type.
+	//
+	// For historical reasons, reflect.TypeOf(ExtensionType) and Type.GoType
+	// may not be identical:
+	//	* for scalars (except []byte), where ExtensionType uses *T,
+	//	while Type.GoType uses T.
+	//	* for repeated fields, where ExtensionType uses []T,
+	//	while Type.GoType uses *[]T.
+	//
+	// Deprecated: Use the GoType method instead.
+	ExtensionType interface{}
+
+	// Field is the field number of the extension.
+	//
+	// Deprecated: Use the Descriptor().Number method instead.
+	Field int32
+
+	// Name is the fully qualified name of extension.
+	//
+	// Deprecated: Use the Descriptor().FullName method instead.
+	Name string
+
+	// Tag is the protobuf struct tag used in the v1 API.
+	//
+	// Deprecated: Do not use.
+	Tag string
+
+	// Filename is the proto filename in which the extension is defined.
+	//
+	// Deprecated: Use Descriptor().ParentFile().Path() instead.
+	Filename string
+}
+
+// Stages of initialization: See the ExtensionInfo.init field.
+const (
+	extensionInfoUninitialized = 0
+	extensionInfoDescInit      = 1
+	extensionInfoFullInit      = 2
+)
+
+func InitExtensionInfo(xi *ExtensionInfo, xd pref.ExtensionDescriptor, goType reflect.Type) {
+	if xi.desc != nil {
+		return
+	}
+	xi.desc = xd
+	xi.goType = goType
+
+	xi.tdesc.ExtensionDescriptor = xi.desc
+	xi.tdesc.xi = xi
+	xi.init = extensionInfoDescInit
+}
+
+func (xi *ExtensionInfo) New() pref.Value {
+	return xi.lazyInit().New()
+}
+func (xi *ExtensionInfo) Zero() pref.Value {
+	return xi.lazyInit().Zero()
+}
+func (xi *ExtensionInfo) ValueOf(v interface{}) pref.Value {
+	return xi.lazyInit().PBValueOf(reflect.ValueOf(v))
+}
+func (xi *ExtensionInfo) InterfaceOf(v pref.Value) interface{} {
+	return xi.lazyInit().GoValueOf(v).Interface()
+}
+func (xi *ExtensionInfo) GoType() reflect.Type {
+	xi.lazyInit()
+	return xi.goType
+}
+func (xi *ExtensionInfo) Descriptor() pref.ExtensionTypeDescriptor {
+	if atomic.LoadUint32(&xi.init) == extensionInfoUninitialized {
+		xi.lazyInitSlow()
+	}
+	return &xi.tdesc
+}
+
+func (xi *ExtensionInfo) lazyInit() Converter {
+	if atomic.LoadUint32(&xi.init) != extensionInfoFullInit {
+		xi.lazyInitSlow()
+	}
+	return xi.conv
+}
+
+func (xi *ExtensionInfo) lazyInitSlow() {
+	xi.mu.Lock()
+	defer xi.mu.Unlock()
+
+	if xi.init == extensionInfoFullInit {
+		return
+	}
+	atomic.StoreUint32(&xi.init, extensionInfoFullInit)
+
+	if xi.desc == nil {
+		xi.initFromLegacy()
+	} else if xi.desc.Cardinality() == pref.Repeated {
+		// Cardinality is initialized lazily, so we defer consulting it until here.
+		xi.goType = reflect.PtrTo(reflect.SliceOf(xi.goType))
+	}
+	xi.conv = NewConverter(xi.goType, xi.desc)
+	xi.tdesc.ExtensionDescriptor = xi.desc
+	xi.tdesc.xi = xi
+
+	if xi.ExtensionType == nil {
+		xi.initToLegacy()
+	}
+}
+
+type extensionTypeDescriptor struct {
+	pref.ExtensionDescriptor
+	xi *ExtensionInfo
+}
+
+func (xtd *extensionTypeDescriptor) Type() pref.ExtensionType {
+	return xtd.xi
+}
+func (xtd *extensionTypeDescriptor) Descriptor() pref.ExtensionDescriptor {
+	return xtd.ExtensionDescriptor
+}