Fix cpdef cross-module dispatching bug, greatly simplify (also simplify optional...
authorRobert Bradshaw <robertwb@math.washington.edu>
Sat, 13 Sep 2008 22:10:38 +0000 (15:10 -0700)
committerRobert Bradshaw <robertwb@math.washington.edu>
Sat, 13 Sep 2008 22:10:38 +0000 (15:10 -0700)
Cython/Compiler/ExprNodes.py
Cython/Compiler/Naming.py
Cython/Compiler/Nodes.py
Cython/Compiler/PyrexTypes.py
Cython/Compiler/Symtab.py

index 703e1980c5cfe6e7de63024bad0d635f719dc8b9..9e7e97299a90262da37968a68e53cc3eee48e8e2 100644 (file)
@@ -1887,6 +1887,9 @@ class SimpleCallNode(CallNode):
                 arg_code = actual_arg.result_as(formal_arg.type)
                 arg_list_code.append(arg_code)
                 
+        if func_type.is_overridable:
+            arg_list_code.append(str(int(self.wrapper_call or self.function.entry.is_unbound_cmethod)))
+                
         if func_type.optional_arg_count:
             if expected_nargs == actual_nargs:
                 optional_args = 'NULL'
@@ -1898,9 +1901,9 @@ class SimpleCallNode(CallNode):
             arg_list_code.append(actual_arg.result_code)
         result = "%s(%s)" % (self.function.result_code,
             join(arg_list_code, ", "))
-        if self.wrapper_call or \
-                self.function.entry.is_unbound_cmethod and self.function.entry.type.is_overridable:
-            result = "(%s = 1, %s)" % (Naming.skip_dispatch_cname, result)
+#        if self.wrapper_call or \
+#                self.function.entry.is_unbound_cmethod and self.function.entry.type.is_overridable:
+#            result = "(%s = 1, %s)" % (Naming.skip_dispatch_cname, result)
         return result
     
     def generate_result_code(self, code):
index 47ec6be33fe2d75969f25e0a3a4eb9dac47e6a7d..13d15c455eb5fbf9e0de1ee9605138c7a62c1d43 100644 (file)
@@ -76,7 +76,6 @@ print_function_kwargs   = pyrex_prefix + "print_kwargs"
 cleanup_cname    = pyrex_prefix + "module_cleanup"
 pymoduledef_cname = pyrex_prefix + "moduledef"
 optional_args_cname = pyrex_prefix + "optional_args"
-no_opt_args      = pyrex_prefix + "no_opt_args"
 import_star      = pyrex_prefix + "import_star"
 import_star_set  = pyrex_prefix + "import_star_set"
 cur_scope_cname  = pyrex_prefix + "cur_scope"
index 2008f92180146e8e9d629324ac32e55dee9b0200..998046845f3b3dabca359ec6f56fdba2a5921536 100644 (file)
@@ -1027,7 +1027,7 @@ class FuncDefNode(StatNode, BlockNode):
         code.exit_cfunc_scope()
         if self.py_func:
             self.py_func.generate_function_definitions(env, code)
-        self.generate_optarg_wrapper_function(env, code)
+        self.generate_wrapper_functions(code)
 
     def declare_argument(self, env, arg):
         if arg.type.is_void:
@@ -1036,7 +1036,8 @@ class FuncDefNode(StatNode, BlockNode):
             error(arg.pos,
                 "Argument type '%s' is incomplete" % arg.type)
         return env.declare_arg(arg.name, arg.type, arg.pos)
-    def generate_optarg_wrapper_function(self, env, code):
+        
+    def generate_wrapper_functions(self, code):
         pass
 
     def generate_execution_code(self, code):
@@ -1093,6 +1094,7 @@ class CFuncDefNode(FuncDefNode):
     #  with_gil      boolean    Acquire GIL around body
     #  type          CFuncType
     #  py_func       wrapper for calling from Python
+    #  overridable   whether or not this is a cpdef function
     
     child_attrs = ["base_type", "declarator", "body", "py_func"]
 
@@ -1188,21 +1190,22 @@ class CFuncDefNode(FuncDefNode):
         if self.overridable:
             self.py_func.analyse_expressions(env)
 
-    def generate_function_header(self, code, with_pymethdef, with_opt_args = 1):
+    def generate_function_header(self, code, with_pymethdef, with_opt_args = 1, with_dispatch = 1, cname = None):
         arg_decls = []
         type = self.type
         visibility = self.entry.visibility
         for arg in type.args[:len(type.args)-type.optional_arg_count]:
             arg_decls.append(arg.declaration_code())
+        if with_dispatch and self.overridable:
+            arg_decls.append(PyrexTypes.c_int_type.declaration_code(Naming.skip_dispatch_cname))
         if type.optional_arg_count and with_opt_args:
             arg_decls.append(type.op_arg_struct.declaration_code(Naming.optional_args_cname))
         if type.has_varargs:
             arg_decls.append("...")
         if not arg_decls:
             arg_decls = ["void"]
-        cname = self.entry.func_cname
-        if not with_opt_args:
-            cname += Naming.no_opt_args
+        if cname is None:
+            cname = self.entry.func_cname
         entity = type.function_header_code(cname, string.join(arg_decls, ", "))
         if visibility == 'public':
             dll_linkage = "DL_EXPORT"
@@ -1279,20 +1282,38 @@ class CFuncDefNode(FuncDefNode):
             
     def caller_will_check_exceptions(self):
         return self.entry.type.exception_check
-                    
-    def generate_optarg_wrapper_function(self, env, code):
-        if self.type.optional_arg_count and \
-                self.type.original_sig and not self.type.original_sig.optional_arg_count:
+        
+    def generate_wrapper_functions(self, code):
+        # If the C signature of a function has changed, we need to generate
+        # wrappers to put in the slots here. 
+        k = 0
+        entry = self.entry
+        func_type = entry.type
+        while entry.prev_entry is not None:
+            k += 1
+            entry = entry.prev_entry
+            entry.func_cname = "%s%swrap_%s" % (self.entry.func_cname, Naming.pyrex_prefix, k)
             code.putln()
-            self.generate_function_header(code, 0, with_opt_args = 0)
+            self.generate_function_header(code, 
+                                          0,
+                                          with_dispatch = entry.type.is_overridable, 
+                                          with_opt_args = entry.type.optional_arg_count, 
+                                          cname = entry.func_cname)
             if not self.return_type.is_void:
                 code.put('return ')
             args = self.type.args
             arglist = [arg.cname for arg in args[:len(args)-self.type.optional_arg_count]]
-            arglist.append('NULL')
+            if entry.type.is_overridable:
+                arglist.append(Naming.skip_dispatch_cname)
+            elif func_type.is_overridable:
+                arglist.append('0')
+            if entry.type.optional_arg_count:
+                arglist.append(Naming.optional_args_cname)
+            elif func_type.optional_arg_count:
+                arglist.append('NULL')
             code.putln('%s(%s);' % (self.entry.func_cname, ', '.join(arglist)))
             code.putln('}')
-
+        
 
 class PyArgDeclNode(Node):
     # Argument which must be a Python object (used
@@ -2070,7 +2091,7 @@ class OverrideCheckNode(StatNode):
         else:
             self_arg = "((PyObject *)%s)" % self.args[0].cname
         code.putln("/* Check if called by wrapper */")
-        code.putln("if (unlikely(%s)) %s = 0;" % (Naming.skip_dispatch_cname, Naming.skip_dispatch_cname))
+        code.putln("if (unlikely(%s)) ;" % Naming.skip_dispatch_cname)
         code.putln("/* Check if overriden in Python */")
         if self.py_func.is_module_scope:
             code.putln("else {")
index 2561d9c710f9cd8a3b22edd9254dd2d4f3924f42..263abb57816028116e19e64e7288340d8b31137f 100644 (file)
@@ -732,7 +732,7 @@ class CFuncType(CType):
             return 1
         if not other_type.is_cfunction:
             return 0
-        if not self.is_overridable and other_type.is_overridable:
+        if self.is_overridable != other_type.is_overridable:
             return 0
         nargs = len(self.args)
         if nargs != len(other_type.args):
@@ -846,6 +846,8 @@ class CFuncType(CType):
         for arg in self.args[:len(self.args)-self.optional_arg_count]:
             arg_decl_list.append(
                 arg.type.declaration_code("", for_display, pyrex = pyrex))
+        if self.is_overridable:
+            arg_decl_list.append("int %s" % Naming.skip_dispatch_cname)
         if self.optional_arg_count:
             arg_decl_list.append(self.op_arg_struct.declaration_code(Naming.optional_args_cname))
         if self.has_varargs:
index fd691a7ca10f5cff187f707be83fcb9e272929b1..9687af61203d3f2334da36495d71c7483939f5dd 100644 (file)
@@ -138,6 +138,7 @@ class Entry:
     utility_code = None
     is_overridable = 0
     buffer_aux = None
+    prev_entry = None
 
     def __init__(self, name, cname, type, pos = None, init = None):
         self.name = name
@@ -277,7 +278,7 @@ class Scope:
         if name and dict.has_key(name):
             if visibility == 'extern':
                 warning(pos, "'%s' redeclared " % name, 0)
-            else:
+            elif visibility != 'ignore':
                 error(pos, "'%s' redeclared " % name)
         entry = Entry(name, cname, type, pos = pos)
         entry.in_cinclude = self.in_cinclude
@@ -1411,22 +1412,8 @@ class CClassScope(ClassScope):
                 if type.same_c_signature_as(entry.type, as_cmethod = 1) and type.nogil == entry.type.nogil:
                     pass
                 elif type.compatible_signature_with(entry.type, as_cmethod = 1) and type.nogil == entry.type.nogil:
-                    if type.optional_arg_count and not type.original_sig.optional_arg_count:
-                        # Need to put a wrapper taking no optional arguments 
-                        # into the method table.
-                        wrapper_func_cname = self.mangle(Naming.func_prefix, name) + Naming.no_opt_args
-                        wrapper_func_name = name + Naming.no_opt_args
-                        if entry.type.optional_arg_count:
-                            old_entry = self.lookup_here(wrapper_func_name)
-                            old_entry.func_cname = wrapper_func_cname
-                        else:
-                            entry.func_cname = wrapper_func_cname
-                            entry.name = wrapper_func_name
-                            entry = self.add_cfunction(name, type, pos, cname or name, visibility)
-                            defining = 1
-                    entry.type = type
-#                if type.narrower_c_signature_than(entry.type, as_cmethod = 1):
-#                    entry.type = type
+                    entry = self.add_cfunction(name, type, pos, cname or name, visibility='ignore')
+                    defining = 1
                 else:
                     error(pos, "Signature not compatible with previous declaration")
                     error(entry.pos, "Previous declaration is here")
@@ -1442,8 +1429,10 @@ class CClassScope(ClassScope):
         
     def add_cfunction(self, name, type, pos, cname, visibility):
         # Add a cfunction entry without giving it a func_cname.
+        prev_entry = self.lookup_here(name)
         entry = ClassScope.add_cfunction(self, name, type, pos, cname, visibility)
         entry.is_cmethod = 1
+        entry.prev_entry = prev_entry
         return entry
     
     def declare_property(self, name, doc, pos):