1--TEST--
2Behavior of union type checks (weak)
3--FILE--
4<?php
5
6function dump($value) {
7    if (is_object($value)) {
8        return 'new ' . get_class($value);
9    }
10    if ($value === INF) {
11        return 'INF';
12    }
13    return json_encode($value, JSON_PRESERVE_ZERO_FRACTION);
14}
15
16function test(string $type, array $values) {
17    $alignment = 16;
18
19    echo "\nType $type:\n";
20    $fn = eval("return function($type \$arg) { return \$arg; };");
21    foreach ($values as $value) {
22        echo str_pad(dump($value), $alignment), ' => ';
23
24        try {
25            error_clear_last();
26            $value = @$fn($value);
27            echo dump($value);
28            if ($e = error_get_last()) {
29                echo ' (', $e['message'], ')';
30            }
31        } catch (TypeError $e) {
32            $msg = $e->getMessage();
33            $msg = strstr($msg, ', called in', true);
34            $msg = str_replace('{closure}(): Argument #1 ($arg)', 'Argument ...', $msg);
35            echo $msg;
36        }
37        echo "\n";
38    }
39}
40
41class WithToString {
42    public function __toString() {
43        return "__toString()";
44    }
45}
46
47$values = [
48    42, 42.0, INF, "42", "42.0", "42x", "x", "",
49    true, false, null, [], new stdClass, new WithToString,
50];
51test('int|float', $values);
52test('int|float|false', $values);
53test('int|float|bool', $values);
54test('int|bool', $values);
55test('int|string|null', $values);
56test('string|bool', $values);
57test('float|array', $values);
58test('string|array', $values);
59test('bool|array', $values);
60
61?>
62--EXPECTF--
63Type int|float:
6442               => 42
6542.0             => 42.0
66INF              => INF
67"42"             => 42
68"42.0"           => 42.0
69"42x"            => {closure:%s:%d}(): Argument #1 ($arg) must be of type int|float, string given
70"x"              => {closure:%s:%d}(): Argument #1 ($arg) must be of type int|float, string given
71""               => {closure:%s:%d}(): Argument #1 ($arg) must be of type int|float, string given
72true             => 1
73false            => 0
74null             => {closure:%s:%d}(): Argument #1 ($arg) must be of type int|float, null given
75[]               => {closure:%s:%d}(): Argument #1 ($arg) must be of type int|float, array given
76new stdClass     => {closure:%s:%d}(): Argument #1 ($arg) must be of type int|float, stdClass given
77new WithToString => {closure:%s:%d}(): Argument #1 ($arg) must be of type int|float, WithToString given
78
79Type int|float|false:
8042               => 42
8142.0             => 42.0
82INF              => INF
83"42"             => 42
84"42.0"           => 42.0
85"42x"            => {closure:%s:%d}(): Argument #1 ($arg) must be of type int|float|false, string given
86"x"              => {closure:%s:%d}(): Argument #1 ($arg) must be of type int|float|false, string given
87""               => {closure:%s:%d}(): Argument #1 ($arg) must be of type int|float|false, string given
88true             => 1
89false            => false
90null             => {closure:%s:%d}(): Argument #1 ($arg) must be of type int|float|false, null given
91[]               => {closure:%s:%d}(): Argument #1 ($arg) must be of type int|float|false, array given
92new stdClass     => {closure:%s:%d}(): Argument #1 ($arg) must be of type int|float|false, stdClass given
93new WithToString => {closure:%s:%d}(): Argument #1 ($arg) must be of type int|float|false, WithToString given
94
95Type int|float|bool:
9642               => 42
9742.0             => 42.0
98INF              => INF
99"42"             => 42
100"42.0"           => 42.0
101"42x"            => true
102"x"              => true
103""               => false
104true             => true
105false            => false
106null             => {closure:%s:%d}(): Argument #1 ($arg) must be of type int|float|bool, null given
107[]               => {closure:%s:%d}(): Argument #1 ($arg) must be of type int|float|bool, array given
108new stdClass     => {closure:%s:%d}(): Argument #1 ($arg) must be of type int|float|bool, stdClass given
109new WithToString => {closure:%s:%d}(): Argument #1 ($arg) must be of type int|float|bool, WithToString given
110
111Type int|bool:
11242               => 42
11342.0             => 42
114INF              => true
115"42"             => 42
116"42.0"           => 42
117"42x"            => true
118"x"              => true
119""               => false
120true             => true
121false            => false
122null             => {closure:%s:%d}(): Argument #1 ($arg) must be of type int|bool, null given
123[]               => {closure:%s:%d}(): Argument #1 ($arg) must be of type int|bool, array given
124new stdClass     => {closure:%s:%d}(): Argument #1 ($arg) must be of type int|bool, stdClass given
125new WithToString => {closure:%s:%d}(): Argument #1 ($arg) must be of type int|bool, WithToString given
126
127Type int|string|null:
12842               => 42
12942.0             => 42
130INF              => "INF"
131"42"             => "42"
132"42.0"           => "42.0"
133"42x"            => "42x"
134"x"              => "x"
135""               => ""
136true             => 1
137false            => 0
138null             => null
139[]               => {closure:%s:%d}(): Argument #1 ($arg) must be of type string|int|null, array given
140new stdClass     => {closure:%s:%d}(): Argument #1 ($arg) must be of type string|int|null, stdClass given
141new WithToString => "__toString()"
142
143Type string|bool:
14442               => "42"
14542.0             => "42"
146INF              => "INF"
147"42"             => "42"
148"42.0"           => "42.0"
149"42x"            => "42x"
150"x"              => "x"
151""               => ""
152true             => true
153false            => false
154null             => {closure:%s:%d}(): Argument #1 ($arg) must be of type string|bool, null given
155[]               => {closure:%s:%d}(): Argument #1 ($arg) must be of type string|bool, array given
156new stdClass     => {closure:%s:%d}(): Argument #1 ($arg) must be of type string|bool, stdClass given
157new WithToString => "__toString()"
158
159Type float|array:
16042               => 42.0
16142.0             => 42.0
162INF              => INF
163"42"             => 42.0
164"42.0"           => 42.0
165"42x"            => {closure:%s:%d}(): Argument #1 ($arg) must be of type array|float, string given
166"x"              => {closure:%s:%d}(): Argument #1 ($arg) must be of type array|float, string given
167""               => {closure:%s:%d}(): Argument #1 ($arg) must be of type array|float, string given
168true             => 1.0
169false            => 0.0
170null             => {closure:%s:%d}(): Argument #1 ($arg) must be of type array|float, null given
171[]               => []
172new stdClass     => {closure:%s:%d}(): Argument #1 ($arg) must be of type array|float, stdClass given
173new WithToString => {closure:%s:%d}(): Argument #1 ($arg) must be of type array|float, WithToString given
174
175Type string|array:
17642               => "42"
17742.0             => "42"
178INF              => "INF"
179"42"             => "42"
180"42.0"           => "42.0"
181"42x"            => "42x"
182"x"              => "x"
183""               => ""
184true             => "1"
185false            => ""
186null             => {closure:%s:%d}(): Argument #1 ($arg) must be of type array|string, null given
187[]               => []
188new stdClass     => {closure:%s:%d}(): Argument #1 ($arg) must be of type array|string, stdClass given
189new WithToString => "__toString()"
190
191Type bool|array:
19242               => true
19342.0             => true
194INF              => true
195"42"             => true
196"42.0"           => true
197"42x"            => true
198"x"              => true
199""               => false
200true             => true
201false            => false
202null             => {closure:%s:%d}(): Argument #1 ($arg) must be of type array|bool, null given
203[]               => []
204new stdClass     => {closure:%s:%d}(): Argument #1 ($arg) must be of type array|bool, stdClass given
205new WithToString => {closure:%s:%d}(): Argument #1 ($arg) must be of type array|bool, WithToString given
206