run ensure_flag_arg_type for short flag values (#14074)

Closes #13654

# User-Facing Changes

- Short flags are now fully type-checked,
  including null and record signatures for literal arguments:

```nushell
def test [-v: record<l: int>] {};
test -v null # error
test -v {l: ""} # error

def test2 [-v: int] {};
let v = ""
test2 -v $v # error
```

- `polars unpivot` `--index`/`--on` and `into value --columns`
now accept `list` values
This commit is contained in:
Solomon 2024-10-17 02:25:17 +00:00 committed by sholderbach
parent 3af575cce7
commit b0427ca9ff
4 changed files with 28 additions and 19 deletions

View File

@ -18,7 +18,7 @@ impl Command for IntoValue {
.input_output_types(vec![(Type::table(), Type::table())]) .input_output_types(vec![(Type::table(), Type::table())])
.named( .named(
"columns", "columns",
SyntaxShape::Table(vec![]), SyntaxShape::List(Box::new(SyntaxShape::Any)),
"list of columns to update", "list of columns to update",
Some('c'), Some('c'),
) )

View File

@ -1067,30 +1067,27 @@ pub fn parse_internal_call(
if let Some(arg_shape) = flag.arg { if let Some(arg_shape) = flag.arg {
if let Some(arg) = spans.get(spans_idx + 1) { if let Some(arg) = spans.get(spans_idx + 1) {
let arg = parse_value(working_set, *arg, &arg_shape); let arg = parse_value(working_set, *arg, &arg_shape);
let (arg_name, val_expression) = ensure_flag_arg_type(
working_set,
flag.long.clone(),
arg.clone(),
&arg_shape,
spans[spans_idx],
);
if flag.long.is_empty() { if flag.long.is_empty() {
if let Some(short) = flag.short { if let Some(short) = flag.short {
call.add_named(( call.add_named((
Spanned { arg_name,
item: String::new(),
span: spans[spans_idx],
},
Some(Spanned { Some(Spanned {
item: short.to_string(), item: short.to_string(),
span: spans[spans_idx], span: spans[spans_idx],
}), }),
Some(arg), Some(val_expression),
)); ));
} }
} else { } else {
call.add_named(( call.add_named((arg_name, None, Some(val_expression)));
Spanned {
item: flag.long.clone(),
span: spans[spans_idx],
},
None,
Some(arg),
));
} }
spans_idx += 1; spans_idx += 1;
} else { } else {

View File

@ -31,13 +31,13 @@ impl PluginCommand for UnpivotDF {
Signature::build(self.name()) Signature::build(self.name())
.required_named( .required_named(
"index", "index",
SyntaxShape::Table(vec![]), SyntaxShape::List(Box::new(SyntaxShape::Any)),
"column names for unpivoting", "column names for unpivoting",
Some('i'), Some('i'),
) )
.required_named( .required_named(
"on", "on",
SyntaxShape::Table(vec![]), SyntaxShape::List(Box::new(SyntaxShape::Any)),
"column names used as value columns", "column names used as value columns",
Some('o'), Some('o'),
) )

View File

@ -1,6 +1,7 @@
use crate::repl::tests::{fail_test, run_test, run_test_contains, TestResult}; use crate::repl::tests::{fail_test, run_test, run_test_contains, TestResult};
use nu_test_support::nu; use nu_test_support::nu;
use pretty_assertions::assert_eq; use pretty_assertions::assert_eq;
use rstest::rstest;
#[test] #[test]
fn no_scope_leak1() -> TestResult { fn no_scope_leak1() -> TestResult {
@ -73,10 +74,21 @@ fn custom_switch1() -> TestResult {
) )
} }
#[test] #[rstest]
fn custom_flag_with_type_checking() -> TestResult { fn custom_flag_with_type_checking(
#[values(
("int", "\"3\""),
("int", "null"),
("record<i: int>", "{i: \"\"}"),
("list<int>", "[\"\"]")
)]
type_sig_value: (&str, &str),
#[values("--dry-run", "-d")] flag: &str,
) -> TestResult {
let (type_sig, value) = type_sig_value;
fail_test( fail_test(
r#"def florb [--dry-run: int] { $dry_run }; let y = "3"; florb --dry-run=$y"#, &format!("def florb [{flag}: {type_sig}] {{}}; let y = {value}; florb {flag} $y"),
"type_mismatch", "type_mismatch",
) )
} }