fix ref-counting & cleanup and add testcase for function default argument values
authorLisandro Dalcin <dalcinl@gmail.com>
Mon, 23 Feb 2009 20:05:13 +0000 (18:05 -0200)
committerLisandro Dalcin <dalcinl@gmail.com>
Mon, 23 Feb 2009 20:05:13 +0000 (18:05 -0200)
Cython/Compiler/ModuleNode.py
Cython/Compiler/Nodes.py
tests/run/argdefault.pyx [new file with mode: 0644]

index d6d8f4cad07d1ba3d6b36b87f4c5f65d42e0d577..3967f8dd9163025a53224e404509deffa927996c 100644 (file)
@@ -1706,6 +1706,10 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode):
                 code.put_decref_clear(entry.pystring_cname,
                                       PyrexTypes.py_object_type,
                                       nanny=False)
+        for entry in env.default_entries:
+            if entry.type.is_pyobject and entry.used:
+                code.putln("Py_DECREF(%s); %s = 0;" % (
+                        code.entry_as_pyobject(entry), entry.cname))
         code.putln("Py_INCREF(Py_None); return Py_None;")
         code.putln('}')
 
index 629270dc35358803ff80c2ac1f81a63b1b8d6602..b1c850abcc11dfd6e643775c52a5443880ca711d 100644 (file)
@@ -992,6 +992,8 @@ class FuncDefNode(StatNode, BlockNode):
                         else:
                             arg.default.allocate_temps(genv)
                             arg.default_entry = genv.add_default_value(arg.type)
+                            if arg.type.is_pyobject:
+                                arg.default_entry.init = 0
                             arg.default_entry.used = 1
                             arg.default_result_code = arg.default_entry.cname
                 else:
@@ -1231,15 +1233,14 @@ class FuncDefNode(StatNode, BlockNode):
             if default:
                 if not default.is_literal:
                     default.generate_evaluation_code(code)
-                    default.make_owned_reference(code)
-                    code.putln(
-                        "%s = %s;" % (
-                            arg.default_entry.cname,
-                            default.result_as(arg.default_entry.type)))
-                    if default.is_temp and default.type.is_pyobject:
-                        code.putln(
-                            "%s = 0;" %
-                                default.result())
+                    assign_code = "%s = %s;" % (
+                        arg.default_entry.cname,
+                        default.result_as(arg.default_entry.type))
+                    if default.type.is_pyobject:
+                        assign_code += " Py_INCREF(%s);" % \
+                            arg.type.as_pyobject(arg.default_entry.cname)
+                    code.putln(assign_code)
+                    default.generate_disposal_code(code)
                     default.free_temps(code)
         # For Python class methods, create and store function object
         if self.assmt:
diff --git a/tests/run/argdefault.pyx b/tests/run/argdefault.pyx
new file mode 100644 (file)
index 0000000..6ef1faa
--- /dev/null
@@ -0,0 +1,78 @@
+__doc__ = """
+>>> f0()
+(1, 2)
+>>> g0()
+(1, 2)
+
+>>> f1()
+[1, 2]
+>>> g1()
+[1, 2]
+
+>>> f2()
+{1: 2}
+>>> g2()
+{1: 2}
+
+>>> f3() #doctest: +ELLIPSIS
+<argdefaultglb.Foo object at ...>
+>>> g3() #doctest: +ELLIPSIS
+<argdefaultglb.Foo object at ...>
+
+>>> f4() #doctest: +ELLIPSIS
+<argdefaultglb.Bar object at ...>
+>>> g4() #doctest: +ELLIPSIS
+<argdefaultglb.Bar object at ...>
+
+>>> f5() #doctest: +ELLIPSIS
+<argdefaultglb.Bla object at ...>
+>>> g5() #doctest: +ELLIPSIS
+<argdefaultglb.Bla object at ...>
+"""
+
+GLB0 = (1, 2)
+def f0(arg=GLB0):
+    return arg
+def g0(arg=(1, 2)):
+    return arg
+
+
+GLB1 = [1, 2]
+def f1(arg=GLB1):
+    return arg
+def g1(arg=[1, 2]):
+    return arg
+
+
+cdef GLB2 = {1: 2}
+def f2(arg=GLB2):
+    return arg
+def g2(arg={1: 2}):
+    return arg
+
+
+class Foo(object):
+    pass
+cdef GLB3 = Foo()
+def f3(arg=GLB3):
+    return arg
+def g3(arg=Foo()):
+    return arg
+
+
+cdef class Bar:
+    pass
+cdef Bar GLB4 = Bar()
+def f4(arg=GLB4):
+    return arg
+def g4(arg=Bar()):
+    return arg
+
+
+cdef class Bla:
+    pass
+cdef Bla GLB5 = Bla()
+def f5(Bla arg=GLB5):
+    return arg
+def g5(Bla arg=Bla()):
+    return arg