Skip to content

Commit 92e83c8

Browse files
committed
Separate out trait constants inheritance and simplify outputting error message
1 parent 4736c5e commit 92e83c8

File tree

9 files changed

+106
-69
lines changed

9 files changed

+106
-69
lines changed

Zend/tests/traits/constant_005.phpt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,4 +19,4 @@ echo "POST-CLASS-GUARD\n";
1919
--EXPECTF--
2020
PRE-CLASS-GUARD
2121

22-
Fatal error: ComposingClass and TestTrait define the same constant (Constant). However, the definition differs and is considered incompatible. Class was composed in %s on line %d
22+
Fatal error: ComposingClass and TestTrait define the same constant (Constant) in the composition of ComposingClass. However, the definition differs and is considered incompatible. Class was composed in %s on line %d

Zend/tests/traits/constant_006.phpt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,4 +19,4 @@ echo "POST-CLASS-GUARD\n";
1919
--EXPECTF--
2020
PRE-CLASS-GUARD
2121

22-
Fatal error: ComposingClass and TestTrait define the same constant (Constant). However, the definition differs and is considered incompatible. Class was composed in %s on line %d
22+
Fatal error: ComposingClass and TestTrait define the same constant (Constant) in the composition of ComposingClass. However, the definition differs and is considered incompatible. Class was composed in %s on line %d

Zend/tests/traits/constant_007.phpt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,4 +19,4 @@ echo "POST-CLASS-GUARD\n";
1919
--EXPECTF--
2020
PRE-CLASS-GUARD
2121

22-
Fatal error: ComposingClass and TestTrait define the same constant (Constant). However, the definition differs and is considered incompatible. Class was composed in %s on line %d
22+
Fatal error: ComposingClass and TestTrait define the same constant (Constant) in the composition of ComposingClass. However, the definition differs and is considered incompatible. Class was composed in %s on line %d

Zend/tests/traits/constant_010.phpt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,4 +19,4 @@ echo "POST-CLASS-GUARD\n";
1919
--EXPECTF--
2020
PRE-CLASS-GUARD
2121

22-
Fatal error: ComposingClass and TestTrait define the same constant (Constant). However, the definition differs and is considered incompatible. Class was composed in %s on line %d
22+
Fatal error: ComposingClass and TestTrait define the same constant (Constant) in the composition of ComposingClass. However, the definition differs and is considered incompatible. Class was composed in %s on line %d

Zend/tests/traits/constant_011.phpt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,4 +13,4 @@ trait Trait2 {
1313
}
1414
?>
1515
--EXPECTF--
16-
Fatal error: Trait2 and Trait1 define the same constant (Constant). However, the definition differs and is considered incompatible. Class was composed in %s on line %d
16+
Fatal error: Trait2 and Trait1 define the same constant (Constant) in the composition of Trait2. However, the definition differs and is considered incompatible. Class was composed in %s on line %d

Zend/tests/traits/constant_012.phpt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,4 +13,4 @@ trait Trait2 {
1313
}
1414
?>
1515
--EXPECTF--
16-
Fatal error: Trait2 and Trait1 define the same constant (Constant). However, the definition differs and is considered incompatible. Class was composed in %s on line %d
16+
Fatal error: Trait2 and Trait1 define the same constant (Constant) in the composition of Trait2. However, the definition differs and is considered incompatible. Class was composed in %s on line %d

Zend/tests/traits/constant_013.phpt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,4 +13,4 @@ trait Trait2 {
1313
}
1414
?>
1515
--EXPECTF--
16-
Fatal error: Trait2 and Trait1 define the same constant (Constant). However, the definition differs and is considered incompatible. Class was composed in %s on line %d
16+
Fatal error: Trait2 and Trait1 define the same constant (Constant) in the composition of Trait2. However, the definition differs and is considered incompatible. Class was composed in %s on line %d

Zend/tests/traits/constant_014.phpt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,4 +18,4 @@ class DerivedClass extends ComposingClass {
1818

1919
?>
2020
--EXPECTF--
21-
Fatal error: DerivedClass::Constant cannot override final constant TestTrait::Constant in %s on line %d
21+
Fatal error: DerivedClass::Constant cannot override final constant ComposingClass::Constant in %s on line %d

Zend/zend_inheritance.c

Lines changed: 98 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -1670,63 +1670,34 @@ static bool do_inherit_constant_check(
16701670

16711671
zend_class_constant *old_constant = Z_PTR_P(zv);
16721672

1673-
if (parent_constant->ce->ce_flags & ZEND_ACC_TRAIT) {
1674-
bool compatible = false;
1675-
uint32_t flags_mask = ZEND_ACC_PPP_MASK | ZEND_ACC_FINAL;
1676-
1677-
if (parent_constant->ce == old_constant->ce) {
1678-
return true;
1679-
}
1680-
if ((ZEND_CLASS_CONST_FLAGS(parent_constant) & flags_mask) == (ZEND_CLASS_CONST_FLAGS(old_constant) & flags_mask)) {
1681-
compatible = check_trait_property_or_constant_value_compatibility(ce, &parent_constant->value, &old_constant->value);
1682-
}
1683-
if (!compatible) {
1684-
if (old_constant->ce != ce) {
1685-
zend_error_noreturn(E_COMPILE_ERROR,
1686-
"%s and %s define the same constant (%s) in the composition of %s. However, the definition differs and is considered incompatible. Class was composed",
1687-
ZSTR_VAL(old_constant->ce->name),
1688-
ZSTR_VAL(parent_constant->ce->name),
1689-
ZSTR_VAL(name),
1690-
ZSTR_VAL(ce->name));
1691-
} else {
1692-
zend_error_noreturn(E_COMPILE_ERROR,
1693-
"%s and %s define the same constant (%s). However, the definition differs and is considered incompatible. Class was composed",
1694-
ZSTR_VAL(old_constant->ce->name),
1695-
ZSTR_VAL(parent_constant->ce->name),
1696-
ZSTR_VAL(name));
1697-
}
1698-
}
1699-
return compatible;
1700-
} else {
1701-
if (parent_constant->ce != old_constant->ce && (ZEND_CLASS_CONST_FLAGS(parent_constant) & ZEND_ACC_FINAL)) {
1702-
zend_error_noreturn(E_COMPILE_ERROR, "%s::%s cannot override final constant %s::%s",
1703-
ZSTR_VAL(old_constant->ce->name), ZSTR_VAL(name),
1704-
ZSTR_VAL(parent_constant->ce->name), ZSTR_VAL(name)
1705-
);
1706-
}
1673+
if (parent_constant->ce != old_constant->ce && (ZEND_CLASS_CONST_FLAGS(parent_constant) & ZEND_ACC_FINAL)) {
1674+
zend_error_noreturn(E_COMPILE_ERROR, "%s::%s cannot override final constant %s::%s",
1675+
ZSTR_VAL(old_constant->ce->name), ZSTR_VAL(name),
1676+
ZSTR_VAL(parent_constant->ce->name), ZSTR_VAL(name)
1677+
);
1678+
}
17071679

1708-
if (old_constant->ce != parent_constant->ce && old_constant->ce != ce) {
1709-
zend_error_noreturn(E_COMPILE_ERROR,
1710-
"%s %s inherits both %s::%s and %s::%s, which is ambiguous",
1711-
zend_get_object_type_uc(ce),
1712-
ZSTR_VAL(ce->name),
1713-
ZSTR_VAL(old_constant->ce->name), ZSTR_VAL(name),
1714-
ZSTR_VAL(parent_constant->ce->name), ZSTR_VAL(name));
1715-
}
1680+
if (old_constant->ce != parent_constant->ce && old_constant->ce != ce) {
1681+
zend_error_noreturn(E_COMPILE_ERROR,
1682+
"%s %s inherits both %s::%s and %s::%s, which is ambiguous",
1683+
zend_get_object_type_uc(ce),
1684+
ZSTR_VAL(ce->name),
1685+
ZSTR_VAL(old_constant->ce->name), ZSTR_VAL(name),
1686+
ZSTR_VAL(parent_constant->ce->name), ZSTR_VAL(name));
17161687
}
17171688

17181689
return false;
17191690
}
17201691
/* }}} */
17211692

1722-
static void do_inherit_trait_or_interface_constant(zend_string *name, zend_class_constant *c, zend_class_entry *ce, zend_class_entry *trait_or_interface) /* {{{ */
1693+
static void do_inherit_interface_constant(zend_string *name, zend_class_constant *c, zend_class_entry *ce, zend_class_entry *iface) /* {{{ */
17231694
{
17241695
if (do_inherit_constant_check(ce, c, name)) {
17251696
zend_class_constant *ct;
17261697
if (Z_TYPE(c->value) == IS_CONSTANT_AST) {
17271698
ce->ce_flags &= ~ZEND_ACC_CONSTANTS_UPDATED;
17281699
ce->ce_flags |= ZEND_ACC_HAS_AST_CONSTANTS;
1729-
if (trait_or_interface->ce_flags & ZEND_ACC_IMMUTABLE) {
1700+
if (iface->ce_flags & ZEND_ACC_IMMUTABLE) {
17301701
ct = zend_arena_alloc(&CG(arena), sizeof(zend_class_constant));
17311702
memcpy(ct, c, sizeof(zend_class_constant));
17321703
c = ct;
@@ -1737,19 +1708,6 @@ static void do_inherit_trait_or_interface_constant(zend_string *name, zend_class
17371708
ct = pemalloc(sizeof(zend_class_constant), 1);
17381709
memcpy(ct, c, sizeof(zend_class_constant));
17391710
c = ct;
1740-
} else if (trait_or_interface->ce_flags & ZEND_ACC_TRAIT) {
1741-
ct = emalloc(sizeof(zend_class_constant));
1742-
memcpy(ct, c, sizeof(zend_class_constant));
1743-
c = ct;
1744-
}
1745-
1746-
if (trait_or_interface->ce_flags & ZEND_ACC_TRAIT) {
1747-
c->ce = ce;
1748-
Z_TRY_ADDREF(c->value);
1749-
c->doc_comment = c->doc_comment ? zend_string_copy(c->doc_comment) : NULL;
1750-
if (c->attributes && (!(GC_FLAGS(c->attributes) & IS_ARRAY_IMMUTABLE))) {
1751-
GC_ADDREF(c->attributes);
1752-
}
17531711
}
17541712

17551713
zend_hash_update_ptr(&ce->constants_table, name, c);
@@ -1764,7 +1722,7 @@ static void do_interface_implementation(zend_class_entry *ce, zend_class_entry *
17641722
zend_class_constant *c;
17651723

17661724
ZEND_HASH_MAP_FOREACH_STR_KEY_PTR(&iface->constants_table, key, c) {
1767-
do_inherit_trait_or_interface_constant(key, c, ce, iface);
1725+
do_inherit_interface_constant(key, c, ce, iface);
17681726
} ZEND_HASH_FOREACH_END();
17691727

17701728
ZEND_HASH_MAP_FOREACH_STR_KEY_PTR(&iface->function_table, key, func) {
@@ -2248,7 +2206,7 @@ static void zend_do_traits_method_binding(zend_class_entry *ce, zend_class_entry
22482206
}
22492207
/* }}} */
22502208

2251-
static zend_class_entry* find_first_definition(zend_class_entry *ce, zend_class_entry **traits, size_t current_trait, zend_string *prop_name, zend_class_entry *colliding_ce) /* {{{ */
2209+
static zend_class_entry* find_first_property_definition(zend_class_entry *ce, zend_class_entry **traits, size_t current_trait, zend_string *prop_name, zend_class_entry *colliding_ce) /* {{{ */
22522210
{
22532211
size_t i;
22542212

@@ -2265,6 +2223,85 @@ static zend_class_entry* find_first_definition(zend_class_entry *ce, zend_class_
22652223
}
22662224
/* }}} */
22672225

2226+
static zend_class_entry* find_first_constant_definition(zend_class_entry *ce, zend_class_entry **traits, size_t current_trait, zend_string *constant_name, zend_class_entry *colliding_ce) /* {{{ */
2227+
{
2228+
size_t i;
2229+
2230+
if (colliding_ce == ce) {
2231+
for (i = 0; i < current_trait; i++) {
2232+
if (traits[i]
2233+
&& zend_hash_exists(&traits[i]->constants_table, constant_name)) {
2234+
return traits[i];
2235+
}
2236+
}
2237+
}
2238+
2239+
return colliding_ce;
2240+
}
2241+
/* }}} */
2242+
2243+
static bool do_trait_constant_check(
2244+
zend_class_entry *ce, zend_class_constant *trait_constant, zend_string *name, zend_class_entry **traits, size_t current_trait
2245+
) {
2246+
bool compatible = false;
2247+
uint32_t flags_mask = ZEND_ACC_PPP_MASK | ZEND_ACC_FINAL;
2248+
2249+
zval *zv = zend_hash_find_known_hash(&ce->constants_table, name);
2250+
if (zv == NULL) {
2251+
return true;
2252+
}
2253+
2254+
zend_class_constant *old_constant = Z_PTR_P(zv);
2255+
2256+
if (trait_constant->ce == old_constant->ce) {
2257+
return true;
2258+
}
2259+
if ((ZEND_CLASS_CONST_FLAGS(trait_constant) & flags_mask) == (ZEND_CLASS_CONST_FLAGS(old_constant) & flags_mask)) {
2260+
compatible = check_trait_property_or_constant_value_compatibility(ce, &trait_constant->value, &old_constant->value);
2261+
}
2262+
if (!compatible) {
2263+
zend_error_noreturn(E_COMPILE_ERROR,
2264+
"%s and %s define the same constant (%s) in the composition of %s. However, the definition differs and is considered incompatible. Class was composed",
2265+
ZSTR_VAL(find_first_constant_definition(ce, traits, current_trait, name, old_constant->ce)->name),
2266+
ZSTR_VAL(trait_constant->ce->name),
2267+
ZSTR_VAL(name),
2268+
ZSTR_VAL(ce->name));
2269+
}
2270+
return compatible;
2271+
}
2272+
/* }}} */
2273+
2274+
static void do_inherit_trait_constant(zend_string *name, zend_class_constant *c, zend_class_entry *ce, zend_class_entry **traits, size_t current_trait) /* {{{ */
2275+
{
2276+
if (do_trait_constant_check(ce, c, name, traits, current_trait)) {
2277+
zend_class_constant *ct;
2278+
if (Z_TYPE(c->value) == IS_CONSTANT_AST) {
2279+
ce->ce_flags &= ~ZEND_ACC_CONSTANTS_UPDATED;
2280+
ce->ce_flags |= ZEND_ACC_HAS_AST_CONSTANTS;
2281+
if (traits[current_trait]->ce_flags & ZEND_ACC_IMMUTABLE) {
2282+
ct = zend_arena_alloc(&CG(arena), sizeof(zend_class_constant));
2283+
memcpy(ct, c, sizeof(zend_class_constant));
2284+
c = ct;
2285+
Z_CONSTANT_FLAGS(c->value) |= CONST_OWNED;
2286+
}
2287+
}
2288+
2289+
ct = emalloc(sizeof(zend_class_constant));
2290+
memcpy(ct, c, sizeof(zend_class_constant));
2291+
c = ct;
2292+
2293+
c->ce = ce;
2294+
Z_TRY_ADDREF(c->value);
2295+
c->doc_comment = c->doc_comment ? zend_string_copy(c->doc_comment) : NULL;
2296+
if (c->attributes && (!(GC_FLAGS(c->attributes) & IS_ARRAY_IMMUTABLE))) {
2297+
GC_ADDREF(c->attributes);
2298+
}
2299+
2300+
zend_hash_update_ptr(&ce->constants_table, name, c);
2301+
}
2302+
}
2303+
/* }}} */
2304+
22682305
static void zend_do_traits_property_and_constant_binding(zend_class_entry *ce, zend_class_entry **traits) /* {{{ */
22692306
{
22702307
size_t i;
@@ -2287,7 +2324,7 @@ static void zend_do_traits_property_and_constant_binding(zend_class_entry *ce, z
22872324
continue;
22882325
}
22892326
ZEND_HASH_MAP_FOREACH_STR_KEY_PTR(&traits[i]->constants_table, constant_name, constant) {
2290-
do_inherit_trait_or_interface_constant(constant_name, constant, ce, traits[i]);
2327+
do_inherit_trait_constant(constant_name, constant, ce, traits, i);
22912328
} ZEND_HASH_FOREACH_END();
22922329

22932330
ZEND_HASH_MAP_FOREACH_STR_KEY_PTR(&traits[i]->properties_info, prop_name, property_info) {
@@ -2323,7 +2360,7 @@ static void zend_do_traits_property_and_constant_binding(zend_class_entry *ce, z
23232360
if (!compatible) {
23242361
zend_error_noreturn(E_COMPILE_ERROR,
23252362
"%s and %s define the same property ($%s) in the composition of %s. However, the definition differs and is considered incompatible. Class was composed",
2326-
ZSTR_VAL(find_first_definition(ce, traits, i, prop_name, colliding_prop->ce)->name),
2363+
ZSTR_VAL(find_first_property_definition(ce, traits, i, prop_name, colliding_prop->ce)->name),
23272364
ZSTR_VAL(property_info->ce->name),
23282365
ZSTR_VAL(prop_name),
23292366
ZSTR_VAL(ce->name));

0 commit comments

Comments
 (0)