2013-10-28 17:37:10 -04:00
|
|
|
// Copyright 2012-2013 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.
|
|
|
|
|
2014-11-25 21:17:11 -05:00
|
|
|
//! Name resolution for lifetimes.
|
|
|
|
//!
|
|
|
|
//! Name resolution for lifetimes follows MUCH simpler rules than the
|
|
|
|
//! full resolve. For example, lifetime names are never exported or
|
|
|
|
//! used between functions, and they operate in a purely top-down
|
|
|
|
//! way. Therefore we break lifetime name resolution into a separate pass.
|
2014-11-06 00:05:53 -08:00
|
|
|
|
2016-03-29 08:50:44 +03:00
|
|
|
use hir::map::Map;
|
2016-11-25 13:21:19 +02:00
|
|
|
use hir::def::Def;
|
2017-11-23 08:05:58 -05:00
|
|
|
use hir::def_id::{CrateNum, DefId, LocalDefId, LOCAL_CRATE};
|
|
|
|
use hir::ItemLocalId;
|
|
|
|
use ty::{self, TyCtxt};
|
2017-01-13 15:09:56 +02:00
|
|
|
|
|
|
|
use std::cell::Cell;
|
2015-04-03 02:51:38 +02:00
|
|
|
use std::mem::replace;
|
2017-11-23 08:05:58 -05:00
|
|
|
use std::rc::Rc;
|
2013-10-28 17:37:10 -04:00
|
|
|
use syntax::ast;
|
2017-01-25 17:32:44 +02:00
|
|
|
use syntax::attr;
|
2017-01-13 15:09:56 +02:00
|
|
|
use syntax::ptr::P;
|
2017-03-15 00:22:48 +00:00
|
|
|
use syntax_pos::Span;
|
2017-01-13 15:09:56 +02:00
|
|
|
use errors::DiagnosticBuilder;
|
2017-12-11 09:00:05 -05:00
|
|
|
use util::nodemap::{DefIdMap, FxHashMap, FxHashSet, NodeMap, NodeSet};
|
2017-11-23 16:41:51 +02:00
|
|
|
use std::slice;
|
2017-11-23 08:05:58 -05:00
|
|
|
use rustc::lint;
|
2014-05-31 18:53:13 -04:00
|
|
|
|
2017-10-16 21:07:26 +02:00
|
|
|
use hir::{self, GenericParamsExt};
|
2017-12-11 09:00:05 -05:00
|
|
|
use hir::intravisit::{self, NestedVisitorMap, Visitor};
|
2015-07-31 00:04:06 -07:00
|
|
|
|
2017-11-16 22:59:45 -08:00
|
|
|
/// The origin of a named lifetime definition.
|
|
|
|
///
|
|
|
|
/// This is used to prevent the usage of in-band lifetimes in `Fn`/`fn` syntax.
|
|
|
|
#[derive(Copy, Clone, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable, Debug)]
|
|
|
|
pub enum LifetimeDefOrigin {
|
|
|
|
// Explicit binders like `fn foo<'a>(x: &'a u8)`
|
|
|
|
Explicit,
|
|
|
|
// In-band declarations like `fn foo(x: &'a u8)`
|
|
|
|
InBand,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl LifetimeDefOrigin {
|
|
|
|
fn from_is_in_band(is_in_band: bool) -> Self {
|
|
|
|
if is_in_band {
|
|
|
|
LifetimeDefOrigin::InBand
|
|
|
|
} else {
|
|
|
|
LifetimeDefOrigin::Explicit
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-11-23 08:05:58 -05:00
|
|
|
// This counts the no of times a lifetime is used
|
|
|
|
#[derive(Clone, Copy, Debug)]
|
|
|
|
pub enum LifetimeUseSet<'tcx> {
|
|
|
|
One(&'tcx hir::Lifetime),
|
|
|
|
Many,
|
|
|
|
}
|
|
|
|
|
2015-01-28 08:34:18 -05:00
|
|
|
#[derive(Clone, Copy, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable, Debug)]
|
2017-01-08 22:40:04 +02:00
|
|
|
pub enum Region {
|
|
|
|
Static,
|
2017-12-11 09:00:05 -05:00
|
|
|
EarlyBound(
|
|
|
|
/* index */ u32,
|
|
|
|
/* lifetime decl */ DefId,
|
|
|
|
LifetimeDefOrigin,
|
|
|
|
),
|
|
|
|
LateBound(
|
|
|
|
ty::DebruijnIndex,
|
|
|
|
/* lifetime decl */ DefId,
|
|
|
|
LifetimeDefOrigin,
|
|
|
|
),
|
2017-01-13 15:09:56 +02:00
|
|
|
LateBoundAnon(ty::DebruijnIndex, /* anon index */ u32),
|
2017-08-15 17:05:25 +02:00
|
|
|
Free(DefId, /* lifetime decl */ DefId),
|
2014-05-31 18:53:13 -04:00
|
|
|
}
|
2013-10-28 17:37:10 -04:00
|
|
|
|
2017-01-11 17:35:54 +02:00
|
|
|
impl Region {
|
2017-12-11 09:00:05 -05:00
|
|
|
fn early(
|
|
|
|
hir_map: &Map,
|
|
|
|
index: &mut u32,
|
|
|
|
def: &hir::LifetimeDef,
|
|
|
|
) -> (hir::LifetimeName, Region) {
|
2017-01-11 17:35:54 +02:00
|
|
|
let i = *index;
|
|
|
|
*index += 1;
|
2017-08-15 17:05:25 +02:00
|
|
|
let def_id = hir_map.local_def_id(def.lifetime.id);
|
2017-11-16 22:59:45 -08:00
|
|
|
let origin = LifetimeDefOrigin::from_is_in_band(def.in_band);
|
2017-10-15 13:43:06 -07:00
|
|
|
debug!("Region::early: index={} def_id={:?}", i, def_id);
|
2017-11-16 22:59:45 -08:00
|
|
|
(def.lifetime.name, Region::EarlyBound(i, def_id, origin))
|
2017-01-11 17:35:54 +02:00
|
|
|
}
|
|
|
|
|
2017-09-19 16:36:54 -07:00
|
|
|
fn late(hir_map: &Map, def: &hir::LifetimeDef) -> (hir::LifetimeName, Region) {
|
2017-01-11 17:35:54 +02:00
|
|
|
let depth = ty::DebruijnIndex::new(1);
|
2017-08-15 17:05:25 +02:00
|
|
|
let def_id = hir_map.local_def_id(def.lifetime.id);
|
2017-11-16 22:59:45 -08:00
|
|
|
let origin = LifetimeDefOrigin::from_is_in_band(def.in_band);
|
|
|
|
(def.lifetime.name, Region::LateBound(depth, def_id, origin))
|
2017-01-11 17:35:54 +02:00
|
|
|
}
|
|
|
|
|
2017-01-13 15:09:56 +02:00
|
|
|
fn late_anon(index: &Cell<u32>) -> Region {
|
|
|
|
let i = index.get();
|
|
|
|
index.set(i + 1);
|
|
|
|
let depth = ty::DebruijnIndex::new(1);
|
|
|
|
Region::LateBoundAnon(depth, i)
|
|
|
|
}
|
|
|
|
|
2017-08-15 17:05:25 +02:00
|
|
|
fn id(&self) -> Option<DefId> {
|
2017-01-11 17:35:54 +02:00
|
|
|
match *self {
|
2017-12-11 09:00:05 -05:00
|
|
|
Region::Static | Region::LateBoundAnon(..) => None,
|
2017-01-13 15:09:56 +02:00
|
|
|
|
2017-12-11 09:00:05 -05:00
|
|
|
Region::EarlyBound(_, id, _) | Region::LateBound(_, id, _) | Region::Free(_, id) => {
|
|
|
|
Some(id)
|
|
|
|
}
|
2017-01-11 17:35:54 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn shifted(self, amount: u32) -> Region {
|
|
|
|
match self {
|
2017-11-16 22:59:45 -08:00
|
|
|
Region::LateBound(depth, id, origin) => {
|
|
|
|
Region::LateBound(depth.shifted(amount), id, origin)
|
2017-01-11 17:35:54 +02:00
|
|
|
}
|
2017-01-13 15:09:56 +02:00
|
|
|
Region::LateBoundAnon(depth, index) => {
|
|
|
|
Region::LateBoundAnon(depth.shifted(amount), index)
|
|
|
|
}
|
2017-12-11 09:00:05 -05:00
|
|
|
_ => self,
|
2017-01-13 15:09:56 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn from_depth(self, depth: u32) -> Region {
|
|
|
|
match self {
|
2017-12-11 09:00:05 -05:00
|
|
|
Region::LateBound(debruijn, id, origin) => Region::LateBound(
|
|
|
|
ty::DebruijnIndex {
|
|
|
|
depth: debruijn.depth - (depth - 1),
|
|
|
|
},
|
|
|
|
id,
|
|
|
|
origin,
|
|
|
|
),
|
|
|
|
Region::LateBoundAnon(debruijn, index) => Region::LateBoundAnon(
|
|
|
|
ty::DebruijnIndex {
|
|
|
|
depth: debruijn.depth - (depth - 1),
|
|
|
|
},
|
|
|
|
index,
|
|
|
|
),
|
|
|
|
_ => self,
|
2017-01-11 17:35:54 +02:00
|
|
|
}
|
|
|
|
}
|
2017-01-25 17:32:44 +02:00
|
|
|
|
2017-12-11 09:00:05 -05:00
|
|
|
fn subst(self, params: &[hir::Lifetime], map: &NamedRegionMap) -> Option<Region> {
|
2017-11-16 22:59:45 -08:00
|
|
|
if let Region::EarlyBound(index, _, _) = self {
|
2017-12-11 09:00:05 -05:00
|
|
|
params
|
|
|
|
.get(index as usize)
|
|
|
|
.and_then(|lifetime| map.defs.get(&lifetime.id).cloned())
|
2017-01-25 17:32:44 +02:00
|
|
|
} else {
|
|
|
|
Some(self)
|
|
|
|
}
|
|
|
|
}
|
2017-01-11 17:35:54 +02:00
|
|
|
}
|
|
|
|
|
2017-01-25 17:32:44 +02:00
|
|
|
/// A set containing, at most, one known element.
|
|
|
|
/// If two distinct values are inserted into a set, then it
|
|
|
|
/// becomes `Many`, which can be used to detect ambiguities.
|
|
|
|
#[derive(Copy, Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Debug)]
|
|
|
|
pub enum Set1<T> {
|
|
|
|
Empty,
|
|
|
|
One(T),
|
2017-12-11 09:00:05 -05:00
|
|
|
Many,
|
2017-01-25 17:32:44 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
impl<T: PartialEq> Set1<T> {
|
|
|
|
pub fn insert(&mut self, value: T) {
|
|
|
|
if let Set1::Empty = *self {
|
|
|
|
*self = Set1::One(value);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if let Set1::One(ref old) = *self {
|
|
|
|
if *old == value {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
*self = Set1::Many;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub type ObjectLifetimeDefault = Set1<Region>;
|
|
|
|
|
2017-11-23 08:05:58 -05:00
|
|
|
/// Maps the id of each lifetime reference to the lifetime decl
|
|
|
|
/// that it corresponds to.
|
|
|
|
///
|
|
|
|
/// FIXME. This struct gets converted to a `ResolveLifetimes` for
|
|
|
|
/// actual use. It has the same data, but indexed by `DefIndex`. This
|
|
|
|
/// is silly.
|
|
|
|
#[derive(Default)]
|
|
|
|
struct NamedRegionMap {
|
2016-04-21 05:10:10 -04:00
|
|
|
// maps from every use of a named (not anonymous) lifetime to a
|
2017-01-08 22:40:04 +02:00
|
|
|
// `Region` describing how that region is bound
|
|
|
|
pub defs: NodeMap<Region>,
|
2016-04-21 05:10:10 -04:00
|
|
|
|
2017-01-06 14:35:23 -05:00
|
|
|
// the set of lifetime def ids that are late-bound; a region can
|
|
|
|
// be late-bound if (a) it does NOT appear in a where-clause and
|
|
|
|
// (b) it DOES appear in the arguments.
|
|
|
|
pub late_bound: NodeSet,
|
|
|
|
|
2017-01-25 17:32:44 +02:00
|
|
|
// For each type and trait definition, maps type parameters
|
|
|
|
// to the trait object lifetime defaults computed from them.
|
|
|
|
pub object_lifetime_defaults: NodeMap<Vec<ObjectLifetimeDefault>>,
|
2016-04-21 05:10:10 -04:00
|
|
|
}
|
2013-10-28 17:37:10 -04:00
|
|
|
|
2017-11-23 08:05:58 -05:00
|
|
|
/// See `NamedRegionMap`.
|
|
|
|
pub struct ResolveLifetimes {
|
|
|
|
defs: FxHashMap<LocalDefId, Rc<FxHashMap<ItemLocalId, Region>>>,
|
|
|
|
late_bound: FxHashMap<LocalDefId, Rc<FxHashSet<ItemLocalId>>>,
|
|
|
|
object_lifetime_defaults:
|
|
|
|
FxHashMap<LocalDefId, Rc<FxHashMap<ItemLocalId, Rc<Vec<ObjectLifetimeDefault>>>>>,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl_stable_hash_for!(struct ::middle::resolve_lifetime::ResolveLifetimes {
|
|
|
|
defs,
|
|
|
|
late_bound,
|
|
|
|
object_lifetime_defaults
|
|
|
|
});
|
|
|
|
|
2016-04-21 05:10:10 -04:00
|
|
|
struct LifetimeContext<'a, 'tcx: 'a> {
|
2017-11-23 08:05:58 -05:00
|
|
|
tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
2016-04-21 05:10:10 -04:00
|
|
|
map: &'a mut NamedRegionMap,
|
2017-01-08 22:40:04 +02:00
|
|
|
scope: ScopeRef<'a>,
|
2015-02-05 21:46:01 +13:00
|
|
|
// Deep breath. Our representation for poly trait refs contains a single
|
|
|
|
// binder and thus we only allow a single level of quantification. However,
|
|
|
|
// the syntax of Rust permits quantification in two places, e.g., `T: for <'a> Foo<'a>`
|
|
|
|
// and `for <'a, 'b> &'b T: Foo<'a>`. In order to get the de Bruijn indices
|
|
|
|
// correct when representing these constraints, we should only introduce one
|
|
|
|
// scope. However, we want to support both locations for the quantifier and
|
|
|
|
// during lifetime resolution we want precise information (so we can't
|
|
|
|
// desugar in an earlier phase).
|
|
|
|
|
|
|
|
// SO, if we encounter a quantifier at the outer scope, we set
|
|
|
|
// trait_ref_hack to true (and introduce a scope), and then if we encounter
|
|
|
|
// a quantifier at the inner scope, we error. If trait_ref_hack is false,
|
|
|
|
// then we introduce the scope at the inner quantifier.
|
|
|
|
|
|
|
|
// I'm sorry.
|
|
|
|
trait_ref_hack: bool,
|
2015-04-03 02:51:38 +02:00
|
|
|
|
2017-11-16 22:59:45 -08:00
|
|
|
// Used to disallow the use of in-band lifetimes in `fn` or `Fn` syntax.
|
|
|
|
is_in_fn_syntax: bool,
|
|
|
|
|
2015-04-03 02:51:38 +02:00
|
|
|
// List of labels in the function/method currently under analysis.
|
2015-09-23 20:04:49 +03:00
|
|
|
labels_in_fn: Vec<(ast::Name, Span)>,
|
2017-01-25 17:32:44 +02:00
|
|
|
|
|
|
|
// Cache for cross-crate per-definition object lifetime defaults.
|
|
|
|
xcrate_object_lifetime_defaults: DefIdMap<Vec<ObjectLifetimeDefault>>,
|
2017-11-23 08:05:58 -05:00
|
|
|
|
|
|
|
lifetime_uses: DefIdMap<LifetimeUseSet<'tcx>>,
|
2013-10-28 17:37:10 -04:00
|
|
|
}
|
|
|
|
|
2017-01-11 17:35:54 +02:00
|
|
|
#[derive(Debug)]
|
2017-01-08 22:40:04 +02:00
|
|
|
enum Scope<'a> {
|
2017-01-11 17:35:54 +02:00
|
|
|
/// Declares lifetimes, and each can be early-bound or late-bound.
|
|
|
|
/// The `DebruijnIndex` of late-bound lifetimes starts at `1` and
|
|
|
|
/// it should be shifted by the number of `Binder`s in between the
|
|
|
|
/// declaration `Binder` and the location it's referenced from.
|
|
|
|
Binder {
|
2017-09-19 16:36:54 -07:00
|
|
|
lifetimes: FxHashMap<hir::LifetimeName, Region>,
|
2017-10-15 13:43:06 -07:00
|
|
|
|
|
|
|
/// if we extend this scope with another scope, what is the next index
|
|
|
|
/// we should use for an early-bound region?
|
|
|
|
next_early_index: u32,
|
|
|
|
|
2017-12-11 09:00:05 -05:00
|
|
|
s: ScopeRef<'a>,
|
2017-01-08 22:40:04 +02:00
|
|
|
},
|
|
|
|
|
2017-01-11 17:35:54 +02:00
|
|
|
/// Lifetimes introduced by a fn are scoped to the call-site for that fn,
|
|
|
|
/// if this is a fn body, otherwise the original definitions are used.
|
2017-01-13 15:09:56 +02:00
|
|
|
/// Unspecified lifetimes are inferred, unless an elision scope is nested,
|
|
|
|
/// e.g. `(&T, fn(&T) -> &T);` becomes `(&'_ T, for<'a> fn(&'a T) -> &'a T)`.
|
2017-01-11 17:35:54 +02:00
|
|
|
Body {
|
|
|
|
id: hir::BodyId,
|
2017-12-11 09:00:05 -05:00
|
|
|
s: ScopeRef<'a>,
|
2017-01-08 22:40:04 +02:00
|
|
|
},
|
|
|
|
|
2017-01-13 15:09:56 +02:00
|
|
|
/// A scope which either determines unspecified lifetimes or errors
|
|
|
|
/// on them (e.g. due to ambiguity). For more details, see `Elide`.
|
|
|
|
Elision {
|
|
|
|
elide: Elide,
|
2017-12-11 09:00:05 -05:00
|
|
|
s: ScopeRef<'a>,
|
2017-01-13 15:09:56 +02:00
|
|
|
},
|
|
|
|
|
2017-01-25 17:32:44 +02:00
|
|
|
/// Use a specific lifetime (if `Some`) or leave it unset (to be
|
|
|
|
/// inferred in a function body or potentially error outside one),
|
|
|
|
/// for the default choice of lifetime in a trait object type.
|
|
|
|
ObjectLifetimeDefault {
|
|
|
|
lifetime: Option<Region>,
|
2017-12-11 09:00:05 -05:00
|
|
|
s: ScopeRef<'a>,
|
2017-01-25 17:32:44 +02:00
|
|
|
},
|
|
|
|
|
2017-12-11 09:00:05 -05:00
|
|
|
Root,
|
2013-10-28 17:37:10 -04:00
|
|
|
}
|
|
|
|
|
2017-01-13 15:09:56 +02:00
|
|
|
#[derive(Clone, Debug)]
|
|
|
|
enum Elide {
|
|
|
|
/// Use a fresh anonymous late-bound lifetime each time, by
|
|
|
|
/// incrementing the counter to generate sequential indices.
|
|
|
|
FreshLateAnon(Cell<u32>),
|
|
|
|
/// Always use this one lifetime.
|
|
|
|
Exact(Region),
|
|
|
|
/// Less or more than one lifetime were found, error on unspecified.
|
2017-12-11 09:00:05 -05:00
|
|
|
Error(Vec<ElisionFailureInfo>),
|
2017-01-13 15:09:56 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(Clone, Debug)]
|
|
|
|
struct ElisionFailureInfo {
|
|
|
|
/// Where we can find the argument pattern.
|
|
|
|
parent: Option<hir::BodyId>,
|
|
|
|
/// The index of the argument in the original definition.
|
|
|
|
index: usize,
|
|
|
|
lifetime_count: usize,
|
2017-12-11 09:00:05 -05:00
|
|
|
have_bound_regions: bool,
|
2017-01-13 15:09:56 +02:00
|
|
|
}
|
|
|
|
|
2017-01-08 22:40:04 +02:00
|
|
|
type ScopeRef<'a> = &'a Scope<'a>;
|
2014-02-26 14:59:49 +01:00
|
|
|
|
2017-01-08 22:40:04 +02:00
|
|
|
const ROOT_SCOPE: ScopeRef<'static> = &Scope::Root;
|
2014-09-12 13:10:30 +03:00
|
|
|
|
2017-11-23 08:05:58 -05:00
|
|
|
pub fn provide(providers: &mut ty::maps::Providers) {
|
|
|
|
*providers = ty::maps::Providers {
|
|
|
|
resolve_lifetimes,
|
|
|
|
|
|
|
|
named_region_map: |tcx, id| {
|
|
|
|
let id = LocalDefId::from_def_id(DefId::local(id)); // (*)
|
|
|
|
tcx.resolve_lifetimes(LOCAL_CRATE).defs.get(&id).cloned()
|
|
|
|
},
|
|
|
|
|
|
|
|
is_late_bound_map: |tcx, id| {
|
|
|
|
let id = LocalDefId::from_def_id(DefId::local(id)); // (*)
|
|
|
|
tcx.resolve_lifetimes(LOCAL_CRATE)
|
|
|
|
.late_bound
|
|
|
|
.get(&id)
|
|
|
|
.cloned()
|
|
|
|
},
|
|
|
|
|
|
|
|
object_lifetime_defaults_map: |tcx, id| {
|
|
|
|
let id = LocalDefId::from_def_id(DefId::local(id)); // (*)
|
|
|
|
tcx.resolve_lifetimes(LOCAL_CRATE)
|
|
|
|
.object_lifetime_defaults
|
|
|
|
.get(&id)
|
|
|
|
.cloned()
|
|
|
|
},
|
|
|
|
|
|
|
|
..*providers
|
|
|
|
};
|
|
|
|
|
|
|
|
// (*) FIXME the query should be defined to take a LocalDefId
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Computes the `ResolveLifetimes` map that contains data for the
|
|
|
|
/// entire crate. You should not read the result of this query
|
|
|
|
/// directly, but rather use `named_region_map`, `is_late_bound_map`,
|
|
|
|
/// etc.
|
|
|
|
fn resolve_lifetimes<'tcx>(
|
|
|
|
tcx: TyCtxt<'_, 'tcx, 'tcx>,
|
|
|
|
for_krate: CrateNum,
|
|
|
|
) -> Rc<ResolveLifetimes> {
|
|
|
|
assert_eq!(for_krate, LOCAL_CRATE);
|
|
|
|
|
2017-12-11 15:52:46 -05:00
|
|
|
let named_region_map = krate(tcx);
|
2017-11-23 08:05:58 -05:00
|
|
|
|
|
|
|
let mut defs = FxHashMap();
|
|
|
|
for (k, v) in named_region_map.defs {
|
|
|
|
let hir_id = tcx.hir.node_to_hir_id(k);
|
|
|
|
let map = defs.entry(hir_id.owner_local_def_id())
|
|
|
|
.or_insert_with(|| Rc::new(FxHashMap()));
|
|
|
|
Rc::get_mut(map).unwrap().insert(hir_id.local_id, v);
|
|
|
|
}
|
|
|
|
let mut late_bound = FxHashMap();
|
|
|
|
for k in named_region_map.late_bound {
|
|
|
|
let hir_id = tcx.hir.node_to_hir_id(k);
|
|
|
|
let map = late_bound
|
|
|
|
.entry(hir_id.owner_local_def_id())
|
|
|
|
.or_insert_with(|| Rc::new(FxHashSet()));
|
|
|
|
Rc::get_mut(map).unwrap().insert(hir_id.local_id);
|
|
|
|
}
|
|
|
|
let mut object_lifetime_defaults = FxHashMap();
|
|
|
|
for (k, v) in named_region_map.object_lifetime_defaults {
|
|
|
|
let hir_id = tcx.hir.node_to_hir_id(k);
|
|
|
|
let map = object_lifetime_defaults
|
|
|
|
.entry(hir_id.owner_local_def_id())
|
|
|
|
.or_insert_with(|| Rc::new(FxHashMap()));
|
|
|
|
Rc::get_mut(map)
|
|
|
|
.unwrap()
|
|
|
|
.insert(hir_id.local_id, Rc::new(v));
|
|
|
|
}
|
|
|
|
|
|
|
|
Rc::new(ResolveLifetimes {
|
|
|
|
defs,
|
|
|
|
late_bound,
|
|
|
|
object_lifetime_defaults,
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2017-12-11 15:52:46 -05:00
|
|
|
fn krate<'tcx>(tcx: TyCtxt<'_, 'tcx, 'tcx>) -> NamedRegionMap {
|
2017-11-23 08:05:58 -05:00
|
|
|
let krate = tcx.hir.krate();
|
2016-04-21 05:10:10 -04:00
|
|
|
let mut map = NamedRegionMap {
|
|
|
|
defs: NodeMap(),
|
2017-01-06 14:35:23 -05:00
|
|
|
late_bound: NodeSet(),
|
2017-11-23 08:05:58 -05:00
|
|
|
object_lifetime_defaults: compute_object_lifetime_defaults(tcx),
|
2016-04-21 05:10:10 -04:00
|
|
|
};
|
2017-11-23 08:05:58 -05:00
|
|
|
{
|
2017-01-11 17:35:54 +02:00
|
|
|
let mut visitor = LifetimeContext {
|
2017-11-23 08:05:58 -05:00
|
|
|
tcx,
|
2016-04-21 05:10:10 -04:00
|
|
|
map: &mut map,
|
2017-01-08 22:40:04 +02:00
|
|
|
scope: ROOT_SCOPE,
|
2015-12-11 20:59:11 +13:00
|
|
|
trait_ref_hack: false,
|
2017-11-16 22:59:45 -08:00
|
|
|
is_in_fn_syntax: false,
|
2015-12-11 20:59:11 +13:00
|
|
|
labels_in_fn: vec![],
|
2017-01-25 17:32:44 +02:00
|
|
|
xcrate_object_lifetime_defaults: DefIdMap(),
|
2017-11-23 08:05:58 -05:00
|
|
|
lifetime_uses: DefIdMap(),
|
2017-01-11 17:35:54 +02:00
|
|
|
};
|
|
|
|
for (_, item) in &krate.items {
|
|
|
|
visitor.visit_item(item);
|
|
|
|
}
|
2017-11-23 08:05:58 -05:00
|
|
|
}
|
2017-12-11 15:52:46 -05:00
|
|
|
map
|
2013-10-28 17:37:10 -04:00
|
|
|
}
|
|
|
|
|
2016-11-09 16:45:26 -05:00
|
|
|
impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
|
2016-11-28 14:00:26 -05:00
|
|
|
fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> {
|
2017-11-23 08:05:58 -05:00
|
|
|
NestedVisitorMap::All(&self.tcx.hir)
|
2017-01-11 17:35:54 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
// We want to nest trait/impl items in their parent, but nothing else.
|
|
|
|
fn visit_nested_item(&mut self, _: hir::ItemId) {}
|
|
|
|
|
|
|
|
fn visit_nested_body(&mut self, body: hir::BodyId) {
|
|
|
|
// Each body has their own set of labels, save labels.
|
|
|
|
let saved = replace(&mut self.labels_in_fn, vec![]);
|
2017-11-23 08:05:58 -05:00
|
|
|
let body = self.tcx.hir.body(body);
|
2017-01-11 17:35:54 +02:00
|
|
|
extract_labels(self, body);
|
2017-12-11 09:00:05 -05:00
|
|
|
self.with(
|
|
|
|
Scope::Body {
|
|
|
|
id: body.id(),
|
|
|
|
s: self.scope,
|
|
|
|
},
|
|
|
|
|_, this| {
|
|
|
|
this.visit_body(body);
|
|
|
|
},
|
|
|
|
);
|
2017-01-11 17:35:54 +02:00
|
|
|
replace(&mut self.labels_in_fn, saved);
|
2016-11-04 18:20:15 -04:00
|
|
|
}
|
|
|
|
|
2016-11-09 16:45:26 -05:00
|
|
|
fn visit_item(&mut self, item: &'tcx hir::Item) {
|
2017-01-11 17:35:54 +02:00
|
|
|
match item.node {
|
|
|
|
hir::ItemFn(ref decl, _, _, _, ref generics, _) => {
|
2017-11-23 08:05:58 -05:00
|
|
|
self.visit_early_late(None,
|
|
|
|
decl,
|
|
|
|
generics,
|
|
|
|
|this| {
|
|
|
|
intravisit::walk_item(this, item);
|
2017-01-11 17:35:54 +02:00
|
|
|
});
|
|
|
|
}
|
2017-12-11 09:00:05 -05:00
|
|
|
hir::ItemExternCrate(_)
|
|
|
|
| hir::ItemUse(..)
|
|
|
|
| hir::ItemMod(..)
|
|
|
|
| hir::ItemAutoImpl(..)
|
|
|
|
| hir::ItemForeignMod(..)
|
|
|
|
| hir::ItemGlobalAsm(..) => {
|
2017-01-11 17:35:54 +02:00
|
|
|
// These sorts of items have no lifetime parameters at all.
|
|
|
|
intravisit::walk_item(self, item);
|
|
|
|
}
|
2017-12-11 09:00:05 -05:00
|
|
|
hir::ItemStatic(..) | hir::ItemConst(..) => {
|
2017-01-13 15:09:56 +02:00
|
|
|
// No lifetime parameters, but implied 'static.
|
|
|
|
let scope = Scope::Elision {
|
2017-02-05 18:14:14 +01:00
|
|
|
elide: Elide::Exact(Region::Static),
|
2017-12-11 09:00:05 -05:00
|
|
|
s: ROOT_SCOPE,
|
2017-01-13 15:09:56 +02:00
|
|
|
};
|
|
|
|
self.with(scope, |_, this| intravisit::walk_item(this, item));
|
|
|
|
}
|
2017-12-11 09:00:05 -05:00
|
|
|
hir::ItemTy(_, ref generics)
|
|
|
|
| hir::ItemEnum(_, ref generics)
|
|
|
|
| hir::ItemStruct(_, ref generics)
|
|
|
|
| hir::ItemUnion(_, ref generics)
|
|
|
|
| hir::ItemTrait(_, _, ref generics, ..)
|
2017-10-02 12:28:16 +00:00
|
|
|
| hir::ItemTraitAlias(ref generics, ..)
|
2017-12-11 09:00:05 -05:00
|
|
|
| hir::ItemImpl(_, _, _, ref generics, ..) => {
|
2017-01-11 17:35:54 +02:00
|
|
|
// These kinds of items have only early bound lifetime parameters.
|
|
|
|
let mut index = if let hir::ItemTrait(..) = item.node {
|
|
|
|
1 // Self comes before lifetimes
|
|
|
|
} else {
|
|
|
|
0
|
|
|
|
};
|
2017-10-16 21:07:26 +02:00
|
|
|
let lifetimes = generics.lifetimes()
|
2017-11-23 08:05:58 -05:00
|
|
|
.map(|def| Region::early(&self.tcx.hir, &mut index, def))
|
2017-12-11 09:00:05 -05:00
|
|
|
.collect();
|
2017-10-16 21:07:26 +02:00
|
|
|
let next_early_index = index + generics.ty_params().count() as u32;
|
2017-01-11 17:35:54 +02:00
|
|
|
let scope = Scope::Binder {
|
2017-07-03 11:19:51 -07:00
|
|
|
lifetimes,
|
2017-10-15 13:43:06 -07:00
|
|
|
next_early_index,
|
2017-12-11 09:00:05 -05:00
|
|
|
s: ROOT_SCOPE,
|
2017-01-11 17:35:54 +02:00
|
|
|
};
|
|
|
|
self.with(scope, |old_scope, this| {
|
2017-10-16 21:07:26 +02:00
|
|
|
this.check_lifetime_params(old_scope, &generics.params);
|
2015-11-17 17:51:44 -05:00
|
|
|
intravisit::walk_item(this, item);
|
2017-01-11 17:35:54 +02:00
|
|
|
});
|
2014-11-15 17:25:05 -05:00
|
|
|
}
|
2017-01-11 17:35:54 +02:00
|
|
|
}
|
2013-10-28 17:37:10 -04:00
|
|
|
}
|
|
|
|
|
2016-11-09 16:45:26 -05:00
|
|
|
fn visit_foreign_item(&mut self, item: &'tcx hir::ForeignItem) {
|
2017-01-11 17:35:54 +02:00
|
|
|
match item.node {
|
|
|
|
hir::ForeignItemFn(ref decl, _, ref generics) => {
|
2017-11-23 08:05:58 -05:00
|
|
|
self.visit_early_late(None,
|
|
|
|
decl,
|
|
|
|
generics,
|
|
|
|
|this| {
|
|
|
|
intravisit::walk_foreign_item(this, item);
|
|
|
|
})
|
2013-10-28 17:37:10 -04:00
|
|
|
}
|
2017-01-11 17:35:54 +02:00
|
|
|
hir::ForeignItemStatic(..) => {
|
|
|
|
intravisit::walk_foreign_item(self, item);
|
2013-10-28 17:37:10 -04:00
|
|
|
}
|
2017-09-03 19:53:58 +01:00
|
|
|
hir::ForeignItemType => {
|
|
|
|
intravisit::walk_foreign_item(self, item);
|
|
|
|
}
|
2013-10-28 17:37:10 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-11-09 16:45:26 -05:00
|
|
|
fn visit_ty(&mut self, ty: &'tcx hir::Ty) {
|
2017-10-15 13:43:06 -07:00
|
|
|
debug!("visit_ty: ty={:?}", ty);
|
2014-11-15 16:47:59 -05:00
|
|
|
match ty.node {
|
2015-07-31 00:04:06 -07:00
|
|
|
hir::TyBareFn(ref c) => {
|
2017-10-15 13:43:06 -07:00
|
|
|
let next_early_index = self.next_early_index();
|
2017-11-16 22:59:45 -08:00
|
|
|
let was_in_fn_syntax = self.is_in_fn_syntax;
|
|
|
|
self.is_in_fn_syntax = true;
|
2017-01-11 17:35:54 +02:00
|
|
|
let scope = Scope::Binder {
|
2017-10-16 21:07:26 +02:00
|
|
|
lifetimes: c.generic_params
|
|
|
|
.lifetimes()
|
2017-11-23 08:05:58 -05:00
|
|
|
.map(|def| Region::late(&self.tcx.hir, def))
|
2017-12-11 09:00:05 -05:00
|
|
|
.collect(),
|
|
|
|
s: self.scope,
|
2017-11-23 08:05:58 -05:00
|
|
|
next_early_index,
|
2017-01-08 22:40:04 +02:00
|
|
|
};
|
2017-01-11 17:35:54 +02:00
|
|
|
self.with(scope, |old_scope, this| {
|
2014-11-15 16:47:59 -05:00
|
|
|
// a bare fn has no bounds, so everything
|
|
|
|
// contained within is scoped within its binder.
|
2017-10-16 21:07:26 +02:00
|
|
|
this.check_lifetime_params(old_scope, &c.generic_params);
|
2015-11-17 17:51:44 -05:00
|
|
|
intravisit::walk_ty(this, ty);
|
2014-11-15 16:47:59 -05:00
|
|
|
});
|
2017-11-16 22:59:45 -08:00
|
|
|
self.is_in_fn_syntax = was_in_fn_syntax;
|
2014-11-15 16:47:59 -05:00
|
|
|
}
|
2017-01-24 17:17:06 +02:00
|
|
|
hir::TyTraitObject(ref bounds, ref lifetime) => {
|
|
|
|
for bound in bounds {
|
|
|
|
self.visit_poly_trait_ref(bound, hir::TraitBoundModifier::None);
|
|
|
|
}
|
2017-01-25 17:32:44 +02:00
|
|
|
if lifetime.is_elided() {
|
|
|
|
self.resolve_object_lifetime_default(lifetime)
|
|
|
|
} else {
|
2017-01-24 17:17:06 +02:00
|
|
|
self.visit_lifetime(lifetime);
|
|
|
|
}
|
|
|
|
}
|
2017-01-25 17:32:44 +02:00
|
|
|
hir::TyRptr(ref lifetime_ref, ref mt) => {
|
|
|
|
self.visit_lifetime(lifetime_ref);
|
|
|
|
let scope = Scope::ObjectLifetimeDefault {
|
|
|
|
lifetime: self.map.defs.get(&lifetime_ref.id).cloned(),
|
2017-12-11 09:00:05 -05:00
|
|
|
s: self.scope,
|
2017-01-25 17:32:44 +02:00
|
|
|
};
|
|
|
|
self.with(scope, |_, this| this.visit_ty(&mt.ty));
|
|
|
|
}
|
2017-10-15 13:43:06 -07:00
|
|
|
hir::TyImplTraitExistential(ref exist_ty, ref lifetimes) => {
|
|
|
|
// Resolve the lifetimes that are applied to the existential type.
|
|
|
|
// These are resolved in the current scope.
|
|
|
|
// `fn foo<'a>() -> impl MyTrait<'a> { ... }` desugars to
|
|
|
|
// `fn foo<'a>() -> MyAnonTy<'a> { ... }`
|
|
|
|
// ^ ^this gets resolved in the current scope
|
|
|
|
for lifetime in lifetimes {
|
|
|
|
self.visit_lifetime(lifetime);
|
|
|
|
|
|
|
|
// Check for predicates like `impl for<'a> SomeTrait<impl OtherTrait<'a>>`
|
|
|
|
// and ban them. Type variables instantiated inside binders aren't
|
|
|
|
// well-supported at the moment, so this doesn't work.
|
|
|
|
// In the future, this should be fixed and this error should be removed.
|
|
|
|
let def = self.map.defs.get(&lifetime.id);
|
2017-11-16 22:59:45 -08:00
|
|
|
if let Some(&Region::LateBound(_, def_id, _)) = def {
|
2017-11-23 08:05:58 -05:00
|
|
|
if let Some(node_id) = self.tcx.hir.as_local_node_id(def_id) {
|
2017-10-15 13:43:06 -07:00
|
|
|
// Ensure that the parent of the def is an item, not HRTB
|
2017-11-23 08:05:58 -05:00
|
|
|
let parent_id = self.tcx.hir.get_parent_node(node_id);
|
2017-10-15 13:43:06 -07:00
|
|
|
let parent_impl_id = hir::ImplItemId { node_id: parent_id };
|
|
|
|
let parent_trait_id = hir::TraitItemId { node_id: parent_id };
|
2017-11-23 08:05:58 -05:00
|
|
|
let krate = self.tcx.hir.forest.krate();
|
2017-12-11 09:00:05 -05:00
|
|
|
if !(krate.items.contains_key(&parent_id)
|
|
|
|
|| krate.impl_items.contains_key(&parent_impl_id)
|
|
|
|
|| krate.trait_items.contains_key(&parent_trait_id))
|
2017-10-15 13:43:06 -07:00
|
|
|
{
|
2017-12-11 09:00:05 -05:00
|
|
|
span_err!(
|
2017-11-23 08:05:58 -05:00
|
|
|
self.tcx.sess,
|
2017-12-11 09:00:05 -05:00
|
|
|
lifetime.span,
|
|
|
|
E0657,
|
|
|
|
"`impl Trait` can only capture lifetimes \
|
|
|
|
bound at the fn or impl level"
|
|
|
|
);
|
2017-10-15 13:43:06 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Resolve the lifetimes in the bounds to the lifetime defs in the generics.
|
|
|
|
// `fn foo<'a>() -> impl MyTrait<'a> { ... }` desugars to
|
|
|
|
// `abstract type MyAnonTy<'b>: MyTrait<'b>;`
|
|
|
|
// ^ ^ this gets resolved in the scope of
|
|
|
|
// the exist_ty generics
|
2017-12-11 09:00:05 -05:00
|
|
|
let hir::ExistTy {
|
|
|
|
ref generics,
|
|
|
|
ref bounds,
|
|
|
|
} = *exist_ty;
|
2017-10-15 13:43:06 -07:00
|
|
|
let mut index = self.next_early_index();
|
|
|
|
debug!("visit_ty: index = {}", index);
|
|
|
|
|
2017-12-09 21:54:58 -08:00
|
|
|
let mut elision = None;
|
|
|
|
let mut lifetimes = FxHashMap();
|
2017-10-16 21:07:26 +02:00
|
|
|
for lt_def in generics.lifetimes() {
|
2017-12-09 21:54:58 -08:00
|
|
|
let (lt_name, region) = Region::early(&self.tcx.hir, &mut index, <_def);
|
|
|
|
if let hir::LifetimeName::Underscore = lt_name {
|
|
|
|
// Pick the elided lifetime "definition" if one exists and use it to make an
|
|
|
|
// elision scope.
|
|
|
|
elision = Some(region);
|
|
|
|
} else {
|
|
|
|
lifetimes.insert(lt_name, region);
|
2017-10-15 13:43:06 -07:00
|
|
|
}
|
2017-12-09 21:54:58 -08:00
|
|
|
}
|
|
|
|
|
2017-10-16 21:07:26 +02:00
|
|
|
let next_early_index = index + generics.ty_params().count() as u32;
|
2017-12-09 21:54:58 -08:00
|
|
|
|
|
|
|
if let Some(elision_region) = elision {
|
|
|
|
let scope = Scope::Elision {
|
|
|
|
elide: Elide::Exact(elision_region),
|
|
|
|
s: self.scope
|
|
|
|
};
|
|
|
|
self.with(scope, |_old_scope, this| {
|
|
|
|
let scope = Scope::Binder { lifetimes, next_early_index, s: this.scope };
|
|
|
|
this.with(scope, |_old_scope, this| {
|
|
|
|
this.visit_generics(generics);
|
|
|
|
for bound in bounds {
|
|
|
|
this.visit_ty_param_bound(bound);
|
|
|
|
}
|
|
|
|
});
|
|
|
|
});
|
|
|
|
} else {
|
|
|
|
let scope = Scope::Binder { lifetimes, next_early_index, s: self.scope };
|
|
|
|
self.with(scope, |_old_scope, this| {
|
|
|
|
this.visit_generics(generics);
|
|
|
|
for bound in bounds {
|
|
|
|
this.visit_ty_param_bound(bound);
|
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
2017-10-15 13:43:06 -07:00
|
|
|
}
|
2017-12-11 09:00:05 -05:00
|
|
|
_ => intravisit::walk_ty(self, ty),
|
2014-11-15 16:47:59 -05:00
|
|
|
}
|
2013-10-28 17:37:10 -04:00
|
|
|
}
|
|
|
|
|
2016-11-09 16:45:26 -05:00
|
|
|
fn visit_trait_item(&mut self, trait_item: &'tcx hir::TraitItem) {
|
2017-12-12 21:11:15 -05:00
|
|
|
use self::hir::TraitItemKind::*;
|
|
|
|
match trait_item.node {
|
|
|
|
Method(ref sig, _) => {
|
|
|
|
let tcx = self.tcx;
|
|
|
|
self.visit_early_late(
|
|
|
|
Some(tcx.hir.get_parent(trait_item.id)),
|
|
|
|
&sig.decl,
|
|
|
|
&trait_item.generics,
|
|
|
|
|this| intravisit::walk_trait_item(this, trait_item),
|
|
|
|
);
|
|
|
|
},
|
|
|
|
Type(ref bounds, ref ty) => {
|
|
|
|
let generics = &trait_item.generics;
|
|
|
|
let mut index = self.next_early_index();
|
|
|
|
debug!("visit_ty: index = {}", index);
|
2017-10-16 21:07:26 +02:00
|
|
|
let lifetimes = generics.lifetimes()
|
2017-12-12 21:11:15 -05:00
|
|
|
.map(|lt_def| Region::early(&self.tcx.hir, &mut index, lt_def))
|
|
|
|
.collect();
|
|
|
|
|
2017-10-16 21:07:26 +02:00
|
|
|
let next_early_index = index + generics.ty_params().count() as u32;
|
2017-12-12 21:11:15 -05:00
|
|
|
let scope = Scope::Binder { lifetimes, next_early_index, s: self.scope };
|
|
|
|
self.with(scope, |_old_scope, this| {
|
|
|
|
this.visit_generics(generics);
|
|
|
|
for bound in bounds {
|
|
|
|
this.visit_ty_param_bound(bound);
|
|
|
|
}
|
|
|
|
if let Some(ty) = ty {
|
|
|
|
this.visit_ty(ty);
|
|
|
|
}
|
|
|
|
});
|
|
|
|
},
|
|
|
|
Const(_, _) => {
|
|
|
|
// Only methods and types support generics.
|
2017-10-16 21:07:26 +02:00
|
|
|
assert!(trait_item.generics.params.is_empty());
|
2017-12-12 21:11:15 -05:00
|
|
|
intravisit::walk_trait_item(self, trait_item);
|
|
|
|
},
|
2015-03-10 12:28:44 +02:00
|
|
|
}
|
2017-01-11 17:35:54 +02:00
|
|
|
}
|
2015-04-03 02:51:38 +02:00
|
|
|
|
2017-01-11 17:35:54 +02:00
|
|
|
fn visit_impl_item(&mut self, impl_item: &'tcx hir::ImplItem) {
|
2017-12-12 21:11:15 -05:00
|
|
|
use self::hir::ImplItemKind::*;
|
|
|
|
match impl_item.node {
|
|
|
|
Method(ref sig, _) => {
|
|
|
|
let tcx = self.tcx;
|
|
|
|
self.visit_early_late(
|
|
|
|
Some(tcx.hir.get_parent(impl_item.id)),
|
|
|
|
&sig.decl,
|
|
|
|
&impl_item.generics,
|
|
|
|
|this| intravisit::walk_impl_item(this, impl_item),
|
|
|
|
)
|
|
|
|
},
|
|
|
|
Type(ref ty) => {
|
|
|
|
let generics = &impl_item.generics;
|
|
|
|
let mut index = self.next_early_index();
|
|
|
|
debug!("visit_ty: index = {}", index);
|
2017-10-16 21:07:26 +02:00
|
|
|
let lifetimes = generics.lifetimes()
|
2017-12-12 21:11:15 -05:00
|
|
|
.map(|lt_def| Region::early(&self.tcx.hir, &mut index, lt_def))
|
|
|
|
.collect();
|
|
|
|
|
2017-10-16 21:07:26 +02:00
|
|
|
let next_early_index = index + generics.ty_params().count() as u32;
|
2017-12-12 21:11:15 -05:00
|
|
|
let scope = Scope::Binder { lifetimes, next_early_index, s: self.scope };
|
|
|
|
self.with(scope, |_old_scope, this| {
|
|
|
|
this.visit_generics(generics);
|
|
|
|
this.visit_ty(ty);
|
|
|
|
});
|
|
|
|
},
|
|
|
|
Const(_, _) => {
|
|
|
|
// Only methods and types support generics.
|
2017-10-16 21:07:26 +02:00
|
|
|
assert!(impl_item.generics.params.is_empty());
|
2017-12-12 21:11:15 -05:00
|
|
|
intravisit::walk_impl_item(self, impl_item);
|
|
|
|
},
|
2017-01-11 17:35:54 +02:00
|
|
|
}
|
2013-10-28 17:37:10 -04:00
|
|
|
}
|
|
|
|
|
2016-11-09 16:45:26 -05:00
|
|
|
fn visit_lifetime(&mut self, lifetime_ref: &'tcx hir::Lifetime) {
|
2017-01-09 17:46:11 +02:00
|
|
|
if lifetime_ref.is_elided() {
|
2017-11-23 16:41:51 +02:00
|
|
|
self.resolve_elided_lifetimes(slice::from_ref(lifetime_ref));
|
2017-01-09 17:46:11 +02:00
|
|
|
return;
|
|
|
|
}
|
2017-03-21 21:35:57 +09:00
|
|
|
if lifetime_ref.is_static() {
|
2017-01-08 22:40:04 +02:00
|
|
|
self.insert_lifetime(lifetime_ref, Region::Static);
|
2013-10-28 17:37:10 -04:00
|
|
|
return;
|
|
|
|
}
|
2014-09-12 13:10:30 +03:00
|
|
|
self.resolve_lifetime_ref(lifetime_ref);
|
2013-10-28 17:37:10 -04:00
|
|
|
}
|
2014-09-05 12:21:02 -07:00
|
|
|
|
2017-01-25 17:32:44 +02:00
|
|
|
fn visit_path(&mut self, path: &'tcx hir::Path, _: ast::NodeId) {
|
|
|
|
for (i, segment) in path.segments.iter().enumerate() {
|
|
|
|
let depth = path.segments.len() - i - 1;
|
2017-09-21 23:24:26 +03:00
|
|
|
if let Some(ref parameters) = segment.parameters {
|
|
|
|
self.visit_segment_parameters(path.def, depth, parameters);
|
|
|
|
}
|
2017-01-13 15:09:56 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn visit_fn_decl(&mut self, fd: &'tcx hir::FnDecl) {
|
|
|
|
let output = match fd.output {
|
|
|
|
hir::DefaultReturn(_) => None,
|
2017-12-11 09:00:05 -05:00
|
|
|
hir::Return(ref ty) => Some(ty),
|
2017-01-13 15:09:56 +02:00
|
|
|
};
|
|
|
|
self.visit_fn_like_elision(&fd.inputs, output);
|
|
|
|
}
|
|
|
|
|
2016-11-09 16:45:26 -05:00
|
|
|
fn visit_generics(&mut self, generics: &'tcx hir::Generics) {
|
2017-10-16 21:07:26 +02:00
|
|
|
check_mixed_explicit_and_in_band_defs(
|
|
|
|
self.tcx,
|
|
|
|
&generics.lifetimes().cloned().collect::<Vec<_>>()
|
|
|
|
);
|
|
|
|
for ty_param in generics.ty_params() {
|
2015-09-29 00:23:54 +03:00
|
|
|
walk_list!(self, visit_ty_param_bound, &ty_param.bounds);
|
2016-07-03 14:38:37 -07:00
|
|
|
if let Some(ref ty) = ty_param.default {
|
|
|
|
self.visit_ty(&ty);
|
2014-09-05 12:21:02 -07:00
|
|
|
}
|
|
|
|
}
|
2015-01-31 12:20:46 -05:00
|
|
|
for predicate in &generics.where_clause.predicates {
|
2014-11-29 17:08:30 +13:00
|
|
|
match predicate {
|
2017-12-11 09:00:05 -05:00
|
|
|
&hir::WherePredicate::BoundPredicate(hir::WhereBoundPredicate {
|
|
|
|
ref bounded_ty,
|
|
|
|
ref bounds,
|
2017-10-16 21:07:26 +02:00
|
|
|
ref bound_generic_params,
|
2017-12-11 09:00:05 -05:00
|
|
|
..
|
|
|
|
}) => {
|
2017-10-16 21:07:26 +02:00
|
|
|
if bound_generic_params.iter().any(|p| p.is_lifetime_param()) {
|
2015-02-05 21:46:01 +13:00
|
|
|
self.trait_ref_hack = true;
|
2017-10-15 13:43:06 -07:00
|
|
|
let next_early_index = self.next_early_index();
|
2017-01-11 17:35:54 +02:00
|
|
|
let scope = Scope::Binder {
|
2017-10-16 21:07:26 +02:00
|
|
|
lifetimes: bound_generic_params.lifetimes()
|
2017-11-23 08:05:58 -05:00
|
|
|
.map(|def| Region::late(&self.tcx.hir, def))
|
2017-12-11 09:00:05 -05:00
|
|
|
.collect(),
|
|
|
|
s: self.scope,
|
2017-11-23 08:05:58 -05:00
|
|
|
next_early_index,
|
2017-01-08 22:40:04 +02:00
|
|
|
};
|
2017-01-11 17:35:54 +02:00
|
|
|
let result = self.with(scope, |old_scope, this| {
|
2017-10-16 21:07:26 +02:00
|
|
|
this.check_lifetime_params(old_scope, &bound_generic_params);
|
2016-02-09 22:00:20 +01:00
|
|
|
this.visit_ty(&bounded_ty);
|
2015-09-29 00:23:54 +03:00
|
|
|
walk_list!(this, visit_ty_param_bound, bounds);
|
2015-02-05 21:46:01 +13:00
|
|
|
});
|
|
|
|
self.trait_ref_hack = false;
|
|
|
|
result
|
|
|
|
} else {
|
2016-02-09 22:00:20 +01:00
|
|
|
self.visit_ty(&bounded_ty);
|
2015-09-29 00:23:54 +03:00
|
|
|
walk_list!(self, visit_ty_param_bound, bounds);
|
2015-02-05 21:46:01 +13:00
|
|
|
}
|
2014-11-29 17:08:30 +13:00
|
|
|
}
|
2017-12-11 09:00:05 -05:00
|
|
|
&hir::WherePredicate::RegionPredicate(hir::WhereRegionPredicate {
|
|
|
|
ref lifetime,
|
|
|
|
ref bounds,
|
|
|
|
..
|
|
|
|
}) => {
|
2015-09-29 00:23:54 +03:00
|
|
|
self.visit_lifetime(lifetime);
|
2015-01-31 12:20:46 -05:00
|
|
|
for bound in bounds {
|
2015-09-29 00:23:54 +03:00
|
|
|
self.visit_lifetime(bound);
|
2014-12-20 02:48:43 -08:00
|
|
|
}
|
2014-12-20 02:29:19 -08:00
|
|
|
}
|
2017-12-11 09:00:05 -05:00
|
|
|
&hir::WherePredicate::EqPredicate(hir::WhereEqPredicate {
|
|
|
|
ref lhs_ty,
|
|
|
|
ref rhs_ty,
|
|
|
|
..
|
|
|
|
}) => {
|
2017-01-16 21:32:13 +03:00
|
|
|
self.visit_ty(lhs_ty);
|
|
|
|
self.visit_ty(rhs_ty);
|
2014-11-29 17:08:30 +13:00
|
|
|
}
|
|
|
|
}
|
2014-09-05 12:21:02 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-12-11 09:00:05 -05:00
|
|
|
fn visit_poly_trait_ref(
|
|
|
|
&mut self,
|
|
|
|
trait_ref: &'tcx hir::PolyTraitRef,
|
|
|
|
_modifier: hir::TraitBoundModifier,
|
|
|
|
) {
|
2014-12-20 00:09:35 -08:00
|
|
|
debug!("visit_poly_trait_ref trait_ref={:?}", trait_ref);
|
2014-11-15 17:09:51 -05:00
|
|
|
|
2017-10-16 21:07:26 +02:00
|
|
|
if !self.trait_ref_hack ||
|
|
|
|
trait_ref.bound_generic_params.iter().any(|p| p.is_lifetime_param())
|
|
|
|
{
|
2015-02-05 21:46:01 +13:00
|
|
|
if self.trait_ref_hack {
|
2017-12-11 09:00:05 -05:00
|
|
|
span_err!(
|
2017-11-23 08:05:58 -05:00
|
|
|
self.tcx.sess,
|
2017-12-11 09:00:05 -05:00
|
|
|
trait_ref.span,
|
|
|
|
E0316,
|
|
|
|
"nested quantification of lifetimes"
|
|
|
|
);
|
2014-09-05 12:21:02 -07:00
|
|
|
}
|
2017-10-15 13:43:06 -07:00
|
|
|
let next_early_index = self.next_early_index();
|
2017-01-11 17:35:54 +02:00
|
|
|
let scope = Scope::Binder {
|
2017-10-16 21:07:26 +02:00
|
|
|
lifetimes: trait_ref.bound_generic_params
|
|
|
|
.lifetimes()
|
2017-11-23 08:05:58 -05:00
|
|
|
.map(|def| Region::late(&self.tcx.hir, def))
|
2017-12-11 09:00:05 -05:00
|
|
|
.collect(),
|
|
|
|
s: self.scope,
|
2017-11-23 08:05:58 -05:00
|
|
|
next_early_index,
|
2017-01-08 22:40:04 +02:00
|
|
|
};
|
2017-01-11 17:35:54 +02:00
|
|
|
self.with(scope, |old_scope, this| {
|
2017-10-16 21:07:26 +02:00
|
|
|
this.check_lifetime_params(old_scope, &trait_ref.bound_generic_params);
|
|
|
|
walk_list!(this, visit_generic_param, &trait_ref.bound_generic_params);
|
2017-01-25 17:32:44 +02:00
|
|
|
this.visit_trait_ref(&trait_ref.trait_ref)
|
2015-02-05 21:46:01 +13:00
|
|
|
})
|
|
|
|
} else {
|
|
|
|
self.visit_trait_ref(&trait_ref.trait_ref)
|
|
|
|
}
|
2014-09-05 12:21:02 -07:00
|
|
|
}
|
2014-11-15 16:47:59 -05:00
|
|
|
}
|
|
|
|
|
2015-04-03 02:51:38 +02:00
|
|
|
#[derive(Copy, Clone, PartialEq)]
|
2017-12-11 09:00:05 -05:00
|
|
|
enum ShadowKind {
|
|
|
|
Label,
|
|
|
|
Lifetime,
|
|
|
|
}
|
|
|
|
struct Original {
|
|
|
|
kind: ShadowKind,
|
|
|
|
span: Span,
|
|
|
|
}
|
|
|
|
struct Shadower {
|
|
|
|
kind: ShadowKind,
|
|
|
|
span: Span,
|
|
|
|
}
|
2015-04-03 02:51:38 +02:00
|
|
|
|
|
|
|
fn original_label(span: Span) -> Original {
|
2017-12-11 09:00:05 -05:00
|
|
|
Original {
|
|
|
|
kind: ShadowKind::Label,
|
|
|
|
span: span,
|
|
|
|
}
|
2015-04-03 02:51:38 +02:00
|
|
|
}
|
|
|
|
fn shadower_label(span: Span) -> Shadower {
|
2017-12-11 09:00:05 -05:00
|
|
|
Shadower {
|
|
|
|
kind: ShadowKind::Label,
|
|
|
|
span: span,
|
|
|
|
}
|
2015-04-03 02:51:38 +02:00
|
|
|
}
|
2017-01-11 17:35:54 +02:00
|
|
|
fn original_lifetime(span: Span) -> Original {
|
2017-12-11 09:00:05 -05:00
|
|
|
Original {
|
|
|
|
kind: ShadowKind::Lifetime,
|
|
|
|
span: span,
|
|
|
|
}
|
2015-04-03 02:51:38 +02:00
|
|
|
}
|
2015-07-31 00:04:06 -07:00
|
|
|
fn shadower_lifetime(l: &hir::Lifetime) -> Shadower {
|
2017-12-11 09:00:05 -05:00
|
|
|
Shadower {
|
|
|
|
kind: ShadowKind::Lifetime,
|
|
|
|
span: l.span,
|
|
|
|
}
|
2015-04-03 02:51:38 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
impl ShadowKind {
|
|
|
|
fn desc(&self) -> &'static str {
|
|
|
|
match *self {
|
|
|
|
ShadowKind::Label => "label",
|
|
|
|
ShadowKind::Lifetime => "lifetime",
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-11-23 08:05:58 -05:00
|
|
|
fn check_mixed_explicit_and_in_band_defs(
|
|
|
|
tcx: TyCtxt<'_, '_, '_>,
|
|
|
|
lifetime_defs: &[hir::LifetimeDef],
|
|
|
|
) {
|
2017-11-16 22:59:45 -08:00
|
|
|
let oob_def = lifetime_defs.iter().find(|lt| !lt.in_band);
|
|
|
|
let in_band_def = lifetime_defs.iter().find(|lt| lt.in_band);
|
|
|
|
|
|
|
|
if let (Some(oob_def), Some(in_band_def)) = (oob_def, in_band_def) {
|
2017-12-11 09:00:05 -05:00
|
|
|
struct_span_err!(
|
2017-11-23 08:05:58 -05:00
|
|
|
tcx.sess,
|
2017-12-11 09:00:05 -05:00
|
|
|
in_band_def.lifetime.span,
|
|
|
|
E0688,
|
|
|
|
"cannot mix in-band and explicit lifetime definitions"
|
|
|
|
).span_label(
|
|
|
|
in_band_def.lifetime.span,
|
|
|
|
"in-band lifetime definition here",
|
|
|
|
)
|
2017-11-16 22:59:45 -08:00
|
|
|
.span_label(oob_def.lifetime.span, "explicit lifetime definition here")
|
|
|
|
.emit();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-11-23 08:05:58 -05:00
|
|
|
fn signal_shadowing_problem(
|
|
|
|
tcx: TyCtxt<'_, '_, '_>,
|
|
|
|
name: ast::Name,
|
|
|
|
orig: Original,
|
|
|
|
shadower: Shadower,
|
|
|
|
) {
|
2015-12-21 10:00:43 +13:00
|
|
|
let mut err = if let (ShadowKind::Lifetime, ShadowKind::Lifetime) = (orig.kind, shadower.kind) {
|
2015-04-03 02:51:38 +02:00
|
|
|
// lifetime/lifetime shadowing is an error
|
2017-12-11 09:00:05 -05:00
|
|
|
struct_span_err!(
|
2017-11-23 08:05:58 -05:00
|
|
|
tcx.sess,
|
2017-12-11 09:00:05 -05:00
|
|
|
shadower.span,
|
|
|
|
E0496,
|
|
|
|
"{} name `{}` shadows a \
|
|
|
|
{} name that is already in scope",
|
|
|
|
shadower.kind.desc(),
|
|
|
|
name,
|
|
|
|
orig.kind.desc()
|
|
|
|
)
|
2015-04-03 02:51:38 +02:00
|
|
|
} else {
|
|
|
|
// shadowing involving a label is only a warning, due to issues with
|
|
|
|
// labels and lifetimes not being macro-hygienic.
|
2017-11-23 08:05:58 -05:00
|
|
|
tcx.sess.struct_span_warn(
|
2017-12-11 09:00:05 -05:00
|
|
|
shadower.span,
|
|
|
|
&format!(
|
|
|
|
"{} name `{}` shadows a \
|
|
|
|
{} name that is already in scope",
|
|
|
|
shadower.kind.desc(),
|
|
|
|
name,
|
|
|
|
orig.kind.desc()
|
|
|
|
),
|
|
|
|
)
|
2015-12-21 10:00:43 +13:00
|
|
|
};
|
2017-05-04 14:17:23 +02:00
|
|
|
err.span_label(orig.span, "first declared here");
|
2017-12-11 09:00:05 -05:00
|
|
|
err.span_label(shadower.span, format!("lifetime {} already in scope", name));
|
2015-12-21 10:00:43 +13:00
|
|
|
err.emit();
|
2015-04-03 02:51:38 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
// Adds all labels in `b` to `ctxt.labels_in_fn`, signalling a warning
|
|
|
|
// if one of the label shadows a lifetime or another label.
|
2017-11-23 08:05:58 -05:00
|
|
|
fn extract_labels(ctxt: &mut LifetimeContext<'_, '_>, body: &hir::Body) {
|
2017-01-11 17:35:54 +02:00
|
|
|
struct GatherLabels<'a, 'tcx: 'a> {
|
2017-11-23 08:05:58 -05:00
|
|
|
tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
2017-01-08 22:40:04 +02:00
|
|
|
scope: ScopeRef<'a>,
|
2015-09-23 20:04:49 +03:00
|
|
|
labels_in_fn: &'a mut Vec<(ast::Name, Span)>,
|
2015-04-03 02:51:38 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
let mut gather = GatherLabels {
|
2017-11-23 08:05:58 -05:00
|
|
|
tcx: ctxt.tcx,
|
2015-04-03 02:51:38 +02:00
|
|
|
scope: ctxt.scope,
|
|
|
|
labels_in_fn: &mut ctxt.labels_in_fn,
|
|
|
|
};
|
2017-01-11 17:35:54 +02:00
|
|
|
gather.visit_body(body);
|
2015-04-03 02:51:38 +02:00
|
|
|
|
2017-01-11 17:35:54 +02:00
|
|
|
impl<'v, 'a, 'tcx> Visitor<'v> for GatherLabels<'a, 'tcx> {
|
2016-11-28 14:00:26 -05:00
|
|
|
fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'v> {
|
|
|
|
NestedVisitorMap::None
|
|
|
|
}
|
2016-11-24 20:15:11 +01:00
|
|
|
|
2017-01-11 17:35:54 +02:00
|
|
|
fn visit_expr(&mut self, ex: &hir::Expr) {
|
2016-05-02 18:22:03 +02:00
|
|
|
if let Some((label, label_span)) = expression_label(ex) {
|
2015-04-03 02:51:38 +02:00
|
|
|
for &(prior, prior_span) in &self.labels_in_fn[..] {
|
2015-05-06 01:49:07 +02:00
|
|
|
// FIXME (#24278): non-hygienic comparison
|
2015-09-23 20:04:49 +03:00
|
|
|
if label == prior {
|
2017-12-11 09:00:05 -05:00
|
|
|
signal_shadowing_problem(
|
2017-11-23 08:05:58 -05:00
|
|
|
self.tcx,
|
2017-12-11 09:00:05 -05:00
|
|
|
label,
|
|
|
|
original_label(prior_span),
|
|
|
|
shadower_label(label_span),
|
|
|
|
);
|
2015-04-03 02:51:38 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-11-23 08:05:58 -05:00
|
|
|
check_if_label_shadows_lifetime(self.tcx, self.scope, label, label_span);
|
2015-04-03 02:51:38 +02:00
|
|
|
|
2016-05-02 18:22:03 +02:00
|
|
|
self.labels_in_fn.push((label, label_span));
|
2015-04-03 02:51:38 +02:00
|
|
|
}
|
2015-11-17 17:51:44 -05:00
|
|
|
intravisit::walk_expr(self, ex)
|
2015-04-03 02:51:38 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-05-02 18:22:03 +02:00
|
|
|
fn expression_label(ex: &hir::Expr) -> Option<(ast::Name, Span)> {
|
2015-04-03 02:51:38 +02:00
|
|
|
match ex.node {
|
2017-12-11 09:00:05 -05:00
|
|
|
hir::ExprWhile(.., Some(label)) | hir::ExprLoop(_, Some(label), _) => {
|
|
|
|
Some((label.node, label.span))
|
|
|
|
}
|
2015-04-03 02:51:38 +02:00
|
|
|
_ => None,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-11-23 08:05:58 -05:00
|
|
|
fn check_if_label_shadows_lifetime(
|
|
|
|
tcx: TyCtxt<'_, '_, '_>,
|
|
|
|
mut scope: ScopeRef<'_>,
|
2017-12-11 09:00:05 -05:00
|
|
|
label: ast::Name,
|
|
|
|
label_span: Span,
|
|
|
|
) {
|
2015-04-03 02:51:38 +02:00
|
|
|
loop {
|
|
|
|
match *scope {
|
2017-12-11 09:00:05 -05:00
|
|
|
Scope::Body { s, .. }
|
|
|
|
| Scope::Elision { s, .. }
|
|
|
|
| Scope::ObjectLifetimeDefault { s, .. } => {
|
|
|
|
scope = s;
|
|
|
|
}
|
2017-01-13 15:09:56 +02:00
|
|
|
|
2017-12-11 09:00:05 -05:00
|
|
|
Scope::Root => {
|
|
|
|
return;
|
|
|
|
}
|
2015-04-03 02:51:38 +02:00
|
|
|
|
2017-12-11 09:00:05 -05:00
|
|
|
Scope::Binder {
|
|
|
|
ref lifetimes,
|
|
|
|
s,
|
|
|
|
next_early_index: _,
|
|
|
|
} => {
|
2017-01-11 17:35:54 +02:00
|
|
|
// FIXME (#24278): non-hygienic comparison
|
2017-09-19 16:36:54 -07:00
|
|
|
if let Some(def) = lifetimes.get(&hir::LifetimeName::Name(label)) {
|
2017-11-23 08:05:58 -05:00
|
|
|
let node_id = tcx.hir.as_local_node_id(def.id().unwrap()).unwrap();
|
2017-08-15 17:05:25 +02:00
|
|
|
|
2017-01-11 17:35:54 +02:00
|
|
|
signal_shadowing_problem(
|
2017-11-23 08:05:58 -05:00
|
|
|
tcx,
|
2017-01-11 17:35:54 +02:00
|
|
|
label,
|
2017-11-23 08:05:58 -05:00
|
|
|
original_lifetime(tcx.hir.span(node_id)),
|
2017-12-11 09:00:05 -05:00
|
|
|
shadower_label(label_span),
|
|
|
|
);
|
2017-01-11 17:35:54 +02:00
|
|
|
return;
|
2015-04-03 02:51:38 +02:00
|
|
|
}
|
|
|
|
scope = s;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-12-11 09:00:05 -05:00
|
|
|
fn compute_object_lifetime_defaults(
|
2017-11-23 08:05:58 -05:00
|
|
|
tcx: TyCtxt<'_, '_, '_>,
|
2017-12-11 09:00:05 -05:00
|
|
|
) -> NodeMap<Vec<ObjectLifetimeDefault>> {
|
2017-01-25 17:32:44 +02:00
|
|
|
let mut map = NodeMap();
|
2017-11-23 08:05:58 -05:00
|
|
|
for item in tcx.hir.krate().items.values() {
|
2017-01-25 17:32:44 +02:00
|
|
|
match item.node {
|
2017-12-11 09:00:05 -05:00
|
|
|
hir::ItemStruct(_, ref generics)
|
|
|
|
| hir::ItemUnion(_, ref generics)
|
|
|
|
| hir::ItemEnum(_, ref generics)
|
|
|
|
| hir::ItemTy(_, ref generics)
|
|
|
|
| hir::ItemTrait(_, _, ref generics, ..) => {
|
2017-11-23 08:05:58 -05:00
|
|
|
let result = object_lifetime_defaults_for_item(tcx, generics);
|
2017-01-25 17:32:44 +02:00
|
|
|
|
|
|
|
// Debugging aid.
|
|
|
|
if attr::contains_name(&item.attrs, "rustc_object_lifetime_default") {
|
2017-12-11 09:00:05 -05:00
|
|
|
let object_lifetime_default_reprs: String = result
|
|
|
|
.iter()
|
|
|
|
.map(|set| match *set {
|
|
|
|
Set1::Empty => "BaseDefault".to_string(),
|
|
|
|
Set1::One(Region::Static) => "'static".to_string(),
|
2017-10-16 21:07:26 +02:00
|
|
|
Set1::One(Region::EarlyBound(i, _, _)) => generics.lifetimes()
|
|
|
|
.nth(i as usize)
|
|
|
|
.unwrap()
|
2017-12-11 09:00:05 -05:00
|
|
|
.lifetime
|
|
|
|
.name
|
|
|
|
.name()
|
|
|
|
.to_string(),
|
|
|
|
Set1::One(_) => bug!(),
|
|
|
|
Set1::Many => "Ambiguous".to_string(),
|
|
|
|
})
|
|
|
|
.collect::<Vec<String>>()
|
|
|
|
.join(",");
|
2017-11-23 08:05:58 -05:00
|
|
|
tcx.sess.span_err(item.span, &object_lifetime_default_reprs);
|
2017-01-25 17:32:44 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
map.insert(item.id, result);
|
|
|
|
}
|
|
|
|
_ => {}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
map
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Scan the bounds and where-clauses on parameters to extract bounds
|
|
|
|
/// of the form `T:'a` so as to determine the `ObjectLifetimeDefault`
|
|
|
|
/// for each type parameter.
|
2017-12-11 09:00:05 -05:00
|
|
|
fn object_lifetime_defaults_for_item(
|
2017-11-23 08:05:58 -05:00
|
|
|
tcx: TyCtxt<'_, '_, '_>,
|
2017-12-11 09:00:05 -05:00
|
|
|
generics: &hir::Generics,
|
|
|
|
) -> Vec<ObjectLifetimeDefault> {
|
2017-09-19 16:36:54 -07:00
|
|
|
fn add_bounds(set: &mut Set1<hir::LifetimeName>, bounds: &[hir::TyParamBound]) {
|
2017-01-25 17:32:44 +02:00
|
|
|
for bound in bounds {
|
|
|
|
if let hir::RegionTyParamBound(ref lifetime) = *bound {
|
|
|
|
set.insert(lifetime.name);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-10-16 21:07:26 +02:00
|
|
|
generics.ty_params()
|
2017-12-11 09:00:05 -05:00
|
|
|
.map(|param| {
|
|
|
|
let mut set = Set1::Empty;
|
2017-01-25 17:32:44 +02:00
|
|
|
|
2017-12-11 09:00:05 -05:00
|
|
|
add_bounds(&mut set, ¶m.bounds);
|
2017-01-25 17:32:44 +02:00
|
|
|
|
2017-11-23 08:05:58 -05:00
|
|
|
let param_def_id = tcx.hir.local_def_id(param.id);
|
2017-12-11 09:00:05 -05:00
|
|
|
for predicate in &generics.where_clause.predicates {
|
|
|
|
// Look for `type: ...` where clauses.
|
|
|
|
let data = match *predicate {
|
|
|
|
hir::WherePredicate::BoundPredicate(ref data) => data,
|
|
|
|
_ => continue,
|
|
|
|
};
|
2017-01-25 17:32:44 +02:00
|
|
|
|
2017-12-11 09:00:05 -05:00
|
|
|
// Ignore `for<'a> type: ...` as they can change what
|
|
|
|
// lifetimes mean (although we could "just" handle it).
|
2017-10-16 21:07:26 +02:00
|
|
|
if !data.bound_generic_params.is_empty() {
|
2017-12-11 09:00:05 -05:00
|
|
|
continue;
|
|
|
|
}
|
2017-01-25 17:32:44 +02:00
|
|
|
|
2017-12-11 09:00:05 -05:00
|
|
|
let def = match data.bounded_ty.node {
|
|
|
|
hir::TyPath(hir::QPath::Resolved(None, ref path)) => path.def,
|
|
|
|
_ => continue,
|
|
|
|
};
|
2017-01-25 17:32:44 +02:00
|
|
|
|
2017-12-11 09:00:05 -05:00
|
|
|
if def == Def::TyParam(param_def_id) {
|
|
|
|
add_bounds(&mut set, &data.bounds);
|
|
|
|
}
|
2017-01-25 17:32:44 +02:00
|
|
|
}
|
|
|
|
|
2017-12-11 09:00:05 -05:00
|
|
|
match set {
|
|
|
|
Set1::Empty => Set1::Empty,
|
|
|
|
Set1::One(name) => {
|
|
|
|
if name == hir::LifetimeName::Static {
|
|
|
|
Set1::One(Region::Static)
|
|
|
|
} else {
|
|
|
|
generics
|
2017-10-16 21:07:26 +02:00
|
|
|
.lifetimes()
|
2017-12-11 09:00:05 -05:00
|
|
|
.enumerate()
|
|
|
|
.find(|&(_, def)| def.lifetime.name == name)
|
|
|
|
.map_or(Set1::Many, |(i, def)| {
|
2017-11-23 08:05:58 -05:00
|
|
|
let def_id = tcx.hir.local_def_id(def.lifetime.id);
|
2017-12-11 09:00:05 -05:00
|
|
|
let origin = LifetimeDefOrigin::from_is_in_band(def.in_band);
|
|
|
|
Set1::One(Region::EarlyBound(i as u32, def_id, origin))
|
|
|
|
})
|
|
|
|
}
|
2017-01-25 17:32:44 +02:00
|
|
|
}
|
2017-12-11 09:00:05 -05:00
|
|
|
Set1::Many => Set1::Many,
|
2017-01-25 17:32:44 +02:00
|
|
|
}
|
2017-12-11 09:00:05 -05:00
|
|
|
})
|
|
|
|
.collect()
|
2017-01-25 17:32:44 +02:00
|
|
|
}
|
|
|
|
|
2016-04-21 05:10:10 -04:00
|
|
|
impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
|
2016-11-09 16:45:26 -05:00
|
|
|
// FIXME(#37666) this works around a limitation in the region inferencer
|
2017-12-11 09:00:05 -05:00
|
|
|
fn hack<F>(&mut self, f: F)
|
|
|
|
where
|
2016-11-09 16:45:26 -05:00
|
|
|
F: for<'b> FnOnce(&mut LifetimeContext<'b, 'tcx>),
|
|
|
|
{
|
|
|
|
f(self)
|
|
|
|
}
|
|
|
|
|
2017-12-11 09:00:05 -05:00
|
|
|
fn with<F>(&mut self, wrap_scope: Scope, f: F)
|
|
|
|
where
|
2017-01-08 22:40:04 +02:00
|
|
|
F: for<'b> FnOnce(ScopeRef, &mut LifetimeContext<'b, 'tcx>),
|
2014-12-08 20:26:43 -05:00
|
|
|
{
|
2017-12-11 09:00:05 -05:00
|
|
|
let LifetimeContext {
|
2017-11-23 08:05:58 -05:00
|
|
|
tcx, ref mut map, ..
|
2017-12-11 09:00:05 -05:00
|
|
|
} = *self;
|
2017-01-11 17:35:54 +02:00
|
|
|
let labels_in_fn = replace(&mut self.labels_in_fn, vec![]);
|
2017-01-25 17:32:44 +02:00
|
|
|
let xcrate_object_lifetime_defaults =
|
|
|
|
replace(&mut self.xcrate_object_lifetime_defaults, DefIdMap());
|
2014-11-15 16:47:59 -05:00
|
|
|
let mut this = LifetimeContext {
|
2017-11-23 08:05:58 -05:00
|
|
|
tcx,
|
2016-04-21 05:10:10 -04:00
|
|
|
map: *map,
|
2014-11-15 16:47:59 -05:00
|
|
|
scope: &wrap_scope,
|
2015-02-05 21:46:01 +13:00
|
|
|
trait_ref_hack: self.trait_ref_hack,
|
2017-11-16 22:59:45 -08:00
|
|
|
is_in_fn_syntax: self.is_in_fn_syntax,
|
2017-07-03 11:19:51 -07:00
|
|
|
labels_in_fn,
|
|
|
|
xcrate_object_lifetime_defaults,
|
2017-11-23 08:05:58 -05:00
|
|
|
lifetime_uses: DefIdMap(),
|
2014-11-15 16:47:59 -05:00
|
|
|
};
|
2014-12-20 00:09:35 -08:00
|
|
|
debug!("entering scope {:?}", this.scope);
|
2014-12-12 11:09:24 -05:00
|
|
|
f(self.scope, &mut this);
|
2014-12-20 00:09:35 -08:00
|
|
|
debug!("exiting scope {:?}", this.scope);
|
2017-01-11 17:35:54 +02:00
|
|
|
self.labels_in_fn = this.labels_in_fn;
|
2017-01-25 17:32:44 +02:00
|
|
|
self.xcrate_object_lifetime_defaults = this.xcrate_object_lifetime_defaults;
|
2017-11-23 08:05:58 -05:00
|
|
|
|
|
|
|
for (def_id, lifetimeuseset) in &this.lifetime_uses {
|
|
|
|
match lifetimeuseset {
|
|
|
|
&LifetimeUseSet::One(_) => {
|
|
|
|
let node_id = this.tcx.hir.as_local_node_id(*def_id).unwrap();
|
|
|
|
debug!("node id first={:?}", node_id);
|
|
|
|
if let hir::map::NodeLifetime(hir_lifetime) = this.tcx.hir.get(node_id) {
|
|
|
|
let span = hir_lifetime.span;
|
|
|
|
let id = hir_lifetime.id;
|
|
|
|
debug!("id ={:?} span = {:?} hir_lifetime = {:?}",
|
|
|
|
node_id,
|
|
|
|
span,
|
|
|
|
hir_lifetime);
|
|
|
|
|
|
|
|
this.tcx
|
|
|
|
.struct_span_lint_node(lint::builtin::SINGLE_USE_LIFETIME,
|
|
|
|
id,
|
|
|
|
span,
|
|
|
|
&format!("lifetime name `{}` only used once",
|
|
|
|
hir_lifetime.name.name()))
|
|
|
|
.emit();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
_ => {
|
|
|
|
debug!("Not one use lifetime");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2014-11-15 16:47:59 -05:00
|
|
|
}
|
2014-11-07 06:53:45 -05:00
|
|
|
|
2014-03-07 08:43:39 +01:00
|
|
|
/// Visits self by adding a scope and handling recursive walk over the contents with `walk`.
|
2014-11-25 21:17:11 -05:00
|
|
|
///
|
|
|
|
/// Handles visiting fns and methods. These are a bit complicated because we must distinguish
|
|
|
|
/// early- vs late-bound lifetime parameters. We do this by checking which lifetimes appear
|
|
|
|
/// within type bounds; those are early bound lifetimes, and the rest are late bound.
|
|
|
|
///
|
|
|
|
/// For example:
|
|
|
|
///
|
|
|
|
/// fn foo<'a,'b,'c,T:Trait<'b>>(...)
|
|
|
|
///
|
|
|
|
/// Here `'a` and `'c` are late bound but `'b` is early bound. Note that early- and late-bound
|
|
|
|
/// lifetimes may be interspersed together.
|
|
|
|
///
|
|
|
|
/// If early bound lifetimes are present, we separate them into their own list (and likewise
|
|
|
|
/// for late bound). They will be numbered sequentially, starting from the lowest index that is
|
|
|
|
/// already in scope (for a fn item, that will be 0, but for a method it might not be). Late
|
|
|
|
/// bound lifetimes are resolved by name and associated with a binder id (`binder_id`), so the
|
|
|
|
/// ordering is not important there.
|
2017-12-11 09:00:05 -05:00
|
|
|
fn visit_early_late<F>(
|
|
|
|
&mut self,
|
|
|
|
parent_id: Option<ast::NodeId>,
|
|
|
|
decl: &'tcx hir::FnDecl,
|
|
|
|
generics: &'tcx hir::Generics,
|
|
|
|
walk: F,
|
|
|
|
) where
|
2016-11-09 16:45:26 -05:00
|
|
|
F: for<'b, 'c> FnOnce(&'b mut LifetimeContext<'c, 'tcx>),
|
2014-12-08 20:26:43 -05:00
|
|
|
{
|
2017-07-29 17:19:57 +03:00
|
|
|
insert_late_bound_lifetimes(self.map, decl, generics);
|
2016-04-21 05:10:10 -04:00
|
|
|
|
2016-08-27 01:13:48 +03:00
|
|
|
// Find the start of nested early scopes, e.g. in methods.
|
2017-01-11 17:35:54 +02:00
|
|
|
let mut index = 0;
|
|
|
|
if let Some(parent_id) = parent_id {
|
2017-11-23 08:05:58 -05:00
|
|
|
let parent = self.tcx.hir.expect_item(parent_id);
|
2016-08-27 01:13:48 +03:00
|
|
|
if let hir::ItemTrait(..) = parent.node {
|
2017-01-11 17:35:54 +02:00
|
|
|
index += 1; // Self comes first.
|
2016-08-27 01:13:48 +03:00
|
|
|
}
|
|
|
|
match parent.node {
|
2017-12-11 09:00:05 -05:00
|
|
|
hir::ItemTrait(_, _, ref generics, ..)
|
|
|
|
| hir::ItemImpl(_, _, _, ref generics, ..) => {
|
2017-10-16 21:07:26 +02:00
|
|
|
index += generics.params.len() as u32;
|
2016-08-27 01:13:48 +03:00
|
|
|
}
|
|
|
|
_ => {}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-12-11 09:00:05 -05:00
|
|
|
let lifetimes = generics
|
2017-10-16 21:07:26 +02:00
|
|
|
.lifetimes()
|
2017-12-11 09:00:05 -05:00
|
|
|
.map(|def| {
|
|
|
|
if self.map.late_bound.contains(&def.lifetime.id) {
|
2017-11-23 08:05:58 -05:00
|
|
|
Region::late(&self.tcx.hir, def)
|
2017-12-11 09:00:05 -05:00
|
|
|
} else {
|
2017-11-23 08:05:58 -05:00
|
|
|
Region::early(&self.tcx.hir, &mut index, def)
|
2017-12-11 09:00:05 -05:00
|
|
|
}
|
|
|
|
})
|
|
|
|
.collect();
|
2017-01-11 17:35:54 +02:00
|
|
|
|
2017-10-16 21:07:26 +02:00
|
|
|
let next_early_index = index + generics.ty_params().count() as u32;
|
2017-10-15 13:43:06 -07:00
|
|
|
|
2017-01-11 17:35:54 +02:00
|
|
|
let scope = Scope::Binder {
|
2017-07-03 11:19:51 -07:00
|
|
|
lifetimes,
|
2017-10-15 13:43:06 -07:00
|
|
|
next_early_index,
|
2017-12-11 09:00:05 -05:00
|
|
|
s: self.scope,
|
2017-01-08 22:40:04 +02:00
|
|
|
};
|
2017-01-11 17:35:54 +02:00
|
|
|
self.with(scope, move |old_scope, this| {
|
2017-10-16 21:07:26 +02:00
|
|
|
this.check_lifetime_params(old_scope, &generics.params);
|
2017-01-11 17:35:54 +02:00
|
|
|
this.hack(walk); // FIXME(#37666) workaround in place of `walk(this)`
|
2014-11-07 06:53:45 -05:00
|
|
|
});
|
2014-03-07 08:43:39 +01:00
|
|
|
}
|
|
|
|
|
2017-10-15 13:43:06 -07:00
|
|
|
/// Returns the next index one would use for an early-bound-region
|
|
|
|
/// if extending the current scope.
|
|
|
|
fn next_early_index(&self) -> u32 {
|
|
|
|
let mut scope = self.scope;
|
|
|
|
loop {
|
|
|
|
match *scope {
|
2017-12-11 09:00:05 -05:00
|
|
|
Scope::Root => return 0,
|
2017-10-15 13:43:06 -07:00
|
|
|
|
2017-12-11 09:00:05 -05:00
|
|
|
Scope::Binder {
|
|
|
|
next_early_index, ..
|
|
|
|
} => return next_early_index,
|
2017-10-15 13:43:06 -07:00
|
|
|
|
2017-12-11 09:00:05 -05:00
|
|
|
Scope::Body { s, .. }
|
|
|
|
| Scope::Elision { s, .. }
|
|
|
|
| Scope::ObjectLifetimeDefault { s, .. } => scope = s,
|
2017-10-15 13:43:06 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-11-23 08:05:58 -05:00
|
|
|
fn resolve_lifetime_ref(&mut self, lifetime_ref: &'tcx hir::Lifetime) {
|
2017-10-15 13:43:06 -07:00
|
|
|
debug!("resolve_lifetime_ref(lifetime_ref={:?})", lifetime_ref);
|
2013-10-28 17:37:10 -04:00
|
|
|
// Walk up the scope chain, tracking the number of fn scopes
|
|
|
|
// that we pass through, until we find a lifetime with the
|
2017-01-11 17:35:54 +02:00
|
|
|
// given name or we run out of scopes.
|
2013-10-28 17:37:10 -04:00
|
|
|
// search.
|
2014-11-15 16:47:59 -05:00
|
|
|
let mut late_depth = 0;
|
2014-09-12 13:10:30 +03:00
|
|
|
let mut scope = self.scope;
|
2017-01-11 17:35:54 +02:00
|
|
|
let mut outermost_body = None;
|
|
|
|
let result = loop {
|
2013-10-28 17:37:10 -04:00
|
|
|
match *scope {
|
2017-01-11 17:35:54 +02:00
|
|
|
Scope::Body { id, s } => {
|
|
|
|
outermost_body = Some(id);
|
|
|
|
scope = s;
|
2013-10-28 17:37:10 -04:00
|
|
|
}
|
|
|
|
|
2017-01-08 22:40:04 +02:00
|
|
|
Scope::Root => {
|
2017-01-11 17:35:54 +02:00
|
|
|
break None;
|
2013-10-28 17:37:10 -04:00
|
|
|
}
|
|
|
|
|
2017-12-11 09:00:05 -05:00
|
|
|
Scope::Binder {
|
|
|
|
ref lifetimes,
|
|
|
|
s,
|
|
|
|
next_early_index: _,
|
|
|
|
} => {
|
2017-01-11 17:35:54 +02:00
|
|
|
if let Some(&def) = lifetimes.get(&lifetime_ref.name) {
|
|
|
|
break Some(def.shifted(late_depth));
|
|
|
|
} else {
|
|
|
|
late_depth += 1;
|
|
|
|
scope = s;
|
2013-10-28 17:37:10 -04:00
|
|
|
}
|
|
|
|
}
|
2017-01-13 15:09:56 +02:00
|
|
|
|
2017-12-11 09:00:05 -05:00
|
|
|
Scope::Elision { s, .. } | Scope::ObjectLifetimeDefault { s, .. } => {
|
2017-01-13 15:09:56 +02:00
|
|
|
scope = s;
|
|
|
|
}
|
2013-10-28 17:37:10 -04:00
|
|
|
}
|
2017-01-11 17:35:54 +02:00
|
|
|
};
|
2013-10-28 17:37:10 -04:00
|
|
|
|
2017-01-11 17:35:54 +02:00
|
|
|
if let Some(mut def) = result {
|
2017-05-11 15:05:00 +03:00
|
|
|
if let Region::EarlyBound(..) = def {
|
|
|
|
// Do not free early-bound regions, only late-bound ones.
|
|
|
|
} else if let Some(body_id) = outermost_body {
|
2017-11-23 08:05:58 -05:00
|
|
|
let fn_id = self.tcx.hir.body_owner(body_id);
|
|
|
|
match self.tcx.hir.get(fn_id) {
|
2017-01-11 17:35:54 +02:00
|
|
|
hir::map::NodeItem(&hir::Item {
|
2017-12-11 09:00:05 -05:00
|
|
|
node: hir::ItemFn(..),
|
|
|
|
..
|
|
|
|
})
|
|
|
|
| hir::map::NodeTraitItem(&hir::TraitItem {
|
|
|
|
node: hir::TraitItemKind::Method(..),
|
|
|
|
..
|
|
|
|
})
|
|
|
|
| hir::map::NodeImplItem(&hir::ImplItem {
|
|
|
|
node: hir::ImplItemKind::Method(..),
|
|
|
|
..
|
2017-01-11 17:35:54 +02:00
|
|
|
}) => {
|
2017-11-23 08:05:58 -05:00
|
|
|
let scope = self.tcx.hir.local_def_id(fn_id);
|
2017-05-07 19:57:51 +03:00
|
|
|
def = Region::Free(scope, def.id().unwrap());
|
2013-10-28 17:37:10 -04:00
|
|
|
}
|
2017-01-11 17:35:54 +02:00
|
|
|
_ => {}
|
2013-10-28 17:37:10 -04:00
|
|
|
}
|
|
|
|
}
|
2017-11-16 22:59:45 -08:00
|
|
|
|
|
|
|
// Check for fn-syntax conflicts with in-band lifetime definitions
|
|
|
|
if self.is_in_fn_syntax {
|
|
|
|
match def {
|
2017-12-11 09:00:05 -05:00
|
|
|
Region::EarlyBound(_, _, LifetimeDefOrigin::InBand)
|
|
|
|
| Region::LateBound(_, _, LifetimeDefOrigin::InBand) => {
|
|
|
|
struct_span_err!(
|
2017-11-23 08:05:58 -05:00
|
|
|
self.tcx.sess,
|
2017-12-11 09:00:05 -05:00
|
|
|
lifetime_ref.span,
|
|
|
|
E0687,
|
2017-11-16 22:59:45 -08:00
|
|
|
"lifetimes used in `fn` or `Fn` syntax must be \
|
2017-12-11 09:00:05 -05:00
|
|
|
explicitly declared using `<...>` binders"
|
|
|
|
).span_label(lifetime_ref.span, "in-band lifetime definition")
|
2017-11-16 22:59:45 -08:00
|
|
|
.emit();
|
2017-12-11 09:00:05 -05:00
|
|
|
}
|
2017-11-16 22:59:45 -08:00
|
|
|
|
2017-12-11 09:00:05 -05:00
|
|
|
Region::Static
|
|
|
|
| Region::EarlyBound(_, _, LifetimeDefOrigin::Explicit)
|
|
|
|
| Region::LateBound(_, _, LifetimeDefOrigin::Explicit)
|
|
|
|
| Region::LateBoundAnon(..)
|
|
|
|
| Region::Free(..) => {}
|
2017-11-16 22:59:45 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-01-11 17:35:54 +02:00
|
|
|
self.insert_lifetime(lifetime_ref, def);
|
|
|
|
} else {
|
2017-12-11 09:00:05 -05:00
|
|
|
struct_span_err!(
|
2017-11-23 08:05:58 -05:00
|
|
|
self.tcx.sess,
|
2017-12-11 09:00:05 -05:00
|
|
|
lifetime_ref.span,
|
|
|
|
E0261,
|
|
|
|
"use of undeclared lifetime name `{}`",
|
|
|
|
lifetime_ref.name.name()
|
|
|
|
).span_label(lifetime_ref.span, "undeclared lifetime")
|
2017-01-11 17:35:54 +02:00
|
|
|
.emit();
|
2013-10-28 17:37:10 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-12-11 09:00:05 -05:00
|
|
|
fn visit_segment_parameters(
|
|
|
|
&mut self,
|
|
|
|
def: Def,
|
|
|
|
depth: usize,
|
|
|
|
params: &'tcx hir::PathParameters,
|
|
|
|
) {
|
2017-07-29 01:13:40 +03:00
|
|
|
if params.parenthesized {
|
2017-11-16 22:59:45 -08:00
|
|
|
let was_in_fn_syntax = self.is_in_fn_syntax;
|
|
|
|
self.is_in_fn_syntax = true;
|
2017-07-29 01:13:40 +03:00
|
|
|
self.visit_fn_like_elision(params.inputs(), Some(¶ms.bindings[0].ty));
|
2017-11-16 22:59:45 -08:00
|
|
|
self.is_in_fn_syntax = was_in_fn_syntax;
|
2017-07-29 01:13:40 +03:00
|
|
|
return;
|
|
|
|
}
|
2017-01-25 17:32:44 +02:00
|
|
|
|
2017-07-29 01:13:40 +03:00
|
|
|
if params.lifetimes.iter().all(|l| l.is_elided()) {
|
|
|
|
self.resolve_elided_lifetimes(¶ms.lifetimes);
|
2017-01-25 17:32:44 +02:00
|
|
|
} else {
|
2017-12-11 09:00:05 -05:00
|
|
|
for l in ¶ms.lifetimes {
|
|
|
|
self.visit_lifetime(l);
|
|
|
|
}
|
2017-01-25 17:32:44 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
// Figure out if this is a type/trait segment,
|
|
|
|
// which requires object lifetime defaults.
|
|
|
|
let parent_def_id = |this: &mut Self, def_id: DefId| {
|
2017-11-23 08:05:58 -05:00
|
|
|
let def_key = this.tcx.def_key(def_id);
|
2017-01-25 17:32:44 +02:00
|
|
|
DefId {
|
|
|
|
krate: def_id.krate,
|
2017-12-11 09:00:05 -05:00
|
|
|
index: def_key.parent.expect("missing parent"),
|
2017-01-25 17:32:44 +02:00
|
|
|
}
|
|
|
|
};
|
|
|
|
let type_def_id = match def {
|
2017-12-11 09:00:05 -05:00
|
|
|
Def::AssociatedTy(def_id) if depth == 1 => Some(parent_def_id(self, def_id)),
|
|
|
|
Def::Variant(def_id) if depth == 0 => Some(parent_def_id(self, def_id)),
|
|
|
|
Def::Struct(def_id)
|
|
|
|
| Def::Union(def_id)
|
|
|
|
| Def::Enum(def_id)
|
|
|
|
| Def::TyAlias(def_id)
|
|
|
|
| Def::Trait(def_id) if depth == 0 =>
|
|
|
|
{
|
|
|
|
Some(def_id)
|
2017-01-25 17:32:44 +02:00
|
|
|
}
|
2017-12-11 09:00:05 -05:00
|
|
|
_ => None,
|
2017-01-25 17:32:44 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
let object_lifetime_defaults = type_def_id.map_or(vec![], |def_id| {
|
|
|
|
let in_body = {
|
|
|
|
let mut scope = self.scope;
|
|
|
|
loop {
|
|
|
|
match *scope {
|
|
|
|
Scope::Root => break false,
|
|
|
|
|
|
|
|
Scope::Body { .. } => break true,
|
|
|
|
|
2017-12-11 09:00:05 -05:00
|
|
|
Scope::Binder { s, .. }
|
|
|
|
| Scope::Elision { s, .. }
|
|
|
|
| Scope::ObjectLifetimeDefault { s, .. } => {
|
2017-01-25 17:32:44 +02:00
|
|
|
scope = s;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
let map = &self.map;
|
2017-11-23 08:05:58 -05:00
|
|
|
let unsubst = if let Some(id) = self.tcx.hir.as_local_node_id(def_id) {
|
2017-01-25 17:32:44 +02:00
|
|
|
&map.object_lifetime_defaults[&id]
|
|
|
|
} else {
|
2017-11-23 08:05:58 -05:00
|
|
|
let tcx = self.tcx;
|
2017-12-11 09:00:05 -05:00
|
|
|
self.xcrate_object_lifetime_defaults
|
|
|
|
.entry(def_id)
|
|
|
|
.or_insert_with(|| {
|
2017-11-23 08:05:58 -05:00
|
|
|
tcx.generics_of(def_id)
|
2017-12-11 09:00:05 -05:00
|
|
|
.types
|
2017-11-23 08:05:58 -05:00
|
|
|
.iter()
|
2017-12-11 09:00:05 -05:00
|
|
|
.map(|def| def.object_lifetime_default)
|
|
|
|
.collect()
|
|
|
|
})
|
2017-01-25 17:32:44 +02:00
|
|
|
};
|
2017-12-11 09:00:05 -05:00
|
|
|
unsubst
|
|
|
|
.iter()
|
|
|
|
.map(|set| match *set {
|
2017-11-23 08:05:58 -05:00
|
|
|
Set1::Empty => if in_body {
|
|
|
|
None
|
|
|
|
} else {
|
|
|
|
Some(Region::Static)
|
|
|
|
},
|
2017-07-29 01:13:40 +03:00
|
|
|
Set1::One(r) => r.subst(¶ms.lifetimes, map),
|
2017-12-11 09:00:05 -05:00
|
|
|
Set1::Many => None,
|
|
|
|
})
|
|
|
|
.collect()
|
2017-01-25 17:32:44 +02:00
|
|
|
});
|
|
|
|
|
2017-07-29 01:13:40 +03:00
|
|
|
for (i, ty) in params.types.iter().enumerate() {
|
2017-01-25 17:32:44 +02:00
|
|
|
if let Some(<) = object_lifetime_defaults.get(i) {
|
|
|
|
let scope = Scope::ObjectLifetimeDefault {
|
|
|
|
lifetime: lt,
|
2017-12-11 09:00:05 -05:00
|
|
|
s: self.scope,
|
2017-01-25 17:32:44 +02:00
|
|
|
};
|
|
|
|
self.with(scope, |_, this| this.visit_ty(ty));
|
|
|
|
} else {
|
|
|
|
self.visit_ty(ty);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-12-11 09:00:05 -05:00
|
|
|
for b in ¶ms.bindings {
|
|
|
|
self.visit_assoc_type_binding(b);
|
|
|
|
}
|
2017-01-25 17:32:44 +02:00
|
|
|
}
|
|
|
|
|
2017-12-11 09:00:05 -05:00
|
|
|
fn visit_fn_like_elision(
|
|
|
|
&mut self,
|
|
|
|
inputs: &'tcx [P<hir::Ty>],
|
|
|
|
output: Option<&'tcx P<hir::Ty>>,
|
|
|
|
) {
|
2017-01-13 15:09:56 +02:00
|
|
|
let mut arg_elide = Elide::FreshLateAnon(Cell::new(0));
|
|
|
|
let arg_scope = Scope::Elision {
|
|
|
|
elide: arg_elide.clone(),
|
2017-12-11 09:00:05 -05:00
|
|
|
s: self.scope,
|
2017-01-13 15:09:56 +02:00
|
|
|
};
|
|
|
|
self.with(arg_scope, |_, this| {
|
|
|
|
for input in inputs {
|
|
|
|
this.visit_ty(input);
|
|
|
|
}
|
|
|
|
match *this.scope {
|
|
|
|
Scope::Elision { ref elide, .. } => {
|
|
|
|
arg_elide = elide.clone();
|
|
|
|
}
|
2017-12-11 09:00:05 -05:00
|
|
|
_ => bug!(),
|
2017-01-13 15:09:56 +02:00
|
|
|
}
|
|
|
|
});
|
|
|
|
|
|
|
|
let output = match output {
|
|
|
|
Some(ty) => ty,
|
2017-12-11 09:00:05 -05:00
|
|
|
None => return,
|
2017-01-13 15:09:56 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
// Figure out if there's a body we can get argument names from,
|
|
|
|
// and whether there's a `self` argument (treated specially).
|
|
|
|
let mut assoc_item_kind = None;
|
|
|
|
let mut impl_self = None;
|
2017-11-23 08:05:58 -05:00
|
|
|
let parent = self.tcx.hir.get_parent_node(output.id);
|
|
|
|
let body = match self.tcx.hir.get(parent) {
|
2017-01-13 15:09:56 +02:00
|
|
|
// `fn` definitions and methods.
|
|
|
|
hir::map::NodeItem(&hir::Item {
|
2017-12-11 09:00:05 -05:00
|
|
|
node: hir::ItemFn(.., body),
|
|
|
|
..
|
|
|
|
}) => Some(body),
|
2017-01-13 15:09:56 +02:00
|
|
|
|
|
|
|
hir::map::NodeTraitItem(&hir::TraitItem {
|
2017-12-11 09:00:05 -05:00
|
|
|
node: hir::TraitItemKind::Method(_, ref m),
|
|
|
|
..
|
2017-01-13 15:09:56 +02:00
|
|
|
}) => {
|
2017-11-23 08:05:58 -05:00
|
|
|
match self.tcx
|
|
|
|
.hir
|
|
|
|
.expect_item(self.tcx.hir.get_parent(parent))
|
2017-12-11 09:00:05 -05:00
|
|
|
.node
|
|
|
|
{
|
2017-01-13 15:09:56 +02:00
|
|
|
hir::ItemTrait(.., ref trait_items) => {
|
2017-12-11 09:00:05 -05:00
|
|
|
assoc_item_kind = trait_items
|
|
|
|
.iter()
|
|
|
|
.find(|ti| ti.id.node_id == parent)
|
|
|
|
.map(|ti| ti.kind);
|
2017-01-13 15:09:56 +02:00
|
|
|
}
|
|
|
|
_ => {}
|
|
|
|
}
|
|
|
|
match *m {
|
|
|
|
hir::TraitMethod::Required(_) => None,
|
|
|
|
hir::TraitMethod::Provided(body) => Some(body),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
hir::map::NodeImplItem(&hir::ImplItem {
|
2017-12-11 09:00:05 -05:00
|
|
|
node: hir::ImplItemKind::Method(_, body),
|
|
|
|
..
|
2017-01-13 15:09:56 +02:00
|
|
|
}) => {
|
2017-11-23 08:05:58 -05:00
|
|
|
match self.tcx
|
|
|
|
.hir
|
|
|
|
.expect_item(self.tcx.hir.get_parent(parent))
|
2017-12-11 09:00:05 -05:00
|
|
|
.node
|
|
|
|
{
|
2017-01-13 15:09:56 +02:00
|
|
|
hir::ItemImpl(.., ref self_ty, ref impl_items) => {
|
|
|
|
impl_self = Some(self_ty);
|
2017-12-11 09:00:05 -05:00
|
|
|
assoc_item_kind = impl_items
|
|
|
|
.iter()
|
|
|
|
.find(|ii| ii.id.node_id == parent)
|
|
|
|
.map(|ii| ii.kind);
|
2017-01-13 15:09:56 +02:00
|
|
|
}
|
|
|
|
_ => {}
|
|
|
|
}
|
|
|
|
Some(body)
|
|
|
|
}
|
|
|
|
|
2017-08-05 03:13:38 +03:00
|
|
|
// Foreign functions, `fn(...) -> R` and `Trait(...) -> R` (both types and bounds).
|
2017-11-23 08:05:58 -05:00
|
|
|
hir::map::NodeForeignItem(_) | hir::map::NodeTy(_) | hir::map::NodeTraitRef(_) =>
|
|
|
|
None,
|
2017-01-13 15:09:56 +02:00
|
|
|
// Everything else (only closures?) doesn't
|
|
|
|
// actually enjoy elision in return types.
|
|
|
|
_ => {
|
|
|
|
self.visit_ty(output);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
let has_self = match assoc_item_kind {
|
|
|
|
Some(hir::AssociatedItemKind::Method { has_self }) => has_self,
|
2017-12-11 09:00:05 -05:00
|
|
|
_ => false,
|
2017-01-13 15:09:56 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
// In accordance with the rules for lifetime elision, we can determine
|
|
|
|
// what region to use for elision in the output type in two ways.
|
|
|
|
// First (determined here), if `self` is by-reference, then the
|
|
|
|
// implied output region is the region of the self parameter.
|
|
|
|
if has_self {
|
|
|
|
// Look for `self: &'a Self` - also desugared from `&'a self`,
|
|
|
|
// and if that matches, use it for elision and return early.
|
|
|
|
let is_self_ty = |def: Def| {
|
|
|
|
if let Def::SelfTy(..) = def {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Can't always rely on literal (or implied) `Self` due
|
|
|
|
// to the way elision rules were originally specified.
|
|
|
|
let impl_self = impl_self.map(|ty| &ty.node);
|
|
|
|
if let Some(&hir::TyPath(hir::QPath::Resolved(None, ref path))) = impl_self {
|
|
|
|
match path.def {
|
|
|
|
// Whitelist the types that unambiguously always
|
|
|
|
// result in the same type constructor being used
|
|
|
|
// (it can't differ between `Self` and `self`).
|
2017-12-11 09:00:05 -05:00
|
|
|
Def::Struct(_) | Def::Union(_) | Def::Enum(_) | Def::PrimTy(_) => {
|
|
|
|
return def == path.def
|
|
|
|
}
|
2017-01-13 15:09:56 +02:00
|
|
|
_ => {}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
false
|
|
|
|
};
|
|
|
|
|
|
|
|
if let hir::TyRptr(lifetime_ref, ref mt) = inputs[0].node {
|
|
|
|
if let hir::TyPath(hir::QPath::Resolved(None, ref path)) = mt.ty.node {
|
|
|
|
if is_self_ty(path.def) {
|
|
|
|
if let Some(&lifetime) = self.map.defs.get(&lifetime_ref.id) {
|
|
|
|
let scope = Scope::Elision {
|
|
|
|
elide: Elide::Exact(lifetime),
|
2017-12-11 09:00:05 -05:00
|
|
|
s: self.scope,
|
2017-01-13 15:09:56 +02:00
|
|
|
};
|
|
|
|
self.with(scope, |_, this| this.visit_ty(output));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Second, if there was exactly one lifetime (either a substitution or a
|
|
|
|
// reference) in the arguments, then any anonymous regions in the output
|
|
|
|
// have that lifetime.
|
|
|
|
let mut possible_implied_output_region = None;
|
|
|
|
let mut lifetime_count = 0;
|
2017-12-11 09:00:05 -05:00
|
|
|
let arg_lifetimes = inputs
|
|
|
|
.iter()
|
|
|
|
.enumerate()
|
|
|
|
.skip(has_self as usize)
|
|
|
|
.map(|(i, input)| {
|
|
|
|
let mut gather = GatherLifetimes {
|
|
|
|
map: self.map,
|
|
|
|
binder_depth: 1,
|
|
|
|
have_bound_regions: false,
|
|
|
|
lifetimes: FxHashSet(),
|
|
|
|
};
|
|
|
|
gather.visit_ty(input);
|
2017-01-13 15:09:56 +02:00
|
|
|
|
2017-12-11 09:00:05 -05:00
|
|
|
lifetime_count += gather.lifetimes.len();
|
2017-01-13 15:09:56 +02:00
|
|
|
|
2017-12-11 09:00:05 -05:00
|
|
|
if lifetime_count == 1 && gather.lifetimes.len() == 1 {
|
|
|
|
// there's a chance that the unique lifetime of this
|
|
|
|
// iteration will be the appropriate lifetime for output
|
|
|
|
// parameters, so lets store it.
|
|
|
|
possible_implied_output_region = gather.lifetimes.iter().cloned().next();
|
|
|
|
}
|
2017-01-13 15:09:56 +02:00
|
|
|
|
2017-12-11 09:00:05 -05:00
|
|
|
ElisionFailureInfo {
|
|
|
|
parent: body,
|
|
|
|
index: i,
|
|
|
|
lifetime_count: gather.lifetimes.len(),
|
|
|
|
have_bound_regions: gather.have_bound_regions,
|
|
|
|
}
|
|
|
|
})
|
|
|
|
.collect();
|
2017-01-13 15:09:56 +02:00
|
|
|
|
|
|
|
let elide = if lifetime_count == 1 {
|
|
|
|
Elide::Exact(possible_implied_output_region.unwrap())
|
|
|
|
} else {
|
|
|
|
Elide::Error(arg_lifetimes)
|
|
|
|
};
|
|
|
|
|
|
|
|
let scope = Scope::Elision {
|
2017-07-03 11:19:51 -07:00
|
|
|
elide,
|
2017-12-11 09:00:05 -05:00
|
|
|
s: self.scope,
|
2017-01-13 15:09:56 +02:00
|
|
|
};
|
|
|
|
self.with(scope, |_, this| this.visit_ty(output));
|
|
|
|
|
|
|
|
struct GatherLifetimes<'a> {
|
|
|
|
map: &'a NamedRegionMap,
|
|
|
|
binder_depth: u32,
|
|
|
|
have_bound_regions: bool,
|
|
|
|
lifetimes: FxHashSet<Region>,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<'v, 'a> Visitor<'v> for GatherLifetimes<'a> {
|
|
|
|
fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'v> {
|
|
|
|
NestedVisitorMap::None
|
|
|
|
}
|
|
|
|
|
|
|
|
fn visit_ty(&mut self, ty: &hir::Ty) {
|
2017-01-17 16:46:23 +02:00
|
|
|
if let hir::TyBareFn(_) = ty.node {
|
|
|
|
self.binder_depth += 1;
|
|
|
|
}
|
2017-01-25 17:32:44 +02:00
|
|
|
if let hir::TyTraitObject(ref bounds, ref lifetime) = ty.node {
|
|
|
|
for bound in bounds {
|
|
|
|
self.visit_poly_trait_ref(bound, hir::TraitBoundModifier::None);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Stay on the safe side and don't include the object
|
|
|
|
// lifetime default (which may not end up being used).
|
|
|
|
if !lifetime.is_elided() {
|
|
|
|
self.visit_lifetime(lifetime);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
intravisit::walk_ty(self, ty);
|
|
|
|
}
|
2017-01-17 16:46:23 +02:00
|
|
|
if let hir::TyBareFn(_) = ty.node {
|
|
|
|
self.binder_depth -= 1;
|
|
|
|
}
|
2017-01-13 15:09:56 +02:00
|
|
|
}
|
|
|
|
|
2017-10-16 21:07:26 +02:00
|
|
|
fn visit_generic_param(&mut self, param: &hir::GenericParam) {
|
|
|
|
if let hir::GenericParam::Lifetime(ref lifetime_def) = *param {
|
|
|
|
for l in &lifetime_def.bounds {
|
|
|
|
self.visit_lifetime(l);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
intravisit::walk_generic_param(self, param);
|
|
|
|
}
|
|
|
|
|
2017-12-11 09:00:05 -05:00
|
|
|
fn visit_poly_trait_ref(
|
|
|
|
&mut self,
|
|
|
|
trait_ref: &hir::PolyTraitRef,
|
|
|
|
modifier: hir::TraitBoundModifier,
|
|
|
|
) {
|
2017-01-13 15:09:56 +02:00
|
|
|
self.binder_depth += 1;
|
|
|
|
intravisit::walk_poly_trait_ref(self, trait_ref, modifier);
|
|
|
|
self.binder_depth -= 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
fn visit_lifetime(&mut self, lifetime_ref: &hir::Lifetime) {
|
|
|
|
if let Some(&lifetime) = self.map.defs.get(&lifetime_ref.id) {
|
|
|
|
match lifetime {
|
2017-12-11 09:00:05 -05:00
|
|
|
Region::LateBound(debruijn, _, _) | Region::LateBoundAnon(debruijn, _)
|
|
|
|
if debruijn.depth < self.binder_depth =>
|
|
|
|
{
|
2017-01-13 15:09:56 +02:00
|
|
|
self.have_bound_regions = true;
|
|
|
|
}
|
|
|
|
_ => {
|
2017-12-11 09:00:05 -05:00
|
|
|
self.lifetimes
|
|
|
|
.insert(lifetime.from_depth(self.binder_depth));
|
2017-01-13 15:09:56 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-11-23 08:05:58 -05:00
|
|
|
fn resolve_elided_lifetimes(&mut self, lifetime_refs: &'tcx [hir::Lifetime]) {
|
2017-01-13 15:09:56 +02:00
|
|
|
if lifetime_refs.is_empty() {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
let span = lifetime_refs[0].span;
|
|
|
|
let mut late_depth = 0;
|
|
|
|
let mut scope = self.scope;
|
|
|
|
let error = loop {
|
|
|
|
match *scope {
|
|
|
|
// Do not assign any resolution, it will be inferred.
|
|
|
|
Scope::Body { .. } => return,
|
|
|
|
|
|
|
|
Scope::Root => break None,
|
|
|
|
|
|
|
|
Scope::Binder { s, .. } => {
|
|
|
|
late_depth += 1;
|
|
|
|
scope = s;
|
|
|
|
}
|
|
|
|
|
|
|
|
Scope::Elision { ref elide, .. } => {
|
|
|
|
let lifetime = match *elide {
|
|
|
|
Elide::FreshLateAnon(ref counter) => {
|
|
|
|
for lifetime_ref in lifetime_refs {
|
|
|
|
let lifetime = Region::late_anon(counter).shifted(late_depth);
|
|
|
|
self.insert_lifetime(lifetime_ref, lifetime);
|
|
|
|
}
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
Elide::Exact(l) => l.shifted(late_depth),
|
2017-12-11 09:00:05 -05:00
|
|
|
Elide::Error(ref e) => break Some(e),
|
2017-01-13 15:09:56 +02:00
|
|
|
};
|
|
|
|
for lifetime_ref in lifetime_refs {
|
|
|
|
self.insert_lifetime(lifetime_ref, lifetime);
|
|
|
|
}
|
|
|
|
return;
|
|
|
|
}
|
2017-01-25 17:32:44 +02:00
|
|
|
|
|
|
|
Scope::ObjectLifetimeDefault { s, .. } => {
|
|
|
|
scope = s;
|
|
|
|
}
|
2017-01-13 15:09:56 +02:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2017-12-11 09:00:05 -05:00
|
|
|
let mut err = struct_span_err!(
|
2017-11-23 08:05:58 -05:00
|
|
|
self.tcx.sess,
|
2017-12-11 09:00:05 -05:00
|
|
|
span,
|
|
|
|
E0106,
|
2017-01-13 15:09:56 +02:00
|
|
|
"missing lifetime specifier{}",
|
2017-12-11 09:00:05 -05:00
|
|
|
if lifetime_refs.len() > 1 { "s" } else { "" }
|
|
|
|
);
|
2017-01-13 15:09:56 +02:00
|
|
|
let msg = if lifetime_refs.len() > 1 {
|
|
|
|
format!("expected {} lifetime parameters", lifetime_refs.len())
|
|
|
|
} else {
|
|
|
|
format!("expected lifetime parameter")
|
|
|
|
};
|
2017-05-04 14:17:23 +02:00
|
|
|
err.span_label(span, msg);
|
2017-01-13 15:09:56 +02:00
|
|
|
|
|
|
|
if let Some(params) = error {
|
|
|
|
if lifetime_refs.len() == 1 {
|
|
|
|
self.report_elision_failure(&mut err, params);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
err.emit();
|
|
|
|
}
|
|
|
|
|
2017-12-11 09:00:05 -05:00
|
|
|
fn report_elision_failure(
|
|
|
|
&mut self,
|
|
|
|
db: &mut DiagnosticBuilder,
|
|
|
|
params: &[ElisionFailureInfo],
|
|
|
|
) {
|
2017-01-13 15:09:56 +02:00
|
|
|
let mut m = String::new();
|
|
|
|
let len = params.len();
|
|
|
|
|
2017-12-11 09:00:05 -05:00
|
|
|
let elided_params: Vec<_> = params
|
|
|
|
.iter()
|
|
|
|
.cloned()
|
|
|
|
.filter(|info| info.lifetime_count > 0)
|
|
|
|
.collect();
|
2017-01-13 15:09:56 +02:00
|
|
|
|
|
|
|
let elided_len = elided_params.len();
|
|
|
|
|
|
|
|
for (i, info) in elided_params.into_iter().enumerate() {
|
|
|
|
let ElisionFailureInfo {
|
2017-12-11 09:00:05 -05:00
|
|
|
parent,
|
|
|
|
index,
|
|
|
|
lifetime_count: n,
|
|
|
|
have_bound_regions,
|
2017-01-13 15:09:56 +02:00
|
|
|
} = info;
|
|
|
|
|
|
|
|
let help_name = if let Some(body) = parent {
|
2017-11-23 08:05:58 -05:00
|
|
|
let arg = &self.tcx.hir.body(body).arguments[index];
|
|
|
|
format!("`{}`", self.tcx.hir.node_to_pretty_string(arg.pat.id))
|
2017-01-13 15:09:56 +02:00
|
|
|
} else {
|
|
|
|
format!("argument {}", index + 1)
|
|
|
|
};
|
|
|
|
|
2017-12-11 09:00:05 -05:00
|
|
|
m.push_str(
|
|
|
|
&(if n == 1 {
|
|
|
|
help_name
|
|
|
|
} else {
|
|
|
|
format!(
|
|
|
|
"one of {}'s {} {}lifetimes",
|
|
|
|
help_name,
|
|
|
|
n,
|
|
|
|
if have_bound_regions { "free " } else { "" }
|
|
|
|
)
|
|
|
|
})[..],
|
|
|
|
);
|
2017-01-13 15:09:56 +02:00
|
|
|
|
|
|
|
if elided_len == 2 && i == 0 {
|
|
|
|
m.push_str(" or ");
|
|
|
|
} else if i + 2 == elided_len {
|
|
|
|
m.push_str(", or ");
|
|
|
|
} else if i != elided_len - 1 {
|
|
|
|
m.push_str(", ");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if len == 0 {
|
2017-12-11 09:00:05 -05:00
|
|
|
help!(
|
|
|
|
db,
|
|
|
|
"this function's return type contains a borrowed value, but \
|
|
|
|
there is no value for it to be borrowed from"
|
|
|
|
);
|
|
|
|
help!(db, "consider giving it a 'static lifetime");
|
2017-01-13 15:09:56 +02:00
|
|
|
} else if elided_len == 0 {
|
2017-12-11 09:00:05 -05:00
|
|
|
help!(
|
|
|
|
db,
|
|
|
|
"this function's return type contains a borrowed value with \
|
|
|
|
an elided lifetime, but the lifetime cannot be derived from \
|
|
|
|
the arguments"
|
|
|
|
);
|
|
|
|
help!(
|
|
|
|
db,
|
|
|
|
"consider giving it an explicit bounded or 'static \
|
|
|
|
lifetime"
|
|
|
|
);
|
2017-01-13 15:09:56 +02:00
|
|
|
} else if elided_len == 1 {
|
2017-12-11 09:00:05 -05:00
|
|
|
help!(
|
|
|
|
db,
|
|
|
|
"this function's return type contains a borrowed value, but \
|
|
|
|
the signature does not say which {} it is borrowed from",
|
|
|
|
m
|
|
|
|
);
|
2017-01-13 15:09:56 +02:00
|
|
|
} else {
|
2017-12-11 09:00:05 -05:00
|
|
|
help!(
|
|
|
|
db,
|
|
|
|
"this function's return type contains a borrowed value, but \
|
|
|
|
the signature does not say whether it is borrowed from {}",
|
|
|
|
m
|
|
|
|
);
|
2017-01-13 15:09:56 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-11-23 08:05:58 -05:00
|
|
|
fn resolve_object_lifetime_default(&mut self, lifetime_ref: &'tcx hir::Lifetime) {
|
2017-01-25 17:32:44 +02:00
|
|
|
let mut late_depth = 0;
|
|
|
|
let mut scope = self.scope;
|
|
|
|
let lifetime = loop {
|
|
|
|
match *scope {
|
|
|
|
Scope::Binder { s, .. } => {
|
|
|
|
late_depth += 1;
|
|
|
|
scope = s;
|
|
|
|
}
|
|
|
|
|
2017-12-11 09:00:05 -05:00
|
|
|
Scope::Root | Scope::Elision { .. } => break Region::Static,
|
2017-01-25 17:32:44 +02:00
|
|
|
|
2017-12-11 09:00:05 -05:00
|
|
|
Scope::Body { .. } | Scope::ObjectLifetimeDefault { lifetime: None, .. } => return,
|
2017-01-25 17:32:44 +02:00
|
|
|
|
2017-12-11 09:00:05 -05:00
|
|
|
Scope::ObjectLifetimeDefault {
|
|
|
|
lifetime: Some(l), ..
|
|
|
|
} => break l,
|
2017-01-25 17:32:44 +02:00
|
|
|
}
|
|
|
|
};
|
|
|
|
self.insert_lifetime(lifetime_ref, lifetime.shifted(late_depth));
|
|
|
|
}
|
|
|
|
|
2017-10-16 21:07:26 +02:00
|
|
|
fn check_lifetime_params(&mut self, old_scope: ScopeRef, params: &'tcx [hir::GenericParam]) {
|
|
|
|
for (i, lifetime_i) in params.lifetimes().enumerate() {
|
|
|
|
for lifetime in params.lifetimes() {
|
2017-09-19 16:36:54 -07:00
|
|
|
match lifetime.lifetime.name {
|
|
|
|
hir::LifetimeName::Static | hir::LifetimeName::Underscore => {
|
|
|
|
let lifetime = lifetime.lifetime;
|
|
|
|
let name = lifetime.name.name();
|
2017-12-11 09:00:05 -05:00
|
|
|
let mut err = struct_span_err!(
|
2017-11-23 08:05:58 -05:00
|
|
|
self.tcx.sess,
|
2017-12-11 09:00:05 -05:00
|
|
|
lifetime.span,
|
|
|
|
E0262,
|
|
|
|
"invalid lifetime parameter name: `{}`",
|
|
|
|
name
|
|
|
|
);
|
|
|
|
err.span_label(
|
|
|
|
lifetime.span,
|
|
|
|
format!("{} is a reserved lifetime name", name),
|
|
|
|
);
|
2017-09-19 16:36:54 -07:00
|
|
|
err.emit();
|
|
|
|
}
|
|
|
|
hir::LifetimeName::Implicit | hir::LifetimeName::Name(_) => {}
|
2013-10-28 17:37:10 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-12-12 11:09:24 -05:00
|
|
|
// It is a hard error to shadow a lifetime within the same scope.
|
2017-10-16 21:07:26 +02:00
|
|
|
for lifetime_j in params.lifetimes().skip(i + 1) {
|
2014-08-05 22:59:24 -04:00
|
|
|
if lifetime_i.lifetime.name == lifetime_j.lifetime.name {
|
2017-12-11 09:00:05 -05:00
|
|
|
struct_span_err!(
|
2017-11-23 08:05:58 -05:00
|
|
|
self.tcx.sess,
|
2017-12-11 09:00:05 -05:00
|
|
|
lifetime_j.lifetime.span,
|
|
|
|
E0263,
|
|
|
|
"lifetime name `{}` declared twice in the same scope",
|
|
|
|
lifetime_j.lifetime.name.name()
|
|
|
|
).span_label(lifetime_j.lifetime.span, "declared twice")
|
|
|
|
.span_label(lifetime_i.lifetime.span, "previous declaration here")
|
2016-08-09 22:42:35 +02:00
|
|
|
.emit();
|
2014-08-05 22:59:24 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-12-12 11:09:24 -05:00
|
|
|
// It is a soft error to shadow a lifetime within a parent scope.
|
|
|
|
self.check_lifetime_def_for_shadowing(old_scope, &lifetime_i.lifetime);
|
|
|
|
|
2015-01-31 12:20:46 -05:00
|
|
|
for bound in &lifetime_i.bounds {
|
2017-09-19 16:36:54 -07:00
|
|
|
match bound.name {
|
|
|
|
hir::LifetimeName::Underscore => {
|
2017-12-11 09:00:05 -05:00
|
|
|
let mut err = struct_span_err!(
|
2017-11-23 08:05:58 -05:00
|
|
|
self.tcx.sess,
|
2017-12-11 09:00:05 -05:00
|
|
|
bound.span,
|
|
|
|
E0637,
|
|
|
|
"invalid lifetime bound name: `'_`"
|
|
|
|
);
|
2017-09-19 16:36:54 -07:00
|
|
|
err.span_label(bound.span, "`'_` is a reserved lifetime name");
|
|
|
|
err.emit();
|
|
|
|
}
|
|
|
|
hir::LifetimeName::Static => {
|
|
|
|
self.insert_lifetime(bound, Region::Static);
|
2017-11-23 08:05:58 -05:00
|
|
|
self.tcx
|
|
|
|
.sess
|
2017-12-11 09:00:05 -05:00
|
|
|
.struct_span_warn(
|
|
|
|
lifetime_i.lifetime.span.to(bound.span),
|
|
|
|
&format!(
|
|
|
|
"unnecessary lifetime parameter `{}`",
|
|
|
|
lifetime_i.lifetime.name.name()
|
|
|
|
),
|
|
|
|
)
|
2017-09-19 16:36:54 -07:00
|
|
|
.help(&format!(
|
|
|
|
"you can use the `'static` lifetime directly, in place \
|
2017-12-11 09:00:05 -05:00
|
|
|
of `{}`",
|
|
|
|
lifetime_i.lifetime.name.name()
|
|
|
|
))
|
2017-09-19 16:36:54 -07:00
|
|
|
.emit();
|
|
|
|
}
|
2017-12-11 09:00:05 -05:00
|
|
|
hir::LifetimeName::Implicit | hir::LifetimeName::Name(_) => {
|
2017-09-19 16:36:54 -07:00
|
|
|
self.resolve_lifetime_ref(bound);
|
|
|
|
}
|
2017-03-21 21:38:32 +09:00
|
|
|
}
|
2013-10-28 17:37:10 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-11-23 08:05:58 -05:00
|
|
|
fn check_lifetime_def_for_shadowing(&self,
|
|
|
|
mut old_scope: ScopeRef,
|
|
|
|
lifetime: &'tcx hir::Lifetime) {
|
2015-04-03 02:51:38 +02:00
|
|
|
for &(label, label_span) in &self.labels_in_fn {
|
2015-05-06 01:49:07 +02:00
|
|
|
// FIXME (#24278): non-hygienic comparison
|
2017-09-19 16:36:54 -07:00
|
|
|
if lifetime.name.name() == label {
|
2017-12-11 09:00:05 -05:00
|
|
|
signal_shadowing_problem(
|
2017-11-23 08:05:58 -05:00
|
|
|
self.tcx,
|
2017-12-11 09:00:05 -05:00
|
|
|
label,
|
|
|
|
original_label(label_span),
|
|
|
|
shadower_lifetime(&lifetime),
|
|
|
|
);
|
2015-04-03 02:51:38 +02:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-12-12 11:09:24 -05:00
|
|
|
loop {
|
|
|
|
match *old_scope {
|
2017-12-11 09:00:05 -05:00
|
|
|
Scope::Body { s, .. }
|
|
|
|
| Scope::Elision { s, .. }
|
|
|
|
| Scope::ObjectLifetimeDefault { s, .. } => {
|
2014-12-12 11:09:24 -05:00
|
|
|
old_scope = s;
|
|
|
|
}
|
|
|
|
|
2017-01-08 22:40:04 +02:00
|
|
|
Scope::Root => {
|
2014-12-12 11:09:24 -05:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2017-12-11 09:00:05 -05:00
|
|
|
Scope::Binder {
|
|
|
|
ref lifetimes,
|
|
|
|
s,
|
|
|
|
next_early_index: _,
|
|
|
|
} => {
|
2017-01-11 17:35:54 +02:00
|
|
|
if let Some(&def) = lifetimes.get(&lifetime.name) {
|
2017-11-23 08:05:58 -05:00
|
|
|
let node_id = self.tcx.hir.as_local_node_id(def.id().unwrap()).unwrap();
|
2017-08-15 17:05:25 +02:00
|
|
|
|
2015-04-03 02:51:38 +02:00
|
|
|
signal_shadowing_problem(
|
2017-11-23 08:05:58 -05:00
|
|
|
self.tcx,
|
2017-09-19 16:36:54 -07:00
|
|
|
lifetime.name.name(),
|
2017-11-23 08:05:58 -05:00
|
|
|
original_lifetime(self.tcx.hir.span(node_id)),
|
2017-12-11 09:00:05 -05:00
|
|
|
shadower_lifetime(&lifetime),
|
|
|
|
);
|
2014-12-12 11:09:24 -05:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
old_scope = s;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-11-23 08:05:58 -05:00
|
|
|
fn insert_lifetime(&mut self, lifetime_ref: &'tcx hir::Lifetime, def: Region) {
|
2013-10-28 17:37:10 -04:00
|
|
|
if lifetime_ref.id == ast::DUMMY_NODE_ID {
|
2017-12-11 09:00:05 -05:00
|
|
|
span_bug!(
|
|
|
|
lifetime_ref.span,
|
|
|
|
"lifetime reference not renumbered, \
|
|
|
|
probably a bug in syntax::fold"
|
|
|
|
);
|
2013-10-28 17:37:10 -04:00
|
|
|
}
|
|
|
|
|
2017-12-11 09:00:05 -05:00
|
|
|
debug!(
|
|
|
|
"insert_lifetime: {} resolved to {:?} span={:?}",
|
2017-11-23 08:05:58 -05:00
|
|
|
self.tcx.hir.node_to_string(lifetime_ref.id),
|
2017-12-11 09:00:05 -05:00
|
|
|
def,
|
2017-11-23 08:05:58 -05:00
|
|
|
self.tcx.sess.codemap().span_to_string(lifetime_ref.span)
|
2017-12-11 09:00:05 -05:00
|
|
|
);
|
2016-04-21 05:10:10 -04:00
|
|
|
self.map.defs.insert(lifetime_ref.id, def);
|
2017-11-23 08:05:58 -05:00
|
|
|
|
|
|
|
match def {
|
|
|
|
Region::LateBoundAnon(..) |
|
|
|
|
Region::Static => {
|
|
|
|
// These are anonymous lifetimes or lifetimes that are not declared.
|
|
|
|
}
|
|
|
|
|
|
|
|
Region::Free(_, def_id) |
|
|
|
|
Region::LateBound(_, def_id, _) |
|
|
|
|
Region::EarlyBound(_, def_id, _) => {
|
|
|
|
// A lifetime declared by the user.
|
|
|
|
if !self.lifetime_uses.contains_key(&def_id) {
|
|
|
|
self.lifetime_uses
|
|
|
|
.insert(def_id, LifetimeUseSet::One(lifetime_ref));
|
|
|
|
} else {
|
|
|
|
self.lifetime_uses.insert(def_id, LifetimeUseSet::Many);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2013-10-28 17:37:10 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-03-07 08:43:39 +01:00
|
|
|
///////////////////////////////////////////////////////////////////////////
|
|
|
|
|
2016-04-21 05:10:10 -04:00
|
|
|
/// Detects late-bound lifetimes and inserts them into
|
|
|
|
/// `map.late_bound`.
|
|
|
|
///
|
|
|
|
/// A region declared on a fn is **late-bound** if:
|
|
|
|
/// - it is constrained by an argument type;
|
|
|
|
/// - it does not appear in a where-clause.
|
|
|
|
///
|
|
|
|
/// "Constrained" basically means that it appears in any type but
|
|
|
|
/// not amongst the inputs to a projection. In other words, `<&'a
|
|
|
|
/// T as Trait<''b>>::Foo` does not constrain `'a` or `'b`.
|
2017-12-11 09:00:05 -05:00
|
|
|
fn insert_late_bound_lifetimes(
|
|
|
|
map: &mut NamedRegionMap,
|
|
|
|
decl: &hir::FnDecl,
|
|
|
|
generics: &hir::Generics,
|
|
|
|
) {
|
|
|
|
debug!(
|
|
|
|
"insert_late_bound_lifetimes(decl={:?}, generics={:?})",
|
|
|
|
decl,
|
|
|
|
generics
|
|
|
|
);
|
2016-04-21 05:10:10 -04:00
|
|
|
|
2017-12-11 09:00:05 -05:00
|
|
|
let mut constrained_by_input = ConstrainedCollector {
|
|
|
|
regions: FxHashSet(),
|
|
|
|
};
|
2016-12-20 22:46:11 +02:00
|
|
|
for arg_ty in &decl.inputs {
|
|
|
|
constrained_by_input.visit_ty(arg_ty);
|
2014-03-07 08:43:39 +01:00
|
|
|
}
|
|
|
|
|
2016-08-06 03:11:17 +03:00
|
|
|
let mut appears_in_output = AllCollector {
|
2016-11-08 14:02:55 +11:00
|
|
|
regions: FxHashSet(),
|
2016-08-06 03:11:17 +03:00
|
|
|
};
|
2016-04-21 05:10:10 -04:00
|
|
|
intravisit::walk_fn_ret_ty(&mut appears_in_output, &decl.output);
|
|
|
|
|
2017-12-11 09:00:05 -05:00
|
|
|
debug!(
|
|
|
|
"insert_late_bound_lifetimes: constrained_by_input={:?}",
|
|
|
|
constrained_by_input.regions
|
|
|
|
);
|
2016-04-21 05:10:10 -04:00
|
|
|
|
|
|
|
// Walk the lifetimes that appear in where clauses.
|
|
|
|
//
|
|
|
|
// Subtle point: because we disallow nested bindings, we can just
|
|
|
|
// ignore binders here and scrape up all names we see.
|
2016-08-06 03:11:17 +03:00
|
|
|
let mut appears_in_where_clause = AllCollector {
|
2016-11-08 14:02:55 +11:00
|
|
|
regions: FxHashSet(),
|
2016-08-06 03:11:17 +03:00
|
|
|
};
|
2017-10-16 21:07:26 +02:00
|
|
|
|
|
|
|
for param in &generics.params {
|
|
|
|
match *param {
|
|
|
|
hir::GenericParam::Lifetime(ref lifetime_def) => {
|
|
|
|
if !lifetime_def.bounds.is_empty() {
|
|
|
|
// `'a: 'b` means both `'a` and `'b` are referenced
|
|
|
|
appears_in_where_clause.visit_generic_param(param);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
hir::GenericParam::Type(ref ty_param) => {
|
|
|
|
walk_list!(
|
|
|
|
&mut appears_in_where_clause,
|
|
|
|
visit_ty_param_bound,
|
|
|
|
&ty_param.bounds
|
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|
2016-04-21 05:10:10 -04:00
|
|
|
}
|
2017-10-16 21:07:26 +02:00
|
|
|
|
2017-12-11 09:00:05 -05:00
|
|
|
walk_list!(
|
|
|
|
&mut appears_in_where_clause,
|
|
|
|
visit_where_predicate,
|
|
|
|
&generics.where_clause.predicates
|
|
|
|
);
|
2016-04-21 05:10:10 -04:00
|
|
|
|
2017-12-11 09:00:05 -05:00
|
|
|
debug!(
|
|
|
|
"insert_late_bound_lifetimes: appears_in_where_clause={:?}",
|
|
|
|
appears_in_where_clause.regions
|
|
|
|
);
|
2016-04-21 05:10:10 -04:00
|
|
|
|
|
|
|
// Late bound regions are those that:
|
|
|
|
// - appear in the inputs
|
|
|
|
// - do not appear in the where-clauses
|
2016-08-06 03:11:17 +03:00
|
|
|
// - are not implicitly captured by `impl Trait`
|
2017-10-16 21:07:26 +02:00
|
|
|
for lifetime in generics.lifetimes() {
|
2016-04-21 05:10:10 -04:00
|
|
|
let name = lifetime.lifetime.name;
|
|
|
|
|
|
|
|
// appears in the where clauses? early-bound.
|
2017-12-11 09:00:05 -05:00
|
|
|
if appears_in_where_clause.regions.contains(&name) {
|
|
|
|
continue;
|
|
|
|
}
|
2016-04-21 05:10:10 -04:00
|
|
|
|
2017-07-29 17:19:57 +03:00
|
|
|
// does not appear in the inputs, but appears in the return type? early-bound.
|
2017-12-11 09:00:05 -05:00
|
|
|
if !constrained_by_input.regions.contains(&name)
|
|
|
|
&& appears_in_output.regions.contains(&name)
|
|
|
|
{
|
2017-01-06 14:35:23 -05:00
|
|
|
continue;
|
|
|
|
}
|
2016-04-21 05:10:10 -04:00
|
|
|
|
2017-12-11 09:00:05 -05:00
|
|
|
debug!(
|
|
|
|
"insert_late_bound_lifetimes: \
|
|
|
|
lifetime {:?} with id {:?} is late-bound",
|
|
|
|
lifetime.lifetime.name,
|
|
|
|
lifetime.lifetime.id
|
|
|
|
);
|
2016-04-21 05:10:10 -04:00
|
|
|
|
2017-01-06 14:35:23 -05:00
|
|
|
let inserted = map.late_bound.insert(lifetime.lifetime.id);
|
2017-12-11 09:00:05 -05:00
|
|
|
assert!(
|
|
|
|
inserted,
|
|
|
|
"visited lifetime {:?} twice",
|
|
|
|
lifetime.lifetime.id
|
|
|
|
);
|
2016-04-21 05:10:10 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
struct ConstrainedCollector {
|
2017-09-19 16:36:54 -07:00
|
|
|
regions: FxHashSet<hir::LifetimeName>,
|
2016-04-21 05:10:10 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
impl<'v> Visitor<'v> for ConstrainedCollector {
|
2016-11-28 14:00:26 -05:00
|
|
|
fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'v> {
|
|
|
|
NestedVisitorMap::None
|
|
|
|
}
|
2016-11-24 20:15:11 +01:00
|
|
|
|
2016-04-21 05:10:10 -04:00
|
|
|
fn visit_ty(&mut self, ty: &'v hir::Ty) {
|
|
|
|
match ty.node {
|
2017-12-11 09:00:05 -05:00
|
|
|
hir::TyPath(hir::QPath::Resolved(Some(_), _))
|
|
|
|
| hir::TyPath(hir::QPath::TypeRelative(..)) => {
|
2016-04-21 05:10:10 -04:00
|
|
|
// ignore lifetimes appearing in associated type
|
|
|
|
// projections, as they are not *constrained*
|
|
|
|
// (defined above)
|
2014-11-29 17:08:30 +13:00
|
|
|
}
|
2014-12-20 02:48:43 -08:00
|
|
|
|
2016-10-27 05:17:42 +03:00
|
|
|
hir::TyPath(hir::QPath::Resolved(None, ref path)) => {
|
2016-04-21 05:10:10 -04:00
|
|
|
// consider only the lifetimes on the final
|
|
|
|
// segment; I am not sure it's even currently
|
|
|
|
// valid to have them elsewhere, but even if it
|
|
|
|
// is, those would be potentially inputs to
|
|
|
|
// projections
|
|
|
|
if let Some(last_segment) = path.segments.last() {
|
|
|
|
self.visit_path_segment(path.span, last_segment);
|
2014-12-20 02:48:43 -08:00
|
|
|
}
|
2014-12-20 02:29:19 -08:00
|
|
|
}
|
2014-08-27 21:46:52 -04:00
|
|
|
|
2016-04-21 05:10:10 -04:00
|
|
|
_ => {
|
|
|
|
intravisit::walk_ty(self, ty);
|
|
|
|
}
|
2014-08-27 21:46:52 -04:00
|
|
|
}
|
|
|
|
}
|
2014-03-07 08:43:39 +01:00
|
|
|
|
2016-04-21 05:10:10 -04:00
|
|
|
fn visit_lifetime(&mut self, lifetime_ref: &'v hir::Lifetime) {
|
|
|
|
self.regions.insert(lifetime_ref.name);
|
|
|
|
}
|
2014-03-07 08:43:39 +01:00
|
|
|
}
|
|
|
|
|
2016-04-21 05:10:10 -04:00
|
|
|
struct AllCollector {
|
2017-09-19 16:36:54 -07:00
|
|
|
regions: FxHashSet<hir::LifetimeName>,
|
2014-08-27 21:46:52 -04:00
|
|
|
}
|
|
|
|
|
2016-04-21 05:10:10 -04:00
|
|
|
impl<'v> Visitor<'v> for AllCollector {
|
2016-11-28 14:00:26 -05:00
|
|
|
fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'v> {
|
|
|
|
NestedVisitorMap::None
|
|
|
|
}
|
2016-11-24 20:15:11 +01:00
|
|
|
|
2016-04-21 05:10:10 -04:00
|
|
|
fn visit_lifetime(&mut self, lifetime_ref: &'v hir::Lifetime) {
|
|
|
|
self.regions.insert(lifetime_ref.name);
|
2014-03-07 08:43:39 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|