Don't suggest adding let in certain if conditions
This commit is contained in:
parent
b17e9d76f2
commit
2ae1ec9119
6 changed files with 142 additions and 8 deletions
|
@ -1278,6 +1278,22 @@ impl Expr {
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// To a first-order approximation, is this a pattern
|
||||||
|
pub fn is_approximately_pattern(&self) -> bool {
|
||||||
|
match &self.peel_parens().kind {
|
||||||
|
ExprKind::Box(_)
|
||||||
|
| ExprKind::Array(_)
|
||||||
|
| ExprKind::Call(_, _)
|
||||||
|
| ExprKind::Tup(_)
|
||||||
|
| ExprKind::Lit(_)
|
||||||
|
| ExprKind::Range(_, _, _)
|
||||||
|
| ExprKind::Underscore
|
||||||
|
| ExprKind::Path(_, _)
|
||||||
|
| ExprKind::Struct(_) => true,
|
||||||
|
_ => false,
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Limit types of a range (inclusive or exclusive)
|
/// Limit types of a range (inclusive or exclusive)
|
||||||
|
|
|
@ -1813,6 +1813,20 @@ impl Expr<'_> {
|
||||||
| ExprKind::Err => true,
|
| ExprKind::Err => true,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// To a first-order approximation, is this a pattern
|
||||||
|
pub fn is_approximately_pattern(&self) -> bool {
|
||||||
|
match &self.kind {
|
||||||
|
ExprKind::Box(_)
|
||||||
|
| ExprKind::Array(_)
|
||||||
|
| ExprKind::Call(..)
|
||||||
|
| ExprKind::Tup(_)
|
||||||
|
| ExprKind::Lit(_)
|
||||||
|
| ExprKind::Path(_)
|
||||||
|
| ExprKind::Struct(..) => true,
|
||||||
|
_ => false,
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Checks if the specified expression is a built-in range literal.
|
/// Checks if the specified expression is a built-in range literal.
|
||||||
|
|
|
@ -265,14 +265,22 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
match (source, self.diagnostic_metadata.in_if_condition) {
|
match (source, self.diagnostic_metadata.in_if_condition) {
|
||||||
(PathSource::Expr(_), Some(Expr { span, kind: ExprKind::Assign(..), .. })) => {
|
(
|
||||||
|
PathSource::Expr(_),
|
||||||
|
Some(Expr { span: expr_span, kind: ExprKind::Assign(lhs, _, _), .. }),
|
||||||
|
) => {
|
||||||
|
// Icky heuristic so we don't suggest:
|
||||||
|
// `if (i + 2) = 2` => `if let (i + 2) = 2` (approximately pattern)
|
||||||
|
// `if 2 = i` => `if let 2 = i` (lhs needs to contain error span)
|
||||||
|
if lhs.is_approximately_pattern() && lhs.span.contains(span) {
|
||||||
err.span_suggestion_verbose(
|
err.span_suggestion_verbose(
|
||||||
span.shrink_to_lo(),
|
expr_span.shrink_to_lo(),
|
||||||
"you might have meant to use pattern matching",
|
"you might have meant to use pattern matching",
|
||||||
"let ".to_string(),
|
"let ".to_string(),
|
||||||
Applicability::MaybeIncorrect,
|
Applicability::MaybeIncorrect,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1035,7 +1035,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
} else {
|
} else {
|
||||||
(Applicability::MaybeIncorrect, false)
|
(Applicability::MaybeIncorrect, false)
|
||||||
};
|
};
|
||||||
if !lhs.is_syntactic_place_expr() && !matches!(lhs.kind, hir::ExprKind::Lit(_)) {
|
if !lhs.is_syntactic_place_expr()
|
||||||
|
&& lhs.is_approximately_pattern()
|
||||||
|
&& !matches!(lhs.kind, hir::ExprKind::Lit(_))
|
||||||
|
{
|
||||||
// Do not suggest `if let x = y` as `==` is way more likely to be the intention.
|
// Do not suggest `if let x = y` as `==` is way more likely to be the intention.
|
||||||
let hir = self.tcx.hir();
|
let hir = self.tcx.hir();
|
||||||
if let hir::Node::Expr(hir::Expr { kind: ExprKind::If { .. }, .. }) =
|
if let hir::Node::Expr(hir::Expr { kind: ExprKind::If { .. }, .. }) =
|
||||||
|
|
24
src/test/ui/expr/if/bad-if-let-suggestion.rs
Normal file
24
src/test/ui/expr/if/bad-if-let-suggestion.rs
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
// FIXME(compiler-errors): This really should suggest `let` on the RHS of the
|
||||||
|
// `&&` operator, but that's kinda hard to do because of precedence.
|
||||||
|
// Instead, for now we just make sure not to suggest `if let let`.
|
||||||
|
fn a() {
|
||||||
|
if let x = 1 && i = 2 {}
|
||||||
|
//~^ ERROR cannot find value `i` in this scope
|
||||||
|
//~| ERROR `let` expressions in this position are unstable
|
||||||
|
//~| ERROR mismatched types
|
||||||
|
//~| ERROR `let` expressions are not supported here
|
||||||
|
}
|
||||||
|
|
||||||
|
fn b() {
|
||||||
|
if (i + j) = i {}
|
||||||
|
//~^ ERROR cannot find value `i` in this scope
|
||||||
|
//~| ERROR cannot find value `i` in this scope
|
||||||
|
//~| ERROR cannot find value `j` in this scope
|
||||||
|
}
|
||||||
|
|
||||||
|
fn c() {
|
||||||
|
if x[0] = 1 {}
|
||||||
|
//~^ ERROR cannot find value `x` in this scope
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {}
|
69
src/test/ui/expr/if/bad-if-let-suggestion.stderr
Normal file
69
src/test/ui/expr/if/bad-if-let-suggestion.stderr
Normal file
|
@ -0,0 +1,69 @@
|
||||||
|
error: `let` expressions are not supported here
|
||||||
|
--> $DIR/bad-if-let-suggestion.rs:5:8
|
||||||
|
|
|
||||||
|
LL | if let x = 1 && i = 2 {}
|
||||||
|
| ^^^^^^^^^
|
||||||
|
|
|
||||||
|
= note: only supported directly in conditions of `if` and `while` expressions
|
||||||
|
|
||||||
|
error[E0425]: cannot find value `i` in this scope
|
||||||
|
--> $DIR/bad-if-let-suggestion.rs:5:21
|
||||||
|
|
|
||||||
|
LL | if let x = 1 && i = 2 {}
|
||||||
|
| ^ not found in this scope
|
||||||
|
|
||||||
|
error[E0425]: cannot find value `i` in this scope
|
||||||
|
--> $DIR/bad-if-let-suggestion.rs:13:9
|
||||||
|
|
|
||||||
|
LL | fn a() {
|
||||||
|
| ------ similarly named function `a` defined here
|
||||||
|
...
|
||||||
|
LL | if (i + j) = i {}
|
||||||
|
| ^ help: a function with a similar name exists: `a`
|
||||||
|
|
||||||
|
error[E0425]: cannot find value `j` in this scope
|
||||||
|
--> $DIR/bad-if-let-suggestion.rs:13:13
|
||||||
|
|
|
||||||
|
LL | fn a() {
|
||||||
|
| ------ similarly named function `a` defined here
|
||||||
|
...
|
||||||
|
LL | if (i + j) = i {}
|
||||||
|
| ^ help: a function with a similar name exists: `a`
|
||||||
|
|
||||||
|
error[E0425]: cannot find value `i` in this scope
|
||||||
|
--> $DIR/bad-if-let-suggestion.rs:13:18
|
||||||
|
|
|
||||||
|
LL | fn a() {
|
||||||
|
| ------ similarly named function `a` defined here
|
||||||
|
...
|
||||||
|
LL | if (i + j) = i {}
|
||||||
|
| ^ help: a function with a similar name exists: `a`
|
||||||
|
|
||||||
|
error[E0425]: cannot find value `x` in this scope
|
||||||
|
--> $DIR/bad-if-let-suggestion.rs:20:8
|
||||||
|
|
|
||||||
|
LL | fn a() {
|
||||||
|
| ------ similarly named function `a` defined here
|
||||||
|
...
|
||||||
|
LL | if x[0] = 1 {}
|
||||||
|
| ^ help: a function with a similar name exists: `a`
|
||||||
|
|
||||||
|
error[E0658]: `let` expressions in this position are unstable
|
||||||
|
--> $DIR/bad-if-let-suggestion.rs:5:8
|
||||||
|
|
|
||||||
|
LL | if let x = 1 && i = 2 {}
|
||||||
|
| ^^^^^^^^^
|
||||||
|
|
|
||||||
|
= note: see issue #53667 <https://github.com/rust-lang/rust/issues/53667> for more information
|
||||||
|
= help: add `#![feature(let_chains)]` to the crate attributes to enable
|
||||||
|
|
||||||
|
error[E0308]: mismatched types
|
||||||
|
--> $DIR/bad-if-let-suggestion.rs:5:8
|
||||||
|
|
|
||||||
|
LL | if let x = 1 && i = 2 {}
|
||||||
|
| ^^^^^^^^^^^^^^^^^^ expected `bool`, found `()`
|
||||||
|
|
||||||
|
error: aborting due to 8 previous errors
|
||||||
|
|
||||||
|
Some errors have detailed explanations: E0308, E0425, E0658.
|
||||||
|
For more information about an error, try `rustc --explain E0308`.
|
Loading…
Add table
Add a link
Reference in a new issue