Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse code

merge

  • Loading branch information...
commit a6abc089060147fb660d45433bb2edd0f748abbd 2 parents d7a2258 + 212c992
scoder authored
2  CHANGES.rst
Source Rendered
@@ -13,6 +13,8 @@ Features added
13 13
 Bugs fixed
14 14
 ----------
15 15
 
  16
+* "obj[1,]" passed a single integer into the item getter instead of a tuple.
  17
+
16 18
 * Cyclic imports at module init time did not work in Py3.
17 19
 
18 20
 * The names of C++ destructors for template classes were built incorrectly.
31  Cython/Compiler/ExprNodes.py
@@ -8919,9 +8919,10 @@ class PrimaryCmpNode(ExprNode, CmpNode):
8919 8919
     #  Instead, we override all the framework methods
8920 8920
     #  which use it.
8921 8921
 
8922  
-    child_attrs = ['operand1', 'operand2', 'cascade']
  8922
+    child_attrs = ['operand1', 'operand2', 'coerced_operand2', 'cascade']
8923 8923
 
8924 8924
     cascade = None
  8925
+    coerced_operand2 = None
8925 8926
     is_memslice_nonecheck = False
8926 8927
 
8927 8928
     def infer_type(self, env):
@@ -8999,9 +9000,11 @@ def analyse_types(self, env):
8999 9000
             self.coerce_operands_to(common_type, env)
9000 9001
 
9001 9002
         if self.cascade:
9002  
-            self.operand2 = self.cascade.optimise_comparison(
9003  
-                self.operand2.coerce_to_simple(env), env)
  9003
+            self.operand2 = self.operand2.coerce_to_simple(env)
9004 9004
             self.cascade.coerce_cascaded_operands_to_temp(env)
  9005
+            operand2 = self.cascade.optimise_comparison(self.operand2, env)
  9006
+            if operand2 is not self.operand2:
  9007
+                self.coerced_operand2 = operand2
9005 9008
         if self.is_python_result():
9006 9009
             self.type = PyrexTypes.py_object_type
9007 9010
         else:
@@ -9105,8 +9108,9 @@ def generate_evaluation_code(self, code):
9105 9108
             self.generate_operation_code(code, self.result(),
9106 9109
                 self.operand1, self.operator, self.operand2)
9107 9110
             if self.cascade:
9108  
-                self.cascade.generate_evaluation_code(code,
9109  
-                    self.result(), self.operand2)
  9111
+                self.cascade.generate_evaluation_code(
  9112
+                    code, self.result(), self.coerced_operand2 or self.operand2,
  9113
+                    needs_evaluation=self.coerced_operand2 is not None)
9110 9114
             self.operand1.generate_disposal_code(code)
9111 9115
             self.operand1.free_temps(code)
9112 9116
             self.operand2.generate_disposal_code(code)
@@ -9141,9 +9145,10 @@ class CascadedCmpNode(Node, CmpNode):
9141 9145
     #  operand2      ExprNode
9142 9146
     #  cascade       CascadedCmpNode
9143 9147
 
9144  
-    child_attrs = ['operand2', 'cascade']
  9148
+    child_attrs = ['operand2', 'coerced_operand2', 'cascade']
9145 9149
 
9146 9150
     cascade = None
  9151
+    coerced_operand2 = None
9147 9152
     constant_result = constant_value_not_set # FIXME: where to calculate this?
9148 9153
 
9149 9154
     def infer_type(self, env):
@@ -9170,7 +9175,9 @@ def optimise_comparison(self, operand1, env):
9170 9175
             if not operand1.type.is_pyobject:
9171 9176
                 operand1 = operand1.coerce_to_pyobject(env)
9172 9177
         if self.cascade:
9173  
-            self.operand2 = self.cascade.optimise_comparison(self.operand2, env)
  9178
+            operand2 = self.cascade.optimise_comparison(self.operand2, env)
  9179
+            if operand2 is not self.operand2:
  9180
+                self.coerced_operand2 = operand2
9174 9181
         return operand1
9175 9182
 
9176 9183
     def coerce_operands_to_pyobjects(self, env):
@@ -9186,18 +9193,24 @@ def coerce_cascaded_operands_to_temp(self, env):
9186 9193
             self.operand2 = self.operand2.coerce_to_simple(env)
9187 9194
             self.cascade.coerce_cascaded_operands_to_temp(env)
9188 9195
 
9189  
-    def generate_evaluation_code(self, code, result, operand1):
  9196
+    def generate_evaluation_code(self, code, result, operand1, needs_evaluation=False):
9190 9197
         if self.type.is_pyobject:
9191 9198
             code.putln("if (__Pyx_PyObject_IsTrue(%s)) {" % result)
9192 9199
             code.put_decref(result, self.type)
9193 9200
         else:
9194 9201
             code.putln("if (%s) {" % result)
  9202
+        if needs_evaluation:
  9203
+            operand1.generate_evaluation_code(code)
9195 9204
         self.operand2.generate_evaluation_code(code)
9196 9205
         self.generate_operation_code(code, result,
9197 9206
             operand1, self.operator, self.operand2)
9198 9207
         if self.cascade:
9199 9208
             self.cascade.generate_evaluation_code(
9200  
-                code, result, self.operand2)
  9209
+                code, result, self.coerced_operand2 or self.operand2,
  9210
+                needs_evaluation=self.coerced_operand2 is not None)
  9211
+        if needs_evaluation:
  9212
+            operand1.generate_disposal_code(code)
  9213
+            operand1.free_temps(code)
9201 9214
         # Cascaded cmp result is always temp
9202 9215
         self.operand2.generate_disposal_code(code)
9203 9216
         self.operand2.free_temps(code)
2  Cython/Compiler/Parsing.pxd
@@ -49,7 +49,7 @@ cpdef p_call_parse_args(PyrexScanner s, bint allow_genexp = *)
49 49
 cdef p_call_build_packed_args(pos, positional_args, keyword_args, star_arg, starstar_arg)
50 50
 cdef p_call(PyrexScanner s, function)
51 51
 cdef p_index(PyrexScanner s, base)
52  
-cdef p_subscript_list(PyrexScanner s)
  52
+cdef tuple p_subscript_list(PyrexScanner s)
53 53
 cdef p_subscript(PyrexScanner s)
54 54
 cdef p_slice_element(PyrexScanner s, follow_set)
55 55
 cdef expect_ellipsis(PyrexScanner s)
12  Cython/Compiler/Parsing.py
@@ -503,14 +503,14 @@ def p_index(s, base):
503 503
     # s.sy == '['
504 504
     pos = s.position()
505 505
     s.next()
506  
-    subscripts = p_subscript_list(s)
507  
-    if len(subscripts) == 1 and len(subscripts[0]) == 2:
  506
+    subscripts, is_single_value = p_subscript_list(s)
  507
+    if is_single_value and len(subscripts[0]) == 2:
508 508
         start, stop = subscripts[0]
509 509
         result = ExprNodes.SliceIndexNode(pos,
510 510
             base = base, start = start, stop = stop)
511 511
     else:
512 512
         indexes = make_slice_nodes(pos, subscripts)
513  
-        if len(indexes) == 1:
  513
+        if is_single_value:
514 514
             index = indexes[0]
515 515
         else:
516 516
             index = ExprNodes.TupleNode(pos, args = indexes)
@@ -520,13 +520,15 @@ def p_index(s, base):
520 520
     return result
521 521
 
522 522
 def p_subscript_list(s):
  523
+    is_single_value = True
523 524
     items = [p_subscript(s)]
524 525
     while s.sy == ',':
  526
+        is_single_value = False
525 527
         s.next()
526 528
         if s.sy == ']':
527 529
             break
528 530
         items.append(p_subscript(s))
529  
-    return items
  531
+    return items, is_single_value
530 532
 
531 533
 #subscript: '.' '.' '.' | test | [test] ':' [test] [':' [test]]
532 534
 
@@ -2117,7 +2119,7 @@ def p_memoryviewslice_access(s, base_type_node):
2117 2119
     # s.sy == '['
2118 2120
     pos = s.position()
2119 2121
     s.next()
2120  
-    subscripts = p_subscript_list(s)
  2122
+    subscripts, _ = p_subscript_list(s)
2121 2123
     # make sure each entry in subscripts is a slice
2122 2124
     for subscript in subscripts:
2123 2125
         if len(subscript) < 2:
22  tests/run/cmp.pyx
@@ -38,6 +38,28 @@ def cascaded_c(double a, double b, double c):
38 38
     """
39 39
     return a < b < c
40 40
 
  41
+def cascaded_mix_pyleft(a, double b, double c):
  42
+    """
  43
+    >>> cascaded_mix_pyleft(1, 2, 3)
  44
+    True
  45
+    >>> cascaded_mix_pyleft(1, 2, -1)
  46
+    False
  47
+    >>> cascaded_mix_pyleft(10, 2, 3)
  48
+    False
  49
+    """
  50
+    return a < b < c
  51
+
  52
+def cascaded_mix_pyright(double a, double b, c):
  53
+    """
  54
+    >>> cascaded_mix_pyright(1, 2, 3)
  55
+    True
  56
+    >>> cascaded_mix_pyright(1, 2, -1)
  57
+    False
  58
+    >>> cascaded_mix_pyright(10, 2, 3)
  59
+    False
  60
+    """
  61
+    return a < b < c
  62
+
41 63
 def typed_cmp(list L):
42 64
     """
43 65
     >>> typed_cmp([1,2,3])
8  tests/run/dict_getitem.pyx
@@ -30,6 +30,14 @@ def test(dict d, index):
30 30
     """
31 31
     return d[index]
32 32
 
  33
+def getitem_tuple(dict d, index):
  34
+    """
  35
+    >>> d = {1: 1, (1,): 2}
  36
+    >>> getitem_tuple(d, 1)
  37
+    (1, 2)
  38
+    """
  39
+    return d[index], d[index,]
  40
+
33 41
 def getitem_in_condition(dict d, key, expected_result):
34 42
     """
35 43
     >>> d = dict(a=1, b=2)
26  tests/run/inop.pyx
@@ -376,3 +376,29 @@ def test_inop_cascaded(x):
376 376
     False
377 377
     """
378 378
     return 1 != x in [2]
  379
+
  380
+def test_inop_cascaded_one():
  381
+    """
  382
+    >>> test_inop_cascaded_one()
  383
+    False
  384
+    """
  385
+    # copied from CPython's test_grammar.py
  386
+    return 1 < 1 > 1 == 1 >= 1 <= 1 != 1 in 1 not in 1 is 1 is not 1
  387
+
  388
+def test_inop_cascaded_int_orig(int x):
  389
+    """
  390
+    >>> test_inop_cascaded_int_orig(1)
  391
+    False
  392
+    """
  393
+    return 1 < 1 > 1 == 1 >= 1 <= 1 != x in 1 not in 1 is 1 is not 1
  394
+
  395
+def test_inop_cascaded_int(int x):
  396
+    """
  397
+    >>> test_inop_cascaded_int(1)
  398
+    False
  399
+    >>> test_inop_cascaded_int(2)
  400
+    True
  401
+    >>> test_inop_cascaded_int(3)
  402
+    False
  403
+    """
  404
+    return 1 != x in [1,2]

0 notes on commit a6abc08

Please sign in to comment.
Something went wrong with that request. Please try again.