reflect/protoreflect: FieldDescriptor.Kind should never be GroupKind for maps or fields of map entry

Resolves golang/protobuf#1615

The protoc compiler disallows setting the message encoding feature of
map fields to delimited since maps, at least for now (as of edition
2023) should always use normal length-prefixed encoding.

But the field (and a message value field inside the map entry) could
inherit such a feature value if it were set as a file-wide default. At
the point where the code changes the kind from message to group, based
on the field's resolved features, the message type hasn't yet been
resolved.  So this change adds a check after the FieldDescriptor's
message type is resolved, to change the kind back from group to
message if the field is a map field or a field in a map entry message.

Change-Id: I785269a4ecd80d1a17866c08b2afc0b01440e0e3
Reviewed-on: https://go-review.googlesource.com/c/protobuf/+/588976
Reviewed-by: Michael Knyszek <mknyszek@google.com>
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Reviewed-by: Cassondra Foesch <cfoesch@gmail.com>
Reviewed-by: Mike Kruskal <mkruskal@google.com>
Reviewed-by: Michael Stapelberg <stapelberg@google.com>
diff --git a/cmd/protoc-gen-go/testdata/protoeditions/maps_and_delimited.pb.go b/cmd/protoc-gen-go/testdata/protoeditions/maps_and_delimited.pb.go
new file mode 100644
index 0000000..19956bb
--- /dev/null
+++ b/cmd/protoc-gen-go/testdata/protoeditions/maps_and_delimited.pb.go
@@ -0,0 +1,307 @@
+// Copyright 2024 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 protoc-gen-go. DO NOT EDIT.
+// source: cmd/protoc-gen-go/testdata/protoeditions/maps_and_delimited.proto
+
+package protoeditions
+
+import (
+	protoreflect "google.golang.org/protobuf/reflect/protoreflect"
+	protoimpl "google.golang.org/protobuf/runtime/protoimpl"
+	reflect "reflect"
+	sync "sync"
+)
+
+type MessageWithMaps struct {
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
+
+	MapWithoutMessage  map[string]string                        `protobuf:"bytes,1,rep,name=map_without_message,json=mapWithoutMessage" json:"map_without_message,omitempty" protobuf_key:"bytes,1,opt,name=key" protobuf_val:"bytes,2,opt,name=value"`
+	MapWithoutMessageB map[uint32][]byte                        `protobuf:"bytes,2,rep,name=map_without_message_b,json=mapWithoutMessageB" json:"map_without_message_b,omitempty" protobuf_key:"varint,1,opt,name=key" protobuf_val:"bytes,2,opt,name=value"`
+	MapWithMessage     map[int64]*MessageWithMaps_NestedMessage `protobuf:"bytes,3,rep,name=map_with_message,json=mapWithMessage" json:"map_with_message,omitempty" protobuf_key:"varint,1,opt,name=key" protobuf_val:"bytes,2,opt,name=value"`
+	NestedMessage      *MessageWithMaps_NestedMessage           `protobuf:"group,4,opt,name=NestedMessage,json=nestedMessage" json:"nested_message,omitempty"`
+	RepeatedMessage    []*MessageWithMaps_NestedMessage         `protobuf:"group,5,rep,name=NestedMessage,json=repeatedMessage" json:"repeated_message,omitempty"`
+}
+
+func (x *MessageWithMaps) Reset() {
+	*x = MessageWithMaps{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_cmd_protoc_gen_go_testdata_protoeditions_maps_and_delimited_proto_msgTypes[0]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
+}
+
+func (x *MessageWithMaps) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*MessageWithMaps) ProtoMessage() {}
+
+func (x *MessageWithMaps) ProtoReflect() protoreflect.Message {
+	mi := &file_cmd_protoc_gen_go_testdata_protoeditions_maps_and_delimited_proto_msgTypes[0]
+	if protoimpl.UnsafeEnabled && x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use MessageWithMaps.ProtoReflect.Descriptor instead.
+func (*MessageWithMaps) Descriptor() ([]byte, []int) {
+	return file_cmd_protoc_gen_go_testdata_protoeditions_maps_and_delimited_proto_rawDescGZIP(), []int{0}
+}
+
+func (x *MessageWithMaps) GetMapWithoutMessage() map[string]string {
+	if x != nil {
+		return x.MapWithoutMessage
+	}
+	return nil
+}
+
+func (x *MessageWithMaps) GetMapWithoutMessageB() map[uint32][]byte {
+	if x != nil {
+		return x.MapWithoutMessageB
+	}
+	return nil
+}
+
+func (x *MessageWithMaps) GetMapWithMessage() map[int64]*MessageWithMaps_NestedMessage {
+	if x != nil {
+		return x.MapWithMessage
+	}
+	return nil
+}
+
+func (x *MessageWithMaps) GetNestedMessage() *MessageWithMaps_NestedMessage {
+	if x != nil {
+		return x.NestedMessage
+	}
+	return nil
+}
+
+func (x *MessageWithMaps) GetRepeatedMessage() []*MessageWithMaps_NestedMessage {
+	if x != nil {
+		return x.RepeatedMessage
+	}
+	return nil
+}
+
+type MessageWithMaps_NestedMessage struct {
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
+
+	Id   *uint64 `protobuf:"varint,1,opt,name=id" json:"id,omitempty"`
+	Name *string `protobuf:"bytes,2,opt,name=name" json:"name,omitempty"`
+}
+
+func (x *MessageWithMaps_NestedMessage) Reset() {
+	*x = MessageWithMaps_NestedMessage{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_cmd_protoc_gen_go_testdata_protoeditions_maps_and_delimited_proto_msgTypes[4]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
+}
+
+func (x *MessageWithMaps_NestedMessage) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*MessageWithMaps_NestedMessage) ProtoMessage() {}
+
+func (x *MessageWithMaps_NestedMessage) ProtoReflect() protoreflect.Message {
+	mi := &file_cmd_protoc_gen_go_testdata_protoeditions_maps_and_delimited_proto_msgTypes[4]
+	if protoimpl.UnsafeEnabled && x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use MessageWithMaps_NestedMessage.ProtoReflect.Descriptor instead.
+func (*MessageWithMaps_NestedMessage) Descriptor() ([]byte, []int) {
+	return file_cmd_protoc_gen_go_testdata_protoeditions_maps_and_delimited_proto_rawDescGZIP(), []int{0, 3}
+}
+
+func (x *MessageWithMaps_NestedMessage) GetId() uint64 {
+	if x != nil && x.Id != nil {
+		return *x.Id
+	}
+	return 0
+}
+
+func (x *MessageWithMaps_NestedMessage) GetName() string {
+	if x != nil && x.Name != nil {
+		return *x.Name
+	}
+	return ""
+}
+
+var File_cmd_protoc_gen_go_testdata_protoeditions_maps_and_delimited_proto protoreflect.FileDescriptor
+
+var file_cmd_protoc_gen_go_testdata_protoeditions_maps_and_delimited_proto_rawDesc = []byte{
+	0x0a, 0x41, 0x63, 0x6d, 0x64, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x2d, 0x67, 0x65, 0x6e,
+	0x2d, 0x67, 0x6f, 0x2f, 0x74, 0x65, 0x73, 0x74, 0x64, 0x61, 0x74, 0x61, 0x2f, 0x70, 0x72, 0x6f,
+	0x74, 0x6f, 0x65, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2f, 0x6d, 0x61, 0x70, 0x73, 0x5f,
+	0x61, 0x6e, 0x64, 0x5f, 0x64, 0x65, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x65, 0x64, 0x2e, 0x70, 0x72,
+	0x6f, 0x74, 0x6f, 0x12, 0x1c, 0x67, 0x6f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x70, 0x72, 0x6f,
+	0x74, 0x6f, 0x63, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x65, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e,
+	0x73, 0x22, 0xfc, 0x06, 0x0a, 0x0f, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x57, 0x69, 0x74,
+	0x68, 0x4d, 0x61, 0x70, 0x73, 0x12, 0x74, 0x0a, 0x13, 0x6d, 0x61, 0x70, 0x5f, 0x77, 0x69, 0x74,
+	0x68, 0x6f, 0x75, 0x74, 0x5f, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x18, 0x01, 0x20, 0x03,
+	0x28, 0x0b, 0x32, 0x44, 0x2e, 0x67, 0x6f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x70, 0x72, 0x6f,
+	0x74, 0x6f, 0x63, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x65, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e,
+	0x73, 0x2e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x57, 0x69, 0x74, 0x68, 0x4d, 0x61, 0x70,
+	0x73, 0x2e, 0x4d, 0x61, 0x70, 0x57, 0x69, 0x74, 0x68, 0x6f, 0x75, 0x74, 0x4d, 0x65, 0x73, 0x73,
+	0x61, 0x67, 0x65, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x11, 0x6d, 0x61, 0x70, 0x57, 0x69, 0x74,
+	0x68, 0x6f, 0x75, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x78, 0x0a, 0x15, 0x6d,
+	0x61, 0x70, 0x5f, 0x77, 0x69, 0x74, 0x68, 0x6f, 0x75, 0x74, 0x5f, 0x6d, 0x65, 0x73, 0x73, 0x61,
+	0x67, 0x65, 0x5f, 0x62, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x45, 0x2e, 0x67, 0x6f, 0x70,
+	0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x2e, 0x70, 0x72, 0x6f, 0x74,
+	0x6f, 0x65, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67,
+	0x65, 0x57, 0x69, 0x74, 0x68, 0x4d, 0x61, 0x70, 0x73, 0x2e, 0x4d, 0x61, 0x70, 0x57, 0x69, 0x74,
+	0x68, 0x6f, 0x75, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x42, 0x45, 0x6e, 0x74, 0x72,
+	0x79, 0x52, 0x12, 0x6d, 0x61, 0x70, 0x57, 0x69, 0x74, 0x68, 0x6f, 0x75, 0x74, 0x4d, 0x65, 0x73,
+	0x73, 0x61, 0x67, 0x65, 0x42, 0x12, 0x6b, 0x0a, 0x10, 0x6d, 0x61, 0x70, 0x5f, 0x77, 0x69, 0x74,
+	0x68, 0x5f, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32,
+	0x41, 0x2e, 0x67, 0x6f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63,
+	0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x65, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x4d,
+	0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x57, 0x69, 0x74, 0x68, 0x4d, 0x61, 0x70, 0x73, 0x2e, 0x4d,
+	0x61, 0x70, 0x57, 0x69, 0x74, 0x68, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x45, 0x6e, 0x74,
+	0x72, 0x79, 0x52, 0x0e, 0x6d, 0x61, 0x70, 0x57, 0x69, 0x74, 0x68, 0x4d, 0x65, 0x73, 0x73, 0x61,
+	0x67, 0x65, 0x12, 0x62, 0x0a, 0x0e, 0x6e, 0x65, 0x73, 0x74, 0x65, 0x64, 0x5f, 0x6d, 0x65, 0x73,
+	0x73, 0x61, 0x67, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x3b, 0x2e, 0x67, 0x6f, 0x70,
+	0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x2e, 0x70, 0x72, 0x6f, 0x74,
+	0x6f, 0x65, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67,
+	0x65, 0x57, 0x69, 0x74, 0x68, 0x4d, 0x61, 0x70, 0x73, 0x2e, 0x4e, 0x65, 0x73, 0x74, 0x65, 0x64,
+	0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x52, 0x0d, 0x6e, 0x65, 0x73, 0x74, 0x65, 0x64, 0x4d,
+	0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x66, 0x0a, 0x10, 0x72, 0x65, 0x70, 0x65, 0x61, 0x74,
+	0x65, 0x64, 0x5f, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x18, 0x05, 0x20, 0x03, 0x28, 0x0b,
+	0x32, 0x3b, 0x2e, 0x67, 0x6f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f,
+	0x63, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x65, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e,
+	0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x57, 0x69, 0x74, 0x68, 0x4d, 0x61, 0x70, 0x73, 0x2e,
+	0x4e, 0x65, 0x73, 0x74, 0x65, 0x64, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x52, 0x0f, 0x72,
+	0x65, 0x70, 0x65, 0x61, 0x74, 0x65, 0x64, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x1a, 0x44,
+	0x0a, 0x16, 0x4d, 0x61, 0x70, 0x57, 0x69, 0x74, 0x68, 0x6f, 0x75, 0x74, 0x4d, 0x65, 0x73, 0x73,
+	0x61, 0x67, 0x65, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18,
+	0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61,
+	0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65,
+	0x3a, 0x02, 0x38, 0x01, 0x1a, 0x45, 0x0a, 0x17, 0x4d, 0x61, 0x70, 0x57, 0x69, 0x74, 0x68, 0x6f,
+	0x75, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x42, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12,
+	0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x03, 0x6b, 0x65,
+	0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c,
+	0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x1a, 0x7e, 0x0a, 0x13, 0x4d,
+	0x61, 0x70, 0x57, 0x69, 0x74, 0x68, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x45, 0x6e, 0x74,
+	0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52,
+	0x03, 0x6b, 0x65, 0x79, 0x12, 0x51, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20,
+	0x01, 0x28, 0x0b, 0x32, 0x3b, 0x2e, 0x67, 0x6f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x70, 0x72,
+	0x6f, 0x74, 0x6f, 0x63, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x65, 0x64, 0x69, 0x74, 0x69, 0x6f,
+	0x6e, 0x73, 0x2e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x57, 0x69, 0x74, 0x68, 0x4d, 0x61,
+	0x70, 0x73, 0x2e, 0x4e, 0x65, 0x73, 0x74, 0x65, 0x64, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65,
+	0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x1a, 0x33, 0x0a, 0x0d, 0x4e,
+	0x65, 0x73, 0x74, 0x65, 0x64, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x0e, 0x0a, 0x02,
+	0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x02, 0x69, 0x64, 0x12, 0x12, 0x0a, 0x04,
+	0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65,
+	0x42, 0x4a, 0x5a, 0x43, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x67, 0x6f, 0x6c, 0x61, 0x6e,
+	0x67, 0x2e, 0x6f, 0x72, 0x67, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x63,
+	0x6d, 0x64, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x2d, 0x67, 0x65, 0x6e, 0x2d, 0x67, 0x6f,
+	0x2f, 0x74, 0x65, 0x73, 0x74, 0x64, 0x61, 0x74, 0x61, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x65,
+	0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x92, 0x03, 0x02, 0x28, 0x02, 0x62, 0x08, 0x65, 0x64,
+	0x69, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x70, 0xe8, 0x07,
+}
+
+var (
+	file_cmd_protoc_gen_go_testdata_protoeditions_maps_and_delimited_proto_rawDescOnce sync.Once
+	file_cmd_protoc_gen_go_testdata_protoeditions_maps_and_delimited_proto_rawDescData = file_cmd_protoc_gen_go_testdata_protoeditions_maps_and_delimited_proto_rawDesc
+)
+
+func file_cmd_protoc_gen_go_testdata_protoeditions_maps_and_delimited_proto_rawDescGZIP() []byte {
+	file_cmd_protoc_gen_go_testdata_protoeditions_maps_and_delimited_proto_rawDescOnce.Do(func() {
+		file_cmd_protoc_gen_go_testdata_protoeditions_maps_and_delimited_proto_rawDescData = protoimpl.X.CompressGZIP(file_cmd_protoc_gen_go_testdata_protoeditions_maps_and_delimited_proto_rawDescData)
+	})
+	return file_cmd_protoc_gen_go_testdata_protoeditions_maps_and_delimited_proto_rawDescData
+}
+
+var file_cmd_protoc_gen_go_testdata_protoeditions_maps_and_delimited_proto_msgTypes = make([]protoimpl.MessageInfo, 5)
+var file_cmd_protoc_gen_go_testdata_protoeditions_maps_and_delimited_proto_goTypes = []any{
+	(*MessageWithMaps)(nil),               // 0: goproto.protoc.protoeditions.MessageWithMaps
+	nil,                                   // 1: goproto.protoc.protoeditions.MessageWithMaps.MapWithoutMessageEntry
+	nil,                                   // 2: goproto.protoc.protoeditions.MessageWithMaps.MapWithoutMessageBEntry
+	nil,                                   // 3: goproto.protoc.protoeditions.MessageWithMaps.MapWithMessageEntry
+	(*MessageWithMaps_NestedMessage)(nil), // 4: goproto.protoc.protoeditions.MessageWithMaps.NestedMessage
+}
+var file_cmd_protoc_gen_go_testdata_protoeditions_maps_and_delimited_proto_depIdxs = []int32{
+	1, // 0: goproto.protoc.protoeditions.MessageWithMaps.map_without_message:type_name -> goproto.protoc.protoeditions.MessageWithMaps.MapWithoutMessageEntry
+	2, // 1: goproto.protoc.protoeditions.MessageWithMaps.map_without_message_b:type_name -> goproto.protoc.protoeditions.MessageWithMaps.MapWithoutMessageBEntry
+	3, // 2: goproto.protoc.protoeditions.MessageWithMaps.map_with_message:type_name -> goproto.protoc.protoeditions.MessageWithMaps.MapWithMessageEntry
+	4, // 3: goproto.protoc.protoeditions.MessageWithMaps.nested_message:type_name -> goproto.protoc.protoeditions.MessageWithMaps.NestedMessage
+	4, // 4: goproto.protoc.protoeditions.MessageWithMaps.repeated_message:type_name -> goproto.protoc.protoeditions.MessageWithMaps.NestedMessage
+	4, // 5: goproto.protoc.protoeditions.MessageWithMaps.MapWithMessageEntry.value:type_name -> goproto.protoc.protoeditions.MessageWithMaps.NestedMessage
+	6, // [6:6] is the sub-list for method output_type
+	6, // [6:6] is the sub-list for method input_type
+	6, // [6:6] is the sub-list for extension type_name
+	6, // [6:6] is the sub-list for extension extendee
+	0, // [0:6] is the sub-list for field type_name
+}
+
+func init() { file_cmd_protoc_gen_go_testdata_protoeditions_maps_and_delimited_proto_init() }
+func file_cmd_protoc_gen_go_testdata_protoeditions_maps_and_delimited_proto_init() {
+	if File_cmd_protoc_gen_go_testdata_protoeditions_maps_and_delimited_proto != nil {
+		return
+	}
+	if !protoimpl.UnsafeEnabled {
+		file_cmd_protoc_gen_go_testdata_protoeditions_maps_and_delimited_proto_msgTypes[0].Exporter = func(v any, i int) any {
+			switch v := v.(*MessageWithMaps); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
+		file_cmd_protoc_gen_go_testdata_protoeditions_maps_and_delimited_proto_msgTypes[4].Exporter = func(v any, i int) any {
+			switch v := v.(*MessageWithMaps_NestedMessage); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
+	}
+	type x struct{}
+	out := protoimpl.TypeBuilder{
+		File: protoimpl.DescBuilder{
+			GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
+			RawDescriptor: file_cmd_protoc_gen_go_testdata_protoeditions_maps_and_delimited_proto_rawDesc,
+			NumEnums:      0,
+			NumMessages:   5,
+			NumExtensions: 0,
+			NumServices:   0,
+		},
+		GoTypes:           file_cmd_protoc_gen_go_testdata_protoeditions_maps_and_delimited_proto_goTypes,
+		DependencyIndexes: file_cmd_protoc_gen_go_testdata_protoeditions_maps_and_delimited_proto_depIdxs,
+		MessageInfos:      file_cmd_protoc_gen_go_testdata_protoeditions_maps_and_delimited_proto_msgTypes,
+	}.Build()
+	File_cmd_protoc_gen_go_testdata_protoeditions_maps_and_delimited_proto = out.File
+	file_cmd_protoc_gen_go_testdata_protoeditions_maps_and_delimited_proto_rawDesc = nil
+	file_cmd_protoc_gen_go_testdata_protoeditions_maps_and_delimited_proto_goTypes = nil
+	file_cmd_protoc_gen_go_testdata_protoeditions_maps_and_delimited_proto_depIdxs = nil
+}
diff --git a/cmd/protoc-gen-go/testdata/protoeditions/maps_and_delimited.proto b/cmd/protoc-gen-go/testdata/protoeditions/maps_and_delimited.proto
new file mode 100644
index 0000000..536cbb7
--- /dev/null
+++ b/cmd/protoc-gen-go/testdata/protoeditions/maps_and_delimited.proto
@@ -0,0 +1,22 @@
+// Copyright 2024 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.
+
+edition = "2023";
+
+package goproto.protoc.protoeditions;
+
+option go_package = "google.golang.org/protobuf/cmd/protoc-gen-go/testdata/protoeditions";
+option features.message_encoding = DELIMITED;
+
+message MessageWithMaps {
+  map<string, string> map_without_message = 1;
+  map<uint32, bytes> map_without_message_b = 2;
+  map<int64, NestedMessage> map_with_message = 3;
+  message NestedMessage {
+    uint64 id = 1;
+    string name = 2;
+  }
+  NestedMessage nested_message = 4;
+  repeated NestedMessage repeated_message = 5;
+}
diff --git a/internal/filedesc/desc.go b/internal/filedesc/desc.go
index ece53be..df53ff4 100644
--- a/internal/filedesc/desc.go
+++ b/internal/filedesc/desc.go
@@ -383,6 +383,10 @@
 	}
 	return fd.L1.Message
 }
+func (fd *Field) IsMapEntry() bool {
+	parent, ok := fd.L0.Parent.(protoreflect.MessageDescriptor)
+	return ok && parent.IsMapEntry()
+}
 func (fd *Field) Format(s fmt.State, r rune)             { descfmt.FormatDesc(s, r, fd) }
 func (fd *Field) ProtoType(protoreflect.FieldDescriptor) {}
 
diff --git a/internal/filedesc/desc_lazy.go b/internal/filedesc/desc_lazy.go
index 570181e..e56c91a 100644
--- a/internal/filedesc/desc_lazy.go
+++ b/internal/filedesc/desc_lazy.go
@@ -45,6 +45,11 @@
 			case protoreflect.MessageKind, protoreflect.GroupKind:
 				fd.L1.Message = file.resolveMessageDependency(fd.L1.Message, listFieldDeps, depIdx)
 				depIdx++
+				if fd.L1.Kind == protoreflect.GroupKind && (fd.IsMap() || fd.IsMapEntry()) {
+					// A map field might inherit delimited encoding from a file-wide default feature.
+					// But maps never actually use delimited encoding. (At least for now...)
+					fd.L1.Kind = protoreflect.MessageKind
+				}
 			}
 
 			// Default is resolved here since it depends on Enum being resolved.
diff --git a/internal/filedesc/desc_test.go b/internal/filedesc/desc_test.go
index 182bf78..3ce8588 100644
--- a/internal/filedesc/desc_test.go
+++ b/internal/filedesc/desc_test.go
@@ -19,7 +19,6 @@
 	"google.golang.org/protobuf/proto"
 	"google.golang.org/protobuf/reflect/protodesc"
 	"google.golang.org/protobuf/reflect/protoreflect"
-
 	"google.golang.org/protobuf/types/descriptorpb"
 )
 
@@ -851,3 +850,103 @@
 	}
 	return string(b)
 }
+
+func TestMapsAreNotDelimited(t *testing.T) {
+	fileDescriptor := &descriptorpb.FileDescriptorProto{
+		Name:    proto.String("test.proto"),
+		Syntax:  proto.String("editions"),
+		Edition: descriptorpb.Edition_EDITION_2023.Enum(),
+		Options: &descriptorpb.FileOptions{
+			Features: &descriptorpb.FeatureSet{
+				MessageEncoding: descriptorpb.FeatureSet_DELIMITED.Enum(),
+			},
+		},
+		MessageType: []*descriptorpb.DescriptorProto{
+			{
+				Name: proto.String("MessageWithMaps"),
+				Field: []*descriptorpb.FieldDescriptorProto{
+					{
+						Name:     proto.String("map_with_message"),
+						Number:   proto.Int32(1),
+						Label:    descriptorpb.FieldDescriptorProto_LABEL_REPEATED.Enum(),
+						Type:     descriptorpb.FieldDescriptorProto_TYPE_MESSAGE.Enum(),
+						TypeName: proto.String(".MessageWithMaps.MapWithMessageEntry"),
+						JsonName: proto.String("mapWithMessage"),
+					},
+					{
+						Name:     proto.String("message"),
+						Number:   proto.Int32(2),
+						Label:    descriptorpb.FieldDescriptorProto_LABEL_REPEATED.Enum(),
+						Type:     descriptorpb.FieldDescriptorProto_TYPE_MESSAGE.Enum(),
+						TypeName: proto.String(".MessageWithMaps"),
+						JsonName: proto.String("message"),
+					},
+				},
+				NestedType: []*descriptorpb.DescriptorProto{
+					{
+						Name:    proto.String("MapWithMessageEntry"),
+						Options: &descriptorpb.MessageOptions{MapEntry: proto.Bool(true)},
+						Field: []*descriptorpb.FieldDescriptorProto{
+							{
+								Name:   proto.String("key"),
+								Number: proto.Int32(1),
+								Label:  descriptorpb.FieldDescriptorProto_LABEL_OPTIONAL.Enum(),
+								Type:   descriptorpb.FieldDescriptorProto_TYPE_STRING.Enum(),
+							},
+							{
+								Name:     proto.String("value"),
+								Number:   proto.Int32(2),
+								Label:    descriptorpb.FieldDescriptorProto_LABEL_OPTIONAL.Enum(),
+								Type:     descriptorpb.FieldDescriptorProto_TYPE_MESSAGE.Enum(),
+								TypeName: proto.String(".MessageWithMaps"),
+							},
+						},
+					},
+				},
+			},
+		},
+	}
+	fd1, err := protodesc.NewFile(fileDescriptor, nil)
+	if err != nil {
+		t.Fatalf("protodesc.NewFile() error: %v", err)
+	}
+
+	b, err := proto.Marshal(fileDescriptor)
+	if err != nil {
+		t.Fatalf("proto.Marshal() error: %v", err)
+	}
+	fd2 := filedesc.Builder{RawDescriptor: b}.Build().File
+
+	tests := []struct {
+		name string
+		desc protoreflect.FileDescriptor
+	}{
+		{"protodesc.NewFile", fd1},
+		{"filedesc.Builder.Build", fd2},
+	}
+	for _, tt := range tests {
+		tt := tt
+		t.Run(tt.name, func(t *testing.T) {
+			mapField := tt.desc.Messages().Get(0).Fields().Get(0)
+			if !mapField.IsMap() {
+				t.Fatalf("field should be a map")
+			}
+			nonMapField := tt.desc.Messages().Get(0).Fields().Get(1)
+			if nonMapField.IsMap() {
+				t.Fatalf("field should not be a map")
+			}
+			// sanity check that delimited default has taken effect
+			if nonMapField.Kind() != protoreflect.GroupKind {
+				t.Fatalf("non-map field should have group kind, instead got %v", nonMapField.Kind())
+			}
+			// now we can confirm that the map fields are NOT groups
+			if mapField.Kind() != protoreflect.MessageKind {
+				t.Fatalf("map field should have message kind, instead got %v", mapField.Kind())
+			}
+			mapValField := mapField.Message().Fields().ByNumber(2)
+			if mapValField.Kind() != protoreflect.MessageKind {
+				t.Fatalf("map value field should have message kind, instead got %v", mapValField.Kind())
+			}
+		})
+	}
+}
diff --git a/reflect/protodesc/desc_resolve.go b/reflect/protodesc/desc_resolve.go
index 254ca58..f3cebab 100644
--- a/reflect/protodesc/desc_resolve.go
+++ b/reflect/protodesc/desc_resolve.go
@@ -46,6 +46,11 @@
 			if f.L1.Kind, f.L1.Enum, f.L1.Message, err = r.findTarget(f.Kind(), f.Parent().FullName(), partialName(fd.GetTypeName()), f.IsWeak()); err != nil {
 				return errors.New("message field %q cannot resolve type: %v", f.FullName(), err)
 			}
+			if f.L1.Kind == protoreflect.GroupKind && (f.IsMap() || f.IsMapEntry()) {
+				// A map field might inherit delimited encoding from a file-wide default feature.
+				// But maps never actually use delimited encoding. (At least for now...)
+				f.L1.Kind = protoreflect.MessageKind
+			}
 			if fd.DefaultValue != nil {
 				v, ev, err := unmarshalDefault(fd.GetDefaultValue(), f, r.allowUnresolvable)
 				if err != nil {