forked from extern/nushell
Rework operator type errors (#14429)
# Description This PR adds two new `ParseError` and `ShellError` cases for type errors relating to operators. - `OperatorUnsupportedType` is used when a type is not supported by an operator in any way, shape, or form. E.g., `+` does not support `bool`. - `OperatorIncompatibleTypes` is used when a operator is used with types it supports, but the combination of types provided cannot be used together. E.g., `filesize + duration` is not a valid combination. The other preexisting error cases related to operators have been removed and replaced with the new ones above. Namely: - `ShellError::OperatorMismatch` - `ShellError::UnsupportedOperator` - `ParseError::UnsupportedOperationLHS` - `ParseError::UnsupportedOperationRHS` - `ParseError::UnsupportedOperationTernary` # User-Facing Changes - `help operators` now lists the precedence of `not` as 55 instead of 0 (above the other boolean operators). Fixes #13675. - `math median` and `math mode` now ignore NaN values so that `[NaN NaN] | math median` and `[NaN NaN] | math mode` no longer trigger a type error. Instead, it's now an empty input error. Fixing this in earnest can be left for a future PR. - Comparisons with `nan` now return false instead of causing an error. E.g., `1 == nan` is now `false`. - All the operator type errors have been standardized and reworked. In particular, they can now have a help message, which is currently used for types errors relating to `++`. ```nu [1] ++ 2 ``` ``` Error: nu::parser::operator_unsupported_type × The '++' operator does not work on values of type 'int'. ╭─[entry #1:1:5] 1 │ [1] ++ 2 · ─┬ ┬ · │ ╰── int · ╰── does not support 'int' ╰──── help: if you meant to append a value to a list or a record to a table, use the `append` command or wrap the value in a list. For example: `$list ++ $value` should be `$list ++ [$value]` or `$list | append $value`. ```
This commit is contained in:
@ -7,20 +7,21 @@ mod nu_schema;
|
||||
mod nu_when;
|
||||
pub mod utils;
|
||||
|
||||
use crate::{Cacheable, PolarsPlugin};
|
||||
use nu_plugin::EngineInterface;
|
||||
use nu_protocol::{
|
||||
ast::Operator, CustomValue, PipelineData, ShellError, Span, Spanned, Type, Value,
|
||||
};
|
||||
use std::{cmp::Ordering, fmt};
|
||||
use uuid::Uuid;
|
||||
|
||||
pub use file_type::PolarsFileType;
|
||||
pub use nu_dataframe::{Axis, Column, NuDataFrame, NuDataFrameCustomValue};
|
||||
pub use nu_expression::{NuExpression, NuExpressionCustomValue};
|
||||
pub use nu_lazyframe::{NuLazyFrame, NuLazyFrameCustomValue};
|
||||
pub use nu_lazygroupby::{NuLazyGroupBy, NuLazyGroupByCustomValue};
|
||||
use nu_plugin::EngineInterface;
|
||||
use nu_protocol::{ast::Operator, CustomValue, PipelineData, ShellError, Span, Spanned, Value};
|
||||
pub use nu_schema::{str_to_dtype, NuSchema};
|
||||
pub use nu_when::{NuWhen, NuWhenCustomValue, NuWhenType};
|
||||
use uuid::Uuid;
|
||||
|
||||
use crate::{Cacheable, PolarsPlugin};
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum PolarsPluginType {
|
||||
@ -217,13 +218,16 @@ pub trait PolarsPluginCustomValue: CustomValue {
|
||||
&self,
|
||||
_plugin: &PolarsPlugin,
|
||||
_engine: &EngineInterface,
|
||||
_lhs_span: Span,
|
||||
lhs_span: Span,
|
||||
operator: Spanned<Operator>,
|
||||
_right: Value,
|
||||
) -> Result<Value, ShellError> {
|
||||
Err(ShellError::UnsupportedOperator {
|
||||
operator: operator.item,
|
||||
span: operator.span,
|
||||
Err(ShellError::OperatorUnsupportedType {
|
||||
op: operator.item,
|
||||
unsupported: Type::Custom(self.type_name().into()),
|
||||
op_span: operator.span,
|
||||
unsupported_span: lhs_span,
|
||||
help: None,
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -18,15 +18,15 @@ pub(super) fn between_dataframes(
|
||||
rhs: &NuDataFrame,
|
||||
) -> Result<NuDataFrame, ShellError> {
|
||||
match operator.item {
|
||||
Operator::Math(Math::Plus) => {
|
||||
Operator::Math(Math::Add) => {
|
||||
lhs.append_df(rhs, Axis::Row, Span::merge(left.span(), right.span()))
|
||||
}
|
||||
_ => Err(ShellError::OperatorMismatch {
|
||||
op => Err(ShellError::OperatorUnsupportedType {
|
||||
op,
|
||||
unsupported: left.get_type(),
|
||||
op_span: operator.span,
|
||||
lhs_ty: left.get_type().to_string(),
|
||||
lhs_span: left.span(),
|
||||
rhs_ty: right.get_type().to_string(),
|
||||
rhs_span: right.span(),
|
||||
unsupported_span: left.span(),
|
||||
help: None,
|
||||
}),
|
||||
}
|
||||
}
|
||||
@ -40,7 +40,7 @@ pub(super) fn compute_between_series(
|
||||
) -> Result<NuDataFrame, ShellError> {
|
||||
let operation_span = Span::merge(left.span(), right.span());
|
||||
match operator.item {
|
||||
Operator::Math(Math::Plus) => {
|
||||
Operator::Math(Math::Add) => {
|
||||
let mut res = (lhs + rhs).map_err(|e| ShellError::GenericError {
|
||||
error: format!("Addition error: {e}"),
|
||||
msg: "".into(),
|
||||
@ -52,7 +52,7 @@ pub(super) fn compute_between_series(
|
||||
res.rename(name.into());
|
||||
NuDataFrame::try_from_series(res, operation_span)
|
||||
}
|
||||
Operator::Math(Math::Minus) => {
|
||||
Operator::Math(Math::Subtract) => {
|
||||
let mut res = (lhs - rhs).map_err(|e| ShellError::GenericError {
|
||||
error: format!("Subtraction error: {e}"),
|
||||
msg: "".into(),
|
||||
@ -181,12 +181,12 @@ pub(super) fn compute_between_series(
|
||||
span: operation_span,
|
||||
}),
|
||||
},
|
||||
_ => Err(ShellError::OperatorMismatch {
|
||||
op => Err(ShellError::OperatorUnsupportedType {
|
||||
op,
|
||||
unsupported: left.get_type(),
|
||||
op_span: operator.span,
|
||||
lhs_ty: left.get_type().to_string(),
|
||||
lhs_span: left.span(),
|
||||
rhs_ty: right.get_type().to_string(),
|
||||
rhs_span: right.span(),
|
||||
unsupported_span: left.span(),
|
||||
help: None,
|
||||
}),
|
||||
}
|
||||
}
|
||||
@ -222,12 +222,12 @@ pub(super) fn compute_series_single_value(
|
||||
right: &Value,
|
||||
) -> Result<NuDataFrame, ShellError> {
|
||||
if !lhs.is_series() {
|
||||
return Err(ShellError::OperatorMismatch {
|
||||
return Err(ShellError::OperatorUnsupportedType {
|
||||
op: operator.item,
|
||||
unsupported: left.get_type(),
|
||||
op_span: operator.span,
|
||||
lhs_ty: left.get_type().to_string(),
|
||||
lhs_span: left.span(),
|
||||
rhs_ty: right.get_type().to_string(),
|
||||
rhs_span: right.span(),
|
||||
unsupported_span: left.span(),
|
||||
help: None,
|
||||
});
|
||||
}
|
||||
|
||||
@ -235,7 +235,7 @@ pub(super) fn compute_series_single_value(
|
||||
let lhs = lhs.as_series(lhs_span)?;
|
||||
|
||||
match operator.item {
|
||||
Operator::Math(Math::Plus) => match &right {
|
||||
Operator::Math(Math::Add) => match &right {
|
||||
Value::Int { val, .. } => {
|
||||
compute_series_i64(&lhs, *val, <ChunkedArray<Int64Type>>::add, lhs_span)
|
||||
}
|
||||
@ -243,27 +243,27 @@ pub(super) fn compute_series_single_value(
|
||||
compute_series_float(&lhs, *val, <ChunkedArray<Float64Type>>::add, lhs_span)
|
||||
}
|
||||
Value::String { val, .. } => add_string_to_series(&lhs, val, lhs_span),
|
||||
_ => Err(ShellError::OperatorMismatch {
|
||||
_ => Err(ShellError::OperatorUnsupportedType {
|
||||
op: operator.item,
|
||||
unsupported: right.get_type(),
|
||||
op_span: operator.span,
|
||||
lhs_ty: left.get_type().to_string(),
|
||||
lhs_span: left.span(),
|
||||
rhs_ty: right.get_type().to_string(),
|
||||
rhs_span: right.span(),
|
||||
unsupported_span: right.span(),
|
||||
help: None,
|
||||
}),
|
||||
},
|
||||
Operator::Math(Math::Minus) => match &right {
|
||||
Operator::Math(Math::Subtract) => match &right {
|
||||
Value::Int { val, .. } => {
|
||||
compute_series_i64(&lhs, *val, <ChunkedArray<Int64Type>>::sub, lhs_span)
|
||||
}
|
||||
Value::Float { val, .. } => {
|
||||
compute_series_float(&lhs, *val, <ChunkedArray<Float64Type>>::sub, lhs_span)
|
||||
}
|
||||
_ => Err(ShellError::OperatorMismatch {
|
||||
_ => Err(ShellError::OperatorUnsupportedType {
|
||||
op: operator.item,
|
||||
unsupported: right.get_type(),
|
||||
op_span: operator.span,
|
||||
lhs_ty: left.get_type().to_string(),
|
||||
lhs_span: left.span(),
|
||||
rhs_ty: right.get_type().to_string(),
|
||||
rhs_span: right.span(),
|
||||
unsupported_span: right.span(),
|
||||
help: None,
|
||||
}),
|
||||
},
|
||||
Operator::Math(Math::Multiply) => match &right {
|
||||
@ -273,12 +273,12 @@ pub(super) fn compute_series_single_value(
|
||||
Value::Float { val, .. } => {
|
||||
compute_series_float(&lhs, *val, <ChunkedArray<Float64Type>>::mul, lhs_span)
|
||||
}
|
||||
_ => Err(ShellError::OperatorMismatch {
|
||||
_ => Err(ShellError::OperatorUnsupportedType {
|
||||
op: operator.item,
|
||||
unsupported: right.get_type(),
|
||||
op_span: operator.span,
|
||||
lhs_ty: left.get_type().to_string(),
|
||||
lhs_span: left.span(),
|
||||
rhs_ty: right.get_type().to_string(),
|
||||
rhs_span: right.span(),
|
||||
unsupported_span: right.span(),
|
||||
help: None,
|
||||
}),
|
||||
},
|
||||
Operator::Math(Math::Divide) => {
|
||||
@ -298,12 +298,12 @@ pub(super) fn compute_series_single_value(
|
||||
compute_series_float(&lhs, *val, <ChunkedArray<Float64Type>>::div, lhs_span)
|
||||
}
|
||||
}
|
||||
_ => Err(ShellError::OperatorMismatch {
|
||||
_ => Err(ShellError::OperatorUnsupportedType {
|
||||
op: operator.item,
|
||||
unsupported: right.get_type(),
|
||||
op_span: operator.span,
|
||||
lhs_ty: left.get_type().to_string(),
|
||||
lhs_span: left.span(),
|
||||
rhs_ty: right.get_type().to_string(),
|
||||
rhs_span: right.span(),
|
||||
unsupported_span: right.span(),
|
||||
help: None,
|
||||
}),
|
||||
}
|
||||
}
|
||||
@ -319,12 +319,12 @@ pub(super) fn compute_series_single_value(
|
||||
Value::Date { val, .. } => {
|
||||
compare_series_i64(&lhs, val.timestamp_millis(), ChunkedArray::equal, lhs_span)
|
||||
}
|
||||
_ => Err(ShellError::OperatorMismatch {
|
||||
_ => Err(ShellError::OperatorUnsupportedType {
|
||||
op: operator.item,
|
||||
unsupported: right.get_type(),
|
||||
op_span: operator.span,
|
||||
lhs_ty: left.get_type().to_string(),
|
||||
lhs_span: left.span(),
|
||||
rhs_ty: right.get_type().to_string(),
|
||||
rhs_span: right.span(),
|
||||
unsupported_span: right.span(),
|
||||
help: None,
|
||||
}),
|
||||
},
|
||||
Operator::Comparison(Comparison::NotEqual) => match &right {
|
||||
@ -344,12 +344,12 @@ pub(super) fn compute_series_single_value(
|
||||
ChunkedArray::not_equal,
|
||||
lhs_span,
|
||||
),
|
||||
_ => Err(ShellError::OperatorMismatch {
|
||||
_ => Err(ShellError::OperatorUnsupportedType {
|
||||
op: operator.item,
|
||||
unsupported: right.get_type(),
|
||||
op_span: operator.span,
|
||||
lhs_ty: left.get_type().to_string(),
|
||||
lhs_span: left.span(),
|
||||
rhs_ty: right.get_type().to_string(),
|
||||
rhs_span: right.span(),
|
||||
unsupported_span: right.span(),
|
||||
help: None,
|
||||
}),
|
||||
},
|
||||
Operator::Comparison(Comparison::LessThan) => match &right {
|
||||
@ -360,12 +360,12 @@ pub(super) fn compute_series_single_value(
|
||||
Value::Date { val, .. } => {
|
||||
compare_series_i64(&lhs, val.timestamp_millis(), ChunkedArray::lt, lhs_span)
|
||||
}
|
||||
_ => Err(ShellError::OperatorMismatch {
|
||||
_ => Err(ShellError::OperatorUnsupportedType {
|
||||
op: operator.item,
|
||||
unsupported: right.get_type(),
|
||||
op_span: operator.span,
|
||||
lhs_ty: left.get_type().to_string(),
|
||||
lhs_span: left.span(),
|
||||
rhs_ty: right.get_type().to_string(),
|
||||
rhs_span: right.span(),
|
||||
unsupported_span: right.span(),
|
||||
help: None,
|
||||
}),
|
||||
},
|
||||
Operator::Comparison(Comparison::LessThanOrEqual) => match &right {
|
||||
@ -376,12 +376,12 @@ pub(super) fn compute_series_single_value(
|
||||
Value::Date { val, .. } => {
|
||||
compare_series_i64(&lhs, val.timestamp_millis(), ChunkedArray::lt_eq, lhs_span)
|
||||
}
|
||||
_ => Err(ShellError::OperatorMismatch {
|
||||
_ => Err(ShellError::OperatorUnsupportedType {
|
||||
op: operator.item,
|
||||
unsupported: right.get_type(),
|
||||
op_span: operator.span,
|
||||
lhs_ty: left.get_type().to_string(),
|
||||
lhs_span: left.span(),
|
||||
rhs_ty: right.get_type().to_string(),
|
||||
rhs_span: right.span(),
|
||||
unsupported_span: right.span(),
|
||||
help: None,
|
||||
}),
|
||||
},
|
||||
Operator::Comparison(Comparison::GreaterThan) => match &right {
|
||||
@ -392,12 +392,12 @@ pub(super) fn compute_series_single_value(
|
||||
Value::Date { val, .. } => {
|
||||
compare_series_i64(&lhs, val.timestamp_millis(), ChunkedArray::gt, lhs_span)
|
||||
}
|
||||
_ => Err(ShellError::OperatorMismatch {
|
||||
_ => Err(ShellError::OperatorUnsupportedType {
|
||||
op: operator.item,
|
||||
unsupported: right.get_type(),
|
||||
op_span: operator.span,
|
||||
lhs_ty: left.get_type().to_string(),
|
||||
lhs_span: left.span(),
|
||||
rhs_ty: right.get_type().to_string(),
|
||||
rhs_span: right.span(),
|
||||
unsupported_span: right.span(),
|
||||
help: None,
|
||||
}),
|
||||
},
|
||||
Operator::Comparison(Comparison::GreaterThanOrEqual) => match &right {
|
||||
@ -408,23 +408,23 @@ pub(super) fn compute_series_single_value(
|
||||
Value::Date { val, .. } => {
|
||||
compare_series_i64(&lhs, val.timestamp_millis(), ChunkedArray::gt_eq, lhs_span)
|
||||
}
|
||||
_ => Err(ShellError::OperatorMismatch {
|
||||
_ => Err(ShellError::OperatorUnsupportedType {
|
||||
op: operator.item,
|
||||
unsupported: right.get_type(),
|
||||
op_span: operator.span,
|
||||
lhs_ty: left.get_type().to_string(),
|
||||
lhs_span: left.span(),
|
||||
rhs_ty: right.get_type().to_string(),
|
||||
rhs_span: right.span(),
|
||||
unsupported_span: right.span(),
|
||||
help: None,
|
||||
}),
|
||||
},
|
||||
// TODO: update this to do a regex match instead of a simple contains?
|
||||
Operator::Comparison(Comparison::RegexMatch) => match &right {
|
||||
Value::String { val, .. } => contains_series_pat(&lhs, val, lhs_span),
|
||||
_ => Err(ShellError::OperatorMismatch {
|
||||
_ => Err(ShellError::OperatorUnsupportedType {
|
||||
op: operator.item,
|
||||
unsupported: right.get_type(),
|
||||
op_span: operator.span,
|
||||
lhs_ty: left.get_type().to_string(),
|
||||
lhs_span: left.span(),
|
||||
rhs_ty: right.get_type().to_string(),
|
||||
rhs_span: right.span(),
|
||||
unsupported_span: right.span(),
|
||||
help: None,
|
||||
}),
|
||||
},
|
||||
Operator::Comparison(Comparison::StartsWith) => match &right {
|
||||
@ -432,12 +432,12 @@ pub(super) fn compute_series_single_value(
|
||||
let starts_with_pattern = format!("^{}", fancy_regex::escape(val));
|
||||
contains_series_pat(&lhs, &starts_with_pattern, lhs_span)
|
||||
}
|
||||
_ => Err(ShellError::OperatorMismatch {
|
||||
_ => Err(ShellError::OperatorUnsupportedType {
|
||||
op: operator.item,
|
||||
unsupported: right.get_type(),
|
||||
op_span: operator.span,
|
||||
lhs_ty: left.get_type().to_string(),
|
||||
lhs_span: left.span(),
|
||||
rhs_ty: right.get_type().to_string(),
|
||||
rhs_span: right.span(),
|
||||
unsupported_span: right.span(),
|
||||
help: None,
|
||||
}),
|
||||
},
|
||||
Operator::Comparison(Comparison::EndsWith) => match &right {
|
||||
@ -445,20 +445,20 @@ pub(super) fn compute_series_single_value(
|
||||
let ends_with_pattern = format!("{}$", fancy_regex::escape(val));
|
||||
contains_series_pat(&lhs, &ends_with_pattern, lhs_span)
|
||||
}
|
||||
_ => Err(ShellError::OperatorMismatch {
|
||||
_ => Err(ShellError::OperatorUnsupportedType {
|
||||
op: operator.item,
|
||||
unsupported: right.get_type(),
|
||||
op_span: operator.span,
|
||||
lhs_ty: left.get_type().to_string(),
|
||||
lhs_span: left.span(),
|
||||
rhs_ty: right.get_type().to_string(),
|
||||
rhs_span: right.span(),
|
||||
unsupported_span: right.span(),
|
||||
help: None,
|
||||
}),
|
||||
},
|
||||
_ => Err(ShellError::OperatorMismatch {
|
||||
_ => Err(ShellError::OperatorUnsupportedType {
|
||||
op: operator.item,
|
||||
unsupported: left.get_type(),
|
||||
op_span: operator.span,
|
||||
lhs_ty: left.get_type().to_string(),
|
||||
lhs_span: left.span(),
|
||||
rhs_ty: right.get_type().to_string(),
|
||||
rhs_span: right.span(),
|
||||
unsupported_span: left.span(),
|
||||
help: None,
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
@ -81,14 +81,14 @@ fn with_operator(
|
||||
left: &NuExpression,
|
||||
right: &NuExpression,
|
||||
lhs_span: Span,
|
||||
rhs_span: Span,
|
||||
_rhs_span: Span,
|
||||
op_span: Span,
|
||||
) -> Result<Value, ShellError> {
|
||||
match operator {
|
||||
Operator::Math(Math::Plus) => {
|
||||
Operator::Math(Math::Add) => {
|
||||
apply_arithmetic(plugin, engine, left, right, lhs_span, Add::add)
|
||||
}
|
||||
Operator::Math(Math::Minus) => {
|
||||
Operator::Math(Math::Subtract) => {
|
||||
apply_arithmetic(plugin, engine, left, right, lhs_span, Sub::sub)
|
||||
}
|
||||
Operator::Math(Math::Multiply) => {
|
||||
@ -100,7 +100,7 @@ fn with_operator(
|
||||
Operator::Math(Math::Modulo) => {
|
||||
apply_arithmetic(plugin, engine, left, right, lhs_span, Rem::rem)
|
||||
}
|
||||
Operator::Math(Math::FloorDivision) => {
|
||||
Operator::Math(Math::FloorDivide) => {
|
||||
apply_arithmetic(plugin, engine, left, right, lhs_span, Div::div)
|
||||
}
|
||||
Operator::Comparison(Comparison::Equal) => Ok(left
|
||||
@ -133,12 +133,12 @@ fn with_operator(
|
||||
.apply_with_expr(right.clone(), Expr::lt_eq)
|
||||
.cache(plugin, engine, lhs_span)?
|
||||
.into_value(lhs_span)),
|
||||
_ => Err(ShellError::OperatorMismatch {
|
||||
op => Err(ShellError::OperatorUnsupportedType {
|
||||
op,
|
||||
unsupported: Type::Custom(TYPE_NAME.into()),
|
||||
op_span,
|
||||
lhs_ty: Type::Custom(TYPE_NAME.into()).to_string(),
|
||||
lhs_span,
|
||||
rhs_ty: Type::Custom(TYPE_NAME.into()).to_string(),
|
||||
rhs_span,
|
||||
unsupported_span: lhs_span,
|
||||
help: None,
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user