fix: use a distinct warning for discarded let assignments to avoid confusion closes #763

This commit is contained in:
rvcas 2023-11-27 21:23:10 -05:00
parent c2725abcea
commit 2980e8e21d
No known key found for this signature in database
GPG Key ID: C09B64E263F7D68C
4 changed files with 33 additions and 5 deletions

View File

@ -1191,7 +1191,7 @@ fn discarded_let_bindings() {
let (warnings, ast) = check(parse(source_code)).unwrap(); let (warnings, ast) = check(parse(source_code)).unwrap();
assert!(matches!(warnings[0], Warning::UnusedVariable { ref name, .. } if name == "unused")); assert!(matches!(warnings[0], Warning::UnusedVariable { ref name, .. } if name == "unused"));
assert!(matches!(warnings[1], Warning::UnusedVariable { ref name, .. } if name == "_")); assert!(matches!(warnings[1], Warning::DiscardedLetAssignment { ref name, .. } if name == "_"));
// Controls that unused let-bindings have been erased from the transformed AST. // Controls that unused let-bindings have been erased from the transformed AST.
match ast.definitions.first() { match ast.definitions.first() {

View File

@ -1535,6 +1535,28 @@ pub enum Warning {
name: String, name: String,
}, },
#[error(
"I came across a discarded variable in a let assignment: {}.\n",
name.if_supports_color(Stderr, |s| s.purple())
)]
#[diagnostic(help("{}", formatdoc! {
r#"If you do want to enforce some side-effects, use {keyword_expect} with {name} instead of {keyword_let}.
You should also know that, unlike in typical imperative languages, unused let-bindings are {fully_ignored} in Aiken.
They will not produce any side-effect (such as error calls). Programs with or without unused variables are semantically equivalent.
"#,
fully_ignored = "fully_ignored".if_supports_color(Stderr, |s| s.bold()),
keyword_expect = "expect".if_supports_color(Stderr, |s| s.yellow()),
keyword_let = "let".if_supports_color(Stderr, |s| s.yellow()),
name = name.if_supports_color(Stderr, |s| s.yellow())
}))]
#[diagnostic(code("unused::discarded_let_assignment"))]
DiscardedLetAssignment {
#[label("discarded")]
location: Span,
name: String,
},
#[error( #[error(
"I came across a validator in a {} module which means\nI'm going to ignore it.\n", "I came across a validator in a {} module which means\nI'm going to ignore it.\n",
"lib/".if_supports_color(Stderr, |s| s.purple()) "lib/".if_supports_color(Stderr, |s| s.purple())
@ -1595,6 +1617,7 @@ impl ExtraData for Warning {
| Warning::UnusedPrivateModuleConstant { .. } | Warning::UnusedPrivateModuleConstant { .. }
| Warning::UnusedType { .. } | Warning::UnusedType { .. }
| Warning::UnusedVariable { .. } | Warning::UnusedVariable { .. }
| Warning::DiscardedLetAssignment { .. }
| Warning::Utf8ByteArrayIsValidHexString { .. } | Warning::Utf8ByteArrayIsValidHexString { .. }
| Warning::ValidatorInLibraryModule { .. } => None, | Warning::ValidatorInLibraryModule { .. } => None,
Warning::UnusedImportedModule { location, .. } => { Warning::UnusedImportedModule { location, .. } => {

View File

@ -1707,7 +1707,8 @@ impl<'a, 'b> ExprTyper<'a, 'b> {
.warnings .warnings
.iter() .iter()
.filter_map(|w| match w { .filter_map(|w| match w {
Warning::UnusedVariable { location, .. } => Some(*location), Warning::UnusedVariable { location, .. }
| Warning::DiscardedLetAssignment { location, .. } => Some(*location),
_ => None, _ => None,
}) })
.collect::<Vec<_>>(); .collect::<Vec<_>>();

View File

@ -10,7 +10,7 @@ use itertools::Itertools;
use super::{ use super::{
environment::{assert_no_labeled_arguments, collapse_links, EntityKind, Environment}, environment::{assert_no_labeled_arguments, collapse_links, EntityKind, Environment},
error::Error, error::{Error, Warning},
hydrator::Hydrator, hydrator::Hydrator,
PatternConstructor, Type, ValueConstructorVariant, PatternConstructor, Type, ValueConstructorVariant,
}; };
@ -150,7 +150,11 @@ impl<'a, 'b> PatternTyper<'a, 'b> {
if is_assignment { if is_assignment {
// Register declaration for the unused variable detection // Register declaration for the unused variable detection
self.environment self.environment
.init_usage(name.to_string(), EntityKind::Variable, location); .warnings
.push(Warning::DiscardedLetAssignment {
name: name.clone(),
location,
});
}; };
Ok(Pattern::Discard { name, location }) Ok(Pattern::Discard { name, location })
} }