diff --git a/src/librustc/traits/error_reporting.rs b/src/librustc/traits/error_reporting.rs index 3eb49092fed1d..502edb4ac6b2e 100644 --- a/src/librustc/traits/error_reporting.rs +++ b/src/librustc/traits/error_reporting.rs @@ -598,11 +598,12 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { } } - pub fn report_selection_error(&self, - obligation: &PredicateObligation<'tcx>, - error: &SelectionError<'tcx>, - fallback_has_occurred: bool) - { + pub fn report_selection_error( + &self, + obligation: &PredicateObligation<'tcx>, + error: &SelectionError<'tcx>, + fallback_has_occurred: bool, + ) { let span = obligation.cause.span; let mut err = match *error { @@ -672,6 +673,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { self.suggest_borrow_on_unsized_slice(&obligation.cause.code, &mut err); self.suggest_remove_reference(&obligation, &mut err, &trait_ref); + self.suggest_semicolon_removal(&obligation, &mut err, span, &trait_ref); // Try to report a help message if !trait_ref.has_infer_types() && @@ -900,9 +902,11 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { /// When encountering an assignment of an unsized trait, like `let x = ""[..];`, provide a /// suggestion to borrow the initializer in order to use have a slice instead. - fn suggest_borrow_on_unsized_slice(&self, - code: &ObligationCauseCode<'tcx>, - err: &mut DiagnosticBuilder<'tcx>) { + fn suggest_borrow_on_unsized_slice( + &self, + code: &ObligationCauseCode<'tcx>, + err: &mut DiagnosticBuilder<'tcx>, + ) { if let &ObligationCauseCode::VariableType(node_id) = code { let parent_node = self.tcx.hir().get_parent_node(node_id); if let Some(Node::Local(ref local)) = self.tcx.hir().find(parent_node) { @@ -924,10 +928,12 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { /// Whenever references are used by mistake, like `for (i, e) in &vec.iter().enumerate()`, /// suggest removing these references until we reach a type that implements the trait. - fn suggest_remove_reference(&self, - obligation: &PredicateObligation<'tcx>, - err: &mut DiagnosticBuilder<'tcx>, - trait_ref: &ty::Binder>) { + fn suggest_remove_reference( + &self, + obligation: &PredicateObligation<'tcx>, + err: &mut DiagnosticBuilder<'tcx>, + trait_ref: &ty::Binder>, + ) { let trait_ref = trait_ref.skip_binder(); let span = obligation.cause.span; @@ -969,6 +975,40 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { } } + fn suggest_semicolon_removal( + &self, + obligation: &PredicateObligation<'tcx>, + err: &mut DiagnosticBuilder<'tcx>, + span: Span, + trait_ref: &ty::Binder>, + ) { + let hir = self.tcx.hir(); + let parent_node = hir.get_parent_node( + hir.hir_to_node_id(obligation.cause.body_id), + ); + let node = hir.find(parent_node); + if let Some(hir::Node::Item(hir::Item { + node: hir::ItemKind::Fn(decl, _, _, body_id), + .. + })) = node { + let body = hir.body(*body_id); + if let hir::ExprKind::Block(blk, _) = &body.value.node { + if decl.output.span().overlaps(span) && blk.expr.is_none() && + "()" == &trait_ref.self_ty().to_string() + { + // FIXME(estebank): When encountering a method with a trait + // bound not satisfied in the return type with a body that has + // no return, suggest removal of semicolon on last statement. + // Once that is added, close #54771. + if let Some(ref stmt) = blk.stmts.last() { + let sp = self.tcx.sess.source_map().end_point(stmt.span); + err.span_label(sp, "consider removing this semicolon"); + } + } + } + } + } + /// Given some node representing a fn-like thing in the HIR map, /// returns a span and `ArgKind` information that describes the /// arguments it expects. This can be supplied to diff --git a/src/test/ui/suggestions/impl-trait-return-trailing-semicolon.rs b/src/test/ui/suggestions/impl-trait-return-trailing-semicolon.rs new file mode 100644 index 0000000000000..e72a2d8ccc629 --- /dev/null +++ b/src/test/ui/suggestions/impl-trait-return-trailing-semicolon.rs @@ -0,0 +1,7 @@ +trait Bar {} +impl Bar for u8 {} +fn foo() -> impl Bar { + 5; //~^ ERROR the trait bound `(): Bar` is not satisfied +} + +fn main() {} diff --git a/src/test/ui/suggestions/impl-trait-return-trailing-semicolon.stderr b/src/test/ui/suggestions/impl-trait-return-trailing-semicolon.stderr new file mode 100644 index 0000000000000..f26fb141ccf80 --- /dev/null +++ b/src/test/ui/suggestions/impl-trait-return-trailing-semicolon.stderr @@ -0,0 +1,13 @@ +error[E0277]: the trait bound `(): Bar` is not satisfied + --> $DIR/impl-trait-return-trailing-semicolon.rs:3:13 + | +LL | fn foo() -> impl Bar { + | ^^^^^^^^ the trait `Bar` is not implemented for `()` +LL | 5; //~^ ERROR the trait bound `(): Bar` is not satisfied + | - consider removing this semicolon + | + = note: the return type of a function must have a statically known size + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0277`.