@@ -172,23 +172,20 @@ static zend_always_inline zend_bool zend_iterable_compatibility_check(zend_arg_i
172172 if (ZEND_TYPE_CODE (arg_info -> type ) == IS_ARRAY ) {
173173 return 1 ;
174174 }
175-
175+
176176 if (ZEND_TYPE_IS_CLASS (arg_info -> type ) && zend_string_equals_literal_ci (ZEND_TYPE_NAME (arg_info -> type ), "Traversable" )) {
177177 return 1 ;
178178 }
179-
179+
180180 return 0 ;
181181}
182182/* }}} */
183183
184184static 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 ) /* {{{ */
185185{
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 ));
190187
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 ) ) {
192189 zend_string * fe_class_name , * proto_class_name ;
193190 const char * class_name ;
194191
@@ -237,14 +234,30 @@ static int zend_do_perform_type_hint_check(const zend_function *fe, zend_arg_inf
237234 zend_string_release (proto_class_name );
238235 zend_string_release (fe_class_name );
239236 } else if (ZEND_TYPE_CODE (fe_arg_info -> type ) != ZEND_TYPE_CODE (proto_arg_info -> type )) {
240- /* Incompatible type */
237+ /* Incompatible built-in types */
241238 return 0 ;
242239 }
243240
244241 return 1 ;
245242}
246243/* }}} */
247244
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+
248261static zend_bool zend_do_perform_implementation_check (const zend_function * fe , const zend_function * proto ) /* {{{ */
249262{
250263 uint32_t i , num_args ;
@@ -312,15 +325,15 @@ static zend_bool zend_do_perform_implementation_check(const zend_function *fe, c
312325 } else {
313326 proto_arg_info = & proto -> common .arg_info [proto -> common .num_args ];
314327 }
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 )) {
317330 switch (ZEND_TYPE_CODE (fe_arg_info -> type )) {
318331 case IS_ITERABLE :
319332 if (!zend_iterable_compatibility_check (proto_arg_info )) {
320333 return 0 ;
321334 }
322335 break ;
323-
336+
324337 default :
325338 return 0 ;
326339 }
@@ -345,15 +358,15 @@ static zend_bool zend_do_perform_implementation_check(const zend_function *fe, c
345358 if (!(fe -> common .fn_flags & ZEND_ACC_HAS_RETURN_TYPE )) {
346359 return 0 ;
347360 }
348-
361+
349362 if (!zend_do_perform_type_hint_check (fe , fe -> common .arg_info - 1 , proto , proto -> common .arg_info - 1 )) {
350363 switch (ZEND_TYPE_CODE (proto -> common .arg_info [-1 ].type )) {
351364 case IS_ITERABLE :
352365 if (!zend_iterable_compatibility_check (fe -> common .arg_info - 1 )) {
353366 return 0 ;
354367 }
355368 break ;
356-
369+
357370 default :
358371 return 0 ;
359372 }
0 commit comments