From a8b37820e86ca3a1951509214d898ae1cc480b6f Mon Sep 17 00:00:00 2001 From: KtorZ Date: Fri, 20 Sep 2024 15:07:23 +0200 Subject: [PATCH] Fix incorrect warning about unused variable when softcasting without explicit right-pattern. See note added in code for a rationale. --- CHANGELOG.md | 1 + crates/aiken-lang/src/tests/check.rs | 19 +++++++++++++++++ crates/aiken-lang/src/tipo/expr.rs | 31 +++++++++++++++++++++++++++- 3 files changed, 50 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 419ce771..4a40fcc6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,6 +13,7 @@ - **aiken-lang**: Fix formatter adding extra unnecessary newlines after literal lists clause values or assignments. @KtorZ - **aiken-lang**: Fix formatting of long multi-line if/is expressions. @KtorZ - **aiken-lang**: Fix extraneous white-space added by the formatter after multiline alternative patterns. @KtorZ +- **aiken-lang**: Fix incorrect warning about unused variable when softcasting without explicit right-pattern. @KtorZ - **uplc**: Fix cost-models for PlutusV1 & PlutusV2. @MicroProofs ### Removed diff --git a/crates/aiken-lang/src/tests/check.rs b/crates/aiken-lang/src/tests/check.rs index 26adb637..f338e9f7 100644 --- a/crates/aiken-lang/src/tests/check.rs +++ b/crates/aiken-lang/src/tests/check.rs @@ -3276,3 +3276,22 @@ fn wrong_arity_on_known_builtin() { Err((_, Error::IncorrectFunctionCallArity { .. })) )) } + +#[test] +fn softcasting_unused_let_binding() { + let source_code = r#" + pub fn is_int(data: Data) -> Bool { + if data is Int { + True + } else { + False + } + } + "#; + + let result = dbg!(check(parse(source_code))); + assert!(result.is_ok()); + + let (warnings, _) = result.unwrap(); + assert!(warnings.is_empty(), "should not contain any warnings"); +} diff --git a/crates/aiken-lang/src/tipo/expr.rs b/crates/aiken-lang/src/tipo/expr.rs index 8f8d0e26..dadd22a5 100644 --- a/crates/aiken-lang/src/tipo/expr.rs +++ b/crates/aiken-lang/src/tipo/expr.rs @@ -1388,7 +1388,36 @@ impl<'a, 'b> ExprTyper<'a, 'b> { // If `expect` is explicitly used, we still check exhaustiveness but instead of returning an // error we emit a warning which explains that using `expect` is unnecessary. match kind { - AssignmentKind::Is => (), + AssignmentKind::Is => { + let pattern_var_name = match pattern { + Pattern::Var { ref name, .. } => Some(name), + _ => None, + }; + + let value_var_name = match typed_value { + TypedExpr::Var { ref name, .. } => Some(name), + _ => None, + }; + + // In case where we have no explicit pattern, we end up introducing a new let + // binding with the same name as the value. However, the assigned value may not + // necessarily be used, resulting in an annoying warning when one only wants to + // assert a type. + // + // if foo is Int { // foo is unused here but shouldn't generated warnings. + // True + // } else { + // False + // } + // + // The following check removes the warning by marking the new let-binding as used + // in this particular context. + if let Some(pattern_var_name) = pattern_var_name { + if Some(pattern_var_name) == value_var_name { + self.environment.increment_usage(pattern_var_name); + } + } + } AssignmentKind::Let { .. } => { self.environment .check_exhaustiveness(&[&pattern], location, true)?