diff options
author | da-woods <dw-git@d-woods.co.uk> | 2021-08-31 21:04:12 +0100 |
---|---|---|
committer | GitHub <noreply@github.com> | 2021-08-31 22:04:12 +0200 |
commit | bad93a3ab3b698ec4106dbf03e1a103e2582d003 (patch) | |
tree | 96eee1fee63a7ad2a708962ecb33a7cac8106a22 | |
parent | 26e544c7b765ceb77edfe923ac9ca29aaa239d12 (diff) | |
download | cython-bad93a3ab3b698ec4106dbf03e1a103e2582d003.tar.gz |
Deduplicate tuples containing IdentifierStringNode (GH-4353)
Compiling ExprNodes.py was creating hundreds of tuples containing ("self", "env") for example, because it wasn't able to match and deduplicate them.
-rw-r--r-- | Cython/Compiler/ExprNodes.py | 5 | ||||
-rw-r--r-- | tests/run/tuple_constants.pyx | 29 |
2 files changed, 34 insertions, 0 deletions
diff --git a/Cython/Compiler/ExprNodes.py b/Cython/Compiler/ExprNodes.py index 98a41f9b0..a2ccc465c 100644 --- a/Cython/Compiler/ExprNodes.py +++ b/Cython/Compiler/ExprNodes.py @@ -209,6 +209,11 @@ def make_dedup_key(outer_type, item_nodes): # For constants, look at the Python value type if we don't know the concrete Cython type. else (node.type, node.constant_result, type(node.constant_result) if node.type is py_object_type else None) if node.has_constant_result() + # IdentifierStringNode doesn't usually have a "constant_result" set because: + # 1. it doesn't usually have unicode_value + # 2. it's often created later in the compilation process after ConstantFolding + # but should be cacheable + else (node.type, node.value, node.unicode_value, "IdentifierStringNode") if isinstance(node, IdentifierStringNode) else None # something we cannot handle => short-circuit below for node in item_nodes ] diff --git a/tests/run/tuple_constants.pyx b/tests/run/tuple_constants.pyx index 55992d933..f60d5d818 100644 --- a/tests/run/tuple_constants.pyx +++ b/tests/run/tuple_constants.pyx @@ -2,6 +2,9 @@ cimport cython module_level_tuple = (1,2,3) +second_module_level_tuple = (1,2,3) # should be deduplicated to be the same as the first +string_module_level_tuple = ("1", "2") +string_module_level_tuple2 = ("1", "2") def return_module_level_tuple(): """ @@ -10,6 +13,32 @@ def return_module_level_tuple(): """ return module_level_tuple +def test_deduplicated_tuples(): + """ + >>> test_deduplicated_tuples() + """ + assert (module_level_tuple is second_module_level_tuple) + assert (module_level_tuple is (1,2,3)) # also deduplicated with a function tuple + assert (string_module_level_tuple is string_module_level_tuple2) + assert (string_module_level_tuple is ("1", "2")) + +def func1(arg1, arg2): + pass + +def func2(arg1, arg2): + pass + +def test_deduplicated_args(): + """ + >>> test_deduplicated_args() + """ + # This is a concern because in large modules *a lot* of similar code objects + # are generated often with the same argument names. Therefore it's worth ensuring that + # they are correctly deduplicated + import sys + if not hasattr(sys, "pypy_version_info"): # test doesn't work on PyPy (which is probably fair enough) + assert func1.__code__.co_varnames is func2.__code__.co_varnames + @cython.test_assert_path_exists("//TupleNode", "//TupleNode[@is_literal = true]") @cython.test_fail_if_path_exists("//TupleNode[@is_literal = false]") |