in rule/merge.go [193:264]
func mergeDict(src, dst *bzl.DictExpr) (*bzl.DictExpr, error) {
if dst == nil {
return src, nil
}
if src == nil {
src = &bzl.DictExpr{List: []*bzl.KeyValueExpr{}}
}
var entries []*dictEntry
entryMap := make(map[string]*dictEntry)
for _, kv := range dst.List {
k, v, err := dictEntryKeyValue(kv)
if err != nil {
return nil, err
}
if _, ok := entryMap[k]; ok {
return nil, fmt.Errorf("dst dict contains more than one case named %q", k)
}
e := &dictEntry{key: k, dstValue: v}
entries = append(entries, e)
entryMap[k] = e
}
for _, kv := range src.List {
k, v, err := dictEntryKeyValue(kv)
if err != nil {
return nil, err
}
e, ok := entryMap[k]
if !ok {
e = &dictEntry{key: k}
entries = append(entries, e)
entryMap[k] = e
}
e.srcValue = v
}
keys := make([]string, 0, len(entries))
haveDefault := false
for _, e := range entries {
e.mergedValue = mergeList(e.srcValue, e.dstValue)
if e.key == "//conditions:default" {
// Keep the default case, even if it's empty.
haveDefault = true
if e.mergedValue == nil {
e.mergedValue = &bzl.ListExpr{}
}
} else if e.mergedValue != nil {
keys = append(keys, e.key)
}
}
if len(keys) == 0 && (!haveDefault || len(entryMap["//conditions:default"].mergedValue.List) == 0) {
return nil, nil
}
sort.Strings(keys)
// Always put the default case last.
if haveDefault {
keys = append(keys, "//conditions:default")
}
mergedEntries := make([]*bzl.KeyValueExpr, len(keys))
for i, k := range keys {
e := entryMap[k]
mergedEntries[i] = &bzl.KeyValueExpr{
Key: &bzl.StringExpr{Value: e.key},
Value: e.mergedValue,
}
}
return &bzl.DictExpr{List: mergedEntries, ForceMultiLine: true}, nil
}