mirror of
https://github.com/rust-lang/rust.git
synced 2024-11-22 14:55:26 +00:00
Rollup merge of #79016 - fanzier:underscore-expressions, r=petrochenkov
Make `_` an expression, to discard values in destructuring assignments This is the third and final step towards implementing destructuring assignment (RFC: rust-lang/rfcs#2909, tracking issue: #71126). This PR is the third and final part of #71156, which was split up to allow for easier review. With this PR, an underscore `_` is parsed as an expression but is allowed *only* on the left-hand side of a destructuring assignment. There it simply discards a value, similarly to the wildcard `_` in patterns. For instance, ```rust (a, _) = (1, 2) ``` will simply assign 1 to `a` and discard the 2. Note that for consistency, ``` _ = foo ``` is also allowed and equivalent to just `foo`. Thanks to ````@varkor```` who helped with the implementation, particularly around pre-expansion gating. r? ````@petrochenkov````
This commit is contained in:
commit
f66af28641
@ -1192,6 +1192,7 @@ impl Expr {
|
|||||||
ExprKind::Field(..) => ExprPrecedence::Field,
|
ExprKind::Field(..) => ExprPrecedence::Field,
|
||||||
ExprKind::Index(..) => ExprPrecedence::Index,
|
ExprKind::Index(..) => ExprPrecedence::Index,
|
||||||
ExprKind::Range(..) => ExprPrecedence::Range,
|
ExprKind::Range(..) => ExprPrecedence::Range,
|
||||||
|
ExprKind::Underscore => ExprPrecedence::Path,
|
||||||
ExprKind::Path(..) => ExprPrecedence::Path,
|
ExprKind::Path(..) => ExprPrecedence::Path,
|
||||||
ExprKind::AddrOf(..) => ExprPrecedence::AddrOf,
|
ExprKind::AddrOf(..) => ExprPrecedence::AddrOf,
|
||||||
ExprKind::Break(..) => ExprPrecedence::Break,
|
ExprKind::Break(..) => ExprPrecedence::Break,
|
||||||
@ -1324,6 +1325,8 @@ pub enum ExprKind {
|
|||||||
Index(P<Expr>, P<Expr>),
|
Index(P<Expr>, P<Expr>),
|
||||||
/// A range (e.g., `1..2`, `1..`, `..2`, `1..=2`, `..=2`; and `..` in destructuring assingment).
|
/// A range (e.g., `1..2`, `1..`, `..2`, `1..=2`, `..=2`; and `..` in destructuring assingment).
|
||||||
Range(Option<P<Expr>>, Option<P<Expr>>, RangeLimits),
|
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
|
/// Variable reference, possibly containing `::` and/or type
|
||||||
/// parameters (e.g., `foo::bar::<baz>`).
|
/// parameters (e.g., `foo::bar::<baz>`).
|
||||||
|
@ -1232,6 +1232,7 @@ pub fn noop_visit_expr<T: MutVisitor>(
|
|||||||
visit_opt(e1, |e1| vis.visit_expr(e1));
|
visit_opt(e1, |e1| vis.visit_expr(e1));
|
||||||
visit_opt(e2, |e2| vis.visit_expr(e2));
|
visit_opt(e2, |e2| vis.visit_expr(e2));
|
||||||
}
|
}
|
||||||
|
ExprKind::Underscore => {}
|
||||||
ExprKind::Path(qself, path) => {
|
ExprKind::Path(qself, path) => {
|
||||||
vis.visit_qself(qself);
|
vis.visit_qself(qself);
|
||||||
vis.visit_path(path);
|
vis.visit_path(path);
|
||||||
|
@ -806,6 +806,7 @@ pub fn walk_expr<'a, V: Visitor<'a>>(visitor: &mut V, expression: &'a Expr) {
|
|||||||
walk_list!(visitor, visit_expr, start);
|
walk_list!(visitor, visit_expr, start);
|
||||||
walk_list!(visitor, visit_expr, end);
|
walk_list!(visitor, visit_expr, end);
|
||||||
}
|
}
|
||||||
|
ExprKind::Underscore => {}
|
||||||
ExprKind::Path(ref maybe_qself, ref path) => {
|
ExprKind::Path(ref maybe_qself, ref path) => {
|
||||||
if let Some(ref qself) = *maybe_qself {
|
if let Some(ref qself) = *maybe_qself {
|
||||||
visitor.visit_ty(&qself.ty);
|
visitor.visit_ty(&qself.ty);
|
||||||
|
@ -164,6 +164,16 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||||||
ExprKind::Range(ref e1, ref e2, lims) => {
|
ExprKind::Range(ref e1, ref e2, lims) => {
|
||||||
self.lower_expr_range(e.span, e1.as_deref(), e2.as_deref(), 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) => {
|
ExprKind::Path(ref qself, ref path) => {
|
||||||
let qpath = self.lower_qpath(
|
let qpath = self.lower_qpath(
|
||||||
e.id,
|
e.id,
|
||||||
@ -863,7 +873,10 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||||||
// Return early in case of an ordinary assignment.
|
// Return early in case of an ordinary assignment.
|
||||||
fn is_ordinary(lower_ctx: &mut LoweringContext<'_, '_>, lhs: &Expr) -> bool {
|
fn is_ordinary(lower_ctx: &mut LoweringContext<'_, '_>, lhs: &Expr) -> bool {
|
||||||
match &lhs.kind {
|
match &lhs.kind {
|
||||||
ExprKind::Array(..) | ExprKind::Struct(..) | ExprKind::Tup(..) => false,
|
ExprKind::Array(..)
|
||||||
|
| ExprKind::Struct(..)
|
||||||
|
| ExprKind::Tup(..)
|
||||||
|
| ExprKind::Underscore => false,
|
||||||
// Check for tuple struct constructor.
|
// Check for tuple struct constructor.
|
||||||
ExprKind::Call(callee, ..) => lower_ctx.extract_tuple_struct_path(callee).is_none(),
|
ExprKind::Call(callee, ..) => lower_ctx.extract_tuple_struct_path(callee).is_none(),
|
||||||
ExprKind::Paren(e) => {
|
ExprKind::Paren(e) => {
|
||||||
@ -943,6 +956,10 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||||||
assignments: &mut Vec<hir::Stmt<'hir>>,
|
assignments: &mut Vec<hir::Stmt<'hir>>,
|
||||||
) -> &'hir hir::Pat<'hir> {
|
) -> &'hir hir::Pat<'hir> {
|
||||||
match &lhs.kind {
|
match &lhs.kind {
|
||||||
|
// Underscore pattern.
|
||||||
|
ExprKind::Underscore => {
|
||||||
|
return self.pat_without_dbm(lhs.span, hir::PatKind::Wild);
|
||||||
|
}
|
||||||
// Slice patterns.
|
// Slice patterns.
|
||||||
ExprKind::Array(elements) => {
|
ExprKind::Array(elements) => {
|
||||||
let (pats, rest) =
|
let (pats, rest) =
|
||||||
|
@ -630,7 +630,11 @@ pub fn check_crate(krate: &ast::Crate, sess: &Session) {
|
|||||||
gate_all!(const_trait_impl, "const trait impls are experimental");
|
gate_all!(const_trait_impl, "const trait impls are experimental");
|
||||||
gate_all!(half_open_range_patterns, "half-open range patterns are unstable");
|
gate_all!(half_open_range_patterns, "half-open range patterns are unstable");
|
||||||
gate_all!(inline_const, "inline-const is experimental");
|
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,
|
// All uses of `gate_all!` below this point were added in #65742,
|
||||||
// and subsequently disabled (with the non-early gating readded).
|
// and subsequently disabled (with the non-early gating readded).
|
||||||
|
@ -2067,6 +2067,7 @@ impl<'a> State<'a> {
|
|||||||
self.print_expr_maybe_paren(e, fake_prec);
|
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(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::Path(Some(ref qself), ref path) => self.print_qpath(path, qself, true),
|
||||||
ast::ExprKind::Break(opt_label, ref opt_expr) => {
|
ast::ExprKind::Break(opt_label, ref opt_expr) => {
|
||||||
|
@ -1089,6 +1089,9 @@ impl<'a> Parser<'a> {
|
|||||||
self.parse_yield_expr(attrs)
|
self.parse_yield_expr(attrs)
|
||||||
} else if self.eat_keyword(kw::Let) {
|
} else if self.eat_keyword(kw::Let) {
|
||||||
self.parse_let_expr(attrs)
|
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) {
|
} else if !self.unclosed_delims.is_empty() && self.check(&token::Semi) {
|
||||||
// Don't complain about bare semicolons after unclosed braces
|
// Don't complain about bare semicolons after unclosed braces
|
||||||
// recovery in order to keep the error count down. Fixing the
|
// recovery in order to keep the error count down. Fixing the
|
||||||
|
@ -3,5 +3,6 @@ mod underscore;
|
|||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
underscore!();
|
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
|
||||||
}
|
}
|
||||||
|
@ -1,8 +1,23 @@
|
|||||||
error: expected expression, found reserved identifier `_`
|
error[E0658]: destructuring assignments are unstable
|
||||||
--> $DIR/underscore.rs:8:9
|
--> $DIR/underscore.rs:8:9
|
||||||
|
|
|
|
||||||
LL | _
|
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: 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
|
::: $DIR/main.rs:5:5
|
||||||
|
|
|
|
||||||
@ -11,5 +26,6 @@ LL | underscore!();
|
|||||||
|
|
|
|
||||||
= note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
|
= 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: aborting due to 2 previous errors
|
||||||
|
|
||||||
|
For more information about this error, try `rustc --explain E0658`.
|
||||||
|
@ -14,4 +14,7 @@ fn main() {
|
|||||||
Struct { a: TupleStruct((a, b), c), b: [d] } =
|
Struct { a: TupleStruct((a, b), c), b: [d] } =
|
||||||
Struct { a: TupleStruct((0, 1), 2), b: [3] };
|
Struct { a: TupleStruct((0, 1), 2), b: [3] };
|
||||||
assert_eq!((a, b, c, d), (0, 1, 2, 3));
|
assert_eq!((a, b, c, d), (0, 1, 2, 3));
|
||||||
|
|
||||||
|
// unnested underscore: just discard
|
||||||
|
_ = 1;
|
||||||
}
|
}
|
||||||
|
@ -9,6 +9,8 @@ fn main() {
|
|||||||
let mut c;
|
let mut c;
|
||||||
[a, .., b, c] = [1, 2, 3, 4, 5];
|
[a, .., b, c] = [1, 2, 3, 4, 5];
|
||||||
assert_eq!((a, b, c), (1, 4, 5));
|
assert_eq!((a, b, c), (1, 4, 5));
|
||||||
|
[_, a, _] = [1, 2, 3];
|
||||||
|
assert_eq!((a, b), (2, 4));
|
||||||
[..] = [1, 2, 3];
|
[..] = [1, 2, 3];
|
||||||
[c, ..] = [5, 6, 6];
|
[c, ..] = [5, 6, 6];
|
||||||
assert_eq!(c, 5);
|
assert_eq!(c, 5);
|
||||||
|
@ -4,4 +4,5 @@ fn main() {
|
|||||||
let (mut a, mut b);
|
let (mut a, mut b);
|
||||||
[a, .., b, ..] = [0, 1]; //~ ERROR `..` can only be used once per slice pattern
|
[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
|
[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
|
||||||
}
|
}
|
||||||
|
@ -12,6 +12,12 @@ error[E0527]: pattern requires 3 elements but array has 2
|
|||||||
LL | [a, a, b] = [1, 2];
|
LL | [a, a, b] = [1, 2];
|
||||||
| ^^^^^^^^^ expected 2 elements
|
| ^^^^^^^^^ 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`.
|
For more information about this error, try `rustc --explain E0527`.
|
||||||
|
@ -12,8 +12,10 @@ fn main() {
|
|||||||
assert_eq!((a, b), (0, 1));
|
assert_eq!((a, b), (0, 1));
|
||||||
Struct { a: b, b: a } = Struct { a: 1, b: 2 };
|
Struct { a: b, b: a } = Struct { a: 1, b: 2 };
|
||||||
assert_eq!((a,b), (2, 1));
|
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 };
|
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 };
|
Struct { .. } = Struct { a: 1, b: 4 };
|
||||||
assert_eq!((a, b), (1, 1));
|
assert_eq!((a, b), (1, 2));
|
||||||
}
|
}
|
||||||
|
@ -9,6 +9,8 @@ fn main() {
|
|||||||
let mut c;
|
let mut c;
|
||||||
let d = Struct { a: 0, b: 1 };
|
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, 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 };
|
Struct { a, ..d } = Struct { a: 1, b: 2 };
|
||||||
//~^ ERROR functional record updates are not allowed in destructuring assignments
|
//~^ ERROR functional record updates are not allowed in destructuring assignments
|
||||||
Struct { a, .. }; //~ ERROR base expression required after `..`
|
Struct { a, .. }; //~ ERROR base expression required after `..`
|
||||||
|
@ -1,11 +1,19 @@
|
|||||||
|
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
|
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 };
|
LL | Struct { a, ..d } = Struct { a: 1, b: 2 };
|
||||||
| ^ help: consider removing the trailing pattern
|
| ^ help: consider removing the trailing pattern
|
||||||
|
|
||||||
error: base expression required after `..`
|
error: base expression required after `..`
|
||||||
--> $DIR/struct_destructure_fail.rs:14:19
|
--> $DIR/struct_destructure_fail.rs:16:19
|
||||||
|
|
|
|
||||||
LL | Struct { a, .. };
|
LL | Struct { a, .. };
|
||||||
| ^ add a base expression here
|
| ^ add a base expression here
|
||||||
@ -16,6 +24,22 @@ error[E0026]: struct `Struct` does not have a field named `c`
|
|||||||
LL | Struct { a, b, c } = Struct { a: 0, b: 1 };
|
LL | Struct { a, b, c } = Struct { a: 0, b: 1 };
|
||||||
| ^ struct `Struct` does not have this field
|
| ^ 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 };
|
||||||
|
| ^^^^
|
||||||
|
|
||||||
For more information about this error, try `rustc --explain E0026`.
|
error: aborting due to 5 previous errors
|
||||||
|
|
||||||
|
Some errors have detailed explanations: E0026, E0027.
|
||||||
|
For more information about an error, try `rustc --explain E0026`.
|
||||||
|
@ -16,6 +16,8 @@ fn main() {
|
|||||||
assert_eq!((a, b), (2, 2));
|
assert_eq!((a, b), (2, 2));
|
||||||
(b, ..) = (5, 6, 7);
|
(b, ..) = (5, 6, 7);
|
||||||
assert_eq!(b, 5);
|
assert_eq!(b, 5);
|
||||||
|
(a, _) = (8, 9);
|
||||||
|
assert_eq!(a, 8);
|
||||||
|
|
||||||
// Test for a non-Copy type (String):
|
// Test for a non-Copy type (String):
|
||||||
let (mut c, mut d);
|
let (mut c, mut d);
|
||||||
|
@ -7,4 +7,5 @@ fn main() {
|
|||||||
(a, .., b, ..) = (0, 1); //~ ERROR `..` can only be used once per tuple pattern
|
(a, .., b, ..) = (0, 1); //~ ERROR `..` can only be used once per tuple pattern
|
||||||
(a, a, b) = (1, 2); //~ ERROR mismatched types
|
(a, a, b) = (1, 2); //~ ERROR mismatched types
|
||||||
(C, ..) = (0,1); //~ ERROR invalid left-hand side of assignment
|
(C, ..) = (0,1); //~ ERROR invalid left-hand side of assignment
|
||||||
|
(_,) = (1, 2); //~ ERROR mismatched types
|
||||||
}
|
}
|
||||||
|
@ -25,7 +25,18 @@ LL | (C, ..) = (0,1);
|
|||||||
| |
|
| |
|
||||||
| cannot assign to this expression
|
| 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.
|
Some errors have detailed explanations: E0070, E0308.
|
||||||
For more information about an error, try `rustc --explain E0070`.
|
For more information about an error, try `rustc --explain E0070`.
|
||||||
|
@ -23,8 +23,10 @@ fn main() {
|
|||||||
assert_eq!((a, b), (0, 1));
|
assert_eq!((a, b), (0, 1));
|
||||||
TupleStruct(a, .., b) = TupleStruct(1, 2);
|
TupleStruct(a, .., b) = TupleStruct(1, 2);
|
||||||
assert_eq!((a, b), (1, 2));
|
assert_eq!((a, b), (1, 2));
|
||||||
|
TupleStruct(_, a) = TupleStruct(2, 2);
|
||||||
|
assert_eq!((a, b), (2, 2));
|
||||||
TupleStruct(..) = TupleStruct(3, 4);
|
TupleStruct(..) = TupleStruct(3, 4);
|
||||||
assert_eq!((a, b), (1, 2));
|
assert_eq!((a, b), (2, 2));
|
||||||
TupleStruct(5,6).assign(&mut a, &mut b);
|
TupleStruct(5,6).assign(&mut a, &mut b);
|
||||||
assert_eq!((a, b), (5, 6));
|
assert_eq!((a, b), (5, 6));
|
||||||
Enum::SingleVariant(a, b) = Enum::SingleVariant(7, 8);
|
Enum::SingleVariant(a, b) = Enum::SingleVariant(7, 8);
|
||||||
|
@ -29,8 +29,12 @@ fn main() {
|
|||||||
|
|
||||||
TupleStruct(a, a, b) = TupleStruct(1, 2);
|
TupleStruct(a, a, b) = TupleStruct(1, 2);
|
||||||
//~^ ERROR this pattern has 3 fields, but the corresponding tuple struct has 2 fields
|
//~^ 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);
|
Enum::SingleVariant(a, a, b) = Enum::SingleVariant(1, 2);
|
||||||
//~^ ERROR this pattern has 3 fields, but the corresponding tuple variant has 2 fields
|
//~^ 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:
|
// Check if `test` is recognized as not a tuple struct but a function call:
|
||||||
test() = TupleStruct(0, 0);
|
test() = TupleStruct(0, 0);
|
||||||
|
@ -23,17 +23,35 @@ LL | struct TupleStruct<S, T>(S, T);
|
|||||||
LL | TupleStruct(a, a, b) = TupleStruct(1, 2);
|
LL | TupleStruct(a, a, b) = TupleStruct(1, 2);
|
||||||
| ^^^^^^^^^^^^^^^^^^^^ expected 2 fields, found 3
|
| ^^^^^^^^^^^^^^^^^^^^ 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
|
--> $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)
|
LL | SingleVariant(S, T)
|
||||||
| ------------------- tuple variant defined here
|
| ------------------- tuple variant defined here
|
||||||
...
|
...
|
||||||
LL | Enum::SingleVariant(a, a, b) = Enum::SingleVariant(1, 2);
|
LL | Enum::SingleVariant(a, a, b) = Enum::SingleVariant(1, 2);
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected 2 fields, found 3
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 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
|
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);
|
LL | test() = TupleStruct(0, 0);
|
||||||
| ------ ^
|
| ------ ^
|
||||||
@ -41,7 +59,7 @@ LL | test() = TupleStruct(0, 0);
|
|||||||
| cannot assign to this expression
|
| cannot assign to this expression
|
||||||
|
|
||||||
error[E0070]: invalid left-hand side of assignment
|
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);
|
LL | (test)() = TupleStruct(0, 0);
|
||||||
| -------- ^
|
| -------- ^
|
||||||
@ -49,14 +67,14 @@ LL | (test)() = TupleStruct(0, 0);
|
|||||||
| cannot assign to this expression
|
| cannot assign to this expression
|
||||||
|
|
||||||
error[E0070]: invalid left-hand side of assignment
|
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);
|
LL | <Alias::<isize> as Test>::test() = TupleStruct(0, 0);
|
||||||
| -------------------------------- ^
|
| -------------------------------- ^
|
||||||
| |
|
| |
|
||||||
| cannot assign to this expression
|
| 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.
|
Some errors have detailed explanations: E0023, E0070.
|
||||||
For more information about an error, try `rustc --explain E0023`.
|
For more information about an error, try `rustc --explain E0023`.
|
||||||
|
@ -4,5 +4,7 @@ struct S { x : u32 }
|
|||||||
|
|
||||||
#[cfg(FALSE)]
|
#[cfg(FALSE)]
|
||||||
fn foo() {
|
fn foo() {
|
||||||
|
_; //~ ERROR destructuring assignments are unstable
|
||||||
|
|
||||||
S { x: 5, .. }; //~ ERROR destructuring assignments are unstable
|
S { x: 5, .. }; //~ ERROR destructuring assignments are unstable
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,14 @@
|
|||||||
error[E0658]: 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, .. };
|
LL | S { x: 5, .. };
|
||||||
| ^^
|
| ^^
|
||||||
@ -7,6 +16,6 @@ LL | S { x: 5, .. };
|
|||||||
= note: see issue #71126 <https://github.com/rust-lang/rust/issues/71126> for more information
|
= 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
|
= 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`.
|
For more information about this error, try `rustc --explain E0658`.
|
||||||
|
@ -8,12 +8,18 @@ trait T {
|
|||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let _: usize = foo(_, _);
|
let _: usize = foo(_, _);
|
||||||
//~^ ERROR expected expression
|
//~^ ERROR `_` can only be used on the left-hand side of an assignment
|
||||||
//~| ERROR expected expression
|
//~| 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(_, _);
|
let _: S = S(_, _);
|
||||||
//~^ ERROR expected expression
|
//~^ ERROR `_` can only be used on the left-hand side of an assignment
|
||||||
//~| ERROR expected expression
|
//~| 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(_, _);
|
let _: usize = T::baz(_, _);
|
||||||
//~^ ERROR expected expression
|
//~^ ERROR `_` can only be used on the left-hand side of an assignment
|
||||||
//~| ERROR expected expression
|
//~| ERROR `_` can only be used on the left-hand side of an assignment
|
||||||
|
//~| ERROR destructuring assignments are unstable
|
||||||
|
//~| ERROR destructuring assignments are unstable
|
||||||
}
|
}
|
||||||
|
@ -1,38 +1,93 @@
|
|||||||
error: expected expression, found reserved identifier `_`
|
error[E0658]: destructuring assignments are unstable
|
||||||
--> $DIR/fn-or-tuple-struct-with-underscore-args.rs:10:24
|
--> $DIR/fn-or-tuple-struct-with-underscore-args.rs:10:24
|
||||||
|
|
|
|
||||||
LL | let _: usize = foo(_, _);
|
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: expected expression, found reserved identifier `_`
|
error[E0658]: destructuring assignments are unstable
|
||||||
--> $DIR/fn-or-tuple-struct-with-underscore-args.rs:10:27
|
--> $DIR/fn-or-tuple-struct-with-underscore-args.rs:10:27
|
||||||
|
|
|
|
||||||
LL | let _: usize = foo(_, _);
|
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: expected expression, found reserved identifier `_`
|
error[E0658]: destructuring assignments are unstable
|
||||||
--> $DIR/fn-or-tuple-struct-with-underscore-args.rs:13:18
|
--> $DIR/fn-or-tuple-struct-with-underscore-args.rs:15:18
|
||||||
|
|
|
|
||||||
LL | let _: S = S(_, _);
|
LL | let _: S = S(_, _);
|
||||||
| ^ 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: expected expression, found reserved identifier `_`
|
error[E0658]: destructuring assignments are unstable
|
||||||
--> $DIR/fn-or-tuple-struct-with-underscore-args.rs:13:21
|
--> $DIR/fn-or-tuple-struct-with-underscore-args.rs:15:21
|
||||||
|
|
|
|
||||||
LL | let _: S = S(_, _);
|
LL | let _: S = S(_, _);
|
||||||
| ^ 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: expected expression, found reserved identifier `_`
|
error[E0658]: destructuring assignments are unstable
|
||||||
--> $DIR/fn-or-tuple-struct-with-underscore-args.rs:16:27
|
--> $DIR/fn-or-tuple-struct-with-underscore-args.rs:20:27
|
||||||
|
|
|
|
||||||
LL | let _: usize = T::baz(_, _);
|
LL | let _: usize = T::baz(_, _);
|
||||||
| ^ 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: expected expression, found reserved identifier `_`
|
error[E0658]: destructuring assignments are unstable
|
||||||
--> $DIR/fn-or-tuple-struct-with-underscore-args.rs:16:30
|
--> $DIR/fn-or-tuple-struct-with-underscore-args.rs:20:30
|
||||||
|
|
|
|
||||||
LL | let _: usize = T::baz(_, _);
|
LL | let _: usize = T::baz(_, _);
|
||||||
| ^ 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: aborting due to 6 previous errors
|
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: 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(_, _);
|
||||||
|
| ^ `_` not allowed here
|
||||||
|
|
||||||
|
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(_, _);
|
||||||
|
| ^ `_` not allowed here
|
||||||
|
|
||||||
|
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(_, _);
|
||||||
|
| ^ `_` not allowed here
|
||||||
|
|
||||||
|
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(_, _);
|
||||||
|
| ^ `_` not allowed here
|
||||||
|
|
||||||
|
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(_, _);
|
||||||
|
| ^ `_` not allowed here
|
||||||
|
|
||||||
|
error: aborting due to 12 previous errors
|
||||||
|
|
||||||
|
For more information about this error, try `rustc --explain E0658`.
|
||||||
|
@ -170,6 +170,7 @@ impl<'a> Sugg<'a> {
|
|||||||
| ast::ExprKind::MacCall(..)
|
| ast::ExprKind::MacCall(..)
|
||||||
| ast::ExprKind::MethodCall(..)
|
| ast::ExprKind::MethodCall(..)
|
||||||
| ast::ExprKind::Paren(..)
|
| ast::ExprKind::Paren(..)
|
||||||
|
| ast::ExprKind::Underscore
|
||||||
| ast::ExprKind::Path(..)
|
| ast::ExprKind::Path(..)
|
||||||
| ast::ExprKind::Repeat(..)
|
| ast::ExprKind::Repeat(..)
|
||||||
| ast::ExprKind::Ret(..)
|
| ast::ExprKind::Ret(..)
|
||||||
|
Loading…
Reference in New Issue
Block a user