Peel borrows before suggesting as_ref/as_deref
This commit is contained in:
parent
c92140e838
commit
a9188226a8
4 changed files with 28 additions and 10 deletions
|
@ -329,15 +329,16 @@ pub struct CtorIsPrivate {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Subdiagnostic)]
|
#[derive(Subdiagnostic)]
|
||||||
#[suggestion(
|
#[multipart_suggestion(
|
||||||
hir_typeck_convert_using_method,
|
hir_typeck_convert_using_method,
|
||||||
code = "{sugg}",
|
|
||||||
applicability = "machine-applicable",
|
applicability = "machine-applicable",
|
||||||
style = "verbose"
|
style = "verbose"
|
||||||
)]
|
)]
|
||||||
pub struct SuggestConvertViaMethod<'tcx> {
|
pub struct SuggestConvertViaMethod<'tcx> {
|
||||||
#[primary_span]
|
#[suggestion_part(code = "{sugg}")]
|
||||||
pub span: Span,
|
pub span: Span,
|
||||||
|
#[suggestion_part(code = "")]
|
||||||
|
pub borrow_removal_span: Option<Span>,
|
||||||
pub sugg: &'static str,
|
pub sugg: &'static str,
|
||||||
pub expected: Ty<'tcx>,
|
pub expected: Ty<'tcx>,
|
||||||
pub found: Ty<'tcx>,
|
pub found: Ty<'tcx>,
|
||||||
|
|
|
@ -413,7 +413,18 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
self.deconstruct_option_or_result(found, expected)
|
self.deconstruct_option_or_result(found, expected)
|
||||||
&& let ty::Ref(_, peeled, hir::Mutability::Not) = *expected_ty_inner.kind()
|
&& let ty::Ref(_, peeled, hir::Mutability::Not) = *expected_ty_inner.kind()
|
||||||
{
|
{
|
||||||
// Check that given `Result<_, E>`, our expected ty is `Result<_, &E>`
|
// Suggest removing any stray borrows (unless there's macro shenanigans involved).
|
||||||
|
let inner_expr = expr.peel_borrows();
|
||||||
|
if !inner_expr.span.eq_ctxt(expr.span) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
let borrow_removal_span = if inner_expr.hir_id == expr.hir_id {
|
||||||
|
None
|
||||||
|
} else {
|
||||||
|
Some(expr.span.shrink_to_lo().until(inner_expr.span))
|
||||||
|
};
|
||||||
|
// Given `Result<_, E>`, check our expected ty is `Result<_, &E>` for
|
||||||
|
// `as_ref` and `as_deref` compatibility.
|
||||||
let error_tys_equate_as_ref = error_tys.map_or(true, |(found, expected)| {
|
let error_tys_equate_as_ref = error_tys.map_or(true, |(found, expected)| {
|
||||||
self.can_eq(self.param_env, self.tcx.mk_imm_ref(self.tcx.lifetimes.re_erased, found), expected)
|
self.can_eq(self.param_env, self.tcx.mk_imm_ref(self.tcx.lifetimes.re_erased, found), expected)
|
||||||
});
|
});
|
||||||
|
@ -425,6 +436,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
sugg: ".as_ref()",
|
sugg: ".as_ref()",
|
||||||
expected,
|
expected,
|
||||||
found,
|
found,
|
||||||
|
borrow_removal_span,
|
||||||
});
|
});
|
||||||
return true;
|
return true;
|
||||||
} else if let Some((deref_ty, _)) =
|
} else if let Some((deref_ty, _)) =
|
||||||
|
@ -437,11 +449,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
sugg: ".as_deref()",
|
sugg: ".as_deref()",
|
||||||
expected,
|
expected,
|
||||||
found,
|
found,
|
||||||
|
borrow_removal_span,
|
||||||
});
|
});
|
||||||
return true;
|
return true;
|
||||||
} else if let ty::Adt(adt, _) = found_ty_inner.peel_refs().kind()
|
} else if let ty::Adt(adt, _) = found_ty_inner.peel_refs().kind()
|
||||||
&& Some(adt.did()) == self.tcx.lang_items().string()
|
&& Some(adt.did()) == self.tcx.lang_items().string()
|
||||||
&& peeled.is_str()
|
&& peeled.is_str()
|
||||||
|
// `Result::map`, conversely, does not take ref of the error type.
|
||||||
&& error_tys.map_or(true, |(found, expected)| {
|
&& error_tys.map_or(true, |(found, expected)| {
|
||||||
self.can_eq(self.param_env, found, expected)
|
self.can_eq(self.param_env, found, expected)
|
||||||
})
|
})
|
||||||
|
|
|
@ -36,8 +36,9 @@ LL | fn takes_option(_arg: Option<&String>) {}
|
||||||
| ^^^^^^^^^^^^ ---------------------
|
| ^^^^^^^^^^^^ ---------------------
|
||||||
help: try using `.as_ref()` to convert `&Option<String>` to `Option<&String>`
|
help: try using `.as_ref()` to convert `&Option<String>` to `Option<&String>`
|
||||||
|
|
|
|
||||||
LL | takes_option(&res.as_ref());
|
LL - takes_option(&res);
|
||||||
| +++++++++
|
LL + takes_option(res.as_ref());
|
||||||
|
|
|
||||||
|
|
||||||
error: aborting due to 2 previous errors
|
error: aborting due to 2 previous errors
|
||||||
|
|
||||||
|
|
|
@ -21,8 +21,9 @@ LL | let Some(ref a): Option<&[u8]> = &some else { return };
|
||||||
found reference `&Option<Vec<u8>>`
|
found reference `&Option<Vec<u8>>`
|
||||||
help: try using `.as_deref()` to convert `&Option<Vec<u8>>` to `Option<&[u8]>`
|
help: try using `.as_deref()` to convert `&Option<Vec<u8>>` to `Option<&[u8]>`
|
||||||
|
|
|
|
||||||
LL | let Some(ref a): Option<&[u8]> = &some.as_deref() else { return };
|
LL - let Some(ref a): Option<&[u8]> = &some else { return };
|
||||||
| +++++++++++
|
LL + let Some(ref a): Option<&[u8]> = some.as_deref() else { return };
|
||||||
|
|
|
||||||
|
|
||||||
error[E0308]: mismatched types
|
error[E0308]: mismatched types
|
||||||
--> $DIR/let-else-ref-bindings.rs:24:34
|
--> $DIR/let-else-ref-bindings.rs:24:34
|
||||||
|
@ -51,8 +52,9 @@ LL | let Some(a): Option<&[u8]> = &some else { return };
|
||||||
found reference `&Option<Vec<u8>>`
|
found reference `&Option<Vec<u8>>`
|
||||||
help: try using `.as_deref()` to convert `&Option<Vec<u8>>` to `Option<&[u8]>`
|
help: try using `.as_deref()` to convert `&Option<Vec<u8>>` to `Option<&[u8]>`
|
||||||
|
|
|
|
||||||
LL | let Some(a): Option<&[u8]> = &some.as_deref() else { return };
|
LL - let Some(a): Option<&[u8]> = &some else { return };
|
||||||
| +++++++++++
|
LL + let Some(a): Option<&[u8]> = some.as_deref() else { return };
|
||||||
|
|
|
||||||
|
|
||||||
error[E0308]: mismatched types
|
error[E0308]: mismatched types
|
||||||
--> $DIR/let-else-ref-bindings.rs:44:46
|
--> $DIR/let-else-ref-bindings.rs:44:46
|
||||||
|
|
Loading…
Add table
Reference in a new issue