runtime/type-builtins.h (102 lines of code) (raw):
/* Copyright (c) Facebook, Inc. and its affiliates. (http://www.facebook.com) */
#pragma once
#include "attributedict.h"
#include "frame.h"
#include "globals.h"
#include "layout.h"
#include "objects.h"
#include "runtime.h"
#include "thread.h"
namespace py {
constexpr View<BuiltinAttribute> kNoAttributes(nullptr, 0);
// Prepare `name_obj` to be used as an attribute name: Raise a TypeError if it
// is not a string; reject some string subclasses. Otherwise return an
// interned string that can be used with attribute accessors.
RawObject attributeName(Thread* thread, const Object& name_obj);
RawObject attributeNameNoException(Thread* thread, const Object& name_obj);
RawObject addBuiltinType(Thread* thread, SymbolId name, LayoutId layout_id,
LayoutId superclass_id, View<BuiltinAttribute> attrs,
word size, bool basetype);
RawObject addImmediateBuiltinType(Thread* thread, SymbolId name,
LayoutId layout_id, LayoutId builtin_base,
LayoutId superclass_id, bool basetype);
void builtinTypeEnableTupleOverflow(Thread* thread, const Type& type);
// Returns the most generic base among `bases` that captures inherited
// attributes with a fixed offset (either from __slots__ or builtin types)
// Note that this simulates `best_base` from CPython's typeobject.c.
RawObject computeFixedAttributeBase(Thread* thread, const Tuple& bases);
RawObject findBuiltinTypeWithName(Thread* thread, const Object& name);
RawObject raiseTypeErrorCannotSetImmutable(Thread* thread, const Type& type);
bool typeIsSubclass(RawObject subclass, RawObject superclass);
void typeAddDocstring(Thread* thread, const Type& type);
void typeAddInstanceDict(Thread* thread, const Type& type);
// Assign all key/values from the dict to the type. This interns the keys as
// necessary or may raise an exception for invalid keys (see attributeName()).
RawObject typeAssignFromDict(Thread* thread, const Type& type,
const Dict& dict);
RawObject typeAt(const Type& type, const Object& name);
RawObject typeAtSetLocation(RawType type, RawObject name, word hash,
Object* location);
RawObject typeAtById(Thread* thread, const Type& type, SymbolId id);
RawObject typeAtPut(Thread* thread, const Type& type, const Object& name,
const Object& value);
RawObject typeAtPutById(Thread* thread, const Type& type, SymbolId id,
const Object& value);
RawObject typeDeleteAttribute(Thread* thread, const Type& receiver,
const Object& name);
RawObject typeRemove(Thread* thread, const Type& type, const Object& name);
RawObject typeRemoveById(Thread* thread, const Type& type, SymbolId id);
RawObject typeKeys(Thread* thread, const Type& type);
word typeLen(Thread* thread, const Type& type);
RawObject typeValues(Thread* thread, const Type& type);
RawObject typeGetAttribute(Thread* thread, const Type& type,
const Object& name);
RawObject typeGetAttributeSetLocation(Thread* thread, const Type& type,
const Object& name, Object* location_out);
// Returns true if the type defines a __set__ method.
bool typeIsDataDescriptor(RawType type);
// Returns true if the type defines a __get__ method.
bool typeIsNonDataDescriptor(RawType type);
// If descr's Type has __get__(), call it with the appropriate arguments and
// return the result. Otherwise, return descr.
RawObject resolveDescriptorGet(Thread* thread, const Object& descr,
const Object& instance,
const Object& instance_type);
RawObject typeInit(Thread* thread, const Type& type, const Str& name,
const Dict& dict, const Tuple& mro);
// Looks up `key` in the dict of each entry in type's MRO. Returns
// `Error::notFound()` if the name was not found.
RawObject typeLookupInMro(Thread* thread, RawType type, RawObject name);
RawObject typeLookupInMroSetLocation(Thread* thread, RawType type,
RawObject name, Object* location);
// Looks up `id` in the dict of each entry in type's MRO. Returns
// `Error::notFound()` if the name was not found.
RawObject typeLookupInMroById(Thread* thread, RawType type, SymbolId id);
RawObject typeNew(Thread* thread, const Type& metaclass, const Str& name,
const Tuple& bases, const Dict& dict, word flags,
bool inherit_slots, bool add_instance_dict);
RawObject typeSetAttr(Thread* thread, const Type& type, const Object& name,
const Object& value);
// Sets __class__ of self to new_type.
// Returns None on success.
// Raises an exception and returns Error::exception() otherwise.
RawObject typeSetDunderClass(Thread* thread, const Object& self,
const Type& new_type);
// Terminate the process if cache invalidation for updating attr_name in type
// objects is unimplemented.
void terminateIfUnimplementedTypeAttrCacheInvalidation(Thread* thread,
const Type& type,
const Object& attr_name);
void initializeTypeTypes(Thread* thread);
inline bool typeIsSubclass(RawObject subclass, RawObject superclass) {
if (DCHECK_IS_ON()) {
Runtime* runtime = Thread::current()->runtime();
DCHECK(runtime->isInstanceOfType(subclass),
"typeIsSubclass subclass must be a type object");
DCHECK(runtime->isInstanceOfType(superclass),
"typeIsSubclass superclass must be a type object");
DCHECK(Tuple::cast(subclass.rawCast<RawType>().mro()).at(0) == subclass,
"unexpected mro");
}
if (subclass == superclass) return true;
RawTuple mro = Tuple::cast(subclass.rawCast<RawType>().mro());
word length = mro.length();
for (word i = 1; i < length; i++) {
if (mro.at(i) == superclass) {
return true;
}
}
return false;
}
inline RawObject typeLookupInMro(Thread* thread, RawType type, RawObject name) {
RawTuple mro = Tuple::cast(type.mro());
word hash = internedStrHash(name);
for (word i = 0, length = mro.length(); i < length; i++) {
DCHECK(thread->runtime()->isInstanceOfType(mro.at(i)), "non-type in MRO");
RawType mro_type = mro.at(i).rawCast<RawType>();
RawObject result = NoneType::object();
if (attributeAtWithHash(mro_type, name, hash, &result)) {
return result;
}
}
return Error::notFound();
}
} // namespace py