From 16592f691b71802f8876a4f087cdc22a21869836 Mon Sep 17 00:00:00 2001 From: David Wood Date: Wed, 10 Apr 2019 23:26:45 +0200 Subject: [PATCH] Suggest removing `?` to resolve type errors. This commit adds a suggestion to remove the `?` from expressions if removing the `?` would resolve a type error. --- src/librustc/infer/error_reporting/mod.rs | 28 ++++++++++++++++++- src/librustc/traits/mod.rs | 1 + src/librustc/traits/structural_impls.rs | 2 ++ src/librustc_typeck/check/_match.rs | 1 + src/test/ui/issue-59756.fixed | 17 +++++++++++ src/test/ui/issue-59756.rs | 2 ++ src/test/ui/issue-59756.stderr | 7 +++-- ...1632-try-desugar-incompatible-types.stderr | 5 +++- 8 files changed, 59 insertions(+), 4 deletions(-) create mode 100644 src/test/ui/issue-59756.fixed diff --git a/src/librustc/infer/error_reporting/mod.rs b/src/librustc/infer/error_reporting/mod.rs index 19663161fe3..9c899fab59e 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 78c80b48ee8..ddca18ce765 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 f3a800bf46d..0711f3539e5 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 affd3a2d16a..032821e6d42 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 00000000000..7b55d0f17e6 --- /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 index 2ce96943275..cccae396b72 100644 --- a/src/test/ui/issue-59756.rs +++ b/src/test/ui/issue-59756.rs @@ -1,3 +1,5 @@ +// run-rustfix + #![allow(warnings)] struct A; diff --git a/src/test/ui/issue-59756.stderr b/src/test/ui/issue-59756.stderr index 58491cdaa58..d46232874fd 100644 --- a/src/test/ui/issue-59756.stderr +++ b/src/test/ui/issue-59756.stderr @@ -1,8 +1,11 @@ error[E0308]: try expression alternatives have incompatible types - --> $DIR/issue-59756.rs:11:5 + --> $DIR/issue-59756.rs:13:5 | LL | foo()? - | ^^^^^^ expected enum `std::result::Result`, found struct `A` + | ^^^^^- + | | | + | | help: try removing this `?` + | expected enum `std::result::Result`, found struct `A` | = note: expected type `std::result::Result` found type `A` 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 8f36a3f9618..bf453571479 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`