diff --git a/crates/nu-parser/src/parser.rs b/crates/nu-parser/src/parser.rs index cc82bde3b3e6..1aee66d786b7 100644 --- a/crates/nu-parser/src/parser.rs +++ b/crates/nu-parser/src/parser.rs @@ -5894,25 +5894,44 @@ pub fn discover_captures_in_expr( if let Some(block_id) = decl.get_block_id() { match seen_blocks.get(&block_id) { Some(capture_list) => { - output.extend(capture_list); + // Push captures onto the outer closure that aren't created by that outer closure + for capture in capture_list { + if !seen.contains(&capture.0) { + output.push(*capture); + } + } } None => { let block = working_set.get_block(block_id); if !block.captures.is_empty() { - output.extend(block.captures.iter().map(|var_id| (*var_id, call.head))); + for capture in &block.captures { + if !seen.contains(capture) { + output.push((*capture, call.head)); + } + } } else { - let mut seen = vec![]; - seen_blocks.insert(block_id, output.clone()); - - let mut result = vec![]; - discover_captures_in_closure( - working_set, - block, - &mut seen, - seen_blocks, - &mut result, - )?; - output.extend(&result); + let result = { + let mut seen = vec![]; + seen_blocks.insert(block_id, output.clone()); + + let mut result = vec![]; + discover_captures_in_closure( + working_set, + block, + &mut seen, + seen_blocks, + &mut result, + )?; + + result + }; + // Push captures onto the outer closure that aren't created by that outer closure + for capture in &result { + if !seen.contains(&capture.0) { + output.push(*capture); + } + } + seen_blocks.insert(block_id, result); } } diff --git a/src/tests/test_parser.rs b/src/tests/test_parser.rs index 6aec8c851731..24ce15b00163 100644 --- a/src/tests/test_parser.rs +++ b/src/tests/test_parser.rs @@ -655,3 +655,13 @@ fn def_with_in_var_mut_2() -> TestResult { "3", ) } + +#[test] +fn properly_nest_captures() -> TestResult { + run_test(r#"do { let b = 3; def c [] { $b }; c }"#, "3") +} + +#[test] +fn properly_nest_captures_call_first() -> TestResult { + run_test(r#"do { let b = 3; c; def c [] { $b }; c }"#, "3") +}