diff --git a/crates/nu-command/src/dataframe/values/nu_dataframe/mod.rs b/crates/nu-command/src/dataframe/values/nu_dataframe/mod.rs index d6227b7135..b3b0d949e1 100644 --- a/crates/nu-command/src/dataframe/values/nu_dataframe/mod.rs +++ b/crates/nu-command/src/dataframe/values/nu_dataframe/mod.rs @@ -316,7 +316,7 @@ impl NuDataFrame { let column = conversion::create_column(&series, row, row + 1, span)?; if column.len() == 0 { - Err(ShellError::AccessBeyondEnd(series.len(), span)) + Err(ShellError::AccessEmptyContent(span)) } else { let value = column .into_iter() diff --git a/crates/nu-command/src/filters/update.rs b/crates/nu-command/src/filters/update.rs index 3fd449327a..5087e68f3d 100644 --- a/crates/nu-command/src/filters/update.rs +++ b/crates/nu-command/src/filters/update.rs @@ -138,6 +138,8 @@ fn update( for idx in 0..*val { if let Some(v) = input.next() { pre_elems.push(v); + } else if idx == 0 { + return Err(ShellError::AccessEmptyContent(*span)); } else { return Err(ShellError::AccessBeyondEnd(idx - 1, *span)); } diff --git a/crates/nu-command/tests/commands/get.rs b/crates/nu-command/tests/commands/get.rs index 81442f537c..693bd0967d 100644 --- a/crates/nu-command/tests/commands/get.rs +++ b/crates/nu-command/tests/commands/get.rs @@ -199,11 +199,17 @@ fn errors_fetching_by_index_out_of_bounds() { "# )); - assert!(actual.err.contains("Row number too large (max: 3)"),); + assert!(actual.err.contains("Row number too large (max: 2)"),); assert!(actual.err.contains("too large"),); }) } +#[test] +fn errors_fetching_by_accessing_empty_list() { + let actual = nu!(cwd: ".", pipeline(r#"[] | get 3"#)); + assert!(actual.err.contains("Row number too large (empty content)"),); +} + #[test] fn quoted_column_access() { let actual = nu!( diff --git a/crates/nu-engine/src/call_ext.rs b/crates/nu-engine/src/call_ext.rs index 78a684b638..4e604ec9d3 100644 --- a/crates/nu-engine/src/call_ext.rs +++ b/crates/nu-engine/src/call_ext.rs @@ -90,9 +90,11 @@ impl CallExt for Call { if let Some(expr) = self.positional_nth(pos) { let result = eval_expression(engine_state, stack, expr)?; FromValue::from_value(&result) + } else if self.positional_len() == 0 { + Err(ShellError::AccessEmptyContent(self.head)) } else { Err(ShellError::AccessBeyondEnd( - self.positional_len(), + self.positional_len() - 1, self.head, )) } diff --git a/crates/nu-plugin/src/protocol/evaluated_call.rs b/crates/nu-plugin/src/protocol/evaluated_call.rs index b1dd2bd9e7..81adbc6357 100644 --- a/crates/nu-plugin/src/protocol/evaluated_call.rs +++ b/crates/nu-plugin/src/protocol/evaluated_call.rs @@ -96,9 +96,11 @@ impl EvaluatedCall { pub fn req(&self, pos: usize) -> Result { if let Some(value) = self.nth(pos) { FromValue::from_value(&value) + } else if self.positional.is_empty() { + Err(ShellError::AccessEmptyContent(self.head)) } else { Err(ShellError::AccessBeyondEnd( - self.positional.len(), + self.positional.len() - 1, self.head, )) } diff --git a/crates/nu-protocol/src/shell_error.rs b/crates/nu-protocol/src/shell_error.rs index 0f50e7d60f..a77850da87 100644 --- a/crates/nu-protocol/src/shell_error.rs +++ b/crates/nu-protocol/src/shell_error.rs @@ -358,6 +358,15 @@ Either make sure {0} is a string, or add a 'to_string' entry for it in ENV_CONVE #[diagnostic(code(nu::shell::access_beyond_end), url(docsrs))] AccessBeyondEnd(usize, #[label = "index too large (max: {0})"] Span), + /// You attempted to access an index when it's empty. + /// + /// ## Resolution + /// + /// Check your lengths and try again. + #[error("Row number too large (empty content).")] + #[diagnostic(code(nu::shell::access_beyond_end), url(docsrs))] + AccessEmptyContent(#[label = "index too large (empty content)"] Span), + /// You attempted to access an index beyond the available length of a stream. /// /// ## Resolution diff --git a/crates/nu-protocol/src/value/mod.rs b/crates/nu-protocol/src/value/mod.rs index 79f6554daa..5303cad8be 100644 --- a/crates/nu-protocol/src/value/mod.rs +++ b/crates/nu-protocol/src/value/mod.rs @@ -641,8 +641,10 @@ impl Value { Value::List { vals: val, .. } => { if let Some(item) = val.get(*count) { current = item.clone(); + } else if val.is_empty() { + return Err(ShellError::AccessEmptyContent(*origin_span)) } else { - return Err(ShellError::AccessBeyondEnd(val.len(), *origin_span)); + return Err(ShellError::AccessBeyondEnd(val.len() - 1, *origin_span)); } } Value::Binary { val, .. } => { @@ -651,8 +653,10 @@ impl Value { val: *item as i64, span: *origin_span, }; + } else if val.is_empty() { + return Err(ShellError::AccessEmptyContent(*origin_span)) } else { - return Err(ShellError::AccessBeyondEnd(val.len(), *origin_span)); + return Err(ShellError::AccessBeyondEnd(val.len() - 1, *origin_span)); } } Value::Range { val, .. } => { @@ -839,8 +843,10 @@ impl Value { Value::List { vals, .. } => { if let Some(v) = vals.get_mut(*row_num) { v.upsert_data_at_cell_path(&cell_path[1..], new_val)? + } else if vals.is_empty() { + return Err(ShellError::AccessEmptyContent(*span)); } else { - return Err(ShellError::AccessBeyondEnd(vals.len(), *span)); + return Err(ShellError::AccessBeyondEnd(vals.len() - 1, *span)); } } v => return Err(ShellError::NotAList(*span, v.span()?)), @@ -931,8 +937,10 @@ impl Value { Value::List { vals, .. } => { if let Some(v) = vals.get_mut(*row_num) { v.update_data_at_cell_path(&cell_path[1..], new_val)? + } else if vals.is_empty() { + return Err(ShellError::AccessEmptyContent(*span)); } else { - return Err(ShellError::AccessBeyondEnd(vals.len(), *span)); + return Err(ShellError::AccessBeyondEnd(vals.len() - 1, *span)); } } v => return Err(ShellError::NotAList(*span, v.span()?)), @@ -1005,8 +1013,10 @@ impl Value { if vals.get_mut(*row_num).is_some() { vals.remove(*row_num); Ok(()) + } else if vals.is_empty() { + Err(ShellError::AccessEmptyContent(*span)) } else { - Err(ShellError::AccessBeyondEnd(vals.len(), *span)) + Err(ShellError::AccessBeyondEnd(vals.len() - 1, *span)) } } v => Err(ShellError::NotAList(*span, v.span()?)), @@ -1069,8 +1079,10 @@ impl Value { Value::List { vals, .. } => { if let Some(v) = vals.get_mut(*row_num) { v.remove_data_at_cell_path(&cell_path[1..]) + } else if vals.is_empty() { + Err(ShellError::AccessEmptyContent(*span)) } else { - Err(ShellError::AccessBeyondEnd(vals.len(), *span)) + Err(ShellError::AccessBeyondEnd(vals.len() - 1, *span)) } } v => Err(ShellError::NotAList(*span, v.span()?)), @@ -1157,8 +1169,10 @@ impl Value { Value::List { vals, .. } => { if let Some(v) = vals.get_mut(*row_num) { v.insert_data_at_cell_path(&cell_path[1..], new_val)? + } else if vals.is_empty() { + return Err(ShellError::AccessEmptyContent(*span)); } else { - return Err(ShellError::AccessBeyondEnd(vals.len(), *span)); + return Err(ShellError::AccessBeyondEnd(vals.len() - 1, *span)); } } v => return Err(ShellError::NotAList(*span, v.span()?)),