From e477cf9475540bf7f5f71940b29fc065cb988982 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Sun, 8 Jan 2023 02:54:59 +0000 Subject: [PATCH 1/6] Suggest coercion of `Result` using `?` Fix #47560. --- compiler/rustc_hir_typeck/src/coercion.rs | 49 ++++++++++++++++++- .../coerce-result-return-value.fixed | 16 ++++++ .../type-check/coerce-result-return-value.rs | 16 ++++++ .../coerce-result-return-value.stderr | 33 +++++++++++++ 4 files changed, 113 insertions(+), 1 deletion(-) create mode 100644 tests/ui/type/type-check/coerce-result-return-value.fixed create mode 100644 tests/ui/type/type-check/coerce-result-return-value.rs create mode 100644 tests/ui/type/type-check/coerce-result-return-value.stderr diff --git a/compiler/rustc_hir_typeck/src/coercion.rs b/compiler/rustc_hir_typeck/src/coercion.rs index bbf7b81a2cc..752e3f79d4a 100644 --- a/compiler/rustc_hir_typeck/src/coercion.rs +++ b/compiler/rustc_hir_typeck/src/coercion.rs @@ -45,7 +45,7 @@ use rustc_hir::intravisit::{self, Visitor}; use rustc_hir::Expr; use rustc_hir_analysis::astconv::AstConv; use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; -use rustc_infer::infer::{Coercion, InferOk, InferResult}; +use rustc_infer::infer::{Coercion, InferOk, InferResult, TyCtxtInferExt}; use rustc_infer::traits::Obligation; use rustc_middle::lint::in_external_macro; use rustc_middle::ty::adjustment::{ @@ -1565,6 +1565,9 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> { && let hir::ExprKind::Loop(loop_blk, ..) = expression.kind { intravisit::walk_block(& mut visitor, loop_blk); } + if let Some(expr) = expression { + self.note_result_coercion(fcx, &mut err, expr, expected, found); + } } ObligationCauseCode::ReturnValue(id) => { err = self.report_return_mismatched_types( @@ -1581,6 +1584,9 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> { let id = fcx.tcx.hir().parent_id(id); unsized_return = self.is_return_ty_unsized(fcx, id); } + if let Some(expr) = expression { + self.note_result_coercion(fcx, &mut err, expr, expected, found); + } } _ => { err = fcx.err_ctxt().report_mismatched_types( @@ -1619,6 +1625,47 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> { } } } + + fn note_result_coercion( + &self, + fcx: &FnCtxt<'_, 'tcx>, + err: &mut Diagnostic, + expr: &hir::Expr<'tcx>, + expected: Ty<'tcx>, + found: Ty<'tcx>, + ) { + let ty::Adt(e, substs_e) = expected.kind() else { return; }; + let ty::Adt(f, substs_f) = found.kind() else { return; }; + if e.did() != f.did() { + return; + } + if Some(e.did()) != fcx.tcx.get_diagnostic_item(sym::Result) { + return; + } + let e = substs_e.type_at(1); + let f = substs_f.type_at(1); + if fcx + .tcx + .infer_ctxt() + .build() + .type_implements_trait( + fcx.tcx.get_diagnostic_item(sym::Into).unwrap(), + [fcx.tcx.erase_regions(f), fcx.tcx.erase_regions(e)], + fcx.param_env, + ) + .must_apply_modulo_regions() + { + err.multipart_suggestion( + "you can rely on the implicit conversion that `?` does to transform the error type", + vec![ + (expr.span.shrink_to_lo(), "Ok(".to_string()), + (expr.span.shrink_to_hi(), "?)".to_string()), + ], + Applicability::MaybeIncorrect, + ); + } + } + fn note_unreachable_loop_return( &self, err: &mut Diagnostic, diff --git a/tests/ui/type/type-check/coerce-result-return-value.fixed b/tests/ui/type/type-check/coerce-result-return-value.fixed new file mode 100644 index 00000000000..91066262303 --- /dev/null +++ b/tests/ui/type/type-check/coerce-result-return-value.fixed @@ -0,0 +1,16 @@ +// run-rustfix +struct A; +struct B; +impl From 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 main() { + let _ = foo1(Ok(())); + let _ = foo2(Ok(())); +} diff --git a/tests/ui/type/type-check/coerce-result-return-value.rs b/tests/ui/type/type-check/coerce-result-return-value.rs new file mode 100644 index 00000000000..9a71376f462 --- /dev/null +++ b/tests/ui/type/type-check/coerce-result-return-value.rs @@ -0,0 +1,16 @@ +// run-rustfix +struct A; +struct B; +impl From 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 main() { + let _ = foo1(Ok(())); + let _ = foo2(Ok(())); +} diff --git a/tests/ui/type/type-check/coerce-result-return-value.stderr b/tests/ui/type/type-check/coerce-result-return-value.stderr new file mode 100644 index 00000000000..7aebc9dcc7a --- /dev/null +++ b/tests/ui/type/type-check/coerce-result-return-value.stderr @@ -0,0 +1,33 @@ +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: you can rely on the implicit conversion that `?` does to transform the error type + | +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: you can rely on the implicit conversion that `?` does to transform the error type + | +LL | return Ok(x?); + | +++ ++ + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0308`. From d5a1609ec450d624fd8bf3f88647e966cf83eee8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Sun, 8 Jan 2023 07:05:23 +0000 Subject: [PATCH 2/6] review comment: use `fcx.infcx` --- compiler/rustc_hir_typeck/src/coercion.rs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/compiler/rustc_hir_typeck/src/coercion.rs b/compiler/rustc_hir_typeck/src/coercion.rs index 752e3f79d4a..893d1e88bf8 100644 --- a/compiler/rustc_hir_typeck/src/coercion.rs +++ b/compiler/rustc_hir_typeck/src/coercion.rs @@ -1645,9 +1645,7 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> { let e = substs_e.type_at(1); let f = substs_f.type_at(1); if fcx - .tcx - .infer_ctxt() - .build() + .infcx .type_implements_trait( fcx.tcx.get_diagnostic_item(sym::Into).unwrap(), [fcx.tcx.erase_regions(f), fcx.tcx.erase_regions(e)], From ddd9a9fb4666401d4f1a92edd8a7d8b33bf0824f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Sun, 8 Jan 2023 07:14:17 +0000 Subject: [PATCH 3/6] Add call in `emit_type_mismatch_suggestions` --- compiler/rustc_hir_typeck/src/coercion.rs | 46 +---------------------- compiler/rustc_hir_typeck/src/demand.rs | 42 ++++++++++++++++++++- 2 files changed, 42 insertions(+), 46 deletions(-) diff --git a/compiler/rustc_hir_typeck/src/coercion.rs b/compiler/rustc_hir_typeck/src/coercion.rs index 893d1e88bf8..d5f37abb8b4 100644 --- a/compiler/rustc_hir_typeck/src/coercion.rs +++ b/compiler/rustc_hir_typeck/src/coercion.rs @@ -45,7 +45,7 @@ use rustc_hir::intravisit::{self, Visitor}; use rustc_hir::Expr; use rustc_hir_analysis::astconv::AstConv; use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; -use rustc_infer::infer::{Coercion, InferOk, InferResult, TyCtxtInferExt}; +use rustc_infer::infer::{Coercion, InferOk, InferResult}; use rustc_infer::traits::Obligation; use rustc_middle::lint::in_external_macro; use rustc_middle::ty::adjustment::{ @@ -1565,9 +1565,6 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> { && let hir::ExprKind::Loop(loop_blk, ..) = expression.kind { intravisit::walk_block(& mut visitor, loop_blk); } - if let Some(expr) = expression { - self.note_result_coercion(fcx, &mut err, expr, expected, found); - } } ObligationCauseCode::ReturnValue(id) => { err = self.report_return_mismatched_types( @@ -1584,9 +1581,6 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> { let id = fcx.tcx.hir().parent_id(id); unsized_return = self.is_return_ty_unsized(fcx, id); } - if let Some(expr) = expression { - self.note_result_coercion(fcx, &mut err, expr, expected, found); - } } _ => { err = fcx.err_ctxt().report_mismatched_types( @@ -1626,44 +1620,6 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> { } } - fn note_result_coercion( - &self, - fcx: &FnCtxt<'_, 'tcx>, - err: &mut Diagnostic, - expr: &hir::Expr<'tcx>, - expected: Ty<'tcx>, - found: Ty<'tcx>, - ) { - let ty::Adt(e, substs_e) = expected.kind() else { return; }; - let ty::Adt(f, substs_f) = found.kind() else { return; }; - if e.did() != f.did() { - return; - } - if Some(e.did()) != fcx.tcx.get_diagnostic_item(sym::Result) { - return; - } - let e = substs_e.type_at(1); - let f = substs_f.type_at(1); - if fcx - .infcx - .type_implements_trait( - fcx.tcx.get_diagnostic_item(sym::Into).unwrap(), - [fcx.tcx.erase_regions(f), fcx.tcx.erase_regions(e)], - fcx.param_env, - ) - .must_apply_modulo_regions() - { - err.multipart_suggestion( - "you can rely on the implicit conversion that `?` does to transform the error type", - vec![ - (expr.span.shrink_to_lo(), "Ok(".to_string()), - (expr.span.shrink_to_hi(), "?)".to_string()), - ], - Applicability::MaybeIncorrect, - ); - } - } - fn note_unreachable_loop_return( &self, err: &mut Diagnostic, diff --git a/compiler/rustc_hir_typeck/src/demand.rs b/compiler/rustc_hir_typeck/src/demand.rs index 665dc8b6a2f..b10bb593ead 100644 --- a/compiler/rustc_hir_typeck/src/demand.rs +++ b/compiler/rustc_hir_typeck/src/demand.rs @@ -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); } @@ -697,6 +698,45 @@ 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 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(), + [self.tcx.erase_regions(f), self.tcx.erase_regions(e)], + self.param_env, + ) + .must_apply_modulo_regions() + { + err.multipart_suggestion( + "you can rely on the implicit conversion that `?` does to transform the error type", + 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( From fcf0ed90187ae60739c76ef3e72e8232bf14746b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Sun, 8 Jan 2023 07:43:24 +0000 Subject: [PATCH 4/6] Do not erase regions --- compiler/rustc_hir_typeck/src/demand.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/rustc_hir_typeck/src/demand.rs b/compiler/rustc_hir_typeck/src/demand.rs index b10bb593ead..d55ea52d16b 100644 --- a/compiler/rustc_hir_typeck/src/demand.rs +++ b/compiler/rustc_hir_typeck/src/demand.rs @@ -719,7 +719,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { .infcx .type_implements_trait( self.tcx.get_diagnostic_item(sym::Into).unwrap(), - [self.tcx.erase_regions(f), self.tcx.erase_regions(e)], + [f, e], self.param_env, ) .must_apply_modulo_regions() From df81147b51f95441c8db74eda92b5c5fadecb20e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Sun, 8 Jan 2023 19:12:15 +0000 Subject: [PATCH 5/6] Ensure suggestion correctness --- compiler/rustc_hir_typeck/src/demand.rs | 10 ++++ .../coerce-result-return-value-2.rs | 24 ++++++++++ .../coerce-result-return-value-2.stderr | 47 +++++++++++++++++++ .../coerce-result-return-value.fixed | 8 ++++ .../type-check/coerce-result-return-value.rs | 8 ++++ .../coerce-result-return-value.stderr | 34 +++++++++++++- 6 files changed, 130 insertions(+), 1 deletion(-) create mode 100644 tests/ui/type/type-check/coerce-result-return-value-2.rs create mode 100644 tests/ui/type/type-check/coerce-result-return-value-2.stderr diff --git a/compiler/rustc_hir_typeck/src/demand.rs b/compiler/rustc_hir_typeck/src/demand.rs index d55ea52d16b..97490194e25 100644 --- a/compiler/rustc_hir_typeck/src/demand.rs +++ b/compiler/rustc_hir_typeck/src/demand.rs @@ -713,6 +713,16 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { 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 diff --git a/tests/ui/type/type-check/coerce-result-return-value-2.rs b/tests/ui/type/type-check/coerce-result-return-value-2.rs new file mode 100644 index 00000000000..23bafa6c5c9 --- /dev/null +++ b/tests/ui/type/type-check/coerce-result-return-value-2.rs @@ -0,0 +1,24 @@ +struct A; +struct B; +impl From 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); + }; +} diff --git a/tests/ui/type/type-check/coerce-result-return-value-2.stderr b/tests/ui/type/type-check/coerce-result-return-value-2.stderr new file mode 100644 index 00000000000..64a8c779fce --- /dev/null +++ b/tests/ui/type/type-check/coerce-result-return-value-2.stderr @@ -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: you can rely on the implicit conversion that `?` does to transform the error type + | +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: you can rely on the implicit conversion that `?` does to transform the error type + | +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`. diff --git a/tests/ui/type/type-check/coerce-result-return-value.fixed b/tests/ui/type/type-check/coerce-result-return-value.fixed index 91066262303..8a05407070d 100644 --- a/tests/ui/type/type-check/coerce-result-return-value.fixed +++ b/tests/ui/type/type-check/coerce-result-return-value.fixed @@ -10,7 +10,15 @@ fn foo1(x: Result<(), A>) -> Result<(), B> { 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(())); } diff --git a/tests/ui/type/type-check/coerce-result-return-value.rs b/tests/ui/type/type-check/coerce-result-return-value.rs index 9a71376f462..442203addb7 100644 --- a/tests/ui/type/type-check/coerce-result-return-value.rs +++ b/tests/ui/type/type-check/coerce-result-return-value.rs @@ -10,7 +10,15 @@ fn foo1(x: Result<(), A>) -> Result<(), B> { 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(())); } diff --git a/tests/ui/type/type-check/coerce-result-return-value.stderr b/tests/ui/type/type-check/coerce-result-return-value.stderr index 7aebc9dcc7a..18993b3cef1 100644 --- a/tests/ui/type/type-check/coerce-result-return-value.stderr +++ b/tests/ui/type/type-check/coerce-result-return-value.stderr @@ -28,6 +28,38 @@ help: you can rely on the implicit conversion that `?` does to transform the err LL | return Ok(x?); | +++ ++ -error: aborting due to 2 previous errors +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: you can rely on the implicit conversion that `?` does to transform the error type + | +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: you can rely on the implicit conversion that `?` does to transform the error type + | +LL | Ok(x?) + | +++ ++ + +error: aborting due to 4 previous errors For more information about this error, try `rustc --explain E0308`. From 62aff3bbc75468bedf751b01a746e52886be760c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Mon, 23 Jan 2023 14:46:30 +0000 Subject: [PATCH 6/6] tweak wording --- compiler/rustc_hir_typeck/src/demand.rs | 3 ++- .../type/type-check/coerce-result-return-value-2.stderr | 4 ++-- .../ui/type/type-check/coerce-result-return-value.stderr | 8 ++++---- 3 files changed, 8 insertions(+), 7 deletions(-) diff --git a/compiler/rustc_hir_typeck/src/demand.rs b/compiler/rustc_hir_typeck/src/demand.rs index 97490194e25..3f185dfae02 100644 --- a/compiler/rustc_hir_typeck/src/demand.rs +++ b/compiler/rustc_hir_typeck/src/demand.rs @@ -735,7 +735,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { .must_apply_modulo_regions() { err.multipart_suggestion( - "you can rely on the implicit conversion that `?` does to transform the error type", + "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()), diff --git a/tests/ui/type/type-check/coerce-result-return-value-2.stderr b/tests/ui/type/type-check/coerce-result-return-value-2.stderr index 64a8c779fce..5992162341e 100644 --- a/tests/ui/type/type-check/coerce-result-return-value-2.stderr +++ b/tests/ui/type/type-check/coerce-result-return-value-2.stderr @@ -9,7 +9,7 @@ LL | true => x, | = note: expected enum `Result<_, B>` found enum `Result<_, A>` -help: you can rely on the implicit conversion that `?` does to transform the error type +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?), | +++ ++ @@ -25,7 +25,7 @@ LL | true => return x, | = note: expected enum `Result<_, B>` found enum `Result<_, A>` -help: you can rely on the implicit conversion that `?` does to transform the error type +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?), | +++ ++ diff --git a/tests/ui/type/type-check/coerce-result-return-value.stderr b/tests/ui/type/type-check/coerce-result-return-value.stderr index 18993b3cef1..55015352078 100644 --- a/tests/ui/type/type-check/coerce-result-return-value.stderr +++ b/tests/ui/type/type-check/coerce-result-return-value.stderr @@ -8,7 +8,7 @@ LL | x | = note: expected enum `Result<_, B>` found enum `Result<_, A>` -help: you can rely on the implicit conversion that `?` does to transform the error type +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?) | +++ ++ @@ -23,7 +23,7 @@ LL | return x; | = note: expected enum `Result<_, B>` found enum `Result<_, A>` -help: you can rely on the implicit conversion that `?` does to transform the error type +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?); | +++ ++ @@ -39,7 +39,7 @@ LL | x | = note: expected enum `Result<_, B>` found enum `Result<_, A>` -help: you can rely on the implicit conversion that `?` does to transform the error type +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?) | +++ ++ @@ -55,7 +55,7 @@ LL | x | = note: expected enum `Result<_, B>` found enum `Result<_, A>` -help: you can rely on the implicit conversion that `?` does to transform the error type +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?) | +++ ++