internal/filedesc, internal/filetype: initial commit

The internal/fileinit package is split apart into two packages:
* internal/filedesc constructs descriptors from the raw proto.
It is very similar to the previous internal/fileinit package.
* internal/filetype wraps descriptors with Go type information

Overview:
* The internal/fileinit package will be deleted in a future CL.
It is kept around since the v1 repo currently depends on it.
* The internal/prototype package is deleted. All former usages of it
are now using internal/filedesc instead. Most significantly,
the reflect/protodesc package was almost entirely re-written.
* The internal/impl package drops support for messages that do not
have a Descriptor method (pre-2016). This removes a significant amount
of technical debt.
filedesc.Builder to parse raw descriptors.
* The internal/encoding/defval package now handles enum values by name.

Change-Id: I3957bcc8588a70470fd6c7de1122216b80615ab7
Reviewed-on: https://go-review.googlesource.com/c/protobuf/+/182360
Reviewed-by: Damien Neil <dneil@google.com>
diff --git a/cmd/protoc-gen-go-grpc/testdata/grpc/deprecation.pb.go b/cmd/protoc-gen-go-grpc/testdata/grpc/deprecation.pb.go
index 33c525e..8a1a6a4 100644
--- a/cmd/protoc-gen-go-grpc/testdata/grpc/deprecation.pb.go
+++ b/cmd/protoc-gen-go-grpc/testdata/grpc/deprecation.pb.go
@@ -5,7 +5,6 @@
 
 import (
 	protoreflect "google.golang.org/protobuf/reflect/protoreflect"
-	protoregistry "google.golang.org/protobuf/reflect/protoregistry"
 	protoimpl "google.golang.org/protobuf/runtime/protoimpl"
 	sync "sync"
 )
@@ -57,6 +56,11 @@
 var file_grpc_deprecation_proto_depIdxs = []int32{
 	0, // goproto.protoc.grpc.DeprecatedService.DeprecatedCall:input_type -> goproto.protoc.grpc.Request
 	1, // goproto.protoc.grpc.DeprecatedService.DeprecatedCall:output_type -> goproto.protoc.grpc.Response
+	1, // starting offset of method output_type sub-list
+	0, // starting offset of method input_type sub-list
+	0, // starting offset of extension type_name sub-list
+	0, // starting offset of extension extendee sub-list
+	0, // starting offset of field type_name sub-list
 }
 
 func init() { file_grpc_deprecation_proto_init() }
@@ -65,13 +69,18 @@
 		return
 	}
 	file_grpc_grpc_proto_init()
-	File_grpc_deprecation_proto = protoimpl.FileBuilder{
-		RawDescriptor:     file_grpc_deprecation_proto_rawDesc,
+	out := protoimpl.TypeBuilder{
+		File: protoimpl.DescBuilder{
+			RawDescriptor: file_grpc_deprecation_proto_rawDesc,
+			NumEnums:      0,
+			NumMessages:   0,
+			NumExtensions: 0,
+			NumServices:   1,
+		},
 		GoTypes:           file_grpc_deprecation_proto_goTypes,
 		DependencyIndexes: file_grpc_deprecation_proto_depIdxs,
-		FilesRegistry:     protoregistry.GlobalFiles,
-		TypesRegistry:     protoregistry.GlobalTypes,
-	}.Init()
+	}.Build()
+	File_grpc_deprecation_proto = out.File
 	file_grpc_deprecation_proto_rawDesc = nil
 	file_grpc_deprecation_proto_goTypes = nil
 	file_grpc_deprecation_proto_depIdxs = nil
diff --git a/cmd/protoc-gen-go-grpc/testdata/grpc/grpc.pb.go b/cmd/protoc-gen-go-grpc/testdata/grpc/grpc.pb.go
index 8a047bb..77bcc61 100644
--- a/cmd/protoc-gen-go-grpc/testdata/grpc/grpc.pb.go
+++ b/cmd/protoc-gen-go-grpc/testdata/grpc/grpc.pb.go
@@ -5,7 +5,6 @@
 
 import (
 	protoreflect "google.golang.org/protobuf/reflect/protoreflect"
-	protoregistry "google.golang.org/protobuf/reflect/protoregistry"
 	protoiface "google.golang.org/protobuf/runtime/protoiface"
 	protoimpl "google.golang.org/protobuf/runtime/protoimpl"
 	sync "sync"
@@ -129,13 +128,18 @@
 }
 var file_grpc_grpc_proto_depIdxs = []int32{
 	0, // goproto.protoc.grpc.test_service.unary_call:input_type -> goproto.protoc.grpc.Request
-	1, // goproto.protoc.grpc.test_service.unary_call:output_type -> goproto.protoc.grpc.Response
 	0, // goproto.protoc.grpc.test_service.downstream_call:input_type -> goproto.protoc.grpc.Request
-	1, // goproto.protoc.grpc.test_service.downstream_call:output_type -> goproto.protoc.grpc.Response
 	0, // goproto.protoc.grpc.test_service.upstream_call:input_type -> goproto.protoc.grpc.Request
-	1, // goproto.protoc.grpc.test_service.upstream_call:output_type -> goproto.protoc.grpc.Response
 	0, // goproto.protoc.grpc.test_service.bidi_call:input_type -> goproto.protoc.grpc.Request
+	1, // goproto.protoc.grpc.test_service.unary_call:output_type -> goproto.protoc.grpc.Response
+	1, // goproto.protoc.grpc.test_service.downstream_call:output_type -> goproto.protoc.grpc.Response
+	1, // goproto.protoc.grpc.test_service.upstream_call:output_type -> goproto.protoc.grpc.Response
 	1, // goproto.protoc.grpc.test_service.bidi_call:output_type -> goproto.protoc.grpc.Response
+	4, // starting offset of method output_type sub-list
+	0, // starting offset of method input_type sub-list
+	0, // starting offset of extension type_name sub-list
+	0, // starting offset of extension extendee sub-list
+	0, // starting offset of field type_name sub-list
 }
 
 func init() { file_grpc_grpc_proto_init() }
@@ -143,14 +147,19 @@
 	if File_grpc_grpc_proto != nil {
 		return
 	}
-	File_grpc_grpc_proto = protoimpl.FileBuilder{
-		RawDescriptor:      file_grpc_grpc_proto_rawDesc,
-		GoTypes:            file_grpc_grpc_proto_goTypes,
-		DependencyIndexes:  file_grpc_grpc_proto_depIdxs,
-		MessageOutputTypes: file_grpc_grpc_proto_msgTypes,
-		FilesRegistry:      protoregistry.GlobalFiles,
-		TypesRegistry:      protoregistry.GlobalTypes,
-	}.Init()
+	out := protoimpl.TypeBuilder{
+		File: protoimpl.DescBuilder{
+			RawDescriptor: file_grpc_grpc_proto_rawDesc,
+			NumEnums:      0,
+			NumMessages:   2,
+			NumExtensions: 0,
+			NumServices:   1,
+		},
+		GoTypes:           file_grpc_grpc_proto_goTypes,
+		DependencyIndexes: file_grpc_grpc_proto_depIdxs,
+		MessageInfos:      file_grpc_grpc_proto_msgTypes,
+	}.Build()
+	File_grpc_grpc_proto = out.File
 	file_grpc_grpc_proto_rawDesc = nil
 	file_grpc_grpc_proto_goTypes = nil
 	file_grpc_grpc_proto_depIdxs = nil
diff --git a/cmd/protoc-gen-go/internal_gengo/main.go b/cmd/protoc-gen-go/internal_gengo/main.go
index a17af06..b3556a4 100644
--- a/cmd/protoc-gen-go/internal_gengo/main.go
+++ b/cmd/protoc-gen-go/internal_gengo/main.go
@@ -44,6 +44,7 @@
 	protoimplPackage     = protogen.GoImportPath("google.golang.org/protobuf/runtime/protoimpl")
 	protoreflectPackage  = protogen.GoImportPath("google.golang.org/protobuf/reflect/protoreflect")
 	protoregistryPackage = protogen.GoImportPath("google.golang.org/protobuf/reflect/protoregistry")
+	prototypePackage     = protogen.GoImportPath("google.golang.org/protobuf/reflect/prototype")
 )
 
 type fileInfo struct {
@@ -65,7 +66,7 @@
 	}
 
 	// Collect all enums, messages, and extensions in "flattened ordering".
-	// See fileinit.FileBuilder.
+	// See filetype.TypeBuilder.
 	f.allEnums = append(f.allEnums, f.Enums...)
 	f.allMessages = append(f.allMessages, f.Messages...)
 	f.allExtensions = append(f.allExtensions, f.Extensions...)
@@ -625,7 +626,7 @@
 		return
 	}
 
-	g.P("var ", extDecsVarName(f), " = []", protoifacePackage.Ident("ExtensionDescV1"), "{")
+	g.P("var ", extDescsVarName(f), " = []", protoifacePackage.Ident("ExtensionDescV1"), "{")
 	for _, extension := range f.allExtensions {
 		// Special case for proto2 message sets: If this extension is extending
 		// proto2.bridge.MessageSet, and its final name component is "message_set_extension",
@@ -668,7 +669,7 @@
 		}
 		fieldName := string(ed.Name())
 		g.P("// extend ", targetName, " { ", ed.Cardinality().String(), " ", typeName, " ", fieldName, " = ", ed.Number(), "; }")
-		g.P(extensionVar(f.File, extension), " = &", extDecsVarName(f), "[", i, "]")
+		g.P(extensionVar(f.File, extension), " = &", extDescsVarName(f), "[", i, "]")
 		g.P()
 	}
 	g.P(")")
diff --git a/cmd/protoc-gen-go/internal_gengo/reflect.go b/cmd/protoc-gen-go/internal_gengo/reflect.go
index 53d7c96..c58a3ef 100644
--- a/cmd/protoc-gen-go/internal_gengo/reflect.go
+++ b/cmd/protoc-gen-go/internal_gengo/reflect.go
@@ -25,7 +25,7 @@
 
 	genFileDescriptor(gen, g, f)
 	if len(f.allEnums) > 0 {
-		g.P("var ", enumTypesVarName(f), " = make([]", protoreflectPackage.Ident("EnumType"), ",", len(f.allEnums), ")")
+		g.P("var ", enumTypesVarName(f), " = make([]", prototypePackage.Ident("Enum"), ",", len(f.allEnums), ")")
 	}
 	if len(f.allMessages) > 0 {
 		g.P("var ", messageTypesVarName(f), " = make([]", protoimplPackage.Ident("MessageInfo"), ",", len(f.allMessages), ")")
@@ -73,17 +73,16 @@
 		}
 	}
 
-	// This ordering is significant. See protoimpl.FileBuilder.GoTypes.
+	// This ordering is significant.
+	// See filetype.TypeBuilder.DependencyIndexes.
+	var depOffsets []string
 	for _, enum := range f.allEnums {
 		genEnum(enum, "")
 	}
 	for _, message := range f.allMessages {
 		genMessage(message, "")
 	}
-	for _, extension := range f.allExtensions {
-		source := string(extension.Desc.FullName())
-		genMessage(extension.Extendee, source+":extendee")
-	}
+	depOffsets = append(depOffsets, fmt.Sprintf("%d, // starting offset of field type_name sub-list", len(depIdxs)))
 	for _, message := range f.allMessages {
 		for _, field := range message.Fields {
 			if field.Desc.IsWeak() {
@@ -94,18 +93,34 @@
 			genMessage(field.Message, source+":type_name")
 		}
 	}
+	depOffsets = append(depOffsets, fmt.Sprintf("%d, // starting offset of extension extendee sub-list", len(depIdxs)))
+	for _, extension := range f.allExtensions {
+		source := string(extension.Desc.FullName())
+		genMessage(extension.Extendee, source+":extendee")
+	}
+	depOffsets = append(depOffsets, fmt.Sprintf("%d, // starting offset of extension type_name sub-list", len(depIdxs)))
 	for _, extension := range f.allExtensions {
 		source := string(extension.Desc.FullName())
 		genEnum(extension.Enum, source+":type_name")
 		genMessage(extension.Message, source+":type_name")
 	}
+	depOffsets = append(depOffsets, fmt.Sprintf("%d, // starting offset of method input_type sub-list", len(depIdxs)))
 	for _, service := range f.Services {
 		for _, method := range service.Methods {
 			source := string(method.Desc.FullName())
 			genMessage(method.Input, source+":input_type")
+		}
+	}
+	depOffsets = append(depOffsets, fmt.Sprintf("%d, // starting offset of method output_type sub-list", len(depIdxs)))
+	for _, service := range f.Services {
+		for _, method := range service.Methods {
+			source := string(method.Desc.FullName())
 			genMessage(method.Output, source+":output_type")
 		}
 	}
+	for i := len(depOffsets) - 1; i >= 0; i-- {
+		depIdxs = append(depIdxs, depOffsets[i])
+	}
 	if len(depIdxs) > math.MaxInt32 {
 		panic("too many dependencies") // sanity check
 	}
@@ -140,29 +155,27 @@
 		g.P(initFuncName(impFile), "()")
 	}
 
-	if len(f.allExtensions) > 0 {
-		g.P("extensionTypes := make([]", protoreflectPackage.Ident("ExtensionType"), ",", len(f.allExtensions), ")")
-	}
-
-	g.P(f.GoDescriptorIdent, " = ", protoimplPackage.Ident("FileBuilder"), "{")
+	g.P("out := ", protoimplPackage.Ident("TypeBuilder"), "{")
+	g.P("File: ", protoimplPackage.Ident("DescBuilder"), "{")
 	g.P("RawDescriptor: ", rawDescVarName(f), ",")
+	g.P("NumEnums: ", len(f.allEnums), ",")
+	g.P("NumMessages: ", len(f.allMessages), ",")
+	g.P("NumExtensions: ", len(f.allExtensions), ",")
+	g.P("NumServices: ", len(f.Services), ",")
+	g.P("},")
 	g.P("GoTypes: ", goTypesVarName(f), ",")
 	g.P("DependencyIndexes: ", depIdxsVarName(f), ",")
-	if len(f.allExtensions) > 0 {
-		g.P("LegacyExtensions: ", extDecsVarName(f), ",")
-	}
-	if len(f.allEnums) > 0 {
-		g.P("EnumOutputTypes: ", enumTypesVarName(f), ",")
-	}
 	if len(f.allMessages) > 0 {
-		g.P("MessageOutputTypes: ", messageTypesVarName(f), ",")
+		g.P("MessageInfos: ", messageTypesVarName(f), ",")
 	}
 	if len(f.allExtensions) > 0 {
-		g.P("ExtensionOutputTypes: extensionTypes,")
+		g.P("LegacyExtensions: ", extDescsVarName(f), ",")
 	}
-	g.P("FilesRegistry: ", protoregistryPackage.Ident("GlobalFiles"), ",")
-	g.P("TypesRegistry: ", protoregistryPackage.Ident("GlobalTypes"), ",")
-	g.P("}.Init()")
+	g.P("}.Build()")
+	g.P(f.GoDescriptorIdent, " = out.File")
+	if len(f.allEnums) > 0 {
+		g.P(enumTypesVarName(f), " = out.Enums")
+	}
 
 	// Set inputs to nil to allow GC to reclaim resources.
 	g.P(rawDescVarName(f), " = nil")
@@ -235,7 +248,7 @@
 
 	// Descriptor method.
 	g.P("func (", enum.GoIdent, ") Descriptor() ", protoreflectPackage.Ident("EnumDescriptor"), " {")
-	g.P("return ", typesVar, "[", idx, "].Descriptor()")
+	g.P("return ", typesVar, "[", idx, "].EnumDescriptor")
 	g.P("}")
 	g.P()
 
@@ -281,7 +294,7 @@
 func messageTypesVarName(f *fileInfo) string {
 	return fileVarName(f.File, "msgTypes")
 }
-func extDecsVarName(f *fileInfo) string {
+func extDescsVarName(f *fileInfo) string {
 	return fileVarName(f.File, "extDescs")
 }
 func initFuncName(f *protogen.File) string {
diff --git a/cmd/protoc-gen-go/testdata/annotations/annotations.pb.go b/cmd/protoc-gen-go/testdata/annotations/annotations.pb.go
index 1759e76..e81a04f 100644
--- a/cmd/protoc-gen-go/testdata/annotations/annotations.pb.go
+++ b/cmd/protoc-gen-go/testdata/annotations/annotations.pb.go
@@ -5,7 +5,7 @@
 
 import (
 	protoreflect "google.golang.org/protobuf/reflect/protoreflect"
-	protoregistry "google.golang.org/protobuf/reflect/protoregistry"
+	prototype "google.golang.org/protobuf/reflect/prototype"
 	protoiface "google.golang.org/protobuf/runtime/protoiface"
 	protoimpl "google.golang.org/protobuf/runtime/protoimpl"
 	sync "sync"
@@ -45,7 +45,7 @@
 }
 
 func (AnnotationsTestEnum) Descriptor() protoreflect.EnumDescriptor {
-	return file_annotations_annotations_proto_enumTypes[0].Descriptor()
+	return file_annotations_annotations_proto_enumTypes[0].EnumDescriptor
 }
 
 func (x AnnotationsTestEnum) Number() protoreflect.EnumNumber {
@@ -138,28 +138,39 @@
 	return file_annotations_annotations_proto_rawDescData
 }
 
-var file_annotations_annotations_proto_enumTypes = make([]protoreflect.EnumType, 1)
+var file_annotations_annotations_proto_enumTypes = make([]prototype.Enum, 1)
 var file_annotations_annotations_proto_msgTypes = make([]protoimpl.MessageInfo, 1)
 var file_annotations_annotations_proto_goTypes = []interface{}{
 	(AnnotationsTestEnum)(0),       // 0: goproto.protoc.annotations.AnnotationsTestEnum
 	(*AnnotationsTestMessage)(nil), // 1: goproto.protoc.annotations.AnnotationsTestMessage
 }
-var file_annotations_annotations_proto_depIdxs = []int32{}
+var file_annotations_annotations_proto_depIdxs = []int32{
+	0, // starting offset of method output_type sub-list
+	0, // starting offset of method input_type sub-list
+	0, // starting offset of extension type_name sub-list
+	0, // starting offset of extension extendee sub-list
+	0, // starting offset of field type_name sub-list
+}
 
 func init() { file_annotations_annotations_proto_init() }
 func file_annotations_annotations_proto_init() {
 	if File_annotations_annotations_proto != nil {
 		return
 	}
-	File_annotations_annotations_proto = protoimpl.FileBuilder{
-		RawDescriptor:      file_annotations_annotations_proto_rawDesc,
-		GoTypes:            file_annotations_annotations_proto_goTypes,
-		DependencyIndexes:  file_annotations_annotations_proto_depIdxs,
-		EnumOutputTypes:    file_annotations_annotations_proto_enumTypes,
-		MessageOutputTypes: file_annotations_annotations_proto_msgTypes,
-		FilesRegistry:      protoregistry.GlobalFiles,
-		TypesRegistry:      protoregistry.GlobalTypes,
-	}.Init()
+	out := protoimpl.TypeBuilder{
+		File: protoimpl.DescBuilder{
+			RawDescriptor: file_annotations_annotations_proto_rawDesc,
+			NumEnums:      1,
+			NumMessages:   1,
+			NumExtensions: 0,
+			NumServices:   0,
+		},
+		GoTypes:           file_annotations_annotations_proto_goTypes,
+		DependencyIndexes: file_annotations_annotations_proto_depIdxs,
+		MessageInfos:      file_annotations_annotations_proto_msgTypes,
+	}.Build()
+	File_annotations_annotations_proto = out.File
+	file_annotations_annotations_proto_enumTypes = out.Enums
 	file_annotations_annotations_proto_rawDesc = nil
 	file_annotations_annotations_proto_goTypes = nil
 	file_annotations_annotations_proto_depIdxs = nil
diff --git a/cmd/protoc-gen-go/testdata/annotations/annotations.pb.go.meta b/cmd/protoc-gen-go/testdata/annotations/annotations.pb.go.meta
index 1a979ed..a70d989 100644
--- a/cmd/protoc-gen-go/testdata/annotations/annotations.pb.go.meta
+++ b/cmd/protoc-gen-go/testdata/annotations/annotations.pb.go.meta
@@ -1 +1 @@
-annotation:{path:5 path:0 source_file:"annotations/annotations.proto" begin:639 end:658} annotation:{path:5 path:0 path:2 path:0 source_file:"annotations/annotations.proto" begin:675 end:722} annotation:{path:4 path:0 source_file:"annotations/annotations.proto" begin:1947 end:1969} annotation:{path:4 path:0 path:2 path:0 source_file:"annotations/annotations.proto" begin:1980 end:2000} annotation:{path:4 path:0 path:2 path:0 source_file:"annotations/annotations.proto" begin:3021 end:3044}
\ No newline at end of file
+annotation:{path:5 path:0 source_file:"annotations/annotations.proto" begin:631 end:650} annotation:{path:5 path:0 path:2 path:0 source_file:"annotations/annotations.proto" begin:667 end:714} annotation:{path:4 path:0 source_file:"annotations/annotations.proto" begin:1941 end:1963} annotation:{path:4 path:0 path:2 path:0 source_file:"annotations/annotations.proto" begin:1974 end:1994} annotation:{path:4 path:0 path:2 path:0 source_file:"annotations/annotations.proto" begin:3015 end:3038}
\ No newline at end of file
diff --git a/cmd/protoc-gen-go/testdata/comments/comments.pb.go b/cmd/protoc-gen-go/testdata/comments/comments.pb.go
index da5aabe..6cdb147 100644
--- a/cmd/protoc-gen-go/testdata/comments/comments.pb.go
+++ b/cmd/protoc-gen-go/testdata/comments/comments.pb.go
@@ -7,7 +7,6 @@
 
 import (
 	protoreflect "google.golang.org/protobuf/reflect/protoreflect"
-	protoregistry "google.golang.org/protobuf/reflect/protoregistry"
 	protoiface "google.golang.org/protobuf/runtime/protoiface"
 	protoimpl "google.golang.org/protobuf/runtime/protoimpl"
 	sync "sync"
@@ -289,21 +288,32 @@
 	(*Message2_Message2A)(nil), // 4: goproto.protoc.comments.Message2.Message2A
 	(*Message2_Message2B)(nil), // 5: goproto.protoc.comments.Message2.Message2B
 }
-var file_comments_comments_proto_depIdxs = []int32{}
+var file_comments_comments_proto_depIdxs = []int32{
+	0, // starting offset of method output_type sub-list
+	0, // starting offset of method input_type sub-list
+	0, // starting offset of extension type_name sub-list
+	0, // starting offset of extension extendee sub-list
+	0, // starting offset of field type_name sub-list
+}
 
 func init() { file_comments_comments_proto_init() }
 func file_comments_comments_proto_init() {
 	if File_comments_comments_proto != nil {
 		return
 	}
-	File_comments_comments_proto = protoimpl.FileBuilder{
-		RawDescriptor:      file_comments_comments_proto_rawDesc,
-		GoTypes:            file_comments_comments_proto_goTypes,
-		DependencyIndexes:  file_comments_comments_proto_depIdxs,
-		MessageOutputTypes: file_comments_comments_proto_msgTypes,
-		FilesRegistry:      protoregistry.GlobalFiles,
-		TypesRegistry:      protoregistry.GlobalTypes,
-	}.Init()
+	out := protoimpl.TypeBuilder{
+		File: protoimpl.DescBuilder{
+			RawDescriptor: file_comments_comments_proto_rawDesc,
+			NumEnums:      0,
+			NumMessages:   6,
+			NumExtensions: 0,
+			NumServices:   0,
+		},
+		GoTypes:           file_comments_comments_proto_goTypes,
+		DependencyIndexes: file_comments_comments_proto_depIdxs,
+		MessageInfos:      file_comments_comments_proto_msgTypes,
+	}.Build()
+	File_comments_comments_proto = out.File
 	file_comments_comments_proto_rawDesc = nil
 	file_comments_comments_proto_goTypes = nil
 	file_comments_comments_proto_depIdxs = nil
diff --git a/cmd/protoc-gen-go/testdata/comments/deprecated.pb.go b/cmd/protoc-gen-go/testdata/comments/deprecated.pb.go
index b19b6d0..22db118 100644
--- a/cmd/protoc-gen-go/testdata/comments/deprecated.pb.go
+++ b/cmd/protoc-gen-go/testdata/comments/deprecated.pb.go
@@ -5,7 +5,7 @@
 
 import (
 	protoreflect "google.golang.org/protobuf/reflect/protoreflect"
-	protoregistry "google.golang.org/protobuf/reflect/protoregistry"
+	prototype "google.golang.org/protobuf/reflect/prototype"
 	protoiface "google.golang.org/protobuf/runtime/protoiface"
 	protoimpl "google.golang.org/protobuf/runtime/protoimpl"
 	sync "sync"
@@ -44,7 +44,7 @@
 }
 
 func (DeprecatedEnum) Descriptor() protoreflect.EnumDescriptor {
-	return file_comments_deprecated_proto_enumTypes[0].Descriptor()
+	return file_comments_deprecated_proto_enumTypes[0].EnumDescriptor
 }
 
 func (x DeprecatedEnum) Number() protoreflect.EnumNumber {
@@ -128,28 +128,39 @@
 	return file_comments_deprecated_proto_rawDescData
 }
 
-var file_comments_deprecated_proto_enumTypes = make([]protoreflect.EnumType, 1)
+var file_comments_deprecated_proto_enumTypes = make([]prototype.Enum, 1)
 var file_comments_deprecated_proto_msgTypes = make([]protoimpl.MessageInfo, 1)
 var file_comments_deprecated_proto_goTypes = []interface{}{
 	(DeprecatedEnum)(0),       // 0: goproto.protoc.comments.DeprecatedEnum
 	(*DeprecatedMessage)(nil), // 1: goproto.protoc.comments.DeprecatedMessage
 }
-var file_comments_deprecated_proto_depIdxs = []int32{}
+var file_comments_deprecated_proto_depIdxs = []int32{
+	0, // starting offset of method output_type sub-list
+	0, // starting offset of method input_type sub-list
+	0, // starting offset of extension type_name sub-list
+	0, // starting offset of extension extendee sub-list
+	0, // starting offset of field type_name sub-list
+}
 
 func init() { file_comments_deprecated_proto_init() }
 func file_comments_deprecated_proto_init() {
 	if File_comments_deprecated_proto != nil {
 		return
 	}
-	File_comments_deprecated_proto = protoimpl.FileBuilder{
-		RawDescriptor:      file_comments_deprecated_proto_rawDesc,
-		GoTypes:            file_comments_deprecated_proto_goTypes,
-		DependencyIndexes:  file_comments_deprecated_proto_depIdxs,
-		EnumOutputTypes:    file_comments_deprecated_proto_enumTypes,
-		MessageOutputTypes: file_comments_deprecated_proto_msgTypes,
-		FilesRegistry:      protoregistry.GlobalFiles,
-		TypesRegistry:      protoregistry.GlobalTypes,
-	}.Init()
+	out := protoimpl.TypeBuilder{
+		File: protoimpl.DescBuilder{
+			RawDescriptor: file_comments_deprecated_proto_rawDesc,
+			NumEnums:      1,
+			NumMessages:   1,
+			NumExtensions: 0,
+			NumServices:   0,
+		},
+		GoTypes:           file_comments_deprecated_proto_goTypes,
+		DependencyIndexes: file_comments_deprecated_proto_depIdxs,
+		MessageInfos:      file_comments_deprecated_proto_msgTypes,
+	}.Build()
+	File_comments_deprecated_proto = out.File
+	file_comments_deprecated_proto_enumTypes = out.Enums
 	file_comments_deprecated_proto_rawDesc = nil
 	file_comments_deprecated_proto_goTypes = nil
 	file_comments_deprecated_proto_depIdxs = nil
diff --git a/cmd/protoc-gen-go/testdata/extensions/base/base.pb.go b/cmd/protoc-gen-go/testdata/extensions/base/base.pb.go
index 1e74be1..4364047 100644
--- a/cmd/protoc-gen-go/testdata/extensions/base/base.pb.go
+++ b/cmd/protoc-gen-go/testdata/extensions/base/base.pb.go
@@ -5,7 +5,6 @@
 
 import (
 	protoreflect "google.golang.org/protobuf/reflect/protoreflect"
-	protoregistry "google.golang.org/protobuf/reflect/protoregistry"
 	protoiface "google.golang.org/protobuf/runtime/protoiface"
 	protoimpl "google.golang.org/protobuf/runtime/protoimpl"
 	sync "sync"
@@ -142,21 +141,32 @@
 	(*BaseMessage)(nil),                 // 0: goproto.protoc.extension.base.BaseMessage
 	(*MessageSetWireFormatMessage)(nil), // 1: goproto.protoc.extension.base.MessageSetWireFormatMessage
 }
-var file_extensions_base_base_proto_depIdxs = []int32{}
+var file_extensions_base_base_proto_depIdxs = []int32{
+	0, // starting offset of method output_type sub-list
+	0, // starting offset of method input_type sub-list
+	0, // starting offset of extension type_name sub-list
+	0, // starting offset of extension extendee sub-list
+	0, // starting offset of field type_name sub-list
+}
 
 func init() { file_extensions_base_base_proto_init() }
 func file_extensions_base_base_proto_init() {
 	if File_extensions_base_base_proto != nil {
 		return
 	}
-	File_extensions_base_base_proto = protoimpl.FileBuilder{
-		RawDescriptor:      file_extensions_base_base_proto_rawDesc,
-		GoTypes:            file_extensions_base_base_proto_goTypes,
-		DependencyIndexes:  file_extensions_base_base_proto_depIdxs,
-		MessageOutputTypes: file_extensions_base_base_proto_msgTypes,
-		FilesRegistry:      protoregistry.GlobalFiles,
-		TypesRegistry:      protoregistry.GlobalTypes,
-	}.Init()
+	out := protoimpl.TypeBuilder{
+		File: protoimpl.DescBuilder{
+			RawDescriptor: file_extensions_base_base_proto_rawDesc,
+			NumEnums:      0,
+			NumMessages:   2,
+			NumExtensions: 0,
+			NumServices:   0,
+		},
+		GoTypes:           file_extensions_base_base_proto_goTypes,
+		DependencyIndexes: file_extensions_base_base_proto_depIdxs,
+		MessageInfos:      file_extensions_base_base_proto_msgTypes,
+	}.Build()
+	File_extensions_base_base_proto = out.File
 	file_extensions_base_base_proto_rawDesc = nil
 	file_extensions_base_base_proto_goTypes = nil
 	file_extensions_base_base_proto_depIdxs = nil
diff --git a/cmd/protoc-gen-go/testdata/extensions/ext/ext.pb.go b/cmd/protoc-gen-go/testdata/extensions/ext/ext.pb.go
index 3d2627f..167390f 100644
--- a/cmd/protoc-gen-go/testdata/extensions/ext/ext.pb.go
+++ b/cmd/protoc-gen-go/testdata/extensions/ext/ext.pb.go
@@ -7,7 +7,7 @@
 	base "google.golang.org/protobuf/cmd/protoc-gen-go/testdata/extensions/base"
 	extra "google.golang.org/protobuf/cmd/protoc-gen-go/testdata/extensions/extra"
 	protoreflect "google.golang.org/protobuf/reflect/protoreflect"
-	protoregistry "google.golang.org/protobuf/reflect/protoregistry"
+	prototype "google.golang.org/protobuf/reflect/prototype"
 	protoiface "google.golang.org/protobuf/runtime/protoiface"
 	protoimpl "google.golang.org/protobuf/runtime/protoimpl"
 	sync "sync"
@@ -47,7 +47,7 @@
 }
 
 func (Enum) Descriptor() protoreflect.EnumDescriptor {
-	return file_extensions_ext_ext_proto_enumTypes[0].Descriptor()
+	return file_extensions_ext_ext_proto_enumTypes[0].EnumDescriptor
 }
 
 func (x Enum) Number() protoreflect.EnumNumber {
@@ -1155,7 +1155,7 @@
 	return file_extensions_ext_ext_proto_rawDescData
 }
 
-var file_extensions_ext_ext_proto_enumTypes = make([]protoreflect.EnumType, 1)
+var file_extensions_ext_ext_proto_enumTypes = make([]prototype.Enum, 1)
 var file_extensions_ext_ext_proto_msgTypes = make([]protoimpl.MessageInfo, 8)
 var file_extensions_ext_ext_proto_goTypes = []interface{}{
 	(Enum)(0),                             // 0: goproto.protoc.extension.ext.Enum
@@ -1228,6 +1228,11 @@
 	6,  // goproto.protoc.extension.ext.message_set_extension:type_name -> goproto.protoc.extension.ext.MessageSetWireFormatExtension
 	8,  // goproto.protoc.extension.ext.ExtendingMessage.extending_message_submessage:type_name -> goproto.protoc.extension.ext.ExtendingMessage.ExtendingMessageSubmessage
 	6,  // goproto.protoc.extension.ext.MessageSetWireFormatExtension.message_set_extension:type_name -> goproto.protoc.extension.ext.MessageSetWireFormatExtension
+	56, // starting offset of method output_type sub-list
+	56, // starting offset of method input_type sub-list
+	44, // starting offset of extension type_name sub-list
+	0,  // starting offset of extension extendee sub-list
+	0,  // starting offset of field type_name sub-list
 }
 
 func init() { file_extensions_ext_ext_proto_init() }
@@ -1235,18 +1240,21 @@
 	if File_extensions_ext_ext_proto != nil {
 		return
 	}
-	extensionTypes := make([]protoreflect.ExtensionType, 44)
-	File_extensions_ext_ext_proto = protoimpl.FileBuilder{
-		RawDescriptor:        file_extensions_ext_ext_proto_rawDesc,
-		GoTypes:              file_extensions_ext_ext_proto_goTypes,
-		DependencyIndexes:    file_extensions_ext_ext_proto_depIdxs,
-		LegacyExtensions:     file_extensions_ext_ext_proto_extDescs,
-		EnumOutputTypes:      file_extensions_ext_ext_proto_enumTypes,
-		MessageOutputTypes:   file_extensions_ext_ext_proto_msgTypes,
-		ExtensionOutputTypes: extensionTypes,
-		FilesRegistry:        protoregistry.GlobalFiles,
-		TypesRegistry:        protoregistry.GlobalTypes,
-	}.Init()
+	out := protoimpl.TypeBuilder{
+		File: protoimpl.DescBuilder{
+			RawDescriptor: file_extensions_ext_ext_proto_rawDesc,
+			NumEnums:      1,
+			NumMessages:   8,
+			NumExtensions: 44,
+			NumServices:   0,
+		},
+		GoTypes:           file_extensions_ext_ext_proto_goTypes,
+		DependencyIndexes: file_extensions_ext_ext_proto_depIdxs,
+		MessageInfos:      file_extensions_ext_ext_proto_msgTypes,
+		LegacyExtensions:  file_extensions_ext_ext_proto_extDescs,
+	}.Build()
+	File_extensions_ext_ext_proto = out.File
+	file_extensions_ext_ext_proto_enumTypes = out.Enums
 	file_extensions_ext_ext_proto_rawDesc = nil
 	file_extensions_ext_ext_proto_goTypes = nil
 	file_extensions_ext_ext_proto_depIdxs = nil
diff --git a/cmd/protoc-gen-go/testdata/extensions/extra/extra.pb.go b/cmd/protoc-gen-go/testdata/extensions/extra/extra.pb.go
index e46cdba..93a95dc 100644
--- a/cmd/protoc-gen-go/testdata/extensions/extra/extra.pb.go
+++ b/cmd/protoc-gen-go/testdata/extensions/extra/extra.pb.go
@@ -5,7 +5,6 @@
 
 import (
 	protoreflect "google.golang.org/protobuf/reflect/protoreflect"
-	protoregistry "google.golang.org/protobuf/reflect/protoregistry"
 	protoiface "google.golang.org/protobuf/runtime/protoiface"
 	protoimpl "google.golang.org/protobuf/runtime/protoimpl"
 	sync "sync"
@@ -87,21 +86,32 @@
 var file_extensions_extra_extra_proto_goTypes = []interface{}{
 	(*ExtraMessage)(nil), // 0: goproto.protoc.extension.extra.ExtraMessage
 }
-var file_extensions_extra_extra_proto_depIdxs = []int32{}
+var file_extensions_extra_extra_proto_depIdxs = []int32{
+	0, // starting offset of method output_type sub-list
+	0, // starting offset of method input_type sub-list
+	0, // starting offset of extension type_name sub-list
+	0, // starting offset of extension extendee sub-list
+	0, // starting offset of field type_name sub-list
+}
 
 func init() { file_extensions_extra_extra_proto_init() }
 func file_extensions_extra_extra_proto_init() {
 	if File_extensions_extra_extra_proto != nil {
 		return
 	}
-	File_extensions_extra_extra_proto = protoimpl.FileBuilder{
-		RawDescriptor:      file_extensions_extra_extra_proto_rawDesc,
-		GoTypes:            file_extensions_extra_extra_proto_goTypes,
-		DependencyIndexes:  file_extensions_extra_extra_proto_depIdxs,
-		MessageOutputTypes: file_extensions_extra_extra_proto_msgTypes,
-		FilesRegistry:      protoregistry.GlobalFiles,
-		TypesRegistry:      protoregistry.GlobalTypes,
-	}.Init()
+	out := protoimpl.TypeBuilder{
+		File: protoimpl.DescBuilder{
+			RawDescriptor: file_extensions_extra_extra_proto_rawDesc,
+			NumEnums:      0,
+			NumMessages:   1,
+			NumExtensions: 0,
+			NumServices:   0,
+		},
+		GoTypes:           file_extensions_extra_extra_proto_goTypes,
+		DependencyIndexes: file_extensions_extra_extra_proto_depIdxs,
+		MessageInfos:      file_extensions_extra_extra_proto_msgTypes,
+	}.Build()
+	File_extensions_extra_extra_proto = out.File
 	file_extensions_extra_extra_proto_rawDesc = nil
 	file_extensions_extra_extra_proto_goTypes = nil
 	file_extensions_extra_extra_proto_depIdxs = nil
diff --git a/cmd/protoc-gen-go/testdata/extensions/proto3/ext3.pb.go b/cmd/protoc-gen-go/testdata/extensions/proto3/ext3.pb.go
index f98c06b..c88a642 100644
--- a/cmd/protoc-gen-go/testdata/extensions/proto3/ext3.pb.go
+++ b/cmd/protoc-gen-go/testdata/extensions/proto3/ext3.pb.go
@@ -5,7 +5,7 @@
 
 import (
 	protoreflect "google.golang.org/protobuf/reflect/protoreflect"
-	protoregistry "google.golang.org/protobuf/reflect/protoregistry"
+	prototype "google.golang.org/protobuf/reflect/prototype"
 	protoiface "google.golang.org/protobuf/runtime/protoiface"
 	protoimpl "google.golang.org/protobuf/runtime/protoimpl"
 	descriptorpb "google.golang.org/protobuf/types/descriptorpb"
@@ -46,7 +46,7 @@
 }
 
 func (Enum) Descriptor() protoreflect.EnumDescriptor {
-	return file_extensions_proto3_ext3_proto_enumTypes[0].Descriptor()
+	return file_extensions_proto3_ext3_proto_enumTypes[0].EnumDescriptor
 }
 
 func (x Enum) Number() protoreflect.EnumNumber {
@@ -686,7 +686,7 @@
 	return file_extensions_proto3_ext3_proto_rawDescData
 }
 
-var file_extensions_proto3_ext3_proto_enumTypes = make([]protoreflect.EnumType, 1)
+var file_extensions_proto3_ext3_proto_enumTypes = make([]prototype.Enum, 1)
 var file_extensions_proto3_ext3_proto_msgTypes = make([]protoimpl.MessageInfo, 1)
 var file_extensions_proto3_ext3_proto_goTypes = []interface{}{
 	(Enum)(0),                           // 0: goproto.protoc.extension.proto3.Enum
@@ -694,44 +694,49 @@
 	(*descriptorpb.MessageOptions)(nil), // 2: google.protobuf.MessageOptions
 }
 var file_extensions_proto3_ext3_proto_depIdxs = []int32{
-	2, // goproto.protoc.extension.proto3.extension_bool:extendee -> google.protobuf.MessageOptions
-	2, // goproto.protoc.extension.proto3.extension_enum:extendee -> google.protobuf.MessageOptions
-	2, // goproto.protoc.extension.proto3.extension_int32:extendee -> google.protobuf.MessageOptions
-	2, // goproto.protoc.extension.proto3.extension_sint32:extendee -> google.protobuf.MessageOptions
-	2, // goproto.protoc.extension.proto3.extension_uint32:extendee -> google.protobuf.MessageOptions
-	2, // goproto.protoc.extension.proto3.extension_int64:extendee -> google.protobuf.MessageOptions
-	2, // goproto.protoc.extension.proto3.extension_sint64:extendee -> google.protobuf.MessageOptions
-	2, // goproto.protoc.extension.proto3.extension_uint64:extendee -> google.protobuf.MessageOptions
-	2, // goproto.protoc.extension.proto3.extension_sfixed32:extendee -> google.protobuf.MessageOptions
-	2, // goproto.protoc.extension.proto3.extension_fixed32:extendee -> google.protobuf.MessageOptions
-	2, // goproto.protoc.extension.proto3.extension_float:extendee -> google.protobuf.MessageOptions
-	2, // goproto.protoc.extension.proto3.extension_sfixed64:extendee -> google.protobuf.MessageOptions
-	2, // goproto.protoc.extension.proto3.extension_fixed64:extendee -> google.protobuf.MessageOptions
-	2, // goproto.protoc.extension.proto3.extension_double:extendee -> google.protobuf.MessageOptions
-	2, // goproto.protoc.extension.proto3.extension_string:extendee -> google.protobuf.MessageOptions
-	2, // goproto.protoc.extension.proto3.extension_bytes:extendee -> google.protobuf.MessageOptions
-	2, // goproto.protoc.extension.proto3.extension_Message:extendee -> google.protobuf.MessageOptions
-	2, // goproto.protoc.extension.proto3.repeated_extension_bool:extendee -> google.protobuf.MessageOptions
-	2, // goproto.protoc.extension.proto3.repeated_extension_enum:extendee -> google.protobuf.MessageOptions
-	2, // goproto.protoc.extension.proto3.repeated_extension_int32:extendee -> google.protobuf.MessageOptions
-	2, // goproto.protoc.extension.proto3.repeated_extension_sint32:extendee -> google.protobuf.MessageOptions
-	2, // goproto.protoc.extension.proto3.repeated_extension_uint32:extendee -> google.protobuf.MessageOptions
-	2, // goproto.protoc.extension.proto3.repeated_extension_int64:extendee -> google.protobuf.MessageOptions
-	2, // goproto.protoc.extension.proto3.repeated_extension_sint64:extendee -> google.protobuf.MessageOptions
-	2, // goproto.protoc.extension.proto3.repeated_extension_uint64:extendee -> google.protobuf.MessageOptions
-	2, // goproto.protoc.extension.proto3.repeated_extension_sfixed32:extendee -> google.protobuf.MessageOptions
-	2, // goproto.protoc.extension.proto3.repeated_extension_fixed32:extendee -> google.protobuf.MessageOptions
-	2, // goproto.protoc.extension.proto3.repeated_extension_float:extendee -> google.protobuf.MessageOptions
-	2, // goproto.protoc.extension.proto3.repeated_extension_sfixed64:extendee -> google.protobuf.MessageOptions
-	2, // goproto.protoc.extension.proto3.repeated_extension_fixed64:extendee -> google.protobuf.MessageOptions
-	2, // goproto.protoc.extension.proto3.repeated_extension_double:extendee -> google.protobuf.MessageOptions
-	2, // goproto.protoc.extension.proto3.repeated_extension_string:extendee -> google.protobuf.MessageOptions
-	2, // goproto.protoc.extension.proto3.repeated_extension_bytes:extendee -> google.protobuf.MessageOptions
-	2, // goproto.protoc.extension.proto3.repeated_extension_Message:extendee -> google.protobuf.MessageOptions
-	0, // goproto.protoc.extension.proto3.extension_enum:type_name -> goproto.protoc.extension.proto3.Enum
-	1, // goproto.protoc.extension.proto3.extension_Message:type_name -> goproto.protoc.extension.proto3.Message
-	0, // goproto.protoc.extension.proto3.repeated_extension_enum:type_name -> goproto.protoc.extension.proto3.Enum
-	1, // goproto.protoc.extension.proto3.repeated_extension_Message:type_name -> goproto.protoc.extension.proto3.Message
+	2,  // goproto.protoc.extension.proto3.extension_bool:extendee -> google.protobuf.MessageOptions
+	2,  // goproto.protoc.extension.proto3.extension_enum:extendee -> google.protobuf.MessageOptions
+	2,  // goproto.protoc.extension.proto3.extension_int32:extendee -> google.protobuf.MessageOptions
+	2,  // goproto.protoc.extension.proto3.extension_sint32:extendee -> google.protobuf.MessageOptions
+	2,  // goproto.protoc.extension.proto3.extension_uint32:extendee -> google.protobuf.MessageOptions
+	2,  // goproto.protoc.extension.proto3.extension_int64:extendee -> google.protobuf.MessageOptions
+	2,  // goproto.protoc.extension.proto3.extension_sint64:extendee -> google.protobuf.MessageOptions
+	2,  // goproto.protoc.extension.proto3.extension_uint64:extendee -> google.protobuf.MessageOptions
+	2,  // goproto.protoc.extension.proto3.extension_sfixed32:extendee -> google.protobuf.MessageOptions
+	2,  // goproto.protoc.extension.proto3.extension_fixed32:extendee -> google.protobuf.MessageOptions
+	2,  // goproto.protoc.extension.proto3.extension_float:extendee -> google.protobuf.MessageOptions
+	2,  // goproto.protoc.extension.proto3.extension_sfixed64:extendee -> google.protobuf.MessageOptions
+	2,  // goproto.protoc.extension.proto3.extension_fixed64:extendee -> google.protobuf.MessageOptions
+	2,  // goproto.protoc.extension.proto3.extension_double:extendee -> google.protobuf.MessageOptions
+	2,  // goproto.protoc.extension.proto3.extension_string:extendee -> google.protobuf.MessageOptions
+	2,  // goproto.protoc.extension.proto3.extension_bytes:extendee -> google.protobuf.MessageOptions
+	2,  // goproto.protoc.extension.proto3.extension_Message:extendee -> google.protobuf.MessageOptions
+	2,  // goproto.protoc.extension.proto3.repeated_extension_bool:extendee -> google.protobuf.MessageOptions
+	2,  // goproto.protoc.extension.proto3.repeated_extension_enum:extendee -> google.protobuf.MessageOptions
+	2,  // goproto.protoc.extension.proto3.repeated_extension_int32:extendee -> google.protobuf.MessageOptions
+	2,  // goproto.protoc.extension.proto3.repeated_extension_sint32:extendee -> google.protobuf.MessageOptions
+	2,  // goproto.protoc.extension.proto3.repeated_extension_uint32:extendee -> google.protobuf.MessageOptions
+	2,  // goproto.protoc.extension.proto3.repeated_extension_int64:extendee -> google.protobuf.MessageOptions
+	2,  // goproto.protoc.extension.proto3.repeated_extension_sint64:extendee -> google.protobuf.MessageOptions
+	2,  // goproto.protoc.extension.proto3.repeated_extension_uint64:extendee -> google.protobuf.MessageOptions
+	2,  // goproto.protoc.extension.proto3.repeated_extension_sfixed32:extendee -> google.protobuf.MessageOptions
+	2,  // goproto.protoc.extension.proto3.repeated_extension_fixed32:extendee -> google.protobuf.MessageOptions
+	2,  // goproto.protoc.extension.proto3.repeated_extension_float:extendee -> google.protobuf.MessageOptions
+	2,  // goproto.protoc.extension.proto3.repeated_extension_sfixed64:extendee -> google.protobuf.MessageOptions
+	2,  // goproto.protoc.extension.proto3.repeated_extension_fixed64:extendee -> google.protobuf.MessageOptions
+	2,  // goproto.protoc.extension.proto3.repeated_extension_double:extendee -> google.protobuf.MessageOptions
+	2,  // goproto.protoc.extension.proto3.repeated_extension_string:extendee -> google.protobuf.MessageOptions
+	2,  // goproto.protoc.extension.proto3.repeated_extension_bytes:extendee -> google.protobuf.MessageOptions
+	2,  // goproto.protoc.extension.proto3.repeated_extension_Message:extendee -> google.protobuf.MessageOptions
+	0,  // goproto.protoc.extension.proto3.extension_enum:type_name -> goproto.protoc.extension.proto3.Enum
+	1,  // goproto.protoc.extension.proto3.extension_Message:type_name -> goproto.protoc.extension.proto3.Message
+	0,  // goproto.protoc.extension.proto3.repeated_extension_enum:type_name -> goproto.protoc.extension.proto3.Enum
+	1,  // goproto.protoc.extension.proto3.repeated_extension_Message:type_name -> goproto.protoc.extension.proto3.Message
+	38, // starting offset of method output_type sub-list
+	38, // starting offset of method input_type sub-list
+	34, // starting offset of extension type_name sub-list
+	0,  // starting offset of extension extendee sub-list
+	0,  // starting offset of field type_name sub-list
 }
 
 func init() { file_extensions_proto3_ext3_proto_init() }
@@ -739,18 +744,21 @@
 	if File_extensions_proto3_ext3_proto != nil {
 		return
 	}
-	extensionTypes := make([]protoreflect.ExtensionType, 34)
-	File_extensions_proto3_ext3_proto = protoimpl.FileBuilder{
-		RawDescriptor:        file_extensions_proto3_ext3_proto_rawDesc,
-		GoTypes:              file_extensions_proto3_ext3_proto_goTypes,
-		DependencyIndexes:    file_extensions_proto3_ext3_proto_depIdxs,
-		LegacyExtensions:     file_extensions_proto3_ext3_proto_extDescs,
-		EnumOutputTypes:      file_extensions_proto3_ext3_proto_enumTypes,
-		MessageOutputTypes:   file_extensions_proto3_ext3_proto_msgTypes,
-		ExtensionOutputTypes: extensionTypes,
-		FilesRegistry:        protoregistry.GlobalFiles,
-		TypesRegistry:        protoregistry.GlobalTypes,
-	}.Init()
+	out := protoimpl.TypeBuilder{
+		File: protoimpl.DescBuilder{
+			RawDescriptor: file_extensions_proto3_ext3_proto_rawDesc,
+			NumEnums:      1,
+			NumMessages:   1,
+			NumExtensions: 34,
+			NumServices:   0,
+		},
+		GoTypes:           file_extensions_proto3_ext3_proto_goTypes,
+		DependencyIndexes: file_extensions_proto3_ext3_proto_depIdxs,
+		MessageInfos:      file_extensions_proto3_ext3_proto_msgTypes,
+		LegacyExtensions:  file_extensions_proto3_ext3_proto_extDescs,
+	}.Build()
+	File_extensions_proto3_ext3_proto = out.File
+	file_extensions_proto3_ext3_proto_enumTypes = out.Enums
 	file_extensions_proto3_ext3_proto_rawDesc = nil
 	file_extensions_proto3_ext3_proto_goTypes = nil
 	file_extensions_proto3_ext3_proto_depIdxs = nil
diff --git a/cmd/protoc-gen-go/testdata/fieldnames/fieldnames.pb.go b/cmd/protoc-gen-go/testdata/fieldnames/fieldnames.pb.go
index 8680fd2..9a9b3cb 100644
--- a/cmd/protoc-gen-go/testdata/fieldnames/fieldnames.pb.go
+++ b/cmd/protoc-gen-go/testdata/fieldnames/fieldnames.pb.go
@@ -5,7 +5,6 @@
 
 import (
 	protoreflect "google.golang.org/protobuf/reflect/protoreflect"
-	protoregistry "google.golang.org/protobuf/reflect/protoregistry"
 	protoiface "google.golang.org/protobuf/runtime/protoiface"
 	protoimpl "google.golang.org/protobuf/runtime/protoimpl"
 	sync "sync"
@@ -382,21 +381,32 @@
 	(*Message)(nil),                      // 0: goproto.protoc.fieldnames.Message
 	(*Message_OneofMessageConflict)(nil), // 1: goproto.protoc.fieldnames.Message.OneofMessageConflict
 }
-var file_fieldnames_fieldnames_proto_depIdxs = []int32{}
+var file_fieldnames_fieldnames_proto_depIdxs = []int32{
+	0, // starting offset of method output_type sub-list
+	0, // starting offset of method input_type sub-list
+	0, // starting offset of extension type_name sub-list
+	0, // starting offset of extension extendee sub-list
+	0, // starting offset of field type_name sub-list
+}
 
 func init() { file_fieldnames_fieldnames_proto_init() }
 func file_fieldnames_fieldnames_proto_init() {
 	if File_fieldnames_fieldnames_proto != nil {
 		return
 	}
-	File_fieldnames_fieldnames_proto = protoimpl.FileBuilder{
-		RawDescriptor:      file_fieldnames_fieldnames_proto_rawDesc,
-		GoTypes:            file_fieldnames_fieldnames_proto_goTypes,
-		DependencyIndexes:  file_fieldnames_fieldnames_proto_depIdxs,
-		MessageOutputTypes: file_fieldnames_fieldnames_proto_msgTypes,
-		FilesRegistry:      protoregistry.GlobalFiles,
-		TypesRegistry:      protoregistry.GlobalTypes,
-	}.Init()
+	out := protoimpl.TypeBuilder{
+		File: protoimpl.DescBuilder{
+			RawDescriptor: file_fieldnames_fieldnames_proto_rawDesc,
+			NumEnums:      0,
+			NumMessages:   2,
+			NumExtensions: 0,
+			NumServices:   0,
+		},
+		GoTypes:           file_fieldnames_fieldnames_proto_goTypes,
+		DependencyIndexes: file_fieldnames_fieldnames_proto_depIdxs,
+		MessageInfos:      file_fieldnames_fieldnames_proto_msgTypes,
+	}.Build()
+	File_fieldnames_fieldnames_proto = out.File
 	file_fieldnames_fieldnames_proto_rawDesc = nil
 	file_fieldnames_fieldnames_proto_goTypes = nil
 	file_fieldnames_fieldnames_proto_depIdxs = nil
diff --git a/cmd/protoc-gen-go/testdata/import_public/a.pb.go b/cmd/protoc-gen-go/testdata/import_public/a.pb.go
index d142745..9ff5681 100644
--- a/cmd/protoc-gen-go/testdata/import_public/a.pb.go
+++ b/cmd/protoc-gen-go/testdata/import_public/a.pb.go
@@ -6,7 +6,6 @@
 import (
 	sub "google.golang.org/protobuf/cmd/protoc-gen-go/testdata/import_public/sub"
 	protoreflect "google.golang.org/protobuf/reflect/protoreflect"
-	protoregistry "google.golang.org/protobuf/reflect/protoregistry"
 	protoiface "google.golang.org/protobuf/runtime/protoiface"
 	protoimpl "google.golang.org/protobuf/runtime/protoimpl"
 	sync "sync"
@@ -160,6 +159,11 @@
 	1, // goproto.protoc.import_public.Public.m:type_name -> goproto.protoc.import_public.sub.M
 	2, // goproto.protoc.import_public.Public.e:type_name -> goproto.protoc.import_public.sub.E
 	3, // goproto.protoc.import_public.Public.local:type_name -> goproto.protoc.import_public.Local
+	3, // starting offset of method output_type sub-list
+	3, // starting offset of method input_type sub-list
+	3, // starting offset of extension type_name sub-list
+	3, // starting offset of extension extendee sub-list
+	0, // starting offset of field type_name sub-list
 }
 
 func init() { file_import_public_a_proto_init() }
@@ -168,14 +172,19 @@
 		return
 	}
 	file_import_public_b_proto_init()
-	File_import_public_a_proto = protoimpl.FileBuilder{
-		RawDescriptor:      file_import_public_a_proto_rawDesc,
-		GoTypes:            file_import_public_a_proto_goTypes,
-		DependencyIndexes:  file_import_public_a_proto_depIdxs,
-		MessageOutputTypes: file_import_public_a_proto_msgTypes,
-		FilesRegistry:      protoregistry.GlobalFiles,
-		TypesRegistry:      protoregistry.GlobalTypes,
-	}.Init()
+	out := protoimpl.TypeBuilder{
+		File: protoimpl.DescBuilder{
+			RawDescriptor: file_import_public_a_proto_rawDesc,
+			NumEnums:      0,
+			NumMessages:   1,
+			NumExtensions: 0,
+			NumServices:   0,
+		},
+		GoTypes:           file_import_public_a_proto_goTypes,
+		DependencyIndexes: file_import_public_a_proto_depIdxs,
+		MessageInfos:      file_import_public_a_proto_msgTypes,
+	}.Build()
+	File_import_public_a_proto = out.File
 	file_import_public_a_proto_rawDesc = nil
 	file_import_public_a_proto_goTypes = nil
 	file_import_public_a_proto_depIdxs = nil
diff --git a/cmd/protoc-gen-go/testdata/import_public/b.pb.go b/cmd/protoc-gen-go/testdata/import_public/b.pb.go
index 8fc7556..da6a3a6 100644
--- a/cmd/protoc-gen-go/testdata/import_public/b.pb.go
+++ b/cmd/protoc-gen-go/testdata/import_public/b.pb.go
@@ -6,7 +6,6 @@
 import (
 	sub "google.golang.org/protobuf/cmd/protoc-gen-go/testdata/import_public/sub"
 	protoreflect "google.golang.org/protobuf/reflect/protoreflect"
-	protoregistry "google.golang.org/protobuf/reflect/protoregistry"
 	protoiface "google.golang.org/protobuf/runtime/protoiface"
 	protoimpl "google.golang.org/protobuf/runtime/protoimpl"
 	sync "sync"
@@ -107,6 +106,11 @@
 var file_import_public_b_proto_depIdxs = []int32{
 	1, // goproto.protoc.import_public.Local.m:type_name -> goproto.protoc.import_public.sub.M
 	2, // goproto.protoc.import_public.Local.e:type_name -> goproto.protoc.import_public.sub.E
+	2, // starting offset of method output_type sub-list
+	2, // starting offset of method input_type sub-list
+	2, // starting offset of extension type_name sub-list
+	2, // starting offset of extension extendee sub-list
+	0, // starting offset of field type_name sub-list
 }
 
 func init() { file_import_public_b_proto_init() }
@@ -114,14 +118,19 @@
 	if File_import_public_b_proto != nil {
 		return
 	}
-	File_import_public_b_proto = protoimpl.FileBuilder{
-		RawDescriptor:      file_import_public_b_proto_rawDesc,
-		GoTypes:            file_import_public_b_proto_goTypes,
-		DependencyIndexes:  file_import_public_b_proto_depIdxs,
-		MessageOutputTypes: file_import_public_b_proto_msgTypes,
-		FilesRegistry:      protoregistry.GlobalFiles,
-		TypesRegistry:      protoregistry.GlobalTypes,
-	}.Init()
+	out := protoimpl.TypeBuilder{
+		File: protoimpl.DescBuilder{
+			RawDescriptor: file_import_public_b_proto_rawDesc,
+			NumEnums:      0,
+			NumMessages:   1,
+			NumExtensions: 0,
+			NumServices:   0,
+		},
+		GoTypes:           file_import_public_b_proto_goTypes,
+		DependencyIndexes: file_import_public_b_proto_depIdxs,
+		MessageInfos:      file_import_public_b_proto_msgTypes,
+	}.Build()
+	File_import_public_b_proto = out.File
 	file_import_public_b_proto_rawDesc = nil
 	file_import_public_b_proto_goTypes = nil
 	file_import_public_b_proto_depIdxs = nil
diff --git a/cmd/protoc-gen-go/testdata/import_public/c.pb.go b/cmd/protoc-gen-go/testdata/import_public/c.pb.go
index 07d1578..955f91b 100644
--- a/cmd/protoc-gen-go/testdata/import_public/c.pb.go
+++ b/cmd/protoc-gen-go/testdata/import_public/c.pb.go
@@ -6,7 +6,6 @@
 import (
 	sub2 "google.golang.org/protobuf/cmd/protoc-gen-go/testdata/import_public/sub2"
 	protoreflect "google.golang.org/protobuf/reflect/protoreflect"
-	protoregistry "google.golang.org/protobuf/reflect/protoregistry"
 	protoiface "google.golang.org/protobuf/runtime/protoiface"
 	protoimpl "google.golang.org/protobuf/runtime/protoimpl"
 	sync "sync"
@@ -112,6 +111,11 @@
 var file_import_public_c_proto_depIdxs = []int32{
 	1, // goproto.protoc.import_public.UsingPublicImport.local:type_name -> goproto.protoc.import_public.Local
 	2, // goproto.protoc.import_public.UsingPublicImport.sub2:type_name -> goproto.protoc.import_public.sub2.Sub2Message
+	2, // starting offset of method output_type sub-list
+	2, // starting offset of method input_type sub-list
+	2, // starting offset of extension type_name sub-list
+	2, // starting offset of extension extendee sub-list
+	0, // starting offset of field type_name sub-list
 }
 
 func init() { file_import_public_c_proto_init() }
@@ -120,14 +124,19 @@
 		return
 	}
 	file_import_public_a_proto_init()
-	File_import_public_c_proto = protoimpl.FileBuilder{
-		RawDescriptor:      file_import_public_c_proto_rawDesc,
-		GoTypes:            file_import_public_c_proto_goTypes,
-		DependencyIndexes:  file_import_public_c_proto_depIdxs,
-		MessageOutputTypes: file_import_public_c_proto_msgTypes,
-		FilesRegistry:      protoregistry.GlobalFiles,
-		TypesRegistry:      protoregistry.GlobalTypes,
-	}.Init()
+	out := protoimpl.TypeBuilder{
+		File: protoimpl.DescBuilder{
+			RawDescriptor: file_import_public_c_proto_rawDesc,
+			NumEnums:      0,
+			NumMessages:   1,
+			NumExtensions: 0,
+			NumServices:   0,
+		},
+		GoTypes:           file_import_public_c_proto_goTypes,
+		DependencyIndexes: file_import_public_c_proto_depIdxs,
+		MessageInfos:      file_import_public_c_proto_msgTypes,
+	}.Build()
+	File_import_public_c_proto = out.File
 	file_import_public_c_proto_rawDesc = nil
 	file_import_public_c_proto_goTypes = nil
 	file_import_public_c_proto_depIdxs = nil
diff --git a/cmd/protoc-gen-go/testdata/import_public/sub/a.pb.go b/cmd/protoc-gen-go/testdata/import_public/sub/a.pb.go
index 68f0084..fc5a845 100644
--- a/cmd/protoc-gen-go/testdata/import_public/sub/a.pb.go
+++ b/cmd/protoc-gen-go/testdata/import_public/sub/a.pb.go
@@ -6,7 +6,7 @@
 import (
 	sub2 "google.golang.org/protobuf/cmd/protoc-gen-go/testdata/import_public/sub2"
 	protoreflect "google.golang.org/protobuf/reflect/protoreflect"
-	protoregistry "google.golang.org/protobuf/reflect/protoregistry"
+	prototype "google.golang.org/protobuf/reflect/prototype"
 	protoiface "google.golang.org/protobuf/runtime/protoiface"
 	protoimpl "google.golang.org/protobuf/runtime/protoimpl"
 	math "math"
@@ -51,7 +51,7 @@
 }
 
 func (E) Descriptor() protoreflect.EnumDescriptor {
-	return file_import_public_sub_a_proto_enumTypes[0].Descriptor()
+	return file_import_public_sub_a_proto_enumTypes[0].EnumDescriptor
 }
 
 func (x E) Number() protoreflect.EnumNumber {
@@ -100,7 +100,7 @@
 }
 
 func (M_Subenum) Descriptor() protoreflect.EnumDescriptor {
-	return file_import_public_sub_a_proto_enumTypes[1].Descriptor()
+	return file_import_public_sub_a_proto_enumTypes[1].EnumDescriptor
 }
 
 func (x M_Subenum) Number() protoreflect.EnumNumber {
@@ -149,7 +149,7 @@
 }
 
 func (M_Submessage_Submessage_Subenum) Descriptor() protoreflect.EnumDescriptor {
-	return file_import_public_sub_a_proto_enumTypes[2].Descriptor()
+	return file_import_public_sub_a_proto_enumTypes[2].EnumDescriptor
 }
 
 func (x M_Submessage_Submessage_Subenum) Number() protoreflect.EnumNumber {
@@ -452,7 +452,7 @@
 	return file_import_public_sub_a_proto_rawDescData
 }
 
-var file_import_public_sub_a_proto_enumTypes = make([]protoreflect.EnumType, 3)
+var file_import_public_sub_a_proto_enumTypes = make([]prototype.Enum, 3)
 var file_import_public_sub_a_proto_msgTypes = make([]protoimpl.MessageInfo, 2)
 var file_import_public_sub_a_proto_goTypes = []interface{}{
 	(E)(0),                               // 0: goproto.protoc.import_public.sub.E
@@ -463,8 +463,13 @@
 	(*M2)(nil),                           // 5: goproto.protoc.import_public.sub.M2
 }
 var file_import_public_sub_a_proto_depIdxs = []int32{
-	3, // goproto.protoc.import_public.sub.extension_field:extendee -> goproto.protoc.import_public.sub.M
 	5, // goproto.protoc.import_public.sub.M.m2:type_name -> goproto.protoc.import_public.sub.M2
+	3, // goproto.protoc.import_public.sub.extension_field:extendee -> goproto.protoc.import_public.sub.M
+	2, // starting offset of method output_type sub-list
+	2, // starting offset of method input_type sub-list
+	2, // starting offset of extension type_name sub-list
+	1, // starting offset of extension extendee sub-list
+	0, // starting offset of field type_name sub-list
 }
 
 func init() { file_import_public_sub_a_proto_init() }
@@ -473,18 +478,21 @@
 		return
 	}
 	file_import_public_sub_b_proto_init()
-	extensionTypes := make([]protoreflect.ExtensionType, 1)
-	File_import_public_sub_a_proto = protoimpl.FileBuilder{
-		RawDescriptor:        file_import_public_sub_a_proto_rawDesc,
-		GoTypes:              file_import_public_sub_a_proto_goTypes,
-		DependencyIndexes:    file_import_public_sub_a_proto_depIdxs,
-		LegacyExtensions:     file_import_public_sub_a_proto_extDescs,
-		EnumOutputTypes:      file_import_public_sub_a_proto_enumTypes,
-		MessageOutputTypes:   file_import_public_sub_a_proto_msgTypes,
-		ExtensionOutputTypes: extensionTypes,
-		FilesRegistry:        protoregistry.GlobalFiles,
-		TypesRegistry:        protoregistry.GlobalTypes,
-	}.Init()
+	out := protoimpl.TypeBuilder{
+		File: protoimpl.DescBuilder{
+			RawDescriptor: file_import_public_sub_a_proto_rawDesc,
+			NumEnums:      3,
+			NumMessages:   2,
+			NumExtensions: 1,
+			NumServices:   0,
+		},
+		GoTypes:           file_import_public_sub_a_proto_goTypes,
+		DependencyIndexes: file_import_public_sub_a_proto_depIdxs,
+		MessageInfos:      file_import_public_sub_a_proto_msgTypes,
+		LegacyExtensions:  file_import_public_sub_a_proto_extDescs,
+	}.Build()
+	File_import_public_sub_a_proto = out.File
+	file_import_public_sub_a_proto_enumTypes = out.Enums
 	file_import_public_sub_a_proto_rawDesc = nil
 	file_import_public_sub_a_proto_goTypes = nil
 	file_import_public_sub_a_proto_depIdxs = nil
diff --git a/cmd/protoc-gen-go/testdata/import_public/sub/b.pb.go b/cmd/protoc-gen-go/testdata/import_public/sub/b.pb.go
index 114c142..dfa99ab 100644
--- a/cmd/protoc-gen-go/testdata/import_public/sub/b.pb.go
+++ b/cmd/protoc-gen-go/testdata/import_public/sub/b.pb.go
@@ -5,7 +5,6 @@
 
 import (
 	protoreflect "google.golang.org/protobuf/reflect/protoreflect"
-	protoregistry "google.golang.org/protobuf/reflect/protoregistry"
 	protoiface "google.golang.org/protobuf/runtime/protoiface"
 	protoimpl "google.golang.org/protobuf/runtime/protoimpl"
 	sync "sync"
@@ -77,21 +76,32 @@
 var file_import_public_sub_b_proto_goTypes = []interface{}{
 	(*M2)(nil), // 0: goproto.protoc.import_public.sub.M2
 }
-var file_import_public_sub_b_proto_depIdxs = []int32{}
+var file_import_public_sub_b_proto_depIdxs = []int32{
+	0, // starting offset of method output_type sub-list
+	0, // starting offset of method input_type sub-list
+	0, // starting offset of extension type_name sub-list
+	0, // starting offset of extension extendee sub-list
+	0, // starting offset of field type_name sub-list
+}
 
 func init() { file_import_public_sub_b_proto_init() }
 func file_import_public_sub_b_proto_init() {
 	if File_import_public_sub_b_proto != nil {
 		return
 	}
-	File_import_public_sub_b_proto = protoimpl.FileBuilder{
-		RawDescriptor:      file_import_public_sub_b_proto_rawDesc,
-		GoTypes:            file_import_public_sub_b_proto_goTypes,
-		DependencyIndexes:  file_import_public_sub_b_proto_depIdxs,
-		MessageOutputTypes: file_import_public_sub_b_proto_msgTypes,
-		FilesRegistry:      protoregistry.GlobalFiles,
-		TypesRegistry:      protoregistry.GlobalTypes,
-	}.Init()
+	out := protoimpl.TypeBuilder{
+		File: protoimpl.DescBuilder{
+			RawDescriptor: file_import_public_sub_b_proto_rawDesc,
+			NumEnums:      0,
+			NumMessages:   1,
+			NumExtensions: 0,
+			NumServices:   0,
+		},
+		GoTypes:           file_import_public_sub_b_proto_goTypes,
+		DependencyIndexes: file_import_public_sub_b_proto_depIdxs,
+		MessageInfos:      file_import_public_sub_b_proto_msgTypes,
+	}.Build()
+	File_import_public_sub_b_proto = out.File
 	file_import_public_sub_b_proto_rawDesc = nil
 	file_import_public_sub_b_proto_goTypes = nil
 	file_import_public_sub_b_proto_depIdxs = nil
diff --git a/cmd/protoc-gen-go/testdata/import_public/sub2/a.pb.go b/cmd/protoc-gen-go/testdata/import_public/sub2/a.pb.go
index 4b84080..cde2a6f 100644
--- a/cmd/protoc-gen-go/testdata/import_public/sub2/a.pb.go
+++ b/cmd/protoc-gen-go/testdata/import_public/sub2/a.pb.go
@@ -5,7 +5,6 @@
 
 import (
 	protoreflect "google.golang.org/protobuf/reflect/protoreflect"
-	protoregistry "google.golang.org/protobuf/reflect/protoregistry"
 	protoiface "google.golang.org/protobuf/runtime/protoiface"
 	protoimpl "google.golang.org/protobuf/runtime/protoimpl"
 	sync "sync"
@@ -78,21 +77,32 @@
 var file_import_public_sub2_a_proto_goTypes = []interface{}{
 	(*Sub2Message)(nil), // 0: goproto.protoc.import_public.sub2.Sub2Message
 }
-var file_import_public_sub2_a_proto_depIdxs = []int32{}
+var file_import_public_sub2_a_proto_depIdxs = []int32{
+	0, // starting offset of method output_type sub-list
+	0, // starting offset of method input_type sub-list
+	0, // starting offset of extension type_name sub-list
+	0, // starting offset of extension extendee sub-list
+	0, // starting offset of field type_name sub-list
+}
 
 func init() { file_import_public_sub2_a_proto_init() }
 func file_import_public_sub2_a_proto_init() {
 	if File_import_public_sub2_a_proto != nil {
 		return
 	}
-	File_import_public_sub2_a_proto = protoimpl.FileBuilder{
-		RawDescriptor:      file_import_public_sub2_a_proto_rawDesc,
-		GoTypes:            file_import_public_sub2_a_proto_goTypes,
-		DependencyIndexes:  file_import_public_sub2_a_proto_depIdxs,
-		MessageOutputTypes: file_import_public_sub2_a_proto_msgTypes,
-		FilesRegistry:      protoregistry.GlobalFiles,
-		TypesRegistry:      protoregistry.GlobalTypes,
-	}.Init()
+	out := protoimpl.TypeBuilder{
+		File: protoimpl.DescBuilder{
+			RawDescriptor: file_import_public_sub2_a_proto_rawDesc,
+			NumEnums:      0,
+			NumMessages:   1,
+			NumExtensions: 0,
+			NumServices:   0,
+		},
+		GoTypes:           file_import_public_sub2_a_proto_goTypes,
+		DependencyIndexes: file_import_public_sub2_a_proto_depIdxs,
+		MessageInfos:      file_import_public_sub2_a_proto_msgTypes,
+	}.Build()
+	File_import_public_sub2_a_proto = out.File
 	file_import_public_sub2_a_proto_rawDesc = nil
 	file_import_public_sub2_a_proto_goTypes = nil
 	file_import_public_sub2_a_proto_depIdxs = nil
diff --git a/cmd/protoc-gen-go/testdata/imports/fmt/m.pb.go b/cmd/protoc-gen-go/testdata/imports/fmt/m.pb.go
index db047a2..8cdb704 100644
--- a/cmd/protoc-gen-go/testdata/imports/fmt/m.pb.go
+++ b/cmd/protoc-gen-go/testdata/imports/fmt/m.pb.go
@@ -5,7 +5,6 @@
 
 import (
 	protoreflect "google.golang.org/protobuf/reflect/protoreflect"
-	protoregistry "google.golang.org/protobuf/reflect/protoregistry"
 	protoiface "google.golang.org/protobuf/runtime/protoiface"
 	protoimpl "google.golang.org/protobuf/runtime/protoimpl"
 	sync "sync"
@@ -75,21 +74,32 @@
 var file_imports_fmt_m_proto_goTypes = []interface{}{
 	(*M)(nil), // 0: fmt.M
 }
-var file_imports_fmt_m_proto_depIdxs = []int32{}
+var file_imports_fmt_m_proto_depIdxs = []int32{
+	0, // starting offset of method output_type sub-list
+	0, // starting offset of method input_type sub-list
+	0, // starting offset of extension type_name sub-list
+	0, // starting offset of extension extendee sub-list
+	0, // starting offset of field type_name sub-list
+}
 
 func init() { file_imports_fmt_m_proto_init() }
 func file_imports_fmt_m_proto_init() {
 	if File_imports_fmt_m_proto != nil {
 		return
 	}
-	File_imports_fmt_m_proto = protoimpl.FileBuilder{
-		RawDescriptor:      file_imports_fmt_m_proto_rawDesc,
-		GoTypes:            file_imports_fmt_m_proto_goTypes,
-		DependencyIndexes:  file_imports_fmt_m_proto_depIdxs,
-		MessageOutputTypes: file_imports_fmt_m_proto_msgTypes,
-		FilesRegistry:      protoregistry.GlobalFiles,
-		TypesRegistry:      protoregistry.GlobalTypes,
-	}.Init()
+	out := protoimpl.TypeBuilder{
+		File: protoimpl.DescBuilder{
+			RawDescriptor: file_imports_fmt_m_proto_rawDesc,
+			NumEnums:      0,
+			NumMessages:   1,
+			NumExtensions: 0,
+			NumServices:   0,
+		},
+		GoTypes:           file_imports_fmt_m_proto_goTypes,
+		DependencyIndexes: file_imports_fmt_m_proto_depIdxs,
+		MessageInfos:      file_imports_fmt_m_proto_msgTypes,
+	}.Build()
+	File_imports_fmt_m_proto = out.File
 	file_imports_fmt_m_proto_rawDesc = nil
 	file_imports_fmt_m_proto_goTypes = nil
 	file_imports_fmt_m_proto_depIdxs = nil
diff --git a/cmd/protoc-gen-go/testdata/imports/test_a_1/m1.pb.go b/cmd/protoc-gen-go/testdata/imports/test_a_1/m1.pb.go
index 8530e07..1106dc6 100644
--- a/cmd/protoc-gen-go/testdata/imports/test_a_1/m1.pb.go
+++ b/cmd/protoc-gen-go/testdata/imports/test_a_1/m1.pb.go
@@ -5,7 +5,7 @@
 
 import (
 	protoreflect "google.golang.org/protobuf/reflect/protoreflect"
-	protoregistry "google.golang.org/protobuf/reflect/protoregistry"
+	prototype "google.golang.org/protobuf/reflect/prototype"
 	protoiface "google.golang.org/protobuf/runtime/protoiface"
 	protoimpl "google.golang.org/protobuf/runtime/protoimpl"
 	sync "sync"
@@ -45,7 +45,7 @@
 }
 
 func (E1) Descriptor() protoreflect.EnumDescriptor {
-	return file_imports_test_a_1_m1_proto_enumTypes[0].Descriptor()
+	return file_imports_test_a_1_m1_proto_enumTypes[0].EnumDescriptor
 }
 
 func (x E1) Number() protoreflect.EnumNumber {
@@ -152,7 +152,7 @@
 	return file_imports_test_a_1_m1_proto_rawDescData
 }
 
-var file_imports_test_a_1_m1_proto_enumTypes = make([]protoreflect.EnumType, 1)
+var file_imports_test_a_1_m1_proto_enumTypes = make([]prototype.Enum, 1)
 var file_imports_test_a_1_m1_proto_msgTypes = make([]protoimpl.MessageInfo, 2)
 var file_imports_test_a_1_m1_proto_goTypes = []interface{}{
 	(E1)(0),      // 0: test.a.E1
@@ -161,6 +161,11 @@
 }
 var file_imports_test_a_1_m1_proto_depIdxs = []int32{
 	1, // test.a.M1_1.m1:type_name -> test.a.M1
+	1, // starting offset of method output_type sub-list
+	1, // starting offset of method input_type sub-list
+	1, // starting offset of extension type_name sub-list
+	1, // starting offset of extension extendee sub-list
+	0, // starting offset of field type_name sub-list
 }
 
 func init() { file_imports_test_a_1_m1_proto_init() }
@@ -168,15 +173,20 @@
 	if File_imports_test_a_1_m1_proto != nil {
 		return
 	}
-	File_imports_test_a_1_m1_proto = protoimpl.FileBuilder{
-		RawDescriptor:      file_imports_test_a_1_m1_proto_rawDesc,
-		GoTypes:            file_imports_test_a_1_m1_proto_goTypes,
-		DependencyIndexes:  file_imports_test_a_1_m1_proto_depIdxs,
-		EnumOutputTypes:    file_imports_test_a_1_m1_proto_enumTypes,
-		MessageOutputTypes: file_imports_test_a_1_m1_proto_msgTypes,
-		FilesRegistry:      protoregistry.GlobalFiles,
-		TypesRegistry:      protoregistry.GlobalTypes,
-	}.Init()
+	out := protoimpl.TypeBuilder{
+		File: protoimpl.DescBuilder{
+			RawDescriptor: file_imports_test_a_1_m1_proto_rawDesc,
+			NumEnums:      1,
+			NumMessages:   2,
+			NumExtensions: 0,
+			NumServices:   0,
+		},
+		GoTypes:           file_imports_test_a_1_m1_proto_goTypes,
+		DependencyIndexes: file_imports_test_a_1_m1_proto_depIdxs,
+		MessageInfos:      file_imports_test_a_1_m1_proto_msgTypes,
+	}.Build()
+	File_imports_test_a_1_m1_proto = out.File
+	file_imports_test_a_1_m1_proto_enumTypes = out.Enums
 	file_imports_test_a_1_m1_proto_rawDesc = nil
 	file_imports_test_a_1_m1_proto_goTypes = nil
 	file_imports_test_a_1_m1_proto_depIdxs = nil
diff --git a/cmd/protoc-gen-go/testdata/imports/test_a_1/m2.pb.go b/cmd/protoc-gen-go/testdata/imports/test_a_1/m2.pb.go
index 911f7b2..1884c23 100644
--- a/cmd/protoc-gen-go/testdata/imports/test_a_1/m2.pb.go
+++ b/cmd/protoc-gen-go/testdata/imports/test_a_1/m2.pb.go
@@ -5,7 +5,6 @@
 
 import (
 	protoreflect "google.golang.org/protobuf/reflect/protoreflect"
-	protoregistry "google.golang.org/protobuf/reflect/protoregistry"
 	protoiface "google.golang.org/protobuf/runtime/protoiface"
 	protoimpl "google.golang.org/protobuf/runtime/protoimpl"
 	sync "sync"
@@ -76,21 +75,32 @@
 var file_imports_test_a_1_m2_proto_goTypes = []interface{}{
 	(*M2)(nil), // 0: test.a.M2
 }
-var file_imports_test_a_1_m2_proto_depIdxs = []int32{}
+var file_imports_test_a_1_m2_proto_depIdxs = []int32{
+	0, // starting offset of method output_type sub-list
+	0, // starting offset of method input_type sub-list
+	0, // starting offset of extension type_name sub-list
+	0, // starting offset of extension extendee sub-list
+	0, // starting offset of field type_name sub-list
+}
 
 func init() { file_imports_test_a_1_m2_proto_init() }
 func file_imports_test_a_1_m2_proto_init() {
 	if File_imports_test_a_1_m2_proto != nil {
 		return
 	}
-	File_imports_test_a_1_m2_proto = protoimpl.FileBuilder{
-		RawDescriptor:      file_imports_test_a_1_m2_proto_rawDesc,
-		GoTypes:            file_imports_test_a_1_m2_proto_goTypes,
-		DependencyIndexes:  file_imports_test_a_1_m2_proto_depIdxs,
-		MessageOutputTypes: file_imports_test_a_1_m2_proto_msgTypes,
-		FilesRegistry:      protoregistry.GlobalFiles,
-		TypesRegistry:      protoregistry.GlobalTypes,
-	}.Init()
+	out := protoimpl.TypeBuilder{
+		File: protoimpl.DescBuilder{
+			RawDescriptor: file_imports_test_a_1_m2_proto_rawDesc,
+			NumEnums:      0,
+			NumMessages:   1,
+			NumExtensions: 0,
+			NumServices:   0,
+		},
+		GoTypes:           file_imports_test_a_1_m2_proto_goTypes,
+		DependencyIndexes: file_imports_test_a_1_m2_proto_depIdxs,
+		MessageInfos:      file_imports_test_a_1_m2_proto_msgTypes,
+	}.Build()
+	File_imports_test_a_1_m2_proto = out.File
 	file_imports_test_a_1_m2_proto_rawDesc = nil
 	file_imports_test_a_1_m2_proto_goTypes = nil
 	file_imports_test_a_1_m2_proto_depIdxs = nil
diff --git a/cmd/protoc-gen-go/testdata/imports/test_a_2/m3.pb.go b/cmd/protoc-gen-go/testdata/imports/test_a_2/m3.pb.go
index fa28027..319f61f 100644
--- a/cmd/protoc-gen-go/testdata/imports/test_a_2/m3.pb.go
+++ b/cmd/protoc-gen-go/testdata/imports/test_a_2/m3.pb.go
@@ -5,7 +5,6 @@
 
 import (
 	protoreflect "google.golang.org/protobuf/reflect/protoreflect"
-	protoregistry "google.golang.org/protobuf/reflect/protoregistry"
 	protoiface "google.golang.org/protobuf/runtime/protoiface"
 	protoimpl "google.golang.org/protobuf/runtime/protoimpl"
 	sync "sync"
@@ -76,21 +75,32 @@
 var file_imports_test_a_2_m3_proto_goTypes = []interface{}{
 	(*M3)(nil), // 0: test.a.M3
 }
-var file_imports_test_a_2_m3_proto_depIdxs = []int32{}
+var file_imports_test_a_2_m3_proto_depIdxs = []int32{
+	0, // starting offset of method output_type sub-list
+	0, // starting offset of method input_type sub-list
+	0, // starting offset of extension type_name sub-list
+	0, // starting offset of extension extendee sub-list
+	0, // starting offset of field type_name sub-list
+}
 
 func init() { file_imports_test_a_2_m3_proto_init() }
 func file_imports_test_a_2_m3_proto_init() {
 	if File_imports_test_a_2_m3_proto != nil {
 		return
 	}
-	File_imports_test_a_2_m3_proto = protoimpl.FileBuilder{
-		RawDescriptor:      file_imports_test_a_2_m3_proto_rawDesc,
-		GoTypes:            file_imports_test_a_2_m3_proto_goTypes,
-		DependencyIndexes:  file_imports_test_a_2_m3_proto_depIdxs,
-		MessageOutputTypes: file_imports_test_a_2_m3_proto_msgTypes,
-		FilesRegistry:      protoregistry.GlobalFiles,
-		TypesRegistry:      protoregistry.GlobalTypes,
-	}.Init()
+	out := protoimpl.TypeBuilder{
+		File: protoimpl.DescBuilder{
+			RawDescriptor: file_imports_test_a_2_m3_proto_rawDesc,
+			NumEnums:      0,
+			NumMessages:   1,
+			NumExtensions: 0,
+			NumServices:   0,
+		},
+		GoTypes:           file_imports_test_a_2_m3_proto_goTypes,
+		DependencyIndexes: file_imports_test_a_2_m3_proto_depIdxs,
+		MessageInfos:      file_imports_test_a_2_m3_proto_msgTypes,
+	}.Build()
+	File_imports_test_a_2_m3_proto = out.File
 	file_imports_test_a_2_m3_proto_rawDesc = nil
 	file_imports_test_a_2_m3_proto_goTypes = nil
 	file_imports_test_a_2_m3_proto_depIdxs = nil
diff --git a/cmd/protoc-gen-go/testdata/imports/test_a_2/m4.pb.go b/cmd/protoc-gen-go/testdata/imports/test_a_2/m4.pb.go
index 0d86e4e..47695eb 100644
--- a/cmd/protoc-gen-go/testdata/imports/test_a_2/m4.pb.go
+++ b/cmd/protoc-gen-go/testdata/imports/test_a_2/m4.pb.go
@@ -5,7 +5,6 @@
 
 import (
 	protoreflect "google.golang.org/protobuf/reflect/protoreflect"
-	protoregistry "google.golang.org/protobuf/reflect/protoregistry"
 	protoiface "google.golang.org/protobuf/runtime/protoiface"
 	protoimpl "google.golang.org/protobuf/runtime/protoimpl"
 	sync "sync"
@@ -76,21 +75,32 @@
 var file_imports_test_a_2_m4_proto_goTypes = []interface{}{
 	(*M4)(nil), // 0: test.a.M4
 }
-var file_imports_test_a_2_m4_proto_depIdxs = []int32{}
+var file_imports_test_a_2_m4_proto_depIdxs = []int32{
+	0, // starting offset of method output_type sub-list
+	0, // starting offset of method input_type sub-list
+	0, // starting offset of extension type_name sub-list
+	0, // starting offset of extension extendee sub-list
+	0, // starting offset of field type_name sub-list
+}
 
 func init() { file_imports_test_a_2_m4_proto_init() }
 func file_imports_test_a_2_m4_proto_init() {
 	if File_imports_test_a_2_m4_proto != nil {
 		return
 	}
-	File_imports_test_a_2_m4_proto = protoimpl.FileBuilder{
-		RawDescriptor:      file_imports_test_a_2_m4_proto_rawDesc,
-		GoTypes:            file_imports_test_a_2_m4_proto_goTypes,
-		DependencyIndexes:  file_imports_test_a_2_m4_proto_depIdxs,
-		MessageOutputTypes: file_imports_test_a_2_m4_proto_msgTypes,
-		FilesRegistry:      protoregistry.GlobalFiles,
-		TypesRegistry:      protoregistry.GlobalTypes,
-	}.Init()
+	out := protoimpl.TypeBuilder{
+		File: protoimpl.DescBuilder{
+			RawDescriptor: file_imports_test_a_2_m4_proto_rawDesc,
+			NumEnums:      0,
+			NumMessages:   1,
+			NumExtensions: 0,
+			NumServices:   0,
+		},
+		GoTypes:           file_imports_test_a_2_m4_proto_goTypes,
+		DependencyIndexes: file_imports_test_a_2_m4_proto_depIdxs,
+		MessageInfos:      file_imports_test_a_2_m4_proto_msgTypes,
+	}.Build()
+	File_imports_test_a_2_m4_proto = out.File
 	file_imports_test_a_2_m4_proto_rawDesc = nil
 	file_imports_test_a_2_m4_proto_goTypes = nil
 	file_imports_test_a_2_m4_proto_depIdxs = nil
diff --git a/cmd/protoc-gen-go/testdata/imports/test_b_1/m1.pb.go b/cmd/protoc-gen-go/testdata/imports/test_b_1/m1.pb.go
index 0dc09b0..acda349 100644
--- a/cmd/protoc-gen-go/testdata/imports/test_b_1/m1.pb.go
+++ b/cmd/protoc-gen-go/testdata/imports/test_b_1/m1.pb.go
@@ -5,7 +5,6 @@
 
 import (
 	protoreflect "google.golang.org/protobuf/reflect/protoreflect"
-	protoregistry "google.golang.org/protobuf/reflect/protoregistry"
 	protoiface "google.golang.org/protobuf/runtime/protoiface"
 	protoimpl "google.golang.org/protobuf/runtime/protoimpl"
 	sync "sync"
@@ -77,21 +76,32 @@
 var file_imports_test_b_1_m1_proto_goTypes = []interface{}{
 	(*M1)(nil), // 0: test.b.part1.M1
 }
-var file_imports_test_b_1_m1_proto_depIdxs = []int32{}
+var file_imports_test_b_1_m1_proto_depIdxs = []int32{
+	0, // starting offset of method output_type sub-list
+	0, // starting offset of method input_type sub-list
+	0, // starting offset of extension type_name sub-list
+	0, // starting offset of extension extendee sub-list
+	0, // starting offset of field type_name sub-list
+}
 
 func init() { file_imports_test_b_1_m1_proto_init() }
 func file_imports_test_b_1_m1_proto_init() {
 	if File_imports_test_b_1_m1_proto != nil {
 		return
 	}
-	File_imports_test_b_1_m1_proto = protoimpl.FileBuilder{
-		RawDescriptor:      file_imports_test_b_1_m1_proto_rawDesc,
-		GoTypes:            file_imports_test_b_1_m1_proto_goTypes,
-		DependencyIndexes:  file_imports_test_b_1_m1_proto_depIdxs,
-		MessageOutputTypes: file_imports_test_b_1_m1_proto_msgTypes,
-		FilesRegistry:      protoregistry.GlobalFiles,
-		TypesRegistry:      protoregistry.GlobalTypes,
-	}.Init()
+	out := protoimpl.TypeBuilder{
+		File: protoimpl.DescBuilder{
+			RawDescriptor: file_imports_test_b_1_m1_proto_rawDesc,
+			NumEnums:      0,
+			NumMessages:   1,
+			NumExtensions: 0,
+			NumServices:   0,
+		},
+		GoTypes:           file_imports_test_b_1_m1_proto_goTypes,
+		DependencyIndexes: file_imports_test_b_1_m1_proto_depIdxs,
+		MessageInfos:      file_imports_test_b_1_m1_proto_msgTypes,
+	}.Build()
+	File_imports_test_b_1_m1_proto = out.File
 	file_imports_test_b_1_m1_proto_rawDesc = nil
 	file_imports_test_b_1_m1_proto_goTypes = nil
 	file_imports_test_b_1_m1_proto_depIdxs = nil
diff --git a/cmd/protoc-gen-go/testdata/imports/test_b_1/m2.pb.go b/cmd/protoc-gen-go/testdata/imports/test_b_1/m2.pb.go
index 484a323..16e918f 100644
--- a/cmd/protoc-gen-go/testdata/imports/test_b_1/m2.pb.go
+++ b/cmd/protoc-gen-go/testdata/imports/test_b_1/m2.pb.go
@@ -5,7 +5,6 @@
 
 import (
 	protoreflect "google.golang.org/protobuf/reflect/protoreflect"
-	protoregistry "google.golang.org/protobuf/reflect/protoregistry"
 	protoiface "google.golang.org/protobuf/runtime/protoiface"
 	protoimpl "google.golang.org/protobuf/runtime/protoimpl"
 	sync "sync"
@@ -77,21 +76,32 @@
 var file_imports_test_b_1_m2_proto_goTypes = []interface{}{
 	(*M2)(nil), // 0: test.b.part2.M2
 }
-var file_imports_test_b_1_m2_proto_depIdxs = []int32{}
+var file_imports_test_b_1_m2_proto_depIdxs = []int32{
+	0, // starting offset of method output_type sub-list
+	0, // starting offset of method input_type sub-list
+	0, // starting offset of extension type_name sub-list
+	0, // starting offset of extension extendee sub-list
+	0, // starting offset of field type_name sub-list
+}
 
 func init() { file_imports_test_b_1_m2_proto_init() }
 func file_imports_test_b_1_m2_proto_init() {
 	if File_imports_test_b_1_m2_proto != nil {
 		return
 	}
-	File_imports_test_b_1_m2_proto = protoimpl.FileBuilder{
-		RawDescriptor:      file_imports_test_b_1_m2_proto_rawDesc,
-		GoTypes:            file_imports_test_b_1_m2_proto_goTypes,
-		DependencyIndexes:  file_imports_test_b_1_m2_proto_depIdxs,
-		MessageOutputTypes: file_imports_test_b_1_m2_proto_msgTypes,
-		FilesRegistry:      protoregistry.GlobalFiles,
-		TypesRegistry:      protoregistry.GlobalTypes,
-	}.Init()
+	out := protoimpl.TypeBuilder{
+		File: protoimpl.DescBuilder{
+			RawDescriptor: file_imports_test_b_1_m2_proto_rawDesc,
+			NumEnums:      0,
+			NumMessages:   1,
+			NumExtensions: 0,
+			NumServices:   0,
+		},
+		GoTypes:           file_imports_test_b_1_m2_proto_goTypes,
+		DependencyIndexes: file_imports_test_b_1_m2_proto_depIdxs,
+		MessageInfos:      file_imports_test_b_1_m2_proto_msgTypes,
+	}.Build()
+	File_imports_test_b_1_m2_proto = out.File
 	file_imports_test_b_1_m2_proto_rawDesc = nil
 	file_imports_test_b_1_m2_proto_goTypes = nil
 	file_imports_test_b_1_m2_proto_depIdxs = nil
diff --git a/cmd/protoc-gen-go/testdata/imports/test_import_a1m1.pb.go b/cmd/protoc-gen-go/testdata/imports/test_import_a1m1.pb.go
index b893f08..9d28776 100644
--- a/cmd/protoc-gen-go/testdata/imports/test_import_a1m1.pb.go
+++ b/cmd/protoc-gen-go/testdata/imports/test_import_a1m1.pb.go
@@ -6,7 +6,6 @@
 import (
 	test_a_1 "google.golang.org/protobuf/cmd/protoc-gen-go/testdata/imports/test_a_1"
 	protoreflect "google.golang.org/protobuf/reflect/protoreflect"
-	protoregistry "google.golang.org/protobuf/reflect/protoregistry"
 	protoiface "google.golang.org/protobuf/runtime/protoiface"
 	protoimpl "google.golang.org/protobuf/runtime/protoimpl"
 	sync "sync"
@@ -91,6 +90,11 @@
 }
 var file_imports_test_import_a1m1_proto_depIdxs = []int32{
 	1, // test.A1M1.f:type_name -> test.a.M1
+	1, // starting offset of method output_type sub-list
+	1, // starting offset of method input_type sub-list
+	1, // starting offset of extension type_name sub-list
+	1, // starting offset of extension extendee sub-list
+	0, // starting offset of field type_name sub-list
 }
 
 func init() { file_imports_test_import_a1m1_proto_init() }
@@ -98,14 +102,19 @@
 	if File_imports_test_import_a1m1_proto != nil {
 		return
 	}
-	File_imports_test_import_a1m1_proto = protoimpl.FileBuilder{
-		RawDescriptor:      file_imports_test_import_a1m1_proto_rawDesc,
-		GoTypes:            file_imports_test_import_a1m1_proto_goTypes,
-		DependencyIndexes:  file_imports_test_import_a1m1_proto_depIdxs,
-		MessageOutputTypes: file_imports_test_import_a1m1_proto_msgTypes,
-		FilesRegistry:      protoregistry.GlobalFiles,
-		TypesRegistry:      protoregistry.GlobalTypes,
-	}.Init()
+	out := protoimpl.TypeBuilder{
+		File: protoimpl.DescBuilder{
+			RawDescriptor: file_imports_test_import_a1m1_proto_rawDesc,
+			NumEnums:      0,
+			NumMessages:   1,
+			NumExtensions: 0,
+			NumServices:   0,
+		},
+		GoTypes:           file_imports_test_import_a1m1_proto_goTypes,
+		DependencyIndexes: file_imports_test_import_a1m1_proto_depIdxs,
+		MessageInfos:      file_imports_test_import_a1m1_proto_msgTypes,
+	}.Build()
+	File_imports_test_import_a1m1_proto = out.File
 	file_imports_test_import_a1m1_proto_rawDesc = nil
 	file_imports_test_import_a1m1_proto_goTypes = nil
 	file_imports_test_import_a1m1_proto_depIdxs = nil
diff --git a/cmd/protoc-gen-go/testdata/imports/test_import_a1m2.pb.go b/cmd/protoc-gen-go/testdata/imports/test_import_a1m2.pb.go
index 06a25da..55d689a 100644
--- a/cmd/protoc-gen-go/testdata/imports/test_import_a1m2.pb.go
+++ b/cmd/protoc-gen-go/testdata/imports/test_import_a1m2.pb.go
@@ -6,7 +6,6 @@
 import (
 	test_a_1 "google.golang.org/protobuf/cmd/protoc-gen-go/testdata/imports/test_a_1"
 	protoreflect "google.golang.org/protobuf/reflect/protoreflect"
-	protoregistry "google.golang.org/protobuf/reflect/protoregistry"
 	protoiface "google.golang.org/protobuf/runtime/protoiface"
 	protoimpl "google.golang.org/protobuf/runtime/protoimpl"
 	sync "sync"
@@ -91,6 +90,11 @@
 }
 var file_imports_test_import_a1m2_proto_depIdxs = []int32{
 	1, // test.A1M2.f:type_name -> test.a.M2
+	1, // starting offset of method output_type sub-list
+	1, // starting offset of method input_type sub-list
+	1, // starting offset of extension type_name sub-list
+	1, // starting offset of extension extendee sub-list
+	0, // starting offset of field type_name sub-list
 }
 
 func init() { file_imports_test_import_a1m2_proto_init() }
@@ -98,14 +102,19 @@
 	if File_imports_test_import_a1m2_proto != nil {
 		return
 	}
-	File_imports_test_import_a1m2_proto = protoimpl.FileBuilder{
-		RawDescriptor:      file_imports_test_import_a1m2_proto_rawDesc,
-		GoTypes:            file_imports_test_import_a1m2_proto_goTypes,
-		DependencyIndexes:  file_imports_test_import_a1m2_proto_depIdxs,
-		MessageOutputTypes: file_imports_test_import_a1m2_proto_msgTypes,
-		FilesRegistry:      protoregistry.GlobalFiles,
-		TypesRegistry:      protoregistry.GlobalTypes,
-	}.Init()
+	out := protoimpl.TypeBuilder{
+		File: protoimpl.DescBuilder{
+			RawDescriptor: file_imports_test_import_a1m2_proto_rawDesc,
+			NumEnums:      0,
+			NumMessages:   1,
+			NumExtensions: 0,
+			NumServices:   0,
+		},
+		GoTypes:           file_imports_test_import_a1m2_proto_goTypes,
+		DependencyIndexes: file_imports_test_import_a1m2_proto_depIdxs,
+		MessageInfos:      file_imports_test_import_a1m2_proto_msgTypes,
+	}.Build()
+	File_imports_test_import_a1m2_proto = out.File
 	file_imports_test_import_a1m2_proto_rawDesc = nil
 	file_imports_test_import_a1m2_proto_goTypes = nil
 	file_imports_test_import_a1m2_proto_depIdxs = nil
diff --git a/cmd/protoc-gen-go/testdata/imports/test_import_all.pb.go b/cmd/protoc-gen-go/testdata/imports/test_import_all.pb.go
index 2f50784..cd82745 100644
--- a/cmd/protoc-gen-go/testdata/imports/test_import_all.pb.go
+++ b/cmd/protoc-gen-go/testdata/imports/test_import_all.pb.go
@@ -9,7 +9,6 @@
 	_ "google.golang.org/protobuf/cmd/protoc-gen-go/testdata/imports/test_a_2"
 	test_b_1 "google.golang.org/protobuf/cmd/protoc-gen-go/testdata/imports/test_b_1"
 	protoreflect "google.golang.org/protobuf/reflect/protoreflect"
-	protoregistry "google.golang.org/protobuf/reflect/protoregistry"
 	protoiface "google.golang.org/protobuf/runtime/protoiface"
 	protoimpl "google.golang.org/protobuf/runtime/protoimpl"
 	sync "sync"
@@ -152,6 +151,11 @@
 	3, // test.All.bm1:type_name -> test.b.part1.M1
 	4, // test.All.bm2:type_name -> test.b.part2.M2
 	5, // test.All.fmt:type_name -> fmt.M
+	5, // starting offset of method output_type sub-list
+	5, // starting offset of method input_type sub-list
+	5, // starting offset of extension type_name sub-list
+	5, // starting offset of extension extendee sub-list
+	0, // starting offset of field type_name sub-list
 }
 
 func init() { file_imports_test_import_all_proto_init() }
@@ -159,14 +163,19 @@
 	if File_imports_test_import_all_proto != nil {
 		return
 	}
-	File_imports_test_import_all_proto = protoimpl.FileBuilder{
-		RawDescriptor:      file_imports_test_import_all_proto_rawDesc,
-		GoTypes:            file_imports_test_import_all_proto_goTypes,
-		DependencyIndexes:  file_imports_test_import_all_proto_depIdxs,
-		MessageOutputTypes: file_imports_test_import_all_proto_msgTypes,
-		FilesRegistry:      protoregistry.GlobalFiles,
-		TypesRegistry:      protoregistry.GlobalTypes,
-	}.Init()
+	out := protoimpl.TypeBuilder{
+		File: protoimpl.DescBuilder{
+			RawDescriptor: file_imports_test_import_all_proto_rawDesc,
+			NumEnums:      0,
+			NumMessages:   1,
+			NumExtensions: 0,
+			NumServices:   0,
+		},
+		GoTypes:           file_imports_test_import_all_proto_goTypes,
+		DependencyIndexes: file_imports_test_import_all_proto_depIdxs,
+		MessageInfos:      file_imports_test_import_all_proto_msgTypes,
+	}.Build()
+	File_imports_test_import_all_proto = out.File
 	file_imports_test_import_all_proto_rawDesc = nil
 	file_imports_test_import_all_proto_goTypes = nil
 	file_imports_test_import_all_proto_depIdxs = nil
diff --git a/cmd/protoc-gen-go/testdata/issue780_oneof_conflict/test.pb.go b/cmd/protoc-gen-go/testdata/issue780_oneof_conflict/test.pb.go
index 2d997fb..45db54d 100644
--- a/cmd/protoc-gen-go/testdata/issue780_oneof_conflict/test.pb.go
+++ b/cmd/protoc-gen-go/testdata/issue780_oneof_conflict/test.pb.go
@@ -5,7 +5,6 @@
 
 import (
 	protoreflect "google.golang.org/protobuf/reflect/protoreflect"
-	protoregistry "google.golang.org/protobuf/reflect/protoregistry"
 	protoiface "google.golang.org/protobuf/runtime/protoiface"
 	protoimpl "google.golang.org/protobuf/runtime/protoimpl"
 	sync "sync"
@@ -108,21 +107,32 @@
 var file_issue780_oneof_conflict_test_proto_goTypes = []interface{}{
 	(*Foo)(nil), // 0: oneoftest.Foo
 }
-var file_issue780_oneof_conflict_test_proto_depIdxs = []int32{}
+var file_issue780_oneof_conflict_test_proto_depIdxs = []int32{
+	0, // starting offset of method output_type sub-list
+	0, // starting offset of method input_type sub-list
+	0, // starting offset of extension type_name sub-list
+	0, // starting offset of extension extendee sub-list
+	0, // starting offset of field type_name sub-list
+}
 
 func init() { file_issue780_oneof_conflict_test_proto_init() }
 func file_issue780_oneof_conflict_test_proto_init() {
 	if File_issue780_oneof_conflict_test_proto != nil {
 		return
 	}
-	File_issue780_oneof_conflict_test_proto = protoimpl.FileBuilder{
-		RawDescriptor:      file_issue780_oneof_conflict_test_proto_rawDesc,
-		GoTypes:            file_issue780_oneof_conflict_test_proto_goTypes,
-		DependencyIndexes:  file_issue780_oneof_conflict_test_proto_depIdxs,
-		MessageOutputTypes: file_issue780_oneof_conflict_test_proto_msgTypes,
-		FilesRegistry:      protoregistry.GlobalFiles,
-		TypesRegistry:      protoregistry.GlobalTypes,
-	}.Init()
+	out := protoimpl.TypeBuilder{
+		File: protoimpl.DescBuilder{
+			RawDescriptor: file_issue780_oneof_conflict_test_proto_rawDesc,
+			NumEnums:      0,
+			NumMessages:   1,
+			NumExtensions: 0,
+			NumServices:   0,
+		},
+		GoTypes:           file_issue780_oneof_conflict_test_proto_goTypes,
+		DependencyIndexes: file_issue780_oneof_conflict_test_proto_depIdxs,
+		MessageInfos:      file_issue780_oneof_conflict_test_proto_msgTypes,
+	}.Build()
+	File_issue780_oneof_conflict_test_proto = out.File
 	file_issue780_oneof_conflict_test_proto_rawDesc = nil
 	file_issue780_oneof_conflict_test_proto_goTypes = nil
 	file_issue780_oneof_conflict_test_proto_depIdxs = nil
diff --git a/cmd/protoc-gen-go/testdata/nopackage/nopackage.pb.go b/cmd/protoc-gen-go/testdata/nopackage/nopackage.pb.go
index a9e3cf5..15c743f 100644
--- a/cmd/protoc-gen-go/testdata/nopackage/nopackage.pb.go
+++ b/cmd/protoc-gen-go/testdata/nopackage/nopackage.pb.go
@@ -5,7 +5,7 @@
 
 import (
 	protoreflect "google.golang.org/protobuf/reflect/protoreflect"
-	protoregistry "google.golang.org/protobuf/reflect/protoregistry"
+	prototype "google.golang.org/protobuf/reflect/prototype"
 	protoiface "google.golang.org/protobuf/runtime/protoiface"
 	protoimpl "google.golang.org/protobuf/runtime/protoimpl"
 	sync "sync"
@@ -45,7 +45,7 @@
 }
 
 func (Enum) Descriptor() protoreflect.EnumDescriptor {
-	return file_nopackage_nopackage_proto_enumTypes[0].Descriptor()
+	return file_nopackage_nopackage_proto_enumTypes[0].EnumDescriptor
 }
 
 func (x Enum) Number() protoreflect.EnumNumber {
@@ -140,7 +140,7 @@
 	return file_nopackage_nopackage_proto_rawDescData
 }
 
-var file_nopackage_nopackage_proto_enumTypes = make([]protoreflect.EnumType, 1)
+var file_nopackage_nopackage_proto_enumTypes = make([]prototype.Enum, 1)
 var file_nopackage_nopackage_proto_msgTypes = make([]protoimpl.MessageInfo, 1)
 var file_nopackage_nopackage_proto_goTypes = []interface{}{
 	(Enum)(0),       // 0: Enum
@@ -148,6 +148,11 @@
 }
 var file_nopackage_nopackage_proto_depIdxs = []int32{
 	0, // Message.enum_field:type_name -> Enum
+	1, // starting offset of method output_type sub-list
+	1, // starting offset of method input_type sub-list
+	1, // starting offset of extension type_name sub-list
+	1, // starting offset of extension extendee sub-list
+	0, // starting offset of field type_name sub-list
 }
 
 func init() { file_nopackage_nopackage_proto_init() }
@@ -155,15 +160,20 @@
 	if File_nopackage_nopackage_proto != nil {
 		return
 	}
-	File_nopackage_nopackage_proto = protoimpl.FileBuilder{
-		RawDescriptor:      file_nopackage_nopackage_proto_rawDesc,
-		GoTypes:            file_nopackage_nopackage_proto_goTypes,
-		DependencyIndexes:  file_nopackage_nopackage_proto_depIdxs,
-		EnumOutputTypes:    file_nopackage_nopackage_proto_enumTypes,
-		MessageOutputTypes: file_nopackage_nopackage_proto_msgTypes,
-		FilesRegistry:      protoregistry.GlobalFiles,
-		TypesRegistry:      protoregistry.GlobalTypes,
-	}.Init()
+	out := protoimpl.TypeBuilder{
+		File: protoimpl.DescBuilder{
+			RawDescriptor: file_nopackage_nopackage_proto_rawDesc,
+			NumEnums:      1,
+			NumMessages:   1,
+			NumExtensions: 0,
+			NumServices:   0,
+		},
+		GoTypes:           file_nopackage_nopackage_proto_goTypes,
+		DependencyIndexes: file_nopackage_nopackage_proto_depIdxs,
+		MessageInfos:      file_nopackage_nopackage_proto_msgTypes,
+	}.Build()
+	File_nopackage_nopackage_proto = out.File
+	file_nopackage_nopackage_proto_enumTypes = out.Enums
 	file_nopackage_nopackage_proto_rawDesc = nil
 	file_nopackage_nopackage_proto_goTypes = nil
 	file_nopackage_nopackage_proto_depIdxs = nil
diff --git a/cmd/protoc-gen-go/testdata/proto2/enum.pb.go b/cmd/protoc-gen-go/testdata/proto2/enum.pb.go
index 8f9c18b..b741f56 100644
--- a/cmd/protoc-gen-go/testdata/proto2/enum.pb.go
+++ b/cmd/protoc-gen-go/testdata/proto2/enum.pb.go
@@ -5,7 +5,7 @@
 
 import (
 	protoreflect "google.golang.org/protobuf/reflect/protoreflect"
-	protoregistry "google.golang.org/protobuf/reflect/protoregistry"
+	prototype "google.golang.org/protobuf/reflect/prototype"
 	protoiface "google.golang.org/protobuf/runtime/protoiface"
 	protoimpl "google.golang.org/protobuf/runtime/protoimpl"
 	sync "sync"
@@ -51,7 +51,7 @@
 }
 
 func (EnumType1) Descriptor() protoreflect.EnumDescriptor {
-	return file_proto2_enum_proto_enumTypes[0].Descriptor()
+	return file_proto2_enum_proto_enumTypes[0].EnumDescriptor
 }
 
 func (x EnumType1) Number() protoreflect.EnumNumber {
@@ -103,7 +103,7 @@
 }
 
 func (EnumType2) Descriptor() protoreflect.EnumDescriptor {
-	return file_proto2_enum_proto_enumTypes[1].Descriptor()
+	return file_proto2_enum_proto_enumTypes[1].EnumDescriptor
 }
 
 func (x EnumType2) Number() protoreflect.EnumNumber {
@@ -154,7 +154,7 @@
 }
 
 func (EnumContainerMessage1_NestedEnumType1A) Descriptor() protoreflect.EnumDescriptor {
-	return file_proto2_enum_proto_enumTypes[2].Descriptor()
+	return file_proto2_enum_proto_enumTypes[2].EnumDescriptor
 }
 
 func (x EnumContainerMessage1_NestedEnumType1A) Number() protoreflect.EnumNumber {
@@ -203,7 +203,7 @@
 }
 
 func (EnumContainerMessage1_NestedEnumType1B) Descriptor() protoreflect.EnumDescriptor {
-	return file_proto2_enum_proto_enumTypes[3].Descriptor()
+	return file_proto2_enum_proto_enumTypes[3].EnumDescriptor
 }
 
 func (x EnumContainerMessage1_NestedEnumType1B) Number() protoreflect.EnumNumber {
@@ -254,7 +254,7 @@
 }
 
 func (EnumContainerMessage1_EnumContainerMessage2_NestedEnumType2A) Descriptor() protoreflect.EnumDescriptor {
-	return file_proto2_enum_proto_enumTypes[4].Descriptor()
+	return file_proto2_enum_proto_enumTypes[4].EnumDescriptor
 }
 
 func (x EnumContainerMessage1_EnumContainerMessage2_NestedEnumType2A) Number() protoreflect.EnumNumber {
@@ -303,7 +303,7 @@
 }
 
 func (EnumContainerMessage1_EnumContainerMessage2_NestedEnumType2B) Descriptor() protoreflect.EnumDescriptor {
-	return file_proto2_enum_proto_enumTypes[5].Descriptor()
+	return file_proto2_enum_proto_enumTypes[5].EnumDescriptor
 }
 
 func (x EnumContainerMessage1_EnumContainerMessage2_NestedEnumType2B) Number() protoreflect.EnumNumber {
@@ -458,7 +458,7 @@
 	return file_proto2_enum_proto_rawDescData
 }
 
-var file_proto2_enum_proto_enumTypes = make([]protoreflect.EnumType, 6)
+var file_proto2_enum_proto_enumTypes = make([]prototype.Enum, 6)
 var file_proto2_enum_proto_msgTypes = make([]protoimpl.MessageInfo, 2)
 var file_proto2_enum_proto_goTypes = []interface{}{
 	(EnumType1)(0), // 0: goproto.protoc.proto2.EnumType1
@@ -473,6 +473,11 @@
 var file_proto2_enum_proto_depIdxs = []int32{
 	1, // goproto.protoc.proto2.EnumContainerMessage1.default_duplicate1:type_name -> goproto.protoc.proto2.EnumType2
 	1, // goproto.protoc.proto2.EnumContainerMessage1.default_duplicate2:type_name -> goproto.protoc.proto2.EnumType2
+	2, // starting offset of method output_type sub-list
+	2, // starting offset of method input_type sub-list
+	2, // starting offset of extension type_name sub-list
+	2, // starting offset of extension extendee sub-list
+	0, // starting offset of field type_name sub-list
 }
 
 func init() { file_proto2_enum_proto_init() }
@@ -480,15 +485,20 @@
 	if File_proto2_enum_proto != nil {
 		return
 	}
-	File_proto2_enum_proto = protoimpl.FileBuilder{
-		RawDescriptor:      file_proto2_enum_proto_rawDesc,
-		GoTypes:            file_proto2_enum_proto_goTypes,
-		DependencyIndexes:  file_proto2_enum_proto_depIdxs,
-		EnumOutputTypes:    file_proto2_enum_proto_enumTypes,
-		MessageOutputTypes: file_proto2_enum_proto_msgTypes,
-		FilesRegistry:      protoregistry.GlobalFiles,
-		TypesRegistry:      protoregistry.GlobalTypes,
-	}.Init()
+	out := protoimpl.TypeBuilder{
+		File: protoimpl.DescBuilder{
+			RawDescriptor: file_proto2_enum_proto_rawDesc,
+			NumEnums:      6,
+			NumMessages:   2,
+			NumExtensions: 0,
+			NumServices:   0,
+		},
+		GoTypes:           file_proto2_enum_proto_goTypes,
+		DependencyIndexes: file_proto2_enum_proto_depIdxs,
+		MessageInfos:      file_proto2_enum_proto_msgTypes,
+	}.Build()
+	File_proto2_enum_proto = out.File
+	file_proto2_enum_proto_enumTypes = out.Enums
 	file_proto2_enum_proto_rawDesc = nil
 	file_proto2_enum_proto_goTypes = nil
 	file_proto2_enum_proto_depIdxs = nil
diff --git a/cmd/protoc-gen-go/testdata/proto2/fields.pb.go b/cmd/protoc-gen-go/testdata/proto2/fields.pb.go
index afc649d..58970fc 100644
--- a/cmd/protoc-gen-go/testdata/proto2/fields.pb.go
+++ b/cmd/protoc-gen-go/testdata/proto2/fields.pb.go
@@ -5,7 +5,7 @@
 
 import (
 	protoreflect "google.golang.org/protobuf/reflect/protoreflect"
-	protoregistry "google.golang.org/protobuf/reflect/protoregistry"
+	prototype "google.golang.org/protobuf/reflect/prototype"
 	protoiface "google.golang.org/protobuf/runtime/protoiface"
 	protoimpl "google.golang.org/protobuf/runtime/protoimpl"
 	math "math"
@@ -49,7 +49,7 @@
 }
 
 func (FieldTestMessage_Enum) Descriptor() protoreflect.EnumDescriptor {
-	return file_proto2_fields_proto_enumTypes[0].Descriptor()
+	return file_proto2_fields_proto_enumTypes[0].EnumDescriptor
 }
 
 func (x FieldTestMessage_Enum) Number() protoreflect.EnumNumber {
@@ -1687,7 +1687,7 @@
 	return file_proto2_fields_proto_rawDescData
 }
 
-var file_proto2_fields_proto_enumTypes = make([]protoreflect.EnumType, 1)
+var file_proto2_fields_proto_enumTypes = make([]prototype.Enum, 1)
 var file_proto2_fields_proto_msgTypes = make([]protoimpl.MessageInfo, 9)
 var file_proto2_fields_proto_goTypes = []interface{}{
 	(FieldTestMessage_Enum)(0),             // 0: goproto.protoc.proto2.FieldTestMessage.Enum
@@ -1702,24 +1702,29 @@
 	(*FieldTestMessage_Message)(nil),       // 9: goproto.protoc.proto2.FieldTestMessage.Message
 }
 var file_proto2_fields_proto_depIdxs = []int32{
-	0, // goproto.protoc.proto2.FieldTestMessage.optional_enum:type_name -> goproto.protoc.proto2.FieldTestMessage.Enum
-	9, // goproto.protoc.proto2.FieldTestMessage.optional_Message:type_name -> goproto.protoc.proto2.FieldTestMessage.Message
-	2, // goproto.protoc.proto2.FieldTestMessage.optionalgroup:type_name -> goproto.protoc.proto2.FieldTestMessage.OptionalGroup
-	0, // goproto.protoc.proto2.FieldTestMessage.required_enum:type_name -> goproto.protoc.proto2.FieldTestMessage.Enum
-	9, // goproto.protoc.proto2.FieldTestMessage.required_Message:type_name -> goproto.protoc.proto2.FieldTestMessage.Message
-	3, // goproto.protoc.proto2.FieldTestMessage.requiredgroup:type_name -> goproto.protoc.proto2.FieldTestMessage.RequiredGroup
-	0, // goproto.protoc.proto2.FieldTestMessage.repeated_enum:type_name -> goproto.protoc.proto2.FieldTestMessage.Enum
-	9, // goproto.protoc.proto2.FieldTestMessage.repeated_Message:type_name -> goproto.protoc.proto2.FieldTestMessage.Message
-	4, // goproto.protoc.proto2.FieldTestMessage.repeatedgroup:type_name -> goproto.protoc.proto2.FieldTestMessage.RepeatedGroup
-	0, // goproto.protoc.proto2.FieldTestMessage.default_enum:type_name -> goproto.protoc.proto2.FieldTestMessage.Enum
-	5, // goproto.protoc.proto2.FieldTestMessage.map_int32_int64:type_name -> goproto.protoc.proto2.FieldTestMessage.MapInt32Int64Entry
-	6, // goproto.protoc.proto2.FieldTestMessage.map_string_message:type_name -> goproto.protoc.proto2.FieldTestMessage.MapStringMessageEntry
-	7, // goproto.protoc.proto2.FieldTestMessage.map_fixed64_enum:type_name -> goproto.protoc.proto2.FieldTestMessage.MapFixed64EnumEntry
-	0, // goproto.protoc.proto2.FieldTestMessage.oneof_enum:type_name -> goproto.protoc.proto2.FieldTestMessage.Enum
-	9, // goproto.protoc.proto2.FieldTestMessage.oneof_Message:type_name -> goproto.protoc.proto2.FieldTestMessage.Message
-	8, // goproto.protoc.proto2.FieldTestMessage.oneofgroup:type_name -> goproto.protoc.proto2.FieldTestMessage.OneofGroup
-	9, // goproto.protoc.proto2.FieldTestMessage.MapStringMessageEntry.value:type_name -> goproto.protoc.proto2.FieldTestMessage.Message
-	0, // goproto.protoc.proto2.FieldTestMessage.MapFixed64EnumEntry.value:type_name -> goproto.protoc.proto2.FieldTestMessage.Enum
+	0,  // goproto.protoc.proto2.FieldTestMessage.optional_enum:type_name -> goproto.protoc.proto2.FieldTestMessage.Enum
+	9,  // goproto.protoc.proto2.FieldTestMessage.optional_Message:type_name -> goproto.protoc.proto2.FieldTestMessage.Message
+	2,  // goproto.protoc.proto2.FieldTestMessage.optionalgroup:type_name -> goproto.protoc.proto2.FieldTestMessage.OptionalGroup
+	0,  // goproto.protoc.proto2.FieldTestMessage.required_enum:type_name -> goproto.protoc.proto2.FieldTestMessage.Enum
+	9,  // goproto.protoc.proto2.FieldTestMessage.required_Message:type_name -> goproto.protoc.proto2.FieldTestMessage.Message
+	3,  // goproto.protoc.proto2.FieldTestMessage.requiredgroup:type_name -> goproto.protoc.proto2.FieldTestMessage.RequiredGroup
+	0,  // goproto.protoc.proto2.FieldTestMessage.repeated_enum:type_name -> goproto.protoc.proto2.FieldTestMessage.Enum
+	9,  // goproto.protoc.proto2.FieldTestMessage.repeated_Message:type_name -> goproto.protoc.proto2.FieldTestMessage.Message
+	4,  // goproto.protoc.proto2.FieldTestMessage.repeatedgroup:type_name -> goproto.protoc.proto2.FieldTestMessage.RepeatedGroup
+	0,  // goproto.protoc.proto2.FieldTestMessage.default_enum:type_name -> goproto.protoc.proto2.FieldTestMessage.Enum
+	5,  // goproto.protoc.proto2.FieldTestMessage.map_int32_int64:type_name -> goproto.protoc.proto2.FieldTestMessage.MapInt32Int64Entry
+	6,  // goproto.protoc.proto2.FieldTestMessage.map_string_message:type_name -> goproto.protoc.proto2.FieldTestMessage.MapStringMessageEntry
+	7,  // goproto.protoc.proto2.FieldTestMessage.map_fixed64_enum:type_name -> goproto.protoc.proto2.FieldTestMessage.MapFixed64EnumEntry
+	0,  // goproto.protoc.proto2.FieldTestMessage.oneof_enum:type_name -> goproto.protoc.proto2.FieldTestMessage.Enum
+	9,  // goproto.protoc.proto2.FieldTestMessage.oneof_Message:type_name -> goproto.protoc.proto2.FieldTestMessage.Message
+	8,  // goproto.protoc.proto2.FieldTestMessage.oneofgroup:type_name -> goproto.protoc.proto2.FieldTestMessage.OneofGroup
+	9,  // goproto.protoc.proto2.FieldTestMessage.MapStringMessageEntry.value:type_name -> goproto.protoc.proto2.FieldTestMessage.Message
+	0,  // goproto.protoc.proto2.FieldTestMessage.MapFixed64EnumEntry.value:type_name -> goproto.protoc.proto2.FieldTestMessage.Enum
+	18, // starting offset of method output_type sub-list
+	18, // starting offset of method input_type sub-list
+	18, // starting offset of extension type_name sub-list
+	18, // starting offset of extension extendee sub-list
+	0,  // starting offset of field type_name sub-list
 }
 
 func init() { file_proto2_fields_proto_init() }
@@ -1727,15 +1732,20 @@
 	if File_proto2_fields_proto != nil {
 		return
 	}
-	File_proto2_fields_proto = protoimpl.FileBuilder{
-		RawDescriptor:      file_proto2_fields_proto_rawDesc,
-		GoTypes:            file_proto2_fields_proto_goTypes,
-		DependencyIndexes:  file_proto2_fields_proto_depIdxs,
-		EnumOutputTypes:    file_proto2_fields_proto_enumTypes,
-		MessageOutputTypes: file_proto2_fields_proto_msgTypes,
-		FilesRegistry:      protoregistry.GlobalFiles,
-		TypesRegistry:      protoregistry.GlobalTypes,
-	}.Init()
+	out := protoimpl.TypeBuilder{
+		File: protoimpl.DescBuilder{
+			RawDescriptor: file_proto2_fields_proto_rawDesc,
+			NumEnums:      1,
+			NumMessages:   9,
+			NumExtensions: 0,
+			NumServices:   0,
+		},
+		GoTypes:           file_proto2_fields_proto_goTypes,
+		DependencyIndexes: file_proto2_fields_proto_depIdxs,
+		MessageInfos:      file_proto2_fields_proto_msgTypes,
+	}.Build()
+	File_proto2_fields_proto = out.File
+	file_proto2_fields_proto_enumTypes = out.Enums
 	file_proto2_fields_proto_rawDesc = nil
 	file_proto2_fields_proto_goTypes = nil
 	file_proto2_fields_proto_depIdxs = nil
diff --git a/cmd/protoc-gen-go/testdata/proto2/nested_messages.pb.go b/cmd/protoc-gen-go/testdata/proto2/nested_messages.pb.go
index 1533c5d..16da78e 100644
--- a/cmd/protoc-gen-go/testdata/proto2/nested_messages.pb.go
+++ b/cmd/protoc-gen-go/testdata/proto2/nested_messages.pb.go
@@ -5,7 +5,6 @@
 
 import (
 	protoreflect "google.golang.org/protobuf/reflect/protoreflect"
-	protoregistry "google.golang.org/protobuf/reflect/protoregistry"
 	protoiface "google.golang.org/protobuf/runtime/protoiface"
 	protoimpl "google.golang.org/protobuf/runtime/protoimpl"
 	sync "sync"
@@ -177,6 +176,11 @@
 	1, // goproto.protoc.proto2.Layer1.l2:type_name -> goproto.protoc.proto2.Layer1.Layer2
 	2, // goproto.protoc.proto2.Layer1.l3:type_name -> goproto.protoc.proto2.Layer1.Layer2.Layer3
 	2, // goproto.protoc.proto2.Layer1.Layer2.l3:type_name -> goproto.protoc.proto2.Layer1.Layer2.Layer3
+	3, // starting offset of method output_type sub-list
+	3, // starting offset of method input_type sub-list
+	3, // starting offset of extension type_name sub-list
+	3, // starting offset of extension extendee sub-list
+	0, // starting offset of field type_name sub-list
 }
 
 func init() { file_proto2_nested_messages_proto_init() }
@@ -184,14 +188,19 @@
 	if File_proto2_nested_messages_proto != nil {
 		return
 	}
-	File_proto2_nested_messages_proto = protoimpl.FileBuilder{
-		RawDescriptor:      file_proto2_nested_messages_proto_rawDesc,
-		GoTypes:            file_proto2_nested_messages_proto_goTypes,
-		DependencyIndexes:  file_proto2_nested_messages_proto_depIdxs,
-		MessageOutputTypes: file_proto2_nested_messages_proto_msgTypes,
-		FilesRegistry:      protoregistry.GlobalFiles,
-		TypesRegistry:      protoregistry.GlobalTypes,
-	}.Init()
+	out := protoimpl.TypeBuilder{
+		File: protoimpl.DescBuilder{
+			RawDescriptor: file_proto2_nested_messages_proto_rawDesc,
+			NumEnums:      0,
+			NumMessages:   3,
+			NumExtensions: 0,
+			NumServices:   0,
+		},
+		GoTypes:           file_proto2_nested_messages_proto_goTypes,
+		DependencyIndexes: file_proto2_nested_messages_proto_depIdxs,
+		MessageInfos:      file_proto2_nested_messages_proto_msgTypes,
+	}.Build()
+	File_proto2_nested_messages_proto = out.File
 	file_proto2_nested_messages_proto_rawDesc = nil
 	file_proto2_nested_messages_proto_goTypes = nil
 	file_proto2_nested_messages_proto_depIdxs = nil
diff --git a/cmd/protoc-gen-go/testdata/proto2/proto2.pb.go b/cmd/protoc-gen-go/testdata/proto2/proto2.pb.go
index 3bd3917..dfa61e5 100644
--- a/cmd/protoc-gen-go/testdata/proto2/proto2.pb.go
+++ b/cmd/protoc-gen-go/testdata/proto2/proto2.pb.go
@@ -5,7 +5,6 @@
 
 import (
 	protoreflect "google.golang.org/protobuf/reflect/protoreflect"
-	protoregistry "google.golang.org/protobuf/reflect/protoregistry"
 	protoiface "google.golang.org/protobuf/runtime/protoiface"
 	protoimpl "google.golang.org/protobuf/runtime/protoimpl"
 	sync "sync"
@@ -98,6 +97,11 @@
 }
 var file_proto2_proto2_proto_depIdxs = []int32{
 	0, // goproto.protoc.proto2.Message.m:type_name -> goproto.protoc.proto2.Message
+	1, // starting offset of method output_type sub-list
+	1, // starting offset of method input_type sub-list
+	1, // starting offset of extension type_name sub-list
+	1, // starting offset of extension extendee sub-list
+	0, // starting offset of field type_name sub-list
 }
 
 func init() { file_proto2_proto2_proto_init() }
@@ -105,14 +109,19 @@
 	if File_proto2_proto2_proto != nil {
 		return
 	}
-	File_proto2_proto2_proto = protoimpl.FileBuilder{
-		RawDescriptor:      file_proto2_proto2_proto_rawDesc,
-		GoTypes:            file_proto2_proto2_proto_goTypes,
-		DependencyIndexes:  file_proto2_proto2_proto_depIdxs,
-		MessageOutputTypes: file_proto2_proto2_proto_msgTypes,
-		FilesRegistry:      protoregistry.GlobalFiles,
-		TypesRegistry:      protoregistry.GlobalTypes,
-	}.Init()
+	out := protoimpl.TypeBuilder{
+		File: protoimpl.DescBuilder{
+			RawDescriptor: file_proto2_proto2_proto_rawDesc,
+			NumEnums:      0,
+			NumMessages:   1,
+			NumExtensions: 0,
+			NumServices:   0,
+		},
+		GoTypes:           file_proto2_proto2_proto_goTypes,
+		DependencyIndexes: file_proto2_proto2_proto_depIdxs,
+		MessageInfos:      file_proto2_proto2_proto_msgTypes,
+	}.Build()
+	File_proto2_proto2_proto = out.File
 	file_proto2_proto2_proto_rawDesc = nil
 	file_proto2_proto2_proto_goTypes = nil
 	file_proto2_proto2_proto_depIdxs = nil
diff --git a/cmd/protoc-gen-go/testdata/proto3/enum.pb.go b/cmd/protoc-gen-go/testdata/proto3/enum.pb.go
index 7515d4a..97a38fc 100644
--- a/cmd/protoc-gen-go/testdata/proto3/enum.pb.go
+++ b/cmd/protoc-gen-go/testdata/proto3/enum.pb.go
@@ -5,7 +5,7 @@
 
 import (
 	protoreflect "google.golang.org/protobuf/reflect/protoreflect"
-	protoregistry "google.golang.org/protobuf/reflect/protoregistry"
+	prototype "google.golang.org/protobuf/reflect/prototype"
 	protoimpl "google.golang.org/protobuf/runtime/protoimpl"
 	sync "sync"
 )
@@ -50,7 +50,7 @@
 }
 
 func (Enum) Descriptor() protoreflect.EnumDescriptor {
-	return file_proto3_enum_proto_enumTypes[0].Descriptor()
+	return file_proto3_enum_proto_enumTypes[0].EnumDescriptor
 }
 
 func (x Enum) Number() protoreflect.EnumNumber {
@@ -89,25 +89,36 @@
 	return file_proto3_enum_proto_rawDescData
 }
 
-var file_proto3_enum_proto_enumTypes = make([]protoreflect.EnumType, 1)
+var file_proto3_enum_proto_enumTypes = make([]prototype.Enum, 1)
 var file_proto3_enum_proto_goTypes = []interface{}{
 	(Enum)(0), // 0: goproto.protoc.proto3.Enum
 }
-var file_proto3_enum_proto_depIdxs = []int32{}
+var file_proto3_enum_proto_depIdxs = []int32{
+	0, // starting offset of method output_type sub-list
+	0, // starting offset of method input_type sub-list
+	0, // starting offset of extension type_name sub-list
+	0, // starting offset of extension extendee sub-list
+	0, // starting offset of field type_name sub-list
+}
 
 func init() { file_proto3_enum_proto_init() }
 func file_proto3_enum_proto_init() {
 	if File_proto3_enum_proto != nil {
 		return
 	}
-	File_proto3_enum_proto = protoimpl.FileBuilder{
-		RawDescriptor:     file_proto3_enum_proto_rawDesc,
+	out := protoimpl.TypeBuilder{
+		File: protoimpl.DescBuilder{
+			RawDescriptor: file_proto3_enum_proto_rawDesc,
+			NumEnums:      1,
+			NumMessages:   0,
+			NumExtensions: 0,
+			NumServices:   0,
+		},
 		GoTypes:           file_proto3_enum_proto_goTypes,
 		DependencyIndexes: file_proto3_enum_proto_depIdxs,
-		EnumOutputTypes:   file_proto3_enum_proto_enumTypes,
-		FilesRegistry:     protoregistry.GlobalFiles,
-		TypesRegistry:     protoregistry.GlobalTypes,
-	}.Init()
+	}.Build()
+	File_proto3_enum_proto = out.File
+	file_proto3_enum_proto_enumTypes = out.Enums
 	file_proto3_enum_proto_rawDesc = nil
 	file_proto3_enum_proto_goTypes = nil
 	file_proto3_enum_proto_depIdxs = nil
diff --git a/cmd/protoc-gen-go/testdata/proto3/fields.pb.go b/cmd/protoc-gen-go/testdata/proto3/fields.pb.go
index 81906e9..6023685 100644
--- a/cmd/protoc-gen-go/testdata/proto3/fields.pb.go
+++ b/cmd/protoc-gen-go/testdata/proto3/fields.pb.go
@@ -5,7 +5,7 @@
 
 import (
 	protoreflect "google.golang.org/protobuf/reflect/protoreflect"
-	protoregistry "google.golang.org/protobuf/reflect/protoregistry"
+	prototype "google.golang.org/protobuf/reflect/prototype"
 	protoiface "google.golang.org/protobuf/runtime/protoiface"
 	protoimpl "google.golang.org/protobuf/runtime/protoimpl"
 	sync "sync"
@@ -45,7 +45,7 @@
 }
 
 func (FieldTestMessage_Enum) Descriptor() protoreflect.EnumDescriptor {
-	return file_proto3_fields_proto_enumTypes[0].Descriptor()
+	return file_proto3_fields_proto_enumTypes[0].EnumDescriptor
 }
 
 func (x FieldTestMessage_Enum) Number() protoreflect.EnumNumber {
@@ -577,7 +577,7 @@
 	return file_proto3_fields_proto_rawDescData
 }
 
-var file_proto3_fields_proto_enumTypes = make([]protoreflect.EnumType, 1)
+var file_proto3_fields_proto_enumTypes = make([]prototype.Enum, 1)
 var file_proto3_fields_proto_msgTypes = make([]protoimpl.MessageInfo, 5)
 var file_proto3_fields_proto_goTypes = []interface{}{
 	(FieldTestMessage_Enum)(0),       // 0: goproto.protoc.proto3.FieldTestMessage.Enum
@@ -597,6 +597,11 @@
 	4, // goproto.protoc.proto3.FieldTestMessage.map_fixed64_enum:type_name -> goproto.protoc.proto3.FieldTestMessage.MapFixed64EnumEntry
 	5, // goproto.protoc.proto3.FieldTestMessage.MapStringMessageEntry.value:type_name -> goproto.protoc.proto3.FieldTestMessage.Message
 	0, // goproto.protoc.proto3.FieldTestMessage.MapFixed64EnumEntry.value:type_name -> goproto.protoc.proto3.FieldTestMessage.Enum
+	9, // starting offset of method output_type sub-list
+	9, // starting offset of method input_type sub-list
+	9, // starting offset of extension type_name sub-list
+	9, // starting offset of extension extendee sub-list
+	0, // starting offset of field type_name sub-list
 }
 
 func init() { file_proto3_fields_proto_init() }
@@ -604,15 +609,20 @@
 	if File_proto3_fields_proto != nil {
 		return
 	}
-	File_proto3_fields_proto = protoimpl.FileBuilder{
-		RawDescriptor:      file_proto3_fields_proto_rawDesc,
-		GoTypes:            file_proto3_fields_proto_goTypes,
-		DependencyIndexes:  file_proto3_fields_proto_depIdxs,
-		EnumOutputTypes:    file_proto3_fields_proto_enumTypes,
-		MessageOutputTypes: file_proto3_fields_proto_msgTypes,
-		FilesRegistry:      protoregistry.GlobalFiles,
-		TypesRegistry:      protoregistry.GlobalTypes,
-	}.Init()
+	out := protoimpl.TypeBuilder{
+		File: protoimpl.DescBuilder{
+			RawDescriptor: file_proto3_fields_proto_rawDesc,
+			NumEnums:      1,
+			NumMessages:   5,
+			NumExtensions: 0,
+			NumServices:   0,
+		},
+		GoTypes:           file_proto3_fields_proto_goTypes,
+		DependencyIndexes: file_proto3_fields_proto_depIdxs,
+		MessageInfos:      file_proto3_fields_proto_msgTypes,
+	}.Build()
+	File_proto3_fields_proto = out.File
+	file_proto3_fields_proto_enumTypes = out.Enums
 	file_proto3_fields_proto_rawDesc = nil
 	file_proto3_fields_proto_goTypes = nil
 	file_proto3_fields_proto_depIdxs = nil
diff --git a/encoding/prototext/other_test.go b/encoding/prototext/other_test.go
index 978a358..ec1842f 100644
--- a/encoding/prototext/other_test.go
+++ b/encoding/prototext/other_test.go
@@ -1,3 +1,7 @@
+// 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 prototext_test
 
 import (
diff --git a/encoding/testprotos/pb2/test.pb.go b/encoding/testprotos/pb2/test.pb.go
index 63b9cf0..738abe7 100644
--- a/encoding/testprotos/pb2/test.pb.go
+++ b/encoding/testprotos/pb2/test.pb.go
@@ -5,7 +5,7 @@
 
 import (
 	protoreflect "google.golang.org/protobuf/reflect/protoreflect"
-	protoregistry "google.golang.org/protobuf/reflect/protoregistry"
+	prototype "google.golang.org/protobuf/reflect/prototype"
 	protoiface "google.golang.org/protobuf/runtime/protoiface"
 	protoimpl "google.golang.org/protobuf/runtime/protoimpl"
 	anypb "google.golang.org/protobuf/types/known/anypb"
@@ -58,7 +58,7 @@
 }
 
 func (Enum) Descriptor() protoreflect.EnumDescriptor {
-	return file_pb2_test_proto_enumTypes[0].Descriptor()
+	return file_pb2_test_proto_enumTypes[0].EnumDescriptor
 }
 
 func (x Enum) Number() protoreflect.EnumNumber {
@@ -113,7 +113,7 @@
 }
 
 func (Enums_NestedEnum) Descriptor() protoreflect.EnumDescriptor {
-	return file_pb2_test_proto_enumTypes[1].Descriptor()
+	return file_pb2_test_proto_enumTypes[1].EnumDescriptor
 }
 
 func (x Enums_NestedEnum) Number() protoreflect.EnumNumber {
@@ -1941,7 +1941,7 @@
 	return file_pb2_test_proto_rawDescData
 }
 
-var file_pb2_test_proto_enumTypes = make([]protoreflect.EnumType, 2)
+var file_pb2_test_proto_enumTypes = make([]prototype.Enum, 2)
 var file_pb2_test_proto_msgTypes = make([]protoimpl.MessageInfo, 20)
 var file_pb2_test_proto_goTypes = []interface{}{
 	(Enum)(0),                             // 0: pb2.Enum
@@ -1986,27 +1986,6 @@
 	(*fieldmaskpb.FieldMask)(nil),         // 39: google.protobuf.FieldMask
 }
 var file_pb2_test_proto_depIdxs = []int32{
-	11, // pb2.opt_ext_bool:extendee -> pb2.Extensions
-	11, // pb2.opt_ext_string:extendee -> pb2.Extensions
-	11, // pb2.opt_ext_enum:extendee -> pb2.Extensions
-	11, // pb2.opt_ext_nested:extendee -> pb2.Extensions
-	11, // pb2.opt_ext_partial:extendee -> pb2.Extensions
-	11, // pb2.rpt_ext_fixed32:extendee -> pb2.Extensions
-	11, // pb2.rpt_ext_enum:extendee -> pb2.Extensions
-	11, // pb2.rpt_ext_nested:extendee -> pb2.Extensions
-	13, // pb2.message_set_extension:extendee -> pb2.MessageSet
-	11, // pb2.ExtensionsContainer.opt_ext_bool:extendee -> pb2.Extensions
-	11, // pb2.ExtensionsContainer.opt_ext_string:extendee -> pb2.Extensions
-	11, // pb2.ExtensionsContainer.opt_ext_enum:extendee -> pb2.Extensions
-	11, // pb2.ExtensionsContainer.opt_ext_nested:extendee -> pb2.Extensions
-	11, // pb2.ExtensionsContainer.opt_ext_partial:extendee -> pb2.Extensions
-	11, // pb2.ExtensionsContainer.rpt_ext_string:extendee -> pb2.Extensions
-	11, // pb2.ExtensionsContainer.rpt_ext_enum:extendee -> pb2.Extensions
-	11, // pb2.ExtensionsContainer.rpt_ext_nested:extendee -> pb2.Extensions
-	13, // pb2.MessageSetExtension.message_set_extension:extendee -> pb2.MessageSet
-	13, // pb2.MessageSetExtension.not_message_set_extension:extendee -> pb2.MessageSet
-	13, // pb2.MessageSetExtension.ext_nested:extendee -> pb2.MessageSet
-	15, // pb2.FakeMessageSetExtension.message_set_extension:extendee -> pb2.FakeMessageSet
 	0,  // pb2.Enums.opt_enum:type_name -> pb2.Enum
 	0,  // pb2.Enums.rpt_enum:type_name -> pb2.Enum
 	1,  // pb2.Enums.opt_nested_enum:type_name -> pb2.Enums.NestedEnum
@@ -2043,6 +2022,27 @@
 	5,  // pb2.Nests.OptGroup.opt_nested:type_name -> pb2.Nested
 	20, // pb2.Nests.OptGroup.optnestedgroup:type_name -> pb2.Nests.OptGroup.OptNestedGroup
 	9,  // pb2.IndirectRequired.StrToNestedEntry.value:type_name -> pb2.NestedWithRequired
+	11, // pb2.opt_ext_bool:extendee -> pb2.Extensions
+	11, // pb2.opt_ext_string:extendee -> pb2.Extensions
+	11, // pb2.opt_ext_enum:extendee -> pb2.Extensions
+	11, // pb2.opt_ext_nested:extendee -> pb2.Extensions
+	11, // pb2.opt_ext_partial:extendee -> pb2.Extensions
+	11, // pb2.rpt_ext_fixed32:extendee -> pb2.Extensions
+	11, // pb2.rpt_ext_enum:extendee -> pb2.Extensions
+	11, // pb2.rpt_ext_nested:extendee -> pb2.Extensions
+	13, // pb2.message_set_extension:extendee -> pb2.MessageSet
+	11, // pb2.ExtensionsContainer.opt_ext_bool:extendee -> pb2.Extensions
+	11, // pb2.ExtensionsContainer.opt_ext_string:extendee -> pb2.Extensions
+	11, // pb2.ExtensionsContainer.opt_ext_enum:extendee -> pb2.Extensions
+	11, // pb2.ExtensionsContainer.opt_ext_nested:extendee -> pb2.Extensions
+	11, // pb2.ExtensionsContainer.opt_ext_partial:extendee -> pb2.Extensions
+	11, // pb2.ExtensionsContainer.rpt_ext_string:extendee -> pb2.Extensions
+	11, // pb2.ExtensionsContainer.rpt_ext_enum:extendee -> pb2.Extensions
+	11, // pb2.ExtensionsContainer.rpt_ext_nested:extendee -> pb2.Extensions
+	13, // pb2.MessageSetExtension.message_set_extension:extendee -> pb2.MessageSet
+	13, // pb2.MessageSetExtension.not_message_set_extension:extendee -> pb2.MessageSet
+	13, // pb2.MessageSetExtension.ext_nested:extendee -> pb2.MessageSet
+	15, // pb2.FakeMessageSetExtension.message_set_extension:extendee -> pb2.FakeMessageSet
 	0,  // pb2.opt_ext_enum:type_name -> pb2.Enum
 	5,  // pb2.opt_ext_nested:type_name -> pb2.Nested
 	8,  // pb2.opt_ext_partial:type_name -> pb2.PartialRequired
@@ -2058,6 +2058,11 @@
 	14, // pb2.MessageSetExtension.not_message_set_extension:type_name -> pb2.MessageSetExtension
 	5,  // pb2.MessageSetExtension.ext_nested:type_name -> pb2.Nested
 	16, // pb2.FakeMessageSetExtension.message_set_extension:type_name -> pb2.FakeMessageSetExtension
+	72, // starting offset of method output_type sub-list
+	72, // starting offset of method input_type sub-list
+	57, // starting offset of extension type_name sub-list
+	36, // starting offset of extension extendee sub-list
+	0,  // starting offset of field type_name sub-list
 }
 
 func init() { file_pb2_test_proto_init() }
@@ -2065,18 +2070,21 @@
 	if File_pb2_test_proto != nil {
 		return
 	}
-	extensionTypes := make([]protoreflect.ExtensionType, 21)
-	File_pb2_test_proto = protoimpl.FileBuilder{
-		RawDescriptor:        file_pb2_test_proto_rawDesc,
-		GoTypes:              file_pb2_test_proto_goTypes,
-		DependencyIndexes:    file_pb2_test_proto_depIdxs,
-		LegacyExtensions:     file_pb2_test_proto_extDescs,
-		EnumOutputTypes:      file_pb2_test_proto_enumTypes,
-		MessageOutputTypes:   file_pb2_test_proto_msgTypes,
-		ExtensionOutputTypes: extensionTypes,
-		FilesRegistry:        protoregistry.GlobalFiles,
-		TypesRegistry:        protoregistry.GlobalTypes,
-	}.Init()
+	out := protoimpl.TypeBuilder{
+		File: protoimpl.DescBuilder{
+			RawDescriptor: file_pb2_test_proto_rawDesc,
+			NumEnums:      2,
+			NumMessages:   20,
+			NumExtensions: 21,
+			NumServices:   0,
+		},
+		GoTypes:           file_pb2_test_proto_goTypes,
+		DependencyIndexes: file_pb2_test_proto_depIdxs,
+		MessageInfos:      file_pb2_test_proto_msgTypes,
+		LegacyExtensions:  file_pb2_test_proto_extDescs,
+	}.Build()
+	File_pb2_test_proto = out.File
+	file_pb2_test_proto_enumTypes = out.Enums
 	file_pb2_test_proto_rawDesc = nil
 	file_pb2_test_proto_goTypes = nil
 	file_pb2_test_proto_depIdxs = nil
diff --git a/encoding/testprotos/pb3/test.pb.go b/encoding/testprotos/pb3/test.pb.go
index 0ec0eaf..1b0349a 100644
--- a/encoding/testprotos/pb3/test.pb.go
+++ b/encoding/testprotos/pb3/test.pb.go
@@ -5,7 +5,7 @@
 
 import (
 	protoreflect "google.golang.org/protobuf/reflect/protoreflect"
-	protoregistry "google.golang.org/protobuf/reflect/protoregistry"
+	prototype "google.golang.org/protobuf/reflect/prototype"
 	protoiface "google.golang.org/protobuf/runtime/protoiface"
 	protoimpl "google.golang.org/protobuf/runtime/protoimpl"
 	sync "sync"
@@ -54,7 +54,7 @@
 }
 
 func (Enum) Descriptor() protoreflect.EnumDescriptor {
-	return file_pb3_test_proto_enumTypes[0].Descriptor()
+	return file_pb3_test_proto_enumTypes[0].EnumDescriptor
 }
 
 func (x Enum) Number() protoreflect.EnumNumber {
@@ -102,7 +102,7 @@
 }
 
 func (Enums_NestedEnum) Descriptor() protoreflect.EnumDescriptor {
-	return file_pb3_test_proto_enumTypes[1].Descriptor()
+	return file_pb3_test_proto_enumTypes[1].EnumDescriptor
 }
 
 func (x Enums_NestedEnum) Number() protoreflect.EnumNumber {
@@ -720,7 +720,7 @@
 	return file_pb3_test_proto_rawDescData
 }
 
-var file_pb3_test_proto_enumTypes = make([]protoreflect.EnumType, 2)
+var file_pb3_test_proto_enumTypes = make([]prototype.Enum, 2)
 var file_pb3_test_proto_msgTypes = make([]protoimpl.MessageInfo, 12)
 var file_pb3_test_proto_goTypes = []interface{}{
 	(Enum)(0),             // 0: pb3.Enum
@@ -753,6 +753,11 @@
 	0,  // pb3.Maps.Uint64ToEnumEntry.value:type_name -> pb3.Enum
 	5,  // pb3.Maps.StrToNestedEntry.value:type_name -> pb3.Nested
 	6,  // pb3.Maps.StrToOneofsEntry.value:type_name -> pb3.Oneofs
+	14, // starting offset of method output_type sub-list
+	14, // starting offset of method input_type sub-list
+	14, // starting offset of extension type_name sub-list
+	14, // starting offset of extension extendee sub-list
+	0,  // starting offset of field type_name sub-list
 }
 
 func init() { file_pb3_test_proto_init() }
@@ -760,15 +765,20 @@
 	if File_pb3_test_proto != nil {
 		return
 	}
-	File_pb3_test_proto = protoimpl.FileBuilder{
-		RawDescriptor:      file_pb3_test_proto_rawDesc,
-		GoTypes:            file_pb3_test_proto_goTypes,
-		DependencyIndexes:  file_pb3_test_proto_depIdxs,
-		EnumOutputTypes:    file_pb3_test_proto_enumTypes,
-		MessageOutputTypes: file_pb3_test_proto_msgTypes,
-		FilesRegistry:      protoregistry.GlobalFiles,
-		TypesRegistry:      protoregistry.GlobalTypes,
-	}.Init()
+	out := protoimpl.TypeBuilder{
+		File: protoimpl.DescBuilder{
+			RawDescriptor: file_pb3_test_proto_rawDesc,
+			NumEnums:      2,
+			NumMessages:   12,
+			NumExtensions: 0,
+			NumServices:   0,
+		},
+		GoTypes:           file_pb3_test_proto_goTypes,
+		DependencyIndexes: file_pb3_test_proto_depIdxs,
+		MessageInfos:      file_pb3_test_proto_msgTypes,
+	}.Build()
+	File_pb3_test_proto = out.File
+	file_pb3_test_proto_enumTypes = out.Enums
 	file_pb3_test_proto_rawDesc = nil
 	file_pb3_test_proto_goTypes = nil
 	file_pb3_test_proto_depIdxs = nil
diff --git a/internal/cmd/generate-types/main.go b/internal/cmd/generate-types/main.go
index 66a852d..d6bb972 100644
--- a/internal/cmd/generate-types/main.go
+++ b/internal/cmd/generate-types/main.go
@@ -20,7 +20,6 @@
 	"strconv"
 	"strings"
 	"text/template"
-	"unicode"
 )
 
 var (
@@ -38,8 +37,7 @@
 	repoRoot = strings.TrimSpace(string(out))
 
 	chdirRoot()
-	writeSource("internal/fileinit/desc_list_gen.go", generateFileinitDescList())
-	writeSource("internal/prototype/protofile_list_gen.go", generateListTypes())
+	writeSource("internal/filedesc/desc_list_gen.go", generateDescListTypes())
 	writeSource("internal/impl/encode_gen.go", generateImplEncode())
 	writeSource("proto/decode_gen.go", generateProtoDecode())
 	writeSource("proto/encode_gen.go", generateProtoEncode())
@@ -83,138 +81,19 @@
 	}
 }
 
-func generateListTypes() string {
-	// TODO: If Go2 has generics, replace this with a single container type.
-	return mustExecute(listTypesTemplate, []DescriptorType{
-		MessageDesc, FieldDesc, OneofDesc, ExtensionDesc, EnumDesc, EnumValueDesc, ServiceDesc, MethodDesc,
-	})
-}
-
-var listTypesTemplate = template.Must(template.New("").Funcs(template.FuncMap{
-	"unexport": func(t DescriptorType) Expr {
-		return Expr(string(unicode.ToLower(rune(t[0]))) + string(t[1:]))
-	},
-}).Parse(`
-	{{- range .}}
-	{{$nameList     := (printf "%ss"     (unexport .))}} {{/* e.g., "messages" */}}
-	{{$nameListMeta := (printf "%ssMeta" (unexport .))}} {{/* e.g., "messagesMeta" */}}
-	{{$nameMeta     := (printf "%sMeta"  (unexport .))}} {{/* e.g., "messageMeta" */}}
-	{{$nameDesc     := (printf "%sDesc"  (unexport .))}} {{/* e.g., "messageDesc" */}}
-
-	type {{$nameListMeta}} struct {
-		once     sync.Once
-		typs     []{{.}}
-		nameOnce sync.Once
-		byName   map[protoreflect.Name]*{{.}}
-		{{- if (eq . "Field")}}
-		jsonOnce sync.Once
-		byJSON   map[string]*{{.}}
-		{{- end}}
-		{{- if .NumberExpr}}
-		numOnce  sync.Once
-		byNum    map[{{.NumberExpr}}]*{{.}}
-		{{- end}}
-	}
-	type {{$nameList}} {{$nameListMeta}}
-
-	func (p *{{$nameListMeta}}) lazyInit(parent protoreflect.Descriptor, ts []{{.}}) *{{$nameList}} {
-		p.once.Do(func() {
-			nb := getNameBuilder()
-			defer putNameBuilder(nb)
-			metas := make([]{{$nameMeta}}, len(ts))
-			for i := range ts {
-				t := &ts[i]
-				if t.{{$nameMeta}} != nil {
-					panic("already initialized")
-				}
-				t.{{$nameMeta}} = &metas[i]
-				t.inheritedMeta.init(nb, parent, i, t.Name, {{printf "%v" (eq . "EnumValue")}})
-			}
-			p.typs = ts
-		})
-		return (*{{$nameList}})(p)
-	}
-	func (p *{{$nameList}}) Len() int            { return len(p.typs) }
-	func (p *{{$nameList}}) Get(i int) {{.Expr}} { return {{$nameDesc}}{&p.typs[i]} }
-	func (p *{{$nameList}}) ByName(s protoreflect.Name) {{.Expr}} {
-		p.nameOnce.Do(func() {
-			if len(p.typs) > 0 {
-				p.byName = make(map[protoreflect.Name]*{{.}}, len(p.typs))
-				for i := range p.typs {
-					t := &p.typs[i]
-					p.byName[t.Name] = t
-				}
-			}
-		})
-		t := p.byName[s]
-		if t == nil {
-			return nil
-		}
-		return {{$nameDesc}}{t}
-	}
-	{{- if (eq . "Field")}}
-	func (p *{{$nameList}}) ByJSONName(s string) {{.Expr}} {
-		p.jsonOnce.Do(func() {
-			if len(p.typs) > 0 {
-				p.byJSON = make(map[string]*{{.}}, len(p.typs))
-				for i := range p.typs {
-					t := &p.typs[i]
-					s := {{$nameDesc}}{t}.JSONName()
-					if _, ok := p.byJSON[s]; !ok {
-						p.byJSON[s] = t
-					}
-				}
-			}
-		})
-		t := p.byJSON[s]
-		if t == nil {
-			return nil
-		}
-		return {{$nameDesc}}{t}
-	}
-	{{- end}}
-	{{- if .NumberExpr}}
-	func (p *{{$nameList}}) ByNumber(n {{.NumberExpr}}) {{.Expr}} {
-		p.numOnce.Do(func() {
-			if len(p.typs) > 0 {
-				p.byNum = make(map[{{.NumberExpr}}]*{{.}}, len(p.typs))
-				for i := range p.typs {
-					t := &p.typs[i]
-					if _, ok := p.byNum[t.Number]; !ok {
-						p.byNum[t.Number] = t
-					}
-				}
-			}
-		})
-		t := p.byNum[n]
-		if t == nil {
-			return nil
-		}
-		return {{$nameDesc}}{t}
-	}
-	{{- end}}
-	func (p *{{$nameList}}) Format(s fmt.State, r rune)          { descfmt.FormatList(s, r, p) }
-	func (p *{{$nameList}}) ProtoInternal(pragma.DoNotImplement) {}
-	{{- end}}
-`))
-
-func generateFileinitDescList() string {
-	return mustExecute(fileinitDescListTemplate, []DescriptorType{
+func generateDescListTypes() string {
+	return mustExecute(descListTypesTemplate, []DescriptorType{
 		EnumDesc, EnumValueDesc, MessageDesc, FieldDesc, OneofDesc, ExtensionDesc, ServiceDesc, MethodDesc,
 	})
 }
 
-var fileinitDescListTemplate = template.Must(template.New("").Funcs(template.FuncMap{
-	"unexport": func(t DescriptorType) Expr {
-		return Expr(string(unicode.ToLower(rune(t[0]))) + string(t[1:]))
-	},
-}).Parse(`
+var descListTypesTemplate = template.Must(template.New("").Parse(`
 	{{- range .}}
-	{{$nameList := (printf "%sDescs" (unexport .))}} {{/* e.g., "messageDescs" */}}
-	{{$nameDesc := (printf "%sDesc"  (unexport .))}} {{/* e.g., "messageDesc" */}}
+	{{$nameList := (printf "%ss" .)}} {{/* e.g., "Messages" */}}
+	{{$nameDesc := (printf "%s"  .)}} {{/* e.g., "Message" */}}
 
 	type {{$nameList}} struct {
-		list   []{{$nameDesc}}
+		List   []{{$nameDesc}}
 		once   sync.Once
 		byName map[protoreflect.Name]*{{$nameDesc}} // protected by once
 		{{- if (eq . "Field")}}
@@ -226,22 +105,14 @@
 	}
 
 	func (p *{{$nameList}}) Len() int {
-		return len(p.list)
+		return len(p.List)
 	}
 	func (p *{{$nameList}}) Get(i int) {{.Expr}} {
-		{{- if (eq . "Message")}}
-		return p.list[i].asDesc()
-		{{- else}}
-		return &p.list[i]
-		{{- end}}
+		return &p.List[i]
 	}
 	func (p *{{$nameList}}) ByName(s protoreflect.Name) {{.Expr}} {
 		if d := p.lazyInit().byName[s]; d != nil {
-			{{- if (eq . "Message")}}
-			return d.asDesc()
-			{{- else}}
 			return d
-			{{- end}}
 		}
 		return nil
 	}
@@ -267,16 +138,16 @@
 	func (p *{{$nameList}}) ProtoInternal(pragma.DoNotImplement) {}
 	func (p *{{$nameList}}) lazyInit() *{{$nameList}} {
 		p.once.Do(func() {
-			if len(p.list) > 0 {
-				p.byName = make(map[protoreflect.Name]*{{$nameDesc}}, len(p.list))
+			if len(p.List) > 0 {
+				p.byName = make(map[protoreflect.Name]*{{$nameDesc}}, len(p.List))
 				{{- if (eq . "Field")}}
-				p.byJSON = make(map[string]*{{$nameDesc}}, len(p.list))
+				p.byJSON = make(map[string]*{{$nameDesc}}, len(p.List))
 				{{- end}}
 				{{- if .NumberExpr}}
-				p.byNum = make(map[{{.NumberExpr}}]*{{$nameDesc}}, len(p.list))
+				p.byNum = make(map[{{.NumberExpr}}]*{{$nameDesc}}, len(p.List))
 				{{- end}}
-				for i := range p.list {
-					d := &p.list[i]
+				for i := range p.List {
+					d := &p.List[i]
 					if _, ok := p.byName[d.Name()]; !ok {
 						p.byName[d.Name()] = d
 					}
diff --git a/internal/cmd/pbdump/pbdump.go b/internal/cmd/pbdump/pbdump.go
index 7a7c3ce..8bc1753 100644
--- a/internal/cmd/pbdump/pbdump.go
+++ b/internal/cmd/pbdump/pbdump.go
@@ -19,8 +19,8 @@
 
 	"google.golang.org/protobuf/internal/encoding/pack"
 	"google.golang.org/protobuf/internal/encoding/wire"
-	"google.golang.org/protobuf/internal/prototype"
 	"google.golang.org/protobuf/internal/scalar"
+	"google.golang.org/protobuf/reflect/protodesc"
 	"google.golang.org/protobuf/reflect/protoreflect"
 
 	"google.golang.org/protobuf/types/descriptorpb"
@@ -202,41 +202,43 @@
 
 // Descriptor returns the field tree as a message descriptor.
 func (fs fields) Descriptor() (protoreflect.MessageDescriptor, error) {
-	ftyp, err := prototype.NewFile(&prototype.File{
-		Syntax:   protoreflect.Proto2,
-		Messages: []prototype.Message{fs.messageDescriptor("M")},
-	})
+	fd, err := protodesc.NewFile(&descriptorpb.FileDescriptorProto{
+		Name:        scalar.String("dump.proto"),
+		Syntax:      scalar.String("proto2"),
+		MessageType: []*descriptorpb.DescriptorProto{fs.messageDescriptor("M")},
+	}, nil)
 	if err != nil {
 		return nil, err
 	}
-	return ftyp.Messages().Get(0), nil
+	return fd.Messages().Get(0), nil
 }
-func (fs fields) messageDescriptor(name protoreflect.FullName) prototype.Message {
-	m := prototype.Message{Name: name.Name()}
+func (fs fields) messageDescriptor(name protoreflect.FullName) *descriptorpb.DescriptorProto {
+	m := &descriptorpb.DescriptorProto{Name: scalar.String(string(name.Name()))}
 	for _, n := range fs.sortedNums() {
-		f := prototype.Field{
-			Name:        protoreflect.Name(fmt.Sprintf("f%d", n)),
-			Number:      n,
-			Cardinality: protoreflect.Optional,
-			Kind:        fs[n].kind,
+		k := fs[n].kind
+		if !k.IsValid() {
+			k = protoreflect.MessageKind
 		}
-		if !f.Kind.IsValid() {
-			f.Kind = protoreflect.MessageKind
+		f := &descriptorpb.FieldDescriptorProto{
+			Name:   scalar.String(fmt.Sprintf("f%d", n)),
+			Number: scalar.Int32(int32(n)),
+			Label:  descriptorpb.FieldDescriptorProto_LABEL_OPTIONAL.Enum(),
+			Type:   descriptorpb.FieldDescriptorProto_Type(k).Enum(),
 		}
-		switch f.Kind {
+		switch k {
 		case protoreflect.BoolKind, protoreflect.EnumKind,
 			protoreflect.Int32Kind, protoreflect.Sint32Kind, protoreflect.Uint32Kind,
 			protoreflect.Int64Kind, protoreflect.Sint64Kind, protoreflect.Uint64Kind,
 			protoreflect.Sfixed32Kind, protoreflect.Fixed32Kind, protoreflect.FloatKind,
 			protoreflect.Sfixed64Kind, protoreflect.Fixed64Kind, protoreflect.DoubleKind:
-			f.Cardinality = protoreflect.Repeated
+			f.Label = descriptorpb.FieldDescriptorProto_LABEL_REPEATED.Enum()
 			f.Options = &descriptorpb.FieldOptions{Packed: scalar.Bool(true)}
 		case protoreflect.MessageKind, protoreflect.GroupKind:
 			s := name.Append(protoreflect.Name(fmt.Sprintf("M%d", n)))
-			f.MessageType = prototype.PlaceholderMessage(s)
-			m.Messages = append(m.Messages, fs[n].sub.messageDescriptor(s))
+			f.TypeName = scalar.String(string("." + s))
+			m.NestedType = append(m.NestedType, fs[n].sub.messageDescriptor(s))
 		}
-		m.Fields = append(m.Fields, f)
+		m.Field = append(m.Field, f)
 	}
 	return m
 }
diff --git a/internal/cmd/pbdump/pbdump_test.go b/internal/cmd/pbdump/pbdump_test.go
index 57ec1b5..a3f6998 100644
--- a/internal/cmd/pbdump/pbdump_test.go
+++ b/internal/cmd/pbdump/pbdump_test.go
@@ -9,13 +9,22 @@
 	"strings"
 	"testing"
 
-	"github.com/google/go-cmp/cmp"
-	"github.com/google/go-cmp/cmp/cmpopts"
-
-	ptype "google.golang.org/protobuf/internal/prototype"
+	"google.golang.org/protobuf/encoding/prototext"
+	"google.golang.org/protobuf/proto"
 	pref "google.golang.org/protobuf/reflect/protoreflect"
+
+	"google.golang.org/protobuf/types/descriptorpb"
 )
 
+func mustMakeMessage(s string) *descriptorpb.DescriptorProto {
+	s = fmt.Sprintf(`name:"test.proto" syntax:"proto2" message_type:[{%s}]`, s)
+	pb := new(descriptorpb.FileDescriptorProto)
+	if err := prototext.Unmarshal([]byte(s), pb); err != nil {
+		panic(err)
+	}
+	return pb.MessageType[0]
+}
+
 func TestFields(t *testing.T) {
 	type fieldsKind struct {
 		kind   pref.Kind
@@ -23,11 +32,11 @@
 	}
 	tests := []struct {
 		inFields []fieldsKind
-		wantMsg  ptype.Message
+		wantMsg  *descriptorpb.DescriptorProto
 		wantErr  string
 	}{{
 		inFields: []fieldsKind{{pref.MessageKind, ""}},
-		wantMsg:  ptype.Message{Name: "M"},
+		wantMsg:  mustMakeMessage(`name:"M"`),
 	}, {
 		inFields: []fieldsKind{{pref.MessageKind, "987654321"}},
 		wantErr:  "invalid field: 987654321",
@@ -52,44 +61,33 @@
 			{pref.MessageKind, "  10.20.30, 10.21   "},
 			{pref.GroupKind, "10"},
 		},
-		wantMsg: ptype.Message{
-			Name: "M",
-			Fields: []ptype.Field{
-				{Name: "f10", Number: 10, Cardinality: pref.Optional, Kind: pref.GroupKind, MessageType: ptype.PlaceholderMessage("M.M10")},
-			},
-			Messages: []ptype.Message{{
-				Name: "M10",
-				Fields: []ptype.Field{
-					{Name: "f20", Number: 20, Cardinality: pref.Optional, Kind: pref.MessageKind, MessageType: ptype.PlaceholderMessage("M.M10.M20")},
-					{Name: "f21", Number: 21, Cardinality: pref.Optional, Kind: pref.MessageKind, MessageType: ptype.PlaceholderMessage("M.M10.M21")},
-				},
-				Messages: []ptype.Message{{
-					Name: "M20",
-					Fields: []ptype.Field{
-						{Name: "f30", Number: 30, Cardinality: pref.Optional, Kind: pref.MessageKind, MessageType: ptype.PlaceholderMessage("M.M10.M20.M30")},
-						{Name: "f31", Number: 31, Cardinality: pref.Repeated, Kind: pref.Int32Kind},
-					},
-					Messages: []ptype.Message{{
-						Name: "M30",
-					}},
+		wantMsg: mustMakeMessage(`
+			name: "M"
+			field: [
+				{name:"f10" number:10 label:LABEL_OPTIONAL type:TYPE_GROUP type_name:".M.M10"}
+			]
+			nested_type: [{
+				name: "M10"
+				field: [
+					{name:"f20" number:20 label:LABEL_OPTIONAL type:TYPE_MESSAGE type_name:".M.M10.M20"},
+					{name:"f21" number:21 label:LABEL_OPTIONAL type:TYPE_MESSAGE type_name:".M.M10.M21"}
+				]
+				nested_type: [{
+					name: "M20"
+					field:[
+						{name:"f30" number:30 label:LABEL_OPTIONAL type:TYPE_MESSAGE, type_name:".M.M10.M20.M30"},
+						{name:"f31" number:31 label:LABEL_REPEATED type:TYPE_INT32 options:{packed:true}}
+					]
+					nested_type: [{
+						name: "M30"
+					}]
 				}, {
-					Name: "M21",
-				}},
-			}},
-		},
+					name: "M21"
+				}]
+			}]
+		`),
 	}}
 
-	opts := cmp.Options{
-		cmp.Comparer(func(x, y pref.Descriptor) bool {
-			if x == nil || y == nil {
-				return x == nil && y == nil
-			}
-			return x.FullName() == y.FullName()
-		}),
-		cmpopts.IgnoreFields(ptype.Field{}, "Default"),
-		cmpopts.IgnoreFields(ptype.Field{}, "Options"),
-		cmpopts.IgnoreUnexported(ptype.Message{}, ptype.Field{}),
-	}
 	for _, tt := range tests {
 		t.Run("", func(t *testing.T) {
 			var fields fields
@@ -106,8 +104,8 @@
 				t.Errorf("all Set calls succeeded, want %v error", tt.wantErr)
 			}
 			gotMsg := fields.messageDescriptor("M")
-			if diff := cmp.Diff(tt.wantMsg, gotMsg, opts); diff != "" {
-				t.Errorf("messageDescriptor() mismatch (-want +got):\n%v", diff)
+			if !proto.Equal(gotMsg, tt.wantMsg) {
+				t.Errorf("messageDescriptor() mismatch:\ngot  %v\nwant %v", gotMsg, tt.wantMsg)
 			}
 			if _, err := fields.Descriptor(); err != nil {
 				t.Errorf("Descriptor() = %v, want nil error", err)
diff --git a/internal/descopts/options.go b/internal/descopts/options.go
index 8ea9307..8401be8 100644
--- a/internal/descopts/options.go
+++ b/internal/descopts/options.go
@@ -5,14 +5,14 @@
 // Package descopts contains the nil pointers to concrete descriptor options.
 //
 // This package exists as a form of reverse dependency injection so that certain
-// packages (e.g., internal/fileinit can avoid a direct dependency on the
-// descriptor proto package).
+// packages (e.g., internal/filedesc and internal/filetype can avoid a direct
+// dependency on the descriptor proto package).
 package descopts
 
 import pref "google.golang.org/protobuf/reflect/protoreflect"
 
 // These variables are set by the init function in descriptor.pb.go via logic
-// in internal/fileinit. In other words, so long as the descriptor proto package
+// in internal/filetype. In other words, so long as the descriptor proto package
 // is linked in, these variables will be populated.
 //
 // Each variable is populated with a nil pointer to the options struct.
diff --git a/internal/encoding/defval/default.go b/internal/encoding/defval/default.go
index a15df02..f03acdf 100644
--- a/internal/encoding/defval/default.go
+++ b/internal/encoding/defval/default.go
@@ -34,54 +34,55 @@
 )
 
 // Unmarshal deserializes the default string s according to the given kind k.
-// When using the Descriptor format on an enum kind, a Value of type string
-// representing the enum identifier is returned. It is the caller's
-// responsibility to verify that the identifier is valid.
-func Unmarshal(s string, k pref.Kind, f Format) (pref.Value, error) {
+// When k is an enum, a list of enum value descriptors must be provided.
+func Unmarshal(s string, k pref.Kind, evs pref.EnumValueDescriptors, f Format) (pref.Value, pref.EnumValueDescriptor, error) {
 	switch k {
 	case pref.BoolKind:
 		if f == GoTag {
 			switch s {
 			case "1":
-				return pref.ValueOf(true), nil
+				return pref.ValueOf(true), nil, nil
 			case "0":
-				return pref.ValueOf(false), nil
+				return pref.ValueOf(false), nil, nil
 			}
 		} else {
 			switch s {
 			case "true":
-				return pref.ValueOf(true), nil
+				return pref.ValueOf(true), nil, nil
 			case "false":
-				return pref.ValueOf(false), nil
+				return pref.ValueOf(false), nil, nil
 			}
 		}
 	case pref.EnumKind:
 		if f == GoTag {
-			// Go tags used the numeric form of the enum value.
+			// Go tags use the numeric form of the enum value.
 			if n, err := strconv.ParseInt(s, 10, 32); err == nil {
-				return pref.ValueOf(pref.EnumNumber(n)), nil
+				if ev := evs.ByNumber(pref.EnumNumber(n)); ev != nil {
+					return pref.ValueOf(ev.Number()), ev, nil
+				}
 			}
 		} else {
-			// Descriptor default_value used the enum identifier.
-			if pref.Name(s).IsValid() {
-				return pref.ValueOf(s), nil
+			// Descriptor default_value use the enum identifier.
+			ev := evs.ByName(pref.Name(s))
+			if ev != nil {
+				return pref.ValueOf(ev.Number()), ev, nil
 			}
 		}
 	case pref.Int32Kind, pref.Sint32Kind, pref.Sfixed32Kind:
 		if v, err := strconv.ParseInt(s, 10, 32); err == nil {
-			return pref.ValueOf(int32(v)), nil
+			return pref.ValueOf(int32(v)), nil, nil
 		}
 	case pref.Int64Kind, pref.Sint64Kind, pref.Sfixed64Kind:
 		if v, err := strconv.ParseInt(s, 10, 64); err == nil {
-			return pref.ValueOf(int64(v)), nil
+			return pref.ValueOf(int64(v)), nil, nil
 		}
 	case pref.Uint32Kind, pref.Fixed32Kind:
 		if v, err := strconv.ParseUint(s, 10, 32); err == nil {
-			return pref.ValueOf(uint32(v)), nil
+			return pref.ValueOf(uint32(v)), nil, nil
 		}
 	case pref.Uint64Kind, pref.Fixed64Kind:
 		if v, err := strconv.ParseUint(s, 10, 64); err == nil {
-			return pref.ValueOf(uint64(v)), nil
+			return pref.ValueOf(uint64(v)), nil, nil
 		}
 	case pref.FloatKind, pref.DoubleKind:
 		var v float64
@@ -98,25 +99,26 @@
 		}
 		if err == nil {
 			if k == pref.FloatKind {
-				return pref.ValueOf(float32(v)), nil
+				return pref.ValueOf(float32(v)), nil, nil
 			} else {
-				return pref.ValueOf(float64(v)), nil
+				return pref.ValueOf(float64(v)), nil, nil
 			}
 		}
 	case pref.StringKind:
 		// String values are already unescaped and can be used as is.
-		return pref.ValueOf(s), nil
+		return pref.ValueOf(s), nil, nil
 	case pref.BytesKind:
 		if b, ok := unmarshalBytes(s); ok {
-			return pref.ValueOf(b), nil
+			return pref.ValueOf(b), nil, nil
 		}
 	}
-	return pref.Value{}, errors.New("invalid default value for %v: %q", k, s)
+	return pref.Value{}, nil, errors.New("invalid default value for %v: %q", k, s)
 }
 
 // Marshal serializes v as the default string according to the given kind k.
-// Enums are serialized in numeric form regardless of format chosen.
-func Marshal(v pref.Value, k pref.Kind, f Format) (string, error) {
+// When specifying the Descriptor format for an enum kind, the associated
+// enum value descriptor must be provided.
+func Marshal(v pref.Value, ev pref.EnumValueDescriptor, k pref.Kind, f Format) (string, error) {
 	switch k {
 	case pref.BoolKind:
 		if f == GoTag {
@@ -133,7 +135,11 @@
 			}
 		}
 	case pref.EnumKind:
-		return strconv.FormatInt(int64(v.Enum()), 10), nil
+		if f == GoTag {
+			return strconv.FormatInt(int64(v.Enum()), 10), nil
+		} else {
+			return string(ev.Name()), nil
+		}
 	case pref.Int32Kind, pref.Sint32Kind, pref.Sfixed32Kind, pref.Int64Kind, pref.Sint64Kind, pref.Sfixed64Kind:
 		return strconv.FormatInt(v.Int(), 10), nil
 	case pref.Uint32Kind, pref.Fixed32Kind, pref.Uint64Kind, pref.Fixed64Kind:
diff --git a/internal/encoding/defval/default_test.go b/internal/encoding/defval/default_test.go
index a25a93f..d81150d 100644
--- a/internal/encoding/defval/default_test.go
+++ b/internal/encoding/defval/default_test.go
@@ -2,52 +2,103 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-package defval
+package defval_test
 
 import (
 	"math"
 	"reflect"
 	"testing"
 
+	"google.golang.org/protobuf/internal/encoding/defval"
+	fdesc "google.golang.org/protobuf/internal/filedesc"
 	pref "google.golang.org/protobuf/reflect/protoreflect"
 )
 
 func Test(t *testing.T) {
+	evs := fdesc.EnumValues{List: []fdesc.EnumValue{{}}}
+	evs.List[0].L0.ParentFile = fdesc.SurrogateProto2
+	evs.List[0].L0.FullName = "ALPHA"
+	evs.List[0].L1.Number = 1
+
 	V := pref.ValueOf
 	tests := []struct {
 		val   pref.Value
+		enum  pref.EnumValueDescriptor
+		enums pref.EnumValueDescriptors
 		kind  pref.Kind
 		strPB string
 		strGo string
-	}{
-		{V(bool(true)), pref.BoolKind, "true", "1"},
-		{V(int32(-0x1234)), pref.Int32Kind, "-4660", "-4660"},
-		{V(float32(math.Pi)), pref.FloatKind, "3.1415927", "3.1415927"},
-		{V(float64(math.Pi)), pref.DoubleKind, "3.141592653589793", "3.141592653589793"},
-		{V(string("hello, \xde\xad\xbe\xef\n")), pref.StringKind, "hello, \xde\xad\xbe\xef\n", "hello, \xde\xad\xbe\xef\n"},
-		{V([]byte("hello, \xde\xad\xbe\xef\n")), pref.BytesKind, "hello, \\336\\255\\276\\357\\n", "hello, \\336\\255\\276\\357\\n"},
-	}
+	}{{
+		val:   V(bool(true)),
+		enum:  nil,
+		enums: nil,
+		kind:  pref.BoolKind,
+		strPB: "true",
+		strGo: "1",
+	}, {
+		val:   V(int32(-0x1234)),
+		enum:  nil,
+		enums: nil,
+		kind:  pref.Int32Kind,
+		strPB: "-4660",
+		strGo: "-4660",
+	}, {
+		val:   V(float32(math.Pi)),
+		enum:  nil,
+		enums: nil,
+		kind:  pref.FloatKind,
+		strPB: "3.1415927",
+		strGo: "3.1415927",
+	}, {
+		val:   V(float64(math.Pi)),
+		enum:  nil,
+		enums: nil,
+		kind:  pref.DoubleKind,
+		strPB: "3.141592653589793",
+		strGo: "3.141592653589793",
+	}, {
+		val:   V(string("hello, \xde\xad\xbe\xef\n")),
+		enum:  nil,
+		enums: nil,
+		kind:  pref.StringKind,
+		strPB: "hello, \xde\xad\xbe\xef\n",
+		strGo: "hello, \xde\xad\xbe\xef\n",
+	}, {
+		val:   V([]byte("hello, \xde\xad\xbe\xef\n")),
+		enum:  nil,
+		enums: nil,
+		kind:  pref.BytesKind,
+		strPB: "hello, \\336\\255\\276\\357\\n",
+		strGo: "hello, \\336\\255\\276\\357\\n",
+	}, {
+		val:   V(pref.EnumNumber(1)),
+		enum:  &evs.List[0],
+		enums: &evs,
+		kind:  pref.EnumKind,
+		strPB: "ALPHA",
+		strGo: "1",
+	}}
 
 	for _, tt := range tests {
 		t.Run("", func(t *testing.T) {
-			gotStrPB, _ := Marshal(tt.val, tt.kind, Descriptor)
-			if gotStrPB != tt.strPB {
-				t.Errorf("Marshal(%v, %v, Descriptor) = %q, want %q", tt.val, tt.kind, gotStrPB, tt.strPB)
+			gotStr, _ := defval.Marshal(tt.val, tt.enum, tt.kind, defval.Descriptor)
+			if gotStr != tt.strPB {
+				t.Errorf("Marshal(%v, %v, Descriptor) = %q, want %q", tt.val, tt.kind, gotStr, tt.strPB)
 			}
 
-			gotStrGo, _ := Marshal(tt.val, tt.kind, GoTag)
-			if gotStrGo != tt.strGo {
-				t.Errorf("Marshal(%v, %v, GoTag) = %q, want %q", tt.val, tt.kind, gotStrGo, tt.strGo)
+			gotStr, _ = defval.Marshal(tt.val, tt.enum, tt.kind, defval.GoTag)
+			if gotStr != tt.strGo {
+				t.Errorf("Marshal(%v, %v, GoTag) = %q, want %q", tt.val, tt.kind, gotStr, tt.strGo)
 			}
 
-			gotValPB, _ := Unmarshal(tt.strPB, tt.kind, Descriptor)
-			if !reflect.DeepEqual(gotValPB.Interface(), tt.val.Interface()) {
-				t.Errorf("Unmarshal(%v, %v, Descriptor) = %q, want %q", tt.strPB, tt.kind, gotValPB, tt.val)
+			gotVal, gotEnum, _ := defval.Unmarshal(tt.strPB, tt.kind, tt.enums, defval.Descriptor)
+			if !reflect.DeepEqual(gotVal.Interface(), tt.val.Interface()) || gotEnum != tt.enum {
+				t.Errorf("Unmarshal(%v, %v, Descriptor) = (%q, %v), want (%q, %v)", tt.strPB, tt.kind, gotVal, gotEnum, tt.val, tt.enum)
 			}
 
-			gotValGo, _ := Unmarshal(tt.strGo, tt.kind, GoTag)
-			if !reflect.DeepEqual(gotValGo.Interface(), tt.val.Interface()) {
-				t.Errorf("Unmarshal(%v, %v, GoTag) = %q, want %q", tt.strGo, tt.kind, gotValGo, tt.val)
+			gotVal, gotEnum, _ = defval.Unmarshal(tt.strGo, tt.kind, tt.enums, defval.GoTag)
+			if !reflect.DeepEqual(gotVal.Interface(), tt.val.Interface()) || gotEnum != tt.enum {
+				t.Errorf("Unmarshal(%v, %v, GoTag) = (%q, %v), want (%q, %v)", tt.strGo, tt.kind, gotVal, gotEnum, tt.val, tt.enum)
 			}
 		})
 	}
diff --git a/internal/encoding/pack/pack_test.go b/internal/encoding/pack/pack_test.go
index d2f8baa..d6704e9 100644
--- a/internal/encoding/pack/pack_test.go
+++ b/internal/encoding/pack/pack_test.go
@@ -11,35 +11,47 @@
 	"math"
 	"testing"
 
-	cmp "github.com/google/go-cmp/cmp"
-	ptype "google.golang.org/protobuf/internal/prototype"
+	"github.com/google/go-cmp/cmp"
+	"google.golang.org/protobuf/encoding/prototext"
+	pdesc "google.golang.org/protobuf/reflect/protodesc"
 	pref "google.golang.org/protobuf/reflect/protoreflect"
+
+	"google.golang.org/protobuf/types/descriptorpb"
 )
 
 var msgDesc = func() pref.MessageDescriptor {
-	mtyp, err := ptype.NewMessage(&ptype.StandaloneMessage{
-		Syntax:   pref.Proto2,
-		FullName: "Message",
-		Fields: []ptype.Field{
-			{Name: "F1", Number: 1, Cardinality: pref.Repeated, Kind: pref.BoolKind, IsPacked: ptype.True},
-			{Name: "F2", Number: 2, Cardinality: pref.Repeated, Kind: pref.Int64Kind, IsPacked: ptype.True},
-			{Name: "F3", Number: 3, Cardinality: pref.Repeated, Kind: pref.Sint64Kind, IsPacked: ptype.True},
-			{Name: "F4", Number: 4, Cardinality: pref.Repeated, Kind: pref.Uint64Kind, IsPacked: ptype.True},
-			{Name: "F5", Number: 5, Cardinality: pref.Repeated, Kind: pref.Fixed32Kind, IsPacked: ptype.True},
-			{Name: "F6", Number: 6, Cardinality: pref.Repeated, Kind: pref.Sfixed32Kind, IsPacked: ptype.True},
-			{Name: "F7", Number: 7, Cardinality: pref.Repeated, Kind: pref.FloatKind, IsPacked: ptype.True},
-			{Name: "F8", Number: 8, Cardinality: pref.Repeated, Kind: pref.Fixed64Kind, IsPacked: ptype.True},
-			{Name: "F9", Number: 9, Cardinality: pref.Repeated, Kind: pref.Sfixed64Kind, IsPacked: ptype.True},
-			{Name: "F10", Number: 10, Cardinality: pref.Repeated, Kind: pref.DoubleKind, IsPacked: ptype.True},
-			{Name: "F11", Number: 11, Cardinality: pref.Optional, Kind: pref.StringKind},
-			{Name: "F12", Number: 12, Cardinality: pref.Optional, Kind: pref.BytesKind},
-			{Name: "F13", Number: 13, Cardinality: pref.Optional, Kind: pref.MessageKind, MessageType: ptype.PlaceholderMessage("Message")},
-			{Name: "F14", Number: 14, Cardinality: pref.Optional, Kind: pref.GroupKind, MessageType: ptype.PlaceholderMessage("Message")}},
-	})
+	const s = `
+		name:   "test.proto"
+		syntax: "proto2"
+		message_type: [{
+			name: "Message"
+			field: [
+				{name:"F1"  number:1  label:LABEL_REPEATED type:TYPE_BOOL     options:{packed:true}},
+				{name:"F2"  number:2  label:LABEL_REPEATED type:TYPE_INT64    options:{packed:true}},
+				{name:"F3"  number:3  label:LABEL_REPEATED type:TYPE_SINT64   options:{packed:true}},
+				{name:"F4"  number:4  label:LABEL_REPEATED type:TYPE_UINT64   options:{packed:true}},
+				{name:"F5"  number:5  label:LABEL_REPEATED type:TYPE_FIXED32  options:{packed:true}},
+				{name:"F6"  number:6  label:LABEL_REPEATED type:TYPE_SFIXED32 options:{packed:true}},
+				{name:"F7"  number:7  label:LABEL_REPEATED type:TYPE_FLOAT    options:{packed:true}},
+				{name:"F8"  number:8  label:LABEL_REPEATED type:TYPE_FIXED64  options:{packed:true}},
+				{name:"F9"  number:9  label:LABEL_REPEATED type:TYPE_SFIXED64 options:{packed:true}},
+				{name:"F10" number:10 label:LABEL_REPEATED type:TYPE_DOUBLE   options:{packed:true}},
+				{name:"F11" number:11 label:LABEL_OPTIONAL type:TYPE_STRING},
+				{name:"F12" number:12 label:LABEL_OPTIONAL type:TYPE_BYTES},
+				{name:"F13" number:13 label:LABEL_OPTIONAL type:TYPE_MESSAGE type_name:".Message"},
+				{name:"F14" number:14 label:LABEL_OPTIONAL type:TYPE_GROUP   type_name:".Message"}
+			]
+		}]
+	`
+	pb := new(descriptorpb.FileDescriptorProto)
+	if err := prototext.Unmarshal([]byte(s), pb); err != nil {
+		panic(err)
+	}
+	fd, err := pdesc.NewFile(pb, nil)
 	if err != nil {
 		panic(err)
 	}
-	return mtyp
+	return fd.Messages().Get(0)
 }()
 
 // dhex decodes a hex-string and returns the bytes and panics if s is invalid.
diff --git a/internal/encoding/tag/tag.go b/internal/encoding/tag/tag.go
index f1f24e8..1c568e3 100644
--- a/internal/encoding/tag/tag.go
+++ b/internal/encoding/tag/tag.go
@@ -12,7 +12,7 @@
 	"strings"
 
 	defval "google.golang.org/protobuf/internal/encoding/defval"
-	ptype "google.golang.org/protobuf/internal/prototype"
+	fdesc "google.golang.org/protobuf/internal/filedesc"
 	pref "google.golang.org/protobuf/reflect/protoreflect"
 )
 
@@ -24,11 +24,13 @@
 // tag does not record sufficient information to determine that.
 // The type is the underlying field type (e.g., a repeated field may be
 // represented by []T, but the Go type passed in is just T).
-// This does not populate the EnumType or MessageType (except for weak message).
+// A list of enum value descriptors must be provided for enum fields.
+// This does not populate the Enum or Message (except for weak message).
 //
 // This function is a best effort attempt; parsing errors are ignored.
-func Unmarshal(tag string, goType reflect.Type) ptype.Field {
-	f := ptype.Field{}
+func Unmarshal(tag string, goType reflect.Type, evs pref.EnumValueDescriptors) pref.FieldDescriptor {
+	f := new(fdesc.Field)
+	f.L0.ParentFile = fdesc.SurrogateProto2
 	for len(tag) > 0 {
 		i := strings.IndexByte(tag, ',')
 		if i < 0 {
@@ -36,88 +38,92 @@
 		}
 		switch s := tag[:i]; {
 		case strings.HasPrefix(s, "name="):
-			f.Name = pref.Name(s[len("name="):])
+			f.L0.FullName = pref.FullName(s[len("name="):])
 		case strings.Trim(s, "0123456789") == "":
 			n, _ := strconv.ParseUint(s, 10, 32)
-			f.Number = pref.FieldNumber(n)
+			f.L1.Number = pref.FieldNumber(n)
 		case s == "opt":
-			f.Cardinality = pref.Optional
+			f.L1.Cardinality = pref.Optional
 		case s == "req":
-			f.Cardinality = pref.Required
+			f.L1.Cardinality = pref.Required
 		case s == "rep":
-			f.Cardinality = pref.Repeated
+			f.L1.Cardinality = pref.Repeated
 		case s == "varint":
 			switch goType.Kind() {
 			case reflect.Bool:
-				f.Kind = pref.BoolKind
+				f.L1.Kind = pref.BoolKind
 			case reflect.Int32:
-				f.Kind = pref.Int32Kind
+				f.L1.Kind = pref.Int32Kind
 			case reflect.Int64:
-				f.Kind = pref.Int64Kind
+				f.L1.Kind = pref.Int64Kind
 			case reflect.Uint32:
-				f.Kind = pref.Uint32Kind
+				f.L1.Kind = pref.Uint32Kind
 			case reflect.Uint64:
-				f.Kind = pref.Uint64Kind
+				f.L1.Kind = pref.Uint64Kind
 			}
 		case s == "zigzag32":
 			if goType.Kind() == reflect.Int32 {
-				f.Kind = pref.Sint32Kind
+				f.L1.Kind = pref.Sint32Kind
 			}
 		case s == "zigzag64":
 			if goType.Kind() == reflect.Int64 {
-				f.Kind = pref.Sint64Kind
+				f.L1.Kind = pref.Sint64Kind
 			}
 		case s == "fixed32":
 			switch goType.Kind() {
 			case reflect.Int32:
-				f.Kind = pref.Sfixed32Kind
+				f.L1.Kind = pref.Sfixed32Kind
 			case reflect.Uint32:
-				f.Kind = pref.Fixed32Kind
+				f.L1.Kind = pref.Fixed32Kind
 			case reflect.Float32:
-				f.Kind = pref.FloatKind
+				f.L1.Kind = pref.FloatKind
 			}
 		case s == "fixed64":
 			switch goType.Kind() {
 			case reflect.Int64:
-				f.Kind = pref.Sfixed64Kind
+				f.L1.Kind = pref.Sfixed64Kind
 			case reflect.Uint64:
-				f.Kind = pref.Fixed64Kind
+				f.L1.Kind = pref.Fixed64Kind
 			case reflect.Float64:
-				f.Kind = pref.DoubleKind
+				f.L1.Kind = pref.DoubleKind
 			}
 		case s == "bytes":
 			switch {
 			case goType.Kind() == reflect.String:
-				f.Kind = pref.StringKind
+				f.L1.Kind = pref.StringKind
 			case goType.Kind() == reflect.Slice && goType.Elem() == byteType:
-				f.Kind = pref.BytesKind
+				f.L1.Kind = pref.BytesKind
 			default:
-				f.Kind = pref.MessageKind
+				f.L1.Kind = pref.MessageKind
 			}
 		case s == "group":
-			f.Kind = pref.GroupKind
+			f.L1.Kind = pref.GroupKind
 		case strings.HasPrefix(s, "enum="):
-			f.Kind = pref.EnumKind
+			f.L1.Kind = pref.EnumKind
 		case strings.HasPrefix(s, "json="):
-			f.JSONName = s[len("json="):]
+			f.L1.JSONName = fdesc.JSONName(s[len("json="):])
 		case s == "packed":
-			f.IsPacked = ptype.True
+			f.L1.HasPacked = true
+			f.L1.IsPacked = true
 		case strings.HasPrefix(s, "weak="):
-			f.IsWeak = true
-			f.MessageType = ptype.PlaceholderMessage(pref.FullName(s[len("weak="):]))
+			f.L1.IsWeak = true
+			f.L1.Message = fdesc.PlaceholderMessage(pref.FullName(s[len("weak="):]))
 		case strings.HasPrefix(s, "def="):
 			// The default tag is special in that everything afterwards is the
 			// default regardless of the presence of commas.
 			s, i = tag[len("def="):], len(tag)
-			f.Default, _ = defval.Unmarshal(s, f.Kind, defval.GoTag)
+			v, ev, _ := defval.Unmarshal(s, f.L1.Kind, evs, defval.GoTag)
+			f.L1.Default = fdesc.DefaultValue(v, ev)
+		case s == "proto3":
+			f.L0.ParentFile = fdesc.SurrogateProto3
 		}
 		tag = strings.TrimPrefix(tag[i:], ",")
 	}
 
 	// The generator uses the group message name instead of the field name.
 	// We obtain the real field name by lowercasing the group name.
-	if f.Kind == pref.GroupKind {
-		f.Name = pref.Name(strings.ToLower(string(f.Name)))
+	if f.L1.Kind == pref.GroupKind {
+		f.L0.FullName = pref.FullName(strings.ToLower(string(f.L0.FullName)))
 	}
 	return f
 }
@@ -169,7 +175,8 @@
 		name = string(fd.Message().Name())
 	}
 	tag = append(tag, "name="+name)
-	if jsonName := fd.JSONName(); jsonName != "" && jsonName != name {
+	if jsonName := fd.JSONName(); jsonName != "" && jsonName != name && !fd.IsExtension() {
+		// TODO: The jsonName != name condition looks wrong.
 		tag = append(tag, "json="+jsonName)
 	}
 	// The previous implementation does not tag extension fields as proto3,
@@ -186,7 +193,7 @@
 	}
 	// This must appear last in the tag, since commas in strings aren't escaped.
 	if fd.HasDefault() {
-		def, _ := defval.Marshal(fd.Default(), fd.Kind(), defval.GoTag)
+		def, _ := defval.Marshal(fd.Default(), fd.DefaultEnumValue(), fd.Kind(), defval.GoTag)
 		tag = append(tag, "def="+def)
 	}
 	return strings.Join(tag, ",")
diff --git a/internal/encoding/tag/tag_test.go b/internal/encoding/tag/tag_test.go
index 0433b42..680ba52 100644
--- a/internal/encoding/tag/tag_test.go
+++ b/internal/encoding/tag/tag_test.go
@@ -2,54 +2,40 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-package tag
+package tag_test
 
 import (
 	"reflect"
 	"testing"
 
-	"github.com/google/go-cmp/cmp"
-	"github.com/google/go-cmp/cmp/cmpopts"
-	ptype "google.golang.org/protobuf/internal/prototype"
+	"google.golang.org/protobuf/internal/encoding/tag"
+	fdesc "google.golang.org/protobuf/internal/filedesc"
+	"google.golang.org/protobuf/proto"
+	pdesc "google.golang.org/protobuf/reflect/protodesc"
 	pref "google.golang.org/protobuf/reflect/protoreflect"
 )
 
 func Test(t *testing.T) {
-	m := &ptype.StandaloneMessage{
-		Syntax:   pref.Proto3,
-		FullName: "golang.org.example.FooMessage",
-		Fields: []ptype.Field{{
-			Name:        "foo_field",
-			Number:      1337,
-			Cardinality: pref.Repeated,
-			Kind:        pref.BytesKind,
-			JSONName:    "fooField",
-			Default:     pref.ValueOf([]byte("hello, \xde\xad\xbe\xef\n")),
-		}},
-	}
-	md, err := ptype.NewMessage(m)
-	if err != nil {
-		t.Fatalf("unexpected NewMessage error: %v", err)
-	}
+	fd := new(fdesc.Field)
+	fd.L0.ParentFile = fdesc.SurrogateProto3
+	fd.L0.FullName = "foo_field"
+	fd.L1.Number = 1337
+	fd.L1.Cardinality = pref.Repeated
+	fd.L1.Kind = pref.BytesKind
+	fd.L1.JSONName = fdesc.JSONName("fooField")
+	fd.L1.Default = fdesc.DefaultValue(pref.ValueOf([]byte("hello, \xde\xad\xbe\xef\n")), nil)
 
 	// Marshal test.
-	gotTag := Marshal(md.Fields().Get(0), "")
+	gotTag := tag.Marshal(fd, "")
 	wantTag := `bytes,1337,rep,name=foo_field,json=fooField,proto3,def=hello, \336\255\276\357\n`
 	if gotTag != wantTag {
 		t.Errorf("Marshal() = `%v`, want `%v`", gotTag, wantTag)
 	}
 
 	// Unmarshal test.
-	gotField := Unmarshal(wantTag, reflect.TypeOf([]byte{}))
-	wantField := m.Fields[0]
-	opts := cmp.Options{
-		cmp.Transformer("UnwrapValue", func(x pref.Value) interface{} {
-			return x.Interface()
-		}),
-		cmpopts.IgnoreUnexported(ptype.Field{}),
-		cmpopts.IgnoreFields(ptype.Field{}, "Options"),
-	}
-	if diff := cmp.Diff(wantField, gotField, opts); diff != "" {
-		t.Errorf("Unmarshal() mismatch (-want +got):\n%v", diff)
+	gotFD := tag.Unmarshal(wantTag, reflect.TypeOf([]byte{}), nil)
+	wantFD := fd
+	if !proto.Equal(pdesc.ToFieldDescriptorProto(gotFD), pdesc.ToFieldDescriptorProto(wantFD)) {
+		t.Errorf("Umarshal() mismatch:\ngot  %v\nwant %v", gotFD, wantFD)
 	}
 }
diff --git a/internal/filedesc/build.go b/internal/filedesc/build.go
new file mode 100644
index 0000000..28bd370
--- /dev/null
+++ b/internal/filedesc/build.go
@@ -0,0 +1,150 @@
+// 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 filedesc provides functionality for constructing descriptors.
+package filedesc
+
+import (
+	"google.golang.org/protobuf/internal/encoding/wire"
+	"google.golang.org/protobuf/internal/fieldnum"
+	"google.golang.org/protobuf/reflect/protoreflect"
+	pref "google.golang.org/protobuf/reflect/protoreflect"
+	preg "google.golang.org/protobuf/reflect/protoregistry"
+)
+
+// DescBuilder construct a protoreflect.FileDescriptor from the raw descriptor.
+type DescBuilder struct {
+	// RawDescriptor is the wire-encoded bytes of FileDescriptorProto
+	// and must be populated.
+	RawDescriptor []byte
+
+	// NumEnums is the total number of enums declared in the file.
+	NumEnums int32
+	// NumMessages is the total number of messages declared in the file.
+	// It includes the implicit message declarations for map entries.
+	NumMessages int32
+	// NumExtensions is the total number of extensions declared in the file.
+	NumExtensions int32
+	// NumServices is the total number of services declared in the file.
+	NumServices int32
+
+	// TypeResolver resolves extension field types for descriptor options.
+	// If nil, it uses protoregistry.GlobalTypes.
+	TypeResolver interface {
+		preg.ExtensionTypeResolver
+	}
+
+	// FileRegistry is use to lookup file, enum, and message dependencies.
+	// Once constructed, the file descriptor is registered here.
+	// If nil, it uses protoregistry.GlobalFiles.
+	FileRegistry interface {
+		FindFileByPath(string) (protoreflect.FileDescriptor, error)
+		FindEnumByName(pref.FullName) (pref.EnumDescriptor, error)
+		FindMessageByName(pref.FullName) (pref.MessageDescriptor, error)
+		Register(...pref.FileDescriptor) error
+	}
+}
+
+// resolverByIndex is an interface DescBuilder.FileRegistry may implement.
+// If so, it permits looking up an enum or message dependency based on the
+// sub-list and element index into filetype.TypeBuilder.DependencyIndexes.
+type resolverByIndex interface {
+	FindEnumByIndex(int32, int32, []Enum, []Message) pref.EnumDescriptor
+	FindMessageByIndex(int32, int32, []Enum, []Message) pref.MessageDescriptor
+}
+
+// Indexes of each sub-list in filetype.TypeBuilder.DependencyIndexes.
+const (
+	listFieldDeps int32 = iota
+	listExtTargets
+	listExtDeps
+	listMethInDeps
+	listMethOutDeps
+)
+
+// Build constructs a FileDescriptor given the parameters set in DescBuilder.
+// It assumes that the inputs are well-formed and panics if any inconsistencies
+// are encountered.
+//
+// If NumEnums+NumMessages+NumExtensions+NumServices is zero,
+// then Build automatically derives them from the raw descriptor.
+func (db DescBuilder) Build() (out struct {
+	File pref.FileDescriptor
+
+	// Enums is all enum descriptors in "flattened ordering".
+	Enums []Enum
+	// Messages is all message descriptors in "flattened ordering".
+	// It includes the implicit message declarations for map entries.
+	Messages []Message
+	// Extensions is all extension descriptors in "flattened ordering".
+	Extensions []Extension
+	// Service is all service descriptors in "flattened ordering".
+	Services []Service
+}) {
+	// Populate the counts if uninitialized.
+	if db.NumEnums+db.NumMessages+db.NumExtensions+db.NumServices == 0 {
+		db.unmarshalCounts(db.RawDescriptor, true)
+	}
+
+	// Initialize resolvers and registries if unpopulated.
+	if db.TypeResolver == nil {
+		db.TypeResolver = preg.GlobalTypes
+	}
+	if db.FileRegistry == nil {
+		db.FileRegistry = preg.GlobalFiles
+	}
+
+	fd := newRawFile(db)
+	out.File = fd
+	out.Enums = fd.allEnums
+	out.Messages = fd.allMessages
+	out.Extensions = fd.allExtensions
+	out.Services = fd.allServices
+
+	if err := db.FileRegistry.Register(fd); err != nil {
+		panic(err)
+	}
+	return out
+}
+
+// unmarshalCounts counts the number of enum, message, extension, and service
+// declarations in the raw message, which is either a FileDescriptorProto
+// or a MessageDescriptorProto depending on whether isFile is set.
+func (db *DescBuilder) unmarshalCounts(b []byte, isFile bool) {
+	for len(b) > 0 {
+		num, typ, n := wire.ConsumeTag(b)
+		b = b[n:]
+		switch typ {
+		case wire.BytesType:
+			v, m := wire.ConsumeBytes(b)
+			b = b[m:]
+			if isFile {
+				switch num {
+				case fieldnum.FileDescriptorProto_EnumType:
+					db.NumEnums++
+				case fieldnum.FileDescriptorProto_MessageType:
+					db.unmarshalCounts(v, false)
+					db.NumMessages++
+				case fieldnum.FileDescriptorProto_Extension:
+					db.NumExtensions++
+				case fieldnum.FileDescriptorProto_Service:
+					db.NumServices++
+				}
+			} else {
+				switch num {
+				case fieldnum.DescriptorProto_EnumType:
+					db.NumEnums++
+				case fieldnum.DescriptorProto_NestedType:
+					db.unmarshalCounts(v, false)
+					db.NumMessages++
+				case fieldnum.DescriptorProto_Extension:
+					db.NumExtensions++
+				}
+			}
+		default:
+			m := wire.ConsumeFieldValue(num, typ, b)
+			b = b[m:]
+		}
+	}
+}
diff --git a/internal/fileinit/fileinit_test.go b/internal/filedesc/build_test.go
similarity index 92%
rename from internal/fileinit/fileinit_test.go
rename to internal/filedesc/build_test.go
index aca3a20..edeb56e 100644
--- a/internal/fileinit/fileinit_test.go
+++ b/internal/filedesc/build_test.go
@@ -1,4 +1,8 @@
-package fileinit_test
+// Copyright 2018 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 filedesc_test
 
 import (
 	"bytes"
@@ -17,10 +21,10 @@
 func TestInit(t *testing.T) {
 	// Compare the FileDescriptorProto for the same test file from two different sources:
 	//
-	// 1. The result of passing the fileinit-produced FileDescriptor through protodesc.
+	// 1. The result of passing the filedesc-produced FileDescriptor through protodesc.
 	// 2. The protoc-generated wire-encoded message.
 	//
-	// This serves as a test of both fileinit and protodesc.
+	// This serves as a test of both filedesc and protodesc.
 	got := protodesc.ToFileDescriptorProto(testpb.File_test_test_proto)
 
 	want := &descriptorpb.FileDescriptorProto{}
diff --git a/internal/filedesc/desc.go b/internal/filedesc/desc.go
new file mode 100644
index 0000000..40c47dc
--- /dev/null
+++ b/internal/filedesc/desc.go
@@ -0,0 +1,555 @@
+// 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 filedesc
+
+import (
+	"bytes"
+	"fmt"
+	"sync"
+	"sync/atomic"
+
+	"google.golang.org/protobuf/internal/descfmt"
+	"google.golang.org/protobuf/internal/descopts"
+	"google.golang.org/protobuf/internal/encoding/defval"
+	"google.golang.org/protobuf/internal/pragma"
+	pref "google.golang.org/protobuf/reflect/protoreflect"
+)
+
+// The types in this file may have a suffix:
+//	• L0: Contains fields common to all descriptors (except File) and
+//	must be initialized up front.
+//	• L1: Contains fields specific to a descriptor and
+//	must be initialized up front.
+//	• L2: Contains fields that are lazily initialized when constructing
+//	from the raw file descriptor. When constructing as a literal, the L2
+//	fields must be initialized up front.
+//
+// The types are exported so that packages like reflect/protodesc can
+// directly construct descriptors.
+
+type (
+	File struct {
+		fileRaw
+		L1 FileL1
+
+		once uint32     // atomically set if L2 is valid
+		mu   sync.Mutex // protects L2
+		L2   *FileL2
+	}
+	FileL1 struct {
+		Syntax  pref.Syntax
+		Path    string
+		Package pref.FullName
+
+		Enums      Enums
+		Messages   Messages
+		Extensions Extensions
+		Services   Services
+	}
+	FileL2 struct {
+		Options func() pref.ProtoMessage
+		Imports FileImports
+	}
+)
+
+func (fd *File) ParentFile() pref.FileDescriptor { return fd }
+func (fd *File) Parent() pref.Descriptor         { return nil }
+func (fd *File) Index() int                      { return 0 }
+func (fd *File) Syntax() pref.Syntax             { return fd.L1.Syntax }
+func (fd *File) Name() pref.Name                 { return fd.L1.Package.Name() }
+func (fd *File) FullName() pref.FullName         { return fd.L1.Package }
+func (fd *File) IsPlaceholder() bool             { return false }
+func (fd *File) Options() pref.ProtoMessage {
+	if f := fd.lazyInit().Options; f != nil {
+		return f()
+	}
+	return descopts.File
+}
+func (fd *File) Path() string                          { return fd.L1.Path }
+func (fd *File) Package() pref.FullName                { return fd.L1.Package }
+func (fd *File) Imports() pref.FileImports             { return &fd.lazyInit().Imports }
+func (fd *File) Enums() pref.EnumDescriptors           { return &fd.L1.Enums }
+func (fd *File) Messages() pref.MessageDescriptors     { return &fd.L1.Messages }
+func (fd *File) Extensions() pref.ExtensionDescriptors { return &fd.L1.Extensions }
+func (fd *File) Services() pref.ServiceDescriptors     { return &fd.L1.Services }
+func (fd *File) Format(s fmt.State, r rune)            { descfmt.FormatDesc(s, r, fd) }
+func (fd *File) ProtoType(pref.FileDescriptor)         {}
+func (fd *File) ProtoInternal(pragma.DoNotImplement)   {}
+
+func (fd *File) lazyInit() *FileL2 {
+	if atomic.LoadUint32(&fd.once) == 0 {
+		fd.lazyInitOnce()
+	}
+	return fd.L2
+}
+
+func (fd *File) lazyInitOnce() {
+	fd.mu.Lock()
+	if fd.L2 == nil {
+		fd.lazyRawInit() // recursively initializes all L2 structures
+	}
+	atomic.StoreUint32(&fd.once, 1)
+	fd.mu.Unlock()
+}
+
+// ProtoLegacyRawDesc is a pseudo-internal API for allowing the v1 code
+// to be able to retrieve the raw descriptor.
+//
+// WARNING: This method is exempt from the compatibility promise and may be
+// removed in the future without warning.
+func (fd *File) ProtoLegacyRawDesc() []byte {
+	return fd.builder.RawDescriptor
+}
+
+type (
+	Enum struct {
+		Base
+		L1 EnumL1
+		L2 *EnumL2 // protected by fileDesc.once
+	}
+	EnumL1 struct{}
+	EnumL2 struct {
+		Options        func() pref.ProtoMessage
+		Values         EnumValues
+		ReservedNames  Names
+		ReservedRanges EnumRanges
+	}
+
+	EnumValue struct {
+		Base
+		L1 EnumValueL1
+	}
+	EnumValueL1 struct {
+		Options func() pref.ProtoMessage
+		Number  pref.EnumNumber
+	}
+)
+
+func (ed *Enum) Options() pref.ProtoMessage {
+	if f := ed.lazyInit().Options; f != nil {
+		return f()
+	}
+	return descopts.Enum
+}
+func (ed *Enum) Values() pref.EnumValueDescriptors { return &ed.lazyInit().Values }
+func (ed *Enum) ReservedNames() pref.Names         { return &ed.lazyInit().ReservedNames }
+func (ed *Enum) ReservedRanges() pref.EnumRanges   { return &ed.lazyInit().ReservedRanges }
+func (ed *Enum) Format(s fmt.State, r rune)        { descfmt.FormatDesc(s, r, ed) }
+func (ed *Enum) ProtoType(pref.EnumDescriptor)     {}
+func (ed *Enum) lazyInit() *EnumL2 {
+	ed.L0.ParentFile.lazyInit() // implicitly initializes L2
+	return ed.L2
+}
+
+func (ed *EnumValue) Options() pref.ProtoMessage {
+	if f := ed.L1.Options; f != nil {
+		return f()
+	}
+	return descopts.EnumValue
+}
+func (ed *EnumValue) Number() pref.EnumNumber            { return ed.L1.Number }
+func (ed *EnumValue) Format(s fmt.State, r rune)         { descfmt.FormatDesc(s, r, ed) }
+func (ed *EnumValue) ProtoType(pref.EnumValueDescriptor) {}
+
+type (
+	Message struct {
+		Base
+		L1 MessageL1
+		L2 *MessageL2 // protected by fileDesc.once
+	}
+	MessageL1 struct {
+		Enums      Enums
+		Messages   Messages
+		Extensions Extensions
+	}
+	MessageL2 struct {
+		Options               func() pref.ProtoMessage
+		IsMapEntry            bool // promoted from google.protobuf.MessageOptions
+		IsMessageSet          bool // promoted from google.protobuf.MessageOptions
+		Fields                Fields
+		Oneofs                Oneofs
+		ReservedNames         Names
+		ReservedRanges        FieldRanges
+		RequiredNumbers       FieldNumbers // must be consistent with Fields.Cardinality
+		ExtensionRanges       FieldRanges
+		ExtensionRangeOptions []func() pref.ProtoMessage // must be same length as ExtensionRanges
+	}
+
+	Field struct {
+		Base
+		L1 FieldL1
+	}
+	FieldL1 struct {
+		Options         func() pref.ProtoMessage
+		Number          pref.FieldNumber
+		Cardinality     pref.Cardinality // must be consistent with Message.RequiredNumbers
+		Kind            pref.Kind
+		JSONName        jsonName
+		IsWeak          bool // promoted from google.protobuf.FieldOptions
+		HasPacked       bool // promoted from google.protobuf.FieldOptions
+		IsPacked        bool // promoted from google.protobuf.FieldOptions
+		Default         defaultValue
+		ContainingOneof pref.OneofDescriptor // must be consistent with Message.Oneofs.Fields
+		Enum            pref.EnumDescriptor
+		Message         pref.MessageDescriptor
+	}
+
+	Oneof struct {
+		Base
+		L1 OneofL1
+	}
+	OneofL1 struct {
+		Options func() pref.ProtoMessage
+		Fields  OneofFields // must be consistent with Message.Fields.ContainingOneof
+	}
+)
+
+func (md *Message) Options() pref.ProtoMessage {
+	if f := md.lazyInit().Options; f != nil {
+		return f()
+	}
+	return descopts.Message
+}
+func (md *Message) IsMapEntry() bool                   { return md.lazyInit().IsMapEntry }
+func (md *Message) Fields() pref.FieldDescriptors      { return &md.lazyInit().Fields }
+func (md *Message) Oneofs() pref.OneofDescriptors      { return &md.lazyInit().Oneofs }
+func (md *Message) ReservedNames() pref.Names          { return &md.lazyInit().ReservedNames }
+func (md *Message) ReservedRanges() pref.FieldRanges   { return &md.lazyInit().ReservedRanges }
+func (md *Message) RequiredNumbers() pref.FieldNumbers { return &md.lazyInit().RequiredNumbers }
+func (md *Message) ExtensionRanges() pref.FieldRanges  { return &md.lazyInit().ExtensionRanges }
+func (md *Message) ExtensionRangeOptions(i int) pref.ProtoMessage {
+	if f := md.lazyInit().ExtensionRangeOptions[i]; f != nil {
+		return f()
+	}
+	return descopts.ExtensionRange
+}
+func (md *Message) Enums() pref.EnumDescriptors           { return &md.L1.Enums }
+func (md *Message) Messages() pref.MessageDescriptors     { return &md.L1.Messages }
+func (md *Message) Extensions() pref.ExtensionDescriptors { return &md.L1.Extensions }
+func (md *Message) ProtoType(pref.MessageDescriptor)      {}
+func (md *Message) Format(s fmt.State, r rune)            { descfmt.FormatDesc(s, r, md) }
+func (md *Message) lazyInit() *MessageL2 {
+	md.L0.ParentFile.lazyInit() // implicitly initializes L2
+	return md.L2
+}
+
+// IsMessageSet is a pseudo-internal API for checking whether a message
+// should serialize in the proto1 message format.
+//
+// WARNING: This method is exempt from the compatibility promise and may be
+// removed in the future without warning.
+func (md *Message) IsMessageSet() bool {
+	return md.lazyInit().IsMessageSet
+}
+
+func (fd *Field) Options() pref.ProtoMessage {
+	if f := fd.L1.Options; f != nil {
+		return f()
+	}
+	return descopts.Field
+}
+func (fd *Field) Number() pref.FieldNumber      { return fd.L1.Number }
+func (fd *Field) Cardinality() pref.Cardinality { return fd.L1.Cardinality }
+func (fd *Field) Kind() pref.Kind               { return fd.L1.Kind }
+func (fd *Field) HasJSONName() bool             { return fd.L1.JSONName.has }
+func (fd *Field) JSONName() string              { return fd.L1.JSONName.get(fd) }
+func (fd *Field) IsPacked() bool {
+	if !fd.L1.HasPacked && fd.L0.ParentFile.L1.Syntax != pref.Proto2 && fd.L1.Cardinality == pref.Repeated {
+		switch fd.L1.Kind {
+		case pref.StringKind, pref.BytesKind, pref.MessageKind, pref.GroupKind:
+		default:
+			return true
+		}
+	}
+	return fd.L1.IsPacked
+}
+func (fd *Field) IsExtension() bool { return false }
+func (fd *Field) IsWeak() bool      { return fd.L1.IsWeak }
+func (fd *Field) IsList() bool      { return fd.Cardinality() == pref.Repeated && !fd.IsMap() }
+func (fd *Field) IsMap() bool       { return fd.Message() != nil && fd.Message().IsMapEntry() }
+func (fd *Field) MapKey() pref.FieldDescriptor {
+	if !fd.IsMap() {
+		return nil
+	}
+	return fd.Message().Fields().ByNumber(1)
+}
+func (fd *Field) MapValue() pref.FieldDescriptor {
+	if !fd.IsMap() {
+		return nil
+	}
+	return fd.Message().Fields().ByNumber(2)
+}
+func (fd *Field) HasDefault() bool                           { return fd.L1.Default.has }
+func (fd *Field) Default() pref.Value                        { return fd.L1.Default.get(fd) }
+func (fd *Field) DefaultEnumValue() pref.EnumValueDescriptor { return fd.L1.Default.enum }
+func (fd *Field) ContainingOneof() pref.OneofDescriptor      { return fd.L1.ContainingOneof }
+func (fd *Field) ContainingMessage() pref.MessageDescriptor {
+	return fd.L0.Parent.(pref.MessageDescriptor)
+}
+func (fd *Field) Enum() pref.EnumDescriptor       { return fd.L1.Enum }
+func (fd *Field) Message() pref.MessageDescriptor { return fd.L1.Message }
+func (fd *Field) Format(s fmt.State, r rune)      { descfmt.FormatDesc(s, r, fd) }
+func (fd *Field) ProtoType(pref.FieldDescriptor)  {}
+
+func (od *Oneof) Options() pref.ProtoMessage {
+	if f := od.L1.Options; f != nil {
+		return f()
+	}
+	return descopts.Oneof
+}
+func (od *Oneof) Fields() pref.FieldDescriptors  { return &od.L1.Fields }
+func (od *Oneof) Format(s fmt.State, r rune)     { descfmt.FormatDesc(s, r, od) }
+func (od *Oneof) ProtoType(pref.OneofDescriptor) {}
+
+type (
+	Extension struct {
+		Base
+		L1 ExtensionL1
+		L2 *ExtensionL2 // protected by fileDesc.once
+	}
+	ExtensionL1 struct {
+		Number   pref.FieldNumber
+		Extendee pref.MessageDescriptor
+		Kind     pref.Kind
+	}
+	ExtensionL2 struct {
+		Options     func() pref.ProtoMessage
+		Cardinality pref.Cardinality
+		JSONName    jsonName
+		IsPacked    bool // promoted from google.protobuf.FieldOptions
+		Default     defaultValue
+		Enum        pref.EnumDescriptor
+		Message     pref.MessageDescriptor
+	}
+)
+
+func (xd *Extension) Options() pref.ProtoMessage {
+	if f := xd.lazyInit().Options; f != nil {
+		return f()
+	}
+	return descopts.Field
+}
+func (xd *Extension) Number() pref.FieldNumber                   { return xd.L1.Number }
+func (xd *Extension) Cardinality() pref.Cardinality              { return xd.lazyInit().Cardinality }
+func (xd *Extension) Kind() pref.Kind                            { return xd.L1.Kind }
+func (xd *Extension) HasJSONName() bool                          { return xd.lazyInit().JSONName.has }
+func (xd *Extension) JSONName() string                           { return xd.lazyInit().JSONName.get(xd) }
+func (xd *Extension) IsPacked() bool                             { return xd.lazyInit().IsPacked }
+func (xd *Extension) IsExtension() bool                          { return true }
+func (xd *Extension) IsWeak() bool                               { return false }
+func (xd *Extension) IsList() bool                               { return xd.Cardinality() == pref.Repeated }
+func (xd *Extension) IsMap() bool                                { return false }
+func (xd *Extension) MapKey() pref.FieldDescriptor               { return nil }
+func (xd *Extension) MapValue() pref.FieldDescriptor             { return nil }
+func (xd *Extension) HasDefault() bool                           { return xd.lazyInit().Default.has }
+func (xd *Extension) Default() pref.Value                        { return xd.lazyInit().Default.get(xd) }
+func (xd *Extension) DefaultEnumValue() pref.EnumValueDescriptor { return xd.lazyInit().Default.enum }
+func (xd *Extension) ContainingOneof() pref.OneofDescriptor      { return nil }
+func (xd *Extension) ContainingMessage() pref.MessageDescriptor  { return xd.L1.Extendee }
+func (xd *Extension) Enum() pref.EnumDescriptor                  { return xd.lazyInit().Enum }
+func (xd *Extension) Message() pref.MessageDescriptor            { return xd.lazyInit().Message }
+func (xd *Extension) Format(s fmt.State, r rune)                 { descfmt.FormatDesc(s, r, xd) }
+func (xd *Extension) ProtoType(pref.FieldDescriptor)             {}
+func (xd *Extension) ProtoInternal(pragma.DoNotImplement)        {}
+func (xd *Extension) lazyInit() *ExtensionL2 {
+	xd.L0.ParentFile.lazyInit() // implicitly initializes L2
+	return xd.L2
+}
+
+type (
+	Service struct {
+		Base
+		L1 ServiceL1
+		L2 *ServiceL2 // protected by fileDesc.once
+	}
+	ServiceL1 struct{}
+	ServiceL2 struct {
+		Options func() pref.ProtoMessage
+		Methods Methods
+	}
+
+	Method struct {
+		Base
+		L1 MethodL1
+	}
+	MethodL1 struct {
+		Options           func() pref.ProtoMessage
+		Input             pref.MessageDescriptor
+		Output            pref.MessageDescriptor
+		IsStreamingClient bool
+		IsStreamingServer bool
+	}
+)
+
+func (sd *Service) Options() pref.ProtoMessage {
+	if f := sd.lazyInit().Options; f != nil {
+		return f()
+	}
+	return descopts.Service
+}
+func (sd *Service) Methods() pref.MethodDescriptors     { return &sd.lazyInit().Methods }
+func (sd *Service) Format(s fmt.State, r rune)          { descfmt.FormatDesc(s, r, sd) }
+func (sd *Service) ProtoType(pref.ServiceDescriptor)    {}
+func (sd *Service) ProtoInternal(pragma.DoNotImplement) {}
+func (sd *Service) lazyInit() *ServiceL2 {
+	sd.L0.ParentFile.lazyInit() // implicitly initializes L2
+	return sd.L2
+}
+
+func (md *Method) Options() pref.ProtoMessage {
+	if f := md.L1.Options; f != nil {
+		return f()
+	}
+	return descopts.Method
+}
+func (md *Method) Input() pref.MessageDescriptor       { return md.L1.Input }
+func (md *Method) Output() pref.MessageDescriptor      { return md.L1.Output }
+func (md *Method) IsStreamingClient() bool             { return md.L1.IsStreamingClient }
+func (md *Method) IsStreamingServer() bool             { return md.L1.IsStreamingServer }
+func (md *Method) Format(s fmt.State, r rune)          { descfmt.FormatDesc(s, r, md) }
+func (md *Method) ProtoType(pref.MethodDescriptor)     {}
+func (md *Method) ProtoInternal(pragma.DoNotImplement) {}
+
+// Surrogate files are can be used to create standalone descriptors
+// where the syntax is only information derived from the parent file.
+var (
+	SurrogateProto2 = &File{L1: FileL1{Syntax: pref.Proto2}, L2: &FileL2{}}
+	SurrogateProto3 = &File{L1: FileL1{Syntax: pref.Proto3}, L2: &FileL2{}}
+)
+
+type (
+	Base struct {
+		L0 BaseL0
+	}
+	BaseL0 struct {
+		FullName   pref.FullName // must be populated
+		ParentFile *File         // must be populated
+		Parent     pref.Descriptor
+		Index      int
+	}
+)
+
+func (d *Base) Name() pref.Name         { return d.L0.FullName.Name() }
+func (d *Base) FullName() pref.FullName { return d.L0.FullName }
+func (d *Base) ParentFile() pref.FileDescriptor {
+	if d.L0.ParentFile == SurrogateProto2 || d.L0.ParentFile == SurrogateProto3 {
+		return nil // surrogate files are not real parents
+	}
+	return d.L0.ParentFile
+}
+func (d *Base) Parent() pref.Descriptor             { return d.L0.Parent }
+func (d *Base) Index() int                          { return d.L0.Index }
+func (d *Base) Syntax() pref.Syntax                 { return d.L0.ParentFile.Syntax() }
+func (d *Base) IsPlaceholder() bool                 { return false }
+func (d *Base) ProtoInternal(pragma.DoNotImplement) {}
+
+func JSONName(s string) jsonName {
+	return jsonName{has: true, name: s}
+}
+
+type jsonName struct {
+	has  bool
+	once sync.Once
+	name string
+}
+
+func (js *jsonName) get(fd pref.FieldDescriptor) string {
+	if !js.has {
+		js.once.Do(func() {
+			js.name = makeJSONName(fd.Name())
+		})
+	}
+	return js.name
+}
+
+// makeJSONName creates a JSON name from the protobuf short name.
+func makeJSONName(s pref.Name) string {
+	var b []byte
+	var wasUnderscore bool
+	for i := 0; i < len(s); i++ { // proto identifiers are always ASCII
+		c := s[i]
+		if c != '_' {
+			isLower := 'a' <= c && c <= 'z'
+			if wasUnderscore && isLower {
+				c -= 'a' - 'A'
+			}
+			b = append(b, c)
+		}
+		wasUnderscore = c == '_'
+	}
+	return string(b)
+}
+
+func DefaultValue(v pref.Value, ev pref.EnumValueDescriptor) defaultValue {
+	dv := defaultValue{has: v.IsValid(), val: v, enum: ev}
+	if b, ok := v.Interface().([]byte); ok {
+		// Store a copy of the default bytes, so that we can detect
+		// accidental mutations of the original value.
+		dv.bytes = append([]byte(nil), b...)
+	}
+	return dv
+}
+
+func unmarshalDefault(b []byte, k pref.Kind, pf *File, ed pref.EnumDescriptor) defaultValue {
+	var evs pref.EnumValueDescriptors
+	if k == pref.EnumKind {
+		// If the enum is declared within the same file, be careful not to
+		// blindly call the Values method, lest we bind ourselves in a deadlock.
+		if ed, ok := ed.(*Enum); ok && ed.L0.ParentFile == pf {
+			evs = &ed.L2.Values
+		} else {
+			evs = ed.Values()
+		}
+	}
+
+	v, ev, err := defval.Unmarshal(string(b), k, evs, defval.Descriptor)
+	if err != nil {
+		panic(err)
+	}
+	return DefaultValue(v, ev)
+}
+
+type defaultValue struct {
+	has   bool
+	val   pref.Value
+	enum  pref.EnumValueDescriptor
+	bytes []byte
+}
+
+func (dv *defaultValue) get(fd pref.FieldDescriptor) pref.Value {
+	// Return the zero value as the default if unpopulated.
+	if !dv.has {
+		switch fd.Kind() {
+		case pref.BoolKind:
+			return pref.ValueOf(false)
+		case pref.Int32Kind, pref.Sint32Kind, pref.Sfixed32Kind:
+			return pref.ValueOf(int32(0))
+		case pref.Int64Kind, pref.Sint64Kind, pref.Sfixed64Kind:
+			return pref.ValueOf(int64(0))
+		case pref.Uint32Kind, pref.Fixed32Kind:
+			return pref.ValueOf(uint32(0))
+		case pref.Uint64Kind, pref.Fixed64Kind:
+			return pref.ValueOf(uint64(0))
+		case pref.FloatKind:
+			return pref.ValueOf(float32(0))
+		case pref.DoubleKind:
+			return pref.ValueOf(float64(0))
+		case pref.StringKind:
+			return pref.ValueOf(string(""))
+		case pref.BytesKind:
+			return pref.ValueOf([]byte(nil))
+		case pref.EnumKind:
+			return pref.ValueOf(fd.Enum().Values().Get(0).Number())
+		}
+	}
+
+	if len(dv.bytes) > 0 && !bytes.Equal(dv.bytes, dv.val.Bytes()) {
+		// TODO: Avoid panic if we're running with the race detector
+		// and instead spawn a goroutine that periodically resets
+		// this value back to the original to induce a race.
+		panic("detected mutation on the default bytes")
+	}
+	return dv.val
+}
diff --git a/internal/filedesc/desc_init.go b/internal/filedesc/desc_init.go
new file mode 100644
index 0000000..03abf8f
--- /dev/null
+++ b/internal/filedesc/desc_init.go
@@ -0,0 +1,390 @@
+// 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 filedesc
+
+import (
+	"google.golang.org/protobuf/internal/encoding/wire"
+	"google.golang.org/protobuf/internal/fieldnum"
+	pref "google.golang.org/protobuf/reflect/protoreflect"
+)
+
+// fileRaw is a data struct used when initializing a file descriptor from
+// a raw FileDescriptorProto.
+type fileRaw struct {
+	builder       DescBuilder
+	allEnums      []Enum
+	allMessages   []Message
+	allExtensions []Extension
+	allServices   []Service
+}
+
+func newRawFile(db DescBuilder) *File {
+	fd := &File{fileRaw: fileRaw{builder: db}}
+	fd.initDecls(db.NumEnums, db.NumMessages, db.NumExtensions, db.NumServices)
+	fd.unmarshalSeed(db.RawDescriptor)
+
+	// Extended message targets are eagerly resolved since registration
+	// needs this information at program init time.
+	for i := range fd.allExtensions {
+		xd := &fd.allExtensions[i]
+		xd.L1.Extendee = fd.resolveMessageDependency(xd.L1.Extendee, listExtTargets, int32(i))
+	}
+
+	fd.checkDecls()
+	return fd
+}
+
+// initDecls pre-allocates slices for the exact number of enums, messages
+// (including map entries), extensions, and services declared in the proto file.
+// This is done to avoid regrowing the slice, which would change the address
+// for any previously seen declaration.
+//
+// The alloc methods "allocates" slices by pulling from the capacity.
+func (fd *File) initDecls(numEnums, numMessages, numExtensions, numServices int32) {
+	fd.allEnums = make([]Enum, 0, numEnums)
+	fd.allMessages = make([]Message, 0, numMessages)
+	fd.allExtensions = make([]Extension, 0, numExtensions)
+	fd.allServices = make([]Service, 0, numServices)
+}
+
+func (fd *File) allocEnums(n int) []Enum {
+	total := len(fd.allEnums)
+	es := fd.allEnums[total : total+n]
+	fd.allEnums = fd.allEnums[:total+n]
+	return es
+}
+func (fd *File) allocMessages(n int) []Message {
+	total := len(fd.allMessages)
+	ms := fd.allMessages[total : total+n]
+	fd.allMessages = fd.allMessages[:total+n]
+	return ms
+}
+func (fd *File) allocExtensions(n int) []Extension {
+	total := len(fd.allExtensions)
+	xs := fd.allExtensions[total : total+n]
+	fd.allExtensions = fd.allExtensions[:total+n]
+	return xs
+}
+func (fd *File) allocServices(n int) []Service {
+	total := len(fd.allServices)
+	xs := fd.allServices[total : total+n]
+	fd.allServices = fd.allServices[:total+n]
+	return xs
+}
+
+// checkDecls performs a sanity check that the expected number of expected
+// declarations matches the number that were found in the descriptor proto.
+func (fd *File) checkDecls() {
+	switch {
+	case len(fd.allEnums) != cap(fd.allEnums):
+	case len(fd.allMessages) != cap(fd.allMessages):
+	case len(fd.allExtensions) != cap(fd.allExtensions):
+	case len(fd.allServices) != cap(fd.allServices):
+	default:
+		return
+	}
+	panic("mismatching cardinality")
+}
+
+func (fd *File) unmarshalSeed(b []byte) {
+	nb := getNameBuilder()
+	defer putNameBuilder(nb)
+
+	var prevField pref.FieldNumber
+	var numEnums, numMessages, numExtensions, numServices int
+	var posEnums, posMessages, posExtensions, posServices int
+	b0 := b
+	for len(b) > 0 {
+		num, typ, n := wire.ConsumeTag(b)
+		b = b[n:]
+		switch typ {
+		case wire.BytesType:
+			v, m := wire.ConsumeBytes(b)
+			b = b[m:]
+			switch num {
+			case fieldnum.FileDescriptorProto_Syntax:
+				switch string(v) {
+				case "proto2":
+					fd.L1.Syntax = pref.Proto2
+				case "proto3":
+					fd.L1.Syntax = pref.Proto3
+				default:
+					panic("invalid syntax")
+				}
+			case fieldnum.FileDescriptorProto_Name:
+				fd.L1.Path = nb.MakeString(v)
+			case fieldnum.FileDescriptorProto_Package:
+				fd.L1.Package = pref.FullName(nb.MakeString(v))
+			case fieldnum.FileDescriptorProto_EnumType:
+				if prevField != fieldnum.FileDescriptorProto_EnumType {
+					if numEnums > 0 {
+						panic("non-contiguous repeated field")
+					}
+					posEnums = len(b0) - len(b) - n - m
+				}
+				numEnums++
+			case fieldnum.FileDescriptorProto_MessageType:
+				if prevField != fieldnum.FileDescriptorProto_MessageType {
+					if numMessages > 0 {
+						panic("non-contiguous repeated field")
+					}
+					posMessages = len(b0) - len(b) - n - m
+				}
+				numMessages++
+			case fieldnum.FileDescriptorProto_Extension:
+				if prevField != fieldnum.FileDescriptorProto_Extension {
+					if numExtensions > 0 {
+						panic("non-contiguous repeated field")
+					}
+					posExtensions = len(b0) - len(b) - n - m
+				}
+				numExtensions++
+			case fieldnum.FileDescriptorProto_Service:
+				if prevField != fieldnum.FileDescriptorProto_Service {
+					if numServices > 0 {
+						panic("non-contiguous repeated field")
+					}
+					posServices = len(b0) - len(b) - n - m
+				}
+				numServices++
+			}
+			prevField = num
+		default:
+			m := wire.ConsumeFieldValue(num, typ, b)
+			b = b[m:]
+			prevField = -1 // ignore known field numbers of unknown wire type
+		}
+	}
+
+	// If syntax is missing, it is assumed to be proto2.
+	if fd.L1.Syntax == 0 {
+		fd.L1.Syntax = pref.Proto2
+	}
+
+	// Must allocate all declarations before parsing each descriptor type
+	// to ensure we handled all descriptors in "flattened ordering".
+	if numEnums > 0 {
+		fd.L1.Enums.List = fd.allocEnums(numEnums)
+	}
+	if numMessages > 0 {
+		fd.L1.Messages.List = fd.allocMessages(numMessages)
+	}
+	if numExtensions > 0 {
+		fd.L1.Extensions.List = fd.allocExtensions(numExtensions)
+	}
+	if numServices > 0 {
+		fd.L1.Services.List = fd.allocServices(numServices)
+	}
+
+	if numEnums > 0 {
+		b := b0[posEnums:]
+		for i := range fd.L1.Enums.List {
+			_, n := wire.ConsumeVarint(b)
+			v, m := wire.ConsumeBytes(b[n:])
+			fd.L1.Enums.List[i].unmarshalSeed(v, nb, fd, fd, i)
+			b = b[n+m:]
+		}
+	}
+	if numMessages > 0 {
+		b := b0[posMessages:]
+		for i := range fd.L1.Messages.List {
+			_, n := wire.ConsumeVarint(b)
+			v, m := wire.ConsumeBytes(b[n:])
+			fd.L1.Messages.List[i].unmarshalSeed(v, nb, fd, fd, i)
+			b = b[n+m:]
+		}
+	}
+	if numExtensions > 0 {
+		b := b0[posExtensions:]
+		for i := range fd.L1.Extensions.List {
+			_, n := wire.ConsumeVarint(b)
+			v, m := wire.ConsumeBytes(b[n:])
+			fd.L1.Extensions.List[i].unmarshalSeed(v, nb, fd, fd, i)
+			b = b[n+m:]
+		}
+	}
+	if numServices > 0 {
+		b := b0[posServices:]
+		for i := range fd.L1.Services.List {
+			_, n := wire.ConsumeVarint(b)
+			v, m := wire.ConsumeBytes(b[n:])
+			fd.L1.Services.List[i].unmarshalSeed(v, nb, fd, fd, i)
+			b = b[n+m:]
+		}
+	}
+}
+
+func (ed *Enum) unmarshalSeed(b []byte, nb *nameBuilder, pf *File, pd pref.Descriptor, i int) {
+	ed.L0.ParentFile = pf
+	ed.L0.Parent = pd
+	ed.L0.Index = i
+
+	for len(b) > 0 {
+		num, typ, n := wire.ConsumeTag(b)
+		b = b[n:]
+		switch typ {
+		case wire.BytesType:
+			v, m := wire.ConsumeBytes(b)
+			b = b[m:]
+			switch num {
+			case fieldnum.EnumDescriptorProto_Name:
+				ed.L0.FullName = nb.AppendFullName(pd.FullName(), v)
+			}
+		default:
+			m := wire.ConsumeFieldValue(num, typ, b)
+			b = b[m:]
+		}
+	}
+}
+
+func (md *Message) unmarshalSeed(b []byte, nb *nameBuilder, pf *File, pd pref.Descriptor, i int) {
+	md.L0.ParentFile = pf
+	md.L0.Parent = pd
+	md.L0.Index = i
+
+	var prevField pref.FieldNumber
+	var numEnums, numMessages, numExtensions int
+	var posEnums, posMessages, posExtensions int
+	b0 := b
+	for len(b) > 0 {
+		num, typ, n := wire.ConsumeTag(b)
+		b = b[n:]
+		switch typ {
+		case wire.BytesType:
+			v, m := wire.ConsumeBytes(b)
+			b = b[m:]
+			switch num {
+			case fieldnum.DescriptorProto_Name:
+				md.L0.FullName = nb.AppendFullName(pd.FullName(), v)
+			case fieldnum.DescriptorProto_EnumType:
+				if prevField != fieldnum.DescriptorProto_EnumType {
+					if numEnums > 0 {
+						panic("non-contiguous repeated field")
+					}
+					posEnums = len(b0) - len(b) - n - m
+				}
+				numEnums++
+			case fieldnum.DescriptorProto_NestedType:
+				if prevField != fieldnum.DescriptorProto_NestedType {
+					if numMessages > 0 {
+						panic("non-contiguous repeated field")
+					}
+					posMessages = len(b0) - len(b) - n - m
+				}
+				numMessages++
+			case fieldnum.DescriptorProto_Extension:
+				if prevField != fieldnum.DescriptorProto_Extension {
+					if numExtensions > 0 {
+						panic("non-contiguous repeated field")
+					}
+					posExtensions = len(b0) - len(b) - n - m
+				}
+				numExtensions++
+			}
+			prevField = num
+		default:
+			m := wire.ConsumeFieldValue(num, typ, b)
+			b = b[m:]
+			prevField = -1 // ignore known field numbers of unknown wire type
+		}
+	}
+
+	// Must allocate all declarations before parsing each descriptor type
+	// to ensure we handled all descriptors in "flattened ordering".
+	if numEnums > 0 {
+		md.L1.Enums.List = pf.allocEnums(numEnums)
+	}
+	if numMessages > 0 {
+		md.L1.Messages.List = pf.allocMessages(numMessages)
+	}
+	if numExtensions > 0 {
+		md.L1.Extensions.List = pf.allocExtensions(numExtensions)
+	}
+
+	if numEnums > 0 {
+		b := b0[posEnums:]
+		for i := range md.L1.Enums.List {
+			_, n := wire.ConsumeVarint(b)
+			v, m := wire.ConsumeBytes(b[n:])
+			md.L1.Enums.List[i].unmarshalSeed(v, nb, pf, md, i)
+			b = b[n+m:]
+		}
+	}
+	if numMessages > 0 {
+		b := b0[posMessages:]
+		for i := range md.L1.Messages.List {
+			_, n := wire.ConsumeVarint(b)
+			v, m := wire.ConsumeBytes(b[n:])
+			md.L1.Messages.List[i].unmarshalSeed(v, nb, pf, md, i)
+			b = b[n+m:]
+		}
+	}
+	if numExtensions > 0 {
+		b := b0[posExtensions:]
+		for i := range md.L1.Extensions.List {
+			_, n := wire.ConsumeVarint(b)
+			v, m := wire.ConsumeBytes(b[n:])
+			md.L1.Extensions.List[i].unmarshalSeed(v, nb, pf, md, i)
+			b = b[n+m:]
+		}
+	}
+}
+
+func (xd *Extension) unmarshalSeed(b []byte, nb *nameBuilder, pf *File, pd pref.Descriptor, i int) {
+	xd.L0.ParentFile = pf
+	xd.L0.Parent = pd
+	xd.L0.Index = i
+
+	for len(b) > 0 {
+		num, typ, n := wire.ConsumeTag(b)
+		b = b[n:]
+		switch typ {
+		case wire.VarintType:
+			v, m := wire.ConsumeVarint(b)
+			b = b[m:]
+			switch num {
+			case fieldnum.FieldDescriptorProto_Number:
+				xd.L1.Number = pref.FieldNumber(v)
+			case fieldnum.FieldDescriptorProto_Type:
+				xd.L1.Kind = pref.Kind(v)
+			}
+		case wire.BytesType:
+			v, m := wire.ConsumeBytes(b)
+			b = b[m:]
+			switch num {
+			case fieldnum.FieldDescriptorProto_Name:
+				xd.L0.FullName = nb.AppendFullName(pd.FullName(), v)
+			case fieldnum.FieldDescriptorProto_Extendee:
+				xd.L1.Extendee = PlaceholderMessage(nb.MakeFullName(v))
+			}
+		default:
+			m := wire.ConsumeFieldValue(num, typ, b)
+			b = b[m:]
+		}
+	}
+}
+
+func (sd *Service) unmarshalSeed(b []byte, nb *nameBuilder, pf *File, pd pref.Descriptor, i int) {
+	sd.L0.ParentFile = pf
+	sd.L0.Parent = pd
+	sd.L0.Index = i
+
+	for len(b) > 0 {
+		num, typ, n := wire.ConsumeTag(b)
+		b = b[n:]
+		switch typ {
+		case wire.BytesType:
+			v, m := wire.ConsumeBytes(b)
+			b = b[m:]
+			switch num {
+			case fieldnum.ServiceDescriptorProto_Name:
+				sd.L0.FullName = nb.AppendFullName(pd.FullName(), v)
+			}
+		default:
+			m := wire.ConsumeFieldValue(num, typ, b)
+			b = b[m:]
+		}
+	}
+}
diff --git a/internal/filedesc/desc_lazy.go b/internal/filedesc/desc_lazy.go
new file mode 100644
index 0000000..8b8ab5a
--- /dev/null
+++ b/internal/filedesc/desc_lazy.go
@@ -0,0 +1,686 @@
+// 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 filedesc
+
+import (
+	"reflect"
+
+	"google.golang.org/protobuf/internal/descopts"
+	"google.golang.org/protobuf/internal/encoding/wire"
+	"google.golang.org/protobuf/internal/fieldnum"
+	"google.golang.org/protobuf/proto"
+	pref "google.golang.org/protobuf/reflect/protoreflect"
+)
+
+func (fd *File) lazyRawInit() {
+	fd.unmarshalFull(fd.builder.RawDescriptor)
+	fd.resolveMessages()
+	fd.resolveExtensions()
+	fd.resolveServices()
+}
+
+func (file *File) resolveMessages() {
+	var depIdx int32
+	for i := range file.allMessages {
+		md := &file.allMessages[i]
+
+		// Resolve message field dependencies.
+		for j := range md.L2.Fields.List {
+			fd := &md.L2.Fields.List[j]
+
+			// Weak fields are only resolved by name.
+			if fd.L1.IsWeak {
+				r := file.builder.FileRegistry
+				if md, _ := r.FindMessageByName(fd.L1.Message.FullName()); md != nil {
+					fd.L1.Message = md
+				}
+				continue
+			}
+
+			// Resolve message field dependency.
+			switch fd.L1.Kind {
+			case pref.EnumKind:
+				fd.L1.Enum = file.resolveEnumDependency(fd.L1.Enum, listFieldDeps, depIdx)
+				depIdx++
+			case pref.MessageKind, pref.GroupKind:
+				fd.L1.Message = file.resolveMessageDependency(fd.L1.Message, listFieldDeps, depIdx)
+				depIdx++
+			}
+
+			// Default is resolved here since it depends on Enum being resolved.
+			if v := fd.L1.Default.val; v.IsValid() {
+				fd.L1.Default = unmarshalDefault(v.Bytes(), fd.L1.Kind, file, fd.L1.Enum)
+			}
+		}
+	}
+}
+
+func (file *File) resolveExtensions() {
+	var depIdx int32
+	for i := range file.allExtensions {
+		xd := &file.allExtensions[i]
+
+		// Resolve extension field dependency.
+		switch xd.L1.Kind {
+		case pref.EnumKind:
+			xd.L2.Enum = file.resolveEnumDependency(xd.L2.Enum, listExtDeps, depIdx)
+			depIdx++
+		case pref.MessageKind, pref.GroupKind:
+			xd.L2.Message = file.resolveMessageDependency(xd.L2.Message, listExtDeps, depIdx)
+			depIdx++
+		}
+
+		// Default is resolved here since it depends on Enum being resolved.
+		if v := xd.L2.Default.val; v.IsValid() {
+			xd.L2.Default = unmarshalDefault(v.Bytes(), xd.L1.Kind, file, xd.L2.Enum)
+		}
+	}
+}
+
+func (file *File) resolveServices() {
+	var depIdx int32
+	for i := range file.allServices {
+		sd := &file.allServices[i]
+
+		// Resolve method dependencies.
+		for j := range sd.L2.Methods.List {
+			md := &sd.L2.Methods.List[j]
+			md.L1.Input = file.resolveMessageDependency(md.L1.Input, listMethInDeps, depIdx)
+			md.L1.Output = file.resolveMessageDependency(md.L1.Output, listMethOutDeps, depIdx)
+			depIdx++
+		}
+	}
+}
+
+func (file *File) resolveEnumDependency(ed pref.EnumDescriptor, i, j int32) pref.EnumDescriptor {
+	r := file.builder.FileRegistry
+	if r, ok := r.(resolverByIndex); ok {
+		if ed2 := r.FindEnumByIndex(i, j, file.allEnums, file.allMessages); ed2 != nil {
+			return ed2
+		}
+	}
+	for i := range file.allEnums {
+		if ed2 := &file.allEnums[i]; ed2.L0.FullName == ed.FullName() {
+			return ed2
+		}
+	}
+	if ed2, _ := r.FindEnumByName(ed.FullName()); ed2 != nil {
+		return ed2
+	}
+	return ed
+}
+
+func (file *File) resolveMessageDependency(md pref.MessageDescriptor, i, j int32) pref.MessageDescriptor {
+	r := file.builder.FileRegistry
+	if r, ok := r.(resolverByIndex); ok {
+		if md2 := r.FindMessageByIndex(i, j, file.allEnums, file.allMessages); md2 != nil {
+			return md2
+		}
+	}
+	for i := range file.allMessages {
+		if md2 := &file.allMessages[i]; md2.L0.FullName == md.FullName() {
+			return md2
+		}
+	}
+	if md2, _ := r.FindMessageByName(md.FullName()); md2 != nil {
+		return md2
+	}
+	return md
+}
+
+func (fd *File) unmarshalFull(b []byte) {
+	nb := getNameBuilder()
+	defer putNameBuilder(nb)
+
+	var enumIdx, messageIdx, extensionIdx, serviceIdx int
+	var rawOptions []byte
+	fd.L2 = new(FileL2)
+	for len(b) > 0 {
+		num, typ, n := wire.ConsumeTag(b)
+		b = b[n:]
+		switch typ {
+		case wire.VarintType:
+			v, m := wire.ConsumeVarint(b)
+			b = b[m:]
+			switch num {
+			case fieldnum.FileDescriptorProto_PublicDependency:
+				fd.L2.Imports[v].IsPublic = true
+			case fieldnum.FileDescriptorProto_WeakDependency:
+				fd.L2.Imports[v].IsWeak = true
+			}
+		case wire.BytesType:
+			v, m := wire.ConsumeBytes(b)
+			b = b[m:]
+			switch num {
+			case fieldnum.FileDescriptorProto_Dependency:
+				path := nb.MakeString(v)
+				imp, _ := fd.builder.FileRegistry.FindFileByPath(path)
+				if imp == nil {
+					imp = PlaceholderFile(path)
+				}
+				fd.L2.Imports = append(fd.L2.Imports, pref.FileImport{FileDescriptor: imp})
+			case fieldnum.FileDescriptorProto_EnumType:
+				fd.L1.Enums.List[enumIdx].unmarshalFull(v, nb)
+				enumIdx++
+			case fieldnum.FileDescriptorProto_MessageType:
+				fd.L1.Messages.List[messageIdx].unmarshalFull(v, nb)
+				messageIdx++
+			case fieldnum.FileDescriptorProto_Extension:
+				fd.L1.Extensions.List[extensionIdx].unmarshalFull(v, nb)
+				extensionIdx++
+			case fieldnum.FileDescriptorProto_Service:
+				fd.L1.Services.List[serviceIdx].unmarshalFull(v, nb)
+				serviceIdx++
+			case fieldnum.FileDescriptorProto_Options:
+				rawOptions = appendOptions(rawOptions, v)
+			}
+		default:
+			m := wire.ConsumeFieldValue(num, typ, b)
+			b = b[m:]
+		}
+	}
+	fd.L2.Options = fd.builder.optionsUnmarshaler(descopts.File, rawOptions)
+}
+
+func (ed *Enum) unmarshalFull(b []byte, nb *nameBuilder) {
+	var rawValues [][]byte
+	var rawOptions []byte
+	ed.L2 = new(EnumL2)
+	for len(b) > 0 {
+		num, typ, n := wire.ConsumeTag(b)
+		b = b[n:]
+		switch typ {
+		case wire.BytesType:
+			v, m := wire.ConsumeBytes(b)
+			b = b[m:]
+			switch num {
+			case fieldnum.EnumDescriptorProto_Value:
+				rawValues = append(rawValues, v)
+			case fieldnum.EnumDescriptorProto_ReservedName:
+				ed.L2.ReservedNames.List = append(ed.L2.ReservedNames.List, pref.Name(nb.MakeString(v)))
+			case fieldnum.EnumDescriptorProto_ReservedRange:
+				ed.L2.ReservedRanges.List = append(ed.L2.ReservedRanges.List, unmarshalEnumReservedRange(v))
+			case fieldnum.EnumDescriptorProto_Options:
+				rawOptions = appendOptions(rawOptions, v)
+			}
+		default:
+			m := wire.ConsumeFieldValue(num, typ, b)
+			b = b[m:]
+		}
+	}
+	if len(rawValues) > 0 {
+		ed.L2.Values.List = make([]EnumValue, len(rawValues))
+		for i, b := range rawValues {
+			ed.L2.Values.List[i].unmarshalFull(b, nb, ed.L0.ParentFile, ed, i)
+		}
+	}
+	ed.L2.Options = ed.L0.ParentFile.builder.optionsUnmarshaler(descopts.Enum, rawOptions)
+}
+
+func unmarshalEnumReservedRange(b []byte) (r [2]pref.EnumNumber) {
+	for len(b) > 0 {
+		num, typ, n := wire.ConsumeTag(b)
+		b = b[n:]
+		switch typ {
+		case wire.VarintType:
+			v, m := wire.ConsumeVarint(b)
+			b = b[m:]
+			switch num {
+			case fieldnum.EnumDescriptorProto_EnumReservedRange_Start:
+				r[0] = pref.EnumNumber(v)
+			case fieldnum.EnumDescriptorProto_EnumReservedRange_End:
+				r[1] = pref.EnumNumber(v)
+			}
+		default:
+			m := wire.ConsumeFieldValue(num, typ, b)
+			b = b[m:]
+		}
+	}
+	return r
+}
+
+func (vd *EnumValue) unmarshalFull(b []byte, nb *nameBuilder, pf *File, pd pref.Descriptor, i int) {
+	vd.L0.ParentFile = pf
+	vd.L0.Parent = pd
+	vd.L0.Index = i
+
+	var rawOptions []byte
+	for len(b) > 0 {
+		num, typ, n := wire.ConsumeTag(b)
+		b = b[n:]
+		switch typ {
+		case wire.VarintType:
+			v, m := wire.ConsumeVarint(b)
+			b = b[m:]
+			switch num {
+			case fieldnum.EnumValueDescriptorProto_Number:
+				vd.L1.Number = pref.EnumNumber(v)
+			}
+		case wire.BytesType:
+			v, m := wire.ConsumeBytes(b)
+			b = b[m:]
+			switch num {
+			case fieldnum.EnumValueDescriptorProto_Name:
+				// NOTE: Enum values are in the same scope as the enum parent.
+				vd.L0.FullName = nb.AppendFullName(pd.Parent().FullName(), v)
+			case fieldnum.EnumValueDescriptorProto_Options:
+				rawOptions = appendOptions(rawOptions, v)
+			}
+		default:
+			m := wire.ConsumeFieldValue(num, typ, b)
+			b = b[m:]
+		}
+	}
+	vd.L1.Options = pf.builder.optionsUnmarshaler(descopts.EnumValue, rawOptions)
+}
+
+func (md *Message) unmarshalFull(b []byte, nb *nameBuilder) {
+	var rawFields, rawOneofs [][]byte
+	var enumIdx, messageIdx, extensionIdx int
+	var rawOptions []byte
+	md.L2 = new(MessageL2)
+	for len(b) > 0 {
+		num, typ, n := wire.ConsumeTag(b)
+		b = b[n:]
+		switch typ {
+		case wire.BytesType:
+			v, m := wire.ConsumeBytes(b)
+			b = b[m:]
+			switch num {
+			case fieldnum.DescriptorProto_Field:
+				rawFields = append(rawFields, v)
+			case fieldnum.DescriptorProto_OneofDecl:
+				rawOneofs = append(rawOneofs, v)
+			case fieldnum.DescriptorProto_ReservedName:
+				md.L2.ReservedNames.List = append(md.L2.ReservedNames.List, pref.Name(nb.MakeString(v)))
+			case fieldnum.DescriptorProto_ReservedRange:
+				md.L2.ReservedRanges.List = append(md.L2.ReservedRanges.List, unmarshalMessageReservedRange(v))
+			case fieldnum.DescriptorProto_ExtensionRange:
+				r, rawOptions := unmarshalMessageExtensionRange(v)
+				opts := md.L0.ParentFile.builder.optionsUnmarshaler(descopts.ExtensionRange, rawOptions)
+				md.L2.ExtensionRanges.List = append(md.L2.ExtensionRanges.List, r)
+				md.L2.ExtensionRangeOptions = append(md.L2.ExtensionRangeOptions, opts)
+			case fieldnum.DescriptorProto_EnumType:
+				md.L1.Enums.List[enumIdx].unmarshalFull(v, nb)
+				enumIdx++
+			case fieldnum.DescriptorProto_NestedType:
+				md.L1.Messages.List[messageIdx].unmarshalFull(v, nb)
+				messageIdx++
+			case fieldnum.DescriptorProto_Extension:
+				md.L1.Extensions.List[extensionIdx].unmarshalFull(v, nb)
+				extensionIdx++
+			case fieldnum.DescriptorProto_Options:
+				md.unmarshalOptions(v)
+				rawOptions = appendOptions(rawOptions, v)
+			}
+		default:
+			m := wire.ConsumeFieldValue(num, typ, b)
+			b = b[m:]
+		}
+	}
+	if len(rawFields) > 0 || len(rawOneofs) > 0 {
+		md.L2.Fields.List = make([]Field, len(rawFields))
+		md.L2.Oneofs.List = make([]Oneof, len(rawOneofs))
+		for i, b := range rawFields {
+			fd := &md.L2.Fields.List[i]
+			fd.unmarshalFull(b, nb, md.L0.ParentFile, md, i)
+			if fd.L1.Cardinality == pref.Required {
+				md.L2.RequiredNumbers.List = append(md.L2.RequiredNumbers.List, fd.L1.Number)
+			}
+		}
+		for i, b := range rawOneofs {
+			od := &md.L2.Oneofs.List[i]
+			od.unmarshalFull(b, nb, md.L0.ParentFile, md, i)
+		}
+	}
+	md.L2.Options = md.L0.ParentFile.builder.optionsUnmarshaler(descopts.Message, rawOptions)
+}
+
+func (md *Message) unmarshalOptions(b []byte) {
+	for len(b) > 0 {
+		num, typ, n := wire.ConsumeTag(b)
+		b = b[n:]
+		switch typ {
+		case wire.VarintType:
+			v, m := wire.ConsumeVarint(b)
+			b = b[m:]
+			switch num {
+			case fieldnum.MessageOptions_MapEntry:
+				md.L2.IsMapEntry = wire.DecodeBool(v)
+			case fieldnum.MessageOptions_MessageSetWireFormat:
+				md.L2.IsMessageSet = wire.DecodeBool(v)
+			}
+		default:
+			m := wire.ConsumeFieldValue(num, typ, b)
+			b = b[m:]
+		}
+	}
+}
+
+func unmarshalMessageReservedRange(b []byte) (r [2]pref.FieldNumber) {
+	for len(b) > 0 {
+		num, typ, n := wire.ConsumeTag(b)
+		b = b[n:]
+		switch typ {
+		case wire.VarintType:
+			v, m := wire.ConsumeVarint(b)
+			b = b[m:]
+			switch num {
+			case fieldnum.DescriptorProto_ReservedRange_Start:
+				r[0] = pref.FieldNumber(v)
+			case fieldnum.DescriptorProto_ReservedRange_End:
+				r[1] = pref.FieldNumber(v)
+			}
+		default:
+			m := wire.ConsumeFieldValue(num, typ, b)
+			b = b[m:]
+		}
+	}
+	return r
+}
+
+func unmarshalMessageExtensionRange(b []byte) (r [2]pref.FieldNumber, rawOptions []byte) {
+	for len(b) > 0 {
+		num, typ, n := wire.ConsumeTag(b)
+		b = b[n:]
+		switch typ {
+		case wire.VarintType:
+			v, m := wire.ConsumeVarint(b)
+			b = b[m:]
+			switch num {
+			case fieldnum.DescriptorProto_ExtensionRange_Start:
+				r[0] = pref.FieldNumber(v)
+			case fieldnum.DescriptorProto_ExtensionRange_End:
+				r[1] = pref.FieldNumber(v)
+			}
+		case wire.BytesType:
+			v, m := wire.ConsumeBytes(b)
+			b = b[m:]
+			switch num {
+			case fieldnum.DescriptorProto_ExtensionRange_Options:
+				rawOptions = appendOptions(rawOptions, v)
+			}
+		default:
+			m := wire.ConsumeFieldValue(num, typ, b)
+			b = b[m:]
+		}
+	}
+	return r, rawOptions
+}
+
+func (fd *Field) unmarshalFull(b []byte, nb *nameBuilder, pf *File, pd pref.Descriptor, i int) {
+	fd.L0.ParentFile = pf
+	fd.L0.Parent = pd
+	fd.L0.Index = i
+
+	var rawTypeName []byte
+	var rawOptions []byte
+	for len(b) > 0 {
+		num, typ, n := wire.ConsumeTag(b)
+		b = b[n:]
+		switch typ {
+		case wire.VarintType:
+			v, m := wire.ConsumeVarint(b)
+			b = b[m:]
+			switch num {
+			case fieldnum.FieldDescriptorProto_Number:
+				fd.L1.Number = pref.FieldNumber(v)
+			case fieldnum.FieldDescriptorProto_Label:
+				fd.L1.Cardinality = pref.Cardinality(v)
+			case fieldnum.FieldDescriptorProto_Type:
+				fd.L1.Kind = pref.Kind(v)
+			case fieldnum.FieldDescriptorProto_OneofIndex:
+				// In Message.unmarshalFull, we allocate slices for both
+				// the field and oneof descriptors before unmarshaling either
+				// of them. This ensures pointers to slice elements are stable.
+				od := &pd.(*Message).L2.Oneofs.List[v]
+				od.L1.Fields.List = append(od.L1.Fields.List, fd)
+				if fd.L1.ContainingOneof != nil {
+					panic("oneof type already set")
+				}
+				fd.L1.ContainingOneof = od
+			}
+		case wire.BytesType:
+			v, m := wire.ConsumeBytes(b)
+			b = b[m:]
+			switch num {
+			case fieldnum.FieldDescriptorProto_Name:
+				fd.L0.FullName = nb.AppendFullName(pd.FullName(), v)
+			case fieldnum.FieldDescriptorProto_JsonName:
+				fd.L1.JSONName = JSONName(nb.MakeString(v))
+			case fieldnum.FieldDescriptorProto_DefaultValue:
+				fd.L1.Default.val = pref.ValueOf(v) // temporarily store as bytes; later resolved in resolveMessages
+			case fieldnum.FieldDescriptorProto_TypeName:
+				rawTypeName = v
+			case fieldnum.FieldDescriptorProto_Options:
+				fd.unmarshalOptions(v)
+				rawOptions = appendOptions(rawOptions, v)
+			}
+		default:
+			m := wire.ConsumeFieldValue(num, typ, b)
+			b = b[m:]
+		}
+	}
+	if rawTypeName != nil {
+		name := nb.MakeFullName(rawTypeName)
+		switch fd.L1.Kind {
+		case pref.EnumKind:
+			fd.L1.Enum = PlaceholderEnum(name)
+		case pref.MessageKind, pref.GroupKind:
+			fd.L1.Message = PlaceholderMessage(name)
+		}
+	}
+	fd.L1.Options = pf.builder.optionsUnmarshaler(descopts.Field, rawOptions)
+}
+
+func (fd *Field) unmarshalOptions(b []byte) {
+	for len(b) > 0 {
+		num, typ, n := wire.ConsumeTag(b)
+		b = b[n:]
+		switch typ {
+		case wire.VarintType:
+			v, m := wire.ConsumeVarint(b)
+			b = b[m:]
+			switch num {
+			case fieldnum.FieldOptions_Packed:
+				fd.L1.HasPacked = true
+				fd.L1.IsPacked = wire.DecodeBool(v)
+			case fieldnum.FieldOptions_Weak:
+				fd.L1.IsWeak = wire.DecodeBool(v)
+			}
+		default:
+			m := wire.ConsumeFieldValue(num, typ, b)
+			b = b[m:]
+		}
+	}
+}
+
+func (od *Oneof) unmarshalFull(b []byte, nb *nameBuilder, pf *File, pd pref.Descriptor, i int) {
+	od.L0.ParentFile = pf
+	od.L0.Parent = pd
+	od.L0.Index = i
+
+	var rawOptions []byte
+	for len(b) > 0 {
+		num, typ, n := wire.ConsumeTag(b)
+		b = b[n:]
+		switch typ {
+		case wire.BytesType:
+			v, m := wire.ConsumeBytes(b)
+			b = b[m:]
+			switch num {
+			case fieldnum.OneofDescriptorProto_Name:
+				od.L0.FullName = nb.AppendFullName(pd.FullName(), v)
+			case fieldnum.OneofDescriptorProto_Options:
+				rawOptions = appendOptions(rawOptions, v)
+			}
+		default:
+			m := wire.ConsumeFieldValue(num, typ, b)
+			b = b[m:]
+		}
+	}
+	od.L1.Options = pf.builder.optionsUnmarshaler(descopts.Oneof, rawOptions)
+}
+
+func (xd *Extension) unmarshalFull(b []byte, nb *nameBuilder) {
+	var rawTypeName []byte
+	var rawOptions []byte
+	xd.L2 = new(ExtensionL2)
+	for len(b) > 0 {
+		num, typ, n := wire.ConsumeTag(b)
+		b = b[n:]
+		switch typ {
+		case wire.VarintType:
+			v, m := wire.ConsumeVarint(b)
+			b = b[m:]
+			switch num {
+			case fieldnum.FieldDescriptorProto_Label:
+				xd.L2.Cardinality = pref.Cardinality(v)
+			}
+		case wire.BytesType:
+			v, m := wire.ConsumeBytes(b)
+			b = b[m:]
+			switch num {
+			case fieldnum.FieldDescriptorProto_JsonName:
+				xd.L2.JSONName = JSONName(nb.MakeString(v))
+			case fieldnum.FieldDescriptorProto_DefaultValue:
+				xd.L2.Default.val = pref.ValueOf(v) // temporarily store as bytes; later resolved in resolveExtensions
+			case fieldnum.FieldDescriptorProto_TypeName:
+				rawTypeName = v
+			case fieldnum.FieldDescriptorProto_Options:
+				xd.unmarshalOptions(v)
+				rawOptions = appendOptions(rawOptions, v)
+			}
+		default:
+			m := wire.ConsumeFieldValue(num, typ, b)
+			b = b[m:]
+		}
+	}
+	if rawTypeName != nil {
+		name := nb.MakeFullName(rawTypeName)
+		switch xd.L1.Kind {
+		case pref.EnumKind:
+			xd.L2.Enum = PlaceholderEnum(name)
+		case pref.MessageKind, pref.GroupKind:
+			xd.L2.Message = PlaceholderMessage(name)
+		}
+	}
+	xd.L2.Options = xd.L0.ParentFile.builder.optionsUnmarshaler(descopts.Field, rawOptions)
+}
+
+func (xd *Extension) unmarshalOptions(b []byte) {
+	for len(b) > 0 {
+		num, typ, n := wire.ConsumeTag(b)
+		b = b[n:]
+		switch typ {
+		case wire.VarintType:
+			v, m := wire.ConsumeVarint(b)
+			b = b[m:]
+			switch num {
+			case fieldnum.FieldOptions_Packed:
+				xd.L2.IsPacked = wire.DecodeBool(v)
+			}
+		default:
+			m := wire.ConsumeFieldValue(num, typ, b)
+			b = b[m:]
+		}
+	}
+}
+
+func (sd *Service) unmarshalFull(b []byte, nb *nameBuilder) {
+	var rawMethods [][]byte
+	var rawOptions []byte
+	sd.L2 = new(ServiceL2)
+	for len(b) > 0 {
+		num, typ, n := wire.ConsumeTag(b)
+		b = b[n:]
+		switch typ {
+		case wire.BytesType:
+			v, m := wire.ConsumeBytes(b)
+			b = b[m:]
+			switch num {
+			case fieldnum.ServiceDescriptorProto_Method:
+				rawMethods = append(rawMethods, v)
+			case fieldnum.ServiceDescriptorProto_Options:
+				rawOptions = appendOptions(rawOptions, v)
+			}
+		default:
+			m := wire.ConsumeFieldValue(num, typ, b)
+			b = b[m:]
+		}
+	}
+	if len(rawMethods) > 0 {
+		sd.L2.Methods.List = make([]Method, len(rawMethods))
+		for i, b := range rawMethods {
+			sd.L2.Methods.List[i].unmarshalFull(b, nb, sd.L0.ParentFile, sd, i)
+		}
+	}
+	sd.L2.Options = sd.L0.ParentFile.builder.optionsUnmarshaler(descopts.Service, rawOptions)
+}
+
+func (md *Method) unmarshalFull(b []byte, nb *nameBuilder, pf *File, pd pref.Descriptor, i int) {
+	md.L0.ParentFile = pf
+	md.L0.Parent = pd
+	md.L0.Index = i
+
+	var rawOptions []byte
+	for len(b) > 0 {
+		num, typ, n := wire.ConsumeTag(b)
+		b = b[n:]
+		switch typ {
+		case wire.VarintType:
+			v, m := wire.ConsumeVarint(b)
+			b = b[m:]
+			switch num {
+			case fieldnum.MethodDescriptorProto_ClientStreaming:
+				md.L1.IsStreamingClient = wire.DecodeBool(v)
+			case fieldnum.MethodDescriptorProto_ServerStreaming:
+				md.L1.IsStreamingServer = wire.DecodeBool(v)
+			}
+		case wire.BytesType:
+			v, m := wire.ConsumeBytes(b)
+			b = b[m:]
+			switch num {
+			case fieldnum.MethodDescriptorProto_Name:
+				md.L0.FullName = nb.AppendFullName(pd.FullName(), v)
+			case fieldnum.MethodDescriptorProto_InputType:
+				md.L1.Input = PlaceholderMessage(nb.MakeFullName(v))
+			case fieldnum.MethodDescriptorProto_OutputType:
+				md.L1.Output = PlaceholderMessage(nb.MakeFullName(v))
+			case fieldnum.MethodDescriptorProto_Options:
+				rawOptions = appendOptions(rawOptions, v)
+			}
+		default:
+			m := wire.ConsumeFieldValue(num, typ, b)
+			b = b[m:]
+		}
+	}
+	md.L1.Options = pf.builder.optionsUnmarshaler(descopts.Method, rawOptions)
+}
+
+// appendOptions appends src to dst, where the returned slice is never nil.
+// This is necessary to distinguish between empty and unpopulated options.
+func appendOptions(dst, src []byte) []byte {
+	if dst == nil {
+		dst = []byte{}
+	}
+	return append(dst, src...)
+}
+
+func (db *DescBuilder) optionsUnmarshaler(p pref.ProtoMessage, b []byte) func() pref.ProtoMessage {
+	if b == nil {
+		return nil
+	}
+	return func() pref.ProtoMessage {
+		p := reflect.New(reflect.TypeOf(p).Elem()).Interface().(pref.ProtoMessage)
+		if err := (proto.UnmarshalOptions{
+			AllowPartial: true,
+			Resolver:     db.TypeResolver,
+		}).Unmarshal(b, p); err != nil {
+			panic(err)
+		}
+		return p
+	}
+}
diff --git a/internal/filedesc/desc_list.go b/internal/filedesc/desc_list.go
new file mode 100644
index 0000000..bbded60
--- /dev/null
+++ b/internal/filedesc/desc_list.go
@@ -0,0 +1,189 @@
+// 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 filedesc
+
+import (
+	"fmt"
+	"sort"
+	"sync"
+
+	"google.golang.org/protobuf/internal/descfmt"
+	"google.golang.org/protobuf/internal/pragma"
+	pref "google.golang.org/protobuf/reflect/protoreflect"
+)
+
+type FileImports []pref.FileImport
+
+func (p *FileImports) Len() int                            { return len(*p) }
+func (p *FileImports) Get(i int) pref.FileImport           { return (*p)[i] }
+func (p *FileImports) Format(s fmt.State, r rune)          { descfmt.FormatList(s, r, p) }
+func (p *FileImports) ProtoInternal(pragma.DoNotImplement) {}
+
+type Names struct {
+	List []pref.Name
+	once sync.Once
+	has  map[pref.Name]struct{} // protected by once
+}
+
+func (p *Names) Len() int            { return len(p.List) }
+func (p *Names) Get(i int) pref.Name { return p.List[i] }
+func (p *Names) Has(s pref.Name) bool {
+	p.once.Do(func() {
+		if len(p.List) > 0 {
+			p.has = make(map[pref.Name]struct{}, len(p.List))
+			for _, s := range p.List {
+				p.has[s] = struct{}{}
+			}
+		}
+	})
+	_, ok := p.has[s]
+	return ok
+}
+func (p *Names) Format(s fmt.State, r rune)          { descfmt.FormatList(s, r, p) }
+func (p *Names) ProtoInternal(pragma.DoNotImplement) {}
+
+type EnumRanges struct {
+	List   [][2]pref.EnumNumber // start inclusive; end inclusive
+	once   sync.Once
+	sorted [][2]pref.EnumNumber         // protected by once
+	has    map[pref.EnumNumber]struct{} // protected by once
+}
+
+func (p *EnumRanges) Len() int                     { return len(p.List) }
+func (p *EnumRanges) Get(i int) [2]pref.EnumNumber { return p.List[i] }
+func (p *EnumRanges) Has(n pref.EnumNumber) bool {
+	p.once.Do(func() {
+		for _, r := range p.List {
+			if r[0] == r[1]-0 {
+				if p.has == nil {
+					p.has = make(map[pref.EnumNumber]struct{}, len(p.List))
+				}
+				p.has[r[0]] = struct{}{}
+			} else {
+				p.sorted = append(p.sorted, r)
+			}
+		}
+		sort.Slice(p.sorted, func(i, j int) bool {
+			return p.sorted[i][0] < p.sorted[j][0]
+		})
+	})
+	if _, ok := p.has[n]; ok {
+		return true
+	}
+	for ls := p.sorted; len(ls) > 0; {
+		i := len(ls) / 2
+		switch r := ls[i]; {
+		case n < r[0]:
+			ls = ls[:i] // search lower
+		case n > r[1]:
+			ls = ls[i+1:] // search upper
+		default:
+			return true
+		}
+	}
+	return false
+}
+func (p *EnumRanges) Format(s fmt.State, r rune)          { descfmt.FormatList(s, r, p) }
+func (p *EnumRanges) ProtoInternal(pragma.DoNotImplement) {}
+
+type FieldRanges struct {
+	List   [][2]pref.FieldNumber // start inclusive; end exclusive
+	once   sync.Once
+	sorted [][2]pref.FieldNumber         // protected by once
+	has    map[pref.FieldNumber]struct{} // protected by once
+}
+
+func (p *FieldRanges) Len() int                      { return len(p.List) }
+func (p *FieldRanges) Get(i int) [2]pref.FieldNumber { return p.List[i] }
+func (p *FieldRanges) Has(n pref.FieldNumber) bool {
+	p.once.Do(func() {
+		for _, r := range p.List {
+			if r[0] == r[1]-1 {
+				if p.has == nil {
+					p.has = make(map[pref.FieldNumber]struct{}, len(p.List))
+				}
+				p.has[r[0]] = struct{}{}
+			} else {
+				p.sorted = append(p.sorted, r)
+			}
+		}
+		sort.Slice(p.sorted, func(i, j int) bool {
+			return p.sorted[i][0] < p.sorted[j][0]
+		})
+	})
+	if _, ok := p.has[n]; ok {
+		return true
+	}
+	for ls := p.sorted; len(ls) > 0; {
+		i := len(ls) / 2
+		switch r := ls[i]; {
+		case n < r[0]:
+			ls = ls[:i] // search lower
+		case n >= r[1]:
+			ls = ls[i+1:] // search higher
+		default:
+			return true
+		}
+	}
+	return false
+}
+func (p *FieldRanges) Format(s fmt.State, r rune)          { descfmt.FormatList(s, r, p) }
+func (p *FieldRanges) ProtoInternal(pragma.DoNotImplement) {}
+
+type FieldNumbers struct {
+	List []pref.FieldNumber
+	once sync.Once
+	has  map[pref.FieldNumber]struct{} // protected by once
+}
+
+func (p *FieldNumbers) Len() int                   { return len(p.List) }
+func (p *FieldNumbers) Get(i int) pref.FieldNumber { return p.List[i] }
+func (p *FieldNumbers) Has(n pref.FieldNumber) bool {
+	p.once.Do(func() {
+		if len(p.List) > 0 {
+			p.has = make(map[pref.FieldNumber]struct{}, len(p.List))
+			for _, n := range p.List {
+				p.has[n] = struct{}{}
+			}
+		}
+	})
+	_, ok := p.has[n]
+	return ok
+}
+func (p *FieldNumbers) Format(s fmt.State, r rune)          { descfmt.FormatList(s, r, p) }
+func (p *FieldNumbers) ProtoInternal(pragma.DoNotImplement) {}
+
+type OneofFields struct {
+	List   []pref.FieldDescriptor
+	once   sync.Once
+	byName map[pref.Name]pref.FieldDescriptor        // protected by once
+	byJSON map[string]pref.FieldDescriptor           // protected by once
+	byNum  map[pref.FieldNumber]pref.FieldDescriptor // protected by once
+}
+
+func (p *OneofFields) Len() int                                         { return len(p.List) }
+func (p *OneofFields) Get(i int) pref.FieldDescriptor                   { return p.List[i] }
+func (p *OneofFields) ByName(s pref.Name) pref.FieldDescriptor          { return p.lazyInit().byName[s] }
+func (p *OneofFields) ByJSONName(s string) pref.FieldDescriptor         { return p.lazyInit().byJSON[s] }
+func (p *OneofFields) ByNumber(n pref.FieldNumber) pref.FieldDescriptor { return p.lazyInit().byNum[n] }
+func (p *OneofFields) Format(s fmt.State, r rune)                       { descfmt.FormatList(s, r, p) }
+func (p *OneofFields) ProtoInternal(pragma.DoNotImplement)              {}
+
+func (p *OneofFields) lazyInit() *OneofFields {
+	p.once.Do(func() {
+		if len(p.List) > 0 {
+			p.byName = make(map[pref.Name]pref.FieldDescriptor, len(p.List))
+			p.byJSON = make(map[string]pref.FieldDescriptor, len(p.List))
+			p.byNum = make(map[pref.FieldNumber]pref.FieldDescriptor, len(p.List))
+			for _, f := range p.List {
+				// Field names and numbers are guaranteed to be unique.
+				p.byName[f.Name()] = f
+				p.byJSON[f.JSONName()] = f
+				p.byNum[f.Number()] = f
+			}
+		}
+	})
+	return p
+}
diff --git a/internal/filedesc/desc_list_gen.go b/internal/filedesc/desc_list_gen.go
new file mode 100644
index 0000000..d875920
--- /dev/null
+++ b/internal/filedesc/desc_list_gen.go
@@ -0,0 +1,345 @@
+// Copyright 2018 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.
+
+// Code generated by generate-types. DO NOT EDIT.
+
+package filedesc
+
+import (
+	"fmt"
+	"sync"
+
+	"google.golang.org/protobuf/internal/descfmt"
+	"google.golang.org/protobuf/internal/pragma"
+	"google.golang.org/protobuf/reflect/protoreflect"
+)
+
+type Enums struct {
+	List   []Enum
+	once   sync.Once
+	byName map[protoreflect.Name]*Enum // protected by once
+}
+
+func (p *Enums) Len() int {
+	return len(p.List)
+}
+func (p *Enums) Get(i int) protoreflect.EnumDescriptor {
+	return &p.List[i]
+}
+func (p *Enums) ByName(s protoreflect.Name) protoreflect.EnumDescriptor {
+	if d := p.lazyInit().byName[s]; d != nil {
+		return d
+	}
+	return nil
+}
+func (p *Enums) Format(s fmt.State, r rune) {
+	descfmt.FormatList(s, r, p)
+}
+func (p *Enums) ProtoInternal(pragma.DoNotImplement) {}
+func (p *Enums) lazyInit() *Enums {
+	p.once.Do(func() {
+		if len(p.List) > 0 {
+			p.byName = make(map[protoreflect.Name]*Enum, len(p.List))
+			for i := range p.List {
+				d := &p.List[i]
+				if _, ok := p.byName[d.Name()]; !ok {
+					p.byName[d.Name()] = d
+				}
+			}
+		}
+	})
+	return p
+}
+
+type EnumValues struct {
+	List   []EnumValue
+	once   sync.Once
+	byName map[protoreflect.Name]*EnumValue       // protected by once
+	byNum  map[protoreflect.EnumNumber]*EnumValue // protected by once
+}
+
+func (p *EnumValues) Len() int {
+	return len(p.List)
+}
+func (p *EnumValues) Get(i int) protoreflect.EnumValueDescriptor {
+	return &p.List[i]
+}
+func (p *EnumValues) ByName(s protoreflect.Name) protoreflect.EnumValueDescriptor {
+	if d := p.lazyInit().byName[s]; d != nil {
+		return d
+	}
+	return nil
+}
+func (p *EnumValues) ByNumber(n protoreflect.EnumNumber) protoreflect.EnumValueDescriptor {
+	if d := p.lazyInit().byNum[n]; d != nil {
+		return d
+	}
+	return nil
+}
+func (p *EnumValues) Format(s fmt.State, r rune) {
+	descfmt.FormatList(s, r, p)
+}
+func (p *EnumValues) ProtoInternal(pragma.DoNotImplement) {}
+func (p *EnumValues) lazyInit() *EnumValues {
+	p.once.Do(func() {
+		if len(p.List) > 0 {
+			p.byName = make(map[protoreflect.Name]*EnumValue, len(p.List))
+			p.byNum = make(map[protoreflect.EnumNumber]*EnumValue, len(p.List))
+			for i := range p.List {
+				d := &p.List[i]
+				if _, ok := p.byName[d.Name()]; !ok {
+					p.byName[d.Name()] = d
+				}
+				if _, ok := p.byNum[d.Number()]; !ok {
+					p.byNum[d.Number()] = d
+				}
+			}
+		}
+	})
+	return p
+}
+
+type Messages struct {
+	List   []Message
+	once   sync.Once
+	byName map[protoreflect.Name]*Message // protected by once
+}
+
+func (p *Messages) Len() int {
+	return len(p.List)
+}
+func (p *Messages) Get(i int) protoreflect.MessageDescriptor {
+	return &p.List[i]
+}
+func (p *Messages) ByName(s protoreflect.Name) protoreflect.MessageDescriptor {
+	if d := p.lazyInit().byName[s]; d != nil {
+		return d
+	}
+	return nil
+}
+func (p *Messages) Format(s fmt.State, r rune) {
+	descfmt.FormatList(s, r, p)
+}
+func (p *Messages) ProtoInternal(pragma.DoNotImplement) {}
+func (p *Messages) lazyInit() *Messages {
+	p.once.Do(func() {
+		if len(p.List) > 0 {
+			p.byName = make(map[protoreflect.Name]*Message, len(p.List))
+			for i := range p.List {
+				d := &p.List[i]
+				if _, ok := p.byName[d.Name()]; !ok {
+					p.byName[d.Name()] = d
+				}
+			}
+		}
+	})
+	return p
+}
+
+type Fields struct {
+	List   []Field
+	once   sync.Once
+	byName map[protoreflect.Name]*Field        // protected by once
+	byJSON map[string]*Field                   // protected by once
+	byNum  map[protoreflect.FieldNumber]*Field // protected by once
+}
+
+func (p *Fields) Len() int {
+	return len(p.List)
+}
+func (p *Fields) Get(i int) protoreflect.FieldDescriptor {
+	return &p.List[i]
+}
+func (p *Fields) ByName(s protoreflect.Name) protoreflect.FieldDescriptor {
+	if d := p.lazyInit().byName[s]; d != nil {
+		return d
+	}
+	return nil
+}
+func (p *Fields) ByJSONName(s string) protoreflect.FieldDescriptor {
+	if d := p.lazyInit().byJSON[s]; d != nil {
+		return d
+	}
+	return nil
+}
+func (p *Fields) ByNumber(n protoreflect.FieldNumber) protoreflect.FieldDescriptor {
+	if d := p.lazyInit().byNum[n]; d != nil {
+		return d
+	}
+	return nil
+}
+func (p *Fields) Format(s fmt.State, r rune) {
+	descfmt.FormatList(s, r, p)
+}
+func (p *Fields) ProtoInternal(pragma.DoNotImplement) {}
+func (p *Fields) lazyInit() *Fields {
+	p.once.Do(func() {
+		if len(p.List) > 0 {
+			p.byName = make(map[protoreflect.Name]*Field, len(p.List))
+			p.byJSON = make(map[string]*Field, len(p.List))
+			p.byNum = make(map[protoreflect.FieldNumber]*Field, len(p.List))
+			for i := range p.List {
+				d := &p.List[i]
+				if _, ok := p.byName[d.Name()]; !ok {
+					p.byName[d.Name()] = d
+				}
+				if _, ok := p.byJSON[d.JSONName()]; !ok {
+					p.byJSON[d.JSONName()] = d
+				}
+				if _, ok := p.byNum[d.Number()]; !ok {
+					p.byNum[d.Number()] = d
+				}
+			}
+		}
+	})
+	return p
+}
+
+type Oneofs struct {
+	List   []Oneof
+	once   sync.Once
+	byName map[protoreflect.Name]*Oneof // protected by once
+}
+
+func (p *Oneofs) Len() int {
+	return len(p.List)
+}
+func (p *Oneofs) Get(i int) protoreflect.OneofDescriptor {
+	return &p.List[i]
+}
+func (p *Oneofs) ByName(s protoreflect.Name) protoreflect.OneofDescriptor {
+	if d := p.lazyInit().byName[s]; d != nil {
+		return d
+	}
+	return nil
+}
+func (p *Oneofs) Format(s fmt.State, r rune) {
+	descfmt.FormatList(s, r, p)
+}
+func (p *Oneofs) ProtoInternal(pragma.DoNotImplement) {}
+func (p *Oneofs) lazyInit() *Oneofs {
+	p.once.Do(func() {
+		if len(p.List) > 0 {
+			p.byName = make(map[protoreflect.Name]*Oneof, len(p.List))
+			for i := range p.List {
+				d := &p.List[i]
+				if _, ok := p.byName[d.Name()]; !ok {
+					p.byName[d.Name()] = d
+				}
+			}
+		}
+	})
+	return p
+}
+
+type Extensions struct {
+	List   []Extension
+	once   sync.Once
+	byName map[protoreflect.Name]*Extension // protected by once
+}
+
+func (p *Extensions) Len() int {
+	return len(p.List)
+}
+func (p *Extensions) Get(i int) protoreflect.ExtensionDescriptor {
+	return &p.List[i]
+}
+func (p *Extensions) ByName(s protoreflect.Name) protoreflect.ExtensionDescriptor {
+	if d := p.lazyInit().byName[s]; d != nil {
+		return d
+	}
+	return nil
+}
+func (p *Extensions) Format(s fmt.State, r rune) {
+	descfmt.FormatList(s, r, p)
+}
+func (p *Extensions) ProtoInternal(pragma.DoNotImplement) {}
+func (p *Extensions) lazyInit() *Extensions {
+	p.once.Do(func() {
+		if len(p.List) > 0 {
+			p.byName = make(map[protoreflect.Name]*Extension, len(p.List))
+			for i := range p.List {
+				d := &p.List[i]
+				if _, ok := p.byName[d.Name()]; !ok {
+					p.byName[d.Name()] = d
+				}
+			}
+		}
+	})
+	return p
+}
+
+type Services struct {
+	List   []Service
+	once   sync.Once
+	byName map[protoreflect.Name]*Service // protected by once
+}
+
+func (p *Services) Len() int {
+	return len(p.List)
+}
+func (p *Services) Get(i int) protoreflect.ServiceDescriptor {
+	return &p.List[i]
+}
+func (p *Services) ByName(s protoreflect.Name) protoreflect.ServiceDescriptor {
+	if d := p.lazyInit().byName[s]; d != nil {
+		return d
+	}
+	return nil
+}
+func (p *Services) Format(s fmt.State, r rune) {
+	descfmt.FormatList(s, r, p)
+}
+func (p *Services) ProtoInternal(pragma.DoNotImplement) {}
+func (p *Services) lazyInit() *Services {
+	p.once.Do(func() {
+		if len(p.List) > 0 {
+			p.byName = make(map[protoreflect.Name]*Service, len(p.List))
+			for i := range p.List {
+				d := &p.List[i]
+				if _, ok := p.byName[d.Name()]; !ok {
+					p.byName[d.Name()] = d
+				}
+			}
+		}
+	})
+	return p
+}
+
+type Methods struct {
+	List   []Method
+	once   sync.Once
+	byName map[protoreflect.Name]*Method // protected by once
+}
+
+func (p *Methods) Len() int {
+	return len(p.List)
+}
+func (p *Methods) Get(i int) protoreflect.MethodDescriptor {
+	return &p.List[i]
+}
+func (p *Methods) ByName(s protoreflect.Name) protoreflect.MethodDescriptor {
+	if d := p.lazyInit().byName[s]; d != nil {
+		return d
+	}
+	return nil
+}
+func (p *Methods) Format(s fmt.State, r rune) {
+	descfmt.FormatList(s, r, p)
+}
+func (p *Methods) ProtoInternal(pragma.DoNotImplement) {}
+func (p *Methods) lazyInit() *Methods {
+	p.once.Do(func() {
+		if len(p.List) > 0 {
+			p.byName = make(map[protoreflect.Name]*Method, len(p.List))
+			for i := range p.List {
+				d := &p.List[i]
+				if _, ok := p.byName[d.Name()]; !ok {
+					p.byName[d.Name()] = d
+				}
+			}
+		}
+	})
+	return p
+}
diff --git a/internal/prototype/type_test.go b/internal/filedesc/desc_test.go
similarity index 80%
rename from internal/prototype/type_test.go
rename to internal/filedesc/desc_test.go
index fb7aed1..b6e0f7d 100644
--- a/internal/prototype/type_test.go
+++ b/internal/filedesc/desc_test.go
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-package prototype_test
+package filedesc_test
 
 import (
 	"fmt"
@@ -12,11 +12,11 @@
 	"strings"
 	"testing"
 
-	protoV1 "github.com/golang/protobuf/proto"
 	"github.com/google/go-cmp/cmp"
 	detrand "google.golang.org/protobuf/internal/detrand"
-	ptype "google.golang.org/protobuf/internal/prototype"
+	"google.golang.org/protobuf/internal/filedesc"
 	scalar "google.golang.org/protobuf/internal/scalar"
+	"google.golang.org/protobuf/proto"
 	pdesc "google.golang.org/protobuf/reflect/protodesc"
 	pref "google.golang.org/protobuf/reflect/protoreflect"
 
@@ -31,158 +31,7 @@
 // TODO: Test protodesc.NewFile with imported files.
 
 func TestFile(t *testing.T) {
-	f1 := &ptype.File{
-		Syntax:  pref.Proto2,
-		Path:    "path/to/file.proto",
-		Package: "test",
-		Options: &descriptorpb.FileOptions{Deprecated: scalar.Bool(true)},
-		Messages: []ptype.Message{{
-			Name: "A", // "test.A"
-			Options: &descriptorpb.MessageOptions{
-				MapEntry:   scalar.Bool(true),
-				Deprecated: scalar.Bool(true),
-			},
-			IsMapEntry: true,
-			Fields: []ptype.Field{{
-				Name:        "key", // "test.A.key"
-				Number:      1,
-				Options:     &descriptorpb.FieldOptions{Deprecated: scalar.Bool(true)},
-				Cardinality: pref.Optional,
-				Kind:        pref.StringKind,
-			}, {
-				Name:        "value", // "test.A.value"
-				Number:      2,
-				Cardinality: pref.Optional,
-				Kind:        pref.MessageKind,
-				MessageType: ptype.PlaceholderMessage("test.B"),
-			}},
-		}, {
-			Name: "B", // "test.B"
-			Fields: []ptype.Field{{
-				Name:        "field_one", // "test.B.field_one"
-				Number:      1,
-				Cardinality: pref.Optional,
-				Kind:        pref.StringKind,
-				Default:     pref.ValueOf("hello, \"world!\"\n"),
-				OneofName:   "O1",
-			}, {
-				Name:        "field_two", // "test.B.field_two"
-				JSONName:    "Field2",
-				Number:      2,
-				Cardinality: pref.Optional,
-				Kind:        pref.EnumKind,
-				Default:     pref.ValueOf(pref.EnumNumber(1)),
-				EnumType:    ptype.PlaceholderEnum("test.E1"),
-				OneofName:   "O2",
-			}, {
-				Name:        "field_three", // "test.B.field_three"
-				Number:      3,
-				Cardinality: pref.Optional,
-				Kind:        pref.MessageKind,
-				MessageType: ptype.PlaceholderMessage("test.C"),
-				OneofName:   "O2",
-			}, {
-				Name:        "field_four", // "test.B.field_four"
-				JSONName:    "Field4",
-				Number:      4,
-				Cardinality: pref.Repeated,
-				Kind:        pref.MessageKind,
-				MessageType: ptype.PlaceholderMessage("test.A"),
-			}, {
-				Name:        "field_five", // "test.B.field_five"
-				Number:      5,
-				Cardinality: pref.Repeated,
-				Kind:        pref.Int32Kind,
-				Options:     &descriptorpb.FieldOptions{Packed: scalar.Bool(true)},
-				IsPacked:    ptype.True,
-			}, {
-				Name:        "field_six", // "test.B.field_six"
-				Number:      6,
-				Cardinality: pref.Required,
-				Kind:        pref.BytesKind,
-			}},
-			Oneofs: []ptype.Oneof{
-				{
-					Name: "O1", // "test.B.O1"
-					Options: &descriptorpb.OneofOptions{
-						UninterpretedOption: []*descriptorpb.UninterpretedOption{
-							{StringValue: []byte("option")},
-						},
-					},
-				},
-				{Name: "O2"}, // "test.B.O2"
-			},
-			ReservedNames:   []pref.Name{"fizz", "buzz"},
-			ReservedRanges:  [][2]pref.FieldNumber{{100, 200}, {300, 301}},
-			ExtensionRanges: [][2]pref.FieldNumber{{1000, 2000}, {3000, 3001}},
-			ExtensionRangeOptions: []pref.ProtoMessage{
-				0: (*descriptorpb.ExtensionRangeOptions)(nil),
-				1: new(descriptorpb.ExtensionRangeOptions),
-			},
-		}, {
-			Name: "C", // "test.C"
-			Messages: []ptype.Message{{
-				Name:   "A", // "test.C.A"
-				Fields: []ptype.Field{{Name: "F", Number: 1, Cardinality: pref.Required, Kind: pref.BytesKind, Default: pref.ValueOf([]byte("dead\xbe\xef"))}},
-			}},
-			Enums: []ptype.Enum{{
-				Name:   "E1", // "test.C.E1"
-				Values: []ptype.EnumValue{{Name: "FOO", Number: 0}, {Name: "BAR", Number: 1}},
-			}},
-			Extensions: []ptype.Extension{{
-				Name:         "X", // "test.C.X"
-				Number:       1000,
-				Cardinality:  pref.Repeated,
-				Kind:         pref.MessageKind,
-				Options:      &descriptorpb.FieldOptions{Packed: scalar.Bool(false)},
-				IsPacked:     ptype.False,
-				MessageType:  ptype.PlaceholderMessage("test.C"),
-				ExtendedType: ptype.PlaceholderMessage("test.B"),
-			}},
-		}},
-		Enums: []ptype.Enum{{
-			Name:    "E1", // "test.E1"
-			Options: &descriptorpb.EnumOptions{Deprecated: scalar.Bool(true)},
-			Values: []ptype.EnumValue{
-				{
-					Name:    "FOO",
-					Number:  0,
-					Options: &descriptorpb.EnumValueOptions{Deprecated: scalar.Bool(true)},
-				},
-				{Name: "BAR", Number: 1},
-			},
-			ReservedNames:  []pref.Name{"FIZZ", "BUZZ"},
-			ReservedRanges: [][2]pref.EnumNumber{{10, 19}, {30, 30}},
-		}},
-		Extensions: []ptype.Extension{{
-			Name:         "X", // "test.X"
-			Number:       1000,
-			Cardinality:  pref.Repeated,
-			Kind:         pref.MessageKind,
-			Options:      &descriptorpb.FieldOptions{Packed: scalar.Bool(true)},
-			IsPacked:     ptype.True,
-			MessageType:  ptype.PlaceholderMessage("test.C"),
-			ExtendedType: ptype.PlaceholderMessage("test.B"),
-		}},
-		Services: []ptype.Service{{
-			Name:    "S", // "test.S"
-			Options: &descriptorpb.ServiceOptions{Deprecated: scalar.Bool(true)},
-			Methods: []ptype.Method{{
-				Name:              "M", // "test.S.M"
-				InputType:         ptype.PlaceholderMessage("test.A"),
-				OutputType:        ptype.PlaceholderMessage("test.C.A"),
-				IsStreamingClient: true,
-				IsStreamingServer: true,
-				Options:           &descriptorpb.MethodOptions{Deprecated: scalar.Bool(true)},
-			}},
-		}},
-	}
-	fd1, err := ptype.NewFile(f1)
-	if err != nil {
-		t.Fatalf("prototype.NewFile() error: %v", err)
-	}
-
-	f2 := &descriptorpb.FileDescriptorProto{
+	f1 := &descriptorpb.FileDescriptorProto{
 		Syntax:  scalar.String("proto2"),
 		Name:    scalar.String("path/to/file.proto"),
 		Package: scalar.String("test"),
@@ -337,17 +186,23 @@
 			}},
 		}},
 	}
-	fd2, err := pdesc.NewFile(f2, nil)
+	fd1, err := pdesc.NewFile(f1, nil)
 	if err != nil {
 		t.Fatalf("protodesc.NewFile() error: %v", err)
 	}
 
+	b, err := proto.Marshal(f1)
+	if err != nil {
+		t.Fatalf("proto.Marshal() error: %v", err)
+	}
+	fd2 := filedesc.DescBuilder{RawDescriptor: b}.Build().File
+
 	tests := []struct {
 		name string
 		desc pref.FileDescriptor
 	}{
-		{"prototype.NewFile", fd1},
-		{"protodesc.NewFile", fd2},
+		{"protodesc.NewFile", fd1},
+		{"filedesc.DescBuilder.Build", fd2},
 	}
 	for _, tt := range tests {
 		tt := tt
@@ -622,7 +477,7 @@
 				"Cardinality":       pref.Repeated,
 				"Kind":              pref.MessageKind,
 				"IsExtension":       true,
-				"IsPacked":          false,
+				"IsPacked":          true,
 				"IsList":            true,
 				"IsMap":             false,
 				"MapKey":            nil,
@@ -715,11 +570,18 @@
 		}
 
 		// Compare with proto.Equal if possible.
-		gotMsg, gotMsgOK := got.(protoV1.Message)
-		wantMsg, wantMsgOK := v.(protoV1.Message)
+		gotMsg, gotMsgOK := got.(proto.Message)
+		wantMsg, wantMsgOK := v.(proto.Message)
 		if gotMsgOK && wantMsgOK {
-			if !protoV1.Equal(gotMsg, wantMsg) {
-				t.Errorf("%v = %v, want %v", p, got, want)
+			gotNil := reflect.ValueOf(gotMsg).IsNil()
+			wantNil := reflect.ValueOf(wantMsg).IsNil()
+			switch {
+			case !gotNil && wantNil:
+				t.Errorf("%v = non-nil, want nil", p)
+			case gotNil && !wantNil:
+				t.Errorf("%v = nil, want non-nil", p)
+			case !proto.Equal(gotMsg, wantMsg):
+				t.Errorf("%v = %v, want %v", p, gotMsg, wantMsg)
 			}
 			continue
 		}
@@ -845,6 +707,7 @@
 			Number:      1000
 			Cardinality: repeated
 			Kind:        message
+			JSONName:    "X"
 			IsExtension: true
 			IsList:      true
 			Extendee:    test.B
@@ -865,6 +728,8 @@
 		Number:      1000
 		Cardinality: repeated
 		Kind:        message
+		JSONName:    "X"
+		IsPacked:    true
 		IsExtension: true
 		IsList:      true
 		Extendee:    test.B
diff --git a/internal/filedesc/name_pure.go b/internal/filedesc/name_pure.go
new file mode 100644
index 0000000..5626829
--- /dev/null
+++ b/internal/filedesc/name_pure.go
@@ -0,0 +1,34 @@
+// Copyright 2018 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.
+
+// +build purego appengine
+
+package filedesc
+
+import pref "google.golang.org/protobuf/reflect/protoreflect"
+
+func getNameBuilder() *nameBuilder { return nil }
+func putNameBuilder(*nameBuilder)  {}
+
+type nameBuilder struct{}
+
+// MakeFullName converts b to a protoreflect.FullName,
+// where b must start with a leading dot.
+func (*nameBuilder) MakeFullName(b []byte) pref.FullName {
+	if len(b) == 0 || b[0] != '.' {
+		panic("name reference must be fully qualified")
+	}
+	return pref.FullName(b[1:])
+}
+
+// AppendFullName is equivalent to protoreflect.FullName.Append.
+func (*nameBuilder) AppendFullName(prefix pref.FullName, name []byte) pref.FullName {
+	return prefix.Append(pref.Name(name))
+}
+
+// MakeString is equivalent to string(b), but optimized for large batches
+// with a shared lifetime.
+func (*nameBuilder) MakeString(b []byte) string {
+	return string(b)
+}
diff --git a/internal/prototype/name_unsafe.go b/internal/filedesc/name_unsafe.go
similarity index 62%
rename from internal/prototype/name_unsafe.go
rename to internal/filedesc/name_unsafe.go
index 588bdbc..317114f 100644
--- a/internal/prototype/name_unsafe.go
+++ b/internal/filedesc/name_unsafe.go
@@ -4,10 +4,9 @@
 
 // +build !purego,!appengine
 
-package prototype
+package filedesc
 
 import (
-	"strings"
 	"sync"
 	"unsafe"
 
@@ -29,22 +28,48 @@
 	sb stringBuilder
 }
 
-// Append is equivalent to protoreflect.FullName.Append, but is optimized for
-// large batches of operations where each name has a shared lifetime.
-func (b *nameBuilder) Append(prefix pref.FullName, name pref.Name) pref.FullName {
-	const batchSize = 1 << 12
+// MakeFullName converts b to a protoreflect.FullName,
+// where b must start with a leading dot.
+func (nb *nameBuilder) MakeFullName(b []byte) pref.FullName {
+	if len(b) == 0 || b[0] != '.' {
+		panic("name reference must be fully qualified")
+	}
+	return pref.FullName(nb.MakeString(b[1:]))
+}
+
+// AppendFullName is equivalent to protoreflect.FullName.Append,
+// but optimized for large batches where each name has a shared lifetime.
+func (nb *nameBuilder) AppendFullName(prefix pref.FullName, name []byte) pref.FullName {
 	n := len(prefix) + len(".") + len(name)
-	if b.sb.Cap()-b.sb.Len() < n {
-		b.sb.Reset()
-		b.sb.Grow(batchSize)
+	if len(prefix) == 0 {
+		n -= len(".")
 	}
-	if !strings.HasSuffix(b.sb.String(), string(prefix)) {
-		b.sb.WriteString(string(prefix))
+	nb.grow(n)
+	nb.sb.WriteString(string(prefix))
+	nb.sb.WriteByte('.')
+	nb.sb.Write(name)
+	return pref.FullName(nb.last(n))
+}
+
+// MakeString is equivalent to string(b), but optimized for large batches
+// with a shared lifetime.
+func (nb *nameBuilder) MakeString(b []byte) string {
+	nb.grow(len(b))
+	nb.sb.Write(b)
+	return nb.last(len(b))
+}
+
+func (nb *nameBuilder) last(n int) string {
+	s := nb.sb.String()
+	return s[len(s)-n:]
+}
+
+func (nb *nameBuilder) grow(n int) {
+	const batchSize = 1 << 16
+	if nb.sb.Cap()-nb.sb.Len() < n {
+		nb.sb.Reset()
+		nb.sb.Grow(batchSize)
 	}
-	b.sb.WriteByte('.')
-	b.sb.WriteString(string(name))
-	s := b.sb.String()
-	return pref.FullName(strings.TrimPrefix(s[len(s)-n:], "."))
 }
 
 // stringsBuilder is a simplified copy of the strings.Builder from Go1.12:
diff --git a/internal/filedesc/placeholder.go b/internal/filedesc/placeholder.go
new file mode 100644
index 0000000..be95831
--- /dev/null
+++ b/internal/filedesc/placeholder.go
@@ -0,0 +1,90 @@
+// 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 filedesc
+
+import (
+	"google.golang.org/protobuf/internal/descopts"
+	"google.golang.org/protobuf/internal/pragma"
+	pref "google.golang.org/protobuf/reflect/protoreflect"
+)
+
+var (
+	emptyNames        = new(Names)
+	emptyEnumRanges   = new(EnumRanges)
+	emptyFieldRanges  = new(FieldRanges)
+	emptyFieldNumbers = new(FieldNumbers)
+
+	emptyFiles      = new(FileImports)
+	emptyMessages   = new(Messages)
+	emptyFields     = new(Fields)
+	emptyOneofs     = new(Oneofs)
+	emptyEnums      = new(Enums)
+	emptyEnumValues = new(EnumValues)
+	emptyExtensions = new(Extensions)
+	emptyServices   = new(Services)
+)
+
+// PlaceholderFile is a placeholder, representing only the file path.
+type PlaceholderFile string
+
+func (f PlaceholderFile) ParentFile() pref.FileDescriptor       { return f }
+func (f PlaceholderFile) Parent() pref.Descriptor               { return nil }
+func (f PlaceholderFile) Index() int                            { return 0 }
+func (f PlaceholderFile) Syntax() pref.Syntax                   { return 0 }
+func (f PlaceholderFile) Name() pref.Name                       { return "" }
+func (f PlaceholderFile) FullName() pref.FullName               { return "" }
+func (f PlaceholderFile) IsPlaceholder() bool                   { return true }
+func (f PlaceholderFile) Options() pref.ProtoMessage            { return descopts.File }
+func (f PlaceholderFile) Path() string                          { return string(f) }
+func (f PlaceholderFile) Package() pref.FullName                { return "" }
+func (f PlaceholderFile) Imports() pref.FileImports             { return emptyFiles }
+func (f PlaceholderFile) Messages() pref.MessageDescriptors     { return emptyMessages }
+func (f PlaceholderFile) Enums() pref.EnumDescriptors           { return emptyEnums }
+func (f PlaceholderFile) Extensions() pref.ExtensionDescriptors { return emptyExtensions }
+func (f PlaceholderFile) Services() pref.ServiceDescriptors     { return emptyServices }
+func (f PlaceholderFile) ProtoType(pref.FileDescriptor)         { return }
+func (f PlaceholderFile) ProtoInternal(pragma.DoNotImplement)   { return }
+
+// PlaceholderEnum is a placeholder, representing only the full name.
+type PlaceholderEnum pref.FullName
+
+func (e PlaceholderEnum) ParentFile() pref.FileDescriptor     { return nil }
+func (e PlaceholderEnum) Parent() pref.Descriptor             { return nil }
+func (e PlaceholderEnum) Index() int                          { return 0 }
+func (e PlaceholderEnum) Syntax() pref.Syntax                 { return 0 }
+func (e PlaceholderEnum) Name() pref.Name                     { return pref.FullName(e).Name() }
+func (e PlaceholderEnum) FullName() pref.FullName             { return pref.FullName(e) }
+func (e PlaceholderEnum) IsPlaceholder() bool                 { return true }
+func (e PlaceholderEnum) Options() pref.ProtoMessage          { return descopts.Enum }
+func (e PlaceholderEnum) Values() pref.EnumValueDescriptors   { return emptyEnumValues }
+func (e PlaceholderEnum) ReservedNames() pref.Names           { return emptyNames }
+func (e PlaceholderEnum) ReservedRanges() pref.EnumRanges     { return emptyEnumRanges }
+func (e PlaceholderEnum) ProtoType(pref.EnumDescriptor)       { return }
+func (e PlaceholderEnum) ProtoInternal(pragma.DoNotImplement) { return }
+
+// PlaceholderMessage is a placeholder, representing only the full name.
+type PlaceholderMessage pref.FullName
+
+func (m PlaceholderMessage) ParentFile() pref.FileDescriptor             { return nil }
+func (m PlaceholderMessage) Parent() pref.Descriptor                     { return nil }
+func (m PlaceholderMessage) Index() int                                  { return 0 }
+func (m PlaceholderMessage) Syntax() pref.Syntax                         { return 0 }
+func (m PlaceholderMessage) Name() pref.Name                             { return pref.FullName(m).Name() }
+func (m PlaceholderMessage) FullName() pref.FullName                     { return pref.FullName(m) }
+func (m PlaceholderMessage) IsPlaceholder() bool                         { return true }
+func (m PlaceholderMessage) Options() pref.ProtoMessage                  { return descopts.Message }
+func (m PlaceholderMessage) IsMapEntry() bool                            { return false }
+func (m PlaceholderMessage) Fields() pref.FieldDescriptors               { return emptyFields }
+func (m PlaceholderMessage) Oneofs() pref.OneofDescriptors               { return emptyOneofs }
+func (m PlaceholderMessage) ReservedNames() pref.Names                   { return emptyNames }
+func (m PlaceholderMessage) ReservedRanges() pref.FieldRanges            { return emptyFieldRanges }
+func (m PlaceholderMessage) RequiredNumbers() pref.FieldNumbers          { return emptyFieldNumbers }
+func (m PlaceholderMessage) ExtensionRanges() pref.FieldRanges           { return emptyFieldRanges }
+func (m PlaceholderMessage) ExtensionRangeOptions(int) pref.ProtoMessage { panic("index out of range") }
+func (m PlaceholderMessage) Messages() pref.MessageDescriptors           { return emptyMessages }
+func (m PlaceholderMessage) Enums() pref.EnumDescriptors                 { return emptyEnums }
+func (m PlaceholderMessage) Extensions() pref.ExtensionDescriptors       { return emptyExtensions }
+func (m PlaceholderMessage) ProtoType(pref.MessageDescriptor)            { return }
+func (m PlaceholderMessage) ProtoInternal(pragma.DoNotImplement)         { return }
diff --git a/internal/fileinit/desc.go b/internal/fileinit/desc.go
index 938167b..21698b6 100644
--- a/internal/fileinit/desc.go
+++ b/internal/fileinit/desc.go
@@ -454,7 +454,7 @@
 	return fd.Message().Fields().ByNumber(2)
 }
 func (fd *fieldDesc) HasDefault() bool                           { return fd.defVal.has }
-func (fd *fieldDesc) Default() pref.Value                        { return fd.defVal.get() }
+func (fd *fieldDesc) Default() pref.Value                        { return fd.defVal.get(fd) }
 func (fd *fieldDesc) DefaultEnumValue() pref.EnumValueDescriptor { return fd.defVal.enum }
 func (fd *fieldDesc) ContainingOneof() pref.OneofDescriptor      { return fd.oneofType }
 func (fd *fieldDesc) ContainingMessage() pref.MessageDescriptor {
@@ -528,7 +528,7 @@
 func (xd *extensionDesc) MapKey() pref.FieldDescriptor               { return nil }
 func (xd *extensionDesc) MapValue() pref.FieldDescriptor             { return nil }
 func (xd *extensionDesc) HasDefault() bool                           { return xd.lazyInit().defVal.has }
-func (xd *extensionDesc) Default() pref.Value                        { return xd.lazyInit().defVal.get() }
+func (xd *extensionDesc) Default() pref.Value                        { return xd.lazyInit().defVal.get(xd) }
 func (xd *extensionDesc) DefaultEnumValue() pref.EnumValueDescriptor { return xd.lazyInit().defVal.enum }
 func (xd *extensionDesc) ContainingOneof() pref.OneofDescriptor      { return nil }
 func (xd *extensionDesc) ContainingMessage() pref.MessageDescriptor  { return xd.extendedType }
diff --git a/internal/fileinit/desc_lazy.go b/internal/fileinit/desc_lazy.go
index 0e26e17..673b100 100644
--- a/internal/fileinit/desc_lazy.go
+++ b/internal/fileinit/desc_lazy.go
@@ -12,8 +12,8 @@
 	defval "google.golang.org/protobuf/internal/encoding/defval"
 	wire "google.golang.org/protobuf/internal/encoding/wire"
 	fieldnum "google.golang.org/protobuf/internal/fieldnum"
+	fdesc "google.golang.org/protobuf/internal/filedesc"
 	pimpl "google.golang.org/protobuf/internal/impl"
-	ptype "google.golang.org/protobuf/internal/prototype"
 	pvalue "google.golang.org/protobuf/internal/value"
 	pref "google.golang.org/protobuf/reflect/protoreflect"
 	preg "google.golang.org/protobuf/reflect/protoregistry"
@@ -95,7 +95,11 @@
 					fd.isPacked = true
 				}
 			}
-			fd.defVal.lazyInit(fd.kind, file.enumValuesOf(fd.enumType))
+
+			// Default is resolved here since it depends on Enum being resolved.
+			if v := fd.defVal.val; v.IsValid() {
+				fd.defVal = unmarshalDefault(v.Bytes(), fd.kind, file, fd.enumType)
+			}
 		}
 	}
 }
@@ -121,7 +125,7 @@
 				et := pimpl.Export{}.EnumTypeOf(reflect.Zero(typ).Interface())
 				xd.lazy.typ = typ
 				xd.lazy.new = func() pref.Value {
-					return xd.lazy.defVal.get()
+					return xd.lazy.defVal.get(xd)
 				}
 				xd.lazy.valueOf = func(v interface{}) pref.Value {
 					ev := v.(pref.Enum)
@@ -146,7 +150,7 @@
 			default:
 				xd.lazy.typ = goTypeForPBKind[xd.lazy.kind]
 				xd.lazy.new = func() pref.Value {
-					return xd.lazy.defVal.get()
+					return xd.lazy.defVal.get(xd)
 				}
 				xd.lazy.valueOf = func(v interface{}) pref.Value {
 					return pref.ValueOf(v)
@@ -179,7 +183,11 @@
 		case pref.MessageKind, pref.GroupKind:
 			xd.lazy.messageType = file.popMessageDependency()
 		}
-		xd.lazy.defVal.lazyInit(xd.lazy.kind, file.enumValuesOf(xd.lazy.enumType))
+
+		// Default is resolved here since it depends on Enum being resolved.
+		if v := xd.lazy.defVal.val; v.IsValid() {
+			xd.lazy.defVal = unmarshalDefault(v.Bytes(), xd.lazy.kind, file, xd.lazy.enumType)
+		}
 	}
 }
 
@@ -271,67 +279,84 @@
 	*fi = fileInit{} // clear fileInit for GC to reclaim resources
 }
 
+func DefaultValue(v pref.Value, ev pref.EnumValueDescriptor) defaultValue {
+	dv := defaultValue{has: v.IsValid(), val: v, enum: ev}
+	if b, ok := v.Interface().([]byte); ok {
+		// Store a copy of the default bytes, so that we can detect
+		// accidental mutations of the original value.
+		dv.bytes = append([]byte(nil), b...)
+	}
+	return dv
+}
+
+func unmarshalDefault(b []byte, k pref.Kind, pf *fileDesc, ed pref.EnumDescriptor) defaultValue {
+	var evs pref.EnumValueDescriptors
+	if k == pref.EnumKind {
+		// If the enum is declared within the same file, be careful not to
+		// blindly call the Values method, lest we bind ourselves in a deadlock.
+		if ed, ok := ed.(*enumDesc); ok && ed.parentFile == pf {
+			evs = &ed.lazy.values
+		} else {
+			evs = ed.Values()
+		}
+	}
+
+	v, ev, err := defval.Unmarshal(string(b), k, evs, defval.Descriptor)
+	if err != nil {
+		panic(err)
+	}
+	dv := defaultValue{has: v.IsValid(), val: v, enum: ev}
+	if b, ok := v.Interface().([]byte); ok {
+		// Store a copy of the default bytes, so that we can detect
+		// accidental mutations of the original value.
+		dv.bytes = append([]byte(nil), b...)
+	}
+	return dv
+}
+
 type defaultValue struct {
 	has   bool
 	val   pref.Value
 	enum  pref.EnumValueDescriptor
-	check func() // only set for non-empty bytes
+	bytes []byte
 }
 
-func (dv *defaultValue) get() pref.Value {
-	if dv.check != nil {
-		dv.check()
+func (dv *defaultValue) get(fd pref.FieldDescriptor) pref.Value {
+	// Return the zero value as the default if unpopulated.
+	if !dv.has {
+		switch fd.Kind() {
+		case pref.BoolKind:
+			return pref.ValueOf(false)
+		case pref.Int32Kind, pref.Sint32Kind, pref.Sfixed32Kind:
+			return pref.ValueOf(int32(0))
+		case pref.Int64Kind, pref.Sint64Kind, pref.Sfixed64Kind:
+			return pref.ValueOf(int64(0))
+		case pref.Uint32Kind, pref.Fixed32Kind:
+			return pref.ValueOf(uint32(0))
+		case pref.Uint64Kind, pref.Fixed64Kind:
+			return pref.ValueOf(uint64(0))
+		case pref.FloatKind:
+			return pref.ValueOf(float32(0))
+		case pref.DoubleKind:
+			return pref.ValueOf(float64(0))
+		case pref.StringKind:
+			return pref.ValueOf(string(""))
+		case pref.BytesKind:
+			return pref.ValueOf([]byte(nil))
+		case pref.EnumKind:
+			return pref.ValueOf(fd.Enum().Values().Get(0).Number())
+		}
+	}
+
+	if len(dv.bytes) > 0 && !bytes.Equal(dv.bytes, dv.val.Bytes()) {
+		// TODO: Avoid panic if we're running with the race detector
+		// and instead spawn a goroutine that periodically resets
+		// this value back to the original to induce a race.
+		panic("detected mutation on the default bytes")
 	}
 	return dv.val
 }
 
-func (dv *defaultValue) lazyInit(k pref.Kind, eds pref.EnumValueDescriptors) {
-	if dv.has {
-		switch k {
-		case pref.EnumKind:
-			// File descriptors always store default enums by name.
-			dv.enum = eds.ByName(pref.Name(dv.val.String()))
-			dv.val = pref.ValueOf(dv.enum.Number())
-		case pref.BytesKind:
-			// Store a copy of the default bytes, so that we can detect
-			// accidental mutations of the original value.
-			b := append([]byte(nil), dv.val.Bytes()...)
-			dv.check = func() {
-				if !bytes.Equal(b, dv.val.Bytes()) {
-					// TODO: Avoid panic if we're running with the race detector
-					// and instead spawn a goroutine that periodically resets
-					// this value back to the original to induce a race.
-					panic("detected mutation on the default bytes")
-				}
-			}
-		}
-	} else {
-		switch k {
-		case pref.BoolKind:
-			dv.val = pref.ValueOf(false)
-		case pref.Int32Kind, pref.Sint32Kind, pref.Sfixed32Kind:
-			dv.val = pref.ValueOf(int32(0))
-		case pref.Int64Kind, pref.Sint64Kind, pref.Sfixed64Kind:
-			dv.val = pref.ValueOf(int64(0))
-		case pref.Uint32Kind, pref.Fixed32Kind:
-			dv.val = pref.ValueOf(uint32(0))
-		case pref.Uint64Kind, pref.Fixed64Kind:
-			dv.val = pref.ValueOf(uint64(0))
-		case pref.FloatKind:
-			dv.val = pref.ValueOf(float32(0))
-		case pref.DoubleKind:
-			dv.val = pref.ValueOf(float64(0))
-		case pref.StringKind:
-			dv.val = pref.ValueOf(string(""))
-		case pref.BytesKind:
-			dv.val = pref.ValueOf([]byte(nil))
-		case pref.EnumKind:
-			dv.enum = eds.Get(0)
-			dv.val = pref.ValueOf(dv.enum.Number())
-		}
-	}
-}
-
 func (fd *fileDesc) unmarshalFull(b []byte) {
 	nb := getNameBuilder()
 	defer putNameBuilder(nb)
@@ -368,7 +393,7 @@
 				}
 			case fieldnum.FileDescriptorProto_Dependency:
 				fd.lazy.imports = append(fd.lazy.imports, pref.FileImport{
-					FileDescriptor: ptype.PlaceholderFile(nb.MakeString(v), ""),
+					FileDescriptor: fdesc.PlaceholderFile(nb.MakeString(v)),
 				})
 			case fieldnum.FileDescriptorProto_EnumType:
 				fd.enums.list[enumIdx].unmarshalFull(v, nb)
@@ -627,7 +652,6 @@
 	fd.parent = pd
 	fd.index = i
 
-	var rawDefVal []byte
 	var rawTypeName []byte
 	for len(b) > 0 {
 		num, typ, n := wire.ConsumeTag(b)
@@ -664,8 +688,7 @@
 				fd.hasJSONName = true
 				fd.jsonName = nb.MakeString(v)
 			case fieldnum.FieldDescriptorProto_DefaultValue:
-				fd.defVal.has = true
-				rawDefVal = v
+				fd.defVal.val = pref.ValueOf(v) // temporarily store as bytes; later resolved in resolveMessages
 			case fieldnum.FieldDescriptorProto_TypeName:
 				rawTypeName = v
 			case fieldnum.FieldDescriptorProto_Options:
@@ -680,13 +703,6 @@
 	if !fd.hasJSONName {
 		fd.jsonName = nb.MakeJSONName(fd.Name())
 	}
-	if rawDefVal != nil {
-		var err error
-		fd.defVal.val, err = defval.Unmarshal(string(rawDefVal), fd.kind, defval.Descriptor)
-		if err != nil {
-			panic(err)
-		}
-	}
 	if fd.isWeak {
 		if len(rawTypeName) == 0 || rawTypeName[0] != '.' {
 			panic("weak target name must be fully qualified")
@@ -695,7 +711,7 @@
 		name := pref.FullName(rawTypeName[1:])
 		fd.messageType, _ = preg.GlobalFiles.FindMessageByName(name)
 		if fd.messageType == nil {
-			fd.messageType = ptype.PlaceholderMessage(pref.FullName(rawTypeName[1:]))
+			fd.messageType = fdesc.PlaceholderMessage(pref.FullName(rawTypeName[1:]))
 		}
 	}
 }
@@ -749,7 +765,6 @@
 }
 
 func (xd *extensionDesc) unmarshalFull(b []byte, nb *nameBuilder) {
-	var rawDefVal []byte
 	xd.lazy = new(extensionLazy)
 	for len(b) > 0 {
 		num, typ, n := wire.ConsumeTag(b)
@@ -772,8 +787,7 @@
 				xd.lazy.hasJSONName = true
 				xd.lazy.jsonName = nb.MakeString(v)
 			case fieldnum.FieldDescriptorProto_DefaultValue:
-				xd.lazy.defVal.has = true
-				rawDefVal = v
+				xd.lazy.defVal.val = pref.ValueOf(v) // temporarily store as bytes; later resolved in resolveExtensions
 			case fieldnum.FieldDescriptorProto_Options:
 				xd.unmarshalOptions(v)
 			}
@@ -782,14 +796,6 @@
 			b = b[m:]
 		}
 	}
-
-	if rawDefVal != nil {
-		var err error
-		xd.lazy.defVal.val, err = defval.Unmarshal(string(rawDefVal), xd.lazy.kind, defval.Descriptor)
-		if err != nil {
-			panic(err)
-		}
-	}
 }
 
 func (xd *extensionDesc) unmarshalOptions(b []byte) {
diff --git a/internal/filetype/build.go b/internal/filetype/build.go
new file mode 100644
index 0000000..635099b
--- /dev/null
+++ b/internal/filetype/build.go
@@ -0,0 +1,329 @@
+// 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 filetype provides functionality for wrapping descriptors
+// with Go type information.
+package filetype
+
+import (
+	"reflect"
+
+	"google.golang.org/protobuf/internal/descopts"
+	fdesc "google.golang.org/protobuf/internal/filedesc"
+	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"
+)
+
+// TypeBuilder constructs type descriptors from a raw file descriptor
+// and associated Go types for each enum and message declaration.
+//
+//
+// Flattened Ordering
+//
+// The protobuf type system represents declarations as a tree. Certain nodes in
+// the tree require us to either associate it with a concrete Go type or to
+// resolve a dependency, which is information that must be provided separately
+// since it cannot be derived from the file descriptor alone.
+//
+// However, representing a tree as Go literals is difficult to simply do in a
+// space and time efficient way. Thus, we store them as a flattened list of
+// objects where the serialization order from the tree-based form is important.
+//
+// The "flattened ordering" is defined as a tree traversal of all enum, message,
+// extension, and service declarations using the following algorithm:
+//
+//	def VisitFileDecls(fd):
+//		for e in fd.Enums:      yield e
+//		for m in fd.Messages:   yield m
+//		for x in fd.Extensions: yield x
+//		for s in fd.Services:   yield s
+//		for m in fd.Messages:   yield from VisitMessageDecls(m)
+//
+//	def VisitMessageDecls(md):
+//		for e in md.Enums:      yield e
+//		for m in md.Messages:   yield m
+//		for x in md.Extensions: yield x
+//		for m in md.Messages:   yield from VisitMessageDecls(m)
+//
+// The traversal starts at the root file descriptor and yields each direct
+// declaration within each node before traversing into sub-declarations
+// that children themselves may have.
+type TypeBuilder struct {
+	// File is the underlying file descriptor builder.
+	File fdesc.DescBuilder
+
+	// GoTypes is a unique set of the Go types for all declarations and
+	// dependencies. Each type is represented as a zero value of the Go type.
+	//
+	// Declarations are Go types generated for enums and messages directly
+	// declared (not publicly imported) in the proto source file.
+	// Messages for map entries are accounted for, but represented by nil.
+	// Enum declarations in "flattened ordering" come first, followed by
+	// message declarations in "flattened ordering".
+	//
+	// Dependencies are Go types for enums or messages referenced by
+	// message fields (excluding weak fields), for parent extended messages of
+	// extension fields, for enums or messages referenced by extension fields,
+	// and for input and output messages referenced by service methods.
+	// Dependencies must come after declarations, but the ordering of
+	// dependencies themselves is unspecified.
+	GoTypes []interface{}
+
+	// DependencyIndexes is an ordered list of indexes into GoTypes for the
+	// dependencies of messages, extensions, or services.
+	//
+	// There are 5 sub-lists in "flattened ordering" concatenated back-to-back:
+	//	0. Message field dependencies: list of the enum or message type
+	//	referred to by every message field.
+	//	1. Extension field targets: list of the extended parent message of
+	//	every extension.
+	//	2. Extension field dependencies: list of the enum or message type
+	//	referred to by every extension field.
+	//	3. Service method inputs: list of the input message type
+	//	referred to by every service method.
+	//	4. Service method outputs: list of the output message type
+	//	referred to by every service method.
+	//
+	// The offset into DependencyIndexes for the start of each sub-list
+	// is appended to the end in reverse order.
+	DependencyIndexes []int32
+
+	// MessageInfos is a list of message infos in "flattened ordering".
+	// If provided, the GoType and PBType for each element is populated.
+	//
+	// Requirement: len(MessageInfos) == len(Build.Messages)
+	MessageInfos []pimpl.MessageInfo
+
+	// LegacyExtensions is a list of legacy extensions in "flattened ordering".
+	// If provided, the pointer to the v1 ExtensionDesc will be stored into the
+	// associated v2 ExtensionType and accessible via a pseudo-internal API.
+	// Also, the v2 ExtensionType will be stored into each v1 ExtensionDesc.
+	//
+	// Requirement: len(LegacyExtensions) == len(Build.Extensions)
+	LegacyExtensions []piface.ExtensionDescV1
+
+	// TypeRegistry is the registry to register each type descriptor.
+	// If nil, it uses protoregistry.GlobalTypes.
+	TypeRegistry interface {
+		Register(...preg.Type) error
+	}
+}
+
+func (tb TypeBuilder) Build() (out struct {
+	File pref.FileDescriptor
+
+	// Enums is all enum types in "flattened ordering".
+	Enums []Enum
+	// Messages is all message types in "flattened ordering".
+	// It includes a stub message type for map entries.
+	Messages []Message
+	// Extensions is all extension types in "flattened ordering".
+	Extensions []Extension
+}) {
+	// Replace the resolver with one that resolves dependencies by index,
+	// which is faster and more reliable than relying on the global registry.
+	if tb.File.FileRegistry == nil {
+		tb.File.FileRegistry = preg.GlobalFiles
+	}
+	tb.File.FileRegistry = &resolverByIndex{
+		goTypes:      tb.GoTypes,
+		depIdxs:      tb.DependencyIndexes,
+		fileRegistry: tb.File.FileRegistry,
+	}
+
+	// Initialize registry if unpopulated.
+	if tb.TypeRegistry == nil {
+		tb.TypeRegistry = preg.GlobalTypes
+	}
+
+	fbOut := tb.File.Build()
+	out.File = fbOut.File
+
+	// Process enums.
+	enumGoTypes := tb.GoTypes[:len(fbOut.Enums)]
+	if len(fbOut.Enums) > 0 {
+		out.Enums = make([]Enum, len(fbOut.Enums))
+		for i := range fbOut.Enums {
+			out.Enums[i] = Enum{
+				EnumDescriptor: &fbOut.Enums[i],
+				NewEnum:        enumMaker(reflect.TypeOf(enumGoTypes[i])),
+			}
+
+			// Register enum types.
+			if err := tb.TypeRegistry.Register(&out.Enums[i]); err != nil {
+				panic(err)
+			}
+		}
+	}
+
+	// Process messages.
+	messageGoTypes := tb.GoTypes[len(fbOut.Enums):][:len(fbOut.Messages)]
+	if tb.MessageInfos != nil && len(tb.MessageInfos) != len(fbOut.Messages) {
+		panic("mismatching message lengths")
+	}
+	if len(fbOut.Messages) > 0 {
+		out.Messages = make([]Message, len(fbOut.Messages))
+		for i := range fbOut.Messages {
+			if messageGoTypes[i] == nil {
+				continue // skip map entry
+			}
+			out.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 = &out.Messages[i]
+			}
+
+			// Register message types.
+			if err := tb.TypeRegistry.Register(&out.Messages[i]); err != nil {
+				panic(err)
+			}
+		}
+
+		// As a special-case for descriptor.proto,
+		// locally register concrete message type for the options.
+		if out.File.Path() == "google/protobuf/descriptor.proto" && out.File.Package() == "google.protobuf" {
+			for i := range fbOut.Messages {
+				switch fbOut.Messages[i].Name() {
+				case "FileOptions":
+					descopts.File = messageGoTypes[i].(pref.ProtoMessage)
+				case "EnumOptions":
+					descopts.Enum = messageGoTypes[i].(pref.ProtoMessage)
+				case "EnumValueOptions":
+					descopts.EnumValue = messageGoTypes[i].(pref.ProtoMessage)
+				case "MessageOptions":
+					descopts.Message = messageGoTypes[i].(pref.ProtoMessage)
+				case "FieldOptions":
+					descopts.Field = messageGoTypes[i].(pref.ProtoMessage)
+				case "OneofOptions":
+					descopts.Oneof = messageGoTypes[i].(pref.ProtoMessage)
+				case "ExtensionRangeOptions":
+					descopts.ExtensionRange = messageGoTypes[i].(pref.ProtoMessage)
+				case "ServiceOptions":
+					descopts.Service = messageGoTypes[i].(pref.ProtoMessage)
+				case "MethodOptions":
+					descopts.Method = messageGoTypes[i].(pref.ProtoMessage)
+				}
+			}
+		}
+	}
+
+	// Process extensions.
+	if tb.LegacyExtensions != nil && len(tb.LegacyExtensions) != len(fbOut.Extensions) {
+		panic("mismatching extension lengths")
+	}
+	if len(fbOut.Extensions) > 0 {
+		var depIdx int32
+		out.Extensions = make([]Extension, len(fbOut.Extensions))
+		for i := range fbOut.Extensions {
+			out.Extensions[i] = Extension{Extension: ptype.Extension{
+				ExtensionDescriptor: &fbOut.Extensions[i],
+			}}
+
+			// For enum and message kinds, determine the referent Go type so
+			// that we can construct their constructors.
+			const listExtDeps = 2
+			switch fbOut.Extensions[i].L1.Kind {
+			case pref.EnumKind:
+				j := depIdxs.Get(tb.DependencyIndexes, listExtDeps, depIdx)
+				goType := reflect.TypeOf(tb.GoTypes[j])
+				out.Extensions[i].NewEnum = enumMaker(goType)
+				depIdx++
+			case pref.MessageKind, pref.GroupKind:
+				j := depIdxs.Get(tb.DependencyIndexes, listExtDeps, depIdx)
+				goType := reflect.TypeOf(tb.GoTypes[j])
+				out.Extensions[i].NewMessage = messageMaker(goType)
+				depIdx++
+			}
+
+			// Keep v1 and v2 extensions in sync.
+			if tb.LegacyExtensions != nil {
+				out.Extensions[i].legacyDesc = &tb.LegacyExtensions[i]
+				tb.LegacyExtensions[i].Type = &out.Extensions[i]
+			}
+
+			// Register extension types.
+			if err := tb.TypeRegistry.Register(&out.Extensions[i]); err != nil {
+				panic(err)
+			}
+		}
+	}
+
+	return out
+}
+
+type depIdxs []int32
+
+// Get retrieves the jth element of the ith sub-list.
+func (x depIdxs) Get(i, j int32) int32 {
+	return x[x[int32(len(x))-i-1]+j]
+}
+
+type (
+	resolverByIndex struct {
+		goTypes []interface{}
+		depIdxs depIdxs
+		fileRegistry
+	}
+	fileRegistry interface {
+		FindFileByPath(string) (pref.FileDescriptor, error)
+		FindEnumByName(pref.FullName) (pref.EnumDescriptor, error)
+		FindMessageByName(pref.FullName) (pref.MessageDescriptor, error)
+		Register(...pref.FileDescriptor) error
+	}
+)
+
+func (r *resolverByIndex) FindEnumByIndex(i, j int32, es []fdesc.Enum, ms []fdesc.Message) pref.EnumDescriptor {
+	if depIdx := int(r.depIdxs.Get(i, j)); int(depIdx) < len(es)+len(ms) {
+		return &es[depIdx]
+	} else {
+		return pimpl.Export{}.EnumDescriptorOf(r.goTypes[depIdx])
+	}
+}
+
+func (r *resolverByIndex) FindMessageByIndex(i, j int32, es []fdesc.Enum, ms []fdesc.Message) pref.MessageDescriptor {
+	if depIdx := int(r.depIdxs.Get(i, j)); depIdx < len(es)+len(ms) {
+		return &ms[depIdx-len(es)]
+	} else {
+		return pimpl.Export{}.MessageDescriptorOf(r.goTypes[depIdx])
+	}
+}
+
+func enumMaker(t reflect.Type) func(pref.EnumNumber) pref.Enum {
+	return func(n pref.EnumNumber) pref.Enum {
+		v := reflect.New(t).Elem()
+		v.SetInt(int64(n))
+		return v.Interface().(pref.Enum)
+	}
+}
+
+func messageMaker(t reflect.Type) func() pref.Message {
+	return func() pref.Message {
+		return reflect.New(t.Elem()).Interface().(pref.ProtoMessage).ProtoReflect()
+	}
+}
+
+type (
+	Enum      = ptype.Enum
+	Message   = ptype.Message
+	Extension struct {
+		ptype.Extension
+		legacyDesc *piface.ExtensionDescV1
+	}
+)
+
+// ProtoLegacyExtensionDesc is a pseudo-internal API for allowing the v1 code
+// to be able to retrieve a v1 ExtensionDesc.
+//
+// WARNING: This method is exempt from the compatibility promise and may be
+// removed in the future without warning.
+func (x *Extension) ProtoLegacyExtensionDesc() *piface.ExtensionDescV1 {
+	return x.legacyDesc
+}
diff --git a/internal/impl/legacy_enum.go b/internal/impl/legacy_enum.go
index 6758e74..7cd05bf 100644
--- a/internal/impl/legacy_enum.go
+++ b/internal/impl/legacy_enum.go
@@ -6,12 +6,11 @@
 
 import (
 	"fmt"
-	"math"
 	"reflect"
 	"sync"
 
-	ptype "google.golang.org/protobuf/internal/prototype"
 	pvalue "google.golang.org/protobuf/internal/value"
+	"google.golang.org/protobuf/reflect/protoreflect"
 	pref "google.golang.org/protobuf/reflect/protoreflect"
 	"google.golang.org/protobuf/reflect/prototype"
 )
@@ -94,78 +93,29 @@
 		return ed.(pref.EnumDescriptor)
 	}
 
-	// Slow-path: initialize EnumDescriptor from the proto descriptor.
-	if t.Kind() != reflect.Int32 || t.PkgPath() == "" {
-		panic(fmt.Sprintf("got %v, want named int32 kind", t))
-	}
-	if t == legacyEnumNumberType {
-		panic(fmt.Sprintf("cannot be %v", t))
-	}
-
-	// Derive the enum descriptor from the raw descriptor proto.
-	e := new(ptype.StandaloneEnum)
+	// Slow-path: initialize EnumDescriptor from the raw descriptor.
 	ev := reflect.Zero(t).Interface()
 	if _, ok := ev.(pref.Enum); ok {
 		panic(fmt.Sprintf("%v already implements proto.Enum", t))
 	}
-	if ed, ok := ev.(enumV1); ok {
-		b, idxs := ed.EnumDescriptor()
-		fd := legacyLoadFileDesc(b)
-
-		// Derive syntax.
-		switch fd.GetSyntax() {
-		case "proto2", "":
-			e.Syntax = pref.Proto2
-		case "proto3":
-			e.Syntax = pref.Proto3
-		}
-
-		// Derive the full name and correct enum descriptor.
-		var ed *legacyEnumDescriptorProto
-		e.FullName = pref.FullName(fd.GetPackage())
-		if len(idxs) == 1 {
-			ed = fd.EnumType[idxs[0]]
-			e.FullName = e.FullName.Append(pref.Name(ed.GetName()))
-		} else {
-			md := fd.MessageType[idxs[0]]
-			e.FullName = e.FullName.Append(pref.Name(md.GetName()))
-			for _, i := range idxs[1 : len(idxs)-1] {
-				md = md.NestedType[i]
-				e.FullName = e.FullName.Append(pref.Name(md.GetName()))
-			}
-			ed = md.EnumType[idxs[len(idxs)-1]]
-			e.FullName = e.FullName.Append(pref.Name(ed.GetName()))
-		}
-
-		// Derive the enum values.
-		for _, vd := range ed.Value {
-			e.Values = append(e.Values, ptype.EnumValue{
-				Name:   pref.Name(vd.GetName()),
-				Number: pref.EnumNumber(vd.GetNumber()),
-			})
-		}
-	} else {
-		// If the type does not implement enumV1, then there is no reliable
-		// way to derive the original protobuf type information.
-		// We are unable to use the global enum registry since it is
-		// unfortunately keyed by the full name, which we do not know.
-		// Furthermore, some generated enums register with a fork of
-		// golang/protobuf so the enum may not even be found in the registry.
-		//
-		// Instead, create a bogus enum descriptor to ensure that
-		// most operations continue to work. For example, prototext and protojson
-		// will be unable to parse a message with an enum value by name.
-		e.Syntax = pref.Proto2
-		e.FullName = legacyDeriveFullName(t)
-		e.Values = []ptype.EnumValue{{Name: "INVALID", Number: math.MinInt32}}
+	edV1, ok := ev.(enumV1)
+	if !ok {
+		panic(fmt.Sprintf("enum %v is no longer supported; please regenerate", t))
 	}
+	b, idxs := edV1.EnumDescriptor()
 
-	ed, err := ptype.NewEnum(e)
-	if err != nil {
-		panic(err)
+	var ed pref.EnumDescriptor
+	if len(idxs) == 1 {
+		ed = legacyLoadFileDesc(b).Enums().Get(idxs[0])
+	} else {
+		md := legacyLoadFileDesc(b).Messages().Get(idxs[0])
+		for _, i := range idxs[1 : len(idxs)-1] {
+			md = md.Messages().Get(i)
+		}
+		ed = md.Enums().Get(idxs[len(idxs)-1])
 	}
 	if ed, ok := legacyEnumDescCache.LoadOrStore(t, ed); ok {
-		return ed.(pref.EnumDescriptor)
+		return ed.(protoreflect.EnumDescriptor)
 	}
 	return ed
 }
diff --git a/internal/impl/legacy_extension.go b/internal/impl/legacy_extension.go
index 33ca82c..ca3475f 100644
--- a/internal/impl/legacy_extension.go
+++ b/internal/impl/legacy_extension.go
@@ -11,7 +11,7 @@
 
 	"google.golang.org/protobuf/internal/descfmt"
 	ptag "google.golang.org/protobuf/internal/encoding/tag"
-	ptype "google.golang.org/protobuf/internal/prototype"
+	"google.golang.org/protobuf/internal/filedesc"
 	pvalue "google.golang.org/protobuf/internal/value"
 	pref "google.golang.org/protobuf/reflect/protoreflect"
 	preg "google.golang.org/protobuf/reflect/protoregistry"
@@ -112,7 +112,7 @@
 		}
 		if ed, ok := reflect.Zero(t).Interface().(enumV1); ok && protoPkg == "" {
 			b, _ := ed.EnumDescriptor()
-			protoPkg = legacyLoadFileDesc(b).GetPackage()
+			protoPkg = string(legacyLoadFileDesc(b).Package())
 		}
 
 		if protoPkg != "" {
@@ -159,46 +159,45 @@
 		return t.(pref.ExtensionType)
 	}
 
-	// Derive basic field information from the struct tag.
+	// Resolve enum or message dependencies.
+	var ed pref.EnumDescriptor
+	var md pref.MessageDescriptor
 	t := reflect.TypeOf(d.ExtensionType)
 	isOptional := t.Kind() == reflect.Ptr && t.Elem().Kind() != reflect.Struct
 	isRepeated := t.Kind() == reflect.Slice && t.Elem().Kind() != reflect.Uint8
 	if isOptional || isRepeated {
 		t = t.Elem()
 	}
-	f := ptag.Unmarshal(d.Tag, t)
+	switch v := reflect.Zero(t).Interface().(type) {
+	case pref.Enum:
+		ed = v.Descriptor()
+	case enumV1:
+		ed = LegacyLoadEnumDesc(t)
+	case pref.ProtoMessage:
+		md = v.ProtoReflect().Descriptor()
+	case messageV1:
+		md = LegacyLoadMessageDesc(t)
+	}
+
+	// Derive basic field information from the struct tag.
+	var evs pref.EnumValueDescriptors
+	if ed != nil {
+		evs = ed.Values()
+	}
+	fd := ptag.Unmarshal(d.Tag, t, evs).(*filedesc.Field)
 
 	// Construct a v2 ExtensionType.
-	var ed pref.EnumDescriptor
-	var md pref.MessageDescriptor
-	switch f.Kind {
-	case pref.EnumKind:
-		if e, ok := reflect.Zero(t).Interface().(pref.Enum); ok {
-			ed = e.Descriptor()
-		} else {
-			ed = LegacyLoadEnumDesc(t)
-		}
-	case pref.MessageKind, pref.GroupKind:
-		if m, ok := reflect.Zero(t).Interface().(pref.ProtoMessage); ok {
-			md = m.ProtoReflect().Descriptor()
-		} else {
-			md = LegacyLoadMessageDesc(t)
-		}
-	}
-	xd, err := ptype.NewExtension(&ptype.StandaloneExtension{
-		FullName:     pref.FullName(d.Name),
-		Number:       pref.FieldNumber(d.Field),
-		Cardinality:  f.Cardinality,
-		Kind:         f.Kind,
-		Default:      f.Default,
-		Options:      f.Options,
-		EnumType:     ed,
-		MessageType:  md,
-		ExtendedType: Export{}.MessageDescriptorOf(d.ExtendedType),
-	})
-	if err != nil {
-		panic(err)
-	}
+	xd := &filedesc.Extension{L2: new(filedesc.ExtensionL2)}
+	xd.L0.ParentFile = filedesc.SurrogateProto2
+	xd.L0.FullName = pref.FullName(d.Name)
+	xd.L1.Number = pref.FieldNumber(d.Field)
+	xd.L2.Cardinality = fd.L1.Cardinality
+	xd.L1.Kind = fd.L1.Kind
+	xd.L2.IsPacked = fd.L1.IsPacked
+	xd.L2.Default = fd.L1.Default
+	xd.L1.Extendee = Export{}.MessageDescriptorOf(d.ExtendedType)
+	xd.L2.Enum = ed
+	xd.L2.Message = md
 	xt := LegacyExtensionTypeOf(xd, t)
 
 	// Cache the conversion for both directions.
diff --git a/internal/impl/legacy_extension_test.go b/internal/impl/legacy_extension_test.go
deleted file mode 100644
index 6ccfa40..0000000
--- a/internal/impl/legacy_extension_test.go
+++ /dev/null
@@ -1,75 +0,0 @@
-// Copyright 2018 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_test
-
-import (
-	"reflect"
-	"testing"
-
-	pimpl "google.golang.org/protobuf/internal/impl"
-	ptype "google.golang.org/protobuf/internal/prototype"
-	pref "google.golang.org/protobuf/reflect/protoreflect"
-	piface "google.golang.org/protobuf/runtime/protoiface"
-
-	proto2_20180125 "google.golang.org/protobuf/internal/testprotos/legacy/proto2.v1.0.0-20180125-92554152"
-)
-
-type legacyExtendedMessage struct {
-	XXX_unrecognized       []byte
-	XXX_InternalExtensions map[int32]pimpl.ExtensionField
-}
-
-func (*legacyExtendedMessage) Reset()         {}
-func (*legacyExtendedMessage) String() string { return "" }
-func (*legacyExtendedMessage) ProtoMessage()  {}
-func (*legacyExtendedMessage) ExtensionRangeArray() []piface.ExtensionRangeV1 {
-	return []piface.ExtensionRangeV1{{Start: 10000, End: 20000}}
-}
-
-func mustMakeExtensionType(x *ptype.StandaloneExtension, v interface{}) pref.ExtensionType {
-	xd, err := ptype.NewExtension(x)
-	if err != nil {
-		panic(err)
-	}
-	return pimpl.LegacyExtensionTypeOf(xd, reflect.TypeOf(v))
-}
-
-var (
-	extParentDesc    = pimpl.Export{}.MessageDescriptorOf((*legacyExtendedMessage)(nil))
-	extMessageV1Desc = pimpl.Export{}.MessageDescriptorOf((*proto2_20180125.Message_ChildMessage)(nil))
-
-	wantType = mustMakeExtensionType(&ptype.StandaloneExtension{
-		FullName:     "fizz.buzz.optional_message_v1",
-		Number:       10007,
-		Cardinality:  pref.Optional,
-		Kind:         pref.MessageKind,
-		MessageType:  extMessageV1Desc,
-		ExtendedType: extParentDesc,
-	}, (*proto2_20180125.Message_ChildMessage)(nil))
-	wantDesc = &piface.ExtensionDescV1{
-		ExtendedType:  (*legacyExtendedMessage)(nil),
-		ExtensionType: (*proto2_20180125.Message_ChildMessage)(nil),
-		Field:         10007,
-		Name:          "fizz.buzz.optional_message_v1",
-		Tag:           "bytes,10007,opt,name=optional_message_v1",
-	}
-)
-
-func BenchmarkConvert(b *testing.B) {
-	b.ReportAllocs()
-	for i := 0; i < b.N; i++ {
-		xd := pimpl.Export{}.ExtensionDescFromType(wantType)
-		gotType := pimpl.Export{}.ExtensionTypeFromDesc(xd)
-		if gotType != wantType {
-			b.Fatalf("ExtensionType mismatch: got %p, want %p", gotType, wantType)
-		}
-
-		xt := pimpl.Export{}.ExtensionTypeFromDesc(wantDesc)
-		gotDesc := pimpl.Export{}.ExtensionDescFromType(xt)
-		if gotDesc != wantDesc {
-			b.Fatalf("ExtensionDesc mismatch: got %p, want %p", gotDesc, wantDesc)
-		}
-	}
-}
diff --git a/internal/impl/legacy_file.go b/internal/impl/legacy_file.go
index ddf33f7..b1293c6 100644
--- a/internal/impl/legacy_file.go
+++ b/internal/impl/legacy_file.go
@@ -9,6 +9,10 @@
 	"compress/gzip"
 	"io/ioutil"
 	"sync"
+
+	"google.golang.org/protobuf/internal/filedesc"
+	"google.golang.org/protobuf/reflect/protoreflect"
+	"google.golang.org/protobuf/reflect/protoregistry"
 )
 
 // Every enum and message type generated by protoc-gen-go since commit 2fc053c5
@@ -28,7 +32,7 @@
 	}
 )
 
-var legacyFileDescCache sync.Map // map[*byte]*descriptorpb.FileDescriptorProto
+var legacyFileDescCache sync.Map // map[*byte]protoreflect.FileDescriptor
 
 // legacyLoadFileDesc unmarshals b as a compressed FileDescriptorProto message.
 //
@@ -36,10 +40,10 @@
 // concatenated series of GZIP files (which would require shenanigans that
 // rely on the concatenation properties of both protobufs and GZIP).
 // File descriptors generated by protoc-gen-go do not rely on that property.
-func legacyLoadFileDesc(b []byte) *legacyFileDescriptorProto {
+func legacyLoadFileDesc(b []byte) protoreflect.FileDescriptor {
 	// Fast-path: check whether we already have a cached file descriptor.
 	if fd, ok := legacyFileDescCache.Load(&b[0]); ok {
-		return fd.(*legacyFileDescriptorProto)
+		return fd.(protoreflect.FileDescriptor)
 	}
 
 	// Slow-path: decompress and unmarshal the file descriptor proto.
@@ -47,13 +51,23 @@
 	if err != nil {
 		panic(err)
 	}
-	b, err = ioutil.ReadAll(zr)
+	b2, err := ioutil.ReadAll(zr)
 	if err != nil {
 		panic(err)
 	}
-	fd := legacyParseFileDescProto(b)
+
+	fd := filedesc.DescBuilder{
+		RawDescriptor: b2,
+		FileRegistry:  resolverOnly{protoregistry.GlobalFiles}, // do not register back to global registry
+	}.Build().File
 	if fd, ok := legacyFileDescCache.LoadOrStore(&b[0], fd); ok {
-		return fd.(*legacyFileDescriptorProto)
+		return fd.(protoreflect.FileDescriptor)
 	}
 	return fd
 }
+
+type resolverOnly struct {
+	*protoregistry.Files
+}
+
+func (resolverOnly) Register(...protoreflect.FileDescriptor) error { return nil }
diff --git a/internal/impl/legacy_message.go b/internal/impl/legacy_message.go
index c54cfc1..58bb07c 100644
--- a/internal/impl/legacy_message.go
+++ b/internal/impl/legacy_message.go
@@ -7,12 +7,9 @@
 import (
 	"fmt"
 	"reflect"
-	"strings"
 	"sync"
-	"unicode"
 
-	ptag "google.golang.org/protobuf/internal/encoding/tag"
-	ptype "google.golang.org/protobuf/internal/prototype"
+	"google.golang.org/protobuf/reflect/protoreflect"
 	pref "google.golang.org/protobuf/reflect/protoreflect"
 	"google.golang.org/protobuf/reflect/prototype"
 )
@@ -50,276 +47,35 @@
 	return mt
 }
 
-var (
-	legacyMessageDescLock  sync.Mutex
-	legacyMessageDescCache sync.Map // map[reflect.Type]protoreflect.MessageDescriptor
-)
+var legacyMessageDescCache sync.Map // map[reflect.Type]protoreflect.MessageDescriptor
 
 // LegacyLoadMessageDesc returns an MessageDescriptor derived from the Go type,
 // which must be a *struct kind and not implement the v2 API already.
 //
 // This is exported for testing purposes.
 func LegacyLoadMessageDesc(t reflect.Type) pref.MessageDescriptor {
-	return legacyMessageDescSet{}.Load(t)
-}
-
-type legacyMessageDescSet struct {
-	visited map[reflect.Type]*ptype.StandaloneMessage
-	descs   []*ptype.StandaloneMessage
-	types   []reflect.Type
-}
-
-func (ms legacyMessageDescSet) Load(t reflect.Type) pref.MessageDescriptor {
 	// Fast-path: check if a MessageDescriptor is cached for this concrete type.
 	if mi, ok := legacyMessageDescCache.Load(t); ok {
 		return mi.(pref.MessageDescriptor)
 	}
 
-	// Slow-path: initialize MessageDescriptor from the Go type.
-	//
-	// Hold a global lock during message creation to ensure that each Go type
-	// maps to exactly one MessageDescriptor. After obtaining the lock, we must
-	// check again whether the message has already been handled.
-	legacyMessageDescLock.Lock()
-	defer legacyMessageDescLock.Unlock()
-	if mi, ok := legacyMessageDescCache.Load(t); ok {
-		return mi.(pref.MessageDescriptor)
-	}
-
-	// Processing t recursively populates descs and types with all sub-messages.
-	// The descriptor for the first type is guaranteed to be at the front.
-	ms.processMessage(t)
-
-	// Within a proto file it is possible for cyclic dependencies to exist
-	// between multiple message types. When these cases arise, the set of
-	// message descriptors must be created together.
-	mds, err := ptype.NewMessages(ms.descs)
-	if err != nil {
-		panic(err)
-	}
-	for i, md := range mds {
-		// Protobuf semantics represents map entries under-the-hood as
-		// pseudo-messages (has a descriptor, but no generated Go type).
-		// Avoid caching these fake messages.
-		if t := ms.types[i]; t.Kind() != reflect.Map {
-			legacyMessageDescCache.Store(t, md)
-		}
-	}
-	return mds[0]
-}
-
-func (ms *legacyMessageDescSet) processMessage(t reflect.Type) pref.MessageDescriptor {
-	// Fast-path: Obtain a placeholder if the message is already processed.
-	if m, ok := ms.visited[t]; ok {
-		return ptype.PlaceholderMessage(m.FullName)
-	}
-
-	// Slow-path: Walk over the struct fields to derive the message descriptor.
-	if t.Kind() != reflect.Ptr || t.Elem().Kind() != reflect.Struct || t.Elem().PkgPath() == "" {
-		panic(fmt.Sprintf("got %v, want named *struct kind", t))
-	}
-
-	// Derive name and syntax from the raw descriptor.
-	m := new(ptype.StandaloneMessage)
+	// Slow-path: initialize MessageDescriptor from the raw descriptor.
 	mv := reflect.New(t.Elem()).Interface()
 	if _, ok := mv.(pref.ProtoMessage); ok {
 		panic(fmt.Sprintf("%v already implements proto.Message", t))
 	}
-	if md, ok := mv.(messageV1); ok {
-		b, idxs := md.Descriptor()
-		fd := legacyLoadFileDesc(b)
+	mdV1, ok := mv.(messageV1)
+	if !ok {
+		panic(fmt.Sprintf("message %v is no longer supported; please regenerate", t))
+	}
+	b, idxs := mdV1.Descriptor()
 
-		// Derive syntax.
-		switch fd.GetSyntax() {
-		case "proto2", "":
-			m.Syntax = pref.Proto2
-		case "proto3":
-			m.Syntax = pref.Proto3
-		}
-
-		// Derive full name.
-		md := fd.MessageType[idxs[0]]
-		m.FullName = pref.FullName(fd.GetPackage()).Append(pref.Name(md.GetName()))
-		for _, i := range idxs[1:] {
-			md = md.NestedType[i]
-			m.FullName = m.FullName.Append(pref.Name(md.GetName()))
-		}
-	} else {
-		// If the type does not implement messageV1, then the only way to
-		// obtain the full name is through the registry. However, this is
-		// unreliable as some generated messages register with a fork of
-		// golang/protobuf, so the registry may not have this information.
-		m.FullName = legacyDeriveFullName(t.Elem())
-		m.Syntax = pref.Proto2
-
-		// Try to determine if the message is using proto3 by checking scalars.
-		for i := 0; i < t.Elem().NumField(); i++ {
-			f := t.Elem().Field(i)
-			if tag := f.Tag.Get("protobuf"); tag != "" {
-				switch f.Type.Kind() {
-				case reflect.Bool, reflect.Int32, reflect.Int64, reflect.Uint32, reflect.Uint64, reflect.Float32, reflect.Float64, reflect.String:
-					m.Syntax = pref.Proto3
-				}
-				for _, s := range strings.Split(tag, ",") {
-					if s == "proto3" {
-						m.Syntax = pref.Proto3
-					}
-				}
-			}
-		}
+	md := legacyLoadFileDesc(b).Messages().Get(idxs[0])
+	for _, i := range idxs[1:] {
+		md = md.Messages().Get(i)
 	}
-	ms.visit(m, t)
-
-	// Obtain a list of oneof wrapper types.
-	var oneofWrappers []reflect.Type
-	if fn, ok := t.MethodByName("XXX_OneofFuncs"); ok {
-		vs := fn.Func.Call([]reflect.Value{reflect.Zero(fn.Type.In(0))})[3]
-		for _, v := range vs.Interface().([]interface{}) {
-			oneofWrappers = append(oneofWrappers, reflect.TypeOf(v))
-		}
+	if md, ok := legacyMessageDescCache.LoadOrStore(t, md); ok {
+		return md.(protoreflect.MessageDescriptor)
 	}
-	if fn, ok := t.MethodByName("XXX_OneofWrappers"); ok {
-		vs := fn.Func.Call([]reflect.Value{reflect.Zero(fn.Type.In(0))})[0]
-		for _, v := range vs.Interface().([]interface{}) {
-			oneofWrappers = append(oneofWrappers, reflect.TypeOf(v))
-		}
-	}
-
-	// Obtain a list of the extension ranges.
-	if fn, ok := t.MethodByName("ExtensionRangeArray"); ok {
-		vs := fn.Func.Call([]reflect.Value{reflect.Zero(fn.Type.In(0))})[0]
-		for i := 0; i < vs.Len(); i++ {
-			v := vs.Index(i)
-			m.ExtensionRanges = append(m.ExtensionRanges, [2]pref.FieldNumber{
-				pref.FieldNumber(v.FieldByName("Start").Int()),
-				pref.FieldNumber(v.FieldByName("End").Int() + 1),
-			})
-		}
-	}
-
-	// Derive the message fields by inspecting the struct fields.
-	for i := 0; i < t.Elem().NumField(); i++ {
-		f := t.Elem().Field(i)
-		if tag := f.Tag.Get("protobuf"); tag != "" {
-			tagKey := f.Tag.Get("protobuf_key")
-			tagVal := f.Tag.Get("protobuf_val")
-			m.Fields = append(m.Fields, ms.parseField(tag, tagKey, tagVal, f.Type, m))
-		}
-		if tag := f.Tag.Get("protobuf_oneof"); tag != "" {
-			name := pref.Name(tag)
-			m.Oneofs = append(m.Oneofs, ptype.Oneof{Name: name})
-			for _, t := range oneofWrappers {
-				if t.Implements(f.Type) {
-					f := t.Elem().Field(0)
-					if tag := f.Tag.Get("protobuf"); tag != "" {
-						ft := ms.parseField(tag, "", "", f.Type, m)
-						ft.OneofName = name
-						m.Fields = append(m.Fields, ft)
-					}
-				}
-			}
-		}
-	}
-
-	return ptype.PlaceholderMessage(m.FullName)
-}
-
-func (ms *legacyMessageDescSet) parseField(tag, tagKey, tagVal string, goType reflect.Type, parent *ptype.StandaloneMessage) ptype.Field {
-	t := goType
-	isOptional := t.Kind() == reflect.Ptr && t.Elem().Kind() != reflect.Struct
-	isRepeated := t.Kind() == reflect.Slice && t.Elem().Kind() != reflect.Uint8
-	if isOptional || isRepeated {
-		t = t.Elem()
-	}
-	f := ptag.Unmarshal(tag, t)
-
-	// Populate EnumType and MessageType.
-	if f.EnumType == nil && f.Kind == pref.EnumKind {
-		if ev, ok := reflect.Zero(t).Interface().(pref.Enum); ok {
-			f.EnumType = ev.Descriptor()
-		} else {
-			f.EnumType = LegacyLoadEnumDesc(t)
-		}
-	}
-	if f.MessageType == nil && (f.Kind == pref.MessageKind || f.Kind == pref.GroupKind) {
-		if mv, ok := reflect.Zero(t).Interface().(pref.ProtoMessage); ok {
-			f.MessageType = mv.ProtoReflect().Descriptor()
-		} else if t.Kind() == reflect.Map {
-			m := &ptype.StandaloneMessage{
-				Syntax:     parent.Syntax,
-				FullName:   parent.FullName.Append(legacyMapEntryName(f.Name)),
-				IsMapEntry: true,
-				Fields: []ptype.Field{
-					ms.parseField(tagKey, "", "", t.Key(), nil),
-					ms.parseField(tagVal, "", "", t.Elem(), nil),
-				},
-			}
-			ms.visit(m, t)
-			f.MessageType = ptype.PlaceholderMessage(m.FullName)
-		} else if mv, ok := legacyMessageDescCache.Load(t); ok {
-			f.MessageType = mv.(pref.MessageDescriptor)
-		} else {
-			f.MessageType = ms.processMessage(t)
-		}
-	}
-	return f
-}
-
-func (ms *legacyMessageDescSet) visit(m *ptype.StandaloneMessage, t reflect.Type) {
-	if ms.visited == nil {
-		ms.visited = make(map[reflect.Type]*ptype.StandaloneMessage)
-	}
-	if t.Kind() != reflect.Map {
-		ms.visited[t] = m
-	}
-	ms.descs = append(ms.descs, m)
-	ms.types = append(ms.types, t)
-}
-
-// legacyDeriveFullName derives a fully qualified protobuf name for the given Go type
-// The provided name is not guaranteed to be stable nor universally unique.
-// It should be sufficiently unique within a program.
-func legacyDeriveFullName(t reflect.Type) pref.FullName {
-	sanitize := func(r rune) rune {
-		switch {
-		case r == '/':
-			return '.'
-		case 'a' <= r && r <= 'z', 'A' <= r && r <= 'Z', '0' <= r && r <= '9':
-			return r
-		default:
-			return '_'
-		}
-	}
-	prefix := strings.Map(sanitize, t.PkgPath())
-	suffix := strings.Map(sanitize, t.Name())
-	if suffix == "" {
-		suffix = fmt.Sprintf("UnknownX%X", reflect.ValueOf(t).Pointer())
-	}
-
-	ss := append(strings.Split(prefix, "."), suffix)
-	for i, s := range ss {
-		if s == "" || ('0' <= s[0] && s[0] <= '9') {
-			ss[i] = "x" + s
-		}
-	}
-	return pref.FullName(strings.Join(ss, "."))
-}
-
-// legacyMapEntryName derives the message name for a map field of a given name.
-// This is identical to MapEntryName from parser.cc in the protoc source.
-func legacyMapEntryName(s pref.Name) pref.Name {
-	var b []byte
-	nextUpper := true
-	for i := 0; i < len(s); i++ {
-		if c := s[i]; c == '_' {
-			nextUpper = true
-		} else {
-			if nextUpper {
-				c = byte(unicode.ToUpper(rune(c)))
-				nextUpper = false
-			}
-			b = append(b, c)
-		}
-	}
-	return pref.Name(append(b, "Entry"...))
+	return md
 }
diff --git a/internal/impl/legacy_parse.go b/internal/impl/legacy_parse.go
deleted file mode 100644
index 90ba1b7..0000000
--- a/internal/impl/legacy_parse.go
+++ /dev/null
@@ -1,169 +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 impl
-
-import (
-	"google.golang.org/protobuf/internal/encoding/wire"
-	"google.golang.org/protobuf/internal/fieldnum"
-)
-
-// To avoid a dependency from legacy to descriptor.proto, use a hand-written parser
-// for the bits of the descriptor we need.
-//
-// TODO: Consider unifying this with the parser in fileinit.
-
-type legacyFileDescriptorProto struct {
-	Syntax      string
-	Package     string
-	EnumType    []*legacyEnumDescriptorProto
-	MessageType []*legacyDescriptorProto
-}
-
-func (fd legacyFileDescriptorProto) GetSyntax() string  { return fd.Syntax }
-func (fd legacyFileDescriptorProto) GetPackage() string { return fd.Package }
-
-func legacyParseFileDescProto(b []byte) *legacyFileDescriptorProto {
-	fd := &legacyFileDescriptorProto{}
-	for len(b) > 0 {
-		num, typ, n := wire.ConsumeTag(b)
-		legacyParseCheck(n)
-		b = b[n:]
-		switch typ {
-		case wire.BytesType:
-			v, n := wire.ConsumeBytes(b)
-			b = b[n:]
-			switch num {
-			case fieldnum.FileDescriptorProto_Syntax:
-				fd.Syntax = string(v)
-			case fieldnum.FileDescriptorProto_Package:
-				fd.Package = string(v)
-			case fieldnum.FileDescriptorProto_EnumType:
-				fd.EnumType = append(fd.EnumType, legacyParseEnumDescProto(v))
-			case fieldnum.FileDescriptorProto_MessageType:
-				fd.MessageType = append(fd.MessageType, parseDescProto(v))
-			}
-		default:
-			n := wire.ConsumeFieldValue(num, typ, b)
-			legacyParseCheck(n)
-			b = b[n:]
-		}
-	}
-	return fd
-}
-
-type legacyDescriptorProto struct {
-	Name       string
-	NestedType []*legacyDescriptorProto
-	EnumType   []*legacyEnumDescriptorProto
-}
-
-func (md legacyDescriptorProto) GetName() string { return md.Name }
-
-func parseDescProto(b []byte) *legacyDescriptorProto {
-	md := &legacyDescriptorProto{}
-	for len(b) > 0 {
-		num, typ, n := wire.ConsumeTag(b)
-		legacyParseCheck(n)
-		b = b[n:]
-		switch typ {
-		case wire.BytesType:
-			v, n := wire.ConsumeBytes(b)
-			legacyParseCheck(n)
-			b = b[n:]
-			switch num {
-			case fieldnum.DescriptorProto_Name:
-				md.Name = string(v)
-			case fieldnum.DescriptorProto_NestedType:
-				md.NestedType = append(md.NestedType, parseDescProto(v))
-			case fieldnum.DescriptorProto_EnumType:
-				md.EnumType = append(md.EnumType, legacyParseEnumDescProto(v))
-			}
-		default:
-			n := wire.ConsumeFieldValue(num, typ, b)
-			legacyParseCheck(n)
-			b = b[n:]
-		}
-	}
-	return md
-}
-
-type legacyEnumDescriptorProto struct {
-	Name  string
-	Value []*legacyEnumValueDescriptorProto
-}
-
-func (ed legacyEnumDescriptorProto) GetName() string { return ed.Name }
-
-func legacyParseEnumDescProto(b []byte) *legacyEnumDescriptorProto {
-	ed := &legacyEnumDescriptorProto{}
-	for len(b) > 0 {
-		num, typ, n := wire.ConsumeTag(b)
-		legacyParseCheck(n)
-		b = b[n:]
-		switch typ {
-		case wire.BytesType:
-			v, n := wire.ConsumeBytes(b)
-			legacyParseCheck(n)
-			b = b[n:]
-			switch num {
-			case fieldnum.EnumDescriptorProto_Name:
-				ed.Name = string(v)
-			case fieldnum.EnumDescriptorProto_Value:
-				ed.Value = append(ed.Value, legacyParseEnumValueDescProto(v))
-			}
-		default:
-			n := wire.ConsumeFieldValue(num, typ, b)
-			legacyParseCheck(n)
-			b = b[n:]
-		}
-	}
-	return ed
-}
-
-type legacyEnumValueDescriptorProto struct {
-	Name   string
-	Number int32
-}
-
-func (ed legacyEnumValueDescriptorProto) GetName() string  { return ed.Name }
-func (ed legacyEnumValueDescriptorProto) GetNumber() int32 { return ed.Number }
-
-func legacyParseEnumValueDescProto(b []byte) *legacyEnumValueDescriptorProto {
-	vd := &legacyEnumValueDescriptorProto{}
-	for len(b) > 0 {
-		num, typ, n := wire.ConsumeTag(b)
-		legacyParseCheck(n)
-		b = b[n:]
-		switch typ {
-		case wire.VarintType:
-			v, n := wire.ConsumeVarint(b)
-			legacyParseCheck(n)
-			b = b[n:]
-			switch num {
-			case fieldnum.EnumValueDescriptorProto_Number:
-				vd.Number = int32(v)
-			}
-		case wire.BytesType:
-			v, n := wire.ConsumeBytes(b)
-			legacyParseCheck(n)
-			b = b[n:]
-			switch num {
-			case fieldnum.EnumDescriptorProto_Name:
-				vd.Name = string(v)
-			}
-		default:
-			n := wire.ConsumeFieldValue(num, typ, b)
-			legacyParseCheck(n)
-			b = b[n:]
-		}
-	}
-	return vd
-}
-
-func legacyParseCheck(n int) {
-	if n < 0 {
-		panic(wire.ParseError(n))
-	}
-}
diff --git a/internal/impl/legacy_test.go b/internal/impl/legacy_test.go
index fc29cdb..a51ae03 100644
--- a/internal/impl/legacy_test.go
+++ b/internal/impl/legacy_test.go
@@ -5,326 +5,333 @@
 package impl_test
 
 import (
+	"fmt"
 	"reflect"
 	"sync"
 	"testing"
 
 	"github.com/google/go-cmp/cmp"
 	"github.com/google/go-cmp/cmp/cmpopts"
+	"google.golang.org/protobuf/encoding/prototext"
 	pimpl "google.golang.org/protobuf/internal/impl"
-	pragma "google.golang.org/protobuf/internal/pragma"
-	ptype "google.golang.org/protobuf/internal/prototype"
+	"google.golang.org/protobuf/internal/pragma"
 	"google.golang.org/protobuf/internal/scalar"
+	"google.golang.org/protobuf/proto"
+	pdesc "google.golang.org/protobuf/reflect/protodesc"
 	pref "google.golang.org/protobuf/reflect/protoreflect"
 	preg "google.golang.org/protobuf/reflect/protoregistry"
 	piface "google.golang.org/protobuf/runtime/protoiface"
 
 	proto2_20180125 "google.golang.org/protobuf/internal/testprotos/legacy/proto2.v1.0.0-20180125-92554152"
+	"google.golang.org/protobuf/types/descriptorpb"
 )
 
-type legacyTestMessage struct {
+type LegacyTestMessage struct {
 	XXX_unrecognized       []byte
 	XXX_InternalExtensions map[int32]pimpl.ExtensionField
 }
 
-func (*legacyTestMessage) Reset()         {}
-func (*legacyTestMessage) String() string { return "" }
-func (*legacyTestMessage) ProtoMessage()  {}
-func (*legacyTestMessage) ExtensionRangeArray() []piface.ExtensionRangeV1 {
+func (*LegacyTestMessage) Reset()         {}
+func (*LegacyTestMessage) String() string { return "" }
+func (*LegacyTestMessage) ProtoMessage()  {}
+func (*LegacyTestMessage) ExtensionRangeArray() []piface.ExtensionRangeV1 {
 	return []piface.ExtensionRangeV1{{Start: 10, End: 20}, {Start: 40, End: 80}, {Start: 10000, End: 20000}}
 }
+func (*LegacyTestMessage) Descriptor() ([]byte, []int) { return legacyFD, []int{0} }
+
+var legacyFD = func() []byte {
+	b, _ := proto.Marshal(pdesc.ToFileDescriptorProto(mustMakeFileDesc(`
+		name:   "legacy.proto"
+		syntax: "proto2"
+		message_type: [{
+			name:            "LegacyTestMessage"
+			extension_range: [{start:10 end:20}, {start:40 end:80}, {start:10000 end:20000}]
+		}]
+	`, nil)))
+	return pimpl.Export{}.CompressGZIP(b)
+}()
 
 func init() {
-	mt := pimpl.Export{}.MessageTypeOf(&legacyTestMessage{})
+	mt := pimpl.Export{}.MessageTypeOf((*LegacyTestMessage)(nil))
+	preg.GlobalFiles.Register(mt.ParentFile())
 	preg.GlobalTypes.Register(mt)
 }
 
+func mustMakeExtensionType(fileDesc, extDesc string, t interface{}, r pdesc.Resolver) pref.ExtensionType {
+	s := fmt.Sprintf(`name:"test.proto" syntax:"proto2" %s extension:[{%s}]`, fileDesc, extDesc)
+	xd := mustMakeFileDesc(s, r).Extensions().Get(0)
+	return pimpl.LegacyExtensionTypeOf(xd, reflect.TypeOf(t))
+}
+
+func mustMakeFileDesc(s string, r pdesc.Resolver) pref.FileDescriptor {
+	pb := new(descriptorpb.FileDescriptorProto)
+	if err := prototext.Unmarshal([]byte(s), pb); err != nil {
+		panic(err)
+	}
+	fd, err := pdesc.NewFile(pb, r)
+	if err != nil {
+		panic(err)
+	}
+	return fd
+}
+
 var (
-	testParentDesc    = pimpl.Export{}.MessageDescriptorOf((*legacyTestMessage)(nil))
+	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()
 
+	depReg = preg.NewFiles(
+		testParentDesc.ParentFile(),
+		testEnumV1Desc.ParentFile(),
+		testMessageV1Desc.ParentFile(),
+		testEnumV2Desc.ParentFile(),
+		testMessageV2Desc.ParentFile(),
+	)
 	extensionTypes = []pref.ExtensionType{
-		mustMakeExtensionType(&ptype.StandaloneExtension{
-			FullName:     "fizz.buzz.optional_bool",
-			Number:       10000,
-			Cardinality:  pref.Optional,
-			Kind:         pref.BoolKind,
-			Default:      pref.ValueOf(true),
-			ExtendedType: testParentDesc,
-		}, nil),
-		mustMakeExtensionType(&ptype.StandaloneExtension{
-			FullName:     "fizz.buzz.optional_int32",
-			Number:       10001,
-			Cardinality:  pref.Optional,
-			Kind:         pref.Int32Kind,
-			Default:      pref.ValueOf(int32(-12345)),
-			ExtendedType: testParentDesc,
-		}, nil),
-		mustMakeExtensionType(&ptype.StandaloneExtension{
-			FullName:     "fizz.buzz.optional_uint32",
-			Number:       10002,
-			Cardinality:  pref.Optional,
-			Kind:         pref.Uint32Kind,
-			Default:      pref.ValueOf(uint32(3200)),
-			ExtendedType: testParentDesc,
-		}, nil),
-		mustMakeExtensionType(&ptype.StandaloneExtension{
-			FullName:     "fizz.buzz.optional_float",
-			Number:       10003,
-			Cardinality:  pref.Optional,
-			Kind:         pref.FloatKind,
-			Default:      pref.ValueOf(float32(3.14159)),
-			ExtendedType: testParentDesc,
-		}, nil),
-		mustMakeExtensionType(&ptype.StandaloneExtension{
-			FullName:     "fizz.buzz.optional_string",
-			Number:       10004,
-			Cardinality:  pref.Optional,
-			Kind:         pref.StringKind,
-			Default:      pref.ValueOf(string("hello, \"world!\"\n")),
-			ExtendedType: testParentDesc,
-		}, nil),
-		mustMakeExtensionType(&ptype.StandaloneExtension{
-			FullName:     "fizz.buzz.optional_bytes",
-			Number:       10005,
-			Cardinality:  pref.Optional,
-			Kind:         pref.BytesKind,
-			Default:      pref.ValueOf([]byte("dead\xde\xad\xbe\xefbeef")),
-			ExtendedType: testParentDesc,
-		}, nil),
-		mustMakeExtensionType(&ptype.StandaloneExtension{
-			FullName:     "fizz.buzz.optional_enum_v1",
-			Number:       10006,
-			Cardinality:  pref.Optional,
-			Kind:         pref.EnumKind,
-			Default:      pref.ValueOf(pref.EnumNumber(0)),
-			EnumType:     testEnumV1Desc,
-			ExtendedType: testParentDesc,
-		}, proto2_20180125.Message_ChildEnum(0)),
-		mustMakeExtensionType(&ptype.StandaloneExtension{
-			FullName:     "fizz.buzz.optional_message_v1",
-			Number:       10007,
-			Cardinality:  pref.Optional,
-			Kind:         pref.MessageKind,
-			MessageType:  testMessageV1Desc,
-			ExtendedType: testParentDesc,
-		}, (*proto2_20180125.Message_ChildMessage)(nil)),
-		mustMakeExtensionType(&ptype.StandaloneExtension{
-			FullName:     "fizz.buzz.optional_enum_v2",
-			Number:       10008,
-			Cardinality:  pref.Optional,
-			Kind:         pref.EnumKind,
-			Default:      pref.ValueOf(pref.EnumNumber(57005)),
-			EnumType:     testEnumV2Desc,
-			ExtendedType: testParentDesc,
-		}, EnumProto2(0)),
-		mustMakeExtensionType(&ptype.StandaloneExtension{
-			FullName:     "fizz.buzz.optional_message_v2",
-			Number:       10009,
-			Cardinality:  pref.Optional,
-			Kind:         pref.MessageKind,
-			MessageType:  testMessageV2Desc,
-			ExtendedType: testParentDesc,
-		}, (*EnumMessages)(nil)),
-		mustMakeExtensionType(&ptype.StandaloneExtension{
-			FullName:     "fizz.buzz.repeated_bool",
-			Number:       10010,
-			Cardinality:  pref.Repeated,
-			Kind:         pref.BoolKind,
-			ExtendedType: testParentDesc,
-		}, nil),
-		mustMakeExtensionType(&ptype.StandaloneExtension{
-			FullName:     "fizz.buzz.repeated_int32",
-			Number:       10011,
-			Cardinality:  pref.Repeated,
-			Kind:         pref.Int32Kind,
-			ExtendedType: testParentDesc,
-		}, nil),
-		mustMakeExtensionType(&ptype.StandaloneExtension{
-			FullName:     "fizz.buzz.repeated_uint32",
-			Number:       10012,
-			Cardinality:  pref.Repeated,
-			Kind:         pref.Uint32Kind,
-			ExtendedType: testParentDesc,
-		}, nil),
-		mustMakeExtensionType(&ptype.StandaloneExtension{
-			FullName:     "fizz.buzz.repeated_float",
-			Number:       10013,
-			Cardinality:  pref.Repeated,
-			Kind:         pref.FloatKind,
-			ExtendedType: testParentDesc,
-		}, nil),
-		mustMakeExtensionType(&ptype.StandaloneExtension{
-			FullName:     "fizz.buzz.repeated_string",
-			Number:       10014,
-			Cardinality:  pref.Repeated,
-			Kind:         pref.StringKind,
-			ExtendedType: testParentDesc,
-		}, nil),
-		mustMakeExtensionType(&ptype.StandaloneExtension{
-			FullName:     "fizz.buzz.repeated_bytes",
-			Number:       10015,
-			Cardinality:  pref.Repeated,
-			Kind:         pref.BytesKind,
-			ExtendedType: testParentDesc,
-		}, nil),
-		mustMakeExtensionType(&ptype.StandaloneExtension{
-			FullName:     "fizz.buzz.repeated_enum_v1",
-			Number:       10016,
-			Cardinality:  pref.Repeated,
-			Kind:         pref.EnumKind,
-			EnumType:     testEnumV1Desc,
-			ExtendedType: testParentDesc,
-		}, proto2_20180125.Message_ChildEnum(0)),
-		mustMakeExtensionType(&ptype.StandaloneExtension{
-			FullName:     "fizz.buzz.repeated_message_v1",
-			Number:       10017,
-			Cardinality:  pref.Repeated,
-			Kind:         pref.MessageKind,
-			MessageType:  testMessageV1Desc,
-			ExtendedType: testParentDesc,
-		}, (*proto2_20180125.Message_ChildMessage)(nil)),
-		mustMakeExtensionType(&ptype.StandaloneExtension{
-			FullName:     "fizz.buzz.repeated_enum_v2",
-			Number:       10018,
-			Cardinality:  pref.Repeated,
-			Kind:         pref.EnumKind,
-			EnumType:     testEnumV2Desc,
-			ExtendedType: testParentDesc,
-		}, EnumProto2(0)),
-		mustMakeExtensionType(&ptype.StandaloneExtension{
-			FullName:     "fizz.buzz.repeated_message_v2",
-			Number:       10019,
-			Cardinality:  pref.Repeated,
-			Kind:         pref.MessageKind,
-			MessageType:  testMessageV2Desc,
-			ExtendedType: testParentDesc,
-		}, (*EnumMessages)(nil)),
+		mustMakeExtensionType(
+			`package:"fizz.buzz" dependency:"legacy.proto"`,
+			`name:"optional_bool" number:10000 label:LABEL_OPTIONAL type:TYPE_BOOL default_value:"true" extendee:".LegacyTestMessage"`,
+			nil, depReg,
+		),
+		mustMakeExtensionType(
+			`package:"fizz.buzz" dependency:"legacy.proto"`,
+			`name:"optional_int32" number:10001 label:LABEL_OPTIONAL type:TYPE_INT32 default_value:"-12345" extendee:".LegacyTestMessage"`,
+			nil, depReg,
+		),
+		mustMakeExtensionType(
+			`package:"fizz.buzz" dependency:"legacy.proto"`,
+			`name:"optional_uint32" number:10002 label:LABEL_OPTIONAL type:TYPE_UINT32 default_value:"3200" extendee:".LegacyTestMessage"`,
+			nil, depReg,
+		),
+		mustMakeExtensionType(
+			`package:"fizz.buzz" dependency:"legacy.proto"`,
+			`name:"optional_float" number:10003 label:LABEL_OPTIONAL type:TYPE_FLOAT default_value:"3.14159" extendee:".LegacyTestMessage"`,
+			nil, depReg,
+		),
+		mustMakeExtensionType(
+			`package:"fizz.buzz" dependency:"legacy.proto"`,
+			`name:"optional_string" number:10004 label:LABEL_OPTIONAL type:TYPE_STRING default_value:"hello, \"world!\"\n" extendee:".LegacyTestMessage"`,
+			nil, depReg,
+		),
+		mustMakeExtensionType(
+			`package:"fizz.buzz" dependency:"legacy.proto"`,
+			`name:"optional_bytes" number:10005 label:LABEL_OPTIONAL type:TYPE_BYTES default_value:"dead\\336\\255\\276\\357beef" extendee:".LegacyTestMessage"`,
+			nil, depReg,
+		),
+		mustMakeExtensionType(
+			`package:"fizz.buzz" dependency:["legacy.proto", "proto2.v1.0.0-20180125-92554152/test.proto"]`,
+			`name:"optional_enum_v1" number:10006 label:LABEL_OPTIONAL type:TYPE_ENUM type_name:".google.golang.org.proto2_20180125.Message.ChildEnum" default_value:"ALPHA" extendee:".LegacyTestMessage"`,
+			proto2_20180125.Message_ChildEnum(0), depReg,
+		),
+		mustMakeExtensionType(
+			`package:"fizz.buzz" dependency:["legacy.proto", "proto2.v1.0.0-20180125-92554152/test.proto"]`,
+			`name:"optional_message_v1" number:10007 label:LABEL_OPTIONAL type:TYPE_MESSAGE type_name:".google.golang.org.proto2_20180125.Message.ChildMessage" extendee:".LegacyTestMessage"`,
+			(*proto2_20180125.Message_ChildMessage)(nil), depReg,
+		),
+		mustMakeExtensionType(
+			`package:"fizz.buzz" dependency:["legacy.proto", "enum2.proto"]`,
+			`name:"optional_enum_v2" number:10008 label:LABEL_OPTIONAL type:TYPE_ENUM type_name:".EnumProto2" default_value:"DEAD" extendee:".LegacyTestMessage"`,
+			EnumProto2(0), depReg,
+		),
+		mustMakeExtensionType(
+			`package:"fizz.buzz" dependency:["legacy.proto", "enum-messages.proto"]`,
+			`name:"optional_message_v2" number:10009 label:LABEL_OPTIONAL type:TYPE_MESSAGE type_name:".EnumMessages" extendee:".LegacyTestMessage"`,
+			(*EnumMessages)(nil), depReg,
+		),
+		mustMakeExtensionType(
+			`package:"fizz.buzz" dependency:"legacy.proto"`,
+			`name:"repeated_bool" number:10010 label:LABEL_REPEATED type:TYPE_BOOL extendee:".LegacyTestMessage"`,
+			nil, depReg,
+		),
+		mustMakeExtensionType(
+			`package:"fizz.buzz" dependency:"legacy.proto"`,
+			`name:"repeated_int32" number:10011 label:LABEL_REPEATED type:TYPE_INT32 extendee:".LegacyTestMessage"`,
+			nil, depReg,
+		),
+		mustMakeExtensionType(
+			`package:"fizz.buzz" dependency:"legacy.proto"`,
+			`name:"repeated_uint32" number:10012 label:LABEL_REPEATED type:TYPE_UINT32 extendee:".LegacyTestMessage"`,
+			nil, depReg,
+		),
+		mustMakeExtensionType(
+			`package:"fizz.buzz" dependency:"legacy.proto"`,
+			`name:"repeated_float" number:10013 label:LABEL_REPEATED type:TYPE_FLOAT extendee:".LegacyTestMessage"`,
+			nil, depReg,
+		),
+		mustMakeExtensionType(
+			`package:"fizz.buzz" dependency:"legacy.proto"`,
+			`name:"repeated_string" number:10014 label:LABEL_REPEATED type:TYPE_STRING extendee:".LegacyTestMessage"`,
+			nil, depReg,
+		),
+		mustMakeExtensionType(
+			`package:"fizz.buzz" dependency:"legacy.proto"`,
+			`name:"repeated_bytes" number:10015 label:LABEL_REPEATED type:TYPE_BYTES extendee:".LegacyTestMessage"`,
+			nil, depReg,
+		),
+		mustMakeExtensionType(
+			`package:"fizz.buzz" dependency:["legacy.proto", "proto2.v1.0.0-20180125-92554152/test.proto"]`,
+			`name:"repeated_enum_v1" number:10016 label:LABEL_REPEATED type:TYPE_ENUM type_name:".google.golang.org.proto2_20180125.Message.ChildEnum" extendee:".LegacyTestMessage"`,
+			proto2_20180125.Message_ChildEnum(0), depReg,
+		),
+		mustMakeExtensionType(
+			`package:"fizz.buzz" dependency:["legacy.proto", "proto2.v1.0.0-20180125-92554152/test.proto"]`,
+			`name:"repeated_message_v1" number:10017 label:LABEL_REPEATED type:TYPE_MESSAGE type_name:".google.golang.org.proto2_20180125.Message.ChildMessage" extendee:".LegacyTestMessage"`,
+			(*proto2_20180125.Message_ChildMessage)(nil), depReg,
+		),
+		mustMakeExtensionType(
+			`package:"fizz.buzz" dependency:["legacy.proto", "enum2.proto"]`,
+			`name:"repeated_enum_v2" number:10018 label:LABEL_REPEATED type:TYPE_ENUM type_name:".EnumProto2" extendee:".LegacyTestMessage"`,
+			EnumProto2(0), depReg,
+		),
+		mustMakeExtensionType(
+			`package:"fizz.buzz" dependency:["legacy.proto", "enum-messages.proto"]`,
+			`name:"repeated_message_v2" number:10019 label:LABEL_REPEATED type:TYPE_MESSAGE type_name:".EnumMessages" extendee:".LegacyTestMessage"`,
+			(*EnumMessages)(nil), depReg,
+		),
 	}
 
 	extensionDescs = []*piface.ExtensionDescV1{{
-		ExtendedType:  (*legacyTestMessage)(nil),
+		ExtendedType:  (*LegacyTestMessage)(nil),
 		ExtensionType: (*bool)(nil),
 		Field:         10000,
 		Name:          "fizz.buzz.optional_bool",
 		Tag:           "varint,10000,opt,name=optional_bool,def=1",
+		Filename:      "test.proto",
 	}, {
-		ExtendedType:  (*legacyTestMessage)(nil),
+		ExtendedType:  (*LegacyTestMessage)(nil),
 		ExtensionType: (*int32)(nil),
 		Field:         10001,
 		Name:          "fizz.buzz.optional_int32",
 		Tag:           "varint,10001,opt,name=optional_int32,def=-12345",
+		Filename:      "test.proto",
 	}, {
-		ExtendedType:  (*legacyTestMessage)(nil),
+		ExtendedType:  (*LegacyTestMessage)(nil),
 		ExtensionType: (*uint32)(nil),
 		Field:         10002,
 		Name:          "fizz.buzz.optional_uint32",
 		Tag:           "varint,10002,opt,name=optional_uint32,def=3200",
+		Filename:      "test.proto",
 	}, {
-		ExtendedType:  (*legacyTestMessage)(nil),
+		ExtendedType:  (*LegacyTestMessage)(nil),
 		ExtensionType: (*float32)(nil),
 		Field:         10003,
 		Name:          "fizz.buzz.optional_float",
 		Tag:           "fixed32,10003,opt,name=optional_float,def=3.14159",
+		Filename:      "test.proto",
 	}, {
-		ExtendedType:  (*legacyTestMessage)(nil),
+		ExtendedType:  (*LegacyTestMessage)(nil),
 		ExtensionType: (*string)(nil),
 		Field:         10004,
 		Name:          "fizz.buzz.optional_string",
 		Tag:           "bytes,10004,opt,name=optional_string,def=hello, \"world!\"\n",
+		Filename:      "test.proto",
 	}, {
-		ExtendedType:  (*legacyTestMessage)(nil),
+		ExtendedType:  (*LegacyTestMessage)(nil),
 		ExtensionType: ([]byte)(nil),
 		Field:         10005,
 		Name:          "fizz.buzz.optional_bytes",
 		Tag:           "bytes,10005,opt,name=optional_bytes,def=dead\\336\\255\\276\\357beef",
+		Filename:      "test.proto",
 	}, {
-		ExtendedType:  (*legacyTestMessage)(nil),
+		ExtendedType:  (*LegacyTestMessage)(nil),
 		ExtensionType: (*proto2_20180125.Message_ChildEnum)(nil),
 		Field:         10006,
 		Name:          "fizz.buzz.optional_enum_v1",
 		Tag:           "varint,10006,opt,name=optional_enum_v1,enum=google.golang.org.proto2_20180125.Message_ChildEnum,def=0",
+		Filename:      "test.proto",
 	}, {
-		ExtendedType:  (*legacyTestMessage)(nil),
+		ExtendedType:  (*LegacyTestMessage)(nil),
 		ExtensionType: (*proto2_20180125.Message_ChildMessage)(nil),
 		Field:         10007,
 		Name:          "fizz.buzz.optional_message_v1",
 		Tag:           "bytes,10007,opt,name=optional_message_v1",
+		Filename:      "test.proto",
 	}, {
-		ExtendedType:  (*legacyTestMessage)(nil),
+		ExtendedType:  (*LegacyTestMessage)(nil),
 		ExtensionType: (*EnumProto2)(nil),
 		Field:         10008,
 		Name:          "fizz.buzz.optional_enum_v2",
 		Tag:           "varint,10008,opt,name=optional_enum_v2,enum=EnumProto2,def=57005",
+		Filename:      "test.proto",
 	}, {
-		ExtendedType:  (*legacyTestMessage)(nil),
+		ExtendedType:  (*LegacyTestMessage)(nil),
 		ExtensionType: (*EnumMessages)(nil),
 		Field:         10009,
 		Name:          "fizz.buzz.optional_message_v2",
 		Tag:           "bytes,10009,opt,name=optional_message_v2",
+		Filename:      "test.proto",
 	}, {
-		ExtendedType:  (*legacyTestMessage)(nil),
+		ExtendedType:  (*LegacyTestMessage)(nil),
 		ExtensionType: ([]bool)(nil),
 		Field:         10010,
 		Name:          "fizz.buzz.repeated_bool",
 		Tag:           "varint,10010,rep,name=repeated_bool",
+		Filename:      "test.proto",
 	}, {
-		ExtendedType:  (*legacyTestMessage)(nil),
+		ExtendedType:  (*LegacyTestMessage)(nil),
 		ExtensionType: ([]int32)(nil),
 		Field:         10011,
 		Name:          "fizz.buzz.repeated_int32",
 		Tag:           "varint,10011,rep,name=repeated_int32",
+		Filename:      "test.proto",
 	}, {
-		ExtendedType:  (*legacyTestMessage)(nil),
+		ExtendedType:  (*LegacyTestMessage)(nil),
 		ExtensionType: ([]uint32)(nil),
 		Field:         10012,
 		Name:          "fizz.buzz.repeated_uint32",
 		Tag:           "varint,10012,rep,name=repeated_uint32",
+		Filename:      "test.proto",
 	}, {
-		ExtendedType:  (*legacyTestMessage)(nil),
+		ExtendedType:  (*LegacyTestMessage)(nil),
 		ExtensionType: ([]float32)(nil),
 		Field:         10013,
 		Name:          "fizz.buzz.repeated_float",
 		Tag:           "fixed32,10013,rep,name=repeated_float",
+		Filename:      "test.proto",
 	}, {
-		ExtendedType:  (*legacyTestMessage)(nil),
+		ExtendedType:  (*LegacyTestMessage)(nil),
 		ExtensionType: ([]string)(nil),
 		Field:         10014,
 		Name:          "fizz.buzz.repeated_string",
 		Tag:           "bytes,10014,rep,name=repeated_string",
+		Filename:      "test.proto",
 	}, {
-		ExtendedType:  (*legacyTestMessage)(nil),
+		ExtendedType:  (*LegacyTestMessage)(nil),
 		ExtensionType: ([][]byte)(nil),
 		Field:         10015,
 		Name:          "fizz.buzz.repeated_bytes",
 		Tag:           "bytes,10015,rep,name=repeated_bytes",
+		Filename:      "test.proto",
 	}, {
-		ExtendedType:  (*legacyTestMessage)(nil),
+		ExtendedType:  (*LegacyTestMessage)(nil),
 		ExtensionType: ([]proto2_20180125.Message_ChildEnum)(nil),
 		Field:         10016,
 		Name:          "fizz.buzz.repeated_enum_v1",
 		Tag:           "varint,10016,rep,name=repeated_enum_v1,enum=google.golang.org.proto2_20180125.Message_ChildEnum",
+		Filename:      "test.proto",
 	}, {
-		ExtendedType:  (*legacyTestMessage)(nil),
+		ExtendedType:  (*LegacyTestMessage)(nil),
 		ExtensionType: ([]*proto2_20180125.Message_ChildMessage)(nil),
 		Field:         10017,
 		Name:          "fizz.buzz.repeated_message_v1",
 		Tag:           "bytes,10017,rep,name=repeated_message_v1",
+		Filename:      "test.proto",
 	}, {
-		ExtendedType:  (*legacyTestMessage)(nil),
+		ExtendedType:  (*LegacyTestMessage)(nil),
 		ExtensionType: ([]EnumProto2)(nil),
 		Field:         10018,
 		Name:          "fizz.buzz.repeated_enum_v2",
 		Tag:           "varint,10018,rep,name=repeated_enum_v2,enum=EnumProto2",
+		Filename:      "test.proto",
 	}, {
-		ExtendedType:  (*legacyTestMessage)(nil),
+		ExtendedType:  (*LegacyTestMessage)(nil),
 		ExtensionType: ([]*EnumMessages)(nil),
 		Field:         10019,
 		Name:          "fizz.buzz.repeated_message_v2",
 		Tag:           "bytes,10019,rep,name=repeated_message_v2",
+		Filename:      "test.proto",
 	}}
 )
 
@@ -333,7 +340,7 @@
 		return x == y // pointer compare messages for object identity
 	})}
 
-	m := pimpl.Export{}.MessageOf(new(legacyTestMessage))
+	m := pimpl.Export{}.MessageOf(new(LegacyTestMessage))
 
 	if n := m.Len(); n != 0 {
 		t.Errorf("KnownFields.Len() = %v, want 0", n)
@@ -490,13 +497,6 @@
 					}
 					return out
 				}),
-				// TODO: Add this when ExtensionType no longer implements
-				// ExtensionDescriptor.
-				/*
-					cmp.Transformer("", func(x pref.ExtensionType) pref.ExtensionDescriptor {
-						return x.Descriptor()
-					}),
-				*/
 				cmp.Transformer("", func(x pref.Descriptor) map[string]interface{} {
 					out := make(map[string]interface{})
 					v := reflect.ValueOf(x)
@@ -558,6 +558,38 @@
 	Enum int32
 )
 
+func (*MessageA) Descriptor() ([]byte, []int) { return concurrentFD, []int{0} }
+func (*MessageB) Descriptor() ([]byte, []int) { return concurrentFD, []int{1} }
+func (Enum) EnumDescriptor() ([]byte, []int)  { return concurrentFD, []int{0} }
+
+var concurrentFD = func() []byte {
+	b, _ := proto.Marshal(pdesc.ToFileDescriptorProto(mustMakeFileDesc(`
+		name:    "concurrent.proto"
+		syntax:  "proto2"
+		package: "legacy"
+		message_type: [{
+			name: "MessageA"
+			field: [
+				{name:"a1" number:1 label:LABEL_REQUIRED type:TYPE_MESSAGE type_name:".legacy.MessageA"},
+				{name:"a2" number:2 label:LABEL_REQUIRED type:TYPE_MESSAGE type_name:".legacy.MessageB"},
+				{name:"a3" number:3 label:LABEL_OPTIONAL type:TYPE_ENUM    type_name:".legacy.Enum"}
+			]
+		}, {
+			name: "MessageB"
+			field: [
+				{name:"a1" number:1 label:LABEL_REQUIRED type:TYPE_MESSAGE type_name:".legacy.MessageA"},
+				{name:"a2" number:2 label:LABEL_REQUIRED type:TYPE_MESSAGE type_name:".legacy.MessageB"},
+				{name:"a3" number:3 label:LABEL_OPTIONAL type:TYPE_ENUM    type_name:".legacy.Enum"}
+			]
+		}]
+		enum_type: [{
+			name:  "Enum"
+			value: [{name:"FOO" number:500}]
+		}]
+	`, nil)))
+	return pimpl.Export{}.CompressGZIP(b)
+}()
+
 // TestConcurrentInit tests that concurrent wrapping of multiple legacy types
 // results in the exact same descriptor being created.
 func TestConcurrentInit(t *testing.T) {
diff --git a/internal/impl/message.go b/internal/impl/message.go
index df2fcee..161f194 100644
--- a/internal/impl/message.go
+++ b/internal/impl/message.go
@@ -283,6 +283,9 @@
 	if fx.Type == extensionFieldsType {
 		fieldOffset := offsetOf(fx)
 		mi.extensionMap = func(p pointer) *extensionMap {
+			if p.IsNil() {
+				return (*extensionMap)(nil)
+			}
 			v := p.Apply(fieldOffset).AsValueOf(extensionFieldsType)
 			return (*extensionMap)(v.Interface().(*map[int32]ExtensionField))
 		}
diff --git a/internal/impl/message_test.go b/internal/impl/message_test.go
index 722d1c0..fb89a2d 100644
--- a/internal/impl/message_test.go
+++ b/internal/impl/message_test.go
@@ -11,13 +11,15 @@
 	"strings"
 	"testing"
 
-	protoV1 "github.com/golang/protobuf/proto"
 	cmp "github.com/google/go-cmp/cmp"
 	cmpopts "github.com/google/go-cmp/cmp/cmpopts"
+	"google.golang.org/protobuf/encoding/prototext"
 	pimpl "google.golang.org/protobuf/internal/impl"
-	ptype "google.golang.org/protobuf/internal/prototype"
 	scalar "google.golang.org/protobuf/internal/scalar"
+	"google.golang.org/protobuf/proto"
+	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"
@@ -158,20 +160,30 @@
 	MyBytesA  *MyString  `protobuf:"22"`
 }
 
-func mustMakeEnumDesc(t ptype.StandaloneEnum) pref.EnumDescriptor {
-	ed, err := ptype.NewEnum(&t)
+func mustMakeEnumDesc(path string, syntax pref.Syntax, enumDesc string) pref.EnumDescriptor {
+	s := fmt.Sprintf(`name:%q syntax:%q enum_type:[{%s}]`, path, syntax, enumDesc)
+	pb := new(descriptorpb.FileDescriptorProto)
+	if err := prototext.Unmarshal([]byte(s), pb); err != nil {
+		panic(err)
+	}
+	fd, err := pdesc.NewFile(pb, nil)
 	if err != nil {
 		panic(err)
 	}
-	return ed
+	return fd.Enums().Get(0)
 }
 
-func mustMakeMessageDesc(t ptype.StandaloneMessage) pref.MessageDescriptor {
-	md, err := ptype.NewMessage(&t)
+func mustMakeMessageDesc(path string, syntax pref.Syntax, fileDesc, msgDesc string, r pdesc.Resolver) pref.MessageDescriptor {
+	s := fmt.Sprintf(`name:%q syntax:%q %s message_type:[{%s}]`, path, syntax, fileDesc, msgDesc)
+	pb := new(descriptorpb.FileDescriptorProto)
+	if err := prototext.Unmarshal([]byte(s), pb); err != nil {
+		panic(err)
+	}
+	fd, err := pdesc.NewFile(pb, r)
 	if err != nil {
 		panic(err)
 	}
-	return md
+	return fd.Messages().Get(0)
 }
 
 var V = pref.ValueOf
@@ -196,35 +208,34 @@
 )
 
 var scalarProto2Type = pimpl.MessageInfo{GoType: reflect.TypeOf(new(ScalarProto2)), PBType: &prototype.Message{
-	MessageDescriptor: mustMakeMessageDesc(ptype.StandaloneMessage{
-		Syntax:   pref.Proto2,
-		FullName: "ScalarProto2",
-		Fields: []ptype.Field{
-			{Name: "f1", Number: 1, Cardinality: pref.Optional, Kind: pref.BoolKind, Default: V(bool(true))},
-			{Name: "f2", Number: 2, Cardinality: pref.Optional, Kind: pref.Int32Kind, Default: V(int32(2))},
-			{Name: "f3", Number: 3, Cardinality: pref.Optional, Kind: pref.Int64Kind, Default: V(int64(3))},
-			{Name: "f4", Number: 4, Cardinality: pref.Optional, Kind: pref.Uint32Kind, Default: V(uint32(4))},
-			{Name: "f5", Number: 5, Cardinality: pref.Optional, Kind: pref.Uint64Kind, Default: V(uint64(5))},
-			{Name: "f6", Number: 6, Cardinality: pref.Optional, Kind: pref.FloatKind, Default: V(float32(6))},
-			{Name: "f7", Number: 7, Cardinality: pref.Optional, Kind: pref.DoubleKind, Default: V(float64(7))},
-			{Name: "f8", Number: 8, Cardinality: pref.Optional, Kind: pref.StringKind, Default: V(string("8"))},
-			{Name: "f9", Number: 9, Cardinality: pref.Optional, Kind: pref.StringKind, Default: V(string("9"))},
-			{Name: "f10", Number: 10, Cardinality: pref.Optional, Kind: pref.BytesKind, Default: V([]byte("10"))},
-			{Name: "f11", Number: 11, Cardinality: pref.Optional, Kind: pref.BytesKind, Default: V([]byte("11"))},
+	MessageDescriptor: mustMakeMessageDesc("scalar2.proto", pref.Proto2, "", `
+		name: "ScalarProto2"
+		field: [
+			{name:"f1"  number:1  label:LABEL_OPTIONAL type:TYPE_BOOL   default_value:"true"},
+			{name:"f2"  number:2  label:LABEL_OPTIONAL type:TYPE_INT32  default_value:"2"},
+			{name:"f3"  number:3  label:LABEL_OPTIONAL type:TYPE_INT64  default_value:"3"},
+			{name:"f4"  number:4  label:LABEL_OPTIONAL type:TYPE_UINT32 default_value:"4"},
+			{name:"f5"  number:5  label:LABEL_OPTIONAL type:TYPE_UINT64 default_value:"5"},
+			{name:"f6"  number:6  label:LABEL_OPTIONAL type:TYPE_FLOAT  default_value:"6"},
+			{name:"f7"  number:7  label:LABEL_OPTIONAL type:TYPE_DOUBLE default_value:"7"},
+			{name:"f8"  number:8  label:LABEL_OPTIONAL type:TYPE_STRING default_value:"8"},
+			{name:"f9"  number:9  label:LABEL_OPTIONAL type:TYPE_STRING default_value:"9"},
+			{name:"f10" number:10 label:LABEL_OPTIONAL type:TYPE_BYTES  default_value:"10"},
+			{name:"f11" number:11 label:LABEL_OPTIONAL type:TYPE_BYTES  default_value:"11"},
 
-			{Name: "f12", Number: 12, Cardinality: pref.Optional, Kind: pref.BoolKind, Default: V(bool(true))},
-			{Name: "f13", Number: 13, Cardinality: pref.Optional, Kind: pref.Int32Kind, Default: V(int32(13))},
-			{Name: "f14", Number: 14, Cardinality: pref.Optional, Kind: pref.Int64Kind, Default: V(int64(14))},
-			{Name: "f15", Number: 15, Cardinality: pref.Optional, Kind: pref.Uint32Kind, Default: V(uint32(15))},
-			{Name: "f16", Number: 16, Cardinality: pref.Optional, Kind: pref.Uint64Kind, Default: V(uint64(16))},
-			{Name: "f17", Number: 17, Cardinality: pref.Optional, Kind: pref.FloatKind, Default: V(float32(17))},
-			{Name: "f18", Number: 18, Cardinality: pref.Optional, Kind: pref.DoubleKind, Default: V(float64(18))},
-			{Name: "f19", Number: 19, Cardinality: pref.Optional, Kind: pref.StringKind, Default: V(string("19"))},
-			{Name: "f20", Number: 20, Cardinality: pref.Optional, Kind: pref.StringKind, Default: V(string("20"))},
-			{Name: "f21", Number: 21, Cardinality: pref.Optional, Kind: pref.BytesKind, Default: V([]byte("21"))},
-			{Name: "f22", Number: 22, Cardinality: pref.Optional, Kind: pref.BytesKind, Default: V([]byte("22"))},
-		},
-	}),
+			{name:"f12" number:12 label:LABEL_OPTIONAL type:TYPE_BOOL   default_value:"true"},
+			{name:"f13" number:13 label:LABEL_OPTIONAL type:TYPE_INT32  default_value:"13"},
+			{name:"f14" number:14 label:LABEL_OPTIONAL type:TYPE_INT64  default_value:"14"},
+			{name:"f15" number:15 label:LABEL_OPTIONAL type:TYPE_UINT32 default_value:"15"},
+			{name:"f16" number:16 label:LABEL_OPTIONAL type:TYPE_UINT64 default_value:"16"},
+			{name:"f17" number:17 label:LABEL_OPTIONAL type:TYPE_FLOAT  default_value:"17"},
+			{name:"f18" number:18 label:LABEL_OPTIONAL type:TYPE_DOUBLE default_value:"18"},
+			{name:"f19" number:19 label:LABEL_OPTIONAL type:TYPE_STRING default_value:"19"},
+			{name:"f20" number:20 label:LABEL_OPTIONAL type:TYPE_STRING default_value:"20"},
+			{name:"f21" number:21 label:LABEL_OPTIONAL type:TYPE_BYTES  default_value:"21"},
+			{name:"f22" number:22 label:LABEL_OPTIONAL type:TYPE_BYTES  default_value:"22"}
+		]
+	`, nil),
 	NewMessage: func() pref.Message {
 		return pref.ProtoMessage(new(ScalarProto2)).ProtoReflect()
 	},
@@ -298,35 +309,34 @@
 }
 
 var scalarProto3Type = pimpl.MessageInfo{GoType: reflect.TypeOf(new(ScalarProto3)), PBType: &prototype.Message{
-	MessageDescriptor: mustMakeMessageDesc(ptype.StandaloneMessage{
-		Syntax:   pref.Proto3,
-		FullName: "ScalarProto3",
-		Fields: []ptype.Field{
-			{Name: "f1", Number: 1, Cardinality: pref.Optional, Kind: pref.BoolKind},
-			{Name: "f2", Number: 2, Cardinality: pref.Optional, Kind: pref.Int32Kind},
-			{Name: "f3", Number: 3, Cardinality: pref.Optional, Kind: pref.Int64Kind},
-			{Name: "f4", Number: 4, Cardinality: pref.Optional, Kind: pref.Uint32Kind},
-			{Name: "f5", Number: 5, Cardinality: pref.Optional, Kind: pref.Uint64Kind},
-			{Name: "f6", Number: 6, Cardinality: pref.Optional, Kind: pref.FloatKind},
-			{Name: "f7", Number: 7, Cardinality: pref.Optional, Kind: pref.DoubleKind},
-			{Name: "f8", Number: 8, Cardinality: pref.Optional, Kind: pref.StringKind},
-			{Name: "f9", Number: 9, Cardinality: pref.Optional, Kind: pref.StringKind},
-			{Name: "f10", Number: 10, Cardinality: pref.Optional, Kind: pref.BytesKind},
-			{Name: "f11", Number: 11, Cardinality: pref.Optional, Kind: pref.BytesKind},
+	MessageDescriptor: mustMakeMessageDesc("scalar3.proto", pref.Proto3, "", `
+		name: "ScalarProto3"
+		field: [
+			{name:"f1"  number:1  label:LABEL_OPTIONAL type:TYPE_BOOL},
+			{name:"f2"  number:2  label:LABEL_OPTIONAL type:TYPE_INT32},
+			{name:"f3"  number:3  label:LABEL_OPTIONAL type:TYPE_INT64},
+			{name:"f4"  number:4  label:LABEL_OPTIONAL type:TYPE_UINT32},
+			{name:"f5"  number:5  label:LABEL_OPTIONAL type:TYPE_UINT64},
+			{name:"f6"  number:6  label:LABEL_OPTIONAL type:TYPE_FLOAT},
+			{name:"f7"  number:7  label:LABEL_OPTIONAL type:TYPE_DOUBLE},
+			{name:"f8"  number:8  label:LABEL_OPTIONAL type:TYPE_STRING},
+			{name:"f9"  number:9  label:LABEL_OPTIONAL type:TYPE_STRING},
+			{name:"f10" number:10 label:LABEL_OPTIONAL type:TYPE_BYTES},
+			{name:"f11" number:11 label:LABEL_OPTIONAL type:TYPE_BYTES},
 
-			{Name: "f12", Number: 12, Cardinality: pref.Optional, Kind: pref.BoolKind},
-			{Name: "f13", Number: 13, Cardinality: pref.Optional, Kind: pref.Int32Kind},
-			{Name: "f14", Number: 14, Cardinality: pref.Optional, Kind: pref.Int64Kind},
-			{Name: "f15", Number: 15, Cardinality: pref.Optional, Kind: pref.Uint32Kind},
-			{Name: "f16", Number: 16, Cardinality: pref.Optional, Kind: pref.Uint64Kind},
-			{Name: "f17", Number: 17, Cardinality: pref.Optional, Kind: pref.FloatKind},
-			{Name: "f18", Number: 18, Cardinality: pref.Optional, Kind: pref.DoubleKind},
-			{Name: "f19", Number: 19, Cardinality: pref.Optional, Kind: pref.StringKind},
-			{Name: "f20", Number: 20, Cardinality: pref.Optional, Kind: pref.StringKind},
-			{Name: "f21", Number: 21, Cardinality: pref.Optional, Kind: pref.BytesKind},
-			{Name: "f22", Number: 22, Cardinality: pref.Optional, Kind: pref.BytesKind},
-		},
-	}),
+			{name:"f12" number:12 label:LABEL_OPTIONAL type:TYPE_BOOL},
+			{name:"f13" number:13 label:LABEL_OPTIONAL type:TYPE_INT32},
+			{name:"f14" number:14 label:LABEL_OPTIONAL type:TYPE_INT64},
+			{name:"f15" number:15 label:LABEL_OPTIONAL type:TYPE_UINT32},
+			{name:"f16" number:16 label:LABEL_OPTIONAL type:TYPE_UINT64},
+			{name:"f17" number:17 label:LABEL_OPTIONAL type:TYPE_FLOAT},
+			{name:"f18" number:18 label:LABEL_OPTIONAL type:TYPE_DOUBLE},
+			{name:"f19" number:19 label:LABEL_OPTIONAL type:TYPE_STRING},
+			{name:"f20" number:20 label:LABEL_OPTIONAL type:TYPE_STRING},
+			{name:"f21" number:21 label:LABEL_OPTIONAL type:TYPE_BYTES},
+			{name:"f22" number:22 label:LABEL_OPTIONAL type:TYPE_BYTES}
+		]
+	`, nil),
 	NewMessage: func() pref.Message {
 		return pref.ProtoMessage(new(ScalarProto3)).ProtoReflect()
 	},
@@ -418,33 +428,32 @@
 }
 
 var listScalarsType = pimpl.MessageInfo{GoType: reflect.TypeOf(new(ListScalars)), PBType: &prototype.Message{
-	MessageDescriptor: mustMakeMessageDesc(ptype.StandaloneMessage{
-		Syntax:   pref.Proto2,
-		FullName: "ListScalars",
-		Fields: []ptype.Field{
-			{Name: "f1", Number: 1, Cardinality: pref.Repeated, Kind: pref.BoolKind},
-			{Name: "f2", Number: 2, Cardinality: pref.Repeated, Kind: pref.Int32Kind},
-			{Name: "f3", Number: 3, Cardinality: pref.Repeated, Kind: pref.Int64Kind},
-			{Name: "f4", Number: 4, Cardinality: pref.Repeated, Kind: pref.Uint32Kind},
-			{Name: "f5", Number: 5, Cardinality: pref.Repeated, Kind: pref.Uint64Kind},
-			{Name: "f6", Number: 6, Cardinality: pref.Repeated, Kind: pref.FloatKind},
-			{Name: "f7", Number: 7, Cardinality: pref.Repeated, Kind: pref.DoubleKind},
-			{Name: "f8", Number: 8, Cardinality: pref.Repeated, Kind: pref.StringKind},
-			{Name: "f9", Number: 9, Cardinality: pref.Repeated, Kind: pref.StringKind},
-			{Name: "f10", Number: 10, Cardinality: pref.Repeated, Kind: pref.BytesKind},
-			{Name: "f11", Number: 11, Cardinality: pref.Repeated, Kind: pref.BytesKind},
+	MessageDescriptor: mustMakeMessageDesc("list-scalars.proto", pref.Proto2, "", `
+		name: "ListScalars"
+		field: [
+			{name:"f1"  number:1  label:LABEL_REPEATED type:TYPE_BOOL},
+			{name:"f2"  number:2  label:LABEL_REPEATED type:TYPE_INT32},
+			{name:"f3"  number:3  label:LABEL_REPEATED type:TYPE_INT64},
+			{name:"f4"  number:4  label:LABEL_REPEATED type:TYPE_UINT32},
+			{name:"f5"  number:5  label:LABEL_REPEATED type:TYPE_UINT64},
+			{name:"f6"  number:6  label:LABEL_REPEATED type:TYPE_FLOAT},
+			{name:"f7"  number:7  label:LABEL_REPEATED type:TYPE_DOUBLE},
+			{name:"f8"  number:8  label:LABEL_REPEATED type:TYPE_STRING},
+			{name:"f9"  number:9  label:LABEL_REPEATED type:TYPE_STRING},
+			{name:"f10" number:10 label:LABEL_REPEATED type:TYPE_BYTES},
+			{name:"f11" number:11 label:LABEL_REPEATED type:TYPE_BYTES},
 
-			{Name: "f12", Number: 12, Cardinality: pref.Repeated, Kind: pref.StringKind},
-			{Name: "f13", Number: 13, Cardinality: pref.Repeated, Kind: pref.StringKind},
-			{Name: "f14", Number: 14, Cardinality: pref.Repeated, Kind: pref.BytesKind},
-			{Name: "f15", Number: 15, Cardinality: pref.Repeated, Kind: pref.BytesKind},
+			{name:"f12" number:12 label:LABEL_REPEATED type:TYPE_STRING},
+			{name:"f13" number:13 label:LABEL_REPEATED type:TYPE_STRING},
+			{name:"f14" number:14 label:LABEL_REPEATED type:TYPE_BYTES},
+			{name:"f15" number:15 label:LABEL_REPEATED type:TYPE_BYTES},
 
-			{Name: "f16", Number: 16, Cardinality: pref.Repeated, Kind: pref.StringKind},
-			{Name: "f17", Number: 17, Cardinality: pref.Repeated, Kind: pref.StringKind},
-			{Name: "f18", Number: 18, Cardinality: pref.Repeated, Kind: pref.BytesKind},
-			{Name: "f19", Number: 19, Cardinality: pref.Repeated, Kind: pref.BytesKind},
-		},
-	}),
+			{name:"f16" number:16 label:LABEL_REPEATED type:TYPE_STRING},
+			{name:"f17" number:17 label:LABEL_REPEATED type:TYPE_STRING},
+			{name:"f18" number:18 label:LABEL_REPEATED type:TYPE_BYTES},
+			{name:"f19" number:19 label:LABEL_REPEATED type:TYPE_BYTES}
+		]
+	`, nil),
 	NewMessage: func() pref.Message {
 		return pref.ProtoMessage(new(ListScalars)).ProtoReflect()
 	},
@@ -575,60 +584,70 @@
 	MyBytes4   MapStrings `protobuf:"25"`
 }
 
-func mustMakeMapEntry(n pref.FieldNumber, keyKind, valKind pref.Kind) ptype.Field {
-	return ptype.Field{
-		Name:        pref.Name(fmt.Sprintf("f%d", n)),
-		Number:      n,
-		Cardinality: pref.Repeated,
-		Kind:        pref.MessageKind,
-		MessageType: mustMakeMessageDesc(ptype.StandaloneMessage{
-			Syntax:   pref.Proto2,
-			FullName: pref.FullName(fmt.Sprintf("MapScalars.F%dEntry", n)),
-			Fields: []ptype.Field{
-				{Name: "key", Number: 1, Cardinality: pref.Optional, Kind: keyKind},
-				{Name: "value", Number: 2, Cardinality: pref.Optional, Kind: valKind},
-			},
-			Options:    &descriptorpb.MessageOptions{MapEntry: scalar.Bool(true)},
-			IsMapEntry: true,
-		}),
-	}
-}
-
 var mapScalarsType = pimpl.MessageInfo{GoType: reflect.TypeOf(new(MapScalars)), PBType: &prototype.Message{
-	MessageDescriptor: mustMakeMessageDesc(ptype.StandaloneMessage{
-		Syntax:   pref.Proto2,
-		FullName: "MapScalars",
-		Fields: []ptype.Field{
-			mustMakeMapEntry(1, pref.BoolKind, pref.StringKind),
-			mustMakeMapEntry(2, pref.Int32Kind, pref.StringKind),
-			mustMakeMapEntry(3, pref.Int64Kind, pref.StringKind),
-			mustMakeMapEntry(4, pref.Uint32Kind, pref.StringKind),
-			mustMakeMapEntry(5, pref.Uint64Kind, pref.StringKind),
-			mustMakeMapEntry(6, pref.StringKind, pref.StringKind),
+	MessageDescriptor: mustMakeMessageDesc("map-scalars.proto", pref.Proto2, "", `
+		name: "MapScalars"
+		field: [
+			{name:"f1"  number:1  label:LABEL_REPEATED type:TYPE_MESSAGE type_name:".MapScalars.F1Entry"},
+			{name:"f2"  number:2  label:LABEL_REPEATED type:TYPE_MESSAGE type_name:".MapScalars.F2Entry"},
+			{name:"f3"  number:3  label:LABEL_REPEATED type:TYPE_MESSAGE type_name:".MapScalars.F3Entry"},
+			{name:"f4"  number:4  label:LABEL_REPEATED type:TYPE_MESSAGE type_name:".MapScalars.F4Entry"},
+			{name:"f5"  number:5  label:LABEL_REPEATED type:TYPE_MESSAGE type_name:".MapScalars.F5Entry"},
+			{name:"f6"  number:6  label:LABEL_REPEATED type:TYPE_MESSAGE type_name:".MapScalars.F6Entry"},
 
-			mustMakeMapEntry(7, pref.StringKind, pref.BoolKind),
-			mustMakeMapEntry(8, pref.StringKind, pref.Int32Kind),
-			mustMakeMapEntry(9, pref.StringKind, pref.Int64Kind),
-			mustMakeMapEntry(10, pref.StringKind, pref.Uint32Kind),
-			mustMakeMapEntry(11, pref.StringKind, pref.Uint64Kind),
-			mustMakeMapEntry(12, pref.StringKind, pref.FloatKind),
-			mustMakeMapEntry(13, pref.StringKind, pref.DoubleKind),
-			mustMakeMapEntry(14, pref.StringKind, pref.StringKind),
-			mustMakeMapEntry(15, pref.StringKind, pref.StringKind),
-			mustMakeMapEntry(16, pref.StringKind, pref.BytesKind),
-			mustMakeMapEntry(17, pref.StringKind, pref.BytesKind),
+			{name:"f7"  number:7  label:LABEL_REPEATED type:TYPE_MESSAGE type_name:".MapScalars.F7Entry"},
+			{name:"f8"  number:8  label:LABEL_REPEATED type:TYPE_MESSAGE type_name:".MapScalars.F8Entry"},
+			{name:"f9"  number:9  label:LABEL_REPEATED type:TYPE_MESSAGE type_name:".MapScalars.F9Entry"},
+			{name:"f10" number:10 label:LABEL_REPEATED type:TYPE_MESSAGE type_name:".MapScalars.F10Entry"},
+			{name:"f11" number:11 label:LABEL_REPEATED type:TYPE_MESSAGE type_name:".MapScalars.F11Entry"},
+			{name:"f12" number:12 label:LABEL_REPEATED type:TYPE_MESSAGE type_name:".MapScalars.F12Entry"},
+			{name:"f13" number:13 label:LABEL_REPEATED type:TYPE_MESSAGE type_name:".MapScalars.F13Entry"},
+			{name:"f14" number:14 label:LABEL_REPEATED type:TYPE_MESSAGE type_name:".MapScalars.F14Entry"},
+			{name:"f15" number:15 label:LABEL_REPEATED type:TYPE_MESSAGE type_name:".MapScalars.F15Entry"},
+			{name:"f16" number:16 label:LABEL_REPEATED type:TYPE_MESSAGE type_name:".MapScalars.F16Entry"},
+			{name:"f17" number:17 label:LABEL_REPEATED type:TYPE_MESSAGE type_name:".MapScalars.F17Entry"},
 
-			mustMakeMapEntry(18, pref.StringKind, pref.StringKind),
-			mustMakeMapEntry(19, pref.StringKind, pref.StringKind),
-			mustMakeMapEntry(20, pref.StringKind, pref.BytesKind),
-			mustMakeMapEntry(21, pref.StringKind, pref.BytesKind),
+			{name:"f18" number:18 label:LABEL_REPEATED type:TYPE_MESSAGE type_name:".MapScalars.F18Entry"},
+			{name:"f19" number:19 label:LABEL_REPEATED type:TYPE_MESSAGE type_name:".MapScalars.F19Entry"},
+			{name:"f20" number:20 label:LABEL_REPEATED type:TYPE_MESSAGE type_name:".MapScalars.F20Entry"},
+			{name:"f21" number:21 label:LABEL_REPEATED type:TYPE_MESSAGE type_name:".MapScalars.F21Entry"},
 
-			mustMakeMapEntry(22, pref.StringKind, pref.StringKind),
-			mustMakeMapEntry(23, pref.StringKind, pref.StringKind),
-			mustMakeMapEntry(24, pref.StringKind, pref.BytesKind),
-			mustMakeMapEntry(25, pref.StringKind, pref.BytesKind),
-		},
-	}),
+			{name:"f22" number:22 label:LABEL_REPEATED type:TYPE_MESSAGE type_name:".MapScalars.F22Entry"},
+			{name:"f23" number:23 label:LABEL_REPEATED type:TYPE_MESSAGE type_name:".MapScalars.F23Entry"},
+			{name:"f24" number:24 label:LABEL_REPEATED type:TYPE_MESSAGE type_name:".MapScalars.F24Entry"},
+			{name:"f25" number:25 label:LABEL_REPEATED type:TYPE_MESSAGE type_name:".MapScalars.F25Entry"}
+		]
+		nested_type: [
+			{name:"F1Entry"  field:[{name:"key" number:1 label:LABEL_OPTIONAL type:TYPE_BOOL},   {name:"value" number:2 label:LABEL_OPTIONAL type:TYPE_STRING}] options:{map_entry:true}},
+			{name:"F2Entry"  field:[{name:"key" number:1 label:LABEL_OPTIONAL type:TYPE_INT32},  {name:"value" number:2 label:LABEL_OPTIONAL type:TYPE_STRING}] options:{map_entry:true}},
+			{name:"F3Entry"  field:[{name:"key" number:1 label:LABEL_OPTIONAL type:TYPE_INT64},  {name:"value" number:2 label:LABEL_OPTIONAL type:TYPE_STRING}] options:{map_entry:true}},
+			{name:"F4Entry"  field:[{name:"key" number:1 label:LABEL_OPTIONAL type:TYPE_UINT32}, {name:"value" number:2 label:LABEL_OPTIONAL type:TYPE_STRING}] options:{map_entry:true}},
+			{name:"F5Entry"  field:[{name:"key" number:1 label:LABEL_OPTIONAL type:TYPE_UINT64}, {name:"value" number:2 label:LABEL_OPTIONAL type:TYPE_STRING}] options:{map_entry:true}},
+			{name:"F6Entry"  field:[{name:"key" number:1 label:LABEL_OPTIONAL type:TYPE_STRING}, {name:"value" number:2 label:LABEL_OPTIONAL type:TYPE_STRING}] options:{map_entry:true}},
+
+			{name:"F7Entry"  field:[{name:"key" number:1 label:LABEL_OPTIONAL type:TYPE_STRING}, {name:"value" number:2 label:LABEL_OPTIONAL type:TYPE_BOOL}]   options:{map_entry:true}},
+			{name:"F8Entry"  field:[{name:"key" number:1 label:LABEL_OPTIONAL type:TYPE_STRING}, {name:"value" number:2 label:LABEL_OPTIONAL type:TYPE_INT32}]  options:{map_entry:true}},
+			{name:"F9Entry"  field:[{name:"key" number:1 label:LABEL_OPTIONAL type:TYPE_STRING}, {name:"value" number:2 label:LABEL_OPTIONAL type:TYPE_INT64}]  options:{map_entry:true}},
+			{name:"F10Entry" field:[{name:"key" number:1 label:LABEL_OPTIONAL type:TYPE_STRING}, {name:"value" number:2 label:LABEL_OPTIONAL type:TYPE_UINT32}] options:{map_entry:true}},
+			{name:"F11Entry" field:[{name:"key" number:1 label:LABEL_OPTIONAL type:TYPE_STRING}, {name:"value" number:2 label:LABEL_OPTIONAL type:TYPE_UINT64}] options:{map_entry:true}},
+			{name:"F12Entry" field:[{name:"key" number:1 label:LABEL_OPTIONAL type:TYPE_STRING}, {name:"value" number:2 label:LABEL_OPTIONAL type:TYPE_FLOAT}]  options:{map_entry:true}},
+			{name:"F13Entry" field:[{name:"key" number:1 label:LABEL_OPTIONAL type:TYPE_STRING}, {name:"value" number:2 label:LABEL_OPTIONAL type:TYPE_DOUBLE}] options:{map_entry:true}},
+			{name:"F14Entry" field:[{name:"key" number:1 label:LABEL_OPTIONAL type:TYPE_STRING}, {name:"value" number:2 label:LABEL_OPTIONAL type:TYPE_STRING}] options:{map_entry:true}},
+			{name:"F15Entry" field:[{name:"key" number:1 label:LABEL_OPTIONAL type:TYPE_STRING}, {name:"value" number:2 label:LABEL_OPTIONAL type:TYPE_STRING}] options:{map_entry:true}},
+			{name:"F16Entry" 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}},
+			{name:"F17Entry" 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}},
+
+			{name:"F18Entry" field:[{name:"key" number:1 label:LABEL_OPTIONAL type:TYPE_STRING}, {name:"value" number:2 label:LABEL_OPTIONAL type:TYPE_STRING}] options:{map_entry:true}},
+			{name:"F19Entry" field:[{name:"key" number:1 label:LABEL_OPTIONAL type:TYPE_STRING}, {name:"value" number:2 label:LABEL_OPTIONAL type:TYPE_STRING}] options:{map_entry:true}},
+			{name:"F20Entry" 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}},
+			{name:"F21Entry" 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}},
+
+			{name:"F22Entry" field:[{name:"key" number:1 label:LABEL_OPTIONAL type:TYPE_STRING}, {name:"value" number:2 label:LABEL_OPTIONAL type:TYPE_STRING}] options:{map_entry:true}},
+			{name:"F23Entry" field:[{name:"key" number:1 label:LABEL_OPTIONAL type:TYPE_STRING}, {name:"value" number:2 label:LABEL_OPTIONAL type:TYPE_STRING}] options:{map_entry:true}},
+			{name:"F24Entry" 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}},
+			{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()
 	},
@@ -760,26 +779,25 @@
 }
 
 var oneofScalarsType = pimpl.MessageInfo{GoType: reflect.TypeOf(new(OneofScalars)), PBType: &prototype.Message{
-	MessageDescriptor: mustMakeMessageDesc(ptype.StandaloneMessage{
-		Syntax:   pref.Proto2,
-		FullName: "OneofScalars",
-		Fields: []ptype.Field{
-			{Name: "f1", Number: 1, Cardinality: pref.Optional, Kind: pref.BoolKind, Default: V(bool(true)), OneofName: "union"},
-			{Name: "f2", Number: 2, Cardinality: pref.Optional, Kind: pref.Int32Kind, Default: V(int32(2)), OneofName: "union"},
-			{Name: "f3", Number: 3, Cardinality: pref.Optional, Kind: pref.Int64Kind, Default: V(int64(3)), OneofName: "union"},
-			{Name: "f4", Number: 4, Cardinality: pref.Optional, Kind: pref.Uint32Kind, Default: V(uint32(4)), OneofName: "union"},
-			{Name: "f5", Number: 5, Cardinality: pref.Optional, Kind: pref.Uint64Kind, Default: V(uint64(5)), OneofName: "union"},
-			{Name: "f6", Number: 6, Cardinality: pref.Optional, Kind: pref.FloatKind, Default: V(float32(6)), OneofName: "union"},
-			{Name: "f7", Number: 7, Cardinality: pref.Optional, Kind: pref.DoubleKind, Default: V(float64(7)), OneofName: "union"},
-			{Name: "f8", Number: 8, Cardinality: pref.Optional, Kind: pref.StringKind, Default: V(string("8")), OneofName: "union"},
-			{Name: "f9", Number: 9, Cardinality: pref.Optional, Kind: pref.StringKind, Default: V(string("9")), OneofName: "union"},
-			{Name: "f10", Number: 10, Cardinality: pref.Optional, Kind: pref.StringKind, Default: V(string("10")), OneofName: "union"},
-			{Name: "f11", Number: 11, Cardinality: pref.Optional, Kind: pref.BytesKind, Default: V([]byte("11")), OneofName: "union"},
-			{Name: "f12", Number: 12, Cardinality: pref.Optional, Kind: pref.BytesKind, Default: V([]byte("12")), OneofName: "union"},
-			{Name: "f13", Number: 13, Cardinality: pref.Optional, Kind: pref.BytesKind, Default: V([]byte("13")), OneofName: "union"},
-		},
-		Oneofs: []ptype.Oneof{{Name: "union"}},
-	}),
+	MessageDescriptor: 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},
+			{name:"f2"  number:2  label:LABEL_OPTIONAL type:TYPE_INT32  default_value:"2"    oneof_index:0},
+			{name:"f3"  number:3  label:LABEL_OPTIONAL type:TYPE_INT64  default_value:"3"    oneof_index:0},
+			{name:"f4"  number:4  label:LABEL_OPTIONAL type:TYPE_UINT32 default_value:"4"    oneof_index:0},
+			{name:"f5"  number:5  label:LABEL_OPTIONAL type:TYPE_UINT64 default_value:"5"    oneof_index:0},
+			{name:"f6"  number:6  label:LABEL_OPTIONAL type:TYPE_FLOAT  default_value:"6"    oneof_index:0},
+			{name:"f7"  number:7  label:LABEL_OPTIONAL type:TYPE_DOUBLE default_value:"7"    oneof_index:0},
+			{name:"f8"  number:8  label:LABEL_OPTIONAL type:TYPE_STRING default_value:"8"    oneof_index:0},
+			{name:"f9"  number:9  label:LABEL_OPTIONAL type:TYPE_STRING default_value:"9"    oneof_index:0},
+			{name:"f10" number:10 label:LABEL_OPTIONAL type:TYPE_STRING default_value:"10"   oneof_index:0},
+			{name:"f11" number:11 label:LABEL_OPTIONAL type:TYPE_BYTES  default_value:"11"   oneof_index:0},
+			{name:"f12" number:12 label:LABEL_OPTIONAL type:TYPE_BYTES  default_value:"12"   oneof_index:0},
+			{name:"f13" number:13 label:LABEL_OPTIONAL type:TYPE_BYTES  default_value:"13"   oneof_index:0}
+		]
+		oneof_decl: [{name:"union"}]
+	`, nil),
 	NewMessage: func() pref.Message {
 		return pref.ProtoMessage(new(OneofScalars)).ProtoReflect()
 	},
@@ -923,11 +941,10 @@
 type EnumProto2 int32
 
 var enumProto2Type = &prototype.Enum{
-	EnumDescriptor: mustMakeEnumDesc(ptype.StandaloneEnum{
-		Syntax:   pref.Proto2,
-		FullName: "EnumProto2",
-		Values:   []ptype.EnumValue{{Name: "DEAD", Number: 0xdead}, {Name: "BEEF", Number: 0xbeef}},
-	}),
+	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)
 	},
@@ -940,11 +957,10 @@
 type EnumProto3 int32
 
 var enumProto3Type = &prototype.Enum{
-	EnumDescriptor: mustMakeEnumDesc(ptype.StandaloneEnum{
-		Syntax:   pref.Proto3,
-		FullName: "EnumProto3",
-		Values:   []ptype.EnumValue{{Name: "ALPHA", Number: 0}, {Name: "BRAVO", Number: 1}},
-	}),
+	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)
 	},
@@ -967,52 +983,41 @@
 }
 
 var enumMessagesType = pimpl.MessageInfo{GoType: reflect.TypeOf(new(EnumMessages)), PBType: &prototype.Message{
-	MessageDescriptor: mustMakeMessageDesc(ptype.StandaloneMessage{
-		Syntax:   pref.Proto2,
-		FullName: "EnumMessages",
-		Fields: []ptype.Field{
-			{Name: "f1", Number: 1, Cardinality: pref.Optional, Kind: pref.EnumKind, Default: V("BEEF"), EnumType: enumProto2Type.Descriptor()},
-			{Name: "f2", Number: 2, Cardinality: pref.Optional, Kind: pref.EnumKind, Default: V("BRAVO"), EnumType: enumProto3Type.Descriptor()},
-			{Name: "f3", Number: 3, Cardinality: pref.Optional, Kind: pref.MessageKind, MessageType: pimpl.Export{}.MessageDescriptorOf(new(proto2_20180125.Message))},
-			{Name: "f4", Number: 4, Cardinality: pref.Optional, Kind: pref.MessageKind, MessageType: ptype.PlaceholderMessage("EnumMessages")},
-			{Name: "f5", Number: 5, Cardinality: pref.Repeated, Kind: pref.EnumKind, EnumType: enumProto2Type.Descriptor()},
-			{Name: "f6", Number: 6, Cardinality: pref.Repeated, Kind: pref.MessageKind, MessageType: scalarProto2Type.PBType.Descriptor()},
-			{Name: "f7", Number: 7, Cardinality: pref.Repeated, Kind: pref.MessageKind, MessageType: enumMapDesc},
-			{Name: "f8", Number: 8, Cardinality: pref.Repeated, Kind: pref.MessageKind, MessageType: messageMapDesc},
-			{Name: "f9", Number: 9, Cardinality: pref.Optional, Kind: pref.EnumKind, Default: V("BEEF"), OneofName: "union", EnumType: enumProto2Type.Descriptor()},
-			{Name: "f10", Number: 10, Cardinality: pref.Optional, Kind: pref.EnumKind, Default: V("BRAVO"), OneofName: "union", EnumType: enumProto3Type.Descriptor()},
-			{Name: "f11", Number: 11, Cardinality: pref.Optional, Kind: pref.MessageKind, OneofName: "union", MessageType: scalarProto2Type.PBType.Descriptor()},
-			{Name: "f12", Number: 12, Cardinality: pref.Optional, Kind: pref.MessageKind, OneofName: "union", MessageType: scalarProto3Type.PBType.Descriptor()},
-		},
-		Oneofs: []ptype.Oneof{{Name: "union"}},
-	}),
+	MessageDescriptor: 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"
+		field: [
+			{name:"f1"  number:1  label:LABEL_OPTIONAL type:TYPE_ENUM    type_name:".EnumProto2" default_value:"BEEF"},
+			{name:"f2"  number:2  label:LABEL_OPTIONAL type:TYPE_ENUM    type_name:".EnumProto3" default_value:"BRAVO"},
+			{name:"f3"  number:3  label:LABEL_OPTIONAL type:TYPE_MESSAGE type_Name:".google.golang.org.proto2_20180125.Message"},
+			{name:"f4"  number:4  label:LABEL_OPTIONAL type:TYPE_MESSAGE type_Name:".EnumMessages"},
+			{name:"f5"  number:5  label:LABEL_REPEATED type:TYPE_ENUM    type_name:".EnumProto2"},
+			{name:"f6"  number:6  label:LABEL_REPEATED type:TYPE_MESSAGE type_name:".ScalarProto2"},
+			{name:"f7"  number:7  label:LABEL_REPEATED type:TYPE_MESSAGE type_name:".EnumMessages.F7Entry"},
+			{name:"f8"  number:8  label:LABEL_REPEATED type:TYPE_MESSAGE type_name:".EnumMessages.F8Entry"},
+			{name:"f9"  number:9  label:LABEL_OPTIONAL type:TYPE_ENUM    type_name:".EnumProto2"   oneof_index:0 default_value:"BEEF"},
+			{name:"f10" number:10 label:LABEL_OPTIONAL type:TYPE_ENUM    type_name:".EnumProto3"   oneof_index:0 default_value:"BRAVO"},
+			{name:"f11" number:11 label:LABEL_OPTIONAL type:TYPE_MESSAGE type_name:".ScalarProto2" oneof_index:0},
+			{name:"f12" number:12 label:LABEL_OPTIONAL type:TYPE_MESSAGE type_name:".ScalarProto3" oneof_index:0}
+		]
+		oneof_decl: [{name:"union"}]
+		nested_type: [
+			{name:"F7Entry" field:[{name:"key" number:1 label:LABEL_OPTIONAL type:TYPE_STRING}, {name:"value" number:2 label:LABEL_OPTIONAL type:TYPE_ENUM    type_name:".EnumProto3"}]   options:{map_entry:true}},
+			{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()
 	},
 }}
 
-var enumMapDesc = mustMakeMessageDesc(ptype.StandaloneMessage{
-	Syntax:   pref.Proto2,
-	FullName: "EnumMessages.F7Entry",
-	Fields: []ptype.Field{
-		{Name: "key", Number: 1, Cardinality: pref.Optional, Kind: pref.StringKind},
-		{Name: "value", Number: 2, Cardinality: pref.Optional, Kind: pref.EnumKind, EnumType: enumProto3Type.Descriptor()},
-	},
-	Options:    &descriptorpb.MessageOptions{MapEntry: scalar.Bool(true)},
-	IsMapEntry: true,
-})
-
-var messageMapDesc = mustMakeMessageDesc(ptype.StandaloneMessage{
-	Syntax:   pref.Proto2,
-	FullName: "EnumMessages.F8Entry",
-	Fields: []ptype.Field{
-		{Name: "key", Number: 1, Cardinality: pref.Optional, Kind: pref.StringKind},
-		{Name: "value", Number: 2, Cardinality: pref.Optional, Kind: pref.MessageKind, MessageType: scalarProto3Type.PBType.Descriptor()},
-	},
-	Options:    &descriptorpb.MessageOptions{MapEntry: scalar.Bool(true)},
-	IsMapEntry: true,
-})
-
 func (m *EnumMessages) ProtoReflect() pref.Message { return enumMessagesType.MessageOf(m) }
 
 func (*EnumMessages) XXX_OneofWrappers() []interface{} {
@@ -1161,7 +1166,9 @@
 
 var cmpOpts = cmp.Options{
 	cmp.Comparer(func(x, y *proto2_20180125.Message) bool {
-		return protoV1.Equal(x, y)
+		mx := pimpl.Export{}.MessageOf(x).Interface()
+		my := pimpl.Export{}.MessageOf(y).Interface()
+		return proto.Equal(mx, my)
 	}),
 	cmp.Transformer("UnwrapValue", func(pv pref.Value) interface{} {
 		switch v := pv.Interface().(type) {
diff --git a/internal/prototype/desc_test.go b/internal/prototype/desc_test.go
deleted file mode 100644
index 05b2e1d..0000000
--- a/internal/prototype/desc_test.go
+++ /dev/null
@@ -1,61 +0,0 @@
-// Copyright 2018 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
-
-import (
-	"reflect"
-	"testing"
-
-	pref "google.golang.org/protobuf/reflect/protoreflect"
-)
-
-// TestDescriptors tests that the implementations do not declare additional
-// methods that do not exist on the interface types.
-func TestDescriptors(t *testing.T) {
-	tests := []interface{}{
-		[]pref.FileDescriptor{placeholderFile{}, fileDesc{}},
-		[]pref.MessageDescriptor{placeholderMessage{}, standaloneMessage{}, messageDesc{}},
-		[]pref.FieldDescriptor{standaloneExtension{}, fieldDesc{}, extensionDesc{}},
-		[]pref.OneofDescriptor{oneofDesc{}},
-		[]pref.EnumDescriptor{placeholderEnum{}, standaloneEnum{}, enumDesc{}},
-		[]pref.EnumValueDescriptor{enumValueDesc{}},
-		[]pref.ServiceDescriptor{serviceDesc{}},
-		[]pref.MethodDescriptor{methodDesc{}},
-
-		[]pref.FileImports{(*fileImports)(nil)},
-		[]pref.MessageDescriptors{(*messages)(nil)},
-		[]pref.Names{(*names)(nil)},
-		[]pref.FieldNumbers{(*numbers)(nil)},
-		[]pref.FieldRanges{(*fieldRanges)(nil)},
-		[]pref.FieldDescriptors{(*fields)(nil), (*oneofFields)(nil)},
-		[]pref.OneofDescriptors{(*oneofs)(nil)},
-		[]pref.ExtensionDescriptors{(*extensions)(nil)},
-		[]pref.EnumRanges{(*enumRanges)(nil)},
-		[]pref.EnumDescriptors{(*enums)(nil)},
-		[]pref.EnumValueDescriptors{(*enumValues)(nil)},
-		[]pref.ServiceDescriptors{(*services)(nil)},
-		[]pref.MethodDescriptors{(*methods)(nil)},
-	}
-
-	for _, tt := range tests {
-		v := reflect.ValueOf(tt) // []T where T is an interface
-		ifaceType := v.Type().Elem()
-		for i := 0; i < v.Len(); i++ {
-			implType := v.Index(i).Elem().Type()
-
-			var hasName bool
-			for j := 0; j < implType.NumMethod(); j++ {
-				if name := implType.Method(j).Name; name == "Format" {
-					hasName = true
-				} else if _, ok := ifaceType.MethodByName(name); !ok {
-					t.Errorf("spurious method: %v.%v", implType, name)
-				}
-			}
-			if !hasName {
-				t.Errorf("missing method: %v.Format", implType)
-			}
-		}
-	}
-}
diff --git a/internal/prototype/name_pure.go b/internal/prototype/name_pure.go
deleted file mode 100644
index 3ec33e5..0000000
--- a/internal/prototype/name_pure.go
+++ /dev/null
@@ -1,19 +0,0 @@
-// Copyright 2018 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.
-
-// +build purego appengine
-
-package prototype
-
-import pref "google.golang.org/protobuf/reflect/protoreflect"
-
-func getNameBuilder() *nameBuilder { return nil }
-func putNameBuilder(*nameBuilder)  {}
-
-type nameBuilder struct{}
-
-// Append is equivalent to protoreflect.FullName.Append.
-func (*nameBuilder) Append(prefix pref.FullName, name pref.Name) pref.FullName {
-	return prefix.Append(name)
-}
diff --git a/internal/prototype/placeholder.go b/internal/prototype/placeholder.go
deleted file mode 100644
index 87ebb30..0000000
--- a/internal/prototype/placeholder.go
+++ /dev/null
@@ -1,32 +0,0 @@
-// Copyright 2018 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
-
-import "google.golang.org/protobuf/reflect/protoreflect"
-
-// PlaceholderFile returns a placeholder protoreflect.FileType where
-// only the Path and Package accessors are valid.
-func PlaceholderFile(path string, pkg protoreflect.FullName) protoreflect.FileDescriptor {
-	// TODO: Is Package needed for placeholders?
-	return placeholderFile{path, placeholderName(pkg)}
-}
-
-// PlaceholderMessage returns a placeholder protoreflect.MessageType
-// where only the Name and FullName accessors are valid.
-//
-// A placeholder can be used within File literals when referencing a message
-// that is declared within that file.
-func PlaceholderMessage(name protoreflect.FullName) protoreflect.MessageDescriptor {
-	return placeholderMessage{placeholderName(name)}
-}
-
-// PlaceholderEnum returns a placeholder protoreflect.EnumType
-// where only the Name and FullName accessors are valid.
-//
-// A placeholder can be used within File literals when referencing an enum
-// that is declared within that file.
-func PlaceholderEnum(name protoreflect.FullName) protoreflect.EnumDescriptor {
-	return placeholderEnum{placeholderName(name)}
-}
diff --git a/internal/prototype/placeholder_type.go b/internal/prototype/placeholder_type.go
deleted file mode 100644
index e4e7742..0000000
--- a/internal/prototype/placeholder_type.go
+++ /dev/null
@@ -1,87 +0,0 @@
-// Copyright 2018 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
-
-import (
-	"fmt"
-
-	descfmt "google.golang.org/protobuf/internal/descfmt"
-	"google.golang.org/protobuf/internal/descopts"
-	"google.golang.org/protobuf/internal/pragma"
-	pref "google.golang.org/protobuf/reflect/protoreflect"
-)
-
-var (
-	emptyFiles       fileImports
-	emptyMessages    messages
-	emptyFields      fields
-	emptyOneofs      oneofs
-	emptyNames       names
-	emptyNumbers     numbers
-	emptyFieldRanges fieldRanges
-	emptyEnums       enums
-	emptyEnumValues  enumValues
-	emptyEnumRanges  enumRanges
-	emptyExtensions  extensions
-	emptyServices    services
-)
-
-type placeholderName pref.FullName
-
-func (t placeholderName) ParentFile() pref.FileDescriptor     { return nil }
-func (t placeholderName) Parent() pref.Descriptor             { return nil }
-func (t placeholderName) Index() int                          { return 0 }
-func (t placeholderName) Syntax() pref.Syntax                 { return 0 }
-func (t placeholderName) Name() pref.Name                     { return pref.FullName(t).Name() }
-func (t placeholderName) FullName() pref.FullName             { return pref.FullName(t) }
-func (t placeholderName) IsPlaceholder() bool                 { return true }
-func (t placeholderName) ProtoInternal(pragma.DoNotImplement) {}
-
-type placeholderFile struct {
-	path string
-	placeholderName
-}
-
-func (t placeholderFile) ParentFile() pref.FileDescriptor       { return t }
-func (t placeholderFile) Options() pref.ProtoMessage            { return descopts.File }
-func (t placeholderFile) Path() string                          { return t.path }
-func (t placeholderFile) Package() pref.FullName                { return t.FullName() }
-func (t placeholderFile) Imports() pref.FileImports             { return &emptyFiles }
-func (t placeholderFile) Enums() pref.EnumDescriptors           { return &emptyEnums }
-func (t placeholderFile) Messages() pref.MessageDescriptors     { return &emptyMessages }
-func (t placeholderFile) Extensions() pref.ExtensionDescriptors { return &emptyExtensions }
-func (t placeholderFile) Services() pref.ServiceDescriptors     { return &emptyServices }
-func (t placeholderFile) Format(s fmt.State, r rune)            { descfmt.FormatDesc(s, r, t) }
-func (t placeholderFile) ProtoType(pref.FileDescriptor)         {}
-
-type placeholderMessage struct {
-	placeholderName
-}
-
-func (t placeholderMessage) Options() pref.ProtoMessage                  { return descopts.Message }
-func (t placeholderMessage) IsMapEntry() bool                            { return false }
-func (t placeholderMessage) Fields() pref.FieldDescriptors               { return &emptyFields }
-func (t placeholderMessage) Oneofs() pref.OneofDescriptors               { return &emptyOneofs }
-func (t placeholderMessage) ReservedNames() pref.Names                   { return &emptyNames }
-func (t placeholderMessage) ReservedRanges() pref.FieldRanges            { return &emptyFieldRanges }
-func (t placeholderMessage) RequiredNumbers() pref.FieldNumbers          { return &emptyNumbers }
-func (t placeholderMessage) ExtensionRanges() pref.FieldRanges           { return &emptyFieldRanges }
-func (t placeholderMessage) ExtensionRangeOptions(int) pref.ProtoMessage { panic("out of bounds") }
-func (t placeholderMessage) Enums() pref.EnumDescriptors                 { return &emptyEnums }
-func (t placeholderMessage) Messages() pref.MessageDescriptors           { return &emptyMessages }
-func (t placeholderMessage) Extensions() pref.ExtensionDescriptors       { return &emptyExtensions }
-func (t placeholderMessage) Format(s fmt.State, r rune)                  { descfmt.FormatDesc(s, r, t) }
-func (t placeholderMessage) ProtoType(pref.MessageDescriptor)            {}
-
-type placeholderEnum struct {
-	placeholderName
-}
-
-func (t placeholderEnum) Options() pref.ProtoMessage        { return descopts.Enum }
-func (t placeholderEnum) Values() pref.EnumValueDescriptors { return &emptyEnumValues }
-func (t placeholderEnum) ReservedNames() pref.Names         { return &emptyNames }
-func (t placeholderEnum) ReservedRanges() pref.EnumRanges   { return &emptyEnumRanges }
-func (t placeholderEnum) Format(s fmt.State, r rune)        { descfmt.FormatDesc(s, r, t) }
-func (t placeholderEnum) ProtoType(pref.EnumDescriptor)     {}
diff --git a/internal/prototype/protofile.go b/internal/prototype/protofile.go
deleted file mode 100644
index 48ba9ee..0000000
--- a/internal/prototype/protofile.go
+++ /dev/null
@@ -1,232 +0,0 @@
-// Copyright 2018 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.
-
-// TODO: Delete this package and re-write functionality to depend on
-// reflect/protodesc and internal/fileinit.
-
-// Package prototype provides builders to construct protobuf types that
-// implement the interfaces defined in the protoreflect package.
-//
-// Protobuf types can either be constructed as standalone types
-// (e.g., StandaloneMessage), or together as a batch of types in a single
-// proto file (e.g., File). When creating standalone types, additional
-// information must be provided such as the full type name and the proto syntax.
-// When creating an entire file, the syntax and full name is derived from
-// the parent type.
-//
-// Most types contain options, defined as messages in descriptor.proto.
-// To avoid cyclic dependencies, the prototype package treats these options
-// as opaque protoreflect.ProtoMessage values. In some cases where the option
-// contains semantically important information (e.g.,
-// google.protobuf.MessageOptions.map_entry), this information must be provided
-// as a field of the corresponding type (e.g., prototype.Message.MapEntry).
-package prototype
-
-import "google.golang.org/protobuf/reflect/protoreflect"
-
-// Every struct has a "meta" struct embedded within it as a pointer.
-// The meta type provides additional data structures for efficient lookup on
-// certain methods (e.g., ByName) or derived information that can be
-// derived from the parent (e.g., FullName). The meta type is lazily allocated
-// and initialized. This architectural approach keeps the literal representation
-// smaller, which then keeps the generated code size smaller.
-
-// TODO: Instead of a top-down construction approach where internal references
-// to message types use placeholder types, we could add a Reference method
-// on Message and Enum that creates a MessageDescriptor or EnumDescriptor
-// reference that only becomes valid after NewFile.
-// However, that API approach is more error prone, as it causes more memory
-// aliasing and provides more opportunity for misuse.
-// Also, it requires that NewFile at least eagerly initialize all
-// messages and enums list types. We can always add that API in the future.
-
-// File is a constructor for protoreflect.FileDescriptor.
-type File struct {
-	Syntax  protoreflect.Syntax
-	Path    string
-	Package protoreflect.FullName
-	Imports []protoreflect.FileImport
-	Options protoreflect.ProtoMessage
-
-	Enums      []Enum
-	Messages   []Message
-	Extensions []Extension
-	Services   []Service
-
-	*fileMeta
-}
-
-// NewFile creates a new protoreflect.FileDescriptor from the provided value.
-// The file must represent a valid proto file according to protobuf semantics.
-//
-// Fields that reference an enum or message that is being declared within the
-// same File can be represented using a placeholder descriptor. NewFile will
-// automatically resolve the placeholder to point to a concrete descriptor.
-// Alternatively, a reference descriptor obtained via Enum.Reference or
-// Message.Reference can be used instead. The placeholder approach makes it
-// possible to declare the file descriptor as a single File literal and
-// is generally easier to use. The reference approach is more performant,
-// but also more error prone.
-//
-// The caller must relinquish full ownership of the input t and must not
-// access or mutate any fields. The input must not contain slices that are
-// sub-slices of each other.
-func NewFile(t *File) (protoreflect.FileDescriptor, error) {
-	// TODO: Provide an unverified make that avoids validating the file.
-	// This is useful for generated code since we know that protoc-gen-go
-	// already validated the protobuf types.
-	ft := newFile(t)
-	if err := validateFile(ft); err != nil {
-		return nil, err
-	}
-
-	// TODO: When using reference descriptors, it is vital that all enums and
-	// messages are touched so that they are initialized before returning.
-	// Otherwise, reference descriptors may still be invalid.
-	//
-	// We can remove this once validateFile is implemented, since it will
-	// inherently touch all the necessary messages and enums.
-	visitMessages(ft)
-
-	return ft, nil
-}
-
-func visitMessages(d interface {
-	Enums() protoreflect.EnumDescriptors
-	Messages() protoreflect.MessageDescriptors
-}) {
-	d.Enums()
-	ms := d.Messages()
-	for i := 0; i < ms.Len(); i++ {
-		visitMessages(ms.Get(i))
-	}
-}
-
-// Message is a constructor for protoreflect.MessageDescriptor.
-type Message struct {
-	Name                  protoreflect.Name
-	Fields                []Field
-	Oneofs                []Oneof
-	ReservedNames         []protoreflect.Name
-	ReservedRanges        [][2]protoreflect.FieldNumber
-	ExtensionRanges       [][2]protoreflect.FieldNumber
-	ExtensionRangeOptions []protoreflect.ProtoMessage
-	Options               protoreflect.ProtoMessage
-	IsMapEntry            bool
-
-	Enums      []Enum
-	Messages   []Message
-	Extensions []Extension
-
-	*messageMeta
-}
-
-// Reference returns m as a reference protoreflect.MessageDescriptor,
-// which can be used to satisfy internal dependencies within a proto file.
-// Methods on the returned descriptor are not valid until the file that this
-// message belongs to has been constructed via NewFile.
-func (m *Message) Reference() protoreflect.MessageDescriptor {
-	return messageDesc{m}
-}
-
-// Field is a constructor for protoreflect.FieldDescriptor.
-type Field struct {
-	Name        protoreflect.Name
-	Number      protoreflect.FieldNumber
-	Cardinality protoreflect.Cardinality
-	Kind        protoreflect.Kind
-	JSONName    string
-	Default     protoreflect.Value
-	OneofName   protoreflect.Name
-	MessageType protoreflect.MessageDescriptor
-	EnumType    protoreflect.EnumDescriptor
-	Options     protoreflect.ProtoMessage
-	IsPacked    OptionalBool
-	IsWeak      bool
-
-	*fieldMeta
-}
-
-// Oneof is a constructor for protoreflect.OneofDescriptor.
-type Oneof struct {
-	Name    protoreflect.Name
-	Options protoreflect.ProtoMessage
-
-	*oneofMeta
-}
-
-// Extension is a constructor for protoreflect.ExtensionDescriptor.
-type Extension struct {
-	Name         protoreflect.Name
-	Number       protoreflect.FieldNumber
-	Cardinality  protoreflect.Cardinality
-	Kind         protoreflect.Kind
-	Default      protoreflect.Value
-	MessageType  protoreflect.MessageDescriptor
-	EnumType     protoreflect.EnumDescriptor
-	ExtendedType protoreflect.MessageDescriptor
-	Options      protoreflect.ProtoMessage
-	IsPacked     OptionalBool
-
-	*extensionMeta
-}
-
-// Enum is a constructor for protoreflect.EnumDescriptor.
-type Enum struct {
-	Name           protoreflect.Name
-	Values         []EnumValue
-	ReservedNames  []protoreflect.Name
-	ReservedRanges [][2]protoreflect.EnumNumber
-	Options        protoreflect.ProtoMessage
-
-	*enumMeta
-}
-
-// Reference returns e as a reference protoreflect.EnumDescriptor,
-// which can be used to satisfy internal dependencies within a proto file.
-// Methods on the returned descriptor are not valid until the file that this
-// enum belongs to has been constructed via NewFile.
-func (e *Enum) Reference() protoreflect.EnumDescriptor {
-	return enumDesc{e}
-}
-
-// EnumValue is a constructor for protoreflect.EnumValueDescriptor.
-type EnumValue struct {
-	Name    protoreflect.Name
-	Number  protoreflect.EnumNumber
-	Options protoreflect.ProtoMessage
-
-	*enumValueMeta
-}
-
-// Service is a constructor for protoreflect.ServiceDescriptor.
-type Service struct {
-	Name    protoreflect.Name
-	Methods []Method
-	Options protoreflect.ProtoMessage
-
-	*serviceMeta
-}
-
-// Method is a constructor for protoreflect.MethodDescriptor.
-type Method struct {
-	Name              protoreflect.Name
-	InputType         protoreflect.MessageDescriptor
-	OutputType        protoreflect.MessageDescriptor
-	IsStreamingClient bool
-	IsStreamingServer bool
-	Options           protoreflect.ProtoMessage
-
-	*methodMeta
-}
-
-// OptionalBool is a tristate boolean.
-type OptionalBool uint8
-
-// Tristate boolean values.
-const (
-	DefaultBool OptionalBool = iota
-	True
-	False
-)
diff --git a/internal/prototype/protofile_list.go b/internal/prototype/protofile_list.go
deleted file mode 100644
index 139c0a1..0000000
--- a/internal/prototype/protofile_list.go
+++ /dev/null
@@ -1,139 +0,0 @@
-// Copyright 2018 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
-
-import (
-	"fmt"
-	"sync"
-
-	"google.golang.org/protobuf/internal/descfmt"
-	"google.golang.org/protobuf/internal/pragma"
-	"google.golang.org/protobuf/internal/set"
-	pref "google.golang.org/protobuf/reflect/protoreflect"
-)
-
-type names []pref.Name
-
-func (p *names) Len() int            { return len(*p) }
-func (p *names) Get(i int) pref.Name { return (*p)[i] }
-func (p *names) Has(s pref.Name) bool {
-	for _, n := range *p {
-		if s == n {
-			return true
-		}
-	}
-	return false
-}
-func (p *names) Format(s fmt.State, r rune)          { descfmt.FormatList(s, r, p) }
-func (p *names) ProtoInternal(pragma.DoNotImplement) {}
-
-// Names returns a Names list from a slice of names.
-func Names(s []pref.Name) pref.Names { return (*names)(&s) }
-
-type numbersMeta struct {
-	once sync.Once
-	ns   []pref.FieldNumber
-	nss  set.Ints
-}
-type numbers numbersMeta
-
-func (p *numbersMeta) lazyInit(fs []Field) *numbers {
-	p.once.Do(func() {
-		for i := range fs {
-			if f := &fs[i]; f.Cardinality == pref.Required {
-				p.ns = append(p.ns, f.Number)
-				p.nss.Set(uint64(f.Number))
-			}
-		}
-	})
-	return (*numbers)(p)
-}
-func (p *numbers) Len() int                            { return len(p.ns) }
-func (p *numbers) Get(i int) pref.FieldNumber          { return p.ns[i] }
-func (p *numbers) Has(n pref.FieldNumber) bool         { return p.nss.Has(uint64(n)) }
-func (p *numbers) Format(s fmt.State, r rune)          { descfmt.FormatList(s, r, p) }
-func (p *numbers) ProtoInternal(pragma.DoNotImplement) {}
-
-type fieldRanges [][2]pref.FieldNumber
-
-func (p *fieldRanges) Len() int                      { return len(*p) }
-func (p *fieldRanges) Get(i int) [2]pref.FieldNumber { return (*p)[i] }
-func (p *fieldRanges) Has(n pref.FieldNumber) bool {
-	for _, r := range *p {
-		if r[0] <= n && n < r[1] {
-			return true
-		}
-	}
-	return false
-}
-func (p *fieldRanges) Format(s fmt.State, r rune)          { descfmt.FormatList(s, r, p) }
-func (p *fieldRanges) ProtoInternal(pragma.DoNotImplement) {}
-
-// FieldRanges returns a FieldRanges list from a slice of ranges.
-func FieldRanges(s [][2]pref.FieldNumber) pref.FieldRanges { return (*fieldRanges)(&s) }
-
-type enumRanges [][2]pref.EnumNumber
-
-func (p *enumRanges) Len() int                     { return len(*p) }
-func (p *enumRanges) Get(i int) [2]pref.EnumNumber { return (*p)[i] }
-func (p *enumRanges) Has(n pref.EnumNumber) bool {
-	for _, r := range *p {
-		if r[0] <= n && n <= r[1] {
-			return true
-		}
-	}
-	return false
-}
-func (p *enumRanges) Format(s fmt.State, r rune)          { descfmt.FormatList(s, r, p) }
-func (p *enumRanges) ProtoInternal(pragma.DoNotImplement) {}
-
-// EnumRanges returns an EnumRanges list from a slice of ranges.
-func EnumRanges(s [][2]pref.EnumNumber) pref.EnumRanges { return (*enumRanges)(&s) }
-
-type fileImports []pref.FileImport
-
-func (p *fileImports) Len() int                            { return len(*p) }
-func (p *fileImports) Get(i int) pref.FileImport           { return (*p)[i] }
-func (p *fileImports) Format(s fmt.State, r rune)          { descfmt.FormatList(s, r, p) }
-func (p *fileImports) ProtoInternal(pragma.DoNotImplement) {}
-
-type oneofFieldsMeta struct {
-	once   sync.Once
-	typs   []pref.FieldDescriptor
-	byName map[pref.Name]pref.FieldDescriptor
-	byJSON map[string]pref.FieldDescriptor
-	byNum  map[pref.FieldNumber]pref.FieldDescriptor
-}
-type oneofFields oneofFieldsMeta
-
-func (p *oneofFieldsMeta) lazyInit(parent pref.Descriptor) *oneofFields {
-	p.once.Do(func() {
-		od := parent.(pref.OneofDescriptor)
-		fs := parent.Parent().(pref.MessageDescriptor).Fields()
-		for i := 0; i < fs.Len(); i++ {
-			if f := fs.Get(i); od == f.ContainingOneof() {
-				p.typs = append(p.typs, f)
-			}
-		}
-		if len(p.typs) > 0 {
-			p.byName = make(map[pref.Name]pref.FieldDescriptor, len(p.typs))
-			p.byJSON = make(map[string]pref.FieldDescriptor, len(p.typs))
-			p.byNum = make(map[pref.FieldNumber]pref.FieldDescriptor, len(p.typs))
-			for _, f := range p.typs {
-				p.byName[f.Name()] = f
-				p.byJSON[f.JSONName()] = f
-				p.byNum[f.Number()] = f
-			}
-		}
-	})
-	return (*oneofFields)(p)
-}
-func (p *oneofFields) Len() int                                         { return len(p.typs) }
-func (p *oneofFields) Get(i int) pref.FieldDescriptor                   { return p.typs[i] }
-func (p *oneofFields) ByName(s pref.Name) pref.FieldDescriptor          { return p.byName[s] }
-func (p *oneofFields) ByJSONName(s string) pref.FieldDescriptor         { return p.byJSON[s] }
-func (p *oneofFields) ByNumber(n pref.FieldNumber) pref.FieldDescriptor { return p.byNum[n] }
-func (p *oneofFields) Format(s fmt.State, r rune)                       { descfmt.FormatList(s, r, p) }
-func (p *oneofFields) ProtoInternal(pragma.DoNotImplement)              {}
diff --git a/internal/prototype/protofile_list_gen.go b/internal/prototype/protofile_list_gen.go
deleted file mode 100644
index 695b66e..0000000
--- a/internal/prototype/protofile_list_gen.go
+++ /dev/null
@@ -1,445 +0,0 @@
-// Copyright 2018 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.
-
-// Code generated by generate-types. DO NOT EDIT.
-
-package prototype
-
-import (
-	"fmt"
-	"sync"
-
-	"google.golang.org/protobuf/internal/descfmt"
-	"google.golang.org/protobuf/internal/pragma"
-	"google.golang.org/protobuf/reflect/protoreflect"
-)
-
-type messagesMeta struct {
-	once     sync.Once
-	typs     []Message
-	nameOnce sync.Once
-	byName   map[protoreflect.Name]*Message
-}
-type messages messagesMeta
-
-func (p *messagesMeta) lazyInit(parent protoreflect.Descriptor, ts []Message) *messages {
-	p.once.Do(func() {
-		nb := getNameBuilder()
-		defer putNameBuilder(nb)
-		metas := make([]messageMeta, len(ts))
-		for i := range ts {
-			t := &ts[i]
-			if t.messageMeta != nil {
-				panic("already initialized")
-			}
-			t.messageMeta = &metas[i]
-			t.inheritedMeta.init(nb, parent, i, t.Name, false)
-		}
-		p.typs = ts
-	})
-	return (*messages)(p)
-}
-func (p *messages) Len() int                                 { return len(p.typs) }
-func (p *messages) Get(i int) protoreflect.MessageDescriptor { return messageDesc{&p.typs[i]} }
-func (p *messages) ByName(s protoreflect.Name) protoreflect.MessageDescriptor {
-	p.nameOnce.Do(func() {
-		if len(p.typs) > 0 {
-			p.byName = make(map[protoreflect.Name]*Message, len(p.typs))
-			for i := range p.typs {
-				t := &p.typs[i]
-				p.byName[t.Name] = t
-			}
-		}
-	})
-	t := p.byName[s]
-	if t == nil {
-		return nil
-	}
-	return messageDesc{t}
-}
-func (p *messages) Format(s fmt.State, r rune)          { descfmt.FormatList(s, r, p) }
-func (p *messages) ProtoInternal(pragma.DoNotImplement) {}
-
-type fieldsMeta struct {
-	once     sync.Once
-	typs     []Field
-	nameOnce sync.Once
-	byName   map[protoreflect.Name]*Field
-	jsonOnce sync.Once
-	byJSON   map[string]*Field
-	numOnce  sync.Once
-	byNum    map[protoreflect.FieldNumber]*Field
-}
-type fields fieldsMeta
-
-func (p *fieldsMeta) lazyInit(parent protoreflect.Descriptor, ts []Field) *fields {
-	p.once.Do(func() {
-		nb := getNameBuilder()
-		defer putNameBuilder(nb)
-		metas := make([]fieldMeta, len(ts))
-		for i := range ts {
-			t := &ts[i]
-			if t.fieldMeta != nil {
-				panic("already initialized")
-			}
-			t.fieldMeta = &metas[i]
-			t.inheritedMeta.init(nb, parent, i, t.Name, false)
-		}
-		p.typs = ts
-	})
-	return (*fields)(p)
-}
-func (p *fields) Len() int                               { return len(p.typs) }
-func (p *fields) Get(i int) protoreflect.FieldDescriptor { return fieldDesc{&p.typs[i]} }
-func (p *fields) ByName(s protoreflect.Name) protoreflect.FieldDescriptor {
-	p.nameOnce.Do(func() {
-		if len(p.typs) > 0 {
-			p.byName = make(map[protoreflect.Name]*Field, len(p.typs))
-			for i := range p.typs {
-				t := &p.typs[i]
-				p.byName[t.Name] = t
-			}
-		}
-	})
-	t := p.byName[s]
-	if t == nil {
-		return nil
-	}
-	return fieldDesc{t}
-}
-func (p *fields) ByJSONName(s string) protoreflect.FieldDescriptor {
-	p.jsonOnce.Do(func() {
-		if len(p.typs) > 0 {
-			p.byJSON = make(map[string]*Field, len(p.typs))
-			for i := range p.typs {
-				t := &p.typs[i]
-				s := fieldDesc{t}.JSONName()
-				if _, ok := p.byJSON[s]; !ok {
-					p.byJSON[s] = t
-				}
-			}
-		}
-	})
-	t := p.byJSON[s]
-	if t == nil {
-		return nil
-	}
-	return fieldDesc{t}
-}
-func (p *fields) ByNumber(n protoreflect.FieldNumber) protoreflect.FieldDescriptor {
-	p.numOnce.Do(func() {
-		if len(p.typs) > 0 {
-			p.byNum = make(map[protoreflect.FieldNumber]*Field, len(p.typs))
-			for i := range p.typs {
-				t := &p.typs[i]
-				if _, ok := p.byNum[t.Number]; !ok {
-					p.byNum[t.Number] = t
-				}
-			}
-		}
-	})
-	t := p.byNum[n]
-	if t == nil {
-		return nil
-	}
-	return fieldDesc{t}
-}
-func (p *fields) Format(s fmt.State, r rune)          { descfmt.FormatList(s, r, p) }
-func (p *fields) ProtoInternal(pragma.DoNotImplement) {}
-
-type oneofsMeta struct {
-	once     sync.Once
-	typs     []Oneof
-	nameOnce sync.Once
-	byName   map[protoreflect.Name]*Oneof
-}
-type oneofs oneofsMeta
-
-func (p *oneofsMeta) lazyInit(parent protoreflect.Descriptor, ts []Oneof) *oneofs {
-	p.once.Do(func() {
-		nb := getNameBuilder()
-		defer putNameBuilder(nb)
-		metas := make([]oneofMeta, len(ts))
-		for i := range ts {
-			t := &ts[i]
-			if t.oneofMeta != nil {
-				panic("already initialized")
-			}
-			t.oneofMeta = &metas[i]
-			t.inheritedMeta.init(nb, parent, i, t.Name, false)
-		}
-		p.typs = ts
-	})
-	return (*oneofs)(p)
-}
-func (p *oneofs) Len() int                               { return len(p.typs) }
-func (p *oneofs) Get(i int) protoreflect.OneofDescriptor { return oneofDesc{&p.typs[i]} }
-func (p *oneofs) ByName(s protoreflect.Name) protoreflect.OneofDescriptor {
-	p.nameOnce.Do(func() {
-		if len(p.typs) > 0 {
-			p.byName = make(map[protoreflect.Name]*Oneof, len(p.typs))
-			for i := range p.typs {
-				t := &p.typs[i]
-				p.byName[t.Name] = t
-			}
-		}
-	})
-	t := p.byName[s]
-	if t == nil {
-		return nil
-	}
-	return oneofDesc{t}
-}
-func (p *oneofs) Format(s fmt.State, r rune)          { descfmt.FormatList(s, r, p) }
-func (p *oneofs) ProtoInternal(pragma.DoNotImplement) {}
-
-type extensionsMeta struct {
-	once     sync.Once
-	typs     []Extension
-	nameOnce sync.Once
-	byName   map[protoreflect.Name]*Extension
-}
-type extensions extensionsMeta
-
-func (p *extensionsMeta) lazyInit(parent protoreflect.Descriptor, ts []Extension) *extensions {
-	p.once.Do(func() {
-		nb := getNameBuilder()
-		defer putNameBuilder(nb)
-		metas := make([]extensionMeta, len(ts))
-		for i := range ts {
-			t := &ts[i]
-			if t.extensionMeta != nil {
-				panic("already initialized")
-			}
-			t.extensionMeta = &metas[i]
-			t.inheritedMeta.init(nb, parent, i, t.Name, false)
-		}
-		p.typs = ts
-	})
-	return (*extensions)(p)
-}
-func (p *extensions) Len() int                                   { return len(p.typs) }
-func (p *extensions) Get(i int) protoreflect.ExtensionDescriptor { return extensionDesc{&p.typs[i]} }
-func (p *extensions) ByName(s protoreflect.Name) protoreflect.ExtensionDescriptor {
-	p.nameOnce.Do(func() {
-		if len(p.typs) > 0 {
-			p.byName = make(map[protoreflect.Name]*Extension, len(p.typs))
-			for i := range p.typs {
-				t := &p.typs[i]
-				p.byName[t.Name] = t
-			}
-		}
-	})
-	t := p.byName[s]
-	if t == nil {
-		return nil
-	}
-	return extensionDesc{t}
-}
-func (p *extensions) Format(s fmt.State, r rune)          { descfmt.FormatList(s, r, p) }
-func (p *extensions) ProtoInternal(pragma.DoNotImplement) {}
-
-type enumsMeta struct {
-	once     sync.Once
-	typs     []Enum
-	nameOnce sync.Once
-	byName   map[protoreflect.Name]*Enum
-}
-type enums enumsMeta
-
-func (p *enumsMeta) lazyInit(parent protoreflect.Descriptor, ts []Enum) *enums {
-	p.once.Do(func() {
-		nb := getNameBuilder()
-		defer putNameBuilder(nb)
-		metas := make([]enumMeta, len(ts))
-		for i := range ts {
-			t := &ts[i]
-			if t.enumMeta != nil {
-				panic("already initialized")
-			}
-			t.enumMeta = &metas[i]
-			t.inheritedMeta.init(nb, parent, i, t.Name, false)
-		}
-		p.typs = ts
-	})
-	return (*enums)(p)
-}
-func (p *enums) Len() int                              { return len(p.typs) }
-func (p *enums) Get(i int) protoreflect.EnumDescriptor { return enumDesc{&p.typs[i]} }
-func (p *enums) ByName(s protoreflect.Name) protoreflect.EnumDescriptor {
-	p.nameOnce.Do(func() {
-		if len(p.typs) > 0 {
-			p.byName = make(map[protoreflect.Name]*Enum, len(p.typs))
-			for i := range p.typs {
-				t := &p.typs[i]
-				p.byName[t.Name] = t
-			}
-		}
-	})
-	t := p.byName[s]
-	if t == nil {
-		return nil
-	}
-	return enumDesc{t}
-}
-func (p *enums) Format(s fmt.State, r rune)          { descfmt.FormatList(s, r, p) }
-func (p *enums) ProtoInternal(pragma.DoNotImplement) {}
-
-type enumValuesMeta struct {
-	once     sync.Once
-	typs     []EnumValue
-	nameOnce sync.Once
-	byName   map[protoreflect.Name]*EnumValue
-	numOnce  sync.Once
-	byNum    map[protoreflect.EnumNumber]*EnumValue
-}
-type enumValues enumValuesMeta
-
-func (p *enumValuesMeta) lazyInit(parent protoreflect.Descriptor, ts []EnumValue) *enumValues {
-	p.once.Do(func() {
-		nb := getNameBuilder()
-		defer putNameBuilder(nb)
-		metas := make([]enumValueMeta, len(ts))
-		for i := range ts {
-			t := &ts[i]
-			if t.enumValueMeta != nil {
-				panic("already initialized")
-			}
-			t.enumValueMeta = &metas[i]
-			t.inheritedMeta.init(nb, parent, i, t.Name, true)
-		}
-		p.typs = ts
-	})
-	return (*enumValues)(p)
-}
-func (p *enumValues) Len() int                                   { return len(p.typs) }
-func (p *enumValues) Get(i int) protoreflect.EnumValueDescriptor { return enumValueDesc{&p.typs[i]} }
-func (p *enumValues) ByName(s protoreflect.Name) protoreflect.EnumValueDescriptor {
-	p.nameOnce.Do(func() {
-		if len(p.typs) > 0 {
-			p.byName = make(map[protoreflect.Name]*EnumValue, len(p.typs))
-			for i := range p.typs {
-				t := &p.typs[i]
-				p.byName[t.Name] = t
-			}
-		}
-	})
-	t := p.byName[s]
-	if t == nil {
-		return nil
-	}
-	return enumValueDesc{t}
-}
-func (p *enumValues) ByNumber(n protoreflect.EnumNumber) protoreflect.EnumValueDescriptor {
-	p.numOnce.Do(func() {
-		if len(p.typs) > 0 {
-			p.byNum = make(map[protoreflect.EnumNumber]*EnumValue, len(p.typs))
-			for i := range p.typs {
-				t := &p.typs[i]
-				if _, ok := p.byNum[t.Number]; !ok {
-					p.byNum[t.Number] = t
-				}
-			}
-		}
-	})
-	t := p.byNum[n]
-	if t == nil {
-		return nil
-	}
-	return enumValueDesc{t}
-}
-func (p *enumValues) Format(s fmt.State, r rune)          { descfmt.FormatList(s, r, p) }
-func (p *enumValues) ProtoInternal(pragma.DoNotImplement) {}
-
-type servicesMeta struct {
-	once     sync.Once
-	typs     []Service
-	nameOnce sync.Once
-	byName   map[protoreflect.Name]*Service
-}
-type services servicesMeta
-
-func (p *servicesMeta) lazyInit(parent protoreflect.Descriptor, ts []Service) *services {
-	p.once.Do(func() {
-		nb := getNameBuilder()
-		defer putNameBuilder(nb)
-		metas := make([]serviceMeta, len(ts))
-		for i := range ts {
-			t := &ts[i]
-			if t.serviceMeta != nil {
-				panic("already initialized")
-			}
-			t.serviceMeta = &metas[i]
-			t.inheritedMeta.init(nb, parent, i, t.Name, false)
-		}
-		p.typs = ts
-	})
-	return (*services)(p)
-}
-func (p *services) Len() int                                 { return len(p.typs) }
-func (p *services) Get(i int) protoreflect.ServiceDescriptor { return serviceDesc{&p.typs[i]} }
-func (p *services) ByName(s protoreflect.Name) protoreflect.ServiceDescriptor {
-	p.nameOnce.Do(func() {
-		if len(p.typs) > 0 {
-			p.byName = make(map[protoreflect.Name]*Service, len(p.typs))
-			for i := range p.typs {
-				t := &p.typs[i]
-				p.byName[t.Name] = t
-			}
-		}
-	})
-	t := p.byName[s]
-	if t == nil {
-		return nil
-	}
-	return serviceDesc{t}
-}
-func (p *services) Format(s fmt.State, r rune)          { descfmt.FormatList(s, r, p) }
-func (p *services) ProtoInternal(pragma.DoNotImplement) {}
-
-type methodsMeta struct {
-	once     sync.Once
-	typs     []Method
-	nameOnce sync.Once
-	byName   map[protoreflect.Name]*Method
-}
-type methods methodsMeta
-
-func (p *methodsMeta) lazyInit(parent protoreflect.Descriptor, ts []Method) *methods {
-	p.once.Do(func() {
-		nb := getNameBuilder()
-		defer putNameBuilder(nb)
-		metas := make([]methodMeta, len(ts))
-		for i := range ts {
-			t := &ts[i]
-			if t.methodMeta != nil {
-				panic("already initialized")
-			}
-			t.methodMeta = &metas[i]
-			t.inheritedMeta.init(nb, parent, i, t.Name, false)
-		}
-		p.typs = ts
-	})
-	return (*methods)(p)
-}
-func (p *methods) Len() int                                { return len(p.typs) }
-func (p *methods) Get(i int) protoreflect.MethodDescriptor { return methodDesc{&p.typs[i]} }
-func (p *methods) ByName(s protoreflect.Name) protoreflect.MethodDescriptor {
-	p.nameOnce.Do(func() {
-		if len(p.typs) > 0 {
-			p.byName = make(map[protoreflect.Name]*Method, len(p.typs))
-			for i := range p.typs {
-				t := &p.typs[i]
-				p.byName[t.Name] = t
-			}
-		}
-	})
-	t := p.byName[s]
-	if t == nil {
-		return nil
-	}
-	return methodDesc{t}
-}
-func (p *methods) Format(s fmt.State, r rune)          { descfmt.FormatList(s, r, p) }
-func (p *methods) ProtoInternal(pragma.DoNotImplement) {}
diff --git a/internal/prototype/protofile_type.go b/internal/prototype/protofile_type.go
deleted file mode 100644
index a00e36b..0000000
--- a/internal/prototype/protofile_type.go
+++ /dev/null
@@ -1,601 +0,0 @@
-// Copyright 2018 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
-
-import (
-	"bytes"
-	"fmt"
-	"strings"
-	"sync"
-
-	"google.golang.org/protobuf/internal/descfmt"
-	"google.golang.org/protobuf/internal/descopts"
-	"google.golang.org/protobuf/internal/pragma"
-	"google.golang.org/protobuf/reflect/protoreflect"
-	pref "google.golang.org/protobuf/reflect/protoreflect"
-)
-
-// inheritedMeta is information inherited from the parent.
-type inheritedMeta struct {
-	parent   pref.Descriptor
-	index    int
-	syntax   pref.Syntax
-	fullName pref.FullName
-}
-
-func (m *inheritedMeta) init(nb *nameBuilder, parent pref.Descriptor, index int, name pref.Name, child bool) {
-	// Most descriptors are namespaced as a child of their parent.
-	// However, EnumValues are the exception in that they are namespaced
-	// as a sibling of the parent Enum type.
-	prefix := parent.FullName()
-	if child {
-		prefix = prefix.Parent()
-	}
-
-	m.parent = parent
-	m.index = index
-	m.syntax = parent.Syntax()
-	m.fullName = nb.Append(prefix, name)
-}
-
-type fileMeta struct {
-	ms messagesMeta
-	es enumsMeta
-	xs extensionsMeta
-	ss servicesMeta
-}
-type fileDesc struct{ f *File }
-
-// altOptions returns m as is if it is non-nil. Otherwise, it returns alt.
-func altOptions(m, alt pref.ProtoMessage) pref.ProtoMessage {
-	if m != nil {
-		return m
-	}
-	return alt
-}
-
-func newFile(f *File) fileDesc {
-	if f.fileMeta != nil {
-		panic("already initialized")
-	}
-	f.fileMeta = new(fileMeta)
-	return fileDesc{f}
-}
-func (t fileDesc) ParentFile() pref.FileDescriptor       { return t }
-func (t fileDesc) Parent() pref.Descriptor               { return nil }
-func (t fileDesc) Index() int                            { return 0 }
-func (t fileDesc) Syntax() pref.Syntax                   { return t.f.Syntax }
-func (t fileDesc) Name() pref.Name                       { return t.f.Package.Name() }
-func (t fileDesc) FullName() pref.FullName               { return t.f.Package }
-func (t fileDesc) IsPlaceholder() bool                   { return false }
-func (t fileDesc) Options() pref.ProtoMessage            { return altOptions(t.f.Options, descopts.File) }
-func (t fileDesc) Path() string                          { return t.f.Path }
-func (t fileDesc) Package() pref.FullName                { return t.f.Package }
-func (t fileDesc) Imports() pref.FileImports             { return (*fileImports)(&t.f.Imports) }
-func (t fileDesc) Enums() pref.EnumDescriptors           { return t.f.es.lazyInit(t, t.f.Enums) }
-func (t fileDesc) Messages() pref.MessageDescriptors     { return t.f.ms.lazyInit(t, t.f.Messages) }
-func (t fileDesc) Extensions() pref.ExtensionDescriptors { return t.f.xs.lazyInit(t, t.f.Extensions) }
-func (t fileDesc) Services() pref.ServiceDescriptors     { return t.f.ss.lazyInit(t, t.f.Services) }
-func (t fileDesc) Format(s fmt.State, r rune)            { descfmt.FormatDesc(s, r, t) }
-func (t fileDesc) ProtoType(pref.FileDescriptor)         {}
-func (t fileDesc) ProtoInternal(pragma.DoNotImplement)   {}
-
-func parentFile(d protoreflect.Descriptor) protoreflect.FileDescriptor {
-	for ; d != nil; d = d.Parent() {
-		if fd, ok := d.(protoreflect.FileDescriptor); ok {
-			return fd
-		}
-	}
-	return nil
-}
-
-type messageMeta struct {
-	inheritedMeta
-
-	fs fieldsMeta
-	os oneofsMeta
-	ns numbersMeta
-	ms messagesMeta
-	es enumsMeta
-	xs extensionsMeta
-}
-type messageDesc struct{ m *Message }
-
-func (t messageDesc) ParentFile() pref.FileDescriptor { return parentFile(t) }
-func (t messageDesc) Parent() pref.Descriptor         { return t.m.parent }
-func (t messageDesc) Index() int                      { return t.m.index }
-func (t messageDesc) Syntax() pref.Syntax             { return t.m.syntax }
-func (t messageDesc) Name() pref.Name                 { return t.m.Name }
-func (t messageDesc) FullName() pref.FullName         { return t.m.fullName }
-func (t messageDesc) IsPlaceholder() bool             { return false }
-func (t messageDesc) Options() pref.ProtoMessage {
-	return altOptions(t.m.Options, descopts.Message)
-}
-func (t messageDesc) IsMapEntry() bool                   { return t.m.IsMapEntry }
-func (t messageDesc) Fields() pref.FieldDescriptors      { return t.m.fs.lazyInit(t, t.m.Fields) }
-func (t messageDesc) Oneofs() pref.OneofDescriptors      { return t.m.os.lazyInit(t, t.m.Oneofs) }
-func (t messageDesc) ReservedNames() pref.Names          { return (*names)(&t.m.ReservedNames) }
-func (t messageDesc) ReservedRanges() pref.FieldRanges   { return (*fieldRanges)(&t.m.ReservedRanges) }
-func (t messageDesc) RequiredNumbers() pref.FieldNumbers { return t.m.ns.lazyInit(t.m.Fields) }
-func (t messageDesc) ExtensionRanges() pref.FieldRanges  { return (*fieldRanges)(&t.m.ExtensionRanges) }
-func (t messageDesc) ExtensionRangeOptions(i int) pref.ProtoMessage {
-	return extensionRangeOptions(i, len(t.m.ExtensionRanges), t.m.ExtensionRangeOptions)
-}
-func (t messageDesc) Enums() pref.EnumDescriptors           { return t.m.es.lazyInit(t, t.m.Enums) }
-func (t messageDesc) Messages() pref.MessageDescriptors     { return t.m.ms.lazyInit(t, t.m.Messages) }
-func (t messageDesc) Extensions() pref.ExtensionDescriptors { return t.m.xs.lazyInit(t, t.m.Extensions) }
-func (t messageDesc) Format(s fmt.State, r rune)            { descfmt.FormatDesc(s, r, t) }
-func (t messageDesc) ProtoType(pref.MessageDescriptor)      {}
-func (t messageDesc) ProtoInternal(pragma.DoNotImplement)   {}
-
-func extensionRangeOptions(i, n int, ms []pref.ProtoMessage) pref.ProtoMessage {
-	if i < 0 || i >= n {
-		panic("out of bounds")
-	}
-	var m pref.ProtoMessage
-	if i < len(ms) {
-		m = ms[i]
-	}
-	if m == nil {
-		m = descopts.ExtensionRange
-	}
-	return m
-}
-
-type fieldMeta struct {
-	inheritedMeta
-
-	js jsonName
-	dv defaultValue
-	ot oneofReference
-	mt messageReference
-	et enumReference
-}
-type fieldDesc struct{ f *Field }
-
-func (t fieldDesc) ParentFile() pref.FileDescriptor { return parentFile(t) }
-func (t fieldDesc) Parent() pref.Descriptor         { return t.f.parent }
-func (t fieldDesc) Index() int                      { return t.f.index }
-func (t fieldDesc) Syntax() pref.Syntax             { return t.f.syntax }
-func (t fieldDesc) Name() pref.Name                 { return t.f.Name }
-func (t fieldDesc) FullName() pref.FullName         { return t.f.fullName }
-func (t fieldDesc) IsPlaceholder() bool             { return false }
-func (t fieldDesc) Options() pref.ProtoMessage      { return altOptions(t.f.Options, descopts.Field) }
-func (t fieldDesc) Number() pref.FieldNumber        { return t.f.Number }
-func (t fieldDesc) Cardinality() pref.Cardinality   { return t.f.Cardinality }
-func (t fieldDesc) Kind() pref.Kind                 { return t.f.Kind }
-func (t fieldDesc) HasJSONName() bool               { return t.f.JSONName != "" }
-func (t fieldDesc) JSONName() string                { return t.f.js.lazyInit(t.f) }
-func (t fieldDesc) IsPacked() bool {
-	return isPacked(t.f.IsPacked, t.f.syntax, t.f.Cardinality, t.f.Kind)
-}
-func (t fieldDesc) IsExtension() bool { return false }
-func (t fieldDesc) IsWeak() bool      { return t.f.IsWeak }
-func (t fieldDesc) IsList() bool {
-	return t.f.Cardinality == pref.Repeated && !t.IsMap()
-}
-func (t fieldDesc) IsMap() bool {
-	mt := t.Message()
-	return mt != nil && mt.IsMapEntry()
-}
-func (t fieldDesc) MapKey() pref.FieldDescriptor {
-	if !t.IsMap() {
-		return nil
-	}
-	return t.Message().Fields().ByNumber(1)
-}
-func (t fieldDesc) MapValue() pref.FieldDescriptor {
-	if !t.IsMap() {
-		return nil
-	}
-	return t.Message().Fields().ByNumber(2)
-}
-func (t fieldDesc) HasDefault() bool                           { return t.f.Default.IsValid() }
-func (t fieldDesc) Default() pref.Value                        { return t.f.dv.value(t, t.f.Default) }
-func (t fieldDesc) DefaultEnumValue() pref.EnumValueDescriptor { return t.f.dv.enum(t, t.f.Default) }
-func (t fieldDesc) ContainingOneof() pref.OneofDescriptor      { return t.f.ot.lazyInit(t, t.f.OneofName) }
-func (t fieldDesc) ContainingMessage() pref.MessageDescriptor {
-	return t.f.parent.(pref.MessageDescriptor)
-}
-func (t fieldDesc) Enum() pref.EnumDescriptor           { return t.f.et.lazyInit(t, &t.f.EnumType) }
-func (t fieldDesc) Message() pref.MessageDescriptor     { return t.f.mt.lazyInit(t, &t.f.MessageType) }
-func (t fieldDesc) Format(s fmt.State, r rune)          { descfmt.FormatDesc(s, r, t) }
-func (t fieldDesc) ProtoType(pref.FieldDescriptor)      {}
-func (t fieldDesc) ProtoInternal(pragma.DoNotImplement) {}
-
-func isPacked(packed OptionalBool, s pref.Syntax, c pref.Cardinality, k pref.Kind) bool {
-	if packed == False || (packed == DefaultBool && s == pref.Proto2) {
-		return false
-	}
-	if c != pref.Repeated {
-		return false
-	}
-	switch k {
-	case pref.StringKind, pref.BytesKind, pref.MessageKind, pref.GroupKind:
-		return false
-	}
-	return true
-}
-
-type jsonName struct {
-	once sync.Once
-	name string
-}
-
-func (p *jsonName) lazyInit(f *Field) string {
-	p.once.Do(func() {
-		// TODO: We may need to share this logic with protojson for implementation
-		// of the FieldMask well-known type.
-		if f.JSONName != "" {
-			p.name = f.JSONName
-			return
-		}
-		var b []byte
-		var wasUnderscore bool
-		for i := 0; i < len(f.Name); i++ { // proto identifiers are always ASCII
-			c := f.Name[i]
-			if c != '_' {
-				isLower := 'a' <= c && c <= 'z'
-				if wasUnderscore && isLower {
-					c -= 'a' - 'A'
-				}
-				b = append(b, c)
-			}
-			wasUnderscore = c == '_'
-		}
-		p.name = string(b)
-	})
-	return p.name
-}
-
-// oneofReference resolves the name of a oneof by searching the parent
-// message for the matching OneofDescriptor declaration.
-type oneofReference struct {
-	once sync.Once
-	otyp pref.OneofDescriptor
-}
-
-func (p *oneofReference) lazyInit(parent pref.Descriptor, name pref.Name) pref.OneofDescriptor {
-	p.once.Do(func() {
-		if name != "" {
-			p.otyp = parent.Parent().(pref.MessageDescriptor).Oneofs().ByName(name)
-			// TODO: We need validate to detect this mismatch.
-		}
-	})
-	return p.otyp
-}
-
-type oneofMeta struct {
-	inheritedMeta
-
-	fs oneofFieldsMeta
-}
-type oneofDesc struct{ o *Oneof }
-
-func (t oneofDesc) ParentFile() pref.FileDescriptor     { return parentFile(t) }
-func (t oneofDesc) Parent() pref.Descriptor             { return t.o.parent }
-func (t oneofDesc) Index() int                          { return t.o.index }
-func (t oneofDesc) Syntax() pref.Syntax                 { return t.o.syntax }
-func (t oneofDesc) Name() pref.Name                     { return t.o.Name }
-func (t oneofDesc) FullName() pref.FullName             { return t.o.fullName }
-func (t oneofDesc) IsPlaceholder() bool                 { return false }
-func (t oneofDesc) Options() pref.ProtoMessage          { return altOptions(t.o.Options, descopts.Oneof) }
-func (t oneofDesc) Fields() pref.FieldDescriptors       { return t.o.fs.lazyInit(t) }
-func (t oneofDesc) Format(s fmt.State, r rune)          { descfmt.FormatDesc(s, r, t) }
-func (t oneofDesc) ProtoType(pref.OneofDescriptor)      {}
-func (t oneofDesc) ProtoInternal(pragma.DoNotImplement) {}
-
-type extensionMeta struct {
-	inheritedMeta
-
-	dv defaultValue
-	xt messageReference
-	mt messageReference
-	et enumReference
-}
-type extensionDesc struct{ x *Extension }
-
-func (t extensionDesc) ParentFile() pref.FileDescriptor { return parentFile(t) }
-func (t extensionDesc) Parent() pref.Descriptor         { return t.x.parent }
-func (t extensionDesc) Syntax() pref.Syntax             { return t.x.syntax }
-func (t extensionDesc) Index() int                      { return t.x.index }
-func (t extensionDesc) Name() pref.Name                 { return t.x.Name }
-func (t extensionDesc) FullName() pref.FullName         { return t.x.fullName }
-func (t extensionDesc) IsPlaceholder() bool             { return false }
-func (t extensionDesc) Options() pref.ProtoMessage {
-	return altOptions(t.x.Options, descopts.Field)
-}
-func (t extensionDesc) Number() pref.FieldNumber      { return t.x.Number }
-func (t extensionDesc) Cardinality() pref.Cardinality { return t.x.Cardinality }
-func (t extensionDesc) Kind() pref.Kind               { return t.x.Kind }
-func (t extensionDesc) HasJSONName() bool             { return false }
-func (t extensionDesc) JSONName() string              { return "" }
-func (t extensionDesc) IsPacked() bool {
-	// Extensions always use proto2 defaults for packing.
-	return isPacked(t.x.IsPacked, pref.Proto2, t.x.Cardinality, t.x.Kind)
-}
-func (t extensionDesc) IsExtension() bool                          { return true }
-func (t extensionDesc) IsWeak() bool                               { return false }
-func (t extensionDesc) IsList() bool                               { return t.x.Cardinality == pref.Repeated }
-func (t extensionDesc) IsMap() bool                                { return false }
-func (t extensionDesc) MapKey() pref.FieldDescriptor               { return nil }
-func (t extensionDesc) MapValue() pref.FieldDescriptor             { return nil }
-func (t extensionDesc) HasDefault() bool                           { return t.x.Default.IsValid() }
-func (t extensionDesc) Default() pref.Value                        { return t.x.dv.value(t, t.x.Default) }
-func (t extensionDesc) DefaultEnumValue() pref.EnumValueDescriptor { return t.x.dv.enum(t, t.x.Default) }
-func (t extensionDesc) ContainingOneof() pref.OneofDescriptor      { return nil }
-func (t extensionDesc) ContainingMessage() pref.MessageDescriptor {
-	return t.x.xt.lazyInit(t, &t.x.ExtendedType)
-}
-func (t extensionDesc) Enum() pref.EnumDescriptor           { return t.x.et.lazyInit(t, &t.x.EnumType) }
-func (t extensionDesc) Message() pref.MessageDescriptor     { return t.x.mt.lazyInit(t, &t.x.MessageType) }
-func (t extensionDesc) Format(s fmt.State, r rune)          { descfmt.FormatDesc(s, r, t) }
-func (t extensionDesc) ProtoType(pref.FieldDescriptor)      {}
-func (t extensionDesc) ProtoInternal(pragma.DoNotImplement) {}
-
-type enumMeta struct {
-	inheritedMeta
-
-	vs enumValuesMeta
-}
-type enumDesc struct{ e *Enum }
-
-func (t enumDesc) ParentFile() pref.FileDescriptor     { return parentFile(t) }
-func (t enumDesc) Parent() pref.Descriptor             { return t.e.parent }
-func (t enumDesc) Index() int                          { return t.e.index }
-func (t enumDesc) Syntax() pref.Syntax                 { return t.e.syntax }
-func (t enumDesc) Name() pref.Name                     { return t.e.Name }
-func (t enumDesc) FullName() pref.FullName             { return t.e.fullName }
-func (t enumDesc) IsPlaceholder() bool                 { return false }
-func (t enumDesc) Options() pref.ProtoMessage          { return altOptions(t.e.Options, descopts.Enum) }
-func (t enumDesc) Values() pref.EnumValueDescriptors   { return t.e.vs.lazyInit(t, t.e.Values) }
-func (t enumDesc) ReservedNames() pref.Names           { return (*names)(&t.e.ReservedNames) }
-func (t enumDesc) ReservedRanges() pref.EnumRanges     { return (*enumRanges)(&t.e.ReservedRanges) }
-func (t enumDesc) Format(s fmt.State, r rune)          { descfmt.FormatDesc(s, r, t) }
-func (t enumDesc) ProtoType(pref.EnumDescriptor)       {}
-func (t enumDesc) ProtoInternal(pragma.DoNotImplement) {}
-
-type enumValueMeta struct {
-	inheritedMeta
-}
-type enumValueDesc struct{ v *EnumValue }
-
-func (t enumValueDesc) ParentFile() pref.FileDescriptor { return parentFile(t) }
-func (t enumValueDesc) Parent() pref.Descriptor         { return t.v.parent }
-func (t enumValueDesc) Index() int                      { return t.v.index }
-func (t enumValueDesc) Syntax() pref.Syntax             { return t.v.syntax }
-func (t enumValueDesc) Name() pref.Name                 { return t.v.Name }
-func (t enumValueDesc) FullName() pref.FullName         { return t.v.fullName }
-func (t enumValueDesc) IsPlaceholder() bool             { return false }
-func (t enumValueDesc) Options() pref.ProtoMessage {
-	return altOptions(t.v.Options, descopts.EnumValue)
-}
-func (t enumValueDesc) Number() pref.EnumNumber             { return t.v.Number }
-func (t enumValueDesc) Format(s fmt.State, r rune)          { descfmt.FormatDesc(s, r, t) }
-func (t enumValueDesc) ProtoType(pref.EnumValueDescriptor)  {}
-func (t enumValueDesc) ProtoInternal(pragma.DoNotImplement) {}
-
-type serviceMeta struct {
-	inheritedMeta
-
-	ms methodsMeta
-}
-type serviceDesc struct{ s *Service }
-
-func (t serviceDesc) ParentFile() pref.FileDescriptor { return parentFile(t) }
-func (t serviceDesc) Parent() pref.Descriptor         { return t.s.parent }
-func (t serviceDesc) Index() int                      { return t.s.index }
-func (t serviceDesc) Syntax() pref.Syntax             { return t.s.syntax }
-func (t serviceDesc) Name() pref.Name                 { return t.s.Name }
-func (t serviceDesc) FullName() pref.FullName         { return t.s.fullName }
-func (t serviceDesc) IsPlaceholder() bool             { return false }
-func (t serviceDesc) Options() pref.ProtoMessage {
-	return altOptions(t.s.Options, descopts.Service)
-}
-func (t serviceDesc) Methods() pref.MethodDescriptors     { return t.s.ms.lazyInit(t, t.s.Methods) }
-func (t serviceDesc) Format(s fmt.State, r rune)          { descfmt.FormatDesc(s, r, t) }
-func (t serviceDesc) ProtoType(pref.ServiceDescriptor)    {}
-func (t serviceDesc) ProtoInternal(pragma.DoNotImplement) {}
-
-type methodMeta struct {
-	inheritedMeta
-
-	mit messageReference
-	mot messageReference
-}
-type methodDesc struct{ m *Method }
-
-func (t methodDesc) ParentFile() pref.FileDescriptor     { return parentFile(t) }
-func (t methodDesc) Parent() pref.Descriptor             { return t.m.parent }
-func (t methodDesc) Index() int                          { return t.m.index }
-func (t methodDesc) Syntax() pref.Syntax                 { return t.m.syntax }
-func (t methodDesc) Name() pref.Name                     { return t.m.Name }
-func (t methodDesc) FullName() pref.FullName             { return t.m.fullName }
-func (t methodDesc) IsPlaceholder() bool                 { return false }
-func (t methodDesc) Options() pref.ProtoMessage          { return altOptions(t.m.Options, descopts.Method) }
-func (t methodDesc) Input() pref.MessageDescriptor       { return t.m.mit.lazyInit(t, &t.m.InputType) }
-func (t methodDesc) Output() pref.MessageDescriptor      { return t.m.mot.lazyInit(t, &t.m.OutputType) }
-func (t methodDesc) IsStreamingClient() bool             { return t.m.IsStreamingClient }
-func (t methodDesc) IsStreamingServer() bool             { return t.m.IsStreamingServer }
-func (t methodDesc) Format(s fmt.State, r rune)          { descfmt.FormatDesc(s, r, t) }
-func (t methodDesc) ProtoType(pref.MethodDescriptor)     {}
-func (t methodDesc) ProtoInternal(pragma.DoNotImplement) {}
-
-type defaultValue struct {
-	once sync.Once
-	val  pref.Value
-	eval pref.EnumValueDescriptor
-	buf  []byte
-}
-
-var (
-	zeroBool    = pref.ValueOf(false)
-	zeroInt32   = pref.ValueOf(int32(0))
-	zeroInt64   = pref.ValueOf(int64(0))
-	zeroUint32  = pref.ValueOf(uint32(0))
-	zeroUint64  = pref.ValueOf(uint64(0))
-	zeroFloat32 = pref.ValueOf(float32(0))
-	zeroFloat64 = pref.ValueOf(float64(0))
-	zeroString  = pref.ValueOf(string(""))
-	zeroBytes   = pref.ValueOf([]byte(nil))
-	zeroEnum    = pref.ValueOf(pref.EnumNumber(0))
-)
-
-func (p *defaultValue) lazyInit(t pref.FieldDescriptor, v pref.Value) {
-	p.once.Do(func() {
-		p.val = v
-		if v.IsValid() {
-			switch t.Kind() {
-			case pref.EnumKind:
-				// Treat a string value as an identifier referencing some enum
-				// value by name and extract the enum number.
-				// If this fails, validateMessage will later detect that the
-				// default value for an enum value is the wrong type.
-				switch v := v.Interface().(type) {
-				case string:
-					if ev := t.Enum().Values().ByName(pref.Name(v)); ev != nil {
-						p.eval = ev
-						p.val = pref.ValueOf(p.eval.Number())
-					}
-				case pref.EnumNumber:
-					p.eval = t.Enum().Values().ByNumber(v)
-				}
-			case pref.BytesKind:
-				// Store a copy of the default bytes, so that we can detect
-				// accidental mutations of the original value.
-				if b, ok := v.Interface().([]byte); ok && len(b) > 0 {
-					p.buf = append([]byte(nil), b...)
-				}
-			}
-			return
-		}
-		switch t.Kind() {
-		case pref.BoolKind:
-			p.val = zeroBool
-		case pref.Int32Kind, pref.Sint32Kind, pref.Sfixed32Kind:
-			p.val = zeroInt32
-		case pref.Int64Kind, pref.Sint64Kind, pref.Sfixed64Kind:
-			p.val = zeroInt64
-		case pref.Uint32Kind, pref.Fixed32Kind:
-			p.val = zeroUint32
-		case pref.Uint64Kind, pref.Fixed64Kind:
-			p.val = zeroUint64
-		case pref.FloatKind:
-			p.val = zeroFloat32
-		case pref.DoubleKind:
-			p.val = zeroFloat64
-		case pref.StringKind:
-			p.val = zeroString
-		case pref.BytesKind:
-			p.val = zeroBytes
-		case pref.EnumKind:
-			p.val = zeroEnum
-			if t.Syntax() == pref.Proto2 {
-				if ed := t.Enum(); ed != nil {
-					if vs := ed.Values(); vs.Len() > 0 {
-						p.val = pref.ValueOf(vs.Get(0).Number())
-					}
-				}
-			}
-		}
-	})
-	if len(p.buf) > 0 && !bytes.Equal(p.buf, p.val.Bytes()) {
-		// TODO: Avoid panic if we're running with the race detector and instead
-		// spawn a goroutine that periodically resets this value back to the
-		// original to induce a race that can be detected by the detector.
-		panic(fmt.Sprintf("proto: detected mutation on the default bytes for %v", t.FullName()))
-	}
-}
-
-func (p *defaultValue) value(t pref.FieldDescriptor, v pref.Value) pref.Value {
-	p.lazyInit(t, v)
-	return p.val
-}
-
-func (p *defaultValue) enum(t pref.FieldDescriptor, v pref.Value) pref.EnumValueDescriptor {
-	p.lazyInit(t, v)
-	return p.eval
-}
-
-// messageReference resolves PlaceholderMessages that reference declarations
-// within the FileDescriptor tree that parent is a member of.
-type messageReference struct{ once sync.Once }
-
-func (p *messageReference) lazyInit(parent pref.Descriptor, pt *pref.MessageDescriptor) pref.MessageDescriptor {
-	p.once.Do(func() {
-		if t := *pt; t != nil && t.IsPlaceholder() {
-			if d, ok := resolveReference(parent, t.FullName()).(pref.MessageDescriptor); ok {
-				*pt = d
-			}
-		}
-	})
-	return *pt
-}
-
-// enumReference resolves PlaceholderEnums that reference declarations
-// within the FileDescriptor tree that parent is a member of.
-type enumReference struct{ once sync.Once }
-
-func (p *enumReference) lazyInit(parent pref.Descriptor, pt *pref.EnumDescriptor) pref.EnumDescriptor {
-	p.once.Do(func() {
-		if t := *pt; t != nil && t.IsPlaceholder() {
-			if d, ok := resolveReference(parent, t.FullName()).(pref.EnumDescriptor); ok {
-				*pt = d
-			}
-		}
-	})
-	return *pt
-}
-
-// resolveReference searches parent for the MessageDescriptor or EnumDescriptor
-// declaration identified by refName. This returns nil if not found.
-func resolveReference(parent pref.Descriptor, refName pref.FullName) pref.Descriptor {
-	// Ascend upwards until a prefix match is found.
-	cur := parent
-	for cur != nil {
-		curName := cur.FullName()
-		if strings.HasPrefix(string(refName), string(curName)) {
-			if len(refName) == len(curName) {
-				refName = refName[len(curName):]
-				break // e.g., refName: foo.firetruck, curName: foo.firetruck
-			} else if refName[len(curName)] == '.' {
-				refName = refName[len(curName)+len("."):]
-				break // e.g., refName: foo.firetruck.driver, curName: foo.firetruck
-			} else if len(curName) == 0 {
-				break // FileDescriptor has no package name
-			}
-			// No match. (e.g., refName: foo.firetruck, curName: foo.fire)
-		}
-		cur = cur.Parent() // nil after ascending above FileDescriptor
-	}
-
-	// Descend downwards to resolve all relative names.
-	for cur != nil && len(refName) > 0 {
-		var head pref.Name
-		head, refName = pref.Name(refName), ""
-		if i := strings.IndexByte(string(head), '.'); i >= 0 {
-			head, refName = head[:i], pref.FullName(head[i+len("."):])
-		}
-
-		// Search the current descriptor for the nested declaration.
-		var next pref.Descriptor
-		if t, ok := cur.(interface {
-			Messages() pref.MessageDescriptors
-		}); ok && next == nil {
-			if d := t.Messages().ByName(head); d != nil {
-				next = d
-			}
-		}
-		if t, ok := cur.(interface {
-			Enums() pref.EnumDescriptors
-		}); ok && next == nil {
-			if d := t.Enums().ByName(head); d != nil {
-				next = d
-			}
-		}
-		cur = next // nil if not found
-	}
-	return cur
-}
diff --git a/internal/prototype/resolve_test.go b/internal/prototype/resolve_test.go
deleted file mode 100644
index 09fb195..0000000
--- a/internal/prototype/resolve_test.go
+++ /dev/null
@@ -1,146 +0,0 @@
-// Copyright 2018 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
-
-import (
-	"testing"
-
-	pref "google.golang.org/protobuf/reflect/protoreflect"
-)
-
-func TestResolve(t *testing.T) {
-	f := &File{
-		Syntax:  pref.Proto2,
-		Package: "test",
-		Messages: []Message{{
-			Name:   "FooMessage",
-			Fields: []Field{{Name: "F", Number: 1, Cardinality: pref.Optional, Kind: pref.BytesKind}},
-			Messages: []Message{{
-				Name:   "FooMessage",
-				Fields: []Field{{Name: "F", Number: 1, Cardinality: pref.Optional, Kind: pref.BytesKind}},
-			}, {
-				Name:   "BarMessage",
-				Fields: []Field{{Name: "F", Number: 1, Cardinality: pref.Optional, Kind: pref.BytesKind}},
-			}},
-			Enums: []Enum{{
-				Name:   "FooEnum",
-				Values: []EnumValue{{Name: "E", Number: 0}},
-			}, {
-				Name:   "BarEnum",
-				Values: []EnumValue{{Name: "E", Number: 0}},
-			}},
-		}, {
-			Name:   "BarMessage",
-			Fields: []Field{{Name: "F", Number: 1, Cardinality: pref.Optional, Kind: pref.BytesKind}},
-		}},
-		Enums: []Enum{{
-			Name:   "FooEnum",
-			Values: []EnumValue{{Name: "E", Number: 0}},
-		}, {
-			Name:   "BarEnum",
-			Values: []EnumValue{{Name: "E", Number: 0}},
-		}},
-	}
-
-	fd, err := NewFile(f)
-	if err != nil {
-		t.Fatalf("NewFile() error: %v", err)
-	}
-
-	tests := []struct {
-		parent pref.Descriptor
-		name   pref.FullName
-		want   pref.Descriptor
-	}{{
-		parent: fd.Enums().Get(0),
-		name:   "test.Foo",
-		want:   nil,
-	}, {
-		parent: fd.Enums().Get(0),
-		name:   "test.FooEnum",
-		want:   fd.Enums().Get(0),
-	}, {
-		parent: fd.Enums().Get(0),
-		name:   "test.BarEnum",
-		want:   fd.Enums().Get(1),
-	}, {
-		parent: fd.Enums().Get(0),
-		name:   "test.BarMessage",
-		want:   fd.Messages().Get(1),
-	}, {
-		parent: fd.Enums().Get(0),
-		name:   "test.FooMessage.BarMessage",
-		want:   fd.Messages().Get(0).Messages().Get(1),
-	}, {
-		parent: fd.Enums().Get(0),
-		name:   "test.FooMessage.Bar",
-		want:   nil,
-	}, {
-		parent: fd.Messages().Get(1),
-		name:   "test.FooMessage.BarEnum",
-		want:   fd.Messages().Get(0).Enums().Get(1),
-	}, {
-		parent: fd.Messages().Get(1),
-		name:   "test.FooEnum",
-		want:   fd.Enums().Get(0),
-	}, {
-		parent: fd.Messages().Get(0),
-		name:   "test.FooEnum",
-		want:   fd.Enums().Get(0),
-	}, {
-		parent: fd.Messages().Get(0),
-		name:   "test.FooEnum.NonExistent",
-		want:   nil,
-	}, {
-		parent: fd.Messages().Get(0),
-		name:   "test.FooMessage.FooEnum",
-		want:   fd.Messages().Get(0).Enums().Get(0),
-	}, {
-		parent: fd.Messages().Get(0),
-		name:   "test.FooMessage",
-		want:   fd.Messages().Get(0),
-	}, {
-		parent: fd.Messages().Get(0),
-		name:   "test.FooMessage.Fizz",
-		want:   nil,
-	}, {
-		parent: fd.Messages().Get(0).Messages().Get(0),
-		name:   "test.FooMessage.FooMessage",
-		want:   fd.Messages().Get(0).Messages().Get(0),
-	}, {
-		parent: fd.Messages().Get(0).Messages().Get(0),
-		name:   "test.FooMessage.BarMessage",
-		want:   fd.Messages().Get(0).Messages().Get(1),
-	}, {
-		parent: fd.Messages().Get(0).Messages().Get(0),
-		name:   "test.BarMessage.FooMessage",
-		want:   nil,
-	}, {
-		parent: fd.Messages().Get(0).Messages().Get(0),
-		name:   "test.BarMessage",
-		want:   fd.Messages().Get(1),
-	}, {
-		parent: fd.Messages().Get(0).Messages().Get(0),
-		name:   "test.BarMessageExtra",
-		want:   nil,
-	}, {
-		parent: fd.Messages().Get(0).Messages().Get(0),
-		name:   "taste.BarMessage",
-		want:   nil,
-	}}
-
-	for _, tt := range tests {
-		got := resolveReference(tt.parent, tt.name)
-		if got != tt.want {
-			fullName := func(d pref.Descriptor) string {
-				if d == nil {
-					return "<nil>"
-				}
-				return string(d.FullName())
-			}
-			t.Errorf("resolveReference(%v, %v) = %v, want %v", fullName(tt.parent), tt.name, fullName(got), fullName(tt.want))
-		}
-	}
-}
diff --git a/internal/prototype/standalone.go b/internal/prototype/standalone.go
deleted file mode 100644
index 05b123e..0000000
--- a/internal/prototype/standalone.go
+++ /dev/null
@@ -1,135 +0,0 @@
-// Copyright 2018 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
-
-import (
-	"google.golang.org/protobuf/internal/errors"
-	"google.golang.org/protobuf/reflect/protoreflect"
-)
-
-// TODO: Should the constructors take in a value rather than a pointer?
-// TODO: Support initializing StandaloneMessage from a google.protobuf.Type?
-
-// StandaloneMessage is a constructor for a protoreflect.MessageDescriptor
-// that does not have a parent and has no child declarations.
-type StandaloneMessage struct {
-	Syntax                protoreflect.Syntax
-	FullName              protoreflect.FullName
-	Fields                []Field
-	Oneofs                []Oneof
-	ReservedNames         []protoreflect.Name
-	ReservedRanges        [][2]protoreflect.FieldNumber
-	ExtensionRanges       [][2]protoreflect.FieldNumber
-	ExtensionRangeOptions []protoreflect.ProtoMessage
-	Options               protoreflect.ProtoMessage
-	IsMapEntry            bool
-
-	fields fieldsMeta
-	oneofs oneofsMeta
-	nums   numbersMeta
-}
-
-// NewMessage creates a new protoreflect.MessageDescriptor.
-// The caller must relinquish full ownership of the input t and must not
-// access or mutate any fields.
-func NewMessage(t *StandaloneMessage) (protoreflect.MessageDescriptor, error) {
-	mt := standaloneMessage{t}
-	if err := validateMessage(mt); err != nil {
-		return nil, err
-	}
-	return mt, nil
-}
-
-// NewMessages creates a set of new protoreflect.MessageDescriptors.
-//
-// This constructor permits the creation of cyclic message types that depend
-// on each other. For example, message A may have a field of type message B,
-// where message B may have a field of type message A. In such a case,
-// a placeholder message is used for these cyclic references.
-//
-// The caller must relinquish full ownership of the input ts and must not
-// access or mutate any fields.
-func NewMessages(ts []*StandaloneMessage) ([]protoreflect.MessageDescriptor, error) {
-	// TODO: Should this be []*T or []T?
-	// TODO: NewMessages is a superset of NewMessage. Do we need NewMessage?
-	ms := map[protoreflect.FullName]protoreflect.MessageDescriptor{}
-	for _, t := range ts {
-		if _, ok := ms[t.FullName]; ok {
-			return nil, errors.New("duplicate message %v", t.FullName)
-		}
-		ms[t.FullName] = standaloneMessage{t}
-	}
-
-	var mts []protoreflect.MessageDescriptor
-	for _, t := range ts {
-		for i, f := range t.Fields {
-			// Resolve placeholder messages with a concrete standalone message.
-			// If this fails, validateMessage will complain about it later.
-			if f.MessageType != nil && f.MessageType.IsPlaceholder() && !f.IsWeak {
-				if m, ok := ms[f.MessageType.FullName()]; ok {
-					t.Fields[i].MessageType = m
-				}
-			}
-		}
-		mt := standaloneMessage{t}
-		if err := validateMessage(mt); err != nil {
-			return nil, err
-		}
-		mts = append(mts, mt)
-	}
-	return mts, nil
-}
-
-// StandaloneEnum is a constructor for a protoreflect.EnumDescriptor
-// that does not have a parent.
-type StandaloneEnum struct {
-	Syntax         protoreflect.Syntax
-	FullName       protoreflect.FullName
-	Values         []EnumValue
-	ReservedNames  []protoreflect.Name
-	ReservedRanges [][2]protoreflect.EnumNumber
-	Options        protoreflect.ProtoMessage
-
-	vals enumValuesMeta
-}
-
-// NewEnum creates a new protoreflect.EnumDescriptor.
-// The caller must relinquish full ownership of the input t and must not
-// access or mutate any fields.
-func NewEnum(t *StandaloneEnum) (protoreflect.EnumDescriptor, error) {
-	et := standaloneEnum{t}
-	if err := validateEnum(et); err != nil {
-		return nil, err
-	}
-	return et, nil
-}
-
-// StandaloneExtension is a constructor for a protoreflect.ExtensionDescriptor
-// that does not have a parent.
-type StandaloneExtension struct {
-	FullName     protoreflect.FullName
-	Number       protoreflect.FieldNumber
-	Cardinality  protoreflect.Cardinality
-	Kind         protoreflect.Kind
-	Default      protoreflect.Value
-	MessageType  protoreflect.MessageDescriptor
-	EnumType     protoreflect.EnumDescriptor
-	ExtendedType protoreflect.MessageDescriptor
-	Options      protoreflect.ProtoMessage
-	IsPacked     OptionalBool
-
-	dv defaultValue
-}
-
-// NewExtension creates a new protoreflect.ExtensionDescriptor.
-// The caller must relinquish full ownership of the input t and must not
-// access or mutate any fields.
-func NewExtension(t *StandaloneExtension) (protoreflect.ExtensionDescriptor, error) {
-	xt := standaloneExtension{t}
-	if err := validateExtension(xt); err != nil {
-		return nil, err
-	}
-	return xt, nil
-}
diff --git a/internal/prototype/standalone_type.go b/internal/prototype/standalone_type.go
deleted file mode 100644
index e7da649..0000000
--- a/internal/prototype/standalone_type.go
+++ /dev/null
@@ -1,105 +0,0 @@
-// Copyright 2018 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
-
-import (
-	"fmt"
-
-	"google.golang.org/protobuf/internal/descfmt"
-	"google.golang.org/protobuf/internal/descopts"
-	"google.golang.org/protobuf/internal/pragma"
-	pref "google.golang.org/protobuf/reflect/protoreflect"
-)
-
-type standaloneMessage struct{ m *StandaloneMessage }
-
-func (t standaloneMessage) ParentFile() pref.FileDescriptor { return nil }
-func (t standaloneMessage) Parent() pref.Descriptor         { return nil }
-func (t standaloneMessage) Index() int                      { return 0 }
-func (t standaloneMessage) Syntax() pref.Syntax             { return t.m.Syntax }
-func (t standaloneMessage) Name() pref.Name                 { return t.m.FullName.Name() }
-func (t standaloneMessage) FullName() pref.FullName         { return t.m.FullName }
-func (t standaloneMessage) IsPlaceholder() bool             { return false }
-func (t standaloneMessage) Options() pref.ProtoMessage {
-	return altOptions(t.m.Options, descopts.Message)
-}
-func (t standaloneMessage) IsMapEntry() bool              { return t.m.IsMapEntry }
-func (t standaloneMessage) Fields() pref.FieldDescriptors { return t.m.fields.lazyInit(t, t.m.Fields) }
-func (t standaloneMessage) Oneofs() pref.OneofDescriptors { return t.m.oneofs.lazyInit(t, t.m.Oneofs) }
-func (t standaloneMessage) ReservedNames() pref.Names     { return (*names)(&t.m.ReservedNames) }
-func (t standaloneMessage) ReservedRanges() pref.FieldRanges {
-	return (*fieldRanges)(&t.m.ReservedRanges)
-}
-func (t standaloneMessage) RequiredNumbers() pref.FieldNumbers { return t.m.nums.lazyInit(t.m.Fields) }
-func (t standaloneMessage) ExtensionRanges() pref.FieldRanges {
-	return (*fieldRanges)(&t.m.ExtensionRanges)
-}
-func (t standaloneMessage) ExtensionRangeOptions(i int) pref.ProtoMessage {
-	return extensionRangeOptions(i, len(t.m.ExtensionRanges), t.m.ExtensionRangeOptions)
-}
-func (t standaloneMessage) Enums() pref.EnumDescriptors           { return &emptyEnums }
-func (t standaloneMessage) Messages() pref.MessageDescriptors     { return &emptyMessages }
-func (t standaloneMessage) Extensions() pref.ExtensionDescriptors { return &emptyExtensions }
-func (t standaloneMessage) Format(s fmt.State, r rune)            { descfmt.FormatDesc(s, r, t) }
-func (t standaloneMessage) ProtoType(pref.MessageDescriptor)      {}
-func (t standaloneMessage) ProtoInternal(pragma.DoNotImplement)   {}
-
-type standaloneEnum struct{ e *StandaloneEnum }
-
-func (t standaloneEnum) ParentFile() pref.FileDescriptor { return nil }
-func (t standaloneEnum) Parent() pref.Descriptor         { return nil }
-func (t standaloneEnum) Index() int                      { return 0 }
-func (t standaloneEnum) Syntax() pref.Syntax             { return t.e.Syntax }
-func (t standaloneEnum) Name() pref.Name                 { return t.e.FullName.Name() }
-func (t standaloneEnum) FullName() pref.FullName         { return t.e.FullName }
-func (t standaloneEnum) IsPlaceholder() bool             { return false }
-func (t standaloneEnum) Options() pref.ProtoMessage {
-	return altOptions(t.e.Options, descopts.Enum)
-}
-func (t standaloneEnum) Values() pref.EnumValueDescriptors   { return t.e.vals.lazyInit(t, t.e.Values) }
-func (t standaloneEnum) ReservedNames() pref.Names           { return (*names)(&t.e.ReservedNames) }
-func (t standaloneEnum) ReservedRanges() pref.EnumRanges     { return (*enumRanges)(&t.e.ReservedRanges) }
-func (t standaloneEnum) Format(s fmt.State, r rune)          { descfmt.FormatDesc(s, r, t) }
-func (t standaloneEnum) ProtoType(pref.EnumDescriptor)       {}
-func (t standaloneEnum) ProtoInternal(pragma.DoNotImplement) {}
-
-type standaloneExtension struct{ x *StandaloneExtension }
-
-func (t standaloneExtension) ParentFile() pref.FileDescriptor { return nil }
-func (t standaloneExtension) Parent() pref.Descriptor         { return nil }
-func (t standaloneExtension) Index() int                      { return 0 }
-func (t standaloneExtension) Syntax() pref.Syntax             { return pref.Proto2 }
-func (t standaloneExtension) Name() pref.Name                 { return t.x.FullName.Name() }
-func (t standaloneExtension) FullName() pref.FullName         { return t.x.FullName }
-func (t standaloneExtension) IsPlaceholder() bool             { return false }
-func (t standaloneExtension) Options() pref.ProtoMessage {
-	return altOptions(t.x.Options, descopts.Field)
-}
-func (t standaloneExtension) Number() pref.FieldNumber      { return t.x.Number }
-func (t standaloneExtension) Cardinality() pref.Cardinality { return t.x.Cardinality }
-func (t standaloneExtension) Kind() pref.Kind               { return t.x.Kind }
-func (t standaloneExtension) HasJSONName() bool             { return false }
-func (t standaloneExtension) JSONName() string              { return "" }
-func (t standaloneExtension) IsPacked() bool {
-	return isPacked(t.x.IsPacked, pref.Proto2, t.x.Cardinality, t.x.Kind)
-}
-func (t standaloneExtension) IsExtension() bool              { return true }
-func (t standaloneExtension) IsWeak() bool                   { return false }
-func (t standaloneExtension) IsList() bool                   { return t.x.Cardinality == pref.Repeated }
-func (t standaloneExtension) IsMap() bool                    { return false }
-func (t standaloneExtension) MapKey() pref.FieldDescriptor   { return nil }
-func (t standaloneExtension) MapValue() pref.FieldDescriptor { return nil }
-func (t standaloneExtension) HasDefault() bool               { return t.x.Default.IsValid() }
-func (t standaloneExtension) Default() pref.Value            { return t.x.dv.value(t, t.x.Default) }
-func (t standaloneExtension) DefaultEnumValue() pref.EnumValueDescriptor {
-	return t.x.dv.enum(t, t.x.Default)
-}
-func (t standaloneExtension) ContainingOneof() pref.OneofDescriptor     { return nil }
-func (t standaloneExtension) ContainingMessage() pref.MessageDescriptor { return t.x.ExtendedType }
-func (t standaloneExtension) Enum() pref.EnumDescriptor                 { return t.x.EnumType }
-func (t standaloneExtension) Message() pref.MessageDescriptor           { return t.x.MessageType }
-func (t standaloneExtension) Format(s fmt.State, r rune)                { descfmt.FormatDesc(s, r, t) }
-func (t standaloneExtension) ProtoType(pref.FieldDescriptor)            {}
-func (t standaloneExtension) ProtoInternal(pragma.DoNotImplement)       {}
diff --git a/internal/prototype/validate.go b/internal/prototype/validate.go
deleted file mode 100644
index 406d5e0..0000000
--- a/internal/prototype/validate.go
+++ /dev/null
@@ -1,46 +0,0 @@
-// Copyright 2018 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
-
-import (
-	pref "google.golang.org/protobuf/reflect/protoreflect"
-)
-
-// TODO: This is important to prevent users from creating invalid types,
-// but is not functionality needed now.
-//
-// Things to verify:
-//	* Weak fields are only used if flags.Proto1Legacy is set
-//	* Weak fields can only reference singular messages
-//	(check if this the case for oneof fields)
-//	* FieldDescriptor.MessageType cannot reference a remote type when the
-//	remote name is a type within the local file.
-//	* Default enum identifiers resolve to a declared number.
-//	* Default values are only allowed in proto2.
-//	* Default strings are valid UTF-8? Note that protoc does not check this.
-//	* Field extensions are only valid in proto2, except when extending the
-//	descriptor options.
-//	* Remote enum and message types are actually found in imported files.
-//	* Placeholder messages and types may only be for weak fields.
-//	* Placeholder full names must be valid.
-//	* The name of each descriptor must be valid.
-//	* Options are of the correct Go type (e.g. *descriptorpb.MessageOptions).
-// 	* len(ExtensionRangeOptions) <= len(ExtensionRanges)
-
-func validateFile(t pref.FileDescriptor) error {
-	return nil
-}
-
-func validateMessage(t pref.MessageDescriptor) error {
-	return nil
-}
-
-func validateExtension(t pref.ExtensionDescriptor) error {
-	return nil
-}
-
-func validateEnum(t pref.EnumDescriptor) error {
-	return nil
-}
diff --git a/internal/testprotos/conformance/conformance.pb.go b/internal/testprotos/conformance/conformance.pb.go
index b2e21e2..ccdb64c 100644
--- a/internal/testprotos/conformance/conformance.pb.go
+++ b/internal/testprotos/conformance/conformance.pb.go
@@ -5,7 +5,7 @@
 
 import (
 	protoreflect "google.golang.org/protobuf/reflect/protoreflect"
-	protoregistry "google.golang.org/protobuf/reflect/protoregistry"
+	prototype "google.golang.org/protobuf/reflect/prototype"
 	protoiface "google.golang.org/protobuf/runtime/protoiface"
 	protoimpl "google.golang.org/protobuf/runtime/protoimpl"
 	sync "sync"
@@ -57,7 +57,7 @@
 }
 
 func (WireFormat) Descriptor() protoreflect.EnumDescriptor {
-	return file_conformance_conformance_proto_enumTypes[0].Descriptor()
+	return file_conformance_conformance_proto_enumTypes[0].EnumDescriptor
 }
 
 func (x WireFormat) Number() protoreflect.EnumNumber {
@@ -119,7 +119,7 @@
 }
 
 func (TestCategory) Descriptor() protoreflect.EnumDescriptor {
-	return file_conformance_conformance_proto_enumTypes[1].Descriptor()
+	return file_conformance_conformance_proto_enumTypes[1].EnumDescriptor
 }
 
 func (x TestCategory) Number() protoreflect.EnumNumber {
@@ -661,7 +661,7 @@
 	return file_conformance_conformance_proto_rawDescData
 }
 
-var file_conformance_conformance_proto_enumTypes = make([]protoreflect.EnumType, 2)
+var file_conformance_conformance_proto_enumTypes = make([]prototype.Enum, 2)
 var file_conformance_conformance_proto_msgTypes = make([]protoimpl.MessageInfo, 4)
 var file_conformance_conformance_proto_goTypes = []interface{}{
 	(WireFormat)(0),             // 0: conformance.WireFormat
@@ -675,6 +675,11 @@
 	0, // conformance.ConformanceRequest.requested_output_format:type_name -> conformance.WireFormat
 	1, // conformance.ConformanceRequest.test_category:type_name -> conformance.TestCategory
 	5, // conformance.ConformanceRequest.jspb_encoding_options:type_name -> conformance.JspbEncodingConfig
+	3, // starting offset of method output_type sub-list
+	3, // starting offset of method input_type sub-list
+	3, // starting offset of extension type_name sub-list
+	3, // starting offset of extension extendee sub-list
+	0, // starting offset of field type_name sub-list
 }
 
 func init() { file_conformance_conformance_proto_init() }
@@ -682,15 +687,20 @@
 	if File_conformance_conformance_proto != nil {
 		return
 	}
-	File_conformance_conformance_proto = protoimpl.FileBuilder{
-		RawDescriptor:      file_conformance_conformance_proto_rawDesc,
-		GoTypes:            file_conformance_conformance_proto_goTypes,
-		DependencyIndexes:  file_conformance_conformance_proto_depIdxs,
-		EnumOutputTypes:    file_conformance_conformance_proto_enumTypes,
-		MessageOutputTypes: file_conformance_conformance_proto_msgTypes,
-		FilesRegistry:      protoregistry.GlobalFiles,
-		TypesRegistry:      protoregistry.GlobalTypes,
-	}.Init()
+	out := protoimpl.TypeBuilder{
+		File: protoimpl.DescBuilder{
+			RawDescriptor: file_conformance_conformance_proto_rawDesc,
+			NumEnums:      2,
+			NumMessages:   4,
+			NumExtensions: 0,
+			NumServices:   0,
+		},
+		GoTypes:           file_conformance_conformance_proto_goTypes,
+		DependencyIndexes: file_conformance_conformance_proto_depIdxs,
+		MessageInfos:      file_conformance_conformance_proto_msgTypes,
+	}.Build()
+	File_conformance_conformance_proto = out.File
+	file_conformance_conformance_proto_enumTypes = out.Enums
 	file_conformance_conformance_proto_rawDesc = nil
 	file_conformance_conformance_proto_goTypes = nil
 	file_conformance_conformance_proto_depIdxs = nil
diff --git a/internal/testprotos/conformance/test_messages_proto2.pb.go b/internal/testprotos/conformance/test_messages_proto2.pb.go
index 50f5d17..df72bef 100644
--- a/internal/testprotos/conformance/test_messages_proto2.pb.go
+++ b/internal/testprotos/conformance/test_messages_proto2.pb.go
@@ -5,7 +5,7 @@
 
 import (
 	protoreflect "google.golang.org/protobuf/reflect/protoreflect"
-	protoregistry "google.golang.org/protobuf/reflect/protoregistry"
+	prototype "google.golang.org/protobuf/reflect/prototype"
 	protoiface "google.golang.org/protobuf/runtime/protoiface"
 	protoimpl "google.golang.org/protobuf/runtime/protoimpl"
 	sync "sync"
@@ -51,7 +51,7 @@
 }
 
 func (ForeignEnumProto2) Descriptor() protoreflect.EnumDescriptor {
-	return file_google_protobuf_test_messages_proto2_proto_enumTypes[0].Descriptor()
+	return file_google_protobuf_test_messages_proto2_proto_enumTypes[0].EnumDescriptor
 }
 
 func (x ForeignEnumProto2) Number() protoreflect.EnumNumber {
@@ -109,7 +109,7 @@
 }
 
 func (TestAllTypesProto2_NestedEnum) Descriptor() protoreflect.EnumDescriptor {
-	return file_google_protobuf_test_messages_proto2_proto_enumTypes[1].Descriptor()
+	return file_google_protobuf_test_messages_proto2_proto_enumTypes[1].EnumDescriptor
 }
 
 func (x TestAllTypesProto2_NestedEnum) Number() protoreflect.EnumNumber {
@@ -1820,7 +1820,7 @@
 	return file_google_protobuf_test_messages_proto2_proto_rawDescData
 }
 
-var file_google_protobuf_test_messages_proto2_proto_enumTypes = make([]protoreflect.EnumType, 2)
+var file_google_protobuf_test_messages_proto2_proto_enumTypes = make([]prototype.Enum, 2)
 var file_google_protobuf_test_messages_proto2_proto_msgTypes = make([]protoimpl.MessageInfo, 26)
 var file_google_protobuf_test_messages_proto2_proto_goTypes = []interface{}{
 	(ForeignEnumProto2)(0),                   // 0: protobuf_test_messages.proto2.ForeignEnumProto2
@@ -1853,9 +1853,6 @@
 	(*TestAllTypesProto2_MessageSetCorrectExtension2)(nil), // 27: protobuf_test_messages.proto2.TestAllTypesProto2.MessageSetCorrectExtension2
 }
 var file_google_protobuf_test_messages_proto2_proto_depIdxs = []int32{
-	2,  // protobuf_test_messages.proto2.extension_int32:extendee -> protobuf_test_messages.proto2.TestAllTypesProto2
-	25, // protobuf_test_messages.proto2.TestAllTypesProto2.MessageSetCorrectExtension1.message_set_extension:extendee -> protobuf_test_messages.proto2.TestAllTypesProto2.MessageSetCorrect
-	25, // protobuf_test_messages.proto2.TestAllTypesProto2.MessageSetCorrectExtension2.message_set_extension:extendee -> protobuf_test_messages.proto2.TestAllTypesProto2.MessageSetCorrect
 	4,  // protobuf_test_messages.proto2.TestAllTypesProto2.optional_nested_message:type_name -> protobuf_test_messages.proto2.TestAllTypesProto2.NestedMessage
 	3,  // protobuf_test_messages.proto2.TestAllTypesProto2.optional_foreign_message:type_name -> protobuf_test_messages.proto2.ForeignMessageProto2
 	1,  // protobuf_test_messages.proto2.TestAllTypesProto2.optional_nested_enum:type_name -> protobuf_test_messages.proto2.TestAllTypesProto2.NestedEnum
@@ -1892,8 +1889,16 @@
 	3,  // protobuf_test_messages.proto2.TestAllTypesProto2.MapStringForeignMessageEntry.value:type_name -> protobuf_test_messages.proto2.ForeignMessageProto2
 	1,  // protobuf_test_messages.proto2.TestAllTypesProto2.MapStringNestedEnumEntry.value:type_name -> protobuf_test_messages.proto2.TestAllTypesProto2.NestedEnum
 	0,  // protobuf_test_messages.proto2.TestAllTypesProto2.MapStringForeignEnumEntry.value:type_name -> protobuf_test_messages.proto2.ForeignEnumProto2
+	2,  // protobuf_test_messages.proto2.extension_int32:extendee -> protobuf_test_messages.proto2.TestAllTypesProto2
+	25, // protobuf_test_messages.proto2.TestAllTypesProto2.MessageSetCorrectExtension1.message_set_extension:extendee -> protobuf_test_messages.proto2.TestAllTypesProto2.MessageSetCorrect
+	25, // protobuf_test_messages.proto2.TestAllTypesProto2.MessageSetCorrectExtension2.message_set_extension:extendee -> protobuf_test_messages.proto2.TestAllTypesProto2.MessageSetCorrect
 	26, // protobuf_test_messages.proto2.TestAllTypesProto2.MessageSetCorrectExtension1.message_set_extension:type_name -> protobuf_test_messages.proto2.TestAllTypesProto2.MessageSetCorrectExtension1
 	27, // protobuf_test_messages.proto2.TestAllTypesProto2.MessageSetCorrectExtension2.message_set_extension:type_name -> protobuf_test_messages.proto2.TestAllTypesProto2.MessageSetCorrectExtension2
+	41, // starting offset of method output_type sub-list
+	41, // starting offset of method input_type sub-list
+	39, // starting offset of extension type_name sub-list
+	36, // starting offset of extension extendee sub-list
+	0,  // starting offset of field type_name sub-list
 }
 
 func init() { file_google_protobuf_test_messages_proto2_proto_init() }
@@ -1901,18 +1906,21 @@
 	if File_google_protobuf_test_messages_proto2_proto != nil {
 		return
 	}
-	extensionTypes := make([]protoreflect.ExtensionType, 3)
-	File_google_protobuf_test_messages_proto2_proto = protoimpl.FileBuilder{
-		RawDescriptor:        file_google_protobuf_test_messages_proto2_proto_rawDesc,
-		GoTypes:              file_google_protobuf_test_messages_proto2_proto_goTypes,
-		DependencyIndexes:    file_google_protobuf_test_messages_proto2_proto_depIdxs,
-		LegacyExtensions:     file_google_protobuf_test_messages_proto2_proto_extDescs,
-		EnumOutputTypes:      file_google_protobuf_test_messages_proto2_proto_enumTypes,
-		MessageOutputTypes:   file_google_protobuf_test_messages_proto2_proto_msgTypes,
-		ExtensionOutputTypes: extensionTypes,
-		FilesRegistry:        protoregistry.GlobalFiles,
-		TypesRegistry:        protoregistry.GlobalTypes,
-	}.Init()
+	out := protoimpl.TypeBuilder{
+		File: protoimpl.DescBuilder{
+			RawDescriptor: file_google_protobuf_test_messages_proto2_proto_rawDesc,
+			NumEnums:      2,
+			NumMessages:   26,
+			NumExtensions: 3,
+			NumServices:   0,
+		},
+		GoTypes:           file_google_protobuf_test_messages_proto2_proto_goTypes,
+		DependencyIndexes: file_google_protobuf_test_messages_proto2_proto_depIdxs,
+		MessageInfos:      file_google_protobuf_test_messages_proto2_proto_msgTypes,
+		LegacyExtensions:  file_google_protobuf_test_messages_proto2_proto_extDescs,
+	}.Build()
+	File_google_protobuf_test_messages_proto2_proto = out.File
+	file_google_protobuf_test_messages_proto2_proto_enumTypes = out.Enums
 	file_google_protobuf_test_messages_proto2_proto_rawDesc = nil
 	file_google_protobuf_test_messages_proto2_proto_goTypes = nil
 	file_google_protobuf_test_messages_proto2_proto_depIdxs = nil
diff --git a/internal/testprotos/conformance/test_messages_proto3.pb.go b/internal/testprotos/conformance/test_messages_proto3.pb.go
index 75ffa5b..97e5fef 100644
--- a/internal/testprotos/conformance/test_messages_proto3.pb.go
+++ b/internal/testprotos/conformance/test_messages_proto3.pb.go
@@ -5,7 +5,7 @@
 
 import (
 	protoreflect "google.golang.org/protobuf/reflect/protoreflect"
-	protoregistry "google.golang.org/protobuf/reflect/protoregistry"
+	prototype "google.golang.org/protobuf/reflect/prototype"
 	protoiface "google.golang.org/protobuf/runtime/protoiface"
 	protoimpl "google.golang.org/protobuf/runtime/protoimpl"
 	anypb "google.golang.org/protobuf/types/known/anypb"
@@ -57,7 +57,7 @@
 }
 
 func (ForeignEnum) Descriptor() protoreflect.EnumDescriptor {
-	return file_google_protobuf_test_messages_proto3_proto_enumTypes[0].Descriptor()
+	return file_google_protobuf_test_messages_proto3_proto_enumTypes[0].EnumDescriptor
 }
 
 func (x ForeignEnum) Number() protoreflect.EnumNumber {
@@ -105,7 +105,7 @@
 }
 
 func (TestAllTypesProto3_NestedEnum) Descriptor() protoreflect.EnumDescriptor {
-	return file_google_protobuf_test_messages_proto3_proto_enumTypes[1].Descriptor()
+	return file_google_protobuf_test_messages_proto3_proto_enumTypes[1].EnumDescriptor
 }
 
 func (x TestAllTypesProto3_NestedEnum) Number() protoreflect.EnumNumber {
@@ -159,7 +159,7 @@
 }
 
 func (TestAllTypesProto3_AliasedEnum) Descriptor() protoreflect.EnumDescriptor {
-	return file_google_protobuf_test_messages_proto3_proto_enumTypes[2].Descriptor()
+	return file_google_protobuf_test_messages_proto3_proto_enumTypes[2].EnumDescriptor
 }
 
 func (x TestAllTypesProto3_AliasedEnum) Number() protoreflect.EnumNumber {
@@ -2029,7 +2029,7 @@
 	return file_google_protobuf_test_messages_proto3_proto_rawDescData
 }
 
-var file_google_protobuf_test_messages_proto3_proto_enumTypes = make([]protoreflect.EnumType, 3)
+var file_google_protobuf_test_messages_proto3_proto_enumTypes = make([]prototype.Enum, 3)
 var file_google_protobuf_test_messages_proto3_proto_msgTypes = make([]protoimpl.MessageInfo, 22)
 var file_google_protobuf_test_messages_proto3_proto_goTypes = []interface{}{
 	(ForeignEnum)(0),                         // 0: protobuf_test_messages.proto3.ForeignEnum
@@ -2142,6 +2142,11 @@
 	4,  // protobuf_test_messages.proto3.TestAllTypesProto3.MapStringForeignMessageEntry.value:type_name -> protobuf_test_messages.proto3.ForeignMessage
 	1,  // protobuf_test_messages.proto3.TestAllTypesProto3.MapStringNestedEnumEntry.value:type_name -> protobuf_test_messages.proto3.TestAllTypesProto3.NestedEnum
 	0,  // protobuf_test_messages.proto3.TestAllTypesProto3.MapStringForeignEnumEntry.value:type_name -> protobuf_test_messages.proto3.ForeignEnum
+	67, // starting offset of method output_type sub-list
+	67, // starting offset of method input_type sub-list
+	67, // starting offset of extension type_name sub-list
+	67, // starting offset of extension extendee sub-list
+	0,  // starting offset of field type_name sub-list
 }
 
 func init() { file_google_protobuf_test_messages_proto3_proto_init() }
@@ -2149,15 +2154,20 @@
 	if File_google_protobuf_test_messages_proto3_proto != nil {
 		return
 	}
-	File_google_protobuf_test_messages_proto3_proto = protoimpl.FileBuilder{
-		RawDescriptor:      file_google_protobuf_test_messages_proto3_proto_rawDesc,
-		GoTypes:            file_google_protobuf_test_messages_proto3_proto_goTypes,
-		DependencyIndexes:  file_google_protobuf_test_messages_proto3_proto_depIdxs,
-		EnumOutputTypes:    file_google_protobuf_test_messages_proto3_proto_enumTypes,
-		MessageOutputTypes: file_google_protobuf_test_messages_proto3_proto_msgTypes,
-		FilesRegistry:      protoregistry.GlobalFiles,
-		TypesRegistry:      protoregistry.GlobalTypes,
-	}.Init()
+	out := protoimpl.TypeBuilder{
+		File: protoimpl.DescBuilder{
+			RawDescriptor: file_google_protobuf_test_messages_proto3_proto_rawDesc,
+			NumEnums:      3,
+			NumMessages:   22,
+			NumExtensions: 0,
+			NumServices:   0,
+		},
+		GoTypes:           file_google_protobuf_test_messages_proto3_proto_goTypes,
+		DependencyIndexes: file_google_protobuf_test_messages_proto3_proto_depIdxs,
+		MessageInfos:      file_google_protobuf_test_messages_proto3_proto_msgTypes,
+	}.Build()
+	File_google_protobuf_test_messages_proto3_proto = out.File
+	file_google_protobuf_test_messages_proto3_proto_enumTypes = out.Enums
 	file_google_protobuf_test_messages_proto3_proto_rawDesc = nil
 	file_google_protobuf_test_messages_proto3_proto_goTypes = nil
 	file_google_protobuf_test_messages_proto3_proto_depIdxs = nil
diff --git a/internal/testprotos/irregular/test.pb.go b/internal/testprotos/irregular/test.pb.go
index fa6aafd..93092dc 100644
--- a/internal/testprotos/irregular/test.pb.go
+++ b/internal/testprotos/irregular/test.pb.go
@@ -5,7 +5,6 @@
 
 import (
 	protoreflect "google.golang.org/protobuf/reflect/protoreflect"
-	protoregistry "google.golang.org/protobuf/reflect/protoregistry"
 	protoiface "google.golang.org/protobuf/runtime/protoiface"
 	protoimpl "google.golang.org/protobuf/runtime/protoimpl"
 	sync "sync"
@@ -186,6 +185,11 @@
 	1, // goproto.proto.irregular.Message.map_message:type_name -> goproto.proto.irregular.Message.MapMessageEntry
 	2, // goproto.proto.irregular.Message.oneof_message:type_name -> goproto.proto.irregular.IrregularMessage
 	2, // goproto.proto.irregular.Message.MapMessageEntry.value:type_name -> goproto.proto.irregular.IrregularMessage
+	6, // starting offset of method output_type sub-list
+	6, // starting offset of method input_type sub-list
+	6, // starting offset of extension type_name sub-list
+	6, // starting offset of extension extendee sub-list
+	0, // starting offset of field type_name sub-list
 }
 
 func init() { file_irregular_test_proto_init() }
@@ -194,14 +198,19 @@
 		return
 	}
 	file_irregular_irregular_proto_init()
-	File_irregular_test_proto = protoimpl.FileBuilder{
-		RawDescriptor:      file_irregular_test_proto_rawDesc,
-		GoTypes:            file_irregular_test_proto_goTypes,
-		DependencyIndexes:  file_irregular_test_proto_depIdxs,
-		MessageOutputTypes: file_irregular_test_proto_msgTypes,
-		FilesRegistry:      protoregistry.GlobalFiles,
-		TypesRegistry:      protoregistry.GlobalTypes,
-	}.Init()
+	out := protoimpl.TypeBuilder{
+		File: protoimpl.DescBuilder{
+			RawDescriptor: file_irregular_test_proto_rawDesc,
+			NumEnums:      0,
+			NumMessages:   2,
+			NumExtensions: 0,
+			NumServices:   0,
+		},
+		GoTypes:           file_irregular_test_proto_goTypes,
+		DependencyIndexes: file_irregular_test_proto_depIdxs,
+		MessageInfos:      file_irregular_test_proto_msgTypes,
+	}.Build()
+	File_irregular_test_proto = out.File
 	file_irregular_test_proto_rawDesc = nil
 	file_irregular_test_proto_goTypes = nil
 	file_irregular_test_proto_depIdxs = nil
diff --git a/internal/testprotos/legacy/legacy.pb.go b/internal/testprotos/legacy/legacy.pb.go
index f867906..86793a1 100644
--- a/internal/testprotos/legacy/legacy.pb.go
+++ b/internal/testprotos/legacy/legacy.pb.go
@@ -17,7 +17,6 @@
 	proto3_v1_2 "google.golang.org/protobuf/internal/testprotos/legacy/proto3.v1.2.0-20180814-aa810b61"
 	proto3_v1_21 "google.golang.org/protobuf/internal/testprotos/legacy/proto3.v1.2.1-20181126-8d0c54c1"
 	protoreflect "google.golang.org/protobuf/reflect/protoreflect"
-	protoregistry "google.golang.org/protobuf/reflect/protoregistry"
 	protoiface "google.golang.org/protobuf/runtime/protoiface"
 	protoimpl "google.golang.org/protobuf/runtime/protoimpl"
 	sync "sync"
@@ -292,6 +291,11 @@
 	10, // google.golang.org.Legacy.f10:type_name -> google.golang.org.proto3_20180814.Message
 	11, // google.golang.org.Legacy.f11:type_name -> google.golang.org.proto2_20181126.Message
 	12, // google.golang.org.Legacy.f12:type_name -> google.golang.org.proto3_20181126.Message
+	12, // starting offset of method output_type sub-list
+	12, // starting offset of method input_type sub-list
+	12, // starting offset of extension type_name sub-list
+	12, // starting offset of extension extendee sub-list
+	0,  // starting offset of field type_name sub-list
 }
 
 func init() { file_legacy_legacy_proto_init() }
@@ -299,14 +303,19 @@
 	if File_legacy_legacy_proto != nil {
 		return
 	}
-	File_legacy_legacy_proto = protoimpl.FileBuilder{
-		RawDescriptor:      file_legacy_legacy_proto_rawDesc,
-		GoTypes:            file_legacy_legacy_proto_goTypes,
-		DependencyIndexes:  file_legacy_legacy_proto_depIdxs,
-		MessageOutputTypes: file_legacy_legacy_proto_msgTypes,
-		FilesRegistry:      protoregistry.GlobalFiles,
-		TypesRegistry:      protoregistry.GlobalTypes,
-	}.Init()
+	out := protoimpl.TypeBuilder{
+		File: protoimpl.DescBuilder{
+			RawDescriptor: file_legacy_legacy_proto_rawDesc,
+			NumEnums:      0,
+			NumMessages:   1,
+			NumExtensions: 0,
+			NumServices:   0,
+		},
+		GoTypes:           file_legacy_legacy_proto_goTypes,
+		DependencyIndexes: file_legacy_legacy_proto_depIdxs,
+		MessageInfos:      file_legacy_legacy_proto_msgTypes,
+	}.Build()
+	File_legacy_legacy_proto = out.File
 	file_legacy_legacy_proto_rawDesc = nil
 	file_legacy_legacy_proto_goTypes = nil
 	file_legacy_legacy_proto_depIdxs = nil
diff --git a/internal/testprotos/test/ext.pb.go b/internal/testprotos/test/ext.pb.go
index 58cb656..7a3363c 100644
--- a/internal/testprotos/test/ext.pb.go
+++ b/internal/testprotos/test/ext.pb.go
@@ -5,7 +5,6 @@
 
 import (
 	protoreflect "google.golang.org/protobuf/reflect/protoreflect"
-	protoregistry "google.golang.org/protobuf/reflect/protoregistry"
 	protoiface "google.golang.org/protobuf/runtime/protoiface"
 	protoimpl "google.golang.org/protobuf/runtime/protoimpl"
 	sync "sync"
@@ -67,6 +66,11 @@
 }
 var file_test_ext_proto_depIdxs = []int32{
 	0, // goproto.proto.test.foreign_int32_extension:extendee -> goproto.proto.test.TestAllExtensions
+	1, // starting offset of method output_type sub-list
+	1, // starting offset of method input_type sub-list
+	1, // starting offset of extension type_name sub-list
+	0, // starting offset of extension extendee sub-list
+	0, // starting offset of field type_name sub-list
 }
 
 func init() { file_test_ext_proto_init() }
@@ -75,16 +79,19 @@
 		return
 	}
 	file_test_test_proto_init()
-	extensionTypes := make([]protoreflect.ExtensionType, 1)
-	File_test_ext_proto = protoimpl.FileBuilder{
-		RawDescriptor:        file_test_ext_proto_rawDesc,
-		GoTypes:              file_test_ext_proto_goTypes,
-		DependencyIndexes:    file_test_ext_proto_depIdxs,
-		LegacyExtensions:     file_test_ext_proto_extDescs,
-		ExtensionOutputTypes: extensionTypes,
-		FilesRegistry:        protoregistry.GlobalFiles,
-		TypesRegistry:        protoregistry.GlobalTypes,
-	}.Init()
+	out := protoimpl.TypeBuilder{
+		File: protoimpl.DescBuilder{
+			RawDescriptor: file_test_ext_proto_rawDesc,
+			NumEnums:      0,
+			NumMessages:   0,
+			NumExtensions: 1,
+			NumServices:   0,
+		},
+		GoTypes:           file_test_ext_proto_goTypes,
+		DependencyIndexes: file_test_ext_proto_depIdxs,
+		LegacyExtensions:  file_test_ext_proto_extDescs,
+	}.Build()
+	File_test_ext_proto = out.File
 	file_test_ext_proto_rawDesc = nil
 	file_test_ext_proto_goTypes = nil
 	file_test_ext_proto_depIdxs = nil
diff --git a/internal/testprotos/test/test.pb.go b/internal/testprotos/test/test.pb.go
index 225870f..809a20c 100644
--- a/internal/testprotos/test/test.pb.go
+++ b/internal/testprotos/test/test.pb.go
@@ -6,7 +6,7 @@
 import (
 	weak "google.golang.org/protobuf/internal/testprotos/test/weak"
 	protoreflect "google.golang.org/protobuf/reflect/protoreflect"
-	protoregistry "google.golang.org/protobuf/reflect/protoregistry"
+	prototype "google.golang.org/protobuf/reflect/prototype"
 	protoiface "google.golang.org/protobuf/runtime/protoiface"
 	protoimpl "google.golang.org/protobuf/runtime/protoimpl"
 	sync "sync"
@@ -52,7 +52,7 @@
 }
 
 func (ForeignEnum) Descriptor() protoreflect.EnumDescriptor {
-	return file_test_test_proto_enumTypes[0].Descriptor()
+	return file_test_test_proto_enumTypes[0].EnumDescriptor
 }
 
 func (x ForeignEnum) Number() protoreflect.EnumNumber {
@@ -101,7 +101,7 @@
 }
 
 func (TestReservedEnumFields) Descriptor() protoreflect.EnumDescriptor {
-	return file_test_test_proto_enumTypes[1].Descriptor()
+	return file_test_test_proto_enumTypes[1].EnumDescriptor
 }
 
 func (x TestReservedEnumFields) Number() protoreflect.EnumNumber {
@@ -159,7 +159,7 @@
 }
 
 func (TestAllTypes_NestedEnum) Descriptor() protoreflect.EnumDescriptor {
-	return file_test_test_proto_enumTypes[2].Descriptor()
+	return file_test_test_proto_enumTypes[2].EnumDescriptor
 }
 
 func (x TestAllTypes_NestedEnum) Number() protoreflect.EnumNumber {
@@ -207,7 +207,7 @@
 }
 
 func (TestDeprecatedMessage_DeprecatedEnum) Descriptor() protoreflect.EnumDescriptor {
-	return file_test_test_proto_enumTypes[3].Descriptor()
+	return file_test_test_proto_enumTypes[3].EnumDescriptor
 }
 
 func (x TestDeprecatedMessage_DeprecatedEnum) Number() protoreflect.EnumNumber {
@@ -3298,7 +3298,7 @@
 	return file_test_test_proto_rawDescData
 }
 
-var file_test_test_proto_enumTypes = make([]protoreflect.EnumType, 4)
+var file_test_test_proto_enumTypes = make([]prototype.Enum, 4)
 var file_test_test_proto_msgTypes = make([]protoimpl.MessageInfo, 37)
 var file_test_test_proto_goTypes = []interface{}{
 	(ForeignEnum)(0),                          // 0: goproto.proto.test.ForeignEnum
@@ -3346,118 +3346,123 @@
 	(ImportEnum)(0),                               // 42: goproto.proto.test.ImportEnum
 }
 var file_test_test_proto_depIdxs = []int32{
-	8,  // goproto.proto.test.optional_int32_extension:extendee -> goproto.proto.test.TestAllExtensions
-	8,  // goproto.proto.test.optional_int64_extension:extendee -> goproto.proto.test.TestAllExtensions
-	8,  // goproto.proto.test.optional_uint32_extension:extendee -> goproto.proto.test.TestAllExtensions
-	8,  // goproto.proto.test.optional_uint64_extension:extendee -> goproto.proto.test.TestAllExtensions
-	8,  // goproto.proto.test.optional_sint32_extension:extendee -> goproto.proto.test.TestAllExtensions
-	8,  // goproto.proto.test.optional_sint64_extension:extendee -> goproto.proto.test.TestAllExtensions
-	8,  // goproto.proto.test.optional_fixed32_extension:extendee -> goproto.proto.test.TestAllExtensions
-	8,  // goproto.proto.test.optional_fixed64_extension:extendee -> goproto.proto.test.TestAllExtensions
-	8,  // goproto.proto.test.optional_sfixed32_extension:extendee -> goproto.proto.test.TestAllExtensions
-	8,  // goproto.proto.test.optional_sfixed64_extension:extendee -> goproto.proto.test.TestAllExtensions
-	8,  // goproto.proto.test.optional_float_extension:extendee -> goproto.proto.test.TestAllExtensions
-	8,  // goproto.proto.test.optional_double_extension:extendee -> goproto.proto.test.TestAllExtensions
-	8,  // goproto.proto.test.optional_bool_extension:extendee -> goproto.proto.test.TestAllExtensions
-	8,  // goproto.proto.test.optional_string_extension:extendee -> goproto.proto.test.TestAllExtensions
-	8,  // goproto.proto.test.optional_bytes_extension:extendee -> goproto.proto.test.TestAllExtensions
-	8,  // goproto.proto.test.optionalgroup_extension:extendee -> goproto.proto.test.TestAllExtensions
-	8,  // goproto.proto.test.optional_nested_message_extension:extendee -> goproto.proto.test.TestAllExtensions
-	8,  // goproto.proto.test.optional_nested_enum_extension:extendee -> goproto.proto.test.TestAllExtensions
-	8,  // goproto.proto.test.repeated_int32_extension:extendee -> goproto.proto.test.TestAllExtensions
-	8,  // goproto.proto.test.repeated_int64_extension:extendee -> goproto.proto.test.TestAllExtensions
-	8,  // goproto.proto.test.repeated_uint32_extension:extendee -> goproto.proto.test.TestAllExtensions
-	8,  // goproto.proto.test.repeated_uint64_extension:extendee -> goproto.proto.test.TestAllExtensions
-	8,  // goproto.proto.test.repeated_sint32_extension:extendee -> goproto.proto.test.TestAllExtensions
-	8,  // goproto.proto.test.repeated_sint64_extension:extendee -> goproto.proto.test.TestAllExtensions
-	8,  // goproto.proto.test.repeated_fixed32_extension:extendee -> goproto.proto.test.TestAllExtensions
-	8,  // goproto.proto.test.repeated_fixed64_extension:extendee -> goproto.proto.test.TestAllExtensions
-	8,  // goproto.proto.test.repeated_sfixed32_extension:extendee -> goproto.proto.test.TestAllExtensions
-	8,  // goproto.proto.test.repeated_sfixed64_extension:extendee -> goproto.proto.test.TestAllExtensions
-	8,  // goproto.proto.test.repeated_float_extension:extendee -> goproto.proto.test.TestAllExtensions
-	8,  // goproto.proto.test.repeated_double_extension:extendee -> goproto.proto.test.TestAllExtensions
-	8,  // goproto.proto.test.repeated_bool_extension:extendee -> goproto.proto.test.TestAllExtensions
-	8,  // goproto.proto.test.repeated_string_extension:extendee -> goproto.proto.test.TestAllExtensions
-	8,  // goproto.proto.test.repeated_bytes_extension:extendee -> goproto.proto.test.TestAllExtensions
-	8,  // goproto.proto.test.repeatedgroup_extension:extendee -> goproto.proto.test.TestAllExtensions
-	8,  // goproto.proto.test.repeated_nested_message_extension:extendee -> goproto.proto.test.TestAllExtensions
-	8,  // goproto.proto.test.repeated_nested_enum_extension:extendee -> goproto.proto.test.TestAllExtensions
-	8,  // goproto.proto.test.default_int32_extension:extendee -> goproto.proto.test.TestAllExtensions
-	8,  // goproto.proto.test.default_int64_extension:extendee -> goproto.proto.test.TestAllExtensions
-	8,  // goproto.proto.test.default_uint32_extension:extendee -> goproto.proto.test.TestAllExtensions
-	8,  // goproto.proto.test.default_uint64_extension:extendee -> goproto.proto.test.TestAllExtensions
-	8,  // goproto.proto.test.default_sint32_extension:extendee -> goproto.proto.test.TestAllExtensions
-	8,  // goproto.proto.test.default_sint64_extension:extendee -> goproto.proto.test.TestAllExtensions
-	8,  // goproto.proto.test.default_fixed32_extension:extendee -> goproto.proto.test.TestAllExtensions
-	8,  // goproto.proto.test.default_fixed64_extension:extendee -> goproto.proto.test.TestAllExtensions
-	8,  // goproto.proto.test.default_sfixed32_extension:extendee -> goproto.proto.test.TestAllExtensions
-	8,  // goproto.proto.test.default_sfixed64_extension:extendee -> goproto.proto.test.TestAllExtensions
-	8,  // goproto.proto.test.default_float_extension:extendee -> goproto.proto.test.TestAllExtensions
-	8,  // goproto.proto.test.default_double_extension:extendee -> goproto.proto.test.TestAllExtensions
-	8,  // goproto.proto.test.default_bool_extension:extendee -> goproto.proto.test.TestAllExtensions
-	8,  // goproto.proto.test.default_string_extension:extendee -> goproto.proto.test.TestAllExtensions
-	8,  // goproto.proto.test.default_bytes_extension:extendee -> goproto.proto.test.TestAllExtensions
-	8,  // goproto.proto.test.TestNestedExtension.nested_string_extension:extendee -> goproto.proto.test.TestAllExtensions
-	8,  // goproto.proto.test.TestRequired.single:extendee -> goproto.proto.test.TestAllExtensions
-	8,  // goproto.proto.test.TestRequired.multi:extendee -> goproto.proto.test.TestAllExtensions
-	19, // goproto.proto.test.TestAllTypes.optionalgroup:type_name -> goproto.proto.test.TestAllTypes.OptionalGroup
-	18, // goproto.proto.test.TestAllTypes.optional_nested_message:type_name -> goproto.proto.test.TestAllTypes.NestedMessage
-	6,  // goproto.proto.test.TestAllTypes.optional_foreign_message:type_name -> goproto.proto.test.ForeignMessage
-	41, // goproto.proto.test.TestAllTypes.optional_import_message:type_name -> goproto.proto.test.ImportMessage
-	2,  // goproto.proto.test.TestAllTypes.optional_nested_enum:type_name -> goproto.proto.test.TestAllTypes.NestedEnum
-	0,  // goproto.proto.test.TestAllTypes.optional_foreign_enum:type_name -> goproto.proto.test.ForeignEnum
-	42, // goproto.proto.test.TestAllTypes.optional_import_enum:type_name -> goproto.proto.test.ImportEnum
-	20, // goproto.proto.test.TestAllTypes.repeatedgroup:type_name -> goproto.proto.test.TestAllTypes.RepeatedGroup
-	18, // goproto.proto.test.TestAllTypes.repeated_nested_message:type_name -> goproto.proto.test.TestAllTypes.NestedMessage
-	6,  // goproto.proto.test.TestAllTypes.repeated_foreign_message:type_name -> goproto.proto.test.ForeignMessage
-	41, // goproto.proto.test.TestAllTypes.repeated_importmessage:type_name -> goproto.proto.test.ImportMessage
-	2,  // goproto.proto.test.TestAllTypes.repeated_nested_enum:type_name -> goproto.proto.test.TestAllTypes.NestedEnum
-	0,  // goproto.proto.test.TestAllTypes.repeated_foreign_enum:type_name -> goproto.proto.test.ForeignEnum
-	42, // goproto.proto.test.TestAllTypes.repeated_importenum:type_name -> goproto.proto.test.ImportEnum
-	21, // goproto.proto.test.TestAllTypes.map_int32_int32:type_name -> goproto.proto.test.TestAllTypes.MapInt32Int32Entry
-	22, // goproto.proto.test.TestAllTypes.map_int64_int64:type_name -> goproto.proto.test.TestAllTypes.MapInt64Int64Entry
-	23, // goproto.proto.test.TestAllTypes.map_uint32_uint32:type_name -> goproto.proto.test.TestAllTypes.MapUint32Uint32Entry
-	24, // goproto.proto.test.TestAllTypes.map_uint64_uint64:type_name -> goproto.proto.test.TestAllTypes.MapUint64Uint64Entry
-	25, // goproto.proto.test.TestAllTypes.map_sint32_sint32:type_name -> goproto.proto.test.TestAllTypes.MapSint32Sint32Entry
-	26, // goproto.proto.test.TestAllTypes.map_sint64_sint64:type_name -> goproto.proto.test.TestAllTypes.MapSint64Sint64Entry
-	27, // goproto.proto.test.TestAllTypes.map_fixed32_fixed32:type_name -> goproto.proto.test.TestAllTypes.MapFixed32Fixed32Entry
-	28, // goproto.proto.test.TestAllTypes.map_fixed64_fixed64:type_name -> goproto.proto.test.TestAllTypes.MapFixed64Fixed64Entry
-	29, // goproto.proto.test.TestAllTypes.map_sfixed32_sfixed32:type_name -> goproto.proto.test.TestAllTypes.MapSfixed32Sfixed32Entry
-	30, // goproto.proto.test.TestAllTypes.map_sfixed64_sfixed64:type_name -> goproto.proto.test.TestAllTypes.MapSfixed64Sfixed64Entry
-	31, // goproto.proto.test.TestAllTypes.map_int32_float:type_name -> goproto.proto.test.TestAllTypes.MapInt32FloatEntry
-	32, // goproto.proto.test.TestAllTypes.map_int32_double:type_name -> goproto.proto.test.TestAllTypes.MapInt32DoubleEntry
-	33, // goproto.proto.test.TestAllTypes.map_bool_bool:type_name -> goproto.proto.test.TestAllTypes.MapBoolBoolEntry
-	34, // goproto.proto.test.TestAllTypes.map_string_string:type_name -> goproto.proto.test.TestAllTypes.MapStringStringEntry
-	35, // goproto.proto.test.TestAllTypes.map_string_bytes:type_name -> goproto.proto.test.TestAllTypes.MapStringBytesEntry
-	36, // goproto.proto.test.TestAllTypes.map_string_nested_message:type_name -> goproto.proto.test.TestAllTypes.MapStringNestedMessageEntry
-	37, // goproto.proto.test.TestAllTypes.map_string_nested_enum:type_name -> goproto.proto.test.TestAllTypes.MapStringNestedEnumEntry
-	2,  // goproto.proto.test.TestAllTypes.default_nested_enum:type_name -> goproto.proto.test.TestAllTypes.NestedEnum
-	0,  // goproto.proto.test.TestAllTypes.default_foreign_enum:type_name -> goproto.proto.test.ForeignEnum
-	18, // goproto.proto.test.TestAllTypes.oneof_nested_message:type_name -> goproto.proto.test.TestAllTypes.NestedMessage
-	2,  // goproto.proto.test.TestAllTypes.oneof_enum:type_name -> goproto.proto.test.TestAllTypes.NestedEnum
-	12, // goproto.proto.test.TestRequiredForeign.optional_message:type_name -> goproto.proto.test.TestRequired
-	12, // goproto.proto.test.TestRequiredForeign.repeated_message:type_name -> goproto.proto.test.TestRequired
-	38, // goproto.proto.test.TestRequiredForeign.map_message:type_name -> goproto.proto.test.TestRequiredForeign.MapMessageEntry
-	39, // goproto.proto.test.TestRequiredGroupFields.optionalgroup:type_name -> goproto.proto.test.TestRequiredGroupFields.OptionalGroup
-	40, // goproto.proto.test.TestRequiredGroupFields.repeatedgroup:type_name -> goproto.proto.test.TestRequiredGroupFields.RepeatedGroup
-	4,  // goproto.proto.test.TestAllTypes.NestedMessage.corecursive:type_name -> goproto.proto.test.TestAllTypes
-	18, // goproto.proto.test.TestAllTypes.MapStringNestedMessageEntry.value:type_name -> goproto.proto.test.TestAllTypes.NestedMessage
-	2,  // goproto.proto.test.TestAllTypes.MapStringNestedEnumEntry.value:type_name -> goproto.proto.test.TestAllTypes.NestedEnum
-	12, // goproto.proto.test.TestRequiredForeign.MapMessageEntry.value:type_name -> goproto.proto.test.TestRequired
-	9,  // goproto.proto.test.optionalgroup_extension:type_name -> goproto.proto.test.OptionalGroup_extension
-	18, // goproto.proto.test.optional_nested_message_extension:type_name -> goproto.proto.test.TestAllTypes.NestedMessage
-	2,  // goproto.proto.test.optional_nested_enum_extension:type_name -> goproto.proto.test.TestAllTypes.NestedEnum
-	10, // goproto.proto.test.repeatedgroup_extension:type_name -> goproto.proto.test.RepeatedGroup_extension
-	18, // goproto.proto.test.repeated_nested_message_extension:type_name -> goproto.proto.test.TestAllTypes.NestedMessage
-	2,  // goproto.proto.test.repeated_nested_enum_extension:type_name -> goproto.proto.test.TestAllTypes.NestedEnum
-	12, // goproto.proto.test.TestRequired.single:type_name -> goproto.proto.test.TestRequired
-	12, // goproto.proto.test.TestRequired.multi:type_name -> goproto.proto.test.TestRequired
-	16, // goproto.proto.test.TestService.Foo:input_type -> goproto.proto.test.FooRequest
-	17, // goproto.proto.test.TestService.Foo:output_type -> goproto.proto.test.FooResponse
-	16, // goproto.proto.test.TestService.TestStream:input_type -> goproto.proto.test.FooRequest
-	17, // goproto.proto.test.TestService.TestStream:output_type -> goproto.proto.test.FooResponse
-	5,  // goproto.proto.test.TestDeprecatedService.Deprecated:input_type -> goproto.proto.test.TestDeprecatedMessage
-	5,  // goproto.proto.test.TestDeprecatedService.Deprecated:output_type -> goproto.proto.test.TestDeprecatedMessage
+	19,  // goproto.proto.test.TestAllTypes.optionalgroup:type_name -> goproto.proto.test.TestAllTypes.OptionalGroup
+	18,  // goproto.proto.test.TestAllTypes.optional_nested_message:type_name -> goproto.proto.test.TestAllTypes.NestedMessage
+	6,   // goproto.proto.test.TestAllTypes.optional_foreign_message:type_name -> goproto.proto.test.ForeignMessage
+	41,  // goproto.proto.test.TestAllTypes.optional_import_message:type_name -> goproto.proto.test.ImportMessage
+	2,   // goproto.proto.test.TestAllTypes.optional_nested_enum:type_name -> goproto.proto.test.TestAllTypes.NestedEnum
+	0,   // goproto.proto.test.TestAllTypes.optional_foreign_enum:type_name -> goproto.proto.test.ForeignEnum
+	42,  // goproto.proto.test.TestAllTypes.optional_import_enum:type_name -> goproto.proto.test.ImportEnum
+	20,  // goproto.proto.test.TestAllTypes.repeatedgroup:type_name -> goproto.proto.test.TestAllTypes.RepeatedGroup
+	18,  // goproto.proto.test.TestAllTypes.repeated_nested_message:type_name -> goproto.proto.test.TestAllTypes.NestedMessage
+	6,   // goproto.proto.test.TestAllTypes.repeated_foreign_message:type_name -> goproto.proto.test.ForeignMessage
+	41,  // goproto.proto.test.TestAllTypes.repeated_importmessage:type_name -> goproto.proto.test.ImportMessage
+	2,   // goproto.proto.test.TestAllTypes.repeated_nested_enum:type_name -> goproto.proto.test.TestAllTypes.NestedEnum
+	0,   // goproto.proto.test.TestAllTypes.repeated_foreign_enum:type_name -> goproto.proto.test.ForeignEnum
+	42,  // goproto.proto.test.TestAllTypes.repeated_importenum:type_name -> goproto.proto.test.ImportEnum
+	21,  // goproto.proto.test.TestAllTypes.map_int32_int32:type_name -> goproto.proto.test.TestAllTypes.MapInt32Int32Entry
+	22,  // goproto.proto.test.TestAllTypes.map_int64_int64:type_name -> goproto.proto.test.TestAllTypes.MapInt64Int64Entry
+	23,  // goproto.proto.test.TestAllTypes.map_uint32_uint32:type_name -> goproto.proto.test.TestAllTypes.MapUint32Uint32Entry
+	24,  // goproto.proto.test.TestAllTypes.map_uint64_uint64:type_name -> goproto.proto.test.TestAllTypes.MapUint64Uint64Entry
+	25,  // goproto.proto.test.TestAllTypes.map_sint32_sint32:type_name -> goproto.proto.test.TestAllTypes.MapSint32Sint32Entry
+	26,  // goproto.proto.test.TestAllTypes.map_sint64_sint64:type_name -> goproto.proto.test.TestAllTypes.MapSint64Sint64Entry
+	27,  // goproto.proto.test.TestAllTypes.map_fixed32_fixed32:type_name -> goproto.proto.test.TestAllTypes.MapFixed32Fixed32Entry
+	28,  // goproto.proto.test.TestAllTypes.map_fixed64_fixed64:type_name -> goproto.proto.test.TestAllTypes.MapFixed64Fixed64Entry
+	29,  // goproto.proto.test.TestAllTypes.map_sfixed32_sfixed32:type_name -> goproto.proto.test.TestAllTypes.MapSfixed32Sfixed32Entry
+	30,  // goproto.proto.test.TestAllTypes.map_sfixed64_sfixed64:type_name -> goproto.proto.test.TestAllTypes.MapSfixed64Sfixed64Entry
+	31,  // goproto.proto.test.TestAllTypes.map_int32_float:type_name -> goproto.proto.test.TestAllTypes.MapInt32FloatEntry
+	32,  // goproto.proto.test.TestAllTypes.map_int32_double:type_name -> goproto.proto.test.TestAllTypes.MapInt32DoubleEntry
+	33,  // goproto.proto.test.TestAllTypes.map_bool_bool:type_name -> goproto.proto.test.TestAllTypes.MapBoolBoolEntry
+	34,  // goproto.proto.test.TestAllTypes.map_string_string:type_name -> goproto.proto.test.TestAllTypes.MapStringStringEntry
+	35,  // goproto.proto.test.TestAllTypes.map_string_bytes:type_name -> goproto.proto.test.TestAllTypes.MapStringBytesEntry
+	36,  // goproto.proto.test.TestAllTypes.map_string_nested_message:type_name -> goproto.proto.test.TestAllTypes.MapStringNestedMessageEntry
+	37,  // goproto.proto.test.TestAllTypes.map_string_nested_enum:type_name -> goproto.proto.test.TestAllTypes.MapStringNestedEnumEntry
+	2,   // goproto.proto.test.TestAllTypes.default_nested_enum:type_name -> goproto.proto.test.TestAllTypes.NestedEnum
+	0,   // goproto.proto.test.TestAllTypes.default_foreign_enum:type_name -> goproto.proto.test.ForeignEnum
+	18,  // goproto.proto.test.TestAllTypes.oneof_nested_message:type_name -> goproto.proto.test.TestAllTypes.NestedMessage
+	2,   // goproto.proto.test.TestAllTypes.oneof_enum:type_name -> goproto.proto.test.TestAllTypes.NestedEnum
+	12,  // goproto.proto.test.TestRequiredForeign.optional_message:type_name -> goproto.proto.test.TestRequired
+	12,  // goproto.proto.test.TestRequiredForeign.repeated_message:type_name -> goproto.proto.test.TestRequired
+	38,  // goproto.proto.test.TestRequiredForeign.map_message:type_name -> goproto.proto.test.TestRequiredForeign.MapMessageEntry
+	39,  // goproto.proto.test.TestRequiredGroupFields.optionalgroup:type_name -> goproto.proto.test.TestRequiredGroupFields.OptionalGroup
+	40,  // goproto.proto.test.TestRequiredGroupFields.repeatedgroup:type_name -> goproto.proto.test.TestRequiredGroupFields.RepeatedGroup
+	4,   // goproto.proto.test.TestAllTypes.NestedMessage.corecursive:type_name -> goproto.proto.test.TestAllTypes
+	18,  // goproto.proto.test.TestAllTypes.MapStringNestedMessageEntry.value:type_name -> goproto.proto.test.TestAllTypes.NestedMessage
+	2,   // goproto.proto.test.TestAllTypes.MapStringNestedEnumEntry.value:type_name -> goproto.proto.test.TestAllTypes.NestedEnum
+	12,  // goproto.proto.test.TestRequiredForeign.MapMessageEntry.value:type_name -> goproto.proto.test.TestRequired
+	8,   // goproto.proto.test.optional_int32_extension:extendee -> goproto.proto.test.TestAllExtensions
+	8,   // goproto.proto.test.optional_int64_extension:extendee -> goproto.proto.test.TestAllExtensions
+	8,   // goproto.proto.test.optional_uint32_extension:extendee -> goproto.proto.test.TestAllExtensions
+	8,   // goproto.proto.test.optional_uint64_extension:extendee -> goproto.proto.test.TestAllExtensions
+	8,   // goproto.proto.test.optional_sint32_extension:extendee -> goproto.proto.test.TestAllExtensions
+	8,   // goproto.proto.test.optional_sint64_extension:extendee -> goproto.proto.test.TestAllExtensions
+	8,   // goproto.proto.test.optional_fixed32_extension:extendee -> goproto.proto.test.TestAllExtensions
+	8,   // goproto.proto.test.optional_fixed64_extension:extendee -> goproto.proto.test.TestAllExtensions
+	8,   // goproto.proto.test.optional_sfixed32_extension:extendee -> goproto.proto.test.TestAllExtensions
+	8,   // goproto.proto.test.optional_sfixed64_extension:extendee -> goproto.proto.test.TestAllExtensions
+	8,   // goproto.proto.test.optional_float_extension:extendee -> goproto.proto.test.TestAllExtensions
+	8,   // goproto.proto.test.optional_double_extension:extendee -> goproto.proto.test.TestAllExtensions
+	8,   // goproto.proto.test.optional_bool_extension:extendee -> goproto.proto.test.TestAllExtensions
+	8,   // goproto.proto.test.optional_string_extension:extendee -> goproto.proto.test.TestAllExtensions
+	8,   // goproto.proto.test.optional_bytes_extension:extendee -> goproto.proto.test.TestAllExtensions
+	8,   // goproto.proto.test.optionalgroup_extension:extendee -> goproto.proto.test.TestAllExtensions
+	8,   // goproto.proto.test.optional_nested_message_extension:extendee -> goproto.proto.test.TestAllExtensions
+	8,   // goproto.proto.test.optional_nested_enum_extension:extendee -> goproto.proto.test.TestAllExtensions
+	8,   // goproto.proto.test.repeated_int32_extension:extendee -> goproto.proto.test.TestAllExtensions
+	8,   // goproto.proto.test.repeated_int64_extension:extendee -> goproto.proto.test.TestAllExtensions
+	8,   // goproto.proto.test.repeated_uint32_extension:extendee -> goproto.proto.test.TestAllExtensions
+	8,   // goproto.proto.test.repeated_uint64_extension:extendee -> goproto.proto.test.TestAllExtensions
+	8,   // goproto.proto.test.repeated_sint32_extension:extendee -> goproto.proto.test.TestAllExtensions
+	8,   // goproto.proto.test.repeated_sint64_extension:extendee -> goproto.proto.test.TestAllExtensions
+	8,   // goproto.proto.test.repeated_fixed32_extension:extendee -> goproto.proto.test.TestAllExtensions
+	8,   // goproto.proto.test.repeated_fixed64_extension:extendee -> goproto.proto.test.TestAllExtensions
+	8,   // goproto.proto.test.repeated_sfixed32_extension:extendee -> goproto.proto.test.TestAllExtensions
+	8,   // goproto.proto.test.repeated_sfixed64_extension:extendee -> goproto.proto.test.TestAllExtensions
+	8,   // goproto.proto.test.repeated_float_extension:extendee -> goproto.proto.test.TestAllExtensions
+	8,   // goproto.proto.test.repeated_double_extension:extendee -> goproto.proto.test.TestAllExtensions
+	8,   // goproto.proto.test.repeated_bool_extension:extendee -> goproto.proto.test.TestAllExtensions
+	8,   // goproto.proto.test.repeated_string_extension:extendee -> goproto.proto.test.TestAllExtensions
+	8,   // goproto.proto.test.repeated_bytes_extension:extendee -> goproto.proto.test.TestAllExtensions
+	8,   // goproto.proto.test.repeatedgroup_extension:extendee -> goproto.proto.test.TestAllExtensions
+	8,   // goproto.proto.test.repeated_nested_message_extension:extendee -> goproto.proto.test.TestAllExtensions
+	8,   // goproto.proto.test.repeated_nested_enum_extension:extendee -> goproto.proto.test.TestAllExtensions
+	8,   // goproto.proto.test.default_int32_extension:extendee -> goproto.proto.test.TestAllExtensions
+	8,   // goproto.proto.test.default_int64_extension:extendee -> goproto.proto.test.TestAllExtensions
+	8,   // goproto.proto.test.default_uint32_extension:extendee -> goproto.proto.test.TestAllExtensions
+	8,   // goproto.proto.test.default_uint64_extension:extendee -> goproto.proto.test.TestAllExtensions
+	8,   // goproto.proto.test.default_sint32_extension:extendee -> goproto.proto.test.TestAllExtensions
+	8,   // goproto.proto.test.default_sint64_extension:extendee -> goproto.proto.test.TestAllExtensions
+	8,   // goproto.proto.test.default_fixed32_extension:extendee -> goproto.proto.test.TestAllExtensions
+	8,   // goproto.proto.test.default_fixed64_extension:extendee -> goproto.proto.test.TestAllExtensions
+	8,   // goproto.proto.test.default_sfixed32_extension:extendee -> goproto.proto.test.TestAllExtensions
+	8,   // goproto.proto.test.default_sfixed64_extension:extendee -> goproto.proto.test.TestAllExtensions
+	8,   // goproto.proto.test.default_float_extension:extendee -> goproto.proto.test.TestAllExtensions
+	8,   // goproto.proto.test.default_double_extension:extendee -> goproto.proto.test.TestAllExtensions
+	8,   // goproto.proto.test.default_bool_extension:extendee -> goproto.proto.test.TestAllExtensions
+	8,   // goproto.proto.test.default_string_extension:extendee -> goproto.proto.test.TestAllExtensions
+	8,   // goproto.proto.test.default_bytes_extension:extendee -> goproto.proto.test.TestAllExtensions
+	8,   // goproto.proto.test.TestNestedExtension.nested_string_extension:extendee -> goproto.proto.test.TestAllExtensions
+	8,   // goproto.proto.test.TestRequired.single:extendee -> goproto.proto.test.TestAllExtensions
+	8,   // goproto.proto.test.TestRequired.multi:extendee -> goproto.proto.test.TestAllExtensions
+	9,   // goproto.proto.test.optionalgroup_extension:type_name -> goproto.proto.test.OptionalGroup_extension
+	18,  // goproto.proto.test.optional_nested_message_extension:type_name -> goproto.proto.test.TestAllTypes.NestedMessage
+	2,   // goproto.proto.test.optional_nested_enum_extension:type_name -> goproto.proto.test.TestAllTypes.NestedEnum
+	10,  // goproto.proto.test.repeatedgroup_extension:type_name -> goproto.proto.test.RepeatedGroup_extension
+	18,  // goproto.proto.test.repeated_nested_message_extension:type_name -> goproto.proto.test.TestAllTypes.NestedMessage
+	2,   // goproto.proto.test.repeated_nested_enum_extension:type_name -> goproto.proto.test.TestAllTypes.NestedEnum
+	12,  // goproto.proto.test.TestRequired.single:type_name -> goproto.proto.test.TestRequired
+	12,  // goproto.proto.test.TestRequired.multi:type_name -> goproto.proto.test.TestRequired
+	16,  // goproto.proto.test.TestService.Foo:input_type -> goproto.proto.test.FooRequest
+	16,  // goproto.proto.test.TestService.TestStream:input_type -> goproto.proto.test.FooRequest
+	5,   // goproto.proto.test.TestDeprecatedService.Deprecated:input_type -> goproto.proto.test.TestDeprecatedMessage
+	17,  // goproto.proto.test.TestService.Foo:output_type -> goproto.proto.test.FooResponse
+	17,  // goproto.proto.test.TestService.TestStream:output_type -> goproto.proto.test.FooResponse
+	5,   // goproto.proto.test.TestDeprecatedService.Deprecated:output_type -> goproto.proto.test.TestDeprecatedMessage
+	109, // starting offset of method output_type sub-list
+	106, // starting offset of method input_type sub-list
+	98,  // starting offset of extension type_name sub-list
+	44,  // starting offset of extension extendee sub-list
+	0,   // starting offset of field type_name sub-list
 }
 
 func init() { file_test_test_proto_init() }
@@ -3467,18 +3472,21 @@
 	}
 	file_test_test_import_proto_init()
 	file_test_test_public_proto_init()
-	extensionTypes := make([]protoreflect.ExtensionType, 54)
-	File_test_test_proto = protoimpl.FileBuilder{
-		RawDescriptor:        file_test_test_proto_rawDesc,
-		GoTypes:              file_test_test_proto_goTypes,
-		DependencyIndexes:    file_test_test_proto_depIdxs,
-		LegacyExtensions:     file_test_test_proto_extDescs,
-		EnumOutputTypes:      file_test_test_proto_enumTypes,
-		MessageOutputTypes:   file_test_test_proto_msgTypes,
-		ExtensionOutputTypes: extensionTypes,
-		FilesRegistry:        protoregistry.GlobalFiles,
-		TypesRegistry:        protoregistry.GlobalTypes,
-	}.Init()
+	out := protoimpl.TypeBuilder{
+		File: protoimpl.DescBuilder{
+			RawDescriptor: file_test_test_proto_rawDesc,
+			NumEnums:      4,
+			NumMessages:   37,
+			NumExtensions: 54,
+			NumServices:   2,
+		},
+		GoTypes:           file_test_test_proto_goTypes,
+		DependencyIndexes: file_test_test_proto_depIdxs,
+		MessageInfos:      file_test_test_proto_msgTypes,
+		LegacyExtensions:  file_test_test_proto_extDescs,
+	}.Build()
+	File_test_test_proto = out.File
+	file_test_test_proto_enumTypes = out.Enums
 	file_test_test_proto_rawDesc = nil
 	file_test_test_proto_goTypes = nil
 	file_test_test_proto_depIdxs = nil
diff --git a/internal/testprotos/test/test_import.pb.go b/internal/testprotos/test/test_import.pb.go
index 6ec7c37..408b5a4 100644
--- a/internal/testprotos/test/test_import.pb.go
+++ b/internal/testprotos/test/test_import.pb.go
@@ -5,7 +5,7 @@
 
 import (
 	protoreflect "google.golang.org/protobuf/reflect/protoreflect"
-	protoregistry "google.golang.org/protobuf/reflect/protoregistry"
+	prototype "google.golang.org/protobuf/reflect/prototype"
 	protoiface "google.golang.org/protobuf/runtime/protoiface"
 	protoimpl "google.golang.org/protobuf/runtime/protoimpl"
 	sync "sync"
@@ -45,7 +45,7 @@
 }
 
 func (ImportEnum) Descriptor() protoreflect.EnumDescriptor {
-	return file_test_test_import_proto_enumTypes[0].Descriptor()
+	return file_test_test_import_proto_enumTypes[0].EnumDescriptor
 }
 
 func (x ImportEnum) Number() protoreflect.EnumNumber {
@@ -123,28 +123,39 @@
 	return file_test_test_import_proto_rawDescData
 }
 
-var file_test_test_import_proto_enumTypes = make([]protoreflect.EnumType, 1)
+var file_test_test_import_proto_enumTypes = make([]prototype.Enum, 1)
 var file_test_test_import_proto_msgTypes = make([]protoimpl.MessageInfo, 1)
 var file_test_test_import_proto_goTypes = []interface{}{
 	(ImportEnum)(0),       // 0: goproto.proto.test.ImportEnum
 	(*ImportMessage)(nil), // 1: goproto.proto.test.ImportMessage
 }
-var file_test_test_import_proto_depIdxs = []int32{}
+var file_test_test_import_proto_depIdxs = []int32{
+	0, // starting offset of method output_type sub-list
+	0, // starting offset of method input_type sub-list
+	0, // starting offset of extension type_name sub-list
+	0, // starting offset of extension extendee sub-list
+	0, // starting offset of field type_name sub-list
+}
 
 func init() { file_test_test_import_proto_init() }
 func file_test_test_import_proto_init() {
 	if File_test_test_import_proto != nil {
 		return
 	}
-	File_test_test_import_proto = protoimpl.FileBuilder{
-		RawDescriptor:      file_test_test_import_proto_rawDesc,
-		GoTypes:            file_test_test_import_proto_goTypes,
-		DependencyIndexes:  file_test_test_import_proto_depIdxs,
-		EnumOutputTypes:    file_test_test_import_proto_enumTypes,
-		MessageOutputTypes: file_test_test_import_proto_msgTypes,
-		FilesRegistry:      protoregistry.GlobalFiles,
-		TypesRegistry:      protoregistry.GlobalTypes,
-	}.Init()
+	out := protoimpl.TypeBuilder{
+		File: protoimpl.DescBuilder{
+			RawDescriptor: file_test_test_import_proto_rawDesc,
+			NumEnums:      1,
+			NumMessages:   1,
+			NumExtensions: 0,
+			NumServices:   0,
+		},
+		GoTypes:           file_test_test_import_proto_goTypes,
+		DependencyIndexes: file_test_test_import_proto_depIdxs,
+		MessageInfos:      file_test_test_import_proto_msgTypes,
+	}.Build()
+	File_test_test_import_proto = out.File
+	file_test_test_import_proto_enumTypes = out.Enums
 	file_test_test_import_proto_rawDesc = nil
 	file_test_test_import_proto_goTypes = nil
 	file_test_test_import_proto_depIdxs = nil
diff --git a/internal/testprotos/test/test_public.pb.go b/internal/testprotos/test/test_public.pb.go
index 832e324..be20ac9 100644
--- a/internal/testprotos/test/test_public.pb.go
+++ b/internal/testprotos/test/test_public.pb.go
@@ -5,7 +5,6 @@
 
 import (
 	protoreflect "google.golang.org/protobuf/reflect/protoreflect"
-	protoregistry "google.golang.org/protobuf/reflect/protoregistry"
 	protoiface "google.golang.org/protobuf/runtime/protoiface"
 	protoimpl "google.golang.org/protobuf/runtime/protoimpl"
 	sync "sync"
@@ -76,21 +75,32 @@
 var file_test_test_public_proto_goTypes = []interface{}{
 	(*PublicImportMessage)(nil), // 0: goproto.proto.test.PublicImportMessage
 }
-var file_test_test_public_proto_depIdxs = []int32{}
+var file_test_test_public_proto_depIdxs = []int32{
+	0, // starting offset of method output_type sub-list
+	0, // starting offset of method input_type sub-list
+	0, // starting offset of extension type_name sub-list
+	0, // starting offset of extension extendee sub-list
+	0, // starting offset of field type_name sub-list
+}
 
 func init() { file_test_test_public_proto_init() }
 func file_test_test_public_proto_init() {
 	if File_test_test_public_proto != nil {
 		return
 	}
-	File_test_test_public_proto = protoimpl.FileBuilder{
-		RawDescriptor:      file_test_test_public_proto_rawDesc,
-		GoTypes:            file_test_test_public_proto_goTypes,
-		DependencyIndexes:  file_test_test_public_proto_depIdxs,
-		MessageOutputTypes: file_test_test_public_proto_msgTypes,
-		FilesRegistry:      protoregistry.GlobalFiles,
-		TypesRegistry:      protoregistry.GlobalTypes,
-	}.Init()
+	out := protoimpl.TypeBuilder{
+		File: protoimpl.DescBuilder{
+			RawDescriptor: file_test_test_public_proto_rawDesc,
+			NumEnums:      0,
+			NumMessages:   1,
+			NumExtensions: 0,
+			NumServices:   0,
+		},
+		GoTypes:           file_test_test_public_proto_goTypes,
+		DependencyIndexes: file_test_test_public_proto_depIdxs,
+		MessageInfos:      file_test_test_public_proto_msgTypes,
+	}.Build()
+	File_test_test_public_proto = out.File
 	file_test_test_public_proto_rawDesc = nil
 	file_test_test_public_proto_goTypes = nil
 	file_test_test_public_proto_depIdxs = nil
diff --git a/internal/testprotos/test/weak/test_weak.pb.go b/internal/testprotos/test/weak/test_weak.pb.go
index ba5b8df..f661776 100644
--- a/internal/testprotos/test/weak/test_weak.pb.go
+++ b/internal/testprotos/test/weak/test_weak.pb.go
@@ -5,7 +5,6 @@
 
 import (
 	protoreflect "google.golang.org/protobuf/reflect/protoreflect"
-	protoregistry "google.golang.org/protobuf/reflect/protoregistry"
 	protoiface "google.golang.org/protobuf/runtime/protoiface"
 	protoimpl "google.golang.org/protobuf/runtime/protoimpl"
 	sync "sync"
@@ -86,21 +85,32 @@
 var file_test_weak_test_weak_proto_goTypes = []interface{}{
 	(*WeakImportMessage)(nil), // 0: goproto.proto.test.weak.WeakImportMessage
 }
-var file_test_weak_test_weak_proto_depIdxs = []int32{}
+var file_test_weak_test_weak_proto_depIdxs = []int32{
+	0, // starting offset of method output_type sub-list
+	0, // starting offset of method input_type sub-list
+	0, // starting offset of extension type_name sub-list
+	0, // starting offset of extension extendee sub-list
+	0, // starting offset of field type_name sub-list
+}
 
 func init() { file_test_weak_test_weak_proto_init() }
 func file_test_weak_test_weak_proto_init() {
 	if File_test_weak_test_weak_proto != nil {
 		return
 	}
-	File_test_weak_test_weak_proto = protoimpl.FileBuilder{
-		RawDescriptor:      file_test_weak_test_weak_proto_rawDesc,
-		GoTypes:            file_test_weak_test_weak_proto_goTypes,
-		DependencyIndexes:  file_test_weak_test_weak_proto_depIdxs,
-		MessageOutputTypes: file_test_weak_test_weak_proto_msgTypes,
-		FilesRegistry:      protoregistry.GlobalFiles,
-		TypesRegistry:      protoregistry.GlobalTypes,
-	}.Init()
+	out := protoimpl.TypeBuilder{
+		File: protoimpl.DescBuilder{
+			RawDescriptor: file_test_weak_test_weak_proto_rawDesc,
+			NumEnums:      0,
+			NumMessages:   1,
+			NumExtensions: 0,
+			NumServices:   0,
+		},
+		GoTypes:           file_test_weak_test_weak_proto_goTypes,
+		DependencyIndexes: file_test_weak_test_weak_proto_depIdxs,
+		MessageInfos:      file_test_weak_test_weak_proto_msgTypes,
+	}.Build()
+	File_test_weak_test_weak_proto = out.File
 	file_test_weak_test_weak_proto_rawDesc = nil
 	file_test_weak_test_weak_proto_goTypes = nil
 	file_test_weak_test_weak_proto_depIdxs = nil
diff --git a/internal/testprotos/test3/test.pb.go b/internal/testprotos/test3/test.pb.go
index 129d836..471ca03 100644
--- a/internal/testprotos/test3/test.pb.go
+++ b/internal/testprotos/test3/test.pb.go
@@ -5,7 +5,7 @@
 
 import (
 	protoreflect "google.golang.org/protobuf/reflect/protoreflect"
-	protoregistry "google.golang.org/protobuf/reflect/protoregistry"
+	prototype "google.golang.org/protobuf/reflect/prototype"
 	protoiface "google.golang.org/protobuf/runtime/protoiface"
 	protoimpl "google.golang.org/protobuf/runtime/protoimpl"
 	sync "sync"
@@ -54,7 +54,7 @@
 }
 
 func (ForeignEnum) Descriptor() protoreflect.EnumDescriptor {
-	return file_test3_test_proto_enumTypes[0].Descriptor()
+	return file_test3_test_proto_enumTypes[0].EnumDescriptor
 }
 
 func (x ForeignEnum) Number() protoreflect.EnumNumber {
@@ -102,7 +102,7 @@
 }
 
 func (TestAllTypes_NestedEnum) Descriptor() protoreflect.EnumDescriptor {
-	return file_test3_test_proto_enumTypes[1].Descriptor()
+	return file_test3_test_proto_enumTypes[1].EnumDescriptor
 }
 
 func (x TestAllTypes_NestedEnum) Number() protoreflect.EnumNumber {
@@ -1265,7 +1265,7 @@
 	return file_test3_test_proto_rawDescData
 }
 
-var file_test3_test_proto_enumTypes = make([]protoreflect.EnumType, 2)
+var file_test3_test_proto_enumTypes = make([]prototype.Enum, 2)
 var file_test3_test_proto_msgTypes = make([]protoimpl.MessageInfo, 20)
 var file_test3_test_proto_goTypes = []interface{}{
 	(ForeignEnum)(0),                   // 0: goproto.proto.test3.ForeignEnum
@@ -1328,6 +1328,11 @@
 	2,  // goproto.proto.test3.TestAllTypes.NestedMessage.corecursive:type_name -> goproto.proto.test3.TestAllTypes
 	4,  // goproto.proto.test3.TestAllTypes.MapStringNestedMessageEntry.value:type_name -> goproto.proto.test3.TestAllTypes.NestedMessage
 	1,  // goproto.proto.test3.TestAllTypes.MapStringNestedEnumEntry.value:type_name -> goproto.proto.test3.TestAllTypes.NestedEnum
+	34, // starting offset of method output_type sub-list
+	34, // starting offset of method input_type sub-list
+	34, // starting offset of extension type_name sub-list
+	34, // starting offset of extension extendee sub-list
+	0,  // starting offset of field type_name sub-list
 }
 
 func init() { file_test3_test_proto_init() }
@@ -1336,15 +1341,20 @@
 		return
 	}
 	file_test3_test_import_proto_init()
-	File_test3_test_proto = protoimpl.FileBuilder{
-		RawDescriptor:      file_test3_test_proto_rawDesc,
-		GoTypes:            file_test3_test_proto_goTypes,
-		DependencyIndexes:  file_test3_test_proto_depIdxs,
-		EnumOutputTypes:    file_test3_test_proto_enumTypes,
-		MessageOutputTypes: file_test3_test_proto_msgTypes,
-		FilesRegistry:      protoregistry.GlobalFiles,
-		TypesRegistry:      protoregistry.GlobalTypes,
-	}.Init()
+	out := protoimpl.TypeBuilder{
+		File: protoimpl.DescBuilder{
+			RawDescriptor: file_test3_test_proto_rawDesc,
+			NumEnums:      2,
+			NumMessages:   20,
+			NumExtensions: 0,
+			NumServices:   0,
+		},
+		GoTypes:           file_test3_test_proto_goTypes,
+		DependencyIndexes: file_test3_test_proto_depIdxs,
+		MessageInfos:      file_test3_test_proto_msgTypes,
+	}.Build()
+	File_test3_test_proto = out.File
+	file_test3_test_proto_enumTypes = out.Enums
 	file_test3_test_proto_rawDesc = nil
 	file_test3_test_proto_goTypes = nil
 	file_test3_test_proto_depIdxs = nil
diff --git a/internal/testprotos/test3/test_import.pb.go b/internal/testprotos/test3/test_import.pb.go
index e5ad6b9..5b34c48 100644
--- a/internal/testprotos/test3/test_import.pb.go
+++ b/internal/testprotos/test3/test_import.pb.go
@@ -5,7 +5,7 @@
 
 import (
 	protoreflect "google.golang.org/protobuf/reflect/protoreflect"
-	protoregistry "google.golang.org/protobuf/reflect/protoregistry"
+	prototype "google.golang.org/protobuf/reflect/prototype"
 	protoiface "google.golang.org/protobuf/runtime/protoiface"
 	protoimpl "google.golang.org/protobuf/runtime/protoimpl"
 	sync "sync"
@@ -45,7 +45,7 @@
 }
 
 func (ImportEnum) Descriptor() protoreflect.EnumDescriptor {
-	return file_test3_test_import_proto_enumTypes[0].Descriptor()
+	return file_test3_test_import_proto_enumTypes[0].EnumDescriptor
 }
 
 func (x ImportEnum) Number() protoreflect.EnumNumber {
@@ -113,28 +113,39 @@
 	return file_test3_test_import_proto_rawDescData
 }
 
-var file_test3_test_import_proto_enumTypes = make([]protoreflect.EnumType, 1)
+var file_test3_test_import_proto_enumTypes = make([]prototype.Enum, 1)
 var file_test3_test_import_proto_msgTypes = make([]protoimpl.MessageInfo, 1)
 var file_test3_test_import_proto_goTypes = []interface{}{
 	(ImportEnum)(0),       // 0: goproto.proto.test3.ImportEnum
 	(*ImportMessage)(nil), // 1: goproto.proto.test3.ImportMessage
 }
-var file_test3_test_import_proto_depIdxs = []int32{}
+var file_test3_test_import_proto_depIdxs = []int32{
+	0, // starting offset of method output_type sub-list
+	0, // starting offset of method input_type sub-list
+	0, // starting offset of extension type_name sub-list
+	0, // starting offset of extension extendee sub-list
+	0, // starting offset of field type_name sub-list
+}
 
 func init() { file_test3_test_import_proto_init() }
 func file_test3_test_import_proto_init() {
 	if File_test3_test_import_proto != nil {
 		return
 	}
-	File_test3_test_import_proto = protoimpl.FileBuilder{
-		RawDescriptor:      file_test3_test_import_proto_rawDesc,
-		GoTypes:            file_test3_test_import_proto_goTypes,
-		DependencyIndexes:  file_test3_test_import_proto_depIdxs,
-		EnumOutputTypes:    file_test3_test_import_proto_enumTypes,
-		MessageOutputTypes: file_test3_test_import_proto_msgTypes,
-		FilesRegistry:      protoregistry.GlobalFiles,
-		TypesRegistry:      protoregistry.GlobalTypes,
-	}.Init()
+	out := protoimpl.TypeBuilder{
+		File: protoimpl.DescBuilder{
+			RawDescriptor: file_test3_test_import_proto_rawDesc,
+			NumEnums:      1,
+			NumMessages:   1,
+			NumExtensions: 0,
+			NumServices:   0,
+		},
+		GoTypes:           file_test3_test_import_proto_goTypes,
+		DependencyIndexes: file_test3_test_import_proto_depIdxs,
+		MessageInfos:      file_test3_test_import_proto_msgTypes,
+	}.Build()
+	File_test3_test_import_proto = out.File
+	file_test3_test_import_proto_enumTypes = out.Enums
 	file_test3_test_import_proto_rawDesc = nil
 	file_test3_test_import_proto_goTypes = nil
 	file_test3_test_import_proto_depIdxs = nil
diff --git a/reflect/protodesc/protodesc.go b/reflect/protodesc/protodesc.go
index f660908..7868bb2 100644
--- a/reflect/protodesc/protodesc.go
+++ b/reflect/protodesc/protodesc.go
@@ -11,7 +11,7 @@
 
 	"google.golang.org/protobuf/internal/encoding/defval"
 	"google.golang.org/protobuf/internal/errors"
-	"google.golang.org/protobuf/internal/prototype"
+	"google.golang.org/protobuf/internal/filedesc"
 	"google.golang.org/protobuf/reflect/protoreflect"
 	"google.golang.org/protobuf/reflect/protoregistry"
 
@@ -42,6 +42,27 @@
 // However, this will complicate future work for validation since File may now
 // diverge from the stored descriptor proto (see above TODO).
 
+// TODO: This is important to prevent users from creating invalid types,
+// but is not functionality needed now.
+//
+// Things to verify:
+//	* Weak fields are only used if flags.Proto1Legacy is set
+//	* Weak fields can only reference singular messages
+//	(check if this the case for oneof fields)
+//	* FieldDescriptor.MessageType cannot reference a remote type when the
+//	remote name is a type within the local file.
+//	* Default enum identifiers resolve to a declared number.
+//	* Default values are only allowed in proto2.
+//	* Default strings are valid UTF-8? Note that protoc does not check this.
+//	* Field extensions are only valid in proto2, except when extending the
+//	descriptor options.
+//	* Remote enum and message types are actually found in imported files.
+//	* Placeholder messages and types may only be for weak fields.
+//	* Placeholder full names must be valid.
+//	* The name of each descriptor must be valid.
+//	* Options are of the correct Go type (e.g. *descriptorpb.MessageOptions).
+// 	* len(ExtensionRangeOptions) <= len(ExtensionRanges)
+
 // NewFile creates a new protoreflect.FileDescriptor from the provided
 // file descriptor message. The file must represent a valid proto file according
 // to protobuf semantics.
@@ -57,306 +78,431 @@
 	if r == nil {
 		r = (*protoregistry.Files)(nil) // empty resolver
 	}
-	var f prototype.File
+	f := &filedesc.File{L2: &filedesc.FileL2{}}
 	switch fd.GetSyntax() {
 	case "proto2", "":
-		f.Syntax = protoreflect.Proto2
+		f.L1.Syntax = protoreflect.Proto2
 	case "proto3":
-		f.Syntax = protoreflect.Proto3
+		f.L1.Syntax = protoreflect.Proto3
 	default:
 		return nil, errors.New("invalid syntax: %v", fd.GetSyntax())
 	}
-	f.Path = fd.GetName()
-	f.Package = protoreflect.FullName(fd.GetPackage())
-	f.Options = fd.GetOptions()
+	f.L1.Path = fd.GetName()
+	f.L1.Package = protoreflect.FullName(fd.GetPackage())
+	if opts := fd.GetOptions(); opts != nil {
+		f.L2.Options = func() protoreflect.ProtoMessage { return opts }
+	}
 
-	f.Imports = make([]protoreflect.FileImport, len(fd.GetDependency()))
+	f.L2.Imports = make(filedesc.FileImports, len(fd.GetDependency()))
 	for _, i := range fd.GetPublicDependency() {
-		if int(i) >= len(f.Imports) || f.Imports[i].IsPublic {
+		if int(i) >= len(f.L2.Imports) || f.L2.Imports[i].IsPublic {
 			return nil, errors.New("invalid or duplicate public import index: %d", i)
 		}
-		f.Imports[i].IsPublic = true
+		f.L2.Imports[i].IsPublic = true
 	}
 	for _, i := range fd.GetWeakDependency() {
-		if int(i) >= len(f.Imports) || f.Imports[i].IsWeak {
+		if int(i) >= len(f.L2.Imports) || f.L2.Imports[i].IsWeak {
 			return nil, errors.New("invalid or duplicate weak import index: %d", i)
 		}
-		f.Imports[i].IsWeak = true
+		f.L2.Imports[i].IsWeak = true
 	}
 	for i, path := range fd.GetDependency() {
-		imp := &f.Imports[i]
-		fd, err := r.FindFileByPath(path)
+		imp := &f.L2.Imports[i]
+		f, err := r.FindFileByPath(path)
 		if err != nil {
-			fd = prototype.PlaceholderFile(path, "")
+			// TODO: This should be an error.
+			f = filedesc.PlaceholderFile(path)
 		}
-		imp.FileDescriptor = fd
+		imp.FileDescriptor = f
 	}
 
-	imps := importedFiles(f.Imports)
+	// Step 1: Pre-initialize all declared enums and messages.
+	// This enables step 2 to properly resolve references to locally defined
+	// enums and messages.
+	rl := make(descsByName)
+	f.L1.Enums.List = rl.initEnumsFromDescriptorProto(fd.GetEnumType(), f)
+	f.L1.Messages.List = rl.initMessagesFromDescriptorProto(fd.GetMessageType(), f)
+	f.L1.Extensions.List = rl.initExtensionsFromDescriptorProto(fd.GetExtension(), f)
+	f.L1.Services.List = rl.initServicesFromDescriptorProto(fd.GetService(), f)
 
-	var err error
-	f.Messages, err = messagesFromDescriptorProto(fd.GetMessageType(), imps, r)
-	if err != nil {
+	// Step 2: Handle every enum, message, extension, or service declaration.
+	r = resolver{local: rl, remote: r} // wrap remote resolver with local declarations
+	imps := importSet{f.L1.Path: true}
+	imps.importFiles(f.L2.Imports)
+	if err := enumsFromDescriptorProto(f.L1.Enums.List, fd.GetEnumType(), imps, r); err != nil {
 		return nil, err
 	}
-	f.Enums, err = enumsFromDescriptorProto(fd.GetEnumType(), r)
-	if err != nil {
+	if err := messagesFromDescriptorProto(f.L1.Messages.List, fd.GetMessageType(), imps, r); err != nil {
 		return nil, err
 	}
-	f.Extensions, err = extensionsFromDescriptorProto(fd.GetExtension(), imps, r)
-	if err != nil {
+	if err := extensionsFromDescriptorProto(f.L1.Extensions.List, fd.GetExtension(), imps, r); err != nil {
 		return nil, err
 	}
-	f.Services, err = servicesFromDescriptorProto(fd.GetService(), imps, r)
-	if err != nil {
+	if err := servicesFromDescriptorProto(f.L1.Services.List, fd.GetService(), imps, r); err != nil {
 		return nil, err
 	}
 
-	return prototype.NewFile(&f)
+	return f, nil
 }
 
-type importSet map[string]bool
+type descsByName map[protoreflect.FullName]protoreflect.Descriptor
 
-func importedFiles(imps []protoreflect.FileImport) importSet {
-	ret := make(importSet)
-	for _, imp := range imps {
-		ret[imp.Path()] = true
-		addPublicImports(imp, ret)
+func (r descsByName) initEnumsFromDescriptorProto(eds []*descriptorpb.EnumDescriptorProto, parent protoreflect.Descriptor) []filedesc.Enum {
+	es := make([]filedesc.Enum, len(eds)) // allocate up-front to ensure stable pointers
+	for i, ed := range eds {
+		e := &es[i]
+		e.L0 = makeBase(parent, ed.GetName(), i)
+		r[e.FullName()] = e
 	}
-	return ret
+	return es
 }
 
-func addPublicImports(fd protoreflect.FileDescriptor, out importSet) {
-	imps := fd.Imports()
-	for i := 0; i < imps.Len(); i++ {
-		imp := imps.Get(i)
-		if imp.IsPublic {
-			out[imp.Path()] = true
-			addPublicImports(imp, out)
+func (r descsByName) initMessagesFromDescriptorProto(mds []*descriptorpb.DescriptorProto, parent protoreflect.Descriptor) []filedesc.Message {
+	ms := make([]filedesc.Message, len(mds)) // allocate up-front to ensure stable pointers
+	for i, md := range mds {
+		m := &ms[i]
+		m.L0 = makeBase(parent, md.GetName(), i)
+		m.L1.Enums.List = r.initEnumsFromDescriptorProto(md.GetEnumType(), m)
+		m.L1.Messages.List = r.initMessagesFromDescriptorProto(md.GetNestedType(), m)
+		m.L1.Extensions.List = r.initExtensionsFromDescriptorProto(md.GetExtension(), m)
+		r[m.FullName()] = m
+	}
+	return ms
+}
+
+func (r descsByName) initExtensionsFromDescriptorProto(xds []*descriptorpb.FieldDescriptorProto, parent protoreflect.Descriptor) []filedesc.Extension {
+	xs := make([]filedesc.Extension, len(xds)) // allocate up-front to ensure stable pointers
+	for i, xd := range xds {
+		x := &xs[i]
+		x.L0 = makeBase(parent, xd.GetName(), i)
+		r[x.FullName()] = x
+	}
+	return xs
+}
+
+func (r descsByName) initServicesFromDescriptorProto(sds []*descriptorpb.ServiceDescriptorProto, parent protoreflect.Descriptor) []filedesc.Service {
+	ss := make([]filedesc.Service, len(sds)) // allocate up-front to ensure stable pointers
+	for i, sd := range sds {
+		s := &ss[i]
+		s.L0 = makeBase(parent, sd.GetName(), i)
+		r[s.FullName()] = s
+	}
+	return ss
+}
+
+func makeBase(parent protoreflect.Descriptor, name string, idx int) filedesc.BaseL0 {
+	return filedesc.BaseL0{
+		FullName:   parent.FullName().Append(protoreflect.Name(name)),
+		ParentFile: parent.ParentFile().(*filedesc.File),
+		Parent:     parent,
+		Index:      idx,
+	}
+}
+
+func enumsFromDescriptorProto(es []filedesc.Enum, eds []*descriptorpb.EnumDescriptorProto, imps importSet, r Resolver) error {
+	for i, ed := range eds {
+		e := &es[i]
+		e.L2 = new(filedesc.EnumL2)
+		if opts := ed.GetOptions(); opts != nil {
+			e.L2.Options = func() protoreflect.ProtoMessage { return opts }
+		}
+		for _, s := range ed.GetReservedName() {
+			e.L2.ReservedNames.List = append(e.L2.ReservedNames.List, protoreflect.Name(s))
+		}
+		for _, rr := range ed.GetReservedRange() {
+			e.L2.ReservedRanges.List = append(e.L2.ReservedRanges.List, [2]protoreflect.EnumNumber{
+				protoreflect.EnumNumber(rr.GetStart()),
+				protoreflect.EnumNumber(rr.GetEnd()),
+			})
+		}
+		e.L2.Values.List = make([]filedesc.EnumValue, len(ed.GetValue()))
+		for j, vd := range ed.GetValue() {
+			v := &e.L2.Values.List[j]
+			v.L0 = makeBase(e, vd.GetName(), j)
+			v.L0.FullName = e.L0.Parent.FullName().Append(protoreflect.Name(vd.GetName())) // enum values are in the same scope as the enum itself
+			if opts := vd.GetOptions(); opts != nil {
+				v.L1.Options = func() protoreflect.ProtoMessage { return opts }
+			}
+			v.L1.Number = protoreflect.EnumNumber(vd.GetNumber())
+			if e.L2.ReservedNames.Has(v.Name()) {
+				return errors.New("enum %v contains value with reserved name %q", e.Name(), v.Name())
+			}
+			if e.L2.ReservedRanges.Has(v.Number()) {
+				return errors.New("enum %v contains value with reserved number %d", e.Name(), v.Number())
+			}
 		}
 	}
+	return nil
 }
 
-func messagesFromDescriptorProto(mds []*descriptorpb.DescriptorProto, imps importSet, r Resolver) (ms []prototype.Message, err error) {
-	for _, md := range mds {
-		var m prototype.Message
-		m.Name = protoreflect.Name(md.GetName())
-		m.Options = md.GetOptions()
-		m.IsMapEntry = md.GetOptions().GetMapEntry()
+func messagesFromDescriptorProto(ms []filedesc.Message, mds []*descriptorpb.DescriptorProto, imps importSet, r Resolver) error {
+	for i, md := range mds {
+		m := &ms[i]
 
+		// Handle nested declarations. All enums must be handled before handling
+		// any messages since an enum field may have a default value that is
+		// specified in the same file being constructed.
+		if err := enumsFromDescriptorProto(m.L1.Enums.List, md.GetEnumType(), imps, r); err != nil {
+			return err
+		}
+		if err := messagesFromDescriptorProto(m.L1.Messages.List, md.GetNestedType(), imps, r); err != nil {
+			return err
+		}
+		if err := extensionsFromDescriptorProto(m.L1.Extensions.List, md.GetExtension(), imps, r); err != nil {
+			return err
+		}
+
+		// Handle the message descriptor itself.
+		m.L2 = new(filedesc.MessageL2)
+		if opts := md.GetOptions(); opts != nil {
+			m.L2.Options = func() protoreflect.ProtoMessage { return opts }
+			m.L2.IsMapEntry = opts.GetMapEntry()
+			m.L2.IsMessageSet = opts.GetMessageSetWireFormat()
+		}
 		for _, s := range md.GetReservedName() {
-			m.ReservedNames = append(m.ReservedNames, protoreflect.Name(s))
+			m.L2.ReservedNames.List = append(m.L2.ReservedNames.List, protoreflect.Name(s))
 		}
 		for _, rr := range md.GetReservedRange() {
-			m.ReservedRanges = append(m.ReservedRanges, [2]protoreflect.FieldNumber{
+			m.L2.ReservedRanges.List = append(m.L2.ReservedRanges.List, [2]protoreflect.FieldNumber{
 				protoreflect.FieldNumber(rr.GetStart()),
 				protoreflect.FieldNumber(rr.GetEnd()),
 			})
 		}
 		for _, xr := range md.GetExtensionRange() {
-			m.ExtensionRanges = append(m.ExtensionRanges, [2]protoreflect.FieldNumber{
+			m.L2.ExtensionRanges.List = append(m.L2.ExtensionRanges.List, [2]protoreflect.FieldNumber{
 				protoreflect.FieldNumber(xr.GetStart()),
 				protoreflect.FieldNumber(xr.GetEnd()),
 			})
-			m.ExtensionRangeOptions = append(m.ExtensionRangeOptions, xr.GetOptions())
+			var optsFunc func() protoreflect.ProtoMessage
+			if opts := xr.GetOptions(); opts != nil {
+				optsFunc = func() protoreflect.ProtoMessage { return opts }
+			}
+			m.L2.ExtensionRangeOptions = append(m.L2.ExtensionRangeOptions, optsFunc)
 		}
-		resNames := prototype.Names(m.ReservedNames)
-		resRanges := prototype.FieldRanges(m.ReservedRanges)
-		extRanges := prototype.FieldRanges(m.ExtensionRanges)
-
-		for _, fd := range md.GetField() {
-			if fd.GetExtendee() != "" {
-				return nil, errors.New("message field may not have extendee")
+		m.L2.Fields.List = make([]filedesc.Field, len(md.GetField()))
+		m.L2.Oneofs.List = make([]filedesc.Oneof, len(md.GetOneofDecl()))
+		for j, fd := range md.GetField() {
+			f := &m.L2.Fields.List[j]
+			f.L0 = makeBase(m, fd.GetName(), j)
+			if opts := fd.GetOptions(); opts != nil {
+				f.L1.Options = func() protoreflect.ProtoMessage { return opts }
+				f.L1.IsWeak = opts.GetWeak()
+				f.L1.HasPacked = opts.Packed != nil
+				f.L1.IsPacked = opts.GetPacked()
 			}
-			var f prototype.Field
-			f.Name = protoreflect.Name(fd.GetName())
-			if resNames.Has(f.Name) {
-				return nil, errors.New("%v contains field with reserved name %q", m.Name, f.Name)
+			if m.L2.ReservedNames.Has(f.Name()) {
+				return errors.New("%v contains field with reserved name %q", m.Name(), f.Name())
 			}
-			f.Number = protoreflect.FieldNumber(fd.GetNumber())
-			if resRanges.Has(f.Number) {
-				return nil, errors.New("%v contains field with reserved number %d", m.Name, f.Number)
+			f.L1.Number = protoreflect.FieldNumber(fd.GetNumber())
+			if m.L2.ReservedRanges.Has(f.Number()) {
+				return errors.New("%v contains field with reserved number %d", m.Name(), f.Number())
 			}
-			if extRanges.Has(f.Number) {
-				return nil, errors.New("%v contains field with number %d in extension range", m.Name, f.Number)
+			if m.L2.ExtensionRanges.Has(f.Number()) {
+				return errors.New("%v contains field with number %d in extension range", m.Name(), f.Number())
 			}
-			f.Cardinality = protoreflect.Cardinality(fd.GetLabel())
-			f.Kind = protoreflect.Kind(fd.GetType())
-			opts := fd.GetOptions()
-			f.Options = opts
-			if opts != nil && opts.Packed != nil {
-				if *opts.Packed {
-					f.IsPacked = prototype.True
-				} else {
-					f.IsPacked = prototype.False
-				}
+			f.L1.Cardinality = protoreflect.Cardinality(fd.GetLabel())
+			if f.L1.Cardinality == protoreflect.Required {
+				m.L2.RequiredNumbers.List = append(m.L2.RequiredNumbers.List, f.L1.Number)
 			}
-			f.IsWeak = opts.GetWeak()
-			f.JSONName = fd.GetJsonName()
-			if fd.DefaultValue != nil {
-				f.Default, err = defval.Unmarshal(fd.GetDefaultValue(), f.Kind, defval.Descriptor)
-				if err != nil {
-					return nil, err
-				}
+			f.L1.Kind = protoreflect.Kind(fd.GetType())
+			if fd.JsonName != nil {
+				f.L1.JSONName = filedesc.JSONName(fd.GetJsonName())
 			}
 			if fd.OneofIndex != nil {
-				i := int(fd.GetOneofIndex())
-				if i >= len(md.GetOneofDecl()) {
-					return nil, errors.New("invalid oneof index: %d", i)
+				k := int(fd.GetOneofIndex())
+				if k >= len(md.GetOneofDecl()) {
+					return errors.New("invalid oneof index: %d", k)
 				}
-				f.OneofName = protoreflect.Name(md.GetOneofDecl()[i].GetName())
+				o := &m.L2.Oneofs.List[k]
+				f.L1.ContainingOneof = o
+				o.L1.Fields.List = append(o.L1.Fields.List, f)
 			}
-			switch f.Kind {
+			if fd.GetExtendee() != "" {
+				return errors.New("message field may not have extendee")
+			}
+			switch f.L1.Kind {
 			case protoreflect.EnumKind:
-				f.EnumType, err = findEnumDescriptor(fd.GetTypeName(), imps, r)
+				ed, err := findEnumDescriptor(fd.GetTypeName(), f.L1.IsWeak, imps, r)
 				if err != nil {
-					return nil, err
+					return err
 				}
-				if opts.GetWeak() && !f.EnumType.IsPlaceholder() {
-					f.EnumType = prototype.PlaceholderEnum(f.EnumType.FullName())
-				}
+				f.L1.Enum = ed
 			case protoreflect.MessageKind, protoreflect.GroupKind:
-				f.MessageType, err = findMessageDescriptor(fd.GetTypeName(), imps, r)
+				md, err := findMessageDescriptor(fd.GetTypeName(), f.L1.IsWeak, imps, r)
 				if err != nil {
-					return nil, err
+					return err
 				}
-				if opts.GetWeak() && !f.MessageType.IsPlaceholder() {
-					f.MessageType = prototype.PlaceholderMessage(f.MessageType.FullName())
-				}
+				f.L1.Message = md
 			default:
 				if fd.GetTypeName() != "" {
-					return nil, errors.New("field of kind %v has type_name set", f.Kind)
+					return errors.New("field of kind %v has type_name set", f.L1.Kind)
 				}
 			}
-			m.Fields = append(m.Fields, f)
+			if fd.DefaultValue != nil {
+				// Handle default value after resolving the enum since the
+				// list of enum values is needed to resolve enums by name.
+				var evs protoreflect.EnumValueDescriptors
+				if f.L1.Kind == protoreflect.EnumKind {
+					evs = f.L1.Enum.Values()
+				}
+				v, ev, err := defval.Unmarshal(fd.GetDefaultValue(), f.L1.Kind, evs, defval.Descriptor)
+				if err != nil {
+					return err
+				}
+				f.L1.Default = filedesc.DefaultValue(v, ev)
+			}
 		}
-		for _, od := range md.GetOneofDecl() {
-			m.Oneofs = append(m.Oneofs, prototype.Oneof{
-				Name:    protoreflect.Name(od.GetName()),
-				Options: od.Options,
-			})
+		for j, od := range md.GetOneofDecl() {
+			o := &m.L2.Oneofs.List[j]
+			o.L0 = makeBase(m, od.GetName(), j)
+			if opts := od.GetOptions(); opts != nil {
+				o.L1.Options = func() protoreflect.ProtoMessage { return opts }
+			}
 		}
-
-		m.Messages, err = messagesFromDescriptorProto(md.GetNestedType(), imps, r)
-		if err != nil {
-			return nil, err
-		}
-		m.Enums, err = enumsFromDescriptorProto(md.GetEnumType(), r)
-		if err != nil {
-			return nil, err
-		}
-		m.Extensions, err = extensionsFromDescriptorProto(md.GetExtension(), imps, r)
-		if err != nil {
-			return nil, err
-		}
-
-		ms = append(ms, m)
 	}
-	return ms, nil
+	return nil
 }
 
-func enumsFromDescriptorProto(eds []*descriptorpb.EnumDescriptorProto, r Resolver) (es []prototype.Enum, err error) {
-	for _, ed := range eds {
-		var e prototype.Enum
-		e.Name = protoreflect.Name(ed.GetName())
-		e.Options = ed.GetOptions()
-		for _, s := range ed.GetReservedName() {
-			e.ReservedNames = append(e.ReservedNames, protoreflect.Name(s))
+func extensionsFromDescriptorProto(xs []filedesc.Extension, xds []*descriptorpb.FieldDescriptorProto, imps importSet, r Resolver) error {
+	for i, xd := range xds {
+		x := &xs[i]
+		x.L2 = new(filedesc.ExtensionL2)
+		if opts := xd.GetOptions(); opts != nil {
+			x.L2.Options = func() protoreflect.ProtoMessage { return opts }
+			x.L2.IsPacked = opts.GetPacked()
 		}
-		for _, rr := range ed.GetReservedRange() {
-			e.ReservedRanges = append(e.ReservedRanges, [2]protoreflect.EnumNumber{
-				protoreflect.EnumNumber(rr.GetStart()),
-				protoreflect.EnumNumber(rr.GetEnd()),
-			})
+		x.L1.Number = protoreflect.FieldNumber(xd.GetNumber())
+		x.L2.Cardinality = protoreflect.Cardinality(xd.GetLabel())
+		x.L1.Kind = protoreflect.Kind(xd.GetType())
+		if xd.JsonName != nil {
+			x.L2.JSONName = filedesc.JSONName(xd.GetJsonName())
 		}
-		resNames := prototype.Names(e.ReservedNames)
-		resRanges := prototype.EnumRanges(e.ReservedRanges)
-
-		for _, vd := range ed.GetValue() {
-			v := prototype.EnumValue{
-				Name:    protoreflect.Name(vd.GetName()),
-				Number:  protoreflect.EnumNumber(vd.GetNumber()),
-				Options: vd.Options,
-			}
-			if resNames.Has(v.Name) {
-				return nil, errors.New("enum %v contains value with reserved name %q", e.Name, v.Name)
-			}
-			if resRanges.Has(v.Number) {
-				return nil, errors.New("enum %v contains value with reserved number %d", e.Name, v.Number)
-			}
-			e.Values = append(e.Values, v)
-		}
-		es = append(es, e)
-	}
-	return es, nil
-}
-
-func extensionsFromDescriptorProto(xds []*descriptorpb.FieldDescriptorProto, imps importSet, r Resolver) (xs []prototype.Extension, err error) {
-	for _, xd := range xds {
 		if xd.OneofIndex != nil {
-			return nil, errors.New("extension may not have oneof_index")
+			return errors.New("extension may not have oneof_index")
 		}
-		var x prototype.Extension
-		x.Name = protoreflect.Name(xd.GetName())
-		x.Number = protoreflect.FieldNumber(xd.GetNumber())
-		x.Cardinality = protoreflect.Cardinality(xd.GetLabel())
-		x.Kind = protoreflect.Kind(xd.GetType())
-		x.Options = xd.GetOptions()
-		if xd.DefaultValue != nil {
-			x.Default, err = defval.Unmarshal(xd.GetDefaultValue(), x.Kind, defval.Descriptor)
-			if err != nil {
-				return nil, err
-			}
+		md, err := findMessageDescriptor(xd.GetExtendee(), false, imps, r)
+		if err != nil {
+			return err
 		}
-		switch x.Kind {
+		x.L1.Extendee = md
+		switch x.L1.Kind {
 		case protoreflect.EnumKind:
-			x.EnumType, err = findEnumDescriptor(xd.GetTypeName(), imps, r)
+			ed, err := findEnumDescriptor(xd.GetTypeName(), false, imps, r)
 			if err != nil {
-				return nil, err
+				return err
 			}
+			x.L2.Enum = ed
 		case protoreflect.MessageKind, protoreflect.GroupKind:
-			x.MessageType, err = findMessageDescriptor(xd.GetTypeName(), imps, r)
+			md, err := findMessageDescriptor(xd.GetTypeName(), false, imps, r)
 			if err != nil {
-				return nil, err
+				return err
 			}
+			x.L2.Message = md
 		default:
 			if xd.GetTypeName() != "" {
-				return nil, errors.New("extension of kind %v has type_name set", x.Kind)
+				return errors.New("field of kind %v has type_name set", x.L1.Kind)
 			}
 		}
-		x.ExtendedType, err = findMessageDescriptor(xd.GetExtendee(), imps, r)
-		if err != nil {
-			return nil, err
+		if xd.DefaultValue != nil {
+			// Handle default value after resolving the enum since the
+			// list of enum values is needed to resolve enums by name.
+			var evs protoreflect.EnumValueDescriptors
+			if x.L1.Kind == protoreflect.EnumKind {
+				evs = x.L2.Enum.Values()
+			}
+			v, ev, err := defval.Unmarshal(xd.GetDefaultValue(), x.L1.Kind, evs, defval.Descriptor)
+			if err != nil {
+				return err
+			}
+			x.L2.Default = filedesc.DefaultValue(v, ev)
 		}
-		xs = append(xs, x)
 	}
-	return xs, nil
+	return nil
 }
 
-func servicesFromDescriptorProto(sds []*descriptorpb.ServiceDescriptorProto, imps importSet, r Resolver) (ss []prototype.Service, err error) {
-	for _, sd := range sds {
-		var s prototype.Service
-		s.Name = protoreflect.Name(sd.GetName())
-		s.Options = sd.GetOptions()
-		for _, md := range sd.GetMethod() {
-			var m prototype.Method
-			m.Name = protoreflect.Name(md.GetName())
-			m.Options = md.GetOptions()
-			m.InputType, err = findMessageDescriptor(md.GetInputType(), imps, r)
-			if err != nil {
-				return nil, err
-			}
-			m.OutputType, err = findMessageDescriptor(md.GetOutputType(), imps, r)
-			if err != nil {
-				return nil, err
-			}
-			m.IsStreamingClient = md.GetClientStreaming()
-			m.IsStreamingServer = md.GetServerStreaming()
-			s.Methods = append(s.Methods, m)
+func servicesFromDescriptorProto(ss []filedesc.Service, sds []*descriptorpb.ServiceDescriptorProto, imps importSet, r Resolver) (err error) {
+	for i, sd := range sds {
+		s := &ss[i]
+		s.L2 = new(filedesc.ServiceL2)
+		if opts := sd.GetOptions(); opts != nil {
+			s.L2.Options = func() protoreflect.ProtoMessage { return opts }
 		}
-		ss = append(ss, s)
+		s.L2.Methods.List = make([]filedesc.Method, len(sd.GetMethod()))
+		for j, md := range sd.GetMethod() {
+			m := &s.L2.Methods.List[j]
+			m.L0 = makeBase(s, md.GetName(), j)
+			if opts := md.GetOptions(); opts != nil {
+				m.L1.Options = func() protoreflect.ProtoMessage { return opts }
+			}
+			m.L1.Input, err = findMessageDescriptor(md.GetInputType(), false, imps, r)
+			if err != nil {
+				return err
+			}
+			m.L1.Output, err = findMessageDescriptor(md.GetOutputType(), false, imps, r)
+			if err != nil {
+				return err
+			}
+			m.L1.IsStreamingClient = md.GetClientStreaming()
+			m.L1.IsStreamingServer = md.GetServerStreaming()
+		}
 	}
-	return ss, nil
+	return nil
+}
+
+type resolver struct {
+	local  descsByName
+	remote Resolver
+}
+
+func (r resolver) FindFileByPath(s string) (protoreflect.FileDescriptor, error) {
+	return r.remote.FindFileByPath(s)
+}
+
+func (r resolver) FindEnumByName(s protoreflect.FullName) (protoreflect.EnumDescriptor, error) {
+	if d, ok := r.local[s]; ok {
+		if ed, ok := d.(protoreflect.EnumDescriptor); ok {
+			return ed, nil
+		}
+		return nil, errors.New("found wrong type")
+	}
+	return r.remote.FindEnumByName(s)
+}
+
+func (r resolver) FindMessageByName(s protoreflect.FullName) (protoreflect.MessageDescriptor, error) {
+	if d, ok := r.local[s]; ok {
+		if md, ok := d.(protoreflect.MessageDescriptor); ok {
+			return md, nil
+		}
+		return nil, errors.New("found wrong type")
+	}
+	return r.remote.FindMessageByName(s)
+}
+
+type importSet map[string]bool
+
+func (is importSet) importFiles(files []protoreflect.FileImport) {
+	for _, imp := range files {
+		is[imp.Path()] = true
+		is.importPublic(imp)
+	}
+}
+
+func (is importSet) importPublic(fd protoreflect.FileDescriptor) {
+	imps := fd.Imports()
+	for i := 0; i < imps.Len(); i++ {
+		if imp := imps.Get(i); imp.IsPublic {
+			is[imp.Path()] = true
+			is.importPublic(imp)
+		}
+	}
+}
+
+// check returns an error if d does not belong to a currently imported file.
+func (is importSet) check(d protoreflect.Descriptor) error {
+	if !is[d.ParentFile().Path()] {
+		return errors.New("reference to type %v without import of %v", d.FullName(), d.ParentFile().Path())
+	}
+	return nil
 }
 
 // TODO: Should we allow relative names? The protoc compiler has emitted
@@ -364,43 +510,48 @@
 // simplifies our implementation as we won't need to implement C++'s namespace
 // scoping rules.
 
-func findMessageDescriptor(s string, imps importSet, r Resolver) (protoreflect.MessageDescriptor, error) {
-	if !strings.HasPrefix(s, ".") {
-		return nil, errors.New("identifier name must be fully qualified with a leading dot: %v", s)
-	}
-	name := protoreflect.FullName(strings.TrimPrefix(s, "."))
-	md, err := r.FindMessageByName(name)
-	if err != nil {
-		return prototype.PlaceholderMessage(name), nil
-	}
-	if err := validateFileInImports(md, imps); err != nil {
-		return nil, err
-	}
-	return md, nil
-}
-
-func findEnumDescriptor(s string, imps importSet, r Resolver) (protoreflect.EnumDescriptor, error) {
+func findEnumDescriptor(s string, isWeak bool, imps importSet, r Resolver) (protoreflect.EnumDescriptor, error) {
 	if !strings.HasPrefix(s, ".") {
 		return nil, errors.New("identifier name must be fully qualified with a leading dot: %v", s)
 	}
 	name := protoreflect.FullName(strings.TrimPrefix(s, "."))
 	ed, err := r.FindEnumByName(name)
 	if err != nil {
-		return prototype.PlaceholderEnum(name), nil
+		if err == protoregistry.NotFound {
+			if isWeak {
+				return filedesc.PlaceholderEnum(name), nil
+			}
+			// TODO: This should be an error.
+			return filedesc.PlaceholderEnum(name), nil
+			// return nil, errors.New("could not resolve enum: %v", name)
+		}
+		return nil, err
 	}
-	if err := validateFileInImports(ed, imps); err != nil {
+	if err := imps.check(ed); err != nil {
 		return nil, err
 	}
 	return ed, nil
 }
 
-func validateFileInImports(d protoreflect.Descriptor, imps importSet) error {
-	fd := d.ParentFile()
-	if fd == nil {
-		return errors.New("%v has no parent FileDescriptor", d.FullName())
+func findMessageDescriptor(s string, isWeak bool, imps importSet, r Resolver) (protoreflect.MessageDescriptor, error) {
+	if !strings.HasPrefix(s, ".") {
+		return nil, errors.New("identifier name must be fully qualified with a leading dot: %v", s)
 	}
-	if !imps[fd.Path()] {
-		return errors.New("reference to type %v without import of %v", d.FullName(), fd.Path())
+	name := protoreflect.FullName(strings.TrimPrefix(s, "."))
+	md, err := r.FindMessageByName(name)
+	if err != nil {
+		if err == protoregistry.NotFound {
+			if isWeak {
+				return filedesc.PlaceholderMessage(name), nil
+			}
+			// TODO: This should be an error.
+			return filedesc.PlaceholderMessage(name), nil
+			// return nil, errors.New("could not resolve message: %v", name)
+		}
+		return nil, err
 	}
-	return nil
+	if err := imps.check(md); err != nil {
+		return nil, err
+	}
+	return md, nil
 }
diff --git a/reflect/protodesc/protodesc_test.go b/reflect/protodesc/protodesc_test.go
index 19c3ab3..1ef9c43 100644
--- a/reflect/protodesc/protodesc_test.go
+++ b/reflect/protodesc/protodesc_test.go
@@ -1,3 +1,7 @@
+// 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 protodesc
 
 import (
@@ -439,7 +443,7 @@
 					Name:     scalar.String("nested_message"),
 					Number:   scalar.Int32(4),
 					Label:    descriptorpb.FieldDescriptorProto_LABEL_OPTIONAL.Enum(),
-					Type:     descriptorpb.FieldDescriptorProto_TYPE_ENUM.Enum(),
+					Type:     descriptorpb.FieldDescriptorProto_TYPE_MESSAGE.Enum(),
 					TypeName: scalar.String(".foo.TopLevelMessage.NestedMessage"),
 				}},
 			}},
@@ -596,14 +600,14 @@
 			for _, dep := range tc.deps {
 				f, err := NewFile(dep, r)
 				if err != nil {
-					t.Fatalf("Error creating dependency: %v", err)
+					t.Fatalf("error creating dependency: %v", err)
 				}
 				if err := r.Register(f); err != nil {
-					t.Fatalf("Error adding dependency: %v", err)
+					t.Fatalf("error adding dependency: %v", err)
 				}
 			}
 			if _, err := NewFile(tc.fd, r); err != nil {
-				t.Errorf("NewFile: got err = %v", err)
+				t.Errorf("unexpected NewFile error: %v", err)
 			}
 		})
 	}
diff --git a/reflect/protodesc/toproto.go b/reflect/protodesc/toproto.go
index 772b65a..26b4f1d 100644
--- a/reflect/protodesc/toproto.go
+++ b/reflect/protodesc/toproto.go
@@ -117,17 +117,11 @@
 		p.JsonName = scalar.String(field.JSONName())
 	}
 	if field.HasDefault() {
-		if field.Kind() == protoreflect.EnumKind {
-			// TODO: defval.Marshal should probably take a FieldDescriptor
-			// instead of a Kind and do this itself.
-			p.DefaultValue = scalar.String(string(field.DefaultEnumValue().Name()))
-		} else {
-			def, err := defval.Marshal(field.Default(), field.Kind(), defval.Descriptor)
-			if err != nil {
-				panic(fmt.Sprintf("%v: %v", field.FullName(), err))
-			}
-			p.DefaultValue = scalar.String(def)
+		def, err := defval.Marshal(field.Default(), field.DefaultEnumValue(), field.Kind(), defval.Descriptor)
+		if err != nil {
+			panic(fmt.Sprintf("%v: %v", field.FullName(), err))
 		}
+		p.DefaultValue = scalar.String(def)
 	}
 	if oneof := field.ContainingOneof(); oneof != nil {
 		p.OneofIndex = scalar.Int32(int32(oneof.Index()))
diff --git a/reflect/protoreflect/type.go b/reflect/protoreflect/type.go
index f406ed3..1aabd05 100644
--- a/reflect/protoreflect/type.go
+++ b/reflect/protoreflect/type.go
@@ -85,6 +85,8 @@
 	// For FileDescriptor, the Path and Package are also valid.
 	IsPlaceholder() bool
 
+	// TODO: Decide memory ownership of Options.
+
 	// Options returns the descriptor options. The caller must not modify
 	// the returned value.
 	//
diff --git a/reflect/protoregistry/registry_test.go b/reflect/protoregistry/registry_test.go
index de0c4a6..29c87e7 100644
--- a/reflect/protoregistry/registry_test.go
+++ b/reflect/protoregistry/registry_test.go
@@ -12,15 +12,29 @@
 	"github.com/google/go-cmp/cmp"
 	"github.com/google/go-cmp/cmp/cmpopts"
 
+	"google.golang.org/protobuf/encoding/prototext"
 	pimpl "google.golang.org/protobuf/internal/impl"
-	ptype "google.golang.org/protobuf/internal/prototype"
+	pdesc "google.golang.org/protobuf/reflect/protodesc"
 	pref "google.golang.org/protobuf/reflect/protoreflect"
 	preg "google.golang.org/protobuf/reflect/protoregistry"
 
 	test2pb "google.golang.org/protobuf/internal/testprotos/test"
 	testpb "google.golang.org/protobuf/reflect/protoregistry/testprotos"
+	"google.golang.org/protobuf/types/descriptorpb"
 )
 
+func mustMakeFile(s string) pref.FileDescriptor {
+	pb := new(descriptorpb.FileDescriptorProto)
+	if err := prototext.Unmarshal([]byte(s), pb); err != nil {
+		panic(err)
+	}
+	fd, err := pdesc.NewFile(pb, nil)
+	if err != nil {
+		panic(err)
+	}
+	return fd
+}
+
 func TestFiles(t *testing.T) {
 	type (
 		file struct {
@@ -28,7 +42,7 @@
 			Pkg  pref.FullName
 		}
 		testFile struct {
-			inFile  *ptype.File
+			inFile  pref.FileDescriptor
 			wantErr string
 		}
 		testRangePkg struct {
@@ -48,12 +62,12 @@
 	}{{
 		// Test that overlapping packages and files are permitted.
 		files: []testFile{
-			{inFile: &ptype.File{Syntax: pref.Proto2, Path: "test1.proto", Package: "foo.bar"}},
-			{inFile: &ptype.File{Syntax: pref.Proto2, Path: "foo/bar/test.proto", Package: "my.test"}},
-			{inFile: &ptype.File{Syntax: pref.Proto2, Path: "foo/bar/test.proto", Package: "foo.bar.baz"}, wantErr: "already registered"},
-			{inFile: &ptype.File{Syntax: pref.Proto2, Path: "test2.proto", Package: "my.test.package"}},
-			{inFile: &ptype.File{Syntax: pref.Proto2, Package: "foo.bar"}},
-			{inFile: &ptype.File{Syntax: pref.Proto2, Path: "foo/bar/baz/../test.proto", Package: "my.test"}},
+			{inFile: mustMakeFile(`syntax:"proto2" name:"test1.proto" package:"foo.bar"`)},
+			{inFile: mustMakeFile(`syntax:"proto2" name:"foo/bar/test.proto" package:"my.test"`)},
+			{inFile: mustMakeFile(`syntax:"proto2" name:"foo/bar/test.proto" package:"foo.bar.baz"`), wantErr: "already registered"},
+			{inFile: mustMakeFile(`syntax:"proto2" name:"test2.proto" package:"my.test.package"`)},
+			{inFile: mustMakeFile(`syntax:"proto2" name:"" package:"foo.bar"`)},
+			{inFile: mustMakeFile(`syntax:"proto2" name:"foo/bar/baz/../test.proto" package:"my.test"`)},
 		},
 
 		rangePkgs: []testRangePkg{{
@@ -100,104 +114,96 @@
 	}, {
 		// Test when new enum conflicts with existing package.
 		files: []testFile{{
-			inFile: &ptype.File{Syntax: pref.Proto2, Path: "test1a.proto", Package: "foo.bar.baz"},
+			inFile: mustMakeFile(`syntax:"proto2" name:"test1a.proto" package:"foo.bar.baz"`),
 		}, {
-			inFile:  &ptype.File{Syntax: pref.Proto2, Path: "test1b.proto", Enums: []ptype.Enum{{Name: "foo"}}},
+			inFile:  mustMakeFile(`syntax:"proto2" name:"test1b.proto" enum_type:[{name:"foo"}]`),
 			wantErr: `file "test1b.proto" has a name conflict over foo`,
 		}},
 	}, {
 		// Test when new package conflicts with existing enum.
 		files: []testFile{{
-			inFile: &ptype.File{Syntax: pref.Proto2, Path: "test2a.proto", Enums: []ptype.Enum{{Name: "foo"}}},
+			inFile: mustMakeFile(`syntax:"proto2" name:"test2a.proto" enum_type:[{name:"foo"}]`),
 		}, {
-			inFile:  &ptype.File{Syntax: pref.Proto2, Path: "test2b.proto", Package: "foo.bar.baz"},
+			inFile:  mustMakeFile(`syntax:"proto2" name:"test2b.proto" package:"foo.bar.baz"`),
 			wantErr: `file "test2b.proto" has a name conflict over foo`,
 		}},
 	}, {
 		// Test when new enum conflicts with existing enum in same package.
 		files: []testFile{{
-			inFile: &ptype.File{Syntax: pref.Proto2, Path: "test3a.proto", Package: "foo", Enums: []ptype.Enum{{Name: "BAR"}}},
+			inFile: mustMakeFile(`syntax:"proto2" name:"test3a.proto" package:"foo" enum_type:[{name:"BAR"}]`),
 		}, {
-			inFile:  &ptype.File{Syntax: pref.Proto2, Path: "test3b.proto", Package: "foo", Enums: []ptype.Enum{{Name: "BAR"}}},
+			inFile:  mustMakeFile(`syntax:"proto2" name:"test3b.proto" package:"foo" enum_type:[{name:"BAR"}]`),
 			wantErr: `file "test3b.proto" has a name conflict over foo.BAR`,
 		}},
 	}, {
 		files: []testFile{{
-			inFile: &ptype.File{
-				Syntax:  pref.Proto2,
-				Path:    "test1.proto",
-				Package: "fizz.buzz",
-				Messages: []ptype.Message{{
-					Name: "Message",
-					Fields: []ptype.Field{{
-						Name:        "Field",
-						Number:      1,
-						Cardinality: pref.Optional,
-						Kind:        pref.StringKind,
-						OneofName:   "Oneof",
-					}},
-					Oneofs:          []ptype.Oneof{{Name: "Oneof"}},
-					ExtensionRanges: [][2]pref.FieldNumber{{1000, 2000}},
-				}},
-				Enums: []ptype.Enum{{
-					Name:   "Enum",
-					Values: []ptype.EnumValue{{Name: "EnumValue", Number: 0}},
-				}},
-				Extensions: []ptype.Extension{{
-					Name:         "Extension",
-					Number:       1000,
-					Cardinality:  pref.Optional,
-					Kind:         pref.StringKind,
-					ExtendedType: ptype.PlaceholderMessage("fizz.buzz.Message"),
-				}},
-				Services: []ptype.Service{{
-					Name: "Service",
-					Methods: []ptype.Method{{
-						Name:              "Method",
-						InputType:         ptype.PlaceholderMessage("fizz.buzz.Message"),
-						OutputType:        ptype.PlaceholderMessage("fizz.buzz.Message"),
-						IsStreamingClient: true,
-						IsStreamingServer: true,
-					}},
-				}},
-			},
+			inFile: mustMakeFile(`
+				syntax:  "proto2"
+				name:    "test1.proto"
+				package: "fizz.buzz"
+				message_type: [{
+					name: "Message"
+					field: [
+						{name:"Field" number:1 label:LABEL_OPTIONAL type:TYPE_STRING oneof_index:0}
+					]
+					oneof_decl:      [{name:"Oneof"}]
+					extension_range: [{start:1000 end:2000}]
+				}]
+				enum_type: [{
+					name:  "Enum"
+					Value: [{name:"EnumValue" number:0}]
+				}]
+				extension: [
+					{name:"Extension" number:1000 label:LABEL_OPTIONAL type:TYPE_STRING extendee:".fizz.buzz.Message"}
+				]
+				service: [{
+					name: "Service"
+					method: [{
+						name:             "Method"
+						input_type:       ".fizz.buzz.Message"
+						output_type:      ".fizz.buzz.Message"
+						client_streaming: true
+						server_streaming: true
+					}]
+				}]
+			`),
 		}, {
-			inFile: &ptype.File{
-				Syntax:  pref.Proto2,
-				Path:    "test2.proto",
-				Package: "fizz.buzz.gazz",
-				Enums: []ptype.Enum{{
-					Name:   "Enum",
-					Values: []ptype.EnumValue{{Name: "EnumValue", Number: 0}},
-				}},
-			},
+			inFile: mustMakeFile(`
+				syntax:  "proto2"
+				name:    "test2.proto"
+				package: "fizz.buzz.gazz"
+				enum_type: [{
+					name:  "Enum"
+					value: [{name:"EnumValue" number:0}]
+				}]
+			`),
 		}, {
-			inFile: &ptype.File{
-				Syntax:  pref.Proto2,
-				Path:    "test3.proto",
-				Package: "fizz.buzz",
-				Enums: []ptype.Enum{{
-					Name:   "Enum1",
-					Values: []ptype.EnumValue{{Name: "EnumValue1", Number: 0}},
+			inFile: mustMakeFile(`
+				syntax:  "proto2"
+				name:    "test3.proto"
+				package: "fizz.buzz"
+				enum_type: [{
+					name:  "Enum1"
+					value: [{name:"EnumValue1" number:0}]
 				}, {
-					Name:   "Enum2",
-					Values: []ptype.EnumValue{{Name: "EnumValue2", Number: 0}},
-				}},
-			},
+					name:  "Enum2"
+					value: [{name:"EnumValue2" number:0}]
+				}]
+			`),
 		}, {
 			// Make sure we can register without package name.
-			inFile: &ptype.File{
-				Syntax: pref.Proto2,
-				Messages: []ptype.Message{{
-					Name: "Message",
-					Messages: []ptype.Message{{
-						Name: "Message",
-						Messages: []ptype.Message{{
-							Name: "Message",
-						}},
-					}},
-				}},
-			},
+			inFile: mustMakeFile(`
+				syntax: "proto2"
+				message_type: [{
+					name: "Message"
+					nested_type: [{
+						name: "Message"
+						nested_type: [{
+							name: "Message"
+						}]
+					}]
+				}]
+			`),
 		}},
 	}}
 
@@ -208,11 +214,7 @@
 		t.Run("", func(t *testing.T) {
 			var files preg.Files
 			for i, tc := range tt.files {
-				fd, err := ptype.NewFile(tc.inFile)
-				if err != nil {
-					t.Fatalf("file %d, prototype.NewFile() error: %v", i, err)
-				}
-				gotErr := files.Register(fd)
+				gotErr := files.Register(tc.inFile)
 				if ((gotErr == nil) != (tc.wantErr == "")) || !strings.Contains(fmt.Sprint(gotErr), tc.wantErr) {
 					t.Errorf("file %d, Register() = %v, want %v", i, gotErr, tc.wantErr)
 				}
diff --git a/reflect/protoregistry/testprotos/test.pb.go b/reflect/protoregistry/testprotos/test.pb.go
index b6d70e4..4ed4811 100644
--- a/reflect/protoregistry/testprotos/test.pb.go
+++ b/reflect/protoregistry/testprotos/test.pb.go
@@ -5,7 +5,7 @@
 
 import (
 	protoreflect "google.golang.org/protobuf/reflect/protoreflect"
-	protoregistry "google.golang.org/protobuf/reflect/protoregistry"
+	prototype "google.golang.org/protobuf/reflect/prototype"
 	protoiface "google.golang.org/protobuf/runtime/protoiface"
 	protoimpl "google.golang.org/protobuf/runtime/protoimpl"
 	sync "sync"
@@ -45,7 +45,7 @@
 }
 
 func (Enum1) Descriptor() protoreflect.EnumDescriptor {
-	return file_test_proto_enumTypes[0].Descriptor()
+	return file_test_proto_enumTypes[0].EnumDescriptor
 }
 
 func (x Enum1) Number() protoreflect.EnumNumber {
@@ -94,7 +94,7 @@
 }
 
 func (Enum2) Descriptor() protoreflect.EnumDescriptor {
-	return file_test_proto_enumTypes[1].Descriptor()
+	return file_test_proto_enumTypes[1].EnumDescriptor
 }
 
 func (x Enum2) Number() protoreflect.EnumNumber {
@@ -143,7 +143,7 @@
 }
 
 func (Enum3) Descriptor() protoreflect.EnumDescriptor {
-	return file_test_proto_enumTypes[2].Descriptor()
+	return file_test_proto_enumTypes[2].EnumDescriptor
 }
 
 func (x Enum3) Number() protoreflect.EnumNumber {
@@ -426,7 +426,7 @@
 	return file_test_proto_rawDescData
 }
 
-var file_test_proto_enumTypes = make([]protoreflect.EnumType, 3)
+var file_test_proto_enumTypes = make([]prototype.Enum, 3)
 var file_test_proto_msgTypes = make([]protoimpl.MessageInfo, 4)
 var file_test_proto_goTypes = []interface{}{
 	(Enum1)(0),       // 0: testprotos.Enum1
@@ -438,16 +438,21 @@
 	(*Message4)(nil), // 6: testprotos.Message4
 }
 var file_test_proto_depIdxs = []int32{
-	3, // testprotos.string_field:extendee -> testprotos.Message1
-	3, // testprotos.enum_field:extendee -> testprotos.Message1
-	3, // testprotos.message_field:extendee -> testprotos.Message1
-	3, // testprotos.Message4.message_field:extendee -> testprotos.Message1
-	3, // testprotos.Message4.enum_field:extendee -> testprotos.Message1
-	3, // testprotos.Message4.string_field:extendee -> testprotos.Message1
-	0, // testprotos.enum_field:type_name -> testprotos.Enum1
-	4, // testprotos.message_field:type_name -> testprotos.Message2
-	4, // testprotos.Message4.message_field:type_name -> testprotos.Message2
-	0, // testprotos.Message4.enum_field:type_name -> testprotos.Enum1
+	3,  // testprotos.string_field:extendee -> testprotos.Message1
+	3,  // testprotos.enum_field:extendee -> testprotos.Message1
+	3,  // testprotos.message_field:extendee -> testprotos.Message1
+	3,  // testprotos.Message4.message_field:extendee -> testprotos.Message1
+	3,  // testprotos.Message4.enum_field:extendee -> testprotos.Message1
+	3,  // testprotos.Message4.string_field:extendee -> testprotos.Message1
+	0,  // testprotos.enum_field:type_name -> testprotos.Enum1
+	4,  // testprotos.message_field:type_name -> testprotos.Message2
+	4,  // testprotos.Message4.message_field:type_name -> testprotos.Message2
+	0,  // testprotos.Message4.enum_field:type_name -> testprotos.Enum1
+	10, // starting offset of method output_type sub-list
+	10, // starting offset of method input_type sub-list
+	6,  // starting offset of extension type_name sub-list
+	0,  // starting offset of extension extendee sub-list
+	0,  // starting offset of field type_name sub-list
 }
 
 func init() { file_test_proto_init() }
@@ -455,18 +460,21 @@
 	if File_test_proto != nil {
 		return
 	}
-	extensionTypes := make([]protoreflect.ExtensionType, 6)
-	File_test_proto = protoimpl.FileBuilder{
-		RawDescriptor:        file_test_proto_rawDesc,
-		GoTypes:              file_test_proto_goTypes,
-		DependencyIndexes:    file_test_proto_depIdxs,
-		LegacyExtensions:     file_test_proto_extDescs,
-		EnumOutputTypes:      file_test_proto_enumTypes,
-		MessageOutputTypes:   file_test_proto_msgTypes,
-		ExtensionOutputTypes: extensionTypes,
-		FilesRegistry:        protoregistry.GlobalFiles,
-		TypesRegistry:        protoregistry.GlobalTypes,
-	}.Init()
+	out := protoimpl.TypeBuilder{
+		File: protoimpl.DescBuilder{
+			RawDescriptor: file_test_proto_rawDesc,
+			NumEnums:      3,
+			NumMessages:   4,
+			NumExtensions: 6,
+			NumServices:   0,
+		},
+		GoTypes:           file_test_proto_goTypes,
+		DependencyIndexes: file_test_proto_depIdxs,
+		MessageInfos:      file_test_proto_msgTypes,
+		LegacyExtensions:  file_test_proto_extDescs,
+	}.Build()
+	File_test_proto = out.File
+	file_test_proto_enumTypes = out.Enums
 	file_test_proto_rawDesc = nil
 	file_test_proto_goTypes = nil
 	file_test_proto_depIdxs = nil
diff --git a/runtime/protoimpl/impl.go b/runtime/protoimpl/impl.go
index 59198a6..8470dbe 100644
--- a/runtime/protoimpl/impl.go
+++ b/runtime/protoimpl/impl.go
@@ -12,7 +12,9 @@
 package protoimpl
 
 import (
+	"google.golang.org/protobuf/internal/filedesc"
 	"google.golang.org/protobuf/internal/fileinit"
+	"google.golang.org/protobuf/internal/filetype"
 	"google.golang.org/protobuf/internal/impl"
 )
 
@@ -58,7 +60,9 @@
 	// being a compilation failure (guaranteed by the Go specification).
 	EnforceVersion uint
 
-	FileBuilder      = fileinit.FileBuilder
+	FileBuilder      = fileinit.FileBuilder // TODO: Remove this.
+	DescBuilder      = filedesc.DescBuilder
+	TypeBuilder      = filetype.TypeBuilder
 	MessageInfo      = impl.MessageInfo
 	SizeCache        = impl.SizeCache
 	UnknownFields    = impl.UnknownFields
diff --git a/types/descriptorpb/descriptor.pb.go b/types/descriptorpb/descriptor.pb.go
index 0dd8234..d2019e5 100644
--- a/types/descriptorpb/descriptor.pb.go
+++ b/types/descriptorpb/descriptor.pb.go
@@ -5,7 +5,7 @@
 
 import (
 	protoreflect "google.golang.org/protobuf/reflect/protoreflect"
-	protoregistry "google.golang.org/protobuf/reflect/protoregistry"
+	prototype "google.golang.org/protobuf/reflect/prototype"
 	protoiface "google.golang.org/protobuf/runtime/protoiface"
 	protoimpl "google.golang.org/protobuf/runtime/protoimpl"
 	sync "sync"
@@ -107,7 +107,7 @@
 }
 
 func (FieldDescriptorProto_Type) Descriptor() protoreflect.EnumDescriptor {
-	return file_google_protobuf_descriptor_proto_enumTypes[0].Descriptor()
+	return file_google_protobuf_descriptor_proto_enumTypes[0].EnumDescriptor
 }
 
 func (x FieldDescriptorProto_Type) Number() protoreflect.EnumNumber {
@@ -163,7 +163,7 @@
 }
 
 func (FieldDescriptorProto_Label) Descriptor() protoreflect.EnumDescriptor {
-	return file_google_protobuf_descriptor_proto_enumTypes[1].Descriptor()
+	return file_google_protobuf_descriptor_proto_enumTypes[1].EnumDescriptor
 }
 
 func (x FieldDescriptorProto_Label) Number() protoreflect.EnumNumber {
@@ -220,7 +220,7 @@
 }
 
 func (FileOptions_OptimizeMode) Descriptor() protoreflect.EnumDescriptor {
-	return file_google_protobuf_descriptor_proto_enumTypes[2].Descriptor()
+	return file_google_protobuf_descriptor_proto_enumTypes[2].EnumDescriptor
 }
 
 func (x FileOptions_OptimizeMode) Number() protoreflect.EnumNumber {
@@ -276,7 +276,7 @@
 }
 
 func (FieldOptions_CType) Descriptor() protoreflect.EnumDescriptor {
-	return file_google_protobuf_descriptor_proto_enumTypes[3].Descriptor()
+	return file_google_protobuf_descriptor_proto_enumTypes[3].EnumDescriptor
 }
 
 func (x FieldOptions_CType) Number() protoreflect.EnumNumber {
@@ -334,7 +334,7 @@
 }
 
 func (FieldOptions_JSType) Descriptor() protoreflect.EnumDescriptor {
-	return file_google_protobuf_descriptor_proto_enumTypes[4].Descriptor()
+	return file_google_protobuf_descriptor_proto_enumTypes[4].EnumDescriptor
 }
 
 func (x FieldOptions_JSType) Number() protoreflect.EnumNumber {
@@ -392,7 +392,7 @@
 }
 
 func (MethodOptions_IdempotencyLevel) Descriptor() protoreflect.EnumDescriptor {
-	return file_google_protobuf_descriptor_proto_enumTypes[5].Descriptor()
+	return file_google_protobuf_descriptor_proto_enumTypes[5].EnumDescriptor
 }
 
 func (x MethodOptions_IdempotencyLevel) Number() protoreflect.EnumNumber {
@@ -3197,7 +3197,7 @@
 	return file_google_protobuf_descriptor_proto_rawDescData
 }
 
-var file_google_protobuf_descriptor_proto_enumTypes = make([]protoreflect.EnumType, 6)
+var file_google_protobuf_descriptor_proto_enumTypes = make([]prototype.Enum, 6)
 var file_google_protobuf_descriptor_proto_msgTypes = make([]protoimpl.MessageInfo, 27)
 var file_google_protobuf_descriptor_proto_goTypes = []interface{}{
 	(FieldDescriptorProto_Type)(0),                // 0: google.protobuf.FieldDescriptorProto.Type
@@ -3278,6 +3278,11 @@
 	31, // google.protobuf.SourceCodeInfo.location:type_name -> google.protobuf.SourceCodeInfo.Location
 	32, // google.protobuf.GeneratedCodeInfo.annotation:type_name -> google.protobuf.GeneratedCodeInfo.Annotation
 	9,  // google.protobuf.DescriptorProto.ExtensionRange.options:type_name -> google.protobuf.ExtensionRangeOptions
+	43, // starting offset of method output_type sub-list
+	43, // starting offset of method input_type sub-list
+	43, // starting offset of extension type_name sub-list
+	43, // starting offset of extension extendee sub-list
+	0,  // starting offset of field type_name sub-list
 }
 
 func init() { file_google_protobuf_descriptor_proto_init() }
@@ -3285,15 +3290,20 @@
 	if File_google_protobuf_descriptor_proto != nil {
 		return
 	}
-	File_google_protobuf_descriptor_proto = protoimpl.FileBuilder{
-		RawDescriptor:      file_google_protobuf_descriptor_proto_rawDesc,
-		GoTypes:            file_google_protobuf_descriptor_proto_goTypes,
-		DependencyIndexes:  file_google_protobuf_descriptor_proto_depIdxs,
-		EnumOutputTypes:    file_google_protobuf_descriptor_proto_enumTypes,
-		MessageOutputTypes: file_google_protobuf_descriptor_proto_msgTypes,
-		FilesRegistry:      protoregistry.GlobalFiles,
-		TypesRegistry:      protoregistry.GlobalTypes,
-	}.Init()
+	out := protoimpl.TypeBuilder{
+		File: protoimpl.DescBuilder{
+			RawDescriptor: file_google_protobuf_descriptor_proto_rawDesc,
+			NumEnums:      6,
+			NumMessages:   27,
+			NumExtensions: 0,
+			NumServices:   0,
+		},
+		GoTypes:           file_google_protobuf_descriptor_proto_goTypes,
+		DependencyIndexes: file_google_protobuf_descriptor_proto_depIdxs,
+		MessageInfos:      file_google_protobuf_descriptor_proto_msgTypes,
+	}.Build()
+	File_google_protobuf_descriptor_proto = out.File
+	file_google_protobuf_descriptor_proto_enumTypes = out.Enums
 	file_google_protobuf_descriptor_proto_rawDesc = nil
 	file_google_protobuf_descriptor_proto_goTypes = nil
 	file_google_protobuf_descriptor_proto_depIdxs = nil
diff --git a/types/known/anypb/any.pb.go b/types/known/anypb/any.pb.go
index 6bdb337..368fd75 100644
--- a/types/known/anypb/any.pb.go
+++ b/types/known/anypb/any.pb.go
@@ -5,7 +5,6 @@
 
 import (
 	protoreflect "google.golang.org/protobuf/reflect/protoreflect"
-	protoregistry "google.golang.org/protobuf/reflect/protoregistry"
 	protoiface "google.golang.org/protobuf/runtime/protoiface"
 	protoimpl "google.golang.org/protobuf/runtime/protoimpl"
 	sync "sync"
@@ -210,21 +209,32 @@
 var file_google_protobuf_any_proto_goTypes = []interface{}{
 	(*Any)(nil), // 0: google.protobuf.Any
 }
-var file_google_protobuf_any_proto_depIdxs = []int32{}
+var file_google_protobuf_any_proto_depIdxs = []int32{
+	0, // starting offset of method output_type sub-list
+	0, // starting offset of method input_type sub-list
+	0, // starting offset of extension type_name sub-list
+	0, // starting offset of extension extendee sub-list
+	0, // starting offset of field type_name sub-list
+}
 
 func init() { file_google_protobuf_any_proto_init() }
 func file_google_protobuf_any_proto_init() {
 	if File_google_protobuf_any_proto != nil {
 		return
 	}
-	File_google_protobuf_any_proto = protoimpl.FileBuilder{
-		RawDescriptor:      file_google_protobuf_any_proto_rawDesc,
-		GoTypes:            file_google_protobuf_any_proto_goTypes,
-		DependencyIndexes:  file_google_protobuf_any_proto_depIdxs,
-		MessageOutputTypes: file_google_protobuf_any_proto_msgTypes,
-		FilesRegistry:      protoregistry.GlobalFiles,
-		TypesRegistry:      protoregistry.GlobalTypes,
-	}.Init()
+	out := protoimpl.TypeBuilder{
+		File: protoimpl.DescBuilder{
+			RawDescriptor: file_google_protobuf_any_proto_rawDesc,
+			NumEnums:      0,
+			NumMessages:   1,
+			NumExtensions: 0,
+			NumServices:   0,
+		},
+		GoTypes:           file_google_protobuf_any_proto_goTypes,
+		DependencyIndexes: file_google_protobuf_any_proto_depIdxs,
+		MessageInfos:      file_google_protobuf_any_proto_msgTypes,
+	}.Build()
+	File_google_protobuf_any_proto = out.File
 	file_google_protobuf_any_proto_rawDesc = nil
 	file_google_protobuf_any_proto_goTypes = nil
 	file_google_protobuf_any_proto_depIdxs = nil
diff --git a/types/known/apipb/api.pb.go b/types/known/apipb/api.pb.go
index dd9ca1d..af46a90 100644
--- a/types/known/apipb/api.pb.go
+++ b/types/known/apipb/api.pb.go
@@ -5,7 +5,6 @@
 
 import (
 	protoreflect "google.golang.org/protobuf/reflect/protoreflect"
-	protoregistry "google.golang.org/protobuf/reflect/protoregistry"
 	protoiface "google.golang.org/protobuf/runtime/protoiface"
 	protoimpl "google.golang.org/protobuf/runtime/protoimpl"
 	sourcecontextpb "google.golang.org/protobuf/types/known/sourcecontextpb"
@@ -454,6 +453,11 @@
 	5, // google.protobuf.Api.syntax:type_name -> google.protobuf.Syntax
 	3, // google.protobuf.Method.options:type_name -> google.protobuf.Option
 	5, // google.protobuf.Method.syntax:type_name -> google.protobuf.Syntax
+	7, // starting offset of method output_type sub-list
+	7, // starting offset of method input_type sub-list
+	7, // starting offset of extension type_name sub-list
+	7, // starting offset of extension extendee sub-list
+	0, // starting offset of field type_name sub-list
 }
 
 func init() { file_google_protobuf_api_proto_init() }
@@ -461,14 +465,19 @@
 	if File_google_protobuf_api_proto != nil {
 		return
 	}
-	File_google_protobuf_api_proto = protoimpl.FileBuilder{
-		RawDescriptor:      file_google_protobuf_api_proto_rawDesc,
-		GoTypes:            file_google_protobuf_api_proto_goTypes,
-		DependencyIndexes:  file_google_protobuf_api_proto_depIdxs,
-		MessageOutputTypes: file_google_protobuf_api_proto_msgTypes,
-		FilesRegistry:      protoregistry.GlobalFiles,
-		TypesRegistry:      protoregistry.GlobalTypes,
-	}.Init()
+	out := protoimpl.TypeBuilder{
+		File: protoimpl.DescBuilder{
+			RawDescriptor: file_google_protobuf_api_proto_rawDesc,
+			NumEnums:      0,
+			NumMessages:   3,
+			NumExtensions: 0,
+			NumServices:   0,
+		},
+		GoTypes:           file_google_protobuf_api_proto_goTypes,
+		DependencyIndexes: file_google_protobuf_api_proto_depIdxs,
+		MessageInfos:      file_google_protobuf_api_proto_msgTypes,
+	}.Build()
+	File_google_protobuf_api_proto = out.File
 	file_google_protobuf_api_proto_rawDesc = nil
 	file_google_protobuf_api_proto_goTypes = nil
 	file_google_protobuf_api_proto_depIdxs = nil
diff --git a/types/known/durationpb/duration.pb.go b/types/known/durationpb/duration.pb.go
index 7f889c3..788e57b 100644
--- a/types/known/durationpb/duration.pb.go
+++ b/types/known/durationpb/duration.pb.go
@@ -5,7 +5,6 @@
 
 import (
 	protoreflect "google.golang.org/protobuf/reflect/protoreflect"
-	protoregistry "google.golang.org/protobuf/reflect/protoregistry"
 	protoiface "google.golang.org/protobuf/runtime/protoiface"
 	protoimpl "google.golang.org/protobuf/runtime/protoimpl"
 	sync "sync"
@@ -171,21 +170,32 @@
 var file_google_protobuf_duration_proto_goTypes = []interface{}{
 	(*Duration)(nil), // 0: google.protobuf.Duration
 }
-var file_google_protobuf_duration_proto_depIdxs = []int32{}
+var file_google_protobuf_duration_proto_depIdxs = []int32{
+	0, // starting offset of method output_type sub-list
+	0, // starting offset of method input_type sub-list
+	0, // starting offset of extension type_name sub-list
+	0, // starting offset of extension extendee sub-list
+	0, // starting offset of field type_name sub-list
+}
 
 func init() { file_google_protobuf_duration_proto_init() }
 func file_google_protobuf_duration_proto_init() {
 	if File_google_protobuf_duration_proto != nil {
 		return
 	}
-	File_google_protobuf_duration_proto = protoimpl.FileBuilder{
-		RawDescriptor:      file_google_protobuf_duration_proto_rawDesc,
-		GoTypes:            file_google_protobuf_duration_proto_goTypes,
-		DependencyIndexes:  file_google_protobuf_duration_proto_depIdxs,
-		MessageOutputTypes: file_google_protobuf_duration_proto_msgTypes,
-		FilesRegistry:      protoregistry.GlobalFiles,
-		TypesRegistry:      protoregistry.GlobalTypes,
-	}.Init()
+	out := protoimpl.TypeBuilder{
+		File: protoimpl.DescBuilder{
+			RawDescriptor: file_google_protobuf_duration_proto_rawDesc,
+			NumEnums:      0,
+			NumMessages:   1,
+			NumExtensions: 0,
+			NumServices:   0,
+		},
+		GoTypes:           file_google_protobuf_duration_proto_goTypes,
+		DependencyIndexes: file_google_protobuf_duration_proto_depIdxs,
+		MessageInfos:      file_google_protobuf_duration_proto_msgTypes,
+	}.Build()
+	File_google_protobuf_duration_proto = out.File
 	file_google_protobuf_duration_proto_rawDesc = nil
 	file_google_protobuf_duration_proto_goTypes = nil
 	file_google_protobuf_duration_proto_depIdxs = nil
diff --git a/types/known/emptypb/empty.pb.go b/types/known/emptypb/empty.pb.go
index b3920f3..72952b4 100644
--- a/types/known/emptypb/empty.pb.go
+++ b/types/known/emptypb/empty.pb.go
@@ -5,7 +5,6 @@
 
 import (
 	protoreflect "google.golang.org/protobuf/reflect/protoreflect"
-	protoregistry "google.golang.org/protobuf/reflect/protoregistry"
 	protoiface "google.golang.org/protobuf/runtime/protoiface"
 	protoimpl "google.golang.org/protobuf/runtime/protoimpl"
 	sync "sync"
@@ -91,21 +90,32 @@
 var file_google_protobuf_empty_proto_goTypes = []interface{}{
 	(*Empty)(nil), // 0: google.protobuf.Empty
 }
-var file_google_protobuf_empty_proto_depIdxs = []int32{}
+var file_google_protobuf_empty_proto_depIdxs = []int32{
+	0, // starting offset of method output_type sub-list
+	0, // starting offset of method input_type sub-list
+	0, // starting offset of extension type_name sub-list
+	0, // starting offset of extension extendee sub-list
+	0, // starting offset of field type_name sub-list
+}
 
 func init() { file_google_protobuf_empty_proto_init() }
 func file_google_protobuf_empty_proto_init() {
 	if File_google_protobuf_empty_proto != nil {
 		return
 	}
-	File_google_protobuf_empty_proto = protoimpl.FileBuilder{
-		RawDescriptor:      file_google_protobuf_empty_proto_rawDesc,
-		GoTypes:            file_google_protobuf_empty_proto_goTypes,
-		DependencyIndexes:  file_google_protobuf_empty_proto_depIdxs,
-		MessageOutputTypes: file_google_protobuf_empty_proto_msgTypes,
-		FilesRegistry:      protoregistry.GlobalFiles,
-		TypesRegistry:      protoregistry.GlobalTypes,
-	}.Init()
+	out := protoimpl.TypeBuilder{
+		File: protoimpl.DescBuilder{
+			RawDescriptor: file_google_protobuf_empty_proto_rawDesc,
+			NumEnums:      0,
+			NumMessages:   1,
+			NumExtensions: 0,
+			NumServices:   0,
+		},
+		GoTypes:           file_google_protobuf_empty_proto_goTypes,
+		DependencyIndexes: file_google_protobuf_empty_proto_depIdxs,
+		MessageInfos:      file_google_protobuf_empty_proto_msgTypes,
+	}.Build()
+	File_google_protobuf_empty_proto = out.File
 	file_google_protobuf_empty_proto_rawDesc = nil
 	file_google_protobuf_empty_proto_goTypes = nil
 	file_google_protobuf_empty_proto_depIdxs = nil
diff --git a/types/known/fieldmaskpb/field_mask.pb.go b/types/known/fieldmaskpb/field_mask.pb.go
index d69e284..b131163 100644
--- a/types/known/fieldmaskpb/field_mask.pb.go
+++ b/types/known/fieldmaskpb/field_mask.pb.go
@@ -5,7 +5,6 @@
 
 import (
 	protoreflect "google.golang.org/protobuf/reflect/protoreflect"
-	protoregistry "google.golang.org/protobuf/reflect/protoregistry"
 	protoiface "google.golang.org/protobuf/runtime/protoiface"
 	protoimpl "google.golang.org/protobuf/runtime/protoimpl"
 	sync "sync"
@@ -291,21 +290,32 @@
 var file_google_protobuf_field_mask_proto_goTypes = []interface{}{
 	(*FieldMask)(nil), // 0: google.protobuf.FieldMask
 }
-var file_google_protobuf_field_mask_proto_depIdxs = []int32{}
+var file_google_protobuf_field_mask_proto_depIdxs = []int32{
+	0, // starting offset of method output_type sub-list
+	0, // starting offset of method input_type sub-list
+	0, // starting offset of extension type_name sub-list
+	0, // starting offset of extension extendee sub-list
+	0, // starting offset of field type_name sub-list
+}
 
 func init() { file_google_protobuf_field_mask_proto_init() }
 func file_google_protobuf_field_mask_proto_init() {
 	if File_google_protobuf_field_mask_proto != nil {
 		return
 	}
-	File_google_protobuf_field_mask_proto = protoimpl.FileBuilder{
-		RawDescriptor:      file_google_protobuf_field_mask_proto_rawDesc,
-		GoTypes:            file_google_protobuf_field_mask_proto_goTypes,
-		DependencyIndexes:  file_google_protobuf_field_mask_proto_depIdxs,
-		MessageOutputTypes: file_google_protobuf_field_mask_proto_msgTypes,
-		FilesRegistry:      protoregistry.GlobalFiles,
-		TypesRegistry:      protoregistry.GlobalTypes,
-	}.Init()
+	out := protoimpl.TypeBuilder{
+		File: protoimpl.DescBuilder{
+			RawDescriptor: file_google_protobuf_field_mask_proto_rawDesc,
+			NumEnums:      0,
+			NumMessages:   1,
+			NumExtensions: 0,
+			NumServices:   0,
+		},
+		GoTypes:           file_google_protobuf_field_mask_proto_goTypes,
+		DependencyIndexes: file_google_protobuf_field_mask_proto_depIdxs,
+		MessageInfos:      file_google_protobuf_field_mask_proto_msgTypes,
+	}.Build()
+	File_google_protobuf_field_mask_proto = out.File
 	file_google_protobuf_field_mask_proto_rawDesc = nil
 	file_google_protobuf_field_mask_proto_goTypes = nil
 	file_google_protobuf_field_mask_proto_depIdxs = nil
diff --git a/types/known/sourcecontextpb/source_context.pb.go b/types/known/sourcecontextpb/source_context.pb.go
index 3327aef..533b37c 100644
--- a/types/known/sourcecontextpb/source_context.pb.go
+++ b/types/known/sourcecontextpb/source_context.pb.go
@@ -5,7 +5,6 @@
 
 import (
 	protoreflect "google.golang.org/protobuf/reflect/protoreflect"
-	protoregistry "google.golang.org/protobuf/reflect/protoregistry"
 	protoiface "google.golang.org/protobuf/runtime/protoiface"
 	protoimpl "google.golang.org/protobuf/runtime/protoimpl"
 	sync "sync"
@@ -96,21 +95,32 @@
 var file_google_protobuf_source_context_proto_goTypes = []interface{}{
 	(*SourceContext)(nil), // 0: google.protobuf.SourceContext
 }
-var file_google_protobuf_source_context_proto_depIdxs = []int32{}
+var file_google_protobuf_source_context_proto_depIdxs = []int32{
+	0, // starting offset of method output_type sub-list
+	0, // starting offset of method input_type sub-list
+	0, // starting offset of extension type_name sub-list
+	0, // starting offset of extension extendee sub-list
+	0, // starting offset of field type_name sub-list
+}
 
 func init() { file_google_protobuf_source_context_proto_init() }
 func file_google_protobuf_source_context_proto_init() {
 	if File_google_protobuf_source_context_proto != nil {
 		return
 	}
-	File_google_protobuf_source_context_proto = protoimpl.FileBuilder{
-		RawDescriptor:      file_google_protobuf_source_context_proto_rawDesc,
-		GoTypes:            file_google_protobuf_source_context_proto_goTypes,
-		DependencyIndexes:  file_google_protobuf_source_context_proto_depIdxs,
-		MessageOutputTypes: file_google_protobuf_source_context_proto_msgTypes,
-		FilesRegistry:      protoregistry.GlobalFiles,
-		TypesRegistry:      protoregistry.GlobalTypes,
-	}.Init()
+	out := protoimpl.TypeBuilder{
+		File: protoimpl.DescBuilder{
+			RawDescriptor: file_google_protobuf_source_context_proto_rawDesc,
+			NumEnums:      0,
+			NumMessages:   1,
+			NumExtensions: 0,
+			NumServices:   0,
+		},
+		GoTypes:           file_google_protobuf_source_context_proto_goTypes,
+		DependencyIndexes: file_google_protobuf_source_context_proto_depIdxs,
+		MessageInfos:      file_google_protobuf_source_context_proto_msgTypes,
+	}.Build()
+	File_google_protobuf_source_context_proto = out.File
 	file_google_protobuf_source_context_proto_rawDesc = nil
 	file_google_protobuf_source_context_proto_goTypes = nil
 	file_google_protobuf_source_context_proto_depIdxs = nil
diff --git a/types/known/structpb/struct.pb.go b/types/known/structpb/struct.pb.go
index 47c693f..261a9f5 100644
--- a/types/known/structpb/struct.pb.go
+++ b/types/known/structpb/struct.pb.go
@@ -5,7 +5,7 @@
 
 import (
 	protoreflect "google.golang.org/protobuf/reflect/protoreflect"
-	protoregistry "google.golang.org/protobuf/reflect/protoregistry"
+	prototype "google.golang.org/protobuf/reflect/prototype"
 	protoiface "google.golang.org/protobuf/runtime/protoiface"
 	protoimpl "google.golang.org/protobuf/runtime/protoimpl"
 	sync "sync"
@@ -50,7 +50,7 @@
 }
 
 func (NullValue) Descriptor() protoreflect.EnumDescriptor {
-	return file_google_protobuf_struct_proto_enumTypes[0].Descriptor()
+	return file_google_protobuf_struct_proto_enumTypes[0].EnumDescriptor
 }
 
 func (x NullValue) Number() protoreflect.EnumNumber {
@@ -373,7 +373,7 @@
 	return file_google_protobuf_struct_proto_rawDescData
 }
 
-var file_google_protobuf_struct_proto_enumTypes = make([]protoreflect.EnumType, 1)
+var file_google_protobuf_struct_proto_enumTypes = make([]prototype.Enum, 1)
 var file_google_protobuf_struct_proto_msgTypes = make([]protoimpl.MessageInfo, 4)
 var file_google_protobuf_struct_proto_goTypes = []interface{}{
 	(NullValue)(0),    // 0: google.protobuf.NullValue
@@ -389,6 +389,11 @@
 	3, // google.protobuf.Value.list_value:type_name -> google.protobuf.ListValue
 	2, // google.protobuf.ListValue.values:type_name -> google.protobuf.Value
 	2, // google.protobuf.Struct.FieldsEntry.value:type_name -> google.protobuf.Value
+	6, // starting offset of method output_type sub-list
+	6, // starting offset of method input_type sub-list
+	6, // starting offset of extension type_name sub-list
+	6, // starting offset of extension extendee sub-list
+	0, // starting offset of field type_name sub-list
 }
 
 func init() { file_google_protobuf_struct_proto_init() }
@@ -396,15 +401,20 @@
 	if File_google_protobuf_struct_proto != nil {
 		return
 	}
-	File_google_protobuf_struct_proto = protoimpl.FileBuilder{
-		RawDescriptor:      file_google_protobuf_struct_proto_rawDesc,
-		GoTypes:            file_google_protobuf_struct_proto_goTypes,
-		DependencyIndexes:  file_google_protobuf_struct_proto_depIdxs,
-		EnumOutputTypes:    file_google_protobuf_struct_proto_enumTypes,
-		MessageOutputTypes: file_google_protobuf_struct_proto_msgTypes,
-		FilesRegistry:      protoregistry.GlobalFiles,
-		TypesRegistry:      protoregistry.GlobalTypes,
-	}.Init()
+	out := protoimpl.TypeBuilder{
+		File: protoimpl.DescBuilder{
+			RawDescriptor: file_google_protobuf_struct_proto_rawDesc,
+			NumEnums:      1,
+			NumMessages:   4,
+			NumExtensions: 0,
+			NumServices:   0,
+		},
+		GoTypes:           file_google_protobuf_struct_proto_goTypes,
+		DependencyIndexes: file_google_protobuf_struct_proto_depIdxs,
+		MessageInfos:      file_google_protobuf_struct_proto_msgTypes,
+	}.Build()
+	File_google_protobuf_struct_proto = out.File
+	file_google_protobuf_struct_proto_enumTypes = out.Enums
 	file_google_protobuf_struct_proto_rawDesc = nil
 	file_google_protobuf_struct_proto_goTypes = nil
 	file_google_protobuf_struct_proto_depIdxs = nil
diff --git a/types/known/timestamppb/timestamp.pb.go b/types/known/timestamppb/timestamp.pb.go
index d0fd90c..aee1cf1 100644
--- a/types/known/timestamppb/timestamp.pb.go
+++ b/types/known/timestamppb/timestamp.pb.go
@@ -5,7 +5,6 @@
 
 import (
 	protoreflect "google.golang.org/protobuf/reflect/protoreflect"
-	protoregistry "google.golang.org/protobuf/reflect/protoregistry"
 	protoiface "google.golang.org/protobuf/runtime/protoiface"
 	protoimpl "google.golang.org/protobuf/runtime/protoimpl"
 	sync "sync"
@@ -191,21 +190,32 @@
 var file_google_protobuf_timestamp_proto_goTypes = []interface{}{
 	(*Timestamp)(nil), // 0: google.protobuf.Timestamp
 }
-var file_google_protobuf_timestamp_proto_depIdxs = []int32{}
+var file_google_protobuf_timestamp_proto_depIdxs = []int32{
+	0, // starting offset of method output_type sub-list
+	0, // starting offset of method input_type sub-list
+	0, // starting offset of extension type_name sub-list
+	0, // starting offset of extension extendee sub-list
+	0, // starting offset of field type_name sub-list
+}
 
 func init() { file_google_protobuf_timestamp_proto_init() }
 func file_google_protobuf_timestamp_proto_init() {
 	if File_google_protobuf_timestamp_proto != nil {
 		return
 	}
-	File_google_protobuf_timestamp_proto = protoimpl.FileBuilder{
-		RawDescriptor:      file_google_protobuf_timestamp_proto_rawDesc,
-		GoTypes:            file_google_protobuf_timestamp_proto_goTypes,
-		DependencyIndexes:  file_google_protobuf_timestamp_proto_depIdxs,
-		MessageOutputTypes: file_google_protobuf_timestamp_proto_msgTypes,
-		FilesRegistry:      protoregistry.GlobalFiles,
-		TypesRegistry:      protoregistry.GlobalTypes,
-	}.Init()
+	out := protoimpl.TypeBuilder{
+		File: protoimpl.DescBuilder{
+			RawDescriptor: file_google_protobuf_timestamp_proto_rawDesc,
+			NumEnums:      0,
+			NumMessages:   1,
+			NumExtensions: 0,
+			NumServices:   0,
+		},
+		GoTypes:           file_google_protobuf_timestamp_proto_goTypes,
+		DependencyIndexes: file_google_protobuf_timestamp_proto_depIdxs,
+		MessageInfos:      file_google_protobuf_timestamp_proto_msgTypes,
+	}.Build()
+	File_google_protobuf_timestamp_proto = out.File
 	file_google_protobuf_timestamp_proto_rawDesc = nil
 	file_google_protobuf_timestamp_proto_goTypes = nil
 	file_google_protobuf_timestamp_proto_depIdxs = nil
diff --git a/types/known/typepb/type.pb.go b/types/known/typepb/type.pb.go
index aae8ab5..dc183e2 100644
--- a/types/known/typepb/type.pb.go
+++ b/types/known/typepb/type.pb.go
@@ -5,7 +5,7 @@
 
 import (
 	protoreflect "google.golang.org/protobuf/reflect/protoreflect"
-	protoregistry "google.golang.org/protobuf/reflect/protoregistry"
+	prototype "google.golang.org/protobuf/reflect/prototype"
 	protoiface "google.golang.org/protobuf/runtime/protoiface"
 	protoimpl "google.golang.org/protobuf/runtime/protoimpl"
 	anypb "google.golang.org/protobuf/types/known/anypb"
@@ -53,7 +53,7 @@
 }
 
 func (Syntax) Descriptor() protoreflect.EnumDescriptor {
-	return file_google_protobuf_type_proto_enumTypes[0].Descriptor()
+	return file_google_protobuf_type_proto_enumTypes[0].EnumDescriptor
 }
 
 func (x Syntax) Number() protoreflect.EnumNumber {
@@ -166,7 +166,7 @@
 }
 
 func (Field_Kind) Descriptor() protoreflect.EnumDescriptor {
-	return file_google_protobuf_type_proto_enumTypes[1].Descriptor()
+	return file_google_protobuf_type_proto_enumTypes[1].EnumDescriptor
 }
 
 func (x Field_Kind) Number() protoreflect.EnumNumber {
@@ -219,7 +219,7 @@
 }
 
 func (Field_Cardinality) Descriptor() protoreflect.EnumDescriptor {
-	return file_google_protobuf_type_proto_enumTypes[2].Descriptor()
+	return file_google_protobuf_type_proto_enumTypes[2].EnumDescriptor
 }
 
 func (x Field_Cardinality) Number() protoreflect.EnumNumber {
@@ -756,7 +756,7 @@
 	return file_google_protobuf_type_proto_rawDescData
 }
 
-var file_google_protobuf_type_proto_enumTypes = make([]protoreflect.EnumType, 3)
+var file_google_protobuf_type_proto_enumTypes = make([]prototype.Enum, 3)
 var file_google_protobuf_type_proto_msgTypes = make([]protoimpl.MessageInfo, 5)
 var file_google_protobuf_type_proto_goTypes = []interface{}{
 	(Syntax)(0),                           // 0: google.protobuf.Syntax
@@ -771,19 +771,24 @@
 	(*anypb.Any)(nil),                     // 9: google.protobuf.Any
 }
 var file_google_protobuf_type_proto_depIdxs = []int32{
-	4, // google.protobuf.Type.fields:type_name -> google.protobuf.Field
-	7, // google.protobuf.Type.options:type_name -> google.protobuf.Option
-	8, // google.protobuf.Type.source_context:type_name -> google.protobuf.SourceContext
-	0, // google.protobuf.Type.syntax:type_name -> google.protobuf.Syntax
-	1, // google.protobuf.Field.kind:type_name -> google.protobuf.Field.Kind
-	2, // google.protobuf.Field.cardinality:type_name -> google.protobuf.Field.Cardinality
-	7, // google.protobuf.Field.options:type_name -> google.protobuf.Option
-	6, // google.protobuf.Enum.enumvalue:type_name -> google.protobuf.EnumValue
-	7, // google.protobuf.Enum.options:type_name -> google.protobuf.Option
-	8, // google.protobuf.Enum.source_context:type_name -> google.protobuf.SourceContext
-	0, // google.protobuf.Enum.syntax:type_name -> google.protobuf.Syntax
-	7, // google.protobuf.EnumValue.options:type_name -> google.protobuf.Option
-	9, // google.protobuf.Option.value:type_name -> google.protobuf.Any
+	4,  // google.protobuf.Type.fields:type_name -> google.protobuf.Field
+	7,  // google.protobuf.Type.options:type_name -> google.protobuf.Option
+	8,  // google.protobuf.Type.source_context:type_name -> google.protobuf.SourceContext
+	0,  // google.protobuf.Type.syntax:type_name -> google.protobuf.Syntax
+	1,  // google.protobuf.Field.kind:type_name -> google.protobuf.Field.Kind
+	2,  // google.protobuf.Field.cardinality:type_name -> google.protobuf.Field.Cardinality
+	7,  // google.protobuf.Field.options:type_name -> google.protobuf.Option
+	6,  // google.protobuf.Enum.enumvalue:type_name -> google.protobuf.EnumValue
+	7,  // google.protobuf.Enum.options:type_name -> google.protobuf.Option
+	8,  // google.protobuf.Enum.source_context:type_name -> google.protobuf.SourceContext
+	0,  // google.protobuf.Enum.syntax:type_name -> google.protobuf.Syntax
+	7,  // google.protobuf.EnumValue.options:type_name -> google.protobuf.Option
+	9,  // google.protobuf.Option.value:type_name -> google.protobuf.Any
+	13, // starting offset of method output_type sub-list
+	13, // starting offset of method input_type sub-list
+	13, // starting offset of extension type_name sub-list
+	13, // starting offset of extension extendee sub-list
+	0,  // starting offset of field type_name sub-list
 }
 
 func init() { file_google_protobuf_type_proto_init() }
@@ -791,15 +796,20 @@
 	if File_google_protobuf_type_proto != nil {
 		return
 	}
-	File_google_protobuf_type_proto = protoimpl.FileBuilder{
-		RawDescriptor:      file_google_protobuf_type_proto_rawDesc,
-		GoTypes:            file_google_protobuf_type_proto_goTypes,
-		DependencyIndexes:  file_google_protobuf_type_proto_depIdxs,
-		EnumOutputTypes:    file_google_protobuf_type_proto_enumTypes,
-		MessageOutputTypes: file_google_protobuf_type_proto_msgTypes,
-		FilesRegistry:      protoregistry.GlobalFiles,
-		TypesRegistry:      protoregistry.GlobalTypes,
-	}.Init()
+	out := protoimpl.TypeBuilder{
+		File: protoimpl.DescBuilder{
+			RawDescriptor: file_google_protobuf_type_proto_rawDesc,
+			NumEnums:      3,
+			NumMessages:   5,
+			NumExtensions: 0,
+			NumServices:   0,
+		},
+		GoTypes:           file_google_protobuf_type_proto_goTypes,
+		DependencyIndexes: file_google_protobuf_type_proto_depIdxs,
+		MessageInfos:      file_google_protobuf_type_proto_msgTypes,
+	}.Build()
+	File_google_protobuf_type_proto = out.File
+	file_google_protobuf_type_proto_enumTypes = out.Enums
 	file_google_protobuf_type_proto_rawDesc = nil
 	file_google_protobuf_type_proto_goTypes = nil
 	file_google_protobuf_type_proto_depIdxs = nil
diff --git a/types/known/wrapperspb/wrappers.pb.go b/types/known/wrapperspb/wrappers.pb.go
index 9558926..a12b986 100644
--- a/types/known/wrapperspb/wrappers.pb.go
+++ b/types/known/wrapperspb/wrappers.pb.go
@@ -5,7 +5,6 @@
 
 import (
 	protoreflect "google.golang.org/protobuf/reflect/protoreflect"
-	protoregistry "google.golang.org/protobuf/reflect/protoregistry"
 	protoiface "google.golang.org/protobuf/runtime/protoiface"
 	protoimpl "google.golang.org/protobuf/runtime/protoimpl"
 	sync "sync"
@@ -467,21 +466,32 @@
 	(*StringValue)(nil), // 7: google.protobuf.StringValue
 	(*BytesValue)(nil),  // 8: google.protobuf.BytesValue
 }
-var file_google_protobuf_wrappers_proto_depIdxs = []int32{}
+var file_google_protobuf_wrappers_proto_depIdxs = []int32{
+	0, // starting offset of method output_type sub-list
+	0, // starting offset of method input_type sub-list
+	0, // starting offset of extension type_name sub-list
+	0, // starting offset of extension extendee sub-list
+	0, // starting offset of field type_name sub-list
+}
 
 func init() { file_google_protobuf_wrappers_proto_init() }
 func file_google_protobuf_wrappers_proto_init() {
 	if File_google_protobuf_wrappers_proto != nil {
 		return
 	}
-	File_google_protobuf_wrappers_proto = protoimpl.FileBuilder{
-		RawDescriptor:      file_google_protobuf_wrappers_proto_rawDesc,
-		GoTypes:            file_google_protobuf_wrappers_proto_goTypes,
-		DependencyIndexes:  file_google_protobuf_wrappers_proto_depIdxs,
-		MessageOutputTypes: file_google_protobuf_wrappers_proto_msgTypes,
-		FilesRegistry:      protoregistry.GlobalFiles,
-		TypesRegistry:      protoregistry.GlobalTypes,
-	}.Init()
+	out := protoimpl.TypeBuilder{
+		File: protoimpl.DescBuilder{
+			RawDescriptor: file_google_protobuf_wrappers_proto_rawDesc,
+			NumEnums:      0,
+			NumMessages:   9,
+			NumExtensions: 0,
+			NumServices:   0,
+		},
+		GoTypes:           file_google_protobuf_wrappers_proto_goTypes,
+		DependencyIndexes: file_google_protobuf_wrappers_proto_depIdxs,
+		MessageInfos:      file_google_protobuf_wrappers_proto_msgTypes,
+	}.Build()
+	File_google_protobuf_wrappers_proto = out.File
 	file_google_protobuf_wrappers_proto_rawDesc = nil
 	file_google_protobuf_wrappers_proto_goTypes = nil
 	file_google_protobuf_wrappers_proto_depIdxs = nil
diff --git a/types/pluginpb/plugin.pb.go b/types/pluginpb/plugin.pb.go
index 1126c26..2f994f6 100644
--- a/types/pluginpb/plugin.pb.go
+++ b/types/pluginpb/plugin.pb.go
@@ -5,7 +5,6 @@
 
 import (
 	protoreflect "google.golang.org/protobuf/reflect/protoreflect"
-	protoregistry "google.golang.org/protobuf/reflect/protoregistry"
 	protoiface "google.golang.org/protobuf/runtime/protoiface"
 	protoimpl "google.golang.org/protobuf/runtime/protoimpl"
 	descriptorpb "google.golang.org/protobuf/types/descriptorpb"
@@ -397,6 +396,11 @@
 	4, // google.protobuf.compiler.CodeGeneratorRequest.proto_file:type_name -> google.protobuf.FileDescriptorProto
 	0, // google.protobuf.compiler.CodeGeneratorRequest.compiler_version:type_name -> google.protobuf.compiler.Version
 	3, // google.protobuf.compiler.CodeGeneratorResponse.file:type_name -> google.protobuf.compiler.CodeGeneratorResponse.File
+	3, // starting offset of method output_type sub-list
+	3, // starting offset of method input_type sub-list
+	3, // starting offset of extension type_name sub-list
+	3, // starting offset of extension extendee sub-list
+	0, // starting offset of field type_name sub-list
 }
 
 func init() { file_google_protobuf_compiler_plugin_proto_init() }
@@ -404,14 +408,19 @@
 	if File_google_protobuf_compiler_plugin_proto != nil {
 		return
 	}
-	File_google_protobuf_compiler_plugin_proto = protoimpl.FileBuilder{
-		RawDescriptor:      file_google_protobuf_compiler_plugin_proto_rawDesc,
-		GoTypes:            file_google_protobuf_compiler_plugin_proto_goTypes,
-		DependencyIndexes:  file_google_protobuf_compiler_plugin_proto_depIdxs,
-		MessageOutputTypes: file_google_protobuf_compiler_plugin_proto_msgTypes,
-		FilesRegistry:      protoregistry.GlobalFiles,
-		TypesRegistry:      protoregistry.GlobalTypes,
-	}.Init()
+	out := protoimpl.TypeBuilder{
+		File: protoimpl.DescBuilder{
+			RawDescriptor: file_google_protobuf_compiler_plugin_proto_rawDesc,
+			NumEnums:      0,
+			NumMessages:   4,
+			NumExtensions: 0,
+			NumServices:   0,
+		},
+		GoTypes:           file_google_protobuf_compiler_plugin_proto_goTypes,
+		DependencyIndexes: file_google_protobuf_compiler_plugin_proto_depIdxs,
+		MessageInfos:      file_google_protobuf_compiler_plugin_proto_msgTypes,
+	}.Build()
+	File_google_protobuf_compiler_plugin_proto = out.File
 	file_google_protobuf_compiler_plugin_proto_rawDesc = nil
 	file_google_protobuf_compiler_plugin_proto_goTypes = nil
 	file_google_protobuf_compiler_plugin_proto_depIdxs = nil