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;
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>,
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 {
}
}
+ 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(
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 {
| 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");
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) => {