protobuf: fix required/group bug in descriptor proto output of editions files

These need to be converted back to the appropriate label/type enums to produce valid descriptor protos under editions.

Change-Id: Ife04c4c556ffb06d1bc477725ff49058928a75ca
Reviewed-on: https://go-review.googlesource.com/c/protobuf/+/575916
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Auto-Submit: Michael Stapelberg <stapelberg@google.com>
Reviewed-by: Michael Stapelberg <stapelberg@google.com>
diff --git a/internal/filedesc/desc.go b/internal/filedesc/desc.go
index f09f734..55b5de1 100644
--- a/internal/filedesc/desc.go
+++ b/internal/filedesc/desc.go
@@ -538,8 +538,9 @@
 // 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: protoreflect.Proto2}, L2: &FileL2{}}
-	SurrogateProto3 = &File{L1: FileL1{Syntax: protoreflect.Proto3}, L2: &FileL2{}}
+	SurrogateProto2      = &File{L1: FileL1{Syntax: protoreflect.Proto2}, L2: &FileL2{}}
+	SurrogateProto3      = &File{L1: FileL1{Syntax: protoreflect.Proto3}, L2: &FileL2{}}
+	SurrogateEdition2023 = &File{L1: FileL1{Syntax: protoreflect.Editions, Edition: Edition2023}, L2: &FileL2{}}
 )
 
 type (
diff --git a/internal/filedesc/editions.go b/internal/filedesc/editions.go
index 5f01803..d1e16a2 100644
--- a/internal/filedesc/editions.go
+++ b/internal/filedesc/editions.go
@@ -20,6 +20,7 @@
 	unmarshalEditionDefaults(editiondefaults.Defaults)
 	SurrogateProto2.L1.EditionFeatures = getFeaturesFor(EditionProto2)
 	SurrogateProto3.L1.EditionFeatures = getFeaturesFor(EditionProto3)
+	SurrogateEdition2023.L1.EditionFeatures = getFeaturesFor(Edition2023)
 }
 
 func unmarshalGoFeature(b []byte, parent EditionFeatures) EditionFeatures {
diff --git a/reflect/protodesc/proto.go b/reflect/protodesc/proto.go
index 7aa21be..a5de8d4 100644
--- a/reflect/protodesc/proto.go
+++ b/reflect/protodesc/proto.go
@@ -163,6 +163,18 @@
 	if field.Syntax() == protoreflect.Proto3 && field.HasOptionalKeyword() {
 		p.Proto3Optional = proto.Bool(true)
 	}
+	if field.Syntax() == protoreflect.Editions {
+		// Editions have no group keyword, this type is only set so that downstream users continue
+		// treating this as delimited encoding.
+		if p.GetType() == descriptorpb.FieldDescriptorProto_TYPE_GROUP {
+			p.Type = descriptorpb.FieldDescriptorProto_TYPE_MESSAGE.Enum()
+		}
+		// Editions have no required keyword, this label is only set so that downstream users continue
+		// treating it as required.
+		if p.GetLabel() == descriptorpb.FieldDescriptorProto_LABEL_REQUIRED {
+			p.Label = descriptorpb.FieldDescriptorProto_LABEL_OPTIONAL.Enum()
+		}
+	}
 	if field.HasDefault() {
 		def, err := defval.Marshal(field.Default(), field.DefaultEnumValue(), field.Kind(), defval.Descriptor)
 		if err != nil && field.DefaultEnumValue() != nil {
diff --git a/reflect/protodesc/proto_test.go b/reflect/protodesc/proto_test.go
new file mode 100644
index 0000000..ec09123
--- /dev/null
+++ b/reflect/protodesc/proto_test.go
@@ -0,0 +1,110 @@
+// 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 protodesc
+
+import (
+	"testing"
+
+	"github.com/google/go-cmp/cmp"
+	"google.golang.org/protobuf/internal/filedesc"
+	"google.golang.org/protobuf/proto"
+	"google.golang.org/protobuf/reflect/protoreflect"
+	"google.golang.org/protobuf/testing/protocmp"
+	"google.golang.org/protobuf/types/descriptorpb"
+)
+
+func TestEditionsRequired(t *testing.T) {
+	fd := new(filedesc.Field)
+	fd.L0.ParentFile = filedesc.SurrogateEdition2023
+	fd.L0.FullName = "foo_field"
+	fd.L1.Number = 1337
+	fd.L1.Cardinality = protoreflect.Required
+	fd.L1.Kind = protoreflect.BytesKind
+
+	want := &descriptorpb.FieldDescriptorProto{
+		Name:   proto.String("foo_field"),
+		Number: proto.Int32(1337),
+		Label:  descriptorpb.FieldDescriptorProto_LABEL_OPTIONAL.Enum(),
+		Type:   descriptorpb.FieldDescriptorProto_TYPE_BYTES.Enum(),
+	}
+
+	got := ToFieldDescriptorProto(fd)
+	if diff := cmp.Diff(want, got, protocmp.Transform()); diff != "" {
+		t.Errorf("ToFieldDescriptor: unexpected diff (-want +got):\n%s", diff)
+	}
+}
+
+func TestProto2Required(t *testing.T) {
+	fd := new(filedesc.Field)
+	fd.L0.ParentFile = filedesc.SurrogateProto2
+	fd.L0.FullName = "foo_field"
+	fd.L1.Number = 1337
+	fd.L1.Cardinality = protoreflect.Required
+	fd.L1.Kind = protoreflect.BytesKind
+
+	want := &descriptorpb.FieldDescriptorProto{
+		Name:   proto.String("foo_field"),
+		Number: proto.Int32(1337),
+		Label:  descriptorpb.FieldDescriptorProto_LABEL_REQUIRED.Enum(),
+		Type:   descriptorpb.FieldDescriptorProto_TYPE_BYTES.Enum(),
+	}
+
+	got := ToFieldDescriptorProto(fd)
+	if diff := cmp.Diff(want, got, protocmp.Transform()); diff != "" {
+		t.Errorf("ToFieldDescriptor: unexpected diff (-want +got):\n%s", diff)
+	}
+}
+
+func TestEditionsDelimited(t *testing.T) {
+	md := new(filedesc.Message)
+	md.L0.ParentFile = filedesc.SurrogateEdition2023
+	md.L0.FullName = "foo_message"
+	fd := new(filedesc.Field)
+	fd.L0.ParentFile = filedesc.SurrogateEdition2023
+	fd.L0.FullName = "foo_field"
+	fd.L1.Number = 1337
+	fd.L1.Cardinality = protoreflect.Optional
+	fd.L1.Kind = protoreflect.GroupKind
+	fd.L1.Message = md
+
+	want := &descriptorpb.FieldDescriptorProto{
+		Name:     proto.String("foo_field"),
+		Number:   proto.Int32(1337),
+		Label:    descriptorpb.FieldDescriptorProto_LABEL_OPTIONAL.Enum(),
+		Type:     descriptorpb.FieldDescriptorProto_TYPE_MESSAGE.Enum(),
+		TypeName: proto.String(".foo_message"),
+	}
+
+	got := ToFieldDescriptorProto(fd)
+	if diff := cmp.Diff(want, got, protocmp.Transform()); diff != "" {
+		t.Errorf("ToFieldDescriptor: unexpected diff (-want +got):\n%s", diff)
+	}
+}
+
+func TestProto2Group(t *testing.T) {
+	md := new(filedesc.Message)
+	md.L0.ParentFile = filedesc.SurrogateProto2
+	md.L0.FullName = "foo_message"
+	fd := new(filedesc.Field)
+	fd.L0.ParentFile = filedesc.SurrogateProto2
+	fd.L0.FullName = "foo_field"
+	fd.L1.Number = 1337
+	fd.L1.Cardinality = protoreflect.Optional
+	fd.L1.Kind = protoreflect.GroupKind
+	fd.L1.Message = md
+
+	want := &descriptorpb.FieldDescriptorProto{
+		Name:     proto.String("foo_field"),
+		Number:   proto.Int32(1337),
+		Label:    descriptorpb.FieldDescriptorProto_LABEL_OPTIONAL.Enum(),
+		Type:     descriptorpb.FieldDescriptorProto_TYPE_GROUP.Enum(),
+		TypeName: proto.String(".foo_message"),
+	}
+
+	got := ToFieldDescriptorProto(fd)
+	if diff := cmp.Diff(want, got, protocmp.Transform()); diff != "" {
+		t.Errorf("ToFieldDescriptor: unexpected diff (-want +got):\n%s", diff)
+	}
+}