Skip to content

Commit 7a2a669

Browse files
committed
rustc: always include elidable lifetimes in HIR types.
1 parent f79feba commit 7a2a669

File tree

15 files changed

+246
-132
lines changed

15 files changed

+246
-132
lines changed

src/librustc/hir/intravisit.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -547,8 +547,8 @@ pub fn walk_ty<'v, V: Visitor<'v>>(visitor: &mut V, typ: &'v Ty) {
547547
TyPtr(ref mutable_type) => {
548548
visitor.visit_ty(&mutable_type.ty)
549549
}
550-
TyRptr(ref opt_lifetime, ref mutable_type) => {
551-
walk_list!(visitor, visit_lifetime, opt_lifetime);
550+
TyRptr(ref lifetime, ref mutable_type) => {
551+
visitor.visit_lifetime(lifetime);
552552
visitor.visit_ty(&mutable_type.ty)
553553
}
554554
TyNever => {},

src/librustc/hir/lowering.rs

Lines changed: 120 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -41,12 +41,12 @@
4141
// in the HIR, especially for multiple identifiers.
4242

4343
use hir;
44-
use hir::map::Definitions;
44+
use hir::map::{Definitions, DefKey};
4545
use hir::map::definitions::DefPathData;
4646
use hir::def_id::{DefIndex, DefId};
4747
use hir::def::{Def, PathResolution};
4848
use session::Session;
49-
use util::nodemap::{NodeMap, FxHashMap};
49+
use util::nodemap::{DefIdMap, NodeMap, FxHashMap};
5050

5151
use std::collections::BTreeMap;
5252
use std::iter;
@@ -78,6 +78,8 @@ pub struct LoweringContext<'a> {
7878
trait_items: BTreeMap<hir::TraitItemId, hir::TraitItem>,
7979
impl_items: BTreeMap<hir::ImplItemId, hir::ImplItem>,
8080
bodies: FxHashMap<hir::BodyId, hir::Body>,
81+
82+
type_def_lifetime_params: DefIdMap<usize>,
8183
}
8284

8385
pub trait Resolver {
@@ -110,6 +112,7 @@ pub fn lower_crate(sess: &Session,
110112
trait_items: BTreeMap::new(),
111113
impl_items: BTreeMap::new(),
112114
bodies: FxHashMap(),
115+
type_def_lifetime_params: DefIdMap(),
113116
}.lower_crate(krate)
114117
}
115118

@@ -123,24 +126,33 @@ enum ParamMode {
123126

124127
impl<'a> LoweringContext<'a> {
125128
fn lower_crate(mut self, c: &Crate) -> hir::Crate {
126-
self.lower_items(c);
127-
let module = self.lower_mod(&c.module);
128-
let attrs = self.lower_attrs(&c.attrs);
129-
let exported_macros = c.exported_macros.iter().map(|m| self.lower_macro_def(m)).collect();
129+
/// Full-crate AST visitor that inserts into a fresh
130+
/// `LoweringContext` any information that may be
131+
/// needed from arbitrary locations in the crate.
132+
/// E.g. The number of lifetime generic parameters
133+
/// declared for every type and trait definition.
134+
struct MiscCollector<'lcx, 'interner: 'lcx> {
135+
lctx: &'lcx mut LoweringContext<'interner>,
136+
}
130137

131-
hir::Crate {
132-
module: module,
133-
attrs: attrs,
134-
span: c.span,
135-
exported_macros: exported_macros,
136-
items: self.items,
137-
trait_items: self.trait_items,
138-
impl_items: self.impl_items,
139-
bodies: self.bodies,
138+
impl<'lcx, 'interner> Visitor<'lcx> for MiscCollector<'lcx, 'interner> {
139+
fn visit_item(&mut self, item: &'lcx Item) {
140+
match item.node {
141+
ItemKind::Struct(_, ref generics) |
142+
ItemKind::Union(_, ref generics) |
143+
ItemKind::Enum(_, ref generics) |
144+
ItemKind::Ty(_, ref generics) |
145+
ItemKind::Trait(_, ref generics, ..) => {
146+
let def_id = self.lctx.resolver.definitions().local_def_id(item.id);
147+
let count = generics.lifetimes.len();
148+
self.lctx.type_def_lifetime_params.insert(def_id, count);
149+
}
150+
_ => {}
151+
}
152+
visit::walk_item(self, item);
153+
}
140154
}
141-
}
142155

143-
fn lower_items(&mut self, c: &Crate) {
144156
struct ItemLowerer<'lcx, 'interner: 'lcx> {
145157
lctx: &'lcx mut LoweringContext<'interner>,
146158
}
@@ -167,8 +179,23 @@ impl<'a> LoweringContext<'a> {
167179
}
168180
}
169181

170-
let mut item_lowerer = ItemLowerer { lctx: self };
171-
visit::walk_crate(&mut item_lowerer, c);
182+
visit::walk_crate(&mut MiscCollector { lctx: &mut self }, c);
183+
visit::walk_crate(&mut ItemLowerer { lctx: &mut self }, c);
184+
185+
let module = self.lower_mod(&c.module);
186+
let attrs = self.lower_attrs(&c.attrs);
187+
let exported_macros = c.exported_macros.iter().map(|m| self.lower_macro_def(m)).collect();
188+
189+
hir::Crate {
190+
module: module,
191+
attrs: attrs,
192+
span: c.span,
193+
exported_macros: exported_macros,
194+
items: self.items,
195+
trait_items: self.trait_items,
196+
impl_items: self.impl_items,
197+
bodies: self.bodies,
198+
}
172199
}
173200

174201
fn record_body(&mut self, value: hir::Expr, decl: Option<&FnDecl>)
@@ -232,6 +259,14 @@ impl<'a> LoweringContext<'a> {
232259
result
233260
}
234261

262+
fn def_key(&mut self, id: DefId) -> DefKey {
263+
if id.is_local() {
264+
self.resolver.definitions().def_key(id.index)
265+
} else {
266+
self.sess.cstore.def_key(id)
267+
}
268+
}
269+
235270
fn lower_opt_sp_ident(&mut self, o_id: Option<Spanned<Ident>>) -> Option<Spanned<Name>> {
236271
o_id.map(|sp_ident| respan(sp_ident.span, sp_ident.node.name))
237272
}
@@ -279,7 +314,11 @@ impl<'a> LoweringContext<'a> {
279314
TyKind::Slice(ref ty) => hir::TySlice(self.lower_ty(ty)),
280315
TyKind::Ptr(ref mt) => hir::TyPtr(self.lower_mt(mt)),
281316
TyKind::Rptr(ref region, ref mt) => {
282-
hir::TyRptr(self.lower_opt_lifetime(region), self.lower_mt(mt))
317+
let lifetime = match *region {
318+
Some(ref lt) => self.lower_lifetime(lt),
319+
None => self.elided_lifetime(t.span)
320+
};
321+
hir::TyRptr(lifetime, self.lower_mt(mt))
283322
}
284323
TyKind::BareFn(ref f) => {
285324
hir::TyBareFn(P(hir::BareFnTy {
@@ -377,7 +416,40 @@ impl<'a> LoweringContext<'a> {
377416
}
378417
_ => param_mode
379418
};
380-
self.lower_path_segment(segment, param_mode)
419+
420+
// Figure out if this is a type/trait segment,
421+
// which may need lifetime elision performed.
422+
let parent_def_id = |this: &mut Self, def_id: DefId| {
423+
DefId {
424+
krate: def_id.krate,
425+
index: this.def_key(def_id).parent.expect("missing parent")
426+
}
427+
};
428+
let type_def_id = match resolution.base_def {
429+
Def::AssociatedTy(def_id) if i + 2 == proj_start => {
430+
Some(parent_def_id(self, def_id))
431+
}
432+
Def::Variant(def_id) if i + 1 == proj_start => {
433+
Some(parent_def_id(self, def_id))
434+
}
435+
Def::Struct(def_id) |
436+
Def::Union(def_id) |
437+
Def::Enum(def_id) |
438+
Def::TyAlias(def_id) |
439+
Def::Trait(def_id) if i + 1 == proj_start => Some(def_id),
440+
_ => None
441+
};
442+
443+
let num_lifetimes = type_def_id.map_or(0, |def_id| {
444+
if let Some(&n) = self.type_def_lifetime_params.get(&def_id) {
445+
return n;
446+
}
447+
assert!(!def_id.is_local());
448+
let (n, _) = self.sess.cstore.item_generics_own_param_counts(def_id);
449+
self.type_def_lifetime_params.insert(def_id, n);
450+
n
451+
});
452+
self.lower_path_segment(p.span, segment, param_mode, num_lifetimes)
381453
}).collect(),
382454
span: p.span,
383455
});
@@ -411,7 +483,7 @@ impl<'a> LoweringContext<'a> {
411483
// 3. `<<std::vec::Vec<T>>::IntoIter>::Item`
412484
// * final path is `<<<std::vec::Vec<T>>::IntoIter>::Item>::clone`
413485
for (i, segment) in p.segments.iter().enumerate().skip(proj_start) {
414-
let segment = P(self.lower_path_segment(segment, param_mode));
486+
let segment = P(self.lower_path_segment(p.span, segment, param_mode, 0));
415487
let qpath = hir::QPath::TypeRelative(ty, segment);
416488

417489
// It's finished, return the extension of the right node type.
@@ -443,7 +515,7 @@ impl<'a> LoweringContext<'a> {
443515
hir::Path {
444516
def: self.expect_full_def(id),
445517
segments: segments.map(|segment| {
446-
self.lower_path_segment(segment, param_mode)
518+
self.lower_path_segment(p.span, segment, param_mode, 0)
447519
}).chain(name.map(|name| {
448520
hir::PathSegment {
449521
name: name,
@@ -464,10 +536,12 @@ impl<'a> LoweringContext<'a> {
464536
}
465537

466538
fn lower_path_segment(&mut self,
539+
path_span: Span,
467540
segment: &PathSegment,
468-
param_mode: ParamMode)
541+
param_mode: ParamMode,
542+
expected_lifetimes: usize)
469543
-> hir::PathSegment {
470-
let parameters = if let Some(ref parameters) = segment.parameters {
544+
let mut parameters = if let Some(ref parameters) = segment.parameters {
471545
match **parameters {
472546
PathParameters::AngleBracketed(ref data) => {
473547
let data = self.lower_angle_bracketed_parameter_data(data, param_mode);
@@ -482,6 +556,14 @@ impl<'a> LoweringContext<'a> {
482556
hir::AngleBracketedParameters(data)
483557
};
484558

559+
if let hir::AngleBracketedParameters(ref mut data) = parameters {
560+
if data.lifetimes.is_empty() {
561+
data.lifetimes = (0..expected_lifetimes).map(|_| {
562+
self.elided_lifetime(path_span)
563+
}).collect();
564+
}
565+
}
566+
485567
hir::PathSegment {
486568
name: segment.identifier.name,
487569
parameters: parameters,
@@ -628,10 +710,6 @@ impl<'a> LoweringContext<'a> {
628710
lts.iter().map(|l| self.lower_lifetime_def(l)).collect()
629711
}
630712

631-
fn lower_opt_lifetime(&mut self, o_lt: &Option<Lifetime>) -> Option<hir::Lifetime> {
632-
o_lt.as_ref().map(|lt| self.lower_lifetime(lt))
633-
}
634-
635713
fn lower_generics(&mut self, g: &Generics) -> hir::Generics {
636714
// Collect `?Trait` bounds in where clause and move them to parameter definitions.
637715
let mut add_bounds = NodeMap();
@@ -751,8 +829,12 @@ impl<'a> LoweringContext<'a> {
751829
}
752830

753831
fn lower_trait_ref(&mut self, p: &TraitRef) -> hir::TraitRef {
832+
let path = match self.lower_qpath(p.ref_id, &None, &p.path, ParamMode::Explicit) {
833+
hir::QPath::Resolved(None, path) => path.and_then(|path| path),
834+
qpath => bug!("lower_trait_ref: unexpected QPath `{:?}`", qpath)
835+
};
754836
hir::TraitRef {
755-
path: self.lower_path(p.ref_id, &p.path, ParamMode::Explicit, false),
837+
path: path,
756838
ref_id: p.ref_id,
757839
}
758840
}
@@ -2276,4 +2358,12 @@ impl<'a> LoweringContext<'a> {
22762358
span: span,
22772359
})
22782360
}
2361+
2362+
fn elided_lifetime(&mut self, span: Span) -> hir::Lifetime {
2363+
hir::Lifetime {
2364+
id: self.next_id(),
2365+
span: span,
2366+
name: keywords::Invalid.name()
2367+
}
2368+
}
22792369
}

src/librustc/hir/mod.rs

Lines changed: 14 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,13 @@ pub mod svh;
7777
pub struct Lifetime {
7878
pub id: NodeId,
7979
pub span: Span,
80+
81+
/// Either "'a", referring to a named lifetime definition,
82+
/// or "" (aka keywords::Invalid), for elision placeholders.
83+
///
84+
/// HIR lowering inserts these placeholders in type paths that
85+
/// refer to type definitions needing lifetime parameters,
86+
/// `&T` and `&mut T`, and trait objects without `... + 'a`.
8087
pub name: Name,
8188
}
8289

@@ -89,6 +96,12 @@ impl fmt::Debug for Lifetime {
8996
}
9097
}
9198

99+
impl Lifetime {
100+
pub fn is_elided(&self) -> bool {
101+
self.name == keywords::Invalid.name()
102+
}
103+
}
104+
92105
/// A lifetime definition, eg `'a: 'b+'c+'d`
93106
#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
94107
pub struct LifetimeDef {
@@ -165,30 +178,6 @@ impl PathParameters {
165178
})
166179
}
167180

168-
pub fn is_empty(&self) -> bool {
169-
match *self {
170-
AngleBracketedParameters(ref data) => data.is_empty(),
171-
172-
// Even if the user supplied no types, something like
173-
// `X()` is equivalent to `X<(),()>`.
174-
ParenthesizedParameters(..) => false,
175-
}
176-
}
177-
178-
pub fn has_lifetimes(&self) -> bool {
179-
match *self {
180-
AngleBracketedParameters(ref data) => !data.lifetimes.is_empty(),
181-
ParenthesizedParameters(_) => false,
182-
}
183-
}
184-
185-
pub fn has_types(&self) -> bool {
186-
match *self {
187-
AngleBracketedParameters(ref data) => !data.types.is_empty(),
188-
ParenthesizedParameters(..) => true,
189-
}
190-
}
191-
192181
/// Returns the types that the user wrote. Note that these do not necessarily map to the type
193182
/// parameters in the parenthesized case.
194183
pub fn types(&self) -> HirVec<&P<Ty>> {
@@ -245,12 +234,6 @@ pub struct AngleBracketedParameterData {
245234
pub bindings: HirVec<TypeBinding>,
246235
}
247236

248-
impl AngleBracketedParameterData {
249-
fn is_empty(&self) -> bool {
250-
self.lifetimes.is_empty() && self.types.is_empty() && self.bindings.is_empty()
251-
}
252-
}
253-
254237
/// A path like `Foo(A,B) -> C`
255238
#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
256239
pub struct ParenthesizedParameterData {
@@ -1208,7 +1191,7 @@ pub enum Ty_ {
12081191
/// A raw pointer (`*const T` or `*mut T`)
12091192
TyPtr(MutTy),
12101193
/// A reference (`&'a T` or `&'a mut T`)
1211-
TyRptr(Option<Lifetime>, MutTy),
1194+
TyRptr(Lifetime, MutTy),
12121195
/// A bare function (e.g. `fn(usize) -> bool`)
12131196
TyBareFn(P<BareFnTy>),
12141197
/// The never type (`!`)

0 commit comments

Comments
 (0)