ExprKind::Field(..) => ExprPrecedence::Field,
ExprKind::Index(..) => ExprPrecedence::Index,
ExprKind::Range(..) => ExprPrecedence::Range,
+ ExprKind::Underscore => ExprPrecedence::Path,
ExprKind::Path(..) => ExprPrecedence::Path,
ExprKind::AddrOf(..) => ExprPrecedence::AddrOf,
ExprKind::Break(..) => ExprPrecedence::Break,
Index(P<Expr>, P<Expr>),
/// A range (e.g., `1..2`, `1..`, `..2`, `1..=2`, `..=2`; and `..` in destructuring assingment).
Range(Option<P<Expr>>, Option<P<Expr>>, RangeLimits),
+ /// An underscore, used in destructuring assignment to ignore a value.
+ Underscore,
/// Variable reference, possibly containing `::` and/or type
/// parameters (e.g., `foo::bar::<baz>`).
visit_opt(e1, |e1| vis.visit_expr(e1));
visit_opt(e2, |e2| vis.visit_expr(e2));
}
+ ExprKind::Underscore => {}
ExprKind::Path(qself, path) => {
vis.visit_qself(qself);
vis.visit_path(path);
walk_list!(visitor, visit_expr, start);
walk_list!(visitor, visit_expr, end);
}
+ ExprKind::Underscore => {}
ExprKind::Path(ref maybe_qself, ref path) => {
if let Some(ref qself) = *maybe_qself {
visitor.visit_ty(&qself.ty);
ExprKind::Range(ref e1, ref e2, lims) => {
self.lower_expr_range(e.span, e1.as_deref(), e2.as_deref(), lims)
}
+ ExprKind::Underscore => {
+ self.sess
+ .struct_span_err(
+ e.span,
+ "in expressions, `_` can only be used on the left-hand side of an assignment",
+ )
+ .span_label(e.span, "`_` not allowed here")
+ .emit();
+ hir::ExprKind::Err
+ }
ExprKind::Path(ref qself, ref path) => {
let qpath = self.lower_qpath(
e.id,
// Return early in case of an ordinary assignment.
fn is_ordinary(lower_ctx: &mut LoweringContext<'_, '_>, lhs: &Expr) -> bool {
match &lhs.kind {
- ExprKind::Array(..) | ExprKind::Struct(..) | ExprKind::Tup(..) => false,
+ ExprKind::Array(..)
+ | ExprKind::Struct(..)
+ | ExprKind::Tup(..)
+ | ExprKind::Underscore => false,
// Check for tuple struct constructor.
ExprKind::Call(callee, ..) => lower_ctx.extract_tuple_struct_path(callee).is_none(),
ExprKind::Paren(e) => {
assignments: &mut Vec<hir::Stmt<'hir>>,
) -> &'hir hir::Pat<'hir> {
match &lhs.kind {
+ // Underscore pattern.
+ ExprKind::Underscore => {
+ return self.pat_without_dbm(lhs.span, hir::PatKind::Wild);
+ }
// Slice patterns.
ExprKind::Array(elements) => {
let (pats, rest) =
gate_all!(const_trait_impl, "const trait impls are experimental");
gate_all!(half_open_range_patterns, "half-open range patterns are unstable");
gate_all!(inline_const, "inline-const is experimental");
- gate_all!(destructuring_assignment, "destructuring assignments are unstable");
+ if sess.parse_sess.span_diagnostic.err_count() == 0 {
+ // Errors for `destructuring_assignment` can get quite noisy, especially where `_` is
+ // involved, so we only emit errors where there are no other parsing errors.
+ gate_all!(destructuring_assignment, "destructuring assignments are unstable");
+ }
// All uses of `gate_all!` below this point were added in #65742,
// and subsequently disabled (with the non-early gating readded).
self.print_expr_maybe_paren(e, fake_prec);
}
}
+ ast::ExprKind::Underscore => self.s.word("_"),
ast::ExprKind::Path(None, ref path) => self.print_path(path, true, 0),
ast::ExprKind::Path(Some(ref qself), ref path) => self.print_qpath(path, qself, true),
ast::ExprKind::Break(opt_label, ref opt_expr) => {
self.parse_yield_expr(attrs)
} else if self.eat_keyword(kw::Let) {
self.parse_let_expr(attrs)
+ } else if self.eat_keyword(kw::Underscore) {
+ self.sess.gated_spans.gate(sym::destructuring_assignment, self.prev_token.span);
+ Ok(self.mk_expr(self.prev_token.span, ExprKind::Underscore, attrs))
} else if !self.unclosed_delims.is_empty() && self.check(&token::Semi) {
// Don't complain about bare semicolons after unclosed braces
// recovery in order to keep the error count down. Fixing the
fn main() {
underscore!();
- //~^ ERROR expected expression, found reserved identifier `_`
+ //~^ ERROR `_` can only be used on the left-hand side of an assignment
+ //~| ERROR destructuring assignments are unstable
}
-error: expected expression, found reserved identifier `_`
+error[E0658]: destructuring assignments are unstable
--> $DIR/underscore.rs:8:9
|
LL | _
- | ^ expected expression
+ | ^
|
::: $DIR/main.rs:5:5
|
LL | underscore!();
| -------------- in this macro invocation
|
+ = note: see issue #71126 <https://github.com/rust-lang/rust/issues/71126> for more information
+ = help: add `#![feature(destructuring_assignment)]` to the crate attributes to enable
= note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
-error: aborting due to previous error
+error: in expressions, `_` can only be used on the left-hand side of an assignment
+ --> $DIR/underscore.rs:8:9
+ |
+LL | _
+ | ^ `_` not allowed here
+ |
+ ::: $DIR/main.rs:5:5
+ |
+LL | underscore!();
+ | -------------- in this macro invocation
+ |
+ = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: aborting due to 2 previous errors
+For more information about this error, try `rustc --explain E0658`.
Struct { a: TupleStruct((a, b), c), b: [d] } =
Struct { a: TupleStruct((0, 1), 2), b: [3] };
assert_eq!((a, b, c, d), (0, 1, 2, 3));
+
+ // unnested underscore: just discard
+ _ = 1;
}
let mut c;
[a, .., b, c] = [1, 2, 3, 4, 5];
assert_eq!((a, b, c), (1, 4, 5));
+ [_, a, _] = [1, 2, 3];
+ assert_eq!((a, b), (2, 4));
[..] = [1, 2, 3];
[c, ..] = [5, 6, 6];
assert_eq!(c, 5);
let (mut a, mut b);
[a, .., b, ..] = [0, 1]; //~ ERROR `..` can only be used once per slice pattern
[a, a, b] = [1, 2]; //~ ERROR pattern requires 3 elements but array has 2
+ [_] = [1, 2]; //~ ERROR pattern requires 1 element but array has 2
}
LL | [a, a, b] = [1, 2];
| ^^^^^^^^^ expected 2 elements
-error: aborting due to 2 previous errors
+error[E0527]: pattern requires 1 element but array has 2
+ --> $DIR/slice_destructure_fail.rs:7:3
+ |
+LL | [_] = [1, 2];
+ | ^^^ expected 2 elements
+
+error: aborting due to 3 previous errors
For more information about this error, try `rustc --explain E0527`.
assert_eq!((a, b), (0, 1));
Struct { a: b, b: a } = Struct { a: 1, b: 2 };
assert_eq!((a,b), (2, 1));
+ Struct { a: _, b } = Struct { a: 1, b: 2 };
+ assert_eq!((a, b), (2, 2));
Struct { a, .. } = Struct { a: 1, b: 3 };
- assert_eq!((a, b), (1, 1));
+ assert_eq!((a, b), (1, 2));
Struct { .. } = Struct { a: 1, b: 4 };
- assert_eq!((a, b), (1, 1));
+ assert_eq!((a, b), (1, 2));
}
let mut c;
let d = Struct { a: 0, b: 1 };
Struct { a, b, c } = Struct { a: 0, b: 1 }; //~ ERROR does not have a field named `c`
+ Struct { a, _ } = Struct { a: 1, b: 2 }; //~ ERROR pattern does not mention field `b`
+ //~| ERROR expected identifier, found reserved identifier `_`
Struct { a, ..d } = Struct { a: 1, b: 2 };
//~^ ERROR functional record updates are not allowed in destructuring assignments
Struct { a, .. }; //~ ERROR base expression required after `..`
+error: expected identifier, found reserved identifier `_`
+ --> $DIR/struct_destructure_fail.rs:12:17
+ |
+LL | Struct { a, _ } = Struct { a: 1, b: 2 };
+ | ------ ^ expected identifier, found reserved identifier
+ | |
+ | while parsing this struct
+
error: functional record updates are not allowed in destructuring assignments
- --> $DIR/struct_destructure_fail.rs:12:19
+ --> $DIR/struct_destructure_fail.rs:14:19
|
LL | Struct { a, ..d } = Struct { a: 1, b: 2 };
| ^ help: consider removing the trailing pattern
error: base expression required after `..`
- --> $DIR/struct_destructure_fail.rs:14:19
+ --> $DIR/struct_destructure_fail.rs:16:19
|
LL | Struct { a, .. };
| ^ add a base expression here
LL | Struct { a, b, c } = Struct { a: 0, b: 1 };
| ^ struct `Struct` does not have this field
-error: aborting due to 3 previous errors
+error[E0027]: pattern does not mention field `b`
+ --> $DIR/struct_destructure_fail.rs:12:5
+ |
+LL | Struct { a, _ } = Struct { a: 1, b: 2 };
+ | ^^^^^^^^^^^^^^^ missing field `b`
+ |
+help: include the missing field in the pattern
+ |
+LL | Struct { a, b, _ } = Struct { a: 1, b: 2 };
+ | ^^^
+help: if you don't care about this missing field, you can explicitly ignore it
+ |
+LL | Struct { a, .., _ } = Struct { a: 1, b: 2 };
+ | ^^^^
+
+error: aborting due to 5 previous errors
-For more information about this error, try `rustc --explain E0026`.
+Some errors have detailed explanations: E0026, E0027.
+For more information about an error, try `rustc --explain E0026`.
assert_eq!((a, b), (2, 2));
(b, ..) = (5, 6, 7);
assert_eq!(b, 5);
+ (a, _) = (8, 9);
+ assert_eq!(a, 8);
// Test for a non-Copy type (String):
let (mut c, mut d);
(a, .., b, ..) = (0, 1); //~ ERROR `..` can only be used once per tuple pattern
(a, a, b) = (1, 2); //~ ERROR mismatched types
(C, ..) = (0,1); //~ ERROR invalid left-hand side of assignment
+ (_,) = (1, 2); //~ ERROR mismatched types
}
| |
| cannot assign to this expression
-error: aborting due to 3 previous errors
+error[E0308]: mismatched types
+ --> $DIR/tuple_destructure_fail.rs:10:5
+ |
+LL | (_,) = (1, 2);
+ | ^^^^ ------ this expression has type `({integer}, {integer})`
+ | |
+ | expected a tuple with 2 elements, found one with 1 element
+ |
+ = note: expected type `({integer}, {integer})`
+ found tuple `(_,)`
+
+error: aborting due to 4 previous errors
Some errors have detailed explanations: E0070, E0308.
For more information about an error, try `rustc --explain E0070`.
assert_eq!((a, b), (0, 1));
TupleStruct(a, .., b) = TupleStruct(1, 2);
assert_eq!((a, b), (1, 2));
+ TupleStruct(_, a) = TupleStruct(2, 2);
+ assert_eq!((a, b), (2, 2));
TupleStruct(..) = TupleStruct(3, 4);
- assert_eq!((a, b), (1, 2));
+ assert_eq!((a, b), (2, 2));
TupleStruct(5,6).assign(&mut a, &mut b);
assert_eq!((a, b), (5, 6));
Enum::SingleVariant(a, b) = Enum::SingleVariant(7, 8);
TupleStruct(a, a, b) = TupleStruct(1, 2);
//~^ ERROR this pattern has 3 fields, but the corresponding tuple struct has 2 fields
+ TupleStruct(_) = TupleStruct(1, 2);
+ //~^ ERROR this pattern has 1 field, but the corresponding tuple struct has 2 fields
Enum::SingleVariant(a, a, b) = Enum::SingleVariant(1, 2);
//~^ ERROR this pattern has 3 fields, but the corresponding tuple variant has 2 fields
+ Enum::SingleVariant(_) = Enum::SingleVariant(1, 2);
+ //~^ ERROR this pattern has 1 field, but the corresponding tuple variant has 2 fields
// Check if `test` is recognized as not a tuple struct but a function call:
test() = TupleStruct(0, 0);
LL | TupleStruct(a, a, b) = TupleStruct(1, 2);
| ^^^^^^^^^^^^^^^^^^^^ expected 2 fields, found 3
-error[E0023]: this pattern has 3 fields, but the corresponding tuple variant has 2 fields
+error[E0023]: this pattern has 1 field, but the corresponding tuple struct has 2 fields
--> $DIR/tuple_struct_destructure_fail.rs:32:5
|
+LL | struct TupleStruct<S, T>(S, T);
+ | ------------------------------- tuple struct defined here
+...
+LL | TupleStruct(_) = TupleStruct(1, 2);
+ | ^^^^^^^^^^^^^^ expected 2 fields, found 1
+
+error[E0023]: this pattern has 3 fields, but the corresponding tuple variant has 2 fields
+ --> $DIR/tuple_struct_destructure_fail.rs:34:5
+ |
LL | SingleVariant(S, T)
| ------------------- tuple variant defined here
...
LL | Enum::SingleVariant(a, a, b) = Enum::SingleVariant(1, 2);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected 2 fields, found 3
+error[E0023]: this pattern has 1 field, but the corresponding tuple variant has 2 fields
+ --> $DIR/tuple_struct_destructure_fail.rs:36:5
+ |
+LL | SingleVariant(S, T)
+ | ------------------- tuple variant defined here
+...
+LL | Enum::SingleVariant(_) = Enum::SingleVariant(1, 2);
+ | ^^^^^^^^^^^^^^^^^^^^^^ expected 2 fields, found 1
+
error[E0070]: invalid left-hand side of assignment
- --> $DIR/tuple_struct_destructure_fail.rs:36:12
+ --> $DIR/tuple_struct_destructure_fail.rs:40:12
|
LL | test() = TupleStruct(0, 0);
| ------ ^
| cannot assign to this expression
error[E0070]: invalid left-hand side of assignment
- --> $DIR/tuple_struct_destructure_fail.rs:38:14
+ --> $DIR/tuple_struct_destructure_fail.rs:42:14
|
LL | (test)() = TupleStruct(0, 0);
| -------- ^
| cannot assign to this expression
error[E0070]: invalid left-hand side of assignment
- --> $DIR/tuple_struct_destructure_fail.rs:40:38
+ --> $DIR/tuple_struct_destructure_fail.rs:44:38
|
LL | <Alias::<isize> as Test>::test() = TupleStruct(0, 0);
| -------------------------------- ^
| |
| cannot assign to this expression
-error: aborting due to 7 previous errors
+error: aborting due to 9 previous errors
Some errors have detailed explanations: E0023, E0070.
For more information about an error, try `rustc --explain E0023`.
#[cfg(FALSE)]
fn foo() {
+ _; //~ ERROR destructuring assignments are unstable
+
S { x: 5, .. }; //~ ERROR destructuring assignments are unstable
}
error[E0658]: destructuring assignments are unstable
- --> $DIR/underscore-range-expr-gating.rs:7:15
+ --> $DIR/underscore-range-expr-gating.rs:7:5
+ |
+LL | _;
+ | ^
+ |
+ = note: see issue #71126 <https://github.com/rust-lang/rust/issues/71126> for more information
+ = help: add `#![feature(destructuring_assignment)]` to the crate attributes to enable
+
+error[E0658]: destructuring assignments are unstable
+ --> $DIR/underscore-range-expr-gating.rs:9:15
|
LL | S { x: 5, .. };
| ^^
= note: see issue #71126 <https://github.com/rust-lang/rust/issues/71126> for more information
= help: add `#![feature(destructuring_assignment)]` to the crate attributes to enable
-error: aborting due to previous error
+error: aborting due to 2 previous errors
For more information about this error, try `rustc --explain E0658`.
fn main() {
let _: usize = foo(_, _);
- //~^ ERROR expected expression
- //~| ERROR expected expression
+ //~^ ERROR `_` can only be used on the left-hand side of an assignment
+ //~| ERROR `_` can only be used on the left-hand side of an assignment
+ //~| ERROR destructuring assignments are unstable
+ //~| ERROR destructuring assignments are unstable
let _: S = S(_, _);
- //~^ ERROR expected expression
- //~| ERROR expected expression
+ //~^ ERROR `_` can only be used on the left-hand side of an assignment
+ //~| ERROR `_` can only be used on the left-hand side of an assignment
+ //~| ERROR destructuring assignments are unstable
+ //~| ERROR destructuring assignments are unstable
let _: usize = T::baz(_, _);
- //~^ ERROR expected expression
- //~| ERROR expected expression
+ //~^ ERROR `_` can only be used on the left-hand side of an assignment
+ //~| ERROR `_` can only be used on the left-hand side of an assignment
+ //~| ERROR destructuring assignments are unstable
+ //~| ERROR destructuring assignments are unstable
}
-error: expected expression, found reserved identifier `_`
+error[E0658]: destructuring assignments are unstable
--> $DIR/fn-or-tuple-struct-with-underscore-args.rs:10:24
|
LL | let _: usize = foo(_, _);
- | ^ expected expression
+ | ^
+ |
+ = note: see issue #71126 <https://github.com/rust-lang/rust/issues/71126> for more information
+ = help: add `#![feature(destructuring_assignment)]` to the crate attributes to enable
+
+error[E0658]: destructuring assignments are unstable
+ --> $DIR/fn-or-tuple-struct-with-underscore-args.rs:10:27
+ |
+LL | let _: usize = foo(_, _);
+ | ^
+ |
+ = note: see issue #71126 <https://github.com/rust-lang/rust/issues/71126> for more information
+ = help: add `#![feature(destructuring_assignment)]` to the crate attributes to enable
+
+error[E0658]: destructuring assignments are unstable
+ --> $DIR/fn-or-tuple-struct-with-underscore-args.rs:15:18
+ |
+LL | let _: S = S(_, _);
+ | ^
+ |
+ = note: see issue #71126 <https://github.com/rust-lang/rust/issues/71126> for more information
+ = help: add `#![feature(destructuring_assignment)]` to the crate attributes to enable
+
+error[E0658]: destructuring assignments are unstable
+ --> $DIR/fn-or-tuple-struct-with-underscore-args.rs:15:21
+ |
+LL | let _: S = S(_, _);
+ | ^
+ |
+ = note: see issue #71126 <https://github.com/rust-lang/rust/issues/71126> for more information
+ = help: add `#![feature(destructuring_assignment)]` to the crate attributes to enable
+
+error[E0658]: destructuring assignments are unstable
+ --> $DIR/fn-or-tuple-struct-with-underscore-args.rs:20:27
+ |
+LL | let _: usize = T::baz(_, _);
+ | ^
+ |
+ = note: see issue #71126 <https://github.com/rust-lang/rust/issues/71126> for more information
+ = help: add `#![feature(destructuring_assignment)]` to the crate attributes to enable
+
+error[E0658]: destructuring assignments are unstable
+ --> $DIR/fn-or-tuple-struct-with-underscore-args.rs:20:30
+ |
+LL | let _: usize = T::baz(_, _);
+ | ^
+ |
+ = note: see issue #71126 <https://github.com/rust-lang/rust/issues/71126> for more information
+ = help: add `#![feature(destructuring_assignment)]` to the crate attributes to enable
+
+error: in expressions, `_` can only be used on the left-hand side of an assignment
+ --> $DIR/fn-or-tuple-struct-with-underscore-args.rs:10:24
+ |
+LL | let _: usize = foo(_, _);
+ | ^ `_` not allowed here
-error: expected expression, found reserved identifier `_`
+error: in expressions, `_` can only be used on the left-hand side of an assignment
--> $DIR/fn-or-tuple-struct-with-underscore-args.rs:10:27
|
LL | let _: usize = foo(_, _);
- | ^ expected expression
+ | ^ `_` not allowed here
-error: expected expression, found reserved identifier `_`
- --> $DIR/fn-or-tuple-struct-with-underscore-args.rs:13:18
+error: in expressions, `_` can only be used on the left-hand side of an assignment
+ --> $DIR/fn-or-tuple-struct-with-underscore-args.rs:15:18
|
LL | let _: S = S(_, _);
- | ^ expected expression
+ | ^ `_` not allowed here
-error: expected expression, found reserved identifier `_`
- --> $DIR/fn-or-tuple-struct-with-underscore-args.rs:13:21
+error: in expressions, `_` can only be used on the left-hand side of an assignment
+ --> $DIR/fn-or-tuple-struct-with-underscore-args.rs:15:21
|
LL | let _: S = S(_, _);
- | ^ expected expression
+ | ^ `_` not allowed here
-error: expected expression, found reserved identifier `_`
- --> $DIR/fn-or-tuple-struct-with-underscore-args.rs:16:27
+error: in expressions, `_` can only be used on the left-hand side of an assignment
+ --> $DIR/fn-or-tuple-struct-with-underscore-args.rs:20:27
|
LL | let _: usize = T::baz(_, _);
- | ^ expected expression
+ | ^ `_` not allowed here
-error: expected expression, found reserved identifier `_`
- --> $DIR/fn-or-tuple-struct-with-underscore-args.rs:16:30
+error: in expressions, `_` can only be used on the left-hand side of an assignment
+ --> $DIR/fn-or-tuple-struct-with-underscore-args.rs:20:30
|
LL | let _: usize = T::baz(_, _);
- | ^ expected expression
+ | ^ `_` not allowed here
-error: aborting due to 6 previous errors
+error: aborting due to 12 previous errors
+For more information about this error, try `rustc --explain E0658`.
| ast::ExprKind::MacCall(..)
| ast::ExprKind::MethodCall(..)
| ast::ExprKind::Paren(..)
+ | ast::ExprKind::Underscore
| ast::ExprKind::Path(..)
| ast::ExprKind::Repeat(..)
| ast::ExprKind::Ret(..)