in runtime/under-builtins-module.cpp [5862:5974]
RawObject FUNC(_builtins, _type_dunder_call)(Thread* thread, Arguments args) {
HandleScope scope(thread);
Runtime* runtime = thread->runtime();
Object self_obj(&scope, args.get(0));
Tuple pargs(&scope, args.get(1));
Dict kwargs(&scope, args.get(2));
word pargs_length = pargs.length();
bool is_kwargs_empty = kwargs.numItems() == 0;
// Shortcut for type(x) calls.
if (pargs_length == 1 && is_kwargs_empty &&
self_obj == runtime->typeAt(LayoutId::kType)) {
return runtime->typeOf(pargs.at(0));
}
if (!runtime->isInstanceOfType(*self_obj)) {
return thread->raiseWithFmt(
LayoutId::kTypeError,
"'__call__' for '%Y' objects doesn't apply to a '%T' object", ID(type),
&self_obj);
}
Type self(&scope, *self_obj);
// `instance = self.__new__(...)`
Object instance(&scope, NoneType::object());
Object call_args_obj(&scope, NoneType::object());
bool use_object_dunder_new =
self.isType() && self.hasFlag(Type::Flag::kHasObjectDunderNew);
if (use_object_dunder_new) {
// Most common case `__new__` was not overridden and is just
// `object.__new__`.
instance = objectNew(thread, self);
if (instance.isErrorException()) return *instance;
} else {
Object dunder_new(&scope, Unbound::object());
Object dunder_new_name(&scope, runtime->symbols()->at(ID(__new__)));
if (self.isType()) {
// Metaclass is "type" so we do not need to check for __new__ being a
// datadescriptor and we can look it up directly on the type.
dunder_new = typeLookupInMro(thread, *self, *dunder_new_name);
}
if (dunder_new.isStaticMethod()) {
// Next most common case `__new__` is overridden with a normal function
dunder_new = StaticMethod::cast(*dunder_new).function();
} else {
// Finally fallback to complete lookup for corner cases
dunder_new = typeGetAttribute(thread, self, dunder_new_name);
}
CHECK(!dunder_new.isError(), "self must have __new__");
thread->stackPush(*dunder_new);
if (is_kwargs_empty) {
thread->stackPush(*self);
for (word i = 0; i < pargs_length; ++i) {
thread->stackPush(pargs.at(i));
}
instance = Interpreter::call(thread, pargs_length + 1);
} else {
MutableTuple call_args(&scope,
runtime->newMutableTuple(pargs_length + 1));
call_args.atPut(0, *self);
call_args.replaceFromWith(1, *pargs, pargs_length);
thread->stackPush(call_args.becomeImmutable());
thread->stackPush(*kwargs);
instance = Interpreter::callEx(thread, CallFunctionExFlag::VAR_KEYWORDS);
call_args_obj = *call_args;
}
if (instance.isErrorException()) return *instance;
if (!typeIsSubclass(runtime->typeOf(*instance), *self)) {
return *instance;
}
}
// instance.__init__(...)
Object dunder_init_name(&scope, runtime->symbols()->at(ID(__init__)));
Object dunder_init(&scope, typeGetAttribute(thread, self, dunder_init_name));
// `object.__init__` does nothing, we may be able to just skip things.
// The exception to the rule being `object.__init__` raising errors when
// arguments are provided and nothing is overridden.
if (dunder_init != runtime->objectDunderInit() ||
(use_object_dunder_new &&
(pargs.length() != 0 || kwargs.numItems() != 0))) {
CHECK(!dunder_init.isError(), "self must have __init__");
Object result(&scope, NoneType::object());
thread->stackPush(*dunder_init);
if (is_kwargs_empty) {
thread->stackPush(*instance);
for (word i = 0; i < pargs_length; ++i) {
thread->stackPush(pargs.at(i));
}
result = Interpreter::call(thread, pargs_length + 1);
} else {
if (!call_args_obj.isMutableTuple()) {
MutableTuple call_args(&scope,
runtime->newMutableTuple(pargs_length + 1));
call_args.atPut(0, *instance);
call_args.replaceFromWith(1, *pargs, pargs_length);
call_args_obj = *call_args;
} else {
MutableTuple::cast(*call_args_obj).atPut(0, *instance);
}
thread->stackPush(*call_args_obj);
thread->stackPush(*kwargs);
result = Interpreter::callEx(thread, CallFunctionExFlag::VAR_KEYWORDS);
}
if (result.isErrorException()) return *result;
if (!result.isNoneType()) {
Object type_name(&scope, self.name());
return thread->raiseWithFmt(LayoutId::kTypeError,
"%S.__init__ returned non None", &type_name);
}
}
return *instance;
}