From 6c97f136126557a982990a1d0ef879996b268cba Mon Sep 17 00:00:00 2001 From: Ethan Brierley Date: Fri, 20 Oct 2023 09:46:17 +0100 Subject: [PATCH 1/2] Invalid `?` suggestion on mismatched `Ok(T)` --- compiler/rustc_hir_typeck/src/demand.rs | 5 +++++ .../issue-116967-cannot-coerce-returned-result.rs | 6 ++++++ ...ue-116967-cannot-coerce-returned-result.stderr | 15 +++++++++++++++ 3 files changed, 26 insertions(+) create mode 100644 tests/ui/type/type-check/issue-116967-cannot-coerce-returned-result.rs create mode 100644 tests/ui/type/type-check/issue-116967-cannot-coerce-returned-result.stderr diff --git a/compiler/rustc_hir_typeck/src/demand.rs b/compiler/rustc_hir_typeck/src/demand.rs index 65ec2f232aed7..3b09fdda0ce0e 100644 --- a/compiler/rustc_hir_typeck/src/demand.rs +++ b/compiler/rustc_hir_typeck/src/demand.rs @@ -983,6 +983,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } else { return false; } + let e_ok = args_e.type_at(0); + let f_ok = args_f.type_at(0); + if !self.infcx.can_eq(self.param_env, f_ok, e_ok) { + return false; + } let e = args_e.type_at(1); let f = args_f.type_at(1); if self diff --git a/tests/ui/type/type-check/issue-116967-cannot-coerce-returned-result.rs b/tests/ui/type/type-check/issue-116967-cannot-coerce-returned-result.rs new file mode 100644 index 0000000000000..adf3049b4bab9 --- /dev/null +++ b/tests/ui/type/type-check/issue-116967-cannot-coerce-returned-result.rs @@ -0,0 +1,6 @@ +fn foo() -> Result { + let out: Result<(), ()> = Ok(()); + out //~ ERROR mismatched types +} + +fn main() {} diff --git a/tests/ui/type/type-check/issue-116967-cannot-coerce-returned-result.stderr b/tests/ui/type/type-check/issue-116967-cannot-coerce-returned-result.stderr new file mode 100644 index 0000000000000..447b22a152d7e --- /dev/null +++ b/tests/ui/type/type-check/issue-116967-cannot-coerce-returned-result.stderr @@ -0,0 +1,15 @@ +error[E0308]: mismatched types + --> $DIR/issue-116967-cannot-coerce-returned-result.rs:3:5 + | +LL | fn foo() -> Result { + | ------------------ expected `Result` because of return type +LL | let out: Result<(), ()> = Ok(()); +LL | out + | ^^^ expected `Result`, found `Result<(), ()>` + | + = note: expected enum `Result` + found enum `Result<(), _>` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0308`. From 24cdb27e2842e5abab2875ce29c365ac5503773e Mon Sep 17 00:00:00 2001 From: Ethan Brierley Date: Sun, 22 Oct 2023 12:05:28 +0100 Subject: [PATCH 2/2] let_chainify `suggest_coercing_result_via_try_operator` --- compiler/rustc_hir_typeck/src/demand.rs | 58 ++++++++++--------------- 1 file changed, 22 insertions(+), 36 deletions(-) diff --git a/compiler/rustc_hir_typeck/src/demand.rs b/compiler/rustc_hir_typeck/src/demand.rs index 3b09fdda0ce0e..b385902c2869a 100644 --- a/compiler/rustc_hir_typeck/src/demand.rs +++ b/compiler/rustc_hir_typeck/src/demand.rs @@ -961,43 +961,29 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { expected: Ty<'tcx>, found: Ty<'tcx>, ) -> bool { - let ty::Adt(e, args_e) = expected.kind() else { - return false; - }; - let ty::Adt(f, args_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_ok = args_e.type_at(0); - let f_ok = args_f.type_at(0); - if !self.infcx.can_eq(self.param_env, f_ok, e_ok) { - return false; - } - let e = args_e.type_at(1); - let f = args_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() + let returned = matches!( + map.find_parent(expr.hir_id), + Some(hir::Node::Expr(hir::Expr { kind: hir::ExprKind::Ret(_), .. })) + ) || map.get_return_block(expr.hir_id).is_some(); + if returned + && let ty::Adt(e, args_e) = expected.kind() + && let ty::Adt(f, args_f) = found.kind() + && e.did() == f.did() + && Some(e.did()) == self.tcx.get_diagnostic_item(sym::Result) + && let e_ok = args_e.type_at(0) + && let f_ok = args_f.type_at(0) + && self.infcx.can_eq(self.param_env, f_ok, e_ok) + && let e_err = args_e.type_at(1) + && let f_err = args_f.type_at(1) + && self + .infcx + .type_implements_trait( + self.tcx.get_diagnostic_item(sym::Into).unwrap(), + [f_err, e_err], + self.param_env, + ) + .must_apply_modulo_regions() { err.multipart_suggestion( "use `?` to coerce and return an appropriate `Err`, and wrap the resulting value \