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