Implement destructuring assignment for structs and slices
Co-authored-by: varkor <github@varkor.com>
This commit is contained in:
parent
cf9cf7c923
commit
de84ad95b4
32 changed files with 619 additions and 108 deletions
|
@ -1061,7 +1061,7 @@ pub struct Expr {
|
||||||
|
|
||||||
// `Expr` is used a lot. Make sure it doesn't unintentionally get bigger.
|
// `Expr` is used a lot. Make sure it doesn't unintentionally get bigger.
|
||||||
#[cfg(target_arch = "x86_64")]
|
#[cfg(target_arch = "x86_64")]
|
||||||
rustc_data_structures::static_assert_size!(Expr, 112);
|
rustc_data_structures::static_assert_size!(Expr, 120);
|
||||||
|
|
||||||
impl Expr {
|
impl Expr {
|
||||||
/// Returns `true` if this expression would be valid somewhere that expects a value;
|
/// Returns `true` if this expression would be valid somewhere that expects a value;
|
||||||
|
@ -1218,6 +1218,16 @@ pub enum RangeLimits {
|
||||||
Closed,
|
Closed,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Encodable, Decodable, Debug)]
|
||||||
|
pub enum StructRest {
|
||||||
|
/// `..x`.
|
||||||
|
Base(P<Expr>),
|
||||||
|
/// `..`.
|
||||||
|
Rest(Span),
|
||||||
|
/// No trailing `..` or expression.
|
||||||
|
None,
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Clone, Encodable, Decodable, Debug)]
|
#[derive(Clone, Encodable, Decodable, Debug)]
|
||||||
pub enum ExprKind {
|
pub enum ExprKind {
|
||||||
/// A `box x` expression.
|
/// A `box x` expression.
|
||||||
|
@ -1312,7 +1322,7 @@ pub enum ExprKind {
|
||||||
Field(P<Expr>, Ident),
|
Field(P<Expr>, Ident),
|
||||||
/// An indexing operation (e.g., `foo[2]`).
|
/// An indexing operation (e.g., `foo[2]`).
|
||||||
Index(P<Expr>, P<Expr>),
|
Index(P<Expr>, P<Expr>),
|
||||||
/// A range (e.g., `1..2`, `1..`, `..2`, `1..=2`, `..=2`).
|
/// 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),
|
||||||
|
|
||||||
/// Variable reference, possibly containing `::` and/or type
|
/// Variable reference, possibly containing `::` and/or type
|
||||||
|
@ -1340,9 +1350,8 @@ pub enum ExprKind {
|
||||||
|
|
||||||
/// A struct literal expression.
|
/// A struct literal expression.
|
||||||
///
|
///
|
||||||
/// E.g., `Foo {x: 1, y: 2}`, or `Foo {x: 1, .. base}`,
|
/// E.g., `Foo {x: 1, y: 2}`, or `Foo {x: 1, .. rest}`.
|
||||||
/// where `base` is the `Option<Expr>`.
|
Struct(Path, Vec<Field>, StructRest),
|
||||||
Struct(Path, Vec<Field>, Option<P<Expr>>),
|
|
||||||
|
|
||||||
/// An array literal constructed from one repeated element.
|
/// An array literal constructed from one repeated element.
|
||||||
///
|
///
|
||||||
|
|
|
@ -1288,7 +1288,11 @@ pub fn noop_visit_expr<T: MutVisitor>(
|
||||||
ExprKind::Struct(path, fields, expr) => {
|
ExprKind::Struct(path, fields, expr) => {
|
||||||
vis.visit_path(path);
|
vis.visit_path(path);
|
||||||
fields.flat_map_in_place(|field| vis.flat_map_field(field));
|
fields.flat_map_in_place(|field| vis.flat_map_field(field));
|
||||||
visit_opt(expr, |expr| vis.visit_expr(expr));
|
match expr {
|
||||||
|
StructRest::Base(expr) => vis.visit_expr(expr),
|
||||||
|
StructRest::Rest(_span) => {}
|
||||||
|
StructRest::None => {}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
ExprKind::Paren(expr) => {
|
ExprKind::Paren(expr) => {
|
||||||
vis.visit_expr(expr);
|
vis.visit_expr(expr);
|
||||||
|
|
|
@ -719,7 +719,11 @@ pub fn walk_expr<'a, V: Visitor<'a>>(visitor: &mut V, expression: &'a Expr) {
|
||||||
ExprKind::Struct(ref path, ref fields, ref optional_base) => {
|
ExprKind::Struct(ref path, ref fields, ref optional_base) => {
|
||||||
visitor.visit_path(path, expression.id);
|
visitor.visit_path(path, expression.id);
|
||||||
walk_list!(visitor, visit_field, fields);
|
walk_list!(visitor, visit_field, fields);
|
||||||
walk_list!(visitor, visit_expr, optional_base);
|
match optional_base {
|
||||||
|
StructRest::Base(expr) => visitor.visit_expr(expr),
|
||||||
|
StructRest::Rest(_span) => {}
|
||||||
|
StructRest::None => {}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
ExprKind::Tup(ref subexpressions) => {
|
ExprKind::Tup(ref subexpressions) => {
|
||||||
walk_list!(visitor, visit_expr, subexpressions);
|
walk_list!(visitor, visit_expr, subexpressions);
|
||||||
|
|
|
@ -187,8 +187,18 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||||
}
|
}
|
||||||
ExprKind::InlineAsm(ref asm) => self.lower_expr_asm(e.span, asm),
|
ExprKind::InlineAsm(ref asm) => self.lower_expr_asm(e.span, asm),
|
||||||
ExprKind::LlvmInlineAsm(ref asm) => self.lower_expr_llvm_asm(asm),
|
ExprKind::LlvmInlineAsm(ref asm) => self.lower_expr_llvm_asm(asm),
|
||||||
ExprKind::Struct(ref path, ref fields, ref maybe_expr) => {
|
ExprKind::Struct(ref path, ref fields, ref rest) => {
|
||||||
let maybe_expr = maybe_expr.as_ref().map(|x| self.lower_expr(x));
|
let rest = match rest {
|
||||||
|
StructRest::Base(e) => Some(self.lower_expr(e)),
|
||||||
|
StructRest::Rest(sp) => {
|
||||||
|
self.sess
|
||||||
|
.struct_span_err(*sp, "base expression required after `..`")
|
||||||
|
.span_label(*sp, "add a base expression here")
|
||||||
|
.emit();
|
||||||
|
Some(&*self.arena.alloc(self.expr_err(*sp)))
|
||||||
|
}
|
||||||
|
StructRest::None => None,
|
||||||
|
};
|
||||||
hir::ExprKind::Struct(
|
hir::ExprKind::Struct(
|
||||||
self.arena.alloc(self.lower_qpath(
|
self.arena.alloc(self.lower_qpath(
|
||||||
e.id,
|
e.id,
|
||||||
|
@ -198,7 +208,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||||
ImplTraitContext::disallowed(),
|
ImplTraitContext::disallowed(),
|
||||||
)),
|
)),
|
||||||
self.arena.alloc_from_iter(fields.iter().map(|x| self.lower_field(x))),
|
self.arena.alloc_from_iter(fields.iter().map(|x| self.lower_field(x))),
|
||||||
maybe_expr,
|
rest,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
ExprKind::Yield(ref opt_expr) => self.lower_expr_yield(e.span, opt_expr.as_deref()),
|
ExprKind::Yield(ref opt_expr) => self.lower_expr_yield(e.span, opt_expr.as_deref()),
|
||||||
|
@ -851,20 +861,22 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||||
whole_span: Span,
|
whole_span: Span,
|
||||||
) -> hir::ExprKind<'hir> {
|
) -> hir::ExprKind<'hir> {
|
||||||
// Return early in case of an ordinary assignment.
|
// Return early in case of an ordinary assignment.
|
||||||
fn is_ordinary(lhs: &Expr) -> bool {
|
fn is_ordinary(lower_ctx: &mut LoweringContext<'_, '_>, lhs: &Expr) -> bool {
|
||||||
match &lhs.kind {
|
match &lhs.kind {
|
||||||
ExprKind::Tup(..) => false,
|
ExprKind::Array(..) | ExprKind::Struct(..) | ExprKind::Tup(..) => false,
|
||||||
|
// Check for tuple struct constructor.
|
||||||
|
ExprKind::Call(callee, ..) => lower_ctx.extract_tuple_struct_path(callee).is_none(),
|
||||||
ExprKind::Paren(e) => {
|
ExprKind::Paren(e) => {
|
||||||
match e.kind {
|
match e.kind {
|
||||||
// We special-case `(..)` for consistency with patterns.
|
// We special-case `(..)` for consistency with patterns.
|
||||||
ExprKind::Range(None, None, RangeLimits::HalfOpen) => false,
|
ExprKind::Range(None, None, RangeLimits::HalfOpen) => false,
|
||||||
_ => is_ordinary(e),
|
_ => is_ordinary(lower_ctx, e),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ => true,
|
_ => true,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if is_ordinary(lhs) {
|
if is_ordinary(self, lhs) {
|
||||||
return hir::ExprKind::Assign(self.lower_expr(lhs), self.lower_expr(rhs), eq_sign_span);
|
return hir::ExprKind::Assign(self.lower_expr(lhs), self.lower_expr(rhs), eq_sign_span);
|
||||||
}
|
}
|
||||||
if !self.sess.features_untracked().destructuring_assignment {
|
if !self.sess.features_untracked().destructuring_assignment {
|
||||||
|
@ -902,6 +914,26 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||||
hir::ExprKind::Block(&self.block_all(whole_span, stmts, None), None)
|
hir::ExprKind::Block(&self.block_all(whole_span, stmts, None), None)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// If the given expression is a path to a tuple struct, returns that path.
|
||||||
|
/// It is not a complete check, but just tries to reject most paths early
|
||||||
|
/// if they are not tuple structs.
|
||||||
|
/// Type checking will take care of the full validation later.
|
||||||
|
fn extract_tuple_struct_path<'a>(&mut self, expr: &'a Expr) -> Option<&'a Path> {
|
||||||
|
// For tuple struct destructuring, it must be a non-qualified path (like in patterns).
|
||||||
|
if let ExprKind::Path(None, path) = &expr.kind {
|
||||||
|
// Does the path resolves to something disallowed in a tuple struct/variant pattern?
|
||||||
|
if let Some(partial_res) = self.resolver.get_partial_res(expr.id) {
|
||||||
|
if partial_res.unresolved_segments() == 0
|
||||||
|
&& !partial_res.base_res().expected_in_tuple_struct_pat()
|
||||||
|
{
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return Some(path);
|
||||||
|
}
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|
||||||
/// Convert the LHS of a destructuring assignment to a pattern.
|
/// Convert the LHS of a destructuring assignment to a pattern.
|
||||||
/// Each sub-assignment is recorded in `assignments`.
|
/// Each sub-assignment is recorded in `assignments`.
|
||||||
fn destructure_assign(
|
fn destructure_assign(
|
||||||
|
@ -911,6 +943,86 @@ 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 {
|
||||||
|
// Slice patterns.
|
||||||
|
ExprKind::Array(elements) => {
|
||||||
|
let (pats, rest) =
|
||||||
|
self.destructure_sequence(elements, "slice", eq_sign_span, assignments);
|
||||||
|
let slice_pat = if let Some((i, span)) = rest {
|
||||||
|
let (before, after) = pats.split_at(i);
|
||||||
|
hir::PatKind::Slice(
|
||||||
|
before,
|
||||||
|
Some(self.pat_without_dbm(span, hir::PatKind::Wild)),
|
||||||
|
after,
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
hir::PatKind::Slice(pats, None, &[])
|
||||||
|
};
|
||||||
|
return self.pat_without_dbm(lhs.span, slice_pat);
|
||||||
|
}
|
||||||
|
// Tuple structs.
|
||||||
|
ExprKind::Call(callee, args) => {
|
||||||
|
if let Some(path) = self.extract_tuple_struct_path(callee) {
|
||||||
|
let (pats, rest) = self.destructure_sequence(
|
||||||
|
args,
|
||||||
|
"tuple struct or variant",
|
||||||
|
eq_sign_span,
|
||||||
|
assignments,
|
||||||
|
);
|
||||||
|
let qpath = self.lower_qpath(
|
||||||
|
callee.id,
|
||||||
|
&None,
|
||||||
|
path,
|
||||||
|
ParamMode::Optional,
|
||||||
|
ImplTraitContext::disallowed(),
|
||||||
|
);
|
||||||
|
// Destructure like a tuple struct.
|
||||||
|
let tuple_struct_pat =
|
||||||
|
hir::PatKind::TupleStruct(qpath, pats, rest.map(|r| r.0));
|
||||||
|
return self.pat_without_dbm(lhs.span, tuple_struct_pat);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Structs.
|
||||||
|
ExprKind::Struct(path, fields, rest) => {
|
||||||
|
let field_pats = self.arena.alloc_from_iter(fields.iter().map(|f| {
|
||||||
|
let pat = self.destructure_assign(&f.expr, eq_sign_span, assignments);
|
||||||
|
hir::FieldPat {
|
||||||
|
hir_id: self.next_id(),
|
||||||
|
ident: f.ident,
|
||||||
|
pat,
|
||||||
|
is_shorthand: f.is_shorthand,
|
||||||
|
span: f.span,
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
let qpath = self.lower_qpath(
|
||||||
|
lhs.id,
|
||||||
|
&None,
|
||||||
|
path,
|
||||||
|
ParamMode::Optional,
|
||||||
|
ImplTraitContext::disallowed(),
|
||||||
|
);
|
||||||
|
let fields_omitted = match rest {
|
||||||
|
StructRest::Base(e) => {
|
||||||
|
self.sess
|
||||||
|
.struct_span_err(
|
||||||
|
e.span,
|
||||||
|
"functional record updates are not allowed in destructuring \
|
||||||
|
assignments",
|
||||||
|
)
|
||||||
|
.span_suggestion(
|
||||||
|
e.span,
|
||||||
|
"consider removing the trailing pattern",
|
||||||
|
String::new(),
|
||||||
|
rustc_errors::Applicability::MachineApplicable,
|
||||||
|
)
|
||||||
|
.emit();
|
||||||
|
true
|
||||||
|
}
|
||||||
|
StructRest::Rest(_) => true,
|
||||||
|
StructRest::None => false,
|
||||||
|
};
|
||||||
|
let struct_pat = hir::PatKind::Struct(qpath, field_pats, fields_omitted);
|
||||||
|
return self.pat_without_dbm(lhs.span, struct_pat);
|
||||||
|
}
|
||||||
// Tuples.
|
// Tuples.
|
||||||
ExprKind::Tup(elements) => {
|
ExprKind::Tup(elements) => {
|
||||||
let (pats, rest) =
|
let (pats, rest) =
|
||||||
|
|
|
@ -630,6 +630,7 @@ 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");
|
||||||
|
|
||||||
// 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).
|
||||||
|
|
|
@ -1729,7 +1729,7 @@ impl<'a> State<'a> {
|
||||||
&mut self,
|
&mut self,
|
||||||
path: &ast::Path,
|
path: &ast::Path,
|
||||||
fields: &[ast::Field],
|
fields: &[ast::Field],
|
||||||
wth: &Option<P<ast::Expr>>,
|
rest: &ast::StructRest,
|
||||||
attrs: &[ast::Attribute],
|
attrs: &[ast::Attribute],
|
||||||
) {
|
) {
|
||||||
self.print_path(path, true, 0);
|
self.print_path(path, true, 0);
|
||||||
|
@ -1750,22 +1750,21 @@ impl<'a> State<'a> {
|
||||||
},
|
},
|
||||||
|f| f.span,
|
|f| f.span,
|
||||||
);
|
);
|
||||||
match *wth {
|
match rest {
|
||||||
Some(ref expr) => {
|
ast::StructRest::Base(_) | ast::StructRest::Rest(_) => {
|
||||||
self.ibox(INDENT_UNIT);
|
self.ibox(INDENT_UNIT);
|
||||||
if !fields.is_empty() {
|
if !fields.is_empty() {
|
||||||
self.s.word(",");
|
self.s.word(",");
|
||||||
self.s.space();
|
self.s.space();
|
||||||
}
|
}
|
||||||
self.s.word("..");
|
self.s.word("..");
|
||||||
self.print_expr(expr);
|
if let ast::StructRest::Base(ref expr) = *rest {
|
||||||
|
self.print_expr(expr);
|
||||||
|
}
|
||||||
self.end();
|
self.end();
|
||||||
}
|
}
|
||||||
_ => {
|
ast::StructRest::None if !fields.is_empty() => self.s.word(","),
|
||||||
if !fields.is_empty() {
|
_ => {}
|
||||||
self.s.word(",")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
self.s.word("}");
|
self.s.word("}");
|
||||||
}
|
}
|
||||||
|
@ -1891,8 +1890,8 @@ impl<'a> State<'a> {
|
||||||
ast::ExprKind::Repeat(ref element, ref count) => {
|
ast::ExprKind::Repeat(ref element, ref count) => {
|
||||||
self.print_expr_repeat(element, count, attrs);
|
self.print_expr_repeat(element, count, attrs);
|
||||||
}
|
}
|
||||||
ast::ExprKind::Struct(ref path, ref fields, ref wth) => {
|
ast::ExprKind::Struct(ref path, ref fields, ref rest) => {
|
||||||
self.print_expr_struct(path, &fields[..], wth, attrs);
|
self.print_expr_struct(path, &fields[..], rest, attrs);
|
||||||
}
|
}
|
||||||
ast::ExprKind::Tup(ref exprs) => {
|
ast::ExprKind::Tup(ref exprs) => {
|
||||||
self.print_expr_tup(&exprs[..], attrs);
|
self.print_expr_tup(&exprs[..], attrs);
|
||||||
|
|
|
@ -298,7 +298,7 @@ impl<'a> ExtCtxt<'a> {
|
||||||
path: ast::Path,
|
path: ast::Path,
|
||||||
fields: Vec<ast::Field>,
|
fields: Vec<ast::Field>,
|
||||||
) -> P<ast::Expr> {
|
) -> P<ast::Expr> {
|
||||||
self.expr(span, ast::ExprKind::Struct(path, fields, None))
|
self.expr(span, ast::ExprKind::Struct(path, fields, ast::StructRest::None))
|
||||||
}
|
}
|
||||||
pub fn expr_struct_ident(
|
pub fn expr_struct_ident(
|
||||||
&self,
|
&self,
|
||||||
|
|
|
@ -484,4 +484,9 @@ impl<Id> Res<Id> {
|
||||||
pub fn matches_ns(&self, ns: Namespace) -> bool {
|
pub fn matches_ns(&self, ns: Namespace) -> bool {
|
||||||
self.ns().map_or(true, |actual_ns| actual_ns == ns)
|
self.ns().map_or(true, |actual_ns| actual_ns == ns)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns whether such a resolved path can occur in a tuple struct/variant pattern
|
||||||
|
pub fn expected_in_tuple_struct_pat(&self) -> bool {
|
||||||
|
matches!(self, Res::Def(DefKind::Ctor(_, CtorKind::Fn), _) | Res::SelfCtor(..))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2087,7 +2087,7 @@ impl<'a> Parser<'a> {
|
||||||
recover: bool,
|
recover: bool,
|
||||||
) -> PResult<'a, P<Expr>> {
|
) -> PResult<'a, P<Expr>> {
|
||||||
let mut fields = Vec::new();
|
let mut fields = Vec::new();
|
||||||
let mut base = None;
|
let mut base = ast::StructRest::None;
|
||||||
let mut recover_async = false;
|
let mut recover_async = false;
|
||||||
|
|
||||||
attrs.extend(self.parse_inner_attributes()?);
|
attrs.extend(self.parse_inner_attributes()?);
|
||||||
|
@ -2102,8 +2102,14 @@ impl<'a> Parser<'a> {
|
||||||
while self.token != token::CloseDelim(token::Brace) {
|
while self.token != token::CloseDelim(token::Brace) {
|
||||||
if self.eat(&token::DotDot) {
|
if self.eat(&token::DotDot) {
|
||||||
let exp_span = self.prev_token.span;
|
let exp_span = self.prev_token.span;
|
||||||
|
// We permit `.. }` on the left-hand side of a destructuring assignment.
|
||||||
|
if self.check(&token::CloseDelim(token::Brace)) {
|
||||||
|
self.sess.gated_spans.gate(sym::destructuring_assignment, self.prev_token.span);
|
||||||
|
base = ast::StructRest::Rest(self.prev_token.span.shrink_to_hi());
|
||||||
|
break;
|
||||||
|
}
|
||||||
match self.parse_expr() {
|
match self.parse_expr() {
|
||||||
Ok(e) => base = Some(e),
|
Ok(e) => base = ast::StructRest::Base(e),
|
||||||
Err(mut e) if recover => {
|
Err(mut e) if recover => {
|
||||||
e.emit();
|
e.emit();
|
||||||
self.recover_stmt();
|
self.recover_stmt();
|
||||||
|
|
|
@ -298,9 +298,7 @@ impl<'a> PathSource<'a> {
|
||||||
_,
|
_,
|
||||||
)
|
)
|
||||||
| Res::SelfCtor(..)),
|
| Res::SelfCtor(..)),
|
||||||
PathSource::TupleStruct(..) => {
|
PathSource::TupleStruct(..) => res.expected_in_tuple_struct_pat(),
|
||||||
matches!(res, Res::Def(DefKind::Ctor(_, CtorKind::Fn), _) | Res::SelfCtor(..))
|
|
||||||
}
|
|
||||||
PathSource::Struct => matches!(res, Res::Def(
|
PathSource::Struct => matches!(res, Res::Def(
|
||||||
DefKind::Struct
|
DefKind::Struct
|
||||||
| DefKind::Union
|
| DefKind::Union
|
||||||
|
|
|
@ -816,7 +816,7 @@ impl<'tcx> DumpVisitor<'tcx> {
|
||||||
path: &'tcx hir::QPath<'tcx>,
|
path: &'tcx hir::QPath<'tcx>,
|
||||||
fields: &'tcx [hir::Field<'tcx>],
|
fields: &'tcx [hir::Field<'tcx>],
|
||||||
variant: &'tcx ty::VariantDef,
|
variant: &'tcx ty::VariantDef,
|
||||||
base: Option<&'tcx hir::Expr<'tcx>>,
|
rest: Option<&'tcx hir::Expr<'tcx>>,
|
||||||
) {
|
) {
|
||||||
if let Some(struct_lit_data) = self.save_ctxt.get_expr_data(ex) {
|
if let Some(struct_lit_data) = self.save_ctxt.get_expr_data(ex) {
|
||||||
if let hir::QPath::Resolved(_, path) = path {
|
if let hir::QPath::Resolved(_, path) = path {
|
||||||
|
@ -836,7 +836,9 @@ impl<'tcx> DumpVisitor<'tcx> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
walk_list!(self, visit_expr, base);
|
if let Some(base) = rest {
|
||||||
|
self.visit_expr(&base);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn process_method_call(
|
fn process_method_call(
|
||||||
|
@ -1399,7 +1401,7 @@ impl<'tcx> Visitor<'tcx> for DumpVisitor<'tcx> {
|
||||||
debug!("visit_expr {:?}", ex.kind);
|
debug!("visit_expr {:?}", ex.kind);
|
||||||
self.process_macro_use(ex.span);
|
self.process_macro_use(ex.span);
|
||||||
match ex.kind {
|
match ex.kind {
|
||||||
hir::ExprKind::Struct(ref path, ref fields, ref base) => {
|
hir::ExprKind::Struct(ref path, ref fields, ref rest) => {
|
||||||
let hir_expr = self.save_ctxt.tcx.hir().expect_expr(ex.hir_id);
|
let hir_expr = self.save_ctxt.tcx.hir().expect_expr(ex.hir_id);
|
||||||
let adt = match self.save_ctxt.typeck_results().expr_ty_opt(&hir_expr) {
|
let adt = match self.save_ctxt.typeck_results().expr_ty_opt(&hir_expr) {
|
||||||
Some(ty) if ty.ty_adt_def().is_some() => ty.ty_adt_def().unwrap(),
|
Some(ty) if ty.ty_adt_def().is_some() => ty.ty_adt_def().unwrap(),
|
||||||
|
@ -1409,7 +1411,7 @@ impl<'tcx> Visitor<'tcx> for DumpVisitor<'tcx> {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
let res = self.save_ctxt.get_path_res(hir_expr.hir_id);
|
let res = self.save_ctxt.get_path_res(hir_expr.hir_id);
|
||||||
self.process_struct_lit(ex, path, fields, adt.variant_of_res(res), *base)
|
self.process_struct_lit(ex, path, fields, adt.variant_of_res(res), *rest)
|
||||||
}
|
}
|
||||||
hir::ExprKind::MethodCall(ref seg, _, args, _) => {
|
hir::ExprKind::MethodCall(ref seg, _, args, _) => {
|
||||||
self.process_method_call(ex, seg, args)
|
self.process_method_call(ex, seg, args)
|
||||||
|
|
|
@ -155,7 +155,7 @@ fn iter_exprs(depth: usize, f: &mut dyn FnMut(P<Expr>)) {
|
||||||
},
|
},
|
||||||
17 => {
|
17 => {
|
||||||
let path = Path::from_ident(Ident::from_str("S"));
|
let path = Path::from_ident(Ident::from_str("S"));
|
||||||
g(ExprKind::Struct(path, vec![], Some(make_x())));
|
g(ExprKind::Struct(path, vec![], StructRest::Base(make_x())));
|
||||||
},
|
},
|
||||||
18 => {
|
18 => {
|
||||||
iter_exprs(depth - 1, &mut |e| g(ExprKind::Try(e)));
|
iter_exprs(depth - 1, &mut |e| g(ExprKind::Try(e)));
|
||||||
|
|
17
src/test/ui/destructuring-assignment/nested_destructure.rs
Normal file
17
src/test/ui/destructuring-assignment/nested_destructure.rs
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
// run-pass
|
||||||
|
|
||||||
|
#![feature(destructuring_assignment)]
|
||||||
|
|
||||||
|
struct Struct<S, T> {
|
||||||
|
a: S,
|
||||||
|
b: T,
|
||||||
|
}
|
||||||
|
|
||||||
|
struct TupleStruct<S, T>(S, T);
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let (a, b, c, d);
|
||||||
|
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));
|
||||||
|
}
|
|
@ -7,18 +7,19 @@ fn main() {
|
||||||
(a, b) += (3, 4); //~ ERROR invalid left-hand side of assignment
|
(a, b) += (3, 4); //~ ERROR invalid left-hand side of assignment
|
||||||
//~| ERROR binary assignment operation `+=` cannot be applied
|
//~| ERROR binary assignment operation `+=` cannot be applied
|
||||||
|
|
||||||
[a, b] = [3, 4]; //~ ERROR invalid left-hand side of assignment
|
[a, b] = [3, 4]; //~ ERROR destructuring assignments are unstable
|
||||||
[a, b] += [3, 4]; //~ ERROR invalid left-hand side of assignment
|
[a, b] += [3, 4]; //~ ERROR invalid left-hand side of assignment
|
||||||
//~| ERROR binary assignment operation `+=` cannot be applied
|
//~| ERROR binary assignment operation `+=` cannot be applied
|
||||||
|
|
||||||
let s = S { x: 3, y: 4 };
|
let s = S { x: 3, y: 4 };
|
||||||
|
|
||||||
S { x: a, y: b } = s; //~ ERROR invalid left-hand side of assignment
|
S { x: a, y: b } = s; //~ ERROR destructuring assignments are unstable
|
||||||
S { x: a, y: b } += s; //~ ERROR invalid left-hand side of assignment
|
S { x: a, y: b } += s; //~ ERROR invalid left-hand side of assignment
|
||||||
//~| ERROR binary assignment operation `+=` cannot be applied
|
//~| ERROR binary assignment operation `+=` cannot be applied
|
||||||
|
|
||||||
S { x: a, ..s } = S { x: 3, y: 4 };
|
S { x: a, ..s } = S { x: 3, y: 4 };
|
||||||
//~^ ERROR invalid left-hand side of assignment
|
//~^ ERROR functional record updates are not allowed in destructuring assignments
|
||||||
|
//~| ERROR destructuring assignments are unstable
|
||||||
|
|
||||||
let c = 3;
|
let c = 3;
|
||||||
|
|
||||||
|
|
|
@ -10,7 +10,46 @@ LL | (a, b) = (3, 4);
|
||||||
= help: add `#![feature(destructuring_assignment)]` to the crate attributes to enable
|
= help: add `#![feature(destructuring_assignment)]` to the crate attributes to enable
|
||||||
|
|
||||||
error[E0658]: destructuring assignments are unstable
|
error[E0658]: destructuring assignments are unstable
|
||||||
--> $DIR/note-unsupported.rs:25:17
|
--> $DIR/note-unsupported.rs:10:12
|
||||||
|
|
|
||||||
|
LL | [a, b] = [3, 4];
|
||||||
|
| ------ ^
|
||||||
|
| |
|
||||||
|
| cannot assign to this 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/note-unsupported.rs:16:22
|
||||||
|
|
|
||||||
|
LL | S { x: a, y: b } = s;
|
||||||
|
| ---------------- ^
|
||||||
|
| |
|
||||||
|
| cannot assign to this 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/note-unsupported.rs:20:21
|
||||||
|
|
|
||||||
|
LL | S { x: a, ..s } = S { x: 3, y: 4 };
|
||||||
|
| --------------- ^
|
||||||
|
| |
|
||||||
|
| cannot assign to this 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: functional record updates are not allowed in destructuring assignments
|
||||||
|
--> $DIR/note-unsupported.rs:20:17
|
||||||
|
|
|
||||||
|
LL | S { x: a, ..s } = S { x: 3, y: 4 };
|
||||||
|
| ^ help: consider removing the trailing pattern
|
||||||
|
|
||||||
|
error[E0658]: destructuring assignments are unstable
|
||||||
|
--> $DIR/note-unsupported.rs:26:17
|
||||||
|
|
|
|
||||||
LL | ((a, b), c) = ((3, 4), 5);
|
LL | ((a, b), c) = ((3, 4), 5);
|
||||||
| ----------- ^
|
| ----------- ^
|
||||||
|
@ -36,14 +75,6 @@ LL | (a, b) += (3, 4);
|
||||||
| |
|
| |
|
||||||
| cannot assign to this expression
|
| cannot assign to this expression
|
||||||
|
|
||||||
error[E0070]: invalid left-hand side of assignment
|
|
||||||
--> $DIR/note-unsupported.rs:10:12
|
|
||||||
|
|
|
||||||
LL | [a, b] = [3, 4];
|
|
||||||
| ------ ^
|
|
||||||
| |
|
|
||||||
| cannot assign to this expression
|
|
||||||
|
|
||||||
error[E0368]: binary assignment operation `+=` cannot be applied to type `[{integer}; 2]`
|
error[E0368]: binary assignment operation `+=` cannot be applied to type `[{integer}; 2]`
|
||||||
--> $DIR/note-unsupported.rs:11:5
|
--> $DIR/note-unsupported.rs:11:5
|
||||||
|
|
|
|
||||||
|
@ -60,14 +91,6 @@ LL | [a, b] += [3, 4];
|
||||||
| |
|
| |
|
||||||
| cannot assign to this expression
|
| cannot assign to this expression
|
||||||
|
|
||||||
error[E0070]: invalid left-hand side of assignment
|
|
||||||
--> $DIR/note-unsupported.rs:16:22
|
|
||||||
|
|
|
||||||
LL | S { x: a, y: b } = s;
|
|
||||||
| ---------------- ^
|
|
||||||
| |
|
|
||||||
| cannot assign to this expression
|
|
||||||
|
|
||||||
error[E0368]: binary assignment operation `+=` cannot be applied to type `S`
|
error[E0368]: binary assignment operation `+=` cannot be applied to type `S`
|
||||||
--> $DIR/note-unsupported.rs:17:5
|
--> $DIR/note-unsupported.rs:17:5
|
||||||
|
|
|
|
||||||
|
@ -86,15 +109,7 @@ LL | S { x: a, y: b } += s;
|
||||||
| |
|
| |
|
||||||
| cannot assign to this expression
|
| cannot assign to this expression
|
||||||
|
|
||||||
error[E0070]: invalid left-hand side of assignment
|
error: aborting due to 12 previous errors
|
||||||
--> $DIR/note-unsupported.rs:20:21
|
|
||||||
|
|
|
||||||
LL | S { x: a, ..s } = S { x: 3, y: 4 };
|
|
||||||
| --------------- ^
|
|
||||||
| |
|
|
||||||
| cannot assign to this expression
|
|
||||||
|
|
||||||
error: aborting due to 11 previous errors
|
Some errors have detailed explanations: E0067, E0368, E0658.
|
||||||
|
|
||||||
Some errors have detailed explanations: E0067, E0070, E0368, E0658.
|
|
||||||
For more information about an error, try `rustc --explain E0067`.
|
For more information about an error, try `rustc --explain E0067`.
|
||||||
|
|
15
src/test/ui/destructuring-assignment/slice_destructure.rs
Normal file
15
src/test/ui/destructuring-assignment/slice_destructure.rs
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
// run-pass
|
||||||
|
|
||||||
|
#![feature(destructuring_assignment)]
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let (mut a, mut b);
|
||||||
|
[a, b] = [0, 1];
|
||||||
|
assert_eq!((a, b), (0, 1));
|
||||||
|
let mut c;
|
||||||
|
[a, .., b, c] = [1, 2, 3, 4, 5];
|
||||||
|
assert_eq!((a, b, c), (1, 4, 5));
|
||||||
|
[..] = [1, 2, 3];
|
||||||
|
[c, ..] = [5, 6, 6];
|
||||||
|
assert_eq!(c, 5);
|
||||||
|
}
|
|
@ -0,0 +1,7 @@
|
||||||
|
#![feature(destructuring_assignment)]
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
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
|
||||||
|
}
|
|
@ -0,0 +1,17 @@
|
||||||
|
error: `..` can only be used once per slice pattern
|
||||||
|
--> $DIR/slice_destructure_fail.rs:5:14
|
||||||
|
|
|
||||||
|
LL | [a, .., b, ..] = [0, 1];
|
||||||
|
| -- ^^ can only be used once per slice pattern
|
||||||
|
| |
|
||||||
|
| previously used here
|
||||||
|
|
||||||
|
error[E0527]: pattern requires 3 elements but array has 2
|
||||||
|
--> $DIR/slice_destructure_fail.rs:6:3
|
||||||
|
|
|
||||||
|
LL | [a, a, b] = [1, 2];
|
||||||
|
| ^^^^^^^^^ expected 2 elements
|
||||||
|
|
||||||
|
error: aborting due to 2 previous errors
|
||||||
|
|
||||||
|
For more information about this error, try `rustc --explain E0527`.
|
19
src/test/ui/destructuring-assignment/struct_destructure.rs
Normal file
19
src/test/ui/destructuring-assignment/struct_destructure.rs
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
// run-pass
|
||||||
|
|
||||||
|
#![feature(destructuring_assignment)]
|
||||||
|
struct Struct<S, T> {
|
||||||
|
a: S,
|
||||||
|
b: T,
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let (mut a, mut b);
|
||||||
|
Struct { a, b } = Struct { a: 0, b: 1 };
|
||||||
|
assert_eq!((a, b), (0, 1));
|
||||||
|
Struct { a: b, b: a } = Struct { a: 1, b: 2 };
|
||||||
|
assert_eq!((a,b), (2, 1));
|
||||||
|
Struct { a, .. } = Struct { a: 1, b: 3 };
|
||||||
|
assert_eq!((a, b), (1, 1));
|
||||||
|
Struct { .. } = Struct { a: 1, b: 4 };
|
||||||
|
assert_eq!((a, b), (1, 1));
|
||||||
|
}
|
|
@ -0,0 +1,15 @@
|
||||||
|
#![feature(destructuring_assignment)]
|
||||||
|
struct Struct<S, T> {
|
||||||
|
a: S,
|
||||||
|
b: T,
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let (mut a, b);
|
||||||
|
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, ..d } = Struct { a: 1, b: 2 };
|
||||||
|
//~^ ERROR functional record updates are not allowed in destructuring assignments
|
||||||
|
Struct { a, .. }; //~ ERROR base expression required after `..`
|
||||||
|
}
|
|
@ -0,0 +1,21 @@
|
||||||
|
error: functional record updates are not allowed in destructuring assignments
|
||||||
|
--> $DIR/struct_destructure_fail.rs:12: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
|
||||||
|
|
|
||||||
|
LL | Struct { a, .. };
|
||||||
|
| ^ add a base expression here
|
||||||
|
|
||||||
|
error[E0026]: struct `Struct` does not have a field named `c`
|
||||||
|
--> $DIR/struct_destructure_fail.rs:11:20
|
||||||
|
|
|
||||||
|
LL | Struct { a, b, c } = Struct { a: 0, b: 1 };
|
||||||
|
| ^ struct `Struct` does not have this field
|
||||||
|
|
||||||
|
error: aborting due to 3 previous errors
|
||||||
|
|
||||||
|
For more information about this error, try `rustc --explain E0026`.
|
|
@ -0,0 +1,34 @@
|
||||||
|
// run-pass
|
||||||
|
|
||||||
|
#![feature(destructuring_assignment)]
|
||||||
|
|
||||||
|
struct TupleStruct<S, T>(S, T);
|
||||||
|
|
||||||
|
impl<S, T> TupleStruct<S, T> {
|
||||||
|
fn assign(self, first: &mut S, second: &mut T) {
|
||||||
|
// Test usage of `Self` instead of the struct name:
|
||||||
|
Self(*first, *second) = self
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
enum Enum<S, T> {
|
||||||
|
SingleVariant(S, T)
|
||||||
|
}
|
||||||
|
|
||||||
|
type Alias<S> = Enum<S, isize>;
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let (mut a, mut b);
|
||||||
|
TupleStruct(a, b) = TupleStruct(0, 1);
|
||||||
|
assert_eq!((a, b), (0, 1));
|
||||||
|
TupleStruct(a, .., b) = TupleStruct(1, 2);
|
||||||
|
assert_eq!((a, b), (1, 2));
|
||||||
|
TupleStruct(..) = TupleStruct(3, 4);
|
||||||
|
assert_eq!((a, b), (1, 2));
|
||||||
|
TupleStruct(5,6).assign(&mut a, &mut b);
|
||||||
|
assert_eq!((a, b), (5, 6));
|
||||||
|
Enum::SingleVariant(a, b) = Enum::SingleVariant(7, 8);
|
||||||
|
assert_eq!((a, b), (7, 8));
|
||||||
|
Alias::SingleVariant(a, b) = Alias::SingleVariant(9, 10);
|
||||||
|
assert_eq!((a, b), (9, 10));
|
||||||
|
}
|
|
@ -0,0 +1,42 @@
|
||||||
|
#![feature(destructuring_assignment)]
|
||||||
|
|
||||||
|
struct TupleStruct<S, T>(S, T);
|
||||||
|
|
||||||
|
enum Enum<S, T> {
|
||||||
|
SingleVariant(S, T)
|
||||||
|
}
|
||||||
|
|
||||||
|
type Alias<S> = Enum<S, isize>;
|
||||||
|
|
||||||
|
trait Test {
|
||||||
|
fn test() -> TupleStruct<isize, isize> {
|
||||||
|
TupleStruct(0, 0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Test for Alias<isize> {}
|
||||||
|
|
||||||
|
fn test() -> TupleStruct<isize, isize> {
|
||||||
|
TupleStruct(0, 0)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let (mut a, mut b);
|
||||||
|
TupleStruct(a, .., b, ..) = TupleStruct(0, 1);
|
||||||
|
//~^ ERROR `..` can only be used once per tuple struct or variant pattern
|
||||||
|
Enum::SingleVariant(a, .., b, ..) = Enum::SingleVariant(0, 1);
|
||||||
|
//~^ ERROR `..` can only be used once per tuple struct or variant pattern
|
||||||
|
|
||||||
|
TupleStruct(a, a, b) = TupleStruct(1, 2);
|
||||||
|
//~^ ERROR this pattern has 3 fields, 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
|
||||||
|
|
||||||
|
// Check if `test` is recognized as not a tuple struct but a function call:
|
||||||
|
test() = TupleStruct(0, 0);
|
||||||
|
//~^ ERROR invalid left-hand side of assignment
|
||||||
|
(test)() = TupleStruct(0, 0);
|
||||||
|
//~^ ERROR invalid left-hand side of assignment
|
||||||
|
<Alias::<isize> as Test>::test() = TupleStruct(0, 0);
|
||||||
|
//~^ ERROR invalid left-hand side of assignment
|
||||||
|
}
|
|
@ -0,0 +1,62 @@
|
||||||
|
error: `..` can only be used once per tuple struct or variant pattern
|
||||||
|
--> $DIR/tuple_struct_destructure_fail.rs:25:27
|
||||||
|
|
|
||||||
|
LL | TupleStruct(a, .., b, ..) = TupleStruct(0, 1);
|
||||||
|
| -- ^^ can only be used once per tuple struct or variant pattern
|
||||||
|
| |
|
||||||
|
| previously used here
|
||||||
|
|
||||||
|
error: `..` can only be used once per tuple struct or variant pattern
|
||||||
|
--> $DIR/tuple_struct_destructure_fail.rs:27:35
|
||||||
|
|
|
||||||
|
LL | Enum::SingleVariant(a, .., b, ..) = Enum::SingleVariant(0, 1);
|
||||||
|
| -- ^^ can only be used once per tuple struct or variant pattern
|
||||||
|
| |
|
||||||
|
| previously used here
|
||||||
|
|
||||||
|
error[E0023]: this pattern has 3 fields, but the corresponding tuple struct has 2 fields
|
||||||
|
--> $DIR/tuple_struct_destructure_fail.rs:30:5
|
||||||
|
|
|
||||||
|
LL | struct TupleStruct<S, T>(S, T);
|
||||||
|
| ------------------------------- tuple struct defined here
|
||||||
|
...
|
||||||
|
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
|
||||||
|
--> $DIR/tuple_struct_destructure_fail.rs:32: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[E0070]: invalid left-hand side of assignment
|
||||||
|
--> $DIR/tuple_struct_destructure_fail.rs:36: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
|
||||||
|
|
|
||||||
|
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
|
||||||
|
|
|
||||||
|
LL | <Alias::<isize> as Test>::test() = TupleStruct(0, 0);
|
||||||
|
| -------------------------------- ^
|
||||||
|
| |
|
||||||
|
| cannot assign to this expression
|
||||||
|
|
||||||
|
error: aborting due to 7 previous errors
|
||||||
|
|
||||||
|
Some errors have detailed explanations: E0023, E0070.
|
||||||
|
For more information about an error, try `rustc --explain E0023`.
|
|
@ -0,0 +1,8 @@
|
||||||
|
fn main() {}
|
||||||
|
|
||||||
|
struct S { x : u32 }
|
||||||
|
|
||||||
|
#[cfg(FALSE)]
|
||||||
|
fn foo() {
|
||||||
|
S { x: 5, .. }; //~ ERROR destructuring assignments are unstable
|
||||||
|
}
|
|
@ -0,0 +1,12 @@
|
||||||
|
error[E0658]: destructuring assignments are unstable
|
||||||
|
--> $DIR/underscore-range-expr-gating.rs:7: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
|
||||||
|
|
||||||
|
For more information about this error, try `rustc --explain E0658`.
|
|
@ -1,7 +1,11 @@
|
||||||
fn main() {
|
fn main() {
|
||||||
let value = [7u8];
|
let value = [7u8];
|
||||||
while Some(0) = value.get(0) { //~ ERROR mismatched types
|
while Some(0) = value.get(0) { //~ ERROR destructuring assignments are unstable
|
||||||
//~^ NOTE expected `bool`, found `()`
|
//~| ERROR invalid left-hand side of assignment
|
||||||
//~| HELP you might have meant to use pattern matching
|
//~| ERROR mismatched types
|
||||||
|
//~| ERROR mismatched types
|
||||||
|
|
||||||
|
// FIXME The following diagnostic should also be emitted
|
||||||
|
// HELP you might have meant to use pattern matching
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,14 +1,38 @@
|
||||||
|
error[E0658]: destructuring assignments are unstable
|
||||||
|
--> $DIR/issue-77218.rs:3:19
|
||||||
|
|
|
||||||
|
LL | while Some(0) = value.get(0) {
|
||||||
|
| ------- ^
|
||||||
|
| |
|
||||||
|
| cannot assign to this 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[E0070]: invalid left-hand side of assignment
|
||||||
|
--> $DIR/issue-77218.rs:3:19
|
||||||
|
|
|
||||||
|
LL | while Some(0) = value.get(0) {
|
||||||
|
| - ^
|
||||||
|
| |
|
||||||
|
| cannot assign to this expression
|
||||||
|
|
||||||
|
error[E0308]: mismatched types
|
||||||
|
--> $DIR/issue-77218.rs:3:16
|
||||||
|
|
|
||||||
|
LL | while Some(0) = value.get(0) {
|
||||||
|
| ^
|
||||||
|
| |
|
||||||
|
| expected integer, found `&u8`
|
||||||
|
| help: consider dereferencing the borrow: `*0`
|
||||||
|
|
||||||
error[E0308]: mismatched types
|
error[E0308]: mismatched types
|
||||||
--> $DIR/issue-77218.rs:3:11
|
--> $DIR/issue-77218.rs:3:11
|
||||||
|
|
|
|
||||||
LL | while Some(0) = value.get(0) {
|
LL | while Some(0) = value.get(0) {
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^ expected `bool`, found `()`
|
| ^^^^^^^^^^^^^^^^^^^^^^ expected `bool`, found `()`
|
||||||
|
|
|
||||||
help: you might have meant to use pattern matching
|
|
||||||
|
|
|
||||||
LL | while let Some(0) = value.get(0) {
|
|
||||||
| ^^^
|
|
||||||
|
|
||||||
error: aborting due to previous error
|
error: aborting due to 4 previous errors
|
||||||
|
|
||||||
For more information about this error, try `rustc --explain E0308`.
|
Some errors have detailed explanations: E0070, E0308, E0658.
|
||||||
|
For more information about an error, try `rustc --explain E0070`.
|
||||||
|
|
|
@ -2,7 +2,12 @@ fn main() {
|
||||||
let foo = Some(0);
|
let foo = Some(0);
|
||||||
let bar = None;
|
let bar = None;
|
||||||
if Some(x) = foo {} //~ ERROR cannot find value `x` in this scope
|
if Some(x) = foo {} //~ ERROR cannot find value `x` in this scope
|
||||||
|
//~^ ERROR mismatched types
|
||||||
|
//~^^ ERROR destructuring assignments are unstable
|
||||||
if Some(foo) = bar {} //~ ERROR mismatched types
|
if Some(foo) = bar {} //~ ERROR mismatched types
|
||||||
|
//~^ ERROR destructuring assignments are unstable
|
||||||
if 3 = foo {} //~ ERROR mismatched types
|
if 3 = foo {} //~ ERROR mismatched types
|
||||||
if Some(3) = foo {} //~ ERROR mismatched types
|
if Some(3) = foo {} //~ ERROR mismatched types
|
||||||
|
//~^ ERROR destructuring assignments are unstable
|
||||||
|
//~^^ ERROR invalid left-hand side of assignment
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,23 +9,53 @@ help: you might have meant to use pattern matching
|
||||||
LL | if let Some(x) = foo {}
|
LL | if let Some(x) = foo {}
|
||||||
| ^^^
|
| ^^^
|
||||||
|
|
||||||
|
error[E0658]: destructuring assignments are unstable
|
||||||
|
--> $DIR/if-let-typo.rs:4:16
|
||||||
|
|
|
||||||
|
LL | if Some(x) = foo {}
|
||||||
|
| ------- ^
|
||||||
|
| |
|
||||||
|
| cannot assign to this 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/if-let-typo.rs:7:18
|
||||||
|
|
|
||||||
|
LL | if Some(foo) = bar {}
|
||||||
|
| --------- ^
|
||||||
|
| |
|
||||||
|
| cannot assign to this 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/if-let-typo.rs:10:16
|
||||||
|
|
|
||||||
|
LL | if Some(3) = foo {}
|
||||||
|
| ------- ^
|
||||||
|
| |
|
||||||
|
| cannot assign to this 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[E0308]: mismatched types
|
error[E0308]: mismatched types
|
||||||
--> $DIR/if-let-typo.rs:5:8
|
--> $DIR/if-let-typo.rs:4:8
|
||||||
|
|
|
||||||
|
LL | if Some(x) = foo {}
|
||||||
|
| ^^^^^^^^^^^^^ expected `bool`, found `()`
|
||||||
|
|
||||||
|
error[E0308]: mismatched types
|
||||||
|
--> $DIR/if-let-typo.rs:7:8
|
||||||
|
|
|
|
||||||
LL | if Some(foo) = bar {}
|
LL | if Some(foo) = bar {}
|
||||||
| ^^^^^^^^^^^^^^^ expected `bool`, found `()`
|
| ^^^^^^^^^^^^^^^ expected `bool`, found `()`
|
||||||
|
|
|
||||||
help: you might have meant to use pattern matching
|
|
||||||
|
|
|
||||||
LL | if let Some(foo) = bar {}
|
|
||||||
| ^^^
|
|
||||||
help: you might have meant to compare for equality
|
|
||||||
|
|
|
||||||
LL | if Some(foo) == bar {}
|
|
||||||
| ^^
|
|
||||||
|
|
||||||
error[E0308]: mismatched types
|
error[E0308]: mismatched types
|
||||||
--> $DIR/if-let-typo.rs:6:8
|
--> $DIR/if-let-typo.rs:9:8
|
||||||
|
|
|
|
||||||
LL | if 3 = foo {}
|
LL | if 3 = foo {}
|
||||||
| ^^^^^^^ expected `bool`, found `()`
|
| ^^^^^^^ expected `bool`, found `()`
|
||||||
|
@ -35,22 +65,21 @@ help: you might have meant to use pattern matching
|
||||||
LL | if let 3 = foo {}
|
LL | if let 3 = foo {}
|
||||||
| ^^^
|
| ^^^
|
||||||
|
|
||||||
|
error[E0070]: invalid left-hand side of assignment
|
||||||
|
--> $DIR/if-let-typo.rs:10:16
|
||||||
|
|
|
||||||
|
LL | if Some(3) = foo {}
|
||||||
|
| - ^
|
||||||
|
| |
|
||||||
|
| cannot assign to this expression
|
||||||
|
|
||||||
error[E0308]: mismatched types
|
error[E0308]: mismatched types
|
||||||
--> $DIR/if-let-typo.rs:7:8
|
--> $DIR/if-let-typo.rs:10:8
|
||||||
|
|
|
|
||||||
LL | if Some(3) = foo {}
|
LL | if Some(3) = foo {}
|
||||||
| ^^^^^^^^^^^^^ expected `bool`, found `()`
|
| ^^^^^^^^^^^^^ expected `bool`, found `()`
|
||||||
|
|
|
||||||
help: you might have meant to use pattern matching
|
|
||||||
|
|
|
||||||
LL | if let Some(3) = foo {}
|
|
||||||
| ^^^
|
|
||||||
help: you might have meant to compare for equality
|
|
||||||
|
|
|
||||||
LL | if Some(3) == foo {}
|
|
||||||
| ^^
|
|
||||||
|
|
||||||
error: aborting due to 4 previous errors
|
error: aborting due to 9 previous errors
|
||||||
|
|
||||||
Some errors have detailed explanations: E0308, E0425.
|
Some errors have detailed explanations: E0070, E0308, E0425, E0658.
|
||||||
For more information about an error, try `rustc --explain E0308`.
|
For more information about an error, try `rustc --explain E0070`.
|
||||||
|
|
|
@ -107,6 +107,15 @@ pub fn eq_expr_opt(l: &Option<P<Expr>>, r: &Option<P<Expr>>) -> bool {
|
||||||
both(l, r, |l, r| eq_expr(l, r))
|
both(l, r, |l, r| eq_expr(l, r))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn eq_struct_rest(l: &StructRest, r: &StructRest) -> bool {
|
||||||
|
match (l, r) {
|
||||||
|
(StructRest::Base(lb), StructRest::Base(rb)) => eq_expr(lb, rb),
|
||||||
|
(StructRest::Rest(_), StructRest::Rest(_)) => true,
|
||||||
|
(StructRest::None, StructRest::None) => true,
|
||||||
|
_ => false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn eq_expr(l: &Expr, r: &Expr) -> bool {
|
pub fn eq_expr(l: &Expr, r: &Expr) -> bool {
|
||||||
use ExprKind::*;
|
use ExprKind::*;
|
||||||
if !over(&l.attrs, &r.attrs, |l, r| eq_attr(l, r)) {
|
if !over(&l.attrs, &r.attrs, |l, r| eq_attr(l, r)) {
|
||||||
|
@ -150,7 +159,7 @@ pub fn eq_expr(l: &Expr, r: &Expr) -> bool {
|
||||||
(Path(lq, lp), Path(rq, rp)) => both(lq, rq, |l, r| eq_qself(l, r)) && eq_path(lp, rp),
|
(Path(lq, lp), Path(rq, rp)) => both(lq, rq, |l, r| eq_qself(l, r)) && eq_path(lp, rp),
|
||||||
(MacCall(l), MacCall(r)) => eq_mac_call(l, r),
|
(MacCall(l), MacCall(r)) => eq_mac_call(l, r),
|
||||||
(Struct(lp, lfs, lb), Struct(rp, rfs, rb)) => {
|
(Struct(lp, lfs, lb), Struct(rp, rfs, rb)) => {
|
||||||
eq_path(lp, rp) && eq_expr_opt(lb, rb) && unordered_over(lfs, rfs, |l, r| eq_field(l, r))
|
eq_path(lp, rp) && eq_struct_rest(lb, rb) && unordered_over(lfs, rfs, |l, r| eq_field(l, r))
|
||||||
},
|
},
|
||||||
_ => false,
|
_ => false,
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,3 +1,14 @@
|
||||||
|
error[E0658]: destructuring assignments are unstable
|
||||||
|
--> $DIR/ice-6250.rs:12:25
|
||||||
|
|
|
||||||
|
LL | Some(reference) = cache.data.get(key) {
|
||||||
|
| --------------- ^
|
||||||
|
| |
|
||||||
|
| cannot assign to this 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[E0601]: `main` function not found in crate `ice_6250`
|
error[E0601]: `main` function not found in crate `ice_6250`
|
||||||
--> $DIR/ice-6250.rs:4:1
|
--> $DIR/ice-6250.rs:4:1
|
||||||
|
|
|
|
||||||
|
@ -10,18 +21,22 @@ LL | | }
|
||||||
LL | | }
|
LL | | }
|
||||||
| |_^ consider adding a `main` function to `$DIR/ice-6250.rs`
|
| |_^ consider adding a `main` function to `$DIR/ice-6250.rs`
|
||||||
|
|
||||||
|
error[E0308]: mismatched types
|
||||||
|
--> $DIR/ice-6250.rs:12:14
|
||||||
|
|
|
||||||
|
LL | Some(reference) = cache.data.get(key) {
|
||||||
|
| ^^^^^^^^^
|
||||||
|
| |
|
||||||
|
| expected integer, found `&i32`
|
||||||
|
| help: consider dereferencing the borrow: `*reference`
|
||||||
|
|
||||||
error[E0308]: mismatched types
|
error[E0308]: mismatched types
|
||||||
--> $DIR/ice-6250.rs:12:9
|
--> $DIR/ice-6250.rs:12:9
|
||||||
|
|
|
|
||||||
LL | Some(reference) = cache.data.get(key) {
|
LL | Some(reference) = cache.data.get(key) {
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `bool`, found `()`
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `bool`, found `()`
|
||||||
|
|
|
||||||
help: you might have meant to use pattern matching
|
|
||||||
|
|
|
||||||
LL | let Some(reference) = cache.data.get(key) {
|
|
||||||
| ^^^
|
|
||||||
|
|
||||||
error: aborting due to 2 previous errors
|
error: aborting due to 4 previous errors
|
||||||
|
|
||||||
Some errors have detailed explanations: E0308, E0601.
|
Some errors have detailed explanations: E0308, E0601, E0658.
|
||||||
For more information about an error, try `rustc --explain E0308`.
|
For more information about an error, try `rustc --explain E0308`.
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue