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    a = b = c = d = 1.0
280    assert typeof(a) == "double"
281    assert typeof(b) == "double"
282    assert typeof(c) == "double"
283    assert typeof(d) == "double"
284    e = a + b + c + d
285    assert typeof(e) == "double"
286
287def increment():
288    """
289    >>> increment()
290    """
291    a = 5
292    a += 1
293    assert typeof(a) == "long"
294
295def loop():
296    """
297    >>> loop()
298    """
299    for a in range(10):
300        pass
301    assert typeof(a) == "long"
302
303    b = 1.0
304    for b in range(5):
305        pass
306    assert typeof(b) == "double"
307
308    for c from 0 <= c < 10 by .5:
309        pass
310    assert typeof(c) == "double"
311
312    for d in range(0, 10L, 2):
313        pass
314    assert typeof(a) == "long"
315
316def loop_over_charptr():
317    """
318    >>> print( loop_over_charptr() )
319    char
320    """
321    cdef char* char_ptr_string = 'abcdefg'
322    for c in char_ptr_string:
323        pass
324    return typeof(c)
325
326def loop_over_bytes_literal():
327    """
328    >>> print( loop_over_bytes_literal() )
329    Python object
330    """
331    for c in b'abcdefg':
332        pass
333    return typeof(c)
334
335def loop_over_bytes():
336    """
337    >>> print( loop_over_bytes() )
338    Python object
339    """
340    cdef bytes bytes_string = b'abcdefg'
341    # bytes in Py2, int in Py3
342    for c in bytes_string:
343        pass
344    return typeof(c)
345
346def loop_over_str():
347    """
348    >>> print( loop_over_str() )
349    str object
350    """
351    cdef str string = 'abcdefg'
352    # str (bytes) in Py2, str (unicode) in Py3
353    for c in string:
354        pass
355    return typeof(c)
356
357def loop_over_unicode():
358    """
359    >>> print( loop_over_unicode() )
360    Py_UCS4
361    """
362    cdef unicode ustring = u'abcdefg'
363    # Py_UCS4 can represent any Unicode character
364    for uchar in ustring:
365        pass
366    return typeof(uchar)
367
368def loop_over_unicode_literal():
369    """
370    >>> print( loop_over_unicode_literal() )
371    Py_UCS4
372    """
373    # Py_UCS4 can represent any Unicode character
374    for uchar in u'abcdefg':
375        pass
376    return typeof(uchar)
377
378def loop_over_int_array():
379    """
380    >>> print( loop_over_int_array() )
381    int
382    """
383    cdef int[10] int_array
384    for i in int_array:
385        pass
386    return typeof(i)
387
388cdef struct MyStruct:
389    int a
390
391def loop_over_struct_ptr():
392    """
393    >>> print( loop_over_struct_ptr() )
394    MyStruct
395    """
396    cdef MyStruct[10] a_list
397    cdef MyStruct *a_ptr = a_list
398    for i in a_list[:10]:
399        pass
400    return typeof(i)
401
402cdef unicode retu():
403    return u"12345"
404
405cdef bytes retb():
406    return b"12345"
407
408def conditional(x):
409    """
410    >>> conditional(True)
411    (True, 'Python object')
412    >>> conditional(False)
413    (False, 'Python object')
414    """
415    if x:
416        a = retu()
417    else:
418        a = retb()
419    return type(a) is unicode, typeof(a)
420
421##################################################
422# type inference tests that work in 'safe' mode
423
424@infer_types(None)
425def double_inference():
426    """
427    >>> values, types = double_inference()
428    >>> values == (1.0, 1.0*2, 1.0*2.0+2.0*2.0, 1.0*2.0)
429    True
430    >>> types
431    ('double', 'double', 'double', 'Python object')
432    """
433    d_a = 1.0
434    d_b = d_a * float(2)
435    d_c = d_a * float(some_float_value()) + d_b * float(some_float_value())
436    o_d = d_a * some_float_value()
437    return (d_a,d_b,d_c,o_d), (typeof(d_a), typeof(d_b), typeof(d_c), typeof(o_d))
438
439cdef object some_float_value():
440    return 2.0
441
442
443@infer_types(None)
444@cython.test_fail_if_path_exists('//DefNode//NameNode[@type.is_pyobject = True]')
445@cython.test_assert_path_exists('//DefNode//NameNode[@type.is_pyobject]',
446                                '//DefNode//NameNode[@type.is_pyobject = False]')
447def double_loop():
448    """
449    >>> double_loop() == 1.0 * 10
450    True
451    """
452    cdef int i
453    d = 1.0
454    for i in range(9):
455        d += 1.0
456    return d
457
458@infer_types(None)
459def safe_only():
460    """
461    >>> safe_only()
462    """
463    a = 1.0
464    assert typeof(a) == "double", typeof(c)
465    b = 1;
466    assert typeof(b) == "long", typeof(b)
467    c = MyType()
468    assert typeof(c) == "MyType", typeof(c)
469    for i in range(10): pass
470    assert typeof(i) == "long", typeof(i)
471    d = 1
472    res = ~d
473    assert typeof(d) == "long", typeof(d)
474
475    # we special-case inference to type str, see
476    # trac #553
477    s = "abc"
478    assert typeof(s) == "Python object", typeof(s)
479    cdef str t = "def"
480    assert typeof(t) == "str object", typeof(t)
481
482    # potentially overflowing arithmetic
483    e = 1
484    e += 1
485    assert typeof(e) == "Python object", typeof(e)
486    f = 1
487    res = f * 10
488    assert typeof(f) == "Python object", typeof(f)
489    g = 1
490    res = 10*(~g)
491    assert typeof(g) == "Python object", typeof(g)
492    for j in range(10):
493        res = -j
494    assert typeof(j) == "Python object", typeof(j)
495    h = 1
496    res = abs(h)
497    assert typeof(h) == "Python object", typeof(h)
498    cdef int c_int = 1
499    assert typeof(abs(c_int)) == "int", typeof(abs(c_int))
500
501@infer_types(None)
502def safe_c_functions():
503    """
504    >>> safe_c_functions()
505    """
506    f = cfunc
507    assert typeof(f) == 'int (*)(int)', typeof(f)
508    assert 2 == f(1)
509
510@infer_types(None)
511def ptr_types():
512    """
513    >>> ptr_types()
514    """
515    cdef int a
516    a_ptr = &a
517    assert typeof(a_ptr) == "int *", typeof(a_ptr)
518    a_ptr_ptr = &a_ptr
519    assert typeof(a_ptr_ptr) == "int **", typeof(a_ptr_ptr)
520    cdef int[1] b
521    b_ref = b
522    assert typeof(b_ref) == "int *", typeof(b_ref)
523    ptr = &a
524    ptr = b
525    assert typeof(ptr) == "int *", typeof(ptr)
526
527def const_types(const double x, double y, double& z):
528    """
529    >>> const_types(1, 1, 1)
530    """
531    a = x
532    a = y
533    a = z
534    assert typeof(a) == "double", typeof(a)
535
536@infer_types(None)
537def args_tuple_keywords(*args, **kwargs):
538    """
539    >>> args_tuple_keywords(1,2,3, a=1, b=2)
540    """
541    assert typeof(args) == "tuple object", typeof(args)
542    assert typeof(kwargs) == "dict object", typeof(kwargs)
543
544@infer_types(None)
545def args_tuple_keywords_reassign_same(*args, **kwargs):
546    """
547    >>> args_tuple_keywords_reassign_same(1,2,3, a=1, b=2)
548    """
549    assert typeof(args) == "tuple object", typeof(args)
550    assert typeof(kwargs) == "dict object", typeof(kwargs)
551
552    args = ()
553    kwargs = {}
554
555@infer_types(None)
556def args_tuple_keywords_reassign_pyobjects(*args, **kwargs):
557    """
558    >>> args_tuple_keywords_reassign_pyobjects(1,2,3, a=1, b=2)
559    """
560    assert typeof(args) == "Python object", typeof(args)
561    assert typeof(kwargs) == "Python object", typeof(kwargs)
562
563    args = []
564    kwargs = "test"
565
566#                 / A -> AA -> AAA
567# Base0 -> Base -
568#                 \ B -> BB
569# C -> CC
570
571cdef class Base0: pass
572cdef class Base(Base0): pass
573cdef class A(Base): pass
574cdef class AA(A): pass
575cdef class AAA(AA): pass
576cdef class B(Base): pass
577cdef class BB(B): pass
578cdef class C: pass
579cdef class CC(C): pass
580
581@infer_types(None)
582def common_extension_type_base():
583    """
584    >>> common_extension_type_base()
585    """
586    x = A()
587    x = AA()
588    assert typeof(x) == "A", typeof(x)
589    y = A()
590    y = B()
591    assert typeof(y) == "Base", typeof(y)
592    z = AAA()
593    z = BB()
594    assert typeof(z) == "Base", typeof(z)
595    w = A()
596    w = CC()
597    assert typeof(w) == "Python object", typeof(w)
598
599cdef class AcceptsKeywords:
600    def __init__(self, *args, **kwds):
601        pass
602
603@infer_types(None)
604def constructor_call():
605    """
606    >>> constructor_call()
607    """
608    x = AcceptsKeywords(a=1, b=2)
609    assert typeof(x) == "AcceptsKeywords", typeof(x)
610
611
612@infer_types(None)
613def large_literals():
614    """
615    >>> large_literals()
616    """
617    # It's only safe to infer small integer literals.
618    a = 10
619    b = 100000000000000000000000000000000
620    assert typeof(a) == "long", typeof(a)
621    assert typeof(b) == "Python object", typeof(b)
622    c, d = 10, 100000000000000000000000000000000
623    assert typeof(c) == "long", typeof(c)
624    assert typeof(d) == "Python object", typeof(d)
625
626
627class EmptyContextManager(object):
628    def __enter__(self):
629        return None
630    def __exit__(self, *args):
631        return 0
632
633def with_statement():
634    """
635    >>> with_statement()
636    Python object
637    Python object
638    """
639    x = 1.0
640    with EmptyContextManager() as x:
641        print(typeof(x))
642    print(typeof(x))
643    return x
644
645@cython.final
646cdef class TypedContextManager(object):
647    cpdef double __enter__(self):
648        return 2.0
649    def __exit__(self, *args):
650        return 0
651
652def with_statement_typed():
653    """
654    >>> with_statement_typed()
655    double
656    double
657    2.0
658    """
659    x = 1.0
660    with TypedContextManager() as x:
661        print(typeof(x))
662    print(typeof(x))
663    return x
664
665def with_statement_untyped():
666    """
667    >>> with_statement_untyped()
668    Python object
669    Python object
670    2.0
671    """
672    x = 1.0
673    cdef object t = TypedContextManager()
674    with t as x:
675        print(typeof(x))
676    print(typeof(x))
677    return x
678
679def self_lookup(a):
680    b = a
681    b = b.foo(keyword=None)
682    print typeof(b)
683
684# Regression test for trac #638.
685
686def bar(foo):
687    qux = foo
688    quux = foo[qux.baz]
689
690
691cdef enum MyEnum:
692    enum_x = 1
693    enum_y = 2
694
695ctypedef long my_long
696def test_int_typedef_inference():
697    """
698    >>> test_int_typedef_inference()
699    """
700    cdef long x = 1
701    cdef my_long y = 2
702    cdef long long z = 3
703    assert typeof(x + y) == typeof(y + x) == 'my_long', typeof(x + y)
704    assert typeof(y + z) == typeof(z + y) == 'long long', typeof(y + z)
705
706from libc.stdint cimport int32_t, int64_t
707def int64_long_sum():
708    cdef long x = 1
709    cdef int32_t x32 = 2
710    cdef int64_t x64 = 3
711    cdef unsigned long ux = 4
712    assert typeof(x + x32) == typeof(x32 + x) == 'long', typeof(x + x32)
713    assert typeof(x + x64) == typeof(x64 + x) == 'int64_t', typeof(x + x64)
714    # The correct answer here is either unsigned long or int64_t, depending on
715    # whether sizeof(long) == 64 or not.  Incorrect signedness is probably
716    # preferable to incorrect width.
717    assert typeof(ux + x64) == typeof(x64 + ux) == 'int64_t', typeof(ux + x64)
718
719cdef class InferInProperties:
720    """
721    >>> InferInProperties().x
722    ('double', 'unicode object', 'MyEnum', 'MyEnum')
723    """
724    cdef MyEnum attr
725    def __cinit__(self):
726        self.attr = enum_x
727
728    property x:
729        def __get__(self):
730            a = 1.0
731            b = u'abc'
732            c = self.attr
733            d = enum_y
734            c = d
735            return typeof(a), typeof(b), typeof(c), typeof(d)
736
737cdef class WithMethods:
738    cdef int offset
739    def __init__(self, offset):
740        self.offset = offset
741    cpdef int one_arg(self, int x):
742        return x + self.offset
743    cpdef int default_arg(self, int x, int y=0):
744        return x + y + self.offset
745
746def test_bound_methods():
747  """
748  >>> test_bound_methods()
749  """
750  o = WithMethods(10)
751  assert typeof(o) == 'WithMethods', typeof(o)
752
753  one_arg = o.one_arg
754  assert one_arg(2) == 12, one_arg(2)
755
756  default_arg = o.default_arg
757  assert default_arg(2) == 12, default_arg(2)
758  assert default_arg(2, 3) == 15, default_arg(2, 2)
759