in starlark/library.go [2221:2283]
func updateDict(dict *Dict, updates Tuple, kwargs []Tuple) error {
if len(updates) == 1 {
switch updates := updates[0].(type) {
case IterableMapping:
// Iterate over dict's key/value pairs, not just keys.
for _, item := range updates.Items() {
if err := dict.SetKey(item[0], item[1]); err != nil {
return err // dict is frozen
}
}
default:
// all other sequences
iter := Iterate(updates)
if iter == nil {
return fmt.Errorf("got %s, want iterable", updates.Type())
}
defer iter.Done()
var pair Value
for i := 0; iter.Next(&pair); i++ {
iter2 := Iterate(pair)
if iter2 == nil {
return fmt.Errorf("dictionary update sequence element #%d is not iterable (%s)", i, pair.Type())
}
defer iter2.Done()
len := Len(pair)
if len < 0 {
return fmt.Errorf("dictionary update sequence element #%d has unknown length (%s)", i, pair.Type())
} else if len != 2 {
return fmt.Errorf("dictionary update sequence element #%d has length %d, want 2", i, len)
}
var k, v Value
iter2.Next(&k)
iter2.Next(&v)
if err := dict.SetKey(k, v); err != nil {
return err
}
}
}
}
// Then add the kwargs.
before := dict.Len()
for _, pair := range kwargs {
if err := dict.SetKey(pair[0], pair[1]); err != nil {
return err // dict is frozen
}
}
// In the common case, each kwarg will add another dict entry.
// If that's not so, check whether it is because there was a duplicate kwarg.
if dict.Len() < before+len(kwargs) {
keys := make(map[String]bool, len(kwargs))
for _, kv := range kwargs {
k := kv[0].(String)
if keys[k] {
return fmt.Errorf("duplicate keyword arg: %v", k)
}
keys[k] = true
}
}
return nil
}