Repository: cython/cython

Issue:
empty for-int-in-range loop doesn't behave as in Python
When optimised into a C loop, the for-in-range loop over an empty range still changes the value of the loop variable. In Python, this is not the case.

```
def go_py_empty():
    i = 20
    for i in range(4,0):
        print u"Spam!"
    return i # == 20

def go_c_empty():
    cdef int i = 20
    for i in range(4,0):
        print u"Spam!"
    return i # == 3
```

At 2009-02-08T11:55:47Z **mlh** added attachment [if_patch.txt](https://gist.github.com/374838b436356df3a17afb7df2827a6f)

Migrated from http://trac.cython.org/ticket/208



Discussion:

Resolving patch:
diff --git a/Cython/Compiler/FlowControl.py b/Cython/Compiler/FlowControl.py
--- a/Cython/Compiler/FlowControl.py
+++ b/Cython/Compiler/FlowControl.py
@@ -313,6 +313,12 @@ def __init__(self, lhs, rhs, entry):
     def __repr__(self):
         return '%s(entry=%r)' % (self.__class__.__name__, self.entry)
 
+    def infer_type(self, scope):
+        return self.rhs.infer_type(scope)
+
+    def type_dependencies(self, scope):
+        return self.rhs.type_dependencies(scope)
+
 
 class Argument(NameAssignment):
     def __init__(self, lhs, rhs, entry):
@@ -325,6 +331,13 @@ def __init__(self, lhs, entry):
         NameAssignment.__init__(self, lhs, lhs, entry)
         self.is_deletion = True
 
+    def infer_type(self, scope):
+        inferred_type = self.rhs.infer_type(scope)
+        if (not inferred_type.is_pyobject and
+            inferred_type.can_coerce_to_pyobject(scope)):
+            return py_object_type
+        return inferred_type
+
 
 class Uninitialized(object):
     pass
diff --git a/Cython/Compiler/TypeInference.py b/Cython/Compiler/TypeInference.py
--- a/Cython/Compiler/TypeInference.py
+++ b/Cython/Compiler/TypeInference.py
@@ -363,7 +363,7 @@ def infer_types(self, scope):
                     continue
                 all = set()
                 for assmt in entry.cf_assignments:
-                    all.update(assmt.rhs.type_dependencies(scope))
+                    all.update(assmt.type_dependencies(scope))
                 if all:
                     dependancies_by_entry[entry] = all
                     for dep in all:
@@ -401,12 +401,12 @@ def resolve_dependancy(dep):
             # Deal with simple circular dependancies...
             for entry, deps in dependancies_by_entry.items():
                 if len(deps) == 1 and deps == set([entry]):
-                    types = [assmt.rhs.infer_type(scope)
+                    types = [assmt.infer_type(scope)
                              for assmt in entry.cf_assignments
-                             if assmt.rhs.type_dependencies(scope) == ()]
+                             if assmt.type_dependencies(scope) == ()]
                     if types:
                         entry.type = spanning_type(types, entry.might_overflow)
-                        types = [assmt.rhs.infer_type(scope)
+                        types = [assmt.infer_type(scope)
                                  for assmt in entry.cf_assignments]
                         entry.type = spanning_type(types, entry.might_overflow) # might be wider...
                         resolve_dependancy(entry)


Test patch:
diff --git a/tests/errors/w_uninitialized_del.pyx b/tests/errors/w_uninitialized_del.pyx
--- a/tests/errors/w_uninitialized_del.pyx
+++ b/tests/errors/w_uninitialized_del.pyx
@@ -9,8 +9,6 @@ def foo(x):
     return a, b
 
 _ERRORS = """
-7:9: Deletion of non-Python, non-C++ object
 7:12: local variable 'b' referenced before assignment
-7:12: Deletion of non-Python, non-C++ object
 9:12: local variable 'a' referenced before assignment
 """
diff --git a/tests/run/type_inference_T768.pyx b/tests/run/type_inference_T768.pyx
new file mode 100644
--- /dev/null
+++ b/tests/run/type_inference_T768.pyx
@@ -0,0 +1,21 @@
+# mode: run
+# ticket: 768
+from cython cimport typeof
+
+def type_inference_del_int():
+    """
+    >>> type_inference_del_int()
+    'Python object'
+    """
+    x = 1
+    del x
+    return typeof(x)
+
+def type_inference_del_dict():
+    """
+    >>> type_inference_del_dict()
+    'dict object'
+    """
+    x = {}
+    del x
+    return typeof(x)
diff --git a/tests/run/type_inference_T768_cpp.pyx b/tests/run/type_inference_T768_cpp.pyx
new file mode 100644
--- /dev/null
+++ b/tests/run/type_inference_T768_cpp.pyx
@@ -0,0 +1,21 @@
+# mode: run
+# tag: cpp
+# ticket: 768
+from cython cimport typeof
+
+cdef extern from "shapes.h" namespace "shapes":
+    cdef cppclass Shape:
+        float area()
+
+    cdef cppclass Circle(Shape):
+        int radius
+        Circle(int)
+
+def type_inference_del_cpp():
+    """
+    >>> type_inference_del_cpp()
+    'Circle *'
+    """
+    x = new Circle(10)
+    del x
+    return typeof(x)