@@ -494,7 +494,12 @@ void shutdown_compiler(void) /* {{{ */
494
494
CG (unlinked_uses ) = NULL ;
495
495
}
496
496
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
+ }
498
503
}
499
504
/* }}} */
500
505
@@ -1436,6 +1441,26 @@ static zend_string *add_intersection_type(zend_string *str,
1436
1441
return str ;
1437
1442
}
1438
1443
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
+
1439
1464
zend_string * zend_type_to_string_resolved (const zend_type type , zend_class_entry * scope ) {
1440
1465
zend_string * str = NULL ;
1441
1466
@@ -1459,6 +1484,8 @@ zend_string *zend_type_to_string_resolved(const zend_type type, zend_class_entry
1459
1484
str = add_type_string (str , resolved , /* is_intersection */ false);
1460
1485
zend_string_release (resolved );
1461
1486
} ZEND_TYPE_LIST_FOREACH_END ();
1487
+ } else if (ZEND_TYPE_IS_ASSOCIATED (type )) {
1488
+ str = add_associated_type (ZEND_TYPE_NAME (type ), scope );
1462
1489
} else if (ZEND_TYPE_HAS_NAME (type )) {
1463
1490
str = resolve_class_name (ZEND_TYPE_NAME (type ), scope );
1464
1491
}
@@ -9031,12 +9058,18 @@ static void zend_compile_use_trait(zend_ast *ast) /* {{{ */
9031
9058
static void zend_associated_table_ht_dtor (zval * val ) {
9032
9059
/* NO OP as we only use it to be able to refer and save pointers to zend_types */
9033
9060
// TODO do we actually want to store copies of types?
9061
+ zend_type * associated_type = Z_PTR_P (val );
9062
+ if (associated_type != & zend_mixed_type ) {
9063
+ zend_type_release (* associated_type , false);
9064
+ efree (associated_type );
9065
+ }
9034
9066
}
9035
9067
9036
9068
static void zend_compile_associated_type (zend_ast * ast ) {
9037
9069
zend_class_entry * ce = CG (active_class_entry );
9038
9070
HashTable * associated_types = ce -> associated_types ;
9039
9071
zend_ast * name_ast = ast -> child [0 ];
9072
+ zend_ast * type_ast = ast -> child [1 ];
9040
9073
zend_string * name = zend_ast_get_str (name_ast );
9041
9074
9042
9075
if ((ce -> ce_flags & ZEND_ACC_INTERFACE ) == 0 ) {
@@ -9056,7 +9089,12 @@ static void zend_compile_associated_type(zend_ast *ast) {
9056
9089
"Cannot have two associated types with the same name \"%s\"" , ZSTR_VAL (name ));
9057
9090
}
9058
9091
9059
- zend_hash_add_new_ptr (associated_types , name , (void * ) & zend_mixed_type );
9092
+ if (type_ast != NULL ) {
9093
+ zend_type type = zend_compile_typename (type_ast );
9094
+ zend_hash_add_new_mem (associated_types , name , & type , sizeof (type ));
9095
+ } else {
9096
+ zend_hash_add_new_ptr (associated_types , name , (void * ) & zend_mixed_type );
9097
+ }
9060
9098
}
9061
9099
9062
9100
static void zend_compile_implements (zend_ast * ast ) /* {{{ */
0 commit comments