void Runtime::builtinTypeCreated()

in runtime/runtime.cpp [1937:2056]


void Runtime::builtinTypeCreated(Thread* thread, const Type& type) {
  LayoutId layout_id = type.instanceLayoutId();
  switch (layout_id) {
    case LayoutId::kObject:
      object_dunder_class_ = typeAtById(thread, type, ID(__class__));
      object_dunder_eq_ = typeAtById(thread, type, ID(__eq__));
      object_dunder_getattribute_ =
          typeAtById(thread, type, ID(__getattribute__));
      object_dunder_hash_ = typeAtById(thread, type, ID(__hash__));
      object_dunder_init_ = typeAtById(thread, type, ID(__init__));
      object_dunder_new_ = typeAtById(thread, type, ID(__new__));
      object_dunder_setattr_ = typeAtById(thread, type, ID(__setattr__));
      type.setFlags(static_cast<Type::Flag>(
          type.flags() | Type::Flag::kHasObjectDunderGetattribute |
          Type::Flag::kHasObjectDunderNew | Type::Flag::kHasObjectDunderHash));
      break;
    case LayoutId::kModule:
      module_dunder_getattribute_ =
          typeAtById(thread, type, ID(__getattribute__));
      type.setFlags(static_cast<Type::Flag>(
          type.flags() | Type::Flag::kHasModuleDunderGetattribute));
      break;
    case LayoutId::kNoneType:
      // NoneType.__class__ does *not* point to the same object as
      // object.__class_ to avoid descriptor resolution for NoneType, but their
      // observable behaviors are same. See the definition of NoneType in
      // builtins.py.
      type.setFlags(static_cast<Type::Flag>(type.flags() |
                                            Type::Flag::kHasObjectDunderClass));
      break;
    case LayoutId::kStr:
      str_dunder_eq_ = typeAtById(thread, type, ID(__eq__));
      str_dunder_hash_ = typeAtById(thread, type, ID(__hash__));
      type.setFlags(static_cast<Type::Flag>(type.flags() |
                                            Type::Flag::kHasStrDunderHash));
      break;
    case LayoutId::kType:
      type_dunder_getattribute_ =
          typeAtById(thread, type, ID(__getattribute__));
      type.setFlags(static_cast<Type::Flag>(
          type.flags() | Type::Flag::kHasTypeDunderGetattribute));
      break;
    default:
      break;
  }

  HandleScope scope(thread);
  Function dunder_getattribute(
      &scope, typeLookupInMroById(thread, *type, ID(__getattribute__)));
  // This detects two instances of `object.__getattribute__`:
  // 1) Manually created `object.__getattribute__` before initializing `object`.
  // 2) Real `object.__getattribute__` after.
  if (Str::cast(dunder_getattribute.qualname())
          .equalsCStr("object.__getattribute__")) {
    type.setFlags(static_cast<Type::Flag>(
        type.flags() | Type::Flag::kHasObjectDunderGetattribute));
  }

  Object dunder_new(&scope, typeLookupInMroById(thread, *type, ID(__new__)));
  if (*dunder_new == object_dunder_new_ ||
      // __new__ cannot be found in this type and this type is initialized
      // before `object`.
      (dunder_new.isErrorNotFound() && object_dunder_new_.isNoneType())) {
    type.setFlags(static_cast<Type::Flag>(type.flags() |
                                          Type::Flag::kHasObjectDunderNew));
  }

  Object dunder_hash(&scope, typeLookupInMroById(thread, *type, ID(__hash__)));
  if (*dunder_hash == object_dunder_hash_ ||
      // __hash__ cannot be found in this type and this type is initialized
      // before `object`.
      (dunder_hash.isErrorNotFound() && object_dunder_hash_.isNoneType())) {
    type.setFlags(static_cast<Type::Flag>(type.flags() |
                                          Type::Flag::kHasObjectDunderHash));
  }

  if (!typeLookupInMroById(thread, *type, ID(__bool__)).isErrorNotFound()) {
    type.setFlags(
        static_cast<Type::Flag>(type.flags() | Type::Flag::kHasDunderBool));
  }

  if (!typeLookupInMroById(thread, *type, ID(__len__)).isErrorNotFound()) {
    type.setFlags(
        static_cast<Type::Flag>(type.flags() | Type::Flag::kHasDunderLen));
  }

  Object dunder_class(&scope,
                      typeLookupInMroById(thread, *type, ID(__class__)));
  if (*dunder_class == object_dunder_class_ ||
      // __class__ cannot be found in this type and this type is initialized
      // before `object`.
      (dunder_class.isErrorNotFound() && object_dunder_class_.isNoneType())) {
    type.setFlags(static_cast<Type::Flag>(type.flags() |
                                          Type::Flag::kHasObjectDunderClass));
  }

  Object dunder_eq(&scope, typeLookupInMroById(thread, *type, ID(__eq__)));
  if (*dunder_eq == object_dunder_eq_ ||
      // __eq__ cannot be found in this type and this type is initialized
      // before `object`.
      (dunder_eq.isErrorNotFound() && object_dunder_eq_.isNoneType())) {
    type.setFlags(
        static_cast<Type::Flag>(type.flags() | Type::Flag::kHasObjectDunderEq));
  }

  if (!typeLookupInMroById(thread, *type, ID(__get__)).isErrorNotFound()) {
    type.setFlags(
        static_cast<Type::Flag>(type.flags() | Type::Flag::kHasDunderGet));
  }

  if (!typeLookupInMroById(thread, *type, ID(__set__)).isErrorNotFound()) {
    type.setFlags(
        static_cast<Type::Flag>(type.flags() | Type::Flag::kHasDunderSet));
  }

  if (!typeLookupInMroById(thread, *type, ID(__delete__)).isErrorNotFound()) {
    type.setFlags(
        static_cast<Type::Flag>(type.flags() | Type::Flag::kHasDunderDelete));
  }
}