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

Reply via email to