diff --git a/src/librustc/infer/error_reporting/mod.rs b/src/librustc/infer/error_reporting/mod.rs index 19663161fe3fa..9c899fab59ef1 100644 --- a/src/librustc/infer/error_reporting/mod.rs +++ b/src/librustc/infer/error_reporting/mod.rs @@ -604,13 +604,39 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { source, ref prior_arms, last_ty, + discrim_hir_id, .. } => match source { hir::MatchSource::IfLetDesugar { .. } => { let msg = "`if let` arms have incompatible types"; err.span_label(cause.span, msg); } - hir::MatchSource::TryDesugar => {} + hir::MatchSource::TryDesugar => { + if let Some(ty::error::ExpectedFound { expected, .. }) = exp_found { + let discrim_expr = self.tcx.hir().expect_expr_by_hir_id(discrim_hir_id); + let discrim_ty = if let hir::ExprKind::Call(_, args) = &discrim_expr.node { + let arg_expr = args.first().expect("try desugaring call w/out arg"); + self.in_progress_tables.and_then(|tables| { + tables.borrow().expr_ty_opt(arg_expr) + }) + } else { + bug!("try desugaring w/out call expr as discriminant"); + }; + + match discrim_ty { + Some(ty) if expected == ty => { + let source_map = self.tcx.sess.source_map(); + err.span_suggestion( + source_map.end_point(cause.span), + "try removing this `?`", + "".to_string(), + Applicability::MachineApplicable, + ); + }, + _ => {}, + } + } + } _ => { let msg = "`match` arms have incompatible types"; err.span_label(cause.span, msg); diff --git a/src/librustc/traits/mod.rs b/src/librustc/traits/mod.rs index 78c80b48ee80d..ddca18ce76572 100644 --- a/src/librustc/traits/mod.rs +++ b/src/librustc/traits/mod.rs @@ -227,6 +227,7 @@ pub enum ObligationCauseCode<'tcx> { source: hir::MatchSource, prior_arms: Vec, last_ty: Ty<'tcx>, + discrim_hir_id: hir::HirId, }, /// Computing common supertype in the pattern guard for the arms of a match expression diff --git a/src/librustc/traits/structural_impls.rs b/src/librustc/traits/structural_impls.rs index f3a800bf46d87..0711f3539e586 100644 --- a/src/librustc/traits/structural_impls.rs +++ b/src/librustc/traits/structural_impls.rs @@ -519,6 +519,7 @@ impl<'a, 'tcx> Lift<'tcx> for traits::ObligationCauseCode<'a> { source, ref prior_arms, last_ty, + discrim_hir_id, } => { tcx.lift(&last_ty).map(|last_ty| { super::MatchExpressionArm { @@ -526,6 +527,7 @@ impl<'a, 'tcx> Lift<'tcx> for traits::ObligationCauseCode<'a> { source, prior_arms: prior_arms.clone(), last_ty, + discrim_hir_id, } }) } diff --git a/src/librustc_typeck/check/_match.rs b/src/librustc_typeck/check/_match.rs index affd3a2d16af7..032821e6d42f2 100644 --- a/src/librustc_typeck/check/_match.rs +++ b/src/librustc_typeck/check/_match.rs @@ -732,6 +732,7 @@ https://doc.rust-lang.org/reference/types.html#trait-objects"); source: match_src, prior_arms: other_arms.clone(), last_ty: prior_arm_ty.unwrap(), + discrim_hir_id: discrim.hir_id, }) }; coercion.coerce(self, &cause, &arm.body, arm_ty); diff --git a/src/test/ui/issue-59756.fixed b/src/test/ui/issue-59756.fixed new file mode 100644 index 0000000000000..7b55d0f17e690 --- /dev/null +++ b/src/test/ui/issue-59756.fixed @@ -0,0 +1,17 @@ +// run-rustfix + +#![allow(warnings)] + +struct A; +struct B; + +fn foo() -> Result { + Ok(A) +} + +fn bar() -> Result { + foo() + //~^ ERROR try expression alternatives have incompatible types [E0308] +} + +fn main() {} diff --git a/src/test/ui/issue-59756.rs b/src/test/ui/issue-59756.rs new file mode 100644 index 0000000000000..cccae396b7210 --- /dev/null +++ b/src/test/ui/issue-59756.rs @@ -0,0 +1,17 @@ +// run-rustfix + +#![allow(warnings)] + +struct A; +struct B; + +fn foo() -> Result { + Ok(A) +} + +fn bar() -> Result { + foo()? + //~^ ERROR try expression alternatives have incompatible types [E0308] +} + +fn main() {} diff --git a/src/test/ui/issue-59756.stderr b/src/test/ui/issue-59756.stderr new file mode 100644 index 0000000000000..d46232874fd2a --- /dev/null +++ b/src/test/ui/issue-59756.stderr @@ -0,0 +1,15 @@ +error[E0308]: try expression alternatives have incompatible types + --> $DIR/issue-59756.rs:13:5 + | +LL | foo()? + | ^^^^^- + | | | + | | help: try removing this `?` + | expected enum `std::result::Result`, found struct `A` + | + = note: expected type `std::result::Result` + found type `A` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0308`. diff --git a/src/test/ui/issues/issue-51632-try-desugar-incompatible-types.stderr b/src/test/ui/issues/issue-51632-try-desugar-incompatible-types.stderr index 8f36a3f961813..bf45357147916 100644 --- a/src/test/ui/issues/issue-51632-try-desugar-incompatible-types.stderr +++ b/src/test/ui/issues/issue-51632-try-desugar-incompatible-types.stderr @@ -2,7 +2,10 @@ error[E0308]: try expression alternatives have incompatible types --> $DIR/issue-51632-try-desugar-incompatible-types.rs:8:5 | LL | missing_discourses()? - | ^^^^^^^^^^^^^^^^^^^^^ expected enum `std::result::Result`, found isize + | ^^^^^^^^^^^^^^^^^^^^- + | | | + | | help: try removing this `?` + | expected enum `std::result::Result`, found isize | = note: expected type `std::result::Result` found type `isize`