diff --git a/crates/aiken-lang/src/tipo/environment.rs b/crates/aiken-lang/src/tipo/environment.rs index 90d35756..b891e844 100644 --- a/crates/aiken-lang/src/tipo/environment.rs +++ b/crates/aiken-lang/src/tipo/environment.rs @@ -1434,8 +1434,8 @@ impl<'a> Environment<'a> { } /// Checks that the given patterns are exhaustive for given type. - /// Currently only performs exhaustiveness checking for custom types, - /// only at the top level (without recursing into constructor arguments). + /// https://github.com/elm/compiler/blob/047d5026fe6547c842db65f7196fed3f0b4743ee/compiler/src/Nitpick/PatternMatches.hs#L397-L475 + /// http://moscova.inria.fr/~maranget/papers/warn/index.html pub fn check_exhaustiveness( &mut self, unchecked_patterns: &[&TypedPattern], @@ -1451,8 +1451,19 @@ impl<'a> Environment<'a> { if matrix.is_useful(&pattern_stack) { matrix.push(pattern_stack); } else { + let index = matrix + .flatten() + .into_iter() + .enumerate() + .find(|(_, p)| p == pattern_stack.head()) + .map(|(i, _)| i) + .expect("should find index"); + + let typed_pattern = unchecked_patterns[index]; + return Err(Error::RedundantMatchClause { - location: unchecked_pattern.location(), + original: typed_pattern.location(), + redundant: unchecked_pattern.location(), }); } } diff --git a/crates/aiken-lang/src/tipo/error.rs b/crates/aiken-lang/src/tipo/error.rs index 518a2b14..7a3090c8 100644 --- a/crates/aiken-lang/src/tipo/error.rs +++ b/crates/aiken-lang/src/tipo/error.rs @@ -543,17 +543,19 @@ Maybe you meant to turn it public using the '{keyword_pub}' keyword?"# #[error( "{}\n", format!( - "I discovered a '{keyword_when}/{keyword_is}' expression with a redundant clause.", + "I discovered a '{keyword_when}/{keyword_is}' expression with a redundant pattern.", 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."))] + #[diagnostic(help("Double check these patterns and then remove one of the clauses."))] RedundantMatchClause { - #[label] - location: Span, + #[label("first found here")] + original: Span, + #[label("redundant")] + redundant: Span, }, #[error("I couldn't figure out the type of a record you're trying to access.\n")] diff --git a/crates/aiken-lang/src/tipo/exhaustive.rs b/crates/aiken-lang/src/tipo/exhaustive.rs index 7d66b0dc..0f444fb1 100644 --- a/crates/aiken-lang/src/tipo/exhaustive.rs +++ b/crates/aiken-lang/src/tipo/exhaustive.rs @@ -41,7 +41,7 @@ impl PatternStack { self.0.insert(index, element); } - fn head(&self) -> &Pattern { + pub(super) fn head(&self) -> &Pattern { &self.0[0] } @@ -385,7 +385,7 @@ pub(crate) enum Complete { No, } -#[derive(Debug, Clone)] +#[derive(Debug, Clone, PartialEq)] pub(crate) enum Pattern { Wildcard, Literal(Literal),