mirror of
https://github.com/nushell/nushell.git
synced 2025-08-10 00:57:49 +02:00
Box ShellError
in Value::Error
(#8375)
# Description Our `ShellError` at the moment has a `std::mem::size_of<ShellError>` of 136 bytes (on AMD64). As a result `Value` directly storing the struct also required 136 bytes (thanks to alignment requirements). This change stores the `Value::Error` `ShellError` on the heap. Pro: - Value now needs just 80 bytes - Should be 1 cacheline less (still at least 2 cachelines) Con: - More small heap allocations when dealing with `Value::Error` - More heap fragmentation - Potential for additional required memcopies # Further code changes Includes a small refactor of `try` due to a type mismatch in its large match. # User-Facing Changes None for regular users. Plugin authors may have to update their matches on `Value` if they use `nu-protocol` Needs benchmarking to see if there is a benefit in real world workloads. **Update** small improvements in runtime for workloads with high volume of values. Significant reduction in maximum resident set size, when many values are held in memory. # Tests + Formatting
This commit is contained in:
committed by
GitHub
parent
c26d91fb61
commit
a52386e837
@ -90,7 +90,8 @@ fn action(
|
||||
"binhex" => GeneralPurpose::new(&alphabet::BIN_HEX, NO_PAD),
|
||||
"crypt" => GeneralPurpose::new(&alphabet::CRYPT, NO_PAD),
|
||||
"mutf7" => GeneralPurpose::new(&alphabet::IMAP_MUTF7, NO_PAD),
|
||||
not_valid => return Value::Error { error:ShellError::GenericError(
|
||||
not_valid => return Value::Error { error:
|
||||
Box::new(ShellError::GenericError(
|
||||
"value is not an accepted character set".to_string(),
|
||||
format!(
|
||||
"{not_valid} is not a valid character-set.\nPlease use `help encode base64` to see a list of valid character sets."
|
||||
@ -98,7 +99,7 @@ fn action(
|
||||
Some(config_character_set.span),
|
||||
None,
|
||||
Vec::new(),
|
||||
)}
|
||||
))}
|
||||
};
|
||||
match input {
|
||||
// Propagate existing errors.
|
||||
@ -111,13 +112,13 @@ fn action(
|
||||
Ok(bytes_written) => bytes_written,
|
||||
Err(err) => {
|
||||
return Value::Error {
|
||||
error: ShellError::GenericError(
|
||||
error: Box::new(ShellError::GenericError(
|
||||
"Error encoding data".into(),
|
||||
err.to_string(),
|
||||
Some(Span::unknown()),
|
||||
None,
|
||||
Vec::new(),
|
||||
),
|
||||
)),
|
||||
}
|
||||
}
|
||||
};
|
||||
@ -125,13 +126,13 @@ fn action(
|
||||
Value::string(std::str::from_utf8(&enc_vec).unwrap_or(""), command_span)
|
||||
}
|
||||
ActionType::Decode => Value::Error {
|
||||
error: ShellError::UnsupportedInput(
|
||||
error: Box::new(ShellError::UnsupportedInput(
|
||||
"Binary data can only be encoded".to_string(),
|
||||
"value originates from here".into(),
|
||||
command_span,
|
||||
// This line requires the Value::Error {} match above.
|
||||
input.expect_span(),
|
||||
),
|
||||
)),
|
||||
},
|
||||
},
|
||||
Value::String {
|
||||
@ -158,20 +159,20 @@ fn action(
|
||||
match String::from_utf8(decoded_value) {
|
||||
Ok(string_value) => Value::string(string_value, command_span),
|
||||
Err(e) => Value::Error {
|
||||
error: ShellError::GenericError(
|
||||
error: Box::new(ShellError::GenericError(
|
||||
"base64 payload isn't a valid utf-8 sequence"
|
||||
.to_owned(),
|
||||
e.to_string(),
|
||||
Some(*value_span),
|
||||
Some("consider using the `--binary` flag".to_owned()),
|
||||
Vec::new(),
|
||||
),
|
||||
)),
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
Err(_) => Value::Error {
|
||||
error: ShellError::GenericError(
|
||||
error: Box::new(ShellError::GenericError(
|
||||
"value could not be base64 decoded".to_string(),
|
||||
format!(
|
||||
"invalid base64 input for character set {}",
|
||||
@ -180,17 +181,17 @@ fn action(
|
||||
Some(command_span),
|
||||
None,
|
||||
Vec::new(),
|
||||
),
|
||||
)),
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
other => Value::Error {
|
||||
error: ShellError::TypeMismatch {
|
||||
error: Box::new(ShellError::TypeMismatch {
|
||||
err_message: format!("string or binary, not {}", other.get_type()),
|
||||
span: other.span().unwrap_or(command_span),
|
||||
},
|
||||
}),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
@ -77,7 +77,7 @@ documentation link at https://docs.rs/encoding_rs/latest/encoding_rs/#statics"#
|
||||
PipelineData::Value(v, ..) => match v {
|
||||
Value::Binary { val: bytes, .. } => super::encoding::decode(head, encoding, &bytes)
|
||||
.map(|val| val.into_pipeline_data()),
|
||||
Value::Error { error } => Err(error),
|
||||
Value::Error { error } => Err(*error),
|
||||
_ => Err(ShellError::OnlySupportsThisInputType {
|
||||
exp_input_type: "binary".into(),
|
||||
wrong_type: v.get_type().to_string(),
|
||||
|
@ -100,7 +100,7 @@ documentation link at https://docs.rs/encoding_rs/latest/encoding_rs/#statics"#
|
||||
super::encoding::encode(head, encoding, &s, span, ignore_errors)
|
||||
.map(|val| val.into_pipeline_data())
|
||||
}
|
||||
Value::Error { error } => Err(error),
|
||||
Value::Error { error } => Err(*error),
|
||||
_ => Err(ShellError::OnlySupportsThisInputType {
|
||||
exp_input_type: "string".into(),
|
||||
wrong_type: v.get_type().to_string(),
|
||||
|
@ -230,7 +230,7 @@ fn format(
|
||||
}
|
||||
}
|
||||
}
|
||||
Value::Error { error } => return Err(error.clone()),
|
||||
Value::Error { error } => return Err(*error.clone()),
|
||||
_ => {
|
||||
return Err(ShellError::OnlySupportsThisInputType {
|
||||
exp_input_type: "record".to_string(),
|
||||
@ -249,7 +249,7 @@ fn format(
|
||||
}
|
||||
// Unwrapping this ShellError is a bit unfortunate.
|
||||
// Ideally, its Span would be preserved.
|
||||
Value::Error { error } => Err(error),
|
||||
Value::Error { error } => Err(*error),
|
||||
_ => Err(ShellError::OnlySupportsThisInputType {
|
||||
exp_input_type: "record".to_string(),
|
||||
wrong_type: data_as_value.get_type().to_string(),
|
||||
|
@ -106,12 +106,12 @@ fn format_value_impl(val: &Value, arg: &Arguments, span: Span) -> Value {
|
||||
},
|
||||
Value::Error { .. } => val.clone(),
|
||||
_ => Value::Error {
|
||||
error: ShellError::OnlySupportsThisInputType {
|
||||
error: Box::new(ShellError::OnlySupportsThisInputType {
|
||||
exp_input_type: "filesize".into(),
|
||||
wrong_type: val.get_type().to_string(),
|
||||
dst_span: span,
|
||||
src_span: val.expect_span(),
|
||||
},
|
||||
}),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
@ -346,11 +346,11 @@ impl Iterator for ParseStreamer {
|
||||
&mut self.excess,
|
||||
),
|
||||
Err(_) => Some(Value::Error {
|
||||
error: ShellError::PipelineMismatch {
|
||||
error: Box::new(ShellError::PipelineMismatch {
|
||||
exp_input_type: "string".into(),
|
||||
dst_span: self.span,
|
||||
src_span: v.span().unwrap_or(self.span),
|
||||
},
|
||||
}),
|
||||
}),
|
||||
}
|
||||
} else {
|
||||
@ -386,15 +386,17 @@ impl Iterator for ParseStreamerExternal {
|
||||
&mut self.excess,
|
||||
),
|
||||
Err(_) => Some(Value::Error {
|
||||
error: ShellError::PipelineMismatch {
|
||||
error: Box::new(ShellError::PipelineMismatch {
|
||||
exp_input_type: "string".into(),
|
||||
dst_span: self.span,
|
||||
src_span: self.span,
|
||||
},
|
||||
}),
|
||||
}),
|
||||
}
|
||||
} else if let Some(Err(err)) = v {
|
||||
Some(Value::Error { error: err })
|
||||
Some(Value::Error {
|
||||
error: Box::new(err),
|
||||
})
|
||||
} else {
|
||||
None
|
||||
}
|
||||
@ -416,13 +418,13 @@ fn stream_helper(
|
||||
Ok(c) => c,
|
||||
Err(e) => {
|
||||
return Some(Value::Error {
|
||||
error: ShellError::GenericError(
|
||||
error: Box::new(ShellError::GenericError(
|
||||
"Error with regular expression captures".into(),
|
||||
e.to_string(),
|
||||
None,
|
||||
None,
|
||||
Vec::new(),
|
||||
),
|
||||
)),
|
||||
})
|
||||
}
|
||||
};
|
||||
|
@ -124,18 +124,18 @@ fn size(
|
||||
move |v| {
|
||||
// First, obtain the span. If this fails, propagate the error that results.
|
||||
let value_span = match v.span() {
|
||||
Err(v) => return Value::Error { error: v },
|
||||
Err(v) => return Value::Error { error: Box::new(v) },
|
||||
Ok(v) => v,
|
||||
};
|
||||
// Now, check if it's a string.
|
||||
match v.as_string() {
|
||||
Ok(s) => counter(&s, span),
|
||||
Err(_) => Value::Error {
|
||||
error: ShellError::PipelineMismatch {
|
||||
error: Box::new(ShellError::PipelineMismatch {
|
||||
exp_input_type: "string".into(),
|
||||
dst_span: span,
|
||||
src_span: value_span,
|
||||
},
|
||||
}),
|
||||
},
|
||||
}
|
||||
},
|
||||
|
@ -110,15 +110,17 @@ fn split_chars_helper(v: &Value, name: Span, graphemes: bool) -> Vec<Value> {
|
||||
}
|
||||
} else {
|
||||
vec![Value::Error {
|
||||
error: ShellError::PipelineMismatch {
|
||||
error: Box::new(ShellError::PipelineMismatch {
|
||||
exp_input_type: "string".into(),
|
||||
dst_span: name,
|
||||
src_span: v_span,
|
||||
},
|
||||
}),
|
||||
}]
|
||||
}
|
||||
}
|
||||
Err(error) => vec![Value::Error { error }],
|
||||
Err(error) => vec![Value::Error {
|
||||
error: Box::new(error),
|
||||
}],
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -182,13 +182,15 @@ fn split_column_helper(
|
||||
} else {
|
||||
match v.span() {
|
||||
Ok(span) => vec![Value::Error {
|
||||
error: ShellError::PipelineMismatch {
|
||||
error: Box::new(ShellError::PipelineMismatch {
|
||||
exp_input_type: "string".into(),
|
||||
dst_span: head,
|
||||
src_span: span,
|
||||
},
|
||||
}),
|
||||
}],
|
||||
Err(error) => vec![Value::Error {
|
||||
error: Box::new(error),
|
||||
}],
|
||||
Err(error) => vec![Value::Error { error }],
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -132,15 +132,17 @@ fn split_row_helper(
|
||||
}
|
||||
} else {
|
||||
vec![Value::Error {
|
||||
error: ShellError::PipelineMismatch {
|
||||
error: Box::new(ShellError::PipelineMismatch {
|
||||
exp_input_type: "string".into(),
|
||||
dst_span: name,
|
||||
src_span: v_span,
|
||||
},
|
||||
}),
|
||||
}]
|
||||
}
|
||||
}
|
||||
Err(error) => vec![Value::Error { error }],
|
||||
Err(error) => vec![Value::Error {
|
||||
error: Box::new(error),
|
||||
}],
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -185,15 +185,17 @@ fn split_words_helper(
|
||||
.collect::<Vec<Value>>()
|
||||
} else {
|
||||
vec![Value::Error {
|
||||
error: ShellError::PipelineMismatch {
|
||||
error: Box::new(ShellError::PipelineMismatch {
|
||||
exp_input_type: "string".into(),
|
||||
dst_span: span,
|
||||
src_span: v_span,
|
||||
},
|
||||
}),
|
||||
}]
|
||||
}
|
||||
}
|
||||
Err(error) => vec![Value::Error { error }],
|
||||
Err(error) => vec![Value::Error {
|
||||
error: Box::new(error),
|
||||
}],
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -89,7 +89,9 @@ fn operate(
|
||||
let r =
|
||||
ret.update_cell_path(&path.members, Box::new(move |old| action(old, head)));
|
||||
if let Err(error) = r {
|
||||
return Value::Error { error };
|
||||
return Value::Error {
|
||||
error: Box::new(error),
|
||||
};
|
||||
}
|
||||
}
|
||||
ret
|
||||
@ -107,12 +109,12 @@ fn action(input: &Value, head: Span) -> Value {
|
||||
},
|
||||
Value::Error { .. } => input.clone(),
|
||||
_ => Value::Error {
|
||||
error: ShellError::OnlySupportsThisInputType {
|
||||
error: Box::new(ShellError::OnlySupportsThisInputType {
|
||||
exp_input_type: "string".into(),
|
||||
wrong_type: input.get_type().to_string(),
|
||||
dst_span: head,
|
||||
src_span: input.expect_span(),
|
||||
},
|
||||
}),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
@ -101,7 +101,9 @@ fn operate(
|
||||
let r =
|
||||
ret.update_cell_path(&path.members, Box::new(move |old| action(old, head)));
|
||||
if let Err(error) = r {
|
||||
return Value::Error { error };
|
||||
return Value::Error {
|
||||
error: Box::new(error),
|
||||
};
|
||||
}
|
||||
}
|
||||
ret
|
||||
@ -119,12 +121,12 @@ fn action(input: &Value, head: Span) -> Value {
|
||||
},
|
||||
Value::Error { .. } => input.clone(),
|
||||
_ => Value::Error {
|
||||
error: ShellError::OnlySupportsThisInputType {
|
||||
error: Box::new(ShellError::OnlySupportsThisInputType {
|
||||
exp_input_type: "string".into(),
|
||||
wrong_type: input.get_type().to_string(),
|
||||
dst_span: head,
|
||||
src_span: input.expect_span(),
|
||||
},
|
||||
}),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
@ -69,12 +69,12 @@ where
|
||||
},
|
||||
Value::Error { .. } => input.clone(),
|
||||
_ => Value::Error {
|
||||
error: ShellError::OnlySupportsThisInputType {
|
||||
error: Box::new(ShellError::OnlySupportsThisInputType {
|
||||
exp_input_type: "string".into(),
|
||||
wrong_type: input.get_type().to_string(),
|
||||
dst_span: head,
|
||||
src_span: input.expect_span(),
|
||||
},
|
||||
}),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
@ -68,7 +68,9 @@ fn operate(
|
||||
let r =
|
||||
ret.update_cell_path(&path.members, Box::new(move |old| action(old, head)));
|
||||
if let Err(error) = r {
|
||||
return Value::Error { error };
|
||||
return Value::Error {
|
||||
error: Box::new(error),
|
||||
};
|
||||
}
|
||||
}
|
||||
ret
|
||||
@ -86,12 +88,12 @@ fn action(input: &Value, head: Span) -> Value {
|
||||
},
|
||||
Value::Error { .. } => input.clone(),
|
||||
_ => Value::Error {
|
||||
error: ShellError::OnlySupportsThisInputType {
|
||||
error: Box::new(ShellError::OnlySupportsThisInputType {
|
||||
exp_input_type: "string".into(),
|
||||
wrong_type: input.get_type().to_string(),
|
||||
dst_span: head,
|
||||
src_span: input.expect_span(),
|
||||
},
|
||||
}),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
@ -48,7 +48,7 @@ impl Command for StrCollect {
|
||||
for value in input {
|
||||
match value {
|
||||
Value::Error { error } => {
|
||||
return Err(error);
|
||||
return Err(*error);
|
||||
}
|
||||
value => {
|
||||
strings.push(value.debug_string("\n", config));
|
||||
|
@ -183,12 +183,12 @@ fn action(
|
||||
),
|
||||
Value::Error { .. } => input.clone(),
|
||||
_ => Value::Error {
|
||||
error: ShellError::OnlySupportsThisInputType {
|
||||
error: Box::new(ShellError::OnlySupportsThisInputType {
|
||||
exp_input_type: "string".into(),
|
||||
wrong_type: input.get_type().to_string(),
|
||||
dst_span: head,
|
||||
src_span: input.expect_span(),
|
||||
},
|
||||
}),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
@ -99,12 +99,12 @@ fn action(input: &Value, args: &Arguments, head: Span) -> Value {
|
||||
}
|
||||
Value::Error { .. } => input.clone(),
|
||||
_ => Value::Error {
|
||||
error: ShellError::OnlySupportsThisInputType {
|
||||
error: Box::new(ShellError::OnlySupportsThisInputType {
|
||||
exp_input_type: "string".into(),
|
||||
wrong_type: input.get_type().to_string(),
|
||||
dst_span: head,
|
||||
src_span: input.expect_span(),
|
||||
},
|
||||
}),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
@ -98,12 +98,12 @@ fn action(input: &Value, args: &Arguments, head: Span) -> Value {
|
||||
}
|
||||
Value::Error { .. } => input.clone(),
|
||||
_ => Value::Error {
|
||||
error: ShellError::OnlySupportsThisInputType {
|
||||
error: Box::new(ShellError::OnlySupportsThisInputType {
|
||||
exp_input_type: "string".into(),
|
||||
wrong_type: input.get_type().to_string(),
|
||||
dst_span: head,
|
||||
src_span: input.expect_span(),
|
||||
},
|
||||
}),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
@ -155,7 +155,7 @@ fn action(
|
||||
Value::String { val: s, .. } => {
|
||||
let (start_index, end_index) = match r {
|
||||
Ok(r) => (r.0 as usize, r.1 as usize),
|
||||
Err(e) => return Value::Error { error: e },
|
||||
Err(e) => return Value::Error { error: Box::new(e) },
|
||||
};
|
||||
|
||||
// When the -e flag is present, search using rfind instead of find.s
|
||||
@ -186,12 +186,12 @@ fn action(
|
||||
}
|
||||
Value::Error { .. } => input.clone(),
|
||||
_ => Value::Error {
|
||||
error: ShellError::OnlySupportsThisInputType {
|
||||
error: Box::new(ShellError::OnlySupportsThisInputType {
|
||||
exp_input_type: "string".into(),
|
||||
wrong_type: input.get_type().to_string(),
|
||||
dst_span: head,
|
||||
src_span: input.expect_span(),
|
||||
},
|
||||
}),
|
||||
},
|
||||
}
|
||||
}
|
||||
@ -235,7 +235,7 @@ fn process_range(
|
||||
Ok((start_index, end_index))
|
||||
}
|
||||
}
|
||||
Value::Error { error } => Err(error.clone()),
|
||||
Value::Error { error } => Err(*error.clone()),
|
||||
_ => Err(ShellError::OnlySupportsThisInputType {
|
||||
exp_input_type: "string".into(),
|
||||
wrong_type: input.get_type().to_string(),
|
||||
|
@ -52,7 +52,7 @@ impl Command for StrJoin {
|
||||
for value in input {
|
||||
match value {
|
||||
Value::Error { error } => {
|
||||
return Err(error);
|
||||
return Err(*error);
|
||||
}
|
||||
value => {
|
||||
strings.push(value.debug_string("\n", config));
|
||||
|
@ -108,12 +108,12 @@ fn action(input: &Value, arg: &Arguments, head: Span) -> Value {
|
||||
),
|
||||
Value::Error { .. } => input.clone(),
|
||||
_ => Value::Error {
|
||||
error: ShellError::OnlySupportsThisInputType {
|
||||
error: Box::new(ShellError::OnlySupportsThisInputType {
|
||||
exp_input_type: "string".into(),
|
||||
wrong_type: input.get_type().to_string(),
|
||||
dst_span: head,
|
||||
src_span: input.expect_span(),
|
||||
},
|
||||
}),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
@ -209,22 +209,22 @@ fn action(
|
||||
}
|
||||
}
|
||||
Err(e) => Value::Error {
|
||||
error: ShellError::IncorrectValue {
|
||||
error: Box::new(ShellError::IncorrectValue {
|
||||
msg: format!("Regex error: {e}"),
|
||||
span: find.span,
|
||||
},
|
||||
}),
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
Value::Error { .. } => input.clone(),
|
||||
_ => Value::Error {
|
||||
error: ShellError::OnlySupportsThisInputType {
|
||||
error: Box::new(ShellError::OnlySupportsThisInputType {
|
||||
exp_input_type: "string".into(),
|
||||
wrong_type: input.get_type().to_string(),
|
||||
dst_span: head,
|
||||
src_span: input.expect_span(),
|
||||
},
|
||||
}),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
@ -77,12 +77,12 @@ fn action(input: &Value, _arg: &CellPathOnlyArgs, head: Span) -> Value {
|
||||
},
|
||||
Value::Error { .. } => input.clone(),
|
||||
_ => Value::Error {
|
||||
error: ShellError::OnlySupportsThisInputType {
|
||||
error: Box::new(ShellError::OnlySupportsThisInputType {
|
||||
exp_input_type: "string".into(),
|
||||
wrong_type: input.get_type().to_string(),
|
||||
dst_span: head,
|
||||
src_span: input.expect_span(),
|
||||
},
|
||||
}),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
@ -114,12 +114,12 @@ fn action(
|
||||
}
|
||||
Value::Error { .. } => input.clone(),
|
||||
_ => Value::Error {
|
||||
error: ShellError::OnlySupportsThisInputType {
|
||||
error: Box::new(ShellError::OnlySupportsThisInputType {
|
||||
exp_input_type: "string".into(),
|
||||
wrong_type: input.get_type().to_string(),
|
||||
dst_span: head,
|
||||
src_span: input.expect_span(),
|
||||
},
|
||||
}),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
@ -155,10 +155,10 @@ fn action(input: &Value, args: &Arguments, head: Span) -> Value {
|
||||
match start.cmp(&end) {
|
||||
Ordering::Equal => Value::string("", head),
|
||||
Ordering::Greater => Value::Error {
|
||||
error: ShellError::TypeMismatch {
|
||||
error: Box::new(ShellError::TypeMismatch {
|
||||
err_message: "End must be greater than or equal to Start".to_string(),
|
||||
span: head,
|
||||
},
|
||||
}),
|
||||
},
|
||||
Ordering::Less => Value::String {
|
||||
val: {
|
||||
@ -200,13 +200,13 @@ fn action(input: &Value, args: &Arguments, head: Span) -> Value {
|
||||
// Propagate errors by explicitly matching them before the final case.
|
||||
Value::Error { .. } => input.clone(),
|
||||
other => Value::Error {
|
||||
error: ShellError::UnsupportedInput(
|
||||
error: Box::new(ShellError::UnsupportedInput(
|
||||
"Only string values are supported".into(),
|
||||
format!("input type: {:?}", other.get_type()),
|
||||
head,
|
||||
// This line requires the Value::Error match above.
|
||||
other.expect_span(),
|
||||
),
|
||||
)),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
@ -191,13 +191,13 @@ fn action(input: &Value, arg: &Arguments, head: Span) -> Value {
|
||||
},
|
||||
ActionMode::Local => {
|
||||
Value::Error {
|
||||
error: ShellError::UnsupportedInput(
|
||||
error: Box::new(ShellError::UnsupportedInput(
|
||||
"Only string values are supported".into(),
|
||||
format!("input type: {:?}", other.get_type()),
|
||||
head,
|
||||
// This line requires the Value::Error match above.
|
||||
other.expect_span(),
|
||||
),
|
||||
)),
|
||||
}
|
||||
}
|
||||
},
|
||||
|
Reference in New Issue
Block a user