From 948965d42fe8bde84e589c660ef9b73f15ee8469 Mon Sep 17 00:00:00 2001 From: 132ikl <132@ikl.sh> Date: Thu, 30 Jan 2025 07:47:22 -0500 Subject: [PATCH] Immediately return error if detected as pipeline input or positional argument (#14874) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit # Description This PR returns error values while checking pipeline input types and positional argument types. This should help return non-nested errors earlier and prevent confusing errors. The positional argument change is directly related to an example given on Discord. Before this PR, this is the error shown: ``` Error: nu::shell::cant_convert × Can't convert to record. ╭─[/home/rose/tmp/script.nu:23:5] 22 │ let entry = $in 23 │ ╭─▶ { 24 │ │ name: $entry, 25 │ │ details: { 26 │ │ context: $context 27 │ │ } 28 │ ├─▶ } · ╰──── can't convert error to record 29 │ } ╰──── ``` After this PR, this is the error shown: ``` Error: nu::shell::eval_block_with_input × Eval block failed with pipeline input ╭─[/home/rose/tmp/script.nu:23:5] 22 │ let entry = $in 23 │ ╭─▶ { 24 │ │ name: $entry, 25 │ │ details: { 26 │ │ context: $context 27 │ │ } 28 │ ├─▶ } · ╰──── source value 29 │ } ╰──── Error: nu::shell::type_mismatch × Type mismatch. ╭─[/home/rose/tmp/much.nu:3:38] 2 │ $in | each { |elem| 3 │ print $elem.details.context.yaml.0 · ┬ · ╰── Can't access record values with a row index. Try specifying a column name instead 4 │ } | each { |elem| ╰──── ``` I'm not certain if the pipeline input error check actually can ever be triggered, but it seems to be a good defensive error handling strategy regardless. My addition of the `Value::Error` case in the first place would suggest it can be, but after looking at it more closely the error that caused me to add the case in the first place was actually unrelated to input typechecking. Additionally, this PR does not affect the handling of nested errors, so something like: ```nushell try { ... } catch {|e| $e | reject raw | to nuon } ``` works the same before and after this PR. # User-Facing Changes Errors values detected as arguments to commands or as pipeline input to commands are immediately thrown, rather than passed to the command. # Tests + Formatting - :green_circle: `toolkit fmt` - :green_circle: `toolkit clippy` - :green_circle: `toolkit test` - :green_circle: `toolkit test stdlib` # After Submitting N/A --- crates/nu-engine/src/eval_ir.rs | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/crates/nu-engine/src/eval_ir.rs b/crates/nu-engine/src/eval_ir.rs index 035f6a394d..4cc8cef782 100644 --- a/crates/nu-engine/src/eval_ir.rs +++ b/crates/nu-engine/src/eval_ir.rs @@ -1251,15 +1251,15 @@ fn gather_arguments( /// Type check helper. Produces `CantConvert` error if `val` is not compatible with `ty`. fn check_type(val: &Value, ty: &Type) -> Result<(), ShellError> { - if val.is_subtype_of(ty) { - Ok(()) - } else { - Err(ShellError::CantConvert { + match val { + Value::Error { error, .. } => Err(*error.clone()), + _ if val.is_subtype_of(ty) => Ok(()), + _ => Err(ShellError::CantConvert { to_type: ty.to_string(), from_type: val.get_type().to_string(), span: val.span(), help: None, - }) + }), } } @@ -1284,12 +1284,12 @@ fn check_input_types( _ => (), } - // Errors and custom values bypass input type checking - if matches!( - input, - PipelineData::Value(Value::Error { .. } | Value::Custom { .. }, ..) - ) { - return Ok(()); + match input { + // early return error directly if detected + PipelineData::Value(Value::Error { error, .. }, ..) => return Err(*error.clone()), + // bypass run-time typechecking for custom types + PipelineData::Value(Value::Custom { .. }, ..) => return Ok(()), + _ => (), } // Check if the input type is compatible with *any* of the command's possible input types