diff --git a/src/librustc_parse/parser/stmt.rs b/src/librustc_parse/parser/stmt.rs index fddfe48bf8670..b3764d2d47be1 100644 --- a/src/librustc_parse/parser/stmt.rs +++ b/src/librustc_parse/parser/stmt.rs @@ -165,9 +165,9 @@ impl<'a> Parser<'a> { // Rewind to before attempting to parse the type and continue parsing. let parser_snapshot_after_type = self.clone(); mem::replace(self, parser_snapshot_before_type); - - let snippet = self.span_to_snippet(pat.span).unwrap(); - err.span_label(pat.span, format!("while parsing the type for `{}`", snippet)); + if let Ok(snip) = self.span_to_snippet(pat.span) { + err.span_label(pat.span, format!("while parsing the type for `{}`", snip)); + } (Some((parser_snapshot_after_type, colon_sp, err)), None) } } diff --git a/src/librustc_trait_selection/traits/error_reporting/mod.rs b/src/librustc_trait_selection/traits/error_reporting/mod.rs index 7d6b3b52c046f..5a9a96887f66a 100644 --- a/src/librustc_trait_selection/traits/error_reporting/mod.rs +++ b/src/librustc_trait_selection/traits/error_reporting/mod.rs @@ -65,7 +65,7 @@ pub trait InferCtxtExt<'tcx> { /// returns a span and `ArgKind` information that describes the /// arguments it expects. This can be supplied to /// `report_arg_count_mismatch`. - fn get_fn_like_arguments(&self, node: Node<'_>) -> (Span, Vec); + fn get_fn_like_arguments(&self, node: Node<'_>) -> Option<(Span, Vec)>; /// Reports an error when the number of arguments needed by a /// trait match doesn't match the number that the expression @@ -611,10 +611,10 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { ) } else { let (closure_span, found) = found_did - .and_then(|did| self.tcx.hir().get_if_local(did)) - .map(|node| { - let (found_span, found) = self.get_fn_like_arguments(node); - (Some(found_span), found) + .and_then(|did| { + let node = self.tcx.hir().get_if_local(did)?; + let (found_span, found) = self.get_fn_like_arguments(node)?; + Some((Some(found_span), found)) }) .unwrap_or((found_span, found)); @@ -672,43 +672,38 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { /// returns a span and `ArgKind` information that describes the /// arguments it expects. This can be supplied to /// `report_arg_count_mismatch`. - fn get_fn_like_arguments(&self, node: Node<'_>) -> (Span, Vec) { - match node { + fn get_fn_like_arguments(&self, node: Node<'_>) -> Option<(Span, Vec)> { + let sm = self.tcx.sess.source_map(); + let hir = self.tcx.hir(); + Some(match node { Node::Expr(&hir::Expr { kind: hir::ExprKind::Closure(_, ref _decl, id, span, _), .. }) => ( - self.tcx.sess.source_map().guess_head_span(span), - self.tcx - .hir() - .body(id) + sm.guess_head_span(span), + hir.body(id) .params .iter() .map(|arg| { if let hir::Pat { kind: hir::PatKind::Tuple(ref args, _), span, .. } = *arg.pat { - ArgKind::Tuple( + Some(ArgKind::Tuple( Some(span), args.iter() .map(|pat| { - let snippet = self - .tcx - .sess - .source_map() - .span_to_snippet(pat.span) - .unwrap(); - (snippet, "_".to_owned()) + sm.span_to_snippet(pat.span) + .ok() + .map(|snippet| (snippet, "_".to_owned())) }) - .collect::>(), - ) + .collect::>>()?, + )) } else { - let name = - self.tcx.sess.source_map().span_to_snippet(arg.pat.span).unwrap(); - ArgKind::Arg(name, "_".to_owned()) + let name = sm.span_to_snippet(arg.pat.span).ok()?; + Some(ArgKind::Arg(name, "_".to_owned())) } }) - .collect::>(), + .collect::>>()?, ), Node::Item(&hir::Item { span, kind: hir::ItemKind::Fn(ref sig, ..), .. }) | Node::ImplItem(&hir::ImplItem { @@ -721,7 +716,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { kind: hir::TraitItemKind::Fn(ref sig, _), .. }) => ( - self.tcx.sess.source_map().guess_head_span(span), + sm.guess_head_span(span), sig.decl .inputs .iter() @@ -735,16 +730,12 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { .collect::>(), ), Node::Ctor(ref variant_data) => { - let span = variant_data - .ctor_hir_id() - .map(|hir_id| self.tcx.hir().span(hir_id)) - .unwrap_or(DUMMY_SP); - let span = self.tcx.sess.source_map().guess_head_span(span); - + let span = variant_data.ctor_hir_id().map(|id| hir.span(id)).unwrap_or(DUMMY_SP); + let span = sm.guess_head_span(span); (span, vec![ArgKind::empty(); variant_data.fields().len()]) } _ => panic!("non-FnLike node found: {:?}", node), - } + }) } /// Reports an error when the number of arguments needed by a diff --git a/src/librustc_trait_selection/traits/error_reporting/suggestions.rs b/src/librustc_trait_selection/traits/error_reporting/suggestions.rs index 6a352602e266a..fcec29aaa8ecb 100644 --- a/src/librustc_trait_selection/traits/error_reporting/suggestions.rs +++ b/src/librustc_trait_selection/traits/error_reporting/suggestions.rs @@ -732,12 +732,13 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { true }; + let sm = self.tcx.sess.source_map(); let (snippet, last_ty) = if let (true, hir::TyKind::TraitObject(..), Ok(snippet), true, Some(last_ty)) = ( // Verify that we're dealing with a return `dyn Trait` ret_ty.span.overlaps(span), &ret_ty.kind, - self.tcx.sess.source_map().span_to_snippet(ret_ty.span), + sm.span_to_snippet(ret_ty.span), // If any of the return types does not conform to the trait, then we can't // suggest `impl Trait` nor trait objects, it is a type mismatch error. all_returns_conform_to_trait, @@ -775,26 +776,23 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { if is_object_safe { // Suggest `-> Box` and `Box::new(returned_value)`. // Get all the return values and collect their span and suggestion. - let mut suggestions = visitor + if let Some(mut suggestions) = visitor .returns .iter() .map(|expr| { - ( - expr.span, - format!( - "Box::new({})", - self.tcx.sess.source_map().span_to_snippet(expr.span).unwrap() - ), - ) + let snip = sm.span_to_snippet(expr.span).ok()?; + Some((expr.span, format!("Box::new({})", snip))) }) - .collect::>(); - // Add the suggestion for the return type. - suggestions.push((ret_ty.span, format!("Box", trait_obj))); - err.multipart_suggestion( - "return a boxed trait object instead", - suggestions, - Applicability::MaybeIncorrect, - ); + .collect::>>() + { + // Add the suggestion for the return type. + suggestions.push((ret_ty.span, format!("Box", trait_obj))); + err.multipart_suggestion( + "return a boxed trait object instead", + suggestions, + Applicability::MaybeIncorrect, + ); + } } else { // This is currently not possible to trigger because E0038 takes precedence, but // leave it in for completeness in case anything changes in an earlier stage. diff --git a/src/librustc_typeck/check/closure.rs b/src/librustc_typeck/check/closure.rs index 922d9ca6485bb..2ccf7890c3042 100644 --- a/src/librustc_typeck/check/closure.rs +++ b/src/librustc_typeck/check/closure.rs @@ -432,18 +432,23 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { body: &hir::Body<'_>, expected_sig: ExpectedSig<'tcx>, ) -> ClosureSignatures<'tcx> { - let expr_map_node = self.tcx.hir().get_if_local(expr_def_id).unwrap(); + let hir = self.tcx.hir(); + let expr_map_node = hir.get_if_local(expr_def_id).unwrap(); let expected_args: Vec<_> = expected_sig .sig .inputs() .iter() .map(|ty| ArgKind::from_expected_ty(ty, None)) .collect(); - let (closure_span, found_args) = self.get_fn_like_arguments(expr_map_node); - let expected_span = expected_sig.cause_span.unwrap_or(closure_span); + let (closure_span, found_args) = match self.get_fn_like_arguments(expr_map_node) { + Some((sp, args)) => (Some(sp), args), + None => (None, Vec::new()), + }; + let expected_span = + expected_sig.cause_span.unwrap_or_else(|| hir.span_if_local(expr_def_id).unwrap()); self.report_arg_count_mismatch( expected_span, - Some(closure_span), + closure_span, expected_args, found_args, true, diff --git a/src/librustc_typeck/check/op.rs b/src/librustc_typeck/check/op.rs index 7367338bddf54..cac9113fd5d30 100644 --- a/src/librustc_typeck/check/op.rs +++ b/src/librustc_typeck/check/op.rs @@ -481,7 +481,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } /// If one of the types is an uncalled function and calling it would yield the other type, - /// suggest calling the function. Returns whether a suggestion was given. + /// suggest calling the function. Returns `true` if suggestion would apply (even if not given). fn add_type_neq_err_label( &self, err: &mut rustc_errors::DiagnosticBuilder<'_>, @@ -514,24 +514,20 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { .lookup_op_method(fn_sig.output(), &[other_ty], Op::Binary(op, is_assign)) .is_ok() { - let (variable_snippet, applicability) = if !fn_sig.inputs().is_empty() { - ( - format!("{}( /* arguments */ )", source_map.span_to_snippet(span).unwrap()), - Applicability::HasPlaceholders, - ) - } else { - ( - format!("{}()", source_map.span_to_snippet(span).unwrap()), - Applicability::MaybeIncorrect, - ) - }; + if let Ok(snippet) = source_map.span_to_snippet(span) { + let (variable_snippet, applicability) = if !fn_sig.inputs().is_empty() { + (format!("{}( /* arguments */ )", snippet), Applicability::HasPlaceholders) + } else { + (format!("{}()", snippet), Applicability::MaybeIncorrect) + }; - err.span_suggestion( - span, - "you might have forgotten to call this function", - variable_snippet, - applicability, - ); + err.span_suggestion( + span, + "you might have forgotten to call this function", + variable_snippet, + applicability, + ); + } return true; } } diff --git a/src/test/ui/issues/issue-70724-add_type_neq_err_label-unwrap.rs b/src/test/ui/issues/issue-70724-add_type_neq_err_label-unwrap.rs new file mode 100644 index 0000000000000..c2683157f797f --- /dev/null +++ b/src/test/ui/issues/issue-70724-add_type_neq_err_label-unwrap.rs @@ -0,0 +1,10 @@ +fn a() -> i32 { + 3 +} + +pub fn main() { + assert_eq!(a, 0); + //~^ ERROR binary operation `==` cannot + //~| ERROR mismatched types + //~| ERROR doesn't implement +} diff --git a/src/test/ui/issues/issue-70724-add_type_neq_err_label-unwrap.stderr b/src/test/ui/issues/issue-70724-add_type_neq_err_label-unwrap.stderr new file mode 100644 index 0000000000000..467c15cc52d45 --- /dev/null +++ b/src/test/ui/issues/issue-70724-add_type_neq_err_label-unwrap.stderr @@ -0,0 +1,41 @@ +error[E0369]: binary operation `==` cannot be applied to type `fn() -> i32 {a}` + --> $DIR/issue-70724-add_type_neq_err_label-unwrap.rs:6:5 + | +LL | assert_eq!(a, 0); + | ^^^^^^^^^^^^^^^^^ + | | + | fn() -> i32 {a} + | {integer} + | help: you might have forgotten to call this function: `*left_val()` + | + = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0308]: mismatched types + --> $DIR/issue-70724-add_type_neq_err_label-unwrap.rs:6:5 + | +LL | assert_eq!(a, 0); + | ^^^^^^^^^^^^^^^^^ expected fn item, found integer + | + = note: expected fn item `fn() -> i32 {a}` + found type `i32` + = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0277]: `fn() -> i32 {a}` doesn't implement `std::fmt::Debug` + --> $DIR/issue-70724-add_type_neq_err_label-unwrap.rs:6:5 + | +LL | fn a() -> i32 { + | - consider calling this function +... +LL | assert_eq!(a, 0); + | ^^^^^^^^^^^^^^^^^ `fn() -> i32 {a}` cannot be formatted using `{:?}` because it doesn't implement `std::fmt::Debug` + | + = help: the trait `std::fmt::Debug` is not implemented for `fn() -> i32 {a}` + = help: use parentheses to call the function: `a()` + = note: required because of the requirements on the impl of `std::fmt::Debug` for `&fn() -> i32 {a}` + = note: required by `std::fmt::Debug::fmt` + = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) + +error: aborting due to 3 previous errors + +Some errors have detailed explanations: E0277, E0308, E0369. +For more information about an error, try `rustc --explain E0277`.