Skip to content

Commit 4797568

Browse files
authored
Rollup merge of #58204 - estebank:impl-trait-semi, r=zackmdavis
On return type `impl Trait` for block with no expr point at last semi Partial solution, doesn't actually validate that the last statement in the function body can satisfy the trait bound, but it's a good incremental improvement over the status quo. ``` 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; | - consider removing this semicolon | = note: the return type of a function must have a statically known size ``` Partially addresses #54771.
2 parents 19e39cb + e6387b6 commit 4797568

File tree

3 files changed

+72
-12
lines changed

3 files changed

+72
-12
lines changed

src/librustc/traits/error_reporting.rs

Lines changed: 52 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -599,11 +599,12 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
599599
}
600600
}
601601

602-
pub fn report_selection_error(&self,
603-
obligation: &PredicateObligation<'tcx>,
604-
error: &SelectionError<'tcx>,
605-
fallback_has_occurred: bool)
606-
{
602+
pub fn report_selection_error(
603+
&self,
604+
obligation: &PredicateObligation<'tcx>,
605+
error: &SelectionError<'tcx>,
606+
fallback_has_occurred: bool,
607+
) {
607608
let span = obligation.cause.span;
608609

609610
let mut err = match *error {
@@ -673,6 +674,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
673674

674675
self.suggest_borrow_on_unsized_slice(&obligation.cause.code, &mut err);
675676
self.suggest_remove_reference(&obligation, &mut err, &trait_ref);
677+
self.suggest_semicolon_removal(&obligation, &mut err, span, &trait_ref);
676678

677679
// Try to report a help message
678680
if !trait_ref.has_infer_types() &&
@@ -901,9 +903,11 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
901903

902904
/// When encountering an assignment of an unsized trait, like `let x = ""[..];`, provide a
903905
/// suggestion to borrow the initializer in order to use have a slice instead.
904-
fn suggest_borrow_on_unsized_slice(&self,
905-
code: &ObligationCauseCode<'tcx>,
906-
err: &mut DiagnosticBuilder<'tcx>) {
906+
fn suggest_borrow_on_unsized_slice(
907+
&self,
908+
code: &ObligationCauseCode<'tcx>,
909+
err: &mut DiagnosticBuilder<'tcx>,
910+
) {
907911
if let &ObligationCauseCode::VariableType(node_id) = code {
908912
let parent_node = self.tcx.hir().get_parent_node(node_id);
909913
if let Some(Node::Local(ref local)) = self.tcx.hir().find(parent_node) {
@@ -925,10 +929,12 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
925929

926930
/// Whenever references are used by mistake, like `for (i, e) in &vec.iter().enumerate()`,
927931
/// suggest removing these references until we reach a type that implements the trait.
928-
fn suggest_remove_reference(&self,
929-
obligation: &PredicateObligation<'tcx>,
930-
err: &mut DiagnosticBuilder<'tcx>,
931-
trait_ref: &ty::Binder<ty::TraitRef<'tcx>>) {
932+
fn suggest_remove_reference(
933+
&self,
934+
obligation: &PredicateObligation<'tcx>,
935+
err: &mut DiagnosticBuilder<'tcx>,
936+
trait_ref: &ty::Binder<ty::TraitRef<'tcx>>,
937+
) {
932938
let trait_ref = trait_ref.skip_binder();
933939
let span = obligation.cause.span;
934940

@@ -970,6 +976,40 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
970976
}
971977
}
972978

979+
fn suggest_semicolon_removal(
980+
&self,
981+
obligation: &PredicateObligation<'tcx>,
982+
err: &mut DiagnosticBuilder<'tcx>,
983+
span: Span,
984+
trait_ref: &ty::Binder<ty::TraitRef<'tcx>>,
985+
) {
986+
let hir = self.tcx.hir();
987+
let parent_node = hir.get_parent_node(
988+
hir.hir_to_node_id(obligation.cause.body_id),
989+
);
990+
let node = hir.find(parent_node);
991+
if let Some(hir::Node::Item(hir::Item {
992+
node: hir::ItemKind::Fn(decl, _, _, body_id),
993+
..
994+
})) = node {
995+
let body = hir.body(*body_id);
996+
if let hir::ExprKind::Block(blk, _) = &body.value.node {
997+
if decl.output.span().overlaps(span) && blk.expr.is_none() &&
998+
"()" == &trait_ref.self_ty().to_string()
999+
{
1000+
// FIXME(estebank): When encountering a method with a trait
1001+
// bound not satisfied in the return type with a body that has
1002+
// no return, suggest removal of semicolon on last statement.
1003+
// Once that is added, close #54771.
1004+
if let Some(ref stmt) = blk.stmts.last() {
1005+
let sp = self.tcx.sess.source_map().end_point(stmt.span);
1006+
err.span_label(sp, "consider removing this semicolon");
1007+
}
1008+
}
1009+
}
1010+
}
1011+
}
1012+
9731013
/// Given some node representing a fn-like thing in the HIR map,
9741014
/// returns a span and `ArgKind` information that describes the
9751015
/// arguments it expects. This can be supplied to
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
trait Bar {}
2+
impl Bar for u8 {}
3+
fn foo() -> impl Bar {
4+
5; //~^ ERROR the trait bound `(): Bar` is not satisfied
5+
}
6+
7+
fn main() {}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
error[E0277]: the trait bound `(): Bar` is not satisfied
2+
--> $DIR/impl-trait-return-trailing-semicolon.rs:3:13
3+
|
4+
LL | fn foo() -> impl Bar {
5+
| ^^^^^^^^ the trait `Bar` is not implemented for `()`
6+
LL | 5; //~^ ERROR the trait bound `(): Bar` is not satisfied
7+
| - consider removing this semicolon
8+
|
9+
= note: the return type of a function must have a statically known size
10+
11+
error: aborting due to previous error
12+
13+
For more information about this error, try `rustc --explain E0277`.

0 commit comments

Comments
 (0)