From d03288cece3e3b30c674138de3c2343375822768 Mon Sep 17 00:00:00 2001 From: rvcas Date: Wed, 15 Feb 2023 12:58:18 -0500 Subject: [PATCH] feat(validator): move return type and arity check to infer --- crates/aiken-lang/src/tipo/error.rs | 33 +++++++++- crates/aiken-lang/src/tipo/infer.rs | 23 ++++--- crates/aiken-project/src/blueprint/error.rs | 72 +-------------------- 3 files changed, 45 insertions(+), 83 deletions(-) diff --git a/crates/aiken-lang/src/tipo/error.rs b/crates/aiken-lang/src/tipo/error.rs index 394de649..2d4c0722 100644 --- a/crates/aiken-lang/src/tipo/error.rs +++ b/crates/aiken-lang/src/tipo/error.rs @@ -756,6 +756,30 @@ The best thing to do from here is to remove it."#))] location: Span, name: String, }, + + #[error("A validator must return {}", "Bool".bright_blue().bold())] + #[diagnostic(code("illegal::validator_return_type"))] + #[diagnostic(help(r#"While analyzing the return type of your validator, I found it to be: + +╰─▶ {signature} + +...but I expected this to be a {type_Bool}. If I am inferring the wrong type, you may want to add a type annotation to the function."# + , type_Bool = "Bool".bright_blue().bold() + , signature = return_type.to_pretty(0).red() + ))] + ValidatorMustReturnBool { + #[label("invalid return type")] + location: Span, + return_type: Arc, + }, + + #[error("Validators requires at least {} arguments.", at_least.to_string().purple().bold())] + #[diagnostic(code("illegal::validator_arity"))] + WrongValidatorArity { + at_least: u8, + #[label("not enough arguments")] + location: Span, + }, } impl Error { @@ -1210,13 +1234,16 @@ pub enum Warning { name: String, }, - #[error("I came across a validator in a {} module\nwhich means I'm going to ignore it.\n", "lib/".purple())] + #[error("I came across a validator in a {} module which means\nI'm going to ignore it.\n", "lib/".purple())] #[diagnostic(help( - "No big deal, but you might want to move it to a\n{} module or remove it to get rid of that warning.", + "No big deal, but you might want to move it to a {} module\nor remove it to get rid of that warning.", "validators/".purple() ))] #[diagnostic(code("unused::validator"))] - ValidatorInLibraryModule { location: Span }, + ValidatorInLibraryModule { + #[label("unused")] + location: Span, + }, } #[derive(Debug, Clone, Copy, PartialEq, Eq)] diff --git a/crates/aiken-lang/src/tipo/infer.rs b/crates/aiken-lang/src/tipo/infer.rs index 8b342e64..348063b9 100644 --- a/crates/aiken-lang/src/tipo/infer.rs +++ b/crates/aiken-lang/src/tipo/infer.rs @@ -268,19 +268,22 @@ fn infer_definition( environment, kind, )? { - // Do we want to do this here? - // or should we remove this and keep the later check - // the later check has a much more specific error message - // we may want to not do this here - environment.unify( - typed_fun.return_type.clone(), - builtins::bool(), - typed_fun.location, - false, - )?; + if !typed_fun.return_type.is_bool() { + return Err(Error::ValidatorMustReturnBool { + return_type: typed_fun.return_type.clone(), + location: typed_fun.location, + }); + } let typed_params = typed_fun.arguments.drain(0..params_length).collect(); + if typed_fun.arguments.len() < 2 { + return Err(Error::WrongValidatorArity { + at_least: 2, + location: typed_fun.location, + }); + } + Ok(Definition::Validator(Validator { doc, end_position, diff --git a/crates/aiken-project/src/blueprint/error.rs b/crates/aiken-project/src/blueprint/error.rs index 0fceaab4..dfb5301d 100644 --- a/crates/aiken-project/src/blueprint/error.rs +++ b/crates/aiken-project/src/blueprint/error.rs @@ -1,44 +1,11 @@ use super::schema; -use crate::module::CheckedModule; -use aiken_lang::{ - ast::{Span, TypedFunction}, - tipo::Type, -}; +use aiken_lang::ast::Span; use miette::{Diagnostic, NamedSource}; use owo_colors::OwoColorize; -use std::{fmt::Debug, sync::Arc}; +use std::fmt::Debug; #[derive(Debug, thiserror::Error, Diagnostic)] pub enum Error { - #[error("A validator must return {}", "Bool".bright_blue().bold())] - #[diagnostic(code("aiken::blueprint::invalid::return_type"))] - #[diagnostic(help(r#"While analyzing the return type of your validator, I found it to be: - -╰─▶ {signature} - -...but I expected this to be a {type_Bool}. If I am inferring the wrong type, you may want to add a type annotation to the function."# - , type_Bool = "Bool".bright_blue().bold() - , signature = return_type.to_pretty(0).red() - ))] - ValidatorMustReturnBool { - #[label("invalid return type")] - location: Span, - #[source_code] - source_code: NamedSource, - return_type: Arc, - }, - - #[error("A {} validator requires at least {} arguments.", name.purple().bold(), at_least.to_string().purple().bold())] - #[diagnostic(code("aiken::blueprint::invalid::arity"))] - WrongValidatorArity { - name: String, - at_least: u8, - #[label("not enough arguments")] - location: Span, - #[source_code] - source_code: NamedSource, - }, - #[error("{}", error)] #[diagnostic(help("{}", error.help()))] #[diagnostic(code("aiken::blueprint::interface"))] @@ -64,38 +31,3 @@ pub enum Error { #[diagnostic(help("I can only compute addresses of validators that are fully applied. For example, a {keyword_spend} validator must have exactly 3 arguments: a datum, a redeemer and a context. If it has more, they need to be provided beforehand and applied directly in the validator. Applying parameters change the validator's compiled code, and thus the address.\n\nThis is why I need you to apply parmeters first.", keyword_spend = "spend".purple()))] ParameterizedValidator { n: usize }, } - -pub fn assert_return_bool(module: &CheckedModule, def: &TypedFunction) -> Result<(), Error> { - if !def.return_type.is_bool() { - Err(Error::ValidatorMustReturnBool { - return_type: def.return_type.clone(), - location: def.location, - source_code: NamedSource::new( - module.input_path.display().to_string(), - module.code.clone(), - ), - }) - } else { - Ok(()) - } -} - -pub fn assert_min_arity( - module: &CheckedModule, - def: &TypedFunction, - at_least: u8, -) -> Result<(), Error> { - if def.arguments.len() < at_least as usize { - Err(Error::WrongValidatorArity { - name: def.name.clone(), - at_least, - location: def.location, - source_code: NamedSource::new( - module.input_path.display().to_string(), - module.code.clone(), - ), - }) - } else { - Ok(()) - } -}