Commit 01fa0faf authored by Kevin Modzelewski's avatar Kevin Modzelewski

Fix bug around implicit calls to __nonzero__

For those calls (such as in conditionals and "not x" expressions),
if for some reason we didn't think the object could be converted to bool,
we would crash in codegen.  This could happen if we knew that the type was a
builtin type (ex: None, or dict) and we hadn't yet implemented __nonzero__.

Unrelated, but implement isinstance(obj, (tuple_of_classes,)).  This also
lets us use multiple exception types in a single except statement.
parent 09d13a5f
......@@ -712,6 +712,8 @@ if _exists("fork"):
return p.stdin, p.stdout
__all__.append("popen4")
# Pyston change: disable custom pickle-registration for now
"""
import copy_reg as _copy_reg
def _make_stat_result(tup, dict):
......@@ -738,3 +740,4 @@ try:
_make_statvfs_result)
except NameError: # statvfs_result may not exist
pass
"""
......@@ -280,12 +280,15 @@ def _subx(pattern, template):
# register myself for pickling
# Pyston change: disable the pickle-registration for now
"""
import copy_reg
def _pickle(p):
return _compile, (p.pattern, p.flags)
copy_reg.pickle(_pattern_type, _pickle, _compile)
"""
# --------------------------------------------------------------------
# experimental stuff (see python-dev discussions for details)
......
......@@ -878,7 +878,8 @@ private:
operand->decvref(emitter);
llvm::Value* v = rtn->getValue();
assert(v->getType() == g.i1);
ASSERT(v->getType() == g.i1, "%s %s", operand->getType()->debugName().c_str(),
rtn->getType()->debugName().c_str());
llvm::Value* negated = emitter.getBuilder()->CreateNot(v);
rtn->decvref(emitter);
return new ConcreteCompilerVariable(BOOL, negated, true);
......@@ -1769,7 +1770,8 @@ private:
// ASSERT(val->getType() == BOOL, "%s", val->getType()->debugName().c_str());
ConcreteCompilerVariable* nonzero = val->nonzero(emitter, getOpInfoForNode(node, exc_info));
assert(nonzero->getType() == BOOL);
ASSERT(nonzero->getType() == BOOL, "%s %s", val->getType()->debugName().c_str(),
nonzero->getType()->debugName().c_str());
val->decvref(emitter);
llvm::Value* llvm_nonzero = nonzero->getValue();
......
......@@ -311,9 +311,6 @@ Box* sortedList(Box* obj) {
}
Box* isinstance_func(Box* obj, Box* cls) {
assert(cls->cls == type_cls);
BoxedClass* ccls = static_cast<BoxedClass*>(cls);
return boxBool(isinstance(obj, cls, 0));
}
......
......@@ -166,6 +166,10 @@ Box* dictContains(BoxedDict* self, Box* k) {
return boxBool(self->d.count(k) != 0);
}
Box* dictNonzero(BoxedDict* self) {
return boxBool(self->d.size());
}
extern "C" Box* dictNew(Box* _cls, BoxedTuple* args, BoxedDict* kwargs) {
if (!isSubclass(_cls->cls, type_cls))
raiseExcHelper(TypeError, "dict.__new__(X): X is not a type object (%s)", getTypeName(_cls)->c_str());
......@@ -266,6 +270,8 @@ void setupDict() {
dict_cls->giveAttr("__setitem__", new BoxedFunction(boxRTFunction((void*)dictSetitem, NONE, 3)));
dict_cls->giveAttr("__contains__", new BoxedFunction(boxRTFunction((void*)dictContains, BOXED_BOOL, 2)));
dict_cls->giveAttr("__nonzero__", new BoxedFunction(boxRTFunction((void*)dictNonzero, BOXED_BOOL, 1)));
dict_cls->freeze();
dict_iterator_cls->giveAttr("__name__", boxStrConstant("dictiterator"));
......
......@@ -292,6 +292,16 @@ Box* longPow(BoxedLong* v1, Box* _v2) {
return r;
}
Box* longNonzero(BoxedLong* self) {
if (!isSubclass(self->cls, long_cls))
raiseExcHelper(TypeError, "descriptor '__pow__' requires a 'long' object but received a '%s'",
getTypeName(self)->c_str());
if (mpz_cmp_si(self->n, 0) == 0)
return False;
return True;
}
void setupLong() {
long_cls->giveAttr("__name__", boxStrConstant("long"));
......@@ -313,6 +323,8 @@ void setupLong() {
long_cls->giveAttr("__repr__", new BoxedFunction(boxRTFunction((void*)longRepr, STR, 1)));
long_cls->giveAttr("__str__", new BoxedFunction(boxRTFunction((void*)longStr, STR, 1)));
long_cls->giveAttr("__nonzero__", new BoxedFunction(boxRTFunction((void*)longNonzero, BOXED_BOOL, 1)));
long_cls->freeze();
}
}
......@@ -1585,6 +1585,15 @@ extern "C" BoxedString* strOrNull(Box* obj) {
extern "C" bool isinstance(Box* obj, Box* cls, int64_t flags) {
bool false_on_noncls = (flags & 0x1);
if (cls->cls == tuple_cls) {
auto t = static_cast<BoxedTuple*>(cls);
for (auto c : t->elts) {
if (isinstance(obj, c, flags))
return true;
}
return false;
}
if (!false_on_noncls) {
assert(cls->cls == type_cls);
} else {
......
......@@ -198,6 +198,10 @@ Box* setContains(BoxedSet* self, Box* v) {
return boxBool(self->s.count(v) != 0);
}
Box* setNonzero(BoxedSet* self) {
return boxBool(self->s.size());
}
} // namespace set
......@@ -265,6 +269,9 @@ void setupSet() {
set_cls->giveAttr("__contains__", new BoxedFunction(boxRTFunction((void*)setContains, BOXED_BOOL, 2)));
frozenset_cls->giveAttr("__contains__", set_cls->getattr("__contains__"));
set_cls->giveAttr("__nonzero__", new BoxedFunction(boxRTFunction((void*)setNonzero, BOXED_BOOL, 1)));
frozenset_cls->giveAttr("__nonzero__", set_cls->getattr("__nonzero__"));
set_cls->giveAttr("add", new BoxedFunction(boxRTFunction((void*)setAdd, NONE, 2)));
set_cls->freeze();
......
......@@ -349,6 +349,10 @@ extern "C" Box* noneHash(Box* v) {
return boxInt(819239); // chosen randomly
}
extern "C" Box* noneNonzero(Box* v) {
return False;
}
extern "C" BoxedString* functionRepr(BoxedFunction* v) {
// TODO there has to be a better way
if (v == repr_obj)
......@@ -479,6 +483,13 @@ Box* typeRepr(BoxedClass* self) {
}
}
Box* typeHash(BoxedClass* self) {
assert(isSubclass(self->cls, type_cls));
// This is how CPython defines it; seems reasonable enough:
return boxInt(reinterpret_cast<intptr_t>(self) >> 4);
}
Box* moduleRepr(BoxedModule* m) {
assert(m->cls == module_cls);
......@@ -694,12 +705,14 @@ void setupRuntime() {
type_cls->giveAttr("__new__", new BoxedFunction(boxRTFunction((void*)typeNew, UNKNOWN, 2)));
type_cls->giveAttr("__repr__", new BoxedFunction(boxRTFunction((void*)typeRepr, STR, 1)));
type_cls->giveAttr("__str__", type_cls->getattr("__repr__"));
type_cls->giveAttr("__hash__", new BoxedFunction(boxRTFunction((void*)typeHash, BOXED_INT, 1)));
type_cls->freeze();
none_cls->giveAttr("__name__", boxStrConstant("NoneType"));
none_cls->giveAttr("__repr__", new BoxedFunction(boxRTFunction((void*)noneRepr, STR, 1)));
none_cls->giveAttr("__str__", none_cls->getattr("__repr__"));
none_cls->giveAttr("__hash__", new BoxedFunction(boxRTFunction((void*)noneHash, UNKNOWN, 1)));
none_cls->giveAttr("__nonzero__", new BoxedFunction(boxRTFunction((void*)noneNonzero, BOXED_BOOL, 1)));
none_cls->freeze();
module_cls->giveAttr("__name__", boxStrConstant("module"));
......
# Regression test: we rely internally on CompilerType.nonzero() always returning a BOOL,
# in at least these two cases.
def f(x):
if x:
pass
print not x
f(None)
f({})
f([])
f({1})
f(())
f("")
f(0.0)
f(1L)
......@@ -32,3 +32,7 @@ print zip([1, 2, 3, 0], ["one", "two", "three"])
print filter(lambda x: x % 2, xrange(20))
print type(enumerate([]))
print list(enumerate(xrange(5, 10)))
print isinstance(1, int)
print isinstance(1, (float, int))
print isinstance(1, (float, (), (int, 3), 4))
# expected: fail
# - exceptions
# - with statements
class TestException(Exception):
pass
......
......@@ -67,3 +67,10 @@ def f11():
except TypeError, e:
print e
f11()
def f12():
try:
raise IndexError
except (KeyError, IndexError), e:
print e
f12()
# expected: fail
# - wip
# Simple opt parse test, taken from the optparse.py docstring:
from optparse import OptionParser
parser = OptionParser()
parser.add_option("-f", "--file", dest="filename",
help="write report to FILE", metavar="FILE")
parser.add_option("-q", "--quiet",
action="store_false", dest="verbose", default=True,
help="don't print status messages to stdout")
(options, args) = parser.parse_args(['test', '--file=/dev/null', 'hello world'])
print options, args
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