mirror of
https://github.com/rust-lang/rust.git
synced 2025-02-10 14:02:57 +00:00
Rollup merge of #106583 - estebank:suggest-result-coercion, r=compiler-errors
Suggest coercion of `Result` using `?` Fix #47560.
This commit is contained in:
commit
b36a8dcea3
@ -59,7 +59,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
|| self.suggest_copied_or_cloned(err, expr, expr_ty, expected)
|
||||
|| self.suggest_clone_for_ref(err, expr, expr_ty, expected)
|
||||
|| self.suggest_into(err, expr, expr_ty, expected)
|
||||
|| self.suggest_floating_point_literal(err, expr, expected);
|
||||
|| self.suggest_floating_point_literal(err, expr, expected)
|
||||
|| self.note_result_coercion(err, expr, expected, expr_ty);
|
||||
if !suggested {
|
||||
self.point_at_expr_source_of_inferred_type(err, expr, expr_ty, expected);
|
||||
}
|
||||
@ -696,6 +697,56 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
);
|
||||
}
|
||||
|
||||
pub(crate) fn note_result_coercion(
|
||||
&self,
|
||||
err: &mut Diagnostic,
|
||||
expr: &hir::Expr<'tcx>,
|
||||
expected: Ty<'tcx>,
|
||||
found: Ty<'tcx>,
|
||||
) -> bool {
|
||||
let ty::Adt(e, substs_e) = expected.kind() else { return false; };
|
||||
let ty::Adt(f, substs_f) = found.kind() else { return false; };
|
||||
if e.did() != f.did() {
|
||||
return false;
|
||||
}
|
||||
if Some(e.did()) != self.tcx.get_diagnostic_item(sym::Result) {
|
||||
return false;
|
||||
}
|
||||
let map = self.tcx.hir();
|
||||
if let Some(hir::Node::Expr(expr)) = map.find_parent(expr.hir_id)
|
||||
&& let hir::ExprKind::Ret(_) = expr.kind
|
||||
{
|
||||
// `return foo;`
|
||||
} else if map.get_return_block(expr.hir_id).is_some() {
|
||||
// Function's tail expression.
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
let e = substs_e.type_at(1);
|
||||
let f = substs_f.type_at(1);
|
||||
if self
|
||||
.infcx
|
||||
.type_implements_trait(
|
||||
self.tcx.get_diagnostic_item(sym::Into).unwrap(),
|
||||
[f, e],
|
||||
self.param_env,
|
||||
)
|
||||
.must_apply_modulo_regions()
|
||||
{
|
||||
err.multipart_suggestion(
|
||||
"use `?` to coerce and return an appropriate `Err`, and wrap the resulting value \
|
||||
in `Ok` so the expression remains of type `Result`",
|
||||
vec![
|
||||
(expr.span.shrink_to_lo(), "Ok(".to_string()),
|
||||
(expr.span.shrink_to_hi(), "?)".to_string()),
|
||||
],
|
||||
Applicability::MaybeIncorrect,
|
||||
);
|
||||
return true;
|
||||
}
|
||||
false
|
||||
}
|
||||
|
||||
/// If the expected type is an enum (Issue #55250) with any variants whose
|
||||
/// sole field is of the found type, suggest such variants. (Issue #42764)
|
||||
fn suggest_compatible_variants(
|
||||
|
24
tests/ui/type/type-check/coerce-result-return-value-2.rs
Normal file
24
tests/ui/type/type-check/coerce-result-return-value-2.rs
Normal file
@ -0,0 +1,24 @@
|
||||
struct A;
|
||||
struct B;
|
||||
impl From<A> for B {
|
||||
fn from(_: A) -> Self { B }
|
||||
}
|
||||
fn foo4(x: Result<(), A>) -> Result<(), B> {
|
||||
match true {
|
||||
true => x, //~ ERROR mismatched types
|
||||
false => x,
|
||||
}
|
||||
}
|
||||
fn foo5(x: Result<(), A>) -> Result<(), B> {
|
||||
match true {
|
||||
true => return x, //~ ERROR mismatched types
|
||||
false => return x,
|
||||
}
|
||||
}
|
||||
fn main() {
|
||||
let _ = foo4(Ok(()));
|
||||
let _ = foo5(Ok(()));
|
||||
let _: Result<(), B> = { //~ ERROR mismatched types
|
||||
Err(A);
|
||||
};
|
||||
}
|
47
tests/ui/type/type-check/coerce-result-return-value-2.stderr
Normal file
47
tests/ui/type/type-check/coerce-result-return-value-2.stderr
Normal file
@ -0,0 +1,47 @@
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/coerce-result-return-value-2.rs:8:17
|
||||
|
|
||||
LL | fn foo4(x: Result<(), A>) -> Result<(), B> {
|
||||
| ------------- expected `Result<(), B>` because of return type
|
||||
LL | match true {
|
||||
LL | true => x,
|
||||
| ^ expected struct `B`, found struct `A`
|
||||
|
|
||||
= note: expected enum `Result<_, B>`
|
||||
found enum `Result<_, A>`
|
||||
help: use `?` to coerce and return an appropriate `Err`, and wrap the resulting value in `Ok` so the expression remains of type `Result`
|
||||
|
|
||||
LL | true => Ok(x?),
|
||||
| +++ ++
|
||||
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/coerce-result-return-value-2.rs:14:24
|
||||
|
|
||||
LL | fn foo5(x: Result<(), A>) -> Result<(), B> {
|
||||
| ------------- expected `Result<(), B>` because of return type
|
||||
LL | match true {
|
||||
LL | true => return x,
|
||||
| ^ expected struct `B`, found struct `A`
|
||||
|
|
||||
= note: expected enum `Result<_, B>`
|
||||
found enum `Result<_, A>`
|
||||
help: use `?` to coerce and return an appropriate `Err`, and wrap the resulting value in `Ok` so the expression remains of type `Result`
|
||||
|
|
||||
LL | true => return Ok(x?),
|
||||
| +++ ++
|
||||
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/coerce-result-return-value-2.rs:21:28
|
||||
|
|
||||
LL | let _: Result<(), B> = {
|
||||
| ____________________________^
|
||||
LL | | Err(A);
|
||||
LL | | };
|
||||
| |_____^ expected enum `Result`, found `()`
|
||||
|
|
||||
= note: expected enum `Result<(), B>`
|
||||
found unit type `()`
|
||||
|
||||
error: aborting due to 3 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0308`.
|
24
tests/ui/type/type-check/coerce-result-return-value.fixed
Normal file
24
tests/ui/type/type-check/coerce-result-return-value.fixed
Normal file
@ -0,0 +1,24 @@
|
||||
// run-rustfix
|
||||
struct A;
|
||||
struct B;
|
||||
impl From<A> for B {
|
||||
fn from(_: A) -> Self { B }
|
||||
}
|
||||
fn foo1(x: Result<(), A>) -> Result<(), B> {
|
||||
Ok(x?) //~ ERROR mismatched types
|
||||
}
|
||||
fn foo2(x: Result<(), A>) -> Result<(), B> {
|
||||
return Ok(x?); //~ ERROR mismatched types
|
||||
}
|
||||
fn foo3(x: Result<(), A>) -> Result<(), B> {
|
||||
if true {
|
||||
Ok(x?) //~ ERROR mismatched types
|
||||
} else {
|
||||
Ok(x?) //~ ERROR mismatched types
|
||||
}
|
||||
}
|
||||
fn main() {
|
||||
let _ = foo1(Ok(()));
|
||||
let _ = foo2(Ok(()));
|
||||
let _ = foo3(Ok(()));
|
||||
}
|
24
tests/ui/type/type-check/coerce-result-return-value.rs
Normal file
24
tests/ui/type/type-check/coerce-result-return-value.rs
Normal file
@ -0,0 +1,24 @@
|
||||
// run-rustfix
|
||||
struct A;
|
||||
struct B;
|
||||
impl From<A> for B {
|
||||
fn from(_: A) -> Self { B }
|
||||
}
|
||||
fn foo1(x: Result<(), A>) -> Result<(), B> {
|
||||
x //~ ERROR mismatched types
|
||||
}
|
||||
fn foo2(x: Result<(), A>) -> Result<(), B> {
|
||||
return x; //~ ERROR mismatched types
|
||||
}
|
||||
fn foo3(x: Result<(), A>) -> Result<(), B> {
|
||||
if true {
|
||||
x //~ ERROR mismatched types
|
||||
} else {
|
||||
x //~ ERROR mismatched types
|
||||
}
|
||||
}
|
||||
fn main() {
|
||||
let _ = foo1(Ok(()));
|
||||
let _ = foo2(Ok(()));
|
||||
let _ = foo3(Ok(()));
|
||||
}
|
65
tests/ui/type/type-check/coerce-result-return-value.stderr
Normal file
65
tests/ui/type/type-check/coerce-result-return-value.stderr
Normal file
@ -0,0 +1,65 @@
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/coerce-result-return-value.rs:8:5
|
||||
|
|
||||
LL | fn foo1(x: Result<(), A>) -> Result<(), B> {
|
||||
| ------------- expected `Result<(), B>` because of return type
|
||||
LL | x
|
||||
| ^ expected struct `B`, found struct `A`
|
||||
|
|
||||
= note: expected enum `Result<_, B>`
|
||||
found enum `Result<_, A>`
|
||||
help: use `?` to coerce and return an appropriate `Err`, and wrap the resulting value in `Ok` so the expression remains of type `Result`
|
||||
|
|
||||
LL | Ok(x?)
|
||||
| +++ ++
|
||||
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/coerce-result-return-value.rs:11:12
|
||||
|
|
||||
LL | fn foo2(x: Result<(), A>) -> Result<(), B> {
|
||||
| ------------- expected `Result<(), B>` because of return type
|
||||
LL | return x;
|
||||
| ^ expected struct `B`, found struct `A`
|
||||
|
|
||||
= note: expected enum `Result<_, B>`
|
||||
found enum `Result<_, A>`
|
||||
help: use `?` to coerce and return an appropriate `Err`, and wrap the resulting value in `Ok` so the expression remains of type `Result`
|
||||
|
|
||||
LL | return Ok(x?);
|
||||
| +++ ++
|
||||
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/coerce-result-return-value.rs:15:9
|
||||
|
|
||||
LL | fn foo3(x: Result<(), A>) -> Result<(), B> {
|
||||
| ------------- expected `Result<(), B>` because of return type
|
||||
LL | if true {
|
||||
LL | x
|
||||
| ^ expected struct `B`, found struct `A`
|
||||
|
|
||||
= note: expected enum `Result<_, B>`
|
||||
found enum `Result<_, A>`
|
||||
help: use `?` to coerce and return an appropriate `Err`, and wrap the resulting value in `Ok` so the expression remains of type `Result`
|
||||
|
|
||||
LL | Ok(x?)
|
||||
| +++ ++
|
||||
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/coerce-result-return-value.rs:17:9
|
||||
|
|
||||
LL | fn foo3(x: Result<(), A>) -> Result<(), B> {
|
||||
| ------------- expected `Result<(), B>` because of return type
|
||||
...
|
||||
LL | x
|
||||
| ^ expected struct `B`, found struct `A`
|
||||
|
|
||||
= note: expected enum `Result<_, B>`
|
||||
found enum `Result<_, A>`
|
||||
help: use `?` to coerce and return an appropriate `Err`, and wrap the resulting value in `Ok` so the expression remains of type `Result`
|
||||
|
|
||||
LL | Ok(x?)
|
||||
| +++ ++
|
||||
|
||||
error: aborting due to 4 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0308`.
|
Loading…
Reference in New Issue
Block a user