fix panic when ..= syntax is used in stepped ranges (#16231)

Fixes #16185

# Description

Stepped range literals where `..=` precedes the second value no longer
cause a parser panic:

```diff
random int 1..=3..5
-Error:   x Main thread panicked.
-  |-> at crates/nu-protocol/src/engine/state_working_set.rs:400:48
-  `-> slice index starts at 8 but ends at 7
+Error: nu::parser::parse_mismatch
+
+  × Parse mismatch during operation.
+   ╭─[entry #1:1:15]
+ 1 │ random int 1..=3..5
+   ·               ─┬
+   ·                ╰── expected number
```
This commit is contained in:
Solomon
2025-07-30 21:38:59 +00:00
committed by GitHub
parent 7f2beb49db
commit 89c0e325fa
2 changed files with 20 additions and 2 deletions

View File

@ -1834,7 +1834,12 @@ pub fn parse_range(working_set: &mut StateWorkingSet, span: Span) -> Option<Expr
return None; return None;
} }
} else { } else {
let op_str = if token.contains("..=") { "..=" } else { ".." }; let op_str = if token[range_op_pos..].starts_with("..=") {
"..="
} else {
".."
};
let op_span = Span::new( let op_span = Span::new(
span.start + range_op_pos, span.start + range_op_pos,
span.start + range_op_pos + op_str.len(), span.start + range_op_pos + op_str.len(),

View File

@ -1,4 +1,5 @@
use crate::repl::tests::{TestResult, fail_test, run_test}; use crate::repl::tests::{TestResult, fail_test, run_test};
use rstest::rstest;
#[test] #[test]
fn int_in_inc_range() -> TestResult { fn int_in_inc_range() -> TestResult {
@ -47,7 +48,8 @@ fn zip_ranges() -> TestResult {
#[test] #[test]
fn int_in_stepped_range() -> TestResult { fn int_in_stepped_range() -> TestResult {
run_test(r#"7 in 1..3..15"#, "true") run_test(r#"7 in 1..3..15"#, "true")?;
run_test(r#"7 in 1..3..=15"#, "true")
} }
#[test] #[test]
@ -74,3 +76,14 @@ fn float_in_unbounded_stepped_range() -> TestResult {
fn float_not_in_unbounded_stepped_range() -> TestResult { fn float_not_in_unbounded_stepped_range() -> TestResult {
run_test(r#"2.1 in 1.2..3.."#, "false") run_test(r#"2.1 in 1.2..3.."#, "false")
} }
#[rstest]
#[case("1..=3..", "expected number")]
#[case("..=3..=15", "expected number")]
#[case("..=(..", "expected closing )")]
#[case("..=()..", "expected at least one range bound")]
#[case("..=..", "expected at least one range bound")]
#[test]
fn bad_range_syntax(#[case] input: &str, #[case] expect: &str) -> TestResult {
fail_test(&format!("def foo [r: range] {{}}; foo {input}"), expect)
}