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:
commit
5d677b2efd
@ -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)))
|
||||
}
|
||||
|
||||
|
@ -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),
|
||||
|
@ -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) {
|
||||
|
@ -8,6 +8,7 @@
|
||||
|
||||
#![feature(in_band_lifetimes)]
|
||||
#![feature(nll)]
|
||||
#![feature(bind_by_move_pattern_guards)]
|
||||
#![feature(rustc_diagnostic_macros)]
|
||||
|
||||
#![recursion_limit="256"]
|
||||
|
@ -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();
|
||||
});
|
||||
|
@ -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);
|
||||
|
@ -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 }`
|
||||
|
@ -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(),
|
||||
|
@ -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,
|
||||
|
@ -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);
|
||||
|
@ -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,
|
||||
|
@ -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()),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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()),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
@ -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,
|
||||
|
@ -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)?;
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
@ -354,6 +354,7 @@
|
||||
label_break_value,
|
||||
lang,
|
||||
lang_items,
|
||||
let_chains,
|
||||
lhs,
|
||||
lib,
|
||||
lifetime,
|
||||
|
@ -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"),
|
||||
}
|
||||
}
|
||||
|
@ -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 }) {}
|
||||
|
@ -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) {}
|
||||
|
6
src/test/ui/rfc-2497-if-let-chains/ast-pretty-check.rs
Normal file
6
src/test/ui/rfc-2497-if-let-chains/ast-pretty-check.rs
Normal file
@ -0,0 +1,6 @@
|
||||
// compile-pass
|
||||
// compile-flags: -Z unpretty=expanded
|
||||
|
||||
fn main() {
|
||||
if let 0 = 1 {}
|
||||
}
|
10
src/test/ui/rfc-2497-if-let-chains/ast-pretty-check.stdout
Normal file
10
src/test/ui/rfc-2497-if-let-chains/ast-pretty-check.stdout
Normal 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 { } }
|
244
src/test/ui/rfc-2497-if-let-chains/disallowed-positions.rs
Normal file
244
src/test/ui/rfc-2497-if-let-chains/disallowed-positions.rs
Normal 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 {}
|
||||
}
|
987
src/test/ui/rfc-2497-if-let-chains/disallowed-positions.stderr
Normal file
987
src/test/ui/rfc-2497-if-let-chains/disallowed-positions.stderr
Normal 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`.
|
136
src/test/ui/rfc-2497-if-let-chains/feature-gate.rs
Normal file
136
src/test/ui/rfc-2497-if-let-chains/feature-gate.rs
Normal 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() {}
|
570
src/test/ui/rfc-2497-if-let-chains/feature-gate.stderr
Normal file
570
src/test/ui/rfc-2497-if-let-chains/feature-gate.stderr
Normal 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`.
|
18
src/test/ui/rfc-2497-if-let-chains/protect-precedences.rs
Normal file
18
src/test/ui/rfc-2497-if-let-chains/protect-precedences.rs
Normal 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());
|
||||
}
|
@ -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) { }
|
||||
}
|
@ -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
|
||||
|
@ -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) { }
|
||||
}
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user