Skip to content

Commit be13cc5

Browse files
committed
Add suggestion to use Option::map_or over erroneous Option::unwrap_or
1 parent abeb720 commit be13cc5

File tree

3 files changed

+84
-0
lines changed

3 files changed

+84
-0
lines changed

compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs

+11
Original file line numberDiff line numberDiff line change
@@ -948,6 +948,17 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
948948
&mut err,
949949
);
950950

951+
self.suggest_deref_unwrap_or(
952+
&mut err,
953+
error_span,
954+
callee_ty,
955+
call_ident,
956+
expected_ty,
957+
provided_ty,
958+
provided_args[*provided_idx],
959+
is_method,
960+
);
961+
951962
// Call out where the function is defined
952963
self.label_fn_like(
953964
&mut err,

compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs

+65
Original file line numberDiff line numberDiff line change
@@ -1429,6 +1429,71 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
14291429
true
14301430
}
14311431

1432+
// Suggest to change `Option<&Vec<T>>::unwrap_or(&[])` to `Option::map_or(&[], |v| v)`.
1433+
#[instrument(level = "trace", skip(self, err, provided_expr))]
1434+
pub(crate) fn suggest_deref_unwrap_or(
1435+
&self,
1436+
err: &mut Diag<'_>,
1437+
error_span: Span,
1438+
callee_ty: Option<Ty<'tcx>>,
1439+
call_ident: Option<Ident>,
1440+
expected_ty: Ty<'tcx>,
1441+
provided_ty: Ty<'tcx>,
1442+
provided_expr: &Expr<'tcx>,
1443+
is_method: bool,
1444+
) {
1445+
if !is_method {
1446+
return;
1447+
}
1448+
let Some(callee_ty) = callee_ty else {
1449+
return;
1450+
};
1451+
let ty::Adt(callee_adt, _) = callee_ty.peel_refs().kind() else {
1452+
return;
1453+
};
1454+
if !self.tcx.is_diagnostic_item(sym::Option, callee_adt.did()) {
1455+
return;
1456+
}
1457+
1458+
if call_ident.map_or(true, |ident| ident.name != sym::unwrap_or) {
1459+
return;
1460+
}
1461+
1462+
let ty::Ref(_, peeled, _mutability) = provided_ty.kind() else {
1463+
return;
1464+
};
1465+
1466+
// NOTE: Can we reuse `suggest_deref_or_ref`?
1467+
1468+
// Create an dummy type `&[_]` so that both &[] and `&Vec<T>` can coerce to it.
1469+
let dummy_ty = if let ty::Array(elem_ty, size) = peeled.kind()
1470+
&& let ty::Infer(_) = elem_ty.kind()
1471+
&& size.try_eval_target_usize(self.tcx, self.param_env) == Some(0)
1472+
{
1473+
let slice = Ty::new_slice(self.tcx, *elem_ty);
1474+
Ty::new_imm_ref(self.tcx, self.tcx.lifetimes.re_static, slice)
1475+
} else {
1476+
provided_ty
1477+
};
1478+
1479+
if !self.can_coerce(expected_ty, dummy_ty) {
1480+
return;
1481+
}
1482+
let (provided_snip, applicability) =
1483+
match self.tcx.sess.source_map().span_to_snippet(provided_expr.span) {
1484+
Ok(snip) => (snip, Applicability::MachineApplicable),
1485+
Err(_) => ("/* _ */".to_owned(), Applicability::MaybeIncorrect),
1486+
};
1487+
let sugg = &format!("map_or({provided_snip}, |v| v)");
1488+
err.span_suggestion_verbose(
1489+
error_span,
1490+
"use `Option::map_or` to deref inner value of `Option`",
1491+
sugg,
1492+
applicability,
1493+
);
1494+
return;
1495+
}
1496+
14321497
/// Suggest wrapping the block in square brackets instead of curly braces
14331498
/// in case the block was mistaken array syntax, e.g. `{ 1 }` -> `[ 1 ]`.
14341499
pub(crate) fn suggest_block_to_brackets(

tests/ui/mismatched_types/transforming-option-ref-issue-127545.stderr

+8
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,10 @@ LL | arg.unwrap_or(&[])
3232
| this argument influences the return type of `unwrap_or`
3333
note: method defined here
3434
--> $SRC_DIR/core/src/option.rs:LL:COL
35+
help: use `Option::map_or` to deref inner value of `Option`
36+
|
37+
LL | arg.map_or(&[], |v| v)
38+
| ~~~~~~~~~~~~~~~~~~
3539

3640
error[E0308]: mismatched types
3741
--> $DIR/transforming-option-ref-issue-127545.rs:13:19
@@ -52,6 +56,10 @@ LL | arg.unwrap_or(v)
5256
| this argument influences the return type of `unwrap_or`
5357
note: method defined here
5458
--> $SRC_DIR/core/src/option.rs:LL:COL
59+
help: use `Option::map_or` to deref inner value of `Option`
60+
|
61+
LL | arg.map_or(v, |v| v)
62+
| ~~~~~~~~~~~~~~~~
5563

5664
error: aborting due to 3 previous errors
5765

0 commit comments

Comments
 (0)