From de2791fe827258a93a02a5125a1a76e64d14ccda Mon Sep 17 00:00:00 2001 From: rvcas Date: Fri, 28 Jul 2023 17:56:56 -0400 Subject: [PATCH] feat(tipo): add new error for redundant clauses --- crates/aiken-lang/src/tipo/error.rs | 16 ++++++++++++++++ crates/aiken-lang/src/tipo/exhaustive.rs | 13 ++++++++++--- crates/aiken-lang/src/tipo/expr.rs | 14 +++----------- 3 files changed, 29 insertions(+), 14 deletions(-) diff --git a/crates/aiken-lang/src/tipo/error.rs b/crates/aiken-lang/src/tipo/error.rs index 7b199fc4..518a2b14 100644 --- a/crates/aiken-lang/src/tipo/error.rs +++ b/crates/aiken-lang/src/tipo/error.rs @@ -540,6 +540,22 @@ Maybe you meant to turn it public using the '{keyword_pub}' keyword?"# leaked: Type, }, + #[error( + "{}\n", + format!( + "I discovered a '{keyword_when}/{keyword_is}' expression with a redundant clause.", + keyword_is = "is".if_supports_color(Stdout, |s| s.purple()), + keyword_when = "when".if_supports_color(Stdout, |s| s.purple()) + ) + )] + #[diagnostic(url("https://aiken-lang.org/language-tour/control-flow#matching"))] + #[diagnostic(code("redundant_pattern_match"))] + #[diagnostic(help("You can safely remove this clause."))] + RedundantMatchClause { + #[label] + location: Span, + }, + #[error("I couldn't figure out the type of a record you're trying to access.\n")] #[diagnostic(url( "https://aiken-lang.org/language-tour/variables-and-constants#type-annotations" diff --git a/crates/aiken-lang/src/tipo/exhaustive.rs b/crates/aiken-lang/src/tipo/exhaustive.rs index cedc1c5b..53c29e45 100644 --- a/crates/aiken-lang/src/tipo/exhaustive.rs +++ b/crates/aiken-lang/src/tipo/exhaustive.rs @@ -428,7 +428,15 @@ fn simplify(environment: &mut Environment, value: &ast::TypedPattern) -> Result< Ok(Pattern::Constructor(name.to_string(), alts, args)) } - ast::Pattern::Tuple { .. } => todo!(), + ast::Pattern::Tuple { elems, .. } => { + let mut p = Pattern::Constructor(NIL_NAME.to_string(), list_constructors(), vec![]); + + for hd in elems.iter().rev() { + p = Pattern::Constructor(CONS_NAME.to_string(), list_constructors(), vec![simplify(environment, hd)?, p]); + } + + Ok(p) + }, ast::Pattern::Var { .. } | ast::Pattern::Discard { .. } => Ok(Pattern::Wildcard), } } @@ -452,8 +460,7 @@ pub(crate) fn compute_match_usefulness( if matrix.is_useful(&pattern_stack) { matrix.push(pattern_stack); } else { - dbg!(&pattern_stack); - todo!("redudant") + return Err(Error::RedundantMatchClause { location: unchecked_pattern.location() }) } } diff --git a/crates/aiken-lang/src/tipo/expr.rs b/crates/aiken-lang/src/tipo/expr.rs index b64f1583..e2046e32 100644 --- a/crates/aiken-lang/src/tipo/expr.rs +++ b/crates/aiken-lang/src/tipo/expr.rs @@ -48,7 +48,7 @@ impl<'a, 'b> ExprTyper<'a, 'b> { subject: &Type, typed_clauses: &[TypedClause], _location: Span, - ) -> Result<(), Vec> { + ) -> Result<(), Error> { let _value_typ = collapse_links(Arc::new(subject.clone())); // Currently guards in exhaustiveness checking are assumed that they can fail, @@ -66,7 +66,7 @@ impl<'a, 'b> ExprTyper<'a, 'b> { } } - let _ = dbg!(compute_match_usefulness(self.environment, &patterns)); + compute_match_usefulness(self.environment, &patterns)?; // self.environment // .check_exhaustiveness(patterns, value_typ, location) @@ -1881,15 +1881,7 @@ impl<'a, 'b> ExprTyper<'a, 'b> { } } - if let Err(unmatched) = - self.check_when_exhaustiveness(&subject_type, &typed_clauses, location) - { - return Err(Error::NotExhaustivePatternMatch { - location, - unmatched, - is_let: false, - }); - } + self.check_when_exhaustiveness(&subject_type, &typed_clauses, location)?; Ok(TypedExpr::When { location,