]> git.lizzy.rs Git - rust.git/blobdiff - src/librustc/traits/error_reporting.rs
suggest to limit lifetime of temporary borrow with let
[rust.git] / src / librustc / traits / error_reporting.rs
index b9bb68798e588fa0321eb43daeb921410bf64082..13eb47a041fa670008cc7cf517d8378e6ece138e 100644 (file)
@@ -21,8 +21,8 @@
 use crate::ty::TypeckTables;
 use crate::ty::{self, AdtKind, DefIdTree, ToPolyTraitRef, ToPredicate, Ty, TyCtxt, TypeFoldable};
 
-use errors::{pluralize, struct_span_err, Applicability, DiagnosticBuilder, Style};
 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
+use rustc_errors::{pluralize, struct_span_err, Applicability, DiagnosticBuilder, Style};
 use rustc_hir as hir;
 use rustc_hir::def_id::{DefId, LOCAL_CRATE};
 use rustc_hir::Node;
@@ -2456,7 +2456,8 @@ fn maybe_note_obligation_cause_for_async_await(
         let target_span = tables
             .generator_interior_types
             .iter()
-            .find(|ty::GeneratorInteriorTypeCause { ty, .. }| {
+            .zip(tables.generator_interior_exprs.iter())
+            .find(|(ty::GeneratorInteriorTypeCause { ty, .. }, _)| {
                 // Careful: the regions for types that appear in the
                 // generator interior are not generally known, so we
                 // want to erase them when comparing (and anyway,
@@ -2479,19 +2480,21 @@ fn maybe_note_obligation_cause_for_async_await(
                 );
                 eq
             })
-            .map(|ty::GeneratorInteriorTypeCause { span, scope_span, .. }| {
-                (span, source_map.span_to_snippet(*span), scope_span)
+            .map(|(ty::GeneratorInteriorTypeCause { span, scope_span, .. }, expr)| {
+                (span, source_map.span_to_snippet(*span), scope_span, expr)
             });
+
         debug!(
             "maybe_note_obligation_cause_for_async_await: target_ty={:?} \
                 generator_interior_types={:?} target_span={:?}",
             target_ty, tables.generator_interior_types, target_span
         );
-        if let Some((target_span, Ok(snippet), scope_span)) = target_span {
+        if let Some((target_span, Ok(snippet), scope_span, expr)) = target_span {
             self.note_obligation_cause_for_async_await(
                 err,
                 *target_span,
                 scope_span,
+                *expr,
                 snippet,
                 generator_did,
                 last_generator,
@@ -2514,6 +2517,7 @@ fn note_obligation_cause_for_async_await(
         err: &mut DiagnosticBuilder<'_>,
         target_span: Span,
         scope_span: &Option<Span>,
+        expr: Option<hir::HirId>,
         snippet: String,
         first_generator: DefId,
         last_generator: Option<DefId>,
@@ -2549,6 +2553,7 @@ fn note_obligation_cause_for_async_await(
         // not implemented.
         let is_send = self.tcx.is_diagnostic_item(sym::send_trait, trait_ref.def_id);
         let is_sync = self.tcx.is_diagnostic_item(sym::sync_trait, trait_ref.def_id);
+        let hir = self.tcx.hir();
         let trait_explanation = if is_send || is_sync {
             let (trait_name, trait_verb) =
                 if is_send { ("`Send`", "sent") } else { ("`Sync`", "shared") };
@@ -2564,8 +2569,8 @@ fn note_obligation_cause_for_async_await(
 
             let message = if let Some(name) = last_generator
                 .and_then(|generator_did| self.tcx.parent(generator_did))
-                .and_then(|parent_did| self.tcx.hir().as_local_hir_id(parent_did))
-                .and_then(|parent_hir_id| self.tcx.hir().opt_name(parent_hir_id))
+                .and_then(|parent_did| hir.as_local_hir_id(parent_did))
+                .and_then(|parent_hir_id| hir.opt_name(parent_hir_id))
             {
                 format!("future returned by `{}` is not {}", name, trait_name)
             } else {
@@ -2573,7 +2578,7 @@ fn note_obligation_cause_for_async_await(
             };
 
             span.push_span_label(original_span, message);
-            err.set_span(span);
+            err.set_span(span.clone());
 
             format!("is not {}", trait_name)
         } else {
@@ -2588,6 +2593,22 @@ fn note_obligation_cause_for_async_await(
             format!("{} occurs here, with `{}` maybe used later", await_or_yield, snippet),
         );
 
+        if let Some(expr_id) = expr {
+            let expr = hir.expect_expr(expr_id);
+            let is_ref = tables.expr_adjustments(expr).iter().any(|adj| adj.is_region_borrow());
+            let parent = hir.get_parent_node(expr_id);
+            if let Some(hir::Node::Expr(e)) = hir.find(parent) {
+                let method_span = hir.span(parent);
+                if tables.is_method_call(e) && is_ref {
+                    err.span_help(
+                        method_span,
+                        "consider moving this method call into a `let` \
+                        binding to create a shorter lived borrow"
+                    );
+                }
+            }
+        }
+
         span.push_span_label(target_span, format!("has type `{}`", target_ty));
 
         // If available, use the scope span to annotate the drop location.