]> git.lizzy.rs Git - rust.git/blobdiff - compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs
Auto merge of #91962 - matthiaskrgr:rollup-2g082jw, r=matthiaskrgr
[rust.git] / compiler / rustc_trait_selection / src / traits / error_reporting / suggestions.rs
index d0b61b2430862ee21a24f3704b40ff9672e8c60f..8624f8c8442e1f3394f1c4bbbfaf955e2cd6234d 100644 (file)
@@ -21,7 +21,7 @@
 use rustc_hir::{AsyncGeneratorKind, GeneratorKind, Node};
 use rustc_middle::ty::{
     self, suggest_arbitrary_trait_bound, suggest_constraining_type_param, AdtKind, DefIdTree,
-    Infer, InferTy, ToPredicate, Ty, TyCtxt, TypeFoldable, WithConstness,
+    Infer, InferTy, ToPredicate, Ty, TyCtxt, TypeFoldable,
 };
 use rustc_middle::ty::{TypeAndMut, TypeckResults};
 use rustc_session::Limit;
@@ -89,6 +89,12 @@ fn suggest_remove_reference(
         trait_ref: ty::Binder<'tcx, ty::TraitRef<'tcx>>,
     );
 
+    fn suggest_remove_await(
+        &self,
+        obligation: &PredicateObligation<'tcx>,
+        err: &mut DiagnosticBuilder<'_>,
+    );
+
     fn suggest_change_mut(
         &self,
         obligation: &PredicateObligation<'tcx>,
@@ -741,7 +747,7 @@ fn suggest_add_reference_to_arg(
 
                     let msg = format!(
                         "the trait bound `{}: {}` is not satisfied",
-                        orig_ty.to_string(),
+                        orig_ty,
                         old_ref.print_only_trait_path(),
                     );
                     if has_custom_message {
@@ -873,6 +879,63 @@ fn suggest_remove_reference(
         }
     }
 
+    fn suggest_remove_await(
+        &self,
+        obligation: &PredicateObligation<'tcx>,
+        err: &mut DiagnosticBuilder<'_>,
+    ) {
+        let span = obligation.cause.span;
+
+        if let ObligationCauseCode::AwaitableExpr(hir_id) = obligation.cause.code.peel_derives() {
+            let hir = self.tcx.hir();
+            if let Some(node) = hir_id.and_then(|hir_id| hir.find(hir_id)) {
+                if let hir::Node::Expr(expr) = node {
+                    // FIXME: use `obligation.predicate.kind()...trait_ref.self_ty()` to see if we have `()`
+                    // and if not maybe suggest doing something else? If we kept the expression around we
+                    // could also check if it is an fn call (very likely) and suggest changing *that*, if
+                    // it is from the local crate.
+                    err.span_suggestion_verbose(
+                        expr.span.shrink_to_hi().with_hi(span.hi()),
+                        "remove the `.await`",
+                        String::new(),
+                        Applicability::MachineApplicable,
+                    );
+                    // FIXME: account for associated `async fn`s.
+                    if let hir::Expr { span, kind: hir::ExprKind::Call(base, _), .. } = expr {
+                        if let ty::PredicateKind::Trait(pred) =
+                            obligation.predicate.kind().skip_binder()
+                        {
+                            err.span_label(
+                                *span,
+                                &format!("this call returns `{}`", pred.self_ty()),
+                            );
+                        }
+                        if let Some(typeck_results) =
+                            self.in_progress_typeck_results.map(|t| t.borrow())
+                        {
+                            let ty = typeck_results.expr_ty_adjusted(base);
+                            if let ty::FnDef(def_id, _substs) = ty.kind() {
+                                if let Some(hir::Node::Item(hir::Item { span, ident, .. })) =
+                                    hir.get_if_local(*def_id)
+                                {
+                                    err.span_suggestion_verbose(
+                                        span.shrink_to_lo(),
+                                        &format!(
+                                            "alternatively, consider making `fn {}` asynchronous",
+                                            ident
+                                        ),
+                                        "async ".to_string(),
+                                        Applicability::MaybeIncorrect,
+                                    );
+                                }
+                            }
+                        }
+                    }
+                }
+            }
+        }
+    }
+
     /// Check if the trait bound is implemented for a different mutability and note it in the
     /// final error.
     fn suggest_change_mut(
@@ -1654,130 +1717,63 @@ fn note_obligation_cause_for_async_await(
             format!("does not implement `{}`", trait_ref.print_only_trait_path())
         };
 
-        let mut explain_yield =
-            |interior_span: Span, yield_span: Span, scope_span: Option<Span>| {
-                let mut span = MultiSpan::from_span(yield_span);
-                if let Ok(snippet) = source_map.span_to_snippet(interior_span) {
-                    // #70935: If snippet contains newlines, display "the value" instead
-                    // so that we do not emit complex diagnostics.
-                    let snippet = &format!("`{}`", snippet);
-                    let snippet = if snippet.contains('\n') { "the value" } else { snippet };
-                    // The multispan can be complex here, like:
-                    // note: future is not `Send` as this value is used across an await
-                    //   --> $DIR/issue-70935-complex-spans.rs:13:9
-                    //    |
-                    // LL |            baz(|| async{
-                    //    |  __________^___-
-                    //    | | _________|
-                    //    | ||
-                    // LL | ||             foo(tx.clone());
-                    // LL | ||         }).await;
-                    //    | ||         -      ^- value is later dropped here
-                    //    | ||_________|______|
-                    //    | |__________|      await occurs here, with value maybe used later
-                    //    |            has type `closure` which is not `Send`
-                    //
-                    // So, detect it and separate into some notes, like:
-                    //
-                    // note: future is not `Send` as this value is used across an await
-                    //   --> $DIR/issue-70935-complex-spans.rs:13:9
-                    //    |
-                    // LL | /         baz(|| async{
-                    // LL | |             foo(tx.clone());
-                    // LL | |         }).await;
-                    //    | |________________^ first, await occurs here, with the value maybe used later...
-                    // note: the value is later dropped here
-                    //   --> $DIR/issue-70935-complex-spans.rs:15:17
-                    //    |
-                    // LL |         }).await;
-                    //    |                 ^
-                    //
-                    // If available, use the scope span to annotate the drop location.
-                    if let Some(scope_span) = scope_span {
-                        let scope_span = source_map.end_point(scope_span);
-                        let is_overlapped =
-                            yield_span.overlaps(scope_span) || yield_span.overlaps(interior_span);
-                        if is_overlapped {
-                            span.push_span_label(
-                                yield_span,
-                                format!(
-                                    "first, {} occurs here, with {} maybe used later...",
-                                    await_or_yield, snippet
-                                ),
-                            );
-                            err.span_note(
-                                span,
-                                &format!(
-                                    "{} {} as this value is used across {}",
-                                    future_or_generator, trait_explanation, an_await_or_yield
-                                ),
-                            );
-                            if source_map.is_multiline(interior_span) {
-                                err.span_note(
-                                    scope_span,
-                                    &format!("{} is later dropped here", snippet),
-                                );
-                                err.span_note(
-                                    interior_span,
-                                    &format!(
-                                        "this has type `{}` which {}",
-                                        target_ty, trait_explanation
-                                    ),
-                                );
-                            } else {
-                                let mut span = MultiSpan::from_span(scope_span);
-                                span.push_span_label(
-                                    interior_span,
-                                    format!("has type `{}` which {}", target_ty, trait_explanation),
-                                );
-                                err.span_note(span, &format!("{} is later dropped here", snippet));
-                            }
-                        } else {
-                            span.push_span_label(
-                                yield_span,
-                                format!(
-                                    "{} occurs here, with {} maybe used later",
-                                    await_or_yield, snippet
-                                ),
-                            );
-                            span.push_span_label(
-                                scope_span,
-                                format!("{} is later dropped here", snippet),
-                            );
-                            span.push_span_label(
-                                interior_span,
-                                format!("has type `{}` which {}", target_ty, trait_explanation),
-                            );
-                            err.span_note(
-                                span,
-                                &format!(
-                                    "{} {} as this value is used across {}",
-                                    future_or_generator, trait_explanation, an_await_or_yield
-                                ),
-                            );
-                        }
+        let mut explain_yield = |interior_span: Span,
+                                 yield_span: Span,
+                                 scope_span: Option<Span>| {
+            let mut span = MultiSpan::from_span(yield_span);
+            if let Ok(snippet) = source_map.span_to_snippet(interior_span) {
+                // #70935: If snippet contains newlines, display "the value" instead
+                // so that we do not emit complex diagnostics.
+                let snippet = &format!("`{}`", snippet);
+                let snippet = if snippet.contains('\n') { "the value" } else { snippet };
+                // note: future is not `Send` as this value is used across an await
+                //   --> $DIR/issue-70935-complex-spans.rs:13:9
+                //    |
+                // LL |            baz(|| async {
+                //    |  ______________-
+                //    | |
+                //    | |
+                // LL | |              foo(tx.clone());
+                // LL | |          }).await;
+                //    | |          - ^^^^^^ await occurs here, with value maybe used later
+                //    | |__________|
+                //    |            has type `closure` which is not `Send`
+                // note: value is later dropped here
+                // LL | |          }).await;
+                //    | |                  ^
+                //
+                span.push_span_label(
+                    yield_span,
+                    format!("{} occurs here, with {} maybe used later", await_or_yield, snippet),
+                );
+                span.push_span_label(
+                    interior_span,
+                    format!("has type `{}` which {}", target_ty, trait_explanation),
+                );
+                // If available, use the scope span to annotate the drop location.
+                let mut scope_note = None;
+                if let Some(scope_span) = scope_span {
+                    let scope_span = source_map.end_point(scope_span);
+
+                    let msg = format!("{} is later dropped here", snippet);
+                    if source_map.is_multiline(yield_span.between(scope_span)) {
+                        span.push_span_label(scope_span, msg);
                     } else {
-                        span.push_span_label(
-                            yield_span,
-                            format!(
-                                "{} occurs here, with {} maybe used later",
-                                await_or_yield, snippet
-                            ),
-                        );
-                        span.push_span_label(
-                            interior_span,
-                            format!("has type `{}` which {}", target_ty, trait_explanation),
-                        );
-                        err.span_note(
-                            span,
-                            &format!(
-                                "{} {} as this value is used across {}",
-                                future_or_generator, trait_explanation, an_await_or_yield
-                            ),
-                        );
+                        scope_note = Some((scope_span, msg));
                     }
                 }
-            };
+                err.span_note(
+                    span,
+                    &format!(
+                        "{} {} as this value is used across {}",
+                        future_or_generator, trait_explanation, an_await_or_yield
+                    ),
+                );
+                if let Some((span, msg)) = scope_note {
+                    err.span_note(span, &msg);
+                }
+            }
+        };
         match interior_or_upvar_span {
             GeneratorInteriorOrUpvar::Interior(interior_span) => {
                 if let Some((scope_span, yield_span, expr, from_awaited_ty)) = interior_extra_info {
@@ -1935,6 +1931,9 @@ fn note_obligation_cause_code<T>(
             | ObligationCauseCode::ReturnType
             | ObligationCauseCode::ReturnValue(_)
             | ObligationCauseCode::BlockTailExpression(_)
+            | ObligationCauseCode::AwaitableExpr(_)
+            | ObligationCauseCode::ForLoopIterator
+            | ObligationCauseCode::QuestionMark
             | ObligationCauseCode::LetElse => {}
             ObligationCauseCode::SliceOrArrayElem => {
                 err.note("slice and array elements must have `Sized` type");
@@ -2186,6 +2185,16 @@ fn note_obligation_cause_code<T>(
                             seen_requirements,
                         )
                     });
+                } else {
+                    ensure_sufficient_stack(|| {
+                        self.note_obligation_cause_code(
+                            err,
+                            &parent_predicate,
+                            &cause_code.peel_derives(),
+                            obligated_types,
+                            seen_requirements,
+                        )
+                    });
                 }
             }
             ObligationCauseCode::ImplDerivedObligation(ref data) => {