diff --git a/src/modules/expression/typeop/cast.rs b/src/modules/expression/typeop/cast.rs index 70c19f38..e6cebcbc 100644 --- a/src/modules/expression/typeop/cast.rs +++ b/src/modules/expression/typeop/cast.rs @@ -56,14 +56,6 @@ impl SyntaxModule for Cast { let message = Message::new_warn_at_position(meta, pos) .message(format!("Casting a value of type '{l_type}' value to a '{r_type}' is not recommended")) .comment(format!("To suppress this warning, use '{flag_name}' compiler flag")); - let (l_type, r_type) = match (l_type, r_type) { - (Type::Failable(l), Type::Failable(r)) => (*l, *r), - (Type::Failable(_), _) | (_, Type::Failable(_)) => { - meta.add_message(message); - return Ok(()); - }, - types => types - }; match (l_type, r_type) { (Type::Array(left), Type::Array(right)) => { if *left != *right && !matches!(*left, Type::Bool | Type::Num) && !matches!(*right, Type::Bool | Type::Num) { diff --git a/src/modules/function/declaration.rs b/src/modules/function/declaration.rs index 818c680f..7210d846 100644 --- a/src/modules/function/declaration.rs +++ b/src/modules/function/declaration.rs @@ -177,9 +177,6 @@ impl SyntaxModule for FunctionDeclaration { self.arg_types.push(Type::Generic); } } - if let Type::Failable(_) = arg_type { - return error!(meta, name_token, "Failable types cannot be used as arguments"); - } match token(meta, "=") { Ok(_) => { if is_ref { @@ -205,21 +202,23 @@ impl SyntaxModule for FunctionDeclaration { }; } let mut returns_tok = None; + let mut declared_failable = false; // Optionally parse the return type match token(meta, ":") { Ok(_) => { returns_tok = meta.get_current_token(); - self.returns = parse_type(meta)? + self.returns = parse_type(meta)?; + if token(meta, "?").is_ok() { + declared_failable = true; + } }, Err(_) => self.returns = Type::Generic } // Parse the body token(meta, "{")?; - let (index_begin, index_end, is_failable) = skip_function_body(meta); - if is_failable && !matches!(self.returns, Type::Failable(_) | Type::Generic) { - return error!(meta, returns_tok, "Failable functions must return a Failable type"); - } else if !is_failable && matches!(self.returns, Type::Failable(_)) { - return error!(meta, returns_tok, "Non-failable functions cannot return a Failable type"); + let (index_begin, index_end, is_failable) = skip_function_body(meta, declared_failable, &returns_tok)?; + if !is_failable && declared_failable { + return error!(meta, returns_tok, "Infallible functions must not have a '?' after the type name"); } // Create a new context with the function body let expr = meta.context.expr[index_begin..index_end].to_vec(); diff --git a/src/modules/function/declaration_utils.rs b/src/modules/function/declaration_utils.rs index c7ca3f4a..90d2d94e 100644 --- a/src/modules/function/declaration_utils.rs +++ b/src/modules/function/declaration_utils.rs @@ -6,7 +6,11 @@ use crate::utils::cc_flags::{CCFlags, get_ccflag_name}; use crate::utils::context::Context; use crate::utils::function_interface::FunctionInterface; -pub fn skip_function_body(meta: &mut ParserMetadata) -> (usize, usize, bool) { +pub fn skip_function_body( + meta: &mut ParserMetadata, + declared_failable: bool, + returns_tok: &Option, +) -> Result<(usize, usize, bool), Failure> { let index_begin = meta.get_index(); let mut is_failable = false; let mut scope = 1; @@ -14,7 +18,12 @@ pub fn skip_function_body(meta: &mut ParserMetadata) -> (usize, usize, bool) { match tok.word.as_str() { "{" => scope += 1, "}" => scope -= 1, - "fail" => is_failable = true, + "fail" => { + if !declared_failable && returns_tok.is_some() { + return error!(meta, Some(tok), "Failable functions must have a '?' after the type name"); + } + is_failable = true + }, "?" => is_failable = true, _ => {} } @@ -22,7 +31,7 @@ pub fn skip_function_body(meta: &mut ParserMetadata) -> (usize, usize, bool) { meta.increment_index(); } let index_end = meta.get_index(); - (index_begin, index_end, is_failable) + Ok((index_begin, index_end, is_failable)) } pub fn is_functions_comment_doc(meta: &mut ParserMetadata) -> bool { diff --git a/src/modules/function/invocation.rs b/src/modules/function/invocation.rs index a98f81eb..4f88251a 100644 --- a/src/modules/function/invocation.rs +++ b/src/modules/function/invocation.rs @@ -101,9 +101,7 @@ impl SyntaxModule for FunctionInvocation { self.is_failable = function_unit.is_failable; if self.is_failable { match syntax(meta, &mut self.failed) { - Ok(_) => if let Type::Failable(t) = &self.kind { - self.kind = *t.clone(); - }, + Ok(_) => (), Err(Failure::Quiet(_)) => return error!(meta, tok => { message: "This function can fail. Please handle the failure", comment: "You can use '?' in the end to propagate the failure" diff --git a/src/modules/types.rs b/src/modules/types.rs index 825b8a1f..6af5b1bd 100644 --- a/src/modules/types.rs +++ b/src/modules/types.rs @@ -10,7 +10,6 @@ pub enum Type { Bool, Num, Array(Box), - Failable(Box), Generic } @@ -20,9 +19,6 @@ impl Type { (_, Type::Generic) => true, (Type::Array(current), Type::Array(other)) => { **current != Type::Generic && **other == Type::Generic - } - (current, Type::Failable(other)) if !matches!(current, Type::Failable(_)) => { - current.is_allowed_in(other) }, _ => false } @@ -33,11 +29,7 @@ impl Type { } pub fn is_array(&self) -> bool { - match self { - Type::Array(_) => true, - Type::Failable(inner) => inner.is_array(), - _ => false, - } + matches!(self, Type::Array(_)) } } @@ -53,7 +45,6 @@ impl Display for Type { } else { write!(f, "[{}]", t) }, - Type::Failable(t) => write!(f, "{}?", t), Type::Generic => write!(f, "Generic") } } @@ -136,10 +127,6 @@ pub fn try_parse_type(meta: &mut ParserMetadata) -> Result { } }; - if token(meta, "?").is_ok() { - return res.map(|t| Type::Failable(Box::new(t))) - } - res } @@ -176,27 +163,4 @@ mod tests { assert!(!a.is_subset_of(&a)); } - - #[test] - fn non_failable_is_a_subset_of_failable() { - let a = Type::Text; - let b = Type::Failable(Box::new(Type::Text)); - - assert!(a.is_subset_of(&b)); - } - - #[test] - fn failable_is_not_a_subset_of_non_failable() { - let a = Type::Text; - let b = Type::Failable(Box::new(Type::Text)); - - assert!(!b.is_subset_of(&a)); - } - - #[test] - fn failable_is_not_a_subset_of_itself() { - let a = Type::Failable(Box::new(Type::Text)); - - assert!(!a.is_subset_of(&a)); - } } diff --git a/src/tests/erroring/function_failable_with_typed_nonfailable_return.ab b/src/tests/erroring/function_failable_with_typed_nonfailable_return.ab index 4b09882b..da222bf2 100644 --- a/src/tests/erroring/function_failable_with_typed_nonfailable_return.ab +++ b/src/tests/erroring/function_failable_with_typed_nonfailable_return.ab @@ -1,5 +1,5 @@ // Output -// Failable functions must return a Failable type +// Failable functions must have a '?' after the type name pub fun test(): Null { fail 1 diff --git a/src/tests/erroring/function_nonfailable_with_typed_failable_return.ab b/src/tests/erroring/function_nonfailable_with_typed_failable_return.ab index 862588c9..cf49eeb2 100644 --- a/src/tests/erroring/function_nonfailable_with_typed_failable_return.ab +++ b/src/tests/erroring/function_nonfailable_with_typed_failable_return.ab @@ -1,5 +1,5 @@ // Output -// Non-failable functions cannot return a Failable type +// Infallible functions must not have a '?' after the type name pub fun test(): Null? { echo "Hello, World!" diff --git a/src/tests/erroring/function_with_failable_typed_arg.ab b/src/tests/erroring/function_with_failable_typed_arg.ab deleted file mode 100644 index 2dac9221..00000000 --- a/src/tests/erroring/function_with_failable_typed_arg.ab +++ /dev/null @@ -1,7 +0,0 @@ -// Output -// Failable types cannot be used as arguments - -pub fun test(a: Text?) { - echo a -} -test("Hello, World!")