diff --git a/CHANGELOG.md b/CHANGELOG.md index e8507849..85540b5e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,16 @@ # Changelog +## v1.0.11-alpha - unreleased + +### Added + +- **aiken-lang**: Binary operator are now treated like first-class citizen in + expressions. In particular, they can be used as function arguments directly: + + ``` + compare_with(a, >=, b) == compare_with(a, fn(l, r) { l >= r }, b) + ``` + ## v1.0.10-alpha - 2023-06-13 ### Added diff --git a/crates/aiken-lang/src/ast.rs b/crates/aiken-lang/src/ast.rs index 1f1374fc..1568f425 100644 --- a/crates/aiken-lang/src/ast.rs +++ b/crates/aiken-lang/src/ast.rs @@ -647,6 +647,24 @@ impl Annotation { } } + pub fn boolean(location: Span) -> Self { + Annotation::Constructor { + name: "Bool".to_string(), + module: None, + arguments: vec![], + location, + } + } + + pub fn int(location: Span) -> Self { + Annotation::Constructor { + name: "Int".to_string(), + module: None, + arguments: vec![], + location, + } + } + pub fn is_logically_equal(&self, other: &Annotation) -> bool { match self { Annotation::Constructor { diff --git a/crates/aiken-lang/src/expr.rs b/crates/aiken-lang/src/expr.rs index d669f171..32c14c29 100644 --- a/crates/aiken-lang/src/expr.rs +++ b/crates/aiken-lang/src/expr.rs @@ -399,6 +399,14 @@ impl TypedExpr { } } +// Represent how a function was written so that we can format it back. +#[derive(Debug, Clone, PartialEq, Copy)] +pub enum FnStyle { + Plain, + Capture, + BinOp(BinOp), +} + #[derive(Debug, Clone, PartialEq)] pub enum UntypedExpr { Int { @@ -424,7 +432,7 @@ pub enum UntypedExpr { Fn { location: Span, - is_capture: bool, + fn_style: FnStyle, arguments: Vec>, body: Box, return_annotation: Option, diff --git a/crates/aiken-lang/src/format.rs b/crates/aiken-lang/src/format.rs index 7bd755aa..e345875c 100644 --- a/crates/aiken-lang/src/format.rs +++ b/crates/aiken-lang/src/format.rs @@ -8,7 +8,7 @@ use crate::{ Use, Validator, CAPTURE_VARIABLE, }, docvec, - expr::{UntypedExpr, DEFAULT_ERROR_STR, DEFAULT_TODO_STR}, + expr::{FnStyle, UntypedExpr, DEFAULT_ERROR_STR, DEFAULT_TODO_STR}, parser::{ extra::{Comment, ModuleExtra}, token::Base, @@ -768,12 +768,18 @@ impl<'comments> Formatter<'comments> { UntypedExpr::UnOp { value, op, .. } => self.un_op(value, op), UntypedExpr::Fn { - is_capture: true, + fn_style: FnStyle::Capture, body, .. } => self.fn_capture(body), UntypedExpr::Fn { + fn_style: FnStyle::BinOp(op), + .. + } => op.to_doc(), + + UntypedExpr::Fn { + fn_style: FnStyle::Plain, return_annotation, arguments: args, body, @@ -1061,7 +1067,9 @@ impl<'comments> Formatter<'comments> { let right = self.expr(right); self.operator_side(left, precedence, left_precedence) + .append(" ") .append(name) + .append(" ") .append(self.operator_side(right, precedence, right_precedence - 1)) } @@ -1093,7 +1101,7 @@ impl<'comments> Formatter<'comments> { let comments = self.pop_comments(expr.location().start); let doc = match expr { UntypedExpr::Fn { - is_capture: true, + fn_style: FnStyle::Capture, body, .. } => self.pipe_capture_right_hand_side(body), @@ -1717,19 +1725,19 @@ impl<'a> Documentable<'a> for &'a UnqualifiedImport { impl<'a> Documentable<'a> for &'a BinOp { fn to_doc(self) -> Document<'a> { match self { - BinOp::And => " && ", - BinOp::Or => " || ", - BinOp::LtInt => " < ", - BinOp::LtEqInt => " <= ", - BinOp::Eq => " == ", - BinOp::NotEq => " != ", - BinOp::GtEqInt => " >= ", - BinOp::GtInt => " > ", - BinOp::AddInt => " + ", - BinOp::SubInt => " - ", - BinOp::MultInt => " * ", - BinOp::DivInt => " / ", - BinOp::ModInt => " % ", + BinOp::And => "&&", + BinOp::Or => "||", + BinOp::LtInt => "<", + BinOp::LtEqInt => "<=", + BinOp::Eq => "==", + BinOp::NotEq => "!=", + BinOp::GtEqInt => ">=", + BinOp::GtInt => ">", + BinOp::AddInt => "+", + BinOp::SubInt => "-", + BinOp::MultInt => "*", + BinOp::DivInt => "/", + BinOp::ModInt => "%", } .to_doc() } diff --git a/crates/aiken-lang/src/parser.rs b/crates/aiken-lang/src/parser.rs index b24a738c..581cf435 100644 --- a/crates/aiken-lang/src/parser.rs +++ b/crates/aiken-lang/src/parser.rs @@ -935,11 +935,91 @@ pub fn expr_parser( arguments, body: Box::new(body), location: span, - is_capture: false, + fn_style: expr::FnStyle::Plain, return_annotation, }, ); + let anon_binop_parser = select! { + Token::EqualEqual => BinOp::Eq, + Token::NotEqual => BinOp::NotEq, + Token::Less => BinOp::LtInt, + Token::LessEqual => BinOp::LtEqInt, + Token::Greater => BinOp::GtInt, + Token::GreaterEqual => BinOp::GtEqInt, + Token::VbarVbar => BinOp::Or, + Token::AmperAmper => BinOp::And, + Token::Plus => BinOp::AddInt, + Token::Minus => BinOp::SubInt, + Token::Slash => BinOp::DivInt, + Token::Star => BinOp::MultInt, + Token::Percent => BinOp::ModInt, + } + .map_with_span(|name, location| { + use BinOp::*; + + let arg_annotation = match name { + Or | And => Some(ast::Annotation::boolean(location)), + Eq | NotEq => None, + LtInt | LtEqInt | GtInt | GtEqInt | AddInt | SubInt | MultInt | DivInt | ModInt => { + Some(ast::Annotation::int(location)) + } + }; + + let return_annotation = match name { + Or | And | Eq | NotEq | LtInt | LtEqInt | GtInt | GtEqInt => { + Some(ast::Annotation::boolean(location)) + } + AddInt | SubInt | MultInt | DivInt | ModInt => Some(ast::Annotation::int(location)), + }; + + let arguments = vec![ + ast::Arg { + arg_name: ast::ArgName::Named { + name: "left".to_string(), + label: "left".to_string(), + location, + is_validator_param: false, + }, + annotation: arg_annotation.clone(), + location, + tipo: (), + }, + ast::Arg { + arg_name: ast::ArgName::Named { + name: "right".to_string(), + label: "right".to_string(), + location, + is_validator_param: false, + }, + annotation: arg_annotation, + location, + tipo: (), + }, + ]; + + let body = expr::UntypedExpr::BinOp { + location, + name, + left: Box::new(expr::UntypedExpr::Var { + location, + name: "left".to_string(), + }), + right: Box::new(expr::UntypedExpr::Var { + location, + name: "right".to_string(), + }), + }; + + expr::UntypedExpr::Fn { + arguments, + body: Box::new(body), + return_annotation, + fn_style: expr::FnStyle::BinOp(name), + location, + } + }); + let when_clause_parser = pattern_parser() .then( just(Token::Vbar) @@ -1083,6 +1163,7 @@ pub fn expr_parser( bytearray, list_parser, anon_fn_parser, + anon_binop_parser, block_parser, when_parser, let_parser, @@ -1205,7 +1286,7 @@ pub fn expr_parser( } else { expr::UntypedExpr::Fn { location: call.location(), - is_capture: true, + fn_style: expr::FnStyle::Capture, arguments: holes, body: Box::new(call), return_annotation: None, @@ -1239,7 +1320,20 @@ pub fn expr_parser( // Negate let op = choice(( just(Token::Bang).to(UnOp::Not), - just(Token::Minus).to(UnOp::Negate), + just(Token::Minus) + // NOTE: Prevent conflict with usage for '-' as a standalone binary op. + // This will make '-' parse when used as standalone binop in a function call. + // For example: + // + // foo(a, -, b) + // + // but it'll fail in a let-binding: + // + // let foo = - + // + // which seems acceptable. + .then_ignore(just(Token::Comma).not().rewind()) + .to(UnOp::Negate), )); let unary = op diff --git a/crates/aiken-lang/src/tests/format.rs b/crates/aiken-lang/src/tests/format.rs index 9154e290..79ca88d4 100644 --- a/crates/aiken-lang/src/tests/format.rs +++ b/crates/aiken-lang/src/tests/format.rs @@ -864,3 +864,26 @@ fn hex_and_numeric_underscore() { assert_fmt(src, src); } + +#[test] +fn first_class_binop() { + let src = indoc! { r#" + fn foo() { + compare_with(a, >, b) + compare_with(a, >=, b) + compare_with(a, <, b) + compare_with(a, <=, b) + compare_with(a, ==, b) + compare_with(a, !=, b) + combine_with(a, &&, b) + combine_with(a, ||, b) + compute_with(a, +, b) + compute_with(a, -, b) + compute_with(a, /, b) + compute_with(a, *, b) + compute_with(a, %, b) + } + "#}; + + assert_fmt(src, src); +} diff --git a/crates/aiken-lang/src/tests/parser.rs b/crates/aiken-lang/src/tests/parser.rs index 19479451..3e4a0cab 100644 --- a/crates/aiken-lang/src/tests/parser.rs +++ b/crates/aiken-lang/src/tests/parser.rs @@ -1369,7 +1369,7 @@ fn anonymous_function() { location: Span::new((), 25..67), value: Box::new(expr::UntypedExpr::Fn { location: Span::new((), 39..67), - is_capture: false, + fn_style: expr::FnStyle::Plain, arguments: vec![ast::Arg { arg_name: ast::ArgName::Named { label: "a".to_string(), @@ -1547,7 +1547,7 @@ fn call() { location: Span::new((), 37..82), value: Box::new(expr::UntypedExpr::Fn { location: Span::new((), 53..82), - is_capture: true, + fn_style: expr::FnStyle::Capture, arguments: vec![ast::Arg { arg_name: ast::ArgName::Named { label: "_capture__0".to_string(), @@ -1574,7 +1574,7 @@ fn call() { location: Span::new((), 65..81), value: expr::UntypedExpr::Fn { location: Span::new((), 65..81), - is_capture: false, + fn_style: expr::FnStyle::Plain, arguments: vec![ast::Arg { arg_name: ast::ArgName::Named { label: "y".to_string(), @@ -3667,3 +3667,1132 @@ fn int_parsing_numeric_underscore() { })], ) } + +#[test] +fn first_class_binop() { + use ast::{Arg, ArgName::*, BinOp::*, CallArg}; + use expr::UntypedExpr::*; + + let code = indoc! {r#" + fn foo() { + compare_with(a, >, b) + compare_with(a, >=, b) + compare_with(a, <, b) + compare_with(a, <=, b) + compare_with(a, ==, b) + compare_with(a, !=, b) + combine_with(a, &&, b) + combine_with(a, ||, b) + compute_with(a, +, b) + compute_with(a, -, b) + compute_with(a, /, b) + compute_with(a, *, b) + compute_with(a, %, b) + } + "#}; + + assert_definitions( + code, + vec![ast::Definition::Fn(Function { + arguments: vec![], + body: Sequence { + location: Span::new((), 13..328), + expressions: vec![ + Call { + arguments: vec![ + ast::CallArg { + label: None, + location: Span::new((), 26..27), + value: Var { + location: Span::new((), 26..27), + name: "a".to_string(), + }, + }, + ast::CallArg { + label: None, + location: Span::new((), 29..30), + value: Fn { + location: Span::new((), 29..30), + fn_style: expr::FnStyle::BinOp(ast::BinOp::GtInt), + arguments: vec![ + Arg { + arg_name: Named { + name: "left".to_string(), + label: "left".to_string(), + location: Span::new((), 29..30), + is_validator_param: false, + }, + location: Span::new((), 29..30), + annotation: Some(ast::Annotation::Constructor { + location: Span::new((), 29..30), + module: None, + name: "Int".to_string(), + arguments: vec![], + }), + tipo: (), + }, + Arg { + arg_name: Named { + name: "right".to_string(), + label: "right".to_string(), + location: Span::new((), 29..30), + is_validator_param: false, + }, + location: Span::new((), 29..30), + annotation: Some(ast::Annotation::Constructor { + location: Span::new((), 29..30), + module: None, + name: "Int".to_string(), + arguments: vec![], + }), + tipo: (), + }, + ], + body: Box::new(BinOp { + location: Span::new((), 29..30), + name: GtInt, + left: Box::new(Var { + location: Span::new((), 29..30), + name: "left".to_string(), + }), + right: Box::new(Var { + location: Span::new((), 29..30), + name: "right".to_string(), + }), + }), + return_annotation: Some(ast::Annotation::Constructor { + location: Span::new((), 29..30), + module: None, + name: "Bool".to_string(), + arguments: vec![], + }), + }, + }, + CallArg { + label: None, + location: Span::new((), 32..33), + value: Var { + location: Span::new((), 32..33), + name: "b".to_string(), + }, + }, + ], + fun: Box::new(Var { + location: Span::new((), 13..25), + name: "compare_with".to_string(), + }), + location: Span::new((), 13..34), + }, + Call { + arguments: vec![ + ast::CallArg { + label: None, + location: Span::new((), 50..51), + value: Var { + location: Span::new((), 50..51), + name: "a".to_string(), + }, + }, + ast::CallArg { + label: None, + location: Span::new((), 53..55), + value: Fn { + location: Span::new((), 53..55), + fn_style: expr::FnStyle::BinOp(GtEqInt), + arguments: vec![ + Arg { + arg_name: Named { + name: "left".to_string(), + label: "left".to_string(), + location: Span::new((), 53..55), + is_validator_param: false, + }, + location: Span::new((), 53..55), + annotation: Some(ast::Annotation::Constructor { + location: Span::new((), 53..55), + module: None, + name: "Int".to_string(), + arguments: vec![], + }), + tipo: (), + }, + Arg { + arg_name: Named { + name: "right".to_string(), + label: "right".to_string(), + location: Span::new((), 53..55), + is_validator_param: false, + }, + location: Span::new((), 53..55), + annotation: Some(ast::Annotation::Constructor { + location: Span::new((), 53..55), + module: None, + name: "Int".to_string(), + arguments: vec![], + }), + tipo: (), + }, + ], + body: Box::new(BinOp { + location: Span::new((), 53..55), + name: GtEqInt, + left: Box::new(Var { + location: Span::new((), 53..55), + name: "left".to_string(), + }), + right: Box::new(Var { + location: Span::new((), 53..55), + name: "right".to_string(), + }), + }), + return_annotation: Some(ast::Annotation::Constructor { + location: Span::new((), 53..55), + module: None, + name: "Bool".to_string(), + arguments: vec![], + }), + }, + }, + ast::CallArg { + label: None, + location: Span::new((), 57..58), + value: Var { + location: Span::new((), 57..58), + name: "b".to_string(), + }, + }, + ], + fun: Box::new(Var { + location: Span::new((), 37..49), + name: "compare_with".to_string(), + }), + location: Span::new((), 37..59), + }, + Call { + arguments: vec![ + CallArg { + label: None, + location: Span::new((), 75..76), + value: Var { + location: Span::new((), 75..76), + name: "a".to_string(), + }, + }, + CallArg { + label: None, + location: Span::new((), 78..79), + value: Fn { + location: Span::new((), 78..79), + fn_style: expr::FnStyle::BinOp(LtInt), + arguments: vec![ + Arg { + arg_name: Named { + name: "left".to_string(), + label: "left".to_string(), + location: Span::new((), 78..79), + is_validator_param: false, + }, + location: Span::new((), 78..79), + annotation: Some(ast::Annotation::Constructor { + location: Span::new((), 78..79), + module: None, + name: "Int".to_string(), + arguments: vec![], + }), + tipo: (), + }, + Arg { + arg_name: Named { + name: "right".to_string(), + label: "right".to_string(), + location: Span::new((), 78..79), + is_validator_param: false, + }, + location: Span::new((), 78..79), + annotation: Some(ast::Annotation::Constructor { + location: Span::new((), 78..79), + module: None, + name: "Int".to_string(), + arguments: vec![], + }), + tipo: (), + }, + ], + body: Box::new(BinOp { + location: Span::new((), 78..79), + name: LtInt, + left: Box::new(Var { + location: Span::new((), 78..79), + name: "left".to_string(), + }), + right: Box::new(Var { + location: Span::new((), 78..79), + name: "right".to_string(), + }), + }), + return_annotation: Some(ast::Annotation::Constructor { + location: Span::new((), 78..79), + module: None, + name: "Bool".to_string(), + arguments: vec![], + }), + }, + }, + CallArg { + label: None, + location: Span::new((), 81..82), + value: Var { + location: Span::new((), 81..82), + name: "b".to_string(), + }, + }, + ], + fun: Box::new(Var { + location: Span::new((), 62..74), + name: "compare_with".to_string(), + }), + location: Span::new((), 62..83), + }, + Call { + arguments: vec![ + CallArg { + label: None, + location: Span::new((), 99..100), + value: Var { + location: Span::new((), 99..100), + name: "a".to_string(), + }, + }, + CallArg { + label: None, + location: Span::new((), 102..104), + value: Fn { + location: Span::new((), 102..104), + fn_style: expr::FnStyle::BinOp(LtEqInt), + arguments: vec![ + Arg { + arg_name: Named { + name: "left".to_string(), + label: "left".to_string(), + location: Span::new((), 102..104), + is_validator_param: false, + }, + location: Span::new((), 102..104), + annotation: Some(ast::Annotation::Constructor { + location: Span::new((), 102..104), + module: None, + name: "Int".to_string(), + arguments: vec![], + }), + tipo: (), + }, + Arg { + arg_name: Named { + name: "right".to_string(), + label: "right".to_string(), + location: Span::new((), 102..104), + is_validator_param: false, + }, + location: Span::new((), 102..104), + annotation: Some(ast::Annotation::Constructor { + location: Span::new((), 102..104), + module: None, + name: "Int".to_string(), + arguments: vec![], + }), + tipo: (), + }, + ], + body: Box::new(BinOp { + location: Span::new((), 102..104), + name: LtEqInt, + left: Box::new(Var { + location: Span::new((), 102..104), + name: "left".to_string(), + }), + right: Box::new(Var { + location: Span::new((), 102..104), + name: "right".to_string(), + }), + }), + return_annotation: Some(ast::Annotation::Constructor { + location: Span::new((), 102..104), + module: None, + name: "Bool".to_string(), + arguments: vec![], + }), + }, + }, + CallArg { + label: None, + location: Span::new((), 106..107), + value: Var { + location: Span::new((), 106..107), + name: "b".to_string(), + }, + }, + ], + fun: Box::new(Var { + location: Span::new((), 86..98), + name: "compare_with".to_string(), + }), + location: Span::new((), 86..108), + }, + Call { + arguments: vec![ + CallArg { + label: None, + location: Span::new((), 124..125), + value: Var { + location: Span::new((), 124..125), + name: "a".to_string(), + }, + }, + CallArg { + label: None, + location: Span::new((), 127..129), + value: Fn { + location: Span::new((), 127..129), + fn_style: expr::FnStyle::BinOp(Eq), + arguments: vec![ + Arg { + arg_name: Named { + name: "left".to_string(), + label: "left".to_string(), + location: Span::new((), 127..129), + is_validator_param: false, + }, + location: Span::new((), 127..129), + annotation: None, + tipo: (), + }, + Arg { + arg_name: Named { + name: "right".to_string(), + label: "right".to_string(), + location: Span::new((), 127..129), + is_validator_param: false, + }, + location: Span::new((), 127..129), + annotation: None, + tipo: (), + }, + ], + body: Box::new(BinOp { + location: Span::new((), 127..129), + name: Eq, + left: Box::new(Var { + location: Span::new((), 127..129), + name: "left".to_string(), + }), + right: Box::new(Var { + location: Span::new((), 127..129), + name: "right".to_string(), + }), + }), + return_annotation: Some(ast::Annotation::Constructor { + location: Span::new((), 127..129), + module: None, + name: "Bool".to_string(), + arguments: vec![], + }), + }, + }, + CallArg { + label: None, + location: Span::new((), 131..132), + value: Var { + location: Span::new((), 131..132), + name: "b".to_string(), + }, + }, + ], + fun: Box::new(Var { + location: Span::new((), 111..123), + name: "compare_with".to_string(), + }), + location: Span::new((), 111..133), + }, + Call { + arguments: vec![ + CallArg { + label: None, + location: Span::new((), 149..150), + value: Var { + location: Span::new((), 149..150), + name: "a".to_string(), + }, + }, + CallArg { + label: None, + location: Span::new((), 152..154), + value: Fn { + location: Span::new((), 152..154), + fn_style: expr::FnStyle::BinOp(NotEq), + arguments: vec![ + Arg { + arg_name: Named { + name: "left".to_string(), + label: "left".to_string(), + location: Span::new((), 152..154), + is_validator_param: false, + }, + location: Span::new((), 152..154), + annotation: None, + tipo: (), + }, + Arg { + arg_name: Named { + name: "right".to_string(), + label: "right".to_string(), + location: Span::new((), 152..154), + is_validator_param: false, + }, + location: Span::new((), 152..154), + annotation: None, + tipo: (), + }, + ], + body: Box::new(BinOp { + location: Span::new((), 152..154), + name: NotEq, + left: Box::new(Var { + location: Span::new((), 152..154), + name: "left".to_string(), + }), + right: Box::new(Var { + location: Span::new((), 152..154), + name: "right".to_string(), + }), + }), + return_annotation: Some(ast::Annotation::Constructor { + location: Span::new((), 152..154), + module: None, + name: "Bool".to_string(), + arguments: vec![], + }), + }, + }, + CallArg { + label: None, + location: Span::new((), 156..157), + value: Var { + location: Span::new((), 156..157), + name: "b".to_string(), + }, + }, + ], + fun: Box::new(Var { + location: Span::new((), 136..148), + name: "compare_with".to_string(), + }), + location: Span::new((), 136..158), + }, + Call { + arguments: vec![ + CallArg { + label: None, + location: Span::new((), 174..175), + value: Var { + location: Span::new((), 174..175), + name: "a".to_string(), + }, + }, + CallArg { + label: None, + location: Span::new((), 177..179), + value: Fn { + location: Span::new((), 177..179), + fn_style: expr::FnStyle::BinOp(And), + arguments: vec![ + Arg { + arg_name: Named { + name: "left".to_string(), + label: "left".to_string(), + location: Span::new((), 177..179), + is_validator_param: false, + }, + location: Span::new((), 177..179), + annotation: Some(ast::Annotation::Constructor { + location: Span::new((), 177..179), + module: None, + name: "Bool".to_string(), + arguments: vec![], + }), + tipo: (), + }, + Arg { + arg_name: Named { + name: "right".to_string(), + label: "right".to_string(), + location: Span::new((), 177..179), + is_validator_param: false, + }, + location: Span::new((), 177..179), + annotation: Some(ast::Annotation::Constructor { + location: Span::new((), 177..179), + module: None, + name: "Bool".to_string(), + arguments: vec![], + }), + tipo: (), + }, + ], + body: Box::new(BinOp { + location: Span::new((), 177..179), + name: And, + left: Box::new(Var { + location: Span::new((), 177..179), + name: "left".to_string(), + }), + right: Box::new(Var { + location: Span::new((), 177..179), + name: "right".to_string(), + }), + }), + return_annotation: Some(ast::Annotation::Constructor { + location: Span::new((), 177..179), + module: None, + name: "Bool".to_string(), + arguments: vec![], + }), + }, + }, + CallArg { + label: None, + location: Span::new((), 181..182), + value: Var { + location: Span::new((), 181..182), + name: "b".to_string(), + }, + }, + ], + fun: Box::new(Var { + location: Span::new((), 161..173), + name: "combine_with".to_string(), + }), + location: Span::new((), 161..183), + }, + Call { + arguments: vec![ + CallArg { + label: None, + location: Span::new((), 199..200), + value: Var { + location: Span::new((), 199..200), + name: "a".to_string(), + }, + }, + CallArg { + label: None, + location: Span::new((), 202..204), + value: Fn { + location: Span::new((), 202..204), + fn_style: expr::FnStyle::BinOp(Or), + arguments: vec![ + Arg { + arg_name: Named { + name: "left".to_string(), + label: "left".to_string(), + location: Span::new((), 202..204), + is_validator_param: false, + }, + location: Span::new((), 202..204), + annotation: Some(ast::Annotation::Constructor { + location: Span::new((), 202..204), + module: None, + name: "Bool".to_string(), + arguments: vec![], + }), + tipo: (), + }, + Arg { + arg_name: Named { + name: "right".to_string(), + label: "right".to_string(), + location: Span::new((), 202..204), + is_validator_param: false, + }, + location: Span::new((), 202..204), + annotation: Some(ast::Annotation::Constructor { + location: Span::new((), 202..204), + module: None, + name: "Bool".to_string(), + arguments: vec![], + }), + tipo: (), + }, + ], + body: Box::new(BinOp { + location: Span::new((), 202..204), + name: Or, + left: Box::new(Var { + location: Span::new((), 202..204), + name: "left".to_string(), + }), + right: Box::new(Var { + location: Span::new((), 202..204), + name: "right".to_string(), + }), + }), + return_annotation: Some(ast::Annotation::Constructor { + location: Span::new((), 202..204), + module: None, + name: "Bool".to_string(), + arguments: vec![], + }), + }, + }, + CallArg { + label: None, + location: Span::new((), 206..207), + value: Var { + location: Span::new((), 206..207), + name: "b".to_string(), + }, + }, + ], + fun: Box::new(Var { + location: Span::new((), 186..198), + name: "combine_with".to_string(), + }), + location: Span::new((), 186..208), + }, + Call { + arguments: vec![ + CallArg { + label: None, + location: Span::new((), 224..225), + value: Var { + location: Span::new((), 224..225), + name: "a".to_string(), + }, + }, + CallArg { + label: None, + location: Span::new((), 227..228), + value: Fn { + location: Span::new((), 227..228), + fn_style: expr::FnStyle::BinOp(AddInt), + arguments: vec![ + Arg { + arg_name: Named { + name: "left".to_string(), + label: "left".to_string(), + location: Span::new((), 227..228), + is_validator_param: false, + }, + location: Span::new((), 227..228), + annotation: Some(ast::Annotation::Constructor { + location: Span::new((), 227..228), + module: None, + name: "Int".to_string(), + arguments: vec![], + }), + tipo: (), + }, + Arg { + arg_name: Named { + name: "right".to_string(), + label: "right".to_string(), + location: Span::new((), 227..228), + is_validator_param: false, + }, + location: Span::new((), 227..228), + annotation: Some(ast::Annotation::Constructor { + location: Span::new((), 227..228), + module: None, + name: "Int".to_string(), + arguments: vec![], + }), + tipo: (), + }, + ], + body: Box::new(BinOp { + location: Span::new((), 227..228), + name: AddInt, + left: Box::new(Var { + location: Span::new((), 227..228), + name: "left".to_string(), + }), + right: Box::new(Var { + location: Span::new((), 227..228), + name: "right".to_string(), + }), + }), + return_annotation: Some(ast::Annotation::Constructor { + location: Span::new((), 227..228), + module: None, + name: "Int".to_string(), + arguments: vec![], + }), + }, + }, + CallArg { + label: None, + location: Span::new((), 230..231), + value: Var { + location: Span::new((), 230..231), + name: "b".to_string(), + }, + }, + ], + fun: Box::new(Var { + location: Span::new((), 211..223), + name: "compute_with".to_string(), + }), + location: Span::new((), 211..232), + }, + Call { + arguments: vec![ + CallArg { + label: None, + location: Span::new((), 248..249), + value: Var { + location: Span::new((), 248..249), + name: "a".to_string(), + }, + }, + CallArg { + label: None, + location: Span::new((), 251..252), + value: Fn { + location: Span::new((), 251..252), + fn_style: expr::FnStyle::BinOp(SubInt), + arguments: vec![ + Arg { + arg_name: Named { + name: "left".to_string(), + label: "left".to_string(), + location: Span::new((), 251..252), + is_validator_param: false, + }, + location: Span::new((), 251..252), + annotation: Some(ast::Annotation::Constructor { + location: Span::new((), 251..252), + module: None, + name: "Int".to_string(), + arguments: vec![], + }), + tipo: (), + }, + Arg { + arg_name: Named { + name: "right".to_string(), + label: "right".to_string(), + location: Span::new((), 251..252), + is_validator_param: false, + }, + location: Span::new((), 251..252), + annotation: Some(ast::Annotation::Constructor { + location: Span::new((), 251..252), + module: None, + name: "Int".to_string(), + arguments: vec![], + }), + tipo: (), + }, + ], + body: Box::new(BinOp { + location: Span::new((), 251..252), + name: SubInt, + left: Box::new(Var { + location: Span::new((), 251..252), + name: "left".to_string(), + }), + right: Box::new(Var { + location: Span::new((), 251..252), + name: "right".to_string(), + }), + }), + return_annotation: Some(ast::Annotation::Constructor { + location: Span::new((), 251..252), + module: None, + name: "Int".to_string(), + arguments: vec![], + }), + }, + }, + CallArg { + label: None, + location: Span::new((), 254..255), + value: Var { + location: Span::new((), 254..255), + name: "b".to_string(), + }, + }, + ], + fun: Box::new(Var { + location: Span::new((), 235..247), + name: "compute_with".to_string(), + }), + location: Span::new((), 235..256), + }, + Call { + arguments: vec![ + CallArg { + label: None, + location: Span::new((), 272..273), + value: Var { + location: Span::new((), 272..273), + name: "a".to_string(), + }, + }, + CallArg { + label: None, + location: Span::new((), 275..276), + value: Fn { + location: Span::new((), 275..276), + fn_style: expr::FnStyle::BinOp(DivInt), + arguments: vec![ + Arg { + arg_name: Named { + name: "left".to_string(), + label: "left".to_string(), + location: Span::new((), 275..276), + is_validator_param: false, + }, + location: Span::new((), 275..276), + annotation: Some(ast::Annotation::Constructor { + location: Span::new((), 275..276), + module: None, + name: "Int".to_string(), + arguments: vec![], + }), + tipo: (), + }, + Arg { + arg_name: Named { + name: "right".to_string(), + label: "right".to_string(), + location: Span::new((), 275..276), + is_validator_param: false, + }, + location: Span::new((), 275..276), + annotation: Some(ast::Annotation::Constructor { + location: Span::new((), 275..276), + module: None, + name: "Int".to_string(), + arguments: vec![], + }), + tipo: (), + }, + ], + body: Box::new(BinOp { + location: Span::new((), 275..276), + name: DivInt, + left: Box::new(Var { + location: Span::new((), 275..276), + name: "left".to_string(), + }), + right: Box::new(Var { + location: Span::new((), 275..276), + name: "right".to_string(), + }), + }), + return_annotation: Some(ast::Annotation::Constructor { + location: Span::new((), 275..276), + module: None, + name: "Int".to_string(), + arguments: vec![], + }), + }, + }, + CallArg { + label: None, + location: Span::new((), 278..279), + value: Var { + location: Span::new((), 278..279), + name: "b".to_string(), + }, + }, + ], + fun: Box::new(Var { + location: Span::new((), 259..271), + name: "compute_with".to_string(), + }), + location: Span::new((), 259..280), + }, + Call { + arguments: vec![ + CallArg { + label: None, + location: Span::new((), 296..297), + value: Var { + location: Span::new((), 296..297), + name: "a".to_string(), + }, + }, + CallArg { + label: None, + location: Span::new((), 299..300), + value: Fn { + location: Span::new((), 299..300), + fn_style: expr::FnStyle::BinOp(MultInt), + arguments: vec![ + Arg { + arg_name: Named { + name: "left".to_string(), + label: "left".to_string(), + location: Span::new((), 299..300), + is_validator_param: false, + }, + location: Span::new((), 299..300), + annotation: Some(ast::Annotation::Constructor { + location: Span::new((), 299..300), + module: None, + name: "Int".to_string(), + arguments: vec![], + }), + tipo: (), + }, + Arg { + arg_name: Named { + name: "right".to_string(), + label: "right".to_string(), + location: Span::new((), 299..300), + is_validator_param: false, + }, + location: Span::new((), 299..300), + annotation: Some(ast::Annotation::Constructor { + location: Span::new((), 299..300), + module: None, + name: "Int".to_string(), + arguments: vec![], + }), + tipo: (), + }, + ], + body: Box::new(BinOp { + location: Span::new((), 299..300), + name: MultInt, + left: Box::new(Var { + location: Span::new((), 299..300), + name: "left".to_string(), + }), + right: Box::new(Var { + location: Span::new((), 299..300), + name: "right".to_string(), + }), + }), + return_annotation: Some(ast::Annotation::Constructor { + location: Span::new((), 299..300), + module: None, + name: "Int".to_string(), + arguments: vec![], + }), + }, + }, + CallArg { + label: None, + location: Span::new((), 302..303), + value: Var { + location: Span::new((), 302..303), + name: "b".to_string(), + }, + }, + ], + fun: Box::new(Var { + location: Span::new((), 283..295), + name: "compute_with".to_string(), + }), + location: Span::new((), 283..304), + }, + Call { + arguments: vec![ + CallArg { + label: None, + location: Span::new((), 320..321), + value: Var { + location: Span::new((), 320..321), + name: "a".to_string(), + }, + }, + CallArg { + label: None, + location: Span::new((), 323..324), + value: Fn { + location: Span::new((), 323..324), + fn_style: expr::FnStyle::BinOp(ModInt), + arguments: vec![ + Arg { + arg_name: Named { + name: "left".to_string(), + label: "left".to_string(), + location: Span::new((), 323..324), + is_validator_param: false, + }, + location: Span::new((), 323..324), + annotation: Some(ast::Annotation::Constructor { + location: Span::new((), 323..324), + module: None, + name: "Int".to_string(), + arguments: vec![], + }), + tipo: (), + }, + Arg { + arg_name: Named { + name: "right".to_string(), + label: "right".to_string(), + location: Span::new((), 323..324), + is_validator_param: false, + }, + location: Span::new((), 323..324), + annotation: Some(ast::Annotation::Constructor { + location: Span::new((), 323..324), + module: None, + name: "Int".to_string(), + arguments: vec![], + }), + tipo: (), + }, + ], + body: Box::new(BinOp { + location: Span::new((), 323..324), + name: ModInt, + left: Box::new(Var { + location: Span::new((), 323..324), + name: "left".to_string(), + }), + right: Box::new(Var { + location: Span::new((), 323..324), + name: "right".to_string(), + }), + }), + return_annotation: Some(ast::Annotation::Constructor { + location: Span::new((), 323..324), + module: None, + name: "Int".to_string(), + arguments: vec![], + }), + }, + }, + CallArg { + label: None, + location: Span::new((), 326..327), + value: Var { + location: Span::new((), 326..327), + name: "b".to_string(), + }, + }, + ], + fun: Box::new(Var { + location: Span::new((), 307..319), + name: "compute_with".to_string(), + }), + location: Span::new((), 307..328), + }, + ], + }, + doc: None, + location: Span::new((), 0..8), + name: "foo".to_string(), + public: false, + return_annotation: None, + return_type: (), + end_position: 329, + can_error: true, + })], + ); +} diff --git a/crates/aiken-lang/src/tipo/expr.rs b/crates/aiken-lang/src/tipo/expr.rs index aa613e71..f4a39b06 100644 --- a/crates/aiken-lang/src/tipo/expr.rs +++ b/crates/aiken-lang/src/tipo/expr.rs @@ -12,7 +12,7 @@ use crate::{ UntypedRecordUpdateArg, }, builtins::{bool, byte_array, function, int, list, string, tuple}, - expr::{TypedExpr, UntypedExpr}, + expr::{FnStyle, TypedExpr, UntypedExpr}, format, tipo::fields::FieldMap, }; @@ -220,12 +220,19 @@ impl<'a, 'b> ExprTyper<'a, 'b> { UntypedExpr::Fn { location, - is_capture, + fn_style, arguments: args, body, return_annotation, .. - } => self.infer_fn(args, &[], *body, is_capture, return_annotation, location), + } => self.infer_fn( + args, + &[], + *body, + fn_style == FnStyle::Capture, + return_annotation, + location, + ), UntypedExpr::If { location, @@ -1011,17 +1018,19 @@ impl<'a, 'b> ExprTyper<'a, 'b> { body, return_annotation, location, - is_capture: false, + fn_style, .. }, - ) if expected_arguments.len() == arguments.len() => self.infer_fn( - arguments, - expected_arguments, - *body, - false, - return_annotation, - location, - ), + ) if fn_style != FnStyle::Capture && expected_arguments.len() == arguments.len() => { + self.infer_fn( + arguments, + expected_arguments, + *body, + false, + return_annotation, + location, + ) + } // Otherwise just perform normal type inference. (_, value) => self.infer(value),