Skip to content

Commit a918822

Browse files
Peel borrows before suggesting as_ref/as_deref
1 parent c92140e commit a918822

File tree

4 files changed

+28
-10
lines changed

4 files changed

+28
-10
lines changed

compiler/rustc_hir_typeck/src/errors.rs

+4-3
Original file line numberDiff line numberDiff line change
@@ -329,15 +329,16 @@ pub struct CtorIsPrivate {
329329
}
330330

331331
#[derive(Subdiagnostic)]
332-
#[suggestion(
332+
#[multipart_suggestion(
333333
hir_typeck_convert_using_method,
334-
code = "{sugg}",
335334
applicability = "machine-applicable",
336335
style = "verbose"
337336
)]
338337
pub struct SuggestConvertViaMethod<'tcx> {
339-
#[primary_span]
338+
#[suggestion_part(code = "{sugg}")]
340339
pub span: Span,
340+
#[suggestion_part(code = "")]
341+
pub borrow_removal_span: Option<Span>,
341342
pub sugg: &'static str,
342343
pub expected: Ty<'tcx>,
343344
pub found: Ty<'tcx>,

compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs

+15-1
Original file line numberDiff line numberDiff line change
@@ -413,7 +413,18 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
413413
self.deconstruct_option_or_result(found, expected)
414414
&& let ty::Ref(_, peeled, hir::Mutability::Not) = *expected_ty_inner.kind()
415415
{
416-
// Check that given `Result<_, E>`, our expected ty is `Result<_, &E>`
416+
// Suggest removing any stray borrows (unless there's macro shenanigans involved).
417+
let inner_expr = expr.peel_borrows();
418+
if !inner_expr.span.eq_ctxt(expr.span) {
419+
return false;
420+
}
421+
let borrow_removal_span = if inner_expr.hir_id == expr.hir_id {
422+
None
423+
} else {
424+
Some(expr.span.shrink_to_lo().until(inner_expr.span))
425+
};
426+
// Given `Result<_, E>`, check our expected ty is `Result<_, &E>` for
427+
// `as_ref` and `as_deref` compatibility.
417428
let error_tys_equate_as_ref = error_tys.map_or(true, |(found, expected)| {
418429
self.can_eq(self.param_env, self.tcx.mk_imm_ref(self.tcx.lifetimes.re_erased, found), expected)
419430
});
@@ -425,6 +436,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
425436
sugg: ".as_ref()",
426437
expected,
427438
found,
439+
borrow_removal_span,
428440
});
429441
return true;
430442
} else if let Some((deref_ty, _)) =
@@ -437,11 +449,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
437449
sugg: ".as_deref()",
438450
expected,
439451
found,
452+
borrow_removal_span,
440453
});
441454
return true;
442455
} else if let ty::Adt(adt, _) = found_ty_inner.peel_refs().kind()
443456
&& Some(adt.did()) == self.tcx.lang_items().string()
444457
&& peeled.is_str()
458+
// `Result::map`, conversely, does not take ref of the error type.
445459
&& error_tys.map_or(true, |(found, expected)| {
446460
self.can_eq(self.param_env, found, expected)
447461
})

tests/ui/issues/issue-100605.stderr

+3-2
Original file line numberDiff line numberDiff line change
@@ -36,8 +36,9 @@ LL | fn takes_option(_arg: Option<&String>) {}
3636
| ^^^^^^^^^^^^ ---------------------
3737
help: try using `.as_ref()` to convert `&Option<String>` to `Option<&String>`
3838
|
39-
LL | takes_option(&res.as_ref());
40-
| +++++++++
39+
LL - takes_option(&res);
40+
LL + takes_option(res.as_ref());
41+
|
4142

4243
error: aborting due to 2 previous errors
4344

tests/ui/let-else/let-else-ref-bindings.stderr

+6-4
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,9 @@ LL | let Some(ref a): Option<&[u8]> = &some else { return };
2121
found reference `&Option<Vec<u8>>`
2222
help: try using `.as_deref()` to convert `&Option<Vec<u8>>` to `Option<&[u8]>`
2323
|
24-
LL | let Some(ref a): Option<&[u8]> = &some.as_deref() else { return };
25-
| +++++++++++
24+
LL - let Some(ref a): Option<&[u8]> = &some else { return };
25+
LL + let Some(ref a): Option<&[u8]> = some.as_deref() else { return };
26+
|
2627

2728
error[E0308]: mismatched types
2829
--> $DIR/let-else-ref-bindings.rs:24:34
@@ -51,8 +52,9 @@ LL | let Some(a): Option<&[u8]> = &some else { return };
5152
found reference `&Option<Vec<u8>>`
5253
help: try using `.as_deref()` to convert `&Option<Vec<u8>>` to `Option<&[u8]>`
5354
|
54-
LL | let Some(a): Option<&[u8]> = &some.as_deref() else { return };
55-
| +++++++++++
55+
LL - let Some(a): Option<&[u8]> = &some else { return };
56+
LL + let Some(a): Option<&[u8]> = some.as_deref() else { return };
57+
|
5658

5759
error[E0308]: mismatched types
5860
--> $DIR/let-else-ref-bindings.rs:44:46

0 commit comments

Comments
 (0)