@@ -172,23 +172,20 @@ static zend_always_inline zend_bool zend_iterable_compatibility_check(zend_arg_i
172
172
if (ZEND_TYPE_CODE (arg_info -> type ) == IS_ARRAY ) {
173
173
return 1 ;
174
174
}
175
-
175
+
176
176
if (ZEND_TYPE_IS_CLASS (arg_info -> type ) && zend_string_equals_literal_ci (ZEND_TYPE_NAME (arg_info -> type ), "Traversable" )) {
177
177
return 1 ;
178
178
}
179
-
179
+
180
180
return 0 ;
181
181
}
182
182
/* }}} */
183
183
184
184
static int zend_do_perform_type_hint_check (const zend_function * fe , zend_arg_info * fe_arg_info , const zend_function * proto , zend_arg_info * proto_arg_info ) /* {{{ */
185
185
{
186
- if (ZEND_LOG_XOR (ZEND_TYPE_IS_CLASS (fe_arg_info -> type ), ZEND_TYPE_IS_CLASS (proto_arg_info -> type ))) {
187
- /* Only one has a type declaration and the other one doesn't */
188
- return 0 ;
189
- }
186
+ ZEND_ASSERT (ZEND_TYPE_IS_SET (fe_arg_info -> type ) && ZEND_TYPE_IS_SET (proto_arg_info -> type ));
190
187
191
- if (ZEND_TYPE_IS_CLASS (fe_arg_info -> type )) {
188
+ if (ZEND_TYPE_IS_CLASS (fe_arg_info -> type ) && ZEND_TYPE_IS_CLASS ( proto_arg_info -> type ) ) {
192
189
zend_string * fe_class_name , * proto_class_name ;
193
190
const char * class_name ;
194
191
@@ -237,14 +234,30 @@ static int zend_do_perform_type_hint_check(const zend_function *fe, zend_arg_inf
237
234
zend_string_release (proto_class_name );
238
235
zend_string_release (fe_class_name );
239
236
} else if (ZEND_TYPE_CODE (fe_arg_info -> type ) != ZEND_TYPE_CODE (proto_arg_info -> type )) {
240
- /* Incompatible type */
237
+ /* Incompatible built-in types */
241
238
return 0 ;
242
239
}
243
240
244
241
return 1 ;
245
242
}
246
243
/* }}} */
247
244
245
+ static int zend_do_perform_arg_type_hint_check (const zend_function * fe , zend_arg_info * fe_arg_info , const zend_function * proto , zend_arg_info * proto_arg_info ) /* {{{ */
246
+ {
247
+ if (!ZEND_TYPE_IS_SET (fe_arg_info -> type )) {
248
+ /* Child with no type is always compatible */
249
+ return 1 ;
250
+ }
251
+
252
+ if (!ZEND_TYPE_IS_SET (proto_arg_info -> type )) {
253
+ /* Child defines a type, but parent doesn't, violates LSP */
254
+ return 0 ;
255
+ }
256
+
257
+ return zend_do_perform_type_hint_check (fe , fe_arg_info , proto , proto_arg_info );
258
+ }
259
+ /* }}} */
260
+
248
261
static zend_bool zend_do_perform_implementation_check (const zend_function * fe , const zend_function * proto ) /* {{{ */
249
262
{
250
263
uint32_t i , num_args ;
@@ -312,15 +325,15 @@ static zend_bool zend_do_perform_implementation_check(const zend_function *fe, c
312
325
} else {
313
326
proto_arg_info = & proto -> common .arg_info [proto -> common .num_args ];
314
327
}
315
-
316
- if (!zend_do_perform_type_hint_check (fe , fe_arg_info , proto , proto_arg_info )) {
328
+
329
+ if (!zend_do_perform_arg_type_hint_check (fe , fe_arg_info , proto , proto_arg_info )) {
317
330
switch (ZEND_TYPE_CODE (fe_arg_info -> type )) {
318
331
case IS_ITERABLE :
319
332
if (!zend_iterable_compatibility_check (proto_arg_info )) {
320
333
return 0 ;
321
334
}
322
335
break ;
323
-
336
+
324
337
default :
325
338
return 0 ;
326
339
}
@@ -345,15 +358,15 @@ static zend_bool zend_do_perform_implementation_check(const zend_function *fe, c
345
358
if (!(fe -> common .fn_flags & ZEND_ACC_HAS_RETURN_TYPE )) {
346
359
return 0 ;
347
360
}
348
-
361
+
349
362
if (!zend_do_perform_type_hint_check (fe , fe -> common .arg_info - 1 , proto , proto -> common .arg_info - 1 )) {
350
363
switch (ZEND_TYPE_CODE (proto -> common .arg_info [-1 ].type )) {
351
364
case IS_ITERABLE :
352
365
if (!zend_iterable_compatibility_check (fe -> common .arg_info - 1 )) {
353
366
return 0 ;
354
367
}
355
368
break ;
356
-
369
+
357
370
default :
358
371
return 0 ;
359
372
}
0 commit comments