summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorStefan Behnel <stefan_ml@behnel.de>2017-10-03 12:11:47 +0200
committerStefan Behnel <stefan_ml@behnel.de>2017-10-03 13:23:43 +0200
commitffdc9b88f9b3515d2b33ed5b95d56b7c09529478 (patch)
tree292a606ee128571e1d81a7301661ece08c563718
parent65c2cd5d9bfb92e649a0ed28a560bc7f5abd9502 (diff)
downloadcython-ffdc9b88f9b3515d2b33ed5b95d56b7c09529478.tar.gz
Repair compilation error for nested module level comprehensions.
Closes #1906.
-rw-r--r--Cython/Compiler/ExprNodes.py14
-rw-r--r--Cython/Compiler/Symtab.py18
-rw-r--r--tests/run/dictcomp.pyx32
3 files changed, 56 insertions, 8 deletions
diff --git a/Cython/Compiler/ExprNodes.py b/Cython/Compiler/ExprNodes.py
index 6406d7e43..fead0a4a5 100644
--- a/Cython/Compiler/ExprNodes.py
+++ b/Cython/Compiler/ExprNodes.py
@@ -7949,8 +7949,7 @@ class ScopedExprNode(ExprNode):
generate_inner_evaluation_code(code)
# normal (non-error) exit
- for entry in py_entries:
- code.put_var_xdecref_clear(entry)
+ self._generate_vars_cleanup(code, py_entries)
# error/loop body exit points
exit_scope = code.new_label('exit_scope')
@@ -7959,8 +7958,7 @@ class ScopedExprNode(ExprNode):
list(zip(code.get_loop_labels(), old_loop_labels))):
if code.label_used(label):
code.put_label(label)
- for entry in py_entries:
- code.put_var_xdecref_clear(entry)
+ self._generate_vars_cleanup(code, py_entries)
code.put_goto(old_label)
code.put_label(exit_scope)
code.putln('} /* exit inner scope */')
@@ -7968,6 +7966,14 @@ class ScopedExprNode(ExprNode):
code.set_loop_labels(old_loop_labels)
code.error_label = old_error_label
+ def _generate_vars_cleanup(self, code, py_entries):
+ for entry in py_entries:
+ if entry.is_cglobal:
+ code.put_var_gotref(entry)
+ code.put_decref_set(entry.cname, "Py_None")
+ else:
+ code.put_var_xdecref_clear(entry)
+
class ComprehensionNode(ScopedExprNode):
# A list/set/dict comprehension
diff --git a/Cython/Compiler/Symtab.py b/Cython/Compiler/Symtab.py
index 32e10b554..ab43c7057 100644
--- a/Cython/Compiler/Symtab.py
+++ b/Cython/Compiler/Symtab.py
@@ -1704,7 +1704,10 @@ class LocalScope(Scope):
# Return None if not found.
entry = Scope.lookup(self, name)
if entry is not None:
- if entry.scope is not self and entry.scope.is_closure_scope:
+ entry_scope = entry.scope
+ while entry_scope.is_genexpr_scope:
+ entry_scope = entry_scope.outer_scope
+ if entry_scope is not self and entry_scope.is_closure_scope:
if hasattr(entry.scope, "scope_class"):
raise InternalError("lookup() after scope class created.")
# The actual c fragment for the different scopes differs
@@ -1740,8 +1743,12 @@ class GeneratorExpressionScope(Scope):
is_genexpr_scope = True
def __init__(self, outer_scope):
- name = outer_scope.global_scope().next_id(Naming.genexpr_id_ref)
- Scope.__init__(self, name, outer_scope, outer_scope)
+ parent_scope = outer_scope
+ # TODO: also ignore class scopes?
+ while parent_scope.is_genexpr_scope:
+ parent_scope = parent_scope.parent_scope
+ name = parent_scope.global_scope().next_id(Naming.genexpr_id_ref)
+ Scope.__init__(self, name, outer_scope, parent_scope)
self.directives = outer_scope.directives
self.genexp_prefix = "%s%d%s" % (Naming.pyrex_prefix, len(name), name)
@@ -1768,7 +1775,10 @@ class GeneratorExpressionScope(Scope):
cname = '%s%s' % (self.genexp_prefix, self.parent_scope.mangle(Naming.var_prefix, name or self.next_id()))
entry = self.declare(name, cname, type, pos, visibility)
entry.is_variable = True
- entry.is_local = True
+ if self.parent_scope.is_module_scope:
+ entry.is_cglobal = True
+ else:
+ entry.is_local = True
entry.in_subscope = True
self.var_entries.append(entry)
self.entries[name] = entry
diff --git a/tests/run/dictcomp.pyx b/tests/run/dictcomp.pyx
index 731020f0b..e0137fe6f 100644
--- a/tests/run/dictcomp.pyx
+++ b/tests/run/dictcomp.pyx
@@ -57,3 +57,35 @@ def sorted(it):
l = list(it)
l.sort()
return l
+
+
+# Copied from sre_compile.py in CPython 3.7. Previously failed to detect variable initialisation.
+_equivalences = (
+ # LATIN SMALL LETTER I, LATIN SMALL LETTER DOTLESS I
+ (0x69, 0x131), # iı
+ # LATIN SMALL LETTER S, LATIN SMALL LETTER LONG S
+ (0x73, 0x17f), # sſ
+ # MICRO SIGN, GREEK SMALL LETTER MU
+ (0xb5, 0x3bc), # µμ
+ # COMBINING GREEK YPOGEGRAMMENI, GREEK SMALL LETTER IOTA, GREEK PROSGEGRAMMENI
+ (0x345, 0x3b9, 0x1fbe), # \u0345ιι
+ # ...
+)
+
+_ignorecase_fixes = {
+ i: tuple(j for j in t if i != j)
+ for t in _equivalences for i in t
+}
+
+def nested_tuple():
+ """
+ >>> modlevel, funclevel = nested_tuple()
+ >>> modlevel == funclevel or (modlevel, funclevel)
+ True
+ """
+ inner_ignorecase_fixes = {
+ i: tuple(j for j in t if i != j)
+ for t in _equivalences for i in t
+ }
+
+ return sorted(_ignorecase_fixes.items()), sorted(inner_ignorecase_fixes.items())