@@ -1242,7 +1242,7 @@ static void do_inherit_method(zend_string *key, zend_function *parent, zend_clas
1242
1242
}
1243
1243
/* }}} */
1244
1244
1245
- static inheritance_status property_types_compatible (
1245
+ static inheritance_status full_property_types_compatible (
1246
1246
const zend_property_info * parent_info , const zend_property_info * child_info ,
1247
1247
prop_variance variance ) {
1248
1248
if (ZEND_TYPE_PURE_MASK (parent_info -> type ) == ZEND_TYPE_PURE_MASK (child_info -> type )
@@ -1284,6 +1284,49 @@ static void emit_incompatible_property_error(
1284
1284
ZSTR_VAL (parent -> ce -> name ));
1285
1285
}
1286
1286
1287
+ static void emit_set_hook_type_error (
1288
+ const zend_property_info * child , const zend_property_info * parent
1289
+ ) {
1290
+ zend_type set_type = parent -> hooks [ZEND_PROPERTY_HOOK_SET ]-> common .arg_info [0 ].type ;
1291
+ zend_string * type_str = zend_type_to_string_resolved (set_type , parent -> ce );
1292
+ zend_error_noreturn (E_COMPILE_ERROR ,
1293
+ "Set type of %s::$%s must be supertype of %s (as in %s %s)" ,
1294
+ ZSTR_VAL (child -> ce -> name ),
1295
+ zend_get_unmangled_property_name (child -> name ),
1296
+ ZSTR_VAL (type_str ),
1297
+ zend_get_object_type_case (parent -> ce , false),
1298
+ ZSTR_VAL (parent -> ce -> name ));
1299
+ }
1300
+
1301
+ static inheritance_status property_types_compatible (
1302
+ const zend_property_info * parent_info ,
1303
+ const zend_property_info * child_info ,
1304
+ prop_variance variance ,
1305
+ bool throw_on_error ,
1306
+ bool throw_on_unresolved
1307
+ ) {
1308
+ inheritance_status result = full_property_types_compatible (parent_info , child_info , variance );
1309
+ if ((result == INHERITANCE_ERROR && throw_on_error ) || (result == INHERITANCE_UNRESOLVED && throw_on_unresolved )) {
1310
+ emit_incompatible_property_error (child_info , parent_info , variance );
1311
+ }
1312
+ if (result != INHERITANCE_SUCCESS ) {
1313
+ return result ;
1314
+ }
1315
+ if (parent_info -> flags & ZEND_ACC_ABSTRACT ) {
1316
+ ZEND_ASSERT (parent_info -> hooks );
1317
+ if (parent_info -> hooks [ZEND_PROPERTY_HOOK_SET ]
1318
+ && (!child_info -> hooks || !child_info -> hooks [ZEND_PROPERTY_HOOK_SET ])) {
1319
+ zend_type set_type = parent_info -> hooks [ZEND_PROPERTY_HOOK_SET ]-> common .arg_info [0 ].type ;
1320
+ inheritance_status result = zend_perform_covariant_type_check (
1321
+ parent_info -> ce , set_type , child_info -> ce , child_info -> type );
1322
+ if ((result == INHERITANCE_ERROR && throw_on_error ) || (result == INHERITANCE_UNRESOLVED && throw_on_unresolved )) {
1323
+ emit_set_hook_type_error (child_info , parent_info );
1324
+ }
1325
+ }
1326
+ }
1327
+ return INHERITANCE_SUCCESS ;
1328
+ }
1329
+
1287
1330
static bool property_has_operation (zend_property_info * prop_info , zend_property_hook_kind kind )
1288
1331
{
1289
1332
return (!(prop_info -> flags & ZEND_ACC_VIRTUAL )
@@ -1428,10 +1471,7 @@ static void do_inherit_property(zend_property_info *parent_info, zend_string *ke
1428
1471
prop_variance variance = prop_get_variance (parent_info );
1429
1472
if (ZEND_TYPE_IS_SET (parent_info -> type )) {
1430
1473
inheritance_status status = property_types_compatible (
1431
- parent_info , child_info , variance );
1432
- if (status == INHERITANCE_ERROR ) {
1433
- emit_incompatible_property_error (child_info , parent_info , variance );
1434
- }
1474
+ parent_info , child_info , variance , true, false);
1435
1475
if (status == INHERITANCE_UNRESOLVED ) {
1436
1476
add_property_compatibility_obligation (ce , child_info , parent_info , variance );
1437
1477
}
@@ -2747,7 +2787,7 @@ static void zend_do_traits_property_binding(zend_class_entry *ce, zend_class_ent
2747
2787
}
2748
2788
2749
2789
if ((colliding_prop -> flags & flags_mask ) == (flags & flags_mask ) &&
2750
- property_types_compatible (property_info , colliding_prop , PROP_INVARIANT ) == INHERITANCE_SUCCESS
2790
+ property_types_compatible (property_info , colliding_prop , PROP_INVARIANT , false, false ) == INHERITANCE_SUCCESS
2751
2791
) {
2752
2792
/* the flags are identical, thus, the properties may be compatible */
2753
2793
zval * op1 , * op2 ;
@@ -3098,11 +3138,7 @@ static void check_variance_obligation(variance_obligation *obligation) {
3098
3138
}
3099
3139
/* Either the compatibility check was successful or only threw a warning. */
3100
3140
} else if (obligation -> type == OBLIGATION_PROPERTY_COMPATIBILITY ) {
3101
- inheritance_status status =
3102
- property_types_compatible (obligation -> parent_prop , obligation -> child_prop , obligation -> variance );
3103
- if (status != INHERITANCE_SUCCESS ) {
3104
- emit_incompatible_property_error (obligation -> child_prop , obligation -> parent_prop , obligation -> variance );
3105
- }
3141
+ property_types_compatible (obligation -> parent_prop , obligation -> child_prop , obligation -> variance , true, true);
3106
3142
} else if (obligation -> type == OBLIGATION_CLASS_CONSTANT_COMPATIBILITY ) {
3107
3143
inheritance_status status =
3108
3144
class_constant_types_compatible (obligation -> parent_const , obligation -> child_const );
@@ -3644,8 +3680,7 @@ static inheritance_status zend_can_early_bind(zend_class_entry *ce, zend_class_e
3644
3680
if (zv ) {
3645
3681
zend_property_info * child_info = Z_PTR_P (zv );
3646
3682
if (ZEND_TYPE_IS_SET (child_info -> type )) {
3647
- inheritance_status status = property_types_compatible (parent_info , child_info , prop_get_variance (parent_info ));
3648
- ZEND_ASSERT (status != INHERITANCE_WARNING );
3683
+ inheritance_status status = property_types_compatible (parent_info , child_info , prop_get_variance (parent_info ), false, false);
3649
3684
if (UNEXPECTED (status != INHERITANCE_SUCCESS )) {
3650
3685
return status ;
3651
3686
}
0 commit comments