mirror of
https://github.com/rust-lang/rust.git
synced 2024-11-23 07:14:28 +00:00
Rollup merge of #104036 - compiler-errors:option-sugg, r=petrochenkov
Suggest `is_some` when we've found `Option` but expected `bool` Thanks `@lunasorcery` for the suggestion.
This commit is contained in:
commit
529f7149d2
@ -42,7 +42,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
|| self.suggest_boxing_when_appropriate(err, expr, expected, expr_ty)
|
||||
|| self.suggest_block_to_brackets_peeling_refs(err, expr, expr_ty, expected)
|
||||
|| self.suggest_copied_or_cloned(err, expr, expr_ty, expected)
|
||||
|| self.suggest_into(err, expr, expr_ty, expected);
|
||||
|| self.suggest_into(err, expr, expr_ty, expected)
|
||||
|| self.suggest_option_to_bool(err, expr, expr_ty, expected);
|
||||
|
||||
self.note_type_is_not_clone(err, expected, expr_ty, expr);
|
||||
self.note_need_for_fn_pointer(err, expected, expr_ty);
|
||||
|
@ -103,8 +103,16 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
}
|
||||
|
||||
if let Some(mut err) = self.demand_suptype_diag(expr.span, expected_ty, ty) {
|
||||
let expr = expr.peel_drop_temps();
|
||||
self.suggest_deref_ref_or_into(&mut err, expr, expected_ty, ty, None);
|
||||
// FIXME(compiler-errors): We probably should fold some of the
|
||||
// `suggest_` functions from `emit_coerce_suggestions` into here,
|
||||
// since some of those aren't necessarily just coerce suggestions.
|
||||
let _ = self.suggest_deref_ref_or_into(
|
||||
&mut err,
|
||||
expr.peel_drop_temps(),
|
||||
expected_ty,
|
||||
ty,
|
||||
None,
|
||||
) || self.suggest_option_to_bool(&mut err, expr, ty, expected_ty);
|
||||
extend_err(&mut err);
|
||||
err.emit();
|
||||
}
|
||||
|
@ -13,7 +13,7 @@ use rustc_hir_analysis::astconv::AstConv;
|
||||
use rustc_infer::infer::{self, TyCtxtInferExt};
|
||||
use rustc_infer::traits::{self, StatementAsExpression};
|
||||
use rustc_middle::lint::in_external_macro;
|
||||
use rustc_middle::ty::{self, Binder, IsSuggestable, ToPredicate, Ty};
|
||||
use rustc_middle::ty::{self, Binder, DefIdTree, IsSuggestable, ToPredicate, Ty};
|
||||
use rustc_session::errors::ExprParenthesesNeeded;
|
||||
use rustc_span::symbol::sym;
|
||||
use rustc_span::Span;
|
||||
@ -1116,6 +1116,53 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
false
|
||||
}
|
||||
|
||||
/// When expecting a `bool` and finding an `Option`, suggests using `let Some(..)` or `.is_some()`
|
||||
pub(crate) fn suggest_option_to_bool(
|
||||
&self,
|
||||
diag: &mut Diagnostic,
|
||||
expr: &hir::Expr<'_>,
|
||||
expr_ty: Ty<'tcx>,
|
||||
expected_ty: Ty<'tcx>,
|
||||
) -> bool {
|
||||
if !expected_ty.is_bool() {
|
||||
return false;
|
||||
}
|
||||
|
||||
let ty::Adt(def, _) = expr_ty.peel_refs().kind() else { return false; };
|
||||
if !self.tcx.is_diagnostic_item(sym::Option, def.did()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
let hir = self.tcx.hir();
|
||||
let cond_parent = hir.parent_iter(expr.hir_id).skip_while(|(_, node)| {
|
||||
matches!(node, hir::Node::Expr(hir::Expr { kind: hir::ExprKind::Binary(op, _, _), .. }) if op.node == hir::BinOpKind::And)
|
||||
}).next();
|
||||
// Don't suggest:
|
||||
// `let Some(_) = a.is_some() && b`
|
||||
// ++++++++++
|
||||
// since the user probably just misunderstood how `let else`
|
||||
// and `&&` work together.
|
||||
if let Some((_, hir::Node::Local(local))) = cond_parent
|
||||
&& let hir::PatKind::Path(qpath) | hir::PatKind::TupleStruct(qpath, _, _) = &local.pat.kind
|
||||
&& let hir::QPath::Resolved(None, path) = qpath
|
||||
&& let Some(did) = path.res.opt_def_id()
|
||||
.and_then(|did| self.tcx.opt_parent(did))
|
||||
.and_then(|did| self.tcx.opt_parent(did))
|
||||
&& self.tcx.is_diagnostic_item(sym::Option, did)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
diag.span_suggestion(
|
||||
expr.span.shrink_to_hi(),
|
||||
"use `Option::is_some` to test if the `Option` has a value",
|
||||
".is_some()",
|
||||
Applicability::MachineApplicable,
|
||||
);
|
||||
|
||||
true
|
||||
}
|
||||
|
||||
/// Suggest wrapping the block in square brackets instead of curly braces
|
||||
/// in case the block was mistaken array syntax, e.g. `{ 1 }` -> `[ 1 ]`.
|
||||
pub(crate) fn suggest_block_to_brackets(
|
||||
|
9
src/test/ui/suggestions/option-to-bool.rs
Normal file
9
src/test/ui/suggestions/option-to-bool.rs
Normal file
@ -0,0 +1,9 @@
|
||||
#![cfg_attr(let_chains, feature(let_chains))]
|
||||
|
||||
fn foo(x: Option<i32>) {
|
||||
if true && x {}
|
||||
//~^ ERROR mismatched types
|
||||
//~| HELP use `Option::is_some` to test if the `Option` has a value
|
||||
}
|
||||
|
||||
fn main() {}
|
16
src/test/ui/suggestions/option-to-bool.stderr
Normal file
16
src/test/ui/suggestions/option-to-bool.stderr
Normal file
@ -0,0 +1,16 @@
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/option-to-bool.rs:4:16
|
||||
|
|
||||
LL | if true && x {}
|
||||
| ^ expected `bool`, found enum `Option`
|
||||
|
|
||||
= note: expected type `bool`
|
||||
found enum `Option<i32>`
|
||||
help: use `Option::is_some` to test if the `Option` has a value
|
||||
|
|
||||
LL | if true && x.is_some() {}
|
||||
| ++++++++++
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0308`.
|
Loading…
Reference in New Issue
Block a user