rustc: always include elidable lifetimes in HIR types.
This commit is contained in:
parent
f79feba205
commit
7a2a669bb7
15 changed files with 248 additions and 134 deletions
|
@ -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 => {},
|
||||
|
|
|
@ -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<hir::TraitItemId, hir::TraitItem>,
|
||||
impl_items: BTreeMap<hir::ImplItemId, hir::ImplItem>,
|
||||
bodies: FxHashMap<hir::BodyId, hir::Body>,
|
||||
|
||||
type_def_lifetime_params: DefIdMap<usize>,
|
||||
}
|
||||
|
||||
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();
|
||||
|
||||
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,
|
||||
/// 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>,
|
||||
}
|
||||
|
||||
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 @@ impl<'a> LoweringContext<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
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 @@ impl<'a> LoweringContext<'a> {
|
|||
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<Spanned<Ident>>) -> Option<Spanned<Name>> {
|
||||
o_id.map(|sp_ident| respan(sp_ident.span, sp_ident.node.name))
|
||||
}
|
||||
|
@ -279,7 +314,11 @@ impl<'a> LoweringContext<'a> {
|
|||
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 @@ impl<'a> LoweringContext<'a> {
|
|||
}
|
||||
_ => 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 @@ impl<'a> LoweringContext<'a> {
|
|||
// 3. `<<std::vec::Vec<T>>::IntoIter>::Item`
|
||||
// * final path is `<<<std::vec::Vec<T>>::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 @@ impl<'a> LoweringContext<'a> {
|
|||
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 @@ impl<'a> LoweringContext<'a> {
|
|||
}
|
||||
|
||||
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 @@ impl<'a> LoweringContext<'a> {
|
|||
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 @@ impl<'a> LoweringContext<'a> {
|
|||
lts.iter().map(|l| self.lower_lifetime_def(l)).collect()
|
||||
}
|
||||
|
||||
fn lower_opt_lifetime(&mut self, o_lt: &Option<Lifetime>) -> Option<hir::Lifetime> {
|
||||
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 @@ impl<'a> LoweringContext<'a> {
|
|||
}
|
||||
|
||||
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 @@ impl<'a> LoweringContext<'a> {
|
|||
span: span,
|
||||
})
|
||||
}
|
||||
|
||||
fn elided_lifetime(&mut self, span: Span) -> hir::Lifetime {
|
||||
hir::Lifetime {
|
||||
id: self.next_id(),
|
||||
span: span,
|
||||
name: keywords::Invalid.name()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -77,6 +77,13 @@ pub mod svh;
|
|||
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 @@ impl fmt::Debug for Lifetime {
|
|||
}
|
||||
}
|
||||
|
||||
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 @@ impl 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<Ty>> {
|
||||
|
@ -245,12 +234,6 @@ pub struct AngleBracketedParameterData {
|
|||
pub bindings: HirVec<TypeBinding>,
|
||||
}
|
||||
|
||||
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<Lifetime>, MutTy),
|
||||
TyRptr(Lifetime, MutTy),
|
||||
/// A bare function (e.g. `fn(usize) -> bool`)
|
||||
TyBareFn(P<BareFnTy>),
|
||||
/// The never type (`!`)
|
||||
|
|
|
@ -26,6 +26,7 @@ use syntax_pos::{self, BytePos};
|
|||
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 @@ impl<'a> State<'a> {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
pub fn print_opt_lifetime(&mut self, lifetime: &Option<hir::Lifetime>) -> 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 @@ impl<'a> State<'a> {
|
|||
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 mut comma = false;
|
||||
for lifetime in &data.lifetimes {
|
||||
if comma {
|
||||
self.word_space(",")?
|
||||
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(",")
|
||||
}
|
||||
};
|
||||
|
||||
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) => {
|
||||
|
|
|
@ -182,6 +182,7 @@ pub trait CrateStore<'tcx> {
|
|||
-> 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<ast::Attribute>;
|
||||
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 @@ impl<'tcx> CrateStore<'tcx> for DummyCrateStore {
|
|||
-> 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<ast::Attribute> { bug!("item_attrs") }
|
||||
fn trait_def<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId)-> ty::TraitDef
|
||||
{ bug!("trait_def") }
|
||||
|
|
|
@ -279,6 +279,9 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
|
|||
}
|
||||
|
||||
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;
|
||||
|
|
|
@ -939,12 +939,12 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> {
|
|||
/// 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<String> {
|
||||
// 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) {
|
||||
|
|
|
@ -377,8 +377,8 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for NonUpperCaseGlobals {
|
|||
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,
|
||||
|
|
|
@ -110,6 +110,11 @@ impl<'tcx> CrateStore<'tcx> for cstore::CStore {
|
|||
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<ast::Attribute>
|
||||
{
|
||||
self.dep_graph.read(DepNode::MetaData(def_id));
|
||||
|
|
|
@ -598,7 +598,20 @@ impl<'a, 'tcx> CrateMetadata {
|
|||
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> {
|
||||
|
|
|
@ -417,9 +417,19 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
fn encode_generics(&mut self, def_id: DefId) -> Lazy<ty::Generics<'tcx>> {
|
||||
fn encode_generics(&mut self, def_id: DefId) -> Lazy<Generics<'tcx>> {
|
||||
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<ty::GenericPredicates<'tcx>> {
|
||||
|
|
|
@ -213,7 +213,7 @@ pub struct Entry<'tcx> {
|
|||
pub ty: Option<Lazy<Ty<'tcx>>>,
|
||||
pub inherent_impls: LazySeq<DefIndex>,
|
||||
pub variances: LazySeq<ty::Variance>,
|
||||
pub generics: Option<Lazy<ty::Generics<'tcx>>>,
|
||||
pub generics: Option<Lazy<Generics<'tcx>>>,
|
||||
pub predicates: Option<Lazy<ty::GenericPredicates<'tcx>>>,
|
||||
|
||||
pub ast: Option<Lazy<astencode::Ast<'tcx>>>,
|
||||
|
@ -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<DefId>,
|
||||
pub parent_regions: u32,
|
||||
pub parent_types: u32,
|
||||
pub regions: LazySeq<ty::RegionParameterDef<'tcx>>,
|
||||
pub types: LazySeq<ty::TypeParameterDef<'tcx>>,
|
||||
pub has_self: bool,
|
||||
}
|
||||
|
||||
#[derive(RustcEncodable, RustcDecodable)]
|
||||
pub struct ModData {
|
||||
pub reexports: LazySeq<def::Export>,
|
||||
|
|
|
@ -404,19 +404,20 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
|
|||
};
|
||||
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 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
|
|||
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 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
|
|||
})
|
||||
}
|
||||
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(
|
||||
|
|
|
@ -1688,9 +1688,15 @@ impl Clean<Type> for hir::Ty {
|
|||
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 @@ impl Clean<Type> for hir::Ty {
|
|||
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 @@ impl Clean<PathParameters> for hir::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)
|
||||
}
|
||||
|
|
|
@ -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() { }
|
||||
|
|
Loading…
Add table
Reference in a new issue