this repo has no description
at trunk 201 lines 6.9 kB view raw
1// Copyright (c) Facebook, Inc. and its affiliates. (http://www.facebook.com) 2#include "super-builtins.h" 3 4#include "attributedict.h" 5#include "builtins.h" 6#include "frame.h" 7#include "globals.h" 8#include "object-builtins.h" 9#include "objects.h" 10#include "runtime.h" 11#include "str-builtins.h" 12#include "thread.h" 13#include "type-builtins.h" 14 15namespace py { 16 17RawObject superGetAttribute(Thread* thread, const Super& super, 18 const Object& name) { 19 // This must return `super`. 20 Runtime* runtime = thread->runtime(); 21 if (name == runtime->symbols()->at(ID(__class__))) { 22 return runtime->typeOf(*super); 23 } 24 25 HandleScope scope(thread); 26 Type start_type(&scope, super.objectType()); 27 Tuple mro(&scope, start_type.mro()); 28 word i; 29 word mro_length = mro.length(); 30 for (i = 0; i < mro_length; i++) { 31 if (super.type() == mro.at(i)) { 32 // skip super->type (if any) 33 i++; 34 break; 35 } 36 } 37 for (; i < mro_length; i++) { 38 Type type(&scope, mro.at(i)); 39 Object value(&scope, typeAt(type, name)); 40 if (value.isError()) { 41 continue; 42 } 43 Type value_type(&scope, runtime->typeOf(*value)); 44 if (!typeIsNonDataDescriptor(*value_type)) { 45 return *value; 46 } 47 Object self(&scope, NoneType::object()); 48 if (super.object() != *start_type) { 49 self = super.object(); 50 } 51 // TODO(T56507184): Remove this once super.__getattribute__ gets cached. 52 if (value.isFunction()) { 53 // See METH(function, __get__) for details. 54 if (self.isNoneType() && 55 start_type.builtinBase() != LayoutId::kNoneType) { 56 return *value; 57 } 58 return runtime->newBoundMethod(value, self); 59 } 60 return Interpreter::callDescriptorGet(thread, value, self, start_type); 61 } 62 63 return objectGetAttribute(thread, super, name); 64} 65 66static const BuiltinAttribute kSuperAttributes[] = { 67 {ID(__thisclass__), RawSuper::kTypeOffset, AttributeFlags::kReadOnly}, 68 {ID(__self__), RawSuper::kObjectOffset, AttributeFlags::kReadOnly}, 69 {ID(__self_class__), RawSuper::kObjectTypeOffset, 70 AttributeFlags::kReadOnly}, 71}; 72 73void initializeSuperType(Thread* thread) { 74 addBuiltinType(thread, ID(super), LayoutId::kSuper, 75 /*superclass_id=*/LayoutId::kObject, kSuperAttributes, 76 Super::kSize, /*basetype=*/true); 77} 78 79RawObject METH(super, __getattribute__)(Thread* thread, Arguments args) { 80 HandleScope scope(thread); 81 Object self_obj(&scope, args.get(0)); 82 if (!self_obj.isSuper()) { 83 return thread->raiseRequiresType(self_obj, ID(super)); 84 } 85 Super self(&scope, *self_obj); 86 Object name(&scope, args.get(1)); 87 name = attributeName(thread, name); 88 if (name.isErrorException()) return *name; 89 Object result(&scope, superGetAttribute(thread, self, name)); 90 if (result.isErrorNotFound()) { 91 return thread->raiseWithFmt(LayoutId::kAttributeError, 92 "super object has no attribute '%S'", &name); 93 } 94 return *result; 95} 96 97RawObject METH(super, __new__)(Thread* thread, Arguments) { 98 return thread->runtime()->newSuper(); 99} 100 101RawObject superInit(Thread* thread, const Super& super, const Object& arg0, 102 const Object& arg1, Frame* frame) { 103 HandleScope scope(thread); 104 Runtime* runtime = thread->runtime(); 105 Object type(&scope, NoneType::object()); 106 Object obj(&scope, NoneType::object()); 107 if (arg0.isUnbound()) { 108 if (!frame->code().isCode()) { 109 return thread->raiseWithFmt(LayoutId::kRuntimeError, 110 "super(): no code object"); 111 } 112 Code code(&scope, frame->code()); 113 if (code.argcount() == 0) { 114 return thread->raiseWithFmt(LayoutId::kRuntimeError, 115 "super(): no arguments"); 116 } 117 Tuple free_vars(&scope, code.freevars()); 118 RawObject cell = Error::notFound(); 119 for (word i = 0, length = free_vars.length(); i < length; i++) { 120 if (free_vars.at(i) == runtime->symbols()->at(ID(__class__))) { 121 cell = frame->local(code.nlocals() + code.numCellvars() + i); 122 break; 123 } 124 } 125 if (cell.isErrorNotFound() || !cell.isCell()) { 126 return thread->raiseWithFmt(LayoutId::kRuntimeError, 127 "super(): __class__ cell not found"); 128 } 129 type = Cell::cast(cell).value(); 130 obj = frame->local(0); 131 // The parameter value may have been moved into a value cell. 132 if (obj.isNoneType() && !code.cell2arg().isNoneType()) { 133 Tuple cell2arg(&scope, code.cell2arg()); 134 for (word i = 0, length = cell2arg.length(); i < length; i++) { 135 if (cell2arg.at(i) == SmallInt::fromWord(0)) { 136 obj = Cell::cast(frame->local(code.nlocals() + i)).value(); 137 break; 138 } 139 } 140 } 141 } else { 142 if (arg1.isUnbound()) { 143 return thread->raiseWithFmt(LayoutId::kTypeError, 144 "super() expected 2 arguments"); 145 } 146 type = *arg0; 147 obj = *arg1; 148 } 149 if (!runtime->isInstanceOfType(*type)) { 150 return thread->raiseWithFmt(LayoutId::kTypeError, 151 "super() argument 1 must be type"); 152 } 153 super.setType(*type); 154 super.setObject(*obj); 155 Object obj_type_obj(&scope, NoneType::object()); 156 if (runtime->isInstanceOfType(*obj) && typeIsSubclass(*obj, *type)) { 157 obj_type_obj = *obj; 158 } else { 159 Type obj_type(&scope, runtime->typeOf(*obj)); 160 if (typeIsSubclass(*obj_type, *type)) { 161 obj_type_obj = *obj_type; 162 } else { 163 return thread->raiseWithFmt(LayoutId::kTypeError, 164 "obj must be an instance or subtype of type"); 165 } 166 } 167 super.setObjectType(*obj_type_obj); 168 return *super; 169} 170 171RawObject METH(super, __init__)(Thread* thread, Arguments args) { 172 // only support idiomatic usage for now 173 // super() -> same as super(__class__, <first argument>) 174 // super(type, obj) -> bound super object; requires isinstance(obj, type) 175 // super(type, type2) -> bound super object; requires issubclass(type2, type) 176 HandleScope scope(thread); 177 Object self_obj(&scope, args.get(0)); 178 if (!self_obj.isSuper()) { 179 return thread->raiseRequiresType(self_obj, ID(super)); 180 } 181 Super super(&scope, *self_obj); 182 Object arg0(&scope, args.get(1)); 183 Object arg1(&scope, args.get(2)); 184 Frame* frame = thread->currentFrame(); 185 if (arg0.isUnbound()) { 186 // frame is for __init__, previous frame is __call__ 187 // this will break if it's not invoked through __call__ 188 DCHECK(!frame->isSentinel(), "super.__init__ must have a frame"); 189 Frame* caller_frame = frame->previousFrame(); 190 if (caller_frame->isSentinel()) { 191 return thread->raiseWithFmt(LayoutId::kRuntimeError, 192 "super(): no current frame"); 193 } 194 frame = caller_frame->previousFrame(); 195 } 196 Object result(&scope, superInit(thread, super, arg0, arg1, frame)); 197 if (result.isErrorException()) return *result; 198 return NoneType::object(); 199} 200 201} // namespace py