11//! Mutators for the `gc` operations.
22use crate :: generators:: gc_ops:: limits:: GcOpsLimits ;
33use crate :: generators:: gc_ops:: ops:: { GcOp , GcOps } ;
4- use crate :: generators:: gc_ops:: types:: { TypeId , Types } ;
4+ use crate :: generators:: gc_ops:: types:: { CompositeType , FieldType , StructField , TypeId , Types } ;
55use mutatis:: {
66 Candidates , Context , DefaultMutate , Generate , Mutate , Result as MutResult , mutators as m,
77} ;
@@ -22,15 +22,11 @@ impl TypesMutator {
2222 types : & mut Types ,
2323 limits : & GcOpsLimits ,
2424 ) -> mutatis:: Result < ( ) > {
25- if c. shrink ( )
26- || types. type_defs . len ( )
27- >= usize:: try_from ( limits. max_types ) . expect ( "max_types is too large" )
28- {
25+ if c. shrink ( ) || types. type_defs . len ( ) >= usize:: try_from ( limits. max_types ) . unwrap ( ) {
2926 return Ok ( ( ) ) ;
3027 }
3128
32- let max_rec_groups =
33- usize:: try_from ( limits. max_rec_groups ) . expect ( "max_rec_groups is too large" ) ;
29+ let max_rec_groups = usize:: try_from ( limits. max_rec_groups ) . unwrap ( ) ;
3430 if types. rec_groups . is_empty ( ) && max_rec_groups == 0 {
3531 return Ok ( ( ) ) ;
3632 }
@@ -54,8 +50,9 @@ impl TypesMutator {
5450 } else {
5551 None
5652 } ;
57- types. insert_empty_struct ( tid, gid, is_final, supertype) ;
58- log:: debug!( "Added empty struct {tid:?} to rec group {gid:?}" ) ;
53+ // Add struct with no fields; fields can be added later by `mutate_struct_fields`.
54+ types. insert_struct ( tid, gid, is_final, supertype, Vec :: new ( ) ) ;
55+ log:: debug!( "Added struct {tid:?} to rec group {gid:?}" ) ;
5956 Ok ( ( ) )
6057 } ) ?;
6158 Ok ( ( ) )
@@ -200,10 +197,8 @@ impl TypesMutator {
200197 ) -> mutatis:: Result < ( ) > {
201198 if c. shrink ( )
202199 || types. rec_groups . is_empty ( )
203- || types. rec_groups . len ( )
204- >= usize:: try_from ( limits. max_rec_groups ) . expect ( "max_rec_groups is too large" )
205- || types. type_defs . len ( )
206- >= usize:: try_from ( limits. max_types ) . expect ( "max_types is too large" )
200+ || types. rec_groups . len ( ) >= usize:: try_from ( limits. max_rec_groups ) . unwrap ( )
201+ || types. type_defs . len ( ) >= usize:: try_from ( limits. max_types ) . unwrap ( )
207202 {
208203 return Ok ( ( ) ) ;
209204 }
@@ -218,16 +213,17 @@ impl TypesMutator {
218213 return Ok ( ( ) ) ;
219214 }
220215
221- // Collect (TypeId, is_final, supertype) for members of the source group.
222- let members: SmallVec < [ ( TypeId , bool , Option < TypeId > ) ; 32 ] > = src_members
223- . iter ( )
224- . filter_map ( |tid| {
225- types
226- . type_defs
227- . get ( tid)
228- . map ( |def| ( * tid, def. is_final , def. supertype ) )
229- } )
230- . collect ( ) ;
216+ // Collect (TypeId, is_final, supertype, fields) for members of the source group.
217+ let members: SmallVec < [ ( TypeId , bool , Option < TypeId > , Vec < StructField > ) ; 32 ] > =
218+ src_members
219+ . iter ( )
220+ . filter_map ( |tid| {
221+ types. type_defs . get ( tid) . map ( |def| {
222+ let CompositeType :: Struct ( ref st) = def. composite_type ;
223+ ( * tid, def. is_final , def. supertype , st. fields . clone ( ) )
224+ } )
225+ } )
226+ . collect ( ) ;
231227
232228 if members. is_empty ( ) {
233229 return Ok ( ( ) ) ;
@@ -239,15 +235,15 @@ impl TypesMutator {
239235
240236 // Allocate fresh type ids for each member and build old-to-new map.
241237 let mut old_to_new: BTreeMap < TypeId , TypeId > = BTreeMap :: new ( ) ;
242- for ( old_tid, _, _) in & members {
238+ for ( old_tid, _, _, _ ) in & members {
243239 old_to_new. insert ( * old_tid, types. fresh_type_id ( ctx. rng ( ) ) ) ;
244240 }
245241
246242 // Insert duplicated defs, rewriting intra-group supertype edges to cloned ids.
247- for ( old_tid, is_final, supertype) in & members {
243+ for ( old_tid, is_final, supertype, fields ) in & members {
248244 let new_tid = old_to_new[ old_tid] ;
249245 let mapped_super = supertype. map ( |st| * old_to_new. get ( & st) . unwrap_or ( & st) ) ;
250- types. insert_empty_struct ( new_tid, new_gid, * is_final, mapped_super) ;
246+ types. insert_struct ( new_tid, new_gid, * is_final, mapped_super, fields . clone ( ) ) ;
251247 }
252248
253249 log:: debug!(
@@ -332,8 +328,7 @@ impl TypesMutator {
332328 if c. shrink ( )
333329 || types. rec_groups . is_empty ( )
334330 || types. type_defs . len ( ) < 2
335- || types. rec_groups . len ( )
336- >= usize:: try_from ( limits. max_rec_groups ) . expect ( "max_rec_groups is too large" )
331+ || types. rec_groups . len ( ) >= usize:: try_from ( limits. max_rec_groups ) . unwrap ( )
337332 {
338333 return Ok ( ( ) ) ;
339334 }
@@ -390,6 +385,19 @@ impl TypesMutator {
390385 Ok ( ( ) )
391386 }
392387
388+ /// Mutate struct fields (add/remove/modify via `m::vec`).
389+ fn mutate_struct_fields (
390+ & mut self ,
391+ c : & mut Candidates < ' _ > ,
392+ types : & mut Types ,
393+ ) -> mutatis:: Result < ( ) > {
394+ for ( _, def) in types. type_defs . iter_mut ( ) {
395+ let CompositeType :: Struct ( ref mut st) = def. composite_type ;
396+ m:: vec ( StructFieldMutator ) . mutate ( c, & mut st. fields ) ?;
397+ }
398+ Ok ( ( ) )
399+ }
400+
393401 /// Run all type / rec-group mutations. [`GcOpsLimits`] come from [`GcOps`].
394402 fn mutate_with_limits (
395403 & mut self ,
@@ -405,10 +413,45 @@ impl TypesMutator {
405413 self . remove_group ( c, types) ?;
406414 self . merge_groups ( c, types) ?;
407415 self . split_group ( c, types, limits) ?;
416+ self . mutate_struct_fields ( c, types) ?;
417+
408418 Ok ( ( ) )
409419 }
410420}
411421
422+ /// Mutator for [`StructField`]: used by `m::vec` to add, remove, and
423+ /// modify fields within a struct type.
424+ #[ derive( Debug , Default ) ]
425+ pub struct StructFieldMutator ;
426+
427+ impl Mutate < StructField > for StructFieldMutator {
428+ fn mutate ( & mut self , c : & mut Candidates < ' _ > , field : & mut StructField ) -> MutResult < ( ) > {
429+ c. mutation ( |ctx| {
430+ let old = format ! ( "{field:?}" ) ;
431+ field. field_type = FieldType :: random ( ctx. rng ( ) ) ;
432+ field. mutable = ( ctx. rng ( ) . gen_u32 ( ) % 2 ) == 0 ;
433+ log:: debug!( "Mutated field {old} -> {field:?}" ) ;
434+ Ok ( ( ) )
435+ } ) ?;
436+ Ok ( ( ) )
437+ }
438+ }
439+
440+ impl Generate < StructField > for StructFieldMutator {
441+ fn generate ( & mut self , ctx : & mut Context ) -> MutResult < StructField > {
442+ let field = StructField {
443+ field_type : FieldType :: random ( ctx. rng ( ) ) ,
444+ mutable : ( ctx. rng ( ) . gen_u32 ( ) % 2 ) == 0 ,
445+ } ;
446+ log:: debug!( "Generated field {field:?}" ) ;
447+ Ok ( field)
448+ }
449+ }
450+
451+ impl DefaultMutate for StructField {
452+ type DefaultMutate = StructFieldMutator ;
453+ }
454+
412455/// Mutator for [`GcOps`].
413456///
414457/// Also implements [`Mutate`] / [`Generate`] for [`GcOp`] so `m::vec` can mutate
@@ -465,7 +508,7 @@ impl Generate<GcOps> for GcOpsMutator {
465508 let mut ops = GcOps :: default ( ) ;
466509 let mut session = mutatis:: Session :: new ( ) ;
467510
468- for _ in 0 ..64 {
511+ for _ in 0 ..2048 {
469512 session. mutate ( & mut ops) ?;
470513 }
471514
0 commit comments