Auto merge of #60861 - Centril:let-chains-ast-intro, r=petrochenkov

[let_chains, 2/6] Introduce `Let(..)` in AST, remove IfLet + WhileLet and parse let chains

Here we remove `ast::ExprKind::{IfLet, WhileLet}` and introduce `ast::ExprKind::Let`.
Moreover, we also:
+ connect the parsing logic for let chains
+ introduce the feature gate
+ rewire HIR lowering a bit.

However, this does not connect the new syntax to semantics in HIR.
That will be the subject of a subsequent PR.

Per https://github.com/rust-lang/rust/issues/53667#issuecomment-471583239.
Next step after https://github.com/rust-lang/rust/pull/59288.

cc @Manishearth re. Clippy.

r? @oli-obk
This commit is contained in:
bors 2019-06-23 12:28:12 +00:00
commit 5d677b2efd
33 changed files with 2333 additions and 624 deletions

View File

@ -4344,53 +4344,147 @@ fn lower_expr(&mut self, e: &Expr) -> hir::Expr {
let ohs = P(self.lower_expr(ohs));
hir::ExprKind::AddrOf(m, ohs)
}
// More complicated than you might expect because the else branch
// might be `if let`.
ExprKind::If(ref cond, ref then, ref else_opt) => {
// `true => then`:
let then_pat = self.pat_bool(e.span, true);
let then_blk = self.lower_block(then, false);
let then_expr = self.expr_block(then_blk, ThinVec::new());
let then_arm = self.arm(hir_vec![then_pat], P(then_expr));
ExprKind::Let(ref pats, ref scrutinee) => {
// If we got here, the `let` expression is not allowed.
self.sess
.struct_span_err(e.span, "`let` expressions are not supported here")
.note("only supported directly in conditions of `if`- and `while`-expressions")
.note("as well as when nested within `&&` and parenthesis in those conditions")
.emit();
// For better recovery, we emit:
// ```
// match scrutinee { pats => true, _ => false }
// ```
// While this doesn't fully match the user's intent, it has key advantages:
// 1. We can avoid using `abort_if_errors`.
// 2. We can typeck both `pats` and `scrutinee`.
// 3. `pats` is allowed to be refutable.
// 4. The return type of the block is `bool` which seems like what the user wanted.
let scrutinee = self.lower_expr(scrutinee);
let then_arm = {
let pats = pats.iter().map(|pat| self.lower_pat(pat)).collect();
let expr = self.expr_bool(e.span, true);
self.arm(pats, P(expr))
};
let else_arm = {
let pats = hir_vec![self.pat_wild(e.span)];
let expr = self.expr_bool(e.span, false);
self.arm(pats, P(expr))
};
hir::ExprKind::Match(
P(scrutinee),
vec![then_arm, else_arm].into(),
hir::MatchSource::Normal,
)
}
// FIXME(#53667): handle lowering of && and parens.
ExprKind::If(ref cond, ref then, ref else_opt) => {
// `_ => else_block` where `else_block` is `{}` if there's `None`:
let else_pat = self.pat_wild(e.span);
let else_expr = match else_opt {
None => self.expr_block_empty(e.span),
Some(els) => match els.node {
ExprKind::IfLet(..) => {
// Wrap the `if let` expr in a block.
let els = self.lower_expr(els);
let blk = self.block_all(els.span, hir_vec![], Some(P(els)));
self.expr_block(P(blk), ThinVec::new())
}
_ => self.lower_expr(els),
}
let (else_expr, contains_else_clause) = match else_opt {
None => (self.expr_block_empty(e.span), false),
Some(els) => (self.lower_expr(els), true),
};
let else_arm = self.arm(hir_vec![else_pat], P(else_expr));
// Lower condition:
let span_block = self.mark_span_with_reason(IfTemporary, cond.span, None);
let cond = self.lower_expr(cond);
// Wrap in a construct equivalent to `{ let _t = $cond; _t }` to preserve drop
// semantics since `if cond { ... }` don't let temporaries live outside of `cond`.
let cond = self.expr_drop_temps(span_block, P(cond), ThinVec::new());
// Handle then + scrutinee:
let then_blk = self.lower_block(then, false);
let then_expr = self.expr_block(then_blk, ThinVec::new());
let (then_pats, scrutinee, desugar) = match cond.node {
// `<pat> => <then>`
ExprKind::Let(ref pats, ref scrutinee) => {
let scrutinee = self.lower_expr(scrutinee);
let pats = pats.iter().map(|pat| self.lower_pat(pat)).collect();
let desugar = hir::MatchSource::IfLetDesugar { contains_else_clause };
(pats, scrutinee, desugar)
}
// `true => then`:
_ => {
// Lower condition:
let cond = self.lower_expr(cond);
// Wrap in a construct equivalent to `{ let _t = $cond; _t }`
// to preserve drop semantics since `if cond { ... }`
// don't let temporaries live outside of `cond`.
let span_block = self.mark_span_with_reason(IfTemporary, cond.span, None);
// Wrap in a construct equivalent to `{ let _t = $cond; _t }`
// to preserve drop semantics since `if cond { ... }` does not
// let temporaries live outside of `cond`.
let cond = self.expr_drop_temps(span_block, P(cond), ThinVec::new());
hir::ExprKind::Match(
P(cond),
vec![then_arm, else_arm].into(),
hir::MatchSource::IfDesugar {
contains_else_clause: else_opt.is_some()
},
)
let desugar = hir::MatchSource::IfDesugar { contains_else_clause };
let pats = hir_vec![self.pat_bool(e.span, true)];
(pats, cond, desugar)
}
};
let then_arm = self.arm(then_pats, P(then_expr));
hir::ExprKind::Match(P(scrutinee), vec![then_arm, else_arm].into(), desugar)
}
// FIXME(#53667): handle lowering of && and parens.
ExprKind::While(ref cond, ref body, opt_label) => {
// Desugar `ExprWhileLet`
// from: `[opt_ident]: while let <pat> = <sub_expr> <body>`
if let ExprKind::Let(ref pats, ref sub_expr) = cond.node {
// to:
//
// [opt_ident]: loop {
// match <sub_expr> {
// <pat> => <body>,
// _ => break
// }
// }
// Note that the block AND the condition are evaluated in the loop scope.
// This is done to allow `break` from inside the condition of the loop.
let (body, break_expr, sub_expr) = self.with_loop_scope(e.id, |this| {
(
this.lower_block(body, false),
this.expr_break(e.span, ThinVec::new()),
this.with_loop_condition_scope(|this| P(this.lower_expr(sub_expr))),
)
});
// `<pat> => <body>`
let pat_arm = {
let body_expr = P(self.expr_block(body, ThinVec::new()));
let pats = pats.iter().map(|pat| self.lower_pat(pat)).collect();
self.arm(pats, body_expr)
};
// `_ => break`
let break_arm = {
let pat_under = self.pat_wild(e.span);
self.arm(hir_vec![pat_under], break_expr)
};
// `match <sub_expr> { ... }`
let arms = hir_vec![pat_arm, break_arm];
let match_expr = self.expr(
sub_expr.span,
hir::ExprKind::Match(sub_expr, arms, hir::MatchSource::WhileLetDesugar),
ThinVec::new(),
);
// `[opt_ident]: loop { ... }`
let loop_block = P(self.block_expr(P(match_expr)));
let loop_expr = hir::ExprKind::Loop(
loop_block,
self.lower_label(opt_label),
hir::LoopSource::WhileLet,
);
// Add attributes to the outer returned expr node.
loop_expr
} else {
self.with_loop_scope(e.id, |this| {
hir::ExprKind::While(
this.with_loop_condition_scope(|this| P(this.lower_expr(cond))),
this.lower_block(body, false),
this.lower_label(opt_label),
)
})
}
}
ExprKind::While(ref cond, ref body, opt_label) => self.with_loop_scope(e.id, |this| {
hir::ExprKind::While(
this.with_loop_condition_scope(|this| P(this.lower_expr(cond))),
this.lower_block(body, false),
this.lower_label(opt_label),
)
}),
ExprKind::Loop(ref body, opt_label) => self.with_loop_scope(e.id, |this| {
hir::ExprKind::Loop(
this.lower_block(body, false),
@ -4703,105 +4797,6 @@ fn lower_expr(&mut self, e: &Expr) -> hir::Expr {
ExprKind::Err => hir::ExprKind::Err,
// Desugar `ExprIfLet`
// from: `if let <pat> = <sub_expr> <body> [<else_opt>]`
ExprKind::IfLet(ref pats, ref sub_expr, ref body, ref else_opt) => {
// to:
//
// match <sub_expr> {
// <pat> => <body>,
// _ => [<else_opt> | ()]
// }
let mut arms = vec![];
// `<pat> => <body>`
{
let body = self.lower_block(body, false);
let body_expr = P(self.expr_block(body, ThinVec::new()));
let pats = pats.iter().map(|pat| self.lower_pat(pat)).collect();
arms.push(self.arm(pats, body_expr));
}
// _ => [<else_opt>|{}]
{
let wildcard_arm: Option<&Expr> = else_opt.as_ref().map(|p| &**p);
let wildcard_pattern = self.pat_wild(e.span);
let body = if let Some(else_expr) = wildcard_arm {
self.lower_expr(else_expr)
} else {
self.expr_block_empty(e.span)
};
arms.push(self.arm(hir_vec![wildcard_pattern], P(body)));
}
let contains_else_clause = else_opt.is_some();
let sub_expr = P(self.lower_expr(sub_expr));
hir::ExprKind::Match(
sub_expr,
arms.into(),
hir::MatchSource::IfLetDesugar {
contains_else_clause,
},
)
}
// Desugar `ExprWhileLet`
// from: `[opt_ident]: while let <pat> = <sub_expr> <body>`
ExprKind::WhileLet(ref pats, ref sub_expr, ref body, opt_label) => {
// to:
//
// [opt_ident]: loop {
// match <sub_expr> {
// <pat> => <body>,
// _ => break
// }
// }
// Note that the block AND the condition are evaluated in the loop scope.
// This is done to allow `break` from inside the condition of the loop.
let (body, break_expr, sub_expr) = self.with_loop_scope(e.id, |this| {
(
this.lower_block(body, false),
this.expr_break(e.span, ThinVec::new()),
this.with_loop_condition_scope(|this| P(this.lower_expr(sub_expr))),
)
});
// `<pat> => <body>`
let pat_arm = {
let body_expr = P(self.expr_block(body, ThinVec::new()));
let pats = pats.iter().map(|pat| self.lower_pat(pat)).collect();
self.arm(pats, body_expr)
};
// `_ => break`
let break_arm = {
let pat_under = self.pat_wild(e.span);
self.arm(hir_vec![pat_under], break_expr)
};
// `match <sub_expr> { ... }`
let arms = hir_vec![pat_arm, break_arm];
let match_expr = self.expr(
sub_expr.span,
hir::ExprKind::Match(sub_expr, arms, hir::MatchSource::WhileLetDesugar),
ThinVec::new(),
);
// `[opt_ident]: loop { ... }`
let loop_block = P(self.block_expr(P(match_expr)));
let loop_expr = hir::ExprKind::Loop(
loop_block,
self.lower_label(opt_label),
hir::LoopSource::WhileLet,
);
// Add attributes to the outer returned expr node.
loop_expr
}
// Desugar `ExprForLoop`
// from: `[opt_ident]: for <pat> in <head> <body>`
ExprKind::ForLoop(ref pat, ref head, ref body, opt_label) => {
@ -5463,10 +5458,15 @@ fn expr_unsafe(&mut self, expr: P<hir::Expr>) -> hir::Expr {
)
}
/// Constructs a `true` or `false` literal expression.
fn expr_bool(&mut self, span: Span, val: bool) -> hir::Expr {
let lit = Spanned { span, node: LitKind::Bool(val) };
self.expr(span, hir::ExprKind::Lit(lit), ThinVec::new())
}
/// Constructs a `true` or `false` literal pattern.
fn pat_bool(&mut self, span: Span, val: bool) -> P<hir::Pat> {
let lit = Spanned { span, node: LitKind::Bool(val) };
let expr = self.expr(span, hir::ExprKind::Lit(lit), ThinVec::new());
let expr = self.expr_bool(span, val);
self.pat(span, hir::PatKind::Lit(P(expr)))
}

View File

@ -324,20 +324,28 @@ fn check_unused_parens_expr(&self,
value: &ast::Expr,
msg: &str,
followed_by_block: bool) {
if let ast::ExprKind::Paren(ref inner) = value.node {
let necessary = followed_by_block && match inner.node {
ast::ExprKind::Ret(_) | ast::ExprKind::Break(..) => true,
_ => parser::contains_exterior_struct_lit(&inner),
};
if !necessary {
let expr_text = if let Ok(snippet) = cx.sess().source_map()
.span_to_snippet(value.span) {
snippet
} else {
pprust::expr_to_string(value)
};
Self::remove_outer_parens(cx, value.span, &expr_text, msg);
match value.node {
ast::ExprKind::Paren(ref inner) => {
let necessary = followed_by_block && match inner.node {
ast::ExprKind::Ret(_) | ast::ExprKind::Break(..) => true,
_ => parser::contains_exterior_struct_lit(&inner),
};
if !necessary {
let expr_text = if let Ok(snippet) = cx.sess().source_map()
.span_to_snippet(value.span) {
snippet
} else {
pprust::expr_to_string(value)
};
Self::remove_outer_parens(cx, value.span, &expr_text, msg);
}
}
ast::ExprKind::Let(_, ref expr) => {
// FIXME(#60336): Properly handle `let true = (false && true)`
// actually needing the parenthesis.
self.check_unused_parens_expr(cx, expr, "`let` head expression", followed_by_block);
}
_ => {}
}
}
@ -399,8 +407,6 @@ fn check_expr(&mut self, cx: &EarlyContext<'_>, e: &ast::Expr) {
let (value, msg, followed_by_block) = match e.node {
If(ref cond, ..) => (cond, "`if` condition", true),
While(ref cond, ..) => (cond, "`while` condition", true),
IfLet(_, ref cond, ..) => (cond, "`if let` head expression", true),
WhileLet(_, ref cond, ..) => (cond, "`while let` head expression", true),
ForLoop(_, ref cond, ..) => (cond, "`for` head expression", true),
Match(ref head, _) => (head, "`match` head expression", true),
Ret(Some(ref value)) => (value, "`return` value", false),

View File

@ -17,13 +17,11 @@
use syntax::feature_gate::is_builtin_attr;
use syntax::source_map::Spanned;
use syntax::symbol::{kw, sym};
use syntax::ptr::P;
use syntax::visit::{self, Visitor};
use syntax::{span_err, struct_span_err, walk_list};
use syntax_ext::proc_macro_decls::is_proc_macro_attr;
use syntax_pos::{Span, MultiSpan};
use errors::{Applicability, FatalError};
use log::debug;
#[derive(Copy, Clone, Debug)]
struct OuterImplTrait {
@ -319,54 +317,6 @@ fn check_late_bound_lifetime_defs(&self, params: &[GenericParam]) {
}
}
/// With eRFC 2497, we need to check whether an expression is ambiguous and warn or error
/// depending on the edition, this function handles that.
fn while_if_let_ambiguity(&self, expr: &P<Expr>) {
if let Some((span, op_kind)) = self.while_if_let_expr_ambiguity(&expr) {
let mut err = self.err_handler().struct_span_err(
span, &format!("ambiguous use of `{}`", op_kind.to_string())
);
err.note(
"this will be a error until the `let_chains` feature is stabilized"
);
err.note(
"see rust-lang/rust#53668 for more information"
);
if let Ok(snippet) = self.session.source_map().span_to_snippet(span) {
err.span_suggestion(
span, "consider adding parentheses", format!("({})", snippet),
Applicability::MachineApplicable,
);
}
err.emit();
}
}
/// With eRFC 2497 adding if-let chains, there is a requirement that the parsing of
/// `&&` and `||` in a if-let statement be unambiguous. This function returns a span and
/// a `BinOpKind` (either `&&` or `||` depending on what was ambiguous) if it is determined
/// that the current expression parsed is ambiguous and will break in future.
fn while_if_let_expr_ambiguity(&self, expr: &P<Expr>) -> Option<(Span, BinOpKind)> {
debug!("while_if_let_expr_ambiguity: expr.node: {:?}", expr.node);
match &expr.node {
ExprKind::Binary(op, _, _) if op.node == BinOpKind::And || op.node == BinOpKind::Or => {
Some((expr.span, op.node))
},
ExprKind::Range(ref lhs, ref rhs, _) => {
let lhs_ambiguous = lhs.as_ref()
.and_then(|lhs| self.while_if_let_expr_ambiguity(lhs));
let rhs_ambiguous = rhs.as_ref()
.and_then(|rhs| self.while_if_let_expr_ambiguity(rhs));
lhs_ambiguous.or(rhs_ambiguous)
}
_ => None,
}
}
fn check_fn_decl(&self, fn_decl: &FnDecl) {
fn_decl
.inputs
@ -493,19 +443,17 @@ fn validate_generics_order<'a>(
impl<'a> Visitor<'a> for AstValidator<'a> {
fn visit_expr(&mut self, expr: &'a Expr) {
match expr.node {
ExprKind::Closure(_, _, _, ref fn_decl, _, _) => {
match &expr.node {
ExprKind::Closure(_, _, _, fn_decl, _, _) => {
self.check_fn_decl(fn_decl);
}
ExprKind::IfLet(_, ref expr, _, _) | ExprKind::WhileLet(_, ref expr, _, _) =>
self.while_if_let_ambiguity(&expr),
ExprKind::InlineAsm(..) if !self.session.target.target.options.allow_asm => {
span_err!(self.session, expr.span, E0472, "asm! is unsupported on this target");
}
_ => {}
}
visit::walk_expr(self, expr)
visit::walk_expr(self, expr);
}
fn visit_ty(&mut self, ty: &'a Ty) {

View File

@ -8,6 +8,7 @@
#![feature(in_band_lifetimes)]
#![feature(nll)]
#![feature(bind_by_move_pattern_guards)]
#![feature(rustc_diagnostic_macros)]
#![recursion_limit="256"]

View File

@ -485,8 +485,6 @@ struct BindingInfo {
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
enum PatternSource {
Match,
IfLet,
WhileLet,
Let,
For,
FnParam,
@ -496,8 +494,6 @@ impl PatternSource {
fn descr(self) -> &'static str {
match self {
PatternSource::Match => "match binding",
PatternSource::IfLet => "if let binding",
PatternSource::WhileLet => "while let binding",
PatternSource::Let => "let binding",
PatternSource::For => "for binding",
PatternSource::FnParam => "function parameter",
@ -3057,13 +3053,7 @@ fn check_consistent_bindings(&mut self, pats: &[P<Pat>]) {
fn resolve_arm(&mut self, arm: &Arm) {
self.ribs[ValueNS].push(Rib::new(NormalRibKind));
let mut bindings_list = FxHashMap::default();
for pattern in &arm.pats {
self.resolve_pattern(&pattern, PatternSource::Match, &mut bindings_list);
}
// This has to happen *after* we determine which pat_idents are variants.
self.check_consistent_bindings(&arm.pats);
self.resolve_pats(&arm.pats, PatternSource::Match);
if let Some(ast::Guard::If(ref expr)) = arm.guard {
self.visit_expr(expr)
@ -3073,6 +3063,16 @@ fn resolve_arm(&mut self, arm: &Arm) {
self.ribs[ValueNS].pop();
}
/// Arising from `source`, resolve a sequence of patterns (top level or-patterns).
fn resolve_pats(&mut self, pats: &[P<Pat>], source: PatternSource) {
let mut bindings_list = FxHashMap::default();
for pat in pats {
self.resolve_pattern(pat, source, &mut bindings_list);
}
// This has to happen *after* we determine which pat_idents are variants
self.check_consistent_bindings(pats);
}
fn resolve_block(&mut self, block: &Block) {
debug!("(resolving block) entering block");
// Move down in the graph, if there's an anonymous module rooted here.
@ -3151,8 +3151,7 @@ fn fresh_binding(&mut self,
);
}
Some(..) if pat_src == PatternSource::Match ||
pat_src == PatternSource::IfLet ||
pat_src == PatternSource::WhileLet => {
pat_src == PatternSource::Let => {
// `Variant1(a) | Variant2(a)`, ok
// Reuse definition from the first `a`.
res = self.ribs[ValueNS].last_mut().unwrap().bindings[&ident];
@ -4345,41 +4344,26 @@ fn resolve_expr(&mut self, expr: &Expr, parent: Option<&Expr>) {
visit::walk_expr(self, expr);
}
ExprKind::IfLet(ref pats, ref subexpression, ref if_block, ref optional_else) => {
self.visit_expr(subexpression);
ExprKind::Let(ref pats, ref scrutinee) => {
self.visit_expr(scrutinee);
self.resolve_pats(pats, PatternSource::Let);
}
ExprKind::If(ref cond, ref then, ref opt_else) => {
self.ribs[ValueNS].push(Rib::new(NormalRibKind));
let mut bindings_list = FxHashMap::default();
for pat in pats {
self.resolve_pattern(pat, PatternSource::IfLet, &mut bindings_list);
}
// This has to happen *after* we determine which pat_idents are variants
self.check_consistent_bindings(pats);
self.visit_block(if_block);
self.visit_expr(cond);
self.visit_block(then);
self.ribs[ValueNS].pop();
optional_else.as_ref().map(|expr| self.visit_expr(expr));
opt_else.as_ref().map(|expr| self.visit_expr(expr));
}
ExprKind::Loop(ref block, label) => self.resolve_labeled_block(label, expr.id, &block),
ExprKind::While(ref subexpression, ref block, label) => {
self.with_resolved_label(label, expr.id, |this| {
this.visit_expr(subexpression);
this.visit_block(block);
});
}
ExprKind::WhileLet(ref pats, ref subexpression, ref block, label) => {
self.with_resolved_label(label, expr.id, |this| {
this.visit_expr(subexpression);
this.ribs[ValueNS].push(Rib::new(NormalRibKind));
let mut bindings_list = FxHashMap::default();
for pat in pats {
this.resolve_pattern(pat, PatternSource::WhileLet, &mut bindings_list);
}
// This has to happen *after* we determine which pat_idents are variants.
this.check_consistent_bindings(pats);
this.visit_expr(subexpression);
this.visit_block(block);
this.ribs[ValueNS].pop();
});

View File

@ -1580,17 +1580,9 @@ fn visit_expr(&mut self, ex: &'l ast::Expr) {
self.visit_expr(subexpression);
visit::walk_block(self, block);
}
ast::ExprKind::WhileLet(ref pats, ref subexpression, ref block, _) => {
ast::ExprKind::Let(ref pats, ref scrutinee) => {
self.process_var_decl_multi(pats);
debug!("for loop, walk sub-expr: {:?}", subexpression.node);
self.visit_expr(subexpression);
visit::walk_block(self, block);
}
ast::ExprKind::IfLet(ref pats, ref subexpression, ref block, ref opt_else) => {
self.process_var_decl_multi(pats);
self.visit_expr(subexpression);
visit::walk_block(self, block);
opt_else.as_ref().map(|el| self.visit_expr(el));
self.visit_expr(scrutinee);
}
ast::ExprKind::Repeat(ref element, ref count) => {
self.visit_expr(element);

View File

@ -1032,10 +1032,9 @@ pub fn precedence(&self) -> ExprPrecedence {
ExprKind::Unary(..) => ExprPrecedence::Unary,
ExprKind::Lit(_) => ExprPrecedence::Lit,
ExprKind::Type(..) | ExprKind::Cast(..) => ExprPrecedence::Cast,
ExprKind::Let(..) => ExprPrecedence::Let,
ExprKind::If(..) => ExprPrecedence::If,
ExprKind::IfLet(..) => ExprPrecedence::IfLet,
ExprKind::While(..) => ExprPrecedence::While,
ExprKind::WhileLet(..) => ExprPrecedence::WhileLet,
ExprKind::ForLoop(..) => ExprPrecedence::ForLoop,
ExprKind::Loop(..) => ExprPrecedence::Loop,
ExprKind::Match(..) => ExprPrecedence::Match,
@ -1116,26 +1115,20 @@ pub enum ExprKind {
Cast(P<Expr>, P<Ty>),
/// A type ascription (e.g., `42: usize`).
Type(P<Expr>, P<Ty>),
/// A `let pats = expr` expression that is only semantically allowed in the condition
/// of `if` / `while` expressions. (e.g., `if let 0 = x { .. }`).
///
/// The `Vec<P<Pat>>` is for or-patterns at the top level.
/// FIXME(54883): Change this to just `P<Pat>`.
Let(Vec<P<Pat>>, P<Expr>),
/// An `if` block, with an optional `else` block.
///
/// `if expr { block } else { expr }`
If(P<Expr>, P<Block>, Option<P<Expr>>),
/// An `if let` expression with an optional else block
///
/// `if let pat = expr { block } else { expr }`
///
/// This is desugared to a `match` expression.
IfLet(Vec<P<Pat>>, P<Expr>, P<Block>, Option<P<Expr>>),
/// A while loop, with an optional label
/// A while loop, with an optional label.
///
/// `'label: while expr { block }`
While(P<Expr>, P<Block>, Option<Label>),
/// A `while let` loop, with an optional label.
///
/// `'label: while let pat = expr { block }`
///
/// This is desugared to a combination of `loop` and `match` expressions.
WhileLet(Vec<P<Pat>>, P<Expr>, P<Block>, Option<Label>),
/// A `for` loop, with an optional label.
///
/// `'label: for pat in expr { block }`

View File

@ -825,7 +825,9 @@ fn may_be_ident(nt: &token::Nonterminal) -> bool {
}
match name {
sym::expr => token.can_begin_expr(),
sym::expr => token.can_begin_expr()
// This exception is here for backwards compatibility.
&& !token.is_keyword(kw::Let),
sym::ty => token.can_begin_type(),
sym::ident => get_macro_name(token).is_some(),
sym::literal => token.can_begin_literal_or_bool(),

View File

@ -560,6 +560,9 @@ pub fn walk_feature_fields<F>(&self, mut f: F)
// Allows calling constructor functions in `const fn`.
(active, const_constructor, "1.37.0", Some(61456), None),
// Allows `if/while p && let q = r && ...` chains.
(active, let_chains, "1.37.0", Some(53667), None),
// #[repr(transparent)] on enums.
(active, transparent_enums, "1.37.0", Some(60405), None),
@ -577,7 +580,8 @@ pub fn walk_feature_fields<F>(&self, mut f: F)
const INCOMPLETE_FEATURES: &[Symbol] = &[
sym::impl_trait_in_bindings,
sym::generic_associated_types,
sym::const_generics
sym::const_generics,
sym::let_chains,
];
declare_features! (
@ -2517,6 +2521,17 @@ pub fn check_crate(krate: &ast::Crate,
"attributes on function parameters are unstable"
));
sess
.let_chains_spans
.borrow()
.iter()
.for_each(|span| gate_feature!(
&ctx,
let_chains,
*span,
"`let` expressions in this position are experimental"
));
let visitor = &mut PostExpansionVisitor {
context: &ctx,
builtin_attributes: &*BUILTIN_ATTRIBUTE_MAP,

View File

@ -1110,28 +1110,20 @@ pub fn noop_visit_expr<T: MutVisitor>(Expr { node, id, span, attrs }: &mut Expr,
vis.visit_ty(ty);
}
ExprKind::AddrOf(_m, ohs) => vis.visit_expr(ohs),
ExprKind::Let(pats, scrutinee) => {
visit_vec(pats, |pat| vis.visit_pat(pat));
vis.visit_expr(scrutinee);
}
ExprKind::If(cond, tr, fl) => {
vis.visit_expr(cond);
vis.visit_block(tr);
visit_opt(fl, |fl| vis.visit_expr(fl));
}
ExprKind::IfLet(pats, expr, tr, fl) => {
visit_vec(pats, |pat| vis.visit_pat(pat));
vis.visit_expr(expr);
vis.visit_block(tr);
visit_opt(fl, |fl| vis.visit_expr(fl));
}
ExprKind::While(cond, body, label) => {
vis.visit_expr(cond);
vis.visit_block(body);
visit_opt(label, |label| vis.visit_label(label));
}
ExprKind::WhileLet(pats, expr, body, label) => {
visit_vec(pats, |pat| vis.visit_pat(pat));
vis.visit_expr(expr);
vis.visit_block(body);
visit_opt(label, |label| vis.visit_label(label));
}
ExprKind::ForLoop(pat, iter, body, label) => {
vis.visit_pat(pat);
vis.visit_expr(iter);

View File

@ -14,11 +14,9 @@
pub fn expr_requires_semi_to_be_stmt(e: &ast::Expr) -> bool {
match e.node {
ast::ExprKind::If(..) |
ast::ExprKind::IfLet(..) |
ast::ExprKind::Match(..) |
ast::ExprKind::Block(..) |
ast::ExprKind::While(..) |
ast::ExprKind::WhileLet(..) |
ast::ExprKind::Loop(..) |
ast::ExprKind::ForLoop(..) |
ast::ExprKind::TryBlock(..) => false,

View File

@ -1491,6 +1491,7 @@ fn mk_sess(sm: Lrc<SourceMap>) -> ParseSess {
edition: Edition::from_session(),
ambiguous_block_expr_parse: Lock::new(FxHashMap::default()),
param_attr_spans: Lock::new(Vec::new()),
let_chains_spans: Lock::new(Vec::new()),
}
}

View File

@ -54,7 +54,9 @@ pub struct ParseSess {
/// operation token that followed it, but that the parser cannot identify without further
/// analysis.
pub ambiguous_block_expr_parse: Lock<FxHashMap<Span, Span>>,
pub param_attr_spans: Lock<Vec<Span>>
pub param_attr_spans: Lock<Vec<Span>>,
// Places where `let` exprs were used and should be feature gated according to `let_chains`.
pub let_chains_spans: Lock<Vec<Span>>,
}
impl ParseSess {
@ -81,6 +83,7 @@ pub fn with_span_handler(handler: Handler, source_map: Lrc<SourceMap>) -> ParseS
edition: Edition::from_session(),
ambiguous_block_expr_parse: Lock::new(FxHashMap::default()),
param_attr_spans: Lock::new(Vec::new()),
let_chains_spans: Lock::new(Vec::new()),
}
}

View File

@ -41,7 +41,7 @@
use crate::parse::lexer::comments::{doc_comment_style, strip_doc_comment_decoration};
use crate::parse::token::{Token, TokenKind, DelimToken};
use crate::parse::{new_sub_parser_from_file, ParseSess, Directory, DirectoryOwnership};
use crate::util::parser::{AssocOp, Fixity};
use crate::util::parser::{AssocOp, Fixity, prec_let_scrutinee_needs_par};
use crate::print::pprust;
use crate::ptr::P;
use crate::parse::PResult;
@ -2215,13 +2215,8 @@ macro_rules! parse_lit {
} else {
ex = ExprKind::Yield(None);
}
} else if self.token.is_keyword(kw::Let) {
// Catch this syntax error here, instead of in `parse_ident`, so
// that we can explicitly mention that let is not to be used as an expression
let mut db = self.fatal("expected expression, found statement (`let`)");
db.span_label(self.token.span, "expected expression");
db.note("variable declaration using `let` is a statement");
return Err(db);
} else if self.eat_keyword(kw::Let) {
return self.parse_let_expr(attrs);
} else if is_span_rust_2018 && self.eat_keyword(kw::Await) {
let (await_hi, e_kind) = self.parse_await_macro_or_alt(lo, self.prev_span)?;
hi = await_hi;
@ -2483,15 +2478,13 @@ fn parse_dot_or_call_expr_with(&mut self,
attrs.extend::<Vec<_>>(expr.attrs.into());
expr.attrs = attrs;
match expr.node {
ExprKind::If(..) | ExprKind::IfLet(..) => {
if !expr.attrs.is_empty() {
// Just point to the first attribute in there...
let span = expr.attrs[0].span;
ExprKind::If(..) if !expr.attrs.is_empty() => {
// Just point to the first attribute in there...
let span = expr.attrs[0].span;
self.span_err(span,
"attributes are not yet allowed on `if` \
expressions");
}
self.span_err(span,
"attributes are not yet allowed on `if` \
expressions");
}
_ => {}
}
@ -3161,13 +3154,10 @@ fn is_at_start_of_range_notation_rhs(&self) -> bool {
}
}
/// Parses an `if` or `if let` expression (`if` token already eaten).
/// Parses an `if` expression (`if` token already eaten).
fn parse_if_expr(&mut self, attrs: ThinVec<Attribute>) -> PResult<'a, P<Expr>> {
if self.check_keyword(kw::Let) {
return self.parse_if_let_expr(attrs);
}
let lo = self.prev_span;
let cond = self.parse_expr_res(Restrictions::NO_STRUCT_LITERAL, None)?;
let cond = self.parse_cond_expr()?;
// Verify that the parsed `if` condition makes sense as a condition. If it is a block, then
// verify that the last statement is either an implicit return (no `;`) or an explicit
@ -3197,22 +3187,32 @@ fn parse_if_expr(&mut self, attrs: ThinVec<Attribute>) -> PResult<'a, P<Expr>> {
Ok(self.mk_expr(lo.to(hi), ExprKind::If(cond, thn, els), attrs))
}
/// Parses an `if let` expression (`if` token already eaten).
fn parse_if_let_expr(&mut self, attrs: ThinVec<Attribute>)
-> PResult<'a, P<Expr>> {
/// Parse the condition of a `if`- or `while`-expression
fn parse_cond_expr(&mut self) -> PResult<'a, P<Expr>> {
let cond = self.parse_expr_res(Restrictions::NO_STRUCT_LITERAL, None)?;
if let ExprKind::Let(..) = cond.node {
// Remove the last feature gating of a `let` expression since it's stable.
let last = self.sess.let_chains_spans.borrow_mut().pop();
debug_assert_eq!(cond.span, last.unwrap());
}
Ok(cond)
}
/// Parses a `let $pats = $expr` pseudo-expression.
/// The `let` token has already been eaten.
fn parse_let_expr(&mut self, attrs: ThinVec<Attribute>) -> PResult<'a, P<Expr>> {
let lo = self.prev_span;
self.expect_keyword(kw::Let)?;
let pats = self.parse_pats()?;
self.expect(&token::Eq)?;
let expr = self.parse_expr_res(Restrictions::NO_STRUCT_LITERAL, None)?;
let thn = self.parse_block()?;
let (hi, els) = if self.eat_keyword(kw::Else) {
let expr = self.parse_else_expr()?;
(expr.span, Some(expr))
} else {
(thn.span, None)
};
Ok(self.mk_expr(lo.to(hi), ExprKind::IfLet(pats, expr, thn, els), attrs))
let expr = self.with_res(
Restrictions::NO_STRUCT_LITERAL,
|this| this.parse_assoc_expr_with(1 + prec_let_scrutinee_needs_par(), None.into())
)?;
let span = lo.to(expr.span);
self.sess.let_chains_spans.borrow_mut().push(span);
Ok(self.mk_expr(span, ExprKind::Let(pats, expr), attrs))
}
/// Parses `move |args| expr`.
@ -3299,28 +3299,11 @@ fn parse_for_expr(&mut self, opt_label: Option<Label>,
fn parse_while_expr(&mut self, opt_label: Option<Label>,
span_lo: Span,
mut attrs: ThinVec<Attribute>) -> PResult<'a, P<Expr>> {
if self.token.is_keyword(kw::Let) {
return self.parse_while_let_expr(opt_label, span_lo, attrs);
}
let cond = self.parse_expr_res(Restrictions::NO_STRUCT_LITERAL, None)?;
let cond = self.parse_cond_expr()?;
let (iattrs, body) = self.parse_inner_attrs_and_block()?;
attrs.extend(iattrs);
let span = span_lo.to(body.span);
return Ok(self.mk_expr(span, ExprKind::While(cond, body, opt_label), attrs));
}
/// Parses a `while let` expression (`while` token already eaten).
fn parse_while_let_expr(&mut self, opt_label: Option<Label>,
span_lo: Span,
mut attrs: ThinVec<Attribute>) -> PResult<'a, P<Expr>> {
self.expect_keyword(kw::Let)?;
let pats = self.parse_pats()?;
self.expect(&token::Eq)?;
let expr = self.parse_expr_res(Restrictions::NO_STRUCT_LITERAL, None)?;
let (iattrs, body) = self.parse_inner_attrs_and_block()?;
attrs.extend(iattrs);
let span = span_lo.to(body.span);
return Ok(self.mk_expr(span, ExprKind::WhileLet(pats, expr, body, opt_label), attrs));
Ok(self.mk_expr(span, ExprKind::While(cond, body, opt_label), attrs))
}
// parse `loop {...}`, `loop` token already eaten

View File

@ -135,6 +135,7 @@ pub(crate) fn ident_can_begin_expr(name: ast::Name, span: Span, is_raw: bool) ->
kw::False,
kw::For,
kw::If,
kw::Let,
kw::Loop,
kw::Match,
kw::Move,

View File

@ -1715,6 +1715,21 @@ pub fn print_block_maybe_unclosed(&mut self,
self.ann.post(self, AnnNode::Block(blk))
}
/// Print a `let pats = scrutinee` expression.
pub fn print_let(&mut self, pats: &[P<ast::Pat>], scrutinee: &ast::Expr) -> io::Result<()> {
self.s.word("let ")?;
self.print_pats(pats)?;
self.s.space()?;
self.word_space("=")?;
self.print_expr_cond_paren(
scrutinee,
Self::cond_needs_par(scrutinee)
|| parser::needs_par_as_let_scrutinee(scrutinee.precedence().order())
)
}
fn print_else(&mut self, els: Option<&ast::Expr>) -> io::Result<()> {
match els {
Some(_else) => {
@ -1729,19 +1744,6 @@ fn print_else(&mut self, els: Option<&ast::Expr>) -> io::Result<()> {
self.print_block(then)?;
self.print_else(e.as_ref().map(|e| &**e))
}
// Another `else if let` block.
ast::ExprKind::IfLet(ref pats, ref expr, ref then, ref e) => {
self.cbox(INDENT_UNIT - 1)?;
self.ibox(0)?;
self.s.word(" else if let ")?;
self.print_pats(pats)?;
self.s.space()?;
self.word_space("=")?;
self.print_expr_as_cond(expr)?;
self.s.space()?;
self.print_block(then)?;
self.print_else(e.as_ref().map(|e| &**e))
}
// Final `else` block.
ast::ExprKind::Block(ref b, _) => {
self.cbox(INDENT_UNIT - 1)?;
@ -1762,20 +1764,10 @@ fn print_else(&mut self, els: Option<&ast::Expr>) -> io::Result<()> {
pub fn print_if(&mut self, test: &ast::Expr, blk: &ast::Block,
elseopt: Option<&ast::Expr>) -> io::Result<()> {
self.head("if")?;
self.print_expr_as_cond(test)?;
self.s.space()?;
self.print_block(blk)?;
self.print_else(elseopt)
}
pub fn print_if_let(&mut self, pats: &[P<ast::Pat>], expr: &ast::Expr, blk: &ast::Block,
elseopt: Option<&ast::Expr>) -> io::Result<()> {
self.head("if let")?;
self.print_pats(pats)?;
self.s.space()?;
self.word_space("=")?;
self.print_expr_as_cond(expr)?;
self.s.space()?;
self.print_block(blk)?;
self.print_else(elseopt)
}
@ -1807,21 +1799,18 @@ fn print_call_post(&mut self, args: &[P<ast::Expr>]) -> io::Result<()> {
}
pub fn print_expr_maybe_paren(&mut self, expr: &ast::Expr, prec: i8) -> io::Result<()> {
let needs_par = expr.precedence().order() < prec;
if needs_par {
self.popen()?;
}
self.print_expr(expr)?;
if needs_par {
self.pclose()?;
}
Ok(())
self.print_expr_cond_paren(expr, expr.precedence().order() < prec)
}
/// Print an expr using syntax that's acceptable in a condition position, such as the `cond` in
/// `if cond { ... }`.
pub fn print_expr_as_cond(&mut self, expr: &ast::Expr) -> io::Result<()> {
let needs_par = match expr.node {
self.print_expr_cond_paren(expr, Self::cond_needs_par(expr))
}
/// Does `expr` need parenthesis when printed in a condition position?
fn cond_needs_par(expr: &ast::Expr) -> bool {
match expr.node {
// These cases need parens due to the parse error observed in #26461: `if return {}`
// parses as the erroneous construct `if (return {})`, not `if (return) {}`.
ast::ExprKind::Closure(..) |
@ -1829,8 +1818,11 @@ pub fn print_expr_as_cond(&mut self, expr: &ast::Expr) -> io::Result<()> {
ast::ExprKind::Break(..) => true,
_ => parser::contains_exterior_struct_lit(expr),
};
}
}
/// Print `expr` or `(expr)` when `needs_par` holds.
fn print_expr_cond_paren(&mut self, expr: &ast::Expr, needs_par: bool) -> io::Result<()> {
if needs_par {
self.popen()?;
}
@ -1962,6 +1954,17 @@ fn print_expr_binary(&mut self,
// of `(x as i32) < ...`. We need to convince it _not_ to do that.
(&ast::ExprKind::Cast { .. }, ast::BinOpKind::Lt) |
(&ast::ExprKind::Cast { .. }, ast::BinOpKind::Shl) => parser::PREC_FORCE_PAREN,
// We are given `(let _ = a) OP b`.
//
// - When `OP <= LAnd` we should print `let _ = a OP b` to avoid redundant parens
// as the parser will interpret this as `(let _ = a) OP b`.
//
// - Otherwise, e.g. when we have `(let a = b) < c` in AST,
// parens are required since the parser would interpret `let a = b < c` as
// `let a = (b < c)`. To achieve this, we force parens.
(&ast::ExprKind::Let { .. }, _) if !parser::needs_par_as_let_scrutinee(prec) => {
parser::PREC_FORCE_PAREN
}
_ => left_prec,
};
@ -2052,12 +2055,12 @@ fn print_expr_outer_attr_style(&mut self,
self.word_space(":")?;
self.print_type(ty)?;
}
ast::ExprKind::Let(ref pats, ref scrutinee) => {
self.print_let(pats, scrutinee)?;
}
ast::ExprKind::If(ref test, ref blk, ref elseopt) => {
self.print_if(test, blk, elseopt.as_ref().map(|e| &**e))?;
}
ast::ExprKind::IfLet(ref pats, ref expr, ref blk, ref elseopt) => {
self.print_if_let(pats, expr, blk, elseopt.as_ref().map(|e| &**e))?;
}
ast::ExprKind::While(ref test, ref blk, opt_label) => {
if let Some(label) = opt_label {
self.print_ident(label.ident)?;
@ -2068,19 +2071,6 @@ fn print_expr_outer_attr_style(&mut self,
self.s.space()?;
self.print_block_with_attrs(blk, attrs)?;
}
ast::ExprKind::WhileLet(ref pats, ref expr, ref blk, opt_label) => {
if let Some(label) = opt_label {
self.print_ident(label.ident)?;
self.word_space(":")?;
}
self.head("while let")?;
self.print_pats(pats)?;
self.s.space()?;
self.word_space("=")?;
self.print_expr_as_cond(expr)?;
self.s.space()?;
self.print_block_with_attrs(blk, attrs)?;
}
ast::ExprKind::ForLoop(ref pat, ref iter, ref blk, opt_label) => {
if let Some(label) = opt_label {
self.print_ident(label.ident)?;

View File

@ -260,6 +260,7 @@ pub enum ExprPrecedence {
Box,
AddrOf,
Let,
Unary,
Call,
@ -277,9 +278,7 @@ pub enum ExprPrecedence {
Path,
Paren,
If,
IfLet,
While,
WhileLet,
ForLoop,
Loop,
Match,
@ -318,6 +317,11 @@ pub fn order(self) -> i8 {
// Unary, prefix
ExprPrecedence::Box |
ExprPrecedence::AddrOf |
// Here `let pats = expr` has `let pats =` as a "unary" prefix of `expr`.
// However, this is not exactly right. When `let _ = a` is the LHS of a binop we
// need parens sometimes. E.g. we can print `(let _ = a) && b` as `let _ = a && b`
// but we need to print `(let _ = a) < b` as-is with parens.
ExprPrecedence::Let |
ExprPrecedence::Unary => PREC_PREFIX,
// Unary, postfix
@ -338,9 +342,7 @@ pub fn order(self) -> i8 {
ExprPrecedence::Path |
ExprPrecedence::Paren |
ExprPrecedence::If |
ExprPrecedence::IfLet |
ExprPrecedence::While |
ExprPrecedence::WhileLet |
ExprPrecedence::ForLoop |
ExprPrecedence::Loop |
ExprPrecedence::Match |
@ -353,6 +355,19 @@ pub fn order(self) -> i8 {
}
}
/// In `let p = e`, operators with precedence `<=` this one requires parenthesis in `e`.
crate fn prec_let_scrutinee_needs_par() -> usize {
AssocOp::LAnd.precedence()
}
/// Suppose we have `let _ = e` and the `order` of `e`.
/// Is the `order` such that `e` in `let _ = e` needs parenthesis when it is on the RHS?
///
/// Conversely, suppose that we have `(let _ = a) OP b` and `order` is that of `OP`.
/// Can we print this as `let _ = a OP b`?
crate fn needs_par_as_let_scrutinee(order: i8) -> bool {
order <= prec_let_scrutinee_needs_par() as i8
}
/// Expressions that syntactically contain an "exterior" struct literal i.e., not surrounded by any
/// parens or other delimiters, e.g., `X { y: 1 }`, `X { y: 1 }.method()`, `foo == X { y: 1 }` and

View File

@ -719,6 +719,10 @@ pub fn walk_expr<'a, V: Visitor<'a>>(visitor: &mut V, expression: &'a Expr) {
visitor.visit_expr(subexpression);
visitor.visit_ty(typ)
}
ExprKind::Let(ref pats, ref scrutinee) => {
walk_list!(visitor, visit_pat, pats);
visitor.visit_expr(scrutinee);
}
ExprKind::If(ref head_expression, ref if_block, ref optional_else) => {
visitor.visit_expr(head_expression);
visitor.visit_block(if_block);
@ -729,18 +733,6 @@ pub fn walk_expr<'a, V: Visitor<'a>>(visitor: &mut V, expression: &'a Expr) {
visitor.visit_expr(subexpression);
visitor.visit_block(block);
}
ExprKind::IfLet(ref pats, ref subexpression, ref if_block, ref optional_else) => {
walk_list!(visitor, visit_pat, pats);
visitor.visit_expr(subexpression);
visitor.visit_block(if_block);
walk_list!(visitor, visit_expr, optional_else);
}
ExprKind::WhileLet(ref pats, ref subexpression, ref block, ref opt_label) => {
walk_list!(visitor, visit_label, opt_label);
walk_list!(visitor, visit_pat, pats);
visitor.visit_expr(subexpression);
visitor.visit_block(block);
}
ExprKind::ForLoop(ref pattern, ref subexpression, ref block, ref opt_label) => {
walk_list!(visitor, visit_label, opt_label);
visitor.visit_pat(pattern);

View File

@ -354,6 +354,7 @@
label_break_value,
lang,
lang_items,
let_chains,
lhs,
lib,
lifetime,

View File

@ -68,7 +68,7 @@ fn iter_exprs(depth: usize, f: &mut dyn FnMut(P<Expr>)) {
let mut g = |e| f(expr(e));
for kind in 0 .. 16 {
for kind in 0..=19 {
match kind {
0 => iter_exprs(depth - 1, &mut |e| g(ExprKind::Box(e))),
1 => iter_exprs(depth - 1, &mut |e| g(ExprKind::Call(e, vec![]))),
@ -79,25 +79,26 @@ fn iter_exprs(depth: usize, f: &mut dyn FnMut(P<Expr>)) {
iter_exprs(depth - 1, &mut |e| g(ExprKind::MethodCall(
seg.clone(), vec![make_x(), e])));
},
3 => {
let op = Spanned { span: DUMMY_SP, node: BinOpKind::Add };
3..=8 => {
let op = Spanned {
span: DUMMY_SP,
node: match kind {
3 => BinOpKind::Add,
4 => BinOpKind::Mul,
5 => BinOpKind::Shl,
6 => BinOpKind::And,
7 => BinOpKind::Or,
8 => BinOpKind::Lt,
_ => unreachable!(),
}
};
iter_exprs(depth - 1, &mut |e| g(ExprKind::Binary(op, e, make_x())));
iter_exprs(depth - 1, &mut |e| g(ExprKind::Binary(op, make_x(), e)));
},
4 => {
let op = Spanned { span: DUMMY_SP, node: BinOpKind::Mul };
iter_exprs(depth - 1, &mut |e| g(ExprKind::Binary(op, e, make_x())));
iter_exprs(depth - 1, &mut |e| g(ExprKind::Binary(op, make_x(), e)));
},
5 => {
let op = Spanned { span: DUMMY_SP, node: BinOpKind::Shl };
iter_exprs(depth - 1, &mut |e| g(ExprKind::Binary(op, e, make_x())));
iter_exprs(depth - 1, &mut |e| g(ExprKind::Binary(op, make_x(), e)));
},
6 => {
9 => {
iter_exprs(depth - 1, &mut |e| g(ExprKind::Unary(UnOp::Deref, e)));
},
7 => {
10 => {
let block = P(Block {
stmts: Vec::new(),
id: DUMMY_NODE_ID,
@ -106,7 +107,7 @@ fn iter_exprs(depth: usize, f: &mut dyn FnMut(P<Expr>)) {
});
iter_exprs(depth - 1, &mut |e| g(ExprKind::If(e, block.clone(), None)));
},
8 => {
11 => {
let decl = P(FnDecl {
inputs: vec![],
output: FunctionRetTy::Default(DUMMY_SP),
@ -120,33 +121,41 @@ fn iter_exprs(depth: usize, f: &mut dyn FnMut(P<Expr>)) {
e,
DUMMY_SP)));
},
9 => {
12 => {
iter_exprs(depth - 1, &mut |e| g(ExprKind::Assign(e, make_x())));
iter_exprs(depth - 1, &mut |e| g(ExprKind::Assign(make_x(), e)));
},
10 => {
13 => {
iter_exprs(depth - 1, &mut |e| g(ExprKind::Field(e, Ident::from_str("f"))));
},
11 => {
14 => {
iter_exprs(depth - 1, &mut |e| g(ExprKind::Range(
Some(e), Some(make_x()), RangeLimits::HalfOpen)));
iter_exprs(depth - 1, &mut |e| g(ExprKind::Range(
Some(make_x()), Some(e), RangeLimits::HalfOpen)));
},
12 => {
15 => {
iter_exprs(depth - 1, &mut |e| g(ExprKind::AddrOf(Mutability::Immutable, e)));
},
13 => {
16 => {
g(ExprKind::Ret(None));
iter_exprs(depth - 1, &mut |e| g(ExprKind::Ret(Some(e))));
},
14 => {
17 => {
let path = Path::from_ident(Ident::from_str("S"));
g(ExprKind::Struct(path, vec![], Some(make_x())));
},
15 => {
18 => {
iter_exprs(depth - 1, &mut |e| g(ExprKind::Try(e)));
},
19 => {
let ps = vec![P(Pat {
id: DUMMY_NODE_ID,
node: PatKind::Wild,
span: DUMMY_SP,
})];
iter_exprs(depth - 1, &mut |e| g(ExprKind::Let(ps.clone(), e)))
},
_ => panic!("bad counter value in iter_exprs"),
}
}

View File

@ -22,8 +22,8 @@ fn main() {
match (true) { //~ ERROR unnecessary parentheses around `match` head expression
_ => {}
}
if let 1 = (1) {} //~ ERROR unnecessary parentheses around `if let` head expression
while let 1 = (2) {} //~ ERROR unnecessary parentheses around `while let` head expression
if let 1 = (1) {} //~ ERROR unnecessary parentheses around `let` head expression
while let 1 = (2) {} //~ ERROR unnecessary parentheses around `let` head expression
let v = X { y: false };
// struct lits needs parens, so these shouldn't warn.
if (v == X { y: true }) {}

View File

@ -40,13 +40,13 @@ error: unnecessary parentheses around `match` head expression
LL | match (true) {
| ^^^^^^ help: remove these parentheses
error: unnecessary parentheses around `if let` head expression
error: unnecessary parentheses around `let` head expression
--> $DIR/lint-unnecessary-parens.rs:25:16
|
LL | if let 1 = (1) {}
| ^^^ help: remove these parentheses
error: unnecessary parentheses around `while let` head expression
error: unnecessary parentheses around `let` head expression
--> $DIR/lint-unnecessary-parens.rs:26:19
|
LL | while let 1 = (2) {}

View File

@ -0,0 +1,6 @@
// compile-pass
// compile-flags: -Z unpretty=expanded
fn main() {
if let 0 = 1 {}
}

View File

@ -0,0 +1,10 @@
#![feature(prelude_import)]
#![no_std]
#[prelude_import]
use ::std::prelude::v1::*;
#[macro_use]
extern crate std;
// compile-pass
// compile-flags: -Z unpretty=expanded
fn main() { if let 0 = 1 { } }

View File

@ -0,0 +1,244 @@
// Here we test that `lowering` behaves correctly wrt. `let $pats = $expr` expressions.
//
// We want to make sure that `let` is banned in situations other than:
//
// expr =
// | ...
// | "if" expr_with_let block {"else" block}?
// | {label ":"}? while" expr_with_let block
// ;
//
// expr_with_let =
// | "let" top_pats "=" expr
// | expr_with_let "&&" expr_with_let
// | "(" expr_with_let ")"
// | expr
// ;
//
// To that end, we check some positions which is not part of the language above.
#![feature(const_generics)]
//~^ WARN the feature `const_generics` is incomplete
#![feature(let_chains)] // Avoid inflating `.stderr` with overzealous gates in this test.
//~^ WARN the feature `let_chains` is incomplete
#![allow(irrefutable_let_patterns)]
use std::ops::Range;
fn main() {}
fn nested_within_if_expr() {
if &let 0 = 0 {} //~ ERROR `let` expressions are not supported here
//~^ ERROR mismatched types
if !let 0 = 0 {} //~ ERROR `let` expressions are not supported here
if *let 0 = 0 {} //~ ERROR `let` expressions are not supported here
//~^ ERROR type `bool` cannot be dereferenced
if -let 0 = 0 {} //~ ERROR `let` expressions are not supported here
//~^ ERROR cannot apply unary operator `-` to type `bool`
fn _check_try_binds_tighter() -> Result<(), ()> {
if let 0 = 0? {}
//~^ ERROR the `?` operator can only be applied to values that implement `std::ops::Try`
Ok(())
}
if (let 0 = 0)? {} //~ ERROR `let` expressions are not supported here
//~^ ERROR the `?` operator can only be applied to values that implement `std::ops::Try`
//~| ERROR the `?` operator can only be used in a function that returns `Result`
if true || let 0 = 0 {} //~ ERROR `let` expressions are not supported here
if (true || let 0 = 0) {} //~ ERROR `let` expressions are not supported here
if true && (true || let 0 = 0) {} //~ ERROR `let` expressions are not supported here
if true || (true && let 0 = 0) {} //~ ERROR `let` expressions are not supported here
let mut x = true;
if x = let 0 = 0 {} //~ ERROR `let` expressions are not supported here
//~^ ERROR mismatched types
if true..(let 0 = 0) {} //~ ERROR `let` expressions are not supported here
//~^ ERROR mismatched types
if ..(let 0 = 0) {} //~ ERROR `let` expressions are not supported here
//~^ ERROR mismatched types
if (let 0 = 0).. {} //~ ERROR `let` expressions are not supported here
//~^ ERROR mismatched types
// Binds as `(let ... = true)..true &&/|| false`.
if let Range { start: _, end: _ } = true..true && false {}
//~^ ERROR `let` expressions are not supported here
//~| ERROR mismatched types
//~| ERROR mismatched types
if let Range { start: _, end: _ } = true..true || false {}
//~^ ERROR `let` expressions are not supported here
//~| ERROR mismatched types
//~| ERROR mismatched types
// Binds as `(let Range { start: F, end } = F)..(|| true)`.
const F: fn() -> bool = || true;
if let Range { start: F, end } = F..|| true {}
//~^ ERROR `let` expressions are not supported here
//~| ERROR mismatched types
//~| ERROR mismatched types
//~| ERROR mismatched types
// Binds as `(let Range { start: true, end } = t)..(&&false)`.
let t = &&true;
if let Range { start: true, end } = t..&&false {}
//~^ ERROR `let` expressions are not supported here
//~| ERROR mismatched types
//~| ERROR mismatched types
//~| ERROR mismatched types
if let true = let true = true {} //~ ERROR `let` expressions are not supported here
}
fn nested_within_while_expr() {
while &let 0 = 0 {} //~ ERROR `let` expressions are not supported here
//~^ ERROR mismatched types
while !let 0 = 0 {} //~ ERROR `let` expressions are not supported here
while *let 0 = 0 {} //~ ERROR `let` expressions are not supported here
//~^ ERROR type `bool` cannot be dereferenced
while -let 0 = 0 {} //~ ERROR `let` expressions are not supported here
//~^ ERROR cannot apply unary operator `-` to type `bool`
fn _check_try_binds_tighter() -> Result<(), ()> {
while let 0 = 0? {}
//~^ ERROR the `?` operator can only be applied to values that implement `std::ops::Try`
Ok(())
}
while (let 0 = 0)? {} //~ ERROR `let` expressions are not supported here
//~^ ERROR the `?` operator can only be applied to values that implement `std::ops::Try`
//~| ERROR the `?` operator can only be used in a function that returns `Result`
while true || let 0 = 0 {} //~ ERROR `let` expressions are not supported here
while (true || let 0 = 0) {} //~ ERROR `let` expressions are not supported here
while true && (true || let 0 = 0) {} //~ ERROR `let` expressions are not supported here
while true || (true && let 0 = 0) {} //~ ERROR `let` expressions are not supported here
let mut x = true;
while x = let 0 = 0 {} //~ ERROR `let` expressions are not supported here
//~^ ERROR mismatched types
while true..(let 0 = 0) {} //~ ERROR `let` expressions are not supported here
//~^ ERROR mismatched types
while ..(let 0 = 0) {} //~ ERROR `let` expressions are not supported here
//~^ ERROR mismatched types
while (let 0 = 0).. {} //~ ERROR `let` expressions are not supported here
//~^ ERROR mismatched types
// Binds as `(let ... = true)..true &&/|| false`.
while let Range { start: _, end: _ } = true..true && false {}
//~^ ERROR `let` expressions are not supported here
//~| ERROR mismatched types
//~| ERROR mismatched types
while let Range { start: _, end: _ } = true..true || false {}
//~^ ERROR `let` expressions are not supported here
//~| ERROR mismatched types
//~| ERROR mismatched types
// Binds as `(let Range { start: F, end } = F)..(|| true)`.
const F: fn() -> bool = || true;
while let Range { start: F, end } = F..|| true {}
//~^ ERROR `let` expressions are not supported here
//~| ERROR mismatched types
//~| ERROR mismatched types
//~| ERROR mismatched types
// Binds as `(let Range { start: true, end } = t)..(&&false)`.
let t = &&true;
while let Range { start: true, end } = t..&&false {}
//~^ ERROR `let` expressions are not supported here
//~| ERROR mismatched types
//~| ERROR mismatched types
//~| ERROR mismatched types
while let true = let true = true {} //~ ERROR `let` expressions are not supported here
}
fn not_error_because_clarified_intent() {
if let Range { start: _, end: _ } = (true..true || false) { }
if let Range { start: _, end: _ } = (true..true && false) { }
while let Range { start: _, end: _ } = (true..true || false) { }
while let Range { start: _, end: _ } = (true..true && false) { }
}
fn outside_if_and_while_expr() {
&let 0 = 0; //~ ERROR `let` expressions are not supported here
!let 0 = 0; //~ ERROR `let` expressions are not supported here
*let 0 = 0; //~ ERROR `let` expressions are not supported here
//~^ ERROR type `bool` cannot be dereferenced
-let 0 = 0; //~ ERROR `let` expressions are not supported here
//~^ ERROR cannot apply unary operator `-` to type `bool`
fn _check_try_binds_tighter() -> Result<(), ()> {
let 0 = 0?;
//~^ ERROR the `?` operator can only be applied to values that implement `std::ops::Try`
Ok(())
}
(let 0 = 0)?; //~ ERROR `let` expressions are not supported here
//~^ ERROR the `?` operator can only be used in a function that returns `Result`
//~| ERROR the `?` operator can only be applied to values that implement `std::ops::Try`
true || let 0 = 0; //~ ERROR `let` expressions are not supported here
(true || let 0 = 0); //~ ERROR `let` expressions are not supported here
true && (true || let 0 = 0); //~ ERROR `let` expressions are not supported here
let mut x = true;
x = let 0 = 0; //~ ERROR `let` expressions are not supported here
true..(let 0 = 0); //~ ERROR `let` expressions are not supported here
..(let 0 = 0); //~ ERROR `let` expressions are not supported here
(let 0 = 0)..; //~ ERROR `let` expressions are not supported here
(let Range { start: _, end: _ } = true..true || false);
//~^ ERROR `let` expressions are not supported here
//~| ERROR mismatched types
(let true = let true = true);
//~^ ERROR `let` expressions are not supported here
//~| ERROR `let` expressions are not supported here
// Check function tail position.
&let 0 = 0
//~^ ERROR `let` expressions are not supported here
//~| ERROR mismatched types
}
// Let's make sure that `let` inside const generic arguments are considered.
fn inside_const_generic_arguments() {
struct A<const B: bool>;
impl<const B: bool> A<{B}> { const O: u32 = 5; }
if let A::<{
true && let 1 = 1 //~ ERROR `let` expressions are not supported here
//~^ ERROR constant contains unimplemented expression type
//~| ERROR constant contains unimplemented expression type
}>::O = 5 {}
while let A::<{
true && let 1 = 1 //~ ERROR `let` expressions are not supported here
//~^ ERROR constant contains unimplemented expression type
//~| ERROR constant contains unimplemented expression type
}>::O = 5 {}
if A::<{
true && let 1 = 1 //~ ERROR `let` expressions are not supported here
//~^ ERROR constant contains unimplemented expression type
//~| ERROR constant contains unimplemented expression type
}>::O == 5 {}
// In the cases above we have `ExprKind::Block` to help us out.
// Below however, we would not have a block and so an implementation might go
// from visiting expressions to types without banning `let` expressions down the tree.
// This tests ensures that we are not caught by surprise should the parser
// admit non-IDENT expressions in const generic arguments.
if A::<
true && let 1 = 1 //~ ERROR expected one of `,` or `>`, found `&&`
>::O == 5 {}
}

View File

@ -0,0 +1,987 @@
error: expected one of `,` or `>`, found `&&`
--> $DIR/disallowed-positions.rs:242:14
|
LL | true && let 1 = 1
| ^^ expected one of `,` or `>` here
warning: the feature `const_generics` is incomplete and may cause the compiler to crash
--> $DIR/disallowed-positions.rs:20:12
|
LL | #![feature(const_generics)]
| ^^^^^^^^^^^^^^
warning: the feature `let_chains` is incomplete and may cause the compiler to crash
--> $DIR/disallowed-positions.rs:22:12
|
LL | #![feature(let_chains)] // Avoid inflating `.stderr` with overzealous gates in this test.
| ^^^^^^^^^^
error: `let` expressions are not supported here
--> $DIR/disallowed-positions.rs:32:9
|
LL | if &let 0 = 0 {}
| ^^^^^^^^^
|
= note: only supported directly in conditions of `if`- and `while`-expressions
= note: as well as when nested within `&&` and parenthesis in those conditions
error: `let` expressions are not supported here
--> $DIR/disallowed-positions.rs:35:9
|
LL | if !let 0 = 0 {}
| ^^^^^^^^^
|
= note: only supported directly in conditions of `if`- and `while`-expressions
= note: as well as when nested within `&&` and parenthesis in those conditions
error: `let` expressions are not supported here
--> $DIR/disallowed-positions.rs:36:9
|
LL | if *let 0 = 0 {}
| ^^^^^^^^^
|
= note: only supported directly in conditions of `if`- and `while`-expressions
= note: as well as when nested within `&&` and parenthesis in those conditions
error: `let` expressions are not supported here
--> $DIR/disallowed-positions.rs:38:9
|
LL | if -let 0 = 0 {}
| ^^^^^^^^^
|
= note: only supported directly in conditions of `if`- and `while`-expressions
= note: as well as when nested within `&&` and parenthesis in those conditions
error: `let` expressions are not supported here
--> $DIR/disallowed-positions.rs:46:9
|
LL | if (let 0 = 0)? {}
| ^^^^^^^^^
|
= note: only supported directly in conditions of `if`- and `while`-expressions
= note: as well as when nested within `&&` and parenthesis in those conditions
error: `let` expressions are not supported here
--> $DIR/disallowed-positions.rs:50:16
|
LL | if true || let 0 = 0 {}
| ^^^^^^^^^
|
= note: only supported directly in conditions of `if`- and `while`-expressions
= note: as well as when nested within `&&` and parenthesis in those conditions
error: `let` expressions are not supported here
--> $DIR/disallowed-positions.rs:51:17
|
LL | if (true || let 0 = 0) {}
| ^^^^^^^^^
|
= note: only supported directly in conditions of `if`- and `while`-expressions
= note: as well as when nested within `&&` and parenthesis in those conditions
error: `let` expressions are not supported here
--> $DIR/disallowed-positions.rs:52:25
|
LL | if true && (true || let 0 = 0) {}
| ^^^^^^^^^
|
= note: only supported directly in conditions of `if`- and `while`-expressions
= note: as well as when nested within `&&` and parenthesis in those conditions
error: `let` expressions are not supported here
--> $DIR/disallowed-positions.rs:53:25
|
LL | if true || (true && let 0 = 0) {}
| ^^^^^^^^^
|
= note: only supported directly in conditions of `if`- and `while`-expressions
= note: as well as when nested within `&&` and parenthesis in those conditions
error: `let` expressions are not supported here
--> $DIR/disallowed-positions.rs:56:12
|
LL | if x = let 0 = 0 {}
| ^^^^^^^^^
|
= note: only supported directly in conditions of `if`- and `while`-expressions
= note: as well as when nested within `&&` and parenthesis in those conditions
error: `let` expressions are not supported here
--> $DIR/disallowed-positions.rs:59:15
|
LL | if true..(let 0 = 0) {}
| ^^^^^^^^^
|
= note: only supported directly in conditions of `if`- and `while`-expressions
= note: as well as when nested within `&&` and parenthesis in those conditions
error: `let` expressions are not supported here
--> $DIR/disallowed-positions.rs:61:11
|
LL | if ..(let 0 = 0) {}
| ^^^^^^^^^
|
= note: only supported directly in conditions of `if`- and `while`-expressions
= note: as well as when nested within `&&` and parenthesis in those conditions
error: `let` expressions are not supported here
--> $DIR/disallowed-positions.rs:63:9
|
LL | if (let 0 = 0).. {}
| ^^^^^^^^^
|
= note: only supported directly in conditions of `if`- and `while`-expressions
= note: as well as when nested within `&&` and parenthesis in those conditions
error: `let` expressions are not supported here
--> $DIR/disallowed-positions.rs:67:8
|
LL | if let Range { start: _, end: _ } = true..true && false {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: only supported directly in conditions of `if`- and `while`-expressions
= note: as well as when nested within `&&` and parenthesis in those conditions
error: `let` expressions are not supported here
--> $DIR/disallowed-positions.rs:71:8
|
LL | if let Range { start: _, end: _ } = true..true || false {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: only supported directly in conditions of `if`- and `while`-expressions
= note: as well as when nested within `&&` and parenthesis in those conditions
error: `let` expressions are not supported here
--> $DIR/disallowed-positions.rs:78:8
|
LL | if let Range { start: F, end } = F..|| true {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: only supported directly in conditions of `if`- and `while`-expressions
= note: as well as when nested within `&&` and parenthesis in those conditions
error: `let` expressions are not supported here
--> $DIR/disallowed-positions.rs:86:8
|
LL | if let Range { start: true, end } = t..&&false {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: only supported directly in conditions of `if`- and `while`-expressions
= note: as well as when nested within `&&` and parenthesis in those conditions
error: `let` expressions are not supported here
--> $DIR/disallowed-positions.rs:92:19
|
LL | if let true = let true = true {}
| ^^^^^^^^^^^^^^^
|
= note: only supported directly in conditions of `if`- and `while`-expressions
= note: as well as when nested within `&&` and parenthesis in those conditions
error: `let` expressions are not supported here
--> $DIR/disallowed-positions.rs:96:12
|
LL | while &let 0 = 0 {}
| ^^^^^^^^^
|
= note: only supported directly in conditions of `if`- and `while`-expressions
= note: as well as when nested within `&&` and parenthesis in those conditions
error: `let` expressions are not supported here
--> $DIR/disallowed-positions.rs:99:12
|
LL | while !let 0 = 0 {}
| ^^^^^^^^^
|
= note: only supported directly in conditions of `if`- and `while`-expressions
= note: as well as when nested within `&&` and parenthesis in those conditions
error: `let` expressions are not supported here
--> $DIR/disallowed-positions.rs:100:12
|
LL | while *let 0 = 0 {}
| ^^^^^^^^^
|
= note: only supported directly in conditions of `if`- and `while`-expressions
= note: as well as when nested within `&&` and parenthesis in those conditions
error: `let` expressions are not supported here
--> $DIR/disallowed-positions.rs:102:12
|
LL | while -let 0 = 0 {}
| ^^^^^^^^^
|
= note: only supported directly in conditions of `if`- and `while`-expressions
= note: as well as when nested within `&&` and parenthesis in those conditions
error: `let` expressions are not supported here
--> $DIR/disallowed-positions.rs:110:12
|
LL | while (let 0 = 0)? {}
| ^^^^^^^^^
|
= note: only supported directly in conditions of `if`- and `while`-expressions
= note: as well as when nested within `&&` and parenthesis in those conditions
error: `let` expressions are not supported here
--> $DIR/disallowed-positions.rs:114:19
|
LL | while true || let 0 = 0 {}
| ^^^^^^^^^
|
= note: only supported directly in conditions of `if`- and `while`-expressions
= note: as well as when nested within `&&` and parenthesis in those conditions
error: `let` expressions are not supported here
--> $DIR/disallowed-positions.rs:115:20
|
LL | while (true || let 0 = 0) {}
| ^^^^^^^^^
|
= note: only supported directly in conditions of `if`- and `while`-expressions
= note: as well as when nested within `&&` and parenthesis in those conditions
error: `let` expressions are not supported here
--> $DIR/disallowed-positions.rs:116:28
|
LL | while true && (true || let 0 = 0) {}
| ^^^^^^^^^
|
= note: only supported directly in conditions of `if`- and `while`-expressions
= note: as well as when nested within `&&` and parenthesis in those conditions
error: `let` expressions are not supported here
--> $DIR/disallowed-positions.rs:117:28
|
LL | while true || (true && let 0 = 0) {}
| ^^^^^^^^^
|
= note: only supported directly in conditions of `if`- and `while`-expressions
= note: as well as when nested within `&&` and parenthesis in those conditions
error: `let` expressions are not supported here
--> $DIR/disallowed-positions.rs:120:15
|
LL | while x = let 0 = 0 {}
| ^^^^^^^^^
|
= note: only supported directly in conditions of `if`- and `while`-expressions
= note: as well as when nested within `&&` and parenthesis in those conditions
error: `let` expressions are not supported here
--> $DIR/disallowed-positions.rs:123:18
|
LL | while true..(let 0 = 0) {}
| ^^^^^^^^^
|
= note: only supported directly in conditions of `if`- and `while`-expressions
= note: as well as when nested within `&&` and parenthesis in those conditions
error: `let` expressions are not supported here
--> $DIR/disallowed-positions.rs:125:14
|
LL | while ..(let 0 = 0) {}
| ^^^^^^^^^
|
= note: only supported directly in conditions of `if`- and `while`-expressions
= note: as well as when nested within `&&` and parenthesis in those conditions
error: `let` expressions are not supported here
--> $DIR/disallowed-positions.rs:127:12
|
LL | while (let 0 = 0).. {}
| ^^^^^^^^^
|
= note: only supported directly in conditions of `if`- and `while`-expressions
= note: as well as when nested within `&&` and parenthesis in those conditions
error: `let` expressions are not supported here
--> $DIR/disallowed-positions.rs:131:11
|
LL | while let Range { start: _, end: _ } = true..true && false {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: only supported directly in conditions of `if`- and `while`-expressions
= note: as well as when nested within `&&` and parenthesis in those conditions
error: `let` expressions are not supported here
--> $DIR/disallowed-positions.rs:135:11
|
LL | while let Range { start: _, end: _ } = true..true || false {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: only supported directly in conditions of `if`- and `while`-expressions
= note: as well as when nested within `&&` and parenthesis in those conditions
error: `let` expressions are not supported here
--> $DIR/disallowed-positions.rs:142:11
|
LL | while let Range { start: F, end } = F..|| true {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: only supported directly in conditions of `if`- and `while`-expressions
= note: as well as when nested within `&&` and parenthesis in those conditions
error: `let` expressions are not supported here
--> $DIR/disallowed-positions.rs:150:11
|
LL | while let Range { start: true, end } = t..&&false {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: only supported directly in conditions of `if`- and `while`-expressions
= note: as well as when nested within `&&` and parenthesis in those conditions
error: `let` expressions are not supported here
--> $DIR/disallowed-positions.rs:156:22
|
LL | while let true = let true = true {}
| ^^^^^^^^^^^^^^^
|
= note: only supported directly in conditions of `if`- and `while`-expressions
= note: as well as when nested within `&&` and parenthesis in those conditions
error: `let` expressions are not supported here
--> $DIR/disallowed-positions.rs:170:6
|
LL | &let 0 = 0;
| ^^^^^^^^^
|
= note: only supported directly in conditions of `if`- and `while`-expressions
= note: as well as when nested within `&&` and parenthesis in those conditions
error: `let` expressions are not supported here
--> $DIR/disallowed-positions.rs:172:6
|
LL | !let 0 = 0;
| ^^^^^^^^^
|
= note: only supported directly in conditions of `if`- and `while`-expressions
= note: as well as when nested within `&&` and parenthesis in those conditions
error: `let` expressions are not supported here
--> $DIR/disallowed-positions.rs:173:6
|
LL | *let 0 = 0;
| ^^^^^^^^^
|
= note: only supported directly in conditions of `if`- and `while`-expressions
= note: as well as when nested within `&&` and parenthesis in those conditions
error: `let` expressions are not supported here
--> $DIR/disallowed-positions.rs:175:6
|
LL | -let 0 = 0;
| ^^^^^^^^^
|
= note: only supported directly in conditions of `if`- and `while`-expressions
= note: as well as when nested within `&&` and parenthesis in those conditions
error: `let` expressions are not supported here
--> $DIR/disallowed-positions.rs:183:6
|
LL | (let 0 = 0)?;
| ^^^^^^^^^
|
= note: only supported directly in conditions of `if`- and `while`-expressions
= note: as well as when nested within `&&` and parenthesis in those conditions
error: `let` expressions are not supported here
--> $DIR/disallowed-positions.rs:187:13
|
LL | true || let 0 = 0;
| ^^^^^^^^^
|
= note: only supported directly in conditions of `if`- and `while`-expressions
= note: as well as when nested within `&&` and parenthesis in those conditions
error: `let` expressions are not supported here
--> $DIR/disallowed-positions.rs:188:14
|
LL | (true || let 0 = 0);
| ^^^^^^^^^
|
= note: only supported directly in conditions of `if`- and `while`-expressions
= note: as well as when nested within `&&` and parenthesis in those conditions
error: `let` expressions are not supported here
--> $DIR/disallowed-positions.rs:189:22
|
LL | true && (true || let 0 = 0);
| ^^^^^^^^^
|
= note: only supported directly in conditions of `if`- and `while`-expressions
= note: as well as when nested within `&&` and parenthesis in those conditions
error: `let` expressions are not supported here
--> $DIR/disallowed-positions.rs:192:9
|
LL | x = let 0 = 0;
| ^^^^^^^^^
|
= note: only supported directly in conditions of `if`- and `while`-expressions
= note: as well as when nested within `&&` and parenthesis in those conditions
error: `let` expressions are not supported here
--> $DIR/disallowed-positions.rs:194:12
|
LL | true..(let 0 = 0);
| ^^^^^^^^^
|
= note: only supported directly in conditions of `if`- and `while`-expressions
= note: as well as when nested within `&&` and parenthesis in those conditions
error: `let` expressions are not supported here
--> $DIR/disallowed-positions.rs:195:8
|
LL | ..(let 0 = 0);
| ^^^^^^^^^
|
= note: only supported directly in conditions of `if`- and `while`-expressions
= note: as well as when nested within `&&` and parenthesis in those conditions
error: `let` expressions are not supported here
--> $DIR/disallowed-positions.rs:196:6
|
LL | (let 0 = 0)..;
| ^^^^^^^^^
|
= note: only supported directly in conditions of `if`- and `while`-expressions
= note: as well as when nested within `&&` and parenthesis in those conditions
error: `let` expressions are not supported here
--> $DIR/disallowed-positions.rs:198:6
|
LL | (let Range { start: _, end: _ } = true..true || false);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: only supported directly in conditions of `if`- and `while`-expressions
= note: as well as when nested within `&&` and parenthesis in those conditions
error: `let` expressions are not supported here
--> $DIR/disallowed-positions.rs:202:6
|
LL | (let true = let true = true);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: only supported directly in conditions of `if`- and `while`-expressions
= note: as well as when nested within `&&` and parenthesis in those conditions
error: `let` expressions are not supported here
--> $DIR/disallowed-positions.rs:202:17
|
LL | (let true = let true = true);
| ^^^^^^^^^^^^^^^
|
= note: only supported directly in conditions of `if`- and `while`-expressions
= note: as well as when nested within `&&` and parenthesis in those conditions
error: `let` expressions are not supported here
--> $DIR/disallowed-positions.rs:207:6
|
LL | &let 0 = 0
| ^^^^^^^^^
|
= note: only supported directly in conditions of `if`- and `while`-expressions
= note: as well as when nested within `&&` and parenthesis in those conditions
error: `let` expressions are not supported here
--> $DIR/disallowed-positions.rs:218:17
|
LL | true && let 1 = 1
| ^^^^^^^^^
|
= note: only supported directly in conditions of `if`- and `while`-expressions
= note: as well as when nested within `&&` and parenthesis in those conditions
error: `let` expressions are not supported here
--> $DIR/disallowed-positions.rs:224:17
|
LL | true && let 1 = 1
| ^^^^^^^^^
|
= note: only supported directly in conditions of `if`- and `while`-expressions
= note: as well as when nested within `&&` and parenthesis in those conditions
error: `let` expressions are not supported here
--> $DIR/disallowed-positions.rs:230:17
|
LL | true && let 1 = 1
| ^^^^^^^^^
|
= note: only supported directly in conditions of `if`- and `while`-expressions
= note: as well as when nested within `&&` and parenthesis in those conditions
error[E0308]: mismatched types
--> $DIR/disallowed-positions.rs:32:8
|
LL | if &let 0 = 0 {}
| ^^^^^^^^^^ expected bool, found &bool
|
= note: expected type `bool`
found type `&bool`
error[E0614]: type `bool` cannot be dereferenced
--> $DIR/disallowed-positions.rs:36:8
|
LL | if *let 0 = 0 {}
| ^^^^^^^^^^
error[E0600]: cannot apply unary operator `-` to type `bool`
--> $DIR/disallowed-positions.rs:38:8
|
LL | if -let 0 = 0 {}
| ^^^^^^^^^^ cannot apply unary operator `-`
|
= note: an implementation of `std::ops::Neg` might be missing for `bool`
error[E0277]: the `?` operator can only be applied to values that implement `std::ops::Try`
--> $DIR/disallowed-positions.rs:46:8
|
LL | if (let 0 = 0)? {}
| ^^^^^^^^^^^^ the `?` operator cannot be applied to type `bool`
|
= help: the trait `std::ops::Try` is not implemented for `bool`
= note: required by `std::ops::Try::into_result`
error[E0277]: the `?` operator can only be used in a function that returns `Result` or `Option` (or another type that implements `std::ops::Try`)
--> $DIR/disallowed-positions.rs:46:8
|
LL | if (let 0 = 0)? {}
| ^^^^^^^^^^^^ cannot use the `?` operator in a function that returns `()`
|
= help: the trait `std::ops::Try` is not implemented for `()`
= note: required by `std::ops::Try::from_error`
error[E0308]: mismatched types
--> $DIR/disallowed-positions.rs:56:8
|
LL | if x = let 0 = 0 {}
| ^^^^^^^^^^^^^
| |
| expected bool, found ()
| help: try comparing for equality: `x == let 0 = 0`
|
= note: expected type `bool`
found type `()`
error[E0308]: mismatched types
--> $DIR/disallowed-positions.rs:59:8
|
LL | if true..(let 0 = 0) {}
| ^^^^^^^^^^^^^^^^^ expected bool, found struct `std::ops::Range`
|
= note: expected type `bool`
found type `std::ops::Range<bool>`
error[E0308]: mismatched types
--> $DIR/disallowed-positions.rs:61:8
|
LL | if ..(let 0 = 0) {}
| ^^^^^^^^^^^^^ expected bool, found struct `std::ops::RangeTo`
|
= note: expected type `bool`
found type `std::ops::RangeTo<bool>`
error[E0308]: mismatched types
--> $DIR/disallowed-positions.rs:63:8
|
LL | if (let 0 = 0).. {}
| ^^^^^^^^^^^^^ expected bool, found struct `std::ops::RangeFrom`
|
= note: expected type `bool`
found type `std::ops::RangeFrom<bool>`
error[E0308]: mismatched types
--> $DIR/disallowed-positions.rs:67:12
|
LL | if let Range { start: _, end: _ } = true..true && false {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ ---- this match expression has type `bool`
| |
| expected bool, found struct `std::ops::Range`
|
= note: expected type `bool`
found type `std::ops::Range<_>`
error[E0308]: mismatched types
--> $DIR/disallowed-positions.rs:67:8
|
LL | if let Range { start: _, end: _ } = true..true && false {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected bool, found struct `std::ops::Range`
|
= note: expected type `bool`
found type `std::ops::Range<bool>`
error[E0308]: mismatched types
--> $DIR/disallowed-positions.rs:71:12
|
LL | if let Range { start: _, end: _ } = true..true || false {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ ---- this match expression has type `bool`
| |
| expected bool, found struct `std::ops::Range`
|
= note: expected type `bool`
found type `std::ops::Range<_>`
error[E0308]: mismatched types
--> $DIR/disallowed-positions.rs:71:8
|
LL | if let Range { start: _, end: _ } = true..true || false {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected bool, found struct `std::ops::Range`
|
= note: expected type `bool`
found type `std::ops::Range<bool>`
error[E0308]: mismatched types
--> $DIR/disallowed-positions.rs:78:12
|
LL | if let Range { start: F, end } = F..|| true {}
| ^^^^^^^^^^^^^^^^^^^^^^^ expected fn pointer, found struct `std::ops::Range`
|
= note: expected type `fn() -> bool`
found type `std::ops::Range<_>`
error[E0308]: mismatched types
--> $DIR/disallowed-positions.rs:78:41
|
LL | if let Range { start: F, end } = F..|| true {}
| ^^^^^^^ expected bool, found closure
|
= note: expected type `bool`
found type `[closure@$DIR/disallowed-positions.rs:78:41: 78:48]`
error[E0308]: mismatched types
--> $DIR/disallowed-positions.rs:78:8
|
LL | if let Range { start: F, end } = F..|| true {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected bool, found struct `std::ops::Range`
|
= note: expected type `bool`
found type `std::ops::Range<bool>`
error[E0308]: mismatched types
--> $DIR/disallowed-positions.rs:86:12
|
LL | if let Range { start: true, end } = t..&&false {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ - this match expression has type `bool`
| |
| expected bool, found struct `std::ops::Range`
|
= note: expected type `bool`
found type `std::ops::Range<_>`
error[E0308]: mismatched types
--> $DIR/disallowed-positions.rs:86:44
|
LL | if let Range { start: true, end } = t..&&false {}
| ^^^^^^^ expected bool, found &&bool
|
= note: expected type `bool`
found type `&&bool`
error[E0308]: mismatched types
--> $DIR/disallowed-positions.rs:86:8
|
LL | if let Range { start: true, end } = t..&&false {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected bool, found struct `std::ops::Range`
|
= note: expected type `bool`
found type `std::ops::Range<bool>`
error[E0277]: the `?` operator can only be applied to values that implement `std::ops::Try`
--> $DIR/disallowed-positions.rs:42:20
|
LL | if let 0 = 0? {}
| ^^ the `?` operator cannot be applied to type `{integer}`
|
= help: the trait `std::ops::Try` is not implemented for `{integer}`
= note: required by `std::ops::Try::into_result`
error[E0308]: mismatched types
--> $DIR/disallowed-positions.rs:96:11
|
LL | while &let 0 = 0 {}
| ^^^^^^^^^^ expected bool, found &bool
|
= note: expected type `bool`
found type `&bool`
error[E0614]: type `bool` cannot be dereferenced
--> $DIR/disallowed-positions.rs:100:11
|
LL | while *let 0 = 0 {}
| ^^^^^^^^^^
error[E0600]: cannot apply unary operator `-` to type `bool`
--> $DIR/disallowed-positions.rs:102:11
|
LL | while -let 0 = 0 {}
| ^^^^^^^^^^ cannot apply unary operator `-`
|
= note: an implementation of `std::ops::Neg` might be missing for `bool`
error[E0277]: the `?` operator can only be applied to values that implement `std::ops::Try`
--> $DIR/disallowed-positions.rs:110:11
|
LL | while (let 0 = 0)? {}
| ^^^^^^^^^^^^ the `?` operator cannot be applied to type `bool`
|
= help: the trait `std::ops::Try` is not implemented for `bool`
= note: required by `std::ops::Try::into_result`
error[E0277]: the `?` operator can only be used in a function that returns `Result` or `Option` (or another type that implements `std::ops::Try`)
--> $DIR/disallowed-positions.rs:110:11
|
LL | while (let 0 = 0)? {}
| ^^^^^^^^^^^^ cannot use the `?` operator in a function that returns `()`
|
= help: the trait `std::ops::Try` is not implemented for `()`
= note: required by `std::ops::Try::from_error`
error[E0308]: mismatched types
--> $DIR/disallowed-positions.rs:120:11
|
LL | while x = let 0 = 0 {}
| ^^^^^^^^^^^^^
| |
| expected bool, found ()
| help: try comparing for equality: `x == let 0 = 0`
|
= note: expected type `bool`
found type `()`
error[E0308]: mismatched types
--> $DIR/disallowed-positions.rs:123:11
|
LL | while true..(let 0 = 0) {}
| ^^^^^^^^^^^^^^^^^ expected bool, found struct `std::ops::Range`
|
= note: expected type `bool`
found type `std::ops::Range<bool>`
error[E0308]: mismatched types
--> $DIR/disallowed-positions.rs:125:11
|
LL | while ..(let 0 = 0) {}
| ^^^^^^^^^^^^^ expected bool, found struct `std::ops::RangeTo`
|
= note: expected type `bool`
found type `std::ops::RangeTo<bool>`
error[E0308]: mismatched types
--> $DIR/disallowed-positions.rs:127:11
|
LL | while (let 0 = 0).. {}
| ^^^^^^^^^^^^^ expected bool, found struct `std::ops::RangeFrom`
|
= note: expected type `bool`
found type `std::ops::RangeFrom<bool>`
error[E0308]: mismatched types
--> $DIR/disallowed-positions.rs:131:15
|
LL | while let Range { start: _, end: _ } = true..true && false {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ ---- this match expression has type `bool`
| |
| expected bool, found struct `std::ops::Range`
|
= note: expected type `bool`
found type `std::ops::Range<_>`
error[E0308]: mismatched types
--> $DIR/disallowed-positions.rs:131:11
|
LL | while let Range { start: _, end: _ } = true..true && false {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected bool, found struct `std::ops::Range`
|
= note: expected type `bool`
found type `std::ops::Range<bool>`
error[E0308]: mismatched types
--> $DIR/disallowed-positions.rs:135:15
|
LL | while let Range { start: _, end: _ } = true..true || false {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ ---- this match expression has type `bool`
| |
| expected bool, found struct `std::ops::Range`
|
= note: expected type `bool`
found type `std::ops::Range<_>`
error[E0308]: mismatched types
--> $DIR/disallowed-positions.rs:135:11
|
LL | while let Range { start: _, end: _ } = true..true || false {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected bool, found struct `std::ops::Range`
|
= note: expected type `bool`
found type `std::ops::Range<bool>`
error[E0308]: mismatched types
--> $DIR/disallowed-positions.rs:142:15
|
LL | while let Range { start: F, end } = F..|| true {}
| ^^^^^^^^^^^^^^^^^^^^^^^ expected fn pointer, found struct `std::ops::Range`
|
= note: expected type `fn() -> bool`
found type `std::ops::Range<_>`
error[E0308]: mismatched types
--> $DIR/disallowed-positions.rs:142:44
|
LL | while let Range { start: F, end } = F..|| true {}
| ^^^^^^^ expected bool, found closure
|
= note: expected type `bool`
found type `[closure@$DIR/disallowed-positions.rs:142:44: 142:51]`
error[E0308]: mismatched types
--> $DIR/disallowed-positions.rs:142:11
|
LL | while let Range { start: F, end } = F..|| true {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected bool, found struct `std::ops::Range`
|
= note: expected type `bool`
found type `std::ops::Range<bool>`
error[E0308]: mismatched types
--> $DIR/disallowed-positions.rs:150:15
|
LL | while let Range { start: true, end } = t..&&false {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ - this match expression has type `bool`
| |
| expected bool, found struct `std::ops::Range`
|
= note: expected type `bool`
found type `std::ops::Range<_>`
error[E0308]: mismatched types
--> $DIR/disallowed-positions.rs:150:47
|
LL | while let Range { start: true, end } = t..&&false {}
| ^^^^^^^ expected bool, found &&bool
|
= note: expected type `bool`
found type `&&bool`
error[E0308]: mismatched types
--> $DIR/disallowed-positions.rs:150:11
|
LL | while let Range { start: true, end } = t..&&false {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected bool, found struct `std::ops::Range`
|
= note: expected type `bool`
found type `std::ops::Range<bool>`
error[E0277]: the `?` operator can only be applied to values that implement `std::ops::Try`
--> $DIR/disallowed-positions.rs:106:23
|
LL | while let 0 = 0? {}
| ^^ the `?` operator cannot be applied to type `{integer}`
|
= help: the trait `std::ops::Try` is not implemented for `{integer}`
= note: required by `std::ops::Try::into_result`
error[E0614]: type `bool` cannot be dereferenced
--> $DIR/disallowed-positions.rs:173:5
|
LL | *let 0 = 0;
| ^^^^^^^^^^
error[E0600]: cannot apply unary operator `-` to type `bool`
--> $DIR/disallowed-positions.rs:175:5
|
LL | -let 0 = 0;
| ^^^^^^^^^^ cannot apply unary operator `-`
|
= note: an implementation of `std::ops::Neg` might be missing for `bool`
error[E0277]: the `?` operator can only be applied to values that implement `std::ops::Try`
--> $DIR/disallowed-positions.rs:183:5
|
LL | (let 0 = 0)?;
| ^^^^^^^^^^^^ the `?` operator cannot be applied to type `bool`
|
= help: the trait `std::ops::Try` is not implemented for `bool`
= note: required by `std::ops::Try::into_result`
error[E0277]: the `?` operator can only be used in a function that returns `Result` or `Option` (or another type that implements `std::ops::Try`)
--> $DIR/disallowed-positions.rs:183:5
|
LL | (let 0 = 0)?;
| ^^^^^^^^^^^^ cannot use the `?` operator in a function that returns `()`
|
= help: the trait `std::ops::Try` is not implemented for `()`
= note: required by `std::ops::Try::from_error`
error[E0308]: mismatched types
--> $DIR/disallowed-positions.rs:198:10
|
LL | (let Range { start: _, end: _ } = true..true || false);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ ---- this match expression has type `bool`
| |
| expected bool, found struct `std::ops::Range`
|
= note: expected type `bool`
found type `std::ops::Range<_>`
error[E0308]: mismatched types
--> $DIR/disallowed-positions.rs:207:5
|
LL | fn outside_if_and_while_expr() {
| - help: try adding a return type: `-> &bool`
...
LL | &let 0 = 0
| ^^^^^^^^^^ expected (), found &bool
|
= note: expected type `()`
found type `&bool`
error[E0277]: the `?` operator can only be applied to values that implement `std::ops::Try`
--> $DIR/disallowed-positions.rs:179:17
|
LL | let 0 = 0?;
| ^^ the `?` operator cannot be applied to type `{integer}`
|
= help: the trait `std::ops::Try` is not implemented for `{integer}`
= note: required by `std::ops::Try::into_result`
error[E0019]: constant contains unimplemented expression type
--> $DIR/disallowed-positions.rs:218:25
|
LL | true && let 1 = 1
| ^
error[E0019]: constant contains unimplemented expression type
--> $DIR/disallowed-positions.rs:218:21
|
LL | true && let 1 = 1
| ^
error[E0019]: constant contains unimplemented expression type
--> $DIR/disallowed-positions.rs:224:25
|
LL | true && let 1 = 1
| ^
error[E0019]: constant contains unimplemented expression type
--> $DIR/disallowed-positions.rs:224:21
|
LL | true && let 1 = 1
| ^
error[E0019]: constant contains unimplemented expression type
--> $DIR/disallowed-positions.rs:230:25
|
LL | true && let 1 = 1
| ^
error[E0019]: constant contains unimplemented expression type
--> $DIR/disallowed-positions.rs:230:21
|
LL | true && let 1 = 1
| ^
error: aborting due to 109 previous errors
Some errors have detailed explanations: E0019, E0277, E0308, E0600, E0614.
For more information about an error, try `rustc --explain E0019`.

View File

@ -0,0 +1,136 @@
// gate-test-let_chains
// Here we test feature gating for ´let_chains`.
// See `disallowed-positions.rs` for the grammar
// defining the language for gated allowed positions.
#![allow(irrefutable_let_patterns)]
use std::ops::Range;
fn _if() {
if let 0 = 1 {} // Stable!
if (let 0 = 1) {}
//~^ ERROR `let` expressions in this position are experimental [E0658]
//~| ERROR `let` expressions are not supported here
if (((let 0 = 1))) {}
//~^ ERROR `let` expressions in this position are experimental [E0658]
//~| ERROR `let` expressions are not supported here
if true && let 0 = 1 {}
//~^ ERROR `let` expressions in this position are experimental [E0658]
//~| ERROR `let` expressions are not supported here
if let 0 = 1 && true {}
//~^ ERROR `let` expressions in this position are experimental [E0658]
//~| ERROR `let` expressions are not supported here
if (let 0 = 1) && true {}
//~^ ERROR `let` expressions in this position are experimental [E0658]
//~| ERROR `let` expressions are not supported here
if true && (let 0 = 1) {}
//~^ ERROR `let` expressions in this position are experimental [E0658]
//~| ERROR `let` expressions are not supported here
if (let 0 = 1) && (let 0 = 1) {}
//~^ ERROR `let` expressions in this position are experimental [E0658]
//~| ERROR `let` expressions in this position are experimental [E0658]
//~| ERROR `let` expressions are not supported here
//~| ERROR `let` expressions are not supported here
if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {}
//~^ ERROR `let` expressions in this position are experimental [E0658]
//~| ERROR `let` expressions in this position are experimental [E0658]
//~| ERROR `let` expressions in this position are experimental [E0658]
//~| ERROR `let` expressions in this position are experimental [E0658]
//~| ERROR `let` expressions in this position are experimental [E0658]
//~| ERROR `let` expressions are not supported here
//~| ERROR `let` expressions are not supported here
//~| ERROR `let` expressions are not supported here
//~| ERROR `let` expressions are not supported here
//~| ERROR `let` expressions are not supported here
if let Range { start: _, end: _ } = (true..true) && false {}
//~^ ERROR `let` expressions in this position are experimental [E0658]
//~| ERROR `let` expressions are not supported here
}
fn _while() {
while let 0 = 1 {} // Stable!
while (let 0 = 1) {}
//~^ ERROR `let` expressions in this position are experimental [E0658]
//~| ERROR `let` expressions are not supported here
while (((let 0 = 1))) {}
//~^ ERROR `let` expressions in this position are experimental [E0658]
//~| ERROR `let` expressions are not supported here
while true && let 0 = 1 {}
//~^ ERROR `let` expressions in this position are experimental [E0658]
//~| ERROR `let` expressions are not supported here
while let 0 = 1 && true {}
//~^ ERROR `let` expressions in this position are experimental [E0658]
//~| ERROR `let` expressions are not supported here
while (let 0 = 1) && true {}
//~^ ERROR `let` expressions in this position are experimental [E0658]
//~| ERROR `let` expressions are not supported here
while true && (let 0 = 1) {}
//~^ ERROR `let` expressions in this position are experimental [E0658]
//~| ERROR `let` expressions are not supported here
while (let 0 = 1) && (let 0 = 1) {}
//~^ ERROR `let` expressions in this position are experimental [E0658]
//~| ERROR `let` expressions in this position are experimental [E0658]
//~| ERROR `let` expressions are not supported here
//~| ERROR `let` expressions are not supported here
while let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {}
//~^ ERROR `let` expressions in this position are experimental [E0658]
//~| ERROR `let` expressions in this position are experimental [E0658]
//~| ERROR `let` expressions in this position are experimental [E0658]
//~| ERROR `let` expressions in this position are experimental [E0658]
//~| ERROR `let` expressions in this position are experimental [E0658]
//~| ERROR `let` expressions are not supported here
//~| ERROR `let` expressions are not supported here
//~| ERROR `let` expressions are not supported here
//~| ERROR `let` expressions are not supported here
//~| ERROR `let` expressions are not supported here
while let Range { start: _, end: _ } = (true..true) && false {}
//~^ ERROR `let` expressions in this position are experimental [E0658]
//~| ERROR `let` expressions are not supported here
}
fn _macros() {
macro_rules! noop_expr { ($e:expr) => {}; }
noop_expr!((let 0 = 1));
//~^ ERROR `let` expressions in this position are experimental [E0658]
macro_rules! use_expr {
($e:expr) => {
if $e {}
while $e {}
}
}
use_expr!((let 0 = 1 && 0 == 0));
//~^ ERROR `let` expressions in this position are experimental [E0658]
//~| ERROR `let` expressions are not supported here
use_expr!((let 0 = 1));
//~^ ERROR `let` expressions in this position are experimental [E0658]
//~| ERROR `let` expressions are not supported here
#[cfg(FALSE)] (let 0 = 1);
//~^ ERROR `let` expressions in this position are experimental [E0658]
use_expr!(let 0 = 1);
//~^ ERROR no rules expected the token `let`
// ^--- FIXME(53667): Consider whether `Let` can be added to `ident_can_begin_expr`.
}
fn main() {}

View File

@ -0,0 +1,570 @@
error: no rules expected the token `let`
--> $DIR/feature-gate.rs:131:15
|
LL | macro_rules! use_expr {
| --------------------- when calling this macro
...
LL | use_expr!(let 0 = 1);
| ^^^ no rules expected this token in macro call
error[E0658]: `let` expressions in this position are experimental
--> $DIR/feature-gate.rs:14:9
|
LL | if (let 0 = 1) {}
| ^^^^^^^^^
|
= note: for more information, see https://github.com/rust-lang/rust/issues/53667
= help: add #![feature(let_chains)] to the crate attributes to enable
error[E0658]: `let` expressions in this position are experimental
--> $DIR/feature-gate.rs:18:11
|
LL | if (((let 0 = 1))) {}
| ^^^^^^^^^
|
= note: for more information, see https://github.com/rust-lang/rust/issues/53667
= help: add #![feature(let_chains)] to the crate attributes to enable
error[E0658]: `let` expressions in this position are experimental
--> $DIR/feature-gate.rs:22:16
|
LL | if true && let 0 = 1 {}
| ^^^^^^^^^
|
= note: for more information, see https://github.com/rust-lang/rust/issues/53667
= help: add #![feature(let_chains)] to the crate attributes to enable
error[E0658]: `let` expressions in this position are experimental
--> $DIR/feature-gate.rs:26:8
|
LL | if let 0 = 1 && true {}
| ^^^^^^^^^
|
= note: for more information, see https://github.com/rust-lang/rust/issues/53667
= help: add #![feature(let_chains)] to the crate attributes to enable
error[E0658]: `let` expressions in this position are experimental
--> $DIR/feature-gate.rs:30:9
|
LL | if (let 0 = 1) && true {}
| ^^^^^^^^^
|
= note: for more information, see https://github.com/rust-lang/rust/issues/53667
= help: add #![feature(let_chains)] to the crate attributes to enable
error[E0658]: `let` expressions in this position are experimental
--> $DIR/feature-gate.rs:34:17
|
LL | if true && (let 0 = 1) {}
| ^^^^^^^^^
|
= note: for more information, see https://github.com/rust-lang/rust/issues/53667
= help: add #![feature(let_chains)] to the crate attributes to enable
error[E0658]: `let` expressions in this position are experimental
--> $DIR/feature-gate.rs:38:9
|
LL | if (let 0 = 1) && (let 0 = 1) {}
| ^^^^^^^^^
|
= note: for more information, see https://github.com/rust-lang/rust/issues/53667
= help: add #![feature(let_chains)] to the crate attributes to enable
error[E0658]: `let` expressions in this position are experimental
--> $DIR/feature-gate.rs:38:24
|
LL | if (let 0 = 1) && (let 0 = 1) {}
| ^^^^^^^^^
|
= note: for more information, see https://github.com/rust-lang/rust/issues/53667
= help: add #![feature(let_chains)] to the crate attributes to enable
error[E0658]: `let` expressions in this position are experimental
--> $DIR/feature-gate.rs:44:8
|
LL | if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {}
| ^^^^^^^^^
|
= note: for more information, see https://github.com/rust-lang/rust/issues/53667
= help: add #![feature(let_chains)] to the crate attributes to enable
error[E0658]: `let` expressions in this position are experimental
--> $DIR/feature-gate.rs:44:21
|
LL | if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {}
| ^^^^^^^^^
|
= note: for more information, see https://github.com/rust-lang/rust/issues/53667
= help: add #![feature(let_chains)] to the crate attributes to enable
error[E0658]: `let` expressions in this position are experimental
--> $DIR/feature-gate.rs:44:35
|
LL | if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {}
| ^^^^^^^^^
|
= note: for more information, see https://github.com/rust-lang/rust/issues/53667
= help: add #![feature(let_chains)] to the crate attributes to enable
error[E0658]: `let` expressions in this position are experimental
--> $DIR/feature-gate.rs:44:48
|
LL | if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {}
| ^^^^^^^^^
|
= note: for more information, see https://github.com/rust-lang/rust/issues/53667
= help: add #![feature(let_chains)] to the crate attributes to enable
error[E0658]: `let` expressions in this position are experimental
--> $DIR/feature-gate.rs:44:61
|
LL | if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {}
| ^^^^^^^^^
|
= note: for more information, see https://github.com/rust-lang/rust/issues/53667
= help: add #![feature(let_chains)] to the crate attributes to enable
error[E0658]: `let` expressions in this position are experimental
--> $DIR/feature-gate.rs:56:8
|
LL | if let Range { start: _, end: _ } = (true..true) && false {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: for more information, see https://github.com/rust-lang/rust/issues/53667
= help: add #![feature(let_chains)] to the crate attributes to enable
error[E0658]: `let` expressions in this position are experimental
--> $DIR/feature-gate.rs:64:12
|
LL | while (let 0 = 1) {}
| ^^^^^^^^^
|
= note: for more information, see https://github.com/rust-lang/rust/issues/53667
= help: add #![feature(let_chains)] to the crate attributes to enable
error[E0658]: `let` expressions in this position are experimental
--> $DIR/feature-gate.rs:68:14
|
LL | while (((let 0 = 1))) {}
| ^^^^^^^^^
|
= note: for more information, see https://github.com/rust-lang/rust/issues/53667
= help: add #![feature(let_chains)] to the crate attributes to enable
error[E0658]: `let` expressions in this position are experimental
--> $DIR/feature-gate.rs:72:19
|
LL | while true && let 0 = 1 {}
| ^^^^^^^^^
|
= note: for more information, see https://github.com/rust-lang/rust/issues/53667
= help: add #![feature(let_chains)] to the crate attributes to enable
error[E0658]: `let` expressions in this position are experimental
--> $DIR/feature-gate.rs:76:11
|
LL | while let 0 = 1 && true {}
| ^^^^^^^^^
|
= note: for more information, see https://github.com/rust-lang/rust/issues/53667
= help: add #![feature(let_chains)] to the crate attributes to enable
error[E0658]: `let` expressions in this position are experimental
--> $DIR/feature-gate.rs:80:12
|
LL | while (let 0 = 1) && true {}
| ^^^^^^^^^
|
= note: for more information, see https://github.com/rust-lang/rust/issues/53667
= help: add #![feature(let_chains)] to the crate attributes to enable
error[E0658]: `let` expressions in this position are experimental
--> $DIR/feature-gate.rs:84:20
|
LL | while true && (let 0 = 1) {}
| ^^^^^^^^^
|
= note: for more information, see https://github.com/rust-lang/rust/issues/53667
= help: add #![feature(let_chains)] to the crate attributes to enable
error[E0658]: `let` expressions in this position are experimental
--> $DIR/feature-gate.rs:88:12
|
LL | while (let 0 = 1) && (let 0 = 1) {}
| ^^^^^^^^^
|
= note: for more information, see https://github.com/rust-lang/rust/issues/53667
= help: add #![feature(let_chains)] to the crate attributes to enable
error[E0658]: `let` expressions in this position are experimental
--> $DIR/feature-gate.rs:88:27
|
LL | while (let 0 = 1) && (let 0 = 1) {}
| ^^^^^^^^^
|
= note: for more information, see https://github.com/rust-lang/rust/issues/53667
= help: add #![feature(let_chains)] to the crate attributes to enable
error[E0658]: `let` expressions in this position are experimental
--> $DIR/feature-gate.rs:94:11
|
LL | while let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {}
| ^^^^^^^^^
|
= note: for more information, see https://github.com/rust-lang/rust/issues/53667
= help: add #![feature(let_chains)] to the crate attributes to enable
error[E0658]: `let` expressions in this position are experimental
--> $DIR/feature-gate.rs:94:24
|
LL | while let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {}
| ^^^^^^^^^
|
= note: for more information, see https://github.com/rust-lang/rust/issues/53667
= help: add #![feature(let_chains)] to the crate attributes to enable
error[E0658]: `let` expressions in this position are experimental
--> $DIR/feature-gate.rs:94:38
|
LL | while let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {}
| ^^^^^^^^^
|
= note: for more information, see https://github.com/rust-lang/rust/issues/53667
= help: add #![feature(let_chains)] to the crate attributes to enable
error[E0658]: `let` expressions in this position are experimental
--> $DIR/feature-gate.rs:94:51
|
LL | while let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {}
| ^^^^^^^^^
|
= note: for more information, see https://github.com/rust-lang/rust/issues/53667
= help: add #![feature(let_chains)] to the crate attributes to enable
error[E0658]: `let` expressions in this position are experimental
--> $DIR/feature-gate.rs:94:64
|
LL | while let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {}
| ^^^^^^^^^
|
= note: for more information, see https://github.com/rust-lang/rust/issues/53667
= help: add #![feature(let_chains)] to the crate attributes to enable
error[E0658]: `let` expressions in this position are experimental
--> $DIR/feature-gate.rs:106:11
|
LL | while let Range { start: _, end: _ } = (true..true) && false {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: for more information, see https://github.com/rust-lang/rust/issues/53667
= help: add #![feature(let_chains)] to the crate attributes to enable
error[E0658]: `let` expressions in this position are experimental
--> $DIR/feature-gate.rs:129:20
|
LL | #[cfg(FALSE)] (let 0 = 1);
| ^^^^^^^^^
|
= note: for more information, see https://github.com/rust-lang/rust/issues/53667
= help: add #![feature(let_chains)] to the crate attributes to enable
error[E0658]: `let` expressions in this position are experimental
--> $DIR/feature-gate.rs:114:17
|
LL | noop_expr!((let 0 = 1));
| ^^^^^^^^^
|
= note: for more information, see https://github.com/rust-lang/rust/issues/53667
= help: add #![feature(let_chains)] to the crate attributes to enable
error[E0658]: `let` expressions in this position are experimental
--> $DIR/feature-gate.rs:123:16
|
LL | use_expr!((let 0 = 1 && 0 == 0));
| ^^^^^^^^^
|
= note: for more information, see https://github.com/rust-lang/rust/issues/53667
= help: add #![feature(let_chains)] to the crate attributes to enable
error[E0658]: `let` expressions in this position are experimental
--> $DIR/feature-gate.rs:126:16
|
LL | use_expr!((let 0 = 1));
| ^^^^^^^^^
|
= note: for more information, see https://github.com/rust-lang/rust/issues/53667
= help: add #![feature(let_chains)] to the crate attributes to enable
error: `let` expressions are not supported here
--> $DIR/feature-gate.rs:14:9
|
LL | if (let 0 = 1) {}
| ^^^^^^^^^
|
= note: only supported directly in conditions of `if`- and `while`-expressions
= note: as well as when nested within `&&` and parenthesis in those conditions
error: `let` expressions are not supported here
--> $DIR/feature-gate.rs:18:11
|
LL | if (((let 0 = 1))) {}
| ^^^^^^^^^
|
= note: only supported directly in conditions of `if`- and `while`-expressions
= note: as well as when nested within `&&` and parenthesis in those conditions
error: `let` expressions are not supported here
--> $DIR/feature-gate.rs:22:16
|
LL | if true && let 0 = 1 {}
| ^^^^^^^^^
|
= note: only supported directly in conditions of `if`- and `while`-expressions
= note: as well as when nested within `&&` and parenthesis in those conditions
error: `let` expressions are not supported here
--> $DIR/feature-gate.rs:26:8
|
LL | if let 0 = 1 && true {}
| ^^^^^^^^^
|
= note: only supported directly in conditions of `if`- and `while`-expressions
= note: as well as when nested within `&&` and parenthesis in those conditions
error: `let` expressions are not supported here
--> $DIR/feature-gate.rs:30:9
|
LL | if (let 0 = 1) && true {}
| ^^^^^^^^^
|
= note: only supported directly in conditions of `if`- and `while`-expressions
= note: as well as when nested within `&&` and parenthesis in those conditions
error: `let` expressions are not supported here
--> $DIR/feature-gate.rs:34:17
|
LL | if true && (let 0 = 1) {}
| ^^^^^^^^^
|
= note: only supported directly in conditions of `if`- and `while`-expressions
= note: as well as when nested within `&&` and parenthesis in those conditions
error: `let` expressions are not supported here
--> $DIR/feature-gate.rs:38:9
|
LL | if (let 0 = 1) && (let 0 = 1) {}
| ^^^^^^^^^
|
= note: only supported directly in conditions of `if`- and `while`-expressions
= note: as well as when nested within `&&` and parenthesis in those conditions
error: `let` expressions are not supported here
--> $DIR/feature-gate.rs:38:24
|
LL | if (let 0 = 1) && (let 0 = 1) {}
| ^^^^^^^^^
|
= note: only supported directly in conditions of `if`- and `while`-expressions
= note: as well as when nested within `&&` and parenthesis in those conditions
error: `let` expressions are not supported here
--> $DIR/feature-gate.rs:44:8
|
LL | if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {}
| ^^^^^^^^^
|
= note: only supported directly in conditions of `if`- and `while`-expressions
= note: as well as when nested within `&&` and parenthesis in those conditions
error: `let` expressions are not supported here
--> $DIR/feature-gate.rs:44:21
|
LL | if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {}
| ^^^^^^^^^
|
= note: only supported directly in conditions of `if`- and `while`-expressions
= note: as well as when nested within `&&` and parenthesis in those conditions
error: `let` expressions are not supported here
--> $DIR/feature-gate.rs:44:35
|
LL | if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {}
| ^^^^^^^^^
|
= note: only supported directly in conditions of `if`- and `while`-expressions
= note: as well as when nested within `&&` and parenthesis in those conditions
error: `let` expressions are not supported here
--> $DIR/feature-gate.rs:44:48
|
LL | if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {}
| ^^^^^^^^^
|
= note: only supported directly in conditions of `if`- and `while`-expressions
= note: as well as when nested within `&&` and parenthesis in those conditions
error: `let` expressions are not supported here
--> $DIR/feature-gate.rs:44:61
|
LL | if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {}
| ^^^^^^^^^
|
= note: only supported directly in conditions of `if`- and `while`-expressions
= note: as well as when nested within `&&` and parenthesis in those conditions
error: `let` expressions are not supported here
--> $DIR/feature-gate.rs:56:8
|
LL | if let Range { start: _, end: _ } = (true..true) && false {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: only supported directly in conditions of `if`- and `while`-expressions
= note: as well as when nested within `&&` and parenthesis in those conditions
error: `let` expressions are not supported here
--> $DIR/feature-gate.rs:64:12
|
LL | while (let 0 = 1) {}
| ^^^^^^^^^
|
= note: only supported directly in conditions of `if`- and `while`-expressions
= note: as well as when nested within `&&` and parenthesis in those conditions
error: `let` expressions are not supported here
--> $DIR/feature-gate.rs:68:14
|
LL | while (((let 0 = 1))) {}
| ^^^^^^^^^
|
= note: only supported directly in conditions of `if`- and `while`-expressions
= note: as well as when nested within `&&` and parenthesis in those conditions
error: `let` expressions are not supported here
--> $DIR/feature-gate.rs:72:19
|
LL | while true && let 0 = 1 {}
| ^^^^^^^^^
|
= note: only supported directly in conditions of `if`- and `while`-expressions
= note: as well as when nested within `&&` and parenthesis in those conditions
error: `let` expressions are not supported here
--> $DIR/feature-gate.rs:76:11
|
LL | while let 0 = 1 && true {}
| ^^^^^^^^^
|
= note: only supported directly in conditions of `if`- and `while`-expressions
= note: as well as when nested within `&&` and parenthesis in those conditions
error: `let` expressions are not supported here
--> $DIR/feature-gate.rs:80:12
|
LL | while (let 0 = 1) && true {}
| ^^^^^^^^^
|
= note: only supported directly in conditions of `if`- and `while`-expressions
= note: as well as when nested within `&&` and parenthesis in those conditions
error: `let` expressions are not supported here
--> $DIR/feature-gate.rs:84:20
|
LL | while true && (let 0 = 1) {}
| ^^^^^^^^^
|
= note: only supported directly in conditions of `if`- and `while`-expressions
= note: as well as when nested within `&&` and parenthesis in those conditions
error: `let` expressions are not supported here
--> $DIR/feature-gate.rs:88:12
|
LL | while (let 0 = 1) && (let 0 = 1) {}
| ^^^^^^^^^
|
= note: only supported directly in conditions of `if`- and `while`-expressions
= note: as well as when nested within `&&` and parenthesis in those conditions
error: `let` expressions are not supported here
--> $DIR/feature-gate.rs:88:27
|
LL | while (let 0 = 1) && (let 0 = 1) {}
| ^^^^^^^^^
|
= note: only supported directly in conditions of `if`- and `while`-expressions
= note: as well as when nested within `&&` and parenthesis in those conditions
error: `let` expressions are not supported here
--> $DIR/feature-gate.rs:94:11
|
LL | while let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {}
| ^^^^^^^^^
|
= note: only supported directly in conditions of `if`- and `while`-expressions
= note: as well as when nested within `&&` and parenthesis in those conditions
error: `let` expressions are not supported here
--> $DIR/feature-gate.rs:94:24
|
LL | while let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {}
| ^^^^^^^^^
|
= note: only supported directly in conditions of `if`- and `while`-expressions
= note: as well as when nested within `&&` and parenthesis in those conditions
error: `let` expressions are not supported here
--> $DIR/feature-gate.rs:94:38
|
LL | while let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {}
| ^^^^^^^^^
|
= note: only supported directly in conditions of `if`- and `while`-expressions
= note: as well as when nested within `&&` and parenthesis in those conditions
error: `let` expressions are not supported here
--> $DIR/feature-gate.rs:94:51
|
LL | while let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {}
| ^^^^^^^^^
|
= note: only supported directly in conditions of `if`- and `while`-expressions
= note: as well as when nested within `&&` and parenthesis in those conditions
error: `let` expressions are not supported here
--> $DIR/feature-gate.rs:94:64
|
LL | while let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {}
| ^^^^^^^^^
|
= note: only supported directly in conditions of `if`- and `while`-expressions
= note: as well as when nested within `&&` and parenthesis in those conditions
error: `let` expressions are not supported here
--> $DIR/feature-gate.rs:106:11
|
LL | while let Range { start: _, end: _ } = (true..true) && false {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: only supported directly in conditions of `if`- and `while`-expressions
= note: as well as when nested within `&&` and parenthesis in those conditions
error: `let` expressions are not supported here
--> $DIR/feature-gate.rs:123:16
|
LL | use_expr!((let 0 = 1 && 0 == 0));
| ^^^^^^^^^
|
= note: only supported directly in conditions of `if`- and `while`-expressions
= note: as well as when nested within `&&` and parenthesis in those conditions
error: `let` expressions are not supported here
--> $DIR/feature-gate.rs:126:16
|
LL | use_expr!((let 0 = 1));
| ^^^^^^^^^
|
= note: only supported directly in conditions of `if`- and `while`-expressions
= note: as well as when nested within `&&` and parenthesis in those conditions
error: aborting due to 63 previous errors
For more information about this error, try `rustc --explain E0658`.

View File

@ -0,0 +1,18 @@
// run-pass
#![allow(irrefutable_let_patterns)]
use std::ops::Range;
fn main() {
let x: bool;
// This should associate as: `(x = (true && false));`.
x = true && false;
assert!(!x);
fn _f1() -> bool {
// Should associate as `(let _ = (return (true && false)))`.
if let _ = return true && false {};
}
assert!(!_f1());
}

View File

@ -1,38 +0,0 @@
// edition:2015
// Enabling `ireffutable_let_patterns` isn't necessary for what this tests, but it makes coming up
// with examples easier.
#[allow(irrefutable_let_patterns)]
fn main() {
use std::ops::Range;
if let Range { start: _, end: _ } = true..true && false { }
//~^ ERROR ambiguous use of `&&`
if let Range { start: _, end: _ } = true..true || false { }
//~^ ERROR ambiguous use of `||`
while let Range { start: _, end: _ } = true..true && false { }
//~^ ERROR ambiguous use of `&&`
while let Range { start: _, end: _ } = true..true || false { }
//~^ ERROR ambiguous use of `||`
if let true = false && false { }
//~^ ERROR ambiguous use of `&&`
while let true = (1 == 2) && false { }
//~^ ERROR ambiguous use of `&&`
// The following cases are not an error as parenthesis are used to
// clarify intent:
if let Range { start: _, end: _ } = true..(true || false) { }
if let Range { start: _, end: _ } = true..(true && false) { }
while let Range { start: _, end: _ } = true..(true || false) { }
while let Range { start: _, end: _ } = true..(true && false) { }
}

View File

@ -1,56 +0,0 @@
error: ambiguous use of `&&`
--> $DIR/syntax-ambiguity-2015.rs:10:47
|
LL | if let Range { start: _, end: _ } = true..true && false { }
| ^^^^^^^^^^^^^ help: consider adding parentheses: `(true && false)`
|
= note: this will be a error until the `let_chains` feature is stabilized
= note: see rust-lang/rust#53668 for more information
error: ambiguous use of `||`
--> $DIR/syntax-ambiguity-2015.rs:13:47
|
LL | if let Range { start: _, end: _ } = true..true || false { }
| ^^^^^^^^^^^^^ help: consider adding parentheses: `(true || false)`
|
= note: this will be a error until the `let_chains` feature is stabilized
= note: see rust-lang/rust#53668 for more information
error: ambiguous use of `&&`
--> $DIR/syntax-ambiguity-2015.rs:16:50
|
LL | while let Range { start: _, end: _ } = true..true && false { }
| ^^^^^^^^^^^^^ help: consider adding parentheses: `(true && false)`
|
= note: this will be a error until the `let_chains` feature is stabilized
= note: see rust-lang/rust#53668 for more information
error: ambiguous use of `||`
--> $DIR/syntax-ambiguity-2015.rs:19:50
|
LL | while let Range { start: _, end: _ } = true..true || false { }
| ^^^^^^^^^^^^^ help: consider adding parentheses: `(true || false)`
|
= note: this will be a error until the `let_chains` feature is stabilized
= note: see rust-lang/rust#53668 for more information
error: ambiguous use of `&&`
--> $DIR/syntax-ambiguity-2015.rs:22:19
|
LL | if let true = false && false { }
| ^^^^^^^^^^^^^^ help: consider adding parentheses: `(false && false)`
|
= note: this will be a error until the `let_chains` feature is stabilized
= note: see rust-lang/rust#53668 for more information
error: ambiguous use of `&&`
--> $DIR/syntax-ambiguity-2015.rs:25:22
|
LL | while let true = (1 == 2) && false { }
| ^^^^^^^^^^^^^^^^^ help: consider adding parentheses: `((1 == 2) && false)`
|
= note: this will be a error until the `let_chains` feature is stabilized
= note: see rust-lang/rust#53668 for more information
error: aborting due to 6 previous errors

View File

@ -1,38 +0,0 @@
// edition:2018
// Enabling `ireffutable_let_patterns` isn't necessary for what this tests, but it makes coming up
// with examples easier.
#[allow(irrefutable_let_patterns)]
fn main() {
use std::ops::Range;
if let Range { start: _, end: _ } = true..true && false { }
//~^ ERROR ambiguous use of `&&`
if let Range { start: _, end: _ } = true..true || false { }
//~^ ERROR ambiguous use of `||`
while let Range { start: _, end: _ } = true..true && false { }
//~^ ERROR ambiguous use of `&&`
while let Range { start: _, end: _ } = true..true || false { }
//~^ ERROR ambiguous use of `||`
if let true = false && false { }
//~^ ERROR ambiguous use of `&&`
while let true = (1 == 2) && false { }
//~^ ERROR ambiguous use of `&&`
// The following cases are not an error as parenthesis are used to
// clarify intent:
if let Range { start: _, end: _ } = true..(true || false) { }
if let Range { start: _, end: _ } = true..(true && false) { }
while let Range { start: _, end: _ } = true..(true || false) { }
while let Range { start: _, end: _ } = true..(true && false) { }
}

View File

@ -1,56 +0,0 @@
error: ambiguous use of `&&`
--> $DIR/syntax-ambiguity-2018.rs:10:47
|
LL | if let Range { start: _, end: _ } = true..true && false { }
| ^^^^^^^^^^^^^ help: consider adding parentheses: `(true && false)`
|
= note: this will be a error until the `let_chains` feature is stabilized
= note: see rust-lang/rust#53668 for more information
error: ambiguous use of `||`
--> $DIR/syntax-ambiguity-2018.rs:13:47
|
LL | if let Range { start: _, end: _ } = true..true || false { }
| ^^^^^^^^^^^^^ help: consider adding parentheses: `(true || false)`
|
= note: this will be a error until the `let_chains` feature is stabilized
= note: see rust-lang/rust#53668 for more information
error: ambiguous use of `&&`
--> $DIR/syntax-ambiguity-2018.rs:16:50
|
LL | while let Range { start: _, end: _ } = true..true && false { }
| ^^^^^^^^^^^^^ help: consider adding parentheses: `(true && false)`
|
= note: this will be a error until the `let_chains` feature is stabilized
= note: see rust-lang/rust#53668 for more information
error: ambiguous use of `||`
--> $DIR/syntax-ambiguity-2018.rs:19:50
|
LL | while let Range { start: _, end: _ } = true..true || false { }
| ^^^^^^^^^^^^^ help: consider adding parentheses: `(true || false)`
|
= note: this will be a error until the `let_chains` feature is stabilized
= note: see rust-lang/rust#53668 for more information
error: ambiguous use of `&&`
--> $DIR/syntax-ambiguity-2018.rs:22:19
|
LL | if let true = false && false { }
| ^^^^^^^^^^^^^^ help: consider adding parentheses: `(false && false)`
|
= note: this will be a error until the `let_chains` feature is stabilized
= note: see rust-lang/rust#53668 for more information
error: ambiguous use of `&&`
--> $DIR/syntax-ambiguity-2018.rs:25:22
|
LL | while let true = (1 == 2) && false { }
| ^^^^^^^^^^^^^^^^^ help: consider adding parentheses: `((1 == 2) && false)`
|
= note: this will be a error until the `let_chains` feature is stabilized
= note: see rust-lang/rust#53668 for more information
error: aborting due to 6 previous errors