about summary refs log tree commit diff
diff options
context:
space:
mode:
authorgaurikholkar <f2013002@goa.bits-pilani.ac.in>2017-06-17 16:27:07 -0700
committergaurikholkar <f2013002@goa.bits-pilani.ac.in>2017-06-29 06:37:18 -0700
commit8fb6f74e57f6c75113074b56f48b16992c5ce1e1 (patch)
treeaeab52c07da93f1a58bae273307b17937f10ffc7
parentae92bd095c16c3aa14b986b089a1ded8df4c8369 (diff)
downloadrust-8fb6f74e57f6c75113074b56f48b16992c5ce1e1.tar.gz
rust-8fb6f74e57f6c75113074b56f48b16992c5ce1e1.zip
Enabling E0611 for inherent functions
-rw-r--r--src/librustc/infer/error_reporting/mod.rs14
-rw-r--r--src/librustc/infer/error_reporting/named_anon_conflict.rs77
-rw-r--r--src/librustc/infer/error_reporting/util.rs25
-rw-r--r--src/test/ui/lifetime-errors/ex1-return-one-existing-name-if-else-using-impl-2.rs18
-rw-r--r--src/test/ui/lifetime-errors/ex1-return-one-existing-name-if-else-using-impl-2.stderr10
-rw-r--r--src/test/ui/lifetime-errors/ex1-return-one-existing-name-if-else-using-impl-3.rs24
-rw-r--r--src/test/ui/lifetime-errors/ex1-return-one-existing-name-if-else-using-impl-3.stderr11
7 files changed, 137 insertions, 42 deletions
diff --git a/src/librustc/infer/error_reporting/mod.rs b/src/librustc/infer/error_reporting/mod.rs
index 1bc01ab858c..b3f7f2d3764 100644
--- a/src/librustc/infer/error_reporting/mod.rs
+++ b/src/librustc/infer/error_reporting/mod.rs
@@ -67,7 +67,7 @@ use hir::def_id::DefId;
 use middle::region;
 use traits::{ObligationCause, ObligationCauseCode};
 use ty::{self, TyCtxt, TypeFoldable};
-use ty::{Region, Issue32330 };
+use ty::{Region, Issue32330};
 use ty::error::TypeError;
 use syntax::ast::DUMMY_NODE_ID;
 use syntax_pos::{Pos, Span};
@@ -272,11 +272,17 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
         for error in errors {
 
             debug!("report_region_errors: error = {:?}", error);
-        // If ConcreteFailure does not have an anonymous region
-            if !self.report_named_anon_conflict(&error){
+            
+            if !self.try_report_named_anon_conflict(&error){
 
                match error.clone() {
-
+                  // These errors could indicate all manner of different
+                  // problems with many different solutions. Rather
+                  // than generate a "one size fits all" error, what we
+                  // attempt to do is go through a number of specific
+                  // scenarios and try to find the best way to present
+                  // the error. If all of these fails, we fall back to a rather
+                  // general bit of code that displays the error information
                   ConcreteFailure(origin, sub, sup) => {
 
                       self.report_concrete_failure(origin, sub, sup).emit();
diff --git a/src/librustc/infer/error_reporting/named_anon_conflict.rs b/src/librustc/infer/error_reporting/named_anon_conflict.rs
index 77af2216910..8af9381107b 100644
--- a/src/librustc/infer/error_reporting/named_anon_conflict.rs
+++ b/src/librustc/infer/error_reporting/named_anon_conflict.rs
@@ -14,6 +14,7 @@ use infer::InferCtxt;
 use ty::{self, Region};
 use infer::region_inference::RegionResolutionError::*;
 use infer::region_inference::RegionResolutionError;
+use hir::map as hir_map;
 
 impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
     // This method walks the Type of the function body arguments using
@@ -23,12 +24,13 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
     // Currently only the case where the function declaration consists of
     // one named region and one anonymous region is handled.
     // Consider the example `fn foo<'a>(x: &'a i32, y: &i32) -> &'a i32`
-    // Here, the `y` and the `Ty` of `y` is returned after being substituted
-    // by that of the named region.
-    pub fn find_arg_with_anonymous_region(&self,
-                                          anon_region: Region<'tcx>,
-                                          named_region: Region<'tcx>)
-                                          -> Option<(&hir::Arg, ty::Ty<'tcx>)> {
+    // Here, we would return the hir::Arg for y, and we return the type &'a
+    // i32, which is the type of y but with the anonymous region replaced
+    // with 'a.
+    fn find_arg_with_anonymous_region(&self,
+                                      anon_region: Region<'tcx>,
+                                      named_region: Region<'tcx>)
+                                      -> Option<(&hir::Arg, ty::Ty<'tcx>)> {
 
         match *anon_region {
             ty::ReFree(ref free_region) => {
@@ -70,29 +72,35 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
     // This method generates the error message for the case when
     // the function arguments consist of a named region and an anonymous
     // region and corresponds to `ConcreteFailure(..)`
-    pub fn report_named_anon_conflict(&self, error: &RegionResolutionError<'tcx>) -> bool {
+    pub fn try_report_named_anon_conflict(&self, error: &RegionResolutionError<'tcx>) -> bool {
 
         let (span, sub, sup) = match *error {
             ConcreteFailure(ref origin, sub, sup) => (origin.span(), sub, sup),
             _ => return false, // inapplicable
         };
 
-        let (named, (var, new_ty)) =
-            if self.is_named_region(sub) && self.is_anonymous_region(sup) {
+        // Determine whether the sub and sup consist of one named region ('a)
+        // and one anonymous (elided) region. If so, find the parameter arg
+        // where the anonymous region appears (there must always be one; we
+        // only introduced anonymous regions in parameters) as well as a
+        // version new_ty of its type where the anonymous region is replaced
+        // with the named one.
+        let (named, (arg, new_ty)) =
+            if self.is_named_region(sub) && self.is_suitable_anonymous_region(sup) {
                 (sub, self.find_arg_with_anonymous_region(sup, sub).unwrap())
-            } else if self.is_named_region(sup) && self.is_anonymous_region(sub) {
+            } else if self.is_named_region(sup) && self.is_suitable_anonymous_region(sub) {
                 (sup, self.find_arg_with_anonymous_region(sub, sup).unwrap())
             } else {
                 return false; // inapplicable
             };
 
-        if let Some(simple_name) = var.pat.simple_name() {
+        if let Some(simple_name) = arg.pat.simple_name() {
             struct_span_err!(self.tcx.sess,
                              span,
                              E0611,
                              "explicit lifetime required in the type of `{}`",
                              simple_name)
-                    .span_label(var.pat.span,
+                    .span_label(arg.pat.span,
                                 format!("consider changing the type of `{}` to `{}`",
                                         simple_name,
                                         new_ty))
@@ -104,7 +112,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
                              span,
                              E0611,
                              "explicit lifetime required in parameter type")
-                    .span_label(var.pat.span,
+                    .span_label(arg.pat.span,
                                 format!("consider changing type to `{}`", new_ty))
                     .span_label(span, format!("lifetime `{}` required", named))
                     .emit();
@@ -112,4 +120,47 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
         return true;
 
     }
+
+    // This method returns whether the given Region is Anonymous
+    pub fn is_suitable_anonymous_region(&self, region: Region<'tcx>) -> bool {
+
+        match *region {
+            ty::ReFree(ref free_region) => {
+                match free_region.bound_region {
+                    ty::BrAnon(..) => {
+                        let anonymous_region_binding_scope = free_region.scope;
+                        let node_id = self.tcx
+                            .hir
+                            .as_local_node_id(anonymous_region_binding_scope)
+                            .unwrap();
+                        match self.tcx.hir.find(node_id) {
+                            Some(hir_map::NodeItem(..)) |
+                            Some(hir_map::NodeTraitItem(..)) => {
+                                // proceed ahead //
+                            }
+                            Some(hir_map::NodeImplItem(..)) => {
+                                if self.tcx.impl_trait_ref(self.tcx.
+associated_item(anonymous_region_binding_scope).container.id()).is_some() {
+                                    // For now, we do not try to target impls of traits. This is
+                                    // because this message is going to suggest that the user
+                                    // change the fn signature, but they may not be free to do so,
+                                    // since the signature must match the trait.
+                                    //
+                                    // FIXME(#42706) -- in some cases, we could do better here.
+                                    return false;//None;
+                                }
+                              else{  }
+
+                            }
+                            _ => return false, // inapplicable
+                            // we target only top-level functions
+                        }
+                        return true;
+                    }
+                    _ => false,
+                }
+            }
+            _ => false,
+        }
+    }
 }
diff --git a/src/librustc/infer/error_reporting/util.rs b/src/librustc/infer/error_reporting/util.rs
index 38bb3e93d00..66c351b49ac 100644
--- a/src/librustc/infer/error_reporting/util.rs
+++ b/src/librustc/infer/error_reporting/util.rs
@@ -12,7 +12,6 @@
 
 use ty::{self, Region};
 use infer::InferCtxt;
-use hir::map as hir_map;
 
 impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
     // This method returns whether the given Region is Named
@@ -28,28 +27,4 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
             _ => false,
         }
     }
-
-    // This method returns whether the given Region is Anonymous
-    pub fn is_anonymous_region(&self, region: Region<'tcx>) -> bool {
-
-        match *region {
-            ty::ReFree(ref free_region) => {
-                match free_region.bound_region {
-                    ty::BrAnon(..) => {
-                        let id = free_region.scope;
-                        let node_id = self.tcx.hir.as_local_node_id(id).unwrap();
-                        match self.tcx.hir.find(node_id) {
-                            Some(hir_map::NodeItem(..)) |
-                            Some(hir_map::NodeTraitItem(..)) => { /* proceed ahead */ }
-                            _ => return false, // inapplicable
-                            // we target only top-level functions
-                        }
-                        return true;
-                    }
-                    _ => false,
-                }
-            }
-            _ => false,
-        }
-    }
 }
diff --git a/src/test/ui/lifetime-errors/ex1-return-one-existing-name-if-else-using-impl-2.rs b/src/test/ui/lifetime-errors/ex1-return-one-existing-name-if-else-using-impl-2.rs
new file mode 100644
index 00000000000..8849f7084b3
--- /dev/null
+++ b/src/test/ui/lifetime-errors/ex1-return-one-existing-name-if-else-using-impl-2.rs
@@ -0,0 +1,18 @@
+// Copyright 2016 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.
+
+trait Foo {
+
+fn foo<'a>(x: &i32, y: &'a i32) -> &'a i32 {
+   if x > y { x } else { y }
+   }
+}
+
+fn main() { }
diff --git a/src/test/ui/lifetime-errors/ex1-return-one-existing-name-if-else-using-impl-2.stderr b/src/test/ui/lifetime-errors/ex1-return-one-existing-name-if-else-using-impl-2.stderr
new file mode 100644
index 00000000000..ec787eb749c
--- /dev/null
+++ b/src/test/ui/lifetime-errors/ex1-return-one-existing-name-if-else-using-impl-2.stderr
@@ -0,0 +1,10 @@
+error[E0611]: explicit lifetime required in the type of `x`
+  --> $DIR/ex1-return-one-existing-name-if-else-using-impl-2.rs:14:15
+   |
+13 | fn foo<'a>(x: &i32, y: &'a i32) -> &'a i32 {
+   |            - consider changing the type of `x` to `&'a i32`
+14 |    if x > y { x } else { y }
+   |               ^ lifetime `'a` required
+
+error: aborting due to previous error(s)
+
diff --git a/src/test/ui/lifetime-errors/ex1-return-one-existing-name-if-else-using-impl-3.rs b/src/test/ui/lifetime-errors/ex1-return-one-existing-name-if-else-using-impl-3.rs
new file mode 100644
index 00000000000..60f794279a5
--- /dev/null
+++ b/src/test/ui/lifetime-errors/ex1-return-one-existing-name-if-else-using-impl-3.rs
@@ -0,0 +1,24 @@
+// Copyright 2016 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.
+
+struct Foo {
+  field: i32
+}
+
+impl Foo {
+  fn foo<'a>(&'a self, x: &i32) -> &i32 {
+   
+    if true { &self.field } else { x }
+
+  }
+
+}
+
+fn main() { }
diff --git a/src/test/ui/lifetime-errors/ex1-return-one-existing-name-if-else-using-impl-3.stderr b/src/test/ui/lifetime-errors/ex1-return-one-existing-name-if-else-using-impl-3.stderr
new file mode 100644
index 00000000000..cedceb559d5
--- /dev/null
+++ b/src/test/ui/lifetime-errors/ex1-return-one-existing-name-if-else-using-impl-3.stderr
@@ -0,0 +1,11 @@
+error[E0611]: explicit lifetime required in the type of `x`
+  --> $DIR/ex1-return-one-existing-name-if-else-using-impl-3.rs:18:36
+   |
+16 |   fn foo<'a>(&'a self, x: &i32) -> &i32 {
+   |                        - consider changing the type of `x` to `&'a i32`
+17 |    
+18 |     if true { &self.field } else { x }
+   |                                    ^ lifetime `'a` required
+
+error: aborting due to previous error(s)
+