|
1 | 1 | use syntax::ast::*;
|
2 | 2 | use rustc::lint::*;
|
3 | 3 | use syntax::codemap::Span;
|
4 |
| -use syntax::visit::{Visitor, walk_ty}; |
| 4 | +use syntax::visit::{Visitor, walk_ty, walk_ty_param_bound}; |
5 | 5 | use std::collections::HashSet;
|
6 | 6 |
|
7 | 7 | use utils::{in_external_macro, span_lint};
|
@@ -68,14 +68,7 @@ fn could_use_elision(func: &FnDecl, slf: Option<&ExplicitSelf>,
|
68 | 68 | // level of the current item.
|
69 | 69 |
|
70 | 70 | // check named LTs
|
71 |
| - let mut allowed_lts = HashSet::new(); |
72 |
| - for lt in named_lts { |
73 |
| - if lt.bounds.is_empty() { |
74 |
| - allowed_lts.insert(Named(lt.lifetime.name)); |
75 |
| - } |
76 |
| - } |
77 |
| - allowed_lts.insert(Unnamed); |
78 |
| - allowed_lts.insert(Static); |
| 71 | + let allowed_lts = allowed_lts_from(named_lts); |
79 | 72 |
|
80 | 73 | // these will collect all the lifetimes for references in arg/return types
|
81 | 74 | let mut input_visitor = RefVisitor(Vec::new());
|
@@ -142,6 +135,18 @@ fn could_use_elision(func: &FnDecl, slf: Option<&ExplicitSelf>,
|
142 | 135 | false
|
143 | 136 | }
|
144 | 137 |
|
| 138 | +fn allowed_lts_from(named_lts: &[LifetimeDef]) -> HashSet<RefLt> { |
| 139 | + let mut allowed_lts = HashSet::new(); |
| 140 | + for lt in named_lts { |
| 141 | + if lt.bounds.is_empty() { |
| 142 | + allowed_lts.insert(Named(lt.lifetime.name)); |
| 143 | + } |
| 144 | + } |
| 145 | + allowed_lts.insert(Unnamed); |
| 146 | + allowed_lts.insert(Static); |
| 147 | + allowed_lts |
| 148 | +} |
| 149 | + |
145 | 150 | /// Number of unique lifetimes in the given vector.
|
146 | 151 | fn unique_lifetimes(lts: &[RefLt]) -> usize {
|
147 | 152 | lts.iter().collect::<HashSet<_>>().len()
|
@@ -186,17 +191,34 @@ impl<'v> Visitor<'v> for RefVisitor {
|
186 | 191 | /// Are any lifetimes mentioned in the `where` clause? If yes, we don't try to
|
187 | 192 | /// reason about elision.
|
188 | 193 | fn has_where_lifetimes(where_clause: &WhereClause) -> bool {
|
189 |
| - let mut where_visitor = RefVisitor(Vec::new()); |
190 | 194 | for predicate in &where_clause.predicates {
|
191 | 195 | match *predicate {
|
192 | 196 | WherePredicate::RegionPredicate(..) => return true,
|
193 | 197 | WherePredicate::BoundPredicate(ref pred) => {
|
194 |
| - walk_ty(&mut where_visitor, &pred.bounded_ty); |
| 198 | + // a predicate like F: Trait or F: for<'a> Trait<'a> |
| 199 | + let mut visitor = RefVisitor(Vec::new()); |
| 200 | + // walk the type F, it may not contain LT refs |
| 201 | + walk_ty(&mut visitor, &pred.bounded_ty); |
| 202 | + if !visitor.0.is_empty() { return true; } |
| 203 | + // if the bounds define new lifetimes, they are fine to occur |
| 204 | + let allowed_lts = allowed_lts_from(&pred.bound_lifetimes); |
| 205 | + // now walk the bounds |
| 206 | + for bound in pred.bounds.iter() { |
| 207 | + walk_ty_param_bound(&mut visitor, bound); |
| 208 | + } |
| 209 | + // and check that all lifetimes are allowed |
| 210 | + for lt in visitor.into_vec() { |
| 211 | + if !allowed_lts.contains(<) { |
| 212 | + return true; |
| 213 | + } |
| 214 | + } |
195 | 215 | }
|
196 | 216 | WherePredicate::EqPredicate(ref pred) => {
|
197 |
| - walk_ty(&mut where_visitor, &pred.ty); |
| 217 | + let mut visitor = RefVisitor(Vec::new()); |
| 218 | + walk_ty(&mut visitor, &pred.ty); |
| 219 | + if !visitor.0.is_empty() { return true; } |
198 | 220 | }
|
199 | 221 | }
|
200 | 222 | }
|
201 |
| - !where_visitor.into_vec().is_empty() |
| 223 | + false |
202 | 224 | }
|
0 commit comments