1 // Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT
2 // file at the top-level directory of this distribution and at
3 // http://rust-lang.org/COPYRIGHT.
5 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8 // option. This file may not be copied, modified, or distributed
9 // except according to those terms.
11 //! Name resolution for lifetimes.
13 //! Name resolution for lifetimes follows MUCH simpler rules than the
14 //! full resolve. For example, lifetime names are never exported or
15 //! used between functions, and they operate in a purely top-down
16 //! way. Therefore we break lifetime name resolution into a separate pass.
20 use hir
::def_id
::DefId
;
21 use middle
::cstore
::CrateStore
;
26 use std
::mem
::replace
;
31 use errors
::DiagnosticBuilder
;
32 use util
::common
::ErrorReported
;
33 use util
::nodemap
::{NodeMap, NodeSet, FxHashSet, FxHashMap, DefIdMap}
;
34 use rustc_back
::slice
;
37 use hir
::intravisit
::{self, Visitor, NestedVisitorMap}
;
39 #[derive(Clone, Copy, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable, Debug)]
42 EarlyBound(/* index */ u32, /* lifetime decl */ DefId
),
43 LateBound(ty
::DebruijnIndex
, /* lifetime decl */ DefId
),
44 LateBoundAnon(ty
::DebruijnIndex
, /* anon index */ u32),
45 Free(DefId
, /* lifetime decl */ DefId
),
49 fn early(hir_map
: &Map
, index
: &mut u32, def
: &hir
::LifetimeDef
)
50 -> (hir
::LifetimeName
, Region
)
54 let def_id
= hir_map
.local_def_id(def
.lifetime
.id
);
55 (def
.lifetime
.name
, Region
::EarlyBound(i
, def_id
))
58 fn late(hir_map
: &Map
, def
: &hir
::LifetimeDef
) -> (hir
::LifetimeName
, Region
) {
59 let depth
= ty
::DebruijnIndex
::new(1);
60 let def_id
= hir_map
.local_def_id(def
.lifetime
.id
);
61 (def
.lifetime
.name
, Region
::LateBound(depth
, def_id
))
64 fn late_anon(index
: &Cell
<u32>) -> Region
{
67 let depth
= ty
::DebruijnIndex
::new(1);
68 Region
::LateBoundAnon(depth
, i
)
71 fn id(&self) -> Option
<DefId
> {
74 Region
::LateBoundAnon(..) => None
,
76 Region
::EarlyBound(_
, id
) |
77 Region
::LateBound(_
, id
) |
78 Region
::Free(_
, id
) => Some(id
)
82 fn shifted(self, amount
: u32) -> Region
{
84 Region
::LateBound(depth
, id
) => {
85 Region
::LateBound(depth
.shifted(amount
), id
)
87 Region
::LateBoundAnon(depth
, index
) => {
88 Region
::LateBoundAnon(depth
.shifted(amount
), index
)
94 fn from_depth(self, depth
: u32) -> Region
{
96 Region
::LateBound(debruijn
, id
) => {
97 Region
::LateBound(ty
::DebruijnIndex
{
98 depth
: debruijn
.depth
- (depth
- 1)
101 Region
::LateBoundAnon(debruijn
, index
) => {
102 Region
::LateBoundAnon(ty
::DebruijnIndex
{
103 depth
: debruijn
.depth
- (depth
- 1)
110 fn subst(self, params
: &[hir
::Lifetime
], map
: &NamedRegionMap
)
112 if let Region
::EarlyBound(index
, _
) = self {
113 params
.get(index
as usize).and_then(|lifetime
| {
114 map
.defs
.get(&lifetime
.id
).cloned()
122 /// A set containing, at most, one known element.
123 /// If two distinct values are inserted into a set, then it
124 /// becomes `Many`, which can be used to detect ambiguities.
125 #[derive(Copy, Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Debug)]
132 impl<T
: PartialEq
> Set1
<T
> {
133 pub fn insert(&mut self, value
: T
) {
134 if let Set1
::Empty
= *self {
135 *self = Set1
::One(value
);
138 if let Set1
::One(ref old
) = *self {
147 pub type ObjectLifetimeDefault
= Set1
<Region
>;
149 // Maps the id of each lifetime reference to the lifetime decl
150 // that it corresponds to.
151 pub struct NamedRegionMap
{
152 // maps from every use of a named (not anonymous) lifetime to a
153 // `Region` describing how that region is bound
154 pub defs
: NodeMap
<Region
>,
156 // the set of lifetime def ids that are late-bound; a region can
157 // be late-bound if (a) it does NOT appear in a where-clause and
158 // (b) it DOES appear in the arguments.
159 pub late_bound
: NodeSet
,
161 // For each type and trait definition, maps type parameters
162 // to the trait object lifetime defaults computed from them.
163 pub object_lifetime_defaults
: NodeMap
<Vec
<ObjectLifetimeDefault
>>,
166 struct LifetimeContext
<'a
, 'tcx
: 'a
> {
168 cstore
: &'a CrateStore
,
169 hir_map
: &'a Map
<'tcx
>,
170 map
: &'a
mut NamedRegionMap
,
172 // Deep breath. Our representation for poly trait refs contains a single
173 // binder and thus we only allow a single level of quantification. However,
174 // the syntax of Rust permits quantification in two places, e.g., `T: for <'a> Foo<'a>`
175 // and `for <'a, 'b> &'b T: Foo<'a>`. In order to get the de Bruijn indices
176 // correct when representing these constraints, we should only introduce one
177 // scope. However, we want to support both locations for the quantifier and
178 // during lifetime resolution we want precise information (so we can't
179 // desugar in an earlier phase).
181 // SO, if we encounter a quantifier at the outer scope, we set
182 // trait_ref_hack to true (and introduce a scope), and then if we encounter
183 // a quantifier at the inner scope, we error. If trait_ref_hack is false,
184 // then we introduce the scope at the inner quantifier.
187 trait_ref_hack
: bool
,
189 // List of labels in the function/method currently under analysis.
190 labels_in_fn
: Vec
<(ast
::Name
, Span
)>,
192 // Cache for cross-crate per-definition object lifetime defaults.
193 xcrate_object_lifetime_defaults
: DefIdMap
<Vec
<ObjectLifetimeDefault
>>,
198 /// Declares lifetimes, and each can be early-bound or late-bound.
199 /// The `DebruijnIndex` of late-bound lifetimes starts at `1` and
200 /// it should be shifted by the number of `Binder`s in between the
201 /// declaration `Binder` and the location it's referenced from.
203 lifetimes
: FxHashMap
<hir
::LifetimeName
, Region
>,
207 /// Lifetimes introduced by a fn are scoped to the call-site for that fn,
208 /// if this is a fn body, otherwise the original definitions are used.
209 /// Unspecified lifetimes are inferred, unless an elision scope is nested,
210 /// e.g. `(&T, fn(&T) -> &T);` becomes `(&'_ T, for<'a> fn(&'a T) -> &'a T)`.
216 /// A scope which either determines unspecified lifetimes or errors
217 /// on them (e.g. due to ambiguity). For more details, see `Elide`.
223 /// Use a specific lifetime (if `Some`) or leave it unset (to be
224 /// inferred in a function body or potentially error outside one),
225 /// for the default choice of lifetime in a trait object type.
226 ObjectLifetimeDefault
{
227 lifetime
: Option
<Region
>,
234 #[derive(Clone, Debug)]
236 /// Use a fresh anonymous late-bound lifetime each time, by
237 /// incrementing the counter to generate sequential indices.
238 FreshLateAnon(Cell
<u32>),
239 /// Always use this one lifetime.
241 /// Less or more than one lifetime were found, error on unspecified.
242 Error(Vec
<ElisionFailureInfo
>)
245 #[derive(Clone, Debug)]
246 struct ElisionFailureInfo
{
247 /// Where we can find the argument pattern.
248 parent
: Option
<hir
::BodyId
>,
249 /// The index of the argument in the original definition.
251 lifetime_count
: usize,
252 have_bound_regions
: bool
255 type ScopeRef
<'a
> = &'a Scope
<'a
>;
257 const ROOT_SCOPE
: ScopeRef
<'
static> = &Scope
::Root
;
259 pub fn krate(sess
: &Session
,
262 -> Result
<NamedRegionMap
, ErrorReported
> {
263 let krate
= hir_map
.krate();
264 let mut map
= NamedRegionMap
{
266 late_bound
: NodeSet(),
267 object_lifetime_defaults
: compute_object_lifetime_defaults(sess
, hir_map
),
269 sess
.track_errors(|| {
270 let mut visitor
= LifetimeContext
{
276 trait_ref_hack
: false,
277 labels_in_fn
: vec
![],
278 xcrate_object_lifetime_defaults
: DefIdMap(),
280 for (_
, item
) in &krate
.items
{
281 visitor
.visit_item(item
);
287 impl<'a
, 'tcx
> Visitor
<'tcx
> for LifetimeContext
<'a
, 'tcx
> {
288 fn nested_visit_map
<'this
>(&'this
mut self) -> NestedVisitorMap
<'this
, 'tcx
> {
289 NestedVisitorMap
::All(self.hir_map
)
292 // We want to nest trait/impl items in their parent, but nothing else.
293 fn visit_nested_item(&mut self, _
: hir
::ItemId
) {}
295 fn visit_nested_body(&mut self, body
: hir
::BodyId
) {
296 // Each body has their own set of labels, save labels.
297 let saved
= replace(&mut self.labels_in_fn
, vec
![]);
298 let body
= self.hir_map
.body(body
);
299 extract_labels(self, body
);
300 self.with(Scope
::Body { id: body.id(), s: self.scope }
, |_
, this
| {
301 this
.visit_body(body
);
303 replace(&mut self.labels_in_fn
, saved
);
306 fn visit_item(&mut self, item
: &'tcx hir
::Item
) {
308 hir
::ItemFn(ref decl
, _
, _
, _
, ref generics
, _
) => {
309 self.visit_early_late(None
, decl
, generics
, |this
| {
310 intravisit
::walk_item(this
, item
);
313 hir
::ItemExternCrate(_
) |
316 hir
::ItemAutoImpl(..) |
317 hir
::ItemForeignMod(..) |
318 hir
::ItemGlobalAsm(..) => {
319 // These sorts of items have no lifetime parameters at all.
320 intravisit
::walk_item(self, item
);
322 hir
::ItemStatic(..) |
323 hir
::ItemConst(..) => {
324 // No lifetime parameters, but implied 'static.
325 let scope
= Scope
::Elision
{
326 elide
: Elide
::Exact(Region
::Static
),
329 self.with(scope
, |_
, this
| intravisit
::walk_item(this
, item
));
331 hir
::ItemTy(_
, ref generics
) |
332 hir
::ItemEnum(_
, ref generics
) |
333 hir
::ItemStruct(_
, ref generics
) |
334 hir
::ItemUnion(_
, ref generics
) |
335 hir
::ItemTrait(_
, _
, ref generics
, ..) |
336 hir
::ItemImpl(_
, _
, _
, ref generics
, ..) => {
337 // These kinds of items have only early bound lifetime parameters.
338 let mut index
= if let hir
::ItemTrait(..) = item
.node
{
339 1 // Self comes before lifetimes
343 let lifetimes
= generics
.lifetimes
.iter().map(|def
| {
344 Region
::early(self.hir_map
, &mut index
, def
)
346 let scope
= Scope
::Binder
{
350 self.with(scope
, |old_scope
, this
| {
351 this
.check_lifetime_defs(old_scope
, &generics
.lifetimes
);
352 intravisit
::walk_item(this
, item
);
358 fn visit_foreign_item(&mut self, item
: &'tcx hir
::ForeignItem
) {
360 hir
::ForeignItemFn(ref decl
, _
, ref generics
) => {
361 self.visit_early_late(None
, decl
, generics
, |this
| {
362 intravisit
::walk_foreign_item(this
, item
);
365 hir
::ForeignItemStatic(..) => {
366 intravisit
::walk_foreign_item(self, item
);
368 hir
::ForeignItemType
=> {
369 intravisit
::walk_foreign_item(self, item
);
374 fn visit_ty(&mut self, ty
: &'tcx hir
::Ty
) {
376 hir
::TyBareFn(ref c
) => {
377 let scope
= Scope
::Binder
{
378 lifetimes
: c
.lifetimes
.iter().map(|def
| {
379 Region
::late(self.hir_map
, def
)
383 self.with(scope
, |old_scope
, this
| {
384 // a bare fn has no bounds, so everything
385 // contained within is scoped within its binder.
386 this
.check_lifetime_defs(old_scope
, &c
.lifetimes
);
387 intravisit
::walk_ty(this
, ty
);
390 hir
::TyTraitObject(ref bounds
, ref lifetime
) => {
391 for bound
in bounds
{
392 self.visit_poly_trait_ref(bound
, hir
::TraitBoundModifier
::None
);
394 if lifetime
.is_elided() {
395 self.resolve_object_lifetime_default(lifetime
)
397 self.visit_lifetime(lifetime
);
400 hir
::TyRptr(ref lifetime_ref
, ref mt
) => {
401 self.visit_lifetime(lifetime_ref
);
402 let scope
= Scope
::ObjectLifetimeDefault
{
403 lifetime
: self.map
.defs
.get(&lifetime_ref
.id
).cloned(),
406 self.with(scope
, |_
, this
| this
.visit_ty(&mt
.ty
));
409 intravisit
::walk_ty(self, ty
)
414 fn visit_trait_item(&mut self, trait_item
: &'tcx hir
::TraitItem
) {
415 if let hir
::TraitItemKind
::Method(ref sig
, _
) = trait_item
.node
{
416 self.visit_early_late(
417 Some(self.hir_map
.get_parent(trait_item
.id
)),
418 &sig
.decl
, &trait_item
.generics
,
419 |this
| intravisit
::walk_trait_item(this
, trait_item
))
421 intravisit
::walk_trait_item(self, trait_item
);
425 fn visit_impl_item(&mut self, impl_item
: &'tcx hir
::ImplItem
) {
426 if let hir
::ImplItemKind
::Method(ref sig
, _
) = impl_item
.node
{
427 self.visit_early_late(
428 Some(self.hir_map
.get_parent(impl_item
.id
)),
429 &sig
.decl
, &impl_item
.generics
,
430 |this
| intravisit
::walk_impl_item(this
, impl_item
))
432 intravisit
::walk_impl_item(self, impl_item
);
436 fn visit_lifetime(&mut self, lifetime_ref
: &'tcx hir
::Lifetime
) {
437 if lifetime_ref
.is_elided() {
438 self.resolve_elided_lifetimes(slice
::ref_slice(lifetime_ref
));
441 if lifetime_ref
.is_static() {
442 self.insert_lifetime(lifetime_ref
, Region
::Static
);
445 self.resolve_lifetime_ref(lifetime_ref
);
448 fn visit_path(&mut self, path
: &'tcx hir
::Path
, _
: ast
::NodeId
) {
449 for (i
, segment
) in path
.segments
.iter().enumerate() {
450 let depth
= path
.segments
.len() - i
- 1;
451 if let Some(ref parameters
) = segment
.parameters
{
452 self.visit_segment_parameters(path
.def
, depth
, parameters
);
457 fn visit_fn_decl(&mut self, fd
: &'tcx hir
::FnDecl
) {
458 let output
= match fd
.output
{
459 hir
::DefaultReturn(_
) => None
,
460 hir
::Return(ref ty
) => Some(ty
)
462 self.visit_fn_like_elision(&fd
.inputs
, output
);
465 fn visit_generics(&mut self, generics
: &'tcx hir
::Generics
) {
466 for ty_param
in generics
.ty_params
.iter() {
467 walk_list
!(self, visit_ty_param_bound
, &ty_param
.bounds
);
468 if let Some(ref ty
) = ty_param
.default {
472 for predicate
in &generics
.where_clause
.predicates
{
474 &hir
::WherePredicate
::BoundPredicate(hir
::WhereBoundPredicate
{ ref bounded_ty
,
478 if !bound_lifetimes
.is_empty() {
479 self.trait_ref_hack
= true;
480 let scope
= Scope
::Binder
{
481 lifetimes
: bound_lifetimes
.iter().map(|def
| {
482 Region
::late(self.hir_map
, def
)
486 let result
= self.with(scope
, |old_scope
, this
| {
487 this
.check_lifetime_defs(old_scope
, bound_lifetimes
);
488 this
.visit_ty(&bounded_ty
);
489 walk_list
!(this
, visit_ty_param_bound
, bounds
);
491 self.trait_ref_hack
= false;
494 self.visit_ty(&bounded_ty
);
495 walk_list
!(self, visit_ty_param_bound
, bounds
);
498 &hir
::WherePredicate
::RegionPredicate(hir
::WhereRegionPredicate
{ref lifetime
,
502 self.visit_lifetime(lifetime
);
503 for bound
in bounds
{
504 self.visit_lifetime(bound
);
507 &hir
::WherePredicate
::EqPredicate(hir
::WhereEqPredicate
{ref lhs_ty
,
510 self.visit_ty(lhs_ty
);
511 self.visit_ty(rhs_ty
);
517 fn visit_poly_trait_ref(&mut self,
518 trait_ref
: &'tcx hir
::PolyTraitRef
,
519 _modifier
: hir
::TraitBoundModifier
) {
520 debug
!("visit_poly_trait_ref trait_ref={:?}", trait_ref
);
522 if !self.trait_ref_hack
|| !trait_ref
.bound_lifetimes
.is_empty() {
523 if self.trait_ref_hack
{
524 span_err
!(self.sess
, trait_ref
.span
, E0316
,
525 "nested quantification of lifetimes");
527 let scope
= Scope
::Binder
{
528 lifetimes
: trait_ref
.bound_lifetimes
.iter().map(|def
| {
529 Region
::late(self.hir_map
, def
)
533 self.with(scope
, |old_scope
, this
| {
534 this
.check_lifetime_defs(old_scope
, &trait_ref
.bound_lifetimes
);
535 for lifetime
in &trait_ref
.bound_lifetimes
{
536 this
.visit_lifetime_def(lifetime
);
538 this
.visit_trait_ref(&trait_ref
.trait_ref
)
541 self.visit_trait_ref(&trait_ref
.trait_ref
)
546 #[derive(Copy, Clone, PartialEq)]
547 enum ShadowKind { Label, Lifetime }
548 struct Original { kind: ShadowKind, span: Span }
549 struct Shadower { kind: ShadowKind, span: Span }
551 fn original_label(span
: Span
) -> Original
{
552 Original { kind: ShadowKind::Label, span: span }
554 fn shadower_label(span
: Span
) -> Shadower
{
555 Shadower { kind: ShadowKind::Label, span: span }
557 fn original_lifetime(span
: Span
) -> Original
{
558 Original { kind: ShadowKind::Lifetime, span: span }
560 fn shadower_lifetime(l
: &hir
::Lifetime
) -> Shadower
{
561 Shadower { kind: ShadowKind::Lifetime, span: l.span }
565 fn desc(&self) -> &'
static str {
567 ShadowKind
::Label
=> "label",
568 ShadowKind
::Lifetime
=> "lifetime",
573 fn signal_shadowing_problem(sess
: &Session
, name
: ast
::Name
, orig
: Original
, shadower
: Shadower
) {
574 let mut err
= if let (ShadowKind
::Lifetime
, ShadowKind
::Lifetime
) = (orig
.kind
, shadower
.kind
) {
575 // lifetime/lifetime shadowing is an error
576 struct_span_err
!(sess
, shadower
.span
, E0496
,
577 "{} name `{}` shadows a \
578 {} name that is already in scope",
579 shadower
.kind
.desc(), name
, orig
.kind
.desc())
581 // shadowing involving a label is only a warning, due to issues with
582 // labels and lifetimes not being macro-hygienic.
583 sess
.struct_span_warn(shadower
.span
,
584 &format
!("{} name `{}` shadows a \
585 {} name that is already in scope",
586 shadower
.kind
.desc(), name
, orig
.kind
.desc()))
588 err
.span_label(orig
.span
, "first declared here");
589 err
.span_label(shadower
.span
,
590 format
!("lifetime {} already in scope", name
));
594 // Adds all labels in `b` to `ctxt.labels_in_fn`, signalling a warning
595 // if one of the label shadows a lifetime or another label.
596 fn extract_labels(ctxt
: &mut LifetimeContext
, body
: &hir
::Body
) {
597 struct GatherLabels
<'a
, 'tcx
: 'a
> {
599 hir_map
: &'a Map
<'tcx
>,
601 labels_in_fn
: &'a
mut Vec
<(ast
::Name
, Span
)>,
604 let mut gather
= GatherLabels
{
606 hir_map
: ctxt
.hir_map
,
608 labels_in_fn
: &mut ctxt
.labels_in_fn
,
610 gather
.visit_body(body
);
612 impl<'v
, 'a
, 'tcx
> Visitor
<'v
> for GatherLabels
<'a
, 'tcx
> {
613 fn nested_visit_map
<'this
>(&'this
mut self) -> NestedVisitorMap
<'this
, 'v
> {
614 NestedVisitorMap
::None
617 fn visit_expr(&mut self, ex
: &hir
::Expr
) {
618 if let Some((label
, label_span
)) = expression_label(ex
) {
619 for &(prior
, prior_span
) in &self.labels_in_fn
[..] {
620 // FIXME (#24278): non-hygienic comparison
622 signal_shadowing_problem(self.sess
,
624 original_label(prior_span
),
625 shadower_label(label_span
));
629 check_if_label_shadows_lifetime(self.sess
,
635 self.labels_in_fn
.push((label
, label_span
));
637 intravisit
::walk_expr(self, ex
)
641 fn expression_label(ex
: &hir
::Expr
) -> Option
<(ast
::Name
, Span
)> {
643 hir
::ExprWhile(.., Some(label
)) |
644 hir
::ExprLoop(_
, Some(label
), _
) => Some((label
.node
, label
.span
)),
649 fn check_if_label_shadows_lifetime
<'a
>(sess
: &'a Session
,
651 mut scope
: ScopeRef
<'a
>,
656 Scope
::Body { s, .. }
|
657 Scope
::Elision { s, .. }
|
658 Scope
::ObjectLifetimeDefault { s, .. }
=> { scope = s; }
660 Scope
::Root
=> { return; }
662 Scope
::Binder { ref lifetimes, s }
=> {
663 // FIXME (#24278): non-hygienic comparison
664 if let Some(def
) = lifetimes
.get(&hir
::LifetimeName
::Name(label
)) {
665 let node_id
= hir_map
.as_local_node_id(def
.id().unwrap())
668 signal_shadowing_problem(
671 original_lifetime(hir_map
.span(node_id
)),
672 shadower_label(label_span
));
682 fn compute_object_lifetime_defaults(sess
: &Session
, hir_map
: &Map
)
683 -> NodeMap
<Vec
<ObjectLifetimeDefault
>> {
684 let mut map
= NodeMap();
685 for item
in hir_map
.krate().items
.values() {
687 hir
::ItemStruct(_
, ref generics
) |
688 hir
::ItemUnion(_
, ref generics
) |
689 hir
::ItemEnum(_
, ref generics
) |
690 hir
::ItemTy(_
, ref generics
) |
691 hir
::ItemTrait(_
, _
, ref generics
, ..) => {
692 let result
= object_lifetime_defaults_for_item(hir_map
, generics
);
695 if attr
::contains_name(&item
.attrs
, "rustc_object_lifetime_default") {
696 let object_lifetime_default_reprs
: String
=
697 result
.iter().map(|set
| {
699 Set1
::Empty
=> "BaseDefault".to_string(),
700 Set1
::One(Region
::Static
) => "'static".to_string(),
701 Set1
::One(Region
::EarlyBound(i
, _
)) => {
702 generics
.lifetimes
[i
as usize].lifetime
.name
.name().to_string()
704 Set1
::One(_
) => bug
!(),
705 Set1
::Many
=> "Ambiguous".to_string(),
707 }).collect
::<Vec
<String
>>().join(",");
708 sess
.span_err(item
.span
, &object_lifetime_default_reprs
);
711 map
.insert(item
.id
, result
);
719 /// Scan the bounds and where-clauses on parameters to extract bounds
720 /// of the form `T:'a` so as to determine the `ObjectLifetimeDefault`
721 /// for each type parameter.
722 fn object_lifetime_defaults_for_item(hir_map
: &Map
, generics
: &hir
::Generics
)
723 -> Vec
<ObjectLifetimeDefault
> {
724 fn add_bounds(set
: &mut Set1
<hir
::LifetimeName
>, bounds
: &[hir
::TyParamBound
]) {
725 for bound
in bounds
{
726 if let hir
::RegionTyParamBound(ref lifetime
) = *bound
{
727 set
.insert(lifetime
.name
);
732 generics
.ty_params
.iter().map(|param
| {
733 let mut set
= Set1
::Empty
;
735 add_bounds(&mut set
, ¶m
.bounds
);
737 let param_def_id
= hir_map
.local_def_id(param
.id
);
738 for predicate
in &generics
.where_clause
.predicates
{
739 // Look for `type: ...` where clauses.
740 let data
= match *predicate
{
741 hir
::WherePredicate
::BoundPredicate(ref data
) => data
,
745 // Ignore `for<'a> type: ...` as they can change what
746 // lifetimes mean (although we could "just" handle it).
747 if !data
.bound_lifetimes
.is_empty() {
751 let def
= match data
.bounded_ty
.node
{
752 hir
::TyPath(hir
::QPath
::Resolved(None
, ref path
)) => path
.def
,
756 if def
== Def
::TyParam(param_def_id
) {
757 add_bounds(&mut set
, &data
.bounds
);
762 Set1
::Empty
=> Set1
::Empty
,
764 if name
== hir
::LifetimeName
::Static
{
765 Set1
::One(Region
::Static
)
767 generics
.lifetimes
.iter().enumerate().find(|&(_
, def
)| {
768 def
.lifetime
.name
== name
769 }).map_or(Set1
::Many
, |(i
, def
)| {
770 let def_id
= hir_map
.local_def_id(def
.lifetime
.id
);
771 Set1
::One(Region
::EarlyBound(i
as u32, def_id
))
775 Set1
::Many
=> Set1
::Many
780 impl<'a
, 'tcx
> LifetimeContext
<'a
, 'tcx
> {
781 // FIXME(#37666) this works around a limitation in the region inferencer
782 fn hack
<F
>(&mut self, f
: F
) where
783 F
: for<'b
> FnOnce(&mut LifetimeContext
<'b
, 'tcx
>),
788 fn with
<F
>(&mut self, wrap_scope
: Scope
, f
: F
) where
789 F
: for<'b
> FnOnce(ScopeRef
, &mut LifetimeContext
<'b
, 'tcx
>),
791 let LifetimeContext {sess, cstore, hir_map, ref mut map, ..}
= *self;
792 let labels_in_fn
= replace(&mut self.labels_in_fn
, vec
![]);
793 let xcrate_object_lifetime_defaults
=
794 replace(&mut self.xcrate_object_lifetime_defaults
, DefIdMap());
795 let mut this
= LifetimeContext
{
801 trait_ref_hack
: self.trait_ref_hack
,
803 xcrate_object_lifetime_defaults
,
805 debug
!("entering scope {:?}", this
.scope
);
806 f(self.scope
, &mut this
);
807 debug
!("exiting scope {:?}", this
.scope
);
808 self.labels_in_fn
= this
.labels_in_fn
;
809 self.xcrate_object_lifetime_defaults
= this
.xcrate_object_lifetime_defaults
;
812 /// Visits self by adding a scope and handling recursive walk over the contents with `walk`.
814 /// Handles visiting fns and methods. These are a bit complicated because we must distinguish
815 /// early- vs late-bound lifetime parameters. We do this by checking which lifetimes appear
816 /// within type bounds; those are early bound lifetimes, and the rest are late bound.
820 /// fn foo<'a,'b,'c,T:Trait<'b>>(...)
822 /// Here `'a` and `'c` are late bound but `'b` is early bound. Note that early- and late-bound
823 /// lifetimes may be interspersed together.
825 /// If early bound lifetimes are present, we separate them into their own list (and likewise
826 /// for late bound). They will be numbered sequentially, starting from the lowest index that is
827 /// already in scope (for a fn item, that will be 0, but for a method it might not be). Late
828 /// bound lifetimes are resolved by name and associated with a binder id (`binder_id`), so the
829 /// ordering is not important there.
830 fn visit_early_late
<F
>(&mut self,
831 parent_id
: Option
<ast
::NodeId
>,
832 decl
: &'tcx hir
::FnDecl
,
833 generics
: &'tcx hir
::Generics
,
835 F
: for<'b
, 'c
> FnOnce(&'b
mut LifetimeContext
<'c
, 'tcx
>),
837 insert_late_bound_lifetimes(self.map
, decl
, generics
);
839 // Find the start of nested early scopes, e.g. in methods.
841 if let Some(parent_id
) = parent_id
{
842 let parent
= self.hir_map
.expect_item(parent_id
);
843 if let hir
::ItemTrait(..) = parent
.node
{
844 index
+= 1; // Self comes first.
847 hir
::ItemTrait(_
, _
, ref generics
, ..) |
848 hir
::ItemImpl(_
, _
, _
, ref generics
, ..) => {
849 index
+= (generics
.lifetimes
.len() + generics
.ty_params
.len()) as u32;
855 let lifetimes
= generics
.lifetimes
.iter().map(|def
| {
856 if self.map
.late_bound
.contains(&def
.lifetime
.id
) {
857 Region
::late(self.hir_map
, def
)
859 Region
::early(self.hir_map
, &mut index
, def
)
863 let scope
= Scope
::Binder
{
867 self.with(scope
, move |old_scope
, this
| {
868 this
.check_lifetime_defs(old_scope
, &generics
.lifetimes
);
869 this
.hack(walk
); // FIXME(#37666) workaround in place of `walk(this)`
873 fn resolve_lifetime_ref(&mut self, lifetime_ref
: &hir
::Lifetime
) {
874 // Walk up the scope chain, tracking the number of fn scopes
875 // that we pass through, until we find a lifetime with the
876 // given name or we run out of scopes.
878 let mut late_depth
= 0;
879 let mut scope
= self.scope
;
880 let mut outermost_body
= None
;
883 Scope
::Body { id, s }
=> {
884 outermost_body
= Some(id
);
892 Scope
::Binder { ref lifetimes, s }
=> {
893 if let Some(&def
) = lifetimes
.get(&lifetime_ref
.name
) {
894 break Some(def
.shifted(late_depth
));
901 Scope
::Elision { s, .. }
|
902 Scope
::ObjectLifetimeDefault { s, .. }
=> {
908 if let Some(mut def
) = result
{
909 if let Region
::EarlyBound(..) = def
{
910 // Do not free early-bound regions, only late-bound ones.
911 } else if let Some(body_id
) = outermost_body
{
912 let fn_id
= self.hir_map
.body_owner(body_id
);
913 match self.hir_map
.get(fn_id
) {
914 hir
::map
::NodeItem(&hir
::Item
{
915 node
: hir
::ItemFn(..), ..
917 hir
::map
::NodeTraitItem(&hir
::TraitItem
{
918 node
: hir
::TraitItemKind
::Method(..), ..
920 hir
::map
::NodeImplItem(&hir
::ImplItem
{
921 node
: hir
::ImplItemKind
::Method(..), ..
923 let scope
= self.hir_map
.local_def_id(fn_id
);
924 def
= Region
::Free(scope
, def
.id().unwrap());
929 self.insert_lifetime(lifetime_ref
, def
);
931 struct_span_err
!(self.sess
, lifetime_ref
.span
, E0261
,
932 "use of undeclared lifetime name `{}`", lifetime_ref
.name
.name())
933 .span_label(lifetime_ref
.span
, "undeclared lifetime")
938 fn visit_segment_parameters(&mut self,
941 params
: &'tcx hir
::PathParameters
) {
942 if params
.parenthesized
{
943 self.visit_fn_like_elision(params
.inputs(), Some(¶ms
.bindings
[0].ty
));
947 if params
.lifetimes
.iter().all(|l
| l
.is_elided()) {
948 self.resolve_elided_lifetimes(¶ms
.lifetimes
);
950 for l
in ¶ms
.lifetimes { self.visit_lifetime(l); }
953 // Figure out if this is a type/trait segment,
954 // which requires object lifetime defaults.
955 let parent_def_id
= |this
: &mut Self, def_id
: DefId
| {
956 let def_key
= if def_id
.is_local() {
957 this
.hir_map
.def_key(def_id
)
959 this
.cstore
.def_key(def_id
)
963 index
: def_key
.parent
.expect("missing parent")
966 let type_def_id
= match def
{
967 Def
::AssociatedTy(def_id
) if depth
== 1 => {
968 Some(parent_def_id(self, def_id
))
970 Def
::Variant(def_id
) if depth
== 0 => {
971 Some(parent_def_id(self, def_id
))
973 Def
::Struct(def_id
) |
976 Def
::TyAlias(def_id
) |
977 Def
::Trait(def_id
) if depth
== 0 => Some(def_id
),
981 let object_lifetime_defaults
= type_def_id
.map_or(vec
![], |def_id
| {
983 let mut scope
= self.scope
;
986 Scope
::Root
=> break false,
988 Scope
::Body { .. }
=> break true,
990 Scope
::Binder { s, .. }
|
991 Scope
::Elision { s, .. }
|
992 Scope
::ObjectLifetimeDefault { s, .. }
=> {
1000 let unsubst
= if let Some(id
) = self.hir_map
.as_local_node_id(def_id
) {
1001 &map
.object_lifetime_defaults
[&id
]
1003 let cstore
= self.cstore
;
1004 let sess
= self.sess
;
1005 self.xcrate_object_lifetime_defaults
.entry(def_id
).or_insert_with(|| {
1006 cstore
.item_generics_cloned_untracked(def_id
, sess
)
1010 def
.object_lifetime_default
1014 unsubst
.iter().map(|set
| {
1020 Some(Region
::Static
)
1023 Set1
::One(r
) => r
.subst(¶ms
.lifetimes
, map
),
1029 for (i
, ty
) in params
.types
.iter().enumerate() {
1030 if let Some(<
) = object_lifetime_defaults
.get(i
) {
1031 let scope
= Scope
::ObjectLifetimeDefault
{
1035 self.with(scope
, |_
, this
| this
.visit_ty(ty
));
1041 for b
in ¶ms
.bindings { self.visit_assoc_type_binding(b); }
1044 fn visit_fn_like_elision(&mut self, inputs
: &'tcx
[P
<hir
::Ty
>],
1045 output
: Option
<&'tcx P
<hir
::Ty
>>) {
1046 let mut arg_elide
= Elide
::FreshLateAnon(Cell
::new(0));
1047 let arg_scope
= Scope
::Elision
{
1048 elide
: arg_elide
.clone(),
1051 self.with(arg_scope
, |_
, this
| {
1052 for input
in inputs
{
1053 this
.visit_ty(input
);
1056 Scope
::Elision { ref elide, .. }
=> {
1057 arg_elide
= elide
.clone();
1063 let output
= match output
{
1068 // Figure out if there's a body we can get argument names from,
1069 // and whether there's a `self` argument (treated specially).
1070 let mut assoc_item_kind
= None
;
1071 let mut impl_self
= None
;
1072 let parent
= self.hir_map
.get_parent_node(output
.id
);
1073 let body
= match self.hir_map
.get(parent
) {
1074 // `fn` definitions and methods.
1075 hir
::map
::NodeItem(&hir
::Item
{
1076 node
: hir
::ItemFn(.., body
), ..
1079 hir
::map
::NodeTraitItem(&hir
::TraitItem
{
1080 node
: hir
::TraitItemKind
::Method(_
, ref m
), ..
1082 match self.hir_map
.expect_item(self.hir_map
.get_parent(parent
)).node
{
1083 hir
::ItemTrait(.., ref trait_items
) => {
1084 assoc_item_kind
= trait_items
.iter().find(|ti
| ti
.id
.node_id
== parent
)
1090 hir
::TraitMethod
::Required(_
) => None
,
1091 hir
::TraitMethod
::Provided(body
) => Some(body
),
1095 hir
::map
::NodeImplItem(&hir
::ImplItem
{
1096 node
: hir
::ImplItemKind
::Method(_
, body
), ..
1098 match self.hir_map
.expect_item(self.hir_map
.get_parent(parent
)).node
{
1099 hir
::ItemImpl(.., ref self_ty
, ref impl_items
) => {
1100 impl_self
= Some(self_ty
);
1101 assoc_item_kind
= impl_items
.iter().find(|ii
| ii
.id
.node_id
== parent
)
1109 // Foreign functions, `fn(...) -> R` and `Trait(...) -> R` (both types and bounds).
1110 hir
::map
::NodeForeignItem(_
) | hir
::map
::NodeTy(_
) | hir
::map
::NodeTraitRef(_
) => None
,
1112 // Everything else (only closures?) doesn't
1113 // actually enjoy elision in return types.
1115 self.visit_ty(output
);
1120 let has_self
= match assoc_item_kind
{
1121 Some(hir
::AssociatedItemKind
::Method { has_self }
) => has_self
,
1125 // In accordance with the rules for lifetime elision, we can determine
1126 // what region to use for elision in the output type in two ways.
1127 // First (determined here), if `self` is by-reference, then the
1128 // implied output region is the region of the self parameter.
1130 // Look for `self: &'a Self` - also desugared from `&'a self`,
1131 // and if that matches, use it for elision and return early.
1132 let is_self_ty
= |def
: Def
| {
1133 if let Def
::SelfTy(..) = def
{
1137 // Can't always rely on literal (or implied) `Self` due
1138 // to the way elision rules were originally specified.
1139 let impl_self
= impl_self
.map(|ty
| &ty
.node
);
1140 if let Some(&hir
::TyPath(hir
::QPath
::Resolved(None
, ref path
))) = impl_self
{
1142 // Whitelist the types that unambiguously always
1143 // result in the same type constructor being used
1144 // (it can't differ between `Self` and `self`).
1148 Def
::PrimTy(_
) => return def
== path
.def
,
1156 if let hir
::TyRptr(lifetime_ref
, ref mt
) = inputs
[0].node
{
1157 if let hir
::TyPath(hir
::QPath
::Resolved(None
, ref path
)) = mt
.ty
.node
{
1158 if is_self_ty(path
.def
) {
1159 if let Some(&lifetime
) = self.map
.defs
.get(&lifetime_ref
.id
) {
1160 let scope
= Scope
::Elision
{
1161 elide
: Elide
::Exact(lifetime
),
1164 self.with(scope
, |_
, this
| this
.visit_ty(output
));
1172 // Second, if there was exactly one lifetime (either a substitution or a
1173 // reference) in the arguments, then any anonymous regions in the output
1174 // have that lifetime.
1175 let mut possible_implied_output_region
= None
;
1176 let mut lifetime_count
= 0;
1177 let arg_lifetimes
= inputs
.iter().enumerate().skip(has_self
as usize).map(|(i
, input
)| {
1178 let mut gather
= GatherLifetimes
{
1181 have_bound_regions
: false,
1182 lifetimes
: FxHashSet()
1184 gather
.visit_ty(input
);
1186 lifetime_count
+= gather
.lifetimes
.len();
1188 if lifetime_count
== 1 && gather
.lifetimes
.len() == 1 {
1189 // there's a chance that the unique lifetime of this
1190 // iteration will be the appropriate lifetime for output
1191 // parameters, so lets store it.
1192 possible_implied_output_region
= gather
.lifetimes
.iter().cloned().next();
1195 ElisionFailureInfo
{
1198 lifetime_count
: gather
.lifetimes
.len(),
1199 have_bound_regions
: gather
.have_bound_regions
1203 let elide
= if lifetime_count
== 1 {
1204 Elide
::Exact(possible_implied_output_region
.unwrap())
1206 Elide
::Error(arg_lifetimes
)
1209 let scope
= Scope
::Elision
{
1213 self.with(scope
, |_
, this
| this
.visit_ty(output
));
1215 struct GatherLifetimes
<'a
> {
1216 map
: &'a NamedRegionMap
,
1218 have_bound_regions
: bool
,
1219 lifetimes
: FxHashSet
<Region
>,
1222 impl<'v
, 'a
> Visitor
<'v
> for GatherLifetimes
<'a
> {
1223 fn nested_visit_map
<'this
>(&'this
mut self) -> NestedVisitorMap
<'this
, 'v
> {
1224 NestedVisitorMap
::None
1227 fn visit_ty(&mut self, ty
: &hir
::Ty
) {
1228 if let hir
::TyBareFn(_
) = ty
.node
{
1229 self.binder_depth
+= 1;
1231 if let hir
::TyTraitObject(ref bounds
, ref lifetime
) = ty
.node
{
1232 for bound
in bounds
{
1233 self.visit_poly_trait_ref(bound
, hir
::TraitBoundModifier
::None
);
1236 // Stay on the safe side and don't include the object
1237 // lifetime default (which may not end up being used).
1238 if !lifetime
.is_elided() {
1239 self.visit_lifetime(lifetime
);
1242 intravisit
::walk_ty(self, ty
);
1244 if let hir
::TyBareFn(_
) = ty
.node
{
1245 self.binder_depth
-= 1;
1249 fn visit_poly_trait_ref(&mut self,
1250 trait_ref
: &hir
::PolyTraitRef
,
1251 modifier
: hir
::TraitBoundModifier
) {
1252 self.binder_depth
+= 1;
1253 intravisit
::walk_poly_trait_ref(self, trait_ref
, modifier
);
1254 self.binder_depth
-= 1;
1257 fn visit_lifetime_def(&mut self, lifetime_def
: &hir
::LifetimeDef
) {
1258 for l
in &lifetime_def
.bounds { self.visit_lifetime(l); }
1261 fn visit_lifetime(&mut self, lifetime_ref
: &hir
::Lifetime
) {
1262 if let Some(&lifetime
) = self.map
.defs
.get(&lifetime_ref
.id
) {
1264 Region
::LateBound(debruijn
, _
) |
1265 Region
::LateBoundAnon(debruijn
, _
)
1266 if debruijn
.depth
< self.binder_depth
=> {
1267 self.have_bound_regions
= true;
1270 self.lifetimes
.insert(lifetime
.from_depth(self.binder_depth
));
1279 fn resolve_elided_lifetimes(&mut self, lifetime_refs
: &[hir
::Lifetime
]) {
1280 if lifetime_refs
.is_empty() {
1284 let span
= lifetime_refs
[0].span
;
1285 let mut late_depth
= 0;
1286 let mut scope
= self.scope
;
1289 // Do not assign any resolution, it will be inferred.
1290 Scope
::Body { .. }
=> return,
1292 Scope
::Root
=> break None
,
1294 Scope
::Binder { s, .. }
=> {
1299 Scope
::Elision { ref elide, .. }
=> {
1300 let lifetime
= match *elide
{
1301 Elide
::FreshLateAnon(ref counter
) => {
1302 for lifetime_ref
in lifetime_refs
{
1303 let lifetime
= Region
::late_anon(counter
).shifted(late_depth
);
1304 self.insert_lifetime(lifetime_ref
, lifetime
);
1308 Elide
::Exact(l
) => l
.shifted(late_depth
),
1309 Elide
::Error(ref e
) => break Some(e
)
1311 for lifetime_ref
in lifetime_refs
{
1312 self.insert_lifetime(lifetime_ref
, lifetime
);
1317 Scope
::ObjectLifetimeDefault { s, .. }
=> {
1323 let mut err
= struct_span_err
!(self.sess
, span
, E0106
,
1324 "missing lifetime specifier{}",
1325 if lifetime_refs
.len() > 1 { "s" }
else { "" }
);
1326 let msg
= if lifetime_refs
.len() > 1 {
1327 format
!("expected {} lifetime parameters", lifetime_refs
.len())
1329 format
!("expected lifetime parameter")
1331 err
.span_label(span
, msg
);
1333 if let Some(params
) = error
{
1334 if lifetime_refs
.len() == 1 {
1335 self.report_elision_failure(&mut err
, params
);
1341 fn report_elision_failure(&mut self,
1342 db
: &mut DiagnosticBuilder
,
1343 params
: &[ElisionFailureInfo
]) {
1344 let mut m
= String
::new();
1345 let len
= params
.len();
1347 let elided_params
: Vec
<_
> = params
.iter().cloned()
1348 .filter(|info
| info
.lifetime_count
> 0)
1351 let elided_len
= elided_params
.len();
1353 for (i
, info
) in elided_params
.into_iter().enumerate() {
1354 let ElisionFailureInfo
{
1355 parent
, index
, lifetime_count
: n
, have_bound_regions
1358 let help_name
= if let Some(body
) = parent
{
1359 let arg
= &self.hir_map
.body(body
).arguments
[index
];
1360 format
!("`{}`", self.hir_map
.node_to_pretty_string(arg
.pat
.id
))
1362 format
!("argument {}", index
+ 1)
1365 m
.push_str(&(if n
== 1 {
1368 format
!("one of {}'s {} {}lifetimes", help_name
, n
,
1369 if have_bound_regions { "free " }
else { "" }
)
1372 if elided_len
== 2 && i
== 0 {
1374 } else if i
+ 2 == elided_len
{
1375 m
.push_str(", or ");
1376 } else if i
!= elided_len
- 1 {
1384 "this function's return type contains a borrowed value, but \
1385 there is no value for it to be borrowed from");
1387 "consider giving it a 'static lifetime");
1388 } else if elided_len
== 0 {
1390 "this function's return type contains a borrowed value with \
1391 an elided lifetime, but the lifetime cannot be derived from \
1394 "consider giving it an explicit bounded or 'static \
1396 } else if elided_len
== 1 {
1398 "this function's return type contains a borrowed value, but \
1399 the signature does not say which {} it is borrowed from",
1403 "this function's return type contains a borrowed value, but \
1404 the signature does not say whether it is borrowed from {}",
1409 fn resolve_object_lifetime_default(&mut self, lifetime_ref
: &hir
::Lifetime
) {
1410 let mut late_depth
= 0;
1411 let mut scope
= self.scope
;
1412 let lifetime
= loop {
1414 Scope
::Binder { s, .. }
=> {
1420 Scope
::Elision { .. }
=> break Region
::Static
,
1422 Scope
::Body { .. }
|
1423 Scope
::ObjectLifetimeDefault { lifetime: None, .. }
=> return,
1425 Scope
::ObjectLifetimeDefault { lifetime: Some(l), .. }
=> break l
1428 self.insert_lifetime(lifetime_ref
, lifetime
.shifted(late_depth
));
1431 fn check_lifetime_defs(&mut self, old_scope
: ScopeRef
, lifetimes
: &[hir
::LifetimeDef
]) {
1432 for i
in 0..lifetimes
.len() {
1433 let lifetime_i
= &lifetimes
[i
];
1435 for lifetime
in lifetimes
{
1436 match lifetime
.lifetime
.name
{
1437 hir
::LifetimeName
::Static
| hir
::LifetimeName
::Underscore
=> {
1438 let lifetime
= lifetime
.lifetime
;
1439 let name
= lifetime
.name
.name();
1440 let mut err
= struct_span_err
!(self.sess
, lifetime
.span
, E0262
,
1441 "invalid lifetime parameter name: `{}`", name
);
1442 err
.span_label(lifetime
.span
,
1443 format
!("{} is a reserved lifetime name", name
));
1446 hir
::LifetimeName
::Implicit
| hir
::LifetimeName
::Name(_
) => {}
1450 // It is a hard error to shadow a lifetime within the same scope.
1451 for j
in i
+ 1..lifetimes
.len() {
1452 let lifetime_j
= &lifetimes
[j
];
1454 if lifetime_i
.lifetime
.name
== lifetime_j
.lifetime
.name
{
1455 struct_span_err
!(self.sess
, lifetime_j
.lifetime
.span
, E0263
,
1456 "lifetime name `{}` declared twice in the same scope",
1457 lifetime_j
.lifetime
.name
.name())
1458 .span_label(lifetime_j
.lifetime
.span
,
1460 .span_label(lifetime_i
.lifetime
.span
,
1461 "previous declaration here")
1466 // It is a soft error to shadow a lifetime within a parent scope.
1467 self.check_lifetime_def_for_shadowing(old_scope
, &lifetime_i
.lifetime
);
1469 for bound
in &lifetime_i
.bounds
{
1471 hir
::LifetimeName
::Underscore
=> {
1472 let mut err
= struct_span_err
!(self.sess
, bound
.span
, E0637
,
1473 "invalid lifetime bound name: `'_`");
1474 err
.span_label(bound
.span
, "`'_` is a reserved lifetime name");
1477 hir
::LifetimeName
::Static
=> {
1478 self.insert_lifetime(bound
, Region
::Static
);
1479 self.sess
.struct_span_warn(lifetime_i
.lifetime
.span
.to(bound
.span
),
1480 &format
!("unnecessary lifetime parameter `{}`",
1481 lifetime_i
.lifetime
.name
.name()))
1483 "you can use the `'static` lifetime directly, in place \
1484 of `{}`", lifetime_i
.lifetime
.name
.name()))
1487 hir
::LifetimeName
::Implicit
|
1488 hir
::LifetimeName
::Name(_
) => {
1489 self.resolve_lifetime_ref(bound
);
1496 fn check_lifetime_def_for_shadowing(&self,
1497 mut old_scope
: ScopeRef
,
1498 lifetime
: &hir
::Lifetime
)
1500 for &(label
, label_span
) in &self.labels_in_fn
{
1501 // FIXME (#24278): non-hygienic comparison
1502 if lifetime
.name
.name() == label
{
1503 signal_shadowing_problem(self.sess
,
1505 original_label(label_span
),
1506 shadower_lifetime(&lifetime
));
1513 Scope
::Body { s, .. }
|
1514 Scope
::Elision { s, .. }
|
1515 Scope
::ObjectLifetimeDefault { s, .. }
=> {
1523 Scope
::Binder { ref lifetimes, s }
=> {
1524 if let Some(&def
) = lifetimes
.get(&lifetime
.name
) {
1525 let node_id
= self.hir_map
1526 .as_local_node_id(def
.id().unwrap())
1529 signal_shadowing_problem(
1531 lifetime
.name
.name(),
1532 original_lifetime(self.hir_map
.span(node_id
)),
1533 shadower_lifetime(&lifetime
));
1543 fn insert_lifetime(&mut self,
1544 lifetime_ref
: &hir
::Lifetime
,
1546 if lifetime_ref
.id
== ast
::DUMMY_NODE_ID
{
1547 span_bug
!(lifetime_ref
.span
,
1548 "lifetime reference not renumbered, \
1549 probably a bug in syntax::fold");
1552 debug
!("{} resolved to {:?} span={:?}",
1553 self.hir_map
.node_to_string(lifetime_ref
.id
),
1555 self.sess
.codemap().span_to_string(lifetime_ref
.span
));
1556 self.map
.defs
.insert(lifetime_ref
.id
, def
);
1560 ///////////////////////////////////////////////////////////////////////////
1562 /// Detects late-bound lifetimes and inserts them into
1563 /// `map.late_bound`.
1565 /// A region declared on a fn is **late-bound** if:
1566 /// - it is constrained by an argument type;
1567 /// - it does not appear in a where-clause.
1569 /// "Constrained" basically means that it appears in any type but
1570 /// not amongst the inputs to a projection. In other words, `<&'a
1571 /// T as Trait<''b>>::Foo` does not constrain `'a` or `'b`.
1572 fn insert_late_bound_lifetimes(map
: &mut NamedRegionMap
,
1574 generics
: &hir
::Generics
) {
1575 debug
!("insert_late_bound_lifetimes(decl={:?}, generics={:?})", decl
, generics
);
1577 let mut constrained_by_input
= ConstrainedCollector { regions: FxHashSet() }
;
1578 for arg_ty
in &decl
.inputs
{
1579 constrained_by_input
.visit_ty(arg_ty
);
1582 let mut appears_in_output
= AllCollector
{
1583 regions
: FxHashSet(),
1586 intravisit
::walk_fn_ret_ty(&mut appears_in_output
, &decl
.output
);
1588 debug
!("insert_late_bound_lifetimes: constrained_by_input={:?}",
1589 constrained_by_input
.regions
);
1591 // Walk the lifetimes that appear in where clauses.
1593 // Subtle point: because we disallow nested bindings, we can just
1594 // ignore binders here and scrape up all names we see.
1595 let mut appears_in_where_clause
= AllCollector
{
1596 regions
: FxHashSet(),
1599 for ty_param
in generics
.ty_params
.iter() {
1600 walk_list
!(&mut appears_in_where_clause
,
1601 visit_ty_param_bound
,
1604 walk_list
!(&mut appears_in_where_clause
,
1605 visit_where_predicate
,
1606 &generics
.where_clause
.predicates
);
1607 // We need to collect argument impl Trait lifetimes as well,
1609 walk_list
!(&mut appears_in_where_clause
,
1611 decl
.inputs
.iter().filter(|ty
| {
1612 if let hir
::TyImplTraitUniversal(..) = ty
.node
{
1618 for lifetime_def
in &generics
.lifetimes
{
1619 if !lifetime_def
.bounds
.is_empty() {
1620 // `'a: 'b` means both `'a` and `'b` are referenced
1621 appears_in_where_clause
.visit_lifetime_def(lifetime_def
);
1625 debug
!("insert_late_bound_lifetimes: appears_in_where_clause={:?}",
1626 appears_in_where_clause
.regions
);
1628 // Late bound regions are those that:
1629 // - appear in the inputs
1630 // - do not appear in the where-clauses
1631 // - are not implicitly captured by `impl Trait`
1632 for lifetime
in &generics
.lifetimes
{
1633 let name
= lifetime
.lifetime
.name
;
1635 // appears in the where clauses? early-bound.
1636 if appears_in_where_clause
.regions
.contains(&name
) { continue; }
1638 // any `impl Trait` in the return type? early-bound.
1639 if appears_in_output
.impl_trait { continue; }
1641 // does not appear in the inputs, but appears in the return type? early-bound.
1642 if !constrained_by_input
.regions
.contains(&name
) &&
1643 appears_in_output
.regions
.contains(&name
) {
1647 debug
!("insert_late_bound_lifetimes: \
1648 lifetime {:?} with id {:?} is late-bound",
1649 lifetime
.lifetime
.name
, lifetime
.lifetime
.id
);
1651 let inserted
= map
.late_bound
.insert(lifetime
.lifetime
.id
);
1652 assert
!(inserted
, "visited lifetime {:?} twice", lifetime
.lifetime
.id
);
1657 struct ConstrainedCollector
{
1658 regions
: FxHashSet
<hir
::LifetimeName
>,
1661 impl<'v
> Visitor
<'v
> for ConstrainedCollector
{
1662 fn nested_visit_map
<'this
>(&'this
mut self) -> NestedVisitorMap
<'this
, 'v
> {
1663 NestedVisitorMap
::None
1666 fn visit_ty(&mut self, ty
: &'v hir
::Ty
) {
1668 hir
::TyPath(hir
::QPath
::Resolved(Some(_
), _
)) |
1669 hir
::TyPath(hir
::QPath
::TypeRelative(..)) => {
1670 // ignore lifetimes appearing in associated type
1671 // projections, as they are not *constrained*
1675 hir
::TyPath(hir
::QPath
::Resolved(None
, ref path
)) => {
1676 // consider only the lifetimes on the final
1677 // segment; I am not sure it's even currently
1678 // valid to have them elsewhere, but even if it
1679 // is, those would be potentially inputs to
1681 if let Some(last_segment
) = path
.segments
.last() {
1682 self.visit_path_segment(path
.span
, last_segment
);
1687 intravisit
::walk_ty(self, ty
);
1692 fn visit_lifetime(&mut self, lifetime_ref
: &'v hir
::Lifetime
) {
1693 self.regions
.insert(lifetime_ref
.name
);
1697 struct AllCollector
{
1698 regions
: FxHashSet
<hir
::LifetimeName
>,
1702 impl<'v
> Visitor
<'v
> for AllCollector
{
1703 fn nested_visit_map
<'this
>(&'this
mut self) -> NestedVisitorMap
<'this
, 'v
> {
1704 NestedVisitorMap
::None
1707 fn visit_lifetime(&mut self, lifetime_ref
: &'v hir
::Lifetime
) {
1708 self.regions
.insert(lifetime_ref
.name
);
1711 fn visit_ty(&mut self, ty
: &hir
::Ty
) {
1712 if let hir
::TyImplTraitExistential(_
) = ty
.node
{
1713 self.impl_trait
= true;
1715 intravisit
::walk_ty(self, ty
);