Commit fb5e9200 authored by Stefan Behnel's avatar Stefan Behnel

Suppress special casing of attribute names in closure classes since they are...

Suppress special casing of attribute names in closure classes since they are not user defined and any local variable name is allowed without being special.

Closes #1797.
parent 66dc4405
...@@ -1334,11 +1334,11 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode): ...@@ -1334,11 +1334,11 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode):
is_final_type = scope.parent_type.is_final_type is_final_type = scope.parent_type.is_final_type
needs_gc = scope.needs_gc() needs_gc = scope.needs_gc()
weakref_slot = scope.lookup_here("__weakref__") weakref_slot = scope.lookup_here("__weakref__") if not scope.is_closure_class_scope else None
if weakref_slot not in scope.var_entries: if weakref_slot not in scope.var_entries:
weakref_slot = None weakref_slot = None
dict_slot = scope.lookup_here("__dict__") dict_slot = scope.lookup_here("__dict__") if not scope.is_closure_class_scope else None
if dict_slot not in scope.var_entries: if dict_slot not in scope.var_entries:
dict_slot = None dict_slot = None
...@@ -2800,7 +2800,7 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode): ...@@ -2800,7 +2800,7 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode):
scope.class_name, scope.class_name,
typeobj_cname, typeobj_cname,
code.error_goto(entry.pos))) code.error_goto(entry.pos)))
weakref_entry = scope.lookup_here("__weakref__") weakref_entry = scope.lookup_here("__weakref__") if not scope.is_closure_class_scope else None
if weakref_entry: if weakref_entry:
if weakref_entry.type is py_object_type: if weakref_entry.type is py_object_type:
tp_weaklistoffset = "%s.tp_weaklistoffset" % typeobj_cname tp_weaklistoffset = "%s.tp_weaklistoffset" % typeobj_cname
...@@ -2815,7 +2815,7 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode): ...@@ -2815,7 +2815,7 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode):
weakref_entry.cname)) weakref_entry.cname))
else: else:
error(weakref_entry.pos, "__weakref__ slot must be of type 'object'") error(weakref_entry.pos, "__weakref__ slot must be of type 'object'")
if scope.lookup_here("__reduce_cython__"): if scope.lookup_here("__reduce_cython__") if not scope.is_closure_class_scope else None:
# Unfortunately, we cannot reliably detect whether a # Unfortunately, we cannot reliably detect whether a
# superclass defined __reduce__ at compile time, so we must # superclass defined __reduce__ at compile time, so we must
# do so at runtime. # do so at runtime.
......
...@@ -2632,6 +2632,7 @@ class CreateClosureClasses(CythonTransform): ...@@ -2632,6 +2632,7 @@ class CreateClosureClasses(CythonTransform):
func_scope.scope_class = entry func_scope.scope_class = entry
class_scope = entry.type.scope class_scope = entry.type.scope
class_scope.is_internal = True class_scope.is_internal = True
class_scope.is_closure_class_scope = True
if Options.closure_freelist_size: if Options.closure_freelist_size:
class_scope.directives['freelist'] = Options.closure_freelist_size class_scope.directives['freelist'] = Options.closure_freelist_size
......
...@@ -1917,6 +1917,7 @@ class CClassScope(ClassScope): ...@@ -1917,6 +1917,7 @@ class CClassScope(ClassScope):
# inherited_var_entries [Entry] Adapted var entries from base class # inherited_var_entries [Entry] Adapted var entries from base class
is_c_class_scope = 1 is_c_class_scope = 1
is_closure_class_scope = False
has_pyobject_attrs = False has_pyobject_attrs = False
has_memoryview_attrs = False has_memoryview_attrs = False
...@@ -1960,7 +1961,7 @@ class CClassScope(ClassScope): ...@@ -1960,7 +1961,7 @@ class CClassScope(ClassScope):
for entry in self.var_entries: for entry in self.var_entries:
if entry.type.is_pyobject: if entry.type.is_pyobject:
if include_weakref or entry.name != "__weakref__": if include_weakref or (self.is_closure_class_scope or entry.name != "__weakref__"):
if include_gc_simple or not entry.type.is_gc_simple: if include_gc_simple or not entry.type.is_gc_simple:
py_attrs.append(entry) py_attrs.append(entry)
elif entry.type == PyrexTypes.c_py_buffer_type: elif entry.type == PyrexTypes.c_py_buffer_type:
...@@ -1980,7 +1981,7 @@ class CClassScope(ClassScope): ...@@ -1980,7 +1981,7 @@ class CClassScope(ClassScope):
error(pos, error(pos,
"C attributes cannot be added in implementation part of" "C attributes cannot be added in implementation part of"
" extension type defined in a pxd") " extension type defined in a pxd")
if get_special_method_signature(name): if not self.is_closure_class_scope and get_special_method_signature(name):
error(pos, error(pos,
"The name '%s' is reserved for a special method." "The name '%s' is reserved for a special method."
% name) % name)
...@@ -1998,7 +1999,7 @@ class CClassScope(ClassScope): ...@@ -1998,7 +1999,7 @@ class CClassScope(ClassScope):
self.has_memoryview_attrs = True self.has_memoryview_attrs = True
elif type.is_cpp_class: elif type.is_cpp_class:
self.has_cpp_class_attrs = True self.has_cpp_class_attrs = True
elif type.is_pyobject and name != '__weakref__': elif type.is_pyobject and (self.is_closure_class_scope or name != '__weakref__'):
self.has_pyobject_attrs = True self.has_pyobject_attrs = True
if (not type.is_builtin_type if (not type.is_builtin_type
or not type.scope or type.scope.needs_gc()): or not type.scope or type.scope.needs_gc()):
...@@ -2011,7 +2012,7 @@ class CClassScope(ClassScope): ...@@ -2011,7 +2012,7 @@ class CClassScope(ClassScope):
# so do conversion ourself rather than rely on the CPython mechanism (through # so do conversion ourself rather than rely on the CPython mechanism (through
# a property; made in AnalyseDeclarationsTransform). # a property; made in AnalyseDeclarationsTransform).
entry.needs_property = True entry.needs_property = True
if name == "__weakref__": if not self.is_closure_class_scope and name == "__weakref__":
error(pos, "Special attribute __weakref__ cannot be exposed to Python") error(pos, "Special attribute __weakref__ cannot be exposed to Python")
if not (type.is_pyobject or type.can_coerce_to_pyobject(self)): if not (type.is_pyobject or type.can_coerce_to_pyobject(self)):
# we're not testing for coercion *from* Python here - that would fail later # we're not testing for coercion *from* Python here - that would fail later
...@@ -2056,7 +2057,7 @@ class CClassScope(ClassScope): ...@@ -2056,7 +2057,7 @@ class CClassScope(ClassScope):
return entry return entry
def lookup_here(self, name): def lookup_here(self, name):
if name == "__new__": if not self.is_closure_class_scope and name == "__new__":
name = EncodedString("__cinit__") name = EncodedString("__cinit__")
entry = ClassScope.lookup_here(self, name) entry = ClassScope.lookup_here(self, name)
if entry and entry.is_builtin_cmethod: if entry and entry.is_builtin_cmethod:
......
...@@ -519,7 +519,7 @@ class DictOffsetSlot(SlotDescriptor): ...@@ -519,7 +519,7 @@ class DictOffsetSlot(SlotDescriptor):
# Slot descriptor for a class' dict offset, for dynamic attributes. # Slot descriptor for a class' dict offset, for dynamic attributes.
def slot_code(self, scope): def slot_code(self, scope):
dict_entry = scope.lookup_here("__dict__") dict_entry = scope.lookup_here("__dict__") if not scope.is_closure_class_scope else None
if dict_entry and dict_entry.is_variable: if dict_entry and dict_entry.is_variable:
if getattr(dict_entry.type, 'cname', None) != 'PyDict_Type': if getattr(dict_entry.type, 'cname', None) != 'PyDict_Type':
error(dict_entry.pos, "__dict__ slot must be of type 'dict'") error(dict_entry.pos, "__dict__ slot must be of type 'dict'")
......
# mode: run
# tag: closures
# ticket: gh-1797
def func():
"""
>>> funcs = func()
>>> [f(1) for f in funcs]
['eq', 'str', 'weakref', 'new', 'dict']
"""
def __eq__(a):
return 'eq'
def __str__(a):
return 'str'
def __weakref__(a):
return 'weakref'
def __new__(a):
return 'new'
def __dict__(a):
return 'dict'
def list_from_gen(g):
return list(g)
# move into closure by using inside of generator expression
return list_from_gen([__eq__, __str__, __weakref__, __new__, __dict__][i] for i in range(5))
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