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):
is_final_type = scope.parent_type.is_final_type
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:
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:
dict_slot = None
......@@ -2800,7 +2800,7 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode):
scope.class_name,
typeobj_cname,
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.type is py_object_type:
tp_weaklistoffset = "%s.tp_weaklistoffset" % typeobj_cname
......@@ -2815,7 +2815,7 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode):
weakref_entry.cname))
else:
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
# superclass defined __reduce__ at compile time, so we must
# do so at runtime.
......
......@@ -2632,6 +2632,7 @@ class CreateClosureClasses(CythonTransform):
func_scope.scope_class = entry
class_scope = entry.type.scope
class_scope.is_internal = True
class_scope.is_closure_class_scope = True
if Options.closure_freelist_size:
class_scope.directives['freelist'] = Options.closure_freelist_size
......
......@@ -1917,6 +1917,7 @@ class CClassScope(ClassScope):
# inherited_var_entries [Entry] Adapted var entries from base class
is_c_class_scope = 1
is_closure_class_scope = False
has_pyobject_attrs = False
has_memoryview_attrs = False
......@@ -1960,7 +1961,7 @@ class CClassScope(ClassScope):
for entry in self.var_entries:
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:
py_attrs.append(entry)
elif entry.type == PyrexTypes.c_py_buffer_type:
......@@ -1980,7 +1981,7 @@ class CClassScope(ClassScope):
error(pos,
"C attributes cannot be added in implementation part of"
" 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,
"The name '%s' is reserved for a special method."
% name)
......@@ -1998,7 +1999,7 @@ class CClassScope(ClassScope):
self.has_memoryview_attrs = True
elif type.is_cpp_class:
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
if (not type.is_builtin_type
or not type.scope or type.scope.needs_gc()):
......@@ -2011,7 +2012,7 @@ class CClassScope(ClassScope):
# so do conversion ourself rather than rely on the CPython mechanism (through
# a property; made in AnalyseDeclarationsTransform).
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")
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
......@@ -2056,7 +2057,7 @@ class CClassScope(ClassScope):
return entry
def lookup_here(self, name):
if name == "__new__":
if not self.is_closure_class_scope and name == "__new__":
name = EncodedString("__cinit__")
entry = ClassScope.lookup_here(self, name)
if entry and entry.is_builtin_cmethod:
......
......@@ -519,7 +519,7 @@ class DictOffsetSlot(SlotDescriptor):
# Slot descriptor for a class' dict offset, for dynamic attributes.
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 getattr(dict_entry.type, 'cname', None) != 'PyDict_Type':
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