in runtime/dict-builtins.cpp [607:738]
RawObject dictMergeImpl(Thread* thread, const Dict& dict, const Object& mapping,
Override do_override) {
Runtime* runtime = thread->runtime();
if (runtime->isInstanceOfDict(*mapping)) {
return dictMergeDict(thread, dict, mapping, do_override);
}
HandleScope scope(thread);
Object key(&scope, NoneType::object());
Object hash_obj(&scope, NoneType::object());
Object value(&scope, NoneType::object());
Object included(&scope, NoneType::object());
Object keys_method(&scope,
runtime->attributeAtById(thread, mapping, ID(keys)));
if (keys_method.isError()) {
return *keys_method;
}
// Generic mapping, use keys() and __getitem__()
Object subscr_method(
&scope, runtime->attributeAtById(thread, mapping, ID(__getitem__)));
if (subscr_method.isError()) {
return *subscr_method;
}
Object keys(&scope, Interpreter::callMethod1(thread, keys_method, mapping));
if (keys.isError()) return *keys;
if (keys.isList()) {
List keys_list(&scope, *keys);
Object dict_result(&scope, NoneType::object());
for (word i = 0; i < keys_list.numItems(); ++i) {
key = keys_list.at(i);
hash_obj = Interpreter::hash(thread, key);
if (hash_obj.isErrorException()) return *hash_obj;
word hash = SmallInt::cast(*hash_obj).value();
if (do_override == Override::kOverride) {
value = Interpreter::callMethod2(thread, subscr_method, mapping, key);
if (value.isError()) return *value;
dict_result = dictAtPut(thread, dict, key, hash, value);
if (dict_result.isErrorException()) return *dict_result;
} else {
included = dictIncludes(thread, dict, key, hash);
if (included.isErrorException()) return *included;
if (included == Bool::falseObj()) {
value = Interpreter::callMethod2(thread, subscr_method, mapping, key);
if (value.isError()) return *value;
dict_result = dictAtPut(thread, dict, key, hash, value);
if (dict_result.isErrorException()) return *dict_result;
} else if (do_override == Override::kError) {
return thread->raise(LayoutId::kKeyError, *key);
}
}
}
return NoneType::object();
}
if (keys.isTuple()) {
Tuple keys_tuple(&scope, *keys);
Object dict_result(&scope, NoneType::object());
for (word i = 0; i < keys_tuple.length(); ++i) {
key = keys_tuple.at(i);
hash_obj = Interpreter::hash(thread, key);
if (hash_obj.isErrorException()) return *hash_obj;
word hash = SmallInt::cast(*hash_obj).value();
if (do_override == Override::kOverride) {
value = Interpreter::callMethod2(thread, subscr_method, mapping, key);
if (value.isError()) return *value;
dict_result = dictAtPut(thread, dict, key, hash, value);
if (dict_result.isErrorException()) return *dict_result;
} else {
included = dictIncludes(thread, dict, key, hash);
if (included.isErrorException()) return *included;
if (included == Bool::falseObj()) {
value = Interpreter::callMethod2(thread, subscr_method, mapping, key);
if (value.isError()) return *value;
dict_result = dictAtPut(thread, dict, key, hash, value);
if (dict_result.isErrorException()) return *dict_result;
} else if (do_override == Override::kError) {
return thread->raise(LayoutId::kKeyError, *key);
}
}
}
return NoneType::object();
}
// keys is probably an iterator
Object iter_method(&scope,
Interpreter::lookupMethod(thread, keys, ID(__iter__)));
if (iter_method.isError()) {
return thread->raiseWithFmt(LayoutId::kTypeError, "keys() is not iterable");
}
Object iterator(&scope, Interpreter::callMethod1(thread, iter_method, keys));
if (iterator.isError()) {
return thread->raiseWithFmt(LayoutId::kTypeError, "keys() is not iterable");
}
Object next_method(&scope,
Interpreter::lookupMethod(thread, iterator, ID(__next__)));
if (next_method.isError()) {
return thread->raiseWithFmt(LayoutId::kTypeError, "keys() is not iterable");
}
Object dict_result(&scope, NoneType::object());
for (;;) {
key = Interpreter::callMethod1(thread, next_method, iterator);
if (key.isError()) {
if (thread->clearPendingStopIteration()) break;
return *key;
}
hash_obj = Interpreter::hash(thread, key);
if (hash_obj.isErrorException()) return *hash_obj;
word hash = SmallInt::cast(*hash_obj).value();
if (do_override == Override::kOverride) {
value = Interpreter::callMethod2(thread, subscr_method, mapping, key);
if (value.isError()) return *value;
dict_result = dictAtPut(thread, dict, key, hash, value);
if (dict_result.isErrorException()) return *dict_result;
} else {
included = dictIncludes(thread, dict, key, hash);
if (included.isErrorException()) return *included;
if (included == Bool::falseObj()) {
value = Interpreter::callMethod2(thread, subscr_method, mapping, key);
if (value.isError()) return *value;
dict_result = dictAtPut(thread, dict, key, hash, value);
if (dict_result.isErrorException()) return *dict_result;
} else if (do_override == Override::kError) {
return thread->raise(LayoutId::kKeyError, *key);
}
}
}
return NoneType::object();
}