Glob: don't allow implicit casting between glob and string (#11992)

# Description
As title, currently on latest main, nushell confused user if it allows
implicit casting between glob and string:
```nushell
let x = "*.txt"
def glob-test [g: glob] { open $g } 
glob-test $x
```
It always expand the glob although `$x` is defined as a string.
This pr implements a solution from @kubouch :
> We could make it really strict and disallow all autocasting between
globs and strings because that's what's causing the "magic" confusion.
Then, modify all builtins that accept globs to accept oneof(glob,
string) and the rules would be that globs always expand and strings
never expand

# User-Facing Changes
After this pr, user needs to use `into glob` to invoke `glob-test`, if
user pass a string variable:
```nushell
let x = "*.txt"
def glob-test [g: glob] { open $g } 
glob-test ($x | into glob)
```
Or else nushell will return an error.
```
 3 │ glob-test $x
   ·           ─┬
   ·            ╰── can't convert string to glob
```

# Tests + Formatting
Done

# After Submitting
Nan
This commit is contained in:
Wind
2024-02-28 23:05:35 +08:00
committed by GitHub
parent eaedb30a8c
commit 387328fe73
17 changed files with 87 additions and 19 deletions

View File

@ -1,7 +1,9 @@
use nu_engine::eval_block;
use nu_protocol::ast::Call;
use nu_protocol::engine::{Command, EngineState, Stack};
use nu_protocol::{Category, Example, PipelineData, ShellError, Signature, SyntaxShape, Type};
use nu_protocol::{
Category, Example, PipelineData, ShellError, Signature, SyntaxShape, Type, Value,
};
#[derive(Clone)]
pub struct Mut;
@ -69,10 +71,22 @@ impl Command for Mut {
call.redirect_stdout,
call.redirect_stderr,
)?;
let mut value = pipeline_data.into_value(call.head);
//println!("Adding: {:?} to {}", rhs, var_id);
// if given variable type is Glob, and our result is string
// then nushell need to convert from Value::String to Value::Glob
// it's assigned by demand, then it's not quoted, and it's required to expand
// if we pass it to other commands.
let var_type = &engine_state.get_var(var_id).ty;
let val_span = value.span();
match value {
Value::String { val, .. } if var_type == &Type::Glob => {
value = Value::glob(val, false, val_span);
}
_ => {}
}
stack.add_var(var_id, pipeline_data.into_value(call.head));
stack.add_var(var_id, value);
Ok(PipelineData::empty())
}