Fix `let` binding in command leaks when error occurs
@@ -101,17 +101,14 @@ fn if_command(args: CommandArgs) -> Result<OutputStream, ShellError> {
//FIXME: should we use the scope that's brought in as well?
let condition = evaluate_baseline_expr(cond, &context);
- match condition {
+ let result = match condition {
Ok(condition) => match condition.as_bool() {
Ok(b) => {
- let result = if b {
+ if b {
run_block(&then_case.block, &context, input, external_redirection)
} else {
run_block(&else_case.block, &context, input, external_redirection)
- };
- context.scope.exit_scope();
-
- result
+ }
}
Err(e) => Ok(OutputStream::from_stream(
vec![UntaggedValue::Error(e).into_untagged_value()].into_iter(),
@@ -120,13 +117,16 @@ fn if_command(args: CommandArgs) -> Result<OutputStream, ShellError> {
Err(e) => Ok(OutputStream::from_stream(
vec![UntaggedValue::Error(e).into_untagged_value()].into_iter(),
)),
- }
+ };
+ context.scope.exit_scope();
+ result
}
#[cfg(test)]
mod tests {
use super::If;
use super::ShellError;
+ use nu_test_support::nu;
#[test]
fn examples_work_as_expected() -> Result<(), ShellError> {
@@ -134,4 +134,21 @@ mod tests {
test_examples(If {})
}
+
+ #[test]
+ fn if_doesnt_leak_on_error() {
+ let actual = nu!(
+ ".",
+ r#"
+ def test-leak [] {
+ let var = "hello"
+ if 0 == "" {echo ok} {echo not}
+ }
+ test-leak
+ echo $var
+ "#
+ );
+
+ assert!(actual.err.contains("unknown variable"));
+ }
}
