33use crate :: generators:: gc_ops:: types:: StackType ;
44use crate :: generators:: gc_ops:: {
55 limits:: GcOpsLimits ,
6- types:: { CompositeType , StructType , TypeId , Types } ,
6+ types:: { CompositeType , RecGroupId , StructType , TypeId , Types } ,
77} ;
88use serde:: { Deserialize , Serialize } ;
9+ use std:: collections:: BTreeMap ;
910use wasm_encoder:: {
1011 CodeSection , ConstExpr , EntityType , ExportKind , ExportSection , Function , FunctionSection ,
1112 GlobalSection , ImportSection , Instruction , Module , RefType , TableSection , TableType ,
@@ -105,12 +106,52 @@ impl GcOps {
105106
106107 let struct_type_base: u32 = types. len ( ) ;
107108
109+ // Sort all types globally so supertypes come before subtypes.
110+ // This is used to order types *within* each rec group.
111+ let mut type_order = Vec :: new ( ) ;
112+ self . types . sort_types_topo ( & mut type_order) ;
113+
114+ // Build a position map so we can sort each group's members
115+ // according to the global type order.
116+ let type_position: BTreeMap < TypeId , usize > = type_order
117+ . iter ( )
118+ . enumerate ( )
119+ . map ( |( i, & id) | ( id, i) )
120+ . collect ( ) ;
121+
122+ // Topological sort of rec groups: if a type in group G has a
123+ // supertype in group H, then H appears before G.
124+ let mut group_order = Vec :: new ( ) ;
125+ self . types . sort_rec_groups_topo ( & mut group_order) ;
126+
127+ // For each group, collect its members sorted by the global type order.
128+ let mut group_members: BTreeMap < RecGroupId , Vec < TypeId > > = BTreeMap :: new ( ) ;
129+ for & gid in & group_order {
130+ if let Some ( member_set) = self . types . rec_groups . get ( & gid) {
131+ let mut members: Vec < TypeId > = member_set. iter ( ) . copied ( ) . collect ( ) ;
132+ members. sort_by_key ( |tid| type_position. get ( tid) . copied ( ) . unwrap_or ( usize:: MAX ) ) ;
133+ group_members. insert ( gid, members) ;
134+ }
135+ }
136+
137+ // Build the type-id-to-wasm-index map directly.
138+ let mut type_ids_to_index: BTreeMap < TypeId , u32 > = BTreeMap :: new ( ) ;
139+ let mut next_idx = struct_type_base;
140+ for g in & group_order {
141+ if let Some ( members) = group_members. get ( g) {
142+ for & tid in members {
143+ type_ids_to_index. insert ( tid, next_idx) ;
144+ next_idx += 1 ;
145+ }
146+ }
147+ }
148+
108149 let encode_ty_id = |ty_id : & TypeId | -> wasm_encoder:: SubType {
109150 let def = & self . types . type_defs [ ty_id] ;
110151 match & def. composite_type {
111152 CompositeType :: Struct ( StructType { } ) => wasm_encoder:: SubType {
112- is_final : true ,
113- supertype_idx : None ,
153+ is_final : def . is_final ,
154+ supertype_idx : def . supertype . map ( |st| type_ids_to_index [ & st ] ) ,
114155 composite_type : wasm_encoder:: CompositeType {
115156 inner : wasm_encoder:: CompositeInnerType :: Struct ( wasm_encoder:: StructType {
116157 fields : Box :: new ( [ ] ) ,
@@ -125,13 +166,12 @@ impl GcOps {
125166
126167 let mut struct_count = 0 ;
127168
128- for member_set in self . types . rec_groups . values ( ) {
129- let member_types: Vec < wasm_encoder:: SubType > =
130- member_set. iter ( ) . map ( |tid| encode_ty_id ( tid) ) . collect ( ) ;
131- let member_count = u32:: try_from ( member_types. len ( ) )
132- . expect ( "member_types len should be within u32 range" ) ;
133- types. ty ( ) . rec ( member_types) ;
134- struct_count += member_count;
169+ // Emit rec groups in the derived order.
170+ for g in & group_order {
171+ let type_ids = group_members. get ( g) . map ( |v| v. as_slice ( ) ) . unwrap_or ( & [ ] ) ;
172+ let members: Vec < wasm_encoder:: SubType > = type_ids. iter ( ) . map ( encode_ty_id) . collect ( ) ;
173+ types. ty ( ) . rec ( members) ;
174+ struct_count += u32:: try_from ( type_ids. len ( ) ) . unwrap ( ) ;
135175 }
136176
137177 let typed_fn_type_base: u32 = struct_type_base + struct_count;
0 commit comments