Auto merge of #127629 - tesuji:suggest-option-ref-unwrap_or, r=estebank
Suggest using `map_or` when `Option<&T>::unwrap_or where T: Deref` fails Fix #127545 Split from https://github.com/rust-lang/rust/pull/127596#pullrequestreview-2171898588
This commit is contained in:
commit
cae4a84146
@ -948,6 +948,17 @@ fn has_error_or_infer<'tcx>(tys: impl IntoIterator<Item = Ty<'tcx>>) -> bool {
|
|||||||
&mut err,
|
&mut err,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
self.suggest_deref_unwrap_or(
|
||||||
|
&mut err,
|
||||||
|
error_span,
|
||||||
|
callee_ty,
|
||||||
|
call_ident,
|
||||||
|
expected_ty,
|
||||||
|
provided_ty,
|
||||||
|
provided_args[*provided_idx],
|
||||||
|
is_method,
|
||||||
|
);
|
||||||
|
|
||||||
// Call out where the function is defined
|
// Call out where the function is defined
|
||||||
self.label_fn_like(
|
self.label_fn_like(
|
||||||
&mut err,
|
&mut err,
|
||||||
|
@ -1429,6 +1429,74 @@ pub(crate) fn suggest_option_to_bool(
|
|||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Suggest to change `Option<&Vec<T>>::unwrap_or(&[])` to `Option::map_or(&[], |v| v)`.
|
||||||
|
#[instrument(level = "trace", skip(self, err, provided_expr))]
|
||||||
|
pub(crate) fn suggest_deref_unwrap_or(
|
||||||
|
&self,
|
||||||
|
err: &mut Diag<'_>,
|
||||||
|
error_span: Span,
|
||||||
|
callee_ty: Option<Ty<'tcx>>,
|
||||||
|
call_ident: Option<Ident>,
|
||||||
|
expected_ty: Ty<'tcx>,
|
||||||
|
provided_ty: Ty<'tcx>,
|
||||||
|
provided_expr: &Expr<'tcx>,
|
||||||
|
is_method: bool,
|
||||||
|
) {
|
||||||
|
if !is_method {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
let Some(callee_ty) = callee_ty else {
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
let ty::Adt(callee_adt, _) = callee_ty.peel_refs().kind() else {
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
let adt_name = if self.tcx.is_diagnostic_item(sym::Option, callee_adt.did()) {
|
||||||
|
"Option"
|
||||||
|
} else if self.tcx.is_diagnostic_item(sym::Result, callee_adt.did()) {
|
||||||
|
"Result"
|
||||||
|
} else {
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
|
||||||
|
let Some(call_ident) = call_ident else {
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
if call_ident.name != sym::unwrap_or {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let ty::Ref(_, peeled, _mutability) = provided_ty.kind() else {
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
|
||||||
|
// NOTE: Can we reuse `suggest_deref_or_ref`?
|
||||||
|
|
||||||
|
// Create an dummy type `&[_]` so that both &[] and `&Vec<T>` can coerce to it.
|
||||||
|
let dummy_ty = if let ty::Array(elem_ty, size) = peeled.kind()
|
||||||
|
&& let ty::Infer(_) = elem_ty.kind()
|
||||||
|
&& size.try_eval_target_usize(self.tcx, self.param_env) == Some(0)
|
||||||
|
{
|
||||||
|
let slice = Ty::new_slice(self.tcx, *elem_ty);
|
||||||
|
Ty::new_imm_ref(self.tcx, self.tcx.lifetimes.re_static, slice)
|
||||||
|
} else {
|
||||||
|
provided_ty
|
||||||
|
};
|
||||||
|
|
||||||
|
if !self.can_coerce(expected_ty, dummy_ty) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
let msg = format!("use `{adt_name}::map_or` to deref inner value of `{adt_name}`");
|
||||||
|
err.multipart_suggestion_verbose(
|
||||||
|
msg,
|
||||||
|
vec![
|
||||||
|
(call_ident.span, "map_or".to_owned()),
|
||||||
|
(provided_expr.span.shrink_to_hi(), ", |v| v".to_owned()),
|
||||||
|
],
|
||||||
|
Applicability::MachineApplicable,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
/// Suggest wrapping the block in square brackets instead of curly braces
|
/// Suggest wrapping the block in square brackets instead of curly braces
|
||||||
/// in case the block was mistaken array syntax, e.g. `{ 1 }` -> `[ 1 ]`.
|
/// in case the block was mistaken array syntax, e.g. `{ 1 }` -> `[ 1 ]`.
|
||||||
pub(crate) fn suggest_block_to_brackets(
|
pub(crate) fn suggest_block_to_brackets(
|
||||||
|
@ -4,3 +4,15 @@
|
|||||||
pub fn foo(arg: Option<&Vec<i32>>) -> Option<&[i32]> {
|
pub fn foo(arg: Option<&Vec<i32>>) -> Option<&[i32]> {
|
||||||
arg //~ ERROR 5:5: 5:8: mismatched types [E0308]
|
arg //~ ERROR 5:5: 5:8: mismatched types [E0308]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn bar(arg: Option<&Vec<i32>>) -> &[i32] {
|
||||||
|
arg.unwrap_or(&[]) //~ ERROR 9:19: 9:22: mismatched types [E0308]
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn barzz<'a>(arg: Option<&'a Vec<i32>>, v: &'a [i32]) -> &'a [i32] {
|
||||||
|
arg.unwrap_or(v) //~ ERROR 13:19: 13:20: mismatched types [E0308]
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn convert_result(arg: Result<&Vec<i32>, ()>) -> &[i32] {
|
||||||
|
arg.unwrap_or(&[]) //~ ERROR 17:19: 17:22: mismatched types [E0308]
|
||||||
|
}
|
||||||
|
@ -13,6 +13,78 @@ help: try using `.map(|v| &**v)` to convert `Option<&Vec<i32>>` to `Option<&[i32
|
|||||||
LL | arg.map(|v| &**v)
|
LL | arg.map(|v| &**v)
|
||||||
| ++++++++++++++
|
| ++++++++++++++
|
||||||
|
|
||||||
error: aborting due to 1 previous error
|
error[E0308]: mismatched types
|
||||||
|
--> $DIR/transforming-option-ref-issue-127545.rs:9:19
|
||||||
|
|
|
||||||
|
LL | arg.unwrap_or(&[])
|
||||||
|
| --------- ^^^ expected `&Vec<i32>`, found `&[_; 0]`
|
||||||
|
| |
|
||||||
|
| arguments to this method are incorrect
|
||||||
|
|
|
||||||
|
= note: expected reference `&Vec<i32>`
|
||||||
|
found reference `&[_; 0]`
|
||||||
|
help: the return type of this call is `&[_; 0]` due to the type of the argument passed
|
||||||
|
--> $DIR/transforming-option-ref-issue-127545.rs:9:5
|
||||||
|
|
|
||||||
|
LL | arg.unwrap_or(&[])
|
||||||
|
| ^^^^^^^^^^^^^^---^
|
||||||
|
| |
|
||||||
|
| this argument influences the return type of `unwrap_or`
|
||||||
|
note: method defined here
|
||||||
|
--> $SRC_DIR/core/src/option.rs:LL:COL
|
||||||
|
help: use `Option::map_or` to deref inner value of `Option`
|
||||||
|
|
|
||||||
|
LL | arg.map_or(&[], |v| v)
|
||||||
|
| ~~~~~~ +++++++
|
||||||
|
|
||||||
|
error[E0308]: mismatched types
|
||||||
|
--> $DIR/transforming-option-ref-issue-127545.rs:13:19
|
||||||
|
|
|
||||||
|
LL | arg.unwrap_or(v)
|
||||||
|
| --------- ^ expected `&Vec<i32>`, found `&[i32]`
|
||||||
|
| |
|
||||||
|
| arguments to this method are incorrect
|
||||||
|
|
|
||||||
|
= note: expected reference `&Vec<i32>`
|
||||||
|
found reference `&'a [i32]`
|
||||||
|
help: the return type of this call is `&'a [i32]` due to the type of the argument passed
|
||||||
|
--> $DIR/transforming-option-ref-issue-127545.rs:13:5
|
||||||
|
|
|
||||||
|
LL | arg.unwrap_or(v)
|
||||||
|
| ^^^^^^^^^^^^^^-^
|
||||||
|
| |
|
||||||
|
| this argument influences the return type of `unwrap_or`
|
||||||
|
note: method defined here
|
||||||
|
--> $SRC_DIR/core/src/option.rs:LL:COL
|
||||||
|
help: use `Option::map_or` to deref inner value of `Option`
|
||||||
|
|
|
||||||
|
LL | arg.map_or(v, |v| v)
|
||||||
|
| ~~~~~~ +++++++
|
||||||
|
|
||||||
|
error[E0308]: mismatched types
|
||||||
|
--> $DIR/transforming-option-ref-issue-127545.rs:17:19
|
||||||
|
|
|
||||||
|
LL | arg.unwrap_or(&[])
|
||||||
|
| --------- ^^^ expected `&Vec<i32>`, found `&[_; 0]`
|
||||||
|
| |
|
||||||
|
| arguments to this method are incorrect
|
||||||
|
|
|
||||||
|
= note: expected reference `&Vec<i32>`
|
||||||
|
found reference `&[_; 0]`
|
||||||
|
help: the return type of this call is `&[_; 0]` due to the type of the argument passed
|
||||||
|
--> $DIR/transforming-option-ref-issue-127545.rs:17:5
|
||||||
|
|
|
||||||
|
LL | arg.unwrap_or(&[])
|
||||||
|
| ^^^^^^^^^^^^^^---^
|
||||||
|
| |
|
||||||
|
| this argument influences the return type of `unwrap_or`
|
||||||
|
note: method defined here
|
||||||
|
--> $SRC_DIR/core/src/result.rs:LL:COL
|
||||||
|
help: use `Result::map_or` to deref inner value of `Result`
|
||||||
|
|
|
||||||
|
LL | arg.map_or(&[], |v| v)
|
||||||
|
| ~~~~~~ +++++++
|
||||||
|
|
||||||
|
error: aborting due to 4 previous errors
|
||||||
|
|
||||||
For more information about this error, try `rustc --explain E0308`.
|
For more information about this error, try `rustc --explain E0308`.
|
||||||
|
Loading…
Reference in New Issue
Block a user