@@ -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
}
@@ -9040,12 +9067,18 @@ static void zend_compile_use_trait(zend_ast *ast) /* {{{ */
9040
9067
static void zend_associated_table_ht_dtor (zval * val ) {
9041
9068
/* NO OP as we only use it to be able to refer and save pointers to zend_types */
9042
9069
// 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
+ }
9043
9075
}
9044
9076
9045
9077
static void zend_compile_associated_type (zend_ast * ast ) {
9046
9078
zend_class_entry * ce = CG (active_class_entry );
9047
9079
HashTable * associated_types = ce -> associated_types ;
9048
9080
zend_ast * name_ast = ast -> child [0 ];
9081
+ zend_ast * type_ast = ast -> child [1 ];
9049
9082
zend_string * name = zend_ast_get_str (name_ast );
9050
9083
9051
9084
if ((ce -> ce_flags & ZEND_ACC_INTERFACE ) == 0 ) {
@@ -9065,7 +9098,12 @@ static void zend_compile_associated_type(zend_ast *ast) {
9065
9098
"Cannot have two associated types with the same name \"%s\"" , ZSTR_VAL (name ));
9066
9099
}
9067
9100
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
+ }
9069
9107
}
9070
9108
9071
9109
static void zend_compile_implements (zend_ast * ast ) /* {{{ */
0 commit comments