diff --git a/crates/nu-engine/src/eval.rs b/crates/nu-engine/src/eval.rs index cfa319d3e8..5168794e8a 100644 --- a/crates/nu-engine/src/eval.rs +++ b/crates/nu-engine/src/eval.rs @@ -61,13 +61,25 @@ pub fn eval_call( if let Some(arg) = call.positional_nth(param_idx) { let result = eval_expression(engine_state, caller_stack, arg)?; - if required && !result.get_type().is_subtype(¶m.shape.to_type()) { - return Err(ShellError::CantConvert { - to_type: param.shape.to_type().to_string(), - from_type: result.get_type().to_string(), - span: result.span(), - help: None, - }); + let param_type = param.shape.to_type(); + if required && !result.get_type().is_subtype(¶m_type) { + // need to check if result is an empty list, and param_type is table or list + // nushell needs to pass type checking for the case. + let empty_list_matches = result + .as_list() + .map(|l| { + l.is_empty() && matches!(param_type, Type::List(_) | Type::Table(_)) + }) + .unwrap_or(false); + + if !empty_list_matches { + return Err(ShellError::CantConvert { + to_type: param.shape.to_type().to_string(), + from_type: result.get_type().to_string(), + span: result.span(), + help: None, + }); + } } callee_stack.add_var(var_id, result); } else if let Some(value) = ¶m.default_value { diff --git a/src/tests/test_custom_commands.rs b/src/tests/test_custom_commands.rs index fe6f8dfa76..f42db73f99 100644 --- a/src/tests/test_custom_commands.rs +++ b/src/tests/test_custom_commands.rs @@ -229,6 +229,18 @@ fn type_check_for_during_eval2() -> TestResult { ) } +#[test] +fn empty_list_matches_list_type() -> TestResult { + let _ = run_test( + r#"def spam [foo: list] { echo $foo }; spam [] | length"#, + "0", + ); + run_test( + r#"def spam [foo: list] { echo $foo }; spam [] | length"#, + "0", + ) +} + #[test] fn path_argument_dont_auto_expand_if_single_quoted() -> TestResult { run_test("def spam [foo: path] { echo $foo }; spam '~/aa'", "~/aa")