diff --git a/crates/aiken-lang/src/expr.rs b/crates/aiken-lang/src/expr.rs index 2af362ea..f6f1b9a9 100644 --- a/crates/aiken-lang/src/expr.rs +++ b/crates/aiken-lang/src/expr.rs @@ -241,6 +241,10 @@ impl TypedExpr { ) } + pub fn is_error_term(&self) -> bool { + matches!(self, Self::ErrorTerm { .. }) + } + /// Returns `true` if the typed expr is [`Assignment`]. pub fn is_assignment(&self) -> bool { matches!(self, Self::Assignment { .. }) diff --git a/crates/aiken-lang/src/tests/check.rs b/crates/aiken-lang/src/tests/check.rs index 4e42833d..971e0a9f 100644 --- a/crates/aiken-lang/src/tests/check.rs +++ b/crates/aiken-lang/src/tests/check.rs @@ -318,19 +318,17 @@ fn mark_constructors_as_used_via_field_access() { bar: Int, } - validator foo { - spend(d: Datum, _r, _c) { - when d is { - D0(params) -> params.foo == 1 - D1(_params) -> False - } + fn spend(d: Datum, _r, _c) { + when d is { + D0(params) -> params.foo == 1 + D1(_params) -> False } } "#; - let (warnings, _) = check_validator(parse(source_code)).unwrap(); + let (warnings, _) = check(parse(source_code)).unwrap(); - assert_eq!(warnings.len(), 1) + assert_eq!(warnings.len(), 2) } #[test] @@ -2506,27 +2504,6 @@ fn validator_public() { assert!(check_validator(parse(source_code)).is_ok()) } -#[test] -fn validator_private_everything() { - let source_code = r#" - type Datum { - foo: Int, - } - - type Redeemer { - bar: Int, - } - - validator bar { - spend(datum: Datum, redeemer: Redeemer, _ctx) { - datum.foo == redeemer.bar - } - } - "#; - - assert!(check_validator(parse(source_code)).is_ok()) -} - #[test] fn tuple_access_on_call() { let source_code = r#" diff --git a/crates/aiken-lang/src/tipo/environment.rs b/crates/aiken-lang/src/tipo/environment.rs index 8fcf33de..a7ee6c23 100644 --- a/crates/aiken-lang/src/tipo/environment.rs +++ b/crates/aiken-lang/src/tipo/environment.rs @@ -309,29 +309,43 @@ impl<'a> Environment<'a> { end_position, handlers, name, - fallback, + mut fallback, location, params, }) => { let handlers = handlers .into_iter() - .map(|fun| { - let Definition::Fn(fun) = + .map(|mut fun| { + let handler_name = format!("{}_{}", &name, &fun.name); + + let old_name = fun.name; + fun.name = handler_name; + + let Definition::Fn(mut fun) = self.generalise_definition(Definition::Fn(fun), module_name) else { unreachable!() }; + fun.name = old_name; + fun }) .collect(); - let Definition::Fn(fallback) = + let fallback_name = format!("{}_{}", &name, &fallback.name); + + let old_name = fallback.name; + fallback.name = fallback_name; + + let Definition::Fn(mut fallback) = self.generalise_definition(Definition::Fn(fallback), module_name) else { unreachable!() }; + fallback.name = old_name; + Definition::Validator(Validator { doc, name, diff --git a/crates/aiken-lang/src/tipo/infer.rs b/crates/aiken-lang/src/tipo/infer.rs index 6e7d6c1a..6fafaf86 100644 --- a/crates/aiken-lang/src/tipo/infer.rs +++ b/crates/aiken-lang/src/tipo/infer.rs @@ -178,102 +178,117 @@ fn infer_definition( }) => { let params_length = params.len(); - let mut typed_handlers = vec![]; + environment.in_new_scope(|environment| { + let fallback_name = format!("{}_{}", &name, &fallback.name); - for mut handler in handlers { - let typed_fun = environment.in_new_scope(|environment| { - let temp_params = params.iter().cloned().chain(handler.arguments); - handler.arguments = temp_params.collect(); + put_params_in_scope(&fallback_name, environment, ¶ms); - put_params_in_scope(&handler.name, environment, ¶ms); + let mut typed_handlers = vec![]; - let mut typed_fun = - infer_function(&handler, module_name, hydrators, environment, tracing)?; + for mut handler in handlers { + let typed_fun = environment.in_new_scope(|environment| { + let temp_params = params.iter().cloned().chain(handler.arguments); + handler.arguments = temp_params.collect(); - if !typed_fun.return_type.is_bool() { + let handler_name = format!("{}_{}", &name, &handler.name); + + let old_name = handler.name; + handler.name = handler_name; + + let mut typed_fun = + infer_function(&handler, module_name, hydrators, environment, tracing)?; + + typed_fun.name = old_name; + + if !typed_fun.return_type.is_bool() { + return Err(Error::ValidatorMustReturnBool { + return_type: typed_fun.return_type.clone(), + location: typed_fun.location, + }); + } + + typed_fun.arguments.drain(0..params_length); + + // TODO: the expected number of args comes from the script purpose + if typed_fun.arguments.len() < 2 || typed_fun.arguments.len() > 3 { + return Err(Error::IncorrectValidatorArity { + count: typed_fun.arguments.len() as u32, + expected: 3, + location: typed_fun.location, + }); + } + + for arg in typed_fun.arguments.iter_mut() { + if arg.tipo.is_unbound() { + arg.tipo = builtins::data(); + } + } + + Ok(typed_fun) + })?; + + typed_handlers.push(typed_fun); + } + + let (typed_params, typed_fallback) = environment.in_new_scope(|environment| { + let temp_params = params.iter().cloned().chain(fallback.arguments); + fallback.arguments = temp_params.collect(); + + let old_name = fallback.name; + fallback.name = fallback_name; + + let mut typed_fallback = + infer_function(&fallback, module_name, hydrators, environment, tracing)?; + + typed_fallback.name = old_name; + + if !typed_fallback.body.is_error_term() && !typed_fallback.return_type.is_bool() + { return Err(Error::ValidatorMustReturnBool { - return_type: typed_fun.return_type.clone(), - location: typed_fun.location, + return_type: typed_fallback.return_type.clone(), + location: typed_fallback.location, }); } - typed_fun.arguments.drain(0..params_length); + let typed_params = typed_fallback + .arguments + .drain(0..params_length) + .map(|mut arg| { + if arg.tipo.is_unbound() { + arg.tipo = builtins::data(); + } - // TODO: the expected number of args comes from the script purpose - if typed_fun.arguments.len() < 2 || typed_fun.arguments.len() > 3 { + arg + }) + .collect(); + + if typed_fallback.arguments.len() != 1 { return Err(Error::IncorrectValidatorArity { - count: typed_fun.arguments.len() as u32, - expected: 3, - location: typed_fun.location, + count: typed_fallback.arguments.len() as u32, + expected: 1, + location: typed_fallback.location, }); } - for arg in typed_fun.arguments.iter_mut() { + for arg in typed_fallback.arguments.iter_mut() { if arg.tipo.is_unbound() { arg.tipo = builtins::data(); } } - Ok(typed_fun) + Ok((typed_params, typed_fallback)) })?; - typed_handlers.push(typed_fun); - } - - let (typed_params, typed_fallback) = environment.in_new_scope(|environment| { - let temp_params = params.iter().cloned().chain(fallback.arguments); - fallback.arguments = temp_params.collect(); - - put_params_in_scope(&fallback.name, environment, ¶ms); - - let mut typed_fallback = - infer_function(&fallback, module_name, hydrators, environment, tracing)?; - - if !typed_fallback.return_type.is_bool() { - return Err(Error::ValidatorMustReturnBool { - return_type: typed_fallback.return_type.clone(), - location: typed_fallback.location, - }); - } - - let typed_params = typed_fallback - .arguments - .drain(0..params_length) - .map(|mut arg| { - if arg.tipo.is_unbound() { - arg.tipo = builtins::data(); - } - - arg - }) - .collect(); - - if typed_fallback.arguments.len() != 1 { - return Err(Error::IncorrectValidatorArity { - count: typed_fallback.arguments.len() as u32, - expected: 1, - location: typed_fallback.location, - }); - } - - for arg in typed_fallback.arguments.iter_mut() { - if arg.tipo.is_unbound() { - arg.tipo = builtins::data(); - } - } - - Ok((typed_params, typed_fallback)) - })?; - - Ok(Definition::Validator(Validator { - doc, - end_position, - handlers: typed_handlers, - fallback: typed_fallback, - name, - location, - params: typed_params, - })) + Ok(Definition::Validator(Validator { + doc, + end_position, + handlers: typed_handlers, + fallback: typed_fallback, + name, + location, + params: typed_params, + })) + }) } Definition::Test(f) => { diff --git a/crates/aiken-project/src/blueprint/validator.rs b/crates/aiken-project/src/blueprint/validator.rs index f6c5212b..f0d6fad5 100644 --- a/crates/aiken-project/src/blueprint/validator.rs +++ b/crates/aiken-project/src/blueprint/validator.rs @@ -550,8 +550,8 @@ mod tests { type UUID { UUID } - validator { - fn opaque_singleton_variants(redeemer: Dict, ctx: Void) { + validator opaque_singleton_variants { + spend(redeemer: Dict, ctx: Void) { True } } @@ -568,8 +568,8 @@ mod tests { denominator: Int, } - validator { - fn opaque_singleton_multi_variants(redeemer: Rational, ctx: Void) { + validator opaque_singleton_multi_variants { + spend(redeemer: Rational, ctx: Void) { True } } @@ -585,8 +585,8 @@ mod tests { foo: Data } - validator { - fn nested_data(datum: Foo, redeemer: Int, ctx: Void) { + validator nested_data { + spend(datum: Foo, redeemer: Int, ctx: Void) { True } } @@ -604,8 +604,8 @@ mod tests { Mul(Expr, Expr) } - validator { - fn recursive_types(redeemer: Expr, ctx: Void) { + validator recursive_types { + spend(redeemer: Expr, ctx: Void) { True } } @@ -632,8 +632,8 @@ mod tests { } } - validator { - fn recursive_generic_types(datum: Foo, redeemer: LinkedList, ctx: Void) { + validator recursive_generic_types { + spend(datum: Foo, redeemer: LinkedList, ctx: Void) { True } } @@ -649,8 +649,8 @@ mod tests { foo: Int } - validator { - fn annotated_data(datum: Data, redeemer: Data, ctx: Void) { + validator annotated_data { + spend(datum: Data, redeemer: Data, ctx: Void) { True } } diff --git a/crates/aiken-project/src/tests/gen_uplc.rs b/crates/aiken-project/src/tests/gen_uplc.rs index cc1a914b..dc71a4ab 100644 --- a/crates/aiken-project/src/tests/gen_uplc.rs +++ b/crates/aiken-project/src/tests/gen_uplc.rs @@ -3687,8 +3687,8 @@ fn when_tuple_deconstruction() { Buy } - validator { - fn spend(dat: Datum, red: RedSpend, ctx: Data) { + validator thing { + spend(dat: Datum, red: RedSpend, ctx: Data) { when (dat, red) is { (A(a), Spend(x)) -> (a.idx == x)? @@ -4046,8 +4046,8 @@ fn generic_validator_type_test() { something: Void, } - validator { - fn err_example(r: A, _ctx: Data) -> Bool { + validator err_example { + spend(r: A, _ctx: Data) -> Bool { when r is { NoA -> False @@ -5562,8 +5562,8 @@ fn opaque_value_in_datum() { } - validator { - fn spend(dat: Dat, red: Data, ctx: Data) { + validator foo { + spend(dat: Dat, red: Data, ctx: Data) { let val = dat.a expect [Pair(_, amount)] = val.inner.inner