1--TEST--
2Return type check elision
3--INI--
4opcache.enable=1
5opcache.enable_cli=1
6opcache.optimization_level=-1
7opcache.opt_debug_level=0x20000
8opcache.preload=
9--EXTENSIONS--
10opcache
11--XFAIL--
12Return types cannot be inferred through prototypes
13--FILE--
14<?php
15
16class Test1 {
17    final public function getIntOrFloat(int $i): int|float {
18        return $i;
19    }
20    final public function getInt(): int {
21        return $this->getIntOrFloat();
22    }
23}
24
25class Test2 {
26    public function getInt(): int {
27        return 42;
28    }
29    public function getInt2(): int {
30        return $this->getInt();
31    }
32    public function getIntOrFloat(int $i): int|float {
33        return $i;
34    }
35    public function getInt3(int $i): int {
36        // Should not elide return type check. Test2::getIntOrFloat() returns only int,
37        // but a child method may return int|float.
38        return $this->getIntOrFloat($i);
39    }
40}
41
42class Test3 {
43    private function getBool() {
44        return true;
45    }
46
47    private function getBool2(): bool {
48        return $this->getBool();
49    }
50}
51
52function getClassUnion(): stdClass|FooBar {
53    return new stdClass;
54}
55
56function getClassIntersection(): Traversable&Countable {
57    return new ArrayObject;
58}
59
60?>
61--EXPECTF--
62$_main:
63     ; (lines=1, args=0, vars=0, tmps=0)
64     ; (after optimizer)
65     ; %s
660000 RETURN int(1)
67
68getClassUnion:
69     ; (lines=3, args=0, vars=0, tmps=1)
70     ; (after optimizer)
71     ; %s
720000 V0 = NEW 0 string("stdClass")
730001 DO_FCALL
740002 RETURN V0
75LIVE RANGES:
76     0: 0001 - 0002 (new)
77
78getClassIntersection:
79     ; (lines=3, args=0, vars=0, tmps=1)
80     ; (after optimizer)
81     ; %s
820000 V0 = NEW 0 string("ArrayObject")
830001 DO_FCALL
840002 RETURN V0
85LIVE RANGES:
86     0: 0001 - 0002 (new)
87
88Test1::getIntOrFloat:
89     ; (lines=2, args=1, vars=1, tmps=0)
90     ; (after optimizer)
91     ; %s
920000 CV0($i) = RECV 1
930001 RETURN CV0($i)
94
95Test1::getInt:
96     ; (lines=3, args=0, vars=0, tmps=1)
97     ; (after optimizer)
98     ; %s
990000 INIT_METHOD_CALL 0 THIS string("getIntOrFloat")
1000001 V0 = DO_UCALL
1010002 RETURN V0
102
103Test2::getInt:
104     ; (lines=1, args=0, vars=0, tmps=0)
105     ; (after optimizer)
106     ; %s
1070000 RETURN int(42)
108
109Test2::getInt2:
110     ; (lines=3, args=0, vars=0, tmps=1)
111     ; (after optimizer)
112     ; %s
1130000 INIT_METHOD_CALL 0 THIS string("getInt")
1140001 V0 = DO_FCALL
1150002 RETURN V0
116
117Test2::getIntOrFloat:
118     ; (lines=2, args=1, vars=1, tmps=0)
119     ; (after optimizer)
120     ; %s
1210000 CV0($i) = RECV 1
1220001 RETURN CV0($i)
123
124Test2::getInt3:
125     ; (lines=6, args=1, vars=1, tmps=1)
126     ; (after optimizer)
127     ; %s
1280000 CV0($i) = RECV 1
1290001 INIT_METHOD_CALL 1 THIS string("getIntOrFloat")
1300002 SEND_VAR CV0($i) 1
1310003 V1 = DO_FCALL
1320004 VERIFY_RETURN_TYPE V1
1330005 RETURN V1
134
135Test3::getBool:
136     ; (lines=1, args=0, vars=0, tmps=0)
137     ; (after optimizer)
138     ; %s
1390000 RETURN bool(true)
140
141Test3::getBool2:
142     ; (lines=2, args=0, vars=0, tmps=1)
143     ; (after optimizer)
144     ; %s
1450000 V0 = QM_ASSIGN bool(true)
1460001 RETURN bool(true)
147