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