1# cython: infer_types = True
2
3
4cimport cython
5from cython cimport typeof, infer_types
6
7from cpython cimport bool
8
9##################################################
10# type inference tests in 'full' mode
11
12cdef class MyType:
13    pass
14
15def simple():
16    """
17    >>> simple()
18    """
19    i = 3
20    assert typeof(i) == "long", typeof(i)
21    x = 1.41
22    assert typeof(x) == "double", typeof(x)
23    xptr = &x
24    assert typeof(xptr) == "double *", typeof(xptr)
25    xptrptr = &xptr
26    assert typeof(xptrptr) == "double **", typeof(xptrptr)
27    b = b"abc"
28    assert typeof(b) == "bytes object", typeof(b)
29    s = "abc"
30    assert typeof(s) == "str object", typeof(s)
31    u = u"xyz"
32    assert typeof(u) == "unicode object", typeof(u)
33    L = [1,2,3]
34    assert typeof(L) == "list object", typeof(L)
35    t = (4,5,6,())
36    assert typeof(t) == "tuple object", typeof(t)
37    t2 = (4, 5.0, 6)
38    assert typeof(t2) == "(long, double, long)", typeof(t)
39
40def builtin_types():
41    """
42    >>> builtin_types()
43    """
44    b = bytes()
45    assert typeof(b) == "bytes object", typeof(b)
46    u = unicode()
47    assert typeof(u) == "unicode object", typeof(u)
48    L = list()
49    assert typeof(L) == "list object", typeof(L)
50    t = tuple()
51    assert typeof(t) == "tuple object", typeof(t)
52    d = dict()
53    assert typeof(d) == "dict object", typeof(d)
54    B = bool()
55    assert typeof(B) == "bool", typeof(B)
56
57def slicing():
58    """
59    >>> slicing()
60    """
61    b = b"abc"
62    assert typeof(b) == "bytes object", typeof(b)
63    b1 = b[1:2]
64    assert typeof(b1) == "bytes object", typeof(b1)
65    b2 = b[1:2:2]
66    assert typeof(b2) == "bytes object", typeof(b2)
67    u = u"xyz"
68    assert typeof(u) == "unicode object", typeof(u)
69    u1 = u[1:2]
70    assert typeof(u1) == "unicode object", typeof(u1)
71    u2 = u[1:2:2]
72    assert typeof(u2) == "unicode object", typeof(u2)
73    s = "xyz"
74    assert typeof(s) == "str object", typeof(s)
75    s1 = s[1:2]
76    assert typeof(s1) == "str object", typeof(s1)
77    s2 = s[1:2:2]
78    assert typeof(s2) == "str object", typeof(s2)
79    L = [1,2,3]
80    assert typeof(L) == "list object", typeof(L)
81    L1 = L[1:2]
82    assert typeof(L1) == "list object", typeof(L1)
83    L2 = L[1:2:2]
84    assert typeof(L2) == "list object", typeof(L2)
85    t = (4,5,6,())
86    assert typeof(t) == "tuple object", typeof(t)
87    t1 = t[1:2]
88    assert typeof(t1) == "tuple object", typeof(t1)
89    t2 = t[1:2:2]
90    assert typeof(t2) == "tuple object", typeof(t2)
91
92def indexing():
93    """
94    >>> indexing()
95    """
96    b = b"abc"
97    assert typeof(b) == "bytes object", typeof(b)
98    b1 = b[1]
99    assert typeof(b1) == "Python object", typeof(b1) # Py2: bytes, Py3: int
100    u = u"xyz"
101    assert typeof(u) == "unicode object", typeof(u)
102    u1 = u[1]
103    assert typeof(u1) == "Py_UCS4", typeof(u1)
104    s = "xyz"
105    assert typeof(s) == "str object", typeof(s)
106    s1 = s[1]
107    assert typeof(s1) == "str object", typeof(s1)
108    L = [1,2,3]
109    assert typeof(L) == "list object", typeof(L)
110    L1 = L[1]
111    assert typeof(L1) == "Python object", typeof(L1)
112    t = (4,5,())
113    assert typeof(t) == "tuple object", typeof(t)
114    t1 = t[1]
115    assert typeof(t1) == "long", typeof(t1)
116    t2 = ('abc', 'def', 'ghi')
117    assert typeof(t2) == "tuple object", typeof(t2)
118    t2_1 = t2[1]
119    assert typeof(t2_1) == "str object", typeof(t2_1)
120    t2_2 = t2[t[0]-3]
121    assert typeof(t2_2) == "str object", typeof(t2_2)
122    t5 = (b'abc', 'def', u'ghi')
123    t5_0 = t5[0]
124    assert typeof(t5_0) == "bytes object", typeof(t5_0)
125    t5_1 = t5[1]
126    assert typeof(t5_1) == "str object", typeof(t5_1)
127    t5_2 = t5[2]
128    assert typeof(t5_2) == "unicode object", typeof(t5_2)
129    t5_3 = t5[t[0]-3]
130    assert typeof(t5_3) == "Python object", typeof(t5_3)
131
132
133def multiple_assignments():
134    """
135    >>> multiple_assignments()
136    """
137    a = 3
138    a = 4
139    a = 5
140    assert typeof(a) == "long", typeof(a)
141    b = a
142    b = 3.1
143    b = 3.14159
144    assert typeof(b) == "double", typeof(b)
145    c = a
146    c = b
147    c = [1,2,3]
148    assert typeof(c) == "Python object", typeof(c)
149    d = b'abc'
150    d = bytes()
151    d = bytes(b'xyz')
152    d = None
153    assert typeof(d) == "bytes object", typeof(d)
154
155
156def arithmetic():
157    """
158    >>> arithmetic()
159    """
160    a = 1 + 2
161    assert typeof(a) == "long", typeof(a)
162    b = 1 + 1.5
163    assert typeof(b) == "double", typeof(b)
164    c = 1 + <object>2
165    assert typeof(c) == "Python object", typeof(c)
166    d = 1 * 1.5 ** 2
167    assert typeof(d) == "double", typeof(d)
168
169cdef class some_class:
170    pass
171
172def unary_operators():
173    """
174    >>> unary_operators()
175    """
176    cdef int x = 1
177    assert typeof(~x) == "int", typeof(~x)
178    cdef some_class obj
179    assert typeof(~obj) == "Python object", typeof(~obj)
180    a = int(1)
181    assert typeof(a) == "Python object", typeof(a)
182    b = not int(3)
183    assert typeof(b) == "bint", typeof(b)
184    c = +int(3)
185    assert typeof(c) == "Python object", typeof(c)
186    d = -int(5)
187    assert typeof(d) == "Python object", typeof(d)
188
189
190def builtin_type_operations():
191    """
192    >>> builtin_type_operations()
193    """
194    b1 = b'a' * 10
195    b1 = 10 * b'a'
196    b1 = 10 * b'a' * 10
197    assert typeof(b1) == "bytes object", typeof(b1)
198    b2 = b'a' + b'b'
199    assert typeof(b2) == "bytes object", typeof(b2)
200    u1 = u'a' * 10
201    u1 = 10 * u'a'
202    assert typeof(u1) == "unicode object", typeof(u1)
203    u2 = u'a' + u'b'
204    assert typeof(u2) == "unicode object", typeof(u2)
205    u3 = u'a%s' % u'b'
206    u3 = u'a%s' % 10
207    assert typeof(u3) == "unicode object", typeof(u3)
208    s1 = "abc %s" % "x"
209    s1 = "abc %s" % 10
210    assert typeof(s1) == "str object", typeof(s1)
211    s2 = "abc %s" + "x"
212    assert typeof(s2) == "str object", typeof(s2)
213    s3 = "abc %s" * 10
214    s3 = "abc %s" * 10 * 10
215    s3 = 10 * "abc %s" * 10
216    assert typeof(s3) == "str object", typeof(s3)
217    L1 = [] + []
218    assert typeof(L1) == "list object", typeof(L1)
219    L2 = [] * 2
220    assert typeof(L2) == "list object", typeof(L2)
221    T1 = () + ()
222    assert typeof(T1) == "tuple object", typeof(T1)
223    T2 = () * 2
224    assert typeof(T2) == "tuple object", typeof(T2)
225
226def builtin_type_methods():
227    """
228    >>> builtin_type_methods()
229    """
230    l = []
231    assert typeof(l) == 'list object', typeof(l)
232    append = l.append
233    assert typeof(append) == 'Python object', typeof(append)
234    append(1)
235    assert l == [1], str(l)
236
237cdef int cfunc(int x):
238    return x+1
239
240def c_functions():
241    """
242    >>> c_functions()
243    """
244    f = cfunc
245    assert typeof(f) == 'int (*)(int)', typeof(f)
246    assert 2 == f(1)
247
248def builtin_functions():
249    """
250    >>> _abs, _getattr = builtin_functions()
251    Python object
252    Python object
253    >>> _abs(-1)
254    1
255    >>> class o(object): pass
256    >>> o.x = 1
257    >>> _getattr(o, 'x')
258    1
259    """
260    _abs = abs
261    print(typeof(_abs))
262    _getattr = getattr
263    print(typeof(_getattr))
264    return _abs, _getattr
265
266def cascade():
267    """
268    >>> cascade()
269    """
270    a = 1.0
271    b = a + 2
272    c = b + 3
273    d = c + 4
274    assert typeof(d) == "double"
275    e = a + b + c + d
276    assert typeof(e) == "double"
277
278def cascaded_assignment():
279    """
280    >>> cascaded_assignment()
281    """
282    a = b = c = d = 1.0
283    assert typeof(a) == "double"
284    assert typeof(b) == "double"
285    assert typeof(c) == "double"
286    assert typeof(d) == "double"
287    e = a + b + c + d
288    assert typeof(e) == "double"
289
290
291def unpacking(x):
292    """
293    >>> unpacking(0)
294    """
295    a, b, c, (d, e) = x, 1, 2.0, [3, [5, 6]]
296    assert typeof(a) == "Python object", typeof(a)
297    assert typeof(b) == "long", typeof(b)
298    assert typeof(c) == "double", typeof(c)
299    assert typeof(d) == "long", typeof(d)
300    assert typeof(e) == "list object", typeof(e)
301
302
303def star_unpacking(*x):
304    """
305    >>> star_unpacking(1, 2)
306    """
307    a, b = x
308    c, *d = x
309    *e, f = x
310    *g, g = x  # re-assignment
311    assert typeof(a) == "Python object", typeof(a)
312    assert typeof(b) == "Python object", typeof(b)
313    assert typeof(c) == "Python object", typeof(c)
314    assert typeof(d) == "list object", typeof(d)
315    assert typeof(e) == "list object", typeof(e)
316    assert typeof(f) == "Python object", typeof(f)
317    assert typeof(g) == "Python object", typeof(f)
318
319
320def increment():
321    """
322    >>> increment()
323    """
324    a = 5
325    a += 1
326    assert typeof(a) == "long"
327
328def loop():
329    """
330    >>> loop()
331    """
332    for a in range(10):
333        pass
334    assert typeof(a) == "long"
335
336    b = 1.0
337    for b in range(5):
338        pass
339    assert typeof(b) == "double"
340
341    for c from 0 <= c < 10 by .5:
342        pass
343    assert typeof(c) == "double"
344
345    for d in range(0, 10L, 2):
346        pass
347    assert typeof(a) == "long"
348
349def loop_over_charptr():
350    """
351    >>> print( loop_over_charptr() )
352    char
353    """
354    cdef char* char_ptr_string = 'abcdefg'
355    for c in char_ptr_string:
356        pass
357    return typeof(c)
358
359def loop_over_bytes_literal():
360    """
361    >>> print( loop_over_bytes_literal() )
362    Python object
363    """
364    for c in b'abcdefg':
365        pass
366    return typeof(c)
367
368def loop_over_bytes():
369    """
370    >>> print( loop_over_bytes() )
371    Python object
372    """
373    cdef bytes bytes_string = b'abcdefg'
374    # bytes in Py2, int in Py3
375    for c in bytes_string:
376        pass
377    return typeof(c)
378
379def loop_over_str():
380    """
381    >>> print( loop_over_str() )
382    str object
383    """
384    cdef str string = 'abcdefg'
385    # str (bytes) in Py2, str (unicode) in Py3
386    for c in string:
387        pass
388    return typeof(c)
389
390def loop_over_unicode():
391    """
392    >>> print( loop_over_unicode() )
393    Py_UCS4
394    """
395    cdef unicode ustring = u'abcdefg'
396    # Py_UCS4 can represent any Unicode character
397    for uchar in ustring:
398        pass
399    return typeof(uchar)
400
401def loop_over_unicode_literal():
402    """
403    >>> print( loop_over_unicode_literal() )
404    Py_UCS4
405    """
406    # Py_UCS4 can represent any Unicode character
407    for uchar in u'abcdefg':
408        pass
409    return typeof(uchar)
410
411def loop_over_int_array():
412    """
413    >>> print( loop_over_int_array() )
414    int
415    """
416    cdef int[10] int_array
417    for i in int_array:
418        pass
419    return typeof(i)
420
421cdef struct MyStruct:
422    int a
423
424def loop_over_struct_ptr():
425    """
426    >>> print( loop_over_struct_ptr() )
427    MyStruct
428    """
429    cdef MyStruct[10] a_list
430    cdef MyStruct *a_ptr = a_list
431    for i in a_list[:10]:
432        pass
433    return typeof(i)
434
435cdef unicode retu():
436    return u"12345"
437
438cdef bytes retb():
439    return b"12345"
440
441def conditional(x):
442    """
443    >>> conditional(True)
444    (True, 'Python object')
445    >>> conditional(False)
446    (False, 'Python object')
447    """
448    if x:
449        a = retu()
450    else:
451        a = retb()
452    return type(a) is unicode, typeof(a)
453
454##################################################
455# type inference tests that work in 'safe' mode
456
457@infer_types(None)
458def double_inference():
459    """
460    >>> values, types = double_inference()
461    >>> values == (1.0, 1.0*2, 1.0*2.0+2.0*2.0, 1.0*2.0)
462    True
463    >>> types
464    ('double', 'double', 'double', 'Python object')
465    """
466    d_a = 1.0
467    d_b = d_a * float(2)
468    d_c = d_a * float(some_float_value()) + d_b * float(some_float_value())
469    o_d = d_a * some_float_value()
470    return (d_a,d_b,d_c,o_d), (typeof(d_a), typeof(d_b), typeof(d_c), typeof(o_d))
471
472cdef object some_float_value():
473    return 2.0
474
475
476@infer_types(None)
477@cython.test_fail_if_path_exists('//DefNode//NameNode[@type.is_pyobject = True]')
478@cython.test_assert_path_exists('//DefNode//NameNode[@type.is_pyobject]',
479                                '//DefNode//NameNode[@type.is_pyobject = False]')
480def double_loop():
481    """
482    >>> double_loop() == 1.0 * 10
483    True
484    """
485    cdef int i
486    d = 1.0
487    for i in range(9):
488        d += 1.0
489    return d
490
491@infer_types(None)
492def safe_only():
493    """
494    >>> safe_only()
495    """
496    a = 1.0
497    assert typeof(a) == "double", typeof(c)
498    b = 1;
499    assert typeof(b) == "long", typeof(b)
500    c = MyType()
501    assert typeof(c) == "MyType", typeof(c)
502    for i in range(10): pass
503    assert typeof(i) == "long", typeof(i)
504    d = 1
505    res = ~d
506    assert typeof(d) == "long", typeof(d)
507
508    # we special-case inference to type str, see
509    # trac #553
510    s = "abc"
511    assert typeof(s) == "Python object", typeof(s)
512    cdef str t = "def"
513    assert typeof(t) == "str object", typeof(t)
514
515    # potentially overflowing arithmetic
516    e = 1
517    e += 1
518    assert typeof(e) == "Python object", typeof(e)
519    f = 1
520    res = f * 10
521    assert typeof(f) == "Python object", typeof(f)
522    g = 1
523    res = 10*(~g)
524    assert typeof(g) == "Python object", typeof(g)
525    for j in range(10):
526        res = -j
527    assert typeof(j) == "Python object", typeof(j)
528    h = 1
529    res = abs(h)
530    assert typeof(h) == "Python object", typeof(h)
531    cdef int c_int = 1
532    assert typeof(abs(c_int)) == "int", typeof(abs(c_int))
533
534@infer_types(None)
535def safe_c_functions():
536    """
537    >>> safe_c_functions()
538    """
539    f = cfunc
540    assert typeof(f) == 'int (*)(int)', typeof(f)
541    assert 2 == f(1)
542
543@infer_types(None)
544def ptr_types():
545    """
546    >>> ptr_types()
547    """
548    cdef int a
549    a_ptr = &a
550    assert typeof(a_ptr) == "int *", typeof(a_ptr)
551    a_ptr_ptr = &a_ptr
552    assert typeof(a_ptr_ptr) == "int **", typeof(a_ptr_ptr)
553    cdef int[1] b
554    b_ref = b
555    assert typeof(b_ref) == "int *", typeof(b_ref)
556    ptr = &a
557    ptr = b
558    assert typeof(ptr) == "int *", typeof(ptr)
559
560def const_types(const double x, double y, double& z):
561    """
562    >>> const_types(1, 1, 1)
563    """
564    a = x
565    a = y
566    a = z
567    assert typeof(a) == "double", typeof(a)
568
569@infer_types(None)
570def args_tuple_keywords(*args, **kwargs):
571    """
572    >>> args_tuple_keywords(1,2,3, a=1, b=2)
573    """
574    assert typeof(args) == "tuple object", typeof(args)
575    assert typeof(kwargs) == "dict object", typeof(kwargs)
576
577@infer_types(None)
578def args_tuple_keywords_reassign_same(*args, **kwargs):
579    """
580    >>> args_tuple_keywords_reassign_same(1,2,3, a=1, b=2)
581    """
582    assert typeof(args) == "tuple object", typeof(args)
583    assert typeof(kwargs) == "dict object", typeof(kwargs)
584
585    args = ()
586    kwargs = {}
587
588@infer_types(None)
589def args_tuple_keywords_reassign_pyobjects(*args, **kwargs):
590    """
591    >>> args_tuple_keywords_reassign_pyobjects(1,2,3, a=1, b=2)
592    """
593    assert typeof(args) == "Python object", typeof(args)
594    assert typeof(kwargs) == "Python object", typeof(kwargs)
595
596    args = []
597    kwargs = "test"
598
599#                 / A -> AA -> AAA
600# Base0 -> Base -
601#                 \ B -> BB
602# C -> CC
603
604cdef class Base0: pass
605cdef class Base(Base0): pass
606cdef class A(Base): pass
607cdef class AA(A): pass
608cdef class AAA(AA): pass
609cdef class B(Base): pass
610cdef class BB(B): pass
611cdef class C: pass
612cdef class CC(C): pass
613
614@infer_types(None)
615def common_extension_type_base():
616    """
617    >>> common_extension_type_base()
618    """
619    x = A()
620    x = AA()
621    assert typeof(x) == "A", typeof(x)
622    y = A()
623    y = B()
624    assert typeof(y) == "Base", typeof(y)
625    z = AAA()
626    z = BB()
627    assert typeof(z) == "Base", typeof(z)
628    w = A()
629    w = CC()
630    assert typeof(w) == "Python object", typeof(w)
631
632cdef class AcceptsKeywords:
633    def __init__(self, *args, **kwds):
634        pass
635
636@infer_types(None)
637def constructor_call():
638    """
639    >>> constructor_call()
640    """
641    x = AcceptsKeywords(a=1, b=2)
642    assert typeof(x) == "AcceptsKeywords", typeof(x)
643
644
645@infer_types(None)
646def large_literals():
647    """
648    >>> large_literals()
649    """
650    # It's only safe to infer small integer literals.
651    a = 10
652    b = 100000000000000000000000000000000
653    assert typeof(a) == "long", typeof(a)
654    assert typeof(b) == "Python object", typeof(b)
655    c, d = 10, 100000000000000000000000000000000
656    assert typeof(c) == "long", typeof(c)
657    assert typeof(d) == "Python object", typeof(d)
658
659
660class EmptyContextManager(object):
661    def __enter__(self):
662        return None
663    def __exit__(self, *args):
664        return 0
665
666def with_statement():
667    """
668    >>> with_statement()
669    Python object
670    Python object
671    """
672    x = 1.0
673    with EmptyContextManager() as x:
674        print(typeof(x))
675    print(typeof(x))
676    return x
677
678@cython.final
679cdef class TypedContextManager(object):
680    cpdef double __enter__(self):
681        return 2.0
682    def __exit__(self, *args):
683        return 0
684
685def with_statement_typed():
686    """
687    >>> with_statement_typed()
688    double
689    double
690    2.0
691    """
692    x = 1.0
693    with TypedContextManager() as x:
694        print(typeof(x))
695    print(typeof(x))
696    return x
697
698def with_statement_untyped():
699    """
700    >>> with_statement_untyped()
701    Python object
702    Python object
703    2.0
704    """
705    x = 1.0
706    cdef object t = TypedContextManager()
707    with t as x:
708        print(typeof(x))
709    print(typeof(x))
710    return x
711
712def self_lookup(a):
713    b = a
714    b = b.foo(keyword=None)
715    print typeof(b)
716
717# Regression test for trac #638.
718
719def bar(foo):
720    qux = foo
721    quux = foo[qux.baz]
722
723
724cdef enum MyEnum:
725    enum_x = 1
726    enum_y = 2
727
728ctypedef long my_long
729def test_int_typedef_inference():
730    """
731    >>> test_int_typedef_inference()
732    """
733    cdef long x = 1
734    cdef my_long y = 2
735    cdef long long z = 3
736    assert typeof(x + y) == typeof(y + x) == 'my_long', typeof(x + y)
737    assert typeof(y + z) == typeof(z + y) == 'long long', typeof(y + z)
738
739from libc.stdint cimport int32_t, int64_t
740def int64_long_sum():
741    cdef long x = 1
742    cdef int32_t x32 = 2
743    cdef int64_t x64 = 3
744    cdef unsigned long ux = 4
745    assert typeof(x + x32) == typeof(x32 + x) == 'long', typeof(x + x32)
746    assert typeof(x + x64) == typeof(x64 + x) == 'int64_t', typeof(x + x64)
747    # The correct answer here is either unsigned long or int64_t, depending on
748    # whether sizeof(long) == 64 or not.  Incorrect signedness is probably
749    # preferable to incorrect width.
750    assert typeof(ux + x64) == typeof(x64 + ux) == 'int64_t', typeof(ux + x64)
751
752cdef class InferInProperties:
753    """
754    >>> InferInProperties().x
755    ('double', 'unicode object', 'MyEnum', 'MyEnum')
756    """
757    cdef MyEnum attr
758    def __cinit__(self):
759        self.attr = enum_x
760
761    property x:
762        def __get__(self):
763            a = 1.0
764            b = u'abc'
765            c = self.attr
766            d = enum_y
767            c = d
768            return typeof(a), typeof(b), typeof(c), typeof(d)
769
770cdef class WithMethods:
771    cdef int offset
772    def __init__(self, offset):
773        self.offset = offset
774    cpdef int one_arg(self, int x):
775        return x + self.offset
776    cpdef int default_arg(self, int x, int y=0):
777        return x + y + self.offset
778
779def test_bound_methods():
780  """
781  >>> test_bound_methods()
782  """
783  o = WithMethods(10)
784  assert typeof(o) == 'WithMethods', typeof(o)
785
786  one_arg = o.one_arg
787  assert one_arg(2) == 12, one_arg(2)
788
789  default_arg = o.default_arg
790  assert default_arg(2) == 12, default_arg(2)
791  assert default_arg(2, 3) == 15, default_arg(2, 2)
792
793def test_builtin_max():
794    """
795    # builtin max is slightly complicated because it gets transformed to EvalWithTempExprNode
796    # See https://github.com/cython/cython/issues/4155
797    >>> test_builtin_max()
798    """
799    class C:
800        a = 2
801        def get_max(self):
802            a = max(self.a, self.a)
803            assert typeof(a) == "Python object", typeof(a)
804    C().get_max()
805