diff --git a/src/librustc/hir/intravisit.rs b/src/librustc/hir/intravisit.rs index d4095c6875c1d10e44b61a8c37060440893502e6..d71263bea0046a76105506ceaada2d47fe52d15c 100644 --- a/src/librustc/hir/intravisit.rs +++ b/src/librustc/hir/intravisit.rs @@ -547,8 +547,8 @@ pub fn walk_ty<'v, V: Visitor<'v>>(visitor: &mut V, typ: &'v Ty) { TyPtr(ref mutable_type) => { visitor.visit_ty(&mutable_type.ty) } - TyRptr(ref opt_lifetime, ref mutable_type) => { - walk_list!(visitor, visit_lifetime, opt_lifetime); + TyRptr(ref lifetime, ref mutable_type) => { + visitor.visit_lifetime(lifetime); visitor.visit_ty(&mutable_type.ty) } TyNever => {}, diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs index 88d461cab9f409cbbf8f0a7ddc0e4c0bf2fd4666..4160ec5b74a92de923f712e48fcf78e71bfd8973 100644 --- a/src/librustc/hir/lowering.rs +++ b/src/librustc/hir/lowering.rs @@ -41,12 +41,12 @@ // in the HIR, especially for multiple identifiers. use hir; -use hir::map::Definitions; +use hir::map::{Definitions, DefKey}; use hir::map::definitions::DefPathData; use hir::def_id::{DefIndex, DefId}; use hir::def::{Def, PathResolution}; use session::Session; -use util::nodemap::{NodeMap, FxHashMap}; +use util::nodemap::{DefIdMap, NodeMap, FxHashMap}; use std::collections::BTreeMap; use std::iter; @@ -78,6 +78,8 @@ pub struct LoweringContext<'a> { trait_items: BTreeMap, impl_items: BTreeMap, bodies: FxHashMap, + + type_def_lifetime_params: DefIdMap, } pub trait Resolver { @@ -110,6 +112,7 @@ pub fn lower_crate(sess: &Session, trait_items: BTreeMap::new(), impl_items: BTreeMap::new(), bodies: FxHashMap(), + type_def_lifetime_params: DefIdMap(), }.lower_crate(krate) } @@ -123,24 +126,33 @@ enum ParamMode { impl<'a> LoweringContext<'a> { fn lower_crate(mut self, c: &Crate) -> hir::Crate { - self.lower_items(c); - let module = self.lower_mod(&c.module); - let attrs = self.lower_attrs(&c.attrs); - let exported_macros = c.exported_macros.iter().map(|m| self.lower_macro_def(m)).collect(); + /// Full-crate AST visitor that inserts into a fresh + /// `LoweringContext` any information that may be + /// needed from arbitrary locations in the crate. + /// E.g. The number of lifetime generic parameters + /// declared for every type and trait definition. + struct MiscCollector<'lcx, 'interner: 'lcx> { + lctx: &'lcx mut LoweringContext<'interner>, + } - hir::Crate { - module: module, - attrs: attrs, - span: c.span, - exported_macros: exported_macros, - items: self.items, - trait_items: self.trait_items, - impl_items: self.impl_items, - bodies: self.bodies, + impl<'lcx, 'interner> Visitor<'lcx> for MiscCollector<'lcx, 'interner> { + fn visit_item(&mut self, item: &'lcx Item) { + match item.node { + ItemKind::Struct(_, ref generics) | + ItemKind::Union(_, ref generics) | + ItemKind::Enum(_, ref generics) | + ItemKind::Ty(_, ref generics) | + ItemKind::Trait(_, ref generics, ..) => { + let def_id = self.lctx.resolver.definitions().local_def_id(item.id); + let count = generics.lifetimes.len(); + self.lctx.type_def_lifetime_params.insert(def_id, count); + } + _ => {} + } + visit::walk_item(self, item); + } } - } - fn lower_items(&mut self, c: &Crate) { struct ItemLowerer<'lcx, 'interner: 'lcx> { lctx: &'lcx mut LoweringContext<'interner>, } @@ -167,8 +179,23 @@ fn visit_impl_item(&mut self, item: &'lcx ImplItem) { } } - let mut item_lowerer = ItemLowerer { lctx: self }; - visit::walk_crate(&mut item_lowerer, c); + visit::walk_crate(&mut MiscCollector { lctx: &mut self }, c); + visit::walk_crate(&mut ItemLowerer { lctx: &mut self }, c); + + let module = self.lower_mod(&c.module); + let attrs = self.lower_attrs(&c.attrs); + let exported_macros = c.exported_macros.iter().map(|m| self.lower_macro_def(m)).collect(); + + hir::Crate { + module: module, + attrs: attrs, + span: c.span, + exported_macros: exported_macros, + items: self.items, + trait_items: self.trait_items, + impl_items: self.impl_items, + bodies: self.bodies, + } } fn record_body(&mut self, value: hir::Expr, decl: Option<&FnDecl>) @@ -232,6 +259,14 @@ fn with_parent_def(&mut self, parent_id: NodeId, f: F) -> T result } + fn def_key(&mut self, id: DefId) -> DefKey { + if id.is_local() { + self.resolver.definitions().def_key(id.index) + } else { + self.sess.cstore.def_key(id) + } + } + fn lower_opt_sp_ident(&mut self, o_id: Option>) -> Option> { o_id.map(|sp_ident| respan(sp_ident.span, sp_ident.node.name)) } @@ -279,7 +314,11 @@ fn lower_ty(&mut self, t: &Ty) -> P { TyKind::Slice(ref ty) => hir::TySlice(self.lower_ty(ty)), TyKind::Ptr(ref mt) => hir::TyPtr(self.lower_mt(mt)), TyKind::Rptr(ref region, ref mt) => { - hir::TyRptr(self.lower_opt_lifetime(region), self.lower_mt(mt)) + let lifetime = match *region { + Some(ref lt) => self.lower_lifetime(lt), + None => self.elided_lifetime(t.span) + }; + hir::TyRptr(lifetime, self.lower_mt(mt)) } TyKind::BareFn(ref f) => { hir::TyBareFn(P(hir::BareFnTy { @@ -377,7 +416,40 @@ fn lower_qpath(&mut self, } _ => param_mode }; - self.lower_path_segment(segment, param_mode) + + // Figure out if this is a type/trait segment, + // which may need lifetime elision performed. + let parent_def_id = |this: &mut Self, def_id: DefId| { + DefId { + krate: def_id.krate, + index: this.def_key(def_id).parent.expect("missing parent") + } + }; + let type_def_id = match resolution.base_def { + Def::AssociatedTy(def_id) if i + 2 == proj_start => { + Some(parent_def_id(self, def_id)) + } + Def::Variant(def_id) if i + 1 == proj_start => { + 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 i + 1 == proj_start => Some(def_id), + _ => None + }; + + let num_lifetimes = type_def_id.map_or(0, |def_id| { + if let Some(&n) = self.type_def_lifetime_params.get(&def_id) { + return n; + } + assert!(!def_id.is_local()); + let (n, _) = self.sess.cstore.item_generics_own_param_counts(def_id); + self.type_def_lifetime_params.insert(def_id, n); + n + }); + self.lower_path_segment(p.span, segment, param_mode, num_lifetimes) }).collect(), span: p.span, }); @@ -411,7 +483,7 @@ fn lower_qpath(&mut self, // 3. `<>::IntoIter>::Item` // * final path is `<<>::IntoIter>::Item>::clone` for (i, segment) in p.segments.iter().enumerate().skip(proj_start) { - let segment = P(self.lower_path_segment(segment, param_mode)); + let segment = P(self.lower_path_segment(p.span, segment, param_mode, 0)); let qpath = hir::QPath::TypeRelative(ty, segment); // It's finished, return the extension of the right node type. @@ -443,7 +515,7 @@ fn lower_path_extra(&mut self, hir::Path { def: self.expect_full_def(id), segments: segments.map(|segment| { - self.lower_path_segment(segment, param_mode) + self.lower_path_segment(p.span, segment, param_mode, 0) }).chain(name.map(|name| { hir::PathSegment { name: name, @@ -464,10 +536,12 @@ fn lower_path(&mut self, } fn lower_path_segment(&mut self, + path_span: Span, segment: &PathSegment, - param_mode: ParamMode) + param_mode: ParamMode, + expected_lifetimes: usize) -> hir::PathSegment { - let parameters = if let Some(ref parameters) = segment.parameters { + let mut parameters = if let Some(ref parameters) = segment.parameters { match **parameters { PathParameters::AngleBracketed(ref data) => { let data = self.lower_angle_bracketed_parameter_data(data, param_mode); @@ -482,6 +556,14 @@ fn lower_path_segment(&mut self, hir::AngleBracketedParameters(data) }; + if let hir::AngleBracketedParameters(ref mut data) = parameters { + if data.lifetimes.is_empty() { + data.lifetimes = (0..expected_lifetimes).map(|_| { + self.elided_lifetime(path_span) + }).collect(); + } + } + hir::PathSegment { name: segment.identifier.name, parameters: parameters, @@ -628,10 +710,6 @@ fn lower_lifetime_defs(&mut self, lts: &Vec) -> hir::HirVec) -> Option { - o_lt.as_ref().map(|lt| self.lower_lifetime(lt)) - } - fn lower_generics(&mut self, g: &Generics) -> hir::Generics { // Collect `?Trait` bounds in where clause and move them to parameter definitions. let mut add_bounds = NodeMap(); @@ -751,8 +829,12 @@ fn lower_variant_data(&mut self, vdata: &VariantData) -> hir::VariantData { } fn lower_trait_ref(&mut self, p: &TraitRef) -> hir::TraitRef { + let path = match self.lower_qpath(p.ref_id, &None, &p.path, ParamMode::Explicit) { + hir::QPath::Resolved(None, path) => path.and_then(|path| path), + qpath => bug!("lower_trait_ref: unexpected QPath `{:?}`", qpath) + }; hir::TraitRef { - path: self.lower_path(p.ref_id, &p.path, ParamMode::Explicit, false), + path: path, ref_id: p.ref_id, } } @@ -2276,4 +2358,12 @@ fn ty(&mut self, span: Span, node: hir::Ty_) -> P { span: span, }) } + + fn elided_lifetime(&mut self, span: Span) -> hir::Lifetime { + hir::Lifetime { + id: self.next_id(), + span: span, + name: keywords::Invalid.name() + } + } } diff --git a/src/librustc/hir/mod.rs b/src/librustc/hir/mod.rs index fe086347884b09c89f24d66e24fce10156bfc7b2..94cb33b138c58341dac9ec70c4850bc740d6829b 100644 --- a/src/librustc/hir/mod.rs +++ b/src/librustc/hir/mod.rs @@ -77,6 +77,13 @@ pub struct Lifetime { pub id: NodeId, pub span: Span, + + /// Either "'a", referring to a named lifetime definition, + /// or "" (aka keywords::Invalid), for elision placeholders. + /// + /// HIR lowering inserts these placeholders in type paths that + /// refer to type definitions needing lifetime parameters, + /// `&T` and `&mut T`, and trait objects without `... + 'a`. pub name: Name, } @@ -89,6 +96,12 @@ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { } } +impl Lifetime { + pub fn is_elided(&self) -> bool { + self.name == keywords::Invalid.name() + } +} + /// A lifetime definition, eg `'a: 'b+'c+'d` #[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)] pub struct LifetimeDef { @@ -165,30 +178,6 @@ pub fn none() -> PathParameters { }) } - pub fn is_empty(&self) -> bool { - match *self { - AngleBracketedParameters(ref data) => data.is_empty(), - - // Even if the user supplied no types, something like - // `X()` is equivalent to `X<(),()>`. - ParenthesizedParameters(..) => false, - } - } - - pub fn has_lifetimes(&self) -> bool { - match *self { - AngleBracketedParameters(ref data) => !data.lifetimes.is_empty(), - ParenthesizedParameters(_) => false, - } - } - - pub fn has_types(&self) -> bool { - match *self { - AngleBracketedParameters(ref data) => !data.types.is_empty(), - ParenthesizedParameters(..) => true, - } - } - /// Returns the types that the user wrote. Note that these do not necessarily map to the type /// parameters in the parenthesized case. pub fn types(&self) -> HirVec<&P> { @@ -245,12 +234,6 @@ pub struct AngleBracketedParameterData { pub bindings: HirVec, } -impl AngleBracketedParameterData { - fn is_empty(&self) -> bool { - self.lifetimes.is_empty() && self.types.is_empty() && self.bindings.is_empty() - } -} - /// A path like `Foo(A,B) -> C` #[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)] pub struct ParenthesizedParameterData { @@ -1208,7 +1191,7 @@ pub enum Ty_ { /// A raw pointer (`*const T` or `*mut T`) TyPtr(MutTy), /// A reference (`&'a T` or `&'a mut T`) - TyRptr(Option, MutTy), + TyRptr(Lifetime, MutTy), /// A bare function (e.g. `fn(usize) -> bool`) TyBareFn(P), /// The never type (`!`) diff --git a/src/librustc/hir/print.rs b/src/librustc/hir/print.rs index d4bb2d37091b26db5105f973940d6399f87c6852..8e866f5717498c188d35b21eb40412f813ee8e63 100644 --- a/src/librustc/hir/print.rs +++ b/src/librustc/hir/print.rs @@ -26,6 +26,7 @@ use hir; use hir::{PatKind, RegionTyParamBound, TraitTyParamBound, TraitBoundModifier, RangeEnd}; +use std::cell::Cell; use std::io::{self, Write, Read}; pub enum AnnNode<'a> { @@ -359,9 +360,9 @@ pub fn print_foreign_mod(&mut self, Ok(()) } - pub fn print_opt_lifetime(&mut self, lifetime: &Option) -> io::Result<()> { - if let Some(l) = *lifetime { - self.print_lifetime(&l)?; + pub fn print_opt_lifetime(&mut self, lifetime: &hir::Lifetime) -> io::Result<()> { + if !lifetime.is_elided() { + self.print_lifetime(lifetime)?; self.nbsp()?; } Ok(()) @@ -1553,65 +1554,49 @@ fn print_path_parameters(&mut self, parameters: &hir::PathParameters, colons_before_params: bool) -> io::Result<()> { - if parameters.is_empty() { - let infer_types = match *parameters { - hir::AngleBracketedParameters(ref data) => data.infer_types, - hir::ParenthesizedParameters(_) => false - }; - - // FIXME(eddyb) See the comment below about infer_types. - if !(infer_types && false) { - return Ok(()); - } - } - - if colons_before_params { - word(&mut self.s, "::")? - } - match *parameters { hir::AngleBracketedParameters(ref data) => { - word(&mut self.s, "<")?; + let start = if colons_before_params { "::<" } else { "<" }; + let empty = Cell::new(true); + let start_or_comma = |this: &mut Self| { + if empty.get() { + empty.set(false); + word(&mut this.s, start) + } else { + this.word_space(",") + } + }; - let mut comma = false; - for lifetime in &data.lifetimes { - if comma { - self.word_space(",")? + if !data.lifetimes.iter().all(|lt| lt.is_elided()) { + for lifetime in &data.lifetimes { + start_or_comma(self)?; + self.print_lifetime(lifetime)?; } - self.print_lifetime(lifetime)?; - comma = true; } if !data.types.is_empty() { - if comma { - self.word_space(",")? - } + start_or_comma(self)?; self.commasep(Inconsistent, &data.types, |s, ty| s.print_type(&ty))?; - comma = true; } // FIXME(eddyb) This would leak into error messages, e.g.: // "non-exhaustive patterns: `Some::<..>(_)` not covered". if data.infer_types && false { - if comma { - self.word_space(",")? - } + start_or_comma(self)?; word(&mut self.s, "..")?; - comma = true; } for binding in data.bindings.iter() { - if comma { - self.word_space(",")? - } + start_or_comma(self)?; self.print_name(binding.name)?; space(&mut self.s)?; self.word_space("=")?; self.print_type(&binding.ty)?; - comma = true; } - word(&mut self.s, ">")? + if !empty.get() { + word(&mut self.s, ">")? + } } hir::ParenthesizedParameters(ref data) => { diff --git a/src/librustc/middle/cstore.rs b/src/librustc/middle/cstore.rs index 496a3d4a498478ce148a59f0d7d9170ec81a7267..8cf13cddc8c7fa97f31d8e01693f4a2dd9d09d91 100644 --- a/src/librustc/middle/cstore.rs +++ b/src/librustc/middle/cstore.rs @@ -182,6 +182,7 @@ fn item_super_predicates<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId) -> ty::GenericPredicates<'tcx>; fn item_generics<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId) -> ty::Generics<'tcx>; + fn item_generics_own_param_counts(&self, def: DefId) -> (usize, usize); fn item_attrs(&self, def_id: DefId) -> Vec; fn trait_def<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId)-> ty::TraitDef; fn adt_def<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId) -> &'tcx ty::AdtDef; @@ -331,6 +332,8 @@ fn item_super_predicates<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId) -> ty::GenericPredicates<'tcx> { bug!("item_super_predicates") } fn item_generics<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId) -> ty::Generics<'tcx> { bug!("item_generics") } + fn item_generics_own_param_counts(&self, def: DefId) -> (usize, usize) + { bug!("item_generics_own_param_counts") } fn item_attrs(&self, def_id: DefId) -> Vec { bug!("item_attrs") } fn trait_def<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId)-> ty::TraitDef { bug!("trait_def") } diff --git a/src/librustc/middle/resolve_lifetime.rs b/src/librustc/middle/resolve_lifetime.rs index dd99aea909faaada82ed1103d70e8f49c7086512..a09f0ed7552bf146c7ab367c792af6a12107bf50 100644 --- a/src/librustc/middle/resolve_lifetime.rs +++ b/src/librustc/middle/resolve_lifetime.rs @@ -279,6 +279,9 @@ fn visit_trait_item(&mut self, trait_item: &'tcx hir::TraitItem) { } fn visit_lifetime(&mut self, lifetime_ref: &'tcx hir::Lifetime) { + if lifetime_ref.is_elided() { + return; + } if lifetime_ref.name == keywords::StaticLifetime.name() { self.insert_lifetime(lifetime_ref, DefStaticRegion); return; diff --git a/src/librustc_borrowck/borrowck/mod.rs b/src/librustc_borrowck/borrowck/mod.rs index 4ce6c9527571e3f505b9fd512cd06254f7c3032b..46179b31d5cb45bc2c212baad7a898355109e9e0 100644 --- a/src/librustc_borrowck/borrowck/mod.rs +++ b/src/librustc_borrowck/borrowck/mod.rs @@ -939,12 +939,12 @@ pub fn report_aliasability_violation(&self, /// Given a type, if it is an immutable reference, return a suggestion to make it mutable fn suggest_mut_for_immutable(&self, pty: &hir::Ty) -> Option { // Check wether the argument is an immutable reference - if let hir::TyRptr(opt_lifetime, hir::MutTy { + if let hir::TyRptr(lifetime, hir::MutTy { mutbl: hir::Mutability::MutImmutable, ref ty }) = pty.node { // Account for existing lifetimes when generating the message - if let Some(lifetime) = opt_lifetime { + if !lifetime.is_elided() { if let Ok(snippet) = self.tcx.sess.codemap().span_to_snippet(ty.span) { if let Ok(lifetime_snippet) = self.tcx.sess.codemap() .span_to_snippet(lifetime.span) { diff --git a/src/librustc_lint/bad_style.rs b/src/librustc_lint/bad_style.rs index d4ab31da8a31ec59064401796222bc825ce08e5e..05ba262ef90c08eae406ba8ebe6f3b6642cb3afc 100644 --- a/src/librustc_lint/bad_style.rs +++ b/src/librustc_lint/bad_style.rs @@ -377,8 +377,8 @@ fn check_impl_item(&mut self, cx: &LateContext, ii: &hir::ImplItem) { fn check_pat(&mut self, cx: &LateContext, p: &hir::Pat) { // Lint for constants that look like binding identifiers (#7526) if let PatKind::Path(hir::QPath::Resolved(None, ref path)) = p.node { - if path.segments.len() == 1 && path.segments[0].parameters.is_empty() { - if let Def::Const(..) = path.def { + if let Def::Const(..) = path.def { + if path.segments.len() == 1 { NonUpperCaseGlobals::check_upper_case(cx, "constant in pattern", path.segments[0].name, diff --git a/src/librustc_metadata/cstore_impl.rs b/src/librustc_metadata/cstore_impl.rs index d100cb53a8b016649659dac39227198151119139..03b2b0114f19c2a8d8d4025d15060f749de60c11 100644 --- a/src/librustc_metadata/cstore_impl.rs +++ b/src/librustc_metadata/cstore_impl.rs @@ -110,6 +110,11 @@ fn item_generics<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId) self.get_crate_data(def.krate).get_generics(def.index, tcx) } + fn item_generics_own_param_counts(&self, def: DefId) -> (usize, usize) { + self.dep_graph.read(DepNode::MetaData(def)); + self.get_crate_data(def.krate).generics_own_param_counts(def.index) + } + fn item_attrs(&self, def_id: DefId) -> Vec { self.dep_graph.read(DepNode::MetaData(def_id)); diff --git a/src/librustc_metadata/decoder.rs b/src/librustc_metadata/decoder.rs index 101531b52afb804b54b9a6432f3a9f2ea2ee7526..bfc4257bda01341ac49734cab5f8620f70709e40 100644 --- a/src/librustc_metadata/decoder.rs +++ b/src/librustc_metadata/decoder.rs @@ -598,7 +598,20 @@ pub fn get_generics(&self, item_id: DefIndex, tcx: TyCtxt<'a, 'tcx, 'tcx>) -> ty::Generics<'tcx> { - self.entry(item_id).generics.unwrap().decode((self, tcx)) + let g = self.entry(item_id).generics.unwrap().decode(self); + ty::Generics { + parent: g.parent, + parent_regions: g.parent_regions, + parent_types: g.parent_types, + regions: g.regions.decode((self, tcx)).collect(), + types: g.types.decode((self, tcx)).collect(), + has_self: g.has_self, + } + } + + pub fn generics_own_param_counts(&self, item_id: DefIndex) -> (usize, usize) { + let g = self.entry(item_id).generics.unwrap().decode(self); + (g.regions.len, g.types.len) } pub fn get_type(&self, id: DefIndex, tcx: TyCtxt<'a, 'tcx, 'tcx>) -> Ty<'tcx> { diff --git a/src/librustc_metadata/encoder.rs b/src/librustc_metadata/encoder.rs index 2f71776ecf758db446399699903730e55b3ae2f4..c407c27b096e1d896d2876b46282aff4696fdb54 100644 --- a/src/librustc_metadata/encoder.rs +++ b/src/librustc_metadata/encoder.rs @@ -417,9 +417,19 @@ fn encode_struct_ctor(&mut self, (adt_def_id, def_id): (DefId, DefId)) -> Entry< } } - fn encode_generics(&mut self, def_id: DefId) -> Lazy> { + fn encode_generics(&mut self, def_id: DefId) -> Lazy> { let tcx = self.tcx; - self.lazy(tcx.item_generics(def_id)) + let g = tcx.item_generics(def_id); + let regions = self.lazy_seq_ref(&g.regions); + let types = self.lazy_seq_ref(&g.types); + self.lazy(&Generics { + parent: g.parent, + parent_regions: g.parent_regions, + parent_types: g.parent_types, + regions: regions, + types: types, + has_self: g.has_self, + }) } fn encode_predicates(&mut self, def_id: DefId) -> Lazy> { diff --git a/src/librustc_metadata/schema.rs b/src/librustc_metadata/schema.rs index 74825a5c6e3f676325a2419ee782aca90cead7ef..4f9f2d23f5d3e775205baee9e4b207e5c7aacf7f 100644 --- a/src/librustc_metadata/schema.rs +++ b/src/librustc_metadata/schema.rs @@ -213,7 +213,7 @@ pub struct Entry<'tcx> { pub ty: Option>>, pub inherent_impls: LazySeq, pub variances: LazySeq, - pub generics: Option>>, + pub generics: Option>>, pub predicates: Option>>, pub ast: Option>>, @@ -247,6 +247,19 @@ pub enum EntryKind<'tcx> { AssociatedConst(AssociatedContainer), } +/// A copy of `ty::Generics` which allows lazy decoding of +/// `regions` and `types` (e.g. knowing the number of type +/// and lifetime parameters before `TyCtxt` is created). +#[derive(RustcEncodable, RustcDecodable)] +pub struct Generics<'tcx> { + pub parent: Option, + pub parent_regions: u32, + pub parent_types: u32, + pub regions: LazySeq>, + pub types: LazySeq>, + pub has_self: bool, +} + #[derive(RustcEncodable, RustcDecodable)] pub struct ModData { pub reexports: LazySeq, diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs index 0a836a8ba22297bfb11d7fec4bf8ec8d278a2145..bc8e56e811ed28b10d9d8942771448a5570a38a2 100644 --- a/src/librustc_typeck/astconv.rs +++ b/src/librustc_typeck/astconv.rs @@ -404,19 +404,20 @@ fn create_substs_for_ast_path(&self, }; let expected_num_region_params = decl_generics.regions.len(); let supplied_num_region_params = lifetimes.len(); - let has_exact_lifetimes = expected_num_region_params == supplied_num_region_params; - let mut can_report_lifetime_count_mismatch = !has_exact_lifetimes; - let mut maybe_report_lifetime_count_mismatch = || { - if can_report_lifetime_count_mismatch { - can_report_lifetime_count_mismatch = false; + let mut reported_lifetime_count_mismatch = false; + let mut report_lifetime_count_mismatch = || { + if !reported_lifetime_count_mismatch { + reported_lifetime_count_mismatch = true; + let all_infer = lifetimes.iter().all(|lt| lt.is_elided()); + let supplied = if all_infer { 0 } else { supplied_num_region_params }; report_lifetime_number_error(tcx, span, - supplied_num_region_params, + supplied, expected_num_region_params); } }; - if supplied_num_region_params != 0 { - maybe_report_lifetime_count_mismatch(); + if expected_num_region_params != supplied_num_region_params { + report_lifetime_count_mismatch(); } // If a self-type was declared, one should be provided. @@ -444,13 +445,9 @@ fn create_substs_for_ast_path(&self, let mut output_assoc_binding = None; let substs = Substs::for_item(tcx, def_id, |def, _| { let i = def.index as usize - self_ty.is_some() as usize; - let l = if has_exact_lifetimes { - Some(&lifetimes[i]) - } else { - None - }; + let l = lifetimes.get(i); self.try_opt_ast_region_to_region(rscope, span, l, Some(def)).unwrap_or_else(|_| { - maybe_report_lifetime_count_mismatch(); + report_lifetime_count_mismatch(); tcx.mk_region(ty::ReStatic) }) }, |def, substs| { @@ -1472,7 +1469,7 @@ pub fn ast_ty_to_ty(&self, rscope: &RegionScope, ast_ty: &hir::Ty) -> Ty<'tcx> { }) } hir::TyRptr(ref region, ref mt) => { - let r = self.opt_ast_region_to_region(rscope, ast_ty.span, region.as_ref(), None); + let r = self.opt_ast_region_to_region(rscope, ast_ty.span, Some(region), None); debug!("TyRef r={:?}", r); let rscope1 = &ObjectLifetimeDefaultRscope::new( diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 080bc5072d69b10e579a8cf9d7107ebda54e9ce0..54a5b9f43c0dc641800c59d1053e559037bf8977 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -1688,9 +1688,15 @@ fn clean(&self, cx: &DocContext) -> Type { match self.node { TyNever => Never, TyPtr(ref m) => RawPointer(m.mutbl.clean(cx), box m.ty.clean(cx)), - TyRptr(ref l, ref m) => - BorrowedRef {lifetime: l.clean(cx), mutability: m.mutbl.clean(cx), - type_: box m.ty.clean(cx)}, + TyRptr(ref l, ref m) => { + let lifetime = if l.is_elided() { + None + } else { + Some(l.clean(cx)) + }; + BorrowedRef {lifetime: lifetime, mutability: m.mutbl.clean(cx), + type_: box m.ty.clean(cx)} + } TySlice(ref ty) => Vector(box ty.clean(cx)), TyArray(ref ty, length) => { use rustc_const_eval::eval_length; @@ -1729,7 +1735,9 @@ fn clean(&self, cx: &DocContext) -> Type { for (i, lt_param) in generics.lifetimes.iter().enumerate() { if let Some(lt) = provided_params.lifetimes().get(i).cloned() .cloned() { - lt_substs.insert(lt_param.lifetime.id, lt.clean(cx)); + if !lt.is_elided() { + lt_substs.insert(lt_param.lifetime.id, lt.clean(cx)); + } } } return cx.enter_alias(ty_substs, lt_substs, || ty.clean(cx)); @@ -2242,7 +2250,11 @@ fn clean(&self, cx: &DocContext) -> PathParameters { match *self { hir::AngleBracketedParameters(ref data) => { PathParameters::AngleBracketed { - lifetimes: data.lifetimes.clean(cx), + lifetimes: if data.lifetimes.iter().all(|lt| lt.is_elided()) { + vec![] + } else { + data.lifetimes.clean(cx) + }, types: data.types.clean(cx), bindings: data.bindings.clean(cx) } diff --git a/src/test/compile-fail/unboxed-closure-sugar-region.rs b/src/test/compile-fail/unboxed-closure-sugar-region.rs index 057b496bd43ebead9d4f321fd67692275a10cdd7..18a1185d695f70ca0de33391fc4fadbc9843bbc5 100644 --- a/src/test/compile-fail/unboxed-closure-sugar-region.rs +++ b/src/test/compile-fail/unboxed-closure-sugar-region.rs @@ -38,9 +38,9 @@ fn test<'a,'b>() { } fn test2(x: &Foo<(isize,),Output=()>, y: &Foo(isize)) { +//~^ ERROR wrong number of lifetime parameters: expected 1, found 0 // Here, the omitted lifetimes are expanded to distinct things. - same_type(x, y) //~ ERROR cannot infer - //~^ ERROR cannot infer + same_type(x, y) } fn main() { }