about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authorMatthew Jasper <mjjasper1@gmail.com>2018-08-05 14:33:38 +0100
committerMatthew Jasper <mjjasper1@gmail.com>2018-08-05 14:33:38 +0100
commitf72b8a44c51313d384deefcda753df668f2e265e (patch)
tree614c7ac810f1a856109e586a1d713f22f193e088 /src
parentddcf17e1ed577bad26e92db3c25499620f853a49 (diff)
downloadrust-f72b8a44c51313d384deefcda753df668f2e265e.tar.gz
rust-f72b8a44c51313d384deefcda753df668f2e265e.zip
Use span of the closure args in free region errors
Diffstat (limited to 'src')
-rw-r--r--src/librustc_mir/borrow_check/nll/region_infer/error_reporting/region_name.rs62
-rw-r--r--src/test/ui/error-codes/E0621-does-not-trigger-for-closures.nll.stderr5
-rw-r--r--src/test/ui/issue-40510-1.nll.stderr20
-rw-r--r--src/test/ui/issue-40510-3.nll.stderr25
-rw-r--r--src/test/ui/issue-49824.nll.stderr25
-rw-r--r--src/test/ui/nll/issue-48238.stderr9
6 files changed, 91 insertions, 55 deletions
diff --git a/src/librustc_mir/borrow_check/nll/region_infer/error_reporting/region_name.rs b/src/librustc_mir/borrow_check/nll/region_infer/error_reporting/region_name.rs
index 79165276430..6a21e002588 100644
--- a/src/librustc_mir/borrow_check/nll/region_infer/error_reporting/region_name.rs
+++ b/src/librustc_mir/borrow_check/nll/region_infer/error_reporting/region_name.rs
@@ -10,6 +10,7 @@
 
 use borrow_check::nll::region_infer::RegionInferenceContext;
 use borrow_check::nll::ToRegionVid;
+use borrow_check::nll::universal_regions::DefiningTy;
 use rustc::hir;
 use rustc::hir::def_id::DefId;
 use rustc::infer::InferCtxt;
@@ -72,7 +73,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
             })
             .or_else(|| {
                 self.give_name_if_anonymous_region_appears_in_output(
-                    infcx.tcx, mir, fr, counter, diag)
+                    infcx.tcx, mir, mir_def_id, fr, counter, diag)
             })
             .unwrap_or_else(|| span_bug!(mir.span, "can't make a name for free region {:?}", fr))
     }
@@ -107,13 +108,46 @@ impl<'tcx> RegionInferenceContext<'tcx> {
                 },
 
                 ty::BoundRegion::BrEnv => {
-                    let closure_span = tcx.hir.span_if_local(mir_def_id).unwrap();
-                    let region_name = self.synthesize_region_name(counter);
-                    diag.span_label(
-                        closure_span,
-                        format!("lifetime `{}` represents the closure body", region_name),
-                    );
-                    Some(region_name)
+                    let mir_node_id = tcx.hir.as_local_node_id(mir_def_id).expect("non-local mir");
+                    let def_ty = self.universal_regions.defining_ty;
+
+                    if let DefiningTy::Closure(def_id, substs) = def_ty {
+                        let args_span = if let hir::ExprKind::Closure(_, _, _, span, _)
+                            = tcx.hir.expect_expr(mir_node_id).node
+                        {
+                            span
+                        } else {
+                            bug!("Closure is not defined by a closure expr");
+                        };
+                        let region_name = self.synthesize_region_name(counter);
+                        diag.span_label(
+                            args_span,
+                            format!("lifetime `{}` represents this closure's body", region_name),
+                        );
+
+                        let closure_kind_ty = substs.closure_kind_ty(def_id, tcx);
+                        let note = match closure_kind_ty.to_opt_closure_kind() {
+                            Some(ty::ClosureKind::Fn) => {
+                                "closure implements `Fn`, so references to captured variables \
+                                 can't escape the closure"
+                            }
+                            Some(ty::ClosureKind::FnMut) => {
+                                "closure implements `FnMut`, so references to captured variables \
+                                 can't escape the closure"
+                            }
+                            Some(ty::ClosureKind::FnOnce) => {
+                                bug!("BrEnv in a `FnOnce` closure");
+                            }
+                            None => bug!("Closure kind not inferred in borrow check"),
+                        };
+
+                        diag.note(note);
+
+                        Some(region_name)
+                    } else {
+                        // Can't have BrEnv in functions, constants or generators.
+                        bug!("BrEnv outside of closure.");
+                    }
                 }
 
                 ty::BoundRegion::BrAnon(_) | ty::BoundRegion::BrFresh(_) => None,
@@ -545,6 +579,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
         &self,
         tcx: TyCtxt<'_, '_, 'tcx>,
         mir: &Mir<'tcx>,
+        mir_def_id: DefId,
         fr: RegionVid,
         counter: &mut usize,
         diag: &mut DiagnosticBuilder<'_>,
@@ -558,9 +593,18 @@ impl<'tcx> RegionInferenceContext<'tcx> {
             return None;
         }
 
+        let mir_node_id = tcx.hir.as_local_node_id(mir_def_id).expect("non-local mir");
+        let args_span = if let hir::ExprKind::Closure(_, _, _, span, _)
+            = tcx.hir.expect_expr(mir_node_id).node
+        {
+            span
+        } else {
+            mir.span
+        };
+
         let region_name = self.synthesize_region_name(counter);
         diag.span_label(
-            mir.span,
+            args_span,
             format!("lifetime `{}` appears in return type", region_name),
         );
 
diff --git a/src/test/ui/error-codes/E0621-does-not-trigger-for-closures.nll.stderr b/src/test/ui/error-codes/E0621-does-not-trigger-for-closures.nll.stderr
index 0ac295c54bc..27a51cb83fb 100644
--- a/src/test/ui/error-codes/E0621-does-not-trigger-for-closures.nll.stderr
+++ b/src/test/ui/error-codes/E0621-does-not-trigger-for-closures.nll.stderr
@@ -8,9 +8,8 @@ error: unsatisfied lifetime constraints
   --> $DIR/E0621-does-not-trigger-for-closures.rs:25:26
    |
 LL |     invoke(&x, |a, b| if a > b { a } else { b }); //~ ERROR E0495
-   |                ----------^^^^^-----------------
-   |                |   |     |
-   |                |   |     requires that `'1` must outlive `'2`
+   |                ------    ^^^^^ requires that `'1` must outlive `'2`
+   |                |   |
    |                |   has type `&'1 i32`
    |                lifetime `'2` appears in return type
 
diff --git a/src/test/ui/issue-40510-1.nll.stderr b/src/test/ui/issue-40510-1.nll.stderr
index 312ec6e742e..7eb6a0e7fb2 100644
--- a/src/test/ui/issue-40510-1.nll.stderr
+++ b/src/test/ui/issue-40510-1.nll.stderr
@@ -1,17 +1,15 @@
 error: unsatisfied lifetime constraints
   --> $DIR/issue-40510-1.rs:18:9
    |
-LL |        || {
-   |   _____-
-   |  |_____|
-   | ||
-LL | ||         &mut x
-   | ||         ^^^^^^ return requires that `'1` must outlive `'2`
-LL | ||     };
-   | ||     -
-   | ||_____|
-   | |______lifetime `'1` represents the closure body
-   |        lifetime `'2` appears in return type
+LL |     || {
+   |     --
+   |     |
+   |     lifetime `'1` represents this closure's body
+   |     lifetime `'2` appears in return type
+LL |         &mut x
+   |         ^^^^^^ return requires that `'1` must outlive `'2`
+   |
+   = note: closure implements `FnMut`, so references to captured variables can't escape the closure
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/issue-40510-3.nll.stderr b/src/test/ui/issue-40510-3.nll.stderr
index eb44850e639..ae3ae3a27ab 100644
--- a/src/test/ui/issue-40510-3.nll.stderr
+++ b/src/test/ui/issue-40510-3.nll.stderr
@@ -1,20 +1,17 @@
 error: unsatisfied lifetime constraints
   --> $DIR/issue-40510-3.rs:18:9
    |
-LL |         || {
-   |    _____-
-   |   |_____|
-   |  ||
-LL |  ||         || {
-   |  ||_________^
-LL | |||             x.push(())
-LL | |||         }
-   | |||_________^ requires that `'1` must outlive `'2`
-LL |  ||     };
-   |  ||     -
-   |  ||_____|
-   |  |______lifetime `'1` represents the closure body
-   |         lifetime `'2` appears in return type
+LL |       || {
+   |       --
+   |       |
+   |       lifetime `'1` represents this closure's body
+   |       lifetime `'2` appears in return type
+LL | /         || {
+LL | |             x.push(())
+LL | |         }
+   | |_________^ requires that `'1` must outlive `'2`
+   |
+   = note: closure implements `FnMut`, so references to captured variables can't escape the closure
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/issue-49824.nll.stderr b/src/test/ui/issue-49824.nll.stderr
index 59345754e9f..432036c9d90 100644
--- a/src/test/ui/issue-49824.nll.stderr
+++ b/src/test/ui/issue-49824.nll.stderr
@@ -1,20 +1,17 @@
 error: unsatisfied lifetime constraints
   --> $DIR/issue-49824.rs:22:9
    |
-LL |         || {
-   |    _____-
-   |   |_____|
-   |  ||
-LL |  ||         || {
-   |  ||_________^
-LL | |||             let _y = &mut x;
-LL | |||         }
-   | |||_________^ requires that `'1` must outlive `'2`
-LL |  ||     };
-   |  ||     -
-   |  ||_____|
-   |  |______lifetime `'1` represents the closure body
-   |         lifetime `'2` appears in return type
+LL |       || {
+   |       --
+   |       |
+   |       lifetime `'1` represents this closure's body
+   |       lifetime `'2` appears in return type
+LL | /         || {
+LL | |             let _y = &mut x;
+LL | |         }
+   | |_________^ requires that `'1` must outlive `'2`
+   |
+   = note: closure implements `FnMut`, so references to captured variables can't escape the closure
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/nll/issue-48238.stderr b/src/test/ui/nll/issue-48238.stderr
index 7bdac345e90..4baa9044424 100644
--- a/src/test/ui/nll/issue-48238.stderr
+++ b/src/test/ui/nll/issue-48238.stderr
@@ -2,11 +2,12 @@ error: unsatisfied lifetime constraints
   --> $DIR/issue-48238.rs:21:13
    |
 LL |     move || use_val(&orig); //~ ERROR
-   |     --------^^^^^^^^^^^^^^
-   |     |       |
-   |     |       argument requires that `'1` must outlive `'2`
-   |     lifetime `'1` represents the closure body
+   |     ------- ^^^^^^^^^^^^^^ argument requires that `'1` must outlive `'2`
+   |     |
+   |     lifetime `'1` represents this closure's body
    |     lifetime `'2` appears in return type
+   |
+   = note: closure implements `Fn`, so references to captured variables can't escape the closure
 
 error: aborting due to previous error