@@ -675,20 +675,40 @@ static inheritance_status zend_is_intersection_subtype_of_type(
675
675
return early_exit_status == INHERITANCE_ERROR ? INHERITANCE_SUCCESS : INHERITANCE_ERROR ;
676
676
}
677
677
678
+ ZEND_API inheritance_status zend_perform_covariant_type_check (
679
+ zend_class_entry * fe_scope , const zend_type * fe_type_ptr ,
680
+ zend_class_entry * proto_scope , const zend_type * proto_type_ptr );
681
+
678
682
static inheritance_status zend_is_type_subtype_of_associated_type (
679
683
zend_class_entry * concrete_scope ,
680
684
const zend_type * concrete_type_ptr ,
681
- const zend_type * associated_type_ptr ,
682
- HashTable * associated_types
685
+ zend_class_entry * associated_type_scope ,
686
+ const zend_type * associated_type_ptr
683
687
) {
684
688
const zend_type associated_type = * associated_type_ptr ;
685
- const zend_type concrete_type = * concrete_type_ptr ;
686
689
690
+ ZEND_ASSERT (CG (bound_associated_types ) && "Have associated type" );
687
691
ZEND_ASSERT (ZEND_TYPE_HAS_NAME (associated_type ));
688
692
689
693
zend_string * associated_type_name = ZEND_TYPE_NAME (associated_type );
694
+ const zend_type * bound_type_ptr = zend_hash_find_ptr (CG (bound_associated_types ), associated_type_name );
695
+ if (bound_type_ptr == NULL ) {
696
+ /* Loosing const qualifier here is OK because this hashtable never frees or does anything with the value */
697
+ zend_hash_add_new_ptr (CG (bound_associated_types ), associated_type_name , (void * )concrete_type_ptr );
698
+ return INHERITANCE_SUCCESS ;
699
+ } else {
700
+ /* Associated type must be invariant */
701
+ const inheritance_status sub_type_status = zend_perform_covariant_type_check (
702
+ concrete_scope , concrete_type_ptr , associated_type_scope , bound_type_ptr );
703
+ const inheritance_status super_type_status = zend_perform_covariant_type_check (
704
+ concrete_scope , concrete_type_ptr , associated_type_scope , bound_type_ptr );
690
705
691
- return INHERITANCE_ERROR ;
706
+ if (sub_type_status != super_type_status ) {
707
+ return INHERITANCE_ERROR ;
708
+ } else {
709
+ return sub_type_status ;
710
+ }
711
+ }
692
712
}
693
713
694
714
ZEND_API inheritance_status zend_perform_covariant_type_check (
@@ -706,9 +726,15 @@ ZEND_API inheritance_status zend_perform_covariant_type_check(
706
726
return INHERITANCE_SUCCESS ;
707
727
}
708
728
729
+ /* If we check for concrete return type */
709
730
if (ZEND_TYPE_IS_ASSOCIATED (proto_type )) {
710
731
return zend_is_type_subtype_of_associated_type (
711
- fe_scope , fe_type_ptr , proto_type_ptr , NULL );
732
+ fe_scope , fe_type_ptr , proto_scope , proto_type_ptr );
733
+ }
734
+ /* If we check for concrete parameter type */
735
+ if (ZEND_TYPE_IS_ASSOCIATED (fe_type )) {
736
+ return zend_is_type_subtype_of_associated_type (
737
+ proto_scope , proto_type_ptr , fe_scope , fe_type_ptr );
712
738
}
713
739
714
740
/* Builtin types may be removed, but not added */
@@ -1852,6 +1878,10 @@ static void zend_link_hooked_object_iter(zend_class_entry *ce) {
1852
1878
}
1853
1879
#endif
1854
1880
1881
+ static void zend_bound_associated_table_ht_dtor (zval * val ) {
1882
+ /* NO OP as we only use it to be able to refer and save pointers to zend_types */
1883
+ }
1884
+
1855
1885
ZEND_API void zend_do_inheritance_ex (zend_class_entry * ce , zend_class_entry * parent_ce , bool checked ) /* {{{ */
1856
1886
{
1857
1887
zend_property_info * property_info ;
@@ -1895,6 +1925,14 @@ ZEND_API void zend_do_inheritance_ex(zend_class_entry *ce, zend_class_entry *par
1895
1925
ce -> default_object_handlers = parent_ce -> default_object_handlers ;
1896
1926
ce -> ce_flags |= ZEND_ACC_RESOLVED_PARENT ;
1897
1927
1928
+ // TODO Add associated_types HT for bound type checking
1929
+ if (parent_ce -> num_associated_types ) {
1930
+ printf ("Hello\n" );
1931
+ HashTable * ht = emalloc (sizeof (HashTable ));
1932
+ zend_hash_init (ht , parent_ce -> num_associated_types , NULL , zend_bound_associated_table_ht_dtor , false);
1933
+ CG (bound_associated_types ) = ht ;
1934
+ }
1935
+
1898
1936
/* Inherit properties */
1899
1937
if (parent_ce -> default_properties_count ) {
1900
1938
zval * src , * dst , * end ;
@@ -2063,6 +2101,12 @@ ZEND_API void zend_do_inheritance_ex(zend_class_entry *ce, zend_class_entry *par
2063
2101
}
2064
2102
}
2065
2103
ce -> ce_flags |= parent_ce -> ce_flags & (ZEND_HAS_STATIC_IN_METHODS | ZEND_ACC_HAS_TYPE_HINTS | ZEND_ACC_HAS_READONLY_PROPS | ZEND_ACC_USE_GUARDS | ZEND_ACC_NOT_SERIALIZABLE | ZEND_ACC_ALLOW_DYNAMIC_PROPERTIES );
2104
+
2105
+ if (CG (bound_associated_types )) {
2106
+ zend_hash_destroy (CG (bound_associated_types ));
2107
+ efree (CG (bound_associated_types ));
2108
+ CG (bound_associated_types ) = NULL ;
2109
+ }
2066
2110
}
2067
2111
/* }}} */
2068
2112
@@ -2195,6 +2239,11 @@ static void do_interface_implementation(zend_class_entry *ce, zend_class_entry *
2195
2239
ZEND_INHERITANCE_RESET_CHILD_OVERRIDE ;
2196
2240
}
2197
2241
2242
+ if (iface -> num_associated_types ) {
2243
+ HashTable * ht = emalloc (sizeof (HashTable ));
2244
+ zend_hash_init (ht , iface -> num_associated_types , NULL , zend_bound_associated_table_ht_dtor , false);
2245
+ CG (bound_associated_types ) = ht ;
2246
+ }
2198
2247
ZEND_HASH_MAP_FOREACH_STR_KEY_PTR (& iface -> constants_table , key , c ) {
2199
2248
do_inherit_iface_constant (key , c , ce , iface );
2200
2249
} ZEND_HASH_FOREACH_END ();
@@ -2216,6 +2265,11 @@ static void do_interface_implementation(zend_class_entry *ce, zend_class_entry *
2216
2265
if (iface -> num_interfaces ) {
2217
2266
zend_do_inherit_interfaces (ce , iface );
2218
2267
}
2268
+ if (CG (bound_associated_types )) {
2269
+ zend_hash_destroy (CG (bound_associated_types ));
2270
+ efree (CG (bound_associated_types ));
2271
+ CG (bound_associated_types ) = NULL ;
2272
+ }
2219
2273
}
2220
2274
/* }}} */
2221
2275
0 commit comments