From aadf3cfb48c37ca305dd9978eb64e95e186797cb Mon Sep 17 00:00:00 2001 From: KtorZ Date: Sat, 24 Feb 2024 19:02:45 +0100 Subject: [PATCH 01/26] Allow test definition to carry one parameter The parameter is special as it takes no annotation but a 'via' keyword followed by an expression that should unify to a Fuzzer, where Fuzzer = fn(Seed) -> (Seed, a). The current commit only allow name identifiers for now. Ultimately, this may allow full expressions. --- crates/aiken-lang/src/ast.rs | 69 +++- crates/aiken-lang/src/format.rs | 99 ++++-- .../snapshots/def_invalid_property_test.snap | 50 +++ .../snapshots/def_property_test.snap | 38 ++ .../parser/definition/snapshots/def_test.snap | 21 ++ .../aiken-lang/src/parser/definition/test.rs | 102 +++++- crates/aiken-lang/src/parser/lexer.rs | 1 + crates/aiken-lang/src/parser/token.rs | 2 + crates/aiken-lang/src/tipo/environment.rs | 35 +- crates/aiken-lang/src/tipo/error.rs | 12 + crates/aiken-lang/src/tipo/expr.rs | 2 +- crates/aiken-lang/src/tipo/infer.rs | 331 ++++++++++++------ crates/aiken-project/src/tests/gen_uplc.rs | 4 +- 13 files changed, 579 insertions(+), 187 deletions(-) create mode 100644 crates/aiken-lang/src/parser/definition/snapshots/def_invalid_property_test.snap create mode 100644 crates/aiken-lang/src/parser/definition/snapshots/def_property_test.snap create mode 100644 crates/aiken-lang/src/parser/definition/snapshots/def_test.snap diff --git a/crates/aiken-lang/src/ast.rs b/crates/aiken-lang/src/ast.rs index 1811243b..68af1566 100644 --- a/crates/aiken-lang/src/ast.rs +++ b/crates/aiken-lang/src/ast.rs @@ -158,12 +158,15 @@ fn str_to_keyword(word: &str) -> Option { } } -pub type TypedFunction = Function, TypedExpr>; -pub type UntypedFunction = Function<(), UntypedExpr>; +pub type TypedFunction = Function, TypedExpr, TypedArg>; +pub type UntypedFunction = Function<(), UntypedExpr, UntypedArg>; + +pub type TypedTest = Function, TypedExpr, TypedArgVia>; +pub type UntypedTest = Function<(), UntypedExpr, UntypedArgVia>; #[derive(Debug, Clone, PartialEq)] -pub struct Function { - pub arguments: Vec>, +pub struct Function { + pub arguments: Vec, pub body: Expr, pub doc: Option, pub location: Span, @@ -178,7 +181,7 @@ pub struct Function { pub type TypedTypeAlias = TypeAlias>; pub type UntypedTypeAlias = TypeAlias<()>; -impl TypedFunction { +impl TypedTest { pub fn test_hint(&self) -> Option<(BinOp, Box, Box)> { do_test_hint(&self.body) } @@ -358,18 +361,24 @@ pub type UntypedValidator = Validator<(), UntypedExpr>; pub struct Validator { pub doc: Option, pub end_position: usize, - pub fun: Function, - pub other_fun: Option>, + pub fun: Function>, + pub other_fun: Option>>, pub location: Span, pub params: Vec>, } -pub type TypedDefinition = Definition, TypedExpr, String>; -pub type UntypedDefinition = Definition<(), UntypedExpr, ()>; +#[derive(Debug, Clone, PartialEq)] +pub struct DefinitionIdentifier { + pub module: Option, + pub name: String, +} + +pub type TypedDefinition = Definition, TypedExpr, String, ()>; +pub type UntypedDefinition = Definition<(), UntypedExpr, (), DefinitionIdentifier>; #[derive(Debug, Clone, PartialEq)] -pub enum Definition { - Fn(Function), +pub enum Definition { + Fn(Function>), TypeAlias(TypeAlias), @@ -379,12 +388,12 @@ pub enum Definition { ModuleConstant(ModuleConstant), - Test(Function), + Test(Function>), Validator(Validator), } -impl Definition { +impl Definition { pub fn location(&self) -> Span { match self { Definition::Fn(Function { location, .. }) @@ -634,6 +643,40 @@ impl Arg { } } +pub type TypedArgVia = ArgVia, ()>; +pub type UntypedArgVia = ArgVia<(), DefinitionIdentifier>; + +#[derive(Debug, Clone, PartialEq)] +pub struct ArgVia { + pub arg_name: ArgName, + pub location: Span, + pub via: Ann, + pub tipo: T, +} + +impl From> for Arg { + fn from(arg: ArgVia) -> Arg { + Arg { + arg_name: arg.arg_name, + location: arg.location, + tipo: arg.tipo, + annotation: None, + doc: None, + } + } +} + +impl From for TypedArgVia { + fn from(arg: TypedArg) -> TypedArgVia { + ArgVia { + arg_name: arg.arg_name, + tipo: arg.tipo, + location: arg.location, + via: (), + } + } +} + #[derive(Debug, Clone, PartialEq, Eq)] pub enum ArgName { Discarded { diff --git a/crates/aiken-lang/src/format.rs b/crates/aiken-lang/src/format.rs index 176aa02c..9d3045fb 100644 --- a/crates/aiken-lang/src/format.rs +++ b/crates/aiken-lang/src/format.rs @@ -1,11 +1,12 @@ use crate::{ ast::{ - Annotation, Arg, ArgName, AssignmentKind, BinOp, ByteArrayFormatPreference, CallArg, - ClauseGuard, Constant, CurveType, DataType, Definition, Function, IfBranch, - LogicalOpChainKind, ModuleConstant, Pattern, RecordConstructor, RecordConstructorArg, - RecordUpdateSpread, Span, TraceKind, TypeAlias, TypedArg, UnOp, UnqualifiedImport, - UntypedArg, UntypedClause, UntypedClauseGuard, UntypedDefinition, UntypedFunction, - UntypedModule, UntypedPattern, UntypedRecordUpdateArg, Use, Validator, CAPTURE_VARIABLE, + Annotation, Arg, ArgName, ArgVia, AssignmentKind, BinOp, ByteArrayFormatPreference, + CallArg, ClauseGuard, Constant, CurveType, DataType, Definition, DefinitionIdentifier, + Function, IfBranch, LogicalOpChainKind, ModuleConstant, Pattern, RecordConstructor, + RecordConstructorArg, RecordUpdateSpread, Span, TraceKind, TypeAlias, TypedArg, UnOp, + UnqualifiedImport, UntypedArg, UntypedArgVia, UntypedClause, UntypedClauseGuard, + UntypedDefinition, UntypedFunction, UntypedModule, UntypedPattern, UntypedRecordUpdateArg, + Use, Validator, CAPTURE_VARIABLE, }, docvec, expr::{FnStyle, UntypedExpr, DEFAULT_ERROR_STR, DEFAULT_TODO_STR}, @@ -231,16 +232,7 @@ impl<'comments> Formatter<'comments> { return_annotation, end_position, .. - }) => self.definition_fn( - public, - "fn", - name, - args, - return_annotation, - body, - *end_position, - false, - ), + }) => self.definition_fn(public, name, args, return_annotation, body, *end_position), Definition::Validator(Validator { end_position, @@ -257,16 +249,7 @@ impl<'comments> Formatter<'comments> { end_position, can_error, .. - }) => self.definition_fn( - &false, - "test", - name, - args, - &None, - body, - *end_position, - *can_error, - ), + }) => self.definition_test(name, args, body, *end_position, *can_error), Definition::TypeAlias(TypeAlias { alias, @@ -488,25 +471,40 @@ impl<'comments> Formatter<'comments> { commented(doc, comments) } + fn fn_arg_via<'a, A>(&mut self, arg: &'a ArgVia) -> Document<'a> { + let comments = self.pop_comments(arg.location.start); + + let doc_comments = self.doc_comments(arg.location.start); + + let doc = arg.arg_name.to_doc().append(" via "); + + let doc = match arg.via.module { + Some(ref module) => doc.append(module.to_doc()).append("."), + None => doc, + } + .append(arg.via.name.to_doc()) + .group(); + + let doc = doc_comments.append(doc.group()).group(); + + commented(doc, comments) + } + #[allow(clippy::too_many_arguments)] fn definition_fn<'a>( &mut self, public: &'a bool, - keyword: &'a str, name: &'a str, args: &'a [UntypedArg], return_annotation: &'a Option, body: &'a UntypedExpr, end_location: usize, - can_error: bool, ) -> Document<'a> { // Fn name and args let head = pub_(*public) - .append(keyword) - .append(" ") + .append("fn ") .append(name) - .append(wrap_args(args.iter().map(|e| (self.fn_arg(e), false)))) - .append(if can_error { " fail" } else { "" }); + .append(wrap_args(args.iter().map(|e| (self.fn_arg(e), false)))); // Add return annotation let head = match return_annotation { @@ -531,6 +529,39 @@ impl<'comments> Formatter<'comments> { .append("}") } + #[allow(clippy::too_many_arguments)] + fn definition_test<'a>( + &mut self, + name: &'a str, + args: &'a [UntypedArgVia], + body: &'a UntypedExpr, + end_location: usize, + can_error: bool, + ) -> Document<'a> { + // Fn name and args + let head = "test " + .to_doc() + .append(name) + .append(wrap_args(args.iter().map(|e| (self.fn_arg_via(e), false)))) + .append(if can_error { " fail" } else { "" }) + .group(); + + // Format body + let body = self.expr(body, true); + + // Add any trailing comments + let body = match printed_comments(self.pop_comments(end_location), false) { + Some(comments) => body.append(line()).append(comments), + None => body, + }; + + // Stick it all together + head.append(" {") + .append(line().append(body).nest(INDENT).group()) + .append(line()) + .append("}") + } + fn definition_validator<'a>( &mut self, params: &'a [UntypedArg], @@ -550,13 +581,11 @@ impl<'comments> Formatter<'comments> { let first_fn = self .definition_fn( &false, - "fn", &fun.name, &fun.arguments, &fun.return_annotation, &fun.body, fun.end_position, - false, ) .group(); let first_fn = commented(fun_doc_comments.append(first_fn).group(), fun_comments); @@ -570,13 +599,11 @@ impl<'comments> Formatter<'comments> { let other_fn = self .definition_fn( &false, - "fn", &other.name, &other.arguments, &other.return_annotation, &other.body, other.end_position, - false, ) .group(); diff --git a/crates/aiken-lang/src/parser/definition/snapshots/def_invalid_property_test.snap b/crates/aiken-lang/src/parser/definition/snapshots/def_invalid_property_test.snap new file mode 100644 index 00000000..7cd61a30 --- /dev/null +++ b/crates/aiken-lang/src/parser/definition/snapshots/def_invalid_property_test.snap @@ -0,0 +1,50 @@ +--- +source: crates/aiken-lang/src/parser/definition/test.rs +description: "Code:\n\ntest foo(x via f, y via g) {\n True\n}\n" +--- +Test( + Function { + arguments: [ + ArgVia { + arg_name: Named { + name: "x", + label: "x", + location: 9..10, + is_validator_param: false, + }, + location: 9..16, + via: DefinitionIdentifier { + module: None, + name: "f", + }, + tipo: (), + }, + ArgVia { + arg_name: Named { + name: "y", + label: "y", + location: 18..19, + is_validator_param: false, + }, + location: 18..25, + via: DefinitionIdentifier { + module: None, + name: "g", + }, + tipo: (), + }, + ], + body: Var { + location: 33..37, + name: "True", + }, + doc: None, + location: 0..26, + name: "foo", + public: false, + return_annotation: None, + return_type: (), + end_position: 38, + can_error: false, + }, +) diff --git a/crates/aiken-lang/src/parser/definition/snapshots/def_property_test.snap b/crates/aiken-lang/src/parser/definition/snapshots/def_property_test.snap new file mode 100644 index 00000000..8047f21e --- /dev/null +++ b/crates/aiken-lang/src/parser/definition/snapshots/def_property_test.snap @@ -0,0 +1,38 @@ +--- +source: crates/aiken-lang/src/parser/definition/test.rs +description: "Code:\n\ntest foo(x via fuzz.any_int) {\n True\n}\n" +--- +Test( + Function { + arguments: [ + ArgVia { + arg_name: Named { + name: "x", + label: "x", + location: 9..10, + is_validator_param: false, + }, + location: 9..27, + via: DefinitionIdentifier { + module: Some( + "fuzz", + ), + name: "any_int", + }, + tipo: (), + }, + ], + body: Var { + location: 35..39, + name: "True", + }, + doc: None, + location: 0..28, + name: "foo", + public: false, + return_annotation: None, + return_type: (), + end_position: 40, + can_error: false, + }, +) diff --git a/crates/aiken-lang/src/parser/definition/snapshots/def_test.snap b/crates/aiken-lang/src/parser/definition/snapshots/def_test.snap new file mode 100644 index 00000000..de24dc47 --- /dev/null +++ b/crates/aiken-lang/src/parser/definition/snapshots/def_test.snap @@ -0,0 +1,21 @@ +--- +source: crates/aiken-lang/src/parser/definition/test.rs +description: "Code:\n\ntest foo() {\n True\n}\n" +--- +Test( + Function { + arguments: [], + body: Var { + location: 17..21, + name: "True", + }, + doc: None, + location: 0..10, + name: "foo", + public: false, + return_annotation: None, + return_type: (), + end_position: 22, + can_error: false, + }, +) diff --git a/crates/aiken-lang/src/parser/definition/test.rs b/crates/aiken-lang/src/parser/definition/test.rs index 6691edb2..33d48628 100644 --- a/crates/aiken-lang/src/parser/definition/test.rs +++ b/crates/aiken-lang/src/parser/definition/test.rs @@ -13,8 +13,12 @@ pub fn parser() -> impl Parser name}) - .then_ignore(just(Token::LeftParen)) - .then_ignore(just(Token::RightParen)) + .then( + via() + .separated_by(just(Token::Comma)) + .allow_trailing() + .delimited_by(just(Token::LeftParen), just(Token::RightParen)), + ) .then(just(Token::Fail).ignored().or_not()) .map_with_span(|name, span| (name, span)) .then( @@ -22,26 +26,72 @@ pub fn parser() -> impl Parser impl Parser { + choice(( + select! {Token::DiscardName {name} => name}.map_with_span(|name, span| { + ast::ArgName::Discarded { + label: name.clone(), name, - public: false, - return_annotation: None, - return_type: (), - can_error: fail.is_some() || old_fail.is_some(), - }) - }) + location: span, + } + }), + select! {Token::Name {name} => name}.map_with_span(move |name, location| { + ast::ArgName::Named { + label: name.clone(), + name, + location, + is_validator_param: false, + } + }), + )) + .then_ignore(just(Token::Via)) + .then( + select! { Token::Name { name } => name } + .then_ignore(just(Token::Dot)) + .or_not(), + ) + .then(select! { Token::Name { name } => name }) + .map_with_span(|((arg_name, module), name), location| ast::ArgVia { + arg_name, + via: ast::DefinitionIdentifier { module, name }, + tipo: (), + location, + }) } #[cfg(test)] mod tests { use crate::assert_definition; + #[test] + fn def_test() { + assert_definition!( + r#" + test foo() { + True + } + "# + ); + } + #[test] fn def_test_fail() { assert_definition!( @@ -54,4 +104,26 @@ mod tests { "# ); } + + #[test] + fn def_property_test() { + assert_definition!( + r#" + test foo(x via fuzz.any_int) { + True + } + "# + ); + } + + #[test] + fn def_invalid_property_test() { + assert_definition!( + r#" + test foo(x via f, y via g) { + True + } + "# + ); + } } diff --git a/crates/aiken-lang/src/parser/lexer.rs b/crates/aiken-lang/src/parser/lexer.rs index 9dea075a..3e0df9cf 100644 --- a/crates/aiken-lang/src/parser/lexer.rs +++ b/crates/aiken-lang/src/parser/lexer.rs @@ -240,6 +240,7 @@ pub fn lexer() -> impl Parser, Error = ParseError> { "type" => Token::Type, "when" => Token::When, "validator" => Token::Validator, + "via" => Token::Via, _ => { if s.chars().next().map_or(false, |c| c.is_uppercase()) { Token::UpName { diff --git a/crates/aiken-lang/src/parser/token.rs b/crates/aiken-lang/src/parser/token.rs index cae2665b..d48e1179 100644 --- a/crates/aiken-lang/src/parser/token.rs +++ b/crates/aiken-lang/src/parser/token.rs @@ -89,6 +89,7 @@ pub enum Token { When, Trace, Validator, + Via, } impl fmt::Display for Token { @@ -176,6 +177,7 @@ impl fmt::Display for Token { Token::Test => "test", Token::Fail => "fail", Token::Validator => "validator", + Token::Via => "via", }; write!(f, "\"{s}\"") } diff --git a/crates/aiken-lang/src/tipo/environment.rs b/crates/aiken-lang/src/tipo/environment.rs index 3ba8e904..8bb9b383 100644 --- a/crates/aiken-lang/src/tipo/environment.rs +++ b/crates/aiken-lang/src/tipo/environment.rs @@ -10,7 +10,7 @@ use crate::{ RecordConstructor, RecordConstructorArg, Span, TypeAlias, TypedDefinition, TypedPattern, UnqualifiedImport, UntypedArg, UntypedDefinition, Use, Validator, PIPE_VARIABLE, }, - builtins::{self, function, generic_var, tuple, unbound_var}, + builtins::{function, generic_var, tuple, unbound_var}, tipo::fields::FieldMap, IdGenerator, }; @@ -1185,23 +1185,22 @@ impl<'a> Environment<'a> { }) } - Definition::Test(Function { name, location, .. }) => { - assert_unique_value_name(names, name, location)?; - hydrators.insert(name.clone(), Hydrator::new()); - let arg_types = vec![]; - let return_type = builtins::bool(); - self.insert_variable( - name.clone(), - ValueConstructorVariant::ModuleFn { - name: name.clone(), - field_map: None, - module: module_name.to_owned(), - arity: 0, - location: *location, - builtin: None, - }, - function(arg_types, return_type), - ); + Definition::Test(test) => { + let arguments = test + .arguments + .iter() + .map(|arg| arg.clone().into()) + .collect::>(); + + self.register_function( + &test.name, + &arguments, + &test.return_annotation, + module_name, + hydrators, + names, + &test.location, + )?; } Definition::DataType(DataType { diff --git a/crates/aiken-lang/src/tipo/error.rs b/crates/aiken-lang/src/tipo/error.rs index 1acbc454..1ed18458 100644 --- a/crates/aiken-lang/src/tipo/error.rs +++ b/crates/aiken-lang/src/tipo/error.rs @@ -946,6 +946,17 @@ The best thing to do from here is to remove it."#))] #[label("{} arguments", if *count < 2 { "not enough" } else { "too many" })] location: Span, }, + + #[error("I caught a test with too many arguments.\n")] + #[diagnostic(code("illegal::test_arity"))] + #[diagnostic(help( + "Tests are allowed to have 0 or 1 argument, but no more. Here I've found a test definition with {count} arguments. If you need to provide multiple values to a test, use a Record or a Tuple.", + ))] + IncorrectTestArity { + count: usize, + #[label("too many arguments")] + location: Span, + }, } impl ExtraData for Error { @@ -997,6 +1008,7 @@ impl ExtraData for Error { | Error::UnnecessarySpreadOperator { .. } | Error::UpdateMultiConstructorType { .. } | Error::ValidatorImported { .. } + | Error::IncorrectTestArity { .. } | Error::ValidatorMustReturnBool { .. } => None, Error::UnknownType { name, .. } diff --git a/crates/aiken-lang/src/tipo/expr.rs b/crates/aiken-lang/src/tipo/expr.rs index 83e55f33..b7bee950 100644 --- a/crates/aiken-lang/src/tipo/expr.rs +++ b/crates/aiken-lang/src/tipo/expr.rs @@ -1860,7 +1860,7 @@ impl<'a, 'b> ExprTyper<'a, 'b> { } } - fn infer_value_constructor( + pub fn infer_value_constructor( &mut self, module: &Option, name: &str, diff --git a/crates/aiken-lang/src/tipo/infer.rs b/crates/aiken-lang/src/tipo/infer.rs index 9b94181b..106a9aa3 100644 --- a/crates/aiken-lang/src/tipo/infer.rs +++ b/crates/aiken-lang/src/tipo/infer.rs @@ -2,15 +2,19 @@ use std::collections::HashMap; use crate::{ ast::{ - ArgName, DataType, Definition, Function, Layer, ModuleConstant, ModuleKind, - RecordConstructor, RecordConstructorArg, Tracing, TypeAlias, TypedDefinition, - TypedFunction, TypedModule, UntypedDefinition, UntypedModule, Use, Validator, + Annotation, Arg, ArgName, DataType, Definition, Function, Layer, ModuleConstant, + ModuleKind, RecordConstructor, RecordConstructorArg, Tracing, TypeAlias, TypedArg, + TypedDefinition, TypedFunction, TypedModule, UntypedArg, UntypedDefinition, UntypedModule, + Use, Validator, }, builtins, builtins::function, + expr::{TypedExpr, UntypedExpr}, line_numbers::LineNumbers, + tipo::{Span, Type}, IdGenerator, }; +use std::rc::Rc; use super::{ environment::{generalise, EntityKind, Environment}, @@ -159,97 +163,14 @@ fn infer_definition( tracing: Tracing, ) -> Result { match def { - Definition::Fn(Function { - doc, - location, - name, - public, - arguments: args, - body, - return_annotation, - end_position, - can_error, - .. - }) => { - let preregistered_fn = environment - .get_variable(&name) - .expect("Could not find preregistered type for function"); - - let field_map = preregistered_fn.field_map().cloned(); - - let preregistered_type = preregistered_fn.tipo.clone(); - - let (args_types, return_type) = preregistered_type - .function_types() - .expect("Preregistered type for fn was not a fn"); - - // Infer the type using the preregistered args + return types as a starting point - let (tipo, args, body, safe_to_generalise) = - environment.in_new_scope(|environment| { - let args = args - .into_iter() - .zip(&args_types) - .map(|(arg_name, tipo)| arg_name.set_type(tipo.clone())) - .collect(); - - let mut expr_typer = ExprTyper::new(environment, lines, tracing); - - expr_typer.hydrator = hydrators - .remove(&name) - .expect("Could not find hydrator for fn"); - - let (args, body) = - expr_typer.infer_fn_with_known_types(args, body, Some(return_type))?; - - let args_types = args.iter().map(|a| a.tipo.clone()).collect(); - - let tipo = function(args_types, body.tipo()); - - let safe_to_generalise = !expr_typer.ungeneralised_function_used; - - Ok::<_, Error>((tipo, args, body, safe_to_generalise)) - })?; - - // Assert that the inferred type matches the type of any recursive call - environment.unify(preregistered_type, tipo.clone(), location, false)?; - - // Generalise the function if safe to do so - let tipo = if safe_to_generalise { - environment.ungeneralised_functions.remove(&name); - - let tipo = generalise(tipo, 0); - - let module_fn = ValueConstructorVariant::ModuleFn { - name: name.clone(), - field_map, - module: module_name.to_owned(), - arity: args.len(), - location, - builtin: None, - }; - - environment.insert_variable(name.clone(), module_fn, tipo.clone()); - - tipo - } else { - tipo - }; - - Ok(Definition::Fn(Function { - doc, - location, - name, - public, - arguments: args, - return_annotation, - return_type: tipo - .return_type() - .expect("Could not find return type for fn"), - body, - can_error, - end_position, - })) - } + Definition::Fn(f) => Ok(Definition::Fn(infer_function( + f, + module_name, + hydrators, + environment, + lines, + tracing, + )?)), Definition::Validator(Validator { doc, @@ -412,20 +333,127 @@ fn infer_definition( } Definition::Test(f) => { - if let Definition::Fn(f) = infer_definition( - Definition::Fn(f), + fn annotate_fuzzer(tipo: &Type, location: &Span) -> Result { + match tipo { + // TODO: Ensure args & first returned element is a Prelude's PRNG. + Type::Fn { ret, .. } => { + let ann = tipo_to_annotation(ret, location)?; + match ann { + Annotation::Tuple { elems, .. } if elems.len() == 2 => { + Ok(elems.get(1).expect("Tuple has two elements").to_owned()) + } + _ => todo!("Fuzzer returns something else than a 2-tuple? "), + } + } + Type::Var { .. } | Type::App { .. } | Type::Tuple { .. } => { + todo!("Fuzzer type isn't a function?"); + } + } + } + + fn tipo_to_annotation(tipo: &Type, location: &Span) -> Result { + match tipo { + Type::App { + name, module, args, .. + } => { + let arguments = args + .iter() + .map(|arg| tipo_to_annotation(arg, location)) + .collect::, _>>()?; + Ok(Annotation::Constructor { + name: name.to_owned(), + module: Some(module.to_owned()), + arguments, + location: *location, + }) + } + Type::Tuple { elems } => { + let elems = elems + .iter() + .map(|arg| tipo_to_annotation(arg, location)) + .collect::, _>>()?; + Ok(Annotation::Tuple { + elems, + location: *location, + }) + } + Type::Fn { .. } | Type::Var { .. } => { + todo!("Fuzzer contains functions and/or non-concrete data-types?"); + } + } + } + + let annotation = match f.arguments.first() { + Some(arg) => { + if f.arguments.len() > 1 { + return Err(Error::IncorrectTestArity { + count: f.arguments.len(), + location: f.arguments.get(1).unwrap().location, + }); + } + + let ValueConstructor { tipo, .. } = ExprTyper::new(environment, lines, tracing) + .infer_value_constructor(&arg.via.module, &arg.via.name, &arg.location)?; + + Ok(Some(annotate_fuzzer(&tipo, &arg.location)?)) + } + None => Ok(None), + }?; + + let typed_f = infer_function( + Function { + doc: f.doc, + location: f.location, + name: f.name, + public: f.public, + arguments: f + .arguments + .into_iter() + .map(|arg| Arg { + annotation: annotation.clone(), + ..arg.into() + }) + .collect(), + return_annotation: f.return_annotation, + return_type: f.return_type, + body: f.body, + can_error: f.can_error, + end_position: f.end_position, + }, module_name, hydrators, environment, lines, tracing, - )? { - environment.unify(f.return_type.clone(), builtins::bool(), f.location, false)?; + )?; - Ok(Definition::Test(f)) - } else { - unreachable!("test definition inferred as something other than a function?") - } + environment.unify( + typed_f.return_type.clone(), + builtins::bool(), + typed_f.location, + false, + )?; + + Ok(Definition::Test(Function { + doc: typed_f.doc, + location: typed_f.location, + name: typed_f.name, + public: typed_f.public, + arguments: match annotation { + Some(_) => vec![typed_f + .arguments + .first() + .expect("has exactly one argument") + .to_owned() + .into()], + None => vec![], + }, + return_annotation: typed_f.return_annotation, + return_type: typed_f.return_type, + body: typed_f.body, + can_error: typed_f.can_error, + end_position: typed_f.end_position, + })) } Definition::TypeAlias(TypeAlias { @@ -640,3 +668,102 @@ fn infer_definition( } } } + +fn infer_function( + f: Function<(), UntypedExpr, UntypedArg>, + module_name: &String, + hydrators: &mut HashMap, + environment: &mut Environment<'_>, + lines: &LineNumbers, + tracing: Tracing, +) -> Result, TypedExpr, TypedArg>, Error> { + let Function { + doc, + location, + name, + public, + arguments, + body, + return_annotation, + end_position, + can_error, + .. + } = f; + + let preregistered_fn = environment + .get_variable(&name) + .expect("Could not find preregistered type for function"); + + let field_map = preregistered_fn.field_map().cloned(); + + let preregistered_type = preregistered_fn.tipo.clone(); + + let (args_types, return_type) = preregistered_type + .function_types() + .expect("Preregistered type for fn was not a fn"); + + // Infer the type using the preregistered args + return types as a starting point + let (tipo, arguments, body, safe_to_generalise) = environment.in_new_scope(|environment| { + let args = arguments + .into_iter() + .zip(&args_types) + .map(|(arg_name, tipo)| arg_name.set_type(tipo.clone())) + .collect(); + + let mut expr_typer = ExprTyper::new(environment, lines, tracing); + + expr_typer.hydrator = hydrators + .remove(&name) + .expect("Could not find hydrator for fn"); + + let (args, body) = expr_typer.infer_fn_with_known_types(args, body, Some(return_type))?; + + let args_types = args.iter().map(|a| a.tipo.clone()).collect(); + + let tipo = function(args_types, body.tipo()); + + let safe_to_generalise = !expr_typer.ungeneralised_function_used; + + Ok::<_, Error>((tipo, args, body, safe_to_generalise)) + })?; + + // Assert that the inferred type matches the type of any recursive call + environment.unify(preregistered_type, tipo.clone(), location, false)?; + + // Generalise the function if safe to do so + let tipo = if safe_to_generalise { + environment.ungeneralised_functions.remove(&name); + + let tipo = generalise(tipo, 0); + + let module_fn = ValueConstructorVariant::ModuleFn { + name: name.clone(), + field_map, + module: module_name.to_owned(), + arity: arguments.len(), + location, + builtin: None, + }; + + environment.insert_variable(name.clone(), module_fn, tipo.clone()); + + tipo + } else { + tipo + }; + + Ok(Function { + doc, + location, + name, + public, + arguments, + return_annotation, + return_type: tipo + .return_type() + .expect("Could not find return type for fn"), + body, + can_error, + end_position, + }) +} diff --git a/crates/aiken-project/src/tests/gen_uplc.rs b/crates/aiken-project/src/tests/gen_uplc.rs index 6647e7f9..a9ab36d5 100644 --- a/crates/aiken-project/src/tests/gen_uplc.rs +++ b/crates/aiken-project/src/tests/gen_uplc.rs @@ -1,6 +1,6 @@ use pretty_assertions::assert_eq; -use aiken_lang::ast::{Definition, Function, TraceLevel, Tracing, TypedFunction, TypedValidator}; +use aiken_lang::ast::{Definition, Function, TraceLevel, Tracing, TypedTest, TypedValidator}; use uplc::{ ast::{Constant, Data, DeBruijn, Name, Program, Term, Type}, builder::{CONSTR_FIELDS_EXPOSER, CONSTR_INDEX_EXPOSER}, @@ -13,7 +13,7 @@ use crate::module::CheckedModules; use super::TestProject; enum TestType { - Func(TypedFunction), + Func(TypedTest), Validator(TypedValidator), } From 3762473a600e5211cbf85e7829625081e8f2056d Mon Sep 17 00:00:00 2001 From: KtorZ Date: Sun, 25 Feb 2024 01:09:26 +0100 Subject: [PATCH 02/26] Add preliminary plumbing to run property test through the CLI. This is very very rough at the moment. But it does a couple of thing: 1. The 'ArgVia' now contains an Expr/TypedExpr which should unify to a Fuzzer. This is to avoid having to introduce custom logic to handle fuzzer referencing. So this now accepts function call, field access etc.. so long as they unify to the right thing. 2. I've done quite a lot of cleanup in aiken-project mostly around the tests and the naming surrounding them. What we used to call 'Script' is now called 'Test' and is an enum between UnitTest (ex-Script) and PropertyTest. I've moved some boilerplate and relevant function under those module Impl. 3. I've completed the end-to-end pipeline of: - Compiling the property test - Compiling the fuzzer - Generating an initial seed - Running property tests sequentially, threading the seed through each step. An interesting finding is that, I had to wrap the prop test in a similar wrapper that we use for validator, to ensure we convert primitive types wrapped in Data back to UPLC terms. This is necessary because the fuzzer return a ProtoPair (and soon an Array) which holds 'Data'. At the moment, we do nothing with the size, though the size should ideally grow after each iteration (up to a certain cap). In addition, there are a couple of todo/fixme that I left in the code as reminders of what's left to do beyond the obvious (error and success reporting, testing, etc..) --- Cargo.lock | 387 +++++++++--------- crates/aiken-lang/src/ast.rs | 41 +- crates/aiken-lang/src/format.rs | 28 +- crates/aiken-lang/src/gen_uplc.rs | 2 +- .../aiken-lang/src/parser/definition/test.rs | 36 +- crates/aiken-lang/src/tipo/infer.rs | 43 +- crates/aiken-project/Cargo.toml | 1 + crates/aiken-project/src/lib.rs | 137 +++++-- crates/aiken-project/src/script.rs | 179 ++++++-- crates/aiken-project/src/telemetry.rs | 22 +- crates/aiken-project/src/tests/gen_uplc.rs | 2 +- crates/uplc/src/machine/error.rs | 2 +- crates/uplc/src/machine/eval_result.rs | 5 +- examples/acceptance_tests/093/aiken.toml | 5 +- examples/acceptance_tests/093/lib/foo.ak | 16 +- 15 files changed, 559 insertions(+), 347 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 654baf0a..e97a58dc 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -19,9 +19,9 @@ checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" [[package]] name = "aes" -version = "0.8.3" +version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac1f845298e95f983ff1944b728ae08b8cebab80d684f0a832ed0fc74dfa27e2" +checksum = "b169f7a6d4742236a0a00c541b845991d0ac43e546831af1249753ab4c3aa3a0" dependencies = [ "cfg-if", "cipher", @@ -30,9 +30,9 @@ dependencies = [ [[package]] name = "ahash" -version = "0.8.7" +version = "0.8.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77c3a9648d43b9cd48db467b3f87fdd6e146bcc88ab0180006cef2179fe11d01" +checksum = "8b79b82693f705137f8fb9b37871d99e4f9a7df12b917eed79c3d3954830a60b" dependencies = [ "cfg-if", "once_cell", @@ -136,6 +136,7 @@ dependencies = [ "itertools", "miette", "notify", + "num-bigint", "owo-colors", "pallas", "petgraph", @@ -164,9 +165,9 @@ checksum = "0942ffc6dcaadf03badf6e6a2d0228460359d5e34b57ccdc720b7382dfbd5ec5" [[package]] name = "anstream" -version = "0.6.11" +version = "0.6.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e2e1ebcb11de5c03c67de28a7df593d32191b44939c482e97702baaaa6ab6a5" +checksum = "d96bd03f33fe50a863e394ee9718a706f988b9079b20c3784fb726e7678b62fb" dependencies = [ "anstyle", "anstyle-parse", @@ -178,9 +179,9 @@ dependencies = [ [[package]] name = "anstyle" -version = "1.0.4" +version = "1.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7079075b41f533b8c61d2a4d073c4676e1f8b249ff94a393b0595db304e0dd87" +checksum = "8901269c6307e8d93993578286ac0edf7f195079ffff5ebdeea6a59ffb7e36bc" [[package]] name = "anstyle-parse" @@ -212,9 +213,9 @@ dependencies = [ [[package]] name = "anyhow" -version = "1.0.79" +version = "1.0.80" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "080e9890a082662b09c1ad45f567faeeb47f22b5fb23895fbe1e651e718e25ca" +checksum = "5ad32ce52e4161730f7098c077cd2ed6229b5804ccf99e5366be1ab72a98b4e1" [[package]] name = "arrayvec" @@ -248,7 +249,7 @@ dependencies = [ "proc-macro2", "quote", "serde", - "syn 2.0.48", + "syn 2.0.52", ] [[package]] @@ -274,7 +275,7 @@ checksum = "c980ee35e870bd1a4d2c8294d4c04d0499e67bca1e4b5cefcc693c2fa00caea9" dependencies = [ "proc-macro2", "quote", - "syn 2.0.48", + "syn 2.0.52", ] [[package]] @@ -458,9 +459,9 @@ dependencies = [ [[package]] name = "bstr" -version = "1.9.0" +version = "1.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c48f0051a4b4c5e0b6d365cd04af53aeaa209e3cc15ec2cdb69e73cc87fbd0dc" +checksum = "05efc5cfd9110c8416e471df0e96702d58690178e206e61b7173706673c93706" dependencies = [ "memchr", "serde", @@ -478,9 +479,9 @@ dependencies = [ [[package]] name = "bumpalo" -version = "3.14.0" +version = "3.15.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f30e7476521f6f8af1a1c4c0b8cc94f0bee37d91763d0ca2665f299b6cd8aec" +checksum = "8ea184aa71bb362a1157c896979544cc23974e08fd265f29ea96b59f0b4a555b" [[package]] name = "byteorder" @@ -529,11 +530,10 @@ dependencies = [ [[package]] name = "cc" -version = "1.0.83" +version = "1.0.88" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1174fb0b6ec23863f8b971027804a42614e347eafb0a95bf0b12cdae21fc4d0" +checksum = "02f341c093d19155a6e41631ce5971aac4e9a868262212153124c15fa22d1cdc" dependencies = [ - "jobserver", "libc", ] @@ -545,9 +545,9 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] name = "chrono" -version = "0.4.32" +version = "0.4.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41daef31d7a747c5c847246f36de49ced6f7403b4cdabc807a97b5cc184cda7a" +checksum = "5bc015644b92d5890fab7489e49d21f879d5c990186827d42ec511919404f38b" dependencies = [ "num-traits", ] @@ -574,9 +574,9 @@ dependencies = [ [[package]] name = "clap" -version = "4.4.18" +version = "4.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e578d6ec4194633722ccf9544794b71b1385c3c027efe0c55db226fc880865c" +checksum = "c918d541ef2913577a0f9566e9ce27cb35b6df072075769e0b26cb5a554520da" dependencies = [ "clap_builder", "clap_derive", @@ -584,9 +584,9 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.4.18" +version = "4.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4df4df40ec50c46000231c914968278b1eb05098cf8f1b3a518a95030e71d1c7" +checksum = "9f3e7391dad68afb0c2ede1bf619f579a3dc9c2ec67f089baa397123a2f3d1eb" dependencies = [ "anstream", "anstyle", @@ -599,30 +599,30 @@ dependencies = [ [[package]] name = "clap_complete" -version = "4.4.9" +version = "4.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df631ae429f6613fcd3a7c1adbdb65f637271e561b03680adaa6573015dfb106" +checksum = "885e4d7d5af40bfb99ae6f9433e292feac98d452dcb3ec3d25dfe7552b77da8c" dependencies = [ "clap", ] [[package]] name = "clap_derive" -version = "4.4.7" +version = "4.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf9804afaaf59a91e75b022a30fb7229a7901f60c755489cc61c9b423b836442" +checksum = "307bc0538d5f0f83b8248db3087aa92fe504e4691294d0c96c0eabc33f47ba47" dependencies = [ "heck", "proc-macro2", "quote", - "syn 2.0.48", + "syn 2.0.52", ] [[package]] name = "clap_lex" -version = "0.6.0" +version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "702fc72eb24e5a1e48ce58027a675bc24edd52096d5397d4aea7c6dd9eca0bd1" +checksum = "98cc8fbded0c607b7ba9dd60cd98df59af97e84d24e49c8557331cfc26d301ce" [[package]] name = "colorchoice" @@ -696,18 +696,18 @@ checksum = "19d374276b40fb8bbdee95aef7c7fa6b5316ec764510eb64b8dd0e2ed0d7e7f5" [[package]] name = "crc32fast" -version = "1.3.2" +version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b540bd8bc810d3885c6ea91e2018302f68baba2129ab3e88f32389ee9370880d" +checksum = "b3855a8a784b474f333699ef2bbca9db2c4a1f6d9088a90a2d25b1eb53111eaa" dependencies = [ "cfg-if", ] [[package]] name = "crossbeam-channel" -version = "0.5.11" +version = "0.5.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "176dc175b78f56c0f321911d9c8eb2b77a78a4860b9c19db83835fea1a46649b" +checksum = "ab3db02a9c5b5121e1e42fbdb1aeb65f5e02624cc58c43f2884c6ccac0b82f95" dependencies = [ "crossbeam-utils", ] @@ -849,9 +849,9 @@ dependencies = [ [[package]] name = "dyn-clone" -version = "1.0.16" +version = "1.0.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "545b22097d44f8a9581187cdf93de7a71e4722bf51200cfaba810865b49a495d" +checksum = "0d6ef0072f8a535281e4876be788938b528e9a1d43900b82c2569af7da799125" [[package]] name = "ecdsa" @@ -869,9 +869,9 @@ dependencies = [ [[package]] name = "either" -version = "1.9.0" +version = "1.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a26ae43d7bcc3b814de94796a5e736d4029efb0ee900c12e2d54c993ad1a1e07" +checksum = "11157ac094ffbdde99aa67b23417ebdd801842852b500e395a45a9c0aac03e4a" [[package]] name = "elliptic-curve" @@ -1072,7 +1072,7 @@ checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac" dependencies = [ "proc-macro2", "quote", - "syn 2.0.48", + "syn 2.0.52", ] [[package]] @@ -1188,7 +1188,7 @@ dependencies = [ "futures-sink", "futures-util", "http", - "indexmap 2.1.0", + "indexmap 2.2.5", "slab", "tokio", "tokio-util", @@ -1197,9 +1197,9 @@ dependencies = [ [[package]] name = "half" -version = "1.8.2" +version = "1.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eabb4a44450da02c90444cf74558da904edde8fb4e9035a9a6a4e15445af0bd7" +checksum = "1b43ede17f21864e81be2fa654110bf1e793774238d86ef8555c37e6519c0403" [[package]] name = "hashbrown" @@ -1234,9 +1234,9 @@ dependencies = [ [[package]] name = "hermit-abi" -version = "0.3.4" +version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5d3d0e0f38255e7fa3cf31335b3a56f05febd18025f4db5ef7a0cfb4f8da651f" +checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024" [[package]] name = "hex" @@ -1392,9 +1392,9 @@ dependencies = [ [[package]] name = "indexmap" -version = "2.1.0" +version = "2.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d530e1a18b1cb4c484e6e34556a0d948706958449fca0cab753d649f2bce3d1f" +checksum = "7b0b929d511467233429c45a44ac1dcaa21ba0f5ba11e4879e6ed28ddb4f9df4" dependencies = [ "equivalent", "hashbrown 0.14.3", @@ -1453,9 +1453,9 @@ dependencies = [ [[package]] name = "insta" -version = "1.34.0" +version = "1.35.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5d64600be34b2fcfc267740a243fa7744441bb4947a619ac4e5bb6507f35fbfc" +checksum = "7c985c1bef99cf13c58fade470483d81a2bfe846ebde60ed28cc2dddec2df9e2" dependencies = [ "console", "lazy_static", @@ -1473,20 +1473,20 @@ checksum = "8f518f335dce6725a761382244631d86cf0ccb2863413590b31338feb467f9c3" [[package]] name = "is-terminal" -version = "0.4.10" +version = "0.4.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0bad00257d07be169d870ab665980b06cdb366d792ad690bf2e76876dc503455" +checksum = "f23ff5ef2b80d608d61efee834934d862cd92461afc0560dedf493e4c033738b" dependencies = [ - "hermit-abi 0.3.4", - "rustix", + "hermit-abi 0.3.9", + "libc", "windows-sys 0.52.0", ] [[package]] name = "is_ci" -version = "1.1.1" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "616cde7c720bb2bb5824a224687d8f77bfd38922027f01d825cd7453be5099fb" +checksum = "7655c9839580ee829dfacba1d1278c2b7883e50a277ff7541299489d6bdfdc45" [[package]] name = "itertools" @@ -1503,20 +1503,11 @@ version = "1.0.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b1a46d1a171d865aa5f83f92695765caa047a9b4cbae2cbf37dbd613a793fd4c" -[[package]] -name = "jobserver" -version = "0.1.27" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8c37f63953c4c63420ed5fd3d6d398c719489b9f872b9fa683262f8edd363c7d" -dependencies = [ - "libc", -] - [[package]] name = "js-sys" -version = "0.3.67" +version = "0.3.68" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a1d36f1235bc969acba30b7f5990b864423a6068a10f7c90ae8f0112e3a59d1" +checksum = "406cda4b368d531c842222cf9d2600a9a4acce8d29423695379c6868a143a9ee" dependencies = [ "wasm-bindgen", ] @@ -1572,9 +1563,9 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" [[package]] name = "libc" -version = "0.2.152" +version = "0.2.153" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "13e3bf6590cbc649f4d1a3eefc9d5d6eb746f5200ffb04e5e142700b8faa56e7" +checksum = "9c198f91728a82281a64e1f4f9eeb25d82cb32a5de251c6bd1b5154d63a8e7bd" [[package]] name = "libgit2-sys" @@ -1607,9 +1598,9 @@ dependencies = [ [[package]] name = "libz-sys" -version = "1.1.14" +version = "1.1.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "295c17e837573c8c821dbaeb3cceb3d745ad082f7572191409e69cbc1b3fd050" +checksum = "037731f5d3aaa87a5675e895b63ddff1a87624bc29f77004ea829809654e48f6" dependencies = [ "cc", "libc", @@ -1641,9 +1632,9 @@ dependencies = [ [[package]] name = "log" -version = "0.4.20" +version = "0.4.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f" +checksum = "90ed8c1e510134f979dbc4f070f87d4313098b704861a105fe34231c70a3901c" [[package]] name = "lsp-server" @@ -1711,7 +1702,7 @@ checksum = "49e7bc1560b95a3c4a25d03de42fe76ca718ab92d1a22a55b9b4cf67b3ae635c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.48", + "syn 2.0.52", ] [[package]] @@ -1759,9 +1750,9 @@ checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" [[package]] name = "miniz_oxide" -version = "0.7.1" +version = "0.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e7810e0be55b428ada41041c41f32c9f1a42817901b4ccf45fa3d4b6561e74c7" +checksum = "9d811f3e15f28568be3407c8e7fdb6514c1cda3cb30683f15b6a1a1dc4ea14a7" dependencies = [ "adler", ] @@ -1852,20 +1843,25 @@ dependencies = [ ] [[package]] -name = "num-integer" -version = "0.1.45" +name = "num-conv" +version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "225d3389fb3509a24c93f5c29eb6bde2586b98d9f016636dff58d7c6f7569cd9" +checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9" + +[[package]] +name = "num-integer" +version = "0.1.46" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f" dependencies = [ - "autocfg", "num-traits", ] [[package]] name = "num-traits" -version = "0.2.17" +version = "0.2.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "39e3200413f237f41ab11ad6d161bc7239c84dcb631773ccd7de3dfe4b5c267c" +checksum = "da0df0e5185db44f69b44f26786fe401b6c293d1907744beaa7fa62b2e5a517a" dependencies = [ "autocfg", "libm", @@ -1877,7 +1873,7 @@ version = "1.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43" dependencies = [ - "hermit-abi 0.3.4", + "hermit-abi 0.3.9", "libc", ] @@ -1898,9 +1894,9 @@ checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" [[package]] name = "openssl" -version = "0.10.63" +version = "0.10.64" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "15c9d69dd87a29568d4d017cfe8ec518706046a05184e5aea92d0af890b803c8" +checksum = "95a0481286a310808298130d22dd1fef0fa571e05a8f44ec801801e84b216b1f" dependencies = [ "bitflags 2.4.2", "cfg-if", @@ -1919,7 +1915,7 @@ checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.48", + "syn 2.0.52", ] [[package]] @@ -1930,9 +1926,9 @@ checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" [[package]] name = "openssl-sys" -version = "0.9.99" +version = "0.9.101" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "22e1bf214306098e4832460f797824c05d25aacdf896f64a985fb0fd992454ae" +checksum = "dda2b0f344e78efc2facf7d195d098df0dd72151b26ab98da807afc26c198dff" dependencies = [ "cc", "libc", @@ -2239,27 +2235,27 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e1d3afd2628e69da2be385eb6f2fd57c8ac7977ceeff6dc166ff1657b0e386a9" dependencies = [ "fixedbitset", - "indexmap 2.1.0", + "indexmap 2.2.5", ] [[package]] name = "pin-project" -version = "1.1.3" +version = "1.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fda4ed1c6c173e3fc7a83629421152e01d7b1f9b7f65fb301e490e8cfc656422" +checksum = "0302c4a0442c456bd56f841aee5c3bfd17967563f6fadc9ceb9f9c23cf3807e0" dependencies = [ "pin-project-internal", ] [[package]] name = "pin-project-internal" -version = "1.1.3" +version = "1.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4359fd9c9171ec6e8c62926d6faaf553a8dc3f64e1507e76da7911b4f6a04405" +checksum = "266c042b60c9c76b8d53061e52b2e0d1116abc57cefc8c5cd671619a56ac3690" dependencies = [ "proc-macro2", "quote", - "syn 2.0.48", + "syn 2.0.52", ] [[package]] @@ -2286,9 +2282,9 @@ dependencies = [ [[package]] name = "pkg-config" -version = "0.3.29" +version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2900ede94e305130c13ddd391e0ab7cbaeb783945ae07a279c268cb05109c6cb" +checksum = "d231b230927b5e4ad203db57bbcbee2802f6bce620b1e4a9024a07d94e2907ec" [[package]] name = "powerfmt" @@ -2428,11 +2424,11 @@ dependencies = [ [[package]] name = "pulldown-cmark" -version = "0.9.3" +version = "0.9.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77a1a2f1f0a7ecff9c31abbe177637be0e97a0aef46cf8738ece09327985d998" +checksum = "57206b407293d2bcd3af849ce869d52068623f19e1b5ff8e8778e3309439682b" dependencies = [ - "bitflags 1.3.2", + "bitflags 2.4.2", "memchr", "unicase", ] @@ -2493,9 +2489,9 @@ dependencies = [ [[package]] name = "rayon" -version = "1.8.1" +version = "1.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa7237101a77a10773db45d62004a272517633fbcc3df19d96455ede1122e051" +checksum = "e4963ed1bc86e4f3ee217022bd855b297cef07fb9eac5dfa1f788b220b49b3bd" dependencies = [ "either", "rayon-core", @@ -2545,9 +2541,9 @@ dependencies = [ [[package]] name = "regex-automata" -version = "0.4.4" +version = "0.4.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b7fa1134405e2ec9353fd416b17f8dacd46c473d7d3fd1cf202706a14eb792a" +checksum = "5bb987efffd3c6d0d8f5f89510bb458559eab11e4f869acb20bf845e016259cd" dependencies = [ "aho-corasick", "memchr", @@ -2562,9 +2558,9 @@ checksum = "c08c74e62047bb2de4ff487b251e4a92e24f48745648451635cec7d591162d9f" [[package]] name = "reqwest" -version = "0.11.23" +version = "0.11.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "37b1ae8d9ac08420c66222fb9096fc5de435c3c48542bc5336c51892cffafb41" +checksum = "c6920094eb85afde5e4a138be3f2de8bbdf28000f0029e72c45025a56b042251" dependencies = [ "base64 0.21.7", "bytes", @@ -2584,9 +2580,11 @@ dependencies = [ "once_cell", "percent-encoding", "pin-project-lite", + "rustls-pemfile", "serde", "serde_json", "serde_urlencoded", + "sync_wrapper", "system-configuration", "tokio", "tokio-native-tls", @@ -2616,9 +2614,9 @@ checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76" [[package]] name = "rustix" -version = "0.38.30" +version = "0.38.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "322394588aaf33c24007e8bb3238ee3e4c5c09c084ab32bc73890b99ff326bca" +checksum = "6ea3e1a662af26cd7a3ba09c0297a31af215563ecf42817c98df621387f4e949" dependencies = [ "bitflags 2.4.2", "errno", @@ -2627,6 +2625,15 @@ dependencies = [ "windows-sys 0.52.0", ] +[[package]] +name = "rustls-pemfile" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1c74cae0a4cf6ccbbf5f359f08efdf8ee7e1dc532573bf0db71968cb56b1448c" +dependencies = [ + "base64 0.21.7", +] + [[package]] name = "rustversion" version = "1.0.14" @@ -2647,9 +2654,9 @@ dependencies = [ [[package]] name = "ryu" -version = "1.0.16" +version = "1.0.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f98d2aa92eebf49b69786be48e4477826b256916e84a57ff2a4f21923b48eb4c" +checksum = "e86697c916019a8588c99b5fac3cead74ec0b4b819707a682fd4d23fa0ce1ba1" [[package]] name = "same-file" @@ -2732,40 +2739,40 @@ dependencies = [ [[package]] name = "semver" -version = "1.0.21" +version = "1.0.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b97ed7a9823b74f99c7742f5336af7be5ecd3eeafcb1507d1fa93347b1d589b0" +checksum = "92d43fe69e652f3df9bdc2b85b2854a0825b86e4fb76bc44d945137d053639ca" dependencies = [ "serde", ] [[package]] name = "serde" -version = "1.0.195" +version = "1.0.197" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "63261df402c67811e9ac6def069e4786148c4563f4b50fd4bf30aa370d626b02" +checksum = "3fb1c873e1b9b056a4dc4c0c198b24c3ffa059243875552b2bd0933b1aee4ce2" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.195" +version = "1.0.197" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "46fe8f8603d81ba86327b23a2e9cdf49e1255fb94a4c5f297f6ee0547178ea2c" +checksum = "7eb0b34b42edc17f6b7cac84a52a1c5f0e1bb2227e997ca9011ea3dd34e8610b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.48", + "syn 2.0.52", ] [[package]] name = "serde_json" -version = "1.0.111" +version = "1.0.114" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "176e46fa42316f18edd598015a5166857fc835ec732f5215eac6b7bdbf0a84f4" +checksum = "c5f09b1bd632ef549eaa9f60a1f8de742bdbc698e6cee2095fc84dde5f549ae0" dependencies = [ - "indexmap 2.1.0", + "indexmap 2.2.5", "itoa", "ryu", "serde", @@ -2779,7 +2786,7 @@ checksum = "0b2e6b945e9d3df726b65d6ee24060aff8e3533d431f677a9695db04eff9dfdb" dependencies = [ "proc-macro2", "quote", - "syn 2.0.48", + "syn 2.0.52", ] [[package]] @@ -2904,12 +2911,12 @@ checksum = "b7c388c1b5e93756d0c740965c41e8822f866621d41acbdf6336a6a168f8840c" [[package]] name = "socket2" -version = "0.5.5" +version = "0.5.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b5fac59a5cb5dd637972e5fca70daf0523c9067fcdc4842f053dae04a18f8e9" +checksum = "05ffd9c0a93b7543e062e759284fcf5f5e3b098501104bfbdde4d404db792871" dependencies = [ "libc", - "windows-sys 0.48.0", + "windows-sys 0.52.0", ] [[package]] @@ -2946,9 +2953,9 @@ dependencies = [ [[package]] name = "strsim" -version = "0.10.0" +version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" +checksum = "5ee073c9e4cd00e28217186dbe12796d692868f432bf2e97ee73bed0c56dfa01" [[package]] name = "strum" @@ -3026,9 +3033,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.48" +version = "2.0.52" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0f3531638e407dfc0814761abb7c00a5b54992b849452a0646b7f65c9f770f3f" +checksum = "b699d15b36d1f02c3e7c69f8ffef53de37aefae075d8488d4ba1a7788d574a07" dependencies = [ "proc-macro2", "quote", @@ -3064,13 +3071,12 @@ dependencies = [ [[package]] name = "tempfile" -version = "3.9.0" +version = "3.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "01ce4141aa927a6d1bd34a041795abd0db1cccba5d5f24b009f694bdf3a1f3fa" +checksum = "85b77fafb263dd9d05cbeac119526425676db3784113aa9295c88498cbf8bff1" dependencies = [ "cfg-if", "fastrand", - "redox_syscall", "rustix", "windows-sys 0.52.0", ] @@ -3108,22 +3114,22 @@ dependencies = [ [[package]] name = "thiserror" -version = "1.0.56" +version = "1.0.57" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d54378c645627613241d077a3a79db965db602882668f9136ac42af9ecb730ad" +checksum = "1e45bcbe8ed29775f228095caf2cd67af7a4ccf756ebff23a306bf3e8b47b24b" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.56" +version = "1.0.57" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa0faa943b50f3db30a20aa7e265dbc66076993efed8463e8de414e5d06d3471" +checksum = "a953cb265bef375dae3de6663da4d3804eee9682ea80d8e2542529b73c531c81" dependencies = [ "proc-macro2", "quote", - "syn 2.0.48", + "syn 2.0.52", ] [[package]] @@ -3137,11 +3143,12 @@ dependencies = [ [[package]] name = "time" -version = "0.3.31" +version = "0.3.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f657ba42c3f86e7680e53c8cd3af8abbe56b5491790b46e22e19c0d57463583e" +checksum = "c8248b6521bb14bc45b4067159b9b6ad792e2d6d754d6c41fb50e29fefe38749" dependencies = [ "deranged", + "num-conv", "powerfmt", "serde", "time-core", @@ -3170,9 +3177,9 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] name = "tokio" -version = "1.35.1" +version = "1.36.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c89b4efa943be685f629b149f53829423f8f5531ea21249408e8e2f8671ec104" +checksum = "61285f6515fa018fb2d1e46eb21223fff441ee8db5d0f1435e8ab4f5cdb80931" dependencies = [ "backtrace", "bytes", @@ -3205,7 +3212,7 @@ checksum = "5b8a1e28f2deaa14e508979454cb3a223b10b938b45af148bc0986de36f1923b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.48", + "syn 2.0.52", ] [[package]] @@ -3270,7 +3277,7 @@ version = "0.19.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1b5bb770da30e5cbfde35a2d7b9b8a2c4b8ef89548a7a6aeab5c9a576e3e7421" dependencies = [ - "indexmap 2.1.0", + "indexmap 2.2.5", "serde", "serde_spanned", "toml_datetime", @@ -3356,7 +3363,7 @@ checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.48", + "syn 2.0.52", ] [[package]] @@ -3421,18 +3428,18 @@ checksum = "3b09c83c3c29d37506a3e260c08c03743a6bb66a9cd432c6934ab501a190571f" [[package]] name = "unicode-normalization" -version = "0.1.22" +version = "0.1.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c5713f0fc4b5db668a2ac63cdb7bb4469d8c9fed047b1d0292cc7b0ce2ba921" +checksum = "a56d1686db2308d901306f92a263857ef59ea39678a5458e7cb17f01415101f5" dependencies = [ "tinyvec", ] [[package]] name = "unicode-segmentation" -version = "1.10.1" +version = "1.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1dd624098567895118886609431a7c3b8f516e41d30e0643f03d94592a147e36" +checksum = "d4c87d22b6e3f4a18d4d40ef354e97c90fcb14dd91d7dc0aa9d8a1172ebf7202" [[package]] name = "unicode-width" @@ -3607,9 +3614,9 @@ checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" [[package]] name = "wasm-bindgen" -version = "0.2.90" +version = "0.2.91" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1223296a201415c7fad14792dbefaace9bd52b62d33453ade1c5b5f07555406" +checksum = "c1e124130aee3fb58c5bdd6b639a0509486b0338acaaae0c84a5124b0f588b7f" dependencies = [ "cfg-if", "wasm-bindgen-macro", @@ -3617,24 +3624,24 @@ dependencies = [ [[package]] name = "wasm-bindgen-backend" -version = "0.2.90" +version = "0.2.91" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fcdc935b63408d58a32f8cc9738a0bffd8f05cc7c002086c6ef20b7312ad9dcd" +checksum = "c9e7e1900c352b609c8488ad12639a311045f40a35491fb69ba8c12f758af70b" dependencies = [ "bumpalo", "log", "once_cell", "proc-macro2", "quote", - "syn 2.0.48", + "syn 2.0.52", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-futures" -version = "0.4.40" +version = "0.4.41" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bde2032aeb86bdfaecc8b261eef3cba735cc426c1f3a3416d1e0791be95fc461" +checksum = "877b9c3f61ceea0e56331985743b13f3d25c406a7098d45180fb5f09bc19ed97" dependencies = [ "cfg-if", "js-sys", @@ -3644,9 +3651,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro" -version = "0.2.90" +version = "0.2.91" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3e4c238561b2d428924c49815533a8b9121c664599558a5d9ec51f8a1740a999" +checksum = "b30af9e2d358182b5c7449424f017eba305ed32a7010509ede96cdc4696c46ed" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -3654,28 +3661,28 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.90" +version = "0.2.91" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bae1abb6806dc1ad9e560ed242107c0f6c84335f1749dd4e8ddb012ebd5e25a7" +checksum = "642f325be6301eb8107a83d12a8ac6c1e1c54345a7ef1a9261962dfefda09e66" dependencies = [ "proc-macro2", "quote", - "syn 2.0.48", + "syn 2.0.52", "wasm-bindgen-backend", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-shared" -version = "0.2.90" +version = "0.2.91" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4d91413b1c31d7539ba5ef2451af3f0b833a005eb27a631cec32bc0635a8602b" +checksum = "4f186bd2dcf04330886ce82d6f33dd75a7bfcf69ecf5763b89fcde53b6ac9838" [[package]] name = "web-sys" -version = "0.3.67" +version = "0.3.68" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "58cd2333b6e0be7a39605f0e255892fd7418a682d8da8fe042fe25128794d2ed" +checksum = "96565907687f7aceb35bc5fc03770a8a0471d82e479f25832f54a0e3f4b28446" dependencies = [ "js-sys", "wasm-bindgen", @@ -3739,7 +3746,7 @@ version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" dependencies = [ - "windows-targets 0.52.0", + "windows-targets 0.52.4", ] [[package]] @@ -3759,17 +3766,17 @@ dependencies = [ [[package]] name = "windows-targets" -version = "0.52.0" +version = "0.52.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a18201040b24831fbb9e4eb208f8892e1f50a37feb53cc7ff887feb8f50e7cd" +checksum = "7dd37b7e5ab9018759f893a1952c9420d060016fc19a472b4bb20d1bdd694d1b" dependencies = [ - "windows_aarch64_gnullvm 0.52.0", - "windows_aarch64_msvc 0.52.0", - "windows_i686_gnu 0.52.0", - "windows_i686_msvc 0.52.0", - "windows_x86_64_gnu 0.52.0", - "windows_x86_64_gnullvm 0.52.0", - "windows_x86_64_msvc 0.52.0", + "windows_aarch64_gnullvm 0.52.4", + "windows_aarch64_msvc 0.52.4", + "windows_i686_gnu 0.52.4", + "windows_i686_msvc 0.52.4", + "windows_x86_64_gnu 0.52.4", + "windows_x86_64_gnullvm 0.52.4", + "windows_x86_64_msvc 0.52.4", ] [[package]] @@ -3780,9 +3787,9 @@ checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" [[package]] name = "windows_aarch64_gnullvm" -version = "0.52.0" +version = "0.52.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cb7764e35d4db8a7921e09562a0304bf2f93e0a51bfccee0bd0bb0b666b015ea" +checksum = "bcf46cf4c365c6f2d1cc93ce535f2c8b244591df96ceee75d8e83deb70a9cac9" [[package]] name = "windows_aarch64_msvc" @@ -3792,9 +3799,9 @@ checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" [[package]] name = "windows_aarch64_msvc" -version = "0.52.0" +version = "0.52.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bbaa0368d4f1d2aaefc55b6fcfee13f41544ddf36801e793edbbfd7d7df075ef" +checksum = "da9f259dd3bcf6990b55bffd094c4f7235817ba4ceebde8e6d11cd0c5633b675" [[package]] name = "windows_i686_gnu" @@ -3804,9 +3811,9 @@ checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" [[package]] name = "windows_i686_gnu" -version = "0.52.0" +version = "0.52.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a28637cb1fa3560a16915793afb20081aba2c92ee8af57b4d5f28e4b3e7df313" +checksum = "b474d8268f99e0995f25b9f095bc7434632601028cf86590aea5c8a5cb7801d3" [[package]] name = "windows_i686_msvc" @@ -3816,9 +3823,9 @@ checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" [[package]] name = "windows_i686_msvc" -version = "0.52.0" +version = "0.52.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ffe5e8e31046ce6230cc7215707b816e339ff4d4d67c65dffa206fd0f7aa7b9a" +checksum = "1515e9a29e5bed743cb4415a9ecf5dfca648ce85ee42e15873c3cd8610ff8e02" [[package]] name = "windows_x86_64_gnu" @@ -3828,9 +3835,9 @@ checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" [[package]] name = "windows_x86_64_gnu" -version = "0.52.0" +version = "0.52.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d6fa32db2bc4a2f5abeacf2b69f7992cd09dca97498da74a151a3132c26befd" +checksum = "5eee091590e89cc02ad514ffe3ead9eb6b660aedca2183455434b93546371a03" [[package]] name = "windows_x86_64_gnullvm" @@ -3840,9 +3847,9 @@ checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" [[package]] name = "windows_x86_64_gnullvm" -version = "0.52.0" +version = "0.52.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a657e1e9d3f514745a572a6846d3c7aa7dbe1658c056ed9c3344c4109a6949e" +checksum = "77ca79f2451b49fa9e2af39f0747fe999fcda4f5e241b2898624dca97a1f2177" [[package]] name = "windows_x86_64_msvc" @@ -3852,15 +3859,15 @@ checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" [[package]] name = "windows_x86_64_msvc" -version = "0.52.0" +version = "0.52.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dff9641d1cd4be8d1a070daf9e3773c5f67e78b4d9d42263020c057706765c04" +checksum = "32b752e52a2da0ddfbdbcc6fceadfeede4c939ed16d13e648833a61dfb611ed8" [[package]] name = "winnow" -version = "0.5.34" +version = "0.5.40" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b7cf47b659b318dccbd69cc4797a39ae128f533dce7902a1096044d1967b9c16" +checksum = "f593a95398737aeed53e489c785df13f3618e41dbcd6718c6addbf1395aa6876" dependencies = [ "memchr", ] @@ -3907,7 +3914,7 @@ checksum = "9ce1b18ccd8e73a9321186f97e46f9f04b778851177567b1975109d26a08d2a6" dependencies = [ "proc-macro2", "quote", - "syn 2.0.48", + "syn 2.0.52", ] [[package]] @@ -3927,7 +3934,7 @@ checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69" dependencies = [ "proc-macro2", "quote", - "syn 2.0.48", + "syn 2.0.52", ] [[package]] diff --git a/crates/aiken-lang/src/ast.rs b/crates/aiken-lang/src/ast.rs index 68af1566..faf7ff98 100644 --- a/crates/aiken-lang/src/ast.rs +++ b/crates/aiken-lang/src/ast.rs @@ -183,7 +183,11 @@ pub type UntypedTypeAlias = TypeAlias<()>; impl TypedTest { pub fn test_hint(&self) -> Option<(BinOp, Box, Box)> { - do_test_hint(&self.body) + if self.arguments.is_empty() { + do_test_hint(&self.body) + } else { + None + } } } @@ -367,17 +371,11 @@ pub struct Validator { pub params: Vec>, } -#[derive(Debug, Clone, PartialEq)] -pub struct DefinitionIdentifier { - pub module: Option, - pub name: String, -} - -pub type TypedDefinition = Definition, TypedExpr, String, ()>; -pub type UntypedDefinition = Definition<(), UntypedExpr, (), DefinitionIdentifier>; +pub type TypedDefinition = Definition, TypedExpr, String>; +pub type UntypedDefinition = Definition<(), UntypedExpr, ()>; #[derive(Debug, Clone, PartialEq)] -pub enum Definition { +pub enum Definition { Fn(Function>), TypeAlias(TypeAlias), @@ -388,12 +386,12 @@ pub enum Definition { ModuleConstant(ModuleConstant), - Test(Function>), + Test(Function>), Validator(Validator), } -impl Definition { +impl Definition { pub fn location(&self) -> Span { match self { Definition::Fn(Function { location, .. }) @@ -643,14 +641,14 @@ impl Arg { } } -pub type TypedArgVia = ArgVia, ()>; -pub type UntypedArgVia = ArgVia<(), DefinitionIdentifier>; +pub type TypedArgVia = ArgVia, TypedExpr>; +pub type UntypedArgVia = ArgVia<(), UntypedExpr>; #[derive(Debug, Clone, PartialEq)] -pub struct ArgVia { +pub struct ArgVia { pub arg_name: ArgName, pub location: Span, - pub via: Ann, + pub via: Expr, pub tipo: T, } @@ -666,17 +664,6 @@ impl From> for Arg { } } -impl From for TypedArgVia { - fn from(arg: TypedArg) -> TypedArgVia { - ArgVia { - arg_name: arg.arg_name, - tipo: arg.tipo, - location: arg.location, - via: (), - } - } -} - #[derive(Debug, Clone, PartialEq, Eq)] pub enum ArgName { Discarded { diff --git a/crates/aiken-lang/src/format.rs b/crates/aiken-lang/src/format.rs index 9d3045fb..25caf3ec 100644 --- a/crates/aiken-lang/src/format.rs +++ b/crates/aiken-lang/src/format.rs @@ -1,12 +1,12 @@ use crate::{ ast::{ Annotation, Arg, ArgName, ArgVia, AssignmentKind, BinOp, ByteArrayFormatPreference, - CallArg, ClauseGuard, Constant, CurveType, DataType, Definition, DefinitionIdentifier, - Function, IfBranch, LogicalOpChainKind, ModuleConstant, Pattern, RecordConstructor, - RecordConstructorArg, RecordUpdateSpread, Span, TraceKind, TypeAlias, TypedArg, UnOp, - UnqualifiedImport, UntypedArg, UntypedArgVia, UntypedClause, UntypedClauseGuard, - UntypedDefinition, UntypedFunction, UntypedModule, UntypedPattern, UntypedRecordUpdateArg, - Use, Validator, CAPTURE_VARIABLE, + CallArg, ClauseGuard, Constant, CurveType, DataType, Definition, Function, IfBranch, + LogicalOpChainKind, ModuleConstant, Pattern, RecordConstructor, RecordConstructorArg, + RecordUpdateSpread, Span, TraceKind, TypeAlias, TypedArg, UnOp, UnqualifiedImport, + UntypedArg, UntypedArgVia, UntypedClause, UntypedClauseGuard, UntypedDefinition, + UntypedFunction, UntypedModule, UntypedPattern, UntypedRecordUpdateArg, Use, Validator, + CAPTURE_VARIABLE, }, docvec, expr::{FnStyle, UntypedExpr, DEFAULT_ERROR_STR, DEFAULT_TODO_STR}, @@ -471,19 +471,17 @@ impl<'comments> Formatter<'comments> { commented(doc, comments) } - fn fn_arg_via<'a, A>(&mut self, arg: &'a ArgVia) -> Document<'a> { + fn fn_arg_via<'a, A>(&mut self, arg: &'a ArgVia) -> Document<'a> { let comments = self.pop_comments(arg.location.start); let doc_comments = self.doc_comments(arg.location.start); - let doc = arg.arg_name.to_doc().append(" via "); - - let doc = match arg.via.module { - Some(ref module) => doc.append(module.to_doc()).append("."), - None => doc, - } - .append(arg.via.name.to_doc()) - .group(); + let doc = arg + .arg_name + .to_doc() + .append(" via ") + .append(self.expr(&arg.via, false)) + .group(); let doc = doc_comments.append(doc.group()).group(); diff --git a/crates/aiken-lang/src/gen_uplc.rs b/crates/aiken-lang/src/gen_uplc.rs index 86fbeaeb..63907f47 100644 --- a/crates/aiken-lang/src/gen_uplc.rs +++ b/crates/aiken-lang/src/gen_uplc.rs @@ -198,7 +198,7 @@ impl<'a> CodeGenerator<'a> { self.finalize(term) } - pub fn generate_test(&mut self, test_body: &TypedExpr, module_name: &String) -> Program { + pub fn generate_raw(&mut self, test_body: &TypedExpr, module_name: &String) -> Program { let mut air_tree = self.build(test_body, module_name, &[]); air_tree = AirTree::no_op(air_tree); diff --git a/crates/aiken-lang/src/parser/definition/test.rs b/crates/aiken-lang/src/parser/definition/test.rs index 33d48628..748c187e 100644 --- a/crates/aiken-lang/src/parser/definition/test.rs +++ b/crates/aiken-lang/src/parser/definition/test.rs @@ -3,7 +3,12 @@ use chumsky::prelude::*; use crate::{ ast, expr::UntypedExpr, - parser::{error::ParseError, expr, token::Token}, + parser::{ + chain::{call::parser as call, field_access, tuple_index::parser as tuple_index, Chain}, + error::ParseError, + expr::{self, var}, + token::Token, + }, }; pub fn parser() -> impl Parser { @@ -63,20 +68,33 @@ pub fn via() -> impl Parser { }), )) .then_ignore(just(Token::Via)) - .then( - select! { Token::Name { name } => name } - .then_ignore(just(Token::Dot)) - .or_not(), - ) - .then(select! { Token::Name { name } => name }) - .map_with_span(|((arg_name, module), name), location| ast::ArgVia { + .then(fuzzer()) + .map_with_span(|(arg_name, via), location| ast::ArgVia { arg_name, - via: ast::DefinitionIdentifier { module, name }, + via, tipo: (), location, }) } +pub fn fuzzer<'a>() -> impl Parser + 'a { + recursive(|expression| { + let chain = choice(( + tuple_index(), + field_access::parser(), + call(expression.clone()), + )); + + var() + .then(chain.repeated()) + .foldl(|expr, chain| match chain { + Chain::Call(args, span) => expr.call(args, span), + Chain::FieldAccess(label, span) => expr.field_access(label, span), + Chain::TupleIndex(index, span) => expr.tuple_index(index, span), + }) + }) +} + #[cfg(test)] mod tests { use crate::assert_definition; diff --git a/crates/aiken-lang/src/tipo/infer.rs b/crates/aiken-lang/src/tipo/infer.rs index 106a9aa3..6f76709d 100644 --- a/crates/aiken-lang/src/tipo/infer.rs +++ b/crates/aiken-lang/src/tipo/infer.rs @@ -2,7 +2,7 @@ use std::collections::HashMap; use crate::{ ast::{ - Annotation, Arg, ArgName, DataType, Definition, Function, Layer, ModuleConstant, + Annotation, Arg, ArgName, ArgVia, DataType, Definition, Function, Layer, ModuleConstant, ModuleKind, RecordConstructor, RecordConstructorArg, Tracing, TypeAlias, TypedArg, TypedDefinition, TypedFunction, TypedModule, UntypedArg, UntypedDefinition, UntypedModule, Use, Validator, @@ -383,7 +383,7 @@ fn infer_definition( } } - let annotation = match f.arguments.first() { + let (typed_via, annotation) = match f.arguments.first() { Some(arg) => { if f.arguments.len() > 1 { return Err(Error::IncorrectTestArity { @@ -392,12 +392,17 @@ fn infer_definition( }); } - let ValueConstructor { tipo, .. } = ExprTyper::new(environment, lines, tracing) - .infer_value_constructor(&arg.via.module, &arg.via.name, &arg.location)?; + let typed_via = + ExprTyper::new(environment, lines, tracing).infer(arg.via.clone())?; - Ok(Some(annotate_fuzzer(&tipo, &arg.location)?)) + let tipo = typed_via.tipo(); + + Ok(( + Some(typed_via), + Some(annotate_fuzzer(&tipo, &arg.location)?), + )) } - None => Ok(None), + None => Ok((None, None)), }?; let typed_f = infer_function( @@ -439,13 +444,25 @@ fn infer_definition( location: typed_f.location, name: typed_f.name, public: typed_f.public, - arguments: match annotation { - Some(_) => vec![typed_f - .arguments - .first() - .expect("has exactly one argument") - .to_owned() - .into()], + arguments: match typed_via { + Some(via) => { + let Arg { + arg_name, + location, + tipo, + .. + } = typed_f + .arguments + .first() + .expect("has exactly one argument") + .to_owned(); + vec![ArgVia { + arg_name, + location, + tipo, + via, + }] + } None => vec![], }, return_annotation: typed_f.return_annotation, diff --git a/crates/aiken-project/Cargo.toml b/crates/aiken-project/Cargo.toml index ca52a5d1..9ada572f 100644 --- a/crates/aiken-project/Cargo.toml +++ b/crates/aiken-project/Cargo.toml @@ -43,6 +43,7 @@ zip = "0.6.4" aiken-lang = { path = "../aiken-lang", version = "1.0.24-alpha" } uplc = { path = '../uplc', version = "1.0.24-alpha" } +num-bigint = "0.4.4" [dev-dependencies] blst = "0.3.11" diff --git a/crates/aiken-project/src/lib.rs b/crates/aiken-project/src/lib.rs index e1112b46..d7199e6c 100644 --- a/crates/aiken-project/src/lib.rs +++ b/crates/aiken-project/src/lib.rs @@ -22,10 +22,13 @@ use crate::blueprint::{ Blueprint, }; use aiken_lang::{ - ast::{Definition, Function, ModuleKind, Tracing, TypedDataType, TypedFunction, Validator}, + ast::{ + Definition, Function, ModuleKind, Span, Tracing, TypedDataType, TypedFunction, Validator, + }, builtins, - gen_uplc::builder::{DataTypeKey, FunctionAccessKey}, - tipo::TypeInfo, + expr::TypedExpr, + gen_uplc::builder::{cast_validator_args, DataTypeKey, FunctionAccessKey}, + tipo::{Type, TypeInfo}, IdGenerator, }; use indexmap::IndexMap; @@ -38,16 +41,17 @@ use pallas::ledger::{ traverse::ComputeHash, }; -use script::{EvalHint, EvalInfo, Script}; +use script::{EvalHint, EvalInfo, PropertyTest, Test}; use std::{ collections::HashMap, fs::{self, File}, io::BufReader, path::{Path, PathBuf}, + rc::Rc, }; use telemetry::EventListener; use uplc::{ - ast::{DeBruijn, Name, Program, Term}, + ast::{DeBruijn, Name, NamedDeBruijn, Program, Term}, machine::cost_model::ExBudget, PlutusData, }; @@ -319,7 +323,7 @@ where self.event_listener.handle_event(Event::RunningTests); } - let results = self.eval_scripts(tests); + let results = self.run_tests(tests.iter().collect()); let errors: Vec = results .iter() @@ -328,14 +332,13 @@ where None } else { Some(Error::TestFailure { - name: e.script.name.clone(), - path: e.script.input_path.clone(), + name: e.test.name().to_string(), + path: e.test.input_path().to_path_buf(), evaluation_hint: e - .script - .evaluation_hint - .as_ref() + .test + .evaluation_hint() .map(|hint| hint.to_string()), - src: e.script.program.to_pretty(), + src: e.test.program().to_pretty(), verbose, }) } @@ -684,7 +687,7 @@ where match_tests: Option>, exact_match: bool, tracing: Tracing, - ) -> Result, Error> { + ) -> Result, Error> { let mut scripts = Vec::new(); let mut testable_validators = Vec::new(); @@ -802,6 +805,7 @@ where name, body, can_error, + arguments, .. } = func_def; @@ -815,13 +819,13 @@ where let evaluation_hint = func_def.test_hint().map(|(bin_op, left_src, right_src)| { let left = generator .clone() - .generate_test(&left_src, &module_name) + .generate_raw(&left_src, &module_name) .try_into() .unwrap(); let right = generator .clone() - .generate_test(&right_src, &module_name) + .generate_raw(&right_src, &module_name) .try_into() .unwrap(); @@ -833,44 +837,91 @@ where } }); - let program = generator.generate_test(body, &module_name); + if arguments.is_empty() { + let program = generator.generate_raw(body, &module_name); - let script = Script::new( - input_path, - module_name, - name.to_string(), - *can_error, - program.try_into().unwrap(), - evaluation_hint, - ); + let test = Test::unit_test( + input_path, + module_name, + name.to_string(), + *can_error, + program.try_into().unwrap(), + evaluation_hint, + ); - programs.push(script); + programs.push(test); + } else { + let parameter = arguments.first().unwrap().to_owned(); + + let via = parameter.via.clone(); + + let body = TypedExpr::Fn { + location: Span::empty(), + tipo: Rc::new(Type::Fn { + args: vec![parameter.tipo.clone()], + ret: body.tipo(), + }), + is_capture: false, + args: vec![parameter.clone().into()], + body: Box::new(body.clone()), + return_annotation: None, + }; + + let program = generator.clone().generate_raw(&body, &module_name); + + let term = cast_validator_args(program.term, &[parameter.into()]); + + let fuzzer: Program = generator + .clone() + .generate_raw(&via, &module_name) + .try_into() + .expect("TODO: provide a better error when one is trying to instantiate something that isn't a fuzzer as one"); + + let prop = Test::property_test( + input_path, + module_name, + name.to_string(), + *can_error, + Program { term, ..program }.try_into().unwrap(), + fuzzer, + ); + + programs.push(prop); + } } Ok(programs) } - fn eval_scripts(&self, scripts: Vec