@@ -284,8 +284,7 @@ impl ExprGenerator<'_> {
284284 match target_type {
285285 Type :: Bool => {
286286 if max_depth == 0 || u. len ( ) < 10 {
287- // no recursion allowed, so, just do a literal
288- Ok ( ast:: Expr :: val ( u. arbitrary :: < bool > ( ) ?) )
287+ self . generate_expr_for_type_structurally_recursive ( target_type, u)
289288 } else {
290289 gen ! ( u,
291290 // bool literal
@@ -534,10 +533,7 @@ impl ExprGenerator<'_> {
534533 }
535534 Type :: Long => {
536535 if max_depth == 0 || u. len ( ) < 10 {
537- // no recursion allowed, so, just do a literal
538- Ok ( ast:: Expr :: val (
539- self . constant_pool . arbitrary_int_constant ( u) ?,
540- ) )
536+ self . generate_expr_for_type_structurally_recursive ( target_type, u)
541537 } else {
542538 gen ! ( u,
543539 // int literal. weighted highly because all the other choices
@@ -605,10 +601,7 @@ impl ExprGenerator<'_> {
605601 }
606602 Type :: String => {
607603 if max_depth == 0 || u. len ( ) < 10 {
608- // no recursion allowed, so, just do a literal
609- Ok ( ast:: Expr :: val (
610- self . constant_pool . arbitrary_string_constant ( u) ?,
611- ) )
604+ self . generate_expr_for_type_structurally_recursive ( target_type, u)
612605 } else {
613606 gen ! ( u,
614607 // string literal. weighted highly because all the other choices
@@ -631,8 +624,7 @@ impl ExprGenerator<'_> {
631624 }
632625 Type :: Set ( target_element_ty) => {
633626 if max_depth == 0 || u. len ( ) < 10 {
634- // no recursion allowed, so, just do empty-set
635- Ok ( ast:: Expr :: set ( vec ! [ ] ) )
627+ self . generate_expr_for_type_structurally_recursive ( target_type, u)
636628 } else {
637629 gen ! ( u,
638630 // set literal
@@ -666,8 +658,7 @@ impl ExprGenerator<'_> {
666658 }
667659 Type :: Record ( m) => {
668660 if max_depth == 0 || u. len ( ) < 10 {
669- // no recursion allowed
670- Err ( Error :: TooDeep )
661+ self . generate_expr_for_type_structurally_recursive ( target_type, u)
671662 } else {
672663 gen ! ( u,
673664 // record literal
@@ -689,17 +680,15 @@ impl ExprGenerator<'_> {
689680 // getting an attr (on a record) with type record
690681 3 => self . generate_get_record_attr_for_type( target_type, max_depth, u) ,
691682 // getting an entity tag with type record
692- 3 => self . generate_get_tag_for_type( target_type, max_depth, u) )
683+ 3 => self . generate_get_tag_for_type( target_type, max_depth, u) ,
684+ // `context`
685+ 1 => Ok ( ast:: Expr :: var( ast:: Var :: Context ) ) )
693686 }
694687 }
695688 Type :: Entity ( ety) => {
696689 if max_depth == 0 || u. len ( ) < 10 {
697690 // no recursion allowed, so, just do `principal`, `action`, or `resource`
698- Ok ( ast:: Expr :: var ( * u. choose ( & [
699- ast:: Var :: Principal ,
700- ast:: Var :: Action ,
701- ast:: Var :: Resource ,
702- ] ) ?) )
691+ self . generate_expr_for_type_structurally_recursive ( target_type, u)
703692 } else {
704693 gen ! ( u,
705694 // UID literal, that exists
@@ -729,14 +718,7 @@ impl ExprGenerator<'_> {
729718 return Err ( Error :: ExtensionsDisabled ) ;
730719 } ;
731720 if max_depth == 0 || u. len ( ) < 10 {
732- // no recursion allowed, so, just call the constructor
733- // Invariant (MethodStyleArgs), Function Style, no worries
734- self . arbitrary_ext_constructor_call_for_type (
735- target_type,
736- ast:: Expr :: val,
737- ast:: Expr :: call_extension_fn,
738- u,
739- )
721+ self . generate_expr_for_type_structurally_recursive ( target_type, u)
740722 } else {
741723 gen ! ( u,
742724 // if-then-else expression, where both arms are extension types
@@ -755,6 +737,65 @@ impl ExprGenerator<'_> {
755737 }
756738 }
757739
740+ /// Get an arbitrary expression of a given type conforming to the schema by
741+ /// structural recursion on the type. This function is guaranteed to
742+ /// terminate regardless of the bytes provided by `u`.
743+ ///
744+ /// To ensure this, it may call it's self recursively, but only on a type
745+ /// obtained from destructing `target_type`. It may not call `generate_expr_for_type`.
746+ fn generate_expr_for_type_structurally_recursive (
747+ & self ,
748+ target_type : & Type ,
749+ u : & mut Unstructured < ' _ > ,
750+ ) -> Result < ast:: Expr > {
751+ match target_type {
752+ Type :: Bool => Ok ( ast:: Expr :: val ( u. arbitrary :: < bool > ( ) ?) ) ,
753+ Type :: Long => Ok ( ast:: Expr :: val (
754+ self . constant_pool . arbitrary_int_constant ( u) ?,
755+ ) ) ,
756+ Type :: String => Ok ( ast:: Expr :: val (
757+ self . constant_pool . arbitrary_string_constant ( u) ?,
758+ ) ) ,
759+ Type :: Set ( el_ty) => {
760+ let mut l = Vec :: new ( ) ;
761+ u. arbitrary_loop ( Some ( 0 ) , Some ( self . settings . max_width as u32 ) , |u| {
762+ l. push ( self . generate_expr_for_type_structurally_recursive ( el_ty, u) ?) ;
763+ Ok ( std:: ops:: ControlFlow :: Continue ( ( ) ) )
764+ } ) ?;
765+ Ok ( ast:: Expr :: set ( l) )
766+ }
767+ Type :: Record ( m) => match u. int_in_range ( 0 ..=3 ) ? {
768+ 0 => Ok ( ast:: Expr :: var ( ast:: Var :: Context ) ) ,
769+ _ => {
770+ let r = m
771+ . iter ( )
772+ . filter_map ( |( a, qt) | {
773+ qt. required . then ( || {
774+ self . generate_expr_for_type_structurally_recursive ( & qt. ty , u)
775+ . map ( |e| ( a. clone ( ) , e) )
776+ } )
777+ } )
778+ . collect :: < Result < IndexMap < _ , _ > > > ( ) ?;
779+ Ok ( ast:: Expr :: record ( r)
780+ . expect ( "can't have duplicate keys because `r` was already a HashMap" ) )
781+ }
782+ } ,
783+ Type :: Entity ( ety) => match u. int_in_range ( 0 ..=3 ) ? {
784+ 0 => Ok ( ast:: Expr :: var ( ast:: Var :: Principal ) ) ,
785+ 1 => Ok ( ast:: Expr :: var ( ast:: Var :: Action ) ) ,
786+ 2 => Ok ( ast:: Expr :: var ( ast:: Var :: Resource ) ) ,
787+ _ => Ok ( ast:: Expr :: val ( self . arbitrary_uid_with_type ( ety, u) ?) ) ,
788+ } ,
789+ Type :: IPAddr | Type :: Decimal | Type :: DateTime | Type :: Duration => self
790+ . arbitrary_ext_constructor_call_for_type (
791+ target_type,
792+ ast:: Expr :: val,
793+ ast:: Expr :: call_extension_fn,
794+ u,
795+ ) ,
796+ }
797+ }
798+
758799 fn generate_ite_for_type (
759800 & self ,
760801 target_type : & Type ,
0 commit comments