Cython 3.2.0b3__py3-none-any.whl → 3.2.2__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- Cython/Compiler/Builtin.py +13 -11
- Cython/Compiler/Code.py +31 -21
- Cython/Compiler/ExprNodes.py +12 -3
- Cython/Compiler/MemoryView.py +1 -8
- Cython/Compiler/Nodes.py +16 -45
- Cython/Compiler/Optimize.py +24 -18
- Cython/Compiler/PyrexTypes.py +4 -5
- Cython/Compiler/Symtab.py +17 -0
- Cython/Compiler/UtilityCode.py +1 -1
- Cython/Compiler/Visitor.py +6 -4
- Cython/Debugger/Cygdb.py +4 -2
- Cython/Includes/cpython/dict.pxd +86 -0
- Cython/Includes/libc/threads.pxd +5 -5
- Cython/Includes/libcpp/mutex.pxd +1 -1
- Cython/Shadow.py +1 -1
- Cython/Utility/Builtins.c +2 -2
- Cython/Utility/Embed.c +2 -2
- Cython/Utility/Exceptions.c +5 -0
- Cython/Utility/ImportExport.c +18 -6
- Cython/Utility/MemoryView_C.c +19 -4
- Cython/Utility/ModuleSetupCode.c +1 -1
- Cython/Utility/ObjectHandling.c +24 -4
- Cython/Utility/Optimize.c +7 -0
- Cython/Utility/Synchronization.c +1 -13
- Cython/Utility/TypeConversion.c +39 -23
- {cython-3.2.0b3.dist-info → cython-3.2.2.dist-info}/METADATA +31 -18
- {cython-3.2.0b3.dist-info → cython-3.2.2.dist-info}/RECORD +30 -30
- {cython-3.2.0b3.dist-info → cython-3.2.2.dist-info}/WHEEL +0 -0
- {cython-3.2.0b3.dist-info → cython-3.2.2.dist-info}/entry_points.txt +0 -0
- {cython-3.2.0b3.dist-info → cython-3.2.2.dist-info}/top_level.txt +0 -0
Cython/Compiler/Builtin.py
CHANGED
|
@@ -20,9 +20,16 @@ pyexec_globals_utility_code = UtilityCode.load("PyExecGlobals", "Builtins.c")
|
|
|
20
20
|
globals_utility_code = UtilityCode.load("Globals", "Builtins.c")
|
|
21
21
|
range_utility_code = UtilityCode.load("PyRange_Check", "Builtins.c")
|
|
22
22
|
include_std_lib_h_utility_code = UtilityCode.load("IncludeStdlibH", "ModuleSetupCode.c")
|
|
23
|
-
pysequence_multiply_utility_code = UtilityCode.load("PySequenceMultiply", "ObjectHandling.c")
|
|
24
23
|
slice_accessor_utility_code = UtilityCode.load("PySliceAccessors", "Builtins.c")
|
|
25
24
|
|
|
25
|
+
def make_sequence_multiply_method(typeobj_cname):
|
|
26
|
+
pysequence_multiply_utility_code = TempitaUtilityCode.load(
|
|
27
|
+
"BuiltinSequenceMultiply", "ObjectHandling.c",
|
|
28
|
+
context={'typeobj': typeobj_cname})
|
|
29
|
+
return BuiltinMethod("__mul__", "Tz", "T", f"__Pyx_{typeobj_cname}_Multiply",
|
|
30
|
+
utility_code=pysequence_multiply_utility_code)
|
|
31
|
+
|
|
32
|
+
|
|
26
33
|
# mapping from builtins to their C-level equivalents
|
|
27
34
|
|
|
28
35
|
class _BuiltinOverride:
|
|
@@ -378,22 +385,18 @@ builtin_types_table = [
|
|
|
378
385
|
]),
|
|
379
386
|
|
|
380
387
|
("bytearray", "&PyByteArray_Type", [
|
|
381
|
-
|
|
382
|
-
utility_code=pysequence_multiply_utility_code),
|
|
388
|
+
make_sequence_multiply_method("PyByteArray_Type"),
|
|
383
389
|
]),
|
|
384
390
|
("bytes", "&PyBytes_Type", [BuiltinMethod("join", "TO", "T", "__Pyx_PyBytes_Join",
|
|
385
391
|
utility_code=UtilityCode.load("StringJoin", "StringTools.c")),
|
|
386
|
-
|
|
387
|
-
utility_code=pysequence_multiply_utility_code),
|
|
392
|
+
make_sequence_multiply_method("PyBytes_Type"),
|
|
388
393
|
]),
|
|
389
394
|
("str", "&PyUnicode_Type", [BuiltinMethod("__contains__", "TO", "b", "PyUnicode_Contains"),
|
|
390
395
|
BuiltinMethod("join", "TO", "T", "PyUnicode_Join"),
|
|
391
|
-
|
|
392
|
-
utility_code=pysequence_multiply_utility_code),
|
|
396
|
+
make_sequence_multiply_method("PyUnicode_Type"),
|
|
393
397
|
]),
|
|
394
398
|
|
|
395
|
-
("tuple", "&PyTuple_Type", [
|
|
396
|
-
utility_code=pysequence_multiply_utility_code),
|
|
399
|
+
("tuple", "&PyTuple_Type", [make_sequence_multiply_method("PyTuple_Type"),
|
|
397
400
|
]),
|
|
398
401
|
|
|
399
402
|
("list", "&PyList_Type", [BuiltinMethod("insert", "TzO", "r", "PyList_Insert"),
|
|
@@ -402,8 +405,7 @@ builtin_types_table = [
|
|
|
402
405
|
utility_code=UtilityCode.load("ListAppend", "Optimize.c")),
|
|
403
406
|
BuiltinMethod("extend", "TO", "r", "__Pyx_PyList_Extend",
|
|
404
407
|
utility_code=UtilityCode.load("ListExtend", "Optimize.c")),
|
|
405
|
-
|
|
406
|
-
utility_code=pysequence_multiply_utility_code),
|
|
408
|
+
make_sequence_multiply_method("PyList_Type"),
|
|
407
409
|
]),
|
|
408
410
|
|
|
409
411
|
("dict", "&PyDict_Type", [BuiltinMethod("__contains__", "TO", "b", "PyDict_Contains"),
|
Cython/Compiler/Code.py
CHANGED
|
@@ -402,7 +402,7 @@ class AbstractUtilityCode:
|
|
|
402
402
|
|
|
403
403
|
requires = None
|
|
404
404
|
|
|
405
|
-
def put_code(self,
|
|
405
|
+
def put_code(self, globalstate: "GlobalState", used_by=None) -> None:
|
|
406
406
|
pass
|
|
407
407
|
|
|
408
408
|
def get_tree(self, **kwargs):
|
|
@@ -738,6 +738,8 @@ class UtilityCode(UtilityCodeBase):
|
|
|
738
738
|
self.file = file
|
|
739
739
|
self.export = export
|
|
740
740
|
self.shared_utility_functions = self.parse_export_functions(export) if export else []
|
|
741
|
+
if export:
|
|
742
|
+
self._validate_suitable_for_sharing()
|
|
741
743
|
|
|
742
744
|
# cached for use in hash and eq
|
|
743
745
|
self._parts_tuple = tuple(getattr(self, part, None) for part in self.code_parts)
|
|
@@ -824,8 +826,14 @@ class UtilityCode(UtilityCodeBase):
|
|
|
824
826
|
self.specialize_list.append(s)
|
|
825
827
|
return s
|
|
826
828
|
|
|
829
|
+
def _validate_suitable_for_sharing(self):
|
|
830
|
+
code_string = getattr(self, "impl")
|
|
831
|
+
if not code_string: return
|
|
832
|
+
assert "NAMED_CGLOBAL(moddict_cname)" not in code_string, \
|
|
833
|
+
f"moddict_cname should not be shared: {self}"
|
|
834
|
+
|
|
827
835
|
@cython.final
|
|
828
|
-
def _put_code_section(self, writer: "CCodeWriter", output: "GlobalState", code_type: str):
|
|
836
|
+
def _put_code_section(self, writer: "CCodeWriter", output: "GlobalState", code_type: str, used_by=None):
|
|
829
837
|
code_string = getattr(self, code_type)
|
|
830
838
|
if not code_string:
|
|
831
839
|
return
|
|
@@ -834,8 +842,10 @@ class UtilityCode(UtilityCodeBase):
|
|
|
834
842
|
|
|
835
843
|
code_string, result_is_module_specific = process_utility_ccode(self, output, code_string)
|
|
836
844
|
|
|
837
|
-
|
|
838
|
-
|
|
845
|
+
used_by = f" (used by {used_by})" if used_by else ''
|
|
846
|
+
name = f"{self.name}.{code_type}" if code_type != 'impl' else self.name
|
|
847
|
+
|
|
848
|
+
writer.putln(f"/* {name}{used_by} */")
|
|
839
849
|
|
|
840
850
|
if can_be_reused and not result_is_module_specific:
|
|
841
851
|
# can be reused across modules
|
|
@@ -860,36 +870,36 @@ class UtilityCode(UtilityCodeBase):
|
|
|
860
870
|
code.putln(f'static {shared.ret}(*{shared.name})({shared.params}); /*proto*/')
|
|
861
871
|
code.putln()
|
|
862
872
|
|
|
863
|
-
def put_code(self,
|
|
873
|
+
def put_code(self, globalstate: "GlobalState", used_by=None) -> None:
|
|
864
874
|
has_shared_utility_code = bool(
|
|
865
|
-
self.shared_utility_functions and
|
|
875
|
+
self.shared_utility_functions and globalstate.module_node.scope.context.shared_utility_qualified_name
|
|
866
876
|
)
|
|
867
877
|
|
|
868
878
|
if self.requires and not has_shared_utility_code:
|
|
869
879
|
for dependency in self.requires:
|
|
870
|
-
|
|
880
|
+
globalstate.use_utility_code(dependency, used_by=self.name)
|
|
871
881
|
|
|
872
882
|
if has_shared_utility_code:
|
|
873
|
-
self._put_shared_function_declarations(
|
|
874
|
-
|
|
883
|
+
self._put_shared_function_declarations(globalstate[self.proto_block])
|
|
884
|
+
globalstate.shared_utility_functions.extend(self.shared_utility_functions)
|
|
875
885
|
|
|
876
886
|
if self.proto:
|
|
877
|
-
self._put_code_section(
|
|
887
|
+
self._put_code_section(globalstate[self.proto_block], globalstate, 'proto', used_by=used_by)
|
|
878
888
|
if not has_shared_utility_code:
|
|
879
|
-
self._put_code_section(
|
|
889
|
+
self._put_code_section(globalstate[self.proto_block], globalstate, 'export')
|
|
880
890
|
if self.impl and not has_shared_utility_code:
|
|
881
|
-
self._put_code_section(
|
|
891
|
+
self._put_code_section(globalstate['utility_code_def'], globalstate, 'impl', used_by=used_by)
|
|
882
892
|
if self.cleanup and Options.generate_cleanup_code:
|
|
883
|
-
self._put_code_section(
|
|
893
|
+
self._put_code_section(globalstate['cleanup_globals'], globalstate, 'cleanup')
|
|
884
894
|
if self.module_state_decls:
|
|
885
|
-
self._put_code_section(
|
|
895
|
+
self._put_code_section(globalstate['module_state_contents'], globalstate, 'module_state_decls')
|
|
886
896
|
if self.module_state_traverse:
|
|
887
|
-
self._put_code_section(
|
|
897
|
+
self._put_code_section(globalstate['module_state_traverse_contents'], globalstate, 'module_state_traverse')
|
|
888
898
|
if self.module_state_clear:
|
|
889
|
-
self._put_code_section(
|
|
899
|
+
self._put_code_section(globalstate['module_state_clear_contents'], globalstate, 'module_state_clear')
|
|
890
900
|
|
|
891
901
|
if self.init:
|
|
892
|
-
self._put_init_code_section(
|
|
902
|
+
self._put_init_code_section(globalstate)
|
|
893
903
|
|
|
894
904
|
|
|
895
905
|
def add_macro_processor(*macro_names, regex=None, is_module_specific=False, _last_macro_processor = [None]):
|
|
@@ -1088,9 +1098,9 @@ class LazyUtilityCode(UtilityCodeBase):
|
|
|
1088
1098
|
def __init__(self, callback):
|
|
1089
1099
|
self.callback = callback
|
|
1090
1100
|
|
|
1091
|
-
def put_code(self, globalstate):
|
|
1101
|
+
def put_code(self, globalstate: "GlobalState", used_by=None) -> None:
|
|
1092
1102
|
utility = self.callback(globalstate.rootwriter)
|
|
1093
|
-
globalstate.use_utility_code(utility)
|
|
1103
|
+
globalstate.use_utility_code(utility, used_by=used_by)
|
|
1094
1104
|
|
|
1095
1105
|
|
|
1096
1106
|
class FunctionState:
|
|
@@ -2471,7 +2481,7 @@ class GlobalState:
|
|
|
2471
2481
|
# Utility code state
|
|
2472
2482
|
#
|
|
2473
2483
|
|
|
2474
|
-
def use_utility_code(self, utility_code):
|
|
2484
|
+
def use_utility_code(self, utility_code, used_by=None):
|
|
2475
2485
|
"""
|
|
2476
2486
|
Adds code to the C file. utility_code should
|
|
2477
2487
|
a) implement __eq__/__hash__ for the purpose of knowing whether the same
|
|
@@ -2482,7 +2492,7 @@ class GlobalState:
|
|
|
2482
2492
|
"""
|
|
2483
2493
|
if utility_code and utility_code not in self.utility_codes:
|
|
2484
2494
|
self.utility_codes.add(utility_code)
|
|
2485
|
-
utility_code.put_code(self)
|
|
2495
|
+
utility_code.put_code(self, used_by=used_by)
|
|
2486
2496
|
|
|
2487
2497
|
def use_entry_utility_code(self, entry):
|
|
2488
2498
|
if entry is None:
|
Cython/Compiler/ExprNodes.py
CHANGED
|
@@ -1813,7 +1813,7 @@ class BytesNode(ConstNode):
|
|
|
1813
1813
|
node.type = dst_type
|
|
1814
1814
|
return node
|
|
1815
1815
|
elif dst_type in (PyrexTypes.c_uchar_ptr_type, PyrexTypes.c_const_uchar_ptr_type, PyrexTypes.c_void_ptr_type):
|
|
1816
|
-
node.type = (PyrexTypes.c_const_char_ptr_type if dst_type
|
|
1816
|
+
node.type = (PyrexTypes.c_const_char_ptr_type if dst_type.base_type.is_const
|
|
1817
1817
|
else PyrexTypes.c_char_ptr_type)
|
|
1818
1818
|
return CastNode(node, dst_type)
|
|
1819
1819
|
elif dst_type.assignable_from(PyrexTypes.c_char_ptr_type):
|
|
@@ -1830,7 +1830,7 @@ class BytesNode(ConstNode):
|
|
|
1830
1830
|
def generate_evaluation_code(self, code):
|
|
1831
1831
|
if self.type.is_pyobject:
|
|
1832
1832
|
result = code.get_py_string_const(self.value)
|
|
1833
|
-
elif self.type.is_const:
|
|
1833
|
+
elif (self.type.is_ptr or self.type.is_array) and self.type.base_type.is_const:
|
|
1834
1834
|
result = code.get_string_const(self.value)
|
|
1835
1835
|
else:
|
|
1836
1836
|
# not const => use plain C string literal and cast to mutable type
|
|
@@ -1900,6 +1900,9 @@ class UnicodeNode(ConstNode):
|
|
|
1900
1900
|
dst_type.is_ptr and dst_type.base_type.is_void):
|
|
1901
1901
|
# Allow using '-3' enforced unicode literals in a C char/char*/void* context.
|
|
1902
1902
|
if self.bytes_value is not None:
|
|
1903
|
+
if dst_type.is_array:
|
|
1904
|
+
# Prevent an invalid assignment from a C string array and use a pointer instead.
|
|
1905
|
+
dst_type = dst_type.element_ptr_type()
|
|
1903
1906
|
return BytesNode(self.pos, value=self.bytes_value).coerce_to(dst_type, env)
|
|
1904
1907
|
if env.directives['c_string_encoding']:
|
|
1905
1908
|
try:
|
|
@@ -9052,11 +9055,14 @@ class TupleNode(SequenceNode):
|
|
|
9052
9055
|
return self.result_code
|
|
9053
9056
|
|
|
9054
9057
|
def calculate_constant_result(self):
|
|
9058
|
+
if self.mult_factor:
|
|
9059
|
+
raise ValueError() # may exceed the compile time memory
|
|
9055
9060
|
self.constant_result = tuple([
|
|
9056
9061
|
arg.constant_result for arg in self.args])
|
|
9057
9062
|
|
|
9058
9063
|
def compile_time_value(self, denv):
|
|
9059
9064
|
values = self.compile_time_value_list(denv)
|
|
9065
|
+
assert self.mult_factor is None, self.mult_factor # set only after parsing
|
|
9060
9066
|
try:
|
|
9061
9067
|
return tuple(values)
|
|
9062
9068
|
except Exception as e:
|
|
@@ -9170,9 +9176,12 @@ class ListNode(SequenceNode):
|
|
|
9170
9176
|
else:
|
|
9171
9177
|
if len(self.args) < len(dst_type.scope.var_entries):
|
|
9172
9178
|
warning(self.pos, "Too few members for '%s'" % dst_type, 1)
|
|
9173
|
-
for i, (arg, member) in enumerate(zip(self.original_args, dst_type.scope.var_entries)):
|
|
9179
|
+
for i, (arg, coerced_arg, member) in enumerate(zip(self.original_args, self.args, dst_type.scope.var_entries)):
|
|
9174
9180
|
if isinstance(arg, CoerceToPyTypeNode):
|
|
9175
9181
|
arg = arg.arg
|
|
9182
|
+
elif member.type.is_struct_or_union and coerced_arg.is_dict_literal:
|
|
9183
|
+
# For struct assignments, use the coerced dict directly, not a struct type call etc.
|
|
9184
|
+
arg = coerced_arg
|
|
9176
9185
|
self.args[i] = arg.coerce_to(member.type, env)
|
|
9177
9186
|
self.type = dst_type
|
|
9178
9187
|
elif dst_type.is_ctuple:
|
Cython/Compiler/MemoryView.py
CHANGED
|
@@ -518,7 +518,6 @@ def get_copy_new_utility(pos, from_memview, to_memview):
|
|
|
518
518
|
func_cname=copy_c_or_fortran_cname(to_memview),
|
|
519
519
|
dtype_is_object=int(to_memview.dtype.is_pyobject),
|
|
520
520
|
),
|
|
521
|
-
requires=[copy_contents_new_utility],
|
|
522
521
|
)
|
|
523
522
|
|
|
524
523
|
|
|
@@ -847,12 +846,7 @@ overlapping_utility = load_memview_c_utility("OverlappingSlices")
|
|
|
847
846
|
refcount_utility = load_memview_c_utility("MemviewRefcount")
|
|
848
847
|
slice_init_utility = load_memview_c_utility("MemviewSliceInit")
|
|
849
848
|
memviewslice_declare_code = load_memview_c_utility("MemviewSliceStruct", context=template_context)
|
|
850
|
-
|
|
851
|
-
copy_contents_new_utility = load_memview_c_utility(
|
|
852
|
-
"MemviewSliceCopyTemplate",
|
|
853
|
-
context=template_context,
|
|
854
|
-
# Requires general memoryview code - dependency is added below.
|
|
855
|
-
)
|
|
849
|
+
copy_contents_new_utility = load_memview_c_utility("MemviewSliceCopy")
|
|
856
850
|
|
|
857
851
|
|
|
858
852
|
@Utils.cached_function
|
|
@@ -887,7 +881,6 @@ def _get_memoryview_shared_utility_code(shared_utility_qualified_name):
|
|
|
887
881
|
memviewslice_declare_code,
|
|
888
882
|
refcount_utility,
|
|
889
883
|
atomic_utility,
|
|
890
|
-
copy_contents_new_utility,
|
|
891
884
|
],
|
|
892
885
|
)
|
|
893
886
|
|
Cython/Compiler/Nodes.py
CHANGED
|
@@ -766,6 +766,7 @@ class CFuncDeclaratorNode(CDeclaratorNode):
|
|
|
766
766
|
level=2)
|
|
767
767
|
|
|
768
768
|
if self.exception_check == '+':
|
|
769
|
+
self.cpp_check(env)
|
|
769
770
|
env.add_include_file('ios') # for std::ios_base::failure
|
|
770
771
|
env.add_include_file('new') # for std::bad_alloc
|
|
771
772
|
env.add_include_file('stdexcept')
|
|
@@ -2019,6 +2020,10 @@ class FuncDefNode(StatNode, BlockNode):
|
|
|
2019
2020
|
outer_scope=genv,
|
|
2020
2021
|
parent_scope=env,
|
|
2021
2022
|
scope_name=self.entry.cname)
|
|
2023
|
+
# FIXME: why do GeneratorDefNode and GeneratorBodyDefNode use the same scope?
|
|
2024
|
+
# This should hit the GeneratorBodyDefNode, not the GeneratorDefNode.
|
|
2025
|
+
if self.is_generator_body or self.is_generator:
|
|
2026
|
+
lenv.is_generator_scope = True
|
|
2022
2027
|
else:
|
|
2023
2028
|
lenv = LocalScope(name=self.entry.name,
|
|
2024
2029
|
outer_scope=genv,
|
|
@@ -3250,7 +3255,7 @@ class DefNode(FuncDefNode):
|
|
|
3250
3255
|
from .ExprNodes import ConstNode
|
|
3251
3256
|
exception_value = ConstNode.for_type(
|
|
3252
3257
|
self.pos, value=str(cfunc_type.exception_value), type=cfunc_type.return_type,
|
|
3253
|
-
constant_result=cfunc_type.exception_value)
|
|
3258
|
+
constant_result=cfunc_type.exception_value.python_value)
|
|
3254
3259
|
declarator = CFuncDeclaratorNode(self.pos,
|
|
3255
3260
|
base=CNameDeclaratorNode(self.pos, name=self.name, cname=None),
|
|
3256
3261
|
args=self.args,
|
|
@@ -8992,7 +8997,6 @@ class CriticalSectionStatNode(TryFinallyStatNode):
|
|
|
8992
8997
|
child_attrs = ["args"] + TryFinallyStatNode.child_attrs
|
|
8993
8998
|
|
|
8994
8999
|
var_type = None
|
|
8995
|
-
state_temp = None
|
|
8996
9000
|
preserve_exception = False
|
|
8997
9001
|
is_pymutex_critical_section = False
|
|
8998
9002
|
|
|
@@ -9002,8 +9006,6 @@ class CriticalSectionStatNode(TryFinallyStatNode):
|
|
|
9002
9006
|
else:
|
|
9003
9007
|
self.var_type = PyrexTypes.c_py_critical_section_type
|
|
9004
9008
|
|
|
9005
|
-
self.create_state_temp_if_needed(pos, body)
|
|
9006
|
-
|
|
9007
9009
|
self.length_tag = str(len(args)) if len(args) > 1 else ""
|
|
9008
9010
|
|
|
9009
9011
|
super().__init__(
|
|
@@ -9011,19 +9013,16 @@ class CriticalSectionStatNode(TryFinallyStatNode):
|
|
|
9011
9013
|
args=args,
|
|
9012
9014
|
body=body,
|
|
9013
9015
|
finally_clause=CriticalSectionExitNode(
|
|
9014
|
-
pos, length_tag=self.length_tag
|
|
9016
|
+
pos, length_tag=self.length_tag),
|
|
9015
9017
|
**kwds,
|
|
9016
9018
|
)
|
|
9017
9019
|
|
|
9018
|
-
def
|
|
9020
|
+
def check_for_yields(self):
|
|
9019
9021
|
from .ParseTreeTransforms import YieldNodeCollector
|
|
9020
9022
|
collector = YieldNodeCollector()
|
|
9021
|
-
collector.visitchildren(body)
|
|
9022
|
-
if
|
|
9023
|
-
|
|
9024
|
-
|
|
9025
|
-
from . import ExprNodes
|
|
9026
|
-
self.state_temp = ExprNodes.TempNode(pos, self.var_type)
|
|
9023
|
+
collector.visitchildren(self.body)
|
|
9024
|
+
if collector.yields:
|
|
9025
|
+
error(self.pos, f"Cannot yield while in a cython.critical_section.")
|
|
9027
9026
|
|
|
9028
9027
|
def analyse_declarations(self, env):
|
|
9029
9028
|
for arg in self.args:
|
|
@@ -9031,6 +9030,7 @@ class CriticalSectionStatNode(TryFinallyStatNode):
|
|
|
9031
9030
|
return super().analyse_declarations(env)
|
|
9032
9031
|
|
|
9033
9032
|
def analyse_expressions(self, env):
|
|
9033
|
+
self.check_for_yields()
|
|
9034
9034
|
cy_pymutex_type = PyrexTypes.get_cy_pymutex_type()
|
|
9035
9035
|
mutex_count = 0
|
|
9036
9036
|
for i, arg in enumerate(self.args):
|
|
@@ -9074,12 +9074,8 @@ class CriticalSectionStatNode(TryFinallyStatNode):
|
|
|
9074
9074
|
|
|
9075
9075
|
code.mark_pos(self.pos)
|
|
9076
9076
|
code.begin_block()
|
|
9077
|
-
|
|
9078
|
-
|
|
9079
|
-
variable = self.state_temp.result()
|
|
9080
|
-
else:
|
|
9081
|
-
variable = Naming.critical_section_variable
|
|
9082
|
-
code.putln(f"{self.var_type.declaration_code(variable)};")
|
|
9077
|
+
variable = Naming.critical_section_variable
|
|
9078
|
+
code.putln(f"{self.var_type.declaration_code(variable)};")
|
|
9083
9079
|
|
|
9084
9080
|
for arg in self.args:
|
|
9085
9081
|
arg.generate_evaluation_code(code)
|
|
@@ -9097,16 +9093,13 @@ class CriticalSectionStatNode(TryFinallyStatNode):
|
|
|
9097
9093
|
arg.generate_disposal_code(code)
|
|
9098
9094
|
arg.free_temps(code)
|
|
9099
9095
|
|
|
9100
|
-
if self.state_temp:
|
|
9101
|
-
self.state_temp.release(code)
|
|
9102
|
-
|
|
9103
9096
|
code.end_block()
|
|
9104
9097
|
|
|
9105
9098
|
def nogil_check(self, env):
|
|
9106
9099
|
error(self.pos, "Critical sections require the GIL")
|
|
9107
9100
|
|
|
9108
9101
|
|
|
9109
|
-
class CriticalSectionExitNode(StatNode
|
|
9102
|
+
class CriticalSectionExitNode(StatNode):
|
|
9110
9103
|
"""
|
|
9111
9104
|
critical_section - the CriticalSectionStatNode that owns this
|
|
9112
9105
|
"""
|
|
@@ -9117,13 +9110,8 @@ class CriticalSectionExitNode(StatNode, CopyWithUpTreeRefsMixin):
|
|
|
9117
9110
|
return self
|
|
9118
9111
|
|
|
9119
9112
|
def generate_execution_code(self, code):
|
|
9120
|
-
if self.critical_section.state_temp:
|
|
9121
|
-
variable_name = self.critical_section.state_temp.result()
|
|
9122
|
-
else:
|
|
9123
|
-
variable_name = Naming.critical_section_variable
|
|
9124
|
-
|
|
9125
9113
|
code.putln(
|
|
9126
|
-
f"__Pyx_PyCriticalSection{self.length_tag}_End(&{
|
|
9114
|
+
f"__Pyx_PyCriticalSection{self.length_tag}_End(&{ Naming.critical_section_variable});"
|
|
9127
9115
|
)
|
|
9128
9116
|
|
|
9129
9117
|
class CythonLockStatNode(TryFinallyStatNode):
|
|
@@ -9162,29 +9150,12 @@ class CythonLockStatNode(TryFinallyStatNode):
|
|
|
9162
9150
|
result.finally_except_clause = result.finally_clause
|
|
9163
9151
|
return result
|
|
9164
9152
|
|
|
9165
|
-
def check_for_yields(self):
|
|
9166
|
-
from .ParseTreeTransforms import YieldNodeCollector
|
|
9167
|
-
collector = YieldNodeCollector()
|
|
9168
|
-
collector.visitchildren(self.body)
|
|
9169
|
-
if collector.yields:
|
|
9170
|
-
# DW - I've disallowed this because it seems like a deadlock disaster waiting to happen.
|
|
9171
|
-
# I'm sure it's technically possible, and we can revise it if people have legitimate
|
|
9172
|
-
# uses.
|
|
9173
|
-
typename = self.arg.type.empty_declaration_code(pyrex=True).strip()
|
|
9174
|
-
error(
|
|
9175
|
-
self.pos,
|
|
9176
|
-
f"Cannot use a 'with' statement with a '{typename}' in a generator. "
|
|
9177
|
-
"If you really want to do this (and you are confident that there are no deadlocks) "
|
|
9178
|
-
"then use try-finally."
|
|
9179
|
-
)
|
|
9180
|
-
|
|
9181
9153
|
def analyse_declarations(self, env):
|
|
9182
9154
|
self.arg.analyse_declarations(env)
|
|
9183
9155
|
return super().analyse_declarations(env)
|
|
9184
9156
|
|
|
9185
9157
|
def analyse_expressions(self, env):
|
|
9186
9158
|
self.arg = self.arg.analyse_expressions(env)
|
|
9187
|
-
self.check_for_yields()
|
|
9188
9159
|
body = self.body
|
|
9189
9160
|
if isinstance(body, StatListNode) and len(body.stats) >= 1:
|
|
9190
9161
|
body = body.stats[0]
|
Cython/Compiler/Optimize.py
CHANGED
|
@@ -219,13 +219,14 @@ class IterationTransform(Visitor.EnvTransform):
|
|
|
219
219
|
return self._optimise_for_loop(node, node.iterator.sequence)
|
|
220
220
|
|
|
221
221
|
def _optimise_for_loop(self, node, iterable, reversed=False):
|
|
222
|
+
iter_type = iterable.type
|
|
222
223
|
annotation_type = None
|
|
223
224
|
if (iterable.is_name or iterable.is_attribute) and iterable.entry and iterable.entry.annotation:
|
|
224
225
|
annotation = iterable.entry.annotation.expr
|
|
225
226
|
if annotation.is_subscript:
|
|
226
227
|
annotation = annotation.base # container base type
|
|
227
228
|
|
|
228
|
-
if Builtin.dict_type in (
|
|
229
|
+
if Builtin.dict_type in (iter_type, annotation_type):
|
|
229
230
|
# like iterating over dict.keys()
|
|
230
231
|
if reversed:
|
|
231
232
|
# CPython raises an error here: not a sequence
|
|
@@ -233,29 +234,31 @@ class IterationTransform(Visitor.EnvTransform):
|
|
|
233
234
|
return self._transform_dict_iteration(
|
|
234
235
|
node, dict_obj=iterable, method=None, keys=True, values=False)
|
|
235
236
|
|
|
236
|
-
if (Builtin.set_type in (
|
|
237
|
-
Builtin.frozenset_type in (
|
|
237
|
+
if (Builtin.set_type in (iter_type, annotation_type) or
|
|
238
|
+
Builtin.frozenset_type in (iter_type, annotation_type)):
|
|
238
239
|
if reversed:
|
|
239
240
|
# CPython raises an error here: not a sequence
|
|
240
241
|
return node
|
|
241
242
|
return self._transform_set_iteration(node, iterable)
|
|
242
243
|
|
|
244
|
+
env = self.current_env()
|
|
245
|
+
|
|
243
246
|
# C array (slice) iteration?
|
|
244
|
-
if
|
|
247
|
+
if iter_type.is_ptr or iter_type.is_array:
|
|
245
248
|
return self._transform_carray_iteration(node, iterable, reversed=reversed)
|
|
246
|
-
if iterable.is_sequence_constructor:
|
|
249
|
+
if iterable.is_sequence_constructor and not env.is_generator_scope:
|
|
247
250
|
# Convert iteration over homogeneous sequences of C types into array iteration.
|
|
248
|
-
|
|
251
|
+
# FIXME: using ListNode in this way currently generates invalid C code inside of generator loops.
|
|
249
252
|
item_type = ExprNodes.infer_sequence_item_type(
|
|
250
|
-
env, iterable, seq_type=
|
|
253
|
+
env, iterable, seq_type=iter_type)
|
|
251
254
|
if item_type and not item_type.is_pyobject and not any(item.is_starred for item in iterable.args):
|
|
252
255
|
iterable = ExprNodes.ListNode(iterable.pos, args=iterable.args).analyse_types(env).coerce_to(
|
|
253
256
|
PyrexTypes.c_array_type(item_type, len(iterable.args)), env)
|
|
254
257
|
return self._transform_carray_iteration(node, iterable, reversed=reversed)
|
|
255
|
-
if iterable.is_string_literal:
|
|
258
|
+
if iterable.is_string_literal and not env.is_generator_scope:
|
|
256
259
|
# Iterate over C array of single character values.
|
|
257
|
-
|
|
258
|
-
if
|
|
260
|
+
# FIXME: using ListNode in this way currently generates invalid C code inside of generator loops.
|
|
261
|
+
if iter_type is Builtin.unicode_type:
|
|
259
262
|
item_type = PyrexTypes.c_py_ucs4_type
|
|
260
263
|
items = map(ord, iterable.value)
|
|
261
264
|
else:
|
|
@@ -266,13 +269,16 @@ class IterationTransform(Visitor.EnvTransform):
|
|
|
266
269
|
iterable = ExprNodes.ListNode(iterable.pos, args=[as_int_node(ch)for ch in items])
|
|
267
270
|
iterable = iterable.analyse_types(env).coerce_to(PyrexTypes.c_array_type(item_type, len(iterable.args)), env)
|
|
268
271
|
return self._transform_carray_iteration(node, iterable, reversed=reversed)
|
|
269
|
-
if
|
|
270
|
-
|
|
271
|
-
|
|
272
|
+
if iter_type is Builtin.bytes_type:
|
|
273
|
+
if env.is_generator_scope:
|
|
274
|
+
return self._transform_indexable_iteration(node, iterable, is_mutable=False, reversed=reversed)
|
|
275
|
+
else:
|
|
276
|
+
return self._transform_bytes_iteration(node, iterable, reversed=reversed)
|
|
277
|
+
if iter_type is Builtin.unicode_type:
|
|
272
278
|
return self._transform_unicode_iteration(node, iterable, reversed=reversed)
|
|
273
279
|
# in principle _transform_indexable_iteration would work on most of the above, and
|
|
274
280
|
# also tuple and list. However, it probably isn't quite as optimized
|
|
275
|
-
if
|
|
281
|
+
if iter_type is Builtin.bytearray_type:
|
|
276
282
|
return self._transform_indexable_iteration(node, iterable, is_mutable=True, reversed=reversed)
|
|
277
283
|
if isinstance(iterable, ExprNodes.CoerceToPyTypeNode) and iterable.arg.type.is_memoryviewslice:
|
|
278
284
|
return self._transform_indexable_iteration(node, iterable.arg, is_mutable=False, reversed=reversed)
|
|
@@ -601,7 +607,8 @@ class IterationTransform(Visitor.EnvTransform):
|
|
|
601
607
|
exception_value=-1)
|
|
602
608
|
|
|
603
609
|
def _transform_unicode_iteration(self, node, slice_node, reversed=False):
|
|
604
|
-
|
|
610
|
+
env = self.current_env()
|
|
611
|
+
if slice_node.is_literal and not env.is_generator_scope:
|
|
605
612
|
# try to reduce to byte iteration for plain Latin-1 strings
|
|
606
613
|
try:
|
|
607
614
|
bytes_value = bytes_literal(slice_node.value.encode('latin1'), 'iso8859-1')
|
|
@@ -614,7 +621,7 @@ class IterationTransform(Visitor.EnvTransform):
|
|
|
614
621
|
slice_node.pos, value=bytes_value,
|
|
615
622
|
constant_result=bytes_value,
|
|
616
623
|
type=PyrexTypes.c_const_char_ptr_type).coerce_to(
|
|
617
|
-
PyrexTypes.c_const_uchar_ptr_type,
|
|
624
|
+
PyrexTypes.c_const_uchar_ptr_type, env),
|
|
618
625
|
start=None,
|
|
619
626
|
stop=ExprNodes.IntNode.for_size(slice_node.pos, len(bytes_value)),
|
|
620
627
|
type=Builtin.unicode_type, # hint for Python conversion
|
|
@@ -646,8 +653,7 @@ class IterationTransform(Visitor.EnvTransform):
|
|
|
646
653
|
is_temp = False,
|
|
647
654
|
)
|
|
648
655
|
if target_value.type != node.target.type:
|
|
649
|
-
target_value = target_value.coerce_to(node.target.type,
|
|
650
|
-
self.current_env())
|
|
656
|
+
target_value = target_value.coerce_to(node.target.type, env)
|
|
651
657
|
target_assign = Nodes.SingleAssignmentNode(
|
|
652
658
|
pos = node.target.pos,
|
|
653
659
|
lhs = node.target,
|
Cython/Compiler/PyrexTypes.py
CHANGED
|
@@ -832,8 +832,7 @@ class MemoryViewSliceType(PyrexType):
|
|
|
832
832
|
copy_func_type, pos=pos, defining=1,
|
|
833
833
|
cname=copy_cname)
|
|
834
834
|
|
|
835
|
-
|
|
836
|
-
env.use_utility_code(utility)
|
|
835
|
+
entry.utility_code_definition = MemoryView.get_copy_new_utility(pos, self, to_memview)
|
|
837
836
|
|
|
838
837
|
MemoryView.use_cython_array_utility_code(env)
|
|
839
838
|
|
|
@@ -3822,9 +3821,9 @@ class ToPyStructUtilityCode(AbstractUtilityCode):
|
|
|
3822
3821
|
def __hash__(self):
|
|
3823
3822
|
return hash(self.header)
|
|
3824
3823
|
|
|
3825
|
-
def put_code(self,
|
|
3826
|
-
code =
|
|
3827
|
-
proto =
|
|
3824
|
+
def put_code(self, globalstate, used_by=None):
|
|
3825
|
+
code = globalstate['utility_code_def']
|
|
3826
|
+
proto = globalstate['utility_code_proto']
|
|
3828
3827
|
|
|
3829
3828
|
code.enter_cfunc_scope(self.env.global_scope())
|
|
3830
3829
|
code.putln("%s {" % self.header)
|
Cython/Compiler/Symtab.py
CHANGED
|
@@ -364,6 +364,7 @@ class Scope:
|
|
|
364
364
|
# is_c_class_scope boolean Is an extension type scope
|
|
365
365
|
# is_local_scope boolean Is a local (i.e. function/method/generator) scope
|
|
366
366
|
# is_closure_scope boolean Is a closure scope
|
|
367
|
+
# is_generator_scope boolean Is a closure scope of a generator
|
|
367
368
|
# is_generator_expression_scope boolean A subset of closure scope used for generator expressions
|
|
368
369
|
# is_passthrough boolean Outer scope is passed directly
|
|
369
370
|
# is_cpp_class_scope boolean Is a C++ class scope
|
|
@@ -386,6 +387,7 @@ class Scope:
|
|
|
386
387
|
is_c_class_scope = 0
|
|
387
388
|
is_closure_scope = 0
|
|
388
389
|
is_local_scope = False
|
|
390
|
+
is_generator_scope = False
|
|
389
391
|
is_generator_expression_scope = 0
|
|
390
392
|
is_comprehension_scope = 0
|
|
391
393
|
is_passthrough = 0
|
|
@@ -1255,6 +1257,20 @@ class Scope:
|
|
|
1255
1257
|
return False
|
|
1256
1258
|
|
|
1257
1259
|
|
|
1260
|
+
class PreImportScope(Scope):
|
|
1261
|
+
|
|
1262
|
+
namespace_cname = Naming.preimport_cname
|
|
1263
|
+
|
|
1264
|
+
def __init__(self):
|
|
1265
|
+
Scope.__init__(self, Options.pre_import, None, None)
|
|
1266
|
+
|
|
1267
|
+
def declare_builtin(self, name, pos):
|
|
1268
|
+
entry = self.declare(name, name, py_object_type, pos, 'private')
|
|
1269
|
+
entry.is_variable = True
|
|
1270
|
+
entry.is_pyglobal = True
|
|
1271
|
+
return entry
|
|
1272
|
+
|
|
1273
|
+
|
|
1258
1274
|
class BuiltinScope(Scope):
|
|
1259
1275
|
# The builtin namespace.
|
|
1260
1276
|
|
|
@@ -2240,6 +2256,7 @@ class ClosureScope(LocalScope):
|
|
|
2240
2256
|
|
|
2241
2257
|
|
|
2242
2258
|
class GeneratorExpressionScope(ClosureScope):
|
|
2259
|
+
is_generator_scope = True
|
|
2243
2260
|
is_generator_expression_scope = True
|
|
2244
2261
|
|
|
2245
2262
|
def declare_assignment_expression_target(self, name, type, pos):
|
Cython/Compiler/UtilityCode.py
CHANGED
Cython/Compiler/Visitor.py
CHANGED
|
@@ -549,7 +549,7 @@ class MethodDispatcherTransform(EnvTransform):
|
|
|
549
549
|
if Future.division in self.current_env().context.future_directives:
|
|
550
550
|
special_method_name = '__truediv__'
|
|
551
551
|
obj_type = operand1.type
|
|
552
|
-
if obj_type.is_builtin_type:
|
|
552
|
+
if obj_type.is_builtin_type and not obj_type.is_exception_type:
|
|
553
553
|
type_name = obj_type.name
|
|
554
554
|
else:
|
|
555
555
|
type_name = "object" # safety measure
|
|
@@ -564,7 +564,7 @@ class MethodDispatcherTransform(EnvTransform):
|
|
|
564
564
|
if special_method_name:
|
|
565
565
|
operand = node.operand
|
|
566
566
|
obj_type = operand.type
|
|
567
|
-
if obj_type.is_builtin_type:
|
|
567
|
+
if obj_type.is_builtin_type and not obj_type.is_exception_type:
|
|
568
568
|
type_name = obj_type.name
|
|
569
569
|
else:
|
|
570
570
|
type_name = "object" # safety measure
|
|
@@ -619,7 +619,8 @@ class MethodDispatcherTransform(EnvTransform):
|
|
|
619
619
|
# => see if it's usable instead
|
|
620
620
|
return self._delegate_to_assigned_value(
|
|
621
621
|
node, function, arg_list, kwargs)
|
|
622
|
-
if arg_list and entry.is_cmethod and entry.scope and
|
|
622
|
+
if (arg_list and entry.is_cmethod and entry.scope and
|
|
623
|
+
entry.scope.parent_type.is_builtin_type and not entry.scope.parent_type.is_exception_type):
|
|
623
624
|
if entry.scope.parent_type is arg_list[0].type:
|
|
624
625
|
# Optimised (unbound) method of a builtin type => try to "de-optimise".
|
|
625
626
|
return self._dispatch_to_method_handler(
|
|
@@ -650,7 +651,8 @@ class MethodDispatcherTransform(EnvTransform):
|
|
|
650
651
|
return node
|
|
651
652
|
obj_type = self_arg.type
|
|
652
653
|
is_unbound_method = False
|
|
653
|
-
|
|
654
|
+
# Exceptions aren't necessarily exact types so could have unknown methods
|
|
655
|
+
if obj_type.is_builtin_type and not obj_type.is_exception_type:
|
|
654
656
|
if obj_type is Builtin.type_type and self_arg.is_name and arg_list and arg_list[0].type.is_pyobject:
|
|
655
657
|
# calling an unbound method like 'list.append(L,x)'
|
|
656
658
|
# (ignoring 'type.mro()' here ...)
|