Commit 7d839c02 authored by Kevin Modzelewski's avatar Kevin Modzelewski

Add more asserts to aggressively enforce return conventions

You can't get the return value from a RewriteArgs without
looking at the return convention.  Debug mode will check the
return convention during the execution of rewrites.

Split "VALID_RETURN" into "HAS_RETURN" and "CAPI_RETURN" since some
places used it to mean either.

Hopefully this helps keep things clean.  There are a lot of places that
were implictly assuming a certain return convention, but now that they
have to explicitly assume it, the issues are more obvious.  Plus
they will get checked in the debug builds.

Also tried to fix things up while going through and doing this refactoring;
I think I found a number of issues.
parent 8c8e595a
...@@ -277,6 +277,8 @@ public: ...@@ -277,6 +277,8 @@ public:
assert(rewriter); assert(rewriter);
} }
Rewriter* getRewriter() { return rewriter; }
friend class Rewriter; friend class Rewriter;
friend class JitFragmentWriter; friend class JitFragmentWriter;
}; };
......
...@@ -908,7 +908,11 @@ Box* slotTpGetattrHookInternal(Box* self, BoxedString* name, GetattrRewriteArgs* ...@@ -908,7 +908,11 @@ Box* slotTpGetattrHookInternal(Box* self, BoxedString* name, GetattrRewriteArgs*
getattr = typeLookup(self->cls, _getattr_str, NULL); getattr = typeLookup(self->cls, _getattr_str, NULL);
if (getattr == NULL) { if (getattr == NULL) {
assert(!rewrite_args || !rewrite_args->out_success); if (rewrite_args) {
// Don't bother rewriting this case:
assert(!rewrite_args->isSuccessful());
rewrite_args = NULL;
}
/* No __getattr__ hook: use a simpler dispatcher */ /* No __getattr__ hook: use a simpler dispatcher */
self->cls->tp_getattro = slot_tp_getattro; self->cls->tp_getattro = slot_tp_getattro;
...@@ -931,13 +935,12 @@ Box* slotTpGetattrHookInternal(Box* self, BoxedString* name, GetattrRewriteArgs* ...@@ -931,13 +935,12 @@ Box* slotTpGetattrHookInternal(Box* self, BoxedString* name, GetattrRewriteArgs*
GetattrRewriteArgs grewrite_args(rewrite_args->rewriter, r_obj_cls, Location::any()); GetattrRewriteArgs grewrite_args(rewrite_args->rewriter, r_obj_cls, Location::any());
getattribute = typeLookup(self->cls, _getattribute_str, &grewrite_args); getattribute = typeLookup(self->cls, _getattribute_str, &grewrite_args);
if (!grewrite_args.out_success) if (!grewrite_args.isSuccessful())
rewrite_args = NULL; rewrite_args = NULL;
else if (getattribute) { else if (getattribute) {
assert(grewrite_args.out_return_convention == GetattrRewriteArgs::VALID_RETURN); r_getattribute = grewrite_args.getReturn(ReturnConvention::HAS_RETURN);
r_getattribute = grewrite_args.out_rtn;
} else { } else {
assert(grewrite_args.out_return_convention == GetattrRewriteArgs::NO_RETURN); grewrite_args.assertReturnConvention(ReturnConvention::NO_RETURN);
} }
} else { } else {
getattribute = typeLookup(self->cls, _getattribute_str, NULL); getattribute = typeLookup(self->cls, _getattribute_str, NULL);
...@@ -973,35 +976,38 @@ Box* slotTpGetattrHookInternal(Box* self, BoxedString* name, GetattrRewriteArgs* ...@@ -973,35 +976,38 @@ Box* slotTpGetattrHookInternal(Box* self, BoxedString* name, GetattrRewriteArgs*
throw e; throw e;
} }
grewrite_args.out_success = false; if (grewrite_args.isSuccessful()) {
grewrite_args.getReturn(); // to make the asserts happy
grewrite_args.clearReturn();
}
res = NULL; res = NULL;
} }
if (!grewrite_args.out_success) if (!grewrite_args.isSuccessful())
rewrite_args = NULL; rewrite_args = NULL;
else if (res) { else {
rewrite_args->out_rtn = grewrite_args.out_rtn; RewriterVar* rtn;
rewrite_args->out_return_convention = grewrite_args.out_return_convention; ReturnConvention return_convention;
} std::tie(rtn, return_convention) = grewrite_args.getReturn();
// Guarding here is a bit tricky, since we need to make sure that we call getattr if (return_convention == ReturnConvention::HAS_RETURN) {
// (or not) at the right times.
// Right now this section is a bit conservative.
if (rewrite_args) {
if (grewrite_args.out_return_convention == GetattrRewriteArgs::NO_RETURN) {
// Do nothing
} else if (grewrite_args.out_return_convention == GetattrRewriteArgs::VALID_RETURN) {
// TODO we should have a HAS_RETURN that takes out the NULL case
assert(res); assert(res);
if (res) rewrite_args->setReturn(rtn, ReturnConvention::HAS_RETURN);
grewrite_args.out_rtn->addGuardNotEq(0); return res;
else } else if (return_convention == ReturnConvention::NO_RETURN) {
grewrite_args.out_rtn->addGuard(0); assert(!res);
} else if (grewrite_args.out_return_convention == GetattrRewriteArgs::NOEXC_POSSIBLE) { } else if (return_convention == ReturnConvention::CAPI_RETURN) {
// TODO maybe we could handle this // If we get a CAPI return, we probably did a function call, and these guards
rewrite_args = NULL; // will probably just make the rewrite fail:
if (res) {
rtn->addGuardNotEq(0);
rewrite_args->setReturn(rtn, ReturnConvention::HAS_RETURN);
return res;
} else
rtn->addGuard(0);
} else { } else {
RELEASE_ASSERT(0, "%d", grewrite_args.out_return_convention); assert(return_convention == ReturnConvention::NOEXC_POSSIBLE);
rewrite_args = NULL;
} }
} }
} else { } else {
...@@ -1044,8 +1050,7 @@ Box* slotTpGetattrHookInternal(Box* self, BoxedString* name, GetattrRewriteArgs* ...@@ -1044,8 +1050,7 @@ Box* slotTpGetattrHookInternal(Box* self, BoxedString* name, GetattrRewriteArgs*
// doesn't exist. // doesn't exist.
if (res) { if (res) {
if (rewrite_args) assert(!rewrite_args); // should have been handled already
rewrite_args->out_success = true;
return res; return res;
} }
...@@ -1059,7 +1064,7 @@ Box* slotTpGetattrHookInternal(Box* self, BoxedString* name, GetattrRewriteArgs* ...@@ -1059,7 +1064,7 @@ Box* slotTpGetattrHookInternal(Box* self, BoxedString* name, GetattrRewriteArgs*
// - we have no way of signalling that "we didn't get an attribute this time but that may be different // - we have no way of signalling that "we didn't get an attribute this time but that may be different
// in future executions through the IC". // in future executions through the IC".
// I think this should only end up mattering anyway if the getattr site throws every single time. // I think this should only end up mattering anyway if the getattr site throws every single time.
CallRewriteArgs crewrite_args(rewrite_args->rewriter, rewrite_args->obj, rewrite_args->destination); CallattrRewriteArgs crewrite_args(rewrite_args->rewriter, rewrite_args->obj, rewrite_args->destination);
assert(PyString_CHECK_INTERNED(name) == SSTATE_INTERNED_IMMORTAL); assert(PyString_CHECK_INTERNED(name) == SSTATE_INTERNED_IMMORTAL);
crewrite_args.arg1 = rewrite_args->rewriter->loadConst((intptr_t)name, Location::forArg(1)); crewrite_args.arg1 = rewrite_args->rewriter->loadConst((intptr_t)name, Location::forArg(1));
...@@ -1067,11 +1072,10 @@ Box* slotTpGetattrHookInternal(Box* self, BoxedString* name, GetattrRewriteArgs* ...@@ -1067,11 +1072,10 @@ Box* slotTpGetattrHookInternal(Box* self, BoxedString* name, GetattrRewriteArgs*
NULL, NULL, NULL, NULL); NULL, NULL, NULL, NULL);
assert(res || S == CAPI); assert(res || S == CAPI);
if (!crewrite_args.out_success) if (!crewrite_args.isSuccessful())
rewrite_args = NULL; rewrite_args = NULL;
else { else {
rewrite_args->out_rtn = crewrite_args.out_rtn; rewrite_args->setReturn(crewrite_args.getReturn());
rewrite_args->out_return_convention = GetattrRewriteArgs::VALID_RETURN;
} }
} else { } else {
// TODO: we already fetched the getattr attribute, it would be faster to call it rather than do // TODO: we already fetched the getattr attribute, it would be faster to call it rather than do
...@@ -1084,8 +1088,6 @@ Box* slotTpGetattrHookInternal(Box* self, BoxedString* name, GetattrRewriteArgs* ...@@ -1084,8 +1088,6 @@ Box* slotTpGetattrHookInternal(Box* self, BoxedString* name, GetattrRewriteArgs*
assert(res || S == CAPI); assert(res || S == CAPI);
} }
if (rewrite_args)
rewrite_args->out_success = true;
return res; return res;
} }
// Force instantiation of the template // Force instantiation of the template
......
...@@ -569,16 +569,15 @@ Box* getattrFuncInternal(BoxedFunctionBase* func, CallRewriteArgs* rewrite_args, ...@@ -569,16 +569,15 @@ Box* getattrFuncInternal(BoxedFunctionBase* func, CallRewriteArgs* rewrite_args,
GetattrRewriteArgs grewrite_args(rewrite_args->rewriter, rewrite_args->arg1, rewrite_args->destination); GetattrRewriteArgs grewrite_args(rewrite_args->rewriter, rewrite_args->arg1, rewrite_args->destination);
rtn = getattrInternal<CAPI>(obj, str, &grewrite_args); rtn = getattrInternal<CAPI>(obj, str, &grewrite_args);
// TODO could make the return valid in the NOEXC_POSSIBLE case via a helper // TODO could make the return valid in the NOEXC_POSSIBLE case via a helper
if (!grewrite_args.out_success || grewrite_args.out_return_convention == GetattrRewriteArgs::NOEXC_POSSIBLE) if (!grewrite_args.isSuccessful())
rewrite_args = NULL; rewrite_args = NULL;
else { else {
if (!rtn && !PyErr_Occurred()) { ReturnConvention return_convention;
assert(grewrite_args.out_return_convention == GetattrRewriteArgs::NO_RETURN); std::tie(r_rtn, return_convention) = grewrite_args.getReturn();
// Convert to NOEXC_POSSIBLE:
if (return_convention == ReturnConvention::NO_RETURN)
r_rtn = rewrite_args->rewriter->loadConst(0); r_rtn = rewrite_args->rewriter->loadConst(0);
} else {
assert(grewrite_args.out_return_convention == GetattrRewriteArgs::VALID_RETURN);
r_rtn = grewrite_args.out_rtn;
}
} }
} else { } else {
rtn = getattrInternal<CAPI>(obj, str, NULL); rtn = getattrInternal<CAPI>(obj, str, NULL);
...@@ -681,16 +680,15 @@ Box* hasattrFuncInternal(BoxedFunctionBase* func, CallRewriteArgs* rewrite_args, ...@@ -681,16 +680,15 @@ Box* hasattrFuncInternal(BoxedFunctionBase* func, CallRewriteArgs* rewrite_args,
if (rewrite_args) { if (rewrite_args) {
GetattrRewriteArgs grewrite_args(rewrite_args->rewriter, rewrite_args->arg1, rewrite_args->destination); GetattrRewriteArgs grewrite_args(rewrite_args->rewriter, rewrite_args->arg1, rewrite_args->destination);
rtn = getattrInternal<CAPI>(obj, str, &grewrite_args); rtn = getattrInternal<CAPI>(obj, str, &grewrite_args);
if (!grewrite_args.out_success || grewrite_args.out_return_convention == GetattrRewriteArgs::NOEXC_POSSIBLE) if (!grewrite_args.isSuccessful())
rewrite_args = NULL; rewrite_args = NULL;
else { else {
if (!rtn && !PyErr_Occurred()) { ReturnConvention return_convention;
assert(grewrite_args.out_return_convention == GetattrRewriteArgs::NO_RETURN); std::tie(r_rtn, return_convention) = grewrite_args.getReturn();
// Convert to NOEXC_POSSIBLE:
if (return_convention == ReturnConvention::NO_RETURN)
r_rtn = rewrite_args->rewriter->loadConst(0); r_rtn = rewrite_args->rewriter->loadConst(0);
} else {
assert(grewrite_args.out_return_convention == GetattrRewriteArgs::VALID_RETURN);
r_rtn = grewrite_args.out_rtn;
}
} }
} else { } else {
rtn = getattrInternal<CAPI>(obj, str, NULL); rtn = getattrInternal<CAPI>(obj, str, NULL);
......
...@@ -32,15 +32,20 @@ BoxedClass* classobj_cls, *instance_cls; ...@@ -32,15 +32,20 @@ BoxedClass* classobj_cls, *instance_cls;
static Box* classLookup(BoxedClassobj* cls, BoxedString* attr, GetattrRewriteArgs* rewrite_args = NULL) { static Box* classLookup(BoxedClassobj* cls, BoxedString* attr, GetattrRewriteArgs* rewrite_args = NULL) {
if (rewrite_args) if (rewrite_args)
assert(!rewrite_args->out_success); assert(!rewrite_args->isSuccessful());
Box* r = cls->getattr(attr, rewrite_args); Box* r = cls->getattr(attr, rewrite_args);
if (r) if (r) {
if (rewrite_args)
rewrite_args->assertReturnConvention(ReturnConvention::HAS_RETURN);
return r; return r;
}
if (rewrite_args) { if (rewrite_args) {
// abort rewriting because we currenly don't guard the particular 'bases' hierarchy if (rewrite_args->isSuccessful()) {
rewrite_args->out_success = false; rewrite_args->getReturn(); // just to make the asserts happy
rewrite_args->clearReturn();
}
rewrite_args = NULL; rewrite_args = NULL;
} }
...@@ -328,62 +333,71 @@ Box* classobjRepr(Box* _obj) { ...@@ -328,62 +333,71 @@ Box* classobjRepr(Box* _obj) {
// Analogous to CPython's instance_getattr2 // Analogous to CPython's instance_getattr2
static Box* instanceGetattributeSimple(BoxedInstance* inst, BoxedString* attr_str, static Box* instanceGetattributeSimple(BoxedInstance* inst, BoxedString* attr_str,
GetattrRewriteArgs* rewriter_args = NULL) { GetattrRewriteArgs* rewrite_args = NULL) {
Box* r = inst->getattr(attr_str, rewriter_args); Box* r = inst->getattr(attr_str, rewrite_args);
if (r) if (r) {
if (rewrite_args)
rewrite_args->assertReturnConvention(ReturnConvention::HAS_RETURN);
return r; return r;
}
RewriterVar* r_inst = NULL; RewriterVar* r_inst = NULL;
RewriterVar* r_inst_cls = NULL; RewriterVar* r_inst_cls = NULL;
if (rewriter_args) { if (rewrite_args) {
if (!rewriter_args->out_success) if (!rewrite_args->isSuccessful())
rewriter_args = NULL; rewrite_args = NULL;
else { else {
rewriter_args->out_success = false; rewrite_args->assertReturnConvention(ReturnConvention::NO_RETURN);
r_inst = rewriter_args->obj; rewrite_args->clearReturn();
r_inst = rewrite_args->obj;
r_inst_cls = r_inst->getAttr(offsetof(BoxedInstance, inst_cls)); r_inst_cls = r_inst->getAttr(offsetof(BoxedInstance, inst_cls));
} }
} }
GetattrRewriteArgs grewriter_inst_args(rewriter_args ? rewriter_args->rewriter : NULL, r_inst_cls, GetattrRewriteArgs grewriter_inst_args(rewrite_args ? rewrite_args->rewriter : NULL, r_inst_cls,
rewriter_args ? rewriter_args->rewriter->getReturnDestination() rewrite_args ? rewrite_args->rewriter->getReturnDestination() : Location());
: Location()); r = classLookup(inst->inst_cls, attr_str, rewrite_args ? &grewriter_inst_args : NULL);
r = classLookup(inst->inst_cls, attr_str, rewriter_args ? &grewriter_inst_args : NULL); if (!grewriter_inst_args.isSuccessful())
if (!grewriter_inst_args.out_success) rewrite_args = NULL;
rewriter_args = NULL;
else
assert(grewriter_inst_args.out_return_convention == GetattrRewriteArgs::VALID_RETURN);
if (r) { if (r) {
Box* rtn = processDescriptor(r, inst, inst->inst_cls); Box* rtn = processDescriptor(r, inst, inst->inst_cls);
if (rewriter_args) { if (rewrite_args) {
RewriterVar* r_rtn = rewriter_args->rewriter->call(true, (void*)processDescriptor, RewriterVar* r_rtn = rewrite_args->rewriter->call(
grewriter_inst_args.out_rtn, r_inst, r_inst_cls); true, (void*)processDescriptor, grewriter_inst_args.getReturn(ReturnConvention::HAS_RETURN), r_inst,
rewriter_args->out_rtn = r_rtn; r_inst_cls);
rewriter_args->out_success = true; rewrite_args->setReturn(r_rtn, ReturnConvention::HAS_RETURN);
rewriter_args->out_return_convention = GetattrRewriteArgs::VALID_RETURN;
} }
return rtn; return rtn;
} }
if (rewrite_args)
grewriter_inst_args.assertReturnConvention(ReturnConvention::NO_RETURN);
return NULL; return NULL;
} }
static Box* instanceGetattributeWithFallback(BoxedInstance* inst, BoxedString* attr_str, static Box* instanceGetattributeWithFallback(BoxedInstance* inst, BoxedString* attr_str,
GetattrRewriteArgs* rewriter_args = NULL) { GetattrRewriteArgs* rewrite_args = NULL) {
Box* attr_obj = instanceGetattributeSimple(inst, attr_str, rewriter_args); Box* attr_obj = instanceGetattributeSimple(inst, attr_str, rewrite_args);
if (attr_obj) { if (attr_obj) {
if (rewrite_args && rewrite_args->isSuccessful())
rewrite_args->assertReturnConvention(
ReturnConvention::HAS_RETURN); // otherwise need to guard on the success
return attr_obj; return attr_obj;
} }
if (rewriter_args) { if (rewrite_args) {
if (!rewriter_args->out_success) if (!rewrite_args->isSuccessful())
rewriter_args = NULL; rewrite_args = NULL;
else else {
rewriter_args->out_success = false; rewrite_args->assertReturnConvention(ReturnConvention::NO_RETURN);
rewrite_args->clearReturn();
}
// abort rewriting for now // abort rewriting for now
rewriter_args = NULL; rewrite_args = NULL;
} }
static BoxedString* getattr_str = internStringImmortal("__getattr__"); static BoxedString* getattr_str = internStringImmortal("__getattr__");
...@@ -398,7 +412,7 @@ static Box* instanceGetattributeWithFallback(BoxedInstance* inst, BoxedString* a ...@@ -398,7 +412,7 @@ static Box* instanceGetattributeWithFallback(BoxedInstance* inst, BoxedString* a
} }
static Box* _instanceGetattribute(Box* _inst, BoxedString* attr_str, bool raise_on_missing, static Box* _instanceGetattribute(Box* _inst, BoxedString* attr_str, bool raise_on_missing,
GetattrRewriteArgs* rewriter_args = NULL) { GetattrRewriteArgs* rewrite_args = NULL) {
RELEASE_ASSERT(_inst->cls == instance_cls, ""); RELEASE_ASSERT(_inst->cls == instance_cls, "");
BoxedInstance* inst = static_cast<BoxedInstance*>(_inst); BoxedInstance* inst = static_cast<BoxedInstance*>(_inst);
...@@ -411,7 +425,7 @@ static Box* _instanceGetattribute(Box* _inst, BoxedString* attr_str, bool raise_ ...@@ -411,7 +425,7 @@ static Box* _instanceGetattribute(Box* _inst, BoxedString* attr_str, bool raise_
return inst->inst_cls; return inst->inst_cls;
} }
Box* attr = instanceGetattributeWithFallback(inst, attr_str, rewriter_args); Box* attr = instanceGetattributeWithFallback(inst, attr_str, rewrite_args);
if (attr) { if (attr) {
return attr; return attr;
} else if (!raise_on_missing) { } else if (!raise_on_missing) {
......
...@@ -92,6 +92,7 @@ static thread_local Timer per_thread_cleanup_timer(-1); ...@@ -92,6 +92,7 @@ static thread_local Timer per_thread_cleanup_timer(-1);
#ifndef NDEBUG #ifndef NDEBUG
static __thread bool in_cleanup_code = false; static __thread bool in_cleanup_code = false;
#endif #endif
static __thread bool is_unwinding = false;
extern "C" { extern "C" {
...@@ -567,6 +568,7 @@ static inline void unwind_loop(ExcInfo* exc_data) { ...@@ -567,6 +568,7 @@ static inline void unwind_loop(ExcInfo* exc_data) {
#if STAT_TIMERS #if STAT_TIMERS
pyston::StatTimer::finishOverride(); pyston::StatTimer::finishOverride();
#endif #endif
pyston::is_unwinding = false;
} }
static_assert(THREADING_USE_GIL, "have to make the unwind session usage in this file thread safe!"); static_assert(THREADING_USE_GIL, "have to make the unwind session usage in this file thread safe!");
// there is a python unwinding implementation detail leaked // there is a python unwinding implementation detail leaked
...@@ -610,6 +612,10 @@ void std::terminate() noexcept { ...@@ -610,6 +612,10 @@ void std::terminate() noexcept {
RELEASE_ASSERT(0, "std::terminate() called!"); RELEASE_ASSERT(0, "std::terminate() called!");
} }
bool std::uncaught_exception() noexcept {
return pyston::is_unwinding;
}
// wrong type signature, but that's okay, it's extern "C" // wrong type signature, but that's okay, it's extern "C"
extern "C" void __gxx_personality_v0() { extern "C" void __gxx_personality_v0() {
RELEASE_ASSERT(0, "__gxx_personality_v0 should never get called"); RELEASE_ASSERT(0, "__gxx_personality_v0 should never get called");
...@@ -684,9 +690,13 @@ extern "C" void __cxa_throw(void* exc_obj, std::type_info* tinfo, void (*dtor)(v ...@@ -684,9 +690,13 @@ extern "C" void __cxa_throw(void* exc_obj, std::type_info* tinfo, void (*dtor)(v
pyston::ExcInfo* exc_data = (pyston::ExcInfo*)exc_obj; pyston::ExcInfo* exc_data = (pyston::ExcInfo*)exc_obj;
checkExcInfo(exc_data); checkExcInfo(exc_data);
ASSERT(!pyston::is_unwinding, "We don't support throwing exceptions in destructors!");
pyston::is_unwinding = true;
#if STAT_TIMERS #if STAT_TIMERS
pyston::StatTimer::overrideCounter(unwinding_stattimer); pyston::StatTimer::overrideCounter(unwinding_stattimer);
#endif #endif
// let unwinding.cpp know we've started unwinding // let unwinding.cpp know we've started unwinding
pyston::logException(exc_data); pyston::logException(exc_data);
pyston::unwind(exc_data); pyston::unwind(exc_data);
......
This diff is collapsed.
...@@ -141,8 +141,9 @@ enum LookupScope { ...@@ -141,8 +141,9 @@ enum LookupScope {
INST_ONLY = 2, INST_ONLY = 2,
CLASS_OR_INST = 3, CLASS_OR_INST = 3,
}; };
struct CallattrRewriteArgs;
template <ExceptionStyle S> template <ExceptionStyle S>
Box* callattrInternal(Box* obj, BoxedString* attr, LookupScope, CallRewriteArgs* rewrite_args, ArgPassSpec argspec, Box* callattrInternal(Box* obj, BoxedString* attr, LookupScope, CallattrRewriteArgs* rewrite_args, ArgPassSpec argspec,
Box* arg1, Box* arg2, Box* arg3, Box** args, Box* arg1, Box* arg2, Box* arg3, Box** args,
const std::vector<BoxedString*>* keyword_names) noexcept(S == CAPI); const std::vector<BoxedString*>* keyword_names) noexcept(S == CAPI);
extern "C" void delattr_internal(Box* obj, BoxedString* attr, bool allow_custom, DelattrRewriteArgs* rewrite_args); extern "C" void delattr_internal(Box* obj, BoxedString* attr, bool allow_custom, DelattrRewriteArgs* rewrite_args);
......
This diff is collapsed.
...@@ -905,13 +905,12 @@ static Box* typeCallInner(CallRewriteArgs* rewrite_args, ArgPassSpec argspec, Bo ...@@ -905,13 +905,12 @@ static Box* typeCallInner(CallRewriteArgs* rewrite_args, ArgPassSpec argspec, Bo
GetattrRewriteArgs grewrite_args(rewrite_args->rewriter, r_ccls, rewrite_args->destination); GetattrRewriteArgs grewrite_args(rewrite_args->rewriter, r_ccls, rewrite_args->destination);
// TODO: if tp_new != Py_CallPythonNew, call that instead? // TODO: if tp_new != Py_CallPythonNew, call that instead?
new_attr = typeLookup(cls, new_str, &grewrite_args); new_attr = typeLookup(cls, new_str, &grewrite_args);
assert(new_attr);
if (!grewrite_args.out_success) if (!grewrite_args.isSuccessful())
rewrite_args = NULL; rewrite_args = NULL;
else { else {
assert(new_attr); r_new = grewrite_args.getReturn(ReturnConvention::HAS_RETURN);
assert(grewrite_args.out_return_convention = GetattrRewriteArgs::VALID_RETURN);
r_new = grewrite_args.out_rtn;
r_new->addGuard((intptr_t)new_attr); r_new->addGuard((intptr_t)new_attr);
} }
...@@ -1049,15 +1048,14 @@ static Box* typeCallInner(CallRewriteArgs* rewrite_args, ArgPassSpec argspec, Bo ...@@ -1049,15 +1048,14 @@ static Box* typeCallInner(CallRewriteArgs* rewrite_args, ArgPassSpec argspec, Bo
GetattrRewriteArgs grewrite_args(rewrite_args->rewriter, r_ccls, rewrite_args->destination); GetattrRewriteArgs grewrite_args(rewrite_args->rewriter, r_ccls, rewrite_args->destination);
init_attr = typeLookup(cls, init_str, &grewrite_args); init_attr = typeLookup(cls, init_str, &grewrite_args);
if (!grewrite_args.out_success) if (!grewrite_args.isSuccessful())
rewrite_args = NULL; rewrite_args = NULL;
else { else {
if (init_attr) { if (init_attr) {
assert(grewrite_args.out_return_convention = GetattrRewriteArgs::VALID_RETURN); r_init = grewrite_args.getReturn(ReturnConvention::HAS_RETURN);
r_init = grewrite_args.out_rtn;
r_init->addGuard((intptr_t)init_attr); r_init->addGuard((intptr_t)init_attr);
} else { } else {
assert(grewrite_args.out_return_convention = GetattrRewriteArgs::NO_RETURN); grewrite_args.assertReturnConvention(ReturnConvention::NO_RETURN);
} }
} }
} else { } else {
......
class C(object):
def __add__(self, rhs):
if rhs == 50:
return NotImplemented
return 0
__eq__ = __add__
def f():
c = C()
for i in xrange(100):
try:
print i, c + i
except TypeError as e:
print e
f()
def f2():
c = C()
for i in xrange(100):
try:
print i, c == i
except TypeError as e:
print e
f2()
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