fix(encode): emit one key when two fields resolve to one name

Assisted-by: GLM 5.3
This commit is contained in:
2026-09-17 23:08:42 +02:00
parent aaea68efc9
commit 30b28fe7fc
4 changed files with 69 additions and 1 deletions
+18 -1
View File
@@ -144,6 +144,16 @@ func (d *tomlDoc) partitionedEntries() (scalars []entry, tables []entry, arrays
// --- reflection walk: struct ---------------------------------------------
func buildStructDoc(v reflect.Value, doc *tomlDoc, ctx string) error {
return walkStructDoc(v, doc, ctx, nil, cachedStructSchema(v.Type()))
}
// walkStructDoc emits the fields of v into doc. prefix is v's index path from
// the struct whose schema resolves key conflicts; an embedded struct is walked
// with the outer schema and a longer prefix, so every leaf competes under the
// decoder's rule: the shallower field wins, the later declaration at equal
// depth. A field another field shadows is skipped, because emitting both
// would duplicate the key and the output would not re-parse.
func walkStructDoc(v reflect.Value, doc *tomlDoc, ctx string, prefix []int, schema structSchema) error {
t := v.Type()
for i := range t.NumField() {
if i%ctxCheckInterval == 0 {
@@ -155,6 +165,7 @@ func buildStructDoc(v reflect.Value, doc *tomlDoc, ctx string) error {
if f.PkgPath != "" {
continue
}
path := append(append([]int{}, prefix...), i)
if f.Anonymous {
tag, _ := f.Tag.Lookup("toml")
if tag == "-" {
@@ -169,12 +180,15 @@ func buildStructDoc(v reflect.Value, doc *tomlDoc, ctx string) error {
case reflect.Struct:
if isScalarStruct(fv.Type()) {
name := strings.ToLower(f.Name)
if !schema.ownsKey(name, path) {
continue
}
if err := doc.appendScalar(name, fv.Interface(), ctx); err != nil {
return err
}
continue
}
if err := buildStructDoc(fv, doc, ctx); err != nil {
if err := walkStructDoc(fv, doc, ctx, path, schema); err != nil {
return err
}
continue
@@ -190,6 +204,9 @@ func buildStructDoc(v reflect.Value, doc *tomlDoc, ctx string) error {
if name == "-" {
continue
}
if !schema.ownsKey(strings.ToLower(name), path) {
continue
}
if fieldOmitted(f, v.Field(i)) {
continue
}