2 EvaluationResult, Obligation, ObligationCause, ObligationCauseCode, PredicateObligation,
5 use crate::infer::InferCtxt;
6 use crate::traits::error_reporting::suggest_constraining_type_param;
8 use rustc::ty::TypeckTables;
9 use rustc::ty::{self, AdtKind, DefIdTree, ToPredicate, Ty, TyCtxt, TypeFoldable, WithConstness};
10 use rustc_errors::{error_code, struct_span_err, Applicability, DiagnosticBuilder, Style};
12 use rustc_hir::def::DefKind;
13 use rustc_hir::def_id::DefId;
14 use rustc_hir::intravisit::Visitor;
16 use rustc_span::symbol::{kw, sym};
17 use rustc_span::{MultiSpan, Span, DUMMY_SP};
20 use super::InferCtxtPrivExt;
21 use crate::traits::query::evaluate_obligation::InferCtxtExt as _;
23 crate trait InferCtxtExt<'tcx> {
24 fn suggest_restricting_param_bound(
26 err: &mut DiagnosticBuilder<'_>,
27 trait_ref: &ty::PolyTraitRef<'_>,
31 fn suggest_borrow_on_unsized_slice(
33 code: &ObligationCauseCode<'tcx>,
34 err: &mut DiagnosticBuilder<'tcx>,
40 err: &mut DiagnosticBuilder<'_>,
46 obligation: &PredicateObligation<'tcx>,
47 err: &mut DiagnosticBuilder<'_>,
48 trait_ref: &ty::Binder<ty::TraitRef<'tcx>>,
52 fn suggest_add_reference_to_arg(
54 obligation: &PredicateObligation<'tcx>,
55 err: &mut DiagnosticBuilder<'tcx>,
56 trait_ref: &ty::Binder<ty::TraitRef<'tcx>>,
58 has_custom_message: bool,
61 fn suggest_remove_reference(
63 obligation: &PredicateObligation<'tcx>,
64 err: &mut DiagnosticBuilder<'tcx>,
65 trait_ref: &ty::Binder<ty::TraitRef<'tcx>>,
68 fn suggest_change_mut(
70 obligation: &PredicateObligation<'tcx>,
71 err: &mut DiagnosticBuilder<'tcx>,
72 trait_ref: &ty::Binder<ty::TraitRef<'tcx>>,
76 fn suggest_semicolon_removal(
78 obligation: &PredicateObligation<'tcx>,
79 err: &mut DiagnosticBuilder<'tcx>,
81 trait_ref: &ty::Binder<ty::TraitRef<'tcx>>,
84 fn suggest_impl_trait(
86 err: &mut DiagnosticBuilder<'tcx>,
88 obligation: &PredicateObligation<'tcx>,
89 trait_ref: &ty::Binder<ty::TraitRef<'tcx>>,
92 fn point_at_returns_when_relevant(
94 err: &mut DiagnosticBuilder<'tcx>,
95 obligation: &PredicateObligation<'tcx>,
98 fn report_closure_arg_mismatch(
101 found_span: Option<Span>,
102 expected_ref: ty::PolyTraitRef<'tcx>,
103 found: ty::PolyTraitRef<'tcx>,
104 ) -> DiagnosticBuilder<'tcx>;
106 fn suggest_fully_qualified_path(
108 err: &mut DiagnosticBuilder<'_>,
114 fn maybe_note_obligation_cause_for_async_await(
116 err: &mut DiagnosticBuilder<'_>,
117 obligation: &PredicateObligation<'tcx>,
120 fn note_obligation_cause_for_async_await(
122 err: &mut DiagnosticBuilder<'_>,
124 scope_span: &Option<Span>,
125 expr: Option<hir::HirId>,
127 first_generator: DefId,
128 last_generator: Option<DefId>,
129 trait_ref: ty::TraitRef<'_>,
131 tables: &ty::TypeckTables<'_>,
132 obligation: &PredicateObligation<'tcx>,
133 next_code: Option<&ObligationCauseCode<'tcx>>,
136 fn note_obligation_cause_code<T>(
138 err: &mut DiagnosticBuilder<'_>,
140 cause_code: &ObligationCauseCode<'tcx>,
141 obligated_types: &mut Vec<&ty::TyS<'tcx>>,
145 fn suggest_new_overflow_limit(&self, err: &mut DiagnosticBuilder<'_>);
148 impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
149 fn suggest_restricting_param_bound(
151 mut err: &mut DiagnosticBuilder<'_>,
152 trait_ref: &ty::PolyTraitRef<'_>,
155 let self_ty = trait_ref.self_ty();
156 let (param_ty, projection) = match &self_ty.kind {
157 ty::Param(_) => (true, None),
158 ty::Projection(projection) => (false, Some(projection)),
162 let suggest_restriction =
163 |generics: &hir::Generics<'_>, msg, err: &mut DiagnosticBuilder<'_>| {
164 let span = generics.where_clause.span_for_predicates_or_empty_place();
165 if !span.from_expansion() && span.desugaring_kind().is_none() {
167 generics.where_clause.span_for_predicates_or_empty_place().shrink_to_hi(),
168 &format!("consider further restricting {}", msg),
171 if !generics.where_clause.predicates.is_empty() {
176 trait_ref.without_const().to_predicate(),
178 Applicability::MachineApplicable,
183 // FIXME: Add check for trait bound that is already present, particularly `?Sized` so we
184 // don't suggest `T: Sized + ?Sized`.
185 let mut hir_id = body_id;
186 while let Some(node) = self.tcx.hir().find(hir_id) {
188 hir::Node::TraitItem(hir::TraitItem {
190 kind: hir::TraitItemKind::Fn(..),
192 }) if param_ty && self_ty == self.tcx.types.self_param => {
193 // Restricting `Self` for a single method.
194 suggest_restriction(&generics, "`Self`", err);
198 hir::Node::Item(hir::Item { kind: hir::ItemKind::Fn(_, generics, _), .. })
199 | hir::Node::TraitItem(hir::TraitItem {
201 kind: hir::TraitItemKind::Fn(..),
204 | hir::Node::ImplItem(hir::ImplItem {
206 kind: hir::ImplItemKind::Method(..),
209 | hir::Node::Item(hir::Item {
210 kind: hir::ItemKind::Trait(_, _, generics, _, _),
213 | hir::Node::Item(hir::Item {
214 kind: hir::ItemKind::Impl { generics, .. }, ..
215 }) if projection.is_some() => {
216 // Missing associated type bound.
217 suggest_restriction(&generics, "the associated type", err);
221 hir::Node::Item(hir::Item {
222 kind: hir::ItemKind::Struct(_, generics),
226 | hir::Node::Item(hir::Item {
227 kind: hir::ItemKind::Enum(_, generics), span, ..
229 | hir::Node::Item(hir::Item {
230 kind: hir::ItemKind::Union(_, generics),
234 | hir::Node::Item(hir::Item {
235 kind: hir::ItemKind::Trait(_, _, generics, ..),
239 | hir::Node::Item(hir::Item {
240 kind: hir::ItemKind::Impl { generics, .. },
244 | hir::Node::Item(hir::Item {
245 kind: hir::ItemKind::Fn(_, generics, _),
249 | hir::Node::Item(hir::Item {
250 kind: hir::ItemKind::TyAlias(_, generics),
254 | hir::Node::Item(hir::Item {
255 kind: hir::ItemKind::TraitAlias(generics, _),
259 | hir::Node::Item(hir::Item {
260 kind: hir::ItemKind::OpaqueTy(hir::OpaqueTy { generics, .. }),
264 | hir::Node::TraitItem(hir::TraitItem { generics, span, .. })
265 | hir::Node::ImplItem(hir::ImplItem { generics, span, .. })
268 // Missing generic type parameter bound.
269 let param_name = self_ty.to_string();
270 let constraint = trait_ref.print_only_trait_path().to_string();
271 if suggest_constraining_type_param(
277 self.tcx.sess.source_map(),
279 Some(trait_ref.def_id()),
285 hir::Node::Crate(..) => return,
290 hir_id = self.tcx.hir().get_parent_item(hir_id);
294 /// When encountering an assignment of an unsized trait, like `let x = ""[..];`, provide a
295 /// suggestion to borrow the initializer in order to use have a slice instead.
296 fn suggest_borrow_on_unsized_slice(
298 code: &ObligationCauseCode<'tcx>,
299 err: &mut DiagnosticBuilder<'tcx>,
301 if let &ObligationCauseCode::VariableType(hir_id) = code {
302 let parent_node = self.tcx.hir().get_parent_node(hir_id);
303 if let Some(Node::Local(ref local)) = self.tcx.hir().find(parent_node) {
304 if let Some(ref expr) = local.init {
305 if let hir::ExprKind::Index(_, _) = expr.kind {
306 if let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(expr.span) {
309 "consider borrowing here",
310 format!("&{}", snippet),
311 Applicability::MachineApplicable,
320 /// Given a closure's `DefId`, return the given name of the closure.
322 /// This doesn't account for reassignments, but it's only used for suggestions.
326 err: &mut DiagnosticBuilder<'_>,
328 ) -> Option<String> {
330 |err: &mut DiagnosticBuilder<'_>, kind: &hir::PatKind<'_>| -> Option<String> {
331 // Get the local name of this closure. This can be inaccurate because
332 // of the possibility of reassignment, but this should be good enough.
334 hir::PatKind::Binding(hir::BindingAnnotation::Unannotated, _, name, None) => {
335 Some(format!("{}", name))
344 let hir = self.tcx.hir();
345 let hir_id = hir.as_local_hir_id(def_id)?;
346 let parent_node = hir.get_parent_node(hir_id);
347 match hir.find(parent_node) {
348 Some(hir::Node::Stmt(hir::Stmt { kind: hir::StmtKind::Local(local), .. })) => {
349 get_name(err, &local.pat.kind)
351 // Different to previous arm because one is `&hir::Local` and the other
352 // is `P<hir::Local>`.
353 Some(hir::Node::Local(local)) => get_name(err, &local.pat.kind),
358 /// We tried to apply the bound to an `fn` or closure. Check whether calling it would
359 /// evaluate to a type that *would* satisfy the trait binding. If it would, suggest calling
360 /// it: `bar(foo)` → `bar(foo())`. This case is *very* likely to be hit if `foo` is `async`.
363 obligation: &PredicateObligation<'tcx>,
364 err: &mut DiagnosticBuilder<'_>,
365 trait_ref: &ty::Binder<ty::TraitRef<'tcx>>,
368 let self_ty = trait_ref.self_ty();
369 let (def_id, output_ty, callable) = match self_ty.kind {
370 ty::Closure(def_id, substs) => {
371 (def_id, self.closure_sig(def_id, substs).output(), "closure")
373 ty::FnDef(def_id, _) => (def_id, self_ty.fn_sig(self.tcx).output(), "function"),
376 let msg = format!("use parentheses to call the {}", callable);
378 let obligation = self.mk_obligation_for_def_id(
380 output_ty.skip_binder(),
381 obligation.cause.clone(),
382 obligation.param_env,
385 match self.evaluate_obligation(&obligation) {
386 Ok(EvaluationResult::EvaluatedToOk)
387 | Ok(EvaluationResult::EvaluatedToOkModuloRegions)
388 | Ok(EvaluationResult::EvaluatedToAmbig) => {}
391 let hir = self.tcx.hir();
392 // Get the name of the callable and the arguments to be used in the suggestion.
393 let snippet = match hir.get_if_local(def_id) {
394 Some(hir::Node::Expr(hir::Expr {
395 kind: hir::ExprKind::Closure(_, decl, _, span, ..),
398 err.span_label(*span, "consider calling this closure");
399 let name = match self.get_closure_name(def_id, err, &msg) {
403 let args = decl.inputs.iter().map(|_| "_").collect::<Vec<_>>().join(", ");
404 format!("{}({})", name, args)
406 Some(hir::Node::Item(hir::Item {
408 kind: hir::ItemKind::Fn(.., body_id),
411 err.span_label(ident.span, "consider calling this function");
412 let body = hir.body(*body_id);
416 .map(|arg| match &arg.pat.kind {
417 hir::PatKind::Binding(_, _, ident, None)
418 // FIXME: provide a better suggestion when encountering `SelfLower`, it
419 // should suggest a method call.
420 if ident.name != kw::SelfLower => ident.to_string(),
421 _ => "_".to_string(),
425 format!("{}({})", ident, args)
430 // When the obligation error has been ensured to have been caused by
431 // an argument, the `obligation.cause.span` points at the expression
432 // of the argument, so we can provide a suggestion. This is signaled
433 // by `points_at_arg`. Otherwise, we give a more general note.
435 obligation.cause.span,
438 Applicability::HasPlaceholders,
441 err.help(&format!("{}: `{}`", msg, snippet));
445 fn suggest_add_reference_to_arg(
447 obligation: &PredicateObligation<'tcx>,
448 err: &mut DiagnosticBuilder<'tcx>,
449 trait_ref: &ty::Binder<ty::TraitRef<'tcx>>,
451 has_custom_message: bool,
457 let span = obligation.cause.span;
458 let param_env = obligation.param_env;
459 let trait_ref = trait_ref.skip_binder();
461 if let ObligationCauseCode::ImplDerivedObligation(obligation) = &obligation.cause.code {
462 // Try to apply the original trait binding obligation by borrowing.
463 let self_ty = trait_ref.self_ty();
464 let found = self_ty.to_string();
465 let new_self_ty = self.tcx.mk_imm_ref(self.tcx.lifetimes.re_static, self_ty);
466 let substs = self.tcx.mk_substs_trait(new_self_ty, &[]);
467 let new_trait_ref = ty::TraitRef::new(obligation.parent_trait_ref.def_id(), substs);
468 let new_obligation = Obligation::new(
469 ObligationCause::dummy(),
471 new_trait_ref.without_const().to_predicate(),
473 if self.predicate_must_hold_modulo_regions(&new_obligation) {
474 if let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(span) {
475 // We have a very specific type of error, where just borrowing this argument
476 // might solve the problem. In cases like this, the important part is the
477 // original type obligation, not the last one that failed, which is arbitrary.
478 // Because of this, we modify the error to refer to the original obligation and
479 // return early in the caller.
481 "the trait bound `{}: {}` is not satisfied",
483 obligation.parent_trait_ref.skip_binder().print_only_trait_path(),
485 if has_custom_message {
488 err.message = vec![(msg, Style::NoStyle)];
490 if snippet.starts_with('&') {
491 // This is already a literal borrow and the obligation is failing
492 // somewhere else in the obligation chain. Do not suggest non-sense.
498 "expected an implementor of trait `{}`",
499 obligation.parent_trait_ref.skip_binder().print_only_trait_path(),
504 "consider borrowing here",
505 format!("&{}", snippet),
506 Applicability::MaybeIncorrect,
515 /// Whenever references are used by mistake, like `for (i, e) in &vec.iter().enumerate()`,
516 /// suggest removing these references until we reach a type that implements the trait.
517 fn suggest_remove_reference(
519 obligation: &PredicateObligation<'tcx>,
520 err: &mut DiagnosticBuilder<'tcx>,
521 trait_ref: &ty::Binder<ty::TraitRef<'tcx>>,
523 let trait_ref = trait_ref.skip_binder();
524 let span = obligation.cause.span;
526 if let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(span) {
528 snippet.chars().filter(|c| !c.is_whitespace()).take_while(|c| *c == '&').count();
529 if let Some('\'') = snippet.chars().filter(|c| !c.is_whitespace()).nth(refs_number) {
530 // Do not suggest removal of borrow from type arguments.
534 let mut trait_type = trait_ref.self_ty();
536 for refs_remaining in 0..refs_number {
537 if let ty::Ref(_, t_type, _) = trait_type.kind {
540 let new_obligation = self.mk_obligation_for_def_id(
543 ObligationCause::dummy(),
544 obligation.param_env,
547 if self.predicate_may_hold(&new_obligation) {
552 .span_take_while(span, |c| c.is_whitespace() || *c == '&');
554 let remove_refs = refs_remaining + 1;
556 let msg = if remove_refs == 1 {
557 "consider removing the leading `&`-reference".to_string()
559 format!("consider removing {} leading `&`-references", remove_refs)
562 err.span_suggestion_short(
566 Applicability::MachineApplicable,
577 /// Check if the trait bound is implemented for a different mutability and note it in the
579 fn suggest_change_mut(
581 obligation: &PredicateObligation<'tcx>,
582 err: &mut DiagnosticBuilder<'tcx>,
583 trait_ref: &ty::Binder<ty::TraitRef<'tcx>>,
586 let span = obligation.cause.span;
587 if let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(span) {
589 snippet.chars().filter(|c| !c.is_whitespace()).take_while(|c| *c == '&').count();
590 if let Some('\'') = snippet.chars().filter(|c| !c.is_whitespace()).nth(refs_number) {
591 // Do not suggest removal of borrow from type arguments.
594 let trait_ref = self.resolve_vars_if_possible(trait_ref);
595 if trait_ref.has_infer_types_or_consts() {
596 // Do not ICE while trying to find if a reborrow would succeed on a trait with
597 // unresolved bindings.
601 if let ty::Ref(region, t_type, mutability) = trait_ref.skip_binder().self_ty().kind {
602 let trait_type = match mutability {
603 hir::Mutability::Mut => self.tcx.mk_imm_ref(region, t_type),
604 hir::Mutability::Not => self.tcx.mk_mut_ref(region, t_type),
607 let new_obligation = self.mk_obligation_for_def_id(
608 trait_ref.skip_binder().def_id,
610 ObligationCause::dummy(),
611 obligation.param_env,
614 if self.evaluate_obligation_no_overflow(&new_obligation).must_apply_modulo_regions()
620 .span_take_while(span, |c| c.is_whitespace() || *c == '&');
621 if points_at_arg && mutability == hir::Mutability::Not && refs_number > 0 {
624 "consider changing this borrow's mutability",
626 Applicability::MachineApplicable,
630 "`{}` is implemented for `{:?}`, but not for `{:?}`",
631 trait_ref.print_only_trait_path(),
633 trait_ref.skip_binder().self_ty(),
641 fn suggest_semicolon_removal(
643 obligation: &PredicateObligation<'tcx>,
644 err: &mut DiagnosticBuilder<'tcx>,
646 trait_ref: &ty::Binder<ty::TraitRef<'tcx>>,
648 let hir = self.tcx.hir();
649 let parent_node = hir.get_parent_node(obligation.cause.body_id);
650 let node = hir.find(parent_node);
651 if let Some(hir::Node::Item(hir::Item {
652 kind: hir::ItemKind::Fn(sig, _, body_id), ..
655 let body = hir.body(*body_id);
656 if let hir::ExprKind::Block(blk, _) = &body.value.kind {
657 if sig.decl.output.span().overlaps(span)
658 && blk.expr.is_none()
659 && "()" == &trait_ref.self_ty().to_string()
661 // FIXME(estebank): When encountering a method with a trait
662 // bound not satisfied in the return type with a body that has
663 // no return, suggest removal of semicolon on last statement.
664 // Once that is added, close #54771.
665 if let Some(ref stmt) = blk.stmts.last() {
666 let sp = self.tcx.sess.source_map().end_point(stmt.span);
667 err.span_label(sp, "consider removing this semicolon");
674 /// If all conditions are met to identify a returned `dyn Trait`, suggest using `impl Trait` if
675 /// applicable and signal that the error has been expanded appropriately and needs to be
677 fn suggest_impl_trait(
679 err: &mut DiagnosticBuilder<'tcx>,
681 obligation: &PredicateObligation<'tcx>,
682 trait_ref: &ty::Binder<ty::TraitRef<'tcx>>,
684 match obligation.cause.code.peel_derives() {
685 // Only suggest `impl Trait` if the return type is unsized because it is `dyn Trait`.
686 ObligationCauseCode::SizedReturnType => {}
690 let hir = self.tcx.hir();
691 let parent_node = hir.get_parent_node(obligation.cause.body_id);
692 let node = hir.find(parent_node);
693 let (sig, body_id) = if let Some(hir::Node::Item(hir::Item {
694 kind: hir::ItemKind::Fn(sig, _, body_id),
702 let body = hir.body(*body_id);
703 let trait_ref = self.resolve_vars_if_possible(trait_ref);
704 let ty = trait_ref.skip_binder().self_ty();
705 let is_object_safe = match ty.kind {
706 ty::Dynamic(predicates, _) => {
707 // If the `dyn Trait` is not object safe, do not suggest `Box<dyn Trait>`.
710 .map_or(true, |def_id| self.tcx.object_safety_violations(def_id).is_empty())
712 // We only want to suggest `impl Trait` to `dyn Trait`s.
713 // For example, `fn foo() -> str` needs to be filtered out.
717 let ret_ty = if let hir::FnRetTy::Return(ret_ty) = sig.decl.output {
723 // Use `TypeVisitor` instead of the output type directly to find the span of `ty` for
724 // cases like `fn foo() -> (dyn Trait, i32) {}`.
725 // Recursively look for `TraitObject` types and if there's only one, use that span to
726 // suggest `impl Trait`.
728 // Visit to make sure there's a single `return` type to suggest `impl Trait`,
729 // otherwise suggest using `Box<dyn Trait>` or an enum.
730 let mut visitor = ReturnsVisitor::default();
731 visitor.visit_body(&body);
733 let tables = self.in_progress_tables.map(|t| t.borrow()).unwrap();
735 let mut ret_types = visitor
738 .filter_map(|expr| tables.node_type_opt(expr.hir_id))
739 .map(|ty| self.resolve_vars_if_possible(&ty));
740 let (last_ty, all_returns_have_same_type) = ret_types.clone().fold(
742 |(last_ty, mut same): (std::option::Option<Ty<'_>>, bool), ty| {
743 let ty = self.resolve_vars_if_possible(&ty);
744 same &= last_ty.map_or(true, |last_ty| last_ty == ty) && ty.kind != ty::Error;
748 let all_returns_conform_to_trait =
749 if let Some(ty_ret_ty) = tables.node_type_opt(ret_ty.hir_id) {
750 match ty_ret_ty.kind {
751 ty::Dynamic(predicates, _) => {
752 let cause = ObligationCause::misc(ret_ty.span, ret_ty.hir_id);
753 let param_env = ty::ParamEnv::empty();
754 ret_types.all(|returned_ty| {
755 predicates.iter().all(|predicate| {
756 let pred = predicate.with_self_ty(self.tcx, returned_ty);
757 let obl = Obligation::new(cause.clone(), param_env, pred);
758 self.predicate_may_hold(&obl)
768 let (snippet, last_ty) =
769 if let (true, hir::TyKind::TraitObject(..), Ok(snippet), true, Some(last_ty)) = (
770 // Verify that we're dealing with a return `dyn Trait`
771 ret_ty.span.overlaps(span),
773 self.tcx.sess.source_map().span_to_snippet(ret_ty.span),
774 // If any of the return types does not conform to the trait, then we can't
775 // suggest `impl Trait` nor trait objects, it is a type mismatch error.
776 all_returns_conform_to_trait,
783 err.code(error_code!(E0746));
784 err.set_primary_message("return type cannot have an unboxed trait object");
785 err.children.clear();
786 let impl_trait_msg = "for information on `impl Trait`, see \
787 <https://doc.rust-lang.org/book/ch10-02-traits.html\
788 #returning-types-that-implement-traits>";
789 let trait_obj_msg = "for information on trait objects, see \
790 <https://doc.rust-lang.org/book/ch17-02-trait-objects.html\
791 #using-trait-objects-that-allow-for-values-of-different-types>";
792 let has_dyn = snippet.split_whitespace().next().map_or(false, |s| s == "dyn");
793 let trait_obj = if has_dyn { &snippet[4..] } else { &snippet[..] };
794 if all_returns_have_same_type {
795 // Suggest `-> impl Trait`.
799 "return `impl {1}` instead, as all return paths are of type `{}`, \
800 which implements `{1}`",
803 format!("impl {}", trait_obj),
804 Applicability::MachineApplicable,
806 err.note(impl_trait_msg);
809 // Suggest `-> Box<dyn Trait>` and `Box::new(returned_value)`.
810 // Get all the return values and collect their span and suggestion.
811 let mut suggestions = visitor
819 self.tcx.sess.source_map().span_to_snippet(expr.span).unwrap()
823 .collect::<Vec<_>>();
824 // Add the suggestion for the return type.
825 suggestions.push((ret_ty.span, format!("Box<dyn {}>", trait_obj)));
826 err.multipart_suggestion(
827 "return a boxed trait object instead",
829 Applicability::MaybeIncorrect,
832 // This is currently not possible to trigger because E0038 takes precedence, but
833 // leave it in for completeness in case anything changes in an earlier stage.
835 "if trait `{}` was object safe, you could return a trait object",
839 err.note(trait_obj_msg);
841 "if all the returned values were of the same type you could use \
842 `impl {}` as the return type",
845 err.note(impl_trait_msg);
846 err.note("you can create a new `enum` with a variant for each returned type");
851 fn point_at_returns_when_relevant(
853 err: &mut DiagnosticBuilder<'tcx>,
854 obligation: &PredicateObligation<'tcx>,
856 match obligation.cause.code.peel_derives() {
857 ObligationCauseCode::SizedReturnType => {}
861 let hir = self.tcx.hir();
862 let parent_node = hir.get_parent_node(obligation.cause.body_id);
863 let node = hir.find(parent_node);
864 if let Some(hir::Node::Item(hir::Item { kind: hir::ItemKind::Fn(_, _, body_id), .. })) =
867 let body = hir.body(*body_id);
868 // Point at all the `return`s in the function as they have failed trait bounds.
869 let mut visitor = ReturnsVisitor::default();
870 visitor.visit_body(&body);
871 let tables = self.in_progress_tables.map(|t| t.borrow()).unwrap();
872 for expr in &visitor.returns {
873 if let Some(returned_ty) = tables.node_type_opt(expr.hir_id) {
874 let ty = self.resolve_vars_if_possible(&returned_ty);
875 err.span_label(expr.span, &format!("this returned value is of type `{}`", ty));
881 fn report_closure_arg_mismatch(
884 found_span: Option<Span>,
885 expected_ref: ty::PolyTraitRef<'tcx>,
886 found: ty::PolyTraitRef<'tcx>,
887 ) -> DiagnosticBuilder<'tcx> {
888 crate fn build_fn_sig_string<'tcx>(
890 trait_ref: &ty::TraitRef<'tcx>,
892 let inputs = trait_ref.substs.type_at(1);
893 let sig = if let ty::Tuple(inputs) = inputs.kind {
895 inputs.iter().map(|k| k.expect_ty()),
896 tcx.mk_ty_infer(ty::TyVar(ty::TyVid { index: 0 })),
898 hir::Unsafety::Normal,
899 ::rustc_target::spec::abi::Abi::Rust,
903 ::std::iter::once(inputs),
904 tcx.mk_ty_infer(ty::TyVar(ty::TyVid { index: 0 })),
906 hir::Unsafety::Normal,
907 ::rustc_target::spec::abi::Abi::Rust,
910 ty::Binder::bind(sig).to_string()
913 let argument_is_closure = expected_ref.skip_binder().substs.type_at(0).is_closure();
914 let mut err = struct_span_err!(
918 "type mismatch in {} arguments",
919 if argument_is_closure { "closure" } else { "function" }
922 let found_str = format!(
923 "expected signature of `{}`",
924 build_fn_sig_string(self.tcx, found.skip_binder())
926 err.span_label(span, found_str);
928 let found_span = found_span.unwrap_or(span);
929 let expected_str = format!(
930 "found signature of `{}`",
931 build_fn_sig_string(self.tcx, expected_ref.skip_binder())
933 err.span_label(found_span, expected_str);
938 fn suggest_fully_qualified_path(
940 err: &mut DiagnosticBuilder<'_>,
945 if let Some(assoc_item) = self.tcx.opt_associated_item(def_id) {
946 if let ty::AssocKind::Const | ty::AssocKind::Type = assoc_item.kind {
948 "{}s cannot be accessed directly on a `trait`, they can only be \
949 accessed through a specific `impl`",
950 assoc_item.kind.suggestion_descr(),
954 "use the fully qualified path to an implementation",
955 format!("<Type as {}>::{}", self.tcx.def_path_str(trait_ref), assoc_item.ident),
956 Applicability::HasPlaceholders,
962 /// Adds an async-await specific note to the diagnostic when the future does not implement
963 /// an auto trait because of a captured type.
965 /// ```ignore (diagnostic)
966 /// note: future does not implement `Qux` as this value is used across an await
967 /// --> $DIR/issue-64130-3-other.rs:17:5
969 /// LL | let x = Foo;
970 /// | - has type `Foo`
971 /// LL | baz().await;
972 /// | ^^^^^^^^^^^ await occurs here, with `x` maybe used later
974 /// | - `x` is later dropped here
977 /// When the diagnostic does not implement `Send` or `Sync` specifically, then the diagnostic
978 /// is "replaced" with a different message and a more specific error.
980 /// ```ignore (diagnostic)
981 /// error: future cannot be sent between threads safely
982 /// --> $DIR/issue-64130-2-send.rs:21:5
984 /// LL | fn is_send<T: Send>(t: T) { }
985 /// | ------- ---- required by this bound in `is_send`
987 /// LL | is_send(bar());
988 /// | ^^^^^^^ future returned by `bar` is not send
990 /// = help: within `impl std::future::Future`, the trait `std::marker::Send` is not
991 /// implemented for `Foo`
992 /// note: future is not send as this value is used across an await
993 /// --> $DIR/issue-64130-2-send.rs:15:5
995 /// LL | let x = Foo;
996 /// | - has type `Foo`
997 /// LL | baz().await;
998 /// | ^^^^^^^^^^^ await occurs here, with `x` maybe used later
1000 /// | - `x` is later dropped here
1003 /// Returns `true` if an async-await specific note was added to the diagnostic.
1004 fn maybe_note_obligation_cause_for_async_await(
1006 err: &mut DiagnosticBuilder<'_>,
1007 obligation: &PredicateObligation<'tcx>,
1010 "maybe_note_obligation_cause_for_async_await: obligation.predicate={:?} \
1011 obligation.cause.span={:?}",
1012 obligation.predicate, obligation.cause.span
1014 let source_map = self.tcx.sess.source_map();
1016 // Attempt to detect an async-await error by looking at the obligation causes, looking
1017 // for a generator to be present.
1019 // When a future does not implement a trait because of a captured type in one of the
1020 // generators somewhere in the call stack, then the result is a chain of obligations.
1022 // Given a `async fn` A that calls a `async fn` B which captures a non-send type and that
1023 // future is passed as an argument to a function C which requires a `Send` type, then the
1024 // chain looks something like this:
1026 // - `BuiltinDerivedObligation` with a generator witness (B)
1027 // - `BuiltinDerivedObligation` with a generator (B)
1028 // - `BuiltinDerivedObligation` with `std::future::GenFuture` (B)
1029 // - `BuiltinDerivedObligation` with `impl std::future::Future` (B)
1030 // - `BuiltinDerivedObligation` with `impl std::future::Future` (B)
1031 // - `BuiltinDerivedObligation` with a generator witness (A)
1032 // - `BuiltinDerivedObligation` with a generator (A)
1033 // - `BuiltinDerivedObligation` with `std::future::GenFuture` (A)
1034 // - `BuiltinDerivedObligation` with `impl std::future::Future` (A)
1035 // - `BuiltinDerivedObligation` with `impl std::future::Future` (A)
1036 // - `BindingObligation` with `impl_send (Send requirement)
1038 // The first obligation in the chain is the most useful and has the generator that captured
1039 // the type. The last generator has information about where the bound was introduced. At
1040 // least one generator should be present for this diagnostic to be modified.
1041 let (mut trait_ref, mut target_ty) = match obligation.predicate {
1042 ty::Predicate::Trait(p, _) => {
1043 (Some(p.skip_binder().trait_ref), Some(p.skip_binder().self_ty()))
1047 let mut generator = None;
1048 let mut last_generator = None;
1049 let mut next_code = Some(&obligation.cause.code);
1050 while let Some(code) = next_code {
1051 debug!("maybe_note_obligation_cause_for_async_await: code={:?}", code);
1053 ObligationCauseCode::BuiltinDerivedObligation(derived_obligation)
1054 | ObligationCauseCode::ImplDerivedObligation(derived_obligation) => {
1055 let ty = derived_obligation.parent_trait_ref.self_ty();
1057 "maybe_note_obligation_cause_for_async_await: \
1058 parent_trait_ref={:?} self_ty.kind={:?}",
1059 derived_obligation.parent_trait_ref, ty.kind
1063 ty::Generator(did, ..) => {
1064 generator = generator.or(Some(did));
1065 last_generator = Some(did);
1067 ty::GeneratorWitness(..) => {}
1068 _ if generator.is_none() => {
1069 trait_ref = Some(*derived_obligation.parent_trait_ref.skip_binder());
1070 target_ty = Some(ty);
1075 next_code = Some(derived_obligation.parent_code.as_ref());
1081 // Only continue if a generator was found.
1083 "maybe_note_obligation_cause_for_async_await: generator={:?} trait_ref={:?} \
1085 generator, trait_ref, target_ty
1087 let (generator_did, trait_ref, target_ty) = match (generator, trait_ref, target_ty) {
1088 (Some(generator_did), Some(trait_ref), Some(target_ty)) => {
1089 (generator_did, trait_ref, target_ty)
1094 let span = self.tcx.def_span(generator_did);
1096 // Do not ICE on closure typeck (#66868).
1097 if self.tcx.hir().as_local_hir_id(generator_did).is_none() {
1101 // Get the tables from the infcx if the generator is the function we are
1102 // currently type-checking; otherwise, get them by performing a query.
1103 // This is needed to avoid cycles.
1104 let in_progress_tables = self.in_progress_tables.map(|t| t.borrow());
1105 let generator_did_root = self.tcx.closure_base_def_id(generator_did);
1107 "maybe_note_obligation_cause_for_async_await: generator_did={:?} \
1108 generator_did_root={:?} in_progress_tables.local_id_root={:?} span={:?}",
1111 in_progress_tables.as_ref().map(|t| t.local_id_root),
1115 let tables: &TypeckTables<'tcx> = match &in_progress_tables {
1116 Some(t) if t.local_id_root == Some(generator_did_root) => t,
1118 query_tables = self.tcx.typeck_tables_of(generator_did);
1123 // Look for a type inside the generator interior that matches the target type to get
1125 let target_ty_erased = self.tcx.erase_regions(&target_ty);
1126 let target_span = tables
1127 .generator_interior_types
1129 .find(|ty::GeneratorInteriorTypeCause { ty, .. }| {
1130 // Careful: the regions for types that appear in the
1131 // generator interior are not generally known, so we
1132 // want to erase them when comparing (and anyway,
1133 // `Send` and other bounds are generally unaffected by
1134 // the choice of region). When erasing regions, we
1135 // also have to erase late-bound regions. This is
1136 // because the types that appear in the generator
1137 // interior generally contain "bound regions" to
1138 // represent regions that are part of the suspended
1139 // generator frame. Bound regions are preserved by
1140 // `erase_regions` and so we must also call
1141 // `erase_late_bound_regions`.
1142 let ty_erased = self.tcx.erase_late_bound_regions(&ty::Binder::bind(*ty));
1143 let ty_erased = self.tcx.erase_regions(&ty_erased);
1144 let eq = ty::TyS::same_type(ty_erased, target_ty_erased);
1146 "maybe_note_obligation_cause_for_async_await: ty_erased={:?} \
1147 target_ty_erased={:?} eq={:?}",
1148 ty_erased, target_ty_erased, eq
1152 .map(|ty::GeneratorInteriorTypeCause { span, scope_span, expr, .. }| {
1153 (span, source_map.span_to_snippet(*span), scope_span, expr)
1157 "maybe_note_obligation_cause_for_async_await: target_ty={:?} \
1158 generator_interior_types={:?} target_span={:?}",
1159 target_ty, tables.generator_interior_types, target_span
1161 if let Some((target_span, Ok(snippet), scope_span, expr)) = target_span {
1162 self.note_obligation_cause_for_async_await(
1182 /// Unconditionally adds the diagnostic note described in
1183 /// `maybe_note_obligation_cause_for_async_await`'s documentation comment.
1184 fn note_obligation_cause_for_async_await(
1186 err: &mut DiagnosticBuilder<'_>,
1188 scope_span: &Option<Span>,
1189 expr: Option<hir::HirId>,
1191 first_generator: DefId,
1192 last_generator: Option<DefId>,
1193 trait_ref: ty::TraitRef<'_>,
1194 target_ty: Ty<'tcx>,
1195 tables: &ty::TypeckTables<'_>,
1196 obligation: &PredicateObligation<'tcx>,
1197 next_code: Option<&ObligationCauseCode<'tcx>>,
1199 let source_map = self.tcx.sess.source_map();
1201 let is_async_fn = self
1203 .parent(first_generator)
1204 .map(|parent_did| self.tcx.asyncness(parent_did))
1205 .map(|parent_asyncness| parent_asyncness == hir::IsAsync::Async)
1207 let is_async_move = self
1210 .as_local_hir_id(first_generator)
1211 .and_then(|hir_id| self.tcx.hir().maybe_body_owned_by(hir_id))
1212 .map(|body_id| self.tcx.hir().body(body_id))
1213 .and_then(|body| body.generator_kind())
1214 .map(|generator_kind| match generator_kind {
1215 hir::GeneratorKind::Async(..) => true,
1219 let await_or_yield = if is_async_fn || is_async_move { "await" } else { "yield" };
1221 // Special case the primary error message when send or sync is the trait that was
1223 let is_send = self.tcx.is_diagnostic_item(sym::send_trait, trait_ref.def_id);
1224 let is_sync = self.tcx.is_diagnostic_item(sym::sync_trait, trait_ref.def_id);
1225 let hir = self.tcx.hir();
1226 let trait_explanation = if is_send || is_sync {
1227 let (trait_name, trait_verb) =
1228 if is_send { ("`Send`", "sent") } else { ("`Sync`", "shared") };
1231 err.set_primary_message(format!(
1232 "future cannot be {} between threads safely",
1236 let original_span = err.span.primary_span().unwrap();
1237 let mut span = MultiSpan::from_span(original_span);
1239 let message = if let Some(name) = last_generator
1240 .and_then(|generator_did| self.tcx.parent(generator_did))
1241 .and_then(|parent_did| hir.as_local_hir_id(parent_did))
1242 .and_then(|parent_hir_id| hir.opt_name(parent_hir_id))
1244 format!("future returned by `{}` is not {}", name, trait_name)
1246 format!("future is not {}", trait_name)
1249 span.push_span_label(original_span, message);
1252 format!("is not {}", trait_name)
1254 format!("does not implement `{}`", trait_ref.print_only_trait_path())
1257 // Look at the last interior type to get a span for the `.await`.
1258 let await_span = tables.generator_interior_types.iter().map(|t| t.span).last().unwrap();
1259 let mut span = MultiSpan::from_span(await_span);
1260 span.push_span_label(
1262 format!("{} occurs here, with `{}` maybe used later", await_or_yield, snippet),
1265 span.push_span_label(target_span, format!("has type `{}`", target_ty));
1267 // If available, use the scope span to annotate the drop location.
1268 if let Some(scope_span) = scope_span {
1269 span.push_span_label(
1270 source_map.end_point(*scope_span),
1271 format!("`{}` is later dropped here", snippet),
1278 "future {} as this value is used across an {}",
1279 trait_explanation, await_or_yield,
1283 if let Some(expr_id) = expr {
1284 let expr = hir.expect_expr(expr_id);
1285 debug!("target_ty evaluated from {:?}", expr);
1287 let parent = hir.get_parent_node(expr_id);
1288 if let Some(hir::Node::Expr(e)) = hir.find(parent) {
1289 let parent_span = hir.span(parent);
1290 let parent_did = parent.owner_def_id();
1293 // fn foo(&self) -> i32 {}
1296 // ^^^^^^^ a temporary `&T` created inside this method call due to `&self`
1299 let is_region_borrow =
1300 tables.expr_adjustments(expr).iter().any(|adj| adj.is_region_borrow());
1303 // struct Foo(*const u8);
1304 // bar(Foo(std::ptr::null())).await;
1305 // ^^^^^^^^^^^^^^^^^^^^^ raw-ptr `*T` created inside this struct ctor.
1307 debug!("parent_def_kind: {:?}", self.tcx.def_kind(parent_did));
1308 let is_raw_borrow_inside_fn_like_call = match self.tcx.def_kind(parent_did) {
1309 Some(DefKind::Fn) | Some(DefKind::Ctor(..)) => target_ty.is_unsafe_ptr(),
1313 if (tables.is_method_call(e) && is_region_borrow)
1314 || is_raw_borrow_inside_fn_like_call
1318 "consider moving this into a `let` \
1319 binding to create a shorter lived borrow",
1325 // Add a note for the item obligation that remains - normally a note pointing to the
1326 // bound that introduced the obligation (e.g. `T: Send`).
1327 debug!("note_obligation_cause_for_async_await: next_code={:?}", next_code);
1328 self.note_obligation_cause_code(
1330 &obligation.predicate,
1336 fn note_obligation_cause_code<T>(
1338 err: &mut DiagnosticBuilder<'_>,
1340 cause_code: &ObligationCauseCode<'tcx>,
1341 obligated_types: &mut Vec<&ty::TyS<'tcx>>,
1347 ObligationCauseCode::ExprAssignable
1348 | ObligationCauseCode::MatchExpressionArm { .. }
1349 | ObligationCauseCode::Pattern { .. }
1350 | ObligationCauseCode::IfExpression { .. }
1351 | ObligationCauseCode::IfExpressionWithNoElse
1352 | ObligationCauseCode::MainFunctionType
1353 | ObligationCauseCode::StartFunctionType
1354 | ObligationCauseCode::IntrinsicType
1355 | ObligationCauseCode::MethodReceiver
1356 | ObligationCauseCode::ReturnNoExpression
1357 | ObligationCauseCode::MiscObligation => {}
1358 ObligationCauseCode::SliceOrArrayElem => {
1359 err.note("slice and array elements must have `Sized` type");
1361 ObligationCauseCode::TupleElem => {
1362 err.note("only the last element of a tuple may have a dynamically sized type");
1364 ObligationCauseCode::ProjectionWf(data) => {
1365 err.note(&format!("required so that the projection `{}` is well-formed", data,));
1367 ObligationCauseCode::ReferenceOutlivesReferent(ref_ty) => {
1369 "required so that reference `{}` does not outlive its referent",
1373 ObligationCauseCode::ObjectTypeBound(object_ty, region) => {
1375 "required so that the lifetime bound of `{}` for `{}` is satisfied",
1379 ObligationCauseCode::ItemObligation(item_def_id) => {
1380 let item_name = tcx.def_path_str(item_def_id);
1381 let msg = format!("required by `{}`", item_name);
1383 if let Some(sp) = tcx.hir().span_if_local(item_def_id) {
1384 let sp = tcx.sess.source_map().def_span(sp);
1385 err.span_label(sp, &msg);
1390 ObligationCauseCode::BindingObligation(item_def_id, span) => {
1391 let item_name = tcx.def_path_str(item_def_id);
1392 let msg = format!("required by this bound in `{}`", item_name);
1393 if let Some(ident) = tcx.opt_item_name(item_def_id) {
1394 err.span_label(ident.span, "");
1396 if span != DUMMY_SP {
1397 err.span_label(span, &msg);
1402 ObligationCauseCode::ObjectCastObligation(object_ty) => {
1404 "required for the cast to the object type `{}`",
1405 self.ty_to_string(object_ty)
1408 ObligationCauseCode::Coercion { source: _, target } => {
1409 err.note(&format!("required by cast to type `{}`", self.ty_to_string(target)));
1411 ObligationCauseCode::RepeatVec(suggest_const_in_array_repeat_expressions) => {
1413 "the `Copy` trait is required because the repeated element will be copied",
1415 if suggest_const_in_array_repeat_expressions {
1417 "this array initializer can be evaluated at compile-time, see issue \
1418 #48147 <https://github.com/rust-lang/rust/issues/49147> \
1419 for more information",
1421 if tcx.sess.opts.unstable_features.is_nightly_build() {
1423 "add `#![feature(const_in_array_repeat_expressions)]` to the \
1424 crate attributes to enable",
1429 ObligationCauseCode::VariableType(_) => {
1430 err.note("all local variables must have a statically known size");
1431 if !self.tcx.features().unsized_locals {
1432 err.help("unsized locals are gated as an unstable feature");
1435 ObligationCauseCode::SizedArgumentType => {
1436 err.note("all function arguments must have a statically known size");
1437 if !self.tcx.features().unsized_locals {
1438 err.help("unsized locals are gated as an unstable feature");
1441 ObligationCauseCode::SizedReturnType => {
1442 err.note("the return type of a function must have a statically known size");
1444 ObligationCauseCode::SizedYieldType => {
1445 err.note("the yield type of a generator must have a statically known size");
1447 ObligationCauseCode::AssignmentLhsSized => {
1448 err.note("the left-hand-side of an assignment must have a statically known size");
1450 ObligationCauseCode::TupleInitializerSized => {
1451 err.note("tuples must have a statically known size to be initialized");
1453 ObligationCauseCode::StructInitializerSized => {
1454 err.note("structs must have a statically known size to be initialized");
1456 ObligationCauseCode::FieldSized { adt_kind: ref item, last } => match *item {
1457 AdtKind::Struct => {
1460 "the last field of a packed struct may only have a \
1461 dynamically sized type if it does not need drop to be run",
1465 "only the last field of a struct may have a dynamically sized type",
1470 err.note("no field of a union may have a dynamically sized type");
1473 err.note("no field of an enum variant may have a dynamically sized type");
1476 ObligationCauseCode::ConstSized => {
1477 err.note("constant expressions must have a statically known size");
1479 ObligationCauseCode::ConstPatternStructural => {
1480 err.note("constants used for pattern-matching must derive `PartialEq` and `Eq`");
1482 ObligationCauseCode::SharedStatic => {
1483 err.note("shared static variables must have a type that implements `Sync`");
1485 ObligationCauseCode::BuiltinDerivedObligation(ref data) => {
1486 let parent_trait_ref = self.resolve_vars_if_possible(&data.parent_trait_ref);
1487 let ty = parent_trait_ref.skip_binder().self_ty();
1488 err.note(&format!("required because it appears within the type `{}`", ty));
1489 obligated_types.push(ty);
1491 let parent_predicate = parent_trait_ref.without_const().to_predicate();
1492 if !self.is_recursive_obligation(obligated_types, &data.parent_code) {
1493 self.note_obligation_cause_code(
1501 ObligationCauseCode::ImplDerivedObligation(ref data) => {
1502 let parent_trait_ref = self.resolve_vars_if_possible(&data.parent_trait_ref);
1504 "required because of the requirements on the impl of `{}` for `{}`",
1505 parent_trait_ref.print_only_trait_path(),
1506 parent_trait_ref.skip_binder().self_ty()
1508 let parent_predicate = parent_trait_ref.without_const().to_predicate();
1509 self.note_obligation_cause_code(
1516 ObligationCauseCode::CompareImplMethodObligation { .. } => {
1518 "the requirement `{}` appears on the impl method \
1519 but not on the corresponding trait method",
1523 ObligationCauseCode::CompareImplTypeObligation { .. } => {
1525 "the requirement `{}` appears on the associated impl type \
1526 but not on the corresponding associated trait type",
1530 ObligationCauseCode::ReturnType
1531 | ObligationCauseCode::ReturnValue(_)
1532 | ObligationCauseCode::BlockTailExpression(_) => (),
1533 ObligationCauseCode::TrivialBound => {
1534 err.help("see issue #48214");
1535 if tcx.sess.opts.unstable_features.is_nightly_build() {
1536 err.help("add `#![feature(trivial_bounds)]` to the crate attributes to enable");
1539 ObligationCauseCode::AssocTypeBound(ref data) => {
1540 err.span_label(data.original, "associated type defined here");
1541 if let Some(sp) = data.impl_span {
1542 err.span_label(sp, "in this `impl` item");
1544 for sp in &data.bounds {
1545 err.span_label(*sp, "restricted in this bound");
1551 fn suggest_new_overflow_limit(&self, err: &mut DiagnosticBuilder<'_>) {
1552 let current_limit = self.tcx.sess.recursion_limit.get();
1553 let suggested_limit = current_limit * 2;
1555 "consider adding a `#![recursion_limit=\"{}\"]` attribute to your crate (`{}`)",
1556 suggested_limit, self.tcx.crate_name,
1561 /// Collect all the returned expressions within the input expression.
1562 /// Used to point at the return spans when we want to suggest some change to them.
1564 struct ReturnsVisitor<'v> {
1565 returns: Vec<&'v hir::Expr<'v>>,
1566 in_block_tail: bool,
1569 impl<'v> Visitor<'v> for ReturnsVisitor<'v> {
1570 type Map = hir::intravisit::ErasedMap<'v>;
1572 fn nested_visit_map(&mut self) -> hir::intravisit::NestedVisitorMap<Self::Map> {
1573 hir::intravisit::NestedVisitorMap::None
1576 fn visit_expr(&mut self, ex: &'v hir::Expr<'v>) {
1577 // Visit every expression to detect `return` paths, either through the function's tail
1578 // expression or `return` statements. We walk all nodes to find `return` statements, but
1579 // we only care about tail expressions when `in_block_tail` is `true`, which means that
1580 // they're in the return path of the function body.
1582 hir::ExprKind::Ret(Some(ex)) => {
1583 self.returns.push(ex);
1585 hir::ExprKind::Block(block, _) if self.in_block_tail => {
1586 self.in_block_tail = false;
1587 for stmt in block.stmts {
1588 hir::intravisit::walk_stmt(self, stmt);
1590 self.in_block_tail = true;
1591 if let Some(expr) = block.expr {
1592 self.visit_expr(expr);
1595 hir::ExprKind::Match(_, arms, _) if self.in_block_tail => {
1597 self.visit_expr(arm.body);
1600 // We need to walk to find `return`s in the entire body.
1601 _ if !self.in_block_tail => hir::intravisit::walk_expr(self, ex),
1602 _ => self.returns.push(ex),
1606 fn visit_body(&mut self, body: &'v hir::Body<'v>) {
1607 assert!(!self.in_block_tail);
1608 if body.generator_kind().is_none() {
1609 if let hir::ExprKind::Block(block, None) = body.value.kind {
1610 if block.expr.is_some() {
1611 self.in_block_tail = true;
1615 hir::intravisit::walk_body(self, body);