this repo has no description
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