diff --git a/crates/nu-engine/src/eval_ir.rs b/crates/nu-engine/src/eval_ir.rs index b3c6d0d0d8..802f58e249 100644 --- a/crates/nu-engine/src/eval_ir.rs +++ b/crates/nu-engine/src/eval_ir.rs @@ -1159,6 +1159,7 @@ fn gather_arguments( // Arguments that didn't get consumed by required/optional let mut rest = vec![]; + let mut rest_span: Option = None; // If we encounter a spread, all further positionals should go to rest let mut always_spread = false; @@ -1178,12 +1179,19 @@ fn gather_arguments( } callee_stack.add_var(var_id, val); } else { + rest_span = Some(rest_span.map_or(val.span(), |s| s.append(val.span()))); rest.push(val); } } - Argument::Spread { vals, .. } => { + Argument::Spread { + vals, + span: spread_span, + .. + } => { if let Value::List { vals, .. } = vals { rest.extend(vals); + // Rest variable should span the spread syntax, not the list values + rest_span = Some(rest_span.map_or(spread_span, |s| s.append(spread_span))); // All further positional args should go to spread always_spread = true; } else if let Value::Error { error, .. } = vals { @@ -1218,7 +1226,7 @@ fn gather_arguments( // Add the collected rest of the arguments if a spread argument exists if let Some(rest_arg) = &block.signature.rest_positional { - let rest_span = rest.first().map(|v| v.span()).unwrap_or(call_head); + let rest_span = rest_span.unwrap_or(call_head); let var_id = expect_positional_var_id(rest_arg, rest_span)?; callee_stack.add_var(var_id, Value::list(rest, rest_span)); } diff --git a/tests/repl/test_engine.rs b/tests/repl/test_engine.rs index c7fca8b2e8..22d81f08cb 100644 --- a/tests/repl/test_engine.rs +++ b/tests/repl/test_engine.rs @@ -439,6 +439,14 @@ fn better_operator_spans() -> TestResult { ) } +#[test] +fn call_rest_arg_span() -> TestResult { + run_test( + r#"let l = [2, 3]; def foo [...rest] { metadata $rest | view span $in.span.start $in.span.end }; foo 1 ...$l"#, + "1 ...$l", + ) +} + #[test] fn range_right_exclusive() -> TestResult { run_test(r#"[1, 4, 5, 8, 9] | slice 1..<3 | math sum"#, "9")