Match ++= capabilities with ++ (#11130)

Allow `++=` to work in all situations `++` does, namely for appending
single elements: `$list ++= 1`.

Resolve #11087

# Description

Bring `++=` to parity with `++`.

# User-Facing Changes

It is now possible to do `$list ++= 1` (appending a single element).
Similarly, this can be done:

```Nushell
~> mut a = [1]
~> $a ++= 2
~> a
╭───┬───╮
│ 0 │ 1 │
│ 1 │ 2 │
╰───┴───╯
```

# Tests + Formatting

Added two tests:

- `commands::assignment::append_assign::append_assign_single_element`
- `commands::assignment::append_assign::append_assign_to_single_element`
This commit is contained in:
Andrej Kolchin
2023-12-06 21:46:37 +00:00
committed by GitHub
parent c1c73811d5
commit 5d5088b5d5
2 changed files with 98 additions and 81 deletions

View File

@ -1,6 +1,6 @@
use nu_protocol::{
ast::{
Bits, Block, Boolean, Comparison, Expr, Expression, Math, Operator, Pipeline,
Assignment, Bits, Block, Boolean, Comparison, Expr, Expression, Math, Operator, Pipeline,
PipelineElement,
},
engine::StateWorkingSet,
@ -130,52 +130,7 @@ pub fn math_result_type(
)
}
},
Operator::Math(Math::Append) => match (&lhs.ty, &rhs.ty) {
(Type::List(a), Type::List(b)) => {
if a == b {
(Type::List(a.clone()), None)
} else {
(Type::List(Box::new(Type::Any)), None)
}
}
(Type::List(a), b) | (b, Type::List(a)) => {
if a == &Box::new(b.clone()) {
(Type::List(a.clone()), None)
} else {
(Type::List(Box::new(Type::Any)), None)
}
}
(Type::Table(a), Type::Table(_)) => (Type::Table(a.clone()), None),
(Type::String, Type::String) => (Type::String, None),
(Type::Binary, Type::Binary) => (Type::Binary, None),
(Type::Any, _) | (_, Type::Any) => (Type::Any, None),
(Type::Table(_) | Type::String | Type::Binary, _) => {
*op = Expression::garbage(op.span);
(
Type::Any,
Some(ParseError::UnsupportedOperationRHS(
"append".into(),
op.span,
lhs.span,
lhs.ty.clone(),
rhs.span,
rhs.ty.clone(),
)),
)
}
_ => {
*op = Expression::garbage(op.span);
(
Type::Any,
Some(ParseError::UnsupportedOperationLHS(
"append".into(),
op.span,
lhs.span,
lhs.ty.clone(),
)),
)
}
},
Operator::Math(Math::Append) => check_append(lhs, rhs, op),
Operator::Math(Math::Minus) => match (&lhs.ty, &rhs.ty) {
(Type::Int, Type::Int) => (Type::Int, None),
(Type::Float, Type::Int) => (Type::Float, None),
@ -924,6 +879,7 @@ pub fn math_result_type(
)
}
},
Operator::Assignment(Assignment::AppendAssign) => check_append(lhs, rhs, op),
Operator::Assignment(_) => match (&lhs.ty, &rhs.ty) {
(x, y) if x == y => (Type::Nothing, None),
(Type::Any, _) => (Type::Nothing, None),
@ -1076,3 +1032,56 @@ pub fn check_block_input_output(working_set: &StateWorkingSet, block: &Block) ->
output_errors
}
fn check_append(
lhs: &Expression,
rhs: &Expression,
op: &mut Expression,
) -> (Type, Option<ParseError>) {
match (&lhs.ty, &rhs.ty) {
(Type::List(a), Type::List(b)) => {
if a == b {
(Type::List(a.clone()), None)
} else {
(Type::List(Box::new(Type::Any)), None)
}
}
(Type::List(a), b) | (b, Type::List(a)) => {
if a == &Box::new(b.clone()) {
(Type::List(a.clone()), None)
} else {
(Type::List(Box::new(Type::Any)), None)
}
}
(Type::Table(a), Type::Table(_)) => (Type::Table(a.clone()), None),
(Type::String, Type::String) => (Type::String, None),
(Type::Binary, Type::Binary) => (Type::Binary, None),
(Type::Any, _) | (_, Type::Any) => (Type::Any, None),
(Type::Table(_) | Type::String | Type::Binary, _) => {
*op = Expression::garbage(op.span);
(
Type::Any,
Some(ParseError::UnsupportedOperationRHS(
"append".into(),
op.span,
lhs.span,
lhs.ty.clone(),
rhs.span,
rhs.ty.clone(),
)),
)
}
_ => {
*op = Expression::garbage(op.span);
(
Type::Any,
Some(ParseError::UnsupportedOperationLHS(
"append".into(),
op.span,
lhs.span,
lhs.ty.clone(),
)),
)
}
}
}