Skip to content

Commit b6cec55

Browse files
committed
Separate out trait constants inheritance and simplify outputting error message
1 parent 2ab94b1 commit b6cec55

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
@@ -1601,63 +1601,34 @@ static bool do_inherit_constant_check(
16011601

16021602
zend_class_constant *old_constant = Z_PTR_P(zv);
16031603

1604-
if (parent_constant->ce->ce_flags & ZEND_ACC_TRAIT) {
1605-
bool compatible = false;
1606-
uint32_t flags_mask = ZEND_ACC_PPP_MASK | ZEND_ACC_FINAL;
1607-
1608-
if (parent_constant->ce == old_constant->ce) {
1609-
return true;
1610-
}
1611-
if ((ZEND_CLASS_CONST_FLAGS(parent_constant) & flags_mask) == (ZEND_CLASS_CONST_FLAGS(old_constant) & flags_mask)) {
1612-
compatible = check_trait_property_or_constant_value_compatibility(ce, &parent_constant->value, &old_constant->value);
1613-
}
1614-
if (!compatible) {
1615-
if (old_constant->ce != ce) {
1616-
zend_error_noreturn(E_COMPILE_ERROR,
1617-
"%s and %s define the same constant (%s) in the composition of %s. However, the definition differs and is considered incompatible. Class was composed",
1618-
ZSTR_VAL(old_constant->ce->name),
1619-
ZSTR_VAL(parent_constant->ce->name),
1620-
ZSTR_VAL(name),
1621-
ZSTR_VAL(ce->name));
1622-
} else {
1623-
zend_error_noreturn(E_COMPILE_ERROR,
1624-
"%s and %s define the same constant (%s). However, the definition differs and is considered incompatible. Class was composed",
1625-
ZSTR_VAL(old_constant->ce->name),
1626-
ZSTR_VAL(parent_constant->ce->name),
1627-
ZSTR_VAL(name));
1628-
}
1629-
}
1630-
return compatible;
1631-
} else {
1632-
if (parent_constant->ce != old_constant->ce && (ZEND_CLASS_CONST_FLAGS(parent_constant) & ZEND_ACC_FINAL)) {
1633-
zend_error_noreturn(E_COMPILE_ERROR, "%s::%s cannot override final constant %s::%s",
1634-
ZSTR_VAL(old_constant->ce->name), ZSTR_VAL(name),
1635-
ZSTR_VAL(parent_constant->ce->name), ZSTR_VAL(name)
1636-
);
1637-
}
1604+
if (parent_constant->ce != old_constant->ce && (ZEND_CLASS_CONST_FLAGS(parent_constant) & ZEND_ACC_FINAL)) {
1605+
zend_error_noreturn(E_COMPILE_ERROR, "%s::%s cannot override final constant %s::%s",
1606+
ZSTR_VAL(old_constant->ce->name), ZSTR_VAL(name),
1607+
ZSTR_VAL(parent_constant->ce->name), ZSTR_VAL(name)
1608+
);
1609+
}
16381610

1639-
if (old_constant->ce != parent_constant->ce && old_constant->ce != ce) {
1640-
zend_error_noreturn(E_COMPILE_ERROR,
1641-
"%s %s inherits both %s::%s and %s::%s, which is ambiguous",
1642-
zend_get_object_type_uc(ce),
1643-
ZSTR_VAL(ce->name),
1644-
ZSTR_VAL(old_constant->ce->name), ZSTR_VAL(name),
1645-
ZSTR_VAL(parent_constant->ce->name), ZSTR_VAL(name));
1646-
}
1611+
if (old_constant->ce != parent_constant->ce && old_constant->ce != ce) {
1612+
zend_error_noreturn(E_COMPILE_ERROR,
1613+
"%s %s inherits both %s::%s and %s::%s, which is ambiguous",
1614+
zend_get_object_type_uc(ce),
1615+
ZSTR_VAL(ce->name),
1616+
ZSTR_VAL(old_constant->ce->name), ZSTR_VAL(name),
1617+
ZSTR_VAL(parent_constant->ce->name), ZSTR_VAL(name));
16471618
}
16481619

16491620
return false;
16501621
}
16511622
/* }}} */
16521623

1653-
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) /* {{{ */
1624+
static void do_inherit_interface_constant(zend_string *name, zend_class_constant *c, zend_class_entry *ce, zend_class_entry *iface) /* {{{ */
16541625
{
16551626
if (do_inherit_constant_check(ce, c, name)) {
16561627
zend_class_constant *ct;
16571628
if (Z_TYPE(c->value) == IS_CONSTANT_AST) {
16581629
ce->ce_flags &= ~ZEND_ACC_CONSTANTS_UPDATED;
16591630
ce->ce_flags |= ZEND_ACC_HAS_AST_CONSTANTS;
1660-
if (trait_or_interface->ce_flags & ZEND_ACC_IMMUTABLE) {
1631+
if (iface->ce_flags & ZEND_ACC_IMMUTABLE) {
16611632
ct = zend_arena_alloc(&CG(arena), sizeof(zend_class_constant));
16621633
memcpy(ct, c, sizeof(zend_class_constant));
16631634
c = ct;
@@ -1668,19 +1639,6 @@ static void do_inherit_trait_or_interface_constant(zend_string *name, zend_class
16681639
ct = pemalloc(sizeof(zend_class_constant), 1);
16691640
memcpy(ct, c, sizeof(zend_class_constant));
16701641
c = ct;
1671-
} else if (trait_or_interface->ce_flags & ZEND_ACC_TRAIT) {
1672-
ct = emalloc(sizeof(zend_class_constant));
1673-
memcpy(ct, c, sizeof(zend_class_constant));
1674-
c = ct;
1675-
}
1676-
1677-
if (trait_or_interface->ce_flags & ZEND_ACC_TRAIT) {
1678-
c->ce = ce;
1679-
Z_TRY_ADDREF(c->value);
1680-
c->doc_comment = c->doc_comment ? zend_string_copy(c->doc_comment) : NULL;
1681-
if (c->attributes && (!(GC_FLAGS(c->attributes) & IS_ARRAY_IMMUTABLE))) {
1682-
GC_ADDREF(c->attributes);
1683-
}
16841642
}
16851643

16861644
zend_hash_update_ptr(&ce->constants_table, name, c);
@@ -1695,7 +1653,7 @@ static void do_interface_implementation(zend_class_entry *ce, zend_class_entry *
16951653
zend_class_constant *c;
16961654

16971655
ZEND_HASH_MAP_FOREACH_STR_KEY_PTR(&iface->constants_table, key, c) {
1698-
do_inherit_trait_or_interface_constant(key, c, ce, iface);
1656+
do_inherit_interface_constant(key, c, ce, iface);
16991657
} ZEND_HASH_FOREACH_END();
17001658

17011659
ZEND_HASH_MAP_FOREACH_STR_KEY_PTR(&iface->function_table, key, func) {
@@ -2179,7 +2137,7 @@ static void zend_do_traits_method_binding(zend_class_entry *ce, zend_class_entry
21792137
}
21802138
/* }}} */
21812139

2182-
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) /* {{{ */
2140+
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) /* {{{ */
21832141
{
21842142
size_t i;
21852143

@@ -2196,6 +2154,85 @@ static zend_class_entry* find_first_definition(zend_class_entry *ce, zend_class_
21962154
}
21972155
/* }}} */
21982156

2157+
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) /* {{{ */
2158+
{
2159+
size_t i;
2160+
2161+
if (colliding_ce == ce) {
2162+
for (i = 0; i < current_trait; i++) {
2163+
if (traits[i]
2164+
&& zend_hash_exists(&traits[i]->constants_table, constant_name)) {
2165+
return traits[i];
2166+
}
2167+
}
2168+
}
2169+
2170+
return colliding_ce;
2171+
}
2172+
/* }}} */
2173+
2174+
static bool do_trait_constant_check(
2175+
zend_class_entry *ce, zend_class_constant *trait_constant, zend_string *name, zend_class_entry **traits, size_t current_trait
2176+
) {
2177+
bool compatible = false;
2178+
uint32_t flags_mask = ZEND_ACC_PPP_MASK | ZEND_ACC_FINAL;
2179+
2180+
zval *zv = zend_hash_find_known_hash(&ce->constants_table, name);
2181+
if (zv == NULL) {
2182+
return true;
2183+
}
2184+
2185+
zend_class_constant *old_constant = Z_PTR_P(zv);
2186+
2187+
if (trait_constant->ce == old_constant->ce) {
2188+
return true;
2189+
}
2190+
if ((ZEND_CLASS_CONST_FLAGS(trait_constant) & flags_mask) == (ZEND_CLASS_CONST_FLAGS(old_constant) & flags_mask)) {
2191+
compatible = check_trait_property_or_constant_value_compatibility(ce, &trait_constant->value, &old_constant->value);
2192+
}
2193+
if (!compatible) {
2194+
zend_error_noreturn(E_COMPILE_ERROR,
2195+
"%s and %s define the same constant (%s) in the composition of %s. However, the definition differs and is considered incompatible. Class was composed",
2196+
ZSTR_VAL(find_first_constant_definition(ce, traits, current_trait, name, old_constant->ce)->name),
2197+
ZSTR_VAL(trait_constant->ce->name),
2198+
ZSTR_VAL(name),
2199+
ZSTR_VAL(ce->name));
2200+
}
2201+
return compatible;
2202+
}
2203+
/* }}} */
2204+
2205+
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) /* {{{ */
2206+
{
2207+
if (do_trait_constant_check(ce, c, name, traits, current_trait)) {
2208+
zend_class_constant *ct;
2209+
if (Z_TYPE(c->value) == IS_CONSTANT_AST) {
2210+
ce->ce_flags &= ~ZEND_ACC_CONSTANTS_UPDATED;
2211+
ce->ce_flags |= ZEND_ACC_HAS_AST_CONSTANTS;
2212+
if (traits[current_trait]->ce_flags & ZEND_ACC_IMMUTABLE) {
2213+
ct = zend_arena_alloc(&CG(arena), sizeof(zend_class_constant));
2214+
memcpy(ct, c, sizeof(zend_class_constant));
2215+
c = ct;
2216+
Z_CONSTANT_FLAGS(c->value) |= CONST_OWNED;
2217+
}
2218+
}
2219+
2220+
ct = emalloc(sizeof(zend_class_constant));
2221+
memcpy(ct, c, sizeof(zend_class_constant));
2222+
c = ct;
2223+
2224+
c->ce = ce;
2225+
Z_TRY_ADDREF(c->value);
2226+
c->doc_comment = c->doc_comment ? zend_string_copy(c->doc_comment) : NULL;
2227+
if (c->attributes && (!(GC_FLAGS(c->attributes) & IS_ARRAY_IMMUTABLE))) {
2228+
GC_ADDREF(c->attributes);
2229+
}
2230+
2231+
zend_hash_update_ptr(&ce->constants_table, name, c);
2232+
}
2233+
}
2234+
/* }}} */
2235+
21992236
static void zend_do_traits_property_and_constant_binding(zend_class_entry *ce, zend_class_entry **traits) /* {{{ */
22002237
{
22012238
size_t i;
@@ -2218,7 +2255,7 @@ static void zend_do_traits_property_and_constant_binding(zend_class_entry *ce, z
22182255
continue;
22192256
}
22202257
ZEND_HASH_MAP_FOREACH_STR_KEY_PTR(&traits[i]->constants_table, constant_name, constant) {
2221-
do_inherit_trait_or_interface_constant(constant_name, constant, ce, traits[i]);
2258+
do_inherit_trait_constant(constant_name, constant, ce, traits, i);
22222259
} ZEND_HASH_FOREACH_END();
22232260

22242261
ZEND_HASH_MAP_FOREACH_STR_KEY_PTR(&traits[i]->properties_info, prop_name, property_info) {
@@ -2254,7 +2291,7 @@ static void zend_do_traits_property_and_constant_binding(zend_class_entry *ce, z
22542291
if (!compatible) {
22552292
zend_error_noreturn(E_COMPILE_ERROR,
22562293
"%s and %s define the same property ($%s) in the composition of %s. However, the definition differs and is considered incompatible. Class was composed",
2257-
ZSTR_VAL(find_first_definition(ce, traits, i, prop_name, colliding_prop->ce)->name),
2294+
ZSTR_VAL(find_first_property_definition(ce, traits, i, prop_name, colliding_prop->ce)->name),
22582295
ZSTR_VAL(property_info->ce->name),
22592296
ZSTR_VAL(prop_name),
22602297
ZSTR_VAL(ce->name));

0 commit comments

Comments
 (0)