mirror of
https://github.com/rust-lang/rust.git
synced 2024-11-25 08:13:41 +00:00
Introduce hir::ExprKind::Let - Take 2
This commit is contained in:
parent
2d9f2eae84
commit
6aa9937a76
@ -1302,7 +1302,9 @@ pub enum ExprKind {
|
||||
Type(P<Expr>, P<Ty>),
|
||||
/// A `let pat = expr` expression that is only semantically allowed in the condition
|
||||
/// of `if` / `while` expressions. (e.g., `if let 0 = x { .. }`).
|
||||
Let(P<Pat>, P<Expr>),
|
||||
///
|
||||
/// `Span` represents the whole `let pat = expr` statement.
|
||||
Let(P<Pat>, P<Expr>, Span),
|
||||
/// An `if` block, with an optional `else` block.
|
||||
///
|
||||
/// `if expr { block } else { expr }`
|
||||
|
@ -1237,7 +1237,7 @@ pub fn noop_visit_expr<T: MutVisitor>(
|
||||
vis.visit_ty(ty);
|
||||
}
|
||||
ExprKind::AddrOf(_, _, ohs) => vis.visit_expr(ohs),
|
||||
ExprKind::Let(pat, scrutinee) => {
|
||||
ExprKind::Let(pat, scrutinee, _) => {
|
||||
vis.visit_pat(pat);
|
||||
vis.visit_expr(scrutinee);
|
||||
}
|
||||
|
@ -779,9 +779,9 @@ 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 pat, ref scrutinee) => {
|
||||
ExprKind::Let(ref pat, ref expr, _) => {
|
||||
visitor.visit_pat(pat);
|
||||
visitor.visit_expr(scrutinee);
|
||||
visitor.visit_expr(expr);
|
||||
}
|
||||
ExprKind::If(ref head_expression, ref if_block, ref optional_else) => {
|
||||
visitor.visit_expr(head_expression);
|
||||
|
@ -86,32 +86,12 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||
let ohs = self.lower_expr(ohs);
|
||||
hir::ExprKind::AddrOf(k, m, ohs)
|
||||
}
|
||||
ExprKind::Let(ref pat, ref scrutinee) => {
|
||||
self.lower_expr_let(e.span, pat, scrutinee)
|
||||
ExprKind::Let(ref pat, ref scrutinee, span) => {
|
||||
hir::ExprKind::Let(self.lower_pat(pat), self.lower_expr(scrutinee), span)
|
||||
}
|
||||
ExprKind::If(ref cond, ref then, ref else_opt) => {
|
||||
self.lower_expr_if(cond, then, else_opt.as_deref())
|
||||
}
|
||||
ExprKind::If(ref cond, ref then, ref else_opt) => match cond.kind {
|
||||
ExprKind::Let(ref pat, ref scrutinee) => {
|
||||
self.lower_expr_if_let(e.span, pat, scrutinee, then, else_opt.as_deref())
|
||||
}
|
||||
ExprKind::Paren(ref paren) => match paren.peel_parens().kind {
|
||||
ExprKind::Let(ref pat, ref scrutinee) => {
|
||||
// A user has written `if (let Some(x) = foo) {`, we want to avoid
|
||||
// confusing them with mentions of nightly features.
|
||||
// If this logic is changed, you will also likely need to touch
|
||||
// `unused::UnusedParens::check_expr`.
|
||||
self.if_let_expr_with_parens(cond, &paren.peel_parens());
|
||||
self.lower_expr_if_let(
|
||||
e.span,
|
||||
pat,
|
||||
scrutinee,
|
||||
then,
|
||||
else_opt.as_deref(),
|
||||
)
|
||||
}
|
||||
_ => self.lower_expr_if(cond, then, else_opt.as_deref()),
|
||||
},
|
||||
_ => self.lower_expr_if(cond, then, else_opt.as_deref()),
|
||||
},
|
||||
ExprKind::While(ref cond, ref body, opt_label) => self
|
||||
.with_loop_scope(e.id, |this| {
|
||||
this.lower_expr_while_in_loop_scope(e.span, cond, body, opt_label)
|
||||
@ -368,126 +348,51 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||
hir::ExprKind::Call(f, self.lower_exprs(&real_args))
|
||||
}
|
||||
|
||||
fn if_let_expr_with_parens(&mut self, cond: &Expr, paren: &Expr) {
|
||||
let start = cond.span.until(paren.span);
|
||||
let end = paren.span.shrink_to_hi().until(cond.span.shrink_to_hi());
|
||||
self.sess
|
||||
.struct_span_err(
|
||||
vec![start, end],
|
||||
"invalid parentheses around `let` expression in `if let`",
|
||||
)
|
||||
.multipart_suggestion(
|
||||
"`if let` needs to be written without parentheses",
|
||||
vec![(start, String::new()), (end, String::new())],
|
||||
rustc_errors::Applicability::MachineApplicable,
|
||||
)
|
||||
.emit();
|
||||
// Ideally, we'd remove the feature gating of a `let` expression since we are already
|
||||
// complaining about it here, but `feature_gate::check_crate` has already run by now:
|
||||
// self.sess.parse_sess.gated_spans.ungate_last(sym::let_chains, paren.span);
|
||||
}
|
||||
|
||||
/// Emit an error and lower `ast::ExprKind::Let(pat, scrutinee)` into:
|
||||
/// ```rust
|
||||
/// match scrutinee { pats => true, _ => false }
|
||||
/// ```
|
||||
fn lower_expr_let(&mut self, span: Span, pat: &Pat, scrutinee: &Expr) -> hir::ExprKind<'hir> {
|
||||
// If we got here, the `let` expression is not allowed.
|
||||
|
||||
if self.sess.opts.unstable_features.is_nightly_build() {
|
||||
self.sess
|
||||
.struct_span_err(span, "`let` expressions are not supported here")
|
||||
.note(
|
||||
"only supported directly without parentheses in conditions of `if`- and \
|
||||
`while`-expressions, as well as in `let` chains within parentheses",
|
||||
)
|
||||
.emit();
|
||||
} else {
|
||||
self.sess
|
||||
.struct_span_err(span, "expected expression, found statement (`let`)")
|
||||
.note("variable declaration using `let` is a statement")
|
||||
.emit();
|
||||
}
|
||||
|
||||
// For better recovery, we emit:
|
||||
// ```
|
||||
// match scrutinee { pat => 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 `pat` and `scrutinee`.
|
||||
// 3. `pat` 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 pat = self.lower_pat(pat);
|
||||
let expr = self.expr_bool(span, true);
|
||||
self.arm(pat, expr)
|
||||
};
|
||||
let else_arm = {
|
||||
let pat = self.pat_wild(span);
|
||||
let expr = self.expr_bool(span, false);
|
||||
self.arm(pat, expr)
|
||||
};
|
||||
hir::ExprKind::Match(
|
||||
scrutinee,
|
||||
arena_vec![self; then_arm, else_arm],
|
||||
hir::MatchSource::Normal,
|
||||
)
|
||||
}
|
||||
|
||||
fn lower_expr_if(
|
||||
&mut self,
|
||||
cond: &Expr,
|
||||
then: &Block,
|
||||
else_opt: Option<&Expr>,
|
||||
) -> hir::ExprKind<'hir> {
|
||||
let cond = self.lower_expr(cond);
|
||||
let wrapped_cond = match cond.kind {
|
||||
hir::ExprKind::Let(..) => cond,
|
||||
_ => self.expr_drop_temps(cond.span, cond, AttrVec::new()),
|
||||
};
|
||||
let lowered_cond = self.lower_expr(cond);
|
||||
let new_cond = self.manage_let_cond(lowered_cond);
|
||||
let then_expr = self.lower_block_expr(then);
|
||||
if let Some(rslt) = else_opt {
|
||||
hir::ExprKind::If(
|
||||
wrapped_cond,
|
||||
self.arena.alloc(then_expr),
|
||||
Some(self.lower_expr(rslt)),
|
||||
)
|
||||
hir::ExprKind::If(new_cond, self.arena.alloc(then_expr), Some(self.lower_expr(rslt)))
|
||||
} else {
|
||||
hir::ExprKind::If(wrapped_cond, self.arena.alloc(then_expr), None)
|
||||
hir::ExprKind::If(new_cond, self.arena.alloc(then_expr), None)
|
||||
}
|
||||
}
|
||||
|
||||
fn lower_expr_if_let(
|
||||
&mut self,
|
||||
span: Span,
|
||||
pat: &Pat,
|
||||
scrutinee: &Expr,
|
||||
then: &Block,
|
||||
else_opt: Option<&Expr>,
|
||||
) -> hir::ExprKind<'hir> {
|
||||
// FIXME(#53667): handle lowering of && and parens.
|
||||
|
||||
// `_ => else_block` where `else_block` is `{}` if there's `None`:
|
||||
let else_pat = self.pat_wild(span);
|
||||
let (else_expr, contains_else_clause) = match else_opt {
|
||||
None => (self.expr_block_empty(span.shrink_to_hi()), false),
|
||||
Some(els) => (self.lower_expr(els), true),
|
||||
};
|
||||
let else_arm = self.arm(else_pat, else_expr);
|
||||
|
||||
// Handle then + scrutinee:
|
||||
let scrutinee = self.lower_expr(scrutinee);
|
||||
let then_pat = self.lower_pat(pat);
|
||||
|
||||
let then_expr = self.lower_block_expr(then);
|
||||
let then_arm = self.arm(then_pat, self.arena.alloc(then_expr));
|
||||
|
||||
let desugar = hir::MatchSource::IfLetDesugar { contains_else_clause };
|
||||
hir::ExprKind::Match(scrutinee, arena_vec![self; then_arm, else_arm], desugar)
|
||||
// If `cond` kind is `let`, returns `let`. Otherwise, wraps and returns `cond`
|
||||
// in a temporary block.
|
||||
fn manage_let_cond(&mut self, cond: &'hir hir::Expr<'hir>) -> &'hir hir::Expr<'hir> {
|
||||
match cond.kind {
|
||||
hir::ExprKind::Let(..) => cond,
|
||||
_ => {
|
||||
let span_block =
|
||||
self.mark_span_with_reason(DesugaringKind::CondTemporary, cond.span, None);
|
||||
self.expr_drop_temps(span_block, cond, AttrVec::new())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// We desugar: `'label: while $cond $body` into:
|
||||
//
|
||||
// ```
|
||||
// 'label: loop {
|
||||
// if { let _t = $cond; _t } {
|
||||
// $body
|
||||
// }
|
||||
// else {
|
||||
// break;
|
||||
// }
|
||||
// }
|
||||
// ```
|
||||
//
|
||||
// Wrap in a construct equivalent to `{ let _t = $cond; _t }`
|
||||
// to preserve drop semantics since `while $cond { ... }` does not
|
||||
// let temporaries live outside of `cond`.
|
||||
fn lower_expr_while_in_loop_scope(
|
||||
&mut self,
|
||||
span: Span,
|
||||
@ -495,72 +400,17 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||
body: &Block,
|
||||
opt_label: Option<Label>,
|
||||
) -> hir::ExprKind<'hir> {
|
||||
// FIXME(#53667): handle lowering of && and parens.
|
||||
|
||||
// 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.
|
||||
|
||||
// `_ => break`:
|
||||
let else_arm = {
|
||||
let else_pat = self.pat_wild(span);
|
||||
let else_expr = self.expr_break(span, ThinVec::new());
|
||||
self.arm(else_pat, else_expr)
|
||||
};
|
||||
|
||||
// Handle then + scrutinee:
|
||||
let (then_pat, scrutinee, desugar, source) = match cond.kind {
|
||||
ExprKind::Let(ref pat, ref scrutinee) => {
|
||||
// to:
|
||||
//
|
||||
// [opt_ident]: loop {
|
||||
// match <sub_expr> {
|
||||
// <pat> => <body>,
|
||||
// _ => break
|
||||
// }
|
||||
// }
|
||||
let scrutinee = self.with_loop_condition_scope(|t| t.lower_expr(scrutinee));
|
||||
let pat = self.lower_pat(pat);
|
||||
(pat, scrutinee, hir::MatchSource::WhileLetDesugar, hir::LoopSource::WhileLet)
|
||||
}
|
||||
_ => {
|
||||
// We desugar: `'label: while $cond $body` into:
|
||||
//
|
||||
// ```
|
||||
// 'label: loop {
|
||||
// match drop-temps { $cond } {
|
||||
// true => $body,
|
||||
// _ => break,
|
||||
// }
|
||||
// }
|
||||
// ```
|
||||
|
||||
// Lower condition:
|
||||
let cond = self.with_loop_condition_scope(|this| this.lower_expr(cond));
|
||||
let span_block =
|
||||
self.mark_span_with_reason(DesugaringKind::CondTemporary, cond.span, None);
|
||||
// Wrap in a construct equivalent to `{ let _t = $cond; _t }`
|
||||
// to preserve drop semantics since `while cond { ... }` does not
|
||||
// let temporaries live outside of `cond`.
|
||||
let cond = self.expr_drop_temps(span_block, cond, ThinVec::new());
|
||||
// `true => <then>`:
|
||||
let pat = self.pat_bool(span, true);
|
||||
(pat, cond, hir::MatchSource::WhileDesugar, hir::LoopSource::While)
|
||||
}
|
||||
};
|
||||
let then_expr = self.lower_block_expr(body);
|
||||
let then_arm = self.arm(then_pat, self.arena.alloc(then_expr));
|
||||
|
||||
// `match <scrutinee> { ... }`
|
||||
let match_expr =
|
||||
self.expr_match(span, scrutinee, arena_vec![self; then_arm, else_arm], desugar);
|
||||
|
||||
// `[opt_ident]: loop { ... }`
|
||||
hir::ExprKind::Loop(
|
||||
self.block_expr(self.arena.alloc(match_expr)),
|
||||
opt_label,
|
||||
source,
|
||||
span.with_hi(cond.span.hi()),
|
||||
)
|
||||
let lowered_cond = self.with_loop_condition_scope(|t| t.lower_expr(cond));
|
||||
let new_cond = self.manage_let_cond(lowered_cond);
|
||||
let then = self.lower_block_expr(body);
|
||||
let expr_break = self.expr_break(span, ThinVec::new());
|
||||
let stmt_break = self.stmt_expr(span, expr_break);
|
||||
let else_blk = self.block_all(span, arena_vec![self; stmt_break], None);
|
||||
let else_expr = self.arena.alloc(self.expr_block(else_blk, ThinVec::new()));
|
||||
let if_kind = hir::ExprKind::If(new_cond, self.arena.alloc(then), Some(else_expr));
|
||||
let if_expr = self.expr(span, if_kind, ThinVec::new());
|
||||
let block = self.block_expr(self.arena.alloc(if_expr));
|
||||
hir::ExprKind::Loop(block, opt_label, hir::LoopSource::While, span.with_hi(cond.span.hi()))
|
||||
}
|
||||
|
||||
/// Desugar `try { <stmts>; <expr> }` into `{ <stmts>; ::std::ops::Try::from_output(<expr>) }`,
|
||||
@ -620,7 +470,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||
fn lower_arm(&mut self, arm: &Arm) -> hir::Arm<'hir> {
|
||||
let pat = self.lower_pat(&arm.pat);
|
||||
let guard = arm.guard.as_ref().map(|cond| {
|
||||
if let ExprKind::Let(ref pat, ref scrutinee) = cond.kind {
|
||||
if let ExprKind::Let(ref pat, ref scrutinee, _) = cond.kind {
|
||||
hir::Guard::IfLet(self.lower_pat(pat), self.lower_expr(scrutinee))
|
||||
} else {
|
||||
hir::Guard::If(self.lower_expr(cond))
|
||||
@ -1468,7 +1318,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||
// `::std::option::Option::None => break`
|
||||
let break_arm = {
|
||||
let break_expr =
|
||||
self.with_loop_scope(e.id, |this| this.expr_break(e.span, ThinVec::new()));
|
||||
self.with_loop_scope(e.id, |this| this.expr_break_alloc(e.span, ThinVec::new()));
|
||||
let pat = self.pat_none(e.span);
|
||||
self.arm(pat, break_expr)
|
||||
};
|
||||
@ -1681,12 +1531,6 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||
// Helper methods for building HIR.
|
||||
// =========================================================================
|
||||
|
||||
/// Constructs a `true` or `false` literal expression.
|
||||
pub(super) fn expr_bool(&mut self, span: Span, val: bool) -> &'hir hir::Expr<'hir> {
|
||||
let lit = Spanned { span, node: LitKind::Bool(val) };
|
||||
self.arena.alloc(self.expr(span, hir::ExprKind::Lit(lit), ThinVec::new()))
|
||||
}
|
||||
|
||||
/// Wrap the given `expr` in a terminating scope using `hir::ExprKind::DropTemps`.
|
||||
///
|
||||
/// In terms of drop order, it has the same effect as wrapping `expr` in
|
||||
@ -1721,9 +1565,14 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||
self.expr(span, hir::ExprKind::Match(arg, arms, source), ThinVec::new())
|
||||
}
|
||||
|
||||
fn expr_break(&mut self, span: Span, attrs: AttrVec) -> &'hir hir::Expr<'hir> {
|
||||
fn expr_break(&mut self, span: Span, attrs: AttrVec) -> hir::Expr<'hir> {
|
||||
let expr_break = hir::ExprKind::Break(self.lower_loop_destination(None), None);
|
||||
self.arena.alloc(self.expr(span, expr_break, attrs))
|
||||
self.expr(span, expr_break, attrs)
|
||||
}
|
||||
|
||||
fn expr_break_alloc(&mut self, span: Span, attrs: AttrVec) -> &'hir hir::Expr<'hir> {
|
||||
let expr_break = self.expr_break(span, attrs);
|
||||
self.arena.alloc(expr_break)
|
||||
}
|
||||
|
||||
fn expr_mut_addr_of(&mut self, span: Span, e: &'hir hir::Expr<'hir>) -> hir::Expr<'hir> {
|
||||
|
@ -2537,12 +2537,6 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||
self.arena.alloc(blk)
|
||||
}
|
||||
|
||||
/// Constructs a `true` or `false` literal pattern.
|
||||
fn pat_bool(&mut self, span: Span, val: bool) -> &'hir hir::Pat<'hir> {
|
||||
let expr = self.expr_bool(span, val);
|
||||
self.pat(span, hir::PatKind::Lit(expr))
|
||||
}
|
||||
|
||||
fn pat_cf_continue(&mut self, span: Span, pat: &'hir hir::Pat<'hir>) -> &'hir hir::Pat<'hir> {
|
||||
let field = self.single_pat_field(span, pat);
|
||||
self.pat_lang_item_variant(span, hir::LangItem::ControlFlowContinue, field)
|
||||
@ -2624,10 +2618,6 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||
)
|
||||
}
|
||||
|
||||
fn pat_wild(&mut self, span: Span) -> &'hir hir::Pat<'hir> {
|
||||
self.pat(span, hir::PatKind::Wild)
|
||||
}
|
||||
|
||||
fn pat(&mut self, span: Span, kind: hir::PatKind<'hir>) -> &'hir hir::Pat<'hir> {
|
||||
self.arena.alloc(hir::Pat {
|
||||
hir_id: self.next_id(),
|
||||
|
@ -18,6 +18,7 @@ use rustc_parse::validate_attr;
|
||||
use rustc_session::lint::builtin::PATTERNS_IN_FNS_WITHOUT_BODY;
|
||||
use rustc_session::lint::{BuiltinLintDiagnostics, LintBuffer};
|
||||
use rustc_session::Session;
|
||||
use rustc_span::source_map::Spanned;
|
||||
use rustc_span::symbol::{kw, sym, Ident};
|
||||
use rustc_span::Span;
|
||||
use std::mem;
|
||||
@ -80,6 +81,9 @@ struct AstValidator<'a> {
|
||||
/// certain positions.
|
||||
is_assoc_ty_bound_banned: bool,
|
||||
|
||||
/// Used to allow `let` expressions in certain syntactic locations.
|
||||
is_let_allowed: bool,
|
||||
|
||||
lint_buffer: &'a mut LintBuffer,
|
||||
}
|
||||
|
||||
@ -96,6 +100,27 @@ impl<'a> AstValidator<'a> {
|
||||
self.is_impl_trait_banned = old;
|
||||
}
|
||||
|
||||
fn with_let_allowed(&mut self, allowed: bool, f: impl FnOnce(&mut Self, bool)) {
|
||||
let old = mem::replace(&mut self.is_let_allowed, allowed);
|
||||
f(self, old);
|
||||
self.is_let_allowed = old;
|
||||
}
|
||||
|
||||
/// Emits an error banning the `let` expression provided in the given location.
|
||||
fn ban_let_expr(&self, expr: &'a Expr) {
|
||||
let sess = &self.session;
|
||||
if sess.opts.unstable_features.is_nightly_build() {
|
||||
sess.struct_span_err(expr.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();
|
||||
} else {
|
||||
sess.struct_span_err(expr.span, "expected expression, found statement (`let`)")
|
||||
.note("variable declaration using `let` is a statement")
|
||||
.emit();
|
||||
}
|
||||
}
|
||||
|
||||
fn with_banned_assoc_ty_bound(&mut self, f: impl FnOnce(&mut Self)) {
|
||||
let old = mem::replace(&mut self.is_assoc_ty_bound_banned, true);
|
||||
f(self);
|
||||
@ -978,20 +1003,49 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
|
||||
}
|
||||
|
||||
fn visit_expr(&mut self, expr: &'a Expr) {
|
||||
match &expr.kind {
|
||||
ExprKind::LlvmInlineAsm(..) if !self.session.target.allow_asm => {
|
||||
self.with_let_allowed(false, |this, let_allowed| match &expr.kind {
|
||||
ExprKind::If(cond, then, opt_else) => {
|
||||
this.visit_block(then);
|
||||
walk_list!(this, visit_expr, opt_else);
|
||||
this.with_let_allowed(true, |this, _| this.visit_expr(cond));
|
||||
return;
|
||||
}
|
||||
ExprKind::Let(..) if !let_allowed => this.ban_let_expr(expr),
|
||||
ExprKind::LlvmInlineAsm(..) if !this.session.target.allow_asm => {
|
||||
struct_span_err!(
|
||||
self.session,
|
||||
this.session,
|
||||
expr.span,
|
||||
E0472,
|
||||
"llvm_asm! is unsupported on this target"
|
||||
)
|
||||
.emit();
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
|
||||
visit::walk_expr(self, expr);
|
||||
ExprKind::Match(expr, arms) => {
|
||||
this.visit_expr(expr);
|
||||
for arm in arms {
|
||||
this.visit_expr(&arm.body);
|
||||
this.visit_pat(&arm.pat);
|
||||
walk_list!(this, visit_attribute, &arm.attrs);
|
||||
if let Some(ref guard) = arm.guard {
|
||||
if let ExprKind::Let(_, ref expr, _) = guard.kind {
|
||||
this.with_let_allowed(true, |this, _| this.visit_expr(expr));
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
ExprKind::Paren(_) | ExprKind::Binary(Spanned { node: BinOpKind::And, .. }, ..) => {
|
||||
this.with_let_allowed(let_allowed, |this, _| visit::walk_expr(this, expr));
|
||||
return;
|
||||
}
|
||||
ExprKind::While(cond, then, opt_label) => {
|
||||
walk_list!(this, visit_label, opt_label);
|
||||
this.visit_block(then);
|
||||
this.with_let_allowed(true, |this, _| this.visit_expr(cond));
|
||||
return;
|
||||
}
|
||||
_ => visit::walk_expr(this, expr),
|
||||
});
|
||||
}
|
||||
|
||||
fn visit_ty(&mut self, ty: &'a Ty) {
|
||||
@ -1634,6 +1688,7 @@ pub fn check_crate(session: &Session, krate: &Crate, lints: &mut LintBuffer) ->
|
||||
bound_context: None,
|
||||
is_impl_trait_banned: false,
|
||||
is_assoc_ty_bound_banned: false,
|
||||
is_let_allowed: false,
|
||||
lint_buffer: lints,
|
||||
};
|
||||
visit::walk_crate(&mut validator, krate);
|
||||
|
@ -1587,19 +1587,14 @@ impl<'a> State<'a> {
|
||||
self.ann.post(self, AnnNode::Block(blk))
|
||||
}
|
||||
|
||||
/// Print a `let pat = scrutinee` expression.
|
||||
crate fn print_let(&mut self, pat: &ast::Pat, scrutinee: &ast::Expr) {
|
||||
/// Print a `let pat = expr` expression.
|
||||
crate fn print_let(&mut self, pat: &ast::Pat, expr: &ast::Expr) {
|
||||
self.s.word("let ");
|
||||
|
||||
self.print_pat(pat);
|
||||
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()),
|
||||
)
|
||||
let npals = || parser::needs_par_as_let_scrutinee(expr.precedence().order());
|
||||
self.print_expr_cond_paren(expr, Self::cond_needs_par(expr) || npals())
|
||||
}
|
||||
|
||||
fn print_else(&mut self, els: Option<&ast::Expr>) {
|
||||
@ -1632,10 +1627,8 @@ impl<'a> State<'a> {
|
||||
|
||||
crate fn print_if(&mut self, test: &ast::Expr, blk: &ast::Block, elseopt: Option<&ast::Expr>) {
|
||||
self.head("if");
|
||||
|
||||
self.print_expr_as_cond(test);
|
||||
self.s.space();
|
||||
|
||||
self.print_block(blk);
|
||||
self.print_else(elseopt)
|
||||
}
|
||||
@ -1668,13 +1661,13 @@ impl<'a> State<'a> {
|
||||
self.print_expr_cond_paren(expr, Self::cond_needs_par(expr))
|
||||
}
|
||||
|
||||
/// Does `expr` need parenthesis when printed in a condition position?
|
||||
// Does `expr` need parenthesis when printed in a condition position?
|
||||
//
|
||||
// These cases need parens due to the parse error observed in #26461: `if return {}`
|
||||
// parses as the erroneous construct `if (return {})`, not `if (return) {}`.
|
||||
fn cond_needs_par(expr: &ast::Expr) -> bool {
|
||||
match expr.kind {
|
||||
// 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(..) | ast::ExprKind::Ret(..) | ast::ExprKind::Break(..) => true,
|
||||
|
||||
ast::ExprKind::Break(..) | ast::ExprKind::Closure(..) | ast::ExprKind::Ret(..) => true,
|
||||
_ => parser::contains_exterior_struct_lit(expr),
|
||||
}
|
||||
}
|
||||
@ -1919,7 +1912,7 @@ impl<'a> State<'a> {
|
||||
self.word_space(":");
|
||||
self.print_type(ty);
|
||||
}
|
||||
ast::ExprKind::Let(ref pat, ref scrutinee) => {
|
||||
ast::ExprKind::Let(ref pat, ref scrutinee, _) => {
|
||||
self.print_let(pat, scrutinee);
|
||||
}
|
||||
ast::ExprKind::If(ref test, ref blk, ref elseopt) => {
|
||||
|
@ -354,6 +354,7 @@ pub trait MacResult {
|
||||
fn make_expr(self: Box<Self>) -> Option<P<ast::Expr>> {
|
||||
None
|
||||
}
|
||||
|
||||
/// Creates zero or more items.
|
||||
fn make_items(self: Box<Self>) -> Option<SmallVec<[P<ast::Item>; 1]>> {
|
||||
None
|
||||
|
@ -1482,6 +1482,7 @@ impl Expr<'_> {
|
||||
ExprKind::Type(..) | ExprKind::Cast(..) => ExprPrecedence::Cast,
|
||||
ExprKind::DropTemps(ref expr, ..) => expr.precedence(),
|
||||
ExprKind::If(..) => ExprPrecedence::If,
|
||||
ExprKind::Let(..) => ExprPrecedence::Let,
|
||||
ExprKind::Loop(..) => ExprPrecedence::Loop,
|
||||
ExprKind::Match(..) => ExprPrecedence::Match,
|
||||
ExprKind::Closure(..) => ExprPrecedence::Closure,
|
||||
@ -1552,6 +1553,7 @@ impl Expr<'_> {
|
||||
| ExprKind::Break(..)
|
||||
| ExprKind::Continue(..)
|
||||
| ExprKind::Ret(..)
|
||||
| ExprKind::Let(..)
|
||||
| ExprKind::Loop(..)
|
||||
| ExprKind::Assign(..)
|
||||
| ExprKind::InlineAsm(..)
|
||||
@ -1634,6 +1636,7 @@ impl Expr<'_> {
|
||||
| ExprKind::Break(..)
|
||||
| ExprKind::Continue(..)
|
||||
| ExprKind::Ret(..)
|
||||
| ExprKind::Let(..)
|
||||
| ExprKind::Loop(..)
|
||||
| ExprKind::Assign(..)
|
||||
| ExprKind::InlineAsm(..)
|
||||
@ -1725,6 +1728,11 @@ pub enum ExprKind<'hir> {
|
||||
/// This construct only exists to tweak the drop order in HIR lowering.
|
||||
/// An example of that is the desugaring of `for` loops.
|
||||
DropTemps(&'hir Expr<'hir>),
|
||||
/// A `let $pat = $expr` expression.
|
||||
///
|
||||
/// These are not `Local` and only occur as expressions.
|
||||
/// The `let Some(x) = foo()` in `if let Some(x) = foo()` is an example of `Let(..)`.
|
||||
Let(&'hir Pat<'hir>, &'hir Expr<'hir>, Span),
|
||||
/// An `if` block, with an optional else block.
|
||||
///
|
||||
/// I.e., `if <expr> { <expr> } else { <expr> }`.
|
||||
@ -1884,15 +1892,6 @@ pub enum LocalSource {
|
||||
pub enum MatchSource {
|
||||
/// A `match _ { .. }`.
|
||||
Normal,
|
||||
/// An `if let _ = _ { .. }` (optionally with `else { .. }`).
|
||||
IfLetDesugar { contains_else_clause: bool },
|
||||
/// An `if let _ = _ => { .. }` match guard.
|
||||
IfLetGuardDesugar,
|
||||
/// A `while _ { .. }` (which was desugared to a `loop { match _ { .. } }`).
|
||||
WhileDesugar,
|
||||
/// A `while let _ = _ { .. }` (which was desugared to a
|
||||
/// `loop { match _ { .. } }`).
|
||||
WhileLetDesugar,
|
||||
/// A desugared `for _ in _ { .. }` loop.
|
||||
ForLoopDesugar,
|
||||
/// A desugared `?` operator.
|
||||
@ -1902,12 +1901,11 @@ pub enum MatchSource {
|
||||
}
|
||||
|
||||
impl MatchSource {
|
||||
pub fn name(self) -> &'static str {
|
||||
#[inline]
|
||||
pub const fn name(self) -> &'static str {
|
||||
use MatchSource::*;
|
||||
match self {
|
||||
Normal => "match",
|
||||
IfLetDesugar { .. } | IfLetGuardDesugar => "if",
|
||||
WhileDesugar | WhileLetDesugar => "while",
|
||||
ForLoopDesugar => "for",
|
||||
TryDesugar => "?",
|
||||
AwaitDesugar => ".await",
|
||||
@ -1922,8 +1920,6 @@ pub enum LoopSource {
|
||||
Loop,
|
||||
/// A `while _ { .. }` loop.
|
||||
While,
|
||||
/// A `while let _ = _ { .. }` loop.
|
||||
WhileLet,
|
||||
/// A `for _ in _ { .. }` loop.
|
||||
ForLoop,
|
||||
}
|
||||
@ -1932,7 +1928,7 @@ impl LoopSource {
|
||||
pub fn name(self) -> &'static str {
|
||||
match self {
|
||||
LoopSource::Loop => "loop",
|
||||
LoopSource::While | LoopSource::WhileLet => "while",
|
||||
LoopSource::While => "while",
|
||||
LoopSource::ForLoop => "for",
|
||||
}
|
||||
}
|
||||
|
@ -1163,6 +1163,10 @@ pub fn walk_expr<'v, V: Visitor<'v>>(visitor: &mut V, expression: &'v Expr<'v>)
|
||||
ExprKind::DropTemps(ref subexpression) => {
|
||||
visitor.visit_expr(subexpression);
|
||||
}
|
||||
ExprKind::Let(ref pat, ref expr, _) => {
|
||||
visitor.visit_expr(expr);
|
||||
visitor.visit_pat(pat);
|
||||
}
|
||||
ExprKind::If(ref cond, ref then, ref else_opt) => {
|
||||
visitor.visit_expr(cond);
|
||||
visitor.visit_expr(then);
|
||||
|
@ -1092,53 +1092,30 @@ impl<'a> State<'a> {
|
||||
}
|
||||
|
||||
fn print_else(&mut self, els: Option<&hir::Expr<'_>>) {
|
||||
match els {
|
||||
Some(else_) => {
|
||||
match else_.kind {
|
||||
// "another else-if"
|
||||
hir::ExprKind::If(ref i, ref then, ref e) => {
|
||||
self.cbox(INDENT_UNIT - 1);
|
||||
self.ibox(0);
|
||||
self.s.word(" else if ");
|
||||
self.print_expr_as_cond(&i);
|
||||
self.s.space();
|
||||
self.print_expr(&then);
|
||||
self.print_else(e.as_ref().map(|e| &**e))
|
||||
}
|
||||
// "final else"
|
||||
hir::ExprKind::Block(ref b, _) => {
|
||||
self.cbox(INDENT_UNIT - 1);
|
||||
self.ibox(0);
|
||||
self.s.word(" else ");
|
||||
self.print_block(&b)
|
||||
}
|
||||
hir::ExprKind::Match(ref expr, arms, _) => {
|
||||
// else if let desugared to match
|
||||
assert!(arms.len() == 2, "if let desugars to match with two arms");
|
||||
|
||||
self.s.word(" else ");
|
||||
self.s.word("{");
|
||||
|
||||
self.cbox(INDENT_UNIT);
|
||||
self.ibox(INDENT_UNIT);
|
||||
self.word_nbsp("match");
|
||||
self.print_expr_as_cond(&expr);
|
||||
self.s.space();
|
||||
self.bopen();
|
||||
for arm in arms {
|
||||
self.print_arm(arm);
|
||||
}
|
||||
self.bclose(expr.span);
|
||||
|
||||
self.s.word("}");
|
||||
}
|
||||
// BLEAH, constraints would be great here
|
||||
_ => {
|
||||
panic!("print_if saw if with weird alternative");
|
||||
}
|
||||
if let Some(els_inner) = els {
|
||||
match els_inner.kind {
|
||||
// Another `else if` block.
|
||||
hir::ExprKind::If(ref i, ref then, ref e) => {
|
||||
self.cbox(INDENT_UNIT - 1);
|
||||
self.ibox(0);
|
||||
self.s.word(" else if ");
|
||||
self.print_expr_as_cond(&i);
|
||||
self.s.space();
|
||||
self.print_expr(&then);
|
||||
self.print_else(e.as_ref().map(|e| &**e))
|
||||
}
|
||||
// Final `else` block.
|
||||
hir::ExprKind::Block(ref b, _) => {
|
||||
self.cbox(INDENT_UNIT - 1);
|
||||
self.ibox(0);
|
||||
self.s.word(" else ");
|
||||
self.print_block(&b)
|
||||
}
|
||||
// Constraints would be great here!
|
||||
_ => {
|
||||
panic!("print_if saw if with weird alternative");
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1165,34 +1142,49 @@ impl<'a> State<'a> {
|
||||
self.pclose()
|
||||
}
|
||||
|
||||
pub fn print_expr_maybe_paren(&mut self, expr: &hir::Expr<'_>, prec: i8) {
|
||||
let needs_par = expr.precedence().order() < prec;
|
||||
fn print_expr_maybe_paren(&mut self, expr: &hir::Expr<'_>, prec: i8) {
|
||||
self.print_expr_cond_paren(expr, expr.precedence().order() < prec)
|
||||
}
|
||||
|
||||
/// Prints 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: &hir::Expr<'_>) {
|
||||
self.print_expr_cond_paren(expr, Self::cond_needs_par(expr))
|
||||
}
|
||||
|
||||
/// Prints `expr` or `(expr)` when `needs_par` holds.
|
||||
fn print_expr_cond_paren(&mut self, expr: &hir::Expr<'_>, needs_par: bool) {
|
||||
if needs_par {
|
||||
self.popen();
|
||||
}
|
||||
self.print_expr(expr);
|
||||
if let hir::ExprKind::DropTemps(ref actual_expr) = expr.kind {
|
||||
self.print_expr(actual_expr);
|
||||
} else {
|
||||
self.print_expr(expr);
|
||||
}
|
||||
if needs_par {
|
||||
self.pclose();
|
||||
}
|
||||
}
|
||||
|
||||
/// 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: &hir::Expr<'_>) {
|
||||
let needs_par = match expr.kind {
|
||||
// These cases need parens due to the parse error observed in #26461: `if return {}`
|
||||
// parses as the erroneous construct `if (return {})`, not `if (return) {}`.
|
||||
hir::ExprKind::Closure(..) | hir::ExprKind::Ret(..) | hir::ExprKind::Break(..) => true,
|
||||
/// Print a `let pat = expr` expression.
|
||||
fn print_let(&mut self, pat: &hir::Pat<'_>, expr: &hir::Expr<'_>) {
|
||||
self.s.word("let ");
|
||||
self.print_pat(pat);
|
||||
self.s.space();
|
||||
self.word_space("=");
|
||||
let npals = || parser::needs_par_as_let_scrutinee(expr.precedence().order());
|
||||
self.print_expr_cond_paren(expr, Self::cond_needs_par(expr) || npals())
|
||||
}
|
||||
|
||||
// Does `expr` need parenthesis when printed in a condition position?
|
||||
//
|
||||
// These cases need parens due to the parse error observed in #26461: `if return {}`
|
||||
// parses as the erroneous construct `if (return {})`, not `if (return) {}`.
|
||||
fn cond_needs_par(expr: &hir::Expr<'_>) -> bool {
|
||||
match expr.kind {
|
||||
hir::ExprKind::Break(..) | hir::ExprKind::Closure(..) | hir::ExprKind::Ret(..) => true,
|
||||
_ => contains_exterior_struct_lit(expr),
|
||||
};
|
||||
|
||||
if needs_par {
|
||||
self.popen();
|
||||
}
|
||||
self.print_expr(expr);
|
||||
if needs_par {
|
||||
self.pclose();
|
||||
}
|
||||
}
|
||||
|
||||
@ -1314,6 +1306,9 @@ impl<'a> State<'a> {
|
||||
(&hir::ExprKind::Cast { .. }, hir::BinOpKind::Lt | hir::BinOpKind::Shl) => {
|
||||
parser::PREC_FORCE_PAREN
|
||||
}
|
||||
(&hir::ExprKind::Let { .. }, _) if !parser::needs_par_as_let_scrutinee(prec) => {
|
||||
parser::PREC_FORCE_PAREN
|
||||
}
|
||||
_ => left_prec,
|
||||
};
|
||||
|
||||
@ -1531,6 +1526,9 @@ impl<'a> State<'a> {
|
||||
// Print `}`:
|
||||
self.bclose_maybe_open(expr.span, true);
|
||||
}
|
||||
hir::ExprKind::Let(ref pat, ref scrutinee, _) => {
|
||||
self.print_let(pat, scrutinee);
|
||||
}
|
||||
hir::ExprKind::If(ref test, ref blk, ref elseopt) => {
|
||||
self.print_if(&test, &blk, elseopt.as_ref().map(|e| &**e));
|
||||
}
|
||||
|
@ -644,17 +644,6 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
|
||||
scrut_span,
|
||||
..
|
||||
}) => match source {
|
||||
hir::MatchSource::IfLetDesugar { .. } => {
|
||||
let msg = "`if let` arms have incompatible types";
|
||||
err.span_label(cause.span, msg);
|
||||
if let Some(ret_sp) = opt_suggest_box_span {
|
||||
self.suggest_boxing_for_return_impl_trait(
|
||||
err,
|
||||
ret_sp,
|
||||
prior_arms.iter().chain(std::iter::once(&arm_span)).map(|s| *s),
|
||||
);
|
||||
}
|
||||
}
|
||||
hir::MatchSource::TryDesugar => {
|
||||
if let Some(ty::error::ExpectedFound { expected, .. }) = exp_found {
|
||||
let scrut_expr = self.tcx.hir().expect_expr(scrut_hir_id);
|
||||
@ -2581,9 +2570,6 @@ impl<'tcx> ObligationCauseExt<'tcx> for ObligationCause<'tcx> {
|
||||
CompareImplTypeObligation { .. } => Error0308("type not compatible with trait"),
|
||||
MatchExpressionArm(box MatchExpressionArmCause { source, .. }) => {
|
||||
Error0308(match source {
|
||||
hir::MatchSource::IfLetDesugar { .. } => {
|
||||
"`if let` arms have incompatible types"
|
||||
}
|
||||
hir::MatchSource::TryDesugar => {
|
||||
"try expression alternatives have incompatible types"
|
||||
}
|
||||
@ -2619,10 +2605,6 @@ impl<'tcx> ObligationCauseExt<'tcx> for ObligationCause<'tcx> {
|
||||
CompareImplMethodObligation { .. } => "method type is compatible with trait",
|
||||
CompareImplTypeObligation { .. } => "associated type is compatible with trait",
|
||||
ExprAssignable => "expression is assignable",
|
||||
MatchExpressionArm(box MatchExpressionArmCause { source, .. }) => match source {
|
||||
hir::MatchSource::IfLetDesugar { .. } => "`if let` arms have compatible types",
|
||||
_ => "`match` arms have compatible types",
|
||||
},
|
||||
IfExpression { .. } => "`if` and `else` have incompatible types",
|
||||
IfExpressionWithNoElse => "`if` missing an `else` returns `()`",
|
||||
MainFunctionType => "`main` function has the correct type",
|
||||
|
@ -614,7 +614,8 @@ trait UnusedDelimLint {
|
||||
let (value, ctx, followed_by_block, left_pos, right_pos) = match e.kind {
|
||||
// Do not lint `unused_braces` in `if let` expressions.
|
||||
If(ref cond, ref block, _)
|
||||
if !matches!(cond.kind, Let(_, _)) || Self::LINT_EXPR_IN_PATTERN_MATCHING_CTX =>
|
||||
if !matches!(cond.kind, Let(_, _, _))
|
||||
|| Self::LINT_EXPR_IN_PATTERN_MATCHING_CTX =>
|
||||
{
|
||||
let left = e.span.lo() + rustc_span::BytePos(2);
|
||||
let right = block.span.lo();
|
||||
@ -623,7 +624,8 @@ trait UnusedDelimLint {
|
||||
|
||||
// Do not lint `unused_braces` in `while let` expressions.
|
||||
While(ref cond, ref block, ..)
|
||||
if !matches!(cond.kind, Let(_, _)) || Self::LINT_EXPR_IN_PATTERN_MATCHING_CTX =>
|
||||
if !matches!(cond.kind, Let(_, _, _))
|
||||
|| Self::LINT_EXPR_IN_PATTERN_MATCHING_CTX =>
|
||||
{
|
||||
let left = e.span.lo() + rustc_span::BytePos(5);
|
||||
let right = block.span.lo();
|
||||
@ -774,7 +776,7 @@ impl UnusedDelimLint for UnusedParens {
|
||||
self.emit_unused_delims_expr(cx, value, ctx, left_pos, right_pos)
|
||||
}
|
||||
}
|
||||
ast::ExprKind::Let(_, ref expr) => {
|
||||
ast::ExprKind::Let(_, ref expr, _) => {
|
||||
self.check_unused_delims_expr(
|
||||
cx,
|
||||
expr,
|
||||
@ -828,7 +830,7 @@ impl UnusedParens {
|
||||
impl EarlyLintPass for UnusedParens {
|
||||
fn check_expr(&mut self, cx: &EarlyContext<'_>, e: &ast::Expr) {
|
||||
match e.kind {
|
||||
ExprKind::Let(ref pat, _) | ExprKind::ForLoop(ref pat, ..) => {
|
||||
ExprKind::Let(ref pat, _, _) | ExprKind::ForLoop(ref pat, ..) => {
|
||||
self.check_unused_parens_pat(cx, pat, false, false);
|
||||
}
|
||||
// We ignore parens in cases like `if (((let Some(0) = Some(1))))` because we already
|
||||
@ -1012,7 +1014,7 @@ impl UnusedDelimLint for UnusedBraces {
|
||||
}
|
||||
}
|
||||
}
|
||||
ast::ExprKind::Let(_, ref expr) => {
|
||||
ast::ExprKind::Let(_, ref expr, _) => {
|
||||
self.check_unused_delims_expr(
|
||||
cx,
|
||||
expr,
|
||||
|
@ -292,6 +292,10 @@ pub enum ExprKind<'tcx> {
|
||||
Loop {
|
||||
body: ExprId,
|
||||
},
|
||||
Let {
|
||||
expr: ExprId,
|
||||
pat: Pat<'tcx>,
|
||||
},
|
||||
/// A `match` expression.
|
||||
Match {
|
||||
scrutinee: ExprId,
|
||||
|
@ -565,6 +565,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||
| ExprKind::If { .. }
|
||||
| ExprKind::Loop { .. }
|
||||
| ExprKind::Block { .. }
|
||||
| ExprKind::Let { .. }
|
||||
| ExprKind::Assign { .. }
|
||||
| ExprKind::AssignOp { .. }
|
||||
| ExprKind::Break { .. }
|
||||
|
@ -284,6 +284,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||
| ExprKind::LogicalOp { .. }
|
||||
| ExprKind::Call { .. }
|
||||
| ExprKind::Field { .. }
|
||||
| ExprKind::Let { .. }
|
||||
| ExprKind::Deref { .. }
|
||||
| ExprKind::Index { .. }
|
||||
| ExprKind::VarRef { .. }
|
||||
|
@ -46,6 +46,7 @@ impl Category {
|
||||
ExprKind::LogicalOp { .. }
|
||||
| ExprKind::Match { .. }
|
||||
| ExprKind::If { .. }
|
||||
| ExprKind::Let { .. }
|
||||
| ExprKind::NeverToAny { .. }
|
||||
| ExprKind::Use { .. }
|
||||
| ExprKind::Adt { .. }
|
||||
|
@ -53,48 +53,66 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||
this.match_expr(destination, expr_span, block, &this.thir[scrutinee], arms)
|
||||
}
|
||||
ExprKind::If { cond, then, else_opt } => {
|
||||
let place = unpack!(
|
||||
block = this.as_temp(
|
||||
block,
|
||||
Some(this.local_scope()),
|
||||
&this.thir[cond],
|
||||
Mutability::Mut
|
||||
)
|
||||
);
|
||||
let operand = Operand::Move(Place::from(place));
|
||||
|
||||
let mut then_block = this.cfg.start_new_block();
|
||||
let mut else_block = this.cfg.start_new_block();
|
||||
let term = TerminatorKind::if_(this.tcx, operand, then_block, else_block);
|
||||
this.cfg.terminate(block, source_info, term);
|
||||
|
||||
unpack!(
|
||||
then_block = this.expr_into_dest(destination, then_block, &this.thir[then])
|
||||
);
|
||||
else_block = if let Some(else_opt) = else_opt {
|
||||
unpack!(this.expr_into_dest(destination, else_block, &this.thir[else_opt]))
|
||||
let local_scope = this.local_scope();
|
||||
let (mut then_blk, mut else_blk) =
|
||||
this.then_else_blocks(block, &this.thir[cond], local_scope, source_info);
|
||||
unpack!(then_blk = this.expr_into_dest(destination, then_blk, &this.thir[then]));
|
||||
else_blk = if let Some(else_opt) = else_opt {
|
||||
unpack!(this.expr_into_dest(destination, else_blk, &this.thir[else_opt]))
|
||||
} else {
|
||||
// Body of the `if` expression without an `else` clause must return `()`, thus
|
||||
// we implicitly generate a `else {}` if it is not specified.
|
||||
let correct_si = this.source_info(expr_span.shrink_to_hi());
|
||||
this.cfg.push_assign_unit(else_block, correct_si, destination, this.tcx);
|
||||
else_block
|
||||
this.cfg.push_assign_unit(else_blk, correct_si, destination, this.tcx);
|
||||
else_blk
|
||||
};
|
||||
|
||||
let join_block = this.cfg.start_new_block();
|
||||
this.cfg.terminate(
|
||||
then_block,
|
||||
then_blk,
|
||||
source_info,
|
||||
TerminatorKind::Goto { target: join_block },
|
||||
);
|
||||
this.cfg.terminate(
|
||||
else_block,
|
||||
else_blk,
|
||||
source_info,
|
||||
TerminatorKind::Goto { target: join_block },
|
||||
);
|
||||
|
||||
join_block.unit()
|
||||
}
|
||||
ExprKind::Let { ref pat, expr } => {
|
||||
let (true_block, false_block) =
|
||||
this.lower_let(block, &this.thir[expr], pat, expr_span);
|
||||
|
||||
let join_block = this.cfg.start_new_block();
|
||||
|
||||
this.cfg.push_assign_constant(
|
||||
true_block,
|
||||
source_info,
|
||||
destination,
|
||||
Constant {
|
||||
span: expr_span,
|
||||
user_ty: None,
|
||||
literal: ty::Const::from_bool(this.tcx, true).into(),
|
||||
},
|
||||
);
|
||||
|
||||
this.cfg.push_assign_constant(
|
||||
false_block,
|
||||
source_info,
|
||||
destination,
|
||||
Constant {
|
||||
span: expr_span,
|
||||
user_ty: None,
|
||||
literal: ty::Const::from_bool(this.tcx, false).into(),
|
||||
},
|
||||
);
|
||||
|
||||
this.cfg.goto(true_block, source_info, join_block);
|
||||
this.cfg.goto(false_block, source_info, join_block);
|
||||
join_block.unit()
|
||||
}
|
||||
ExprKind::NeverToAny { source } => {
|
||||
let source = &this.thir[source];
|
||||
let is_call =
|
||||
|
@ -38,11 +38,11 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||
pub(crate) fn then_else_blocks(
|
||||
&mut self,
|
||||
mut block: BasicBlock,
|
||||
expr: ExprRef<'tcx>,
|
||||
expr: &Expr<'tcx>,
|
||||
scope: region::Scope,
|
||||
source_info: SourceInfo,
|
||||
) -> (BasicBlock, BasicBlock) {
|
||||
let this = self;
|
||||
let expr = this.hir.mirror(expr);
|
||||
let expr_span = expr.span;
|
||||
|
||||
match expr.kind {
|
||||
@ -52,24 +52,23 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||
let else_block = unpack!(
|
||||
then_block = this.in_scope(region_scope, lint_level, |this| {
|
||||
let (then_block, else_block) =
|
||||
this.then_else_blocks(block, value, source_info);
|
||||
this.then_else_blocks(block, &this.thir[value], scope, source_info);
|
||||
then_block.and(else_block)
|
||||
})
|
||||
);
|
||||
(then_block, else_block)
|
||||
}
|
||||
ExprKind::Let { expr, pat } => {
|
||||
// TODO: Use correct span.
|
||||
this.lower_let(block, &expr, &pat, expr_span)
|
||||
ExprKind::Let { expr, ref pat } => {
|
||||
// FIXME: Use correct span.
|
||||
this.lower_let(block, &this.thir[expr], pat, expr_span)
|
||||
}
|
||||
_ => {
|
||||
let local_scope = Some(this.local_scope());
|
||||
let place =
|
||||
unpack!(block = this.as_temp(block, local_scope, expr, Mutability::Mut));
|
||||
let mutability = Mutability::Mut;
|
||||
let place = unpack!(block = this.as_temp(block, Some(scope), expr, mutability));
|
||||
let operand = Operand::Move(Place::from(place));
|
||||
let then_block = this.cfg.start_new_block();
|
||||
let else_block = this.cfg.start_new_block();
|
||||
let term = TerminatorKind::if_(this.hir.tcx(), operand, then_block, else_block);
|
||||
let term = TerminatorKind::if_(this.tcx, operand, then_block, else_block);
|
||||
this.cfg.terminate(block, source_info, term);
|
||||
(then_block, else_block)
|
||||
}
|
||||
@ -1699,6 +1698,46 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||
// Pat binding - used for `let` and function parameters as well.
|
||||
|
||||
impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||
pub fn lower_let(
|
||||
&mut self,
|
||||
mut block: BasicBlock,
|
||||
expr: &Expr<'tcx>,
|
||||
pat: &Pat<'tcx>,
|
||||
span: Span,
|
||||
) -> (BasicBlock, BasicBlock) {
|
||||
let expr_span = expr.span;
|
||||
let expr_place_builder = unpack!(block = self.lower_scrutinee(block, expr, expr_span));
|
||||
let mut guard_candidate = Candidate::new(expr_place_builder.clone(), &pat, false);
|
||||
let wildcard = Pat::wildcard_from_ty(pat.ty);
|
||||
let mut otherwise_candidate = Candidate::new(expr_place_builder.clone(), &wildcard, false);
|
||||
let fake_borrow_temps = self.lower_match_tree(
|
||||
block,
|
||||
pat.span,
|
||||
false,
|
||||
&mut [&mut guard_candidate, &mut otherwise_candidate],
|
||||
);
|
||||
let mut opt_expr_place: Option<(Option<&Place<'tcx>>, Span)> = None;
|
||||
let expr_place: Place<'tcx>;
|
||||
if let Ok(expr_builder) =
|
||||
expr_place_builder.try_upvars_resolved(self.tcx, self.typeck_results)
|
||||
{
|
||||
expr_place = expr_builder.into_place(self.tcx, self.typeck_results);
|
||||
opt_expr_place = Some((Some(&expr_place), expr_span));
|
||||
}
|
||||
self.declare_bindings(None, pat.span.to(span), pat, ArmHasGuard(false), opt_expr_place);
|
||||
let post_guard_block = self.bind_pattern(
|
||||
self.source_info(pat.span),
|
||||
guard_candidate,
|
||||
None,
|
||||
&fake_borrow_temps,
|
||||
expr.span,
|
||||
None,
|
||||
None,
|
||||
);
|
||||
let otherwise_post_guard_block = otherwise_candidate.pre_binding_block.unwrap();
|
||||
(post_guard_block, otherwise_post_guard_block)
|
||||
}
|
||||
|
||||
/// Initializes each of the bindings from the candidate by
|
||||
/// moving/copying/ref'ing the source as appropriate. Tests the guard, if
|
||||
/// any, and then branches to the arm. Returns the block for the case where
|
||||
@ -1852,48 +1891,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||
(e.span, self.test_bool(block, e, source_info))
|
||||
}
|
||||
Guard::IfLet(ref pat, scrutinee) => {
|
||||
let scrutinee = &self.thir[scrutinee];
|
||||
let scrutinee_span = scrutinee.span;
|
||||
let scrutinee_place_builder =
|
||||
unpack!(block = self.lower_scrutinee(block, scrutinee, scrutinee_span));
|
||||
let mut guard_candidate =
|
||||
Candidate::new(scrutinee_place_builder.clone(), &pat, false);
|
||||
let wildcard = Pat::wildcard_from_ty(pat.ty);
|
||||
let mut otherwise_candidate =
|
||||
Candidate::new(scrutinee_place_builder.clone(), &wildcard, false);
|
||||
let fake_borrow_temps = self.lower_match_tree(
|
||||
block,
|
||||
pat.span,
|
||||
false,
|
||||
&mut [&mut guard_candidate, &mut otherwise_candidate],
|
||||
);
|
||||
let mut opt_scrutinee_place: Option<(Option<&Place<'tcx>>, Span)> = None;
|
||||
let scrutinee_place: Place<'tcx>;
|
||||
if let Ok(scrutinee_builder) =
|
||||
scrutinee_place_builder.try_upvars_resolved(self.tcx, self.typeck_results)
|
||||
{
|
||||
scrutinee_place =
|
||||
scrutinee_builder.into_place(self.tcx, self.typeck_results);
|
||||
opt_scrutinee_place = Some((Some(&scrutinee_place), scrutinee_span));
|
||||
}
|
||||
self.declare_bindings(
|
||||
None,
|
||||
pat.span.to(arm_span.unwrap()),
|
||||
pat,
|
||||
ArmHasGuard(false),
|
||||
opt_scrutinee_place,
|
||||
);
|
||||
let post_guard_block = self.bind_pattern(
|
||||
self.source_info(pat.span),
|
||||
guard_candidate,
|
||||
None,
|
||||
&fake_borrow_temps,
|
||||
scrutinee_span,
|
||||
None,
|
||||
None,
|
||||
);
|
||||
let otherwise_post_guard_block = otherwise_candidate.pre_binding_block.unwrap();
|
||||
(scrutinee_span, (post_guard_block, otherwise_post_guard_block))
|
||||
let s = &self.thir[scrutinee];
|
||||
(s.span, self.lower_let(block, s, pat, arm_span.unwrap()))
|
||||
}
|
||||
};
|
||||
let source_info = self.source_info(guard_span);
|
||||
|
@ -325,6 +325,7 @@ impl<'a, 'tcx> Visitor<'a, 'tcx> for UnsafetyVisitor<'a, 'tcx> {
|
||||
| ExprKind::Return { .. }
|
||||
| ExprKind::Yield { .. }
|
||||
| ExprKind::Loop { .. }
|
||||
| ExprKind::Let { .. }
|
||||
| ExprKind::Match { .. }
|
||||
| ExprKind::Box { .. }
|
||||
| ExprKind::If { .. }
|
||||
@ -475,6 +476,14 @@ impl<'a, 'tcx> Visitor<'a, 'tcx> for UnsafetyVisitor<'a, 'tcx> {
|
||||
}
|
||||
}
|
||||
}
|
||||
ExprKind::Let { expr: expr_id, .. } => {
|
||||
let let_expr = &self.thir[expr_id];
|
||||
if let ty::Adt(adt_def, _) = let_expr.ty.kind() {
|
||||
if adt_def.is_union() {
|
||||
self.requires_unsafe(expr.span, AccessToUnionField);
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
visit::walk_expr(self, expr);
|
||||
|
@ -590,6 +590,9 @@ impl<'tcx> Cx<'tcx> {
|
||||
},
|
||||
Err(err) => bug!("invalid loop id for continue: {}", err),
|
||||
},
|
||||
hir::ExprKind::Let(ref pat, ref expr, _) => {
|
||||
ExprKind::Let { expr: self.mirror_expr(expr), pat: self.pattern_from_hir(pat) }
|
||||
}
|
||||
hir::ExprKind::If(cond, then, else_opt) => ExprKind::If {
|
||||
cond: self.mirror_expr(cond),
|
||||
then: self.mirror_expr(then),
|
||||
|
@ -55,9 +55,10 @@ impl<'tcx> Visitor<'tcx> for MatchVisitor<'_, 'tcx> {
|
||||
|
||||
fn visit_expr(&mut self, ex: &'tcx hir::Expr<'tcx>) {
|
||||
intravisit::walk_expr(self, ex);
|
||||
|
||||
if let hir::ExprKind::Match(ref scrut, ref arms, source) = ex.kind {
|
||||
self.check_match(scrut, arms, source);
|
||||
match &ex.kind {
|
||||
hir::ExprKind::Match(scrut, arms, source) => self.check_match(scrut, arms, *source),
|
||||
hir::ExprKind::Let(pat, scrut, span) => self.check_let(pat, scrut, *span),
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
@ -117,6 +118,31 @@ impl<'tcx> MatchVisitor<'_, 'tcx> {
|
||||
check_for_bindings_named_same_as_variants(self, pat);
|
||||
}
|
||||
|
||||
fn let_source(&mut self, pat: &'tcx hir::Pat<'tcx>, _expr: &hir::Expr<'_>) -> LetSource {
|
||||
let hir = self.tcx.hir();
|
||||
let parent = hir.get_parent_node(pat.hir_id);
|
||||
let parent_parent = hir.get_parent_node(parent);
|
||||
let parent_parent_node = hir.get(parent_parent);
|
||||
|
||||
let parent_parent_parent = hir.get_parent_node(parent_parent);
|
||||
let parent_parent_parent_parent = hir.get_parent_node(parent_parent_parent);
|
||||
let parent_parent_parent_parent_node = hir.get(parent_parent_parent_parent);
|
||||
|
||||
if let hir::Node::Expr(hir::Expr {
|
||||
kind: hir::ExprKind::Loop(_, _, hir::LoopSource::While, _),
|
||||
..
|
||||
}) = parent_parent_parent_parent_node
|
||||
{
|
||||
LetSource::WhileLet
|
||||
} else if let hir::Node::Expr(hir::Expr { kind: hir::ExprKind::If { .. }, .. }) =
|
||||
parent_parent_node
|
||||
{
|
||||
LetSource::IfLet
|
||||
} else {
|
||||
LetSource::GenericLet
|
||||
}
|
||||
}
|
||||
|
||||
fn lower_pattern<'p>(
|
||||
&self,
|
||||
cx: &mut MatchCheckCtxt<'p, 'tcx>,
|
||||
@ -144,6 +170,14 @@ impl<'tcx> MatchVisitor<'_, 'tcx> {
|
||||
}
|
||||
}
|
||||
|
||||
fn check_let(&mut self, pat: &'tcx hir::Pat<'tcx>, expr: &hir::Expr<'_>, span: Span) {
|
||||
self.check_patterns(pat);
|
||||
let ls = self.let_source(pat, expr);
|
||||
let mut cx = self.new_cx(expr.hir_id);
|
||||
let tpat = self.lower_pattern(&mut cx, pat, &mut false).0;
|
||||
check_let_reachability(&mut cx, ls, pat.hir_id, &tpat, span);
|
||||
}
|
||||
|
||||
fn check_match(
|
||||
&mut self,
|
||||
scrut: &hir::Expr<'_>,
|
||||
@ -158,7 +192,13 @@ impl<'tcx> MatchVisitor<'_, 'tcx> {
|
||||
if let Some(hir::Guard::IfLet(ref pat, _)) = arm.guard {
|
||||
self.check_patterns(pat);
|
||||
let tpat = self.lower_pattern(&mut cx, pat, &mut false).0;
|
||||
check_if_let_guard(&mut cx, &tpat, pat.hir_id);
|
||||
check_let_reachability(
|
||||
&mut cx,
|
||||
LetSource::IfLetGuard,
|
||||
pat.hir_id,
|
||||
&tpat,
|
||||
tpat.span,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@ -181,8 +221,16 @@ impl<'tcx> MatchVisitor<'_, 'tcx> {
|
||||
let scrut_ty = self.typeck_results.expr_ty_adjusted(scrut);
|
||||
let report = compute_match_usefulness(&cx, &arms, scrut.hir_id, scrut_ty);
|
||||
|
||||
// Report unreachable arms.
|
||||
report_arm_reachability(&cx, &report, source);
|
||||
report_arm_reachability(&cx, &report, |_, arm_span, arm_hir_id, catchall| {
|
||||
match source {
|
||||
hir::MatchSource::ForLoopDesugar | hir::MatchSource::Normal => {
|
||||
unreachable_pattern(cx.tcx, arm_span, arm_hir_id, catchall);
|
||||
}
|
||||
// Unreachable patterns in try and await expressions occur when one of
|
||||
// the arms are an uninhabited type. Which is OK.
|
||||
hir::MatchSource::AwaitDesugar | hir::MatchSource::TryDesugar => {}
|
||||
}
|
||||
});
|
||||
|
||||
// Check if the match is exhaustive.
|
||||
// Note: An empty match isn't the same as an empty matrix for diagnostics purposes,
|
||||
@ -349,89 +397,99 @@ fn unreachable_pattern(tcx: TyCtxt<'_>, span: Span, id: HirId, catchall: Option<
|
||||
});
|
||||
}
|
||||
|
||||
fn irrefutable_let_pattern(tcx: TyCtxt<'_>, span: Span, id: HirId, source: hir::MatchSource) {
|
||||
tcx.struct_span_lint_hir(IRREFUTABLE_LET_PATTERNS, id, span, |lint| match source {
|
||||
hir::MatchSource::IfLetDesugar { .. } => {
|
||||
let mut diag = lint.build("irrefutable `if let` pattern");
|
||||
diag.note("this pattern will always match, so the `if let` is useless");
|
||||
diag.help("consider replacing the `if let` with a `let`");
|
||||
fn irrefutable_let_pattern(id: HirId, ls: LetSource, span: Span, tcx: TyCtxt<'_>) {
|
||||
macro_rules! emit_diag {
|
||||
(
|
||||
$lint:expr,
|
||||
$source_name:expr,
|
||||
$note_sufix:expr,
|
||||
$help_sufix:expr
|
||||
) => {{
|
||||
let mut diag = $lint.build(concat!("irrefutable ", $source_name, " pattern"));
|
||||
diag.note(concat!("this pattern will always match, so the ", $note_sufix));
|
||||
diag.help(concat!("consider ", $help_sufix));
|
||||
diag.emit()
|
||||
}};
|
||||
}
|
||||
|
||||
tcx.struct_span_lint_hir(IRREFUTABLE_LET_PATTERNS, id, span, |lint| match ls {
|
||||
LetSource::GenericLet => {
|
||||
emit_diag!(lint, "`let`", "`let` is useless", "removing `let`");
|
||||
}
|
||||
hir::MatchSource::WhileLetDesugar => {
|
||||
let mut diag = lint.build("irrefutable `while let` pattern");
|
||||
diag.note("this pattern will always match, so the loop will never exit");
|
||||
diag.help("consider instead using a `loop { ... }` with a `let` inside it");
|
||||
diag.emit()
|
||||
LetSource::IfLet => {
|
||||
emit_diag!(
|
||||
lint,
|
||||
"`if let`",
|
||||
"`if let` is useless",
|
||||
"replacing the `if let` with a `let`"
|
||||
);
|
||||
}
|
||||
hir::MatchSource::IfLetGuardDesugar => {
|
||||
let mut diag = lint.build("irrefutable `if let` guard pattern");
|
||||
diag.note("this pattern will always match, so the guard is useless");
|
||||
diag.help("consider removing the guard and adding a `let` inside the match arm");
|
||||
diag.emit()
|
||||
LetSource::IfLetGuard => {
|
||||
emit_diag!(
|
||||
lint,
|
||||
"`if let` guard",
|
||||
"guard is useless",
|
||||
"removing the guard and adding a `let` inside the match arm"
|
||||
);
|
||||
}
|
||||
_ => {
|
||||
bug!(
|
||||
"expected `if let`, `while let`, or `if let` guard HIR match source, found {:?}",
|
||||
source,
|
||||
)
|
||||
LetSource::WhileLet => {
|
||||
emit_diag!(
|
||||
lint,
|
||||
"`while let`",
|
||||
"loop will never exit",
|
||||
"instead using a `loop { ... }` with a `let` inside it"
|
||||
);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
fn check_if_let_guard<'p, 'tcx>(
|
||||
fn check_let_reachability<'p, 'tcx>(
|
||||
cx: &mut MatchCheckCtxt<'p, 'tcx>,
|
||||
pat: &'p super::Pat<'tcx>,
|
||||
ls: LetSource,
|
||||
pat_id: HirId,
|
||||
pat: &'p super::Pat<'tcx>,
|
||||
span: Span,
|
||||
) {
|
||||
let arms = [MatchArm { pat, hir_id: pat_id, has_guard: false }];
|
||||
let report = compute_match_usefulness(&cx, &arms, pat_id, pat.ty);
|
||||
report_arm_reachability(&cx, &report, hir::MatchSource::IfLetGuardDesugar);
|
||||
|
||||
report_arm_reachability(&cx, &report, |arm_index, arm_span, arm_hir_id, _| {
|
||||
match ls {
|
||||
LetSource::IfLet | LetSource::WhileLet => {
|
||||
match arm_index {
|
||||
// The arm with the user-specified pattern.
|
||||
0 => unreachable_pattern(cx.tcx, arm_span, arm_hir_id, None),
|
||||
// The arm with the wildcard pattern.
|
||||
1 => irrefutable_let_pattern(pat_id, ls, arm_span, cx.tcx),
|
||||
_ => bug!(),
|
||||
}
|
||||
}
|
||||
LetSource::IfLetGuard if arm_index == 0 => {
|
||||
unreachable_pattern(cx.tcx, arm_span, arm_hir_id, None);
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
});
|
||||
|
||||
if report.non_exhaustiveness_witnesses.is_empty() {
|
||||
// The match is exhaustive, i.e. the `if let` pattern is irrefutable.
|
||||
irrefutable_let_pattern(cx.tcx, pat.span, pat_id, hir::MatchSource::IfLetGuardDesugar)
|
||||
irrefutable_let_pattern(pat_id, ls, span, cx.tcx);
|
||||
}
|
||||
}
|
||||
|
||||
/// Report unreachable arms, if any.
|
||||
fn report_arm_reachability<'p, 'tcx>(
|
||||
fn report_arm_reachability<'p, 'tcx, F>(
|
||||
cx: &MatchCheckCtxt<'p, 'tcx>,
|
||||
report: &UsefulnessReport<'p, 'tcx>,
|
||||
source: hir::MatchSource,
|
||||
) {
|
||||
unreachable: F,
|
||||
) where
|
||||
F: Fn(usize, Span, HirId, Option<Span>),
|
||||
{
|
||||
use Reachability::*;
|
||||
let mut catchall = None;
|
||||
for (arm_index, (arm, is_useful)) in report.arm_usefulness.iter().enumerate() {
|
||||
match is_useful {
|
||||
Unreachable => {
|
||||
match source {
|
||||
hir::MatchSource::WhileDesugar => bug!(),
|
||||
|
||||
hir::MatchSource::IfLetDesugar { .. } | hir::MatchSource::WhileLetDesugar => {
|
||||
// Check which arm we're on.
|
||||
match arm_index {
|
||||
// The arm with the user-specified pattern.
|
||||
0 => unreachable_pattern(cx.tcx, arm.pat.span, arm.hir_id, None),
|
||||
// The arm with the wildcard pattern.
|
||||
1 => irrefutable_let_pattern(cx.tcx, arm.pat.span, arm.hir_id, source),
|
||||
_ => bug!(),
|
||||
}
|
||||
}
|
||||
|
||||
hir::MatchSource::IfLetGuardDesugar => {
|
||||
assert_eq!(arm_index, 0);
|
||||
unreachable_pattern(cx.tcx, arm.pat.span, arm.hir_id, None);
|
||||
}
|
||||
|
||||
hir::MatchSource::ForLoopDesugar | hir::MatchSource::Normal => {
|
||||
unreachable_pattern(cx.tcx, arm.pat.span, arm.hir_id, catchall);
|
||||
}
|
||||
|
||||
// Unreachable patterns in try and await expressions occur when one of
|
||||
// the arms are an uninhabited type. Which is OK.
|
||||
hir::MatchSource::AwaitDesugar | hir::MatchSource::TryDesugar => {}
|
||||
}
|
||||
}
|
||||
Unreachable => unreachable(arm_index, arm.pat.span, arm.hir_id, catchall),
|
||||
Reachable(unreachables) if unreachables.is_empty() => {}
|
||||
// The arm is reachable, but contains unreachable subpatterns (from or-patterns).
|
||||
Reachable(unreachables) => {
|
||||
@ -723,3 +781,11 @@ fn check_borrow_conflicts_in_at_patterns(cx: &MatchVisitor<'_, '_>, pat: &Pat<'_
|
||||
err.emit();
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
pub enum LetSource {
|
||||
GenericLet,
|
||||
IfLet,
|
||||
IfLetGuard,
|
||||
WhileLet,
|
||||
}
|
||||
|
@ -57,6 +57,9 @@ pub fn walk_expr<'a, 'tcx: 'a, V: Visitor<'a, 'tcx>>(visitor: &mut V, expr: &Exp
|
||||
Use { source } => visitor.visit_expr(&visitor.thir()[source]),
|
||||
NeverToAny { source } => visitor.visit_expr(&visitor.thir()[source]),
|
||||
Pointer { source, cast: _ } => visitor.visit_expr(&visitor.thir()[source]),
|
||||
Let { expr, .. } => {
|
||||
visitor.visit_expr(&visitor.thir()[expr]);
|
||||
}
|
||||
Loop { body } => visitor.visit_expr(&visitor.thir()[body]),
|
||||
Match { scrutinee, ref arms } => {
|
||||
visitor.visit_expr(&visitor.thir()[scrutinee]);
|
||||
|
@ -1867,7 +1867,7 @@ impl<'a> Parser<'a> {
|
||||
})?;
|
||||
let span = lo.to(expr.span);
|
||||
self.sess.gated_spans.gate(sym::let_chains, span);
|
||||
Ok(self.mk_expr(span, ExprKind::Let(pat, expr), attrs))
|
||||
Ok(self.mk_expr(span, ExprKind::Let(pat, expr, span), attrs))
|
||||
}
|
||||
|
||||
/// Parses an `else { ... }` expression (`else` token already eaten).
|
||||
|
@ -48,11 +48,8 @@ impl NonConstExpr {
|
||||
|
||||
Self::Match(TryDesugar) => &[sym::const_try],
|
||||
|
||||
Self::Match(IfLetGuardDesugar) => bug!("`if let` guard outside a `match` expression"),
|
||||
|
||||
// All other expressions are allowed.
|
||||
Self::Loop(Loop | While | WhileLet)
|
||||
| Self::Match(WhileDesugar | WhileLetDesugar | Normal | IfLetDesugar { .. }) => &[],
|
||||
Self::Loop(Loop | While) | Self::Match(Normal) => &[],
|
||||
};
|
||||
|
||||
Some(gates)
|
||||
@ -277,9 +274,7 @@ impl<'tcx> Visitor<'tcx> for CheckConstVisitor<'tcx> {
|
||||
hir::ExprKind::Match(_, _, source) => {
|
||||
let non_const_expr = match source {
|
||||
// These are handled by `ExprKind::Loop` above.
|
||||
hir::MatchSource::WhileDesugar
|
||||
| hir::MatchSource::WhileLetDesugar
|
||||
| hir::MatchSource::ForLoopDesugar => None,
|
||||
hir::MatchSource::ForLoopDesugar => None,
|
||||
|
||||
_ => Some(NonConstExpr::Match(*source)),
|
||||
};
|
||||
|
@ -429,6 +429,11 @@ impl<'tcx> Visitor<'tcx> for IrMaps<'tcx> {
|
||||
intravisit::walk_expr(self, expr);
|
||||
}
|
||||
|
||||
hir::ExprKind::Let(ref pat, ..) => {
|
||||
self.add_from_pat(pat);
|
||||
intravisit::walk_expr(self, expr);
|
||||
}
|
||||
|
||||
// live nodes required for interesting control flow:
|
||||
hir::ExprKind::If(..) | hir::ExprKind::Match(..) | hir::ExprKind::Loop(..) => {
|
||||
self.add_live_node_for_node(expr.hir_id, ExprNode(expr.span));
|
||||
@ -852,6 +857,11 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
|
||||
})
|
||||
}
|
||||
|
||||
hir::ExprKind::Let(ref pat, ref scrutinee, _) => {
|
||||
let succ = self.propagate_through_expr(scrutinee, succ);
|
||||
self.define_bindings_in_pat(pat, succ)
|
||||
}
|
||||
|
||||
// Note that labels have been resolved, so we don't need to look
|
||||
// at the label ident
|
||||
hir::ExprKind::Loop(ref blk, ..) => self.propagate_through_loop(expr, &blk, succ),
|
||||
@ -1303,6 +1313,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Liveness<'a, 'tcx> {
|
||||
|
||||
fn visit_expr(&mut self, ex: &'tcx Expr<'tcx>) {
|
||||
check_expr(self, ex);
|
||||
intravisit::walk_expr(self, ex);
|
||||
}
|
||||
|
||||
fn visit_arm(&mut self, arm: &'tcx hir::Arm<'tcx>) {
|
||||
@ -1358,6 +1369,10 @@ fn check_expr<'tcx>(this: &mut Liveness<'_, 'tcx>, expr: &'tcx Expr<'tcx>) {
|
||||
}
|
||||
}
|
||||
|
||||
hir::ExprKind::Let(ref pat, ..) => {
|
||||
this.check_unused_vars_in_pat(pat, None, |_, _, _, _| {});
|
||||
}
|
||||
|
||||
// no correctness conditions related to liveness
|
||||
hir::ExprKind::Call(..)
|
||||
| hir::ExprKind::MethodCall(..)
|
||||
@ -1388,8 +1403,6 @@ fn check_expr<'tcx>(this: &mut Liveness<'_, 'tcx>, expr: &'tcx Expr<'tcx>) {
|
||||
| hir::ExprKind::Type(..)
|
||||
| hir::ExprKind::Err => {}
|
||||
}
|
||||
|
||||
intravisit::walk_expr(this, expr);
|
||||
}
|
||||
|
||||
impl<'tcx> Liveness<'_, 'tcx> {
|
||||
|
@ -221,6 +221,7 @@ impl<'tcx> CheckInlineAssembly<'tcx> {
|
||||
| ExprKind::Index(..)
|
||||
| ExprKind::Path(..)
|
||||
| ExprKind::AddrOf(..)
|
||||
| ExprKind::Let(..)
|
||||
| ExprKind::Break(..)
|
||||
| ExprKind::Continue(..)
|
||||
| ExprKind::Ret(..)
|
||||
|
@ -2309,7 +2309,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
|
||||
self.resolve_expr(e, Some(&expr));
|
||||
}
|
||||
|
||||
ExprKind::Let(ref pat, ref scrutinee) => {
|
||||
ExprKind::Let(ref pat, ref scrutinee, _) => {
|
||||
self.visit_expr(scrutinee);
|
||||
self.resolve_pattern_top(pat, PatternSource::Let);
|
||||
}
|
||||
|
@ -24,27 +24,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
) -> Ty<'tcx> {
|
||||
let tcx = self.tcx;
|
||||
|
||||
use hir::MatchSource::*;
|
||||
let (source_if, if_no_else, force_scrutinee_bool) = match match_src {
|
||||
IfLetDesugar { contains_else_clause, .. } => (true, !contains_else_clause, false),
|
||||
WhileDesugar => (false, false, true),
|
||||
_ => (false, false, false),
|
||||
};
|
||||
|
||||
// Type check the discriminant and get its type.
|
||||
let scrutinee_ty = if force_scrutinee_bool {
|
||||
// Here we want to ensure:
|
||||
//
|
||||
// 1. That default match bindings are *not* accepted in the condition of an
|
||||
// `if` expression. E.g. given `fn foo() -> &bool;` we reject `if foo() { .. }`.
|
||||
//
|
||||
// 2. By expecting `bool` for `expr` we get nice diagnostics for e.g. `if x = y { .. }`.
|
||||
//
|
||||
// FIXME(60707): Consider removing hack with principled solution.
|
||||
self.check_expr_has_type_or_error(scrut, self.tcx.types.bool, |_| {})
|
||||
} else {
|
||||
self.demand_scrutinee_type(scrut, arms_contain_ref_bindings(arms), arms.is_empty())
|
||||
};
|
||||
let acrb = arms_contain_ref_bindings(arms);
|
||||
let scrutinee_ty = self.demand_scrutinee_type(scrut, acrb, arms.is_empty());
|
||||
|
||||
// If there are no arms, that is a diverging match; a special case.
|
||||
if arms.is_empty() {
|
||||
@ -52,7 +33,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
return tcx.types.never;
|
||||
}
|
||||
|
||||
self.warn_arms_when_scrutinee_diverges(arms, match_src);
|
||||
self.warn_arms_when_scrutinee_diverges(arms);
|
||||
|
||||
// Otherwise, we have to union together the types that the arms produce and so forth.
|
||||
let scrut_diverges = self.diverges.replace(Diverges::Maybe);
|
||||
@ -112,128 +93,95 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
}
|
||||
|
||||
self.diverges.set(Diverges::Maybe);
|
||||
let arm_ty = if source_if
|
||||
&& if_no_else
|
||||
&& i != 0
|
||||
&& self.if_fallback_coercion(
|
||||
expr.span,
|
||||
&arms[0].body,
|
||||
&mut coercion,
|
||||
|hir_id, span| self.coercion_reason_match(hir_id, span),
|
||||
) {
|
||||
tcx.ty_error()
|
||||
} else {
|
||||
// Only call this if this is not an `if` expr with an expected type and no `else`
|
||||
// clause to avoid duplicated type errors. (#60254)
|
||||
self.check_expr_with_expectation(&arm.body, expected)
|
||||
};
|
||||
|
||||
let arm_ty = self.check_expr_with_expectation(&arm.body, expected);
|
||||
all_arms_diverge &= self.diverges.get();
|
||||
|
||||
let opt_suggest_box_span =
|
||||
self.opt_suggest_box_span(arm.body.span, arm_ty, orig_expected);
|
||||
|
||||
if source_if {
|
||||
let then_expr = &arms[0].body;
|
||||
match (i, if_no_else) {
|
||||
(0, _) => coercion.coerce(self, &self.misc(expr.span), &arm.body, arm_ty),
|
||||
(_, true) => {} // Handled above to avoid duplicated type errors (#60254).
|
||||
(_, _) => {
|
||||
let then_ty = prior_arm_ty.unwrap();
|
||||
let cause = self.if_cause(
|
||||
expr.span,
|
||||
then_expr,
|
||||
&arm.body,
|
||||
then_ty,
|
||||
arm_ty,
|
||||
opt_suggest_box_span,
|
||||
);
|
||||
coercion.coerce(self, &cause, &arm.body, arm_ty);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
let (arm_span, semi_span) =
|
||||
self.get_appropriate_arm_semicolon_removal_span(&arms, i, prior_arm_ty, arm_ty);
|
||||
let (span, code) = match i {
|
||||
// The reason for the first arm to fail is not that the match arms diverge,
|
||||
// but rather that there's a prior obligation that doesn't hold.
|
||||
0 => (arm_span, ObligationCauseCode::BlockTailExpression(arm.body.hir_id)),
|
||||
_ => (
|
||||
expr.span,
|
||||
ObligationCauseCode::MatchExpressionArm(box MatchExpressionArmCause {
|
||||
arm_span,
|
||||
scrut_span: scrut.span,
|
||||
semi_span,
|
||||
source: match_src,
|
||||
prior_arms: other_arms.clone(),
|
||||
last_ty: prior_arm_ty.unwrap(),
|
||||
scrut_hir_id: scrut.hir_id,
|
||||
opt_suggest_box_span,
|
||||
}),
|
||||
),
|
||||
};
|
||||
let cause = self.cause(span, code);
|
||||
|
||||
// This is the moral equivalent of `coercion.coerce(self, cause, arm.body, arm_ty)`.
|
||||
// We use it this way to be able to expand on the potential error and detect when a
|
||||
// `match` tail statement could be a tail expression instead. If so, we suggest
|
||||
// removing the stray semicolon.
|
||||
coercion.coerce_inner(
|
||||
self,
|
||||
&cause,
|
||||
Some(&arm.body),
|
||||
arm_ty,
|
||||
Some(&mut |err: &mut DiagnosticBuilder<'_>| {
|
||||
let can_coerce_to_return_ty = match self.ret_coercion.as_ref() {
|
||||
Some(ret_coercion) if self.in_tail_expr => {
|
||||
let ret_ty = ret_coercion.borrow().expected_ty();
|
||||
let ret_ty = self.inh.infcx.shallow_resolve(ret_ty);
|
||||
self.can_coerce(arm_ty, ret_ty)
|
||||
&& prior_arm_ty.map_or(true, |t| self.can_coerce(t, ret_ty))
|
||||
// The match arms need to unify for the case of `impl Trait`.
|
||||
&& !matches!(ret_ty.kind(), ty::Opaque(..))
|
||||
}
|
||||
_ => false,
|
||||
};
|
||||
if let (Expectation::IsLast(stmt), Some(ret), true) =
|
||||
(orig_expected, self.ret_type_span, can_coerce_to_return_ty)
|
||||
{
|
||||
let semi_span = expr.span.shrink_to_hi().with_hi(stmt.hi());
|
||||
let mut ret_span: MultiSpan = semi_span.into();
|
||||
ret_span.push_span_label(
|
||||
expr.span,
|
||||
"this could be implicitly returned but it is a statement, not a \
|
||||
tail expression"
|
||||
.to_owned(),
|
||||
);
|
||||
ret_span.push_span_label(
|
||||
ret,
|
||||
"the `match` arms can conform to this return type".to_owned(),
|
||||
);
|
||||
ret_span.push_span_label(
|
||||
semi_span,
|
||||
"the `match` is a statement because of this semicolon, consider \
|
||||
removing it"
|
||||
.to_owned(),
|
||||
);
|
||||
err.span_note(
|
||||
ret_span,
|
||||
"you might have meant to return the `match` expression",
|
||||
);
|
||||
err.tool_only_span_suggestion(
|
||||
semi_span,
|
||||
"remove this semicolon",
|
||||
String::new(),
|
||||
Applicability::MaybeIncorrect,
|
||||
);
|
||||
}
|
||||
let (arm_span, semi_span) =
|
||||
self.get_appropriate_arm_semicolon_removal_span(&arms, i, prior_arm_ty, arm_ty);
|
||||
let (span, code) = match i {
|
||||
// The reason for the first arm to fail is not that the match arms diverge,
|
||||
// but rather that there's a prior obligation that doesn't hold.
|
||||
0 => (arm_span, ObligationCauseCode::BlockTailExpression(arm.body.hir_id)),
|
||||
_ => (
|
||||
expr.span,
|
||||
ObligationCauseCode::MatchExpressionArm(box MatchExpressionArmCause {
|
||||
arm_span,
|
||||
scrut_span: scrut.span,
|
||||
semi_span,
|
||||
source: match_src,
|
||||
prior_arms: other_arms.clone(),
|
||||
last_ty: prior_arm_ty.unwrap(),
|
||||
scrut_hir_id: scrut.hir_id,
|
||||
opt_suggest_box_span,
|
||||
}),
|
||||
false,
|
||||
);
|
||||
),
|
||||
};
|
||||
let cause = self.cause(span, code);
|
||||
|
||||
other_arms.push(arm_span);
|
||||
if other_arms.len() > 5 {
|
||||
other_arms.remove(0);
|
||||
}
|
||||
// This is the moral equivalent of `coercion.coerce(self, cause, arm.body, arm_ty)`.
|
||||
// We use it this way to be able to expand on the potential error and detect when a
|
||||
// `match` tail statement could be a tail expression instead. If so, we suggest
|
||||
// removing the stray semicolon.
|
||||
coercion.coerce_inner(
|
||||
self,
|
||||
&cause,
|
||||
Some(&arm.body),
|
||||
arm_ty,
|
||||
Some(&mut |err: &mut DiagnosticBuilder<'_>| {
|
||||
let can_coerce_to_return_ty = match self.ret_coercion.as_ref() {
|
||||
Some(ret_coercion) if self.in_tail_expr => {
|
||||
let ret_ty = ret_coercion.borrow().expected_ty();
|
||||
let ret_ty = self.inh.infcx.shallow_resolve(ret_ty);
|
||||
self.can_coerce(arm_ty, ret_ty)
|
||||
&& prior_arm_ty.map_or(true, |t| self.can_coerce(t, ret_ty))
|
||||
// The match arms need to unify for the case of `impl Trait`.
|
||||
&& !matches!(ret_ty.kind(), ty::Opaque(..))
|
||||
}
|
||||
_ => false,
|
||||
};
|
||||
if let (Expectation::IsLast(stmt), Some(ret), true) =
|
||||
(orig_expected, self.ret_type_span, can_coerce_to_return_ty)
|
||||
{
|
||||
let semi_span = expr.span.shrink_to_hi().with_hi(stmt.hi());
|
||||
let mut ret_span: MultiSpan = semi_span.into();
|
||||
ret_span.push_span_label(
|
||||
expr.span,
|
||||
"this could be implicitly returned but it is a statement, not a \
|
||||
tail expression"
|
||||
.to_owned(),
|
||||
);
|
||||
ret_span.push_span_label(
|
||||
ret,
|
||||
"the `match` arms can conform to this return type".to_owned(),
|
||||
);
|
||||
ret_span.push_span_label(
|
||||
semi_span,
|
||||
"the `match` is a statement because of this semicolon, consider \
|
||||
removing it"
|
||||
.to_owned(),
|
||||
);
|
||||
err.span_note(
|
||||
ret_span,
|
||||
"you might have meant to return the `match` expression",
|
||||
);
|
||||
err.tool_only_span_suggestion(
|
||||
semi_span,
|
||||
"remove this semicolon",
|
||||
String::new(),
|
||||
Applicability::MaybeIncorrect,
|
||||
);
|
||||
}
|
||||
}),
|
||||
false,
|
||||
);
|
||||
|
||||
other_arms.push(arm_span);
|
||||
if other_arms.len() > 5 {
|
||||
other_arms.remove(0);
|
||||
}
|
||||
prior_arm_ty = Some(arm_ty);
|
||||
}
|
||||
@ -283,39 +231,27 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
|
||||
/// When the previously checked expression (the scrutinee) diverges,
|
||||
/// warn the user about the match arms being unreachable.
|
||||
fn warn_arms_when_scrutinee_diverges(
|
||||
&self,
|
||||
arms: &'tcx [hir::Arm<'tcx>],
|
||||
source: hir::MatchSource,
|
||||
) {
|
||||
use hir::MatchSource::*;
|
||||
let msg = match source {
|
||||
IfLetDesugar { .. } => "block in `if` expression",
|
||||
WhileDesugar { .. } | WhileLetDesugar { .. } => "block in `while` expression",
|
||||
_ => "arm",
|
||||
};
|
||||
fn warn_arms_when_scrutinee_diverges(&self, arms: &'tcx [hir::Arm<'tcx>]) {
|
||||
for arm in arms {
|
||||
self.warn_if_unreachable(arm.body.hir_id, arm.body.span, msg);
|
||||
self.warn_if_unreachable(arm.body.hir_id, arm.body.span, "arm");
|
||||
}
|
||||
}
|
||||
|
||||
/// Handle the fallback arm of a desugared if(-let) like a missing else.
|
||||
///
|
||||
/// Returns `true` if there was an error forcing the coercion to the `()` type.
|
||||
pub(crate) fn if_fallback_coercion<F, T>(
|
||||
pub(super) fn if_fallback_coercion<T>(
|
||||
&self,
|
||||
span: Span,
|
||||
then_expr: &'tcx hir::Expr<'tcx>,
|
||||
coercion: &mut CoerceMany<'tcx, '_, T>,
|
||||
ret_reason: F,
|
||||
) -> bool
|
||||
where
|
||||
F: Fn(hir::HirId, Span) -> Option<(Span, String)>,
|
||||
T: AsCoercionSite,
|
||||
{
|
||||
// If this `if` expr is the parent's function return expr,
|
||||
// the cause of the type coercion is the return type, point at it. (#25228)
|
||||
let ret_reason = ret_reason(then_expr.hir_id, span);
|
||||
let ret_reason = self.maybe_get_coercion_reason(then_expr.hir_id, span);
|
||||
let cause = self.cause(span, ObligationCauseCode::IfExpressionWithNoElse);
|
||||
let mut error = false;
|
||||
coercion.coerce_forced_unit(
|
||||
@ -338,55 +274,34 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
error
|
||||
}
|
||||
|
||||
pub(crate) fn coercion_reason_if(
|
||||
&self,
|
||||
hir_id: hir::HirId,
|
||||
span: Span,
|
||||
) -> Option<(Span, String)> {
|
||||
self.coercion_reason_inner(hir_id, span, 1)
|
||||
}
|
||||
|
||||
pub(crate) fn coercion_reason_match(
|
||||
&self,
|
||||
hir_id: hir::HirId,
|
||||
span: Span,
|
||||
) -> Option<(Span, String)> {
|
||||
self.coercion_reason_inner(hir_id, span, 2)
|
||||
}
|
||||
|
||||
fn coercion_reason_inner(
|
||||
&self,
|
||||
hir_id: hir::HirId,
|
||||
span: Span,
|
||||
parent_index: usize,
|
||||
) -> Option<(Span, String)> {
|
||||
let hir = self.tcx.hir();
|
||||
let mut parent_iter = hir.parent_iter(hir_id);
|
||||
let (_, node) = parent_iter.nth(parent_index)?;
|
||||
match node {
|
||||
hir::Node::Block(block) => {
|
||||
let expr = block.expr?;
|
||||
// check that the body's parent is an fn
|
||||
let (_, parent) = parent_iter.nth(1)?;
|
||||
if let hir::Node::Item(hir::Item { kind: hir::ItemKind::Fn(..), .. }) = parent {
|
||||
// check that the `if` expr without `else` is the fn body's expr
|
||||
if expr.span == span {
|
||||
let (fn_decl, _) = self.get_fn_decl(hir_id)?;
|
||||
fn maybe_get_coercion_reason(&self, hir_id: hir::HirId, sp: Span) -> Option<(Span, String)> {
|
||||
let node = {
|
||||
let rslt = self.tcx.hir().get_parent_node(self.tcx.hir().get_parent_node(hir_id));
|
||||
self.tcx.hir().get(rslt)
|
||||
};
|
||||
if let hir::Node::Block(block) = node {
|
||||
// check that the body's parent is an fn
|
||||
let parent = self
|
||||
.tcx
|
||||
.hir()
|
||||
.get(self.tcx.hir().get_parent_node(self.tcx.hir().get_parent_node(block.hir_id)));
|
||||
if let (Some(expr), hir::Node::Item(hir::Item { kind: hir::ItemKind::Fn(..), .. })) =
|
||||
(&block.expr, parent)
|
||||
{
|
||||
// check that the `if` expr without `else` is the fn body's expr
|
||||
if expr.span == sp {
|
||||
return self.get_fn_decl(hir_id).and_then(|(fn_decl, _)| {
|
||||
let span = fn_decl.output.span();
|
||||
let snippet = self.tcx.sess.source_map().span_to_snippet(span).ok()?;
|
||||
return Some((
|
||||
span,
|
||||
format!("expected `{}` because of this return type", snippet),
|
||||
));
|
||||
}
|
||||
Some((span, format!("expected `{}` because of this return type", snippet)))
|
||||
});
|
||||
}
|
||||
None
|
||||
}
|
||||
hir::Node::Local(hir::Local { ty: Some(_), pat, .. }) => {
|
||||
Some((pat.span, "expected because of this assignment".to_string()))
|
||||
}
|
||||
_ => None,
|
||||
}
|
||||
if let hir::Node::Local(hir::Local { ty: Some(_), pat, .. }) = node {
|
||||
return Some((pat.span, "expected because of this assignment".to_string()));
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
pub(crate) fn if_cause(
|
||||
@ -492,7 +407,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
)
|
||||
}
|
||||
|
||||
fn demand_scrutinee_type(
|
||||
pub(super) fn demand_scrutinee_type(
|
||||
&self,
|
||||
scrut: &'tcx hir::Expr<'tcx>,
|
||||
contains_ref_bindings: Option<hir::Mutability>,
|
||||
|
@ -187,7 +187,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
|
||||
// Warn for non-block expressions with diverging children.
|
||||
match expr.kind {
|
||||
ExprKind::Block(..) | ExprKind::If(..) | ExprKind::Loop(..) | ExprKind::Match(..) => {}
|
||||
ExprKind::Block(..)
|
||||
| ExprKind::If(..)
|
||||
| ExprKind::Let(..)
|
||||
| ExprKind::Loop(..)
|
||||
| ExprKind::Match(..) => {}
|
||||
// If `expr` is a result of desugaring the try block and is an ok-wrapped
|
||||
// diverging expression (e.g. it arose from desugaring of `try { return }`),
|
||||
// we skip issuing a warning because it is autogenerated code.
|
||||
@ -262,6 +266,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
}
|
||||
}
|
||||
ExprKind::Ret(ref expr_opt) => self.check_expr_return(expr_opt.as_deref(), expr),
|
||||
ExprKind::Let(pat, let_expr, _) => self.check_expr_let(let_expr, pat),
|
||||
ExprKind::Loop(body, _, source, _) => {
|
||||
self.check_expr_loop(body, source, expected, expr)
|
||||
}
|
||||
@ -802,7 +807,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
) -> Ty<'tcx> {
|
||||
let cond_ty = self.check_expr_has_type_or_error(cond_expr, self.tcx.types.bool, |_| {});
|
||||
|
||||
self.warn_if_unreachable(cond_expr.hir_id, then_expr.span, "block in `if` expression");
|
||||
self.warn_if_unreachable(
|
||||
cond_expr.hir_id,
|
||||
then_expr.span,
|
||||
"block in `if` or `while` expression",
|
||||
);
|
||||
|
||||
let cond_diverges = self.diverges.get();
|
||||
self.diverges.set(Diverges::Maybe);
|
||||
@ -837,9 +846,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
// We won't diverge unless both branches do (or the condition does).
|
||||
self.diverges.set(cond_diverges | then_diverges & else_diverges);
|
||||
} else {
|
||||
self.if_fallback_coercion(sp, then_expr, &mut coerce, |hir_id, span| {
|
||||
self.coercion_reason_if(hir_id, span)
|
||||
});
|
||||
self.if_fallback_coercion(sp, then_expr, &mut coerce);
|
||||
|
||||
// If the condition is false we can't diverge.
|
||||
self.diverges.set(cond_diverges);
|
||||
@ -875,26 +882,16 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
};
|
||||
if !lhs.is_syntactic_place_expr() {
|
||||
// Do not suggest `if let x = y` as `==` is way more likely to be the intention.
|
||||
let mut span_err = || {
|
||||
// Likely `if let` intended.
|
||||
let hir = self.tcx.hir();
|
||||
if let hir::Node::Expr(hir::Expr { kind: ExprKind::If { .. }, .. }) =
|
||||
hir.get(hir.get_parent_node(hir.get_parent_node(expr.hir_id)))
|
||||
{
|
||||
err.span_suggestion_verbose(
|
||||
expr.span.shrink_to_lo(),
|
||||
"you might have meant to use pattern matching",
|
||||
"let ".to_string(),
|
||||
applicability,
|
||||
);
|
||||
};
|
||||
if let hir::Node::Expr(hir::Expr {
|
||||
kind: ExprKind::Match(_, _, hir::MatchSource::WhileDesugar),
|
||||
..
|
||||
}) = self.tcx.hir().get(
|
||||
self.tcx.hir().get_parent_node(self.tcx.hir().get_parent_node(expr.hir_id)),
|
||||
) {
|
||||
span_err();
|
||||
} else if let hir::Node::Expr(hir::Expr { kind: ExprKind::If { .. }, .. }) =
|
||||
self.tcx.hir().get(self.tcx.hir().get_parent_node(expr.hir_id))
|
||||
{
|
||||
span_err();
|
||||
}
|
||||
}
|
||||
if eq {
|
||||
@ -929,6 +926,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
}
|
||||
}
|
||||
|
||||
fn check_expr_let(&self, expr: &'tcx hir::Expr<'tcx>, pat: &'tcx hir::Pat<'tcx>) -> Ty<'tcx> {
|
||||
self.warn_if_unreachable(expr.hir_id, expr.span, "block in `let` expression");
|
||||
let expr_ty = self.demand_scrutinee_type(expr, pat.contains_explicit_ref_binding(), false);
|
||||
self.check_pat_top(pat, expr_ty, Some(expr.span), true);
|
||||
self.tcx.types.bool
|
||||
}
|
||||
|
||||
fn check_expr_loop(
|
||||
&self,
|
||||
body: &'tcx hir::Block<'tcx>,
|
||||
@ -943,7 +947,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
Some(CoerceMany::new(coerce_to))
|
||||
}
|
||||
|
||||
hir::LoopSource::While | hir::LoopSource::WhileLet | hir::LoopSource::ForLoop => None,
|
||||
hir::LoopSource::While | hir::LoopSource::ForLoop => None,
|
||||
};
|
||||
|
||||
let ctxt = BreakableCtxt {
|
||||
|
@ -229,6 +229,10 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> {
|
||||
}
|
||||
}
|
||||
|
||||
hir::ExprKind::Let(ref pat, ref expr, _) => {
|
||||
self.walk_local(expr, pat, |t| t.borrow_expr(&expr, ty::ImmBorrow));
|
||||
}
|
||||
|
||||
hir::ExprKind::Match(ref discr, arms, _) => {
|
||||
let discr_place = return_if_err!(self.mc.cat_expr(&discr));
|
||||
|
||||
@ -428,10 +432,12 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> {
|
||||
|
||||
fn walk_stmt(&mut self, stmt: &hir::Stmt<'_>) {
|
||||
match stmt.kind {
|
||||
hir::StmtKind::Local(ref local) => {
|
||||
self.walk_local(&local);
|
||||
hir::StmtKind::Local(hir::Local { pat, init: Some(ref expr), .. }) => {
|
||||
self.walk_local(expr, pat, |_| {});
|
||||
}
|
||||
|
||||
hir::StmtKind::Local(_) => {}
|
||||
|
||||
hir::StmtKind::Item(_) => {
|
||||
// We don't visit nested items in this visitor,
|
||||
// only the fn body we were given.
|
||||
@ -443,16 +449,14 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> {
|
||||
}
|
||||
}
|
||||
|
||||
fn walk_local(&mut self, local: &hir::Local<'_>) {
|
||||
if let Some(ref expr) = local.init {
|
||||
// Variable declarations with
|
||||
// initializers are considered
|
||||
// "assigns", which is handled by
|
||||
// `walk_pat`:
|
||||
self.walk_expr(&expr);
|
||||
let init_place = return_if_err!(self.mc.cat_expr(&expr));
|
||||
self.walk_irrefutable_pat(&init_place, &local.pat);
|
||||
}
|
||||
fn walk_local<F>(&mut self, expr: &hir::Expr<'_>, pat: &hir::Pat<'_>, mut f: F)
|
||||
where
|
||||
F: FnMut(&mut Self),
|
||||
{
|
||||
self.walk_expr(&expr);
|
||||
let expr_place = return_if_err!(self.mc.cat_expr(&expr));
|
||||
f(self);
|
||||
self.walk_irrefutable_pat(&expr_place, &pat);
|
||||
}
|
||||
|
||||
/// Indicates that the value of `blk` will be consumed, meaning either copied or moved
|
||||
|
@ -368,6 +368,7 @@ impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx> {
|
||||
| hir::ExprKind::Tup(..)
|
||||
| hir::ExprKind::Binary(..)
|
||||
| hir::ExprKind::Block(..)
|
||||
| hir::ExprKind::Let(..)
|
||||
| hir::ExprKind::Loop(..)
|
||||
| hir::ExprKind::Match(..)
|
||||
| hir::ExprKind::Lit(..)
|
||||
|
@ -191,7 +191,7 @@ pub fn add_else_branch_if_let(x: Option<u32>) -> u32 {
|
||||
}
|
||||
|
||||
#[cfg(not(cfail1))]
|
||||
#[rustc_clean(cfg="cfail2", except="hir_owner_nodes")]
|
||||
#[rustc_clean(cfg="cfail2", except="hir_owner_nodes,typeck")]
|
||||
#[rustc_clean(cfg="cfail3")]
|
||||
pub fn add_else_branch_if_let(x: Option<u32>) -> u32 {
|
||||
let mut ret = 1;
|
||||
|
@ -141,7 +141,7 @@ pub fn change_break_label() {
|
||||
}
|
||||
|
||||
#[cfg(not(cfail1))]
|
||||
#[rustc_clean(cfg="cfail2", except="hir_owner_nodes")]
|
||||
#[rustc_clean(cfg="cfail2", except="hir_owner_nodes,typeck")]
|
||||
#[rustc_clean(cfg="cfail3")]
|
||||
pub fn change_break_label() {
|
||||
let mut _x = 0;
|
||||
@ -153,8 +153,6 @@ pub fn change_break_label() {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Add loop label to continue
|
||||
#[cfg(cfail1)]
|
||||
pub fn add_loop_label_to_continue() {
|
||||
@ -191,7 +189,7 @@ pub fn change_continue_label() {
|
||||
}
|
||||
|
||||
#[cfg(not(cfail1))]
|
||||
#[rustc_clean(cfg="cfail2", except="hir_owner_nodes")]
|
||||
#[rustc_clean(cfg="cfail2", except="hir_owner_nodes,typeck")]
|
||||
#[rustc_clean(cfg="cfail3")]
|
||||
pub fn change_continue_label() {
|
||||
let mut _x = 0;
|
||||
|
@ -141,7 +141,7 @@ pub fn change_break_label() {
|
||||
}
|
||||
|
||||
#[cfg(not(cfail1))]
|
||||
#[rustc_clean(cfg="cfail2", except="hir_owner_nodes, optimized_mir")]
|
||||
#[rustc_clean(cfg="cfail2", except="hir_owner_nodes,optimized_mir,typeck")]
|
||||
#[rustc_clean(cfg="cfail3")]
|
||||
pub fn change_break_label() {
|
||||
let mut _x = 0;
|
||||
@ -191,7 +191,7 @@ pub fn change_continue_label() {
|
||||
}
|
||||
|
||||
#[cfg(not(cfail1))]
|
||||
#[rustc_clean(cfg="cfail2", except="hir_owner_nodes")]
|
||||
#[rustc_clean(cfg="cfail2", except="hir_owner_nodes,typeck")]
|
||||
#[rustc_clean(cfg="cfail3")]
|
||||
pub fn change_continue_label() {
|
||||
let mut _x = 0;
|
||||
|
@ -94,35 +94,34 @@
|
||||
bb7: {
|
||||
StorageLive(_10); // scope 2 at $DIR/funky_arms.rs:24:17: 24:26
|
||||
_10 = ((_7 as Some).0: usize); // scope 2 at $DIR/funky_arms.rs:24:17: 24:26
|
||||
StorageLive(_11); // scope 3 at $DIR/funky_arms.rs:26:43: 26:46
|
||||
_11 = &mut (*_1); // scope 3 at $DIR/funky_arms.rs:26:43: 26:46
|
||||
StorageLive(_12); // scope 3 at $DIR/funky_arms.rs:26:48: 26:51
|
||||
_12 = _2; // scope 3 at $DIR/funky_arms.rs:26:48: 26:51
|
||||
StorageLive(_13); // scope 3 at $DIR/funky_arms.rs:26:53: 26:57
|
||||
_13 = _6; // scope 3 at $DIR/funky_arms.rs:26:53: 26:57
|
||||
StorageLive(_14); // scope 3 at $DIR/funky_arms.rs:26:59: 26:79
|
||||
StorageLive(_15); // scope 3 at $DIR/funky_arms.rs:26:59: 26:75
|
||||
StorageLive(_16); // scope 3 at $DIR/funky_arms.rs:26:59: 26:68
|
||||
_16 = _10; // scope 3 at $DIR/funky_arms.rs:26:59: 26:68
|
||||
_15 = move _16 as u32 (Misc); // scope 3 at $DIR/funky_arms.rs:26:59: 26:75
|
||||
StorageDead(_16); // scope 3 at $DIR/funky_arms.rs:26:74: 26:75
|
||||
_14 = Add(move _15, const 1_u32); // scope 3 at $DIR/funky_arms.rs:26:59: 26:79
|
||||
StorageDead(_15); // scope 3 at $DIR/funky_arms.rs:26:78: 26:79
|
||||
StorageLive(_17); // scope 3 at $DIR/funky_arms.rs:26:81: 26:86
|
||||
_17 = _3; // scope 3 at $DIR/funky_arms.rs:26:81: 26:86
|
||||
_0 = float_to_exponential_common_exact::<T>(move _11, move _12, move _13, move _14, move _17) -> bb8; // scope 3 at $DIR/funky_arms.rs:26:9: 26:87
|
||||
StorageLive(_11); // scope 2 at $DIR/funky_arms.rs:26:43: 26:46
|
||||
_11 = &mut (*_1); // scope 2 at $DIR/funky_arms.rs:26:43: 26:46
|
||||
StorageLive(_12); // scope 2 at $DIR/funky_arms.rs:26:48: 26:51
|
||||
_12 = _2; // scope 2 at $DIR/funky_arms.rs:26:48: 26:51
|
||||
StorageLive(_13); // scope 2 at $DIR/funky_arms.rs:26:53: 26:57
|
||||
_13 = _6; // scope 2 at $DIR/funky_arms.rs:26:53: 26:57
|
||||
StorageLive(_14); // scope 2 at $DIR/funky_arms.rs:26:59: 26:79
|
||||
StorageLive(_15); // scope 2 at $DIR/funky_arms.rs:26:59: 26:75
|
||||
StorageLive(_16); // scope 2 at $DIR/funky_arms.rs:26:59: 26:68
|
||||
_16 = _10; // scope 2 at $DIR/funky_arms.rs:26:59: 26:68
|
||||
_15 = move _16 as u32 (Misc); // scope 2 at $DIR/funky_arms.rs:26:59: 26:75
|
||||
StorageDead(_16); // scope 2 at $DIR/funky_arms.rs:26:74: 26:75
|
||||
_14 = Add(move _15, const 1_u32); // scope 2 at $DIR/funky_arms.rs:26:59: 26:79
|
||||
StorageDead(_15); // scope 2 at $DIR/funky_arms.rs:26:78: 26:79
|
||||
StorageLive(_17); // scope 2 at $DIR/funky_arms.rs:26:81: 26:86
|
||||
_17 = _3; // scope 2 at $DIR/funky_arms.rs:26:81: 26:86
|
||||
_0 = float_to_exponential_common_exact::<T>(move _11, move _12, move _13, move _14, move _17) -> bb8; // scope 2 at $DIR/funky_arms.rs:26:9: 26:87
|
||||
// mir::Constant
|
||||
// + span: $DIR/funky_arms.rs:26:9: 26:42
|
||||
// + literal: Const { ty: for<'r, 's, 't0> fn(&'r mut std::fmt::Formatter<'s>, &'t0 T, core::num::flt2dec::Sign, u32, bool) -> std::result::Result<(), std::fmt::Error> {float_to_exponential_common_exact::<T>}, val: Value(Scalar(<ZST>)) }
|
||||
}
|
||||
|
||||
bb8: {
|
||||
StorageDead(_17); // scope 3 at $DIR/funky_arms.rs:26:86: 26:87
|
||||
StorageDead(_14); // scope 3 at $DIR/funky_arms.rs:26:86: 26:87
|
||||
StorageDead(_13); // scope 3 at $DIR/funky_arms.rs:26:86: 26:87
|
||||
StorageDead(_12); // scope 3 at $DIR/funky_arms.rs:26:86: 26:87
|
||||
StorageDead(_11); // scope 3 at $DIR/funky_arms.rs:26:86: 26:87
|
||||
StorageDead(_10); // scope 2 at $DIR/funky_arms.rs:27:5: 27:6
|
||||
StorageDead(_17); // scope 2 at $DIR/funky_arms.rs:26:86: 26:87
|
||||
StorageDead(_14); // scope 2 at $DIR/funky_arms.rs:26:86: 26:87
|
||||
StorageDead(_13); // scope 2 at $DIR/funky_arms.rs:26:86: 26:87
|
||||
StorageDead(_12); // scope 2 at $DIR/funky_arms.rs:26:86: 26:87
|
||||
StorageDead(_11); // scope 2 at $DIR/funky_arms.rs:26:86: 26:87
|
||||
goto -> bb10; // scope 2 at $DIR/funky_arms.rs:24:5: 29:6
|
||||
}
|
||||
|
||||
@ -135,6 +134,7 @@
|
||||
}
|
||||
|
||||
bb10: {
|
||||
StorageDead(_10); // scope 2 at $DIR/funky_arms.rs:29:5: 29:6
|
||||
StorageDead(_6); // scope 1 at $DIR/funky_arms.rs:30:1: 30:2
|
||||
StorageDead(_4); // scope 0 at $DIR/funky_arms.rs:30:1: 30:2
|
||||
StorageDead(_7); // scope 0 at $DIR/funky_arms.rs:30:1: 30:2
|
||||
|
@ -26,7 +26,7 @@ fn main() -> () {
|
||||
_8 = const false; // scope 0 at $DIR/issue-41888.rs:7:9: 7:10
|
||||
StorageLive(_1); // scope 0 at $DIR/issue-41888.rs:7:9: 7:10
|
||||
StorageLive(_2); // scope 1 at $DIR/issue-41888.rs:8:8: 8:14
|
||||
_2 = cond() -> [return: bb1, unwind: bb11]; // scope 1 at $DIR/issue-41888.rs:8:8: 8:14
|
||||
_2 = cond() -> [return: bb1, unwind: bb12]; // scope 1 at $DIR/issue-41888.rs:8:8: 8:14
|
||||
// mir::Constant
|
||||
// + span: $DIR/issue-41888.rs:8:8: 8:12
|
||||
// + literal: Const { ty: fn() -> bool {cond}, val: Value(Scalar(<ZST>)) }
|
||||
@ -42,12 +42,12 @@ fn main() -> () {
|
||||
_4 = K; // scope 1 at $DIR/issue-41888.rs:9:18: 9:19
|
||||
_3 = E::F(move _4); // scope 1 at $DIR/issue-41888.rs:9:13: 9:20
|
||||
StorageDead(_4); // scope 1 at $DIR/issue-41888.rs:9:19: 9:20
|
||||
goto -> bb14; // scope 1 at $DIR/issue-41888.rs:9:9: 9:10
|
||||
goto -> bb15; // scope 1 at $DIR/issue-41888.rs:9:9: 9:10
|
||||
}
|
||||
|
||||
bb3: {
|
||||
_0 = const (); // scope 1 at $DIR/issue-41888.rs:14:6: 14:6
|
||||
goto -> bb8; // scope 1 at $DIR/issue-41888.rs:8:5: 14:6
|
||||
goto -> bb9; // scope 1 at $DIR/issue-41888.rs:8:5: 14:6
|
||||
}
|
||||
|
||||
bb4: {
|
||||
@ -69,17 +69,21 @@ fn main() -> () {
|
||||
StorageLive(_6); // scope 1 at $DIR/issue-41888.rs:10:21: 10:23
|
||||
_9 = const false; // scope 1 at $DIR/issue-41888.rs:10:21: 10:23
|
||||
_6 = move ((_1 as F).0: K); // scope 1 at $DIR/issue-41888.rs:10:21: 10:23
|
||||
_0 = const (); // scope 2 at $DIR/issue-41888.rs:10:29: 13:10
|
||||
StorageDead(_6); // scope 1 at $DIR/issue-41888.rs:13:9: 13:10
|
||||
_0 = const (); // scope 1 at $DIR/issue-41888.rs:10:29: 13:10
|
||||
goto -> bb8; // scope 1 at $DIR/issue-41888.rs:10:9: 13:10
|
||||
}
|
||||
|
||||
bb8: {
|
||||
StorageDead(_2); // scope 1 at $DIR/issue-41888.rs:14:5: 14:6
|
||||
goto -> bb20; // scope 0 at $DIR/issue-41888.rs:15:1: 15:2
|
||||
StorageDead(_6); // scope 1 at $DIR/issue-41888.rs:13:9: 13:10
|
||||
goto -> bb9; // scope 1 at $DIR/issue-41888.rs:8:5: 14:6
|
||||
}
|
||||
|
||||
bb9: {
|
||||
StorageDead(_2); // scope 1 at $DIR/issue-41888.rs:14:5: 14:6
|
||||
goto -> bb21; // scope 0 at $DIR/issue-41888.rs:15:1: 15:2
|
||||
}
|
||||
|
||||
bb10: {
|
||||
_7 = const false; // scope 0 at $DIR/issue-41888.rs:15:1: 15:2
|
||||
_8 = const false; // scope 0 at $DIR/issue-41888.rs:15:1: 15:2
|
||||
_9 = const false; // scope 0 at $DIR/issue-41888.rs:15:1: 15:2
|
||||
@ -87,27 +91,27 @@ fn main() -> () {
|
||||
return; // scope 0 at $DIR/issue-41888.rs:15:2: 15:2
|
||||
}
|
||||
|
||||
bb10 (cleanup): {
|
||||
goto -> bb11; // scope 1 at $DIR/issue-41888.rs:9:19: 9:20
|
||||
}
|
||||
|
||||
bb11 (cleanup): {
|
||||
goto -> bb12; // scope 0 at $DIR/issue-41888.rs:15:1: 15:2
|
||||
goto -> bb12; // scope 1 at $DIR/issue-41888.rs:9:19: 9:20
|
||||
}
|
||||
|
||||
bb12 (cleanup): {
|
||||
resume; // scope 0 at $DIR/issue-41888.rs:6:1: 15:2
|
||||
goto -> bb13; // scope 0 at $DIR/issue-41888.rs:15:1: 15:2
|
||||
}
|
||||
|
||||
bb13 (cleanup): {
|
||||
resume; // scope 0 at $DIR/issue-41888.rs:6:1: 15:2
|
||||
}
|
||||
|
||||
bb14 (cleanup): {
|
||||
_7 = const true; // scope 1 at $DIR/issue-41888.rs:9:9: 9:10
|
||||
_8 = const true; // scope 1 at $DIR/issue-41888.rs:9:9: 9:10
|
||||
_9 = const true; // scope 1 at $DIR/issue-41888.rs:9:9: 9:10
|
||||
_1 = move _3; // scope 1 at $DIR/issue-41888.rs:9:9: 9:10
|
||||
goto -> bb10; // scope 1 at $DIR/issue-41888.rs:9:9: 9:10
|
||||
goto -> bb11; // scope 1 at $DIR/issue-41888.rs:9:9: 9:10
|
||||
}
|
||||
|
||||
bb14: {
|
||||
bb15: {
|
||||
_7 = const true; // scope 1 at $DIR/issue-41888.rs:9:9: 9:10
|
||||
_8 = const true; // scope 1 at $DIR/issue-41888.rs:9:9: 9:10
|
||||
_9 = const true; // scope 1 at $DIR/issue-41888.rs:9:9: 9:10
|
||||
@ -115,38 +119,38 @@ fn main() -> () {
|
||||
goto -> bb4; // scope 1 at $DIR/issue-41888.rs:9:9: 9:10
|
||||
}
|
||||
|
||||
bb15: {
|
||||
bb16: {
|
||||
_7 = const false; // scope 0 at $DIR/issue-41888.rs:15:1: 15:2
|
||||
goto -> bb9; // scope 0 at $DIR/issue-41888.rs:15:1: 15:2
|
||||
goto -> bb10; // scope 0 at $DIR/issue-41888.rs:15:1: 15:2
|
||||
}
|
||||
|
||||
bb16 (cleanup): {
|
||||
goto -> bb12; // scope 0 at $DIR/issue-41888.rs:15:1: 15:2
|
||||
bb17 (cleanup): {
|
||||
goto -> bb13; // scope 0 at $DIR/issue-41888.rs:15:1: 15:2
|
||||
}
|
||||
|
||||
bb17: {
|
||||
drop(_1) -> [return: bb15, unwind: bb12]; // scope 0 at $DIR/issue-41888.rs:15:1: 15:2
|
||||
bb18: {
|
||||
drop(_1) -> [return: bb16, unwind: bb13]; // scope 0 at $DIR/issue-41888.rs:15:1: 15:2
|
||||
}
|
||||
|
||||
bb18 (cleanup): {
|
||||
drop(_1) -> bb12; // scope 0 at $DIR/issue-41888.rs:15:1: 15:2
|
||||
}
|
||||
|
||||
bb19: {
|
||||
_10 = discriminant(_1); // scope 0 at $DIR/issue-41888.rs:15:1: 15:2
|
||||
switchInt(move _10) -> [0_isize: bb15, otherwise: bb17]; // scope 0 at $DIR/issue-41888.rs:15:1: 15:2
|
||||
bb19 (cleanup): {
|
||||
drop(_1) -> bb13; // scope 0 at $DIR/issue-41888.rs:15:1: 15:2
|
||||
}
|
||||
|
||||
bb20: {
|
||||
switchInt(_7) -> [false: bb15, otherwise: bb19]; // scope 0 at $DIR/issue-41888.rs:15:1: 15:2
|
||||
_10 = discriminant(_1); // scope 0 at $DIR/issue-41888.rs:15:1: 15:2
|
||||
switchInt(move _10) -> [0_isize: bb16, otherwise: bb18]; // scope 0 at $DIR/issue-41888.rs:15:1: 15:2
|
||||
}
|
||||
|
||||
bb21 (cleanup): {
|
||||
_11 = discriminant(_1); // scope 0 at $DIR/issue-41888.rs:15:1: 15:2
|
||||
switchInt(move _11) -> [0_isize: bb16, otherwise: bb18]; // scope 0 at $DIR/issue-41888.rs:15:1: 15:2
|
||||
bb21: {
|
||||
switchInt(_7) -> [false: bb16, otherwise: bb20]; // scope 0 at $DIR/issue-41888.rs:15:1: 15:2
|
||||
}
|
||||
|
||||
bb22 (cleanup): {
|
||||
switchInt(_7) -> [false: bb12, otherwise: bb21]; // scope 0 at $DIR/issue-41888.rs:15:1: 15:2
|
||||
_11 = discriminant(_1); // scope 0 at $DIR/issue-41888.rs:15:1: 15:2
|
||||
switchInt(move _11) -> [0_isize: bb17, otherwise: bb19]; // scope 0 at $DIR/issue-41888.rs:15:1: 15:2
|
||||
}
|
||||
|
||||
bb23 (cleanup): {
|
||||
switchInt(_7) -> [false: bb13, otherwise: bb22]; // scope 0 at $DIR/issue-41888.rs:15:1: 15:2
|
||||
}
|
||||
}
|
||||
|
@ -13,8 +13,8 @@
|
||||
let _4: u32; // in scope 1 at $DIR/issue-75439.rs:9:27: 9:29
|
||||
scope 3 {
|
||||
debug ip => _4; // in scope 3 at $DIR/issue-75439.rs:9:27: 9:29
|
||||
scope 4 {
|
||||
}
|
||||
}
|
||||
scope 4 {
|
||||
}
|
||||
}
|
||||
scope 2 {
|
||||
@ -49,7 +49,7 @@
|
||||
}
|
||||
|
||||
bb5: {
|
||||
StorageLive(_5); // scope 3 at $DIR/issue-75439.rs:10:14: 10:38
|
||||
StorageLive(_5); // scope 1 at $DIR/issue-75439.rs:10:14: 10:38
|
||||
StorageLive(_6); // scope 4 at $DIR/issue-75439.rs:10:33: 10:35
|
||||
_6 = _4; // scope 4 at $DIR/issue-75439.rs:10:33: 10:35
|
||||
_5 = transmute::<u32, [u8; 4]>(move _6) -> bb8; // scope 4 at $DIR/issue-75439.rs:10:23: 10:36
|
||||
@ -61,25 +61,25 @@
|
||||
bb6: {
|
||||
StorageLive(_4); // scope 1 at $DIR/issue-75439.rs:9:27: 9:29
|
||||
_4 = _2[3 of 4]; // scope 1 at $DIR/issue-75439.rs:9:27: 9:29
|
||||
goto -> bb5; // scope 1 at $DIR/issue-75439.rs:9:5: 13:6
|
||||
goto -> bb5; // scope 1 at $DIR/issue-75439.rs:9:12: 9:30
|
||||
}
|
||||
|
||||
bb7: {
|
||||
StorageLive(_4); // scope 1 at $DIR/issue-75439.rs:9:27: 9:29
|
||||
_4 = _2[3 of 4]; // scope 1 at $DIR/issue-75439.rs:9:27: 9:29
|
||||
goto -> bb5; // scope 1 at $DIR/issue-75439.rs:9:5: 13:6
|
||||
goto -> bb5; // scope 1 at $DIR/issue-75439.rs:9:12: 9:30
|
||||
}
|
||||
|
||||
bb8: {
|
||||
StorageDead(_6); // scope 4 at $DIR/issue-75439.rs:10:35: 10:36
|
||||
((_0 as Some).0: [u8; 4]) = move _5; // scope 3 at $DIR/issue-75439.rs:10:9: 10:39
|
||||
discriminant(_0) = 1; // scope 3 at $DIR/issue-75439.rs:10:9: 10:39
|
||||
StorageDead(_5); // scope 3 at $DIR/issue-75439.rs:10:38: 10:39
|
||||
StorageDead(_4); // scope 1 at $DIR/issue-75439.rs:11:5: 11:6
|
||||
((_0 as Some).0: [u8; 4]) = move _5; // scope 1 at $DIR/issue-75439.rs:10:9: 10:39
|
||||
discriminant(_0) = 1; // scope 1 at $DIR/issue-75439.rs:10:9: 10:39
|
||||
StorageDead(_5); // scope 1 at $DIR/issue-75439.rs:10:38: 10:39
|
||||
goto -> bb9; // scope 1 at $DIR/issue-75439.rs:9:5: 13:6
|
||||
}
|
||||
|
||||
bb9: {
|
||||
StorageDead(_4); // scope 1 at $DIR/issue-75439.rs:13:5: 13:6
|
||||
StorageDead(_2); // scope 0 at $DIR/issue-75439.rs:14:1: 14:2
|
||||
return; // scope 0 at $DIR/issue-75439.rs:14:2: 14:2
|
||||
}
|
||||
|
@ -37,17 +37,17 @@
|
||||
bb2: {
|
||||
StorageLive(_6); // scope 0 at $DIR/simplify-locals-fixedpoint.rs:4:18: 4:19
|
||||
_6 = (((_1.0: std::option::Option<u8>) as Some).0: u8); // scope 0 at $DIR/simplify-locals-fixedpoint.rs:4:18: 4:19
|
||||
- StorageLive(_7); // scope 1 at $DIR/simplify-locals-fixedpoint.rs:5:12: 5:20
|
||||
- StorageLive(_8); // scope 1 at $DIR/simplify-locals-fixedpoint.rs:5:12: 5:13
|
||||
- _8 = _6; // scope 1 at $DIR/simplify-locals-fixedpoint.rs:5:12: 5:13
|
||||
- _7 = Gt(move _8, const 42_u8); // scope 1 at $DIR/simplify-locals-fixedpoint.rs:5:12: 5:20
|
||||
- StorageDead(_8); // scope 1 at $DIR/simplify-locals-fixedpoint.rs:5:19: 5:20
|
||||
- StorageDead(_7); // scope 1 at $DIR/simplify-locals-fixedpoint.rs:7:9: 7:10
|
||||
StorageDead(_6); // scope 0 at $DIR/simplify-locals-fixedpoint.rs:8:5: 8:6
|
||||
- StorageLive(_7); // scope 0 at $DIR/simplify-locals-fixedpoint.rs:5:12: 5:20
|
||||
- StorageLive(_8); // scope 0 at $DIR/simplify-locals-fixedpoint.rs:5:12: 5:13
|
||||
- _8 = _6; // scope 0 at $DIR/simplify-locals-fixedpoint.rs:5:12: 5:13
|
||||
- _7 = Gt(move _8, const 42_u8); // scope 0 at $DIR/simplify-locals-fixedpoint.rs:5:12: 5:20
|
||||
- StorageDead(_8); // scope 0 at $DIR/simplify-locals-fixedpoint.rs:5:19: 5:20
|
||||
- StorageDead(_7); // scope 0 at $DIR/simplify-locals-fixedpoint.rs:7:9: 7:10
|
||||
goto -> bb3; // scope 0 at $DIR/simplify-locals-fixedpoint.rs:4:5: 8:6
|
||||
}
|
||||
|
||||
bb3: {
|
||||
StorageDead(_6); // scope 0 at $DIR/simplify-locals-fixedpoint.rs:8:5: 8:6
|
||||
drop(_1) -> bb4; // scope 0 at $DIR/simplify-locals-fixedpoint.rs:9:1: 9:2
|
||||
}
|
||||
|
||||
|
@ -6,15 +6,15 @@
|
||||
let mut _1: std::option::Option<Empty>; // in scope 0 at $DIR/unreachable.rs:9:23: 9:30
|
||||
let mut _2: isize; // in scope 0 at $DIR/unreachable.rs:9:12: 9:20
|
||||
let _3: Empty; // in scope 0 at $DIR/unreachable.rs:9:17: 9:19
|
||||
let mut _4: i32; // in scope 0 at $DIR/unreachable.rs:10:13: 10:19
|
||||
let _5: (); // in scope 0 at $DIR/unreachable.rs:12:9: 16:10
|
||||
let mut _6: bool; // in scope 0 at $DIR/unreachable.rs:12:12: 12:16
|
||||
let mut _7: !; // in scope 0 at $DIR/unreachable.rs:18:9: 18:21
|
||||
scope 1 {
|
||||
debug _x => _3; // in scope 1 at $DIR/unreachable.rs:9:17: 9:19
|
||||
let mut _4: i32; // in scope 1 at $DIR/unreachable.rs:10:13: 10:19
|
||||
scope 2 {
|
||||
debug _y => _4; // in scope 2 at $DIR/unreachable.rs:10:13: 10:19
|
||||
}
|
||||
}
|
||||
scope 2 {
|
||||
debug _y => _4; // in scope 2 at $DIR/unreachable.rs:10:13: 10:19
|
||||
}
|
||||
|
||||
bb0: {
|
||||
@ -33,6 +33,7 @@
|
||||
|
||||
bb2: {
|
||||
_0 = const (); // scope 0 at $DIR/unreachable.rs:19:6: 19:6
|
||||
StorageDead(_3); // scope 0 at $DIR/unreachable.rs:19:5: 19:6
|
||||
StorageDead(_1); // scope 0 at $DIR/unreachable.rs:20:1: 20:2
|
||||
return; // scope 0 at $DIR/unreachable.rs:20:2: 20:2
|
||||
- }
|
||||
@ -40,7 +41,7 @@
|
||||
- bb3: {
|
||||
- StorageLive(_3); // scope 0 at $DIR/unreachable.rs:9:17: 9:19
|
||||
- _3 = move ((_1 as Some).0: Empty); // scope 0 at $DIR/unreachable.rs:9:17: 9:19
|
||||
- StorageLive(_4); // scope 1 at $DIR/unreachable.rs:10:13: 10:19
|
||||
- StorageLive(_4); // scope 0 at $DIR/unreachable.rs:10:13: 10:19
|
||||
- StorageLive(_5); // scope 2 at $DIR/unreachable.rs:12:9: 16:10
|
||||
- StorageLive(_6); // scope 2 at $DIR/unreachable.rs:12:12: 12:16
|
||||
- _6 = const true; // scope 2 at $DIR/unreachable.rs:12:12: 12:16
|
||||
|
@ -6,17 +6,17 @@
|
||||
let mut _1: std::option::Option<Empty>; // in scope 0 at $DIR/unreachable_asm.rs:11:23: 11:30
|
||||
let mut _2: isize; // in scope 0 at $DIR/unreachable_asm.rs:11:12: 11:20
|
||||
let _3: Empty; // in scope 0 at $DIR/unreachable_asm.rs:11:17: 11:19
|
||||
let mut _4: i32; // in scope 0 at $DIR/unreachable_asm.rs:12:13: 12:19
|
||||
let _5: (); // in scope 0 at $DIR/unreachable_asm.rs:14:9: 18:10
|
||||
let mut _6: bool; // in scope 0 at $DIR/unreachable_asm.rs:14:12: 14:16
|
||||
let _7: (); // in scope 0 at $DIR/unreachable_asm.rs:21:9: 21:37
|
||||
let mut _8: !; // in scope 0 at $DIR/unreachable_asm.rs:22:9: 22:21
|
||||
scope 1 {
|
||||
debug _x => _3; // in scope 1 at $DIR/unreachable_asm.rs:11:17: 11:19
|
||||
let mut _4: i32; // in scope 1 at $DIR/unreachable_asm.rs:12:13: 12:19
|
||||
scope 2 {
|
||||
debug _y => _4; // in scope 2 at $DIR/unreachable_asm.rs:12:13: 12:19
|
||||
scope 3 {
|
||||
}
|
||||
}
|
||||
scope 2 {
|
||||
debug _y => _4; // in scope 2 at $DIR/unreachable_asm.rs:12:13: 12:19
|
||||
scope 3 {
|
||||
}
|
||||
}
|
||||
|
||||
@ -35,6 +35,7 @@
|
||||
|
||||
bb2: {
|
||||
_0 = const (); // scope 0 at $DIR/unreachable_asm.rs:23:6: 23:6
|
||||
StorageDead(_3); // scope 0 at $DIR/unreachable_asm.rs:23:5: 23:6
|
||||
StorageDead(_1); // scope 0 at $DIR/unreachable_asm.rs:24:1: 24:2
|
||||
return; // scope 0 at $DIR/unreachable_asm.rs:24:2: 24:2
|
||||
}
|
||||
@ -42,7 +43,7 @@
|
||||
bb3: {
|
||||
StorageLive(_3); // scope 0 at $DIR/unreachable_asm.rs:11:17: 11:19
|
||||
_3 = move ((_1 as Some).0: Empty); // scope 0 at $DIR/unreachable_asm.rs:11:17: 11:19
|
||||
StorageLive(_4); // scope 1 at $DIR/unreachable_asm.rs:12:13: 12:19
|
||||
StorageLive(_4); // scope 0 at $DIR/unreachable_asm.rs:12:13: 12:19
|
||||
StorageLive(_5); // scope 2 at $DIR/unreachable_asm.rs:14:9: 18:10
|
||||
StorageLive(_6); // scope 2 at $DIR/unreachable_asm.rs:14:12: 14:16
|
||||
_6 = const true; // scope 2 at $DIR/unreachable_asm.rs:14:12: 14:16
|
||||
|
@ -6,6 +6,7 @@
|
||||
let mut _1: std::option::Option<Empty>; // in scope 0 at $DIR/unreachable_asm_2.rs:11:23: 11:30
|
||||
let mut _2: isize; // in scope 0 at $DIR/unreachable_asm_2.rs:11:12: 11:20
|
||||
let _3: Empty; // in scope 0 at $DIR/unreachable_asm_2.rs:11:17: 11:19
|
||||
let mut _4: i32; // in scope 0 at $DIR/unreachable_asm_2.rs:12:13: 12:19
|
||||
let _5: (); // in scope 0 at $DIR/unreachable_asm_2.rs:14:9: 22:10
|
||||
let mut _6: bool; // in scope 0 at $DIR/unreachable_asm_2.rs:14:12: 14:16
|
||||
let _7: (); // in scope 0 at $DIR/unreachable_asm_2.rs:16:13: 16:41
|
||||
@ -13,13 +14,12 @@
|
||||
let mut _9: !; // in scope 0 at $DIR/unreachable_asm_2.rs:24:9: 24:21
|
||||
scope 1 {
|
||||
debug _x => _3; // in scope 1 at $DIR/unreachable_asm_2.rs:11:17: 11:19
|
||||
let mut _4: i32; // in scope 1 at $DIR/unreachable_asm_2.rs:12:13: 12:19
|
||||
scope 2 {
|
||||
debug _y => _4; // in scope 2 at $DIR/unreachable_asm_2.rs:12:13: 12:19
|
||||
scope 3 {
|
||||
}
|
||||
scope 4 {
|
||||
}
|
||||
}
|
||||
scope 2 {
|
||||
debug _y => _4; // in scope 2 at $DIR/unreachable_asm_2.rs:12:13: 12:19
|
||||
scope 3 {
|
||||
}
|
||||
scope 4 {
|
||||
}
|
||||
}
|
||||
|
||||
@ -38,6 +38,7 @@
|
||||
|
||||
bb2: {
|
||||
_0 = const (); // scope 0 at $DIR/unreachable_asm_2.rs:25:6: 25:6
|
||||
StorageDead(_3); // scope 0 at $DIR/unreachable_asm_2.rs:25:5: 25:6
|
||||
StorageDead(_1); // scope 0 at $DIR/unreachable_asm_2.rs:26:1: 26:2
|
||||
return; // scope 0 at $DIR/unreachable_asm_2.rs:26:2: 26:2
|
||||
}
|
||||
@ -45,7 +46,7 @@
|
||||
bb3: {
|
||||
StorageLive(_3); // scope 0 at $DIR/unreachable_asm_2.rs:11:17: 11:19
|
||||
_3 = move ((_1 as Some).0: Empty); // scope 0 at $DIR/unreachable_asm_2.rs:11:17: 11:19
|
||||
StorageLive(_4); // scope 1 at $DIR/unreachable_asm_2.rs:12:13: 12:19
|
||||
StorageLive(_4); // scope 0 at $DIR/unreachable_asm_2.rs:12:13: 12:19
|
||||
StorageLive(_5); // scope 2 at $DIR/unreachable_asm_2.rs:14:9: 22:10
|
||||
StorageLive(_6); // scope 2 at $DIR/unreachable_asm_2.rs:14:12: 14:16
|
||||
_6 = const true; // scope 2 at $DIR/unreachable_asm_2.rs:14:12: 14:16
|
||||
|
@ -34,6 +34,7 @@
|
||||
|
||||
bb2: {
|
||||
_0 = const (); // scope 1 at $DIR/unreachable_diverging.rs:19:6: 19:6
|
||||
StorageDead(_4); // scope 1 at $DIR/unreachable_diverging.rs:19:5: 19:6
|
||||
StorageDead(_1); // scope 0 at $DIR/unreachable_diverging.rs:20:1: 20:2
|
||||
StorageDead(_2); // scope 0 at $DIR/unreachable_diverging.rs:20:1: 20:2
|
||||
return; // scope 0 at $DIR/unreachable_diverging.rs:20:2: 20:2
|
||||
@ -42,31 +43,31 @@
|
||||
bb3: {
|
||||
StorageLive(_4); // scope 1 at $DIR/unreachable_diverging.rs:14:17: 14:21
|
||||
_4 = move ((_2 as Some).0: Empty); // scope 1 at $DIR/unreachable_diverging.rs:14:17: 14:21
|
||||
StorageLive(_5); // scope 2 at $DIR/unreachable_diverging.rs:15:9: 17:10
|
||||
StorageLive(_6); // scope 2 at $DIR/unreachable_diverging.rs:15:12: 15:13
|
||||
_6 = _1; // scope 2 at $DIR/unreachable_diverging.rs:15:12: 15:13
|
||||
- switchInt(move _6) -> [false: bb5, otherwise: bb4]; // scope 2 at $DIR/unreachable_diverging.rs:15:9: 17:10
|
||||
+ goto -> bb4; // scope 2 at $DIR/unreachable_diverging.rs:15:9: 17:10
|
||||
StorageLive(_5); // scope 1 at $DIR/unreachable_diverging.rs:15:9: 17:10
|
||||
StorageLive(_6); // scope 1 at $DIR/unreachable_diverging.rs:15:12: 15:13
|
||||
_6 = _1; // scope 1 at $DIR/unreachable_diverging.rs:15:12: 15:13
|
||||
- switchInt(move _6) -> [false: bb5, otherwise: bb4]; // scope 1 at $DIR/unreachable_diverging.rs:15:9: 17:10
|
||||
+ goto -> bb4; // scope 1 at $DIR/unreachable_diverging.rs:15:9: 17:10
|
||||
}
|
||||
|
||||
bb4: {
|
||||
- _5 = loop_forever() -> bb6; // scope 2 at $DIR/unreachable_diverging.rs:16:13: 16:27
|
||||
+ _5 = loop_forever() -> bb5; // scope 2 at $DIR/unreachable_diverging.rs:16:13: 16:27
|
||||
- _5 = loop_forever() -> bb6; // scope 1 at $DIR/unreachable_diverging.rs:16:13: 16:27
|
||||
+ _5 = loop_forever() -> bb5; // scope 1 at $DIR/unreachable_diverging.rs:16:13: 16:27
|
||||
// mir::Constant
|
||||
// + span: $DIR/unreachable_diverging.rs:16:13: 16:25
|
||||
// + literal: Const { ty: fn() {loop_forever}, val: Value(Scalar(<ZST>)) }
|
||||
}
|
||||
|
||||
bb5: {
|
||||
- _5 = const (); // scope 2 at $DIR/unreachable_diverging.rs:17:10: 17:10
|
||||
- goto -> bb6; // scope 2 at $DIR/unreachable_diverging.rs:15:9: 17:10
|
||||
- _5 = const (); // scope 1 at $DIR/unreachable_diverging.rs:17:10: 17:10
|
||||
- goto -> bb6; // scope 1 at $DIR/unreachable_diverging.rs:15:9: 17:10
|
||||
- }
|
||||
-
|
||||
- bb6: {
|
||||
StorageDead(_6); // scope 2 at $DIR/unreachable_diverging.rs:17:9: 17:10
|
||||
StorageDead(_5); // scope 2 at $DIR/unreachable_diverging.rs:17:9: 17:10
|
||||
StorageLive(_7); // scope 2 at $DIR/unreachable_diverging.rs:18:9: 18:22
|
||||
unreachable; // scope 2 at $DIR/unreachable_diverging.rs:18:15: 18:19
|
||||
StorageDead(_6); // scope 1 at $DIR/unreachable_diverging.rs:17:9: 17:10
|
||||
StorageDead(_5); // scope 1 at $DIR/unreachable_diverging.rs:17:9: 17:10
|
||||
StorageLive(_7); // scope 1 at $DIR/unreachable_diverging.rs:18:9: 18:22
|
||||
unreachable; // scope 1 at $DIR/unreachable_diverging.rs:18:15: 18:19
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -9,6 +9,8 @@
|
||||
let mut _4: isize; // in scope 0 at $DIR/while_let_loops.rs:7:15: 7:25
|
||||
let mut _5: !; // in scope 0 at $DIR/while_let_loops.rs:7:33: 10:6
|
||||
let mut _6: !; // in scope 0 at $DIR/while_let_loops.rs:7:5: 10:6
|
||||
let _7: (); // in scope 0 at $DIR/while_let_loops.rs:7:5: 10:6
|
||||
let mut _8: !; // in scope 0 at $DIR/while_let_loops.rs:7:5: 10:6
|
||||
scope 1 {
|
||||
debug _x => _1; // in scope 1 at $DIR/while_let_loops.rs:6:9: 6:15
|
||||
}
|
||||
@ -25,8 +27,10 @@
|
||||
}
|
||||
|
||||
bb1: {
|
||||
StorageLive(_7); // scope 1 at $DIR/while_let_loops.rs:7:5: 10:6
|
||||
nop; // scope 1 at $DIR/while_let_loops.rs:7:5: 10:6
|
||||
goto -> bb4; // scope 1 at $DIR/while_let_loops.rs:7:5: 10:6
|
||||
StorageDead(_7); // scope 1 at $DIR/while_let_loops.rs:10:5: 10:6
|
||||
goto -> bb4; // scope 1 at no-location
|
||||
}
|
||||
|
||||
bb2: {
|
||||
|
@ -9,6 +9,8 @@
|
||||
let mut _4: isize; // in scope 0 at $DIR/while_let_loops.rs:7:15: 7:25
|
||||
let mut _5: !; // in scope 0 at $DIR/while_let_loops.rs:7:33: 10:6
|
||||
let mut _6: !; // in scope 0 at $DIR/while_let_loops.rs:7:5: 10:6
|
||||
let _7: (); // in scope 0 at $DIR/while_let_loops.rs:7:5: 10:6
|
||||
let mut _8: !; // in scope 0 at $DIR/while_let_loops.rs:7:5: 10:6
|
||||
scope 1 {
|
||||
debug _x => _1; // in scope 1 at $DIR/while_let_loops.rs:6:9: 6:15
|
||||
}
|
||||
@ -25,8 +27,10 @@
|
||||
}
|
||||
|
||||
bb1: {
|
||||
StorageLive(_7); // scope 1 at $DIR/while_let_loops.rs:7:5: 10:6
|
||||
nop; // scope 1 at $DIR/while_let_loops.rs:7:5: 10:6
|
||||
goto -> bb4; // scope 1 at $DIR/while_let_loops.rs:7:5: 10:6
|
||||
StorageDead(_7); // scope 1 at $DIR/while_let_loops.rs:10:5: 10:6
|
||||
goto -> bb4; // scope 1 at no-location
|
||||
}
|
||||
|
||||
bb2: {
|
||||
|
@ -20,36 +20,40 @@ fn while_loop(_1: bool) -> () {
|
||||
|
||||
bb1: {
|
||||
StorageDead(_3); // scope 0 at $DIR/while-storage.rs:10:21: 10:22
|
||||
switchInt(_2) -> [false: bb6, otherwise: bb2]; // scope 0 at $DIR/while-storage.rs:10:5: 14:6
|
||||
switchInt(move _2) -> [false: bb3, otherwise: bb2]; // scope 0 at $DIR/while-storage.rs:10:5: 14:6
|
||||
}
|
||||
|
||||
bb2: {
|
||||
StorageLive(_4); // scope 0 at $DIR/while-storage.rs:11:12: 11:23
|
||||
StorageLive(_5); // scope 0 at $DIR/while-storage.rs:11:21: 11:22
|
||||
_5 = _1; // scope 0 at $DIR/while-storage.rs:11:21: 11:22
|
||||
_4 = get_bool(move _5) -> bb3; // scope 0 at $DIR/while-storage.rs:11:12: 11:23
|
||||
_4 = get_bool(move _5) -> bb4; // scope 0 at $DIR/while-storage.rs:11:12: 11:23
|
||||
// mir::Constant
|
||||
// + span: $DIR/while-storage.rs:11:12: 11:20
|
||||
// + literal: Const { ty: fn(bool) -> bool {get_bool}, val: Value(Scalar(<ZST>)) }
|
||||
}
|
||||
|
||||
bb3: {
|
||||
StorageDead(_5); // scope 0 at $DIR/while-storage.rs:11:22: 11:23
|
||||
switchInt(move _4) -> [false: bb5, otherwise: bb4]; // scope 0 at $DIR/while-storage.rs:11:9: 13:10
|
||||
goto -> bb7; // scope 0 at no-location
|
||||
}
|
||||
|
||||
bb4: {
|
||||
StorageDead(_4); // scope 0 at $DIR/while-storage.rs:13:9: 13:10
|
||||
goto -> bb6; // scope 0 at no-location
|
||||
StorageDead(_5); // scope 0 at $DIR/while-storage.rs:11:22: 11:23
|
||||
switchInt(move _4) -> [false: bb6, otherwise: bb5]; // scope 0 at $DIR/while-storage.rs:11:9: 13:10
|
||||
}
|
||||
|
||||
bb5: {
|
||||
StorageDead(_4); // scope 0 at $DIR/while-storage.rs:13:9: 13:10
|
||||
goto -> bb7; // scope 0 at no-location
|
||||
}
|
||||
|
||||
bb6: {
|
||||
StorageDead(_4); // scope 0 at $DIR/while-storage.rs:13:9: 13:10
|
||||
StorageDead(_2); // scope 0 at $DIR/while-storage.rs:14:5: 14:6
|
||||
goto -> bb0; // scope 0 at $DIR/while-storage.rs:10:5: 14:6
|
||||
}
|
||||
|
||||
bb6: {
|
||||
bb7: {
|
||||
StorageDead(_2); // scope 0 at $DIR/while-storage.rs:14:5: 14:6
|
||||
return; // scope 0 at $DIR/while-storage.rs:15:2: 15:2
|
||||
}
|
||||
|
@ -161,7 +161,7 @@ fn iter_exprs(depth: usize, f: &mut dyn FnMut(P<Expr>)) {
|
||||
19 => {
|
||||
let pat =
|
||||
P(Pat { id: DUMMY_NODE_ID, kind: PatKind::Wild, span: DUMMY_SP, tokens: None });
|
||||
iter_exprs(depth - 1, &mut |e| g(ExprKind::Let(pat.clone(), e)))
|
||||
iter_exprs(depth - 1, &mut |e| g(ExprKind::Let(pat.clone(), e, DUMMY_SP)))
|
||||
}
|
||||
_ => panic!("bad counter value in iter_exprs"),
|
||||
}
|
||||
|
@ -1,11 +1,8 @@
|
||||
warning: irrefutable `if let` pattern
|
||||
--> $DIR/issue-78720.rs:6:5
|
||||
--> $DIR/issue-78720.rs:6:8
|
||||
|
|
||||
LL | / if let a = "" {
|
||||
LL | |
|
||||
LL | | drop(|_: ()| drop(a));
|
||||
LL | | }
|
||||
| |_____^
|
||||
LL | if let a = "" {
|
||||
| ^^^^^^^^^^
|
||||
|
|
||||
= note: `#[warn(irrefutable_let_patterns)]` on by default
|
||||
= note: this pattern will always match, so the `if let` is useless
|
||||
|
@ -1,7 +1,7 @@
|
||||
// check-pass
|
||||
|
||||
fn macros() {
|
||||
macro_rules! foo{
|
||||
macro_rules! foo {
|
||||
($p:pat, $e:expr, $b:block) => {{
|
||||
if let $p = $e $b
|
||||
//~^ WARN irrefutable `if let`
|
||||
|
@ -1,8 +1,8 @@
|
||||
warning: irrefutable `if let` pattern
|
||||
--> $DIR/if-let.rs:6:13
|
||||
--> $DIR/if-let.rs:6:16
|
||||
|
|
||||
LL | if let $p = $e $b
|
||||
| ^^^^^^^^^^^^^^^^^
|
||||
| ^^^
|
||||
...
|
||||
LL | / foo!(a, 1, {
|
||||
LL | | println!("irrefutable pattern");
|
||||
@ -15,10 +15,10 @@ LL | | });
|
||||
= note: this warning originates in the macro `foo` (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||
|
||||
warning: irrefutable `if let` pattern
|
||||
--> $DIR/if-let.rs:6:13
|
||||
--> $DIR/if-let.rs:6:16
|
||||
|
|
||||
LL | if let $p = $e $b
|
||||
| ^^^^^^^^^^^^^^^^^
|
||||
| ^^^
|
||||
...
|
||||
LL | / bar!(a, 1, {
|
||||
LL | | println!("irrefutable pattern");
|
||||
@ -30,51 +30,37 @@ LL | | });
|
||||
= note: this warning originates in the macro `foo` (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||
|
||||
warning: irrefutable `if let` pattern
|
||||
--> $DIR/if-let.rs:26:5
|
||||
--> $DIR/if-let.rs:26:8
|
||||
|
|
||||
LL | / if let a = 1 {
|
||||
LL | | println!("irrefutable pattern");
|
||||
LL | | }
|
||||
| |_____^
|
||||
LL | if let a = 1 {
|
||||
| ^^^^^^^^^
|
||||
|
|
||||
= note: this pattern will always match, so the `if let` is useless
|
||||
= help: consider replacing the `if let` with a `let`
|
||||
|
||||
warning: irrefutable `if let` pattern
|
||||
--> $DIR/if-let.rs:30:5
|
||||
--> $DIR/if-let.rs:30:8
|
||||
|
|
||||
LL | / if let a = 1 {
|
||||
LL | | println!("irrefutable pattern");
|
||||
LL | | } else if true {
|
||||
LL | | println!("else-if in irrefutable `if let`");
|
||||
LL | | } else {
|
||||
LL | | println!("else in irrefutable `if let`");
|
||||
LL | | }
|
||||
| |_____^
|
||||
LL | if let a = 1 {
|
||||
| ^^^^^^^^^
|
||||
|
|
||||
= note: this pattern will always match, so the `if let` is useless
|
||||
= help: consider replacing the `if let` with a `let`
|
||||
|
||||
warning: irrefutable `if let` pattern
|
||||
--> $DIR/if-let.rs:40:12
|
||||
--> $DIR/if-let.rs:40:15
|
||||
|
|
||||
LL | } else if let a = 1 {
|
||||
| ____________^
|
||||
LL | | println!("irrefutable pattern");
|
||||
LL | | }
|
||||
| |_____^
|
||||
LL | } else if let a = 1 {
|
||||
| ^^^^^^^^^
|
||||
|
|
||||
= note: this pattern will always match, so the `if let` is useless
|
||||
= help: consider replacing the `if let` with a `let`
|
||||
|
||||
warning: irrefutable `if let` pattern
|
||||
--> $DIR/if-let.rs:46:12
|
||||
--> $DIR/if-let.rs:46:15
|
||||
|
|
||||
LL | } else if let a = 1 {
|
||||
| ____________^
|
||||
LL | | println!("irrefutable pattern");
|
||||
LL | | }
|
||||
| |_____^
|
||||
LL | } else if let a = 1 {
|
||||
| ^^^^^^^^^
|
||||
|
|
||||
= note: this pattern will always match, so the `if let` is useless
|
||||
= help: consider replacing the `if let` with a `let`
|
||||
|
@ -3,6 +3,6 @@
|
||||
#![allow(unused_parens)]
|
||||
// pretty-expanded FIXME #23616
|
||||
|
||||
fn foo() { if (return) { } } //~ WARNING unreachable block in `if` expression
|
||||
fn foo() { if (return) { } } //~ WARNING unreachable block in `if`
|
||||
|
||||
pub fn main() { foo(); }
|
||||
|
@ -1,8 +1,8 @@
|
||||
warning: unreachable block in `if` expression
|
||||
warning: unreachable block in `if` or `while` expression
|
||||
--> $DIR/if-ret.rs:6:24
|
||||
|
|
||||
LL | fn foo() { if (return) { } }
|
||||
| -------- ^^^ unreachable block in `if` expression
|
||||
| -------- ^^^ unreachable block in `if` or `while` expression
|
||||
| |
|
||||
| any code following this expression is unreachable
|
||||
|
|
||||
|
@ -3,8 +3,6 @@ error[E0308]: mismatched types
|
||||
|
|
||||
LL | assert!(1,1);
|
||||
| ^^^^^^^^^^^^^ expected `bool`, found integer
|
||||
|
|
||||
= note: this error originates in the macro `assert` (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
|
@ -9,12 +9,11 @@ extern crate std;
|
||||
pub fn main() ({
|
||||
(if (true as bool)
|
||||
({ } as
|
||||
()) else {match ((Some as
|
||||
()) else if (let Some(a) =
|
||||
((Some as
|
||||
fn(i32) -> Option<i32> {Option::<i32>::Some})((3
|
||||
as
|
||||
i32))
|
||||
as Option<i32>) {
|
||||
Some(a) => { }
|
||||
_ => { }
|
||||
}} as ())
|
||||
} as ())
|
||||
as Option<i32>) as bool)
|
||||
({ } as ()) as ())
|
||||
} as ())
|
||||
|
@ -1,7 +1,9 @@
|
||||
// check-pass
|
||||
|
||||
#![feature(let_chains)] //~ WARN the feature `let_chains` is incomplete
|
||||
|
||||
fn main() {
|
||||
if true && let x = 1 { //~ ERROR `let` expressions are not supported here
|
||||
if true && let x = 1 { //~ WARN irrefutable `let` pattern
|
||||
let _ = x;
|
||||
}
|
||||
}
|
||||
|
@ -1,13 +1,5 @@
|
||||
error: `let` expressions are not supported here
|
||||
--> $DIR/issue-82290.rs:4:16
|
||||
|
|
||||
LL | if true && let x = 1 {
|
||||
| ^^^^^^^^^
|
||||
|
|
||||
= note: only supported directly without parentheses in conditions of `if`- and `while`-expressions, as well as in `let` chains within parentheses
|
||||
|
||||
warning: the feature `let_chains` is incomplete and may not be safe to use and/or cause compiler crashes
|
||||
--> $DIR/issue-82290.rs:1:12
|
||||
--> $DIR/issue-82290.rs:3:12
|
||||
|
|
||||
LL | #![feature(let_chains)]
|
||||
| ^^^^^^^^^^
|
||||
@ -15,5 +7,15 @@ LL | #![feature(let_chains)]
|
||||
= note: `#[warn(incomplete_features)]` on by default
|
||||
= note: see issue #53667 <https://github.com/rust-lang/rust/issues/53667> for more information
|
||||
|
||||
error: aborting due to previous error; 1 warning emitted
|
||||
warning: irrefutable `let` pattern
|
||||
--> $DIR/issue-82290.rs:6:16
|
||||
|
|
||||
LL | if true && let x = 1 {
|
||||
| ^^^^^^^^^
|
||||
|
|
||||
= note: `#[warn(irrefutable_let_patterns)]` on by default
|
||||
= note: this pattern will always match, so the `let` is useless
|
||||
= help: consider removing `let`
|
||||
|
||||
warning: 2 warnings emitted
|
||||
|
||||
|
@ -1,8 +1,8 @@
|
||||
error: irrefutable `if let` pattern
|
||||
--> $DIR/deny-irrefutable-let-patterns.rs:7:5
|
||||
--> $DIR/deny-irrefutable-let-patterns.rs:7:8
|
||||
|
|
||||
LL | if let _ = 5 {}
|
||||
| ^^^^^^^^^^^^^^^
|
||||
| ^^^^^^^^^
|
||||
|
|
||||
note: the lint level is defined here
|
||||
--> $DIR/deny-irrefutable-let-patterns.rs:4:9
|
||||
@ -13,12 +13,10 @@ LL | #![deny(irrefutable_let_patterns)]
|
||||
= help: consider replacing the `if let` with a `let`
|
||||
|
||||
error: irrefutable `while let` pattern
|
||||
--> $DIR/deny-irrefutable-let-patterns.rs:9:5
|
||||
--> $DIR/deny-irrefutable-let-patterns.rs:9:11
|
||||
|
|
||||
LL | / while let _ = 5 {
|
||||
LL | | break;
|
||||
LL | | }
|
||||
| |_____^
|
||||
LL | while let _ = 5 {
|
||||
| ^^^^^^^^^
|
||||
|
|
||||
= note: this pattern will always match, so the loop will never exit
|
||||
= help: consider instead using a `loop { ... }` with a `let` inside it
|
||||
|
@ -4,7 +4,7 @@
|
||||
#![deny(unreachable_code)]
|
||||
|
||||
fn foo() {
|
||||
if {return} { //~ ERROR unreachable block in `if` expression
|
||||
if {return} { //~ ERROR unreachable block in `if`
|
||||
println!("Hello, world!");
|
||||
}
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
error: unreachable block in `if` expression
|
||||
error: unreachable block in `if` or `while` expression
|
||||
--> $DIR/expr_if.rs:7:17
|
||||
|
|
||||
LL | if {return} {
|
||||
@ -7,7 +7,7 @@ LL | if {return} {
|
||||
| | any code following this expression is unreachable
|
||||
LL | | println!("Hello, world!");
|
||||
LL | | }
|
||||
| |_____^ unreachable block in `if` expression
|
||||
| |_____^ unreachable block in `if` or `while` expression
|
||||
|
|
||||
note: the lint level is defined here
|
||||
--> $DIR/expr_if.rs:4:9
|
||||
|
@ -5,7 +5,7 @@
|
||||
|
||||
fn foo() {
|
||||
while {return} {
|
||||
//~^ ERROR unreachable block in `while` expression
|
||||
//~^ ERROR unreachable block in `if`
|
||||
println!("Hello, world!");
|
||||
}
|
||||
}
|
||||
@ -20,7 +20,7 @@ fn bar() {
|
||||
fn baz() {
|
||||
// Here, we cite the `while` loop as dead.
|
||||
while {return} {
|
||||
//~^ ERROR unreachable block in `while` expression
|
||||
//~^ ERROR unreachable block in `if`
|
||||
println!("I am dead.");
|
||||
}
|
||||
println!("I am, too.");
|
||||
|
@ -1,4 +1,4 @@
|
||||
error: unreachable block in `while` expression
|
||||
error: unreachable block in `if` or `while` expression
|
||||
--> $DIR/expr_while.rs:7:20
|
||||
|
|
||||
LL | while {return} {
|
||||
@ -8,7 +8,7 @@ LL | while {return} {
|
||||
LL | |
|
||||
LL | | println!("Hello, world!");
|
||||
LL | | }
|
||||
| |_____^ unreachable block in `while` expression
|
||||
| |_____^ unreachable block in `if` or `while` expression
|
||||
|
|
||||
note: the lint level is defined here
|
||||
--> $DIR/expr_while.rs:4:9
|
||||
@ -16,7 +16,7 @@ note: the lint level is defined here
|
||||
LL | #![deny(unreachable_code)]
|
||||
| ^^^^^^^^^^^^^^^^
|
||||
|
||||
error: unreachable block in `while` expression
|
||||
error: unreachable block in `if` or `while` expression
|
||||
--> $DIR/expr_while.rs:22:20
|
||||
|
|
||||
LL | while {return} {
|
||||
@ -26,7 +26,7 @@ LL | while {return} {
|
||||
LL | |
|
||||
LL | | println!("I am dead.");
|
||||
LL | | }
|
||||
| |_____^ unreachable block in `while` expression
|
||||
| |_____^ unreachable block in `if` or `while` expression
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
|
||||
|
@ -9,33 +9,25 @@ fn _if_let_guard() {
|
||||
|
||||
() if (let 0 = 1) => {}
|
||||
//~^ ERROR `let` expressions in this position are experimental
|
||||
//~| ERROR `let` expressions are not supported here
|
||||
|
||||
() if (((let 0 = 1))) => {}
|
||||
//~^ ERROR `let` expressions in this position are experimental
|
||||
//~| ERROR `let` expressions are not supported here
|
||||
|
||||
() if true && let 0 = 1 => {}
|
||||
//~^ ERROR `let` expressions in this position are experimental
|
||||
//~| ERROR `let` expressions are not supported here
|
||||
|
||||
() if let 0 = 1 && true => {}
|
||||
//~^ ERROR `let` expressions in this position are experimental
|
||||
//~| ERROR `let` expressions are not supported here
|
||||
|
||||
() if (let 0 = 1) && true => {}
|
||||
//~^ ERROR `let` expressions in this position are experimental
|
||||
//~| ERROR `let` expressions are not supported here
|
||||
|
||||
() if true && (let 0 = 1) => {}
|
||||
//~^ ERROR `let` expressions in this position are experimental
|
||||
//~| ERROR `let` expressions are not supported here
|
||||
|
||||
() if (let 0 = 1) && (let 0 = 1) => {}
|
||||
//~^ ERROR `let` expressions in this position are experimental
|
||||
//~| ERROR `let` expressions in this position are experimental
|
||||
//~| 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
|
||||
@ -43,15 +35,9 @@ fn _if_let_guard() {
|
||||
//~| ERROR `let` expressions in this position are experimental
|
||||
//~| ERROR `let` expressions in this position are experimental
|
||||
//~| ERROR `let` expressions in this position are experimental
|
||||
//~| 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
|
||||
//~| ERROR `let` expressions are not supported here
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
@ -67,10 +53,8 @@ fn _macros() {
|
||||
}
|
||||
use_expr!((let 0 = 1 && 0 == 0));
|
||||
//~^ ERROR `let` expressions in this position are experimental
|
||||
//~| ERROR `let` expressions are not supported here
|
||||
use_expr!((let 0 = 1));
|
||||
//~^ ERROR `let` expressions in this position are experimental
|
||||
//~| ERROR `let` expressions are not supported here
|
||||
match () {
|
||||
#[cfg(FALSE)]
|
||||
() if let 0 = 1 => {}
|
||||
|
@ -1,5 +1,5 @@
|
||||
error: no rules expected the token `let`
|
||||
--> $DIR/feature-gate.rs:80:15
|
||||
--> $DIR/feature-gate.rs:64:15
|
||||
|
|
||||
LL | macro_rules! use_expr {
|
||||
| --------------------- when calling this macro
|
||||
@ -18,7 +18,7 @@ LL | () if let 0 = 1 => {}
|
||||
= help: you can write `if matches!(<expr>, <pattern>)` instead of `if let <pattern> = <expr>`
|
||||
|
||||
error[E0658]: `if let` guards are experimental
|
||||
--> $DIR/feature-gate.rs:76:12
|
||||
--> $DIR/feature-gate.rs:60:12
|
||||
|
|
||||
LL | () if let 0 = 1 => {}
|
||||
| ^^^^^^^^^^^^
|
||||
@ -38,7 +38,7 @@ LL | () if (let 0 = 1) => {}
|
||||
= help: you can write `matches!(<expr>, <pattern>)` instead of `let <pattern> = <expr>`
|
||||
|
||||
error[E0658]: `let` expressions in this position are experimental
|
||||
--> $DIR/feature-gate.rs:14:18
|
||||
--> $DIR/feature-gate.rs:13:18
|
||||
|
|
||||
LL | () if (((let 0 = 1))) => {}
|
||||
| ^^^^^^^^^
|
||||
@ -48,7 +48,7 @@ LL | () if (((let 0 = 1))) => {}
|
||||
= help: you can write `matches!(<expr>, <pattern>)` instead of `let <pattern> = <expr>`
|
||||
|
||||
error[E0658]: `let` expressions in this position are experimental
|
||||
--> $DIR/feature-gate.rs:18:23
|
||||
--> $DIR/feature-gate.rs:16:23
|
||||
|
|
||||
LL | () if true && let 0 = 1 => {}
|
||||
| ^^^^^^^^^
|
||||
@ -58,7 +58,7 @@ LL | () if true && let 0 = 1 => {}
|
||||
= help: you can write `matches!(<expr>, <pattern>)` instead of `let <pattern> = <expr>`
|
||||
|
||||
error[E0658]: `let` expressions in this position are experimental
|
||||
--> $DIR/feature-gate.rs:22:15
|
||||
--> $DIR/feature-gate.rs:19:15
|
||||
|
|
||||
LL | () if let 0 = 1 && true => {}
|
||||
| ^^^^^^^^^
|
||||
@ -68,7 +68,7 @@ LL | () if let 0 = 1 && true => {}
|
||||
= help: you can write `matches!(<expr>, <pattern>)` instead of `let <pattern> = <expr>`
|
||||
|
||||
error[E0658]: `let` expressions in this position are experimental
|
||||
--> $DIR/feature-gate.rs:26:16
|
||||
--> $DIR/feature-gate.rs:22:16
|
||||
|
|
||||
LL | () if (let 0 = 1) && true => {}
|
||||
| ^^^^^^^^^
|
||||
@ -78,7 +78,7 @@ LL | () if (let 0 = 1) && true => {}
|
||||
= help: you can write `matches!(<expr>, <pattern>)` instead of `let <pattern> = <expr>`
|
||||
|
||||
error[E0658]: `let` expressions in this position are experimental
|
||||
--> $DIR/feature-gate.rs:30:24
|
||||
--> $DIR/feature-gate.rs:25:24
|
||||
|
|
||||
LL | () if true && (let 0 = 1) => {}
|
||||
| ^^^^^^^^^
|
||||
@ -88,7 +88,7 @@ LL | () if true && (let 0 = 1) => {}
|
||||
= help: you can write `matches!(<expr>, <pattern>)` instead of `let <pattern> = <expr>`
|
||||
|
||||
error[E0658]: `let` expressions in this position are experimental
|
||||
--> $DIR/feature-gate.rs:34:16
|
||||
--> $DIR/feature-gate.rs:28:16
|
||||
|
|
||||
LL | () if (let 0 = 1) && (let 0 = 1) => {}
|
||||
| ^^^^^^^^^
|
||||
@ -98,7 +98,7 @@ LL | () if (let 0 = 1) && (let 0 = 1) => {}
|
||||
= help: you can write `matches!(<expr>, <pattern>)` instead of `let <pattern> = <expr>`
|
||||
|
||||
error[E0658]: `let` expressions in this position are experimental
|
||||
--> $DIR/feature-gate.rs:34:31
|
||||
--> $DIR/feature-gate.rs:28:31
|
||||
|
|
||||
LL | () if (let 0 = 1) && (let 0 = 1) => {}
|
||||
| ^^^^^^^^^
|
||||
@ -108,7 +108,7 @@ LL | () if (let 0 = 1) && (let 0 = 1) => {}
|
||||
= help: you can write `matches!(<expr>, <pattern>)` instead of `let <pattern> = <expr>`
|
||||
|
||||
error[E0658]: `let` expressions in this position are experimental
|
||||
--> $DIR/feature-gate.rs:40:15
|
||||
--> $DIR/feature-gate.rs:32:15
|
||||
|
|
||||
LL | () if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) => {}
|
||||
| ^^^^^^^^^
|
||||
@ -118,7 +118,7 @@ LL | () if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 =
|
||||
= help: you can write `matches!(<expr>, <pattern>)` instead of `let <pattern> = <expr>`
|
||||
|
||||
error[E0658]: `let` expressions in this position are experimental
|
||||
--> $DIR/feature-gate.rs:40:28
|
||||
--> $DIR/feature-gate.rs:32:28
|
||||
|
|
||||
LL | () if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) => {}
|
||||
| ^^^^^^^^^
|
||||
@ -128,7 +128,7 @@ LL | () if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 =
|
||||
= help: you can write `matches!(<expr>, <pattern>)` instead of `let <pattern> = <expr>`
|
||||
|
||||
error[E0658]: `let` expressions in this position are experimental
|
||||
--> $DIR/feature-gate.rs:40:42
|
||||
--> $DIR/feature-gate.rs:32:42
|
||||
|
|
||||
LL | () if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) => {}
|
||||
| ^^^^^^^^^
|
||||
@ -138,7 +138,7 @@ LL | () if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 =
|
||||
= help: you can write `matches!(<expr>, <pattern>)` instead of `let <pattern> = <expr>`
|
||||
|
||||
error[E0658]: `let` expressions in this position are experimental
|
||||
--> $DIR/feature-gate.rs:40:55
|
||||
--> $DIR/feature-gate.rs:32:55
|
||||
|
|
||||
LL | () if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) => {}
|
||||
| ^^^^^^^^^
|
||||
@ -148,7 +148,7 @@ LL | () if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 =
|
||||
= help: you can write `matches!(<expr>, <pattern>)` instead of `let <pattern> = <expr>`
|
||||
|
||||
error[E0658]: `let` expressions in this position are experimental
|
||||
--> $DIR/feature-gate.rs:40:68
|
||||
--> $DIR/feature-gate.rs:32:68
|
||||
|
|
||||
LL | () if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) => {}
|
||||
| ^^^^^^^^^
|
||||
@ -158,7 +158,7 @@ LL | () if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 =
|
||||
= help: you can write `matches!(<expr>, <pattern>)` instead of `let <pattern> = <expr>`
|
||||
|
||||
error[E0658]: `let` expressions in this position are experimental
|
||||
--> $DIR/feature-gate.rs:52:15
|
||||
--> $DIR/feature-gate.rs:39:15
|
||||
|
|
||||
LL | () if let Range { start: _, end: _ } = (true..true) && false => {}
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
@ -168,7 +168,7 @@ LL | () if let Range { start: _, end: _ } = (true..true) && false => {}
|
||||
= help: you can write `matches!(<expr>, <pattern>)` instead of `let <pattern> = <expr>`
|
||||
|
||||
error[E0658]: `let` expressions in this position are experimental
|
||||
--> $DIR/feature-gate.rs:68:16
|
||||
--> $DIR/feature-gate.rs:54:16
|
||||
|
|
||||
LL | use_expr!((let 0 = 1 && 0 == 0));
|
||||
| ^^^^^^^^^
|
||||
@ -178,7 +178,7 @@ LL | use_expr!((let 0 = 1 && 0 == 0));
|
||||
= help: you can write `matches!(<expr>, <pattern>)` instead of `let <pattern> = <expr>`
|
||||
|
||||
error[E0658]: `let` expressions in this position are experimental
|
||||
--> $DIR/feature-gate.rs:71:16
|
||||
--> $DIR/feature-gate.rs:56:16
|
||||
|
|
||||
LL | use_expr!((let 0 = 1));
|
||||
| ^^^^^^^^^
|
||||
@ -187,134 +187,6 @@ LL | use_expr!((let 0 = 1));
|
||||
= help: add `#![feature(let_chains)]` to the crate attributes to enable
|
||||
= help: you can write `matches!(<expr>, <pattern>)` instead of `let <pattern> = <expr>`
|
||||
|
||||
error: `let` expressions are not supported here
|
||||
--> $DIR/feature-gate.rs:10:16
|
||||
|
|
||||
LL | () if (let 0 = 1) => {}
|
||||
| ^^^^^^^^^
|
||||
|
|
||||
= note: only supported directly without parentheses in conditions of `if`- and `while`-expressions, as well as in `let` chains within parentheses
|
||||
|
||||
error: `let` expressions are not supported here
|
||||
--> $DIR/feature-gate.rs:14:18
|
||||
|
|
||||
LL | () if (((let 0 = 1))) => {}
|
||||
| ^^^^^^^^^
|
||||
|
|
||||
= note: only supported directly without parentheses in conditions of `if`- and `while`-expressions, as well as in `let` chains within parentheses
|
||||
|
||||
error: `let` expressions are not supported here
|
||||
--> $DIR/feature-gate.rs:18:23
|
||||
|
|
||||
LL | () if true && let 0 = 1 => {}
|
||||
| ^^^^^^^^^
|
||||
|
|
||||
= note: only supported directly without parentheses in conditions of `if`- and `while`-expressions, as well as in `let` chains within parentheses
|
||||
|
||||
error: `let` expressions are not supported here
|
||||
--> $DIR/feature-gate.rs:22:15
|
||||
|
|
||||
LL | () if let 0 = 1 && true => {}
|
||||
| ^^^^^^^^^
|
||||
|
|
||||
= note: only supported directly without parentheses in conditions of `if`- and `while`-expressions, as well as in `let` chains within parentheses
|
||||
|
||||
error: `let` expressions are not supported here
|
||||
--> $DIR/feature-gate.rs:26:16
|
||||
|
|
||||
LL | () if (let 0 = 1) && true => {}
|
||||
| ^^^^^^^^^
|
||||
|
|
||||
= note: only supported directly without parentheses in conditions of `if`- and `while`-expressions, as well as in `let` chains within parentheses
|
||||
|
||||
error: `let` expressions are not supported here
|
||||
--> $DIR/feature-gate.rs:30:24
|
||||
|
|
||||
LL | () if true && (let 0 = 1) => {}
|
||||
| ^^^^^^^^^
|
||||
|
|
||||
= note: only supported directly without parentheses in conditions of `if`- and `while`-expressions, as well as in `let` chains within parentheses
|
||||
|
||||
error: `let` expressions are not supported here
|
||||
--> $DIR/feature-gate.rs:34:16
|
||||
|
|
||||
LL | () if (let 0 = 1) && (let 0 = 1) => {}
|
||||
| ^^^^^^^^^
|
||||
|
|
||||
= note: only supported directly without parentheses in conditions of `if`- and `while`-expressions, as well as in `let` chains within parentheses
|
||||
|
||||
error: `let` expressions are not supported here
|
||||
--> $DIR/feature-gate.rs:34:31
|
||||
|
|
||||
LL | () if (let 0 = 1) && (let 0 = 1) => {}
|
||||
| ^^^^^^^^^
|
||||
|
|
||||
= note: only supported directly without parentheses in conditions of `if`- and `while`-expressions, as well as in `let` chains within parentheses
|
||||
|
||||
error: `let` expressions are not supported here
|
||||
--> $DIR/feature-gate.rs:40:15
|
||||
|
|
||||
LL | () if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) => {}
|
||||
| ^^^^^^^^^
|
||||
|
|
||||
= note: only supported directly without parentheses in conditions of `if`- and `while`-expressions, as well as in `let` chains within parentheses
|
||||
|
||||
error: `let` expressions are not supported here
|
||||
--> $DIR/feature-gate.rs:40:28
|
||||
|
|
||||
LL | () if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) => {}
|
||||
| ^^^^^^^^^
|
||||
|
|
||||
= note: only supported directly without parentheses in conditions of `if`- and `while`-expressions, as well as in `let` chains within parentheses
|
||||
|
||||
error: `let` expressions are not supported here
|
||||
--> $DIR/feature-gate.rs:40:42
|
||||
|
|
||||
LL | () if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) => {}
|
||||
| ^^^^^^^^^
|
||||
|
|
||||
= note: only supported directly without parentheses in conditions of `if`- and `while`-expressions, as well as in `let` chains within parentheses
|
||||
|
||||
error: `let` expressions are not supported here
|
||||
--> $DIR/feature-gate.rs:40:55
|
||||
|
|
||||
LL | () if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) => {}
|
||||
| ^^^^^^^^^
|
||||
|
|
||||
= note: only supported directly without parentheses in conditions of `if`- and `while`-expressions, as well as in `let` chains within parentheses
|
||||
|
||||
error: `let` expressions are not supported here
|
||||
--> $DIR/feature-gate.rs:40:68
|
||||
|
|
||||
LL | () if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) => {}
|
||||
| ^^^^^^^^^
|
||||
|
|
||||
= note: only supported directly without parentheses in conditions of `if`- and `while`-expressions, as well as in `let` chains within parentheses
|
||||
|
||||
error: `let` expressions are not supported here
|
||||
--> $DIR/feature-gate.rs:52:15
|
||||
|
|
||||
LL | () if let Range { start: _, end: _ } = (true..true) && false => {}
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= note: only supported directly without parentheses in conditions of `if`- and `while`-expressions, as well as in `let` chains within parentheses
|
||||
|
||||
error: `let` expressions are not supported here
|
||||
--> $DIR/feature-gate.rs:68:16
|
||||
|
|
||||
LL | use_expr!((let 0 = 1 && 0 == 0));
|
||||
| ^^^^^^^^^
|
||||
|
|
||||
= note: only supported directly without parentheses in conditions of `if`- and `while`-expressions, as well as in `let` chains within parentheses
|
||||
|
||||
error: `let` expressions are not supported here
|
||||
--> $DIR/feature-gate.rs:71:16
|
||||
|
|
||||
LL | use_expr!((let 0 = 1));
|
||||
| ^^^^^^^^^
|
||||
|
|
||||
= note: only supported directly without parentheses in conditions of `if`- and `while`-expressions, as well as in `let` chains within parentheses
|
||||
|
||||
error: aborting due to 35 previous errors
|
||||
error: aborting due to 19 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0658`.
|
||||
|
@ -201,7 +201,6 @@ fn outside_if_and_while_expr() {
|
||||
|
||||
(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
|
||||
|
@ -1,5 +1,5 @@
|
||||
error: expressions must be enclosed in braces to be used as const generic arguments
|
||||
--> $DIR/disallowed-positions.rs:236:9
|
||||
--> $DIR/disallowed-positions.rs:235:9
|
||||
|
|
||||
LL | true && let 1 = 1
|
||||
| ^^^^^^^^^^^^^^^^^
|
||||
@ -15,7 +15,8 @@ error: `let` expressions are not supported here
|
||||
LL | if &let 0 = 0 {}
|
||||
| ^^^^^^^^^
|
||||
|
|
||||
= note: only supported directly without parentheses in conditions of `if`- and `while`-expressions, as well as in `let` chains within parentheses
|
||||
= 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
|
||||
@ -23,7 +24,8 @@ error: `let` expressions are not supported here
|
||||
LL | if !let 0 = 0 {}
|
||||
| ^^^^^^^^^
|
||||
|
|
||||
= note: only supported directly without parentheses in conditions of `if`- and `while`-expressions, as well as in `let` chains within parentheses
|
||||
= 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
|
||||
@ -31,7 +33,8 @@ error: `let` expressions are not supported here
|
||||
LL | if *let 0 = 0 {}
|
||||
| ^^^^^^^^^
|
||||
|
|
||||
= note: only supported directly without parentheses in conditions of `if`- and `while`-expressions, as well as in `let` chains within parentheses
|
||||
= 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
|
||||
@ -39,7 +42,8 @@ error: `let` expressions are not supported here
|
||||
LL | if -let 0 = 0 {}
|
||||
| ^^^^^^^^^
|
||||
|
|
||||
= note: only supported directly without parentheses in conditions of `if`- and `while`-expressions, as well as in `let` chains within parentheses
|
||||
= 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
|
||||
@ -47,7 +51,8 @@ error: `let` expressions are not supported here
|
||||
LL | if (let 0 = 0)? {}
|
||||
| ^^^^^^^^^
|
||||
|
|
||||
= note: only supported directly without parentheses in conditions of `if`- and `while`-expressions, as well as in `let` chains within parentheses
|
||||
= 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
|
||||
@ -55,7 +60,8 @@ error: `let` expressions are not supported here
|
||||
LL | if true || let 0 = 0 {}
|
||||
| ^^^^^^^^^
|
||||
|
|
||||
= note: only supported directly without parentheses in conditions of `if`- and `while`-expressions, as well as in `let` chains within parentheses
|
||||
= 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
|
||||
@ -63,7 +69,8 @@ error: `let` expressions are not supported here
|
||||
LL | if (true || let 0 = 0) {}
|
||||
| ^^^^^^^^^
|
||||
|
|
||||
= note: only supported directly without parentheses in conditions of `if`- and `while`-expressions, as well as in `let` chains within parentheses
|
||||
= 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
|
||||
@ -71,7 +78,8 @@ error: `let` expressions are not supported here
|
||||
LL | if true && (true || let 0 = 0) {}
|
||||
| ^^^^^^^^^
|
||||
|
|
||||
= note: only supported directly without parentheses in conditions of `if`- and `while`-expressions, as well as in `let` chains within parentheses
|
||||
= 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
|
||||
@ -79,7 +87,8 @@ error: `let` expressions are not supported here
|
||||
LL | if true || (true && let 0 = 0) {}
|
||||
| ^^^^^^^^^
|
||||
|
|
||||
= note: only supported directly without parentheses in conditions of `if`- and `while`-expressions, as well as in `let` chains within parentheses
|
||||
= 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
|
||||
@ -87,7 +96,8 @@ error: `let` expressions are not supported here
|
||||
LL | if x = let 0 = 0 {}
|
||||
| ^^^^^^^^^
|
||||
|
|
||||
= note: only supported directly without parentheses in conditions of `if`- and `while`-expressions, as well as in `let` chains within parentheses
|
||||
= 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
|
||||
@ -95,7 +105,8 @@ error: `let` expressions are not supported here
|
||||
LL | if true..(let 0 = 0) {}
|
||||
| ^^^^^^^^^
|
||||
|
|
||||
= note: only supported directly without parentheses in conditions of `if`- and `while`-expressions, as well as in `let` chains within parentheses
|
||||
= 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
|
||||
@ -103,7 +114,8 @@ error: `let` expressions are not supported here
|
||||
LL | if ..(let 0 = 0) {}
|
||||
| ^^^^^^^^^
|
||||
|
|
||||
= note: only supported directly without parentheses in conditions of `if`- and `while`-expressions, as well as in `let` chains within parentheses
|
||||
= 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
|
||||
@ -111,7 +123,8 @@ error: `let` expressions are not supported here
|
||||
LL | if (let 0 = 0).. {}
|
||||
| ^^^^^^^^^
|
||||
|
|
||||
= note: only supported directly without parentheses in conditions of `if`- and `while`-expressions, as well as in `let` chains within parentheses
|
||||
= 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
|
||||
@ -119,7 +132,8 @@ error: `let` expressions are not supported here
|
||||
LL | if let Range { start: _, end: _ } = true..true && false {}
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= note: only supported directly without parentheses in conditions of `if`- and `while`-expressions, as well as in `let` chains within parentheses
|
||||
= 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
|
||||
@ -127,7 +141,8 @@ error: `let` expressions are not supported here
|
||||
LL | if let Range { start: _, end: _ } = true..true || false {}
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= note: only supported directly without parentheses in conditions of `if`- and `while`-expressions, as well as in `let` chains within parentheses
|
||||
= 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
|
||||
@ -135,7 +150,8 @@ error: `let` expressions are not supported here
|
||||
LL | if let Range { start: F, end } = F..|| true {}
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= note: only supported directly without parentheses in conditions of `if`- and `while`-expressions, as well as in `let` chains within parentheses
|
||||
= 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
|
||||
@ -143,7 +159,8 @@ error: `let` expressions are not supported here
|
||||
LL | if let Range { start: true, end } = t..&&false {}
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= note: only supported directly without parentheses in conditions of `if`- and `while`-expressions, as well as in `let` chains within parentheses
|
||||
= 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
|
||||
@ -151,7 +168,8 @@ error: `let` expressions are not supported here
|
||||
LL | if let true = let true = true {}
|
||||
| ^^^^^^^^^^^^^^^
|
||||
|
|
||||
= note: only supported directly without parentheses in conditions of `if`- and `while`-expressions, as well as in `let` chains within parentheses
|
||||
= 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
|
||||
@ -159,7 +177,8 @@ error: `let` expressions are not supported here
|
||||
LL | while &let 0 = 0 {}
|
||||
| ^^^^^^^^^
|
||||
|
|
||||
= note: only supported directly without parentheses in conditions of `if`- and `while`-expressions, as well as in `let` chains within parentheses
|
||||
= 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
|
||||
@ -167,7 +186,8 @@ error: `let` expressions are not supported here
|
||||
LL | while !let 0 = 0 {}
|
||||
| ^^^^^^^^^
|
||||
|
|
||||
= note: only supported directly without parentheses in conditions of `if`- and `while`-expressions, as well as in `let` chains within parentheses
|
||||
= 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
|
||||
@ -175,7 +195,8 @@ error: `let` expressions are not supported here
|
||||
LL | while *let 0 = 0 {}
|
||||
| ^^^^^^^^^
|
||||
|
|
||||
= note: only supported directly without parentheses in conditions of `if`- and `while`-expressions, as well as in `let` chains within parentheses
|
||||
= 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
|
||||
@ -183,7 +204,8 @@ error: `let` expressions are not supported here
|
||||
LL | while -let 0 = 0 {}
|
||||
| ^^^^^^^^^
|
||||
|
|
||||
= note: only supported directly without parentheses in conditions of `if`- and `while`-expressions, as well as in `let` chains within parentheses
|
||||
= 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
|
||||
@ -191,7 +213,8 @@ error: `let` expressions are not supported here
|
||||
LL | while (let 0 = 0)? {}
|
||||
| ^^^^^^^^^
|
||||
|
|
||||
= note: only supported directly without parentheses in conditions of `if`- and `while`-expressions, as well as in `let` chains within parentheses
|
||||
= 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
|
||||
@ -199,7 +222,8 @@ error: `let` expressions are not supported here
|
||||
LL | while true || let 0 = 0 {}
|
||||
| ^^^^^^^^^
|
||||
|
|
||||
= note: only supported directly without parentheses in conditions of `if`- and `while`-expressions, as well as in `let` chains within parentheses
|
||||
= 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
|
||||
@ -207,7 +231,8 @@ error: `let` expressions are not supported here
|
||||
LL | while (true || let 0 = 0) {}
|
||||
| ^^^^^^^^^
|
||||
|
|
||||
= note: only supported directly without parentheses in conditions of `if`- and `while`-expressions, as well as in `let` chains within parentheses
|
||||
= 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
|
||||
@ -215,7 +240,8 @@ error: `let` expressions are not supported here
|
||||
LL | while true && (true || let 0 = 0) {}
|
||||
| ^^^^^^^^^
|
||||
|
|
||||
= note: only supported directly without parentheses in conditions of `if`- and `while`-expressions, as well as in `let` chains within parentheses
|
||||
= 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
|
||||
@ -223,7 +249,8 @@ error: `let` expressions are not supported here
|
||||
LL | while true || (true && let 0 = 0) {}
|
||||
| ^^^^^^^^^
|
||||
|
|
||||
= note: only supported directly without parentheses in conditions of `if`- and `while`-expressions, as well as in `let` chains within parentheses
|
||||
= 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
|
||||
@ -231,7 +258,8 @@ error: `let` expressions are not supported here
|
||||
LL | while x = let 0 = 0 {}
|
||||
| ^^^^^^^^^
|
||||
|
|
||||
= note: only supported directly without parentheses in conditions of `if`- and `while`-expressions, as well as in `let` chains within parentheses
|
||||
= 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
|
||||
@ -239,7 +267,8 @@ error: `let` expressions are not supported here
|
||||
LL | while true..(let 0 = 0) {}
|
||||
| ^^^^^^^^^
|
||||
|
|
||||
= note: only supported directly without parentheses in conditions of `if`- and `while`-expressions, as well as in `let` chains within parentheses
|
||||
= 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
|
||||
@ -247,7 +276,8 @@ error: `let` expressions are not supported here
|
||||
LL | while ..(let 0 = 0) {}
|
||||
| ^^^^^^^^^
|
||||
|
|
||||
= note: only supported directly without parentheses in conditions of `if`- and `while`-expressions, as well as in `let` chains within parentheses
|
||||
= 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
|
||||
@ -255,7 +285,8 @@ error: `let` expressions are not supported here
|
||||
LL | while (let 0 = 0).. {}
|
||||
| ^^^^^^^^^
|
||||
|
|
||||
= note: only supported directly without parentheses in conditions of `if`- and `while`-expressions, as well as in `let` chains within parentheses
|
||||
= 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
|
||||
@ -263,7 +294,8 @@ error: `let` expressions are not supported here
|
||||
LL | while let Range { start: _, end: _ } = true..true && false {}
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= note: only supported directly without parentheses in conditions of `if`- and `while`-expressions, as well as in `let` chains within parentheses
|
||||
= 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
|
||||
@ -271,7 +303,8 @@ error: `let` expressions are not supported here
|
||||
LL | while let Range { start: _, end: _ } = true..true || false {}
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= note: only supported directly without parentheses in conditions of `if`- and `while`-expressions, as well as in `let` chains within parentheses
|
||||
= 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
|
||||
@ -279,7 +312,8 @@ error: `let` expressions are not supported here
|
||||
LL | while let Range { start: F, end } = F..|| true {}
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= note: only supported directly without parentheses in conditions of `if`- and `while`-expressions, as well as in `let` chains within parentheses
|
||||
= 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
|
||||
@ -287,7 +321,8 @@ error: `let` expressions are not supported here
|
||||
LL | while let Range { start: true, end } = t..&&false {}
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= note: only supported directly without parentheses in conditions of `if`- and `while`-expressions, as well as in `let` chains within parentheses
|
||||
= 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
|
||||
@ -295,7 +330,8 @@ error: `let` expressions are not supported here
|
||||
LL | while let true = let true = true {}
|
||||
| ^^^^^^^^^^^^^^^
|
||||
|
|
||||
= note: only supported directly without parentheses in conditions of `if`- and `while`-expressions, as well as in `let` chains within parentheses
|
||||
= 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
|
||||
@ -303,7 +339,8 @@ error: `let` expressions are not supported here
|
||||
LL | &let 0 = 0;
|
||||
| ^^^^^^^^^
|
||||
|
|
||||
= note: only supported directly without parentheses in conditions of `if`- and `while`-expressions, as well as in `let` chains within parentheses
|
||||
= 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
|
||||
@ -311,7 +348,8 @@ error: `let` expressions are not supported here
|
||||
LL | !let 0 = 0;
|
||||
| ^^^^^^^^^
|
||||
|
|
||||
= note: only supported directly without parentheses in conditions of `if`- and `while`-expressions, as well as in `let` chains within parentheses
|
||||
= 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
|
||||
@ -319,7 +357,8 @@ error: `let` expressions are not supported here
|
||||
LL | *let 0 = 0;
|
||||
| ^^^^^^^^^
|
||||
|
|
||||
= note: only supported directly without parentheses in conditions of `if`- and `while`-expressions, as well as in `let` chains within parentheses
|
||||
= 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
|
||||
@ -327,7 +366,8 @@ error: `let` expressions are not supported here
|
||||
LL | -let 0 = 0;
|
||||
| ^^^^^^^^^
|
||||
|
|
||||
= note: only supported directly without parentheses in conditions of `if`- and `while`-expressions, as well as in `let` chains within parentheses
|
||||
= 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
|
||||
@ -335,7 +375,8 @@ error: `let` expressions are not supported here
|
||||
LL | (let 0 = 0)?;
|
||||
| ^^^^^^^^^
|
||||
|
|
||||
= note: only supported directly without parentheses in conditions of `if`- and `while`-expressions, as well as in `let` chains within parentheses
|
||||
= 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
|
||||
@ -343,7 +384,8 @@ error: `let` expressions are not supported here
|
||||
LL | true || let 0 = 0;
|
||||
| ^^^^^^^^^
|
||||
|
|
||||
= note: only supported directly without parentheses in conditions of `if`- and `while`-expressions, as well as in `let` chains within parentheses
|
||||
= 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
|
||||
@ -351,7 +393,8 @@ error: `let` expressions are not supported here
|
||||
LL | (true || let 0 = 0);
|
||||
| ^^^^^^^^^
|
||||
|
|
||||
= note: only supported directly without parentheses in conditions of `if`- and `while`-expressions, as well as in `let` chains within parentheses
|
||||
= 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
|
||||
@ -359,7 +402,8 @@ error: `let` expressions are not supported here
|
||||
LL | true && (true || let 0 = 0);
|
||||
| ^^^^^^^^^
|
||||
|
|
||||
= note: only supported directly without parentheses in conditions of `if`- and `while`-expressions, as well as in `let` chains within parentheses
|
||||
= 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
|
||||
@ -367,7 +411,8 @@ error: `let` expressions are not supported here
|
||||
LL | x = let 0 = 0;
|
||||
| ^^^^^^^^^
|
||||
|
|
||||
= note: only supported directly without parentheses in conditions of `if`- and `while`-expressions, as well as in `let` chains within parentheses
|
||||
= 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
|
||||
@ -375,7 +420,8 @@ error: `let` expressions are not supported here
|
||||
LL | true..(let 0 = 0);
|
||||
| ^^^^^^^^^
|
||||
|
|
||||
= note: only supported directly without parentheses in conditions of `if`- and `while`-expressions, as well as in `let` chains within parentheses
|
||||
= 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
|
||||
@ -383,7 +429,8 @@ error: `let` expressions are not supported here
|
||||
LL | ..(let 0 = 0);
|
||||
| ^^^^^^^^^
|
||||
|
|
||||
= note: only supported directly without parentheses in conditions of `if`- and `while`-expressions, as well as in `let` chains within parentheses
|
||||
= 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
|
||||
@ -391,7 +438,8 @@ error: `let` expressions are not supported here
|
||||
LL | (let 0 = 0)..;
|
||||
| ^^^^^^^^^
|
||||
|
|
||||
= note: only supported directly without parentheses in conditions of `if`- and `while`-expressions, as well as in `let` chains within parentheses
|
||||
= 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
|
||||
@ -399,7 +447,8 @@ error: `let` expressions are not supported here
|
||||
LL | (let Range { start: _, end: _ } = true..true || false);
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= note: only supported directly without parentheses in conditions of `if`- and `while`-expressions, as well as in `let` chains within parentheses
|
||||
= 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
|
||||
@ -407,55 +456,53 @@ error: `let` expressions are not supported here
|
||||
LL | (let true = let true = true);
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= note: only supported directly without parentheses in conditions of `if`- and `while`-expressions, as well as in `let` chains within parentheses
|
||||
= 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 without parentheses in conditions of `if`- and `while`-expressions, as well as in `let` chains within parentheses
|
||||
|
||||
error: `let` expressions are not supported here
|
||||
--> $DIR/disallowed-positions.rs:207:6
|
||||
--> $DIR/disallowed-positions.rs:206:6
|
||||
|
|
||||
LL | &let 0 = 0
|
||||
| ^^^^^^^^^
|
||||
|
|
||||
= note: only supported directly without parentheses in conditions of `if`- and `while`-expressions, as well as in `let` chains within parentheses
|
||||
= 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
|
||||
--> $DIR/disallowed-positions.rs:217:17
|
||||
|
|
||||
LL | true && let 1 = 1
|
||||
| ^^^^^^^^^
|
||||
|
|
||||
= note: only supported directly without parentheses in conditions of `if`- and `while`-expressions, as well as in `let` chains within parentheses
|
||||
= 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:222:17
|
||||
--> $DIR/disallowed-positions.rs:221:17
|
||||
|
|
||||
LL | true && let 1 = 1
|
||||
| ^^^^^^^^^
|
||||
|
|
||||
= note: only supported directly without parentheses in conditions of `if`- and `while`-expressions, as well as in `let` chains within parentheses
|
||||
= 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:226:17
|
||||
--> $DIR/disallowed-positions.rs:225:17
|
||||
|
|
||||
LL | true && let 1 = 1
|
||||
| ^^^^^^^^^
|
||||
|
|
||||
= note: only supported directly without parentheses in conditions of `if`- and `while`-expressions, as well as in `let` chains within parentheses
|
||||
= 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:236:17
|
||||
--> $DIR/disallowed-positions.rs:235:17
|
||||
|
|
||||
LL | true && let 1 = 1
|
||||
| ^^^^^^^^^
|
||||
|
|
||||
= note: only supported directly without parentheses in conditions of `if`- and `while`-expressions, as well as in `let` chains within parentheses
|
||||
= note: only supported directly in conditions of `if`- and `while`-expressions
|
||||
= note: as well as when nested within `&&` and parenthesis in those conditions
|
||||
|
||||
warning: the feature `const_generics` is incomplete and may not be safe to use and/or cause compiler crashes
|
||||
--> $DIR/disallowed-positions.rs:20:12
|
||||
@ -939,7 +986,7 @@ LL | (let Range { start: _, end: _ } = true..true || false);
|
||||
found struct `std::ops::Range<_>`
|
||||
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/disallowed-positions.rs:207:5
|
||||
--> $DIR/disallowed-positions.rs:206:5
|
||||
|
|
||||
LL | fn outside_if_and_while_expr() {
|
||||
| - help: try adding a return type: `-> &bool`
|
||||
@ -960,7 +1007,7 @@ note: required by `branch`
|
||||
LL | fn branch(self) -> ControlFlow<Self::Residual, Self::Output>;
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: aborting due to 104 previous errors; 2 warnings emitted
|
||||
error: aborting due to 103 previous errors; 2 warnings emitted
|
||||
|
||||
Some errors have detailed explanations: E0277, E0308, E0600, E0614.
|
||||
For more information about an error, try `rustc --explain E0277`.
|
||||
|
@ -13,33 +13,25 @@ fn _if() {
|
||||
|
||||
if (let 0 = 1) {}
|
||||
//~^ ERROR `let` expressions in this position are experimental [E0658]
|
||||
//~| ERROR invalid parentheses around `let` expression in `if let`
|
||||
|
||||
if (((let 0 = 1))) {}
|
||||
//~^ ERROR `let` expressions in this position are experimental [E0658]
|
||||
//~| ERROR invalid parentheses around `let` expression in `if let`
|
||||
|
||||
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]
|
||||
@ -47,15 +39,9 @@ fn _if() {
|
||||
//~| 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() {
|
||||
@ -63,33 +49,25 @@ fn _while() {
|
||||
|
||||
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]
|
||||
@ -97,15 +75,9 @@ fn _while() {
|
||||
//~| 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() {
|
||||
@ -122,12 +94,8 @@ fn _macros() {
|
||||
}
|
||||
use_expr!((let 0 = 1 && 0 == 0));
|
||||
//~^ ERROR `let` expressions in this position are experimental [E0658]
|
||||
//~| ERROR `let` expressions are not supported here
|
||||
//~| ERROR `let` expressions are not supported here
|
||||
use_expr!((let 0 = 1));
|
||||
//~^ ERROR `let` expressions in this position are experimental [E0658]
|
||||
//~| ERROR invalid parentheses around `let` expression in `if let`
|
||||
//~| 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);
|
||||
|
@ -1,5 +1,5 @@
|
||||
error: no rules expected the token `let`
|
||||
--> $DIR/feature-gate.rs:133:15
|
||||
--> $DIR/feature-gate.rs:101:15
|
||||
|
|
||||
LL | macro_rules! use_expr {
|
||||
| --------------------- when calling this macro
|
||||
@ -18,7 +18,7 @@ LL | if (let 0 = 1) {}
|
||||
= help: you can write `matches!(<expr>, <pattern>)` instead of `let <pattern> = <expr>`
|
||||
|
||||
error[E0658]: `let` expressions in this position are experimental
|
||||
--> $DIR/feature-gate.rs:18:11
|
||||
--> $DIR/feature-gate.rs:17:11
|
||||
|
|
||||
LL | if (((let 0 = 1))) {}
|
||||
| ^^^^^^^^^
|
||||
@ -28,7 +28,7 @@ LL | if (((let 0 = 1))) {}
|
||||
= help: you can write `matches!(<expr>, <pattern>)` instead of `let <pattern> = <expr>`
|
||||
|
||||
error[E0658]: `let` expressions in this position are experimental
|
||||
--> $DIR/feature-gate.rs:22:16
|
||||
--> $DIR/feature-gate.rs:20:16
|
||||
|
|
||||
LL | if true && let 0 = 1 {}
|
||||
| ^^^^^^^^^
|
||||
@ -38,7 +38,7 @@ LL | if true && let 0 = 1 {}
|
||||
= help: you can write `matches!(<expr>, <pattern>)` instead of `let <pattern> = <expr>`
|
||||
|
||||
error[E0658]: `let` expressions in this position are experimental
|
||||
--> $DIR/feature-gate.rs:26:8
|
||||
--> $DIR/feature-gate.rs:23:8
|
||||
|
|
||||
LL | if let 0 = 1 && true {}
|
||||
| ^^^^^^^^^
|
||||
@ -48,7 +48,7 @@ LL | if let 0 = 1 && true {}
|
||||
= help: you can write `matches!(<expr>, <pattern>)` instead of `let <pattern> = <expr>`
|
||||
|
||||
error[E0658]: `let` expressions in this position are experimental
|
||||
--> $DIR/feature-gate.rs:30:9
|
||||
--> $DIR/feature-gate.rs:26:9
|
||||
|
|
||||
LL | if (let 0 = 1) && true {}
|
||||
| ^^^^^^^^^
|
||||
@ -58,7 +58,7 @@ LL | if (let 0 = 1) && true {}
|
||||
= help: you can write `matches!(<expr>, <pattern>)` instead of `let <pattern> = <expr>`
|
||||
|
||||
error[E0658]: `let` expressions in this position are experimental
|
||||
--> $DIR/feature-gate.rs:34:17
|
||||
--> $DIR/feature-gate.rs:29:17
|
||||
|
|
||||
LL | if true && (let 0 = 1) {}
|
||||
| ^^^^^^^^^
|
||||
@ -68,7 +68,7 @@ LL | if true && (let 0 = 1) {}
|
||||
= help: you can write `matches!(<expr>, <pattern>)` instead of `let <pattern> = <expr>`
|
||||
|
||||
error[E0658]: `let` expressions in this position are experimental
|
||||
--> $DIR/feature-gate.rs:38:9
|
||||
--> $DIR/feature-gate.rs:32:9
|
||||
|
|
||||
LL | if (let 0 = 1) && (let 0 = 1) {}
|
||||
| ^^^^^^^^^
|
||||
@ -78,7 +78,7 @@ LL | if (let 0 = 1) && (let 0 = 1) {}
|
||||
= help: you can write `matches!(<expr>, <pattern>)` instead of `let <pattern> = <expr>`
|
||||
|
||||
error[E0658]: `let` expressions in this position are experimental
|
||||
--> $DIR/feature-gate.rs:38:24
|
||||
--> $DIR/feature-gate.rs:32:24
|
||||
|
|
||||
LL | if (let 0 = 1) && (let 0 = 1) {}
|
||||
| ^^^^^^^^^
|
||||
@ -88,7 +88,7 @@ LL | if (let 0 = 1) && (let 0 = 1) {}
|
||||
= help: you can write `matches!(<expr>, <pattern>)` instead of `let <pattern> = <expr>`
|
||||
|
||||
error[E0658]: `let` expressions in this position are experimental
|
||||
--> $DIR/feature-gate.rs:44:8
|
||||
--> $DIR/feature-gate.rs:36:8
|
||||
|
|
||||
LL | if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {}
|
||||
| ^^^^^^^^^
|
||||
@ -98,7 +98,7 @@ LL | if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {}
|
||||
= help: you can write `matches!(<expr>, <pattern>)` instead of `let <pattern> = <expr>`
|
||||
|
||||
error[E0658]: `let` expressions in this position are experimental
|
||||
--> $DIR/feature-gate.rs:44:21
|
||||
--> $DIR/feature-gate.rs:36:21
|
||||
|
|
||||
LL | if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {}
|
||||
| ^^^^^^^^^
|
||||
@ -108,7 +108,7 @@ LL | if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {}
|
||||
= help: you can write `matches!(<expr>, <pattern>)` instead of `let <pattern> = <expr>`
|
||||
|
||||
error[E0658]: `let` expressions in this position are experimental
|
||||
--> $DIR/feature-gate.rs:44:35
|
||||
--> $DIR/feature-gate.rs:36:35
|
||||
|
|
||||
LL | if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {}
|
||||
| ^^^^^^^^^
|
||||
@ -118,7 +118,7 @@ LL | if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {}
|
||||
= help: you can write `matches!(<expr>, <pattern>)` instead of `let <pattern> = <expr>`
|
||||
|
||||
error[E0658]: `let` expressions in this position are experimental
|
||||
--> $DIR/feature-gate.rs:44:48
|
||||
--> $DIR/feature-gate.rs:36:48
|
||||
|
|
||||
LL | if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {}
|
||||
| ^^^^^^^^^
|
||||
@ -128,7 +128,7 @@ LL | if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {}
|
||||
= help: you can write `matches!(<expr>, <pattern>)` instead of `let <pattern> = <expr>`
|
||||
|
||||
error[E0658]: `let` expressions in this position are experimental
|
||||
--> $DIR/feature-gate.rs:44:61
|
||||
--> $DIR/feature-gate.rs:36:61
|
||||
|
|
||||
LL | if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {}
|
||||
| ^^^^^^^^^
|
||||
@ -138,7 +138,7 @@ LL | if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {}
|
||||
= help: you can write `matches!(<expr>, <pattern>)` instead of `let <pattern> = <expr>`
|
||||
|
||||
error[E0658]: `let` expressions in this position are experimental
|
||||
--> $DIR/feature-gate.rs:56:8
|
||||
--> $DIR/feature-gate.rs:43:8
|
||||
|
|
||||
LL | if let Range { start: _, end: _ } = (true..true) && false {}
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
@ -148,7 +148,7 @@ LL | if let Range { start: _, end: _ } = (true..true) && false {}
|
||||
= help: you can write `matches!(<expr>, <pattern>)` instead of `let <pattern> = <expr>`
|
||||
|
||||
error[E0658]: `let` expressions in this position are experimental
|
||||
--> $DIR/feature-gate.rs:64:12
|
||||
--> $DIR/feature-gate.rs:50:12
|
||||
|
|
||||
LL | while (let 0 = 1) {}
|
||||
| ^^^^^^^^^
|
||||
@ -158,7 +158,7 @@ LL | while (let 0 = 1) {}
|
||||
= help: you can write `matches!(<expr>, <pattern>)` instead of `let <pattern> = <expr>`
|
||||
|
||||
error[E0658]: `let` expressions in this position are experimental
|
||||
--> $DIR/feature-gate.rs:68:14
|
||||
--> $DIR/feature-gate.rs:53:14
|
||||
|
|
||||
LL | while (((let 0 = 1))) {}
|
||||
| ^^^^^^^^^
|
||||
@ -168,7 +168,7 @@ LL | while (((let 0 = 1))) {}
|
||||
= help: you can write `matches!(<expr>, <pattern>)` instead of `let <pattern> = <expr>`
|
||||
|
||||
error[E0658]: `let` expressions in this position are experimental
|
||||
--> $DIR/feature-gate.rs:72:19
|
||||
--> $DIR/feature-gate.rs:56:19
|
||||
|
|
||||
LL | while true && let 0 = 1 {}
|
||||
| ^^^^^^^^^
|
||||
@ -178,7 +178,7 @@ LL | while true && let 0 = 1 {}
|
||||
= help: you can write `matches!(<expr>, <pattern>)` instead of `let <pattern> = <expr>`
|
||||
|
||||
error[E0658]: `let` expressions in this position are experimental
|
||||
--> $DIR/feature-gate.rs:76:11
|
||||
--> $DIR/feature-gate.rs:59:11
|
||||
|
|
||||
LL | while let 0 = 1 && true {}
|
||||
| ^^^^^^^^^
|
||||
@ -188,7 +188,7 @@ LL | while let 0 = 1 && true {}
|
||||
= help: you can write `matches!(<expr>, <pattern>)` instead of `let <pattern> = <expr>`
|
||||
|
||||
error[E0658]: `let` expressions in this position are experimental
|
||||
--> $DIR/feature-gate.rs:80:12
|
||||
--> $DIR/feature-gate.rs:62:12
|
||||
|
|
||||
LL | while (let 0 = 1) && true {}
|
||||
| ^^^^^^^^^
|
||||
@ -198,7 +198,7 @@ LL | while (let 0 = 1) && true {}
|
||||
= help: you can write `matches!(<expr>, <pattern>)` instead of `let <pattern> = <expr>`
|
||||
|
||||
error[E0658]: `let` expressions in this position are experimental
|
||||
--> $DIR/feature-gate.rs:84:20
|
||||
--> $DIR/feature-gate.rs:65:20
|
||||
|
|
||||
LL | while true && (let 0 = 1) {}
|
||||
| ^^^^^^^^^
|
||||
@ -208,7 +208,7 @@ LL | while true && (let 0 = 1) {}
|
||||
= help: you can write `matches!(<expr>, <pattern>)` instead of `let <pattern> = <expr>`
|
||||
|
||||
error[E0658]: `let` expressions in this position are experimental
|
||||
--> $DIR/feature-gate.rs:88:12
|
||||
--> $DIR/feature-gate.rs:68:12
|
||||
|
|
||||
LL | while (let 0 = 1) && (let 0 = 1) {}
|
||||
| ^^^^^^^^^
|
||||
@ -218,7 +218,7 @@ LL | while (let 0 = 1) && (let 0 = 1) {}
|
||||
= help: you can write `matches!(<expr>, <pattern>)` instead of `let <pattern> = <expr>`
|
||||
|
||||
error[E0658]: `let` expressions in this position are experimental
|
||||
--> $DIR/feature-gate.rs:88:27
|
||||
--> $DIR/feature-gate.rs:68:27
|
||||
|
|
||||
LL | while (let 0 = 1) && (let 0 = 1) {}
|
||||
| ^^^^^^^^^
|
||||
@ -228,7 +228,7 @@ LL | while (let 0 = 1) && (let 0 = 1) {}
|
||||
= help: you can write `matches!(<expr>, <pattern>)` instead of `let <pattern> = <expr>`
|
||||
|
||||
error[E0658]: `let` expressions in this position are experimental
|
||||
--> $DIR/feature-gate.rs:94:11
|
||||
--> $DIR/feature-gate.rs:72:11
|
||||
|
|
||||
LL | while let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {}
|
||||
| ^^^^^^^^^
|
||||
@ -238,7 +238,7 @@ LL | while let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {
|
||||
= help: you can write `matches!(<expr>, <pattern>)` instead of `let <pattern> = <expr>`
|
||||
|
||||
error[E0658]: `let` expressions in this position are experimental
|
||||
--> $DIR/feature-gate.rs:94:24
|
||||
--> $DIR/feature-gate.rs:72:24
|
||||
|
|
||||
LL | while let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {}
|
||||
| ^^^^^^^^^
|
||||
@ -248,7 +248,7 @@ LL | while let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {
|
||||
= help: you can write `matches!(<expr>, <pattern>)` instead of `let <pattern> = <expr>`
|
||||
|
||||
error[E0658]: `let` expressions in this position are experimental
|
||||
--> $DIR/feature-gate.rs:94:38
|
||||
--> $DIR/feature-gate.rs:72:38
|
||||
|
|
||||
LL | while let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {}
|
||||
| ^^^^^^^^^
|
||||
@ -258,7 +258,7 @@ LL | while let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {
|
||||
= help: you can write `matches!(<expr>, <pattern>)` instead of `let <pattern> = <expr>`
|
||||
|
||||
error[E0658]: `let` expressions in this position are experimental
|
||||
--> $DIR/feature-gate.rs:94:51
|
||||
--> $DIR/feature-gate.rs:72:51
|
||||
|
|
||||
LL | while let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {}
|
||||
| ^^^^^^^^^
|
||||
@ -268,7 +268,7 @@ LL | while let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {
|
||||
= help: you can write `matches!(<expr>, <pattern>)` instead of `let <pattern> = <expr>`
|
||||
|
||||
error[E0658]: `let` expressions in this position are experimental
|
||||
--> $DIR/feature-gate.rs:94:64
|
||||
--> $DIR/feature-gate.rs:72:64
|
||||
|
|
||||
LL | while let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {}
|
||||
| ^^^^^^^^^
|
||||
@ -278,7 +278,7 @@ LL | while let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {
|
||||
= help: you can write `matches!(<expr>, <pattern>)` instead of `let <pattern> = <expr>`
|
||||
|
||||
error[E0658]: `let` expressions in this position are experimental
|
||||
--> $DIR/feature-gate.rs:106:11
|
||||
--> $DIR/feature-gate.rs:79:11
|
||||
|
|
||||
LL | while let Range { start: _, end: _ } = (true..true) && false {}
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
@ -288,7 +288,7 @@ LL | while let Range { start: _, end: _ } = (true..true) && false {}
|
||||
= help: you can write `matches!(<expr>, <pattern>)` instead of `let <pattern> = <expr>`
|
||||
|
||||
error[E0658]: `let` expressions in this position are experimental
|
||||
--> $DIR/feature-gate.rs:131:20
|
||||
--> $DIR/feature-gate.rs:99:20
|
||||
|
|
||||
LL | #[cfg(FALSE)] (let 0 = 1);
|
||||
| ^^^^^^^^^
|
||||
@ -298,7 +298,7 @@ LL | #[cfg(FALSE)] (let 0 = 1);
|
||||
= help: you can write `matches!(<expr>, <pattern>)` instead of `let <pattern> = <expr>`
|
||||
|
||||
error[E0658]: `let` expressions in this position are experimental
|
||||
--> $DIR/feature-gate.rs:114:17
|
||||
--> $DIR/feature-gate.rs:86:17
|
||||
|
|
||||
LL | noop_expr!((let 0 = 1));
|
||||
| ^^^^^^^^^
|
||||
@ -308,7 +308,7 @@ LL | noop_expr!((let 0 = 1));
|
||||
= help: you can write `matches!(<expr>, <pattern>)` instead of `let <pattern> = <expr>`
|
||||
|
||||
error[E0658]: `let` expressions in this position are experimental
|
||||
--> $DIR/feature-gate.rs:123:16
|
||||
--> $DIR/feature-gate.rs:95:16
|
||||
|
|
||||
LL | use_expr!((let 0 = 1 && 0 == 0));
|
||||
| ^^^^^^^^^
|
||||
@ -318,7 +318,7 @@ LL | use_expr!((let 0 = 1 && 0 == 0));
|
||||
= help: you can write `matches!(<expr>, <pattern>)` instead of `let <pattern> = <expr>`
|
||||
|
||||
error[E0658]: `let` expressions in this position are experimental
|
||||
--> $DIR/feature-gate.rs:127:16
|
||||
--> $DIR/feature-gate.rs:97:16
|
||||
|
|
||||
LL | use_expr!((let 0 = 1));
|
||||
| ^^^^^^^^^
|
||||
@ -327,274 +327,6 @@ LL | use_expr!((let 0 = 1));
|
||||
= help: add `#![feature(let_chains)]` to the crate attributes to enable
|
||||
= help: you can write `matches!(<expr>, <pattern>)` instead of `let <pattern> = <expr>`
|
||||
|
||||
error: invalid parentheses around `let` expression in `if let`
|
||||
--> $DIR/feature-gate.rs:14:8
|
||||
|
|
||||
LL | if (let 0 = 1) {}
|
||||
| ^ ^
|
||||
|
|
||||
help: `if let` needs to be written without parentheses
|
||||
|
|
||||
LL - if (let 0 = 1) {}
|
||||
LL + if let 0 = 1 {}
|
||||
|
|
||||
|
||||
error: invalid parentheses around `let` expression in `if let`
|
||||
--> $DIR/feature-gate.rs:18:8
|
||||
|
|
||||
LL | if (((let 0 = 1))) {}
|
||||
| ^^^ ^^^
|
||||
|
|
||||
help: `if let` needs to be written without parentheses
|
||||
|
|
||||
LL - if (((let 0 = 1))) {}
|
||||
LL + if let 0 = 1 {}
|
||||
|
|
||||
|
||||
error: `let` expressions are not supported here
|
||||
--> $DIR/feature-gate.rs:22:16
|
||||
|
|
||||
LL | if true && let 0 = 1 {}
|
||||
| ^^^^^^^^^
|
||||
|
|
||||
= note: only supported directly without parentheses in conditions of `if`- and `while`-expressions, as well as in `let` chains within parentheses
|
||||
|
||||
error: `let` expressions are not supported here
|
||||
--> $DIR/feature-gate.rs:26:8
|
||||
|
|
||||
LL | if let 0 = 1 && true {}
|
||||
| ^^^^^^^^^
|
||||
|
|
||||
= note: only supported directly without parentheses in conditions of `if`- and `while`-expressions, as well as in `let` chains within parentheses
|
||||
|
||||
error: `let` expressions are not supported here
|
||||
--> $DIR/feature-gate.rs:30:9
|
||||
|
|
||||
LL | if (let 0 = 1) && true {}
|
||||
| ^^^^^^^^^
|
||||
|
|
||||
= note: only supported directly without parentheses in conditions of `if`- and `while`-expressions, as well as in `let` chains within parentheses
|
||||
|
||||
error: `let` expressions are not supported here
|
||||
--> $DIR/feature-gate.rs:34:17
|
||||
|
|
||||
LL | if true && (let 0 = 1) {}
|
||||
| ^^^^^^^^^
|
||||
|
|
||||
= note: only supported directly without parentheses in conditions of `if`- and `while`-expressions, as well as in `let` chains within parentheses
|
||||
|
||||
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 without parentheses in conditions of `if`- and `while`-expressions, as well as in `let` chains within parentheses
|
||||
|
||||
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 without parentheses in conditions of `if`- and `while`-expressions, as well as in `let` chains within parentheses
|
||||
|
||||
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 without parentheses in conditions of `if`- and `while`-expressions, as well as in `let` chains within parentheses
|
||||
|
||||
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 without parentheses in conditions of `if`- and `while`-expressions, as well as in `let` chains within parentheses
|
||||
|
||||
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 without parentheses in conditions of `if`- and `while`-expressions, as well as in `let` chains within parentheses
|
||||
|
||||
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 without parentheses in conditions of `if`- and `while`-expressions, as well as in `let` chains within parentheses
|
||||
|
||||
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 without parentheses in conditions of `if`- and `while`-expressions, as well as in `let` chains within parentheses
|
||||
|
||||
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 without parentheses in conditions of `if`- and `while`-expressions, as well as in `let` chains within parentheses
|
||||
|
||||
error: `let` expressions are not supported here
|
||||
--> $DIR/feature-gate.rs:64:12
|
||||
|
|
||||
LL | while (let 0 = 1) {}
|
||||
| ^^^^^^^^^
|
||||
|
|
||||
= note: only supported directly without parentheses in conditions of `if`- and `while`-expressions, as well as in `let` chains within parentheses
|
||||
|
||||
error: `let` expressions are not supported here
|
||||
--> $DIR/feature-gate.rs:68:14
|
||||
|
|
||||
LL | while (((let 0 = 1))) {}
|
||||
| ^^^^^^^^^
|
||||
|
|
||||
= note: only supported directly without parentheses in conditions of `if`- and `while`-expressions, as well as in `let` chains within parentheses
|
||||
|
||||
error: `let` expressions are not supported here
|
||||
--> $DIR/feature-gate.rs:72:19
|
||||
|
|
||||
LL | while true && let 0 = 1 {}
|
||||
| ^^^^^^^^^
|
||||
|
|
||||
= note: only supported directly without parentheses in conditions of `if`- and `while`-expressions, as well as in `let` chains within parentheses
|
||||
|
||||
error: `let` expressions are not supported here
|
||||
--> $DIR/feature-gate.rs:76:11
|
||||
|
|
||||
LL | while let 0 = 1 && true {}
|
||||
| ^^^^^^^^^
|
||||
|
|
||||
= note: only supported directly without parentheses in conditions of `if`- and `while`-expressions, as well as in `let` chains within parentheses
|
||||
|
||||
error: `let` expressions are not supported here
|
||||
--> $DIR/feature-gate.rs:80:12
|
||||
|
|
||||
LL | while (let 0 = 1) && true {}
|
||||
| ^^^^^^^^^
|
||||
|
|
||||
= note: only supported directly without parentheses in conditions of `if`- and `while`-expressions, as well as in `let` chains within parentheses
|
||||
|
||||
error: `let` expressions are not supported here
|
||||
--> $DIR/feature-gate.rs:84:20
|
||||
|
|
||||
LL | while true && (let 0 = 1) {}
|
||||
| ^^^^^^^^^
|
||||
|
|
||||
= note: only supported directly without parentheses in conditions of `if`- and `while`-expressions, as well as in `let` chains within parentheses
|
||||
|
||||
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 without parentheses in conditions of `if`- and `while`-expressions, as well as in `let` chains within parentheses
|
||||
|
||||
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 without parentheses in conditions of `if`- and `while`-expressions, as well as in `let` chains within parentheses
|
||||
|
||||
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 without parentheses in conditions of `if`- and `while`-expressions, as well as in `let` chains within parentheses
|
||||
|
||||
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 without parentheses in conditions of `if`- and `while`-expressions, as well as in `let` chains within parentheses
|
||||
|
||||
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 without parentheses in conditions of `if`- and `while`-expressions, as well as in `let` chains within parentheses
|
||||
|
||||
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 without parentheses in conditions of `if`- and `while`-expressions, as well as in `let` chains within parentheses
|
||||
|
||||
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 without parentheses in conditions of `if`- and `while`-expressions, as well as in `let` chains within parentheses
|
||||
|
||||
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 without parentheses in conditions of `if`- and `while`-expressions, as well as in `let` chains within parentheses
|
||||
|
||||
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 without parentheses in conditions of `if`- and `while`-expressions, as well as in `let` chains within parentheses
|
||||
|
||||
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 without parentheses in conditions of `if`- and `while`-expressions, as well as in `let` chains within parentheses
|
||||
|
||||
error: invalid parentheses around `let` expression in `if let`
|
||||
--> $DIR/feature-gate.rs:127:15
|
||||
|
|
||||
LL | use_expr!((let 0 = 1));
|
||||
| ^ ^
|
||||
|
|
||||
help: `if let` needs to be written without parentheses
|
||||
|
|
||||
LL - use_expr!((let 0 = 1));
|
||||
LL + use_expr!(let 0 = 1);
|
||||
|
|
||||
|
||||
error: `let` expressions are not supported here
|
||||
--> $DIR/feature-gate.rs:127:16
|
||||
|
|
||||
LL | use_expr!((let 0 = 1));
|
||||
| ^^^^^^^^^
|
||||
|
|
||||
= note: only supported directly without parentheses in conditions of `if`- and `while`-expressions, as well as in `let` chains within parentheses
|
||||
|
||||
error: aborting due to 65 previous errors
|
||||
error: aborting due to 33 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0658`.
|
||||
|
@ -10,7 +10,8 @@ fn main() {
|
||||
|
||||
fn _f1() -> bool {
|
||||
// Should associate as `(let _ = (return (true && false)))`.
|
||||
if let _ = return true && false {}; //~ WARNING unreachable_code
|
||||
if let _ = return true && false {};
|
||||
//~^ WARNING unreachable block in `if`
|
||||
}
|
||||
assert!(!_f1());
|
||||
}
|
||||
|
@ -1,8 +1,8 @@
|
||||
warning: unreachable block in `if` expression
|
||||
warning: unreachable block in `if` or `while` expression
|
||||
--> $DIR/protect-precedences.rs:13:41
|
||||
|
|
||||
LL | if let _ = return true && false {};
|
||||
| -------------------- ^^ unreachable block in `if` expression
|
||||
| -------------------- ^^ unreachable block in `if` or `while` expression
|
||||
| |
|
||||
| any code following this expression is unreachable
|
||||
|
|
||||
|
@ -55,10 +55,10 @@ LL | let U1 { a } = u1;
|
||||
= note: the field may not be properly initialized: using uninitialized data will cause undefined behavior
|
||||
|
||||
error[E0133]: access to union field is unsafe and requires unsafe function or block
|
||||
--> $DIR/union-unsafe.rs:65:20
|
||||
--> $DIR/union-unsafe.rs:65:8
|
||||
|
|
||||
LL | if let U1 { a: 12 } = u1 {}
|
||||
| ^^ access to union field
|
||||
| ^^^^^^^^^^^^^^^^^^^^^ access to union field
|
||||
|
|
||||
= note: the field may not be properly initialized: using uninitialized data will cause undefined behavior
|
||||
|
||||
|
@ -1,8 +1,8 @@
|
||||
warning: irrefutable `while let` pattern
|
||||
--> $DIR/while-let.rs:7:13
|
||||
--> $DIR/while-let.rs:7:19
|
||||
|
|
||||
LL | while let $p = $e $b
|
||||
| ^^^^^^^^^^^^^^^^^^^^
|
||||
| ^^^
|
||||
...
|
||||
LL | / foo!(_a, 1, {
|
||||
LL | | println!("irrefutable pattern");
|
||||
@ -15,10 +15,10 @@ LL | | });
|
||||
= note: this warning originates in the macro `foo` (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||
|
||||
warning: irrefutable `while let` pattern
|
||||
--> $DIR/while-let.rs:7:13
|
||||
--> $DIR/while-let.rs:7:19
|
||||
|
|
||||
LL | while let $p = $e $b
|
||||
| ^^^^^^^^^^^^^^^^^^^^
|
||||
| ^^^
|
||||
...
|
||||
LL | / bar!(_a, 1, {
|
||||
LL | | println!("irrefutable pattern");
|
||||
@ -30,13 +30,10 @@ LL | | });
|
||||
= note: this warning originates in the macro `foo` (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||
|
||||
warning: irrefutable `while let` pattern
|
||||
--> $DIR/while-let.rs:27:5
|
||||
--> $DIR/while-let.rs:27:11
|
||||
|
|
||||
LL | / while let _a = 1 {
|
||||
LL | | println!("irrefutable pattern");
|
||||
LL | | break;
|
||||
LL | | }
|
||||
| |_____^
|
||||
LL | while let _a = 1 {
|
||||
| ^^^^^^^^^^
|
||||
|
|
||||
= note: this pattern will always match, so the loop will never exit
|
||||
= help: consider instead using a `loop { ... }` with a `let` inside it
|
||||
|
@ -1,5 +1,6 @@
|
||||
use clippy_utils::consts::{constant, Constant};
|
||||
use clippy_utils::diagnostics::span_lint_and_help;
|
||||
use clippy_utils::higher;
|
||||
use clippy_utils::source::snippet_opt;
|
||||
use clippy_utils::{is_direct_expn_of, is_expn_of, match_panic_call};
|
||||
use if_chain::if_chain;
|
||||
@ -116,8 +117,8 @@ enum AssertKind {
|
||||
/// where `message` is any expression and `c` is a constant bool.
|
||||
fn match_assert_with_message<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) -> Option<AssertKind> {
|
||||
if_chain! {
|
||||
if let ExprKind::If(cond, then, _) = expr.kind;
|
||||
if let ExprKind::Unary(UnOp::Not, expr) = cond.kind;
|
||||
if let Some(higher::If { cond, then, .. }) = higher::If::hir(expr);
|
||||
if let ExprKind::Unary(UnOp::Not, ref expr) = cond.kind;
|
||||
// bind the first argument of the `assert!` macro
|
||||
if let Some((Constant::Bool(is_true), _)) = constant(cx, cx.typeck_results(), expr);
|
||||
// block
|
||||
|
@ -1,4 +1,5 @@
|
||||
use clippy_utils::diagnostics::{span_lint, span_lint_and_sugg};
|
||||
use clippy_utils::higher;
|
||||
use clippy_utils::source::snippet_block_with_applicability;
|
||||
use clippy_utils::ty::implements_trait;
|
||||
use clippy_utils::{differing_macro_contexts, get_parent_expr};
|
||||
@ -92,7 +93,7 @@ impl<'tcx> LateLintPass<'tcx> for BlocksInIfConditions {
|
||||
if in_external_macro(cx.sess(), expr.span) {
|
||||
return;
|
||||
}
|
||||
if let ExprKind::If(cond, _, _) = &expr.kind {
|
||||
if let Some(higher::If { cond, .. }) = higher::If::hir(expr) {
|
||||
if let ExprKind::Block(block, _) = &cond.kind {
|
||||
if block.rules == BlockCheckMode::DefaultBlock {
|
||||
if block.stmts.is_empty() {
|
||||
|
@ -1,9 +1,9 @@
|
||||
use clippy_utils::diagnostics::span_lint_and_then;
|
||||
use clippy_utils::visitors::LocalUsedVisitor;
|
||||
use clippy_utils::{is_lang_ctor, path_to_local, peel_ref_operators, SpanlessEq};
|
||||
use clippy_utils::{higher, is_lang_ctor, path_to_local, peel_ref_operators, SpanlessEq};
|
||||
use if_chain::if_chain;
|
||||
use rustc_hir::LangItem::OptionNone;
|
||||
use rustc_hir::{Arm, Expr, ExprKind, Guard, HirId, Pat, PatKind, StmtKind};
|
||||
use rustc_hir::{Expr, ExprKind, Guard, HirId, Pat, PatKind, StmtKind};
|
||||
use rustc_lint::{LateContext, LateLintPass};
|
||||
use rustc_session::{declare_lint_pass, declare_tool_lint};
|
||||
use rustc_span::{MultiSpan, Span};
|
||||
@ -49,22 +49,44 @@ declare_lint_pass!(CollapsibleMatch => [COLLAPSIBLE_MATCH]);
|
||||
|
||||
impl<'tcx> LateLintPass<'tcx> for CollapsibleMatch {
|
||||
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &Expr<'tcx>) {
|
||||
if let Some(higher::IfLet {
|
||||
let_pat,
|
||||
if_then,
|
||||
if_else,
|
||||
..
|
||||
}) = higher::IfLet::hir(expr)
|
||||
{
|
||||
check_arm(cx, if_then, None, let_pat, if_else);
|
||||
|
||||
check_if_let(cx, if_then, let_pat);
|
||||
}
|
||||
|
||||
if let ExprKind::Match(_expr, arms, _source) = expr.kind {
|
||||
if let Some(wild_arm) = arms.iter().rfind(|arm| arm_is_wild_like(cx, arm)) {
|
||||
if let Some(wild_arm) = arms.iter().rfind(|arm| is_wild_like(cx, &arm.pat.kind, &arm.guard)) {
|
||||
for arm in arms {
|
||||
check_arm(arm, wild_arm, cx);
|
||||
check_arm(cx, arm.body, arm.guard.as_ref(), arm.pat, Some(wild_arm.body));
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(first_arm) = arms.get(0) {
|
||||
check_if_let(cx, &first_arm.body, &first_arm.pat);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn check_arm<'tcx>(arm: &Arm<'tcx>, wild_outer_arm: &Arm<'tcx>, cx: &LateContext<'tcx>) {
|
||||
let expr = strip_singleton_blocks(arm.body);
|
||||
fn check_arm<'tcx>(
|
||||
cx: &LateContext<'tcx>,
|
||||
outer_block: &'tcx Expr<'tcx>,
|
||||
outer_guard: Option<&Guard<'tcx>>,
|
||||
outer_pat: &'tcx Pat<'tcx>,
|
||||
wild_outer_block: Option<&'tcx Expr<'tcx>>,
|
||||
) {
|
||||
let expr = strip_singleton_blocks(outer_block);
|
||||
if_chain! {
|
||||
if let ExprKind::Match(expr_in, arms_inner, _) = expr.kind;
|
||||
// the outer arm pattern and the inner match
|
||||
if expr_in.span.ctxt() == arm.pat.span.ctxt();
|
||||
if expr_in.span.ctxt() == outer_pat.span.ctxt();
|
||||
// there must be no more than two arms in the inner match for this lint
|
||||
if arms_inner.len() == 2;
|
||||
// no if guards on the inner match
|
||||
@ -73,18 +95,18 @@ fn check_arm<'tcx>(arm: &Arm<'tcx>, wild_outer_arm: &Arm<'tcx>, cx: &LateContext
|
||||
// match <local> { .. }
|
||||
if let Some(binding_id) = path_to_local(peel_ref_operators(cx, expr_in));
|
||||
// one of the branches must be "wild-like"
|
||||
if let Some(wild_inner_arm_idx) = arms_inner.iter().rposition(|arm_inner| arm_is_wild_like(cx, arm_inner));
|
||||
if let Some(wild_inner_arm_idx) = arms_inner.iter().rposition(|arm_inner| is_wild_like(cx, &arm_inner.pat.kind, &arm_inner.guard));
|
||||
let (wild_inner_arm, non_wild_inner_arm) =
|
||||
(&arms_inner[wild_inner_arm_idx], &arms_inner[1 - wild_inner_arm_idx]);
|
||||
if !pat_contains_or(non_wild_inner_arm.pat);
|
||||
// the binding must come from the pattern of the containing match arm
|
||||
// ..<local>.. => match <local> { .. }
|
||||
if let Some(binding_span) = find_pat_binding(arm.pat, binding_id);
|
||||
if let Some(binding_span) = find_pat_binding(outer_pat, binding_id);
|
||||
// the "wild-like" branches must be equal
|
||||
if SpanlessEq::new(cx).eq_expr(wild_inner_arm.body, wild_outer_arm.body);
|
||||
if wild_outer_block.map(|el| SpanlessEq::new(cx).eq_expr(wild_inner_arm.body, el)).unwrap_or(true);
|
||||
// the binding must not be used in the if guard
|
||||
let mut used_visitor = LocalUsedVisitor::new(cx, binding_id);
|
||||
if match arm.guard {
|
||||
if match outer_guard {
|
||||
None => true,
|
||||
Some(Guard::If(expr) | Guard::IfLet(_, expr)) => !used_visitor.check_expr(expr),
|
||||
};
|
||||
@ -107,6 +129,31 @@ fn check_arm<'tcx>(arm: &Arm<'tcx>, wild_outer_arm: &Arm<'tcx>, cx: &LateContext
|
||||
}
|
||||
}
|
||||
|
||||
fn check_if_let<'tcx>(cx: &LateContext<'tcx>, outer_expr: &'tcx Expr<'tcx>, outer_pat: &'tcx Pat<'tcx>) {
|
||||
let block_inner = strip_singleton_blocks(outer_expr);
|
||||
if_chain! {
|
||||
if let Some(higher::IfLet { if_then: inner_if_then, let_expr: inner_let_expr, let_pat: inner_let_pat, .. }) = higher::IfLet::hir(block_inner);
|
||||
if let Some(binding_id) = path_to_local(peel_ref_operators(cx, inner_let_expr));
|
||||
if let Some(binding_span) = find_pat_binding(outer_pat, binding_id);
|
||||
let mut used_visitor = LocalUsedVisitor::new(cx, binding_id);
|
||||
if !used_visitor.check_expr(inner_if_then);
|
||||
then {
|
||||
span_lint_and_then(
|
||||
cx,
|
||||
COLLAPSIBLE_MATCH,
|
||||
block_inner.span,
|
||||
"unnecessary nested `if let` or `match`",
|
||||
|diag| {
|
||||
let mut help_span = MultiSpan::from_spans(vec![binding_span, inner_let_pat.span]);
|
||||
help_span.push_span_label(binding_span, "replace this binding".into());
|
||||
help_span.push_span_label(inner_let_pat.span, "with this pattern".into());
|
||||
diag.span_help(help_span, "the outer pattern can be modified to include the inner pattern");
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn strip_singleton_blocks<'hir>(mut expr: &'hir Expr<'hir>) -> &'hir Expr<'hir> {
|
||||
while let ExprKind::Block(block, _) = expr.kind {
|
||||
match (block.stmts, block.expr) {
|
||||
@ -122,13 +169,13 @@ fn strip_singleton_blocks<'hir>(mut expr: &'hir Expr<'hir>) -> &'hir Expr<'hir>
|
||||
}
|
||||
|
||||
/// A "wild-like" pattern is wild ("_") or `None`.
|
||||
/// For this lint to apply, both the outer and inner match expressions
|
||||
/// For this lint to apply, both the outer and inner patterns
|
||||
/// must have "wild-like" branches that can be combined.
|
||||
fn arm_is_wild_like(cx: &LateContext<'_>, arm: &Arm<'_>) -> bool {
|
||||
if arm.guard.is_some() {
|
||||
fn is_wild_like(cx: &LateContext<'_>, pat_kind: &PatKind<'_>, arm_guard: &Option<Guard<'_>>) -> bool {
|
||||
if arm_guard.is_some() {
|
||||
return false;
|
||||
}
|
||||
match arm.pat.kind {
|
||||
match pat_kind {
|
||||
PatKind::Binding(..) | PatKind::Wild => true,
|
||||
PatKind::Path(ref qpath) => is_lang_ctor(cx, qpath, OptionNone),
|
||||
_ => false,
|
||||
|
@ -316,9 +316,10 @@ fn scan_block_for_eq(cx: &LateContext<'tcx>, blocks: &[&Block<'tcx>]) -> Option<
|
||||
let mut start_eq = usize::MAX;
|
||||
let mut end_eq = usize::MAX;
|
||||
let mut expr_eq = true;
|
||||
for win in blocks.windows(2) {
|
||||
let l_stmts = win[0].stmts;
|
||||
let r_stmts = win[1].stmts;
|
||||
let mut iter = blocks.windows(2);
|
||||
while let Some(&[win0, win1]) = iter.next() {
|
||||
let l_stmts = win0.stmts;
|
||||
let r_stmts = win1.stmts;
|
||||
|
||||
// `SpanlessEq` now keeps track of the locals and is therefore context sensitive clippy#6752.
|
||||
// The comparison therefore needs to be done in a way that builds the correct context.
|
||||
@ -335,22 +336,22 @@ fn scan_block_for_eq(cx: &LateContext<'tcx>, blocks: &[&Block<'tcx>]) -> Option<
|
||||
it1.zip(it2)
|
||||
.fold(0, |acc, (l, r)| if evaluator.eq_stmt(l, r) { acc + 1 } else { 0 })
|
||||
};
|
||||
let block_expr_eq = both(&win[0].expr, &win[1].expr, |l, r| evaluator.eq_expr(l, r));
|
||||
let block_expr_eq = both(&win0.expr, &win1.expr, |l, r| evaluator.eq_expr(l, r));
|
||||
|
||||
// IF_SAME_THEN_ELSE
|
||||
if_chain! {
|
||||
if block_expr_eq;
|
||||
if l_stmts.len() == r_stmts.len();
|
||||
if l_stmts.len() == current_start_eq;
|
||||
if !is_lint_allowed(cx, IF_SAME_THEN_ELSE, win[0].hir_id);
|
||||
if !is_lint_allowed(cx, IF_SAME_THEN_ELSE, win[1].hir_id);
|
||||
if !is_lint_allowed(cx, IF_SAME_THEN_ELSE, win0.hir_id);
|
||||
if !is_lint_allowed(cx, IF_SAME_THEN_ELSE, win1.hir_id);
|
||||
then {
|
||||
span_lint_and_note(
|
||||
cx,
|
||||
IF_SAME_THEN_ELSE,
|
||||
win[0].span,
|
||||
win0.span,
|
||||
"this `if` has identical blocks",
|
||||
Some(win[1].span),
|
||||
Some(win1.span),
|
||||
"same as this",
|
||||
);
|
||||
|
||||
|
@ -232,6 +232,7 @@ fn is_linted_explicit_deref_position(parent: Option<Node<'_>>, child_id: HirId,
|
||||
| ExprKind::If(..)
|
||||
| ExprKind::Loop(..)
|
||||
| ExprKind::Match(..)
|
||||
| ExprKind::Let(..)
|
||||
| ExprKind::Closure(..)
|
||||
| ExprKind::Block(..)
|
||||
| ExprKind::Assign(..)
|
||||
|
@ -1,3 +1,4 @@
|
||||
use clippy_utils::higher;
|
||||
use clippy_utils::{
|
||||
can_move_expr_to_closure_no_visit,
|
||||
diagnostics::span_lint_and_sugg,
|
||||
@ -5,6 +6,7 @@ use clippy_utils::{
|
||||
source::{reindent_multiline, snippet_indent, snippet_with_applicability, snippet_with_context},
|
||||
SpanlessEq,
|
||||
};
|
||||
use core::fmt::Write;
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_hir::{
|
||||
intravisit::{walk_expr, ErasedMap, NestedVisitorMap, Visitor},
|
||||
@ -13,7 +15,6 @@ use rustc_hir::{
|
||||
use rustc_lint::{LateContext, LateLintPass};
|
||||
use rustc_session::{declare_lint_pass, declare_tool_lint};
|
||||
use rustc_span::{Span, SyntaxContext, DUMMY_SP};
|
||||
use std::fmt::Write;
|
||||
|
||||
declare_clippy_lint! {
|
||||
/// ### What it does
|
||||
@ -62,10 +63,11 @@ declare_lint_pass!(HashMapPass => [MAP_ENTRY]);
|
||||
impl<'tcx> LateLintPass<'tcx> for HashMapPass {
|
||||
#[allow(clippy::too_many_lines)]
|
||||
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
|
||||
let (cond_expr, then_expr, else_expr) = match expr.kind {
|
||||
ExprKind::If(c, t, e) => (c, t, e),
|
||||
let (cond_expr, then_expr, else_expr) = match higher::If::hir(expr) {
|
||||
Some(higher::If { cond, then, r#else }) => (cond, then, r#else),
|
||||
_ => return,
|
||||
};
|
||||
|
||||
let (map_ty, contains_expr) = match try_parse_contains(cx, cond_expr) {
|
||||
Some(x) => x,
|
||||
None => return,
|
||||
|
@ -100,7 +100,7 @@ fn check_closure<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
|
||||
|
||||
if ex.span.ctxt() != expr.span.ctxt() {
|
||||
if decl.inputs.is_empty() {
|
||||
if let Some(VecArgs::Vec(&[])) = higher::vec_macro(cx, ex) {
|
||||
if let Some(VecArgs::Vec(&[])) = higher::VecArgs::hir(cx, ex) {
|
||||
// replace `|| vec![]` with `Vec::new`
|
||||
span_lint_and_sugg(
|
||||
cx,
|
||||
|
@ -3,6 +3,7 @@ use clippy_utils::consts::{
|
||||
Constant::{Int, F32, F64},
|
||||
};
|
||||
use clippy_utils::diagnostics::span_lint_and_sugg;
|
||||
use clippy_utils::higher;
|
||||
use clippy_utils::{eq_expr_value, get_parent_expr, numeric_literal, sugg};
|
||||
use if_chain::if_chain;
|
||||
use rustc_errors::Applicability;
|
||||
@ -545,11 +546,11 @@ fn are_negated<'a>(cx: &LateContext<'_>, expr1: &'a Expr<'a>, expr2: &'a Expr<'a
|
||||
|
||||
fn check_custom_abs(cx: &LateContext<'_>, expr: &Expr<'_>) {
|
||||
if_chain! {
|
||||
if let ExprKind::If(cond, body, else_body) = expr.kind;
|
||||
if let ExprKind::Block(block, _) = body.kind;
|
||||
if let Some(higher::If { cond, then, r#else }) = higher::If::hir(expr);
|
||||
if let ExprKind::Block(block, _) = then.kind;
|
||||
if block.stmts.is_empty();
|
||||
if let Some(if_body_expr) = block.expr;
|
||||
if let Some(ExprKind::Block(else_block, _)) = else_body.map(|el| &el.kind);
|
||||
if let Some(ExprKind::Block(else_block, _)) = r#else.map(|el| &el.kind);
|
||||
if else_block.stmts.is_empty();
|
||||
if let Some(else_body_expr) = else_block.expr;
|
||||
if let Some((if_expr_positive, body)) = are_negated(cx, if_body_expr, else_body_expr);
|
||||
|
@ -1,9 +1,10 @@
|
||||
use clippy_utils::diagnostics::span_lint_and_help;
|
||||
use clippy_utils::higher;
|
||||
use clippy_utils::ty::is_type_diagnostic_item;
|
||||
use clippy_utils::SpanlessEq;
|
||||
use if_chain::if_chain;
|
||||
use rustc_hir::intravisit::{self as visit, NestedVisitorMap, Visitor};
|
||||
use rustc_hir::{Expr, ExprKind, MatchSource};
|
||||
use rustc_hir::{Expr, ExprKind};
|
||||
use rustc_lint::{LateContext, LateLintPass};
|
||||
use rustc_middle::hir::map::Map;
|
||||
use rustc_session::{declare_lint_pass, declare_tool_lint};
|
||||
@ -42,7 +43,7 @@ declare_clippy_lint! {
|
||||
declare_lint_pass!(IfLetMutex => [IF_LET_MUTEX]);
|
||||
|
||||
impl<'tcx> LateLintPass<'tcx> for IfLetMutex {
|
||||
fn check_expr(&mut self, cx: &LateContext<'tcx>, ex: &'tcx Expr<'tcx>) {
|
||||
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) {
|
||||
let mut arm_visit = ArmVisitor {
|
||||
mutex_lock_called: false,
|
||||
found_mutex: None,
|
||||
@ -53,25 +54,23 @@ impl<'tcx> LateLintPass<'tcx> for IfLetMutex {
|
||||
found_mutex: None,
|
||||
cx,
|
||||
};
|
||||
if let ExprKind::Match(
|
||||
op,
|
||||
arms,
|
||||
MatchSource::IfLetDesugar {
|
||||
contains_else_clause: true,
|
||||
},
|
||||
) = ex.kind
|
||||
if let Some(higher::IfLet {
|
||||
let_expr,
|
||||
if_then,
|
||||
if_else: Some(if_else),
|
||||
..
|
||||
}) = higher::IfLet::hir(expr)
|
||||
{
|
||||
op_visit.visit_expr(op);
|
||||
op_visit.visit_expr(let_expr);
|
||||
if op_visit.mutex_lock_called {
|
||||
for arm in arms {
|
||||
arm_visit.visit_arm(arm);
|
||||
}
|
||||
arm_visit.visit_expr(if_then);
|
||||
arm_visit.visit_expr(if_else);
|
||||
|
||||
if arm_visit.mutex_lock_called && arm_visit.same_mutex(cx, op_visit.found_mutex.unwrap()) {
|
||||
span_lint_and_help(
|
||||
cx,
|
||||
IF_LET_MUTEX,
|
||||
ex.span,
|
||||
expr.span,
|
||||
"calling `Mutex::lock` inside the scope of another `Mutex::lock` causes a deadlock",
|
||||
None,
|
||||
"move the lock call outside of the `if let ...` expression",
|
||||
|
@ -1,10 +1,11 @@
|
||||
use clippy_utils::diagnostics::span_lint_and_sugg;
|
||||
use clippy_utils::higher;
|
||||
use clippy_utils::method_chain_args;
|
||||
use clippy_utils::source::snippet_with_applicability;
|
||||
use clippy_utils::ty::is_type_diagnostic_item;
|
||||
use if_chain::if_chain;
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_hir::{Expr, ExprKind, MatchSource, PatKind, QPath};
|
||||
use rustc_hir::{Expr, ExprKind, PatKind, QPath};
|
||||
use rustc_lint::{LateContext, LateLintPass};
|
||||
use rustc_session::{declare_lint_pass, declare_tool_lint};
|
||||
use rustc_span::sym;
|
||||
@ -44,17 +45,17 @@ declare_lint_pass!(OkIfLet => [IF_LET_SOME_RESULT]);
|
||||
impl<'tcx> LateLintPass<'tcx> for OkIfLet {
|
||||
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
|
||||
if_chain! { //begin checking variables
|
||||
if let ExprKind::Match(op, body, MatchSource::IfLetDesugar { .. }) = expr.kind; //test if expr is if let
|
||||
if let ExprKind::MethodCall(_, ok_span, result_types, _) = op.kind; //check is expr.ok() has type Result<T,E>.ok(, _)
|
||||
if let PatKind::TupleStruct(QPath::Resolved(_, x), y, _) = body[0].pat.kind; //get operation
|
||||
if method_chain_args(op, &["ok"]).is_some(); //test to see if using ok() methoduse std::marker::Sized;
|
||||
if let Some(higher::IfLet { let_pat, let_expr, .. }) = higher::IfLet::hir(expr);
|
||||
if let ExprKind::MethodCall(_, ok_span, ref result_types, _) = let_expr.kind; //check is expr.ok() has type Result<T,E>.ok(, _)
|
||||
if let PatKind::TupleStruct(QPath::Resolved(_, ref x), ref y, _) = let_pat.kind; //get operation
|
||||
if method_chain_args(let_expr, &["ok"]).is_some(); //test to see if using ok() methoduse std::marker::Sized;
|
||||
if is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(&result_types[0]), sym::result_type);
|
||||
if rustc_hir_pretty::to_string(rustc_hir_pretty::NO_ANN, |s| s.print_path(x, false)) == "Some";
|
||||
|
||||
then {
|
||||
let mut applicability = Applicability::MachineApplicable;
|
||||
let some_expr_string = snippet_with_applicability(cx, y[0].span, "", &mut applicability);
|
||||
let trimmed_ok = snippet_with_applicability(cx, op.span.until(ok_span), "", &mut applicability);
|
||||
let trimmed_ok = snippet_with_applicability(cx, let_expr.span.until(ok_span), "", &mut applicability);
|
||||
let sugg = format!(
|
||||
"if let Ok({}) = {}",
|
||||
some_expr_string,
|
||||
@ -63,7 +64,7 @@ impl<'tcx> LateLintPass<'tcx> for OkIfLet {
|
||||
span_lint_and_sugg(
|
||||
cx,
|
||||
IF_LET_SOME_RESULT,
|
||||
expr.span.with_hi(op.span.hi()),
|
||||
expr.span.with_hi(let_expr.span.hi()),
|
||||
"matching on `Some` with `ok()` is redundant",
|
||||
&format!("consider matching on `Ok({})` and removing the call to `ok` instead", some_expr_string),
|
||||
sugg,
|
||||
|
@ -1,6 +1,6 @@
|
||||
use clippy_utils::diagnostics::span_lint_and_help;
|
||||
use clippy_utils::source::snippet_with_macro_callsite;
|
||||
use clippy_utils::{is_else_clause, is_lang_ctor, meets_msrv, msrvs};
|
||||
use clippy_utils::{higher, is_else_clause, is_lang_ctor, meets_msrv, msrvs};
|
||||
use if_chain::if_chain;
|
||||
use rustc_hir::LangItem::{OptionNone, OptionSome};
|
||||
use rustc_hir::{Expr, ExprKind};
|
||||
@ -70,7 +70,7 @@ impl LateLintPass<'_> for IfThenSomeElseNone {
|
||||
}
|
||||
|
||||
if_chain! {
|
||||
if let ExprKind::If(cond, then, Some(els)) = expr.kind;
|
||||
if let Some(higher::If { cond, then, r#else: Some(els) }) = higher::If::hir(expr);
|
||||
if let ExprKind::Block(then_block, _) = then.kind;
|
||||
if let Some(then_expr) = then_block.expr;
|
||||
if let ExprKind::Call(then_call, [then_arg]) = then_expr.kind;
|
||||
|
@ -1,4 +1,5 @@
|
||||
use clippy_utils::diagnostics::span_lint_and_sugg;
|
||||
use clippy_utils::higher;
|
||||
use clippy_utils::{in_macro, SpanlessEq};
|
||||
use if_chain::if_chain;
|
||||
use rustc_ast::ast::LitKind;
|
||||
@ -42,7 +43,7 @@ impl<'tcx> LateLintPass<'tcx> for ImplicitSaturatingSub {
|
||||
return;
|
||||
}
|
||||
if_chain! {
|
||||
if let ExprKind::If(cond, then, None) = &expr.kind;
|
||||
if let Some(higher::If { cond, then, .. }) = higher::If::hir(expr);
|
||||
|
||||
// Check if the conditional expression is a binary operation
|
||||
if let ExprKind::Binary(ref cond_op, cond_left, cond_right) = cond.kind;
|
||||
|
@ -96,7 +96,7 @@ impl<'tcx> LateLintPass<'tcx> for IndexingSlicing {
|
||||
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
|
||||
if let ExprKind::Index(array, index) = &expr.kind {
|
||||
let ty = cx.typeck_results().expr_ty(array).peel_refs();
|
||||
if let Some(range) = higher::range(index) {
|
||||
if let Some(range) = higher::Range::hir(index) {
|
||||
// Ranged indexes, i.e., &x[n..m], &x[n..], &x[..n] and &x[..]
|
||||
if let ty::Array(_, s) = ty.kind() {
|
||||
let size: u128 = if let Some(size) = s.try_eval_usize(cx.tcx, cx.param_env) {
|
||||
|
@ -172,7 +172,7 @@ fn is_infinite(cx: &LateContext<'_>, expr: &Expr<'_>) -> Finiteness {
|
||||
Finite
|
||||
}
|
||||
},
|
||||
ExprKind::Struct(..) => higher::range(expr).map_or(false, |r| r.end.is_none()).into(),
|
||||
ExprKind::Struct(..) => higher::Range::hir(expr).map_or(false, |r| r.end.is_none()).into(),
|
||||
_ => Finite,
|
||||
}
|
||||
}
|
||||
|
@ -64,7 +64,7 @@ impl<'tcx> LateLintPass<'tcx> for LetIfSeq {
|
||||
if let hir::StmtKind::Local(local) = stmt.kind;
|
||||
if let hir::PatKind::Binding(mode, canonical_id, ident, None) = local.pat.kind;
|
||||
if let hir::StmtKind::Expr(if_) = expr.kind;
|
||||
if let hir::ExprKind::If(cond, then, ref else_) = if_.kind;
|
||||
if let hir::ExprKind::If(hir::Expr { kind: hir::ExprKind::DropTemps(cond), ..}, then, else_) = if_.kind;
|
||||
let mut used_visitor = LocalUsedVisitor::new(cx, canonical_id);
|
||||
if !used_visitor.check_expr(cond);
|
||||
if let hir::ExprKind::Block(then, _) = then.kind;
|
||||
@ -79,7 +79,7 @@ impl<'tcx> LateLintPass<'tcx> for LetIfSeq {
|
||||
);
|
||||
if has_interior_mutability { return; }
|
||||
|
||||
let (default_multi_stmts, default) = if let Some(else_) = *else_ {
|
||||
let (default_multi_stmts, default) = if let Some(else_) = else_ {
|
||||
if let hir::ExprKind::Block(else_, _) = else_.kind {
|
||||
if let Some(default) = check_assign(cx, canonical_id, else_) {
|
||||
(else_.stmts.len() > 1, default)
|
||||
|
@ -1,11 +1,12 @@
|
||||
use super::utils::make_iterator_snippet;
|
||||
use super::MANUAL_FLATTEN;
|
||||
use clippy_utils::diagnostics::span_lint_and_then;
|
||||
use clippy_utils::higher;
|
||||
use clippy_utils::{is_lang_ctor, path_to_local_id};
|
||||
use if_chain::if_chain;
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_hir::LangItem::{OptionSome, ResultOk};
|
||||
use rustc_hir::{Expr, ExprKind, MatchSource, Pat, PatKind, StmtKind};
|
||||
use rustc_hir::{Expr, ExprKind, Pat, PatKind, StmtKind};
|
||||
use rustc_lint::LateContext;
|
||||
use rustc_middle::ty;
|
||||
use rustc_span::source_map::Span;
|
||||
@ -36,14 +37,12 @@ pub(super) fn check<'tcx>(
|
||||
|
||||
if_chain! {
|
||||
if let Some(inner_expr) = inner_expr;
|
||||
if let ExprKind::Match(
|
||||
match_expr, match_arms, MatchSource::IfLetDesugar{ contains_else_clause: false }
|
||||
) = inner_expr.kind;
|
||||
if let Some(higher::IfLet { let_pat, let_expr, if_else: None, .. }) = higher::IfLet::hir(inner_expr);
|
||||
// Ensure match_expr in `if let` statement is the same as the pat from the for-loop
|
||||
if let PatKind::Binding(_, pat_hir_id, _, _) = pat.kind;
|
||||
if path_to_local_id(match_expr, pat_hir_id);
|
||||
if path_to_local_id(let_expr, pat_hir_id);
|
||||
// Ensure the `if let` statement is for the `Some` variant of `Option` or the `Ok` variant of `Result`
|
||||
if let PatKind::TupleStruct(ref qpath, _, _) = match_arms[0].pat.kind;
|
||||
if let PatKind::TupleStruct(ref qpath, _, _) = let_pat.kind;
|
||||
let some_ctor = is_lang_ctor(cx, qpath, OptionSome);
|
||||
let ok_ctor = is_lang_ctor(cx, qpath, ResultOk);
|
||||
if some_ctor || ok_ctor;
|
||||
@ -55,7 +54,7 @@ pub(super) fn check<'tcx>(
|
||||
// Prepare the help message
|
||||
let mut applicability = Applicability::MaybeIncorrect;
|
||||
let arg_snippet = make_iterator_snippet(cx, arg, &mut applicability);
|
||||
let copied = match cx.typeck_results().expr_ty(match_expr).kind() {
|
||||
let copied = match cx.typeck_results().expr_ty(let_expr).kind() {
|
||||
ty::Ref(_, inner, _) => match inner.kind() {
|
||||
ty::Ref(..) => ".copied()",
|
||||
_ => ""
|
||||
|
@ -27,7 +27,7 @@ pub(super) fn check<'tcx>(
|
||||
start: Some(start),
|
||||
end: Some(end),
|
||||
limits,
|
||||
}) = higher::range(arg)
|
||||
}) = higher::Range::hir(arg)
|
||||
{
|
||||
// the var must be a single name
|
||||
if let PatKind::Binding(_, canonical_id, _, _) = pat.kind {
|
||||
|
@ -551,7 +551,7 @@ declare_lint_pass!(Loops => [
|
||||
impl<'tcx> LateLintPass<'tcx> for Loops {
|
||||
#[allow(clippy::too_many_lines)]
|
||||
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
|
||||
if let Some((pat, arg, body, span)) = higher::for_loop(expr) {
|
||||
if let Some(higher::ForLoop { pat, arg, body, span }) = higher::ForLoop::hir(expr) {
|
||||
// we don't want to check expanded macros
|
||||
// this check is not at the top of the function
|
||||
// since higher::for_loop expressions are marked as expansions
|
||||
@ -580,8 +580,8 @@ impl<'tcx> LateLintPass<'tcx> for Loops {
|
||||
|
||||
while_let_on_iterator::check(cx, expr);
|
||||
|
||||
if let Some((cond, body)) = higher::while_loop(expr) {
|
||||
while_immutable_condition::check(cx, cond, body);
|
||||
if let Some(higher::While { if_cond, if_then, .. }) = higher::While::hir(&expr) {
|
||||
while_immutable_condition::check(cx, if_cond, if_then);
|
||||
}
|
||||
|
||||
needless_collect::check(expr, cx);
|
||||
|
@ -14,7 +14,7 @@ pub(super) fn check(cx: &LateContext<'_>, arg: &Expr<'_>, body: &Expr<'_>) {
|
||||
start: Some(start),
|
||||
end: Some(end),
|
||||
..
|
||||
}) = higher::range(arg)
|
||||
}) = higher::Range::hir(arg)
|
||||
{
|
||||
let mut_ids = vec![check_for_mutability(cx, start), check_for_mutability(cx, end)];
|
||||
if mut_ids[0].is_some() || mut_ids[1].is_some() {
|
||||
|
@ -34,7 +34,7 @@ pub(super) fn check<'tcx>(
|
||||
start: Some(start),
|
||||
ref end,
|
||||
limits,
|
||||
}) = higher::range(arg)
|
||||
}) = higher::Range::hir(arg)
|
||||
{
|
||||
// the var must be a single name
|
||||
if let PatKind::Binding(_, canonical_id, ident, _) = pat.kind {
|
||||
|
@ -1,7 +1,7 @@
|
||||
use super::utils::make_iterator_snippet;
|
||||
use super::NEVER_LOOP;
|
||||
use clippy_utils::diagnostics::span_lint_and_then;
|
||||
use clippy_utils::higher;
|
||||
use clippy_utils::higher::ForLoop;
|
||||
use clippy_utils::source::snippet;
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_hir::{Block, Expr, ExprKind, HirId, InlineAsmOperand, LoopSource, Node, Pat, Stmt, StmtKind};
|
||||
@ -16,7 +16,7 @@ pub(super) fn check(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
|
||||
if_chain! {
|
||||
if let LoopSource::ForLoop = source;
|
||||
if let Some((_, Node::Expr(parent_match))) = cx.tcx.hir().parent_iter(expr.hir_id).nth(1);
|
||||
if let Some((pat, iterator, _, for_span)) = higher::for_loop(parent_match);
|
||||
if let Some(ForLoop { arg: iterator, pat, span: for_span, .. }) = ForLoop::hir(parent_match);
|
||||
then {
|
||||
// Suggests using an `if let` instead. This is `Unspecified` because the
|
||||
// loop may (probably) contain `break` statements which would be invalid
|
||||
@ -111,6 +111,7 @@ fn never_loop_expr(expr: &Expr<'_>, main_loop_id: HirId) -> NeverLoopResult {
|
||||
| ExprKind::Unary(_, e)
|
||||
| ExprKind::Cast(e, _)
|
||||
| ExprKind::Type(e, _)
|
||||
| ExprKind::Let(_, e, _)
|
||||
| ExprKind::Field(e, _)
|
||||
| ExprKind::AddrOf(_, _, e)
|
||||
| ExprKind::Struct(_, _, Some(e))
|
||||
@ -128,7 +129,7 @@ fn never_loop_expr(expr: &Expr<'_>, main_loop_id: HirId) -> NeverLoopResult {
|
||||
// Break can come from the inner loop so remove them.
|
||||
absorb_break(&never_loop_block(b, main_loop_id))
|
||||
},
|
||||
ExprKind::If(e, e2, ref e3) => {
|
||||
ExprKind::If(e, e2, e3) => {
|
||||
let e1 = never_loop_expr(e, main_loop_id);
|
||||
let e2 = never_loop_expr(e2, main_loop_id);
|
||||
let e3 = e3
|
||||
@ -156,7 +157,7 @@ fn never_loop_expr(expr: &Expr<'_>, main_loop_id: HirId) -> NeverLoopResult {
|
||||
NeverLoopResult::AlwaysBreak
|
||||
}
|
||||
},
|
||||
ExprKind::Break(_, ref e) | ExprKind::Ret(ref e) => e.as_ref().map_or(NeverLoopResult::AlwaysBreak, |e| {
|
||||
ExprKind::Break(_, e) | ExprKind::Ret(e) => e.as_ref().map_or(NeverLoopResult::AlwaysBreak, |e| {
|
||||
combine_seq(never_loop_expr(e, main_loop_id), NeverLoopResult::AlwaysBreak)
|
||||
}),
|
||||
ExprKind::InlineAsm(asm) => asm
|
||||
|
@ -1,8 +1,9 @@
|
||||
use super::WHILE_LET_LOOP;
|
||||
use clippy_utils::diagnostics::span_lint_and_sugg;
|
||||
use clippy_utils::higher;
|
||||
use clippy_utils::source::snippet_with_applicability;
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_hir::{Block, Expr, ExprKind, MatchSource, StmtKind};
|
||||
use rustc_hir::{Block, Expr, ExprKind, MatchSource, Pat, StmtKind};
|
||||
use rustc_lint::{LateContext, LintContext};
|
||||
use rustc_middle::lint::in_external_macro;
|
||||
|
||||
@ -11,41 +12,25 @@ pub(super) fn check(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, loop_block: &'
|
||||
let inner_stmt_expr = extract_expr_from_first_stmt(loop_block);
|
||||
// or extract the first expression (if any) from the block
|
||||
if let Some(inner) = inner_stmt_expr.or_else(|| extract_first_expr(loop_block)) {
|
||||
if let ExprKind::Match(matchexpr, arms, ref source) = inner.kind {
|
||||
// ensure "if let" compatible match structure
|
||||
match *source {
|
||||
MatchSource::Normal | MatchSource::IfLetDesugar { .. } => {
|
||||
if arms.len() == 2
|
||||
&& arms[0].guard.is_none()
|
||||
&& arms[1].guard.is_none()
|
||||
&& is_simple_break_expr(arms[1].body)
|
||||
{
|
||||
if in_external_macro(cx.sess(), expr.span) {
|
||||
return;
|
||||
}
|
||||
if let Some(higher::IfLet {
|
||||
let_pat,
|
||||
let_expr,
|
||||
if_else: Some(if_else),
|
||||
..
|
||||
}) = higher::IfLet::hir(inner)
|
||||
{
|
||||
if is_simple_break_expr(if_else) {
|
||||
could_be_while_let(cx, expr, let_pat, let_expr);
|
||||
}
|
||||
}
|
||||
|
||||
// NOTE: we used to build a body here instead of using
|
||||
// ellipsis, this was removed because:
|
||||
// 1) it was ugly with big bodies;
|
||||
// 2) it was not indented properly;
|
||||
// 3) it wasn’t very smart (see #675).
|
||||
let mut applicability = Applicability::HasPlaceholders;
|
||||
span_lint_and_sugg(
|
||||
cx,
|
||||
WHILE_LET_LOOP,
|
||||
expr.span,
|
||||
"this loop could be written as a `while let` loop",
|
||||
"try",
|
||||
format!(
|
||||
"while let {} = {} {{ .. }}",
|
||||
snippet_with_applicability(cx, arms[0].pat.span, "..", &mut applicability),
|
||||
snippet_with_applicability(cx, matchexpr.span, "..", &mut applicability),
|
||||
),
|
||||
applicability,
|
||||
);
|
||||
}
|
||||
},
|
||||
_ => (),
|
||||
if let ExprKind::Match(ref matchexpr, ref arms, MatchSource::Normal) = inner.kind {
|
||||
if arms.len() == 2
|
||||
&& arms[0].guard.is_none()
|
||||
&& arms[1].guard.is_none()
|
||||
&& is_simple_break_expr(&arms[1].body)
|
||||
{
|
||||
could_be_while_let(cx, expr, &arms[0].pat, matchexpr);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -54,14 +39,12 @@ pub(super) fn check(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, loop_block: &'
|
||||
/// If a block begins with a statement (possibly a `let` binding) and has an
|
||||
/// expression, return it.
|
||||
fn extract_expr_from_first_stmt<'tcx>(block: &Block<'tcx>) -> Option<&'tcx Expr<'tcx>> {
|
||||
if block.stmts.is_empty() {
|
||||
return None;
|
||||
}
|
||||
if let StmtKind::Local(local) = block.stmts[0].kind {
|
||||
local.init //.map(|expr| expr)
|
||||
} else {
|
||||
None
|
||||
if let Some(first_stmt) = block.stmts.get(0) {
|
||||
if let StmtKind::Local(local) = first_stmt.kind {
|
||||
return local.init;
|
||||
}
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
/// If a block begins with an expression (with or without semicolon), return it.
|
||||
@ -86,3 +69,34 @@ fn is_simple_break_expr(expr: &Expr<'_>) -> bool {
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
fn could_be_while_let<'tcx>(
|
||||
cx: &LateContext<'tcx>,
|
||||
expr: &'tcx Expr<'_>,
|
||||
let_pat: &'tcx Pat<'_>,
|
||||
let_expr: &'tcx Expr<'_>,
|
||||
) {
|
||||
if in_external_macro(cx.sess(), expr.span) {
|
||||
return;
|
||||
}
|
||||
|
||||
// NOTE: we used to build a body here instead of using
|
||||
// ellipsis, this was removed because:
|
||||
// 1) it was ugly with big bodies;
|
||||
// 2) it was not indented properly;
|
||||
// 3) it wasn’t very smart (see #675).
|
||||
let mut applicability = Applicability::HasPlaceholders;
|
||||
span_lint_and_sugg(
|
||||
cx,
|
||||
WHILE_LET_LOOP,
|
||||
expr.span,
|
||||
"this loop could be written as a `while let` loop",
|
||||
"try",
|
||||
format!(
|
||||
"while let {} = {} {{ .. }}",
|
||||
snippet_with_applicability(cx, let_pat.span, "..", &mut applicability),
|
||||
snippet_with_applicability(cx, let_expr.span, "..", &mut applicability),
|
||||
),
|
||||
applicability,
|
||||
);
|
||||
}
|
||||
|
@ -1,5 +1,6 @@
|
||||
use super::WHILE_LET_ON_ITERATOR;
|
||||
use clippy_utils::diagnostics::span_lint_and_sugg;
|
||||
use clippy_utils::higher;
|
||||
use clippy_utils::source::snippet_with_applicability;
|
||||
use clippy_utils::{
|
||||
get_enclosing_loop_or_closure, is_refutable, is_trait_method, match_def_path, paths, visitors::is_res_used,
|
||||
@ -7,27 +8,31 @@ use clippy_utils::{
|
||||
use if_chain::if_chain;
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_hir::intravisit::{walk_expr, ErasedMap, NestedVisitorMap, Visitor};
|
||||
use rustc_hir::{def::Res, Expr, ExprKind, HirId, Local, MatchSource, Mutability, Node, PatKind, QPath, UnOp};
|
||||
use rustc_hir::{def::Res, Expr, ExprKind, HirId, Local, Mutability, PatKind, QPath, UnOp};
|
||||
use rustc_lint::LateContext;
|
||||
use rustc_span::{symbol::sym, Span, Symbol};
|
||||
|
||||
pub(super) fn check(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
|
||||
let (scrutinee_expr, iter_expr, some_pat, loop_expr) = if_chain! {
|
||||
if let ExprKind::Match(scrutinee_expr, [arm, _], MatchSource::WhileLetDesugar) = expr.kind;
|
||||
if let Some(higher::WhileLet {
|
||||
if_then,
|
||||
let_pat,
|
||||
let_expr,
|
||||
..
|
||||
}) = higher::WhileLet::hir(expr);
|
||||
// check for `Some(..)` pattern
|
||||
if let PatKind::TupleStruct(QPath::Resolved(None, pat_path), some_pat, _) = arm.pat.kind;
|
||||
if let PatKind::TupleStruct(QPath::Resolved(None, pat_path), some_pat, _) = let_pat.kind;
|
||||
if let Res::Def(_, pat_did) = pat_path.res;
|
||||
if match_def_path(cx, pat_did, &paths::OPTION_SOME);
|
||||
// check for call to `Iterator::next`
|
||||
if let ExprKind::MethodCall(method_name, _, [iter_expr], _) = scrutinee_expr.kind;
|
||||
if let ExprKind::MethodCall(method_name, _, [iter_expr], _) = let_expr.kind;
|
||||
if method_name.ident.name == sym::next;
|
||||
if is_trait_method(cx, scrutinee_expr, sym::Iterator);
|
||||
if let Some(iter_expr) = try_parse_iter_expr(cx, iter_expr);
|
||||
if is_trait_method(cx, let_expr, sym::Iterator);
|
||||
if let Some(iter_expr_struct) = try_parse_iter_expr(cx, iter_expr);
|
||||
// get the loop containing the match expression
|
||||
if let Some((_, Node::Expr(loop_expr))) = cx.tcx.hir().parent_iter(expr.hir_id).nth(1);
|
||||
if !uses_iter(cx, &iter_expr, arm.body);
|
||||
if !uses_iter(cx, &iter_expr_struct, if_then);
|
||||
then {
|
||||
(scrutinee_expr, iter_expr, some_pat, loop_expr)
|
||||
(let_expr, iter_expr_struct, some_pat, expr)
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
@ -81,6 +86,7 @@ struct IterExpr {
|
||||
/// The path being used.
|
||||
path: Res,
|
||||
}
|
||||
|
||||
/// Parses any expression to find out which field of which variable is used. Will return `None` if
|
||||
/// the expression might have side effects.
|
||||
fn try_parse_iter_expr(cx: &LateContext<'_>, mut e: &Expr<'_>) -> Option<IterExpr> {
|
||||
@ -285,6 +291,7 @@ fn needs_mutable_borrow(cx: &LateContext<'tcx>, iter_expr: &IterExpr, loop_expr:
|
||||
}
|
||||
impl Visitor<'tcx> for NestedLoopVisitor<'a, 'b, 'tcx> {
|
||||
type Map = ErasedMap<'tcx>;
|
||||
|
||||
fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
|
||||
NestedVisitorMap::None
|
||||
}
|
||||
|
@ -1,5 +1,6 @@
|
||||
use crate::{map_unit_fn::OPTION_MAP_UNIT_FN, matches::MATCH_AS_REF};
|
||||
use clippy_utils::diagnostics::span_lint_and_sugg;
|
||||
use clippy_utils::higher;
|
||||
use clippy_utils::source::{snippet_with_applicability, snippet_with_context};
|
||||
use clippy_utils::ty::{is_type_diagnostic_item, peel_mid_ty_refs_is_mutable};
|
||||
use clippy_utils::{
|
||||
@ -9,7 +10,7 @@ use clippy_utils::{
|
||||
use rustc_ast::util::parser::PREC_POSTFIX;
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_hir::LangItem::{OptionNone, OptionSome};
|
||||
use rustc_hir::{Arm, BindingAnnotation, Block, Expr, ExprKind, HirId, MatchSource, Mutability, Pat, PatKind};
|
||||
use rustc_hir::{Arm, BindingAnnotation, Block, Expr, ExprKind, HirId, Mutability, Pat, PatKind};
|
||||
use rustc_lint::{LateContext, LateLintPass, LintContext};
|
||||
use rustc_middle::lint::in_external_macro;
|
||||
use rustc_session::{declare_lint_pass, declare_tool_lint};
|
||||
@ -43,163 +44,176 @@ declare_lint_pass!(ManualMap => [MANUAL_MAP]);
|
||||
impl LateLintPass<'_> for ManualMap {
|
||||
#[allow(clippy::too_many_lines)]
|
||||
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
|
||||
if let ExprKind::Match(
|
||||
scrutinee,
|
||||
[arm1 @ Arm { guard: None, .. }, arm2 @ Arm { guard: None, .. }],
|
||||
match_kind,
|
||||
) = expr.kind
|
||||
if let Some(higher::IfLet {
|
||||
let_pat,
|
||||
let_expr,
|
||||
if_then,
|
||||
if_else: Some(if_else),
|
||||
}) = higher::IfLet::hir(expr)
|
||||
{
|
||||
if in_external_macro(cx.sess(), expr.span) || in_constant(cx, expr.hir_id) {
|
||||
return;
|
||||
}
|
||||
manage_lint(cx, expr, (&let_pat.kind, if_then), (&PatKind::Wild, if_else), let_expr);
|
||||
}
|
||||
|
||||
let (scrutinee_ty, ty_ref_count, ty_mutability) =
|
||||
peel_mid_ty_refs_is_mutable(cx.typeck_results().expr_ty(scrutinee));
|
||||
if !(is_type_diagnostic_item(cx, scrutinee_ty, sym::option_type)
|
||||
&& is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(expr), sym::option_type))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
let expr_ctxt = expr.span.ctxt();
|
||||
let (some_expr, some_pat, pat_ref_count, is_wild_none) = match (
|
||||
try_parse_pattern(cx, arm1.pat, expr_ctxt),
|
||||
try_parse_pattern(cx, arm2.pat, expr_ctxt),
|
||||
) {
|
||||
(Some(OptionPat::Wild), Some(OptionPat::Some { pattern, ref_count }))
|
||||
if is_none_expr(cx, arm1.body) =>
|
||||
{
|
||||
(arm2.body, pattern, ref_count, true)
|
||||
},
|
||||
(Some(OptionPat::None), Some(OptionPat::Some { pattern, ref_count }))
|
||||
if is_none_expr(cx, arm1.body) =>
|
||||
{
|
||||
(arm2.body, pattern, ref_count, false)
|
||||
},
|
||||
(Some(OptionPat::Some { pattern, ref_count }), Some(OptionPat::Wild))
|
||||
if is_none_expr(cx, arm2.body) =>
|
||||
{
|
||||
(arm1.body, pattern, ref_count, true)
|
||||
},
|
||||
(Some(OptionPat::Some { pattern, ref_count }), Some(OptionPat::None))
|
||||
if is_none_expr(cx, arm2.body) =>
|
||||
{
|
||||
(arm1.body, pattern, ref_count, false)
|
||||
},
|
||||
_ => return,
|
||||
};
|
||||
|
||||
// Top level or patterns aren't allowed in closures.
|
||||
if matches!(some_pat.kind, PatKind::Or(_)) {
|
||||
return;
|
||||
}
|
||||
|
||||
let some_expr = match get_some_expr(cx, some_expr, expr_ctxt) {
|
||||
Some(expr) => expr,
|
||||
None => return,
|
||||
};
|
||||
|
||||
// These two lints will go back and forth with each other.
|
||||
if cx.typeck_results().expr_ty(some_expr) == cx.tcx.types.unit
|
||||
&& !is_lint_allowed(cx, OPTION_MAP_UNIT_FN, expr.hir_id)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// `map` won't perform any adjustments.
|
||||
if !cx.typeck_results().expr_adjustments(some_expr).is_empty() {
|
||||
return;
|
||||
}
|
||||
|
||||
if !can_move_expr_to_closure(cx, some_expr) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Determine which binding mode to use.
|
||||
let explicit_ref = some_pat.contains_explicit_ref_binding();
|
||||
let binding_ref = explicit_ref.or_else(|| (ty_ref_count != pat_ref_count).then(|| ty_mutability));
|
||||
|
||||
let as_ref_str = match binding_ref {
|
||||
Some(Mutability::Mut) => ".as_mut()",
|
||||
Some(Mutability::Not) => ".as_ref()",
|
||||
None => "",
|
||||
};
|
||||
|
||||
let mut app = Applicability::MachineApplicable;
|
||||
|
||||
// Remove address-of expressions from the scrutinee. Either `as_ref` will be called, or
|
||||
// it's being passed by value.
|
||||
let scrutinee = peel_hir_expr_refs(scrutinee).0;
|
||||
let (scrutinee_str, _) = snippet_with_context(cx, scrutinee.span, expr_ctxt, "..", &mut app);
|
||||
let scrutinee_str =
|
||||
if scrutinee.span.ctxt() == expr.span.ctxt() && scrutinee.precedence().order() < PREC_POSTFIX {
|
||||
format!("({})", scrutinee_str)
|
||||
} else {
|
||||
scrutinee_str.into()
|
||||
};
|
||||
|
||||
let body_str = if let PatKind::Binding(annotation, id, some_binding, None) = some_pat.kind {
|
||||
match can_pass_as_func(cx, id, some_expr) {
|
||||
Some(func) if func.span.ctxt() == some_expr.span.ctxt() => {
|
||||
snippet_with_applicability(cx, func.span, "..", &mut app).into_owned()
|
||||
},
|
||||
_ => {
|
||||
if path_to_local_id(some_expr, id)
|
||||
&& !is_lint_allowed(cx, MATCH_AS_REF, expr.hir_id)
|
||||
&& binding_ref.is_some()
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// `ref` and `ref mut` annotations were handled earlier.
|
||||
let annotation = if matches!(annotation, BindingAnnotation::Mutable) {
|
||||
"mut "
|
||||
} else {
|
||||
""
|
||||
};
|
||||
format!(
|
||||
"|{}{}| {}",
|
||||
annotation,
|
||||
some_binding,
|
||||
snippet_with_context(cx, some_expr.span, expr_ctxt, "..", &mut app).0
|
||||
)
|
||||
},
|
||||
}
|
||||
} else if !is_wild_none && explicit_ref.is_none() {
|
||||
// TODO: handle explicit reference annotations.
|
||||
format!(
|
||||
"|{}| {}",
|
||||
snippet_with_context(cx, some_pat.span, expr_ctxt, "..", &mut app).0,
|
||||
snippet_with_context(cx, some_expr.span, expr_ctxt, "..", &mut app).0
|
||||
)
|
||||
} else {
|
||||
// Refutable bindings and mixed reference annotations can't be handled by `map`.
|
||||
return;
|
||||
};
|
||||
|
||||
span_lint_and_sugg(
|
||||
if let ExprKind::Match(scrutinee, [then @ Arm { guard: None, .. }, r#else @ Arm { guard: None, .. }], _) =
|
||||
expr.kind
|
||||
{
|
||||
manage_lint(
|
||||
cx,
|
||||
MANUAL_MAP,
|
||||
expr.span,
|
||||
"manual implementation of `Option::map`",
|
||||
"try this",
|
||||
if matches!(match_kind, MatchSource::IfLetDesugar { .. }) && is_else_clause(cx.tcx, expr) {
|
||||
format!("{{ {}{}.map({}) }}", scrutinee_str, as_ref_str, body_str)
|
||||
} else {
|
||||
format!("{}{}.map({})", scrutinee_str, as_ref_str, body_str)
|
||||
},
|
||||
app,
|
||||
expr,
|
||||
(&then.pat.kind, then.body),
|
||||
(&r#else.pat.kind, r#else.body),
|
||||
scrutinee,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn manage_lint<'tcx>(
|
||||
cx: &LateContext<'tcx>,
|
||||
expr: &'tcx Expr<'_>,
|
||||
then: (&'tcx PatKind<'_>, &'tcx Expr<'_>),
|
||||
r#else: (&'tcx PatKind<'_>, &'tcx Expr<'_>),
|
||||
scrut: &'tcx Expr<'_>,
|
||||
) {
|
||||
if in_external_macro(cx.sess(), expr.span) || in_constant(cx, expr.hir_id) {
|
||||
return;
|
||||
}
|
||||
|
||||
let (scrutinee_ty, ty_ref_count, ty_mutability) = peel_mid_ty_refs_is_mutable(cx.typeck_results().expr_ty(scrut));
|
||||
if !(is_type_diagnostic_item(cx, scrutinee_ty, sym::option_type)
|
||||
&& is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(expr), sym::option_type))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
let (then_pat, then_expr) = then;
|
||||
let (else_pat, else_expr) = r#else;
|
||||
|
||||
let expr_ctxt = expr.span.ctxt();
|
||||
let (some_expr, some_pat, pat_ref_count, is_wild_none) = match (
|
||||
try_parse_pattern(cx, then_pat, expr_ctxt),
|
||||
try_parse_pattern(cx, else_pat, expr_ctxt),
|
||||
) {
|
||||
(Some(OptionPat::Wild), Some(OptionPat::Some { pattern, ref_count })) if is_none_expr(cx, then_expr) => {
|
||||
(else_expr, pattern, ref_count, true)
|
||||
},
|
||||
(Some(OptionPat::None), Some(OptionPat::Some { pattern, ref_count })) if is_none_expr(cx, then_expr) => {
|
||||
(else_expr, pattern, ref_count, false)
|
||||
},
|
||||
(Some(OptionPat::Some { pattern, ref_count }), Some(OptionPat::Wild)) if is_none_expr(cx, else_expr) => {
|
||||
(then_expr, pattern, ref_count, true)
|
||||
},
|
||||
(Some(OptionPat::Some { pattern, ref_count }), Some(OptionPat::None)) if is_none_expr(cx, else_expr) => {
|
||||
(then_expr, pattern, ref_count, false)
|
||||
},
|
||||
_ => return,
|
||||
};
|
||||
|
||||
// Top level or patterns aren't allowed in closures.
|
||||
if matches!(some_pat.kind, PatKind::Or(_)) {
|
||||
return;
|
||||
}
|
||||
|
||||
let some_expr = match get_some_expr(cx, some_expr, expr_ctxt) {
|
||||
Some(expr) => expr,
|
||||
None => return,
|
||||
};
|
||||
|
||||
if cx.typeck_results().expr_ty(some_expr) == cx.tcx.types.unit && !is_lint_allowed(cx, OPTION_MAP_UNIT_FN, expr.hir_id) {
|
||||
return;
|
||||
}
|
||||
|
||||
// `map` won't perform any adjustments.
|
||||
if !cx.typeck_results().expr_adjustments(some_expr).is_empty() {
|
||||
return;
|
||||
}
|
||||
|
||||
if !can_move_expr_to_closure(cx, some_expr) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Determine which binding mode to use.
|
||||
let explicit_ref = some_pat.contains_explicit_ref_binding();
|
||||
let binding_ref = explicit_ref.or_else(|| (ty_ref_count != pat_ref_count).then(|| ty_mutability));
|
||||
|
||||
let as_ref_str = match binding_ref {
|
||||
Some(Mutability::Mut) => ".as_mut()",
|
||||
Some(Mutability::Not) => ".as_ref()",
|
||||
None => "",
|
||||
};
|
||||
|
||||
let mut app = Applicability::MachineApplicable;
|
||||
|
||||
// Remove address-of expressions from the scrutinee. Either `as_ref` will be called, or
|
||||
// it's being passed by value.
|
||||
let scrutinee = peel_hir_expr_refs(scrut).0;
|
||||
let (scrutinee_str, _) = snippet_with_context(cx, scrutinee.span, expr_ctxt, "..", &mut app);
|
||||
let scrutinee_str = if scrutinee.span.ctxt() == expr.span.ctxt() && scrutinee.precedence().order() < PREC_POSTFIX {
|
||||
format!("({})", scrutinee_str)
|
||||
} else {
|
||||
scrutinee_str.into()
|
||||
};
|
||||
|
||||
let body_str = if let PatKind::Binding(annotation, id, some_binding, None) = some_pat.kind {
|
||||
match can_pass_as_func(cx, id, some_expr) {
|
||||
Some(func) if func.span.ctxt() == some_expr.span.ctxt() => {
|
||||
snippet_with_applicability(cx, func.span, "..", &mut app).into_owned()
|
||||
},
|
||||
_ => {
|
||||
if path_to_local_id(some_expr, id)
|
||||
&& !is_lint_allowed(cx, MATCH_AS_REF, expr.hir_id)
|
||||
&& binding_ref.is_some()
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// `ref` and `ref mut` annotations were handled earlier.
|
||||
let annotation = if matches!(annotation, BindingAnnotation::Mutable) {
|
||||
"mut "
|
||||
} else {
|
||||
""
|
||||
};
|
||||
format!(
|
||||
"|{}{}| {}",
|
||||
annotation,
|
||||
some_binding,
|
||||
snippet_with_context(cx, some_expr.span, expr_ctxt, "..", &mut app).0
|
||||
)
|
||||
},
|
||||
}
|
||||
} else if !is_wild_none && explicit_ref.is_none() {
|
||||
// TODO: handle explicit reference annotations.
|
||||
format!(
|
||||
"|{}| {}",
|
||||
snippet_with_context(cx, some_pat.span, expr_ctxt, "..", &mut app).0,
|
||||
snippet_with_context(cx, some_expr.span, expr_ctxt, "..", &mut app).0
|
||||
)
|
||||
} else {
|
||||
// Refutable bindings and mixed reference annotations can't be handled by `map`.
|
||||
return;
|
||||
};
|
||||
|
||||
span_lint_and_sugg(
|
||||
cx,
|
||||
MANUAL_MAP,
|
||||
expr.span,
|
||||
"manual implementation of `Option::map`",
|
||||
"try this",
|
||||
if is_else_clause(cx.tcx, expr) {
|
||||
format!("{{ {}{}.map({}) }}", scrutinee_str, as_ref_str, body_str)
|
||||
} else {
|
||||
format!("{}{}.map({})", scrutinee_str, as_ref_str, body_str)
|
||||
},
|
||||
app,
|
||||
);
|
||||
}
|
||||
|
||||
// Checks whether the expression could be passed as a function, or whether a closure is needed.
|
||||
// Returns the function to be passed to `map` if it exists.
|
||||
fn can_pass_as_func(cx: &LateContext<'tcx>, binding: HirId, expr: &'tcx Expr<'_>) -> Option<&'tcx Expr<'tcx>> {
|
||||
match expr.kind {
|
||||
ExprKind::Call(func, [arg])
|
||||
if path_to_local_id(arg, binding) && cx.typeck_results().expr_adjustments(arg).is_empty() =>
|
||||
if path_to_local_id (arg, binding) && cx.typeck_results().expr_adjustments(arg).is_empty() =>
|
||||
{
|
||||
Some(func)
|
||||
},
|
||||
@ -221,21 +235,28 @@ enum OptionPat<'a> {
|
||||
|
||||
// Try to parse into a recognized `Option` pattern.
|
||||
// i.e. `_`, `None`, `Some(..)`, or a reference to any of those.
|
||||
fn try_parse_pattern(cx: &LateContext<'tcx>, pat: &'tcx Pat<'_>, ctxt: SyntaxContext) -> Option<OptionPat<'tcx>> {
|
||||
fn f(cx: &LateContext<'tcx>, pat: &'tcx Pat<'_>, ref_count: usize, ctxt: SyntaxContext) -> Option<OptionPat<'tcx>> {
|
||||
match pat.kind {
|
||||
fn try_parse_pattern(
|
||||
cx: &LateContext<'tcx>,
|
||||
pat_kind: &'tcx PatKind<'_>,
|
||||
ctxt: SyntaxContext,
|
||||
) -> Option<OptionPat<'tcx>> {
|
||||
fn f(
|
||||
cx: &LateContext<'tcx>,
|
||||
pat_kind: &'tcx PatKind<'_>,
|
||||
ref_count: usize,
|
||||
ctxt: SyntaxContext,
|
||||
) -> Option<OptionPat<'tcx>> {
|
||||
match pat_kind {
|
||||
PatKind::Wild => Some(OptionPat::Wild),
|
||||
PatKind::Ref(pat, _) => f(cx, pat, ref_count + 1, ctxt),
|
||||
PatKind::Ref(ref_pat, _) => f(cx, &ref_pat.kind, ref_count + 1, ctxt),
|
||||
PatKind::Path(ref qpath) if is_lang_ctor(cx, qpath, OptionNone) => Some(OptionPat::None),
|
||||
PatKind::TupleStruct(ref qpath, [pattern], _)
|
||||
if is_lang_ctor(cx, qpath, OptionSome) && pat.span.ctxt() == ctxt =>
|
||||
{
|
||||
PatKind::TupleStruct(ref qpath, [pattern], _) if is_lang_ctor(cx, qpath, OptionSome) => {
|
||||
Some(OptionPat::Some { pattern, ref_count })
|
||||
},
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
f(cx, pat, 0, ctxt)
|
||||
f(cx, pat_kind, 0, ctxt)
|
||||
}
|
||||
|
||||
// Checks for an expression wrapped by the `Some` constructor. Returns the contained expression.
|
||||
|
@ -73,7 +73,7 @@ impl<'tcx> LateLintPass<'tcx> for ManualStrip {
|
||||
}
|
||||
|
||||
if_chain! {
|
||||
if let ExprKind::If(cond, then, _) = &expr.kind;
|
||||
if let Some(higher::If { cond, then, .. }) = higher::If::hir(expr);
|
||||
if let ExprKind::MethodCall(_, _, [target_arg, pattern], _) = cond.kind;
|
||||
if let Some(method_def_id) = cx.typeck_results().type_dependent_def_id(cond.hir_id);
|
||||
if let ExprKind::Path(target_path) = &target_arg.kind;
|
||||
@ -212,7 +212,7 @@ fn find_stripping<'tcx>(
|
||||
if is_ref_str(self.cx, ex);
|
||||
let unref = peel_ref(ex);
|
||||
if let ExprKind::Index(indexed, index) = &unref.kind;
|
||||
if let Some(higher::Range { start, end, .. }) = higher::range(index);
|
||||
if let Some(higher::Range { start, end, .. }) = higher::Range::hir(index);
|
||||
if let ExprKind::Path(path) = &indexed.kind;
|
||||
if self.cx.qpath_res(path, ex.hir_id) == self.target;
|
||||
then {
|
||||
|
@ -2,6 +2,7 @@ use clippy_utils::consts::{constant, miri_to_const, Constant};
|
||||
use clippy_utils::diagnostics::{
|
||||
multispan_sugg, span_lint_and_help, span_lint_and_note, span_lint_and_sugg, span_lint_and_then,
|
||||
};
|
||||
use clippy_utils::higher;
|
||||
use clippy_utils::source::{expr_block, indent_of, snippet, snippet_block, snippet_opt, snippet_with_applicability};
|
||||
use clippy_utils::sugg::Sugg;
|
||||
use clippy_utils::ty::{implements_trait, is_type_diagnostic_item, match_type, peel_mid_ty_refs};
|
||||
@ -12,8 +13,10 @@ use clippy_utils::{
|
||||
strip_pat_refs,
|
||||
};
|
||||
use clippy_utils::{paths, search_same, SpanlessEq, SpanlessHash};
|
||||
use core::array;
|
||||
use core::iter::{once, ExactSizeIterator};
|
||||
use if_chain::if_chain;
|
||||
use rustc_ast::ast::LitKind;
|
||||
use rustc_ast::ast::{Attribute, LitKind};
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_hir::def::{CtorKind, DefKind, Res};
|
||||
use rustc_hir::LangItem::{OptionNone, OptionSome};
|
||||
@ -628,8 +631,11 @@ impl<'tcx> LateLintPass<'tcx> for Matches {
|
||||
check_match_single_binding(cx, ex, arms, expr);
|
||||
}
|
||||
}
|
||||
if let ExprKind::Match(ex, arms, _) = expr.kind {
|
||||
check_match_ref_pats(cx, ex, arms, expr);
|
||||
if let ExprKind::Match(ref ex, ref arms, _) = expr.kind {
|
||||
check_match_ref_pats(cx, ex, arms.iter().map(|el| el.pat), expr);
|
||||
}
|
||||
if let Some(higher::IfLet { let_pat, let_expr, .. }) = higher::IfLet::hir(expr) {
|
||||
check_match_ref_pats(cx, let_expr, once(let_pat), expr);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1179,39 +1185,40 @@ fn is_panic_block(block: &Block<'_>) -> bool {
|
||||
}
|
||||
}
|
||||
|
||||
fn check_match_ref_pats(cx: &LateContext<'_>, ex: &Expr<'_>, arms: &[Arm<'_>], expr: &Expr<'_>) {
|
||||
if has_only_ref_pats(arms) {
|
||||
let mut suggs = Vec::with_capacity(arms.len() + 1);
|
||||
let (title, msg) = if let ExprKind::AddrOf(BorrowKind::Ref, Mutability::Not, inner) = ex.kind {
|
||||
let span = ex.span.source_callsite();
|
||||
suggs.push((span, Sugg::hir_with_macro_callsite(cx, inner, "..").to_string()));
|
||||
(
|
||||
"you don't need to add `&` to both the expression and the patterns",
|
||||
"try",
|
||||
)
|
||||
} else {
|
||||
let span = ex.span.source_callsite();
|
||||
suggs.push((span, Sugg::hir_with_macro_callsite(cx, ex, "..").deref().to_string()));
|
||||
(
|
||||
"you don't need to add `&` to all patterns",
|
||||
"instead of prefixing all patterns with `&`, you can dereference the expression",
|
||||
)
|
||||
};
|
||||
|
||||
suggs.extend(arms.iter().filter_map(|a| {
|
||||
if let PatKind::Ref(refp, _) = a.pat.kind {
|
||||
Some((a.pat.span, snippet(cx, refp.span, "..").to_string()))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}));
|
||||
|
||||
span_lint_and_then(cx, MATCH_REF_PATS, expr.span, title, |diag| {
|
||||
if !expr.span.from_expansion() {
|
||||
multispan_sugg(diag, msg, suggs);
|
||||
}
|
||||
});
|
||||
fn check_match_ref_pats<'a, 'b, I>(cx: &LateContext<'_>, ex: &Expr<'_>, pats: I, expr: &Expr<'_>)
|
||||
where
|
||||
'b: 'a,
|
||||
I: Clone + Iterator<Item = &'a Pat<'b>>,
|
||||
{
|
||||
if !has_only_ref_pats(pats.clone()) {
|
||||
return;
|
||||
}
|
||||
|
||||
let (first_sugg, msg, title);
|
||||
let span = ex.span.source_callsite();
|
||||
if let ExprKind::AddrOf(BorrowKind::Ref, Mutability::Not, ref inner) = ex.kind {
|
||||
first_sugg = once((span, Sugg::hir_with_macro_callsite(cx, inner, "..").to_string()));
|
||||
msg = "try";
|
||||
title = "you don't need to add `&` to both the expression and the patterns";
|
||||
} else {
|
||||
first_sugg = once((span, Sugg::hir_with_macro_callsite(cx, ex, "..").deref().to_string()));
|
||||
msg = "instead of prefixing all patterns with `&`, you can dereference the expression";
|
||||
title = "you don't need to add `&` to all patterns";
|
||||
}
|
||||
|
||||
let remaining_suggs = pats.filter_map(|pat| {
|
||||
if let PatKind::Ref(ref refp, _) = pat.kind {
|
||||
Some((pat.span, snippet(cx, refp.span, "..").to_string()))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
});
|
||||
|
||||
span_lint_and_then(cx, MATCH_REF_PATS, expr.span, title, |diag| {
|
||||
if !expr.span.from_expansion() {
|
||||
multispan_sugg(diag, msg, first_sugg.chain(remaining_suggs));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
fn check_match_as_ref(cx: &LateContext<'_>, ex: &Expr<'_>, arms: &[Arm<'_>], expr: &Expr<'_>) {
|
||||
@ -1286,46 +1293,99 @@ fn check_wild_in_or_pats(cx: &LateContext<'_>, arms: &[Arm<'_>]) {
|
||||
|
||||
/// Lint a `match` or `if let .. { .. } else { .. }` expr that could be replaced by `matches!`
|
||||
fn check_match_like_matches<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) -> bool {
|
||||
if let ExprKind::Match(ex, arms, ref match_source) = &expr.kind {
|
||||
match match_source {
|
||||
MatchSource::Normal => find_matches_sugg(cx, ex, arms, expr, false),
|
||||
MatchSource::IfLetDesugar { .. } => find_matches_sugg(cx, ex, arms, expr, true),
|
||||
_ => false,
|
||||
}
|
||||
} else {
|
||||
false
|
||||
if let Some(higher::IfLet {
|
||||
let_pat,
|
||||
let_expr,
|
||||
if_then,
|
||||
if_else: Some(if_else),
|
||||
}) = higher::IfLet::hir(expr)
|
||||
{
|
||||
return find_matches_sugg(
|
||||
cx,
|
||||
let_expr,
|
||||
array::IntoIter::new([(&[][..], Some(let_pat), if_then, None), (&[][..], None, if_else, None)]),
|
||||
expr,
|
||||
true,
|
||||
);
|
||||
}
|
||||
|
||||
if let ExprKind::Match(scrut, arms, MatchSource::Normal) = expr.kind {
|
||||
return find_matches_sugg(
|
||||
cx,
|
||||
scrut,
|
||||
arms.iter().map(|arm| {
|
||||
(
|
||||
cx.tcx.hir().attrs(arm.hir_id),
|
||||
Some(arm.pat),
|
||||
arm.body,
|
||||
arm.guard.as_ref(),
|
||||
)
|
||||
}),
|
||||
expr,
|
||||
false,
|
||||
);
|
||||
}
|
||||
|
||||
false
|
||||
}
|
||||
|
||||
/// Lint a `match` or desugared `if let` for replacement by `matches!`
|
||||
fn find_matches_sugg(cx: &LateContext<'_>, ex: &Expr<'_>, arms: &[Arm<'_>], expr: &Expr<'_>, desugared: bool) -> bool {
|
||||
/// Lint a `match` or `if let` for replacement by `matches!`
|
||||
fn find_matches_sugg<'a, 'b, I>(
|
||||
cx: &LateContext<'_>,
|
||||
ex: &Expr<'_>,
|
||||
mut iter: I,
|
||||
expr: &Expr<'_>,
|
||||
is_if_let: bool,
|
||||
) -> bool
|
||||
where
|
||||
'b: 'a,
|
||||
I: Clone
|
||||
+ DoubleEndedIterator
|
||||
+ ExactSizeIterator
|
||||
+ Iterator<
|
||||
Item = (
|
||||
&'a [Attribute],
|
||||
Option<&'a Pat<'b>>,
|
||||
&'a Expr<'b>,
|
||||
Option<&'a Guard<'b>>,
|
||||
),
|
||||
>,
|
||||
{
|
||||
if_chain! {
|
||||
if arms.len() >= 2;
|
||||
if iter.len() >= 2;
|
||||
if cx.typeck_results().expr_ty(expr).is_bool();
|
||||
if let Some((b1_arm, b0_arms)) = arms.split_last();
|
||||
if let Some(b0) = find_bool_lit(&b0_arms[0].body.kind, desugared);
|
||||
if let Some(b1) = find_bool_lit(&b1_arm.body.kind, desugared);
|
||||
if is_wild(b1_arm.pat);
|
||||
if let Some((_, last_pat_opt, last_expr, _)) = iter.next_back();
|
||||
let iter_without_last = iter.clone();
|
||||
if let Some((first_attrs, _, first_expr, first_guard)) = iter.next();
|
||||
if let Some(b0) = find_bool_lit(&first_expr.kind, is_if_let);
|
||||
if let Some(b1) = find_bool_lit(&last_expr.kind, is_if_let);
|
||||
if b0 != b1;
|
||||
let if_guard = &b0_arms[0].guard;
|
||||
if if_guard.is_none() || b0_arms.len() == 1;
|
||||
if cx.tcx.hir().attrs(b0_arms[0].hir_id).is_empty();
|
||||
if b0_arms[1..].iter()
|
||||
if first_guard.is_none() || iter.len() == 0;
|
||||
if first_attrs.is_empty();
|
||||
if iter
|
||||
.all(|arm| {
|
||||
find_bool_lit(&arm.body.kind, desugared).map_or(false, |b| b == b0) &&
|
||||
arm.guard.is_none() && cx.tcx.hir().attrs(arm.hir_id).is_empty()
|
||||
find_bool_lit(&arm.2.kind, is_if_let).map_or(false, |b| b == b0) && arm.3.is_none() && arm.0.is_empty()
|
||||
});
|
||||
then {
|
||||
if let Some(ref last_pat) = last_pat_opt {
|
||||
if !is_wild(last_pat) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// The suggestion may be incorrect, because some arms can have `cfg` attributes
|
||||
// evaluated into `false` and so such arms will be stripped before.
|
||||
let mut applicability = Applicability::MaybeIncorrect;
|
||||
let pat = {
|
||||
use itertools::Itertools as _;
|
||||
b0_arms.iter()
|
||||
.map(|arm| snippet_with_applicability(cx, arm.pat.span, "..", &mut applicability))
|
||||
iter_without_last
|
||||
.filter_map(|arm| {
|
||||
let pat_span = arm.1?.span;
|
||||
Some(snippet_with_applicability(cx, pat_span, "..", &mut applicability))
|
||||
})
|
||||
.join(" | ")
|
||||
};
|
||||
let pat_and_guard = if let Some(Guard::If(g)) = if_guard {
|
||||
let pat_and_guard = if let Some(Guard::If(g)) = first_guard {
|
||||
format!("{} if {}", pat, snippet_with_applicability(cx, g.span, "..", &mut applicability))
|
||||
} else {
|
||||
pat
|
||||
@ -1342,7 +1402,7 @@ fn find_matches_sugg(cx: &LateContext<'_>, ex: &Expr<'_>, arms: &[Arm<'_>], expr
|
||||
cx,
|
||||
MATCH_LIKE_MATCHES_MACRO,
|
||||
expr.span,
|
||||
&format!("{} expression looks like `matches!` macro", if desugared { "if let .. else" } else { "match" }),
|
||||
&format!("{} expression looks like `matches!` macro", if is_if_let { "if let .. else" } else { "match" }),
|
||||
"try this",
|
||||
format!(
|
||||
"{}matches!({}, {})",
|
||||
@ -1360,7 +1420,7 @@ fn find_matches_sugg(cx: &LateContext<'_>, ex: &Expr<'_>, arms: &[Arm<'_>], expr
|
||||
}
|
||||
|
||||
/// Extract a `bool` or `{ bool }`
|
||||
fn find_bool_lit(ex: &ExprKind<'_>, desugared: bool) -> Option<bool> {
|
||||
fn find_bool_lit(ex: &ExprKind<'_>, is_if_let: bool) -> Option<bool> {
|
||||
match ex {
|
||||
ExprKind::Lit(Spanned {
|
||||
node: LitKind::Bool(b), ..
|
||||
@ -1372,7 +1432,7 @@ fn find_bool_lit(ex: &ExprKind<'_>, desugared: bool) -> Option<bool> {
|
||||
..
|
||||
},
|
||||
_,
|
||||
) if desugared => {
|
||||
) if is_if_let => {
|
||||
if let ExprKind::Lit(Spanned {
|
||||
node: LitKind::Bool(b), ..
|
||||
}) = exp.kind
|
||||
@ -1644,19 +1704,26 @@ fn is_ref_some_arm(cx: &LateContext<'_>, arm: &Arm<'_>) -> Option<BindingAnnotat
|
||||
None
|
||||
}
|
||||
|
||||
fn has_only_ref_pats(arms: &[Arm<'_>]) -> bool {
|
||||
let mapped = arms
|
||||
.iter()
|
||||
.map(|a| {
|
||||
match a.pat.kind {
|
||||
PatKind::Ref(..) => Some(true), // &-patterns
|
||||
PatKind::Wild => Some(false), // an "anything" wildcard is also fine
|
||||
_ => None, // any other pattern is not fine
|
||||
fn has_only_ref_pats<'a, 'b, I>(pats: I) -> bool
|
||||
where
|
||||
'b: 'a,
|
||||
I: Iterator<Item = &'a Pat<'b>>,
|
||||
{
|
||||
let mut at_least_one_is_true = false;
|
||||
for opt in pats.map(|pat| match pat.kind {
|
||||
PatKind::Ref(..) => Some(true), // &-patterns
|
||||
PatKind::Wild => Some(false), // an "anything" wildcard is also fine
|
||||
_ => None, // any other pattern is not fine
|
||||
}) {
|
||||
if let Some(inner) = opt {
|
||||
if inner {
|
||||
at_least_one_is_true = true;
|
||||
}
|
||||
})
|
||||
.collect::<Option<Vec<bool>>>();
|
||||
// look for Some(v) where there's at least one true element
|
||||
mapped.map_or(false, |v| v.iter().any(|el| *el))
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
at_least_one_is_true
|
||||
}
|
||||
|
||||
pub fn overlapping<T>(ranges: &[SpannedRange<T>]) -> Option<(&SpannedRange<T>, &SpannedRange<T>)>
|
||||
@ -1745,6 +1812,7 @@ where
|
||||
mod redundant_pattern_match {
|
||||
use super::REDUNDANT_PATTERN_MATCHING;
|
||||
use clippy_utils::diagnostics::span_lint_and_then;
|
||||
use clippy_utils::higher;
|
||||
use clippy_utils::source::{snippet, snippet_with_applicability};
|
||||
use clippy_utils::ty::{implements_trait, is_type_diagnostic_item, is_type_lang_item, match_type};
|
||||
use clippy_utils::{is_lang_ctor, is_qpath_def_path, is_trait_method, paths};
|
||||
@ -1755,22 +1823,27 @@ mod redundant_pattern_match {
|
||||
use rustc_hir::LangItem::{OptionNone, OptionSome, PollPending, PollReady, ResultErr, ResultOk};
|
||||
use rustc_hir::{
|
||||
intravisit::{walk_expr, ErasedMap, NestedVisitorMap, Visitor},
|
||||
Arm, Block, Expr, ExprKind, LangItem, MatchSource, Node, PatKind, QPath,
|
||||
Arm, Block, Expr, ExprKind, LangItem, MatchSource, Node, Pat, PatKind, QPath,
|
||||
};
|
||||
use rustc_lint::LateContext;
|
||||
use rustc_middle::ty::{self, subst::GenericArgKind, Ty};
|
||||
use rustc_span::sym;
|
||||
|
||||
pub fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
|
||||
if let ExprKind::Match(op, arms, ref match_source) = &expr.kind {
|
||||
match match_source {
|
||||
MatchSource::Normal => find_sugg_for_match(cx, expr, op, arms),
|
||||
MatchSource::IfLetDesugar { contains_else_clause } => {
|
||||
find_sugg_for_if_let(cx, expr, op, &arms[0], "if", *contains_else_clause);
|
||||
},
|
||||
MatchSource::WhileLetDesugar => find_sugg_for_if_let(cx, expr, op, &arms[0], "while", false),
|
||||
_ => {},
|
||||
}
|
||||
if let Some(higher::IfLet {
|
||||
if_else,
|
||||
let_pat,
|
||||
let_expr,
|
||||
..
|
||||
}) = higher::IfLet::ast(cx, expr)
|
||||
{
|
||||
find_sugg_for_if_let(cx, expr, let_pat, let_expr, "if", if_else.is_some())
|
||||
}
|
||||
if let ExprKind::Match(op, arms, MatchSource::Normal) = &expr.kind {
|
||||
find_sugg_for_match(cx, expr, op, arms)
|
||||
}
|
||||
if let Some(higher::WhileLet { let_pat, let_expr, .. }) = higher::WhileLet::hir(expr) {
|
||||
find_sugg_for_if_let(cx, expr, let_pat, let_expr, "while", false)
|
||||
}
|
||||
}
|
||||
|
||||
@ -1924,18 +1997,18 @@ mod redundant_pattern_match {
|
||||
fn find_sugg_for_if_let<'tcx>(
|
||||
cx: &LateContext<'tcx>,
|
||||
expr: &'tcx Expr<'_>,
|
||||
op: &'tcx Expr<'tcx>,
|
||||
arm: &Arm<'_>,
|
||||
let_pat: &Pat<'_>,
|
||||
let_expr: &'tcx Expr<'_>,
|
||||
keyword: &'static str,
|
||||
has_else: bool,
|
||||
) {
|
||||
// also look inside refs
|
||||
let mut kind = &arm.pat.kind;
|
||||
let mut kind = &let_pat.kind;
|
||||
// if we have &None for example, peel it so we can detect "if let None = x"
|
||||
if let PatKind::Ref(inner, _mutability) = kind {
|
||||
kind = &inner.kind;
|
||||
}
|
||||
let op_ty = cx.typeck_results().expr_ty(op);
|
||||
let op_ty = cx.typeck_results().expr_ty(let_expr);
|
||||
// Determine which function should be used, and the type contained by the corresponding
|
||||
// variant.
|
||||
let (good_method, inner_ty) = match kind {
|
||||
@ -1989,38 +2062,38 @@ mod redundant_pattern_match {
|
||||
// scrutinee would be, so they have to be considered as well.
|
||||
// e.g. in `if let Some(x) = foo.lock().unwrap().baz.as_ref() { .. }` the lock will be held
|
||||
// for the duration if body.
|
||||
let needs_drop = type_needs_ordered_drop(cx, check_ty) || temporaries_need_ordered_drop(cx, op);
|
||||
let needs_drop = type_needs_ordered_drop(cx, check_ty) || temporaries_need_ordered_drop(cx, let_expr);
|
||||
|
||||
// check that `while_let_on_iterator` lint does not trigger
|
||||
if_chain! {
|
||||
if keyword == "while";
|
||||
if let ExprKind::MethodCall(method_path, _, _, _) = op.kind;
|
||||
if let ExprKind::MethodCall(method_path, _, _, _) = let_expr.kind;
|
||||
if method_path.ident.name == sym::next;
|
||||
if is_trait_method(cx, op, sym::Iterator);
|
||||
if is_trait_method(cx, let_expr, sym::Iterator);
|
||||
then {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
let result_expr = match &op.kind {
|
||||
let result_expr = match &let_expr.kind {
|
||||
ExprKind::AddrOf(_, _, borrowed) => borrowed,
|
||||
_ => op,
|
||||
_ => let_expr,
|
||||
};
|
||||
span_lint_and_then(
|
||||
cx,
|
||||
REDUNDANT_PATTERN_MATCHING,
|
||||
arm.pat.span,
|
||||
let_pat.span,
|
||||
&format!("redundant pattern matching, consider using `{}`", good_method),
|
||||
|diag| {
|
||||
// while let ... = ... { ... }
|
||||
// if/while let ... = ... { ... }
|
||||
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
let expr_span = expr.span;
|
||||
|
||||
// while let ... = ... { ... }
|
||||
// if/while let ... = ... { ... }
|
||||
// ^^^
|
||||
let op_span = result_expr.span.source_callsite();
|
||||
|
||||
// while let ... = ... { ... }
|
||||
// if/while let ... = ... { ... }
|
||||
// ^^^^^^^^^^^^^^^^^^^
|
||||
let span = expr_span.until(op_span.shrink_to_hi());
|
||||
|
||||
|
@ -18,7 +18,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>, cal
|
||||
// since it is already covered by `&loops::ITER_NEXT_LOOP`
|
||||
let mut parent_expr_opt = get_parent_expr(cx, expr);
|
||||
while let Some(parent_expr) = parent_expr_opt {
|
||||
if higher::for_loop(parent_expr).is_some() {
|
||||
if higher::ForLoop::hir(parent_expr).is_some() {
|
||||
return;
|
||||
}
|
||||
parent_expr_opt = get_parent_expr(cx, parent_expr);
|
||||
@ -29,7 +29,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>, cal
|
||||
if_chain! {
|
||||
if let hir::ExprKind::Index(caller_var, index_expr) = &caller_expr.kind;
|
||||
if let Some(higher::Range { start: Some(start_expr), end: None, limits: ast::RangeLimits::HalfOpen })
|
||||
= higher::range(index_expr);
|
||||
= higher::Range::hir(index_expr);
|
||||
if let hir::ExprKind::Lit(ref start_lit) = &start_expr.kind;
|
||||
if let ast::LitKind::Int(start_idx, _) = start_lit.node;
|
||||
then {
|
||||
|
@ -53,7 +53,7 @@ impl<'a, 'tcx> intravisit::Visitor<'tcx> for MutVisitor<'a, 'tcx> {
|
||||
return;
|
||||
}
|
||||
|
||||
if let Some((_, arg, body, _)) = higher::for_loop(expr) {
|
||||
if let Some(higher::ForLoop { arg, body, .. }) = higher::ForLoop::hir(expr) {
|
||||
// A `for` loop lowers to:
|
||||
// ```rust
|
||||
// match ::std::iter::Iterator::next(&mut iter) {
|
||||
|
@ -3,6 +3,7 @@
|
||||
//! This lint is **warn** by default
|
||||
|
||||
use clippy_utils::diagnostics::{span_lint, span_lint_and_sugg};
|
||||
use clippy_utils::higher;
|
||||
use clippy_utils::source::snippet_with_applicability;
|
||||
use clippy_utils::sugg::Sugg;
|
||||
use clippy_utils::{is_else_clause, is_expn_of};
|
||||
@ -77,10 +78,15 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessBool {
|
||||
if e.span.from_expansion() {
|
||||
return;
|
||||
}
|
||||
if let ExprKind::If(pred, then_block, Some(else_expr)) = e.kind {
|
||||
if let Some(higher::If {
|
||||
cond,
|
||||
then,
|
||||
r#else: Some(r#else),
|
||||
}) = higher::If::hir(e)
|
||||
{
|
||||
let reduce = |ret, not| {
|
||||
let mut applicability = Applicability::MachineApplicable;
|
||||
let snip = Sugg::hir_with_applicability(cx, pred, "<predicate>", &mut applicability);
|
||||
let snip = Sugg::hir_with_applicability(cx, cond, "<predicate>", &mut applicability);
|
||||
let mut snip = if not { !snip } else { snip };
|
||||
|
||||
if ret {
|
||||
@ -101,8 +107,8 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessBool {
|
||||
applicability,
|
||||
);
|
||||
};
|
||||
if let ExprKind::Block(then_block, _) = then_block.kind {
|
||||
match (fetch_bool_block(then_block), fetch_bool_expr(else_expr)) {
|
||||
if let ExprKind::Block(then, _) = then.kind {
|
||||
match (fetch_bool_block(then), fetch_bool_expr(r#else)) {
|
||||
(RetBool(true), RetBool(true)) | (Bool(true), Bool(true)) => {
|
||||
span_lint(
|
||||
cx,
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user