Commit d737295f authored by Stefan Behnel's avatar Stefan Behnel

generate the expected (fast) code for isinstance() checks on builtin types

parent 9215510d
...@@ -1839,6 +1839,59 @@ class OptimizeBuiltinCalls(Visitor.EnvTransform): ...@@ -1839,6 +1839,59 @@ class OptimizeBuiltinCalls(Visitor.EnvTransform):
is_temp = False) is_temp = False)
return ExprNodes.CastNode(node, PyrexTypes.py_object_type) return ExprNodes.CastNode(node, PyrexTypes.py_object_type)
Py_type_check_func_type = PyrexTypes.CFuncType(
PyrexTypes.c_bint_type, [
PyrexTypes.CFuncTypeArg("arg", PyrexTypes.py_object_type, None)
])
def _handle_simple_function_isinstance(self, node, pos_args):
"""Replace isinstance() checks against builtin types by the
corresponding C-API call.
"""
if len(pos_args) != 2:
return node
arg, types = pos_args
temp = None
if isinstance(types, ExprNodes.TupleNode):
types = types.args
arg = temp = UtilNodes.ResultRefNode(arg)
elif types.type is Builtin.type_type:
types = [types]
else:
return node
tests = []
test_nodes = []
env = self.current_env()
for test_type_node in types:
if not test_type_node.entry:
return node
entry = env.lookup(test_type_node.entry.name)
if not entry or not entry.type or not entry.type.is_builtin_type:
return node
type_check_function = entry.type.type_check_function(exact=False)
if not type_check_function:
return node
if type_check_function not in tests:
tests.append(type_check_function)
test_nodes.append(
ExprNodes.PythonCapiCallNode(
test_type_node.pos, type_check_function, self.Py_type_check_func_type,
args = [arg],
is_temp = True,
))
def join_with_or(a,b, make_binop_node=ExprNodes.binop_node):
or_node = make_binop_node(node.pos, 'or', a, b)
or_node.type = PyrexTypes.c_bint_type
or_node.is_temp = True
return or_node
test_node = reduce(join_with_or, test_nodes).coerce_to(node.type, env)
if temp is not None:
test_node = UtilNodes.EvalWithTempExprNode(temp, test_node)
return test_node
### special methods ### special methods
Pyx_tp_new_func_type = PyrexTypes.CFuncType( Pyx_tp_new_func_type = PyrexTypes.CFuncType(
......
cimport cython
cdef class A: cdef class A:
pass pass
def test_all(): @cython.test_assert_path_exists('//SimpleCallNode//SimpleCallNode')
@cython.test_fail_if_path_exists('//SimpleCallNode//PythonCapiCallNode',
'//PythonCapiCallNode//SimpleCallNode')
def test_non_optimised():
""" """
>>> test_all() >>> test_non_optimised()
True
"""
# Non-optimized
cdef object foo = A
assert isinstance(A(), foo)
assert isinstance(0, (int, long))
assert not isinstance(u"xyz", (int, long))
assert isinstance(complex(), complex) # FIXME: this should be optimised, too!
return True
@cython.test_assert_path_exists('//PythonCapiCallNode',
'//PythonCapiCallNode//SimpleCallNode')
@cython.test_fail_if_path_exists('//SimpleCallNode//SimpleCallNode',
'//SimpleCallNode//PythonCapiCallNode')
def test_optimised():
"""
>>> test_optimised()
True True
""" """
new_type = type('a',(),{}) new_type = type('a',(),{})
...@@ -14,23 +37,39 @@ def test_all(): ...@@ -14,23 +37,39 @@ def test_all():
assert isinstance(int(), int) assert isinstance(int(), int)
assert isinstance(long(), long) assert isinstance(long(), long)
assert isinstance(float(), float) assert isinstance(float(), float)
assert isinstance(complex(), complex)
assert isinstance(bytes(), bytes) assert isinstance(bytes(), bytes)
assert isinstance(str(), str) assert isinstance(str(), str)
assert isinstance(unicode(), unicode) assert isinstance(unicode(), unicode)
assert isinstance(tuple(), tuple) assert isinstance(tuple(), tuple)
assert isinstance(list(), list) assert isinstance(list(), list)
assert isinstance(dict(), dict) assert isinstance(dict(), dict)
# if py_ver > (2, 3): assert isinstance(set(), set)
# assert isinstance(set(), set)
assert isinstance(slice(0), slice) assert isinstance(slice(0), slice)
assert isinstance(A, type)
assert isinstance(A(), A)
assert not isinstance(u"foo", int) assert not isinstance(u"foo", int)
assert isinstance(A, type)
return True
# Non-optimized @cython.test_assert_path_exists('//PythonCapiCallNode')
cdef object foo = A @cython.test_fail_if_path_exists('//SimpleCallNode//SimpleCallNode',
assert isinstance(A(), foo) '//SimpleCallNode//PythonCapiCallNode',
assert isinstance(0, (int, long)) '//TupleNode//NameNode')
assert not isinstance(u"xyz", (int, long)) def test_optimised_tuple():
"""
>>> test_optimised_tuple()
True
"""
assert isinstance(bool(), (bool, int, long, float, bytes, str, unicode, tuple, list, dict, set, slice))
assert isinstance(int(), (bool, int, long, float, bytes, str, unicode, tuple, list, dict, set, slice))
assert isinstance(list(), (bool, int, long, float, bytes, str, unicode, tuple, list, dict, set, slice))
return True
@cython.test_assert_path_exists('//SimpleCallNode//SimpleCallNode')
@cython.test_fail_if_path_exists('//SimpleCallNode//PythonCapiCallNode',
'//PythonCapiCallNode//SimpleCallNode')
def test_custom():
"""
>>> test_custom()
True
"""
assert isinstance(A(), A)
return True return True
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