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>
This commit is contained in:
Josh Humphries 2024-05-29 09:43:14 -04:00 committed by Michael Stapelberg
parent ca837e5c65
commit 3b8611b60b
6 changed files with 443 additions and 1 deletions

View File

@ -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
}

View File

@ -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;
}

View File

@ -383,6 +383,10 @@ func (fd *Field) Message() protoreflect.MessageDescriptor {
}
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) {}

View File

@ -45,6 +45,11 @@ func (file *File) resolveMessages() {
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.

View File

@ -19,7 +19,6 @@ import (
"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 @@ func compactMultiFormat(s string) string {
}
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())
}
})
}
}

View File

@ -46,6 +46,11 @@ func (r *resolver) resolveMessageDependencies(ms []filedesc.Message, mds []*desc
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 {