@@ -58,10 +58,20 @@ impl<'a> Generator<'a> {
5858 SCALARS [ self . seed . choice ( SCALARS . len ( ) ) ] . clone ( )
5959 }
6060
61+ /// A scalar usable as a `Map` key / `Set` element (`Hashable`): no `Float`.
62+ fn pick_hashable_scalar ( & mut self ) -> Ty {
63+ const HASHABLE : & [ Ty ] = & [ Ty :: Int , Ty :: Bool , Ty :: String ] ;
64+ HASHABLE [ self . seed . choice ( HASHABLE . len ( ) ) ] . clone ( )
65+ }
66+
6167 /// A type for a binding/param/return: scalars dominate; compounds appear when
6268 /// available. Compound payloads are restricted to scalars to keep the surface
6369 /// finite and generation simple.
6470 fn pick_type ( & mut self ) -> Ty {
71+ // Collections are deliberately *not* pickable here: an empty `C.new<T>()`
72+ // in an inferred position lowers to a Rust `C::new()` whose element type
73+ // can't be inferred (E0282) when only `len()` is observed. Collections are
74+ // instead emitted, always populated, by `gen_collection_stmt`.
6575 match self . seed . weighted ( & [ 10 , 2 , 2 , 3 , 3 ] ) {
6676 0 => self . pick_scalar ( ) ,
6777 1 => Ty :: Option ( Box :: new ( self . pick_scalar ( ) ) ) ,
@@ -294,6 +304,24 @@ impl<'a> Generator<'a> {
294304 . join ( "\n " ) ;
295305 format ! ( "{pad}match {access} {{\n {arms}\n {pad}}}\n " )
296306 }
307+ // Collections are observed by their length (a deterministic Int);
308+ // element iteration order isn't guaranteed identical across backends.
309+ Ty :: List ( _) => {
310+ let len = format ! ( "List.len(list: read {access})" ) ;
311+ format ! ( "{pad}{}\n " , self . log_scalar( & len, & Ty :: Int ) )
312+ }
313+ Ty :: Map ( _, _) => {
314+ let len = format ! ( "Map.len(map: read {access})" ) ;
315+ format ! ( "{pad}{}\n " , self . log_scalar( & len, & Ty :: Int ) )
316+ }
317+ Ty :: Set ( _) => {
318+ let len = format ! ( "Set.len(set: read {access})" ) ;
319+ format ! ( "{pad}{}\n " , self . log_scalar( & len, & Ty :: Int ) )
320+ }
321+ Ty :: Deque ( _) => {
322+ let len = format ! ( "Deque.len(deque: read {access})" ) ;
323+ format ! ( "{pad}{}\n " , self . log_scalar( & len, & Ty :: Int ) )
324+ }
297325 }
298326 }
299327
@@ -328,19 +356,116 @@ impl<'a> Generator<'a> {
328356 // -- statements ------------------------------------------------------
329357
330358 fn gen_stmt ( & mut self , scope : & mut Scope ) -> String {
331- // Bias toward lets; sometimes assign; sometimes a `?`-unwrap.
332- match self . seed . weighted ( & [ 6 , 2 , 2 ] ) {
359+ // Bias toward lets; sometimes assign, a `?`-unwrap, or a populated
360+ // collection.
361+ match self . seed . weighted ( & [ 6 , 2 , 2 , 3 ] ) {
333362 0 => self . gen_let ( scope) ,
334363 1 => self
335364 . gen_assign ( scope)
336365 . unwrap_or_else ( || self . gen_let ( scope) ) ,
337- _ => self
366+ 2 => self
338367 . gen_try ( scope)
339368 . or_else ( || self . gen_assign ( scope) )
340369 . unwrap_or_else ( || self . gen_let ( scope) ) ,
370+ _ => self . gen_collection_stmt ( scope) ,
341371 }
342372 }
343373
374+ /// Build a populated collection: `let mut v: C = C.new<..>()` followed by a
375+ /// few inserts. Returned as a single (possibly multi-line) statement whose
376+ /// continuation lines are pre-indented to match the caller's block.
377+ fn gen_collection_stmt ( & mut self , scope : & mut Scope ) -> String {
378+ let name = self . fresh_var ( ) ;
379+ // Always at least one element: a non-empty collection lets the Rust
380+ // backend infer the element type from the pushed literal (an empty
381+ // `C.new<T>()` observed only via `len()` is un-inferable — E0282).
382+ let count = 1 + self . seed . choice ( 3 ) ; // 1..=3 elements
383+ let ( ty, new_expr, mut inserts, len_expr) : ( Ty , String , Vec < String > , String ) =
384+ match self . seed . choice ( 4 ) {
385+ 0 => {
386+ let elem = self . pick_scalar ( ) ;
387+ let ty = Ty :: List ( Box :: new ( elem. clone ( ) ) ) ;
388+ let inserts = ( 0 ..count)
389+ . map ( |_| {
390+ let v = self . gen_literal ( & elem) ;
391+ format ! ( "List.push(list: mut {name}, value: read {v})" )
392+ } )
393+ . collect ( ) ;
394+ (
395+ ty,
396+ format ! ( "List.new<{}>()" , elem. render( ) ) ,
397+ inserts,
398+ format ! ( "List.len(list: read {name})" ) ,
399+ )
400+ }
401+ 1 => {
402+ let elem = self . pick_scalar ( ) ;
403+ let ty = Ty :: Deque ( Box :: new ( elem. clone ( ) ) ) ;
404+ let inserts = ( 0 ..count)
405+ . map ( |_| {
406+ let v = self . gen_literal ( & elem) ;
407+ format ! ( "Deque.push_back(deque: mut {name}, value: read {v})" )
408+ } )
409+ . collect ( ) ;
410+ (
411+ ty,
412+ format ! ( "Deque.new<{}>()" , elem. render( ) ) ,
413+ inserts,
414+ format ! ( "Deque.len(deque: read {name})" ) ,
415+ )
416+ }
417+ 2 => {
418+ let elem = self . pick_hashable_scalar ( ) ;
419+ let ty = Ty :: Set ( Box :: new ( elem. clone ( ) ) ) ;
420+ let inserts = ( 0 ..count)
421+ . map ( |_| {
422+ let v = self . gen_literal ( & elem) ;
423+ format ! ( "Set.insert(set: mut {name}, value: read {v})" )
424+ } )
425+ . collect ( ) ;
426+ (
427+ ty,
428+ format ! ( "Set.new<{}>()" , elem. render( ) ) ,
429+ inserts,
430+ format ! ( "Set.len(set: read {name})" ) ,
431+ )
432+ }
433+ _ => {
434+ let key = self . pick_hashable_scalar ( ) ;
435+ let value = self . pick_scalar ( ) ;
436+ let ty = Ty :: Map ( Box :: new ( key. clone ( ) ) , Box :: new ( value. clone ( ) ) ) ;
437+ let inserts = ( 0 ..count)
438+ . map ( |_| {
439+ let k = self . gen_literal ( & key) ;
440+ let v = self . gen_literal ( & value) ;
441+ format ! ( "Map.insert(map: mut {name}, key: read {k}, value: read {v})" )
442+ } )
443+ . collect ( ) ;
444+ (
445+ ty,
446+ format ! ( "Map.new<{}, {}>()" , key. render( ) , value. render( ) ) ,
447+ inserts,
448+ format ! ( "Map.len(map: read {name})" ) ,
449+ )
450+ }
451+ } ;
452+ let ty_render = ty. render ( ) ;
453+ scope. bindings . push ( Binding {
454+ name : name. clone ( ) ,
455+ ty,
456+ mutable : true ,
457+ } ) ;
458+ let mut lines = vec ! [ format!( "let mut {name}: {ty_render} = {new_expr}" ) ] ;
459+ lines. append ( & mut inserts) ;
460+ // Observe the length so the collection contributes to stdout (deterministic
461+ // across backends, unlike element iteration order).
462+ lines. push ( format ! (
463+ "Log.write(message: read String.from_int(value: {len_expr}))"
464+ ) ) ;
465+ // Caller prefixes the first line with one indent; pre-indent the rest.
466+ lines. join ( "\n " )
467+ }
468+
344469 fn gen_let ( & mut self , scope : & mut Scope ) -> String {
345470 let ty = self . pick_type ( ) ;
346471 // Occasionally exercise the None/Err constructors (they need a known type,
@@ -496,6 +621,14 @@ impl<'a> Generator<'a> {
496621 let def = self . sum_def ( name) ;
497622 def. variants [ self . seed . choice ( def. variants . len ( ) ) ] . clone ( )
498623 }
624+ // Collections are constructed empty here; populated instances are
625+ // built by `gen_collection_stmt` (new + a few inserts).
626+ Ty :: List ( inner) => format ! ( "List.new<{}>()" , inner. render( ) ) ,
627+ Ty :: Map ( key, value) => {
628+ format ! ( "Map.new<{}, {}>()" , key. render( ) , value. render( ) )
629+ }
630+ Ty :: Set ( inner) => format ! ( "Set.new<{}>()" , inner. render( ) ) ,
631+ Ty :: Deque ( inner) => format ! ( "Deque.new<{}>()" , inner. render( ) ) ,
499632 }
500633 }
501634
@@ -597,9 +730,14 @@ impl<'a> Generator<'a> {
597730 }
598731 } ,
599732 // Compounds have no operator forms: just construct.
600- Ty :: Option ( _) | Ty :: Result ( _, _) | Ty :: Struct ( _) | Ty :: Sum ( _) => {
601- self . gen_construct ( ty, scope)
602- }
733+ Ty :: Option ( _)
734+ | Ty :: Result ( _, _)
735+ | Ty :: Struct ( _)
736+ | Ty :: Sum ( _)
737+ | Ty :: List ( _)
738+ | Ty :: Map ( _, _)
739+ | Ty :: Set ( _)
740+ | Ty :: Deque ( _) => self . gen_construct ( ty, scope) ,
603741 }
604742 }
605743
0 commit comments