From f747ee0aca9dd1a7a0dbd7889f3e11ccb5bc0655 Mon Sep 17 00:00:00 2001 From: KtorZ Date: Fri, 10 Feb 2023 10:34:49 +0100 Subject: [PATCH] Improve error message when finding a non-exhaustive let-binding. --- crates/aiken-lang/src/tipo/error.rs | 20 ++++++++++++++++---- crates/aiken-lang/src/tipo/expr.rs | 2 ++ 2 files changed, 18 insertions(+), 4 deletions(-) diff --git a/crates/aiken-lang/src/tipo/error.rs b/crates/aiken-lang/src/tipo/error.rs index c481ffbf..fba72b68 100644 --- a/crates/aiken-lang/src/tipo/error.rs +++ b/crates/aiken-lang/src/tipo/error.rs @@ -389,15 +389,26 @@ If you really meant to return that last expression, try to replace it with the f tipo: Arc, }, - #[error("I realized that a given 'when/is' expression is non-exhaustive.\n")] + #[error("{}\n", if *is_let { + "I noticed a let assignment matching a value with more than one constructor.".to_string() + } else { + format!( + "I realized that a given '{keyword_when}/{keyword_is}' expression is non-exhaustive.", + keyword_is = "is".purple(), + keyword_when = "when".purple() + ) + } + )] #[diagnostic(url("https://aiken-lang.org/language-tour/control-flow#matching"))] #[diagnostic(code("non_exhaustive_pattern_match"))] - #[diagnostic(help(r#"When clauses must be exhaustive -- that is, they must cover all possible cases of the type they match. While it is recommended to have an explicit branch for each constructor, you can also use the wildcard '{discard}' as a last branch to match any remaining result. + #[diagnostic(help(r#"Let bindings and when clauses must be exhaustive -- that is, they must cover all possible cases of the type they match. In {keyword_when}/{keyword_is} pattern-match, it is recommended to have an explicit branch for each constructor as it prevents future silly mistakes when adding new constructors to a type. However, you can also use the wildcard '{discard}' as a last branch to match any remaining result. -In this particular instance, the following cases are missing: +In this particular instance, the following cases are unmatched: {missing}"# , discard = "_".yellow() + , keyword_is = "is".purple() + , keyword_when = "when".purple() , missing = unmatched .iter() .map(|s| format!("─▶ {s}")) @@ -405,9 +416,10 @@ In this particular instance, the following cases are missing: .join("") ))] NotExhaustivePatternMatch { - #[label] + #[label("{}", if *is_let { "use when/is" } else { "non-exhaustive" })] location: Span, unmatched: Vec, + is_let: bool, }, #[error("I tripped over a call attempt on something that isn't a function.\n")] diff --git a/crates/aiken-lang/src/tipo/expr.rs b/crates/aiken-lang/src/tipo/expr.rs index cb745d35..c73c645d 100644 --- a/crates/aiken-lang/src/tipo/expr.rs +++ b/crates/aiken-lang/src/tipo/expr.rs @@ -889,6 +889,7 @@ impl<'a, 'b> ExprTyper<'a, 'b> { return Err(Error::NotExhaustivePatternMatch { location, unmatched, + is_let: true, }); } } else if !value_is_data @@ -2054,6 +2055,7 @@ impl<'a, 'b> ExprTyper<'a, 'b> { return Err(Error::NotExhaustivePatternMatch { location, unmatched, + is_let: false, }); }