@@ -494,7 +494,12 @@ void shutdown_compiler(void) /* {{{ */
494494 CG (unlinked_uses ) = NULL ;
495495 }
496496 CG (current_linking_class ) = NULL ;
497- ZEND_ASSERT (CG (bound_associated_types ) == NULL );
497+ /* This can happen during a fatal error */
498+ if (CG (bound_associated_types )) {
499+ zend_hash_destroy (CG (bound_associated_types ));
500+ FREE_HASHTABLE (CG (bound_associated_types ));
501+ CG (bound_associated_types ) = NULL ;
502+ }
498503}
499504/* }}} */
500505
@@ -1436,6 +1441,26 @@ static zend_string *add_intersection_type(zend_string *str,
14361441 return str ;
14371442}
14381443
1444+ static zend_string * add_associated_type (zend_string * associated_type , zend_class_entry * scope )
1445+ {
1446+ const zend_type * constraint = zend_hash_find_ptr (scope -> associated_types , associated_type );
1447+ ZEND_ASSERT (constraint != NULL );
1448+
1449+ zend_string * constraint_type_str = zend_type_to_string_resolved (* constraint , scope );
1450+
1451+ size_t len = ZSTR_LEN (associated_type ) + ZSTR_LEN (constraint_type_str ) + strlen ("<>" );
1452+ zend_string * result = zend_string_alloc (len , 0 );
1453+
1454+ memcpy (ZSTR_VAL (result ), ZSTR_VAL (associated_type ), ZSTR_LEN (associated_type ));
1455+ ZSTR_VAL (result )[ZSTR_LEN (associated_type )] = '<' ;
1456+ memcpy (ZSTR_VAL (result ) + ZSTR_LEN (associated_type ) + 1 , ZSTR_VAL (constraint_type_str ), ZSTR_LEN (constraint_type_str ));
1457+ ZSTR_VAL (result )[len - 1 ] = '>' ;
1458+ ZSTR_VAL (result )[len ] = '\0' ;
1459+
1460+ zend_string_release (constraint_type_str );
1461+ return result ;
1462+ }
1463+
14391464zend_string * zend_type_to_string_resolved (const zend_type type , zend_class_entry * scope ) {
14401465 zend_string * str = NULL ;
14411466
@@ -1459,6 +1484,8 @@ zend_string *zend_type_to_string_resolved(const zend_type type, zend_class_entry
14591484 str = add_type_string (str , resolved , /* is_intersection */ false);
14601485 zend_string_release (resolved );
14611486 } ZEND_TYPE_LIST_FOREACH_END ();
1487+ } else if (ZEND_TYPE_IS_ASSOCIATED (type )) {
1488+ str = add_associated_type (ZEND_TYPE_NAME (type ), scope );
14621489 } else if (ZEND_TYPE_HAS_NAME (type )) {
14631490 str = resolve_class_name (ZEND_TYPE_NAME (type ), scope );
14641491 }
@@ -9040,12 +9067,18 @@ static void zend_compile_use_trait(zend_ast *ast) /* {{{ */
90409067static void zend_associated_table_ht_dtor (zval * val ) {
90419068 /* NO OP as we only use it to be able to refer and save pointers to zend_types */
90429069 // TODO do we actually want to store copies of types?
9070+ zend_type * associated_type = Z_PTR_P (val );
9071+ if (associated_type != & zend_mixed_type ) {
9072+ zend_type_release (* associated_type , false);
9073+ efree (associated_type );
9074+ }
90439075}
90449076
90459077static void zend_compile_associated_type (zend_ast * ast ) {
90469078 zend_class_entry * ce = CG (active_class_entry );
90479079 HashTable * associated_types = ce -> associated_types ;
90489080 zend_ast * name_ast = ast -> child [0 ];
9081+ zend_ast * type_ast = ast -> child [1 ];
90499082 zend_string * name = zend_ast_get_str (name_ast );
90509083
90519084 if ((ce -> ce_flags & ZEND_ACC_INTERFACE ) == 0 ) {
@@ -9065,7 +9098,12 @@ static void zend_compile_associated_type(zend_ast *ast) {
90659098 "Cannot have two associated types with the same name \"%s\"" , ZSTR_VAL (name ));
90669099 }
90679100
9068- zend_hash_add_new_ptr (associated_types , name , (void * ) & zend_mixed_type );
9101+ if (type_ast != NULL ) {
9102+ zend_type type = zend_compile_typename (type_ast );
9103+ zend_hash_add_new_mem (associated_types , name , & type , sizeof (type ));
9104+ } else {
9105+ zend_hash_add_new_ptr (associated_types , name , (void * ) & zend_mixed_type );
9106+ }
90699107}
90709108
90719109static void zend_compile_implements (zend_ast * ast ) /* {{{ */
0 commit comments