@@ -675,20 +675,40 @@ static inheritance_status zend_is_intersection_subtype_of_type(
675675 return early_exit_status == INHERITANCE_ERROR ? INHERITANCE_SUCCESS : INHERITANCE_ERROR ;
676676}
677677
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+
678682static inheritance_status zend_is_type_subtype_of_associated_type (
679683 zend_class_entry * concrete_scope ,
680684 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
683687) {
684688 const zend_type associated_type = * associated_type_ptr ;
685- const zend_type concrete_type = * concrete_type_ptr ;
686689
690+ ZEND_ASSERT (CG (bound_associated_types ) && "Have associated type" );
687691 ZEND_ASSERT (ZEND_TYPE_HAS_NAME (associated_type ));
688692
689693 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 );
690705
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+ }
692712}
693713
694714ZEND_API inheritance_status zend_perform_covariant_type_check (
@@ -706,9 +726,15 @@ ZEND_API inheritance_status zend_perform_covariant_type_check(
706726 return INHERITANCE_SUCCESS ;
707727 }
708728
729+ /* If we check for concrete return type */
709730 if (ZEND_TYPE_IS_ASSOCIATED (proto_type )) {
710731 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 );
712738 }
713739
714740 /* Builtin types may be removed, but not added */
@@ -1852,6 +1878,10 @@ static void zend_link_hooked_object_iter(zend_class_entry *ce) {
18521878}
18531879#endif
18541880
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+
18551885ZEND_API void zend_do_inheritance_ex (zend_class_entry * ce , zend_class_entry * parent_ce , bool checked ) /* {{{ */
18561886{
18571887 zend_property_info * property_info ;
@@ -1895,6 +1925,14 @@ ZEND_API void zend_do_inheritance_ex(zend_class_entry *ce, zend_class_entry *par
18951925 ce -> default_object_handlers = parent_ce -> default_object_handlers ;
18961926 ce -> ce_flags |= ZEND_ACC_RESOLVED_PARENT ;
18971927
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+
18981936 /* Inherit properties */
18991937 if (parent_ce -> default_properties_count ) {
19001938 zval * src , * dst , * end ;
@@ -2063,6 +2101,12 @@ ZEND_API void zend_do_inheritance_ex(zend_class_entry *ce, zend_class_entry *par
20632101 }
20642102 }
20652103 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+ }
20662110}
20672111/* }}} */
20682112
@@ -2195,6 +2239,11 @@ static void do_interface_implementation(zend_class_entry *ce, zend_class_entry *
21952239 ZEND_INHERITANCE_RESET_CHILD_OVERRIDE ;
21962240 }
21972241
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+ }
21982247 ZEND_HASH_MAP_FOREACH_STR_KEY_PTR (& iface -> constants_table , key , c ) {
21992248 do_inherit_iface_constant (key , c , ce , iface );
22002249 } ZEND_HASH_FOREACH_END ();
@@ -2216,6 +2265,11 @@ static void do_interface_implementation(zend_class_entry *ce, zend_class_entry *
22162265 if (iface -> num_interfaces ) {
22172266 zend_do_inherit_interfaces (ce , iface );
22182267 }
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+ }
22192273}
22202274/* }}} */
22212275
0 commit comments