Hi!
Attached patch tries to solve the issue.
How it works:
- `declare_pyfunction` accepts new argument, called `allow_redefine`
which means that this function can be redefined.
This flag is set when function isn't cpdef wrapper. If allow_redefine
is False old declare_pyfunction is called.
- When scope.declare_pyfunction() is called it checks was this name
already defined
- it's okay if it was defined with py_object_type
- if it was defined with unspecified_type set entry type to py_object_type
- if entry type has other type fallback to old declare_pyfunction() behavior
- if it wasn't create dummy entry with py_object_type
- Then create real private entry for function with is_lambda flag
set (should be renamed to something more generic, any ideas?)
- ID is added to function cname.
ps:
I've noticed interesting thing, this code compiles:
def foo():
pass
foo = 1
but this not:
foo = 1
def foo():
pass
--
vitja.
diff -r c4b0a644eb78 Cython/Compiler/Code.py
--- a/Cython/Compiler/Code.py Sun Nov 28 19:00:19 2010 +0100
+++ b/Cython/Compiler/Code.py Mon Nov 29 23:17:21 2010 +0300
@@ -1289,7 +1289,7 @@
method_flags += [method_coexist]
self.putln(
'{__Pyx_NAMESTR("%s"), (PyCFunction)%s, %s, __Pyx_DOCSTR(%s)}%s' % (
- entry.name,
+ entry.pretty_name or entry.name,
entry.func_cname,
"|".join(method_flags),
doc_code,
diff -r c4b0a644eb78 Cython/Compiler/Nodes.py
--- a/Cython/Compiler/Nodes.py Sun Nov 28 19:00:19 2010 +0100
+++ b/Cython/Compiler/Nodes.py Mon Nov 29 23:17:21 2010 +0300
@@ -2138,9 +2138,10 @@
entry = env.lookup_here(name)
if entry and entry.type.is_cfunction and not self.is_wrapper:
warning(self.pos, "Overriding cdef method with def method.", 5)
- entry = env.declare_pyfunction(name, self.pos)
+ entry = env.declare_pyfunction(name, self.pos, not self.is_wrapper)
self.entry = entry
- prefix = env.scope_prefix
+ prefix = env.next_id(env.scope_prefix)
+
entry.func_cname = \
Naming.pyfunc_prefix + prefix + name
entry.pymethdef_cname = \
diff -r c4b0a644eb78 Cython/Compiler/Symtab.py
--- a/Cython/Compiler/Symtab.py Sun Nov 28 19:00:19 2010 +0100
+++ b/Cython/Compiler/Symtab.py Mon Nov 29 23:17:21 2010 +0300
@@ -155,6 +155,7 @@
is_declared_generic = 0
is_readonly = 0
func_cname = None
+ pretty_name = None
func_modifiers = []
doc = None
init_to_none = 0
@@ -513,16 +514,35 @@
def declare_builtin(self, name, pos):
return self.outer_scope.declare_builtin(name, pos)
-
- def declare_pyfunction(self, name, pos):
+
+ def declare_pyfunction(self, name, pos, allow_redefine=False, visibility='extern'):
# Add an entry for a Python function.
entry = self.lookup_here(name)
- if entry and not entry.type.is_cfunction:
- # This is legal Python, but for now will produce invalid C.
- error(pos, "'%s' already declared" % name)
- entry = self.declare_var(name, py_object_type, pos, visibility='extern')
+
+ def declare_pyfunction_classic(entry):
+ if entry and not entry.type.is_cfunction:
+ # This is legal Python, but for now will produce invalid C.
+ error(pos, "'%s' already declared" % name)
+ entry = self.declare_var(name, py_object_type, pos, visibility=visibility)
+ entry.signature = pyfunction_signature
+ self.pyfunc_entries.append(entry)
+ return entry
+
+ if not allow_redefine:
+ return declare_pyfunction_classic(entry)
+ if entry:
+ if entry.type.is_unspecified:
+ entry.type = py_object_type
+ elif not entry.type.is_pyobject:
+ return declare_pyfunction_classic(entry)
+ else: # declare entry stub
+ entry = self.declare_var(name, py_object_type, pos, visibility=visibility)
+ entry = self.declare_var(None, py_object_type, pos,
+ cname=name, visibility='private')
+ entry.name = EncodedString(name)
+ entry.qualified_name = self.qualify_name(name)
entry.signature = pyfunction_signature
- self.pyfunc_entries.append(entry)
+ entry.is_lambda = True
return entry
def declare_lambda_function(self, func_cname, pos):
@@ -530,6 +550,7 @@
entry = self.declare_var(None, py_object_type, pos,
cname=func_cname, visibility='private')
entry.name = EncodedString(func_cname)
+ entry.pretty_name = '<lambda>'
entry.func_cname = func_cname
entry.signature = pyfunction_signature
entry.is_lambda = True
@@ -1335,17 +1356,8 @@
# return "%s->%s" % (self.cur_scope_cname, name)
# return "%s->%s" % (self.closure_cname, name)
- def declare_pyfunction(self, name, pos):
- # Add an entry for a Python function.
- entry = self.lookup_here(name)
- if entry and not entry.type.is_cfunction:
- # This is legal Python, but for now may produce invalid C.
- error(pos, "'%s' already declared" % name)
- entry = self.declare_var(name, py_object_type, pos)
- entry.signature = pyfunction_signature
- self.pyfunc_entries.append(entry)
- return entry
-
+ def declare_pyfunction(self, name, pos, allow_redefine=False):
+ return LocalScope.declare_pyfunction(self, name, pos, allow_redefine, visibility='private')
class StructOrUnionScope(Scope):
# Namespace of a C struct or union.
@@ -1519,7 +1531,7 @@
return entry
- def declare_pyfunction(self, name, pos):
+ def declare_pyfunction(self, name, pos, allow_redefine=False):
# Add an entry for a method.
if name in ('__eq__', '__ne__', '__lt__', '__gt__', '__le__', '__ge__'):
error(pos, "Special method %s must be implemented via __richcmp__" % name)
@@ -1763,7 +1775,7 @@
is_property_scope = 1
- def declare_pyfunction(self, name, pos):
+ def declare_pyfunction(self, name, pos, allow_redefine=False):
# Add an entry for a method.
signature = get_property_accessor_signature(name)
if signature:
diff -r c4b0a644eb78 tests/errors/e_redeclmeth.pyx
--- a/tests/errors/e_redeclmeth.pyx Sun Nov 28 19:00:19 2010 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,8 +0,0 @@
-class C:
- def f(self):
- pass
- def f(self):
- pass
-_ERRORS = u"""
-4:1: 'f' already declared
-"""
diff -r c4b0a644eb78 tests/run/pyfuncion_redefine_T489.pyx
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/run/pyfuncion_redefine_T489.pyx Mon Nov 29 23:17:21 2010 +0300
@@ -0,0 +1,60 @@
+"""
+>>> xxx
+[0, 1, 2, 3]
+"""
+
+xxx = []
+foo = 0
+xxx.append(foo)
+def foo():
+ """XXX"""
+ return 1
+xxx.append(foo())
+def foo():
+ return 2
+xxx.append(foo())
+foo = 3
+xxx.append(foo)
+
+def closure_scope(a):
+ """
+ >>> closure_scope(0)
+ [0, 1, 2, 3]
+ """
+ ret = []
+ foo = a + 0
+ ret.append(foo)
+ def foo():
+ return a + 1
+ ret.append(foo())
+ def foo():
+ return a + 2
+ ret.append(foo())
+ foo = a + 3
+ ret.append(foo)
+ return ret
+
+class ClassScope:
+ """
+ >>> obj = ClassScope()
+ [0, 1, 2, 3]
+ """
+ x = []
+ def __init__(self):
+ r = []
+ for x in self.x:
+ if callable(x):
+ r.append(x(self))
+ else:
+ r.append(x)
+ print r
+ foo = 0
+ x.append(foo)
+ def foo(self):
+ return 1
+ x.append(foo)
+ def foo(self):
+ return 2
+ x.append(foo)
+ foo = 3
+ x.append(foo)
_______________________________________________
Cython-dev mailing list
[email protected]
http://codespeak.net/mailman/listinfo/cython-dev