]> git.lizzy.rs Git - rust.git/commitdiff
Added fully elaborated type label for inferred arguments.
authorDavid Wood <david@davidtw.co>
Mon, 23 Jul 2018 11:09:30 +0000 (13:09 +0200)
committerDavid Wood <david@davidtw.co>
Fri, 27 Jul 2018 09:18:11 +0000 (11:18 +0200)
src/librustc/infer/error_reporting/need_type_info.rs
src/librustc_mir/borrow_check/nll/region_infer/error_reporting/mod.rs
src/librustc_mir/borrow_check/nll/region_infer/error_reporting/region_name.rs
src/test/ui/issue-52533.nll.stderr [new file with mode: 0644]
src/test/ui/issue-52533.rs [new file with mode: 0644]
src/test/ui/issue-52533.stderr [new file with mode: 0644]

index dbcb63addb846f3ee68ebc05add77f631357dddb..693219ec4b03f518e4d2c39429364f95bc8e2bff 100644 (file)
@@ -74,7 +74,7 @@ fn visit_body(&mut self, body: &'gcx Body) {
 
 
 impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
-    fn extract_type_name(&self, ty: &'a Ty<'tcx>) -> String {
+    pub fn extract_type_name(&self, ty: &'a Ty<'tcx>) -> String {
         if let ty::TyInfer(ty::TyVar(ty_vid)) = (*ty).sty {
             let ty_vars = self.type_variables.borrow();
             if let TypeVariableOrigin::TypeParameterDefinition(_, name) =
index 836eaa23f68534cf6544550d4309c290f8d009f1..7ba1e50cef348b3a35ae57c31e3241d23610f3dc 100644 (file)
@@ -404,9 +404,9 @@ fn report_general_error(
 
         let counter = &mut 1;
         let fr_name = self.give_region_a_name(
-            infcx.tcx, mir, mir_def_id, fr, counter, &mut diag);
+            infcx, mir, mir_def_id, fr, counter, &mut diag);
         let outlived_fr_name = self.give_region_a_name(
-            infcx.tcx, mir, mir_def_id, outlived_fr, counter, &mut diag);
+            infcx, mir, mir_def_id, outlived_fr, counter, &mut diag);
 
         match (category, outlived_fr_is_local, fr_is_local) {
             (ConstraintCategory::Return, true, _) => {
index c0eca026331ba3891b2cef0b85d1e58f0db485b9..05ac130f0004def2af429f6bca551de8d5046611 100644 (file)
@@ -12,6 +12,7 @@
 use borrow_check::nll::ToRegionVid;
 use rustc::hir;
 use rustc::hir::def_id::DefId;
+use rustc::infer::InferCtxt;
 use rustc::mir::Mir;
 use rustc::ty::subst::{Substs, UnpackedKind};
 use rustc::ty::{self, RegionVid, Ty, TyCtxt};
@@ -48,7 +49,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
     /// and then return the name `'1` for us to use.
     crate fn give_region_a_name(
         &self,
-        tcx: TyCtxt<'_, '_, 'tcx>,
+        infcx: &InferCtxt<'_, '_, 'tcx>,
         mir: &Mir<'tcx>,
         mir_def_id: DefId,
         fr: RegionVid,
@@ -59,17 +60,18 @@ impl<'tcx> RegionInferenceContext<'tcx> {
 
         assert!(self.universal_regions.is_universal_region(fr));
 
-        self.give_name_from_error_region(tcx, mir_def_id, fr, counter, diag)
+        self.give_name_from_error_region(infcx.tcx, mir_def_id, fr, counter, diag)
             .or_else(|| {
                 self.give_name_if_anonymous_region_appears_in_arguments(
-                    tcx, mir, mir_def_id, fr, counter, diag)
+                    infcx, mir, mir_def_id, fr, counter, diag)
             })
             .or_else(|| {
                 self.give_name_if_anonymous_region_appears_in_upvars(
-                    tcx, mir, fr, counter, diag)
+                    infcx.tcx, mir, fr, counter, diag)
             })
             .or_else(|| {
-                self.give_name_if_anonymous_region_appears_in_output(tcx, mir, fr, counter, diag)
+                self.give_name_if_anonymous_region_appears_in_output(
+                    infcx.tcx, mir, fr, counter, diag)
             })
             .unwrap_or_else(|| span_bug!(mir.span, "can't make a name for free region {:?}", fr))
     }
@@ -130,7 +132,7 @@ fn give_name_from_error_region(
     /// ```
     fn give_name_if_anonymous_region_appears_in_arguments(
         &self,
-        tcx: TyCtxt<'_, '_, 'tcx>,
+        infcx: &InferCtxt<'_, '_, 'tcx>,
         mir: &Mir<'tcx>,
         mir_def_id: DefId,
         fr: RegionVid,
@@ -138,12 +140,12 @@ fn give_name_if_anonymous_region_appears_in_arguments(
         diag: &mut DiagnosticBuilder<'_>,
     ) -> Option<InternedString> {
         let implicit_inputs = self.universal_regions.defining_ty.implicit_inputs();
-        let argument_index = self.get_argument_index_for_region(tcx, fr)?;
+        let argument_index = self.get_argument_index_for_region(infcx.tcx, fr)?;
 
         let arg_ty =
             self.universal_regions.unnormalized_input_tys[implicit_inputs + argument_index];
         if let Some(region_name) = self.give_name_if_we_can_match_hir_ty_from_argument(
-            tcx,
+            infcx,
             mir_def_id,
             fr,
             arg_ty,
@@ -169,7 +171,7 @@ fn give_name_if_anonymous_region_appears_in_arguments(
 
     fn give_name_if_we_can_match_hir_ty_from_argument(
         &self,
-        tcx: TyCtxt<'_, '_, 'tcx>,
+        infcx: &InferCtxt<'_, '_, 'tcx>,
         mir_def_id: DefId,
         needle_fr: RegionVid,
         argument_ty: Ty<'tcx>,
@@ -177,17 +179,23 @@ fn give_name_if_we_can_match_hir_ty_from_argument(
         counter: &mut usize,
         diag: &mut DiagnosticBuilder<'_>,
     ) -> Option<InternedString> {
-        let mir_node_id = tcx.hir.as_local_node_id(mir_def_id)?;
-        let fn_decl = tcx.hir.fn_decl(mir_node_id)?;
+        let mir_node_id = infcx.tcx.hir.as_local_node_id(mir_def_id)?;
+        let fn_decl = infcx.tcx.hir.fn_decl(mir_node_id)?;
         let argument_hir_ty: &hir::Ty = &fn_decl.inputs[argument_index];
         match argument_hir_ty.node {
             // This indicates a variable with no type annotation, like
             // `|x|`... in that case, we can't highlight the type but
             // must highlight the variable.
-            hir::TyKind::Infer => None,
+            hir::TyKind::Infer => self.give_name_if_we_cannot_match_hir_ty(
+                infcx,
+                argument_ty,
+                argument_hir_ty,
+                counter,
+                diag,
+            ),
 
             _ => self.give_name_if_we_can_match_hir_ty(
-                tcx,
+                infcx.tcx,
                 needle_fr,
                 argument_ty,
                 argument_hir_ty,
@@ -197,6 +205,40 @@ fn give_name_if_we_can_match_hir_ty_from_argument(
         }
     }
 
+    /// Attempts to highlight the specific part of a type in an argument
+    /// that has no type annotation.
+    /// For example, we might produce an annotation like this:
+    ///
+    /// ```
+    ///  |     foo(|a, b| b)
+    ///  |          -  -
+    ///  |          |  |
+    ///  |          |  has type `&'1 u32`
+    ///  |          has type `&'2 u32`
+    /// ```
+    fn give_name_if_we_cannot_match_hir_ty(
+        &self,
+        infcx: &InferCtxt<'_, '_, 'tcx>,
+        argument_ty: Ty<'tcx>,
+        argument_hir_ty: &hir::Ty,
+        counter: &mut usize,
+        diag: &mut DiagnosticBuilder<'_>,
+    ) -> Option<InternedString> {
+        let mut type_name = infcx.extract_type_name(&argument_ty);
+
+        type_name.find("&").map(|index| {
+            let region_name = self.synthesize_region_name(counter).as_str();
+            type_name.insert_str(index + 1, &format!("{} ", region_name));
+
+            diag.span_label(
+                argument_hir_ty.span,
+                format!("has type `{}`", type_name),
+            );
+
+            region_name.as_interned_str()
+        })
+    }
+
     /// Attempts to highlight the specific part of a type annotation
     /// that contains the anonymous reference we want to give a name
     /// to. For example, we might produce an annotation like this:
diff --git a/src/test/ui/issue-52533.nll.stderr b/src/test/ui/issue-52533.nll.stderr
new file mode 100644 (file)
index 0000000..7931bc3
--- /dev/null
@@ -0,0 +1,17 @@
+warning: not reporting region error due to nll
+  --> $DIR/issue-52533.rs:15:16
+   |
+LL |     foo(|a, b| b)
+   |                ^
+
+error: unsatisfied lifetime constraints
+  --> $DIR/issue-52533.rs:15:16
+   |
+LL |     foo(|a, b| b)
+   |          -  -  ^ free region requires that `'1` must outlive `'2`
+   |          |  |
+   |          |  lifetime `'1` appears in this argument
+   |          lifetime `'2` appears in this argument
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/issue-52533.rs b/src/test/ui/issue-52533.rs
new file mode 100644 (file)
index 0000000..08f2805
--- /dev/null
@@ -0,0 +1,17 @@
+// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+fn foo(_: impl for<'a> FnOnce(&'a u32, &u32) -> &'a u32) {
+}
+
+fn main() {
+    foo(|a, b| b)
+    //~^ ERROR lifetime of reference outlives lifetime of borrowed content...
+}
diff --git a/src/test/ui/issue-52533.stderr b/src/test/ui/issue-52533.stderr
new file mode 100644 (file)
index 0000000..76a2470
--- /dev/null
@@ -0,0 +1,20 @@
+error[E0312]: lifetime of reference outlives lifetime of borrowed content...
+  --> $DIR/issue-52533.rs:15:16
+   |
+LL |     foo(|a, b| b)
+   |                ^
+   |
+note: ...the reference is valid for the anonymous lifetime #2 defined on the body at 15:9...
+  --> $DIR/issue-52533.rs:15:9
+   |
+LL |     foo(|a, b| b)
+   |         ^^^^^^^^
+note: ...but the borrowed content is only valid for the anonymous lifetime #3 defined on the body at 15:9
+  --> $DIR/issue-52533.rs:15:9
+   |
+LL |     foo(|a, b| b)
+   |         ^^^^^^^^
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0312`.