]> git.lizzy.rs Git - rust.git/commitdiff
lifetimes: try to fix w.r.t. lifetimes from parent scopes (fixes #162)
authorGeorg Brandl <georg@python.org>
Thu, 13 Aug 2015 15:24:47 +0000 (17:24 +0200)
committerManish Goregaokar <manishsmail@gmail.com>
Thu, 13 Aug 2015 16:15:42 +0000 (21:45 +0530)
src/lifetimes.rs
tests/compile-fail/lifetimes.rs

index 03b4de6c948ed7b18496ced7f2441f64177bd5a2..c333f04ab449be72877268cec310285670f877b1 100644 (file)
@@ -18,14 +18,23 @@ fn get_lints(&self) -> LintArray {
         lint_array!(NEEDLESS_LIFETIMES)
     }
 
-    fn check_fn(&mut self, cx: &Context, kind: FnKind, decl: &FnDecl,
-                _: &Block, span: Span, _: NodeId) {
-        if in_external_macro(cx, span) {
-            return;
+    fn check_item(&mut self, cx: &Context, item: &Item) {
+        if let ItemFn(ref decl, _, _, _, ref generics, _) = item.node {
+            check_fn_inner(cx, decl, None, &generics.lifetimes, item.span);
         }
-        if could_use_elision(kind, decl) {
-            span_lint(cx, NEEDLESS_LIFETIMES, span,
-                      "explicit lifetimes given in parameter types where they could be elided");
+    }
+
+    fn check_impl_item(&mut self, cx: &Context, item: &ImplItem) {
+        if let MethodImplItem(ref sig, _) = item.node {
+            check_fn_inner(cx, &*sig.decl, Some(&sig.explicit_self),
+                           &sig.generics.lifetimes, item.span);
+        }
+    }
+
+    fn check_trait_item(&mut self, cx: &Context, item: &TraitItem) {
+        if let MethodTraitItem(ref sig, _) = item.node {
+            check_fn_inner(cx, &*sig.decl, Some(&sig.explicit_self),
+                           &sig.generics.lifetimes, item.span);
         }
     }
 }
@@ -39,10 +48,34 @@ enum RefLt {
 }
 use self::RefLt::*;
 
-fn could_use_elision(kind: FnKind, func: &FnDecl) -> bool {
+fn check_fn_inner(cx: &Context, decl: &FnDecl, slf: Option<&ExplicitSelf>,
+                  named_lts: &[LifetimeDef], span: Span) {
+    if in_external_macro(cx, span) {
+        return;
+    }
+    if could_use_elision(decl, slf, named_lts) {
+        span_lint(cx, NEEDLESS_LIFETIMES, span,
+                  "explicit lifetimes given in parameter types where they could be elided");
+    }
+}
+
+fn could_use_elision(func: &FnDecl, slf: Option<&ExplicitSelf>,
+                     named_lts: &[LifetimeDef]) -> bool {
     // There are two scenarios where elision works:
     // * no output references, all input references have different LT
     // * output references, exactly one input reference with same LT
+    // All lifetimes must be unnamed, 'static or defined without bounds on the
+    // level of the current item.
+
+    // check named LTs
+    let mut allowed_lts = HashSet::new();
+    for lt in named_lts {
+        if lt.bounds.is_empty() {
+            allowed_lts.insert(Named(lt.lifetime.name));
+        }
+    }
+    allowed_lts.insert(Unnamed);
+    allowed_lts.insert(Static);
 
     // these will collect all the lifetimes for references in arg/return types
     let mut input_visitor = RefVisitor(Vec::new());
@@ -50,8 +83,8 @@ fn could_use_elision(kind: FnKind, func: &FnDecl) -> bool {
 
     // extract lifetime in "self" argument for methods (there is a "self" argument
     // in func.inputs, but its type is TyInfer)
-    if let FnKind::FkMethod(_, sig, _) = kind {
-        match sig.explicit_self.node {
+    if let Some(slf) = slf {
+        match slf.node {
             SelfRegion(ref opt_lt, _, _) => input_visitor.record(opt_lt),
             SelfExplicit(ref ty, _) => walk_ty(&mut input_visitor, ty),
             _ => { }
@@ -69,6 +102,13 @@ fn could_use_elision(kind: FnKind, func: &FnDecl) -> bool {
     let input_lts = input_visitor.into_vec();
     let output_lts = output_visitor.into_vec();
 
+    // check for lifetimes from higher scopes
+    for lt in input_lts.iter().chain(output_lts.iter()) {
+        if !allowed_lts.contains(lt) {
+            return false;
+        }
+    }
+
     // no input lifetimes? easy case!
     if input_lts.is_empty() {
         return false;
index 36daa69fb317b1c90d19df800a208c6a810fafe8..7f463ec70b42ec71491a00ca64b7463e7c97b0dc 100755 (executable)
@@ -31,11 +31,13 @@ fn deep_reference_3<'a>(x: &'a u8, _y: u8) -> Result<&'a u8, ()> { Ok(x) }
 
 type Ref<'r> = &'r u8;
 
-fn lifetime_param_1<'a>(_x: Ref<'a>, _y: &'a u8) { }
+fn lifetime_param_1<'a>(_x: Ref<'a>, _y: &'a u8) { } // no error, same lifetime on two params
 
-fn lifetime_param_2<'a, 'b: 'a>(_x: Ref<'a>, _y: &'b u8) { }
+fn lifetime_param_2<'a, 'b>(_x: Ref<'a>, _y: &'b u8) { }
 //~^ERROR explicit lifetimes given
 
+fn lifetime_param_3<'a, 'b: 'a>(_x: Ref<'a>, _y: &'b u8) { } // no error, bounded lifetime
+
 struct X {
     x: u8,
 }
@@ -68,6 +70,7 @@ fn main() {
     let _ = deep_reference_3(&1, 2);
     lifetime_param_1(&1, &2);
     lifetime_param_2(&1, &2);
+    lifetime_param_3(&1, &2);
 
     let foo = X { x: 1 };
     foo.self_and_out();