mirror of
https://github.com/rust-lang/rust.git
synced 2025-02-02 18:12:51 +00:00
fix #102320, suggest unwrap_or_else when a closure is passed to unwrap_or instead of suggesting calling it
This commit is contained in:
parent
756e7be5eb
commit
01882733c9
@ -65,7 +65,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// When encountering an fn-like type, try accessing the output of the type
|
/// When encountering an fn-like type, try accessing the output of the type
|
||||||
/// // and suggesting calling it if it satisfies a predicate (i.e. if the
|
/// and suggesting calling it if it satisfies a predicate (i.e. if the
|
||||||
/// output has a method or a field):
|
/// output has a method or a field):
|
||||||
/// ```compile_fail,E0308
|
/// ```compile_fail,E0308
|
||||||
/// fn foo(x: usize) -> usize { x }
|
/// fn foo(x: usize) -> usize { x }
|
||||||
@ -139,7 +139,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||||||
sugg,
|
sugg,
|
||||||
applicability,
|
applicability,
|
||||||
);
|
);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
false
|
false
|
||||||
@ -338,6 +337,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||||||
} else {
|
} else {
|
||||||
err.span_suggestion(sp, &msg, suggestion, applicability);
|
err.span_suggestion(sp, &msg, suggestion, applicability);
|
||||||
}
|
}
|
||||||
|
} else if self.suggest_else_fn_with_closure(err, expr, found, expected)
|
||||||
|
{
|
||||||
} else if self.suggest_fn_call(err, expr, found, |output| self.can_coerce(output, expected))
|
} else if self.suggest_fn_call(err, expr, found, |output| self.can_coerce(output, expected))
|
||||||
&& let ty::FnDef(def_id, ..) = &found.kind()
|
&& let ty::FnDef(def_id, ..) = &found.kind()
|
||||||
&& let Some(sp) = self.tcx.hir().span_if_local(*def_id)
|
&& let Some(sp) = self.tcx.hir().span_if_local(*def_id)
|
||||||
|
@ -2324,6 +2324,60 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// issue #102320, for `unwrap_or` with closure as argument, suggest `unwrap_or_else`
|
||||||
|
/// FIXME: currently not working for suggesting `map_or_else`, see #102408
|
||||||
|
pub(crate) fn suggest_else_fn_with_closure(
|
||||||
|
&self,
|
||||||
|
err: &mut Diagnostic,
|
||||||
|
expr: &hir::Expr<'_>,
|
||||||
|
found: Ty<'tcx>,
|
||||||
|
expected: Ty<'tcx>,
|
||||||
|
) -> bool {
|
||||||
|
let Some((_def_id_or_name, output, _inputs)) = self.extract_callable_info(expr, found)
|
||||||
|
else { return false; };
|
||||||
|
|
||||||
|
if !self.can_coerce(output, expected) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
let parent = self.tcx.hir().get_parent_node(expr.hir_id);
|
||||||
|
if let Some(Node::Expr(call_expr)) = self.tcx.hir().find(parent) &&
|
||||||
|
let hir::ExprKind::MethodCall(
|
||||||
|
hir::PathSegment { ident: method_name, .. },
|
||||||
|
self_expr,
|
||||||
|
args,
|
||||||
|
..,
|
||||||
|
) = call_expr.kind &&
|
||||||
|
let Some(self_ty) = self.typeck_results.borrow().expr_ty_opt(self_expr) {
|
||||||
|
let new_name = Ident {
|
||||||
|
name: Symbol::intern(&format!("{}_else", method_name.as_str())),
|
||||||
|
span: method_name.span,
|
||||||
|
};
|
||||||
|
let probe = self.lookup_probe(
|
||||||
|
expr.span,
|
||||||
|
new_name,
|
||||||
|
self_ty,
|
||||||
|
self_expr,
|
||||||
|
ProbeScope::TraitsInScope,
|
||||||
|
);
|
||||||
|
|
||||||
|
// check the method arguments number
|
||||||
|
if let Ok(pick) = probe &&
|
||||||
|
let fn_sig = self.tcx.fn_sig(pick.item.def_id) &&
|
||||||
|
let fn_args = fn_sig.skip_binder().inputs() &&
|
||||||
|
fn_args.len() == args.len() + 1 {
|
||||||
|
err.span_suggestion_verbose(
|
||||||
|
method_name.span.shrink_to_hi(),
|
||||||
|
&format!("try calling `{}` instead", new_name.name.as_str()),
|
||||||
|
"_else",
|
||||||
|
Applicability::MaybeIncorrect,
|
||||||
|
);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
false
|
||||||
|
}
|
||||||
|
|
||||||
/// Checks whether there is a local type somewhere in the chain of
|
/// Checks whether there is a local type somewhere in the chain of
|
||||||
/// autoderefs of `rcvr_ty`.
|
/// autoderefs of `rcvr_ty`.
|
||||||
fn type_derefs_to_local(
|
fn type_derefs_to_local(
|
||||||
|
8
src/test/ui/suggestions/sugg-else-for-closure.fixed
Normal file
8
src/test/ui/suggestions/sugg-else-for-closure.fixed
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
// run-rustfix
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let x = "com.example.app";
|
||||||
|
let y: Option<&str> = None;
|
||||||
|
let _s = y.unwrap_or_else(|| x.split('.').nth(1).unwrap());
|
||||||
|
//~^ ERROR: mismatched types [E0308]
|
||||||
|
}
|
8
src/test/ui/suggestions/sugg-else-for-closure.rs
Normal file
8
src/test/ui/suggestions/sugg-else-for-closure.rs
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
// run-rustfix
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let x = "com.example.app";
|
||||||
|
let y: Option<&str> = None;
|
||||||
|
let _s = y.unwrap_or(|| x.split('.').nth(1).unwrap());
|
||||||
|
//~^ ERROR: mismatched types [E0308]
|
||||||
|
}
|
23
src/test/ui/suggestions/sugg-else-for-closure.stderr
Normal file
23
src/test/ui/suggestions/sugg-else-for-closure.stderr
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
error[E0308]: mismatched types
|
||||||
|
--> $DIR/sugg-else-for-closure.rs:6:26
|
||||||
|
|
|
||||||
|
LL | let _s = y.unwrap_or(|| x.split('.').nth(1).unwrap());
|
||||||
|
| --------- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `&str`, found closure
|
||||||
|
| |
|
||||||
|
| arguments to this function are incorrect
|
||||||
|
|
|
||||||
|
= note: expected reference `&str`
|
||||||
|
found closure `[closure@$DIR/sugg-else-for-closure.rs:6:26: 6:28]`
|
||||||
|
note: associated function defined here
|
||||||
|
--> $SRC_DIR/core/src/option.rs:LL:COL
|
||||||
|
|
|
||||||
|
LL | pub const fn unwrap_or(self, default: T) -> T
|
||||||
|
| ^^^^^^^^^
|
||||||
|
help: try calling `unwrap_or_else` instead
|
||||||
|
|
|
||||||
|
LL | let _s = y.unwrap_or_else(|| x.split('.').nth(1).unwrap());
|
||||||
|
| +++++
|
||||||
|
|
||||||
|
error: aborting due to previous error
|
||||||
|
|
||||||
|
For more information about this error, try `rustc --explain E0308`.
|
Loading…
Reference in New Issue
Block a user