From 007b40be01ca4e0eb0bca875e9134e4f87c9cd4b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Wed, 17 Apr 2019 18:30:26 -0700 Subject: [PATCH 1/2] Point at try `?` on errors affecting the err match arm of the desugared code --- src/librustc/hir/lowering.rs | 22 +++++++++++++------ src/test/ui/issues/issue-32709.stderr | 4 ++-- .../ui/try-block/try-block-bad-type.stderr | 4 ++-- src/test/ui/try-on-option.stderr | 4 ++-- 4 files changed, 21 insertions(+), 13 deletions(-) diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs index a8269bb1395..42ad571cf28 100644 --- a/src/librustc/hir/lowering.rs +++ b/src/librustc/hir/lowering.rs @@ -4685,6 +4685,14 @@ impl<'a> LoweringContext<'a> { Symbol::intern("try_trait") ].into()), ); + let try_span = self.sess.source_map().end_point(e.span); + let try_span = self.mark_span_with_reason( + CompilerDesugaringKind::QuestionMark, + try_span, + Some(vec![ + Symbol::intern("try_trait") + ].into()), + ); // `Try::into_result()` let discr = { @@ -4729,14 +4737,14 @@ impl<'a> LoweringContext<'a> { // return Try::from_error(From::from(err)),` let err_arm = { let err_ident = self.str_to_ident("err"); - let (err_local, err_local_nid) = self.pat_ident(e.span, err_ident); + let (err_local, err_local_nid) = self.pat_ident(try_span, err_ident); let from_expr = { let path = &["convert", "From", "from"]; let from = P(self.expr_std_path( - e.span, path, None, ThinVec::new())); - let err_expr = self.expr_ident(e.span, err_ident, err_local_nid); + try_span, path, None, ThinVec::new())); + let err_expr = self.expr_ident(try_span, err_ident, err_local_nid); - self.expr_call(e.span, from, hir_vec![err_expr]) + self.expr_call(try_span, from, hir_vec![err_expr]) }; let from_err_expr = self.wrap_in_try_constructor("from_error", from_expr, unstable_span); @@ -4745,7 +4753,7 @@ impl<'a> LoweringContext<'a> { let ret_expr = if let Some(catch_node) = catch_scope { let target_id = Ok(self.lower_node_id(catch_node).hir_id); P(self.expr( - e.span, + try_span, hir::ExprKind::Break( hir::Destination { label: None, @@ -4756,10 +4764,10 @@ impl<'a> LoweringContext<'a> { thin_attrs, )) } else { - P(self.expr(e.span, hir::ExprKind::Ret(Some(from_err_expr)), thin_attrs)) + P(self.expr(try_span, hir::ExprKind::Ret(Some(from_err_expr)), thin_attrs)) }; - let err_pat = self.pat_err(e.span, err_local); + let err_pat = self.pat_err(try_span, err_local); self.arm(hir_vec![err_pat], ret_expr) }; diff --git a/src/test/ui/issues/issue-32709.stderr b/src/test/ui/issues/issue-32709.stderr index 9127c754658..4a37e0a2e52 100644 --- a/src/test/ui/issues/issue-32709.stderr +++ b/src/test/ui/issues/issue-32709.stderr @@ -1,8 +1,8 @@ error[E0277]: the trait bound `(): std::convert::From<{integer}>` is not satisfied - --> $DIR/issue-32709.rs:4:5 + --> $DIR/issue-32709.rs:4:11 | LL | Err(5)?; - | ^^^^^^^ the trait `std::convert::From<{integer}>` is not implemented for `()` + | ^ the trait `std::convert::From<{integer}>` is not implemented for `()` | = note: required by `std::convert::From::from` diff --git a/src/test/ui/try-block/try-block-bad-type.stderr b/src/test/ui/try-block/try-block-bad-type.stderr index 07e7149793c..a39c8cfba12 100644 --- a/src/test/ui/try-block/try-block-bad-type.stderr +++ b/src/test/ui/try-block/try-block-bad-type.stderr @@ -1,8 +1,8 @@ error[E0277]: the trait bound `i32: std::convert::From<&str>` is not satisfied - --> $DIR/try-block-bad-type.rs:7:9 + --> $DIR/try-block-bad-type.rs:7:16 | LL | Err("")?; - | ^^^^^^^^ the trait `std::convert::From<&str>` is not implemented for `i32` + | ^ the trait `std::convert::From<&str>` is not implemented for `i32` | = help: the following implementations were found: > diff --git a/src/test/ui/try-on-option.stderr b/src/test/ui/try-on-option.stderr index 7dfa1a7d3a0..3e081d03766 100644 --- a/src/test/ui/try-on-option.stderr +++ b/src/test/ui/try-on-option.stderr @@ -1,8 +1,8 @@ error[E0277]: the trait bound `(): std::convert::From` is not satisfied - --> $DIR/try-on-option.rs:7:5 + --> $DIR/try-on-option.rs:7:6 | LL | x?; - | ^^ the trait `std::convert::From` is not implemented for `()` + | ^ the trait `std::convert::From` is not implemented for `()` | = note: required by `std::convert::From::from` From 1e99b2ec9dc60dc01a413118051d273ed7688c7e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Wed, 17 Apr 2019 19:50:50 -0700 Subject: [PATCH 2/2] Give custom error for E0277 on `?` error case --- src/librustc/traits/error_reporting.rs | 12 ++++++++++++ src/test/ui/issues/issue-32709.stderr | 2 +- src/test/ui/try-block/try-block-bad-type.rs | 2 +- src/test/ui/try-block/try-block-bad-type.stderr | 2 +- src/test/ui/try-on-option.rs | 4 ++-- src/test/ui/try-on-option.stderr | 2 +- 6 files changed, 18 insertions(+), 6 deletions(-) diff --git a/src/librustc/traits/error_reporting.rs b/src/librustc/traits/error_reporting.rs index 5b5a7cc9ed8..14c81a806c2 100644 --- a/src/librustc/traits/error_reporting.rs +++ b/src/librustc/traits/error_reporting.rs @@ -638,6 +638,18 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { let OnUnimplementedNote { message, label, note } = self.on_unimplemented_note(trait_ref, obligation); let have_alt_message = message.is_some() || label.is_some(); + let is_try = self.tcx.sess.source_map().span_to_snippet(span) + .map(|s| &s == "?") + .unwrap_or(false); + let is_from = format!("{}", trait_ref).starts_with("std::convert::From<"); + let message = if is_try && is_from { + Some(format!( + "`?` couldn't convert the error to `{}`", + trait_ref.self_ty(), + )) + } else { + message + }; let mut err = struct_span_err!( self.tcx.sess, diff --git a/src/test/ui/issues/issue-32709.stderr b/src/test/ui/issues/issue-32709.stderr index 4a37e0a2e52..84cca5b20af 100644 --- a/src/test/ui/issues/issue-32709.stderr +++ b/src/test/ui/issues/issue-32709.stderr @@ -1,4 +1,4 @@ -error[E0277]: the trait bound `(): std::convert::From<{integer}>` is not satisfied +error[E0277]: `?` couldn't convert the error to `()` --> $DIR/issue-32709.rs:4:11 | LL | Err(5)?; diff --git a/src/test/ui/try-block/try-block-bad-type.rs b/src/test/ui/try-block/try-block-bad-type.rs index 0e297dd8ff1..4dfc8e6a2fc 100644 --- a/src/test/ui/try-block/try-block-bad-type.rs +++ b/src/test/ui/try-block/try-block-bad-type.rs @@ -4,7 +4,7 @@ pub fn main() { let res: Result = try { - Err("")?; //~ ERROR the trait bound `i32: std::convert::From<&str>` is not satisfied + Err("")?; //~ ERROR `?` couldn't convert the error 5 }; diff --git a/src/test/ui/try-block/try-block-bad-type.stderr b/src/test/ui/try-block/try-block-bad-type.stderr index a39c8cfba12..13593c4e8e7 100644 --- a/src/test/ui/try-block/try-block-bad-type.stderr +++ b/src/test/ui/try-block/try-block-bad-type.stderr @@ -1,4 +1,4 @@ -error[E0277]: the trait bound `i32: std::convert::From<&str>` is not satisfied +error[E0277]: `?` couldn't convert the error to `i32` --> $DIR/try-block-bad-type.rs:7:16 | LL | Err("")?; diff --git a/src/test/ui/try-on-option.rs b/src/test/ui/try-on-option.rs index 9c8e8b33ad6..5d94cee8e37 100644 --- a/src/test/ui/try-on-option.rs +++ b/src/test/ui/try-on-option.rs @@ -4,12 +4,12 @@ fn main() {} fn foo() -> Result { let x: Option = None; - x?; //~ the trait bound + x?; //~ ERROR `?` couldn't convert the error Ok(22) } fn bar() -> u32 { let x: Option = None; - x?; //~ the `?` operator + x?; //~ ERROR the `?` operator 22 } diff --git a/src/test/ui/try-on-option.stderr b/src/test/ui/try-on-option.stderr index 3e081d03766..4465fbe14b7 100644 --- a/src/test/ui/try-on-option.stderr +++ b/src/test/ui/try-on-option.stderr @@ -1,4 +1,4 @@ -error[E0277]: the trait bound `(): std::convert::From` is not satisfied +error[E0277]: `?` couldn't convert the error to `()` --> $DIR/try-on-option.rs:7:6 | LL | x?;