all: drop reflect/prototype package

Remove the remaining uses of the prototype package.

The most significant change is to impl.MessageInfo, which now directly
implements the MessageType interface. This involves two notable changes
to exported fields of MessageInfo:

  - PBType is now Desc.
  - GoType is now GoReflectType. (Name changed to avoid a conflict with
    the GoType method of the MessageType interface.)

Fixes golang/protobuf#911

Change-Id: Ie2aa4766d6887ceaa9cf06b1f109aa6e6e2a208f
Reviewed-on: https://go-review.googlesource.com/c/protobuf/+/189340
Reviewed-by: Joe Tsai <thebrokentoaster@gmail.com>
diff --git a/internal/cmd/generate-types/impl.go b/internal/cmd/generate-types/impl.go
index e08e4d9..8be3e02 100644
--- a/internal/cmd/generate-types/impl.go
+++ b/internal/cmd/generate-types/impl.go
@@ -602,13 +602,13 @@
 var implMessageTemplate = template.Must(template.New("").Parse(`
 {{range . -}}
 func (m *{{.}}) Descriptor() protoreflect.MessageDescriptor {
-	return m.messageInfo().PBType.Descriptor()
+	return m.messageInfo().Desc
 }
 func (m *{{.}}) Type() protoreflect.MessageType {
-	return m.messageInfo().PBType
+	return m.messageInfo()
 }
 func (m *{{.}}) New() protoreflect.Message {
-	return m.messageInfo().PBType.New()
+	return m.messageInfo().New()
 }
 func (m *{{.}}) Interface() protoreflect.ProtoMessage {
 	{{if eq . "messageState" -}}
@@ -621,7 +621,7 @@
 	{{- end -}}
 }
 func (m *{{.}}) ProtoUnwrap() interface{} {
-	return m.pointer().AsIfaceOf(m.messageInfo().GoType.Elem())
+	return m.pointer().AsIfaceOf(m.messageInfo().GoReflectType.Elem())
 }
 func (m *{{.}}) ProtoMethods() *protoiface.Methods {
 	m.messageInfo().init()
diff --git a/internal/filetype/build.go b/internal/filetype/build.go
index 8d0e7bd..0237dea 100644
--- a/internal/filetype/build.go
+++ b/internal/filetype/build.go
@@ -15,7 +15,6 @@
 	pimpl "google.golang.org/protobuf/internal/impl"
 	pref "google.golang.org/protobuf/reflect/protoreflect"
 	preg "google.golang.org/protobuf/reflect/protoregistry"
-	ptype "google.golang.org/protobuf/reflect/prototype"
 	piface "google.golang.org/protobuf/runtime/protoiface"
 )
 
@@ -163,23 +162,18 @@
 		panic("mismatching message lengths")
 	}
 	if len(fbOut.Messages) > 0 {
-		messages := make([]Message, len(fbOut.Messages))
 		for i := range fbOut.Messages {
 			if messageGoTypes[i] == nil {
 				continue // skip map entry
 			}
-			messages[i] = Message{
-				MessageDescriptor: &fbOut.Messages[i],
-				NewMessage:        messageMaker(reflect.TypeOf(messageGoTypes[i])),
-			}
 
 			if tb.MessageInfos != nil {
-				tb.MessageInfos[i].GoType = reflect.TypeOf(messageGoTypes[i])
-				tb.MessageInfos[i].PBType = &messages[i]
+				tb.MessageInfos[i].GoReflectType = reflect.TypeOf(messageGoTypes[i])
+				tb.MessageInfos[i].Desc = &fbOut.Messages[i]
 			}
 
 			// Register message types.
-			if err := tb.TypeRegistry.Register(&messages[i]); err != nil {
+			if err := tb.TypeRegistry.Register(&tb.MessageInfos[i]); err != nil {
 				panic(err)
 			}
 		}
@@ -335,10 +329,6 @@
 	}
 }
 
-type (
-	Message = ptype.Message
-)
-
 type Extension struct {
 	desc       pref.ExtensionDescriptor
 	tdesc      extensionTypeDescriptor
diff --git a/internal/impl/api_export.go b/internal/impl/api_export.go
index d031d17..a149612 100644
--- a/internal/impl/api_export.go
+++ b/internal/impl/api_export.go
@@ -10,7 +10,6 @@
 
 	"google.golang.org/protobuf/encoding/prototext"
 	pref "google.golang.org/protobuf/reflect/protoreflect"
-	"google.golang.org/protobuf/reflect/prototype"
 	piface "google.golang.org/protobuf/runtime/protoiface"
 )
 
@@ -33,12 +32,7 @@
 // EnumTypeOf returns the protoreflect.EnumType for e.
 func (Export) EnumTypeOf(e enum) pref.EnumType {
 	if ev, ok := e.(pref.Enum); ok {
-		return &prototype.Enum{
-			EnumDescriptor: ev.Descriptor(),
-			NewEnum: func(n pref.EnumNumber) pref.Enum {
-				return reflect.ValueOf(n).Convert(reflect.TypeOf(e)).Interface().(pref.Enum)
-			},
-		}
+		return ev.Type()
 	}
 	return legacyLoadEnumType(reflect.TypeOf(e))
 }
@@ -76,14 +70,9 @@
 // MessageTypeOf returns the protoreflect.MessageType for m.
 func (Export) MessageTypeOf(m message) pref.MessageType {
 	if mv, ok := m.(pref.ProtoMessage); ok {
-		return &prototype.Message{
-			MessageDescriptor: mv.ProtoReflect().Descriptor(),
-			NewMessage: func() pref.Message {
-				return reflect.New(reflect.TypeOf(m).Elem()).Interface().(pref.ProtoMessage).ProtoReflect()
-			},
-		}
+		return mv.ProtoReflect().Type()
 	}
-	return legacyLoadMessageInfo(reflect.TypeOf(m)).PBType
+	return legacyLoadMessageInfo(reflect.TypeOf(m))
 }
 
 // MessageDescriptorOf returns the protoreflect.MessageDescriptor for m.
diff --git a/internal/impl/codec_field.go b/internal/impl/codec_field.go
index 9d587d2..16873e4 100644
--- a/internal/impl/codec_field.go
+++ b/internal/impl/codec_field.go
@@ -138,7 +138,7 @@
 		return 0, wire.ParseError(n)
 	}
 	if p.Elem().IsNil() {
-		p.SetPointer(pointerOfValue(reflect.New(mi.GoType.Elem())))
+		p.SetPointer(pointerOfValue(reflect.New(mi.GoReflectType.Elem())))
 	}
 	if _, err := mi.unmarshalPointer(v, p.Elem(), 0, opts); err != nil {
 		return 0, err
@@ -256,7 +256,7 @@
 		return 0, errUnknown
 	}
 	if p.Elem().IsNil() {
-		p.SetPointer(pointerOfValue(reflect.New(mi.GoType.Elem())))
+		p.SetPointer(pointerOfValue(reflect.New(mi.GoReflectType.Elem())))
 	}
 	return mi.unmarshalPointer(b, p.Elem(), num, opts)
 }
@@ -367,7 +367,7 @@
 	if n < 0 {
 		return 0, wire.ParseError(n)
 	}
-	m := reflect.New(mi.GoType.Elem()).Interface()
+	m := reflect.New(mi.GoReflectType.Elem()).Interface()
 	mp := pointerOfIface(m)
 	if _, err := mi.unmarshalPointer(v, mp, 0, opts); err != nil {
 		return 0, err
@@ -571,7 +571,7 @@
 	if wtyp != wire.StartGroupType {
 		return 0, errUnknown
 	}
-	m := reflect.New(mi.GoType.Elem()).Interface()
+	m := reflect.New(mi.GoReflectType.Elem()).Interface()
 	mp := pointerOfIface(m)
 	n, err := mi.unmarshalPointer(b, mp, num, opts)
 	if err != nil {
diff --git a/internal/impl/codec_message.go b/internal/impl/codec_message.go
index 7014861..d1e36dd 100644
--- a/internal/impl/codec_message.go
+++ b/internal/impl/codec_message.go
@@ -44,7 +44,7 @@
 	mi.extensionOffset = si.extensionOffset
 
 	mi.coderFields = make(map[wire.Number]*coderFieldInfo)
-	fields := mi.PBType.Descriptor().Fields()
+	fields := mi.Desc.Fields()
 	for i := 0; i < fields.Len(); i++ {
 		fd := fields.Get(i)
 
@@ -80,9 +80,9 @@
 		mi.orderedCoderFields = append(mi.orderedCoderFields, cf)
 		mi.coderFields[cf.num] = cf
 	}
-	if messageset.IsMessageSet(mi.PBType.Descriptor()) {
+	if messageset.IsMessageSet(mi.Desc) {
 		if !mi.extensionOffset.IsValid() {
-			panic(fmt.Sprintf("%v: MessageSet with no extensions field", mi.PBType.Descriptor().FullName()))
+			panic(fmt.Sprintf("%v: MessageSet with no extensions field", mi.Desc.FullName()))
 		}
 		cf := &coderFieldInfo{
 			num:       messageset.FieldItem,
@@ -114,7 +114,7 @@
 		mi.denseCoderFields[cf.num] = cf
 	}
 
-	mi.needsInitCheck = needsInitCheck(mi.PBType.Descriptor())
+	mi.needsInitCheck = needsInitCheck(mi.Desc)
 	mi.methods = piface.Methods{
 		Flags:         piface.SupportMarshalDeterministic | piface.SupportUnmarshalDiscardUnknown,
 		MarshalAppend: mi.marshalAppend,
diff --git a/internal/impl/decode.go b/internal/impl/decode.go
index 4821852..3bc25e0 100644
--- a/internal/impl/decode.go
+++ b/internal/impl/decode.go
@@ -138,7 +138,7 @@
 	xt := x.GetType()
 	if xt == nil {
 		var err error
-		xt, err = opts.Resolver().FindExtensionByNumber(mi.PBType.Descriptor().FullName(), num)
+		xt, err = opts.Resolver().FindExtensionByNumber(mi.Desc.FullName(), num)
 		if err != nil {
 			if err == preg.NotFound {
 				return 0, errUnknown
diff --git a/internal/impl/isinit.go b/internal/impl/isinit.go
index 079afe0..ffc65e9 100644
--- a/internal/impl/isinit.go
+++ b/internal/impl/isinit.go
@@ -29,7 +29,7 @@
 	if p.IsNil() {
 		for _, f := range mi.orderedCoderFields {
 			if f.isRequired {
-				return errors.RequiredNotSet(string(mi.PBType.Descriptor().Fields().ByNumber(f.num).FullName()))
+				return errors.RequiredNotSet(string(mi.Desc.Fields().ByNumber(f.num).FullName()))
 			}
 		}
 		return nil
@@ -47,7 +47,7 @@
 		fptr := p.Apply(f.offset)
 		if f.isPointer && fptr.Elem().IsNil() {
 			if f.isRequired {
-				return errors.RequiredNotSet(string(mi.PBType.Descriptor().Fields().ByNumber(f.num).FullName()))
+				return errors.RequiredNotSet(string(mi.Desc.Fields().ByNumber(f.num).FullName()))
 			}
 			continue
 		}
diff --git a/internal/impl/legacy_enum.go b/internal/impl/legacy_enum.go
index ffbdbeb..279baa9 100644
--- a/internal/impl/legacy_enum.go
+++ b/internal/impl/legacy_enum.go
@@ -13,7 +13,6 @@
 	"google.golang.org/protobuf/internal/filedesc"
 	"google.golang.org/protobuf/reflect/protoreflect"
 	pref "google.golang.org/protobuf/reflect/protoreflect"
-	"google.golang.org/protobuf/reflect/prototype"
 )
 
 // legacyWrapEnum wraps v as a protoreflect.Enum,
@@ -35,18 +34,10 @@
 
 	// Slow-path: derive enum descriptor and initialize EnumType.
 	var et pref.EnumType
-	var m sync.Map // map[protoreflect.EnumNumber]proto.Enum
 	ed := LegacyLoadEnumDesc(t)
-	et = &prototype.Enum{
-		EnumDescriptor: ed,
-		NewEnum: func(n pref.EnumNumber) pref.Enum {
-			if e, ok := m.Load(n); ok {
-				return e.(pref.Enum)
-			}
-			e := &legacyEnumWrapper{num: n, pbTyp: et, goTyp: t}
-			m.Store(n, e)
-			return e
-		},
+	et = &legacyEnumType{
+		desc:   ed,
+		goType: t,
 	}
 	if et, ok := legacyEnumTypeCache.LoadOrStore(t, et); ok {
 		return et.(pref.EnumType)
@@ -54,6 +45,27 @@
 	return et
 }
 
+type legacyEnumType struct {
+	desc   pref.EnumDescriptor
+	goType reflect.Type
+	m      sync.Map // map[protoreflect.EnumNumber]proto.Enum
+}
+
+func (t *legacyEnumType) New(n pref.EnumNumber) pref.Enum {
+	if e, ok := t.m.Load(n); ok {
+		return e.(pref.Enum)
+	}
+	e := &legacyEnumWrapper{num: n, pbTyp: t, goTyp: t.goType}
+	t.m.Store(n, e)
+	return e
+}
+func (t *legacyEnumType) GoType() reflect.Type {
+	return t.goType
+}
+func (t *legacyEnumType) Descriptor() pref.EnumDescriptor {
+	return t.desc
+}
+
 type legacyEnumWrapper struct {
 	num   pref.EnumNumber
 	pbTyp pref.EnumType
diff --git a/internal/impl/legacy_message.go b/internal/impl/legacy_message.go
index e4e446b..c70e30f 100644
--- a/internal/impl/legacy_message.go
+++ b/internal/impl/legacy_message.go
@@ -16,7 +16,6 @@
 	"google.golang.org/protobuf/internal/strs"
 	"google.golang.org/protobuf/reflect/protoreflect"
 	pref "google.golang.org/protobuf/reflect/protoreflect"
-	"google.golang.org/protobuf/reflect/prototype"
 )
 
 // legacyWrapMessage wraps v as a protoreflect.ProtoMessage,
@@ -37,19 +36,14 @@
 	}
 
 	// Slow-path: derive message descriptor and initialize MessageInfo.
-	md := LegacyLoadMessageDesc(t)
-	mt := new(MessageInfo)
-	mt.GoType = t
-	mt.PBType = &prototype.Message{
-		MessageDescriptor: md,
-		NewMessage: func() pref.Message {
-			return mt.MessageOf(reflect.New(t.Elem()).Interface())
-		},
+	mi := &MessageInfo{
+		Desc:          LegacyLoadMessageDesc(t),
+		GoReflectType: t,
 	}
-	if mt, ok := legacyMessageTypeCache.LoadOrStore(t, mt); ok {
-		return mt.(*MessageInfo)
+	if mi, ok := legacyMessageTypeCache.LoadOrStore(t, mi); ok {
+		return mi.(*MessageInfo)
 	}
-	return mt
+	return mi
 }
 
 var legacyMessageDescCache sync.Map // map[reflect.Type]protoreflect.MessageDescriptor
diff --git a/internal/impl/legacy_test.go b/internal/impl/legacy_test.go
index 89cd0bc..63b084d 100644
--- a/internal/impl/legacy_test.go
+++ b/internal/impl/legacy_test.go
@@ -78,14 +78,13 @@
 	testParentDesc    = pimpl.Export{}.MessageDescriptorOf((*LegacyTestMessage)(nil))
 	testEnumV1Desc    = pimpl.Export{}.EnumDescriptorOf(proto2_20180125.Message_ChildEnum(0))
 	testMessageV1Desc = pimpl.Export{}.MessageDescriptorOf((*proto2_20180125.Message_ChildMessage)(nil))
-	testEnumV2Desc    = enumProto2Type.Descriptor()
-	testMessageV2Desc = enumMessagesType.PBType.Descriptor()
+	testMessageV2Desc = enumMessagesType.Desc
 
 	depReg = preg.NewFiles(
 		testParentDesc.ParentFile(),
 		testEnumV1Desc.ParentFile(),
 		testMessageV1Desc.ParentFile(),
-		testEnumV2Desc.ParentFile(),
+		enumProto2Desc.ParentFile(),
 		testMessageV2Desc.ParentFile(),
 	)
 	extensionTypes = []pref.ExtensionType{
diff --git a/internal/impl/message.go b/internal/impl/message.go
index 6100663..9e1c3a3 100644
--- a/internal/impl/message.go
+++ b/internal/impl/message.go
@@ -12,6 +12,7 @@
 	"sync"
 	"sync/atomic"
 
+	"google.golang.org/protobuf/reflect/protoreflect"
 	pref "google.golang.org/protobuf/reflect/protoreflect"
 	piface "google.golang.org/protobuf/runtime/protoiface"
 )
@@ -20,13 +21,13 @@
 // that represents a message. A given instance of MessageInfo is tied to
 // exactly one Go type, which must be a pointer to a struct type.
 type MessageInfo struct {
-	// GoType is the underlying message Go type and must be populated.
+	// GoReflectType is the underlying message Go type and must be populated.
 	// Once set, this field must never be mutated.
-	GoType reflect.Type // pointer to struct
+	GoReflectType reflect.Type // pointer to struct
 
-	// PBType is the underlying message descriptor type and must be populated.
+	// Desc is the underlying message descriptor type and must be populated.
 	// Once set, this field must never be mutated.
-	PBType pref.MessageType
+	Desc pref.MessageDescriptor
 
 	// Exporter must be provided in a purego environment in order to provide
 	// access to unexported fields.
@@ -95,7 +96,7 @@
 		return
 	}
 
-	t := mi.GoType
+	t := mi.GoReflectType
 	if t.Kind() != reflect.Ptr && t.Elem().Kind() != reflect.Struct {
 		panic(fmt.Sprintf("got %v, want *struct kind", t))
 	}
@@ -222,7 +223,7 @@
 // any discrepancies.
 func (mi *MessageInfo) makeKnownFieldsFunc(si structInfo) {
 	mi.fields = map[pref.FieldNumber]*fieldInfo{}
-	md := mi.PBType.Descriptor()
+	md := mi.Desc
 	for i := 0; i < md.Fields().Len(); i++ {
 		fd := md.Fields().Get(i)
 		fs := si.fieldsByNumber[fd.Number()]
@@ -296,3 +297,14 @@
 		}
 	}
 }
+
+func (mi *MessageInfo) GoType() reflect.Type {
+	return mi.GoReflectType
+}
+func (mi *MessageInfo) New() protoreflect.Message {
+	return mi.MessageOf(reflect.New(mi.GoReflectType.Elem()).Interface())
+}
+func (mi *MessageInfo) Zero() protoreflect.Message {
+	return mi.MessageOf(reflect.Zero(mi.GoReflectType).Interface())
+}
+func (mi *MessageInfo) Descriptor() protoreflect.MessageDescriptor { return mi.Desc }
diff --git a/internal/impl/message_reflect.go b/internal/impl/message_reflect.go
index b0f1778..bb7d638 100644
--- a/internal/impl/message_reflect.go
+++ b/internal/impl/message_reflect.go
@@ -95,8 +95,8 @@
 // it must be implemented by calling this method.
 func (mi *MessageInfo) MessageOf(m interface{}) pref.Message {
 	// TODO: Switch the input to be an opaque Pointer.
-	if reflect.TypeOf(m) != mi.GoType {
-		panic(fmt.Sprintf("type mismatch: got %T, want %v", m, mi.GoType))
+	if reflect.TypeOf(m) != mi.GoReflectType {
+		panic(fmt.Sprintf("type mismatch: got %T, want %v", m, mi.GoReflectType))
 	}
 	p := pointerOfIface(m)
 	if p.IsNil() {
@@ -112,7 +112,7 @@
 	return (*messageReflectWrapper)(m)
 }
 func (m *messageIfaceWrapper) ProtoUnwrap() interface{} {
-	return m.p.AsIfaceOf(m.mi.GoType.Elem())
+	return m.p.AsIfaceOf(m.mi.GoReflectType.Elem())
 }
 
 type extensionMap map[int32]ExtensionField
@@ -181,11 +181,11 @@
 		return fi, nil
 	}
 	if fd.IsExtension() {
-		if fd.ContainingMessage().FullName() != mi.PBType.Descriptor().FullName() {
+		if fd.ContainingMessage().FullName() != mi.Desc.FullName() {
 			// TODO: Should this be exact containing message descriptor match?
 			panic("mismatching containing message")
 		}
-		if !mi.PBType.Descriptor().ExtensionRanges().Has(fd.Number()) {
+		if !mi.Desc.ExtensionRanges().Has(fd.Number()) {
 			panic("invalid extension field")
 		}
 		xtd, ok := fd.(pref.ExtensionTypeDescriptor)
diff --git a/internal/impl/message_reflect_gen.go b/internal/impl/message_reflect_gen.go
index a1c09b4..5376920 100644
--- a/internal/impl/message_reflect_gen.go
+++ b/internal/impl/message_reflect_gen.go
@@ -12,19 +12,19 @@
 )
 
 func (m *messageState) Descriptor() protoreflect.MessageDescriptor {
-	return m.messageInfo().PBType.Descriptor()
+	return m.messageInfo().Desc
 }
 func (m *messageState) Type() protoreflect.MessageType {
-	return m.messageInfo().PBType
+	return m.messageInfo()
 }
 func (m *messageState) New() protoreflect.Message {
-	return m.messageInfo().PBType.New()
+	return m.messageInfo().New()
 }
 func (m *messageState) Interface() protoreflect.ProtoMessage {
 	return m.ProtoUnwrap().(protoreflect.ProtoMessage)
 }
 func (m *messageState) ProtoUnwrap() interface{} {
-	return m.pointer().AsIfaceOf(m.messageInfo().GoType.Elem())
+	return m.pointer().AsIfaceOf(m.messageInfo().GoReflectType.Elem())
 }
 func (m *messageState) ProtoMethods() *protoiface.Methods {
 	m.messageInfo().init()
@@ -119,13 +119,13 @@
 }
 
 func (m *messageReflectWrapper) Descriptor() protoreflect.MessageDescriptor {
-	return m.messageInfo().PBType.Descriptor()
+	return m.messageInfo().Desc
 }
 func (m *messageReflectWrapper) Type() protoreflect.MessageType {
-	return m.messageInfo().PBType
+	return m.messageInfo()
 }
 func (m *messageReflectWrapper) New() protoreflect.Message {
-	return m.messageInfo().PBType.New()
+	return m.messageInfo().New()
 }
 func (m *messageReflectWrapper) Interface() protoreflect.ProtoMessage {
 	if m, ok := m.ProtoUnwrap().(protoreflect.ProtoMessage); ok {
@@ -134,7 +134,7 @@
 	return (*messageIfaceWrapper)(m)
 }
 func (m *messageReflectWrapper) ProtoUnwrap() interface{} {
-	return m.pointer().AsIfaceOf(m.messageInfo().GoType.Elem())
+	return m.pointer().AsIfaceOf(m.messageInfo().GoReflectType.Elem())
 }
 func (m *messageReflectWrapper) ProtoMethods() *protoiface.Methods {
 	m.messageInfo().init()
diff --git a/internal/impl/message_test.go b/internal/impl/message_test.go
index 0fb8ae0..de73ff9 100644
--- a/internal/impl/message_test.go
+++ b/internal/impl/message_test.go
@@ -21,7 +21,6 @@
 	pdesc "google.golang.org/protobuf/reflect/protodesc"
 	pref "google.golang.org/protobuf/reflect/protoreflect"
 	"google.golang.org/protobuf/reflect/protoregistry"
-	"google.golang.org/protobuf/reflect/prototype"
 
 	proto2_20180125 "google.golang.org/protobuf/internal/testprotos/legacy/proto2.v1.0.0-20180125-92554152"
 	testpb "google.golang.org/protobuf/internal/testprotos/test"
@@ -209,8 +208,7 @@
 	MapBytes   map[MyString]MyBytes
 )
 
-var scalarProto2Type = pimpl.MessageInfo{GoType: reflect.TypeOf(new(ScalarProto2)), PBType: &prototype.Message{
-	MessageDescriptor: mustMakeMessageDesc("scalar2.proto", pref.Proto2, "", `
+var scalarProto2Type = pimpl.MessageInfo{GoReflectType: reflect.TypeOf(new(ScalarProto2)), Desc: mustMakeMessageDesc("scalar2.proto", pref.Proto2, "", `
 		name: "ScalarProto2"
 		field: [
 			{name:"f1"  number:1  label:LABEL_OPTIONAL type:TYPE_BOOL   default_value:"true"},
@@ -238,10 +236,7 @@
 			{name:"f22" number:22 label:LABEL_OPTIONAL type:TYPE_BYTES  default_value:"22"}
 		]
 	`, nil),
-	NewMessage: func() pref.Message {
-		return pref.ProtoMessage(new(ScalarProto2)).ProtoReflect()
-	},
-}}
+}
 
 func (m *ScalarProto2) ProtoReflect() pref.Message { return scalarProto2Type.MessageOf(m) }
 
@@ -315,8 +310,7 @@
 	MyBytesA  MyString  `protobuf:"22"`
 }
 
-var scalarProto3Type = pimpl.MessageInfo{GoType: reflect.TypeOf(new(ScalarProto3)), PBType: &prototype.Message{
-	MessageDescriptor: mustMakeMessageDesc("scalar3.proto", pref.Proto3, "", `
+var scalarProto3Type = pimpl.MessageInfo{GoReflectType: reflect.TypeOf(new(ScalarProto3)), Desc: mustMakeMessageDesc("scalar3.proto", pref.Proto3, "", `
 		name: "ScalarProto3"
 		field: [
 			{name:"f1"  number:1  label:LABEL_OPTIONAL type:TYPE_BOOL},
@@ -344,10 +338,7 @@
 			{name:"f22" number:22 label:LABEL_OPTIONAL type:TYPE_BYTES}
 		]
 	`, nil),
-	NewMessage: func() pref.Message {
-		return pref.ProtoMessage(new(ScalarProto3)).ProtoReflect()
-	},
-}}
+}
 
 func (m *ScalarProto3) ProtoReflect() pref.Message { return scalarProto3Type.MessageOf(m) }
 
@@ -439,8 +430,7 @@
 	MyBytes4   ListStrings `protobuf:"19"`
 }
 
-var listScalarsType = pimpl.MessageInfo{GoType: reflect.TypeOf(new(ListScalars)), PBType: &prototype.Message{
-	MessageDescriptor: mustMakeMessageDesc("list-scalars.proto", pref.Proto2, "", `
+var listScalarsType = pimpl.MessageInfo{GoReflectType: reflect.TypeOf(new(ListScalars)), Desc: mustMakeMessageDesc("list-scalars.proto", pref.Proto2, "", `
 		name: "ListScalars"
 		field: [
 			{name:"f1"  number:1  label:LABEL_REPEATED type:TYPE_BOOL},
@@ -466,10 +456,7 @@
 			{name:"f19" number:19 label:LABEL_REPEATED type:TYPE_BYTES}
 		]
 	`, nil),
-	NewMessage: func() pref.Message {
-		return pref.ProtoMessage(new(ListScalars)).ProtoReflect()
-	},
-}}
+}
 
 func (m *ListScalars) ProtoReflect() pref.Message { return listScalarsType.MessageOf(m) }
 
@@ -596,8 +583,7 @@
 	MyBytes4   MapStrings `protobuf:"25"`
 }
 
-var mapScalarsType = pimpl.MessageInfo{GoType: reflect.TypeOf(new(MapScalars)), PBType: &prototype.Message{
-	MessageDescriptor: mustMakeMessageDesc("map-scalars.proto", pref.Proto2, "", `
+var mapScalarsType = pimpl.MessageInfo{GoReflectType: reflect.TypeOf(new(MapScalars)), Desc: mustMakeMessageDesc("map-scalars.proto", pref.Proto2, "", `
 		name: "MapScalars"
 		field: [
 			{name:"f1"  number:1  label:LABEL_REPEATED type:TYPE_MESSAGE type_name:".MapScalars.F1Entry"},
@@ -660,10 +646,7 @@
 			{name:"F25Entry" field:[{name:"key" number:1 label:LABEL_OPTIONAL type:TYPE_STRING}, {name:"value" number:2 label:LABEL_OPTIONAL type:TYPE_BYTES}]  options:{map_entry:true}}
 		]
 	`, nil),
-	NewMessage: func() pref.Message {
-		return pref.ProtoMessage(new(MapScalars)).ProtoReflect()
-	},
-}}
+}
 
 func (m *MapScalars) ProtoReflect() pref.Message { return mapScalarsType.MessageOf(m) }
 
@@ -790,8 +773,7 @@
 	Union isOneofScalars_Union `protobuf_oneof:"union"`
 }
 
-var oneofScalarsType = pimpl.MessageInfo{GoType: reflect.TypeOf(new(OneofScalars)), PBType: &prototype.Message{
-	MessageDescriptor: mustMakeMessageDesc("oneof-scalars.proto", pref.Proto2, "", `
+var oneofScalarsType = pimpl.MessageInfo{GoReflectType: reflect.TypeOf(new(OneofScalars)), Desc: mustMakeMessageDesc("oneof-scalars.proto", pref.Proto2, "", `
 		name: "OneofScalars"
 		field: [
 			{name:"f1"  number:1  label:LABEL_OPTIONAL type:TYPE_BOOL   default_value:"true" oneof_index:0},
@@ -810,10 +792,7 @@
 		]
 		oneof_decl: [{name:"union"}]
 	`, nil),
-	NewMessage: func() pref.Message {
-		return pref.ProtoMessage(new(OneofScalars)).ProtoReflect()
-	},
-}}
+}
 
 func (m *OneofScalars) ProtoReflect() pref.Message { return oneofScalarsType.MessageOf(m) }
 
@@ -952,37 +931,31 @@
 
 type EnumProto2 int32
 
-var enumProto2Type = &prototype.Enum{
-	EnumDescriptor: mustMakeEnumDesc("enum2.proto", pref.Proto2, `
-		name:  "EnumProto2"
-		value: [{name:"DEAD" number:0xdead}, {name:"BEEF" number:0xbeef}]
-	`),
-	NewEnum: func(n pref.EnumNumber) pref.Enum {
-		return EnumProto2(n)
-	},
-}
+var enumProto2Desc = mustMakeEnumDesc("enum2.proto", pref.Proto2, `
+	name:  "EnumProto2"
+	value: [{name:"DEAD" number:0xdead}, {name:"BEEF" number:0xbeef}]
+`)
 
-func (e EnumProto2) Descriptor() pref.EnumDescriptor { return enumProto2Type.Descriptor() }
-func (e EnumProto2) Type() pref.EnumType             { return enumProto2Type }
+func (e EnumProto2) Descriptor() pref.EnumDescriptor { return enumProto2Desc }
+func (e EnumProto2) Type() pref.EnumType             { return e }
 func (e EnumProto2) Enum() *EnumProto2               { return &e }
 func (e EnumProto2) Number() pref.EnumNumber         { return pref.EnumNumber(e) }
+func (t EnumProto2) GoType() reflect.Type            { return reflect.TypeOf(t) }
+func (t EnumProto2) New(n pref.EnumNumber) pref.Enum { return EnumProto2(n) }
 
 type EnumProto3 int32
 
-var enumProto3Type = &prototype.Enum{
-	EnumDescriptor: mustMakeEnumDesc("enum3.proto", pref.Proto3, `
-		name:  "EnumProto3",
-		value: [{name:"ALPHA" number:0}, {name:"BRAVO" number:1}]
-	`),
-	NewEnum: func(n pref.EnumNumber) pref.Enum {
-		return EnumProto3(n)
-	},
-}
+var enumProto3Desc = mustMakeEnumDesc("enum3.proto", pref.Proto3, `
+	name:  "EnumProto3",
+	value: [{name:"ALPHA" number:0}, {name:"BRAVO" number:1}]
+`)
 
-func (e EnumProto3) Descriptor() pref.EnumDescriptor { return enumProto3Type.Descriptor() }
-func (e EnumProto3) Type() pref.EnumType             { return enumProto3Type }
+func (e EnumProto3) Descriptor() pref.EnumDescriptor { return enumProto3Desc }
+func (e EnumProto3) Type() pref.EnumType             { return e }
 func (e EnumProto3) Enum() *EnumProto3               { return &e }
 func (e EnumProto3) Number() pref.EnumNumber         { return pref.EnumNumber(e) }
+func (t EnumProto3) GoType() reflect.Type            { return reflect.TypeOf(t) }
+func (t EnumProto3) New(n pref.EnumNumber) pref.Enum { return EnumProto3(n) }
 
 type EnumMessages struct {
 	EnumP2        *EnumProto2              `protobuf:"1"`
@@ -996,8 +969,7 @@
 	Union         isEnumMessages_Union     `protobuf_oneof:"union"`
 }
 
-var enumMessagesType = pimpl.MessageInfo{GoType: reflect.TypeOf(new(EnumMessages)), PBType: &prototype.Message{
-	MessageDescriptor: mustMakeMessageDesc("enum-messages.proto", pref.Proto2, `
+var enumMessagesType = pimpl.MessageInfo{GoReflectType: reflect.TypeOf(new(EnumMessages)), Desc: mustMakeMessageDesc("enum-messages.proto", pref.Proto2, `
 		dependency: ["enum2.proto", "enum3.proto", "scalar2.proto", "scalar3.proto", "proto2.v1.0.0-20180125-92554152/test.proto"]
 	`, `
 		name: "EnumMessages"
@@ -1021,16 +993,13 @@
 			{name:"F8Entry" field:[{name:"key" number:1 label:LABEL_OPTIONAL type:TYPE_STRING}, {name:"value" number:2 label:LABEL_OPTIONAL type:TYPE_MESSAGE type_name:".ScalarProto3"}] options:{map_entry:true}}
 		]
 	`, protoregistry.NewFiles(
-		EnumProto2(0).Descriptor().ParentFile(),
-		EnumProto3(0).Descriptor().ParentFile(),
-		((*ScalarProto2)(nil)).ProtoReflect().Descriptor().ParentFile(),
-		((*ScalarProto3)(nil)).ProtoReflect().Descriptor().ParentFile(),
-		pimpl.Export{}.MessageDescriptorOf((*proto2_20180125.Message)(nil)).ParentFile(),
-	)),
-	NewMessage: func() pref.Message {
-		return pref.ProtoMessage(new(EnumMessages)).ProtoReflect()
-	},
-}}
+	EnumProto2(0).Descriptor().ParentFile(),
+	EnumProto3(0).Descriptor().ParentFile(),
+	((*ScalarProto2)(nil)).ProtoReflect().Descriptor().ParentFile(),
+	((*ScalarProto3)(nil)).ProtoReflect().Descriptor().ParentFile(),
+	pimpl.Export{}.MessageDescriptorOf((*proto2_20180125.Message)(nil)).ParentFile(),
+)),
+}
 
 func (m *EnumMessages) ProtoReflect() pref.Message { return enumMessagesType.MessageOf(m) }
 
diff --git a/internal/impl/pointer_reflect.go b/internal/impl/pointer_reflect.go
index 7b4510a..74345ec 100644
--- a/internal/impl/pointer_reflect.go
+++ b/internal/impl/pointer_reflect.go
@@ -170,7 +170,7 @@
 
 func (m *atomicNilMessage) Init(mi *MessageInfo) *messageReflectWrapper {
 	m.once.Do(func() {
-		m.m.p = pointerOfIface(reflect.Zero(mi.GoType).Interface())
+		m.m.p = pointerOfIface(reflect.Zero(mi.GoReflectType).Interface())
 		m.m.mi = mi
 	})
 	return &m.m
diff --git a/internal/testprotos/irregular/irregular.go b/internal/testprotos/irregular/irregular.go
index ec44589..8127f0b 100644
--- a/internal/testprotos/irregular/irregular.go
+++ b/internal/testprotos/irregular/irregular.go
@@ -5,10 +5,11 @@
 package irregular
 
 import (
+	"reflect"
+
 	"google.golang.org/protobuf/encoding/prototext"
 	"google.golang.org/protobuf/reflect/protodesc"
 	pref "google.golang.org/protobuf/reflect/protoreflect"
-	"google.golang.org/protobuf/reflect/prototype"
 
 	"google.golang.org/protobuf/types/descriptorpb"
 )
@@ -22,16 +23,11 @@
 
 type message IrregularMessage
 
-var messageType = &prototype.Message{
-	MessageDescriptor: fileDesc.Messages().Get(0),
-	NewMessage: func() pref.Message {
-		return &message{}
-	},
-}
-
-func (m *message) Descriptor() pref.MessageDescriptor { return messageType.Descriptor() }
-func (m *message) Type() pref.MessageType             { return messageType }
+func (m *message) Descriptor() pref.MessageDescriptor { return fileDesc.Messages().Get(0) }
+func (m *message) Type() pref.MessageType             { return m }
 func (m *message) New() pref.Message                  { return &message{} }
+func (m *message) Zero() pref.Message                 { return (*message)(nil) }
+func (m *message) GoType() reflect.Type               { return reflect.TypeOf(&message{}) }
 func (m *message) Interface() pref.ProtoMessage       { return (*IrregularMessage)(m) }
 
 var fieldDescS = fileDesc.Messages().Get(0).Fields().Get(0)
diff --git a/proto/decode_test.go b/proto/decode_test.go
index c2b5ce9..9819838 100644
--- a/proto/decode_test.go
+++ b/proto/decode_test.go
@@ -16,7 +16,6 @@
 	"google.golang.org/protobuf/proto"
 	"google.golang.org/protobuf/reflect/protodesc"
 	"google.golang.org/protobuf/reflect/protoreflect"
-	"google.golang.org/protobuf/reflect/prototype"
 	"google.golang.org/protobuf/runtime/protoiface"
 	"google.golang.org/protobuf/runtime/protoimpl"
 
@@ -1614,11 +1613,10 @@
 }
 
 var messageInfo_TestNoEnforceUTF8 = protoimpl.MessageInfo{
-	GoType: reflect.TypeOf((*TestNoEnforceUTF8)(nil)),
-	PBType: &prototype.Message{
-		MessageDescriptor: func() protoreflect.MessageDescriptor {
-			pb := new(descriptorpb.FileDescriptorProto)
-			if err := prototext.Unmarshal([]byte(`
+	GoReflectType: reflect.TypeOf((*TestNoEnforceUTF8)(nil)),
+	Desc: func() protoreflect.MessageDescriptor {
+		pb := new(descriptorpb.FileDescriptorProto)
+		if err := prototext.Unmarshal([]byte(`
 				syntax:  "proto3"
 				name:    "test.proto"
 				message_type: [{
@@ -1634,23 +1632,19 @@
 					oneof_decl: [{name:"oneof_field"}]
 				}]
 			`), pb); err != nil {
-				panic(err)
-			}
-			fd, err := protodesc.NewFile(pb, nil)
-			if err != nil {
-				panic(err)
-			}
-			md := fd.Messages().Get(0)
-			for i := 0; i < md.Fields().Len(); i++ {
-				md.Fields().Get(i).(*filedesc.Field).L1.HasEnforceUTF8 = true
-				md.Fields().Get(i).(*filedesc.Field).L1.EnforceUTF8 = false
-			}
-			return md
-		}(),
-		NewMessage: func() protoreflect.Message {
-			return protoreflect.ProtoMessage(new(TestNoEnforceUTF8)).ProtoReflect()
-		},
-	},
+			panic(err)
+		}
+		fd, err := protodesc.NewFile(pb, nil)
+		if err != nil {
+			panic(err)
+		}
+		md := fd.Messages().Get(0)
+		for i := 0; i < md.Fields().Len(); i++ {
+			md.Fields().Get(i).(*filedesc.Field).L1.HasEnforceUTF8 = true
+			md.Fields().Get(i).(*filedesc.Field).L1.EnforceUTF8 = false
+		}
+		return md
+	}(),
 	OneofWrappers: []interface{}{
 		(*TestNoEnforceUTF8_OneofString)(nil),
 		(*TestNoEnforceUTF8_OneofBytes)(nil),
diff --git a/reflect/prototype/type.go b/reflect/prototype/type.go
deleted file mode 100644
index cc36eaa..0000000
--- a/reflect/prototype/type.go
+++ /dev/null
@@ -1,118 +0,0 @@
-// 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 prototype provides constructors for protoreflect.EnumType,
-// protoreflect.MessageType, and protoreflect.ExtensionType.
-package prototype
-
-import (
-	"fmt"
-	"reflect"
-	"sync"
-
-	"google.golang.org/protobuf/internal/descfmt"
-	"google.golang.org/protobuf/reflect/protoreflect"
-)
-
-// Enum is a protoreflect.EnumType which combines a
-// protoreflect.EnumDescriptor with a constructor function.
-//
-// Both EnumDescriptor and NewEnum must be populated.
-// Once constructed, the exported fields must not be modified.
-type Enum struct {
-	protoreflect.EnumDescriptor
-
-	// NewEnum constructs a new protoreflect.Enum representing the provided
-	// enum number. The returned Go type must be identical for every call.
-	NewEnum func(protoreflect.EnumNumber) protoreflect.Enum
-
-	once   sync.Once
-	goType reflect.Type
-}
-
-func (t *Enum) New(n protoreflect.EnumNumber) protoreflect.Enum {
-	e := t.NewEnum(n)
-	t.once.Do(func() {
-		t.goType = reflect.TypeOf(e)
-		if e.Descriptor() != t.Descriptor() {
-			panic(fmt.Sprintf("mismatching enum descriptor: got %v, want %v", e.Descriptor(), t.Descriptor()))
-		}
-		if e.Descriptor().IsPlaceholder() {
-			panic("enum descriptor must not be a placeholder")
-		}
-	})
-	if t.goType != reflect.TypeOf(e) {
-		panic(fmt.Sprintf("mismatching types for enum: got %T, want %v", e, t.goType))
-	}
-	return e
-}
-
-func (t *Enum) GoType() reflect.Type {
-	t.New(0) // initialize t.typ
-	return t.goType
-}
-
-func (t *Enum) Descriptor() protoreflect.EnumDescriptor {
-	return t.EnumDescriptor
-}
-
-func (t *Enum) Format(s fmt.State, r rune) {
-	descfmt.FormatDesc(s, r, t)
-}
-
-// Message is a protoreflect.MessageType which combines a
-// protoreflect.MessageDescriptor with a constructor function.
-//
-// Both MessageDescriptor and NewMessage must be populated.
-// Once constructed, the exported fields must not be modified.
-type Message struct {
-	protoreflect.MessageDescriptor
-
-	// NewMessage constructs an empty, newly allocated protoreflect.Message.
-	// The returned Go type must be identical for every call.
-	NewMessage func() protoreflect.Message
-
-	once   sync.Once
-	goType reflect.Type
-}
-
-func (t *Message) New() protoreflect.Message {
-	m := t.NewMessage()
-	mi := m.Interface()
-	t.once.Do(func() {
-		t.goType = reflect.TypeOf(mi)
-		if m.Descriptor() != t.Descriptor() {
-			panic(fmt.Sprintf("mismatching message descriptor: got %v, want %v", m.Descriptor(), t.Descriptor()))
-		}
-		if m.Descriptor().IsPlaceholder() {
-			panic("message descriptor must not be a placeholder")
-		}
-	})
-	if t.goType != reflect.TypeOf(mi) {
-		panic(fmt.Sprintf("mismatching types for message: got %T, want %v", mi, t.goType))
-	}
-	return m
-}
-
-func (t *Message) Zero() protoreflect.Message {
-	return t.New() // TODO: return a read-only message instead
-}
-
-func (t *Message) GoType() reflect.Type {
-	t.New() // initialize t.goType
-	return t.goType
-}
-
-func (t *Message) Descriptor() protoreflect.MessageDescriptor {
-	return t.MessageDescriptor
-}
-
-func (t *Message) Format(s fmt.State, r rune) {
-	descfmt.FormatDesc(s, r, t)
-}
-
-var (
-	_ protoreflect.EnumType    = (*Enum)(nil)
-	_ protoreflect.MessageType = (*Message)(nil)
-)
diff --git a/types/dynamicpb/dynamic.go b/types/dynamicpb/dynamic.go
index fa9155b..64efbe1 100644
--- a/types/dynamicpb/dynamic.go
+++ b/types/dynamicpb/dynamic.go
@@ -7,10 +7,10 @@
 
 import (
 	"math"
+	"reflect"
 
 	"google.golang.org/protobuf/internal/errors"
 	pref "google.golang.org/protobuf/reflect/protoreflect"
-	"google.golang.org/protobuf/reflect/prototype"
 	protoimpl "google.golang.org/protobuf/runtime/protoimpl"
 )
 
@@ -30,7 +30,7 @@
 //
 // Operations which modify a Message are not safe for concurrent use.
 type Message struct {
-	typ     prototype.Message
+	desc    pref.MessageDescriptor
 	known   map[pref.FieldNumber]pref.Value
 	ext     map[pref.FieldNumber]pref.FieldDescriptor
 	unknown pref.RawFields
@@ -39,10 +39,7 @@
 // New creates a new message with the provided descriptor.
 func New(desc pref.MessageDescriptor) *Message {
 	return &Message{
-		typ: prototype.Message{
-			MessageDescriptor: desc,
-			NewMessage:        func() pref.Message { return New(desc) },
-		},
+		desc:  desc,
 		known: make(map[pref.FieldNumber]pref.Value),
 		ext:   make(map[pref.FieldNumber]pref.FieldDescriptor),
 	}
@@ -60,12 +57,12 @@
 
 // Descriptor returns the message descriptor.
 func (m *Message) Descriptor() pref.MessageDescriptor {
-	return m.typ.Descriptor()
+	return m.desc
 }
 
 // Type returns the message type.
 func (m *Message) Type() pref.MessageType {
-	return &m.typ
+	return (*messageType)(m)
 }
 
 // New returns a newly allocated empty message with the same descriptor.
@@ -273,6 +270,13 @@
 	}
 }
 
+type messageType Message
+
+func (mt *messageType) New() pref.Message                  { return New(mt.desc) }
+func (mt *messageType) Zero() pref.Message                 { return New(mt.desc) }
+func (mt *messageType) GoType() reflect.Type               { return reflect.TypeOf((*Message)(nil)) }
+func (mt *messageType) Descriptor() pref.MessageDescriptor { return mt.desc }
+
 type emptyList struct {
 	desc pref.FieldDescriptor
 }