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) { ...@@ -1523,6 +1523,38 @@ extern "C" Box* getattr(Box* obj, const char* attr) {
raiseAttributeError(obj, 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) { void setattrInternal(Box* obj, const std::string& attr, Box* val, SetattrRewriteArgs* rewrite_args) {
assert(gc::isValidGCObject(val)); assert(gc::isValidGCObject(val));
...@@ -1549,6 +1581,12 @@ void setattrInternal(Box* obj, const std::string& attr, Box* val, SetattrRewrite ...@@ -1549,6 +1581,12 @@ void setattrInternal(Box* obj, const std::string& attr, Box* val, SetattrRewrite
Box* _set_ = NULL; Box* _set_ = NULL;
RewriterVar* r_set = NULL; RewriterVar* r_set = NULL;
if (descr) { 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) { if (rewrite_args) {
RewriterVar* r_cls = r_descr->getAttr(BOX_CLS_OFFSET, Location::any()); RewriterVar* r_cls = r_descr->getAttr(BOX_CLS_OFFSET, Location::any());
GetattrRewriteArgs trewrite_args(rewrite_args->rewriter, r_cls, 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 ...@@ -1578,6 +1616,9 @@ void setattrInternal(Box* obj, const std::string& attr, Box* val, SetattrRewrite
} else { } else {
runtimeCallInternal(_set_, NULL, ArgPassSpec(3), descr, obj, val, NULL, NULL); runtimeCallInternal(_set_, NULL, ArgPassSpec(3), descr, obj, val, NULL, NULL);
} }
// We don't need to to the invalidation stuff in this case.
return;
} else { } else {
obj->setattr(attr, val, rewrite_args); obj->setattr(attr, val, rewrite_args);
} }
......
...@@ -640,7 +640,7 @@ static Box* func_name(Box* b, void*) { ...@@ -640,7 +640,7 @@ static Box* func_name(Box* b, void*) {
return boxString(func->f->source->getName()); 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"); RELEASE_ASSERT(0, "not implemented");
} }
...@@ -989,8 +989,34 @@ static Box* type_name(Box* b, void*) { ...@@ -989,8 +989,34 @@ static Box* type_name(Box* b, void*) {
} }
} }
static int type_set_name(Box* b, Box* v, void*) { static void type_set_name(Box* b, Box* v, void*) {
RELEASE_ASSERT(false, "not implemented"); 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. // cls should be obj->cls.
......
...@@ -529,10 +529,10 @@ public: ...@@ -529,10 +529,10 @@ public:
class BoxedGetsetDescriptor : public Box { class BoxedGetsetDescriptor : public Box {
public: public:
Box* (*get)(Box*, void*); Box* (*get)(Box*, void*);
int (*set)(Box*, Box*, void*); void (*set)(Box*, Box*, void*);
void* closure; 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) {} : get(get), set(set), closure(closure) {}
DEFAULT_CLASS(getset_cls); 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): class C(object):
pass 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