enable flag value type checking (#11311)

# Description
Fixes: #11310

# User-Facing Changes
After the change, the following code will go to error:
```nushell
> def a [--x: int = 3] { "aa" }
> let y = "aa"
> a --x=$y
Error: nu::parser::type_mismatch

  × Type mismatch.
   ╭─[entry #32:2:1]
 2 │ let y = "aa"
 3 │ a --x=$y
   ·       ─┬
   ·        ╰── expected int, found string
   ╰────
```
This commit is contained in:
WindSoilder 2023-12-20 18:07:19 +08:00 committed by GitHub
parent 1cecb37628
commit 697f3c03f1
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 59 additions and 23 deletions

View File

@ -344,6 +344,37 @@ pub fn parse_external_call(
} }
} }
fn ensure_flag_arg_type(
working_set: &mut StateWorkingSet,
arg_name: String,
arg: Expression,
arg_shape: &SyntaxShape,
long_name_span: Span,
) -> (Spanned<String>, Expression) {
if !type_compatible(&arg.ty, &arg_shape.to_type()) {
working_set.error(ParseError::TypeMismatch(
arg_shape.to_type(),
arg.ty,
arg.span,
));
(
Spanned {
item: arg_name,
span: long_name_span,
},
Expression::garbage(arg.span),
)
} else {
(
Spanned {
item: arg_name,
span: long_name_span,
},
arg,
)
}
}
fn parse_long_flag( fn parse_long_flag(
working_set: &mut StateWorkingSet, working_set: &mut StateWorkingSet,
spans: &[Span], spans: &[Span],
@ -368,25 +399,21 @@ fn parse_long_flag(
span.start += long_name_len + 3; //offset by long flag and '=' span.start += long_name_len + 3; //offset by long flag and '='
let arg = parse_value(working_set, span, arg_shape); let arg = parse_value(working_set, span, arg_shape);
let (arg_name, val_expression) = ensure_flag_arg_type(
( working_set,
Some(Spanned { long_name,
item: long_name, arg,
span: Span::new(arg_span.start, arg_span.start + long_name_len + 2), arg_shape,
}), Span::new(arg_span.start, arg_span.start + long_name_len + 2),
Some(arg), );
) (Some(arg_name), Some(val_expression))
} else if let Some(arg) = spans.get(*spans_idx + 1) { } else 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);
*spans_idx += 1; *spans_idx += 1;
( let (arg_name, val_expression) =
Some(Spanned { ensure_flag_arg_type(working_set, long_name, arg, arg_shape, arg_span);
item: long_name, (Some(arg_name), Some(val_expression))
span: arg_span,
}),
Some(arg),
)
} else { } else {
working_set.error(ParseError::MissingFlagParam( working_set.error(ParseError::MissingFlagParam(
arg_shape.to_string(), arg_shape.to_string(),
@ -411,13 +438,14 @@ fn parse_long_flag(
let arg = parse_value(working_set, span, &SyntaxShape::Boolean); let arg = parse_value(working_set, span, &SyntaxShape::Boolean);
( let (arg_name, val_expression) = ensure_flag_arg_type(
Some(Spanned { working_set,
item: long_name, long_name,
span: Span::new(arg_span.start, arg_span.start + long_name_len + 2), arg,
}), &SyntaxShape::Boolean,
Some(arg), Span::new(arg_span.start, arg_span.start + long_name_len + 2),
) );
(Some(arg_name), Some(val_expression))
} else { } else {
( (
Some(Spanned { Some(Spanned {

View File

@ -73,6 +73,14 @@ fn custom_switch1() -> TestResult {
) )
} }
#[test]
fn custom_flag_with_type_checking() -> TestResult {
fail_test(
r#"def florb [--dry-run: int] { $dry_run }; let y = "3"; florb --dry-run=$y"#,
"type_mismatch",
)
}
#[test] #[test]
fn custom_switch2() -> TestResult { fn custom_switch2() -> TestResult {
run_test( run_test(
@ -116,7 +124,7 @@ fn custom_flag1() -> TestResult {
r#"def florb [ r#"def florb [
--age: int = 0 --age: int = 0
--name = "foobar" --name = "foobar"
] { ] {
($age | into string) + $name ($age | into string) + $name
} }
florb"#, florb"#,