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.
@@ -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
- BuiltinMethod("__mul__", "Tz", "T", "__Pyx_PySequence_Multiply",
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
- BuiltinMethod("__mul__", "Tz", "T", "__Pyx_PySequence_Multiply",
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
- BuiltinMethod("__mul__", "Tz", "T", "__Pyx_PySequence_Multiply",
392
- utility_code=pysequence_multiply_utility_code),
396
+ make_sequence_multiply_method("PyUnicode_Type"),
393
397
  ]),
394
398
 
395
- ("tuple", "&PyTuple_Type", [BuiltinMethod("__mul__", "Tz", "T", "__Pyx_PySequence_Multiply",
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
- BuiltinMethod("__mul__", "Tz", "T", "__Pyx_PySequence_Multiply",
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, output):
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
- code_type_name = code_type if code_type != 'impl' else ''
838
- writer.putln(f"/* {self.name}{'.' if code_type_name else ''}{code_type_name} */")
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, output: "GlobalState") -> None:
873
+ def put_code(self, globalstate: "GlobalState", used_by=None) -> None:
864
874
  has_shared_utility_code = bool(
865
- self.shared_utility_functions and output.module_node.scope.context.shared_utility_qualified_name
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
- output.use_utility_code(dependency)
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(output[self.proto_block])
874
- output.shared_utility_functions.extend(self.shared_utility_functions)
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(output[self.proto_block], output, 'proto')
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(output[self.proto_block], output, 'export')
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(output['utility_code_def'], output, 'impl')
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(output['cleanup_globals'], output, 'cleanup')
893
+ self._put_code_section(globalstate['cleanup_globals'], globalstate, 'cleanup')
884
894
  if self.module_state_decls:
885
- self._put_code_section(output['module_state_contents'], output, 'module_state_decls')
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(output['module_state_traverse_contents'], output, 'module_state_traverse')
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(output['module_state_clear_contents'], output, 'module_state_clear')
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(output)
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:
@@ -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 == PyrexTypes.c_const_uchar_ptr_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:
@@ -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, critical_section=self),
9016
+ pos, length_tag=self.length_tag),
9015
9017
  **kwds,
9016
9018
  )
9017
9019
 
9018
- def create_state_temp_if_needed(self, pos, body):
9020
+ def check_for_yields(self):
9019
9021
  from .ParseTreeTransforms import YieldNodeCollector
9020
9022
  collector = YieldNodeCollector()
9021
- collector.visitchildren(body)
9022
- if not collector.yields:
9023
- return
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
- if self.state_temp:
9078
- self.state_temp.allocate(code)
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, CopyWithUpTreeRefsMixin):
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(&{variable_name});"
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]
@@ -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 (iterable.type, annotation_type):
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 (iterable.type, annotation_type) or
237
- Builtin.frozenset_type in (iterable.type, annotation_type)):
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 iterable.type.is_ptr or iterable.type.is_array:
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
- env = self.current_env()
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=iterable.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
- env = self.current_env()
258
- if iterable.type is Builtin.unicode_type:
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 iterable.type is Builtin.bytes_type:
270
- return self._transform_bytes_iteration(node, iterable, reversed=reversed)
271
- if iterable.type is Builtin.unicode_type:
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 iterable.type is Builtin.bytearray_type:
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
- if slice_node.is_literal:
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, self.current_env()),
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,
@@ -832,8 +832,7 @@ class MemoryViewSliceType(PyrexType):
832
832
  copy_func_type, pos=pos, defining=1,
833
833
  cname=copy_cname)
834
834
 
835
- utility = MemoryView.get_copy_new_utility(pos, self, to_memview)
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, output):
3826
- code = output['utility_code_def']
3827
- proto = output['utility_code_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):
@@ -201,7 +201,7 @@ class CythonUtilityCode(Code.UtilityCodeBase):
201
201
  self.tree = tree
202
202
  return tree
203
203
 
204
- def put_code(self, output):
204
+ def put_code(self, globalstate, used_by=None):
205
205
  pass
206
206
 
207
207
  @classmethod
@@ -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 entry.scope.parent_type.is_builtin_type:
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
- if obj_type.is_builtin_type:
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 ...)