Skip to content

text: use the type name only for group-like DELIMITED fields - #805

Open
v0ropaev wants to merge 1 commit into
anthropics:mainfrom
v0ropaev:fix/text-group-like-scope
Open

v0ropaev wants to merge 1 commit into
anthropics:mainfrom
v0ropaev:fix/text-group-like-scope

Conversation

@v0ropaev

Copy link
Copy Markdown
Contributor

In text format, a field is written under its type's name instead of its own name when it is group-like. buffa decided that from the field's effective type and its name alone, so any DELIMITED field whose name is the lowercased type name counted as group-like. C++ (IsGroupLike in descriptor.cc) and protobuf-go (isGroupLike in internal/filedesc) also require the type to be nested in the field's own message, in the same file. So in an editions file, a field named after a top-level type, a type nested in some other message, or an imported type was written under the type name, and protoc and prototext reject that name as an unknown field.

edition = "2023";
package demo;
option features.message_encoding = DELIMITED;
message Payload { int32 x = 1; }
message Outer { Payload payload = 1; }

buffa wrote Payload {x: 1} for this message. protoc writes payload {x: 1}, and protoc --encode=demo.Outer fails on buffa's output with Message type "demo.Outer" has no field named "Payload". A buffa-to-buffa round trip hid the problem because the generated parser accepted both spellings.

text_field_name now gets the containing message's name and checks that the type is declared directly inside it. A type nested in the containing message is always in the same file, so this one check also covers the same-file rule. The writer and the parser both get their field names from this function, so the parser now accepts the type name only for a group-like field, as C++ does. Proto2 groups are always nested in their own message and keep their type name. The editions conformance messages also use nested types, so their output doesn't change.

The new buffa-test fixture has an Outer message with DELIMITED fields of a top-level type, a type nested in another message, a type from another file, a repeated field and a oneof member, plus a type nested in Outer as the control. Its expected output matches what protoc 36.2 prints for the same message. There are also unit tests for text_field_name.

This touches the same repeated_encode_stmt signature in impl_text.rs as #802, so whichever goes in second will need a small rebase. I'm happy to do it.

@github-actions

Copy link
Copy Markdown

All contributors have signed the CLA ✍️ ✅
Posted by the CLA Assistant Lite bot.

An editions DELIMITED field whose name is the lowercased name of its
type was written in text format under the type name whatever the scope
of the type, so `Payload payload = 1` with a top-level `Payload` came
out as `Payload { ... }`. C++ IsGroupLike and protobuf-go isGroupLike
also require the type to be nested in the field's own message, and for
any other field they write the field name and reject the type name, so
protoc and prototext could not read what buffa wrote.

text_field_name now takes the containing message's name and requires
the type's scope to match it. A type nested in the containing message
is in the same file, so this also covers their same-file check. The
generated parser stops accepting the type name for such a field, as
C++ and Go do. Proto2 groups are always nested in their message and
keep their type name.
@v0ropaev
v0ropaev force-pushed the fix/text-group-like-scope branch from ecadf63 to a9dc821 Compare October 28, 2026 12:24

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant