Old Fuzzer, new Sampler
This commit is contained in:
		
							parent
							
								
									c0fabcd26a
								
							
						
					
					
						commit
						84a0abeb0f
					
				|  | @ -258,7 +258,7 @@ fn str_to_keyword(word: &str) -> Option<Token> { | |||
|         "or" => Some(Token::Or), | ||||
|         "validator" => Some(Token::Validator), | ||||
|         "via" => Some(Token::Via), | ||||
|         "benchmark" => Some(Token::Benchmark), | ||||
|         "bench" => Some(Token::Benchmark), | ||||
|         _ => None, | ||||
|     } | ||||
| } | ||||
|  |  | |||
|  | @ -8,7 +8,8 @@ pub const BOOL: &str = "Bool"; | |||
| pub const BOOL_CONSTRUCTORS: &[&str] = &["False", "True"]; | ||||
| pub const BYTE_ARRAY: &str = "ByteArray"; | ||||
| pub const DATA: &str = "Data"; | ||||
| pub const GENERATOR: &str = "Generator"; | ||||
| pub const FUZZER: &str = "Fuzzer"; | ||||
| pub const SAMPLER: &str = "Sampler"; | ||||
| pub const G1_ELEMENT: &str = "G1Element"; | ||||
| pub const G2_ELEMENT: &str = "G2Element"; | ||||
| pub const INT: &str = "Int"; | ||||
|  | @ -179,7 +180,7 @@ impl Type { | |||
|         }) | ||||
|     } | ||||
| 
 | ||||
|     pub fn generator(c: Rc<Type>, a: Rc<Type>) -> Rc<Type> { | ||||
|     pub fn fuzzer(a: Rc<Type>) -> Rc<Type> { | ||||
|         let prng_annotation = Annotation::Constructor { | ||||
|             location: Span::empty(), | ||||
|             module: None, | ||||
|  | @ -188,15 +189,15 @@ impl Type { | |||
|         }; | ||||
| 
 | ||||
|         Rc::new(Type::Fn { | ||||
|             args: vec![c, Type::prng()], | ||||
|             args: vec![Type::prng()], | ||||
|             ret: Type::option(Type::tuple(vec![Type::prng(), a])), | ||||
|             alias: Some( | ||||
|                 TypeAliasAnnotation { | ||||
|                     alias: GENERATOR.to_string(), | ||||
|                     parameters: vec!["c".to_string(), "a".to_string()], | ||||
|                     alias: FUZZER.to_string(), | ||||
|                     parameters: vec!["a".to_string()], | ||||
|                     annotation: Annotation::Fn { | ||||
|                         location: Span::empty(), | ||||
|                         arguments: vec![Annotation::data(Span::empty()), prng_annotation.clone()], | ||||
|                         arguments: vec![prng_annotation.clone()], | ||||
|                         ret: Annotation::Constructor { | ||||
|                             location: Span::empty(), | ||||
|                             module: None, | ||||
|  | @ -220,6 +221,53 @@ impl Type { | |||
|         }) | ||||
|     } | ||||
| 
 | ||||
|     pub fn sampler(a: Rc<Type>) -> Rc<Type> { | ||||
|         let prng_annotation = Annotation::Constructor { | ||||
|             location: Span::empty(), | ||||
|             module: None, | ||||
|             name: PRNG.to_string(), | ||||
|             arguments: vec![], | ||||
|         }; | ||||
| 
 | ||||
|         Rc::new(Type::Fn { | ||||
|             args: vec![Type::int()], | ||||
|             ret: Type::fuzzer(a), | ||||
|             alias: Some( | ||||
|                 TypeAliasAnnotation { | ||||
|                     alias: SAMPLER.to_string(), | ||||
|                     parameters: vec!["a".to_string()], | ||||
|                     annotation: Annotation::Fn { | ||||
|                         location: Span::empty(), | ||||
|                         arguments: vec![Annotation::int(Span::empty())], | ||||
|                         ret: Annotation::Fn { | ||||
|                             location: Span::empty(), | ||||
|                             arguments: vec![prng_annotation.clone()], | ||||
|                             ret: Annotation::Constructor { | ||||
|                                 location: Span::empty(), | ||||
|                                 module: None, | ||||
|                                 name: OPTION.to_string(), | ||||
|                                 arguments: vec![Annotation::Tuple { | ||||
|                                     location: Span::empty(), | ||||
|                                     elems: vec![ | ||||
|                                         prng_annotation, | ||||
|                                         Annotation::Var { | ||||
|                                             location: Span::empty(), | ||||
|                                             name: "a".to_string(), | ||||
|                                         }, | ||||
|                                     ], | ||||
|                                 }], | ||||
|                             } | ||||
|                             .into(), | ||||
|                         } | ||||
|                         .into(), | ||||
|                     } | ||||
|                     .into(), | ||||
|                 } | ||||
|                 .into(), | ||||
|             ), | ||||
|         }) | ||||
|     } | ||||
| 
 | ||||
|     pub fn map(k: Rc<Type>, v: Rc<Type>) -> Rc<Type> { | ||||
|         Rc::new(Type::App { | ||||
|             public: true, | ||||
|  |  | |||
|  | @ -477,23 +477,38 @@ pub fn prelude(id_gen: &IdGenerator) -> TypeInfo { | |||
|         ), | ||||
|     ); | ||||
| 
 | ||||
|     // Generator
 | ||||
|     // Fuzzer
 | ||||
|     //
 | ||||
|     // pub type Generator<c, a> =
 | ||||
|     //   fn(Data, PRNG) -> Option<(PRNG, a)>
 | ||||
|     let generator_context = Type::generic_var(id_gen.next()); | ||||
|     let generator_value = Type::generic_var(id_gen.next()); | ||||
|     // pub type Fuzzer<a> =
 | ||||
|     //   fn(PRNG) -> Option<(PRNG, a)>
 | ||||
|     let fuzzer_generic = Type::generic_var(id_gen.next()); | ||||
|     prelude.types.insert( | ||||
|         well_known::GENERATOR.to_string(), | ||||
|         well_known::FUZZER.to_string(), | ||||
|         TypeConstructor { | ||||
|             location: Span::empty(), | ||||
|             parameters: vec![generator_context.clone(), generator_value.clone()], | ||||
|             tipo: Type::generator(generator_context, generator_value), | ||||
|             parameters: vec![fuzzer_generic.clone()], | ||||
|             tipo: Type::fuzzer(fuzzer_generic), | ||||
|             module: "".to_string(), | ||||
|             public: true, | ||||
|         }, | ||||
|     ); | ||||
| 
 | ||||
|     // Sampler
 | ||||
|     //
 | ||||
|     // pub type Sampler<a> =
 | ||||
|     //   fn(Int) -> Fuzzer<a>
 | ||||
|     let sampler_generic = Type::generic_var(id_gen.next()); | ||||
|     prelude.types.insert( | ||||
|         well_known::SAMPLER.to_string(), | ||||
|         TypeConstructor { | ||||
|             location: Span::empty(), | ||||
|             parameters: vec![sampler_generic.clone()], | ||||
|             tipo: Type::sampler(sampler_generic), | ||||
|             module: "".to_string(), | ||||
|             public: true, | ||||
|         } | ||||
|     ); | ||||
| 
 | ||||
|     prelude | ||||
| } | ||||
| 
 | ||||
|  |  | |||
|  | @ -135,7 +135,7 @@ mod tests { | |||
|     fn def_benchmark() { | ||||
|         assert_definition!( | ||||
|             r#" | ||||
|             benchmark foo(x via fuzz.any_int) { | ||||
|             bench foo(x via fuzz.any_int) { | ||||
|                 True | ||||
|             } | ||||
|             "#
 | ||||
|  | @ -146,7 +146,7 @@ mod tests { | |||
|     fn def_invalid_benchmark() { | ||||
|         assert_definition!( | ||||
|             r#" | ||||
|             benchmark foo(x via f, y via g) { | ||||
|             bench foo(x via f, y via g) { | ||||
|                 True | ||||
|             } | ||||
|             "#
 | ||||
|  | @ -157,7 +157,7 @@ mod tests { | |||
|     fn def_benchmark_annotated_fuzzer() { | ||||
|         assert_definition!( | ||||
|             r#" | ||||
|             benchmark foo(x: Int via foo()) { | ||||
|             bench foo(x: Int via foo()) { | ||||
|                 True | ||||
|             } | ||||
|             "#
 | ||||
|  |  | |||
|  | @ -1,7 +1,7 @@ | |||
| --- | ||||
| source: crates/aiken-lang/src/parser/definition/benchmark.rs | ||||
| assertion_line: 136 | ||||
| description: "Code:\n\nbenchmark foo(x via fuzz.any_int) {\n    True\n}\n" | ||||
| description: "Code:\n\nbench foo(x via fuzz.any_int) {\n    True\n}\n" | ||||
| snapshot_kind: text | ||||
| --- | ||||
| Benchmark( | ||||
|  | @ -13,35 +13,35 @@ Benchmark( | |||
|                         Named { | ||||
|                             name: "x", | ||||
|                             label: "x", | ||||
|                             location: 14..15, | ||||
|                             location: 10..11, | ||||
|                         }, | ||||
|                     ), | ||||
|                     location: 14..15, | ||||
|                     location: 10..11, | ||||
|                     annotation: None, | ||||
|                     doc: None, | ||||
|                     is_validator_param: false, | ||||
|                 }, | ||||
|                 via: FieldAccess { | ||||
|                     location: 20..32, | ||||
|                     location: 16..28, | ||||
|                     label: "any_int", | ||||
|                     container: Var { | ||||
|                         location: 20..24, | ||||
|                         location: 16..20, | ||||
|                         name: "fuzz", | ||||
|                     }, | ||||
|                 }, | ||||
|             }, | ||||
|         ], | ||||
|         body: Var { | ||||
|             location: 40..44, | ||||
|             location: 36..40, | ||||
|             name: "True", | ||||
|         }, | ||||
|         doc: None, | ||||
|         location: 0..33, | ||||
|         location: 0..29, | ||||
|         name: "foo", | ||||
|         public: false, | ||||
|         return_annotation: None, | ||||
|         return_type: (), | ||||
|         end_position: 45, | ||||
|         end_position: 41, | ||||
|         on_test_failure: FailImmediately, | ||||
|     }, | ||||
| ) | ||||
|  |  | |||
|  | @ -1,7 +1,7 @@ | |||
| --- | ||||
| source: crates/aiken-lang/src/parser/definition/benchmark.rs | ||||
| assertion_line: 158 | ||||
| description: "Code:\n\nbenchmark foo(x: Int via foo()) {\n    True\n}\n" | ||||
| description: "Code:\n\nbench foo(x: Int via foo()) {\n    True\n}\n" | ||||
| snapshot_kind: text | ||||
| --- | ||||
| Benchmark( | ||||
|  | @ -13,13 +13,13 @@ Benchmark( | |||
|                         Named { | ||||
|                             name: "x", | ||||
|                             label: "x", | ||||
|                             location: 14..15, | ||||
|                             location: 10..11, | ||||
|                         }, | ||||
|                     ), | ||||
|                     location: 14..20, | ||||
|                     location: 10..16, | ||||
|                     annotation: Some( | ||||
|                         Constructor { | ||||
|                             location: 17..20, | ||||
|                             location: 13..16, | ||||
|                             module: None, | ||||
|                             name: "Int", | ||||
|                             arguments: [], | ||||
|  | @ -31,24 +31,24 @@ Benchmark( | |||
|                 via: Call { | ||||
|                     arguments: [], | ||||
|                     fun: Var { | ||||
|                         location: 25..28, | ||||
|                         location: 21..24, | ||||
|                         name: "foo", | ||||
|                     }, | ||||
|                     location: 25..30, | ||||
|                     location: 21..26, | ||||
|                 }, | ||||
|             }, | ||||
|         ], | ||||
|         body: Var { | ||||
|             location: 38..42, | ||||
|             location: 34..38, | ||||
|             name: "True", | ||||
|         }, | ||||
|         doc: None, | ||||
|         location: 0..31, | ||||
|         location: 0..27, | ||||
|         name: "foo", | ||||
|         public: false, | ||||
|         return_annotation: None, | ||||
|         return_type: (), | ||||
|         end_position: 43, | ||||
|         end_position: 39, | ||||
|         on_test_failure: FailImmediately, | ||||
|     }, | ||||
| ) | ||||
|  |  | |||
|  | @ -1,7 +1,7 @@ | |||
| --- | ||||
| source: crates/aiken-lang/src/parser/definition/benchmark.rs | ||||
| assertion_line: 147 | ||||
| description: "Code:\n\nbenchmark foo(x via f, y via g) {\n    True\n}\n" | ||||
| description: "Code:\n\nbench foo(x via f, y via g) {\n    True\n}\n" | ||||
| snapshot_kind: text | ||||
| --- | ||||
| Benchmark( | ||||
|  | @ -13,16 +13,16 @@ Benchmark( | |||
|                         Named { | ||||
|                             name: "x", | ||||
|                             label: "x", | ||||
|                             location: 14..15, | ||||
|                             location: 10..11, | ||||
|                         }, | ||||
|                     ), | ||||
|                     location: 14..15, | ||||
|                     location: 10..11, | ||||
|                     annotation: None, | ||||
|                     doc: None, | ||||
|                     is_validator_param: false, | ||||
|                 }, | ||||
|                 via: Var { | ||||
|                     location: 20..21, | ||||
|                     location: 16..17, | ||||
|                     name: "f", | ||||
|                 }, | ||||
|             }, | ||||
|  | @ -32,31 +32,31 @@ Benchmark( | |||
|                         Named { | ||||
|                             name: "y", | ||||
|                             label: "y", | ||||
|                             location: 23..24, | ||||
|                             location: 19..20, | ||||
|                         }, | ||||
|                     ), | ||||
|                     location: 23..24, | ||||
|                     location: 19..20, | ||||
|                     annotation: None, | ||||
|                     doc: None, | ||||
|                     is_validator_param: false, | ||||
|                 }, | ||||
|                 via: Var { | ||||
|                     location: 29..30, | ||||
|                     location: 25..26, | ||||
|                     name: "g", | ||||
|                 }, | ||||
|             }, | ||||
|         ], | ||||
|         body: Var { | ||||
|             location: 38..42, | ||||
|             location: 34..38, | ||||
|             name: "True", | ||||
|         }, | ||||
|         doc: None, | ||||
|         location: 0..31, | ||||
|         location: 0..27, | ||||
|         name: "foo", | ||||
|         public: false, | ||||
|         return_annotation: None, | ||||
|         return_type: (), | ||||
|         end_position: 43, | ||||
|         end_position: 39, | ||||
|         on_test_failure: FailImmediately, | ||||
|     }, | ||||
| ) | ||||
|  |  | |||
|  | @ -243,7 +243,7 @@ pub fn lexer() -> impl Parser<char, Vec<(Token, Span)>, Error = ParseError> { | |||
|         "when" => Token::When, | ||||
|         "validator" => Token::Validator, | ||||
|         "via" => Token::Via, | ||||
|         "benchmark" => Token::Benchmark, | ||||
|         "bench" => Token::Benchmark, | ||||
|         _ => { | ||||
|             if s.chars().next().map_or(false, |c| c.is_uppercase()) { | ||||
|                 Token::UpName { | ||||
|  |  | |||
|  | @ -183,7 +183,7 @@ impl fmt::Display for Token { | |||
|             Token::Once => "once", | ||||
|             Token::Validator => "validator", | ||||
|             Token::Via => "via", | ||||
|             Token::Benchmark => "benchmark", | ||||
|             Token::Benchmark => "bench", | ||||
|         }; | ||||
|         write!(f, "{s}") | ||||
|     } | ||||
|  |  | |||
|  | @ -332,14 +332,12 @@ impl PropertyTest { | |||
|     ) -> Result<Option<Counterexample<'a>>, FuzzerError> { | ||||
|         let mut prng = initial_prng; | ||||
|         let mut counterexample = None; | ||||
|         let mut iteration = 0; | ||||
| 
 | ||||
|         while *remaining > 0 && counterexample.is_none() { | ||||
|             let (next_prng, cex) = self.run_once(prng, labels, plutus_version, iteration)?; | ||||
|             let (next_prng, cex) = self.run_once(prng, labels, plutus_version)?; | ||||
|             prng = next_prng; | ||||
|             counterexample = cex; | ||||
|             *remaining -= 1; | ||||
|             iteration += 1; | ||||
|         } | ||||
| 
 | ||||
|         Ok(counterexample) | ||||
|  | @ -350,12 +348,11 @@ impl PropertyTest { | |||
|         prng: Prng, | ||||
|         labels: &mut BTreeMap<String, usize>, | ||||
|         plutus_version: &'a PlutusVersion, | ||||
|         iteration: usize, | ||||
|     ) -> Result<(Prng, Option<Counterexample<'a>>), FuzzerError> { | ||||
|         use OnTestFailure::*; | ||||
| 
 | ||||
|         let (next_prng, value) = prng | ||||
|             .sample(&self.fuzzer.program, iteration)? | ||||
|             .sample(&self.fuzzer.program)? | ||||
|             .expect("A seeded PRNG returned 'None' which indicates a fuzzer is ill-formed and implemented wrongly; please contact library's authors."); | ||||
| 
 | ||||
|         let mut result = self.eval(&value, plutus_version); | ||||
|  | @ -386,8 +383,8 @@ impl PropertyTest { | |||
|                 value, | ||||
|                 choices: next_prng.choices(), | ||||
|                 cache: Cache::new(move |choices| { | ||||
|                     match Prng::from_choices(choices, iteration) | ||||
|                         .sample(&self.fuzzer.program, iteration) | ||||
|                     match Prng::from_choices(choices) | ||||
|                         .sample(&self.fuzzer.program) | ||||
|                     { | ||||
|                         Err(..) => Status::Invalid, | ||||
|                         Ok(None) => Status::Invalid, | ||||
|  | @ -454,7 +451,7 @@ pub struct Benchmark { | |||
|     pub name: String, | ||||
|     pub on_test_failure: OnTestFailure, | ||||
|     pub program: Program<Name>, | ||||
|     pub fuzzer: Fuzzer<Name>, | ||||
|     pub sampler: Fuzzer<Name>, | ||||
| } | ||||
| 
 | ||||
| unsafe impl Send for Benchmark {} | ||||
|  | @ -467,11 +464,12 @@ impl Benchmark { | |||
|         plutus_version: &PlutusVersion, | ||||
|     ) -> Vec<BenchmarkResult> { | ||||
|         let mut results = Vec::with_capacity(n); | ||||
|         let mut remaining = n; | ||||
|         let mut iteration = 0; | ||||
|         let mut prng = Prng::from_seed(seed); | ||||
| 
 | ||||
|         while remaining > 0 { | ||||
|             match prng.sample(&self.fuzzer.program, n - remaining) { | ||||
|         while n > iteration { | ||||
|             let fuzzer = self.sampler.program.apply_data(Data::integer(num_bigint::BigInt::from(iteration as i64))); | ||||
|             match prng.sample(&fuzzer) { | ||||
|                 Ok(Some((new_prng, value))) => { | ||||
|                     prng = new_prng; | ||||
|                     let mut eval_result = self.eval(&value, plutus_version); | ||||
|  | @ -496,7 +494,7 @@ impl Benchmark { | |||
|                     break; | ||||
|                 } | ||||
|             } | ||||
|             remaining -= 1; | ||||
|             iteration += 1; | ||||
|         } | ||||
| 
 | ||||
|         results | ||||
|  | @ -534,12 +532,10 @@ pub enum Prng { | |||
|     Seeded { | ||||
|         choices: Vec<u8>, | ||||
|         uplc: PlutusData, | ||||
|         iteration: usize, | ||||
|     }, | ||||
|     Replayed { | ||||
|         choices: Vec<u8>, | ||||
|         uplc: PlutusData, | ||||
|         iteration: usize, | ||||
|     }, | ||||
| } | ||||
| 
 | ||||
|  | @ -588,12 +584,11 @@ impl Prng { | |||
|                     Data::bytestring(vec![]),          // Random choices
 | ||||
|                 ], | ||||
|             ), | ||||
|             iteration: 0, | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     /// Construct a Pseudo-random number generator from a pre-defined list of choices.
 | ||||
|     pub fn from_choices(choices: &[u8], iteration: usize) -> Prng { | ||||
|     pub fn from_choices(choices: &[u8]) -> Prng { | ||||
|         Prng::Replayed { | ||||
|             uplc: Data::constr( | ||||
|                 Prng::REPLAYED, | ||||
|  | @ -603,7 +598,6 @@ impl Prng { | |||
|                 ], | ||||
|             ), | ||||
|             choices: choices.to_vec(), | ||||
|             iteration, | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|  | @ -611,11 +605,10 @@ impl Prng { | |||
|     pub fn sample( | ||||
|         &self, | ||||
|         fuzzer: &Program<Name>, | ||||
|         iteration: usize, | ||||
|         // iteration: usize,
 | ||||
|     ) -> Result<Option<(Prng, PlutusData)>, FuzzerError> { | ||||
|         let program = Program::<NamedDeBruijn>::try_from( | ||||
|             fuzzer | ||||
|                 .apply_data(Data::integer(num_bigint::BigInt::from(iteration as i64))) | ||||
|                 .apply_data(self.uplc())).unwrap(); | ||||
|         let mut result = program.eval(ExBudget::max()); | ||||
|         result | ||||
|  | @ -624,7 +617,7 @@ impl Prng { | |||
|                 traces: result.logs(), | ||||
|                 uplc_error, | ||||
|             }) | ||||
|             .map(|term| Prng::from_result(term, iteration)) | ||||
|             .map(|term| Prng::from_result(term)) | ||||
|     } | ||||
| 
 | ||||
|     /// Obtain a Prng back from a fuzzer execution. As a reminder, fuzzers have the following
 | ||||
|  | @ -639,10 +632,9 @@ impl Prng { | |||
|     /// aborted altogether with 'None'.
 | ||||
|     pub fn from_result( | ||||
|         result: Term<NamedDeBruijn>, | ||||
|         iteration: usize, | ||||
|     ) -> Option<(Self, PlutusData)> { | ||||
|         /// Interpret the given 'PlutusData' as one of two Prng constructors.
 | ||||
|         fn as_prng(cst: &PlutusData, iteration: usize) -> Prng { | ||||
|         fn as_prng(cst: &PlutusData) -> Prng { | ||||
|             if let PlutusData::Constr(Constr { tag, fields, .. }) = cst { | ||||
|                 if *tag == 121 + Prng::SEEDED { | ||||
|                     if let [PlutusData::BoundedBytes(bytes), PlutusData::BoundedBytes(choices)] = | ||||
|  | @ -659,7 +651,6 @@ impl Prng { | |||
|                                     PlutusData::BoundedBytes(vec![].into()), | ||||
|                                 ], | ||||
|                             ), | ||||
|                             iteration, | ||||
|                         }; | ||||
|                     } | ||||
|                 } | ||||
|  | @ -670,7 +661,6 @@ impl Prng { | |||
|                         return Prng::Replayed { | ||||
|                             choices: choices.to_vec(), | ||||
|                             uplc: cst.clone(), | ||||
|                             iteration, | ||||
|                         }; | ||||
|                     } | ||||
|                 } | ||||
|  | @ -684,7 +674,7 @@ impl Prng { | |||
|                 if *tag == 121 + Prng::SOME { | ||||
|                     if let [PlutusData::Array(elems)] = &fields[..] { | ||||
|                         if let [new_seed, value] = &elems[..] { | ||||
|                             return Some((as_prng(new_seed, iteration), value.clone())); | ||||
|                             return Some((as_prng(new_seed), value.clone())); | ||||
|                         } | ||||
|                     } | ||||
|                 } | ||||
|  |  | |||
|  | @ -1773,17 +1773,27 @@ fn pipe_wrong_arity_fully_saturated_return_fn() { | |||
| #[test] | ||||
| fn fuzzer_ok_basic() { | ||||
|     let source_code = r#" | ||||
|         fn int() -> Generator<Void, Int> { todo } | ||||
|         fn int() -> Fuzzer<Int> { todo } | ||||
|         test prop(n via int()) { True } | ||||
|     "#;
 | ||||
| 
 | ||||
|     assert!(check(parse(source_code)).is_ok()); | ||||
| } | ||||
| 
 | ||||
| #[test] | ||||
| fn sampler_ok_basic() { | ||||
|     let source_code = r#" | ||||
|         fn int() -> Sampler<Int> { todo } | ||||
|         bench prop(n via int()) { True } | ||||
|     "#;
 | ||||
| 
 | ||||
|     assert!(check(parse(source_code)).is_ok()); | ||||
| } | ||||
| 
 | ||||
| #[test] | ||||
| fn fuzzer_ok_explicit() { | ||||
|     let source_code = r#" | ||||
|         fn int(void: Void, prng: PRNG) -> Option<(PRNG, Int)> { todo } | ||||
|         fn int(prng: PRNG) -> Option<(PRNG, Int)> { todo } | ||||
|         test prop(n via int) { Void } | ||||
|     "#;
 | ||||
| 
 | ||||
|  | @ -1793,8 +1803,8 @@ fn fuzzer_ok_explicit() { | |||
| #[test] | ||||
| fn fuzzer_ok_list() { | ||||
|     let source_code = r#" | ||||
|         fn int() -> Generator<Void, Int> { todo } | ||||
|         fn list(a: Generator<Void, a>) -> Generator<Void, List<a>> { todo } | ||||
|         fn int() -> Fuzzer<Int> { todo } | ||||
|         fn list(a: Fuzzer<a>) -> Fuzzer<List<a>> { todo } | ||||
| 
 | ||||
|         test prop(xs via list(int())) { True } | ||||
|     "#;
 | ||||
|  | @ -1805,8 +1815,8 @@ fn fuzzer_ok_list() { | |||
| #[test] | ||||
| fn fuzzer_err_unbound() { | ||||
|     let source_code = r#" | ||||
|         fn any() -> Generator<Void, a> { todo } | ||||
|         fn list(a: Generator<Void, a>) -> Generator<Void, List<a>> { todo } | ||||
|         fn any() -> Fuzzer<a> { todo } | ||||
|         fn list(a: Fuzzer<a>) -> Fuzzer<List<a>> { todo } | ||||
| 
 | ||||
|         test prop(xs via list(any())) { todo } | ||||
|     "#;
 | ||||
|  | @ -1838,7 +1848,7 @@ fn fuzzer_err_unify_1() { | |||
| #[test] | ||||
| fn fuzzer_err_unify_2() { | ||||
|     let source_code = r#" | ||||
|         fn any() -> Generator<Void, a> { todo } | ||||
|         fn any() -> Fuzzer<a> { todo } | ||||
|         test prop(xs via any) { todo } | ||||
|     "#;
 | ||||
| 
 | ||||
|  | @ -1857,8 +1867,8 @@ fn fuzzer_err_unify_2() { | |||
| #[test] | ||||
| fn fuzzer_err_unify_3() { | ||||
|     let source_code = r#" | ||||
|         fn list(a: Generator<Void, a>) -> Generator<Void, List<a>> { todo } | ||||
|         fn int() -> Generator<Void, Int> { todo } | ||||
|         fn list(a: Fuzzer<a>) -> Fuzzer<List<a>> { todo } | ||||
|         fn int() -> Fuzzer<Int> { todo } | ||||
| 
 | ||||
|         test prop(xs: Int via list(int())) { todo } | ||||
|     "#;
 | ||||
|  |  | |||
|  | @ -838,8 +838,7 @@ fn infer_fuzzer( | |||
| ) -> Result<(Annotation, Rc<Type>), Error> { | ||||
|     let could_not_unify = || Error::CouldNotUnify { | ||||
|         location: *location, | ||||
|         expected: Type::generator( | ||||
|             Type::void(), | ||||
|         expected: Type::fuzzer( | ||||
|             expected_inner_type | ||||
|                 .clone() | ||||
|                 .unwrap_or_else(|| Type::generic_var(0)), | ||||
|  | @ -863,7 +862,7 @@ fn infer_fuzzer( | |||
|                 contains_opaque: _, | ||||
|                 alias: _, | ||||
|             } if module.is_empty() && name == "Option" && args.len() == 1 => { | ||||
|                 match args.first().expect("args.len() == 2 && args[0].is_void()").borrow() { | ||||
|                 match args.first().expect("args.len() == 1").borrow() { | ||||
|                     Type::Tuple { elems, .. } if elems.len() == 2 => { | ||||
|                         let wrapped = elems.get(1).expect("Tuple has two elements"); | ||||
| 
 | ||||
|  | @ -878,7 +877,7 @@ fn infer_fuzzer( | |||
|                         // `unify` now that we have figured out the type carried by the fuzzer.
 | ||||
|                         environment.unify( | ||||
|                             tipo.clone(), | ||||
|                             Type::generator(Type::void(), wrapped.clone()), | ||||
|                             Type::fuzzer(wrapped.clone()), | ||||
|                             *location, | ||||
|                             false, | ||||
|                         )?; | ||||
|  | @ -916,8 +915,7 @@ fn infer_sampler( | |||
| ) -> Result<(Annotation, Rc<Type>), Error> { | ||||
|     let could_not_unify = || Error::CouldNotUnify { | ||||
|         location: *location, | ||||
|         expected: Type::generator( | ||||
|             Type::int(), | ||||
|         expected: Type::sampler( | ||||
|             expected_inner_type | ||||
|                 .clone() | ||||
|                 .unwrap_or_else(|| Type::generic_var(0)), | ||||
|  | @ -930,34 +928,12 @@ fn infer_sampler( | |||
|     match tipo.borrow() { | ||||
|         Type::Fn { | ||||
|             ret, | ||||
|             args: _, | ||||
|             args, | ||||
|             alias: _, | ||||
|         } => match ret.borrow() { | ||||
|             Type::App { | ||||
|                 module, | ||||
|                 name, | ||||
|                 args, | ||||
|                 public: _, | ||||
|                 contains_opaque: _, | ||||
|                 alias: _, | ||||
|             } if module.is_empty() && name == "Option" && args.len() == 1 => { | ||||
|                 match args.first().expect("args.len() == 2 && args[0].is_int()").borrow() { | ||||
|                     Type::Tuple { elems, .. } if elems.len() == 2 => { | ||||
|                         let wrapped = elems.get(1).expect("Tuple has two elements"); | ||||
| 
 | ||||
|                         environment.unify( | ||||
|                             tipo.clone(), | ||||
|                             Type::generator(Type::int(), wrapped.clone()), | ||||
|                             *location, | ||||
|                             false, | ||||
|                         )?; | ||||
| 
 | ||||
|                         Ok((annotate_fuzzer(wrapped, location)?, wrapped.clone())) | ||||
|                     } | ||||
|                     _ => Err(could_not_unify()), | ||||
|                 } | ||||
|             } | ||||
|             _ => Err(could_not_unify()), | ||||
|         } => if args.len() == 1 && args[0].is_int() { | ||||
|             infer_fuzzer(environment, expected_inner_type, ret, &Span::empty()) | ||||
|         } else { | ||||
|             Err(could_not_unify()) | ||||
|         }, | ||||
| 
 | ||||
|         Type::Var { tipo, alias } => match &*tipo.deref().borrow() { | ||||
|  |  | |||
|  | @ -193,7 +193,7 @@ impl Error { | |||
|                 test.input_path.to_path_buf(), | ||||
|                 test.program.to_pretty(), | ||||
|             ), | ||||
|             TestResult::Benchmark(_) => ("benchmark".to_string(), PathBuf::new(), String::new()), // todo
 | ||||
|             TestResult::Benchmark(_) => ("bench".to_string(), PathBuf::new(), String::new()), // todo
 | ||||
|         }; | ||||
| 
 | ||||
|         Error::TestFailure { | ||||
|  |  | |||
|  | @ -112,10 +112,8 @@ mod test { | |||
| 
 | ||||
|             const max_int: Int = 255 | ||||
| 
 | ||||
|             pub type Fuzzer<a> = Generator<Void, a> | ||||
| 
 | ||||
|             pub fn int() -> Fuzzer<Int> { | ||||
|               fn(v: Void, prng: PRNG) -> Option<(PRNG, Int)> { | ||||
|               fn(prng: PRNG) -> Option<(PRNG, Int)> { | ||||
|                 when prng is { | ||||
|                   Seeded { seed, choices } -> { | ||||
|                      let choice = | ||||
|  | @ -163,21 +161,21 @@ mod test { | |||
|             } | ||||
| 
 | ||||
|             pub fn constant(a: a) -> Fuzzer<a> { | ||||
|               fn(v, s0) { Some((s0, a)) } | ||||
|               fn(s0) { Some((s0, a)) } | ||||
|             } | ||||
| 
 | ||||
|             pub fn and_then(fuzz_a: Fuzzer<a>, f: fn(a) -> Fuzzer<b>) -> Fuzzer<b> { | ||||
|               fn(v, s0) { | ||||
|                 when fuzz_a(v, s0) is { | ||||
|                   Some((s1, a)) -> f(a)(v, s1) | ||||
|               fn(s0) { | ||||
|                 when fuzz_a(s0) is { | ||||
|                   Some((s1, a)) -> f(a)(s1) | ||||
|                   None -> None | ||||
|                 } | ||||
|               } | ||||
|             } | ||||
| 
 | ||||
|             pub fn map(fuzz_a: Fuzzer<a>, f: fn(a) -> b) -> Fuzzer<b> { | ||||
|               fn(v, s0) { | ||||
|                 when fuzz_a(v, s0) is { | ||||
|               fn(s0) { | ||||
|                 when fuzz_a(s0) is { | ||||
|                   Some((s1, a)) -> Some((s1, f(a))) | ||||
|                   None -> None | ||||
|                 } | ||||
|  | @ -185,10 +183,10 @@ mod test { | |||
|             } | ||||
| 
 | ||||
|             pub fn map2(fuzz_a: Fuzzer<a>, fuzz_b: Fuzzer<b>, f: fn(a, b) -> c) -> Fuzzer<c> { | ||||
|               fn(v, s0) { | ||||
|                 when fuzz_a(v, s0) is { | ||||
|               fn(s0) { | ||||
|                 when fuzz_a(s0) is { | ||||
|                   Some((s1, a)) -> | ||||
|                     when fuzz_b(Void, s1) is { | ||||
|                     when fuzz_b(s1) is { | ||||
|                       Some((s2, b)) -> Some((s2, f(a, b))) | ||||
|                       None -> None | ||||
|                     } | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue
	
	 Riley-Kilgore
						Riley-Kilgore