]> git.lizzy.rs Git - rust.git/commitdiff
track anonymous regions in return types, fix tidy errors
authorgaurikholkar <f2013002@goa.bits-pilani.ac.in>
Tue, 20 Jun 2017 13:42:11 +0000 (06:42 -0700)
committergaurikholkar <f2013002@goa.bits-pilani.ac.in>
Thu, 29 Jun 2017 13:37:18 +0000 (06:37 -0700)
src/librustc/infer/error_reporting/mod.rs
src/librustc/infer/error_reporting/named_anon_conflict.rs
src/test/ui/lifetime-errors/ex1-return-one-existing-name-if-else-using-impl-3.rs
src/test/ui/lifetime-errors/ex1-return-one-existing-name-return-type-is-anon.rs [new file with mode: 0644]
src/test/ui/lifetime-errors/ex1-return-one-existing-name-return-type-is-anon.stderr [new file with mode: 0644]

index b3f7f2d376445ee60906ce365f91ed66c43cae64..9e2d922b932d1624f5db2e4a1143dbaa84928c37 100644 (file)
@@ -272,7 +272,7 @@ pub fn report_region_errors(&self, errors: &Vec<RegionResolutionError<'tcx>>) {
         for error in errors {
 
             debug!("report_region_errors: error = {:?}", error);
-            
+
             if !self.try_report_named_anon_conflict(&error){
 
                match error.clone() {
index 8af9381107b8d9aafaf362ddc31eacbee6d453cf..edb7887b504b1e1e3bcd584a5db353d83fb422ae 100644 (file)
@@ -15,6 +15,7 @@
 use infer::region_inference::RegionResolutionError::*;
 use infer::region_inference::RegionResolutionError;
 use hir::map as hir_map;
+use hir::def_id::DefId;
 
 impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
     // This method walks the Type of the function body arguments using
@@ -24,13 +25,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, we would return the hir::Arg for y, and we return the type &'a
+    // Here, we would return the hir::Arg for y, we return the type &'a
     // i32, which is the type of y but with the anonymous region replaced
-    // with 'a.
+    // with 'a and also the corresponding bound region.
     fn find_arg_with_anonymous_region(&self,
                                       anon_region: Region<'tcx>,
                                       named_region: Region<'tcx>)
-                                      -> Option<(&hir::Arg, ty::Ty<'tcx>)> {
+                                      -> Option<(&hir::Arg, ty::Ty<'tcx>, ty::BoundRegion)> {
 
         match *anon_region {
             ty::ReFree(ref free_region) => {
@@ -55,7 +56,7 @@ fn find_arg_with_anonymous_region(&self,
                                                           r
                                                       });
                                     if found_anon_region {
-                                        return Some((arg, new_arg_ty));
+                                        return Some((arg, new_arg_ty, free_region.bound_region));
                                     } else {
                                         None
                                     }
@@ -85,15 +86,36 @@ pub fn try_report_named_anon_conflict(&self, error: &RegionResolutionError<'tcx>
         // 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_suitable_anonymous_region(sub) {
-                (sup, self.find_arg_with_anonymous_region(sub, sup).unwrap())
+        let (named, (arg, new_ty, br), scope_def_id) =
+            if self.is_named_region(sub) && self.is_suitable_anonymous_region(sup).is_some() {
+                (sub,
+                 self.find_arg_with_anonymous_region(sup, sub).unwrap(),
+                 self.is_suitable_anonymous_region(sup).unwrap())
+            } else if self.is_named_region(sup) &&
+                      self.is_suitable_anonymous_region(sub).is_some() {
+                (sup,
+                 self.find_arg_with_anonymous_region(sub, sup).unwrap(),
+                 self.is_suitable_anonymous_region(sub).unwrap())
             } else {
                 return false; // inapplicable
             };
 
+        // Here, we check for the case where the anonymous region
+        // is in the return type.
+        // FIXME(#42703) - Need to handle certain cases here.
+        let ret_ty = self.tcx.type_of(scope_def_id);
+        match ret_ty.sty {
+            ty::TyFnDef(_, _, sig) => {
+                let late_bound_regions = self.tcx
+                    .collect_referenced_late_bound_regions(&sig.output());
+                if late_bound_regions.iter().any(|r| *r == br) {
+                    return false;
+                } else {
+                }
+            }
+            _ => {}
+        }
+
         if let Some(simple_name) = arg.pat.simple_name() {
             struct_span_err!(self.tcx.sess,
                              span,
@@ -122,7 +144,8 @@ pub fn try_report_named_anon_conflict(&self, error: &RegionResolutionError<'tcx>
     }
 
     // This method returns whether the given Region is Anonymous
-    pub fn is_suitable_anonymous_region(&self, region: Region<'tcx>) -> bool {
+    // and returns the DefId corresponding to the region.
+    pub fn is_suitable_anonymous_region(&self, region: Region<'tcx>) -> Option<DefId> {
 
         match *region {
             ty::ReFree(ref free_region) => {
@@ -147,20 +170,20 @@ pub fn is_suitable_anonymous_region(&self, region: Region<'tcx>) -> bool {
                                     // since the signature must match the trait.
                                     //
                                     // FIXME(#42706) -- in some cases, we could do better here.
-                                    return false;//None;
+                                    return None;
                                 }
                               else{  }
 
                             }
-                            _ => return false, // inapplicable
+                            _ => return None, // inapplicable
                             // we target only top-level functions
                         }
-                        return true;
+                        return Some(anonymous_region_binding_scope);
                     }
-                    _ => false,
+                    _ => None,
                 }
             }
-            _ => false,
+            _ => None,
         }
     }
 }
index 60f794279a52409074260b46cc9e393b6ee2ecaf..362290ff3fa7d9cd5f7e52229e3648ca0939d67c 100644 (file)
@@ -14,7 +14,7 @@ struct Foo {
 
 impl Foo {
   fn foo<'a>(&'a self, x: &i32) -> &i32 {
-   
+
     if true { &self.field } else { x }
 
   }
diff --git a/src/test/ui/lifetime-errors/ex1-return-one-existing-name-return-type-is-anon.rs b/src/test/ui/lifetime-errors/ex1-return-one-existing-name-return-type-is-anon.rs
new file mode 100644 (file)
index 0000000..96b733b
--- /dev/null
@@ -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>(&self, x: &'a i32) -> &i32 {
+
+    x
+
+  }
+
+}
+
+fn main() { }
diff --git a/src/test/ui/lifetime-errors/ex1-return-one-existing-name-return-type-is-anon.stderr b/src/test/ui/lifetime-errors/ex1-return-one-existing-name-return-type-is-anon.stderr
new file mode 100644 (file)
index 0000000..e32de58
--- /dev/null
@@ -0,0 +1,27 @@
+error[E0312]: lifetime of reference outlives lifetime of borrowed content...
+  --> $DIR/ex1-return-one-existing-name-return-type-is-anon.rs:18:5
+   |
+18 |     x
+   |     ^
+   |
+note: ...the reference is valid for the anonymous lifetime #1 defined on the method body at 16:3...
+  --> $DIR/ex1-return-one-existing-name-return-type-is-anon.rs:16:3
+   |
+16 | /   fn foo<'a>(&self, x: &'a i32) -> &i32 {
+17 | |    
+18 | |     x
+19 | |
+20 | |   }
+   | |___^
+note: ...but the borrowed content is only valid for the lifetime 'a as defined on the method body at 16:3
+  --> $DIR/ex1-return-one-existing-name-return-type-is-anon.rs:16:3
+   |
+16 | /   fn foo<'a>(&self, x: &'a i32) -> &i32 {
+17 | |    
+18 | |     x
+19 | |
+20 | |   }
+   | |___^
+
+error: aborting due to previous error(s)
+