1
Fork 0

Rollup merge of #106896 - Ezrashaw:str-cast-bool-emptyness, r=compiler-errors

suggest `is_empty` for collections when casting to `bool`

Fixes #106883

Matches on slices, `String` and `str`. It would be nice to do this with something like `Deref<Target=str>` as well, but AFAIK it's not possible in this part of the compiler.
This commit is contained in:
Matthias Krüger 2023-01-15 21:17:34 +01:00 committed by GitHub
commit 5610231454
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 142 additions and 4 deletions

View file

@ -31,7 +31,9 @@
use super::FnCtxt;
use crate::type_error_struct;
use rustc_errors::{struct_span_err, Applicability, DelayDm, DiagnosticBuilder, ErrorGuaranteed};
use rustc_errors::{
struct_span_err, Applicability, DelayDm, Diagnostic, DiagnosticBuilder, ErrorGuaranteed,
};
use rustc_hir as hir;
use rustc_macros::{TypeFoldable, TypeVisitable};
use rustc_middle::mir::Mutability;
@ -270,6 +272,9 @@ impl<'a, 'tcx> CastCheck<'tcx> {
}
));
}
self.try_suggest_collection_to_bool(fcx, &mut err);
err.emit();
}
CastError::NeedViaInt => {
@ -517,6 +522,9 @@ impl<'a, 'tcx> CastCheck<'tcx> {
} else {
err.span_label(self.span, "invalid cast");
}
self.try_suggest_collection_to_bool(fcx, &mut err);
err.emit();
}
CastError::SizedUnsizedCast => {
@ -1080,4 +1088,40 @@ impl<'a, 'tcx> CastCheck<'tcx> {
},
);
}
/// Attempt to suggest using `.is_empty` when trying to cast from a
/// collection type to a boolean.
fn try_suggest_collection_to_bool(&self, fcx: &FnCtxt<'a, 'tcx>, err: &mut Diagnostic) {
if self.cast_ty.is_bool() {
let derefed = fcx
.autoderef(self.expr_span, self.expr_ty)
.silence_errors()
.find(|t| matches!(t.0.kind(), ty::Str | ty::Slice(..)));
if let Some((deref_ty, _)) = derefed {
// Give a note about what the expr derefs to.
if deref_ty != self.expr_ty.peel_refs() {
err.span_note(
self.expr_span,
format!(
"this expression `Deref`s to `{}` which implements `is_empty`",
fcx.ty_to_string(deref_ty)
),
);
}
// Create a multipart suggestion: add `!` and `.is_empty()` in
// place of the cast.
let suggestion = vec![
(self.expr_span.shrink_to_lo(), "!".to_string()),
(self.span.with_lo(self.expr_span.hi()), ".is_empty()".to_string()),
];
err.multipart_suggestion_verbose(format!(
"consider using the `is_empty` method on `{}` to determine if it contains anything",
fcx.ty_to_string(self.expr_ty),
), suggestion, Applicability::MaybeIncorrect);
}
}
}
}