Commit 3dbee69b authored by Travis Hance's avatar Travis Hance

implement set for getset descriptors, and setting for type __name__

parent e22da6f3
......@@ -1523,6 +1523,38 @@ extern "C" Box* getattr(Box* obj, const char* attr) {
raiseAttributeError(obj, attr);
}
bool dataDescriptorSetSpecialCases(Box* obj, Box* val, Box* descr, SetattrRewriteArgs* rewrite_args,
RewriterVar* r_descr, const std::string& attr_name) {
// Special case: getset descriptor
if (descr->cls == getset_cls) {
BoxedGetsetDescriptor* getset_descr = static_cast<BoxedGetsetDescriptor*>(descr);
// TODO type checking goes here
if (getset_descr->set == NULL) {
raiseExcHelper(AttributeError, "attribute '%s' of '%s' object is not writable", attr_name.c_str(),
getTypeName(getset_descr));
}
if (rewrite_args) {
RewriterVar* r_obj = rewrite_args->obj;
RewriterVar* r_val = rewrite_args->attrval;
r_descr->addAttrGuard(offsetof(BoxedGetsetDescriptor, set), (intptr_t)getset_descr->set);
RewriterVar* r_closure = r_descr->getAttr(offsetof(BoxedGetsetDescriptor, closure));
rewrite_args->rewriter->call(
/* can_call_into_python */ true, (void*)getset_descr->set, { r_obj, r_val, r_closure });
rewrite_args->out_success = true;
}
getset_descr->set(obj, val, getset_descr->closure);
return true;
}
return false;
}
void setattrInternal(Box* obj, const std::string& attr, Box* val, SetattrRewriteArgs* rewrite_args) {
assert(gc::isValidGCObject(val));
......@@ -1549,6 +1581,12 @@ void setattrInternal(Box* obj, const std::string& attr, Box* val, SetattrRewrite
Box* _set_ = NULL;
RewriterVar* r_set = NULL;
if (descr) {
bool special_case_worked = dataDescriptorSetSpecialCases(obj, val, descr, rewrite_args, r_descr, attr);
if (special_case_worked) {
// We don't need to to the invalidation stuff in this case.
return;
}
if (rewrite_args) {
RewriterVar* r_cls = r_descr->getAttr(BOX_CLS_OFFSET, Location::any());
GetattrRewriteArgs trewrite_args(rewrite_args->rewriter, r_cls, Location::any());
......@@ -1578,6 +1616,9 @@ void setattrInternal(Box* obj, const std::string& attr, Box* val, SetattrRewrite
} else {
runtimeCallInternal(_set_, NULL, ArgPassSpec(3), descr, obj, val, NULL, NULL);
}
// We don't need to to the invalidation stuff in this case.
return;
} else {
obj->setattr(attr, val, rewrite_args);
}
......
......@@ -640,7 +640,7 @@ static Box* func_name(Box* b, void*) {
return boxString(func->f->source->getName());
}
static int func_set_name(Box*, Box*, void*) {
static void func_set_name(Box*, Box*, void*) {
RELEASE_ASSERT(0, "not implemented");
}
......@@ -989,8 +989,34 @@ static Box* type_name(Box* b, void*) {
}
}
static int type_set_name(Box* b, Box* v, void*) {
RELEASE_ASSERT(false, "not implemented");
static void type_set_name(Box* b, Box* v, void*) {
assert(b->cls == type_cls);
BoxedClass* type = static_cast<BoxedClass*>(b);
// Awkward... in CPython you can only set __name__ for heaptype classes
// (those with ht_name) but in Pyston right now we have some heaptype classes that
// aren't heaptype in CPython, and we have to restrict those too.
// TODO is this predicate right?
bool is_heaptype = (type->tp_flags & Py_TPFLAGS_HEAPTYPE);
if (!(is_heaptype && type->is_user_defined)) {
raiseExcHelper(TypeError, "can't set %s.__name__", type->tp_name);
}
if (!v) {
raiseExcHelper(TypeError, "can't delete %s.__name__", type->tp_name);
}
if (!PyString_Check(v)) {
raiseExcHelper(TypeError, "can only assign string to %s.__name__, not '%s'", type->tp_name, getTypeName(v));
}
BoxedString* s = static_cast<BoxedString*>(v);
if (strlen(s->s.c_str()) != s->s.size()) {
raiseExcHelper(ValueError, "__name__ must not contain null bytes");
}
BoxedHeapClass* ht = static_cast<BoxedHeapClass*>(type);
ht->ht_name = s;
ht->tp_name = s->s.c_str();
}
// cls should be obj->cls.
......
......@@ -529,10 +529,10 @@ public:
class BoxedGetsetDescriptor : public Box {
public:
Box* (*get)(Box*, void*);
int (*set)(Box*, Box*, void*);
void (*set)(Box*, Box*, void*);
void* closure;
BoxedGetsetDescriptor(Box* (*get)(Box*, void*), int (*set)(Box*, Box*, void*), void* closure)
BoxedGetsetDescriptor(Box* (*get)(Box*, void*), void (*set)(Box*, Box*, void*), void* closure)
: get(get), set(set), closure(closure) {}
DEFAULT_CLASS(getset_cls);
......
# expected: fail
# This fails becasue we currently don't support setting for getset descriptors,
# and __name__ is a getset descriptor.
class C(object):
pass
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment