1
Fork 0

Auto merge of #45930 - jplatte:generics_refactoring, r=eddyb

Generics refactoring (groundwork for const generics)

These changes were suggested by @eddyb.

After this change, the `Generics` contain one `Vec` of an enum for the generic parameters, rather than two separate `Vec`s for lifetime and type parameters. Type params and const params will need to be in a shared `Vec` to preserve their ordering, and moving lifetimes into the same `Vec` should simplify the code that processes `Generics`.
This commit is contained in:
bors 2017-12-21 20:12:13 +00:00
commit 250b492052
51 changed files with 1020 additions and 832 deletions

View file

@ -279,6 +279,9 @@ pub trait Visitor<'v> : Sized {
fn visit_ty(&mut self, t: &'v Ty) { fn visit_ty(&mut self, t: &'v Ty) {
walk_ty(self, t) walk_ty(self, t)
} }
fn visit_generic_param(&mut self, p: &'v GenericParam) {
walk_generic_param(self, p)
}
fn visit_generics(&mut self, g: &'v Generics) { fn visit_generics(&mut self, g: &'v Generics) {
walk_generics(self, g) walk_generics(self, g)
} }
@ -336,9 +339,6 @@ pub trait Visitor<'v> : Sized {
fn visit_lifetime(&mut self, lifetime: &'v Lifetime) { fn visit_lifetime(&mut self, lifetime: &'v Lifetime) {
walk_lifetime(self, lifetime) walk_lifetime(self, lifetime)
} }
fn visit_lifetime_def(&mut self, lifetime: &'v LifetimeDef) {
walk_lifetime_def(self, lifetime)
}
fn visit_qpath(&mut self, qpath: &'v QPath, id: NodeId, span: Span) { fn visit_qpath(&mut self, qpath: &'v QPath, id: NodeId, span: Span) {
walk_qpath(self, qpath, id, span) walk_qpath(self, qpath, id, span)
} }
@ -430,17 +430,12 @@ pub fn walk_lifetime<'v, V: Visitor<'v>>(visitor: &mut V, lifetime: &'v Lifetime
} }
} }
pub fn walk_lifetime_def<'v, V: Visitor<'v>>(visitor: &mut V, lifetime_def: &'v LifetimeDef) {
visitor.visit_lifetime(&lifetime_def.lifetime);
walk_list!(visitor, visit_lifetime, &lifetime_def.bounds);
}
pub fn walk_poly_trait_ref<'v, V>(visitor: &mut V, pub fn walk_poly_trait_ref<'v, V>(visitor: &mut V,
trait_ref: &'v PolyTraitRef, trait_ref: &'v PolyTraitRef,
_modifier: TraitBoundModifier) _modifier: TraitBoundModifier)
where V: Visitor<'v> where V: Visitor<'v>
{ {
walk_list!(visitor, visit_lifetime_def, &trait_ref.bound_lifetimes); walk_list!(visitor, visit_generic_param, &trait_ref.bound_generic_params);
visitor.visit_trait_ref(&trait_ref.trait_ref); visitor.visit_trait_ref(&trait_ref.trait_ref);
} }
@ -581,7 +576,7 @@ pub fn walk_ty<'v, V: Visitor<'v>>(visitor: &mut V, typ: &'v Ty) {
} }
TyBareFn(ref function_declaration) => { TyBareFn(ref function_declaration) => {
visitor.visit_fn_decl(&function_declaration.decl); visitor.visit_fn_decl(&function_declaration.decl);
walk_list!(visitor, visit_lifetime_def, &function_declaration.lifetimes); walk_list!(visitor, visit_generic_param, &function_declaration.generic_params);
} }
TyPath(ref qpath) => { TyPath(ref qpath) => {
visitor.visit_qpath(qpath, typ.id, typ.span); visitor.visit_qpath(qpath, typ.id, typ.span);
@ -729,14 +724,23 @@ pub fn walk_ty_param_bound<'v, V: Visitor<'v>>(visitor: &mut V, bound: &'v TyPar
} }
} }
pub fn walk_generics<'v, V: Visitor<'v>>(visitor: &mut V, generics: &'v Generics) { pub fn walk_generic_param<'v, V: Visitor<'v>>(visitor: &mut V, param: &'v GenericParam) {
for param in &generics.ty_params { match *param {
visitor.visit_id(param.id); GenericParam::Lifetime(ref ld) => {
visitor.visit_name(param.span, param.name); visitor.visit_lifetime(&ld.lifetime);
walk_list!(visitor, visit_ty_param_bound, &param.bounds); walk_list!(visitor, visit_lifetime, &ld.bounds);
walk_list!(visitor, visit_ty, &param.default); }
GenericParam::Type(ref ty_param) => {
visitor.visit_id(ty_param.id);
visitor.visit_name(ty_param.span, ty_param.name);
walk_list!(visitor, visit_ty_param_bound, &ty_param.bounds);
walk_list!(visitor, visit_ty, &ty_param.default);
}
} }
walk_list!(visitor, visit_lifetime_def, &generics.lifetimes); }
pub fn walk_generics<'v, V: Visitor<'v>>(visitor: &mut V, generics: &'v Generics) {
walk_list!(visitor, visit_generic_param, &generics.params);
visitor.visit_id(generics.where_clause.id); visitor.visit_id(generics.where_clause.id);
walk_list!(visitor, visit_where_predicate, &generics.where_clause.predicates); walk_list!(visitor, visit_where_predicate, &generics.where_clause.predicates);
} }
@ -748,11 +752,11 @@ pub fn walk_where_predicate<'v, V: Visitor<'v>>(
match predicate { match predicate {
&WherePredicate::BoundPredicate(WhereBoundPredicate{ref bounded_ty, &WherePredicate::BoundPredicate(WhereBoundPredicate{ref bounded_ty,
ref bounds, ref bounds,
ref bound_lifetimes, ref bound_generic_params,
..}) => { ..}) => {
visitor.visit_ty(bounded_ty); visitor.visit_ty(bounded_ty);
walk_list!(visitor, visit_ty_param_bound, bounds); walk_list!(visitor, visit_ty_param_bound, bounds);
walk_list!(visitor, visit_lifetime_def, bound_lifetimes); walk_list!(visitor, visit_generic_param, bound_generic_params);
} }
&WherePredicate::RegionPredicate(WhereRegionPredicate{ref lifetime, &WherePredicate::RegionPredicate(WhereRegionPredicate{ref lifetime,
ref bounds, ref bounds,

View file

@ -253,7 +253,9 @@ impl<'a> LoweringContext<'a> {
ItemKind::Ty(_, ref generics) | ItemKind::Ty(_, ref generics) |
ItemKind::Trait(_, _, ref generics, ..) => { ItemKind::Trait(_, _, ref generics, ..) => {
let def_id = self.lctx.resolver.definitions().local_def_id(item.id); let def_id = self.lctx.resolver.definitions().local_def_id(item.id);
let count = generics.lifetimes.len(); let count = generics.params.iter()
.filter(|param| param.is_lifetime_param())
.count();
self.lctx.type_def_lifetime_params.insert(def_id, count); self.lctx.type_def_lifetime_params.insert(def_id, count);
} }
_ => {} _ => {}
@ -306,8 +308,8 @@ impl<'a> LoweringContext<'a> {
let item_lifetimes = match self.lctx.items.get(&item.id).unwrap().node { let item_lifetimes = match self.lctx.items.get(&item.id).unwrap().node {
hir::Item_::ItemImpl(_,_,_,ref generics,..) | hir::Item_::ItemImpl(_,_,_,ref generics,..) |
hir::Item_::ItemTrait(_,_,ref generics,..) => hir::Item_::ItemTrait(_,_,ref generics,..) =>
generics.lifetimes.clone(), generics.lifetimes().cloned().collect::<Vec<_>>(),
_ => Vec::new().into(), _ => Vec::new(),
}; };
self.lctx.with_parent_impl_lifetime_defs(&item_lifetimes, |this| { self.lctx.with_parent_impl_lifetime_defs(&item_lifetimes, |this| {
@ -532,14 +534,14 @@ impl<'a> LoweringContext<'a> {
span.with_ctxt(SyntaxContext::empty().apply_mark(mark)) span.with_ctxt(SyntaxContext::empty().apply_mark(mark))
} }
// Creates a new hir::LifetimeDef for every new lifetime encountered // Creates a new hir::GenericParam for every new lifetime and type parameter
// while evaluating `f`. Definitions are created with the parent provided. // encountered while evaluating `f`. Definitions are created with the parent
// If no `parent_id` is provided, no definitions will be returned. // provided. If no `parent_id` is provided, no definitions will be returned.
fn collect_in_band_defs<T, F>( fn collect_in_band_defs<T, F>(
&mut self, &mut self,
parent_id: Option<DefId>, parent_id: Option<DefId>,
f: F f: F
) -> (Vec<hir::TyParam>, Vec<hir::LifetimeDef>, T) where F: FnOnce(&mut LoweringContext) -> T ) -> (Vec<hir::GenericParam>, T) where F: FnOnce(&mut LoweringContext) -> T
{ {
assert!(!self.is_collecting_in_band_lifetimes); assert!(!self.is_collecting_in_band_lifetimes);
assert!(self.lifetimes_to_define.is_empty()); assert!(self.lifetimes_to_define.is_empty());
@ -554,7 +556,7 @@ impl<'a> LoweringContext<'a> {
let in_band_ty_params = self.in_band_ty_params.split_off(0); let in_band_ty_params = self.in_band_ty_params.split_off(0);
let lifetimes_to_define = self.lifetimes_to_define.split_off(0); let lifetimes_to_define = self.lifetimes_to_define.split_off(0);
let lifetime_defs = match parent_id { let mut params = match parent_id {
Some(parent_id) => lifetimes_to_define.into_iter().map(|(span, name)| { Some(parent_id) => lifetimes_to_define.into_iter().map(|(span, name)| {
let def_node_id = self.next_id().node_id; let def_node_id = self.next_id().node_id;
@ -567,7 +569,7 @@ impl<'a> LoweringContext<'a> {
Mark::root() Mark::root()
); );
hir::LifetimeDef { hir::GenericParam::Lifetime(hir::LifetimeDef {
lifetime: hir::Lifetime { lifetime: hir::Lifetime {
id: def_node_id, id: def_node_id,
span, span,
@ -576,12 +578,14 @@ impl<'a> LoweringContext<'a> {
bounds: Vec::new().into(), bounds: Vec::new().into(),
pure_wrt_drop: false, pure_wrt_drop: false,
in_band: true, in_band: true,
} })
}).collect(), }).collect(),
None => Vec::new(), None => Vec::new(),
}; };
(in_band_ty_params, lifetime_defs, res) params.extend(in_band_ty_params.into_iter().map(|tp| hir::GenericParam::Type(tp)));
(params, res)
} }
// Evaluates `f` with the lifetimes in `lt_defs` in-scope. // Evaluates `f` with the lifetimes in `lt_defs` in-scope.
@ -635,24 +639,24 @@ impl<'a> LoweringContext<'a> {
) -> (hir::Generics, T) ) -> (hir::Generics, T)
where F: FnOnce(&mut LoweringContext) -> T where F: FnOnce(&mut LoweringContext) -> T
{ {
let (in_band_ty_defs, in_band_lifetime_defs, (mut lowered_generics, res)) = let (in_band_defs, (mut lowered_generics, res)) =
self.with_in_scope_lifetime_defs(&generics.lifetimes, |this| { self.with_in_scope_lifetime_defs(
this.collect_in_band_defs(parent_id, |this| { &generics.params
(this.lower_generics(generics), f(this)) .iter()
}) .filter_map(|p| match *p {
}); GenericParam::Lifetime(ref ld) => Some(ld.clone()),
_ => None,
})
.collect::<Vec<_>>(),
|this| {
this.collect_in_band_defs(parent_id, |this| {
(this.lower_generics(generics), f(this))
})
}
);
lowered_generics.ty_params = lowered_generics.params =
lowered_generics.ty_params lowered_generics.params.iter().cloned().chain(in_band_defs).collect();
.iter().cloned()
.chain(in_band_ty_defs.into_iter())
.collect();
lowered_generics.lifetimes =
lowered_generics.lifetimes
.iter().cloned()
.chain(in_band_lifetime_defs.into_iter())
.collect();
(lowered_generics, res) (lowered_generics, res)
} }
@ -877,9 +881,16 @@ impl<'a> LoweringContext<'a> {
hir::TyRptr(lifetime, self.lower_mt(mt, itctx)) hir::TyRptr(lifetime, self.lower_mt(mt, itctx))
} }
TyKind::BareFn(ref f) => { TyKind::BareFn(ref f) => {
self.with_in_scope_lifetime_defs(&f.lifetimes, |this| self.with_in_scope_lifetime_defs(
hir::TyBareFn(P(hir::BareFnTy { &f.generic_params
lifetimes: this.lower_lifetime_defs(&f.lifetimes), .iter()
.filter_map(|p| match *p {
GenericParam::Lifetime(ref ld) => Some(ld.clone()),
_ => None,
})
.collect::<Vec<_>>(),
|this| hir::TyBareFn(P(hir::BareFnTy {
generic_params: this.lower_generic_params(&f.generic_params, &NodeMap()),
unsafety: this.lower_unsafety(f.unsafety), unsafety: this.lower_unsafety(f.unsafety),
abi: f.abi, abi: f.abi,
decl: this.lower_fn_decl(&f.decl, None, false), decl: this.lower_fn_decl(&f.decl, None, false),
@ -954,9 +965,7 @@ impl<'a> LoweringContext<'a> {
hir::TyImplTraitExistential(hir::ExistTy { hir::TyImplTraitExistential(hir::ExistTy {
generics: hir::Generics { generics: hir::Generics {
lifetimes: lifetime_defs, params: lifetime_defs,
// Type parameters are taken from environment:
ty_params: Vec::new().into(),
where_clause: hir::WhereClause { where_clause: hir::WhereClause {
id: self.next_id().node_id, id: self.next_id().node_id,
predicates: Vec::new().into(), predicates: Vec::new().into(),
@ -1027,7 +1036,7 @@ impl<'a> LoweringContext<'a> {
&mut self, &mut self,
parent_index: DefIndex, parent_index: DefIndex,
bounds: &hir::TyParamBounds bounds: &hir::TyParamBounds
) -> (HirVec<hir::Lifetime>, HirVec<hir::LifetimeDef>) { ) -> (HirVec<hir::Lifetime>, HirVec<hir::GenericParam>) {
// This visitor walks over impl trait bounds and creates defs for all lifetimes which // This visitor walks over impl trait bounds and creates defs for all lifetimes which
// appear in the bounds, excluding lifetimes that are created within the bounds. // appear in the bounds, excluding lifetimes that are created within the bounds.
@ -1039,7 +1048,7 @@ impl<'a> LoweringContext<'a> {
currently_bound_lifetimes: Vec<hir::LifetimeName>, currently_bound_lifetimes: Vec<hir::LifetimeName>,
already_defined_lifetimes: HashSet<hir::LifetimeName>, already_defined_lifetimes: HashSet<hir::LifetimeName>,
output_lifetimes: Vec<hir::Lifetime>, output_lifetimes: Vec<hir::Lifetime>,
output_lifetime_defs: Vec<hir::LifetimeDef>, output_lifetime_params: Vec<hir::GenericParam>,
} }
impl<'r, 'a: 'r, 'v> hir::intravisit::Visitor<'v> for ImplTraitLifetimeCollector<'r, 'a> { impl<'r, 'a: 'r, 'v> hir::intravisit::Visitor<'v> for ImplTraitLifetimeCollector<'r, 'a> {
@ -1078,14 +1087,16 @@ impl<'a> LoweringContext<'a> {
let old_len = self.currently_bound_lifetimes.len(); let old_len = self.currently_bound_lifetimes.len();
// Record the introduction of 'a in `for<'a> ...` // Record the introduction of 'a in `for<'a> ...`
for lt_def in &polytr.bound_lifetimes { for param in &polytr.bound_generic_params {
// Introduce lifetimes one at a time so that we can handle if let hir::GenericParam::Lifetime(ref lt_def) = *param {
// cases like `fn foo<'d>() -> impl for<'a, 'b: 'a, 'c: 'b + 'd>` // Introduce lifetimes one at a time so that we can handle
self.currently_bound_lifetimes.push(lt_def.lifetime.name); // cases like `fn foo<'d>() -> impl for<'a, 'b: 'a, 'c: 'b + 'd>`
self.currently_bound_lifetimes.push(lt_def.lifetime.name);
// Visit the lifetime bounds // Visit the lifetime bounds
for lt_bound in &lt_def.bounds { for lt_bound in &lt_def.bounds {
self.visit_lifetime(&lt_bound); self.visit_lifetime(&lt_bound);
}
} }
} }
@ -1133,12 +1144,12 @@ impl<'a> LoweringContext<'a> {
span: lifetime.span, span: lifetime.span,
name: name, name: name,
}; };
self.output_lifetime_defs.push(hir::LifetimeDef { self.output_lifetime_params.push(hir::GenericParam::Lifetime(hir::LifetimeDef {
lifetime: def_lifetime, lifetime: def_lifetime,
bounds: Vec::new().into(), bounds: Vec::new().into(),
pure_wrt_drop: false, pure_wrt_drop: false,
in_band: false, in_band: false,
}); }));
} }
} }
} }
@ -1150,7 +1161,7 @@ impl<'a> LoweringContext<'a> {
currently_bound_lifetimes: Vec::new(), currently_bound_lifetimes: Vec::new(),
already_defined_lifetimes: HashSet::new(), already_defined_lifetimes: HashSet::new(),
output_lifetimes: Vec::new(), output_lifetimes: Vec::new(),
output_lifetime_defs: Vec::new(), output_lifetime_params: Vec::new(),
}; };
for bound in bounds { for bound in bounds {
@ -1159,7 +1170,7 @@ impl<'a> LoweringContext<'a> {
( (
lifetime_collector.output_lifetimes.into(), lifetime_collector.output_lifetimes.into(),
lifetime_collector.output_lifetime_defs.into() lifetime_collector.output_lifetime_params.into()
) )
} }
@ -1568,13 +1579,6 @@ impl<'a> LoweringContext<'a> {
} }
} }
fn lower_ty_params(&mut self, tps: &Vec<TyParam>, add_bounds: &NodeMap<Vec<TyParamBound>>)
-> hir::HirVec<hir::TyParam> {
tps.iter().map(|tp| {
self.lower_ty_param(tp, add_bounds.get(&tp.id).map_or(&[][..], |x| &x))
}).collect()
}
fn lower_lifetime(&mut self, l: &Lifetime) -> hir::Lifetime { fn lower_lifetime(&mut self, l: &Lifetime) -> hir::Lifetime {
let name = match self.lower_ident(l.ident) { let name = match self.lower_ident(l.ident) {
x if x == "'_" => hir::LifetimeName::Underscore, x if x == "'_" => hir::LifetimeName::Underscore,
@ -1620,12 +1624,31 @@ impl<'a> LoweringContext<'a> {
lts.iter().map(|l| self.lower_lifetime(l)).collect() lts.iter().map(|l| self.lower_lifetime(l)).collect()
} }
fn lower_lifetime_defs(&mut self, lts: &Vec<LifetimeDef>) -> hir::HirVec<hir::LifetimeDef> { fn lower_generic_params(
lts.iter().map(|l| self.lower_lifetime_def(l)).collect() &mut self,
params: &Vec<GenericParam>,
add_bounds: &NodeMap<Vec<TyParamBound>>,
) -> hir::HirVec<hir::GenericParam> {
params.iter()
.map(|param| match *param {
GenericParam::Lifetime(ref lifetime_def) => {
hir::GenericParam::Lifetime(self.lower_lifetime_def(lifetime_def))
}
GenericParam::Type(ref ty_param) => {
hir::GenericParam::Type(self.lower_ty_param(
ty_param,
add_bounds.get(&ty_param.id).map_or(&[][..], |x| &x)
))
}
})
.collect()
} }
fn lower_generics(&mut self, g: &Generics) -> hir::Generics { fn lower_generics(&mut self, g: &Generics) -> hir::Generics {
// Collect `?Trait` bounds in where clause and move them to parameter definitions. // Collect `?Trait` bounds in where clause and move them to parameter definitions.
// FIXME: This could probably be done with less rightward drift. Also looks like two control
// paths where report_error is called are also the only paths that advance to after
// the match statement, so the error reporting could probably just be moved there.
let mut add_bounds = NodeMap(); let mut add_bounds = NodeMap();
for pred in &g.where_clause.predicates { for pred in &g.where_clause.predicates {
if let WherePredicate::BoundPredicate(ref bound_pred) = *pred { if let WherePredicate::BoundPredicate(ref bound_pred) = *pred {
@ -1640,17 +1663,20 @@ impl<'a> LoweringContext<'a> {
match bound_pred.bounded_ty.node { match bound_pred.bounded_ty.node {
TyKind::Path(None, ref path) TyKind::Path(None, ref path)
if path.segments.len() == 1 && if path.segments.len() == 1 &&
bound_pred.bound_lifetimes.is_empty() => { bound_pred.bound_generic_params.is_empty() => {
if let Some(Def::TyParam(def_id)) = if let Some(Def::TyParam(def_id)) =
self.resolver.get_resolution(bound_pred.bounded_ty.id) self.resolver.get_resolution(bound_pred.bounded_ty.id)
.map(|d| d.base_def()) { .map(|d| d.base_def()) {
if let Some(node_id) = if let Some(node_id) =
self.resolver.definitions().as_local_node_id(def_id) { self.resolver.definitions().as_local_node_id(def_id) {
for ty_param in &g.ty_params { for param in &g.params {
if node_id == ty_param.id { if let GenericParam::Type(ref ty_param) = *param {
add_bounds.entry(ty_param.id).or_insert(Vec::new()) if node_id == ty_param.id {
.push(bound.clone()); add_bounds.entry(ty_param.id)
continue 'next_bound; .or_insert(Vec::new())
.push(bound.clone());
continue 'next_bound;
}
} }
} }
} }
@ -1665,8 +1691,7 @@ impl<'a> LoweringContext<'a> {
} }
hir::Generics { hir::Generics {
ty_params: self.lower_ty_params(&g.ty_params, &add_bounds), params: self.lower_generic_params(&g.params, &add_bounds),
lifetimes: self.lower_lifetime_defs(&g.lifetimes),
where_clause: self.lower_where_clause(&g.where_clause), where_clause: self.lower_where_clause(&g.where_clause),
span: g.span, span: g.span,
} }
@ -1684,24 +1709,33 @@ impl<'a> LoweringContext<'a> {
fn lower_where_predicate(&mut self, pred: &WherePredicate) -> hir::WherePredicate { fn lower_where_predicate(&mut self, pred: &WherePredicate) -> hir::WherePredicate {
match *pred { match *pred {
WherePredicate::BoundPredicate(WhereBoundPredicate{ ref bound_lifetimes, WherePredicate::BoundPredicate(WhereBoundPredicate{ ref bound_generic_params,
ref bounded_ty, ref bounded_ty,
ref bounds, ref bounds,
span}) => { span}) => {
self.with_in_scope_lifetime_defs(bound_lifetimes, |this| { self.with_in_scope_lifetime_defs(
hir::WherePredicate::BoundPredicate(hir::WhereBoundPredicate { &bound_generic_params.iter()
bound_lifetimes: this.lower_lifetime_defs(bound_lifetimes), .filter_map(|p| match *p {
bounded_ty: this.lower_ty(bounded_ty, ImplTraitContext::Disallowed), GenericParam::Lifetime(ref ld) => Some(ld.clone()),
bounds: bounds.iter().filter_map(|bound| match *bound { _ => None,
// Ignore `?Trait` bounds. })
// Tthey were copied into type parameters already. .collect::<Vec<_>>(),
TraitTyParamBound(_, TraitBoundModifier::Maybe) => None, |this| {
_ => Some(this.lower_ty_param_bound( hir::WherePredicate::BoundPredicate(hir::WhereBoundPredicate {
bound, ImplTraitContext::Disallowed)) bound_generic_params:
}).collect(), this.lower_generic_params(bound_generic_params, &NodeMap()),
span, bounded_ty: this.lower_ty(bounded_ty, ImplTraitContext::Disallowed),
}) bounds: bounds.iter().filter_map(|bound| match *bound {
}) // Ignore `?Trait` bounds.
// Tthey were copied into type parameters already.
TraitTyParamBound(_, TraitBoundModifier::Maybe) => None,
_ => Some(this.lower_ty_param_bound(
bound, ImplTraitContext::Disallowed))
}).collect(),
span,
})
}
)
} }
WherePredicate::RegionPredicate(WhereRegionPredicate{ ref lifetime, WherePredicate::RegionPredicate(WhereRegionPredicate{ ref lifetime,
ref bounds, ref bounds,
@ -1761,12 +1795,19 @@ impl<'a> LoweringContext<'a> {
p: &PolyTraitRef, p: &PolyTraitRef,
itctx: ImplTraitContext) itctx: ImplTraitContext)
-> hir::PolyTraitRef { -> hir::PolyTraitRef {
let bound_lifetimes = self.lower_lifetime_defs(&p.bound_lifetimes); let bound_generic_params = self.lower_generic_params(&p.bound_generic_params, &NodeMap());
let trait_ref = self.with_parent_impl_lifetime_defs(&bound_lifetimes, let trait_ref = self.with_parent_impl_lifetime_defs(
|this| this.lower_trait_ref(&p.trait_ref, itctx)); &bound_generic_params.iter()
.filter_map(|p| match *p {
hir::GenericParam::Lifetime(ref ld) => Some(ld.clone()),
_ => None,
})
.collect::<Vec<_>>(),
|this| this.lower_trait_ref(&p.trait_ref, itctx),
);
hir::PolyTraitRef { hir::PolyTraitRef {
bound_lifetimes, bound_generic_params,
trait_ref, trait_ref,
span: p.span, span: p.span,
} }
@ -1945,11 +1986,19 @@ impl<'a> LoweringContext<'a> {
}); });
let new_impl_items = self.with_in_scope_lifetime_defs( let new_impl_items = self.with_in_scope_lifetime_defs(
&ast_generics.lifetimes, |this| { &ast_generics.params
impl_items.iter() .iter()
.map(|item| this.lower_impl_item_ref(item)) .filter_map(|p| match *p {
.collect() GenericParam::Lifetime(ref ld) => Some(ld.clone()),
}); _ => None,
})
.collect::<Vec<_>>(),
|this| {
impl_items.iter()
.map(|item| this.lower_impl_item_ref(item))
.collect()
}
);
hir::ItemImpl(self.lower_unsafety(unsafety), hir::ItemImpl(self.lower_unsafety(unsafety),
@ -3621,7 +3670,7 @@ impl<'a> LoweringContext<'a> {
// Turn trait object paths into `TyTraitObject` instead. // Turn trait object paths into `TyTraitObject` instead.
if let Def::Trait(_) = path.def { if let Def::Trait(_) = path.def {
let principal = hir::PolyTraitRef { let principal = hir::PolyTraitRef {
bound_lifetimes: hir_vec![], bound_generic_params: hir::HirVec::new(),
trait_ref: hir::TraitRef { trait_ref: hir::TraitRef {
path: path.and_then(|path| path), path: path.and_then(|path| path),
ref_id: id.node_id, ref_id: id.node_id,

View file

@ -326,7 +326,7 @@ impl<'a, 'hir> Visitor<'hir> for NodeCollector<'a, 'hir> {
} }
fn visit_generics(&mut self, generics: &'hir Generics) { fn visit_generics(&mut self, generics: &'hir Generics) {
for ty_param in generics.ty_params.iter() { for ty_param in generics.ty_params() {
self.insert(ty_param.id, NodeTyParam(ty_param)); self.insert(ty_param.id, NodeTyParam(ty_param));
} }

View file

@ -183,14 +183,25 @@ impl<'a> visit::Visitor<'a> for DefCollector<'a> {
}); });
} }
fn visit_generics(&mut self, generics: &'a Generics) { fn visit_generic_param(&mut self, param: &'a GenericParam) {
for ty_param in generics.ty_params.iter() { match *param {
self.create_def(ty_param.id, GenericParam::Lifetime(ref lifetime_def) => {
DefPathData::TypeParam(ty_param.ident.name.as_str()), self.create_def(
REGULAR_SPACE); lifetime_def.lifetime.id,
DefPathData::LifetimeDef(lifetime_def.lifetime.ident.name.as_str()),
REGULAR_SPACE
);
}
GenericParam::Type(ref ty_param) => {
self.create_def(
ty_param.id,
DefPathData::TypeParam(ty_param.ident.name.as_str()),
REGULAR_SPACE
);
}
} }
visit::walk_generics(self, generics); visit::walk_generic_param(self, param);
} }
fn visit_trait_item(&mut self, ti: &'a TraitItem) { fn visit_trait_item(&mut self, ti: &'a TraitItem) {
@ -268,12 +279,6 @@ impl<'a> visit::Visitor<'a> for DefCollector<'a> {
visit::walk_ty(self, ty); visit::walk_ty(self, ty);
} }
fn visit_lifetime_def(&mut self, def: &'a LifetimeDef) {
self.create_def(def.lifetime.id,
DefPathData::LifetimeDef(def.lifetime.ident.name.as_str()),
REGULAR_SPACE);
}
fn visit_stmt(&mut self, stmt: &'a Stmt) { fn visit_stmt(&mut self, stmt: &'a Stmt) {
match stmt.node { match stmt.node {
StmtKind::Mac(..) => self.visit_macro_invoc(stmt.id, false), StmtKind::Mac(..) => self.visit_macro_invoc(stmt.id, false),

View file

@ -48,6 +48,8 @@ use rustc_data_structures::indexed_vec;
use serialize::{self, Encoder, Encodable, Decoder, Decodable}; use serialize::{self, Encoder, Encodable, Decoder, Decodable};
use std::collections::BTreeMap; use std::collections::BTreeMap;
use std::fmt; use std::fmt;
use std::iter;
use std::slice;
/// HIR doesn't commit to a concrete storage type and has its own alias for a vector. /// HIR doesn't commit to a concrete storage type and has its own alias for a vector.
/// It can be `Vec`, `P<[T]>` or potentially `Box<[T]>`, or some other container with similar /// It can be `Vec`, `P<[T]>` or potentially `Box<[T]>`, or some other container with similar
@ -398,12 +400,67 @@ pub struct TyParam {
pub synthetic: Option<SyntheticTyParamKind>, pub synthetic: Option<SyntheticTyParamKind>,
} }
#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
pub enum GenericParam {
Lifetime(LifetimeDef),
Type(TyParam),
}
impl GenericParam {
pub fn is_lifetime_param(&self) -> bool {
match *self {
GenericParam::Lifetime(_) => true,
_ => false,
}
}
pub fn is_type_param(&self) -> bool {
match *self {
GenericParam::Type(_) => true,
_ => false,
}
}
}
pub trait GenericParamsExt {
fn lifetimes<'a>(&'a self) -> iter::FilterMap<
slice::Iter<GenericParam>,
fn(&GenericParam) -> Option<&LifetimeDef>,
>;
fn ty_params<'a>(&'a self) -> iter::FilterMap<
slice::Iter<GenericParam>,
fn(&GenericParam) -> Option<&TyParam>,
>;
}
impl GenericParamsExt for [GenericParam] {
fn lifetimes<'a>(&'a self) -> iter::FilterMap<
slice::Iter<GenericParam>,
fn(&GenericParam) -> Option<&LifetimeDef>,
> {
self.iter().filter_map(|param| match *param {
GenericParam::Lifetime(ref l) => Some(l),
_ => None,
})
}
fn ty_params<'a>(&'a self) -> iter::FilterMap<
slice::Iter<GenericParam>,
fn(&GenericParam) -> Option<&TyParam>,
> {
self.iter().filter_map(|param| match *param {
GenericParam::Type(ref t) => Some(t),
_ => None,
})
}
}
/// Represents lifetimes and type parameters attached to a declaration /// Represents lifetimes and type parameters attached to a declaration
/// of a function, enum, trait, etc. /// of a function, enum, trait, etc.
#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)] #[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
pub struct Generics { pub struct Generics {
pub lifetimes: HirVec<LifetimeDef>, pub params: HirVec<GenericParam>,
pub ty_params: HirVec<TyParam>,
pub where_clause: WhereClause, pub where_clause: WhereClause,
pub span: Span, pub span: Span,
} }
@ -411,8 +468,7 @@ pub struct Generics {
impl Generics { impl Generics {
pub fn empty() -> Generics { pub fn empty() -> Generics {
Generics { Generics {
lifetimes: HirVec::new(), params: HirVec::new(),
ty_params: HirVec::new(),
where_clause: WhereClause { where_clause: WhereClause {
id: DUMMY_NODE_ID, id: DUMMY_NODE_ID,
predicates: HirVec::new(), predicates: HirVec::new(),
@ -422,15 +478,19 @@ impl Generics {
} }
pub fn is_lt_parameterized(&self) -> bool { pub fn is_lt_parameterized(&self) -> bool {
!self.lifetimes.is_empty() self.params.iter().any(|param| param.is_lifetime_param())
} }
pub fn is_type_parameterized(&self) -> bool { pub fn is_type_parameterized(&self) -> bool {
!self.ty_params.is_empty() self.params.iter().any(|param| param.is_type_param())
} }
pub fn is_parameterized(&self) -> bool { pub fn lifetimes<'a>(&'a self) -> impl Iterator<Item = &'a LifetimeDef> {
self.is_lt_parameterized() || self.is_type_parameterized() self.params.lifetimes()
}
pub fn ty_params<'a>(&'a self) -> impl Iterator<Item = &'a TyParam> {
self.params.ty_params()
} }
} }
@ -450,17 +510,22 @@ impl UnsafeGeneric {
impl Generics { impl Generics {
pub fn carries_unsafe_attr(&self) -> Option<UnsafeGeneric> { pub fn carries_unsafe_attr(&self) -> Option<UnsafeGeneric> {
for r in &self.lifetimes { for param in &self.params {
if r.pure_wrt_drop { match *param {
return Some(UnsafeGeneric::Region(r.clone(), "may_dangle")); GenericParam::Lifetime(ref l) => {
if l.pure_wrt_drop {
return Some(UnsafeGeneric::Region(l.clone(), "may_dangle"));
}
}
GenericParam::Type(ref t) => {
if t.pure_wrt_drop {
return Some(UnsafeGeneric::Type(t.clone(), "may_dangle"));
}
}
} }
} }
for t in &self.ty_params {
if t.pure_wrt_drop { None
return Some(UnsafeGeneric::Type(t.clone(), "may_dangle"));
}
}
return None;
} }
} }
@ -493,8 +558,8 @@ pub enum WherePredicate {
#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)] #[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
pub struct WhereBoundPredicate { pub struct WhereBoundPredicate {
pub span: Span, pub span: Span,
/// Any lifetimes from a `for` binding /// Any generics from a `for` binding
pub bound_lifetimes: HirVec<LifetimeDef>, pub bound_generic_params: HirVec<GenericParam>,
/// The type being bounded /// The type being bounded
pub bounded_ty: P<Ty>, pub bounded_ty: P<Ty>,
/// Trait and lifetime bounds (`Clone+Send+'static`) /// Trait and lifetime bounds (`Clone+Send+'static`)
@ -1475,7 +1540,7 @@ pub enum PrimTy {
pub struct BareFnTy { pub struct BareFnTy {
pub unsafety: Unsafety, pub unsafety: Unsafety,
pub abi: Abi, pub abi: Abi,
pub lifetimes: HirVec<LifetimeDef>, pub generic_params: HirVec<GenericParam>,
pub decl: P<FnDecl>, pub decl: P<FnDecl>,
pub arg_names: HirVec<Spanned<Name>>, pub arg_names: HirVec<Spanned<Name>>,
} }
@ -1733,7 +1798,7 @@ pub struct TraitRef {
#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)] #[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
pub struct PolyTraitRef { pub struct PolyTraitRef {
/// The `'a` in `<'a> Foo<&'a T>` /// The `'a` in `<'a> Foo<&'a T>`
pub bound_lifetimes: HirVec<LifetimeDef>, pub bound_generic_params: HirVec<GenericParam>,
/// The `Foo<&'a T>` in `<'a> Foo<&'a T>` /// The `Foo<&'a T>` in `<'a> Foo<&'a T>`
pub trait_ref: TraitRef, pub trait_ref: TraitRef,

View file

@ -390,16 +390,7 @@ impl<'a> State<'a> {
self.pclose()?; self.pclose()?;
} }
hir::TyBareFn(ref f) => { hir::TyBareFn(ref f) => {
let generics = hir::Generics { self.print_ty_fn(f.abi, f.unsafety, &f.decl, None, &f.generic_params,
lifetimes: f.lifetimes.clone(),
ty_params: hir::HirVec::new(),
where_clause: hir::WhereClause {
id: ast::DUMMY_NODE_ID,
predicates: hir::HirVec::new(),
},
span: syntax_pos::DUMMY_SP,
};
self.print_ty_fn(f.abi, f.unsafety, &f.decl, None, &generics,
&f.arg_names[..])?; &f.arg_names[..])?;
} }
hir::TyPath(ref qpath) => { hir::TyPath(ref qpath) => {
@ -635,15 +626,15 @@ impl<'a> State<'a> {
self.s.word(&ga.asm.as_str())?; self.s.word(&ga.asm.as_str())?;
self.end()? self.end()?
} }
hir::ItemTy(ref ty, ref params) => { hir::ItemTy(ref ty, ref generics) => {
self.ibox(indent_unit)?; self.ibox(indent_unit)?;
self.ibox(0)?; self.ibox(0)?;
self.word_nbsp(&visibility_qualified(&item.vis, "type"))?; self.word_nbsp(&visibility_qualified(&item.vis, "type"))?;
self.print_name(item.name)?; self.print_name(item.name)?;
self.print_generics(params)?; self.print_generic_params(&generics.params)?;
self.end()?; // end the inner ibox self.end()?; // end the inner ibox
self.print_where_clause(&params.where_clause)?; self.print_where_clause(&generics.where_clause)?;
self.s.space()?; self.s.space()?;
self.word_space("=")?; self.word_space("=")?;
self.print_type(&ty)?; self.print_type(&ty)?;
@ -686,8 +677,8 @@ impl<'a> State<'a> {
self.print_unsafety(unsafety)?; self.print_unsafety(unsafety)?;
self.word_nbsp("impl")?; self.word_nbsp("impl")?;
if generics.is_parameterized() { if !generics.params.is_empty() {
self.print_generics(generics)?; self.print_generic_params(&generics.params)?;
self.s.space()?; self.s.space()?;
} }
@ -725,7 +716,7 @@ impl<'a> State<'a> {
self.print_unsafety(unsafety)?; self.print_unsafety(unsafety)?;
self.word_nbsp("trait")?; self.word_nbsp("trait")?;
self.print_name(item.name)?; self.print_name(item.name)?;
self.print_generics(generics)?; self.print_generic_params(&generics.params)?;
let mut real_bounds = Vec::with_capacity(bounds.len()); let mut real_bounds = Vec::with_capacity(bounds.len());
for b in bounds.iter() { for b in bounds.iter() {
if let TraitTyParamBound(ref ptr, hir::TraitBoundModifier::Maybe) = *b { if let TraitTyParamBound(ref ptr, hir::TraitBoundModifier::Maybe) = *b {
@ -750,7 +741,7 @@ impl<'a> State<'a> {
self.print_visibility(&item.vis)?; self.print_visibility(&item.vis)?;
self.word_nbsp("trait")?; self.word_nbsp("trait")?;
self.print_name(item.name)?; self.print_name(item.name)?;
self.print_generics(generics)?; self.print_generic_params(&generics.params)?;
let mut real_bounds = Vec::with_capacity(bounds.len()); let mut real_bounds = Vec::with_capacity(bounds.len());
// FIXME(durka) this seems to be some quite outdated syntax // FIXME(durka) this seems to be some quite outdated syntax
for b in bounds.iter() { for b in bounds.iter() {
@ -775,25 +766,20 @@ impl<'a> State<'a> {
self.print_path(&t.path, false) self.print_path(&t.path, false)
} }
fn print_formal_lifetime_list(&mut self, lifetimes: &[hir::LifetimeDef]) -> io::Result<()> { fn print_formal_generic_params(
if !lifetimes.is_empty() { &mut self,
self.s.word("for<")?; generic_params: &[hir::GenericParam]
let mut comma = false; ) -> io::Result<()> {
for lifetime_def in lifetimes { if !generic_params.is_empty() {
if comma { self.s.word("for")?;
self.word_space(",")? self.print_generic_params(generic_params)?;
}
self.print_lifetime_def(lifetime_def)?;
comma = true;
}
self.s.word(">")?;
self.nbsp()?; self.nbsp()?;
} }
Ok(()) Ok(())
} }
fn print_poly_trait_ref(&mut self, t: &hir::PolyTraitRef) -> io::Result<()> { fn print_poly_trait_ref(&mut self, t: &hir::PolyTraitRef) -> io::Result<()> {
self.print_formal_lifetime_list(&t.bound_lifetimes)?; self.print_formal_generic_params(&t.bound_generic_params)?;
self.print_trait_ref(&t.trait_ref) self.print_trait_ref(&t.trait_ref)
} }
@ -806,7 +792,7 @@ impl<'a> State<'a> {
-> io::Result<()> { -> io::Result<()> {
self.head(&visibility_qualified(visibility, "enum"))?; self.head(&visibility_qualified(visibility, "enum"))?;
self.print_name(name)?; self.print_name(name)?;
self.print_generics(generics)?; self.print_generic_params(&generics.params)?;
self.print_where_clause(&generics.where_clause)?; self.print_where_clause(&generics.where_clause)?;
self.s.space()?; self.s.space()?;
self.print_variants(&enum_definition.variants, span) self.print_variants(&enum_definition.variants, span)
@ -859,7 +845,7 @@ impl<'a> State<'a> {
print_finalizer: bool) print_finalizer: bool)
-> io::Result<()> { -> io::Result<()> {
self.print_name(name)?; self.print_name(name)?;
self.print_generics(generics)?; self.print_generic_params(&generics.params)?;
if !struct_def.is_struct() { if !struct_def.is_struct() {
if struct_def.is_tuple() { if struct_def.is_tuple() {
self.popen()?; self.popen()?;
@ -1941,7 +1927,7 @@ impl<'a> State<'a> {
self.nbsp()?; self.nbsp()?;
self.print_name(name)?; self.print_name(name)?;
} }
self.print_generics(generics)?; self.print_generic_params(&generics.params)?;
self.popen()?; self.popen()?;
let mut i = 0; let mut i = 0;
@ -2056,31 +2042,19 @@ impl<'a> State<'a> {
Ok(()) Ok(())
} }
pub fn print_generics(&mut self, generics: &hir::Generics) -> io::Result<()> { pub fn print_generic_params(&mut self, generic_params: &[hir::GenericParam]) -> io::Result<()> {
let total = generics.lifetimes.len() + generics.ty_params.len(); if !generic_params.is_empty() {
if total == 0 { self.s.word("<")?;
return Ok(());
self.commasep(Inconsistent, generic_params, |s, param| {
match *param {
hir::GenericParam::Lifetime(ref ld) => s.print_lifetime_def(ld),
hir::GenericParam::Type(ref tp) => s.print_ty_param(tp),
}
})?;
self.s.word(">")?;
} }
self.s.word("<")?;
let mut ints = Vec::new();
for i in 0..total {
ints.push(i);
}
self.commasep(Inconsistent, &ints[..], |s, &idx| {
if idx < generics.lifetimes.len() {
let lifetime = &generics.lifetimes[idx];
s.print_lifetime_def(lifetime)
} else {
let idx = idx - generics.lifetimes.len();
let param = &generics.ty_params[idx];
s.print_ty_param(param)
}
})?;
self.s.word(">")?;
Ok(()) Ok(())
} }
@ -2111,11 +2085,13 @@ impl<'a> State<'a> {
} }
match predicate { match predicate {
&hir::WherePredicate::BoundPredicate(hir::WhereBoundPredicate{ref bound_lifetimes, &hir::WherePredicate::BoundPredicate(hir::WhereBoundPredicate {
ref bounded_ty, ref bound_generic_params,
ref bounds, ref bounded_ty,
..}) => { ref bounds,
self.print_formal_lifetime_list(bound_lifetimes)?; ..
}) => {
self.print_formal_generic_params(bound_generic_params)?;
self.print_type(&bounded_ty)?; self.print_type(&bounded_ty)?;
self.print_bounds(":", bounds)?; self.print_bounds(":", bounds)?;
} }
@ -2184,17 +2160,16 @@ impl<'a> State<'a> {
unsafety: hir::Unsafety, unsafety: hir::Unsafety,
decl: &hir::FnDecl, decl: &hir::FnDecl,
name: Option<ast::Name>, name: Option<ast::Name>,
generics: &hir::Generics, generic_params: &[hir::GenericParam],
arg_names: &[Spanned<ast::Name>]) arg_names: &[Spanned<ast::Name>])
-> io::Result<()> { -> io::Result<()> {
self.ibox(indent_unit)?; self.ibox(indent_unit)?;
if !generics.lifetimes.is_empty() || !generics.ty_params.is_empty() { if !generic_params.is_empty() {
self.s.word("for")?; self.s.word("for")?;
self.print_generics(generics)?; self.print_generic_params(generic_params)?;
} }
let generics = hir::Generics { let generics = hir::Generics {
lifetimes: hir::HirVec::new(), params: hir::HirVec::new(),
ty_params: hir::HirVec::new(),
where_clause: hir::WhereClause { where_clause: hir::WhereClause {
id: ast::DUMMY_NODE_ID, id: ast::DUMMY_NODE_ID,
predicates: hir::HirVec::new(), predicates: hir::HirVec::new(),

View file

@ -200,9 +200,13 @@ impl_stable_hash_for!(struct hir::TyParam {
synthetic synthetic
}); });
impl_stable_hash_for!(enum hir::GenericParam {
Lifetime(lifetime_def),
Type(ty_param)
});
impl_stable_hash_for!(struct hir::Generics { impl_stable_hash_for!(struct hir::Generics {
lifetimes, params,
ty_params,
where_clause, where_clause,
span span
}); });
@ -224,7 +228,7 @@ impl_stable_hash_for!(enum hir::WherePredicate {
impl_stable_hash_for!(struct hir::WhereBoundPredicate { impl_stable_hash_for!(struct hir::WhereBoundPredicate {
span, span,
bound_lifetimes, bound_generic_params,
bounded_ty, bounded_ty,
bounds bounds
}); });
@ -291,7 +295,7 @@ impl_stable_hash_for!(enum hir::PrimTy {
impl_stable_hash_for!(struct hir::BareFnTy { impl_stable_hash_for!(struct hir::BareFnTy {
unsafety, unsafety,
abi, abi,
lifetimes, generic_params,
decl, decl,
arg_names arg_names
}); });
@ -345,7 +349,7 @@ impl<'gcx> HashStable<StableHashingContext<'gcx>> for hir::TraitRef {
impl_stable_hash_for!(struct hir::PolyTraitRef { impl_stable_hash_for!(struct hir::PolyTraitRef {
bound_lifetimes, bound_generic_params,
trait_ref, trait_ref,
span span
}); });

View file

@ -783,6 +783,11 @@ impl<'a, 'tcx> hir_visit::Visitor<'tcx> for LateContext<'a, 'tcx> {
hir_visit::walk_decl(self, d); hir_visit::walk_decl(self, d);
} }
fn visit_generic_param(&mut self, p: &'tcx hir::GenericParam) {
run_lints!(self, check_generic_param, late_passes, p);
hir_visit::walk_generic_param(self, p);
}
fn visit_generics(&mut self, g: &'tcx hir::Generics) { fn visit_generics(&mut self, g: &'tcx hir::Generics) {
run_lints!(self, check_generics, late_passes, g); run_lints!(self, check_generics, late_passes, g);
hir_visit::walk_generics(self, g); hir_visit::walk_generics(self, g);
@ -819,11 +824,6 @@ impl<'a, 'tcx> hir_visit::Visitor<'tcx> for LateContext<'a, 'tcx> {
hir_visit::walk_lifetime(self, lt); hir_visit::walk_lifetime(self, lt);
} }
fn visit_lifetime_def(&mut self, lt: &'tcx hir::LifetimeDef) {
run_lints!(self, check_lifetime_def, late_passes, lt);
hir_visit::walk_lifetime_def(self, lt);
}
fn visit_path(&mut self, p: &'tcx hir::Path, id: ast::NodeId) { fn visit_path(&mut self, p: &'tcx hir::Path, id: ast::NodeId) {
run_lints!(self, check_path, late_passes, p, id); run_lints!(self, check_path, late_passes, p, id);
hir_visit::walk_path(self, p); hir_visit::walk_path(self, p);
@ -945,6 +945,11 @@ impl<'a> ast_visit::Visitor<'a> for EarlyContext<'a> {
run_lints!(self, check_expr_post, early_passes, e); run_lints!(self, check_expr_post, early_passes, e);
} }
fn visit_generic_param(&mut self, param: &'a ast::GenericParam) {
run_lints!(self, check_generic_param, early_passes, param);
ast_visit::walk_generic_param(self, param);
}
fn visit_generics(&mut self, g: &'a ast::Generics) { fn visit_generics(&mut self, g: &'a ast::Generics) {
run_lints!(self, check_generics, early_passes, g); run_lints!(self, check_generics, early_passes, g);
ast_visit::walk_generics(self, g); ast_visit::walk_generics(self, g);
@ -971,10 +976,6 @@ impl<'a> ast_visit::Visitor<'a> for EarlyContext<'a> {
self.check_id(lt.id); self.check_id(lt.id);
} }
fn visit_lifetime_def(&mut self, lt: &'a ast::LifetimeDef) {
run_lints!(self, check_lifetime_def, early_passes, lt);
}
fn visit_path(&mut self, p: &'a ast::Path, id: ast::NodeId) { fn visit_path(&mut self, p: &'a ast::Path, id: ast::NodeId) {
run_lints!(self, check_path, early_passes, p, id); run_lints!(self, check_path, early_passes, p, id);
self.check_id(id); self.check_id(id);

View file

@ -155,6 +155,7 @@ pub trait LateLintPass<'a, 'tcx>: LintPass {
fn check_expr(&mut self, _: &LateContext<'a, 'tcx>, _: &'tcx hir::Expr) { } fn check_expr(&mut self, _: &LateContext<'a, 'tcx>, _: &'tcx hir::Expr) { }
fn check_expr_post(&mut self, _: &LateContext<'a, 'tcx>, _: &'tcx hir::Expr) { } fn check_expr_post(&mut self, _: &LateContext<'a, 'tcx>, _: &'tcx hir::Expr) { }
fn check_ty(&mut self, _: &LateContext<'a, 'tcx>, _: &'tcx hir::Ty) { } fn check_ty(&mut self, _: &LateContext<'a, 'tcx>, _: &'tcx hir::Ty) { }
fn check_generic_param(&mut self, _: &LateContext<'a, 'tcx>, _: &'tcx hir::GenericParam) { }
fn check_generics(&mut self, _: &LateContext<'a, 'tcx>, _: &'tcx hir::Generics) { } fn check_generics(&mut self, _: &LateContext<'a, 'tcx>, _: &'tcx hir::Generics) { }
fn check_fn(&mut self, fn check_fn(&mut self,
_: &LateContext<'a, 'tcx>, _: &LateContext<'a, 'tcx>,
@ -196,7 +197,6 @@ pub trait LateLintPass<'a, 'tcx>: LintPass {
_: &'tcx hir::Variant, _: &'tcx hir::Variant,
_: &'tcx hir::Generics) { } _: &'tcx hir::Generics) { }
fn check_lifetime(&mut self, _: &LateContext<'a, 'tcx>, _: &'tcx hir::Lifetime) { } fn check_lifetime(&mut self, _: &LateContext<'a, 'tcx>, _: &'tcx hir::Lifetime) { }
fn check_lifetime_def(&mut self, _: &LateContext<'a, 'tcx>, _: &'tcx hir::LifetimeDef) { }
fn check_path(&mut self, _: &LateContext<'a, 'tcx>, _: &'tcx hir::Path, _: ast::NodeId) { } fn check_path(&mut self, _: &LateContext<'a, 'tcx>, _: &'tcx hir::Path, _: ast::NodeId) { }
fn check_attribute(&mut self, _: &LateContext<'a, 'tcx>, _: &'tcx ast::Attribute) { } fn check_attribute(&mut self, _: &LateContext<'a, 'tcx>, _: &'tcx ast::Attribute) { }
@ -227,6 +227,7 @@ pub trait EarlyLintPass: LintPass {
fn check_expr(&mut self, _: &EarlyContext, _: &ast::Expr) { } fn check_expr(&mut self, _: &EarlyContext, _: &ast::Expr) { }
fn check_expr_post(&mut self, _: &EarlyContext, _: &ast::Expr) { } fn check_expr_post(&mut self, _: &EarlyContext, _: &ast::Expr) { }
fn check_ty(&mut self, _: &EarlyContext, _: &ast::Ty) { } fn check_ty(&mut self, _: &EarlyContext, _: &ast::Ty) { }
fn check_generic_param(&mut self, _: &EarlyContext, _: &ast::GenericParam) { }
fn check_generics(&mut self, _: &EarlyContext, _: &ast::Generics) { } fn check_generics(&mut self, _: &EarlyContext, _: &ast::Generics) { }
fn check_fn(&mut self, _: &EarlyContext, fn check_fn(&mut self, _: &EarlyContext,
_: ast_visit::FnKind, _: &ast::FnDecl, _: Span, _: ast::NodeId) { } _: ast_visit::FnKind, _: &ast::FnDecl, _: Span, _: ast::NodeId) { }
@ -244,7 +245,6 @@ pub trait EarlyLintPass: LintPass {
fn check_variant(&mut self, _: &EarlyContext, _: &ast::Variant, _: &ast::Generics) { } fn check_variant(&mut self, _: &EarlyContext, _: &ast::Variant, _: &ast::Generics) { }
fn check_variant_post(&mut self, _: &EarlyContext, _: &ast::Variant, _: &ast::Generics) { } fn check_variant_post(&mut self, _: &EarlyContext, _: &ast::Variant, _: &ast::Generics) { }
fn check_lifetime(&mut self, _: &EarlyContext, _: &ast::Lifetime) { } fn check_lifetime(&mut self, _: &EarlyContext, _: &ast::Lifetime) { }
fn check_lifetime_def(&mut self, _: &EarlyContext, _: &ast::LifetimeDef) { }
fn check_path(&mut self, _: &EarlyContext, _: &ast::Path, _: ast::NodeId) { } fn check_path(&mut self, _: &EarlyContext, _: &ast::Path, _: ast::NodeId) { }
fn check_attribute(&mut self, _: &EarlyContext, _: &ast::Attribute) { } fn check_attribute(&mut self, _: &EarlyContext, _: &ast::Attribute) { }

View file

@ -37,7 +37,7 @@ use hir::intravisit;
// Returns true if the given set of generics implies that the item it's // Returns true if the given set of generics implies that the item it's
// associated with must be inlined. // associated with must be inlined.
fn generics_require_inlining(generics: &hir::Generics) -> bool { fn generics_require_inlining(generics: &hir::Generics) -> bool {
!generics.ty_params.is_empty() generics.params.iter().any(|param| param.is_type_param())
} }
// Returns true if the given item must be inlined because it may be // Returns true if the given item must be inlined because it may be

View file

@ -33,7 +33,7 @@ use util::nodemap::{DefIdMap, FxHashMap, FxHashSet, NodeMap, NodeSet};
use std::slice; use std::slice;
use rustc::lint; use rustc::lint;
use hir; use hir::{self, GenericParamsExt};
use hir::intravisit::{self, NestedVisitorMap, Visitor}; use hir::intravisit::{self, NestedVisitorMap, Visitor};
/// The origin of a named lifetime definition. /// The origin of a named lifetime definition.
@ -491,19 +491,17 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
} else { } else {
0 0
}; };
let lifetimes = generics let lifetimes = generics.lifetimes()
.lifetimes
.iter()
.map(|def| Region::early(&self.tcx.hir, &mut index, def)) .map(|def| Region::early(&self.tcx.hir, &mut index, def))
.collect(); .collect();
let next_early_index = index + generics.ty_params.len() as u32; let next_early_index = index + generics.ty_params().count() as u32;
let scope = Scope::Binder { let scope = Scope::Binder {
lifetimes, lifetimes,
next_early_index, next_early_index,
s: ROOT_SCOPE, s: ROOT_SCOPE,
}; };
self.with(scope, |old_scope, this| { self.with(scope, |old_scope, this| {
this.check_lifetime_defs(old_scope, &generics.lifetimes); this.check_lifetime_params(old_scope, &generics.params);
intravisit::walk_item(this, item); intravisit::walk_item(this, item);
}); });
} }
@ -537,8 +535,8 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
let was_in_fn_syntax = self.is_in_fn_syntax; let was_in_fn_syntax = self.is_in_fn_syntax;
self.is_in_fn_syntax = true; self.is_in_fn_syntax = true;
let scope = Scope::Binder { let scope = Scope::Binder {
lifetimes: c.lifetimes lifetimes: c.generic_params
.iter() .lifetimes()
.map(|def| Region::late(&self.tcx.hir, def)) .map(|def| Region::late(&self.tcx.hir, def))
.collect(), .collect(),
s: self.scope, s: self.scope,
@ -547,7 +545,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
self.with(scope, |old_scope, this| { self.with(scope, |old_scope, this| {
// a bare fn has no bounds, so everything // a bare fn has no bounds, so everything
// contained within is scoped within its binder. // contained within is scoped within its binder.
this.check_lifetime_defs(old_scope, &c.lifetimes); this.check_lifetime_params(old_scope, &c.generic_params);
intravisit::walk_ty(this, ty); intravisit::walk_ty(this, ty);
}); });
self.is_in_fn_syntax = was_in_fn_syntax; self.is_in_fn_syntax = was_in_fn_syntax;
@ -621,7 +619,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
let mut elision = None; let mut elision = None;
let mut lifetimes = FxHashMap(); let mut lifetimes = FxHashMap();
for lt_def in &generics.lifetimes { for lt_def in generics.lifetimes() {
let (lt_name, region) = Region::early(&self.tcx.hir, &mut index, &lt_def); let (lt_name, region) = Region::early(&self.tcx.hir, &mut index, &lt_def);
if let hir::LifetimeName::Underscore = lt_name { if let hir::LifetimeName::Underscore = lt_name {
// Pick the elided lifetime "definition" if one exists and use it to make an // Pick the elided lifetime "definition" if one exists and use it to make an
@ -632,7 +630,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
} }
} }
let next_early_index = index + generics.ty_params.len() as u32; let next_early_index = index + generics.ty_params().count() as u32;
if let Some(elision_region) = elision { if let Some(elision_region) = elision {
let scope = Scope::Elision { let scope = Scope::Elision {
@ -678,11 +676,11 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
let generics = &trait_item.generics; let generics = &trait_item.generics;
let mut index = self.next_early_index(); let mut index = self.next_early_index();
debug!("visit_ty: index = {}", index); debug!("visit_ty: index = {}", index);
let lifetimes = generics.lifetimes.iter() let lifetimes = generics.lifetimes()
.map(|lt_def| Region::early(&self.tcx.hir, &mut index, lt_def)) .map(|lt_def| Region::early(&self.tcx.hir, &mut index, lt_def))
.collect(); .collect();
let next_early_index = index + generics.ty_params.len() as u32; let next_early_index = index + generics.ty_params().count() as u32;
let scope = Scope::Binder { lifetimes, next_early_index, s: self.scope }; let scope = Scope::Binder { lifetimes, next_early_index, s: self.scope };
self.with(scope, |_old_scope, this| { self.with(scope, |_old_scope, this| {
this.visit_generics(generics); this.visit_generics(generics);
@ -696,7 +694,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
}, },
Const(_, _) => { Const(_, _) => {
// Only methods and types support generics. // Only methods and types support generics.
assert!(!trait_item.generics.is_parameterized()); assert!(trait_item.generics.params.is_empty());
intravisit::walk_trait_item(self, trait_item); intravisit::walk_trait_item(self, trait_item);
}, },
} }
@ -718,11 +716,11 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
let generics = &impl_item.generics; let generics = &impl_item.generics;
let mut index = self.next_early_index(); let mut index = self.next_early_index();
debug!("visit_ty: index = {}", index); debug!("visit_ty: index = {}", index);
let lifetimes = generics.lifetimes.iter() let lifetimes = generics.lifetimes()
.map(|lt_def| Region::early(&self.tcx.hir, &mut index, lt_def)) .map(|lt_def| Region::early(&self.tcx.hir, &mut index, lt_def))
.collect(); .collect();
let next_early_index = index + generics.ty_params.len() as u32; let next_early_index = index + generics.ty_params().count() as u32;
let scope = Scope::Binder { lifetimes, next_early_index, s: self.scope }; let scope = Scope::Binder { lifetimes, next_early_index, s: self.scope };
self.with(scope, |_old_scope, this| { self.with(scope, |_old_scope, this| {
this.visit_generics(generics); this.visit_generics(generics);
@ -731,7 +729,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
}, },
Const(_, _) => { Const(_, _) => {
// Only methods and types support generics. // Only methods and types support generics.
assert!(!impl_item.generics.is_parameterized()); assert!(impl_item.generics.params.is_empty());
intravisit::walk_impl_item(self, impl_item); intravisit::walk_impl_item(self, impl_item);
}, },
} }
@ -767,8 +765,11 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
} }
fn visit_generics(&mut self, generics: &'tcx hir::Generics) { fn visit_generics(&mut self, generics: &'tcx hir::Generics) {
check_mixed_explicit_and_in_band_defs(self.tcx, &generics.lifetimes); check_mixed_explicit_and_in_band_defs(
for ty_param in generics.ty_params.iter() { self.tcx,
&generics.lifetimes().cloned().collect::<Vec<_>>()
);
for ty_param in generics.ty_params() {
walk_list!(self, visit_ty_param_bound, &ty_param.bounds); walk_list!(self, visit_ty_param_bound, &ty_param.bounds);
if let Some(ref ty) = ty_param.default { if let Some(ref ty) = ty_param.default {
self.visit_ty(&ty); self.visit_ty(&ty);
@ -779,22 +780,21 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
&hir::WherePredicate::BoundPredicate(hir::WhereBoundPredicate { &hir::WherePredicate::BoundPredicate(hir::WhereBoundPredicate {
ref bounded_ty, ref bounded_ty,
ref bounds, ref bounds,
ref bound_lifetimes, ref bound_generic_params,
.. ..
}) => { }) => {
if !bound_lifetimes.is_empty() { if bound_generic_params.iter().any(|p| p.is_lifetime_param()) {
self.trait_ref_hack = true; self.trait_ref_hack = true;
let next_early_index = self.next_early_index(); let next_early_index = self.next_early_index();
let scope = Scope::Binder { let scope = Scope::Binder {
lifetimes: bound_lifetimes lifetimes: bound_generic_params.lifetimes()
.iter()
.map(|def| Region::late(&self.tcx.hir, def)) .map(|def| Region::late(&self.tcx.hir, def))
.collect(), .collect(),
s: self.scope, s: self.scope,
next_early_index, next_early_index,
}; };
let result = self.with(scope, |old_scope, this| { let result = self.with(scope, |old_scope, this| {
this.check_lifetime_defs(old_scope, bound_lifetimes); this.check_lifetime_params(old_scope, &bound_generic_params);
this.visit_ty(&bounded_ty); this.visit_ty(&bounded_ty);
walk_list!(this, visit_ty_param_bound, bounds); walk_list!(this, visit_ty_param_bound, bounds);
}); });
@ -834,7 +834,9 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
) { ) {
debug!("visit_poly_trait_ref trait_ref={:?}", trait_ref); debug!("visit_poly_trait_ref trait_ref={:?}", trait_ref);
if !self.trait_ref_hack || !trait_ref.bound_lifetimes.is_empty() { if !self.trait_ref_hack ||
trait_ref.bound_generic_params.iter().any(|p| p.is_lifetime_param())
{
if self.trait_ref_hack { if self.trait_ref_hack {
span_err!( span_err!(
self.tcx.sess, self.tcx.sess,
@ -845,19 +847,16 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
} }
let next_early_index = self.next_early_index(); let next_early_index = self.next_early_index();
let scope = Scope::Binder { let scope = Scope::Binder {
lifetimes: trait_ref lifetimes: trait_ref.bound_generic_params
.bound_lifetimes .lifetimes()
.iter()
.map(|def| Region::late(&self.tcx.hir, def)) .map(|def| Region::late(&self.tcx.hir, def))
.collect(), .collect(),
s: self.scope, s: self.scope,
next_early_index, next_early_index,
}; };
self.with(scope, |old_scope, this| { self.with(scope, |old_scope, this| {
this.check_lifetime_defs(old_scope, &trait_ref.bound_lifetimes); this.check_lifetime_params(old_scope, &trait_ref.bound_generic_params);
for lifetime in &trait_ref.bound_lifetimes { walk_list!(this, visit_generic_param, &trait_ref.bound_generic_params);
this.visit_lifetime_def(lifetime);
}
this.visit_trait_ref(&trait_ref.trait_ref) this.visit_trait_ref(&trait_ref.trait_ref)
}) })
} else { } else {
@ -1087,8 +1086,9 @@ fn compute_object_lifetime_defaults(
.map(|set| match *set { .map(|set| match *set {
Set1::Empty => "BaseDefault".to_string(), Set1::Empty => "BaseDefault".to_string(),
Set1::One(Region::Static) => "'static".to_string(), Set1::One(Region::Static) => "'static".to_string(),
Set1::One(Region::EarlyBound(i, _, _)) => generics.lifetimes Set1::One(Region::EarlyBound(i, _, _)) => generics.lifetimes()
[i as usize] .nth(i as usize)
.unwrap()
.lifetime .lifetime
.name .name
.name() .name()
@ -1124,9 +1124,7 @@ fn object_lifetime_defaults_for_item(
} }
} }
generics generics.ty_params()
.ty_params
.iter()
.map(|param| { .map(|param| {
let mut set = Set1::Empty; let mut set = Set1::Empty;
@ -1142,7 +1140,7 @@ fn object_lifetime_defaults_for_item(
// Ignore `for<'a> type: ...` as they can change what // Ignore `for<'a> type: ...` as they can change what
// lifetimes mean (although we could "just" handle it). // lifetimes mean (although we could "just" handle it).
if !data.bound_lifetimes.is_empty() { if !data.bound_generic_params.is_empty() {
continue; continue;
} }
@ -1163,8 +1161,7 @@ fn object_lifetime_defaults_for_item(
Set1::One(Region::Static) Set1::One(Region::Static)
} else { } else {
generics generics
.lifetimes .lifetimes()
.iter()
.enumerate() .enumerate()
.find(|&(_, def)| def.lifetime.name == name) .find(|&(_, def)| def.lifetime.name == name)
.map_or(Set1::Many, |(i, def)| { .map_or(Set1::Many, |(i, def)| {
@ -1283,15 +1280,14 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
match parent.node { match parent.node {
hir::ItemTrait(_, _, ref generics, ..) hir::ItemTrait(_, _, ref generics, ..)
| hir::ItemImpl(_, _, _, ref generics, ..) => { | hir::ItemImpl(_, _, _, ref generics, ..) => {
index += (generics.lifetimes.len() + generics.ty_params.len()) as u32; index += generics.params.len() as u32;
} }
_ => {} _ => {}
} }
} }
let lifetimes = generics let lifetimes = generics
.lifetimes .lifetimes()
.iter()
.map(|def| { .map(|def| {
if self.map.late_bound.contains(&def.lifetime.id) { if self.map.late_bound.contains(&def.lifetime.id) {
Region::late(&self.tcx.hir, def) Region::late(&self.tcx.hir, def)
@ -1301,7 +1297,7 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
}) })
.collect(); .collect();
let next_early_index = index + generics.ty_params.len() as u32; let next_early_index = index + generics.ty_params().count() as u32;
let scope = Scope::Binder { let scope = Scope::Binder {
lifetimes, lifetimes,
@ -1309,7 +1305,7 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
s: self.scope, s: self.scope,
}; };
self.with(scope, move |old_scope, this| { self.with(scope, move |old_scope, this| {
this.check_lifetime_defs(old_scope, &generics.lifetimes); this.check_lifetime_params(old_scope, &generics.params);
this.hack(walk); // FIXME(#37666) workaround in place of `walk(this)` this.hack(walk); // FIXME(#37666) workaround in place of `walk(this)`
}); });
} }
@ -1769,6 +1765,16 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
} }
} }
fn visit_generic_param(&mut self, param: &hir::GenericParam) {
if let hir::GenericParam::Lifetime(ref lifetime_def) = *param {
for l in &lifetime_def.bounds {
self.visit_lifetime(l);
}
}
intravisit::walk_generic_param(self, param);
}
fn visit_poly_trait_ref( fn visit_poly_trait_ref(
&mut self, &mut self,
trait_ref: &hir::PolyTraitRef, trait_ref: &hir::PolyTraitRef,
@ -1779,12 +1785,6 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
self.binder_depth -= 1; self.binder_depth -= 1;
} }
fn visit_lifetime_def(&mut self, lifetime_def: &hir::LifetimeDef) {
for l in &lifetime_def.bounds {
self.visit_lifetime(l);
}
}
fn visit_lifetime(&mut self, lifetime_ref: &hir::Lifetime) { fn visit_lifetime(&mut self, lifetime_ref: &hir::Lifetime) {
if let Some(&lifetime) = self.map.defs.get(&lifetime_ref.id) { if let Some(&lifetime) = self.map.defs.get(&lifetime_ref.id) {
match lifetime { match lifetime {
@ -1980,11 +1980,9 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
self.insert_lifetime(lifetime_ref, lifetime.shifted(late_depth)); self.insert_lifetime(lifetime_ref, lifetime.shifted(late_depth));
} }
fn check_lifetime_defs(&mut self, old_scope: ScopeRef, lifetimes: &'tcx [hir::LifetimeDef]) { fn check_lifetime_params(&mut self, old_scope: ScopeRef, params: &'tcx [hir::GenericParam]) {
for i in 0..lifetimes.len() { for (i, lifetime_i) in params.lifetimes().enumerate() {
let lifetime_i = &lifetimes[i]; for lifetime in params.lifetimes() {
for lifetime in lifetimes {
match lifetime.lifetime.name { match lifetime.lifetime.name {
hir::LifetimeName::Static | hir::LifetimeName::Underscore => { hir::LifetimeName::Static | hir::LifetimeName::Underscore => {
let lifetime = lifetime.lifetime; let lifetime = lifetime.lifetime;
@ -2007,9 +2005,7 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
} }
// It is a hard error to shadow a lifetime within the same scope. // It is a hard error to shadow a lifetime within the same scope.
for j in i + 1..lifetimes.len() { for lifetime_j in params.lifetimes().skip(i + 1) {
let lifetime_j = &lifetimes[j];
if lifetime_i.lifetime.name == lifetime_j.lifetime.name { if lifetime_i.lifetime.name == lifetime_j.lifetime.name {
struct_span_err!( struct_span_err!(
self.tcx.sess, self.tcx.sess,
@ -2200,24 +2196,30 @@ fn insert_late_bound_lifetimes(
let mut appears_in_where_clause = AllCollector { let mut appears_in_where_clause = AllCollector {
regions: FxHashSet(), regions: FxHashSet(),
}; };
for ty_param in generics.ty_params.iter() {
walk_list!( for param in &generics.params {
&mut appears_in_where_clause, match *param {
visit_ty_param_bound, hir::GenericParam::Lifetime(ref lifetime_def) => {
&ty_param.bounds if !lifetime_def.bounds.is_empty() {
); // `'a: 'b` means both `'a` and `'b` are referenced
appears_in_where_clause.visit_generic_param(param);
}
}
hir::GenericParam::Type(ref ty_param) => {
walk_list!(
&mut appears_in_where_clause,
visit_ty_param_bound,
&ty_param.bounds
);
}
}
} }
walk_list!( walk_list!(
&mut appears_in_where_clause, &mut appears_in_where_clause,
visit_where_predicate, visit_where_predicate,
&generics.where_clause.predicates &generics.where_clause.predicates
); );
for lifetime_def in &generics.lifetimes {
if !lifetime_def.bounds.is_empty() {
// `'a: 'b` means both `'a` and `'b` are referenced
appears_in_where_clause.visit_lifetime_def(lifetime_def);
}
}
debug!( debug!(
"insert_late_bound_lifetimes: appears_in_where_clause={:?}", "insert_late_bound_lifetimes: appears_in_where_clause={:?}",
@ -2228,7 +2230,7 @@ fn insert_late_bound_lifetimes(
// - appear in the inputs // - appear in the inputs
// - do not appear in the where-clauses // - do not appear in the where-clauses
// - are not implicitly captured by `impl Trait` // - are not implicitly captured by `impl Trait`
for lifetime in &generics.lifetimes { for lifetime in generics.lifetimes() {
let name = lifetime.lifetime.name; let name = lifetime.lifetime.name;
// appears in the where clauses? early-bound. // appears in the where clauses? early-bound.

View file

@ -126,8 +126,8 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for NonCamelCaseTypes {
self.check_case(cx, "variant", v.node.name, v.span); self.check_case(cx, "variant", v.node.name, v.span);
} }
fn check_generics(&mut self, cx: &LateContext, it: &hir::Generics) { fn check_generic_param(&mut self, cx: &LateContext, param: &hir::GenericParam) {
for gen in it.ty_params.iter() { if let hir::GenericParam::Type(ref gen) = *param {
self.check_case(cx, "type parameter", gen.name, gen.span); self.check_case(cx, "type parameter", gen.name, gen.span);
} }
} }
@ -232,6 +232,17 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for NonSnakeCase {
} }
} }
fn check_generic_param(&mut self, cx: &LateContext, param: &hir::GenericParam) {
if let hir::GenericParam::Lifetime(ref ld) = *param {
self.check_snake_case(
cx,
"lifetime",
&ld.lifetime.name.name().as_str(),
Some(ld.lifetime.span)
);
}
}
fn check_fn(&mut self, fn check_fn(&mut self,
cx: &LateContext, cx: &LateContext,
fk: FnKind, fk: FnKind,
@ -280,13 +291,6 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for NonSnakeCase {
} }
} }
fn check_lifetime_def(&mut self, cx: &LateContext, t: &hir::LifetimeDef) {
self.check_snake_case(cx,
"lifetime",
&t.lifetime.name.name().as_str(),
Some(t.lifetime.span));
}
fn check_pat(&mut self, cx: &LateContext, p: &hir::Pat) { fn check_pat(&mut self, cx: &LateContext, p: &hir::Pat) {
if let &PatKind::Binding(_, _, ref path1, _) = &p.node { if let &PatKind::Binding(_, _, ref path1, _) = &p.node {
self.check_snake_case(cx, "variable", &path1.node.as_str(), Some(p.span)); self.check_snake_case(cx, "variable", &path1.node.as_str(), Some(p.span));

View file

@ -507,21 +507,21 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for MissingCopyImplementations {
} }
let (def, ty) = match item.node { let (def, ty) = match item.node {
hir::ItemStruct(_, ref ast_generics) => { hir::ItemStruct(_, ref ast_generics) => {
if ast_generics.is_parameterized() { if !ast_generics.params.is_empty() {
return; return;
} }
let def = cx.tcx.adt_def(cx.tcx.hir.local_def_id(item.id)); let def = cx.tcx.adt_def(cx.tcx.hir.local_def_id(item.id));
(def, cx.tcx.mk_adt(def, cx.tcx.intern_substs(&[]))) (def, cx.tcx.mk_adt(def, cx.tcx.intern_substs(&[])))
} }
hir::ItemUnion(_, ref ast_generics) => { hir::ItemUnion(_, ref ast_generics) => {
if ast_generics.is_parameterized() { if !ast_generics.params.is_empty() {
return; return;
} }
let def = cx.tcx.adt_def(cx.tcx.hir.local_def_id(item.id)); let def = cx.tcx.adt_def(cx.tcx.hir.local_def_id(item.id));
(def, cx.tcx.mk_adt(def, cx.tcx.intern_substs(&[]))) (def, cx.tcx.mk_adt(def, cx.tcx.intern_substs(&[])))
} }
hir::ItemEnum(_, ref ast_generics) => { hir::ItemEnum(_, ref ast_generics) => {
if ast_generics.is_parameterized() { if !ast_generics.params.is_empty() {
return; return;
} }
let def = cx.tcx.adt_def(cx.tcx.hir.local_def_id(item.id)); let def = cx.tcx.adt_def(cx.tcx.hir.local_def_id(item.id));

View file

@ -744,7 +744,7 @@ impl LintPass for VariantSizeDifferences {
impl<'a, 'tcx> LateLintPass<'a, 'tcx> for VariantSizeDifferences { impl<'a, 'tcx> LateLintPass<'a, 'tcx> for VariantSizeDifferences {
fn check_item(&mut self, cx: &LateContext, it: &hir::Item) { fn check_item(&mut self, cx: &LateContext, it: &hir::Item) {
if let hir::ItemEnum(ref enum_definition, ref gens) = it.node { if let hir::ItemEnum(ref enum_definition, ref gens) = it.node {
if gens.ty_params.is_empty() { if gens.params.iter().all(|param| param.is_lifetime_param()) {
// sizes only make sense for non-generic types // sizes only make sense for non-generic types
let item_def_id = cx.tcx.hir.local_def_id(it.id); let item_def_id = cx.tcx.hir.local_def_id(it.id);
let t = cx.tcx.type_of(item_def_id); let t = cx.tcx.type_of(item_def_id);

View file

@ -1078,8 +1078,8 @@ impl<'a, 'b: 'a, 'tcx: 'b> IsolatedEncoder<'a, 'b, 'tcx> {
} }
hir::ItemConst(..) => self.encode_optimized_mir(def_id), hir::ItemConst(..) => self.encode_optimized_mir(def_id),
hir::ItemFn(_, _, constness, _, ref generics, _) => { hir::ItemFn(_, _, constness, _, ref generics, _) => {
let tps_len = generics.ty_params.len(); let has_tps = generics.ty_params().next().is_some();
let needs_inline = tps_len > 0 || attr::requests_inline(&item.attrs); let needs_inline = has_tps || attr::requests_inline(&item.attrs);
let always_encode_mir = self.tcx.sess.opts.debugging_opts.always_encode_mir; let always_encode_mir = self.tcx.sess.opts.debugging_opts.always_encode_mir;
if needs_inline || constness == hir::Constness::Const || always_encode_mir { if needs_inline || constness == hir::Constness::Const || always_encode_mir {
self.encode_optimized_mir(def_id) self.encode_optimized_mir(def_id)
@ -1480,7 +1480,7 @@ impl<'a, 'b, 'tcx> IndexBuilder<'a, 'b, 'tcx> {
} }
fn encode_info_for_generics(&mut self, generics: &hir::Generics) { fn encode_info_for_generics(&mut self, generics: &hir::Generics) {
for ty_param in &generics.ty_params { for ty_param in generics.ty_params() {
let def_id = self.tcx.hir.local_def_id(ty_param.id); let def_id = self.tcx.hir.local_def_id(ty_param.id);
let has_default = Untracked(ty_param.default.is_some()); let has_default = Untracked(ty_param.default.is_some());
self.record(def_id, IsolatedEncoder::encode_info_for_ty_param, (def_id, has_default)); self.record(def_id, IsolatedEncoder::encode_info_for_ty_param, (def_id, has_default));

View file

@ -922,7 +922,7 @@ impl<'b, 'a, 'v> ItemLikeVisitor<'v> for RootCollector<'b, 'a, 'v> {
hir::ItemEnum(_, ref generics) | hir::ItemEnum(_, ref generics) |
hir::ItemStruct(_, ref generics) | hir::ItemStruct(_, ref generics) |
hir::ItemUnion(_, ref generics) => { hir::ItemUnion(_, ref generics) => {
if !generics.is_parameterized() { if generics.params.is_empty() {
if self.mode == MonoItemCollectionMode::Eager { if self.mode == MonoItemCollectionMode::Eager {
let def_id = self.tcx.hir.local_def_id(item.id); let def_id = self.tcx.hir.local_def_id(item.id);
debug!("RootCollector: ADT drop-glue for {}", debug!("RootCollector: ADT drop-glue for {}",

View file

@ -250,7 +250,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
ItemKind::Trait(is_auto, _, ref generics, ref bounds, ref trait_items) => { ItemKind::Trait(is_auto, _, ref generics, ref bounds, ref trait_items) => {
if is_auto == IsAuto::Yes { if is_auto == IsAuto::Yes {
// Auto traits cannot have generics, super traits nor contain items. // Auto traits cannot have generics, super traits nor contain items.
if !generics.ty_params.is_empty() { if generics.is_parameterized() {
self.err_handler().span_err(item.span, self.err_handler().span_err(item.span,
"auto traits cannot have generics"); "auto traits cannot have generics");
} }
@ -283,17 +283,25 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
} }
} }
} }
ItemKind::TraitAlias(Generics { ref ty_params, .. }, ..) => { ItemKind::TraitAlias(Generics { ref params, .. }, ..) => {
for &TyParam { ref bounds, ref default, span, .. } in ty_params { for param in params {
if !bounds.is_empty() { if let GenericParam::Type(TyParam {
self.err_handler().span_err(span, ref bounds,
"type parameters on the left side of a \ ref default,
trait alias cannot be bounded"); span,
} ..
if !default.is_none() { }) = *param
self.err_handler().span_err(span, {
"type parameters on the left side of a \ if !bounds.is_empty() {
trait alias cannot have defaults"); self.err_handler().span_err(span,
"type parameters on the left side of a \
trait alias cannot be bounded");
}
if !default.is_none() {
self.err_handler().span_err(span,
"type parameters on the left side of a \
trait alias cannot have defaults");
}
} }
} }
} }
@ -352,9 +360,21 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
} }
fn visit_generics(&mut self, g: &'a Generics) { fn visit_generics(&mut self, g: &'a Generics) {
let mut seen_non_lifetime_param = false;
let mut seen_default = None; let mut seen_default = None;
for ty_param in &g.ty_params { for param in &g.params {
if ty_param.default.is_some() { match (param, seen_non_lifetime_param) {
(&GenericParam::Lifetime(ref ld), true) => {
self.err_handler()
.span_err(ld.lifetime.span, "lifetime parameters must be leading");
},
(&GenericParam::Lifetime(_), false) => {}
_ => {
seen_non_lifetime_param = true;
}
}
if let GenericParam::Type(ref ty_param @ TyParam { default: Some(_), .. }) = *param {
seen_default = Some(ty_param.span); seen_default = Some(ty_param.span);
} else if let Some(span) = seen_default { } else if let Some(span) = seen_default {
self.err_handler() self.err_handler()

View file

@ -224,10 +224,6 @@ impl<'v> hir_visit::Visitor<'v> for StatCollector<'v> {
self.record("Lifetime", Id::Node(lifetime.id), lifetime); self.record("Lifetime", Id::Node(lifetime.id), lifetime);
hir_visit::walk_lifetime(self, lifetime) hir_visit::walk_lifetime(self, lifetime)
} }
fn visit_lifetime_def(&mut self, lifetime: &'v hir::LifetimeDef) {
self.record("LifetimeDef", Id::None, lifetime);
hir_visit::walk_lifetime_def(self, lifetime)
}
fn visit_qpath(&mut self, qpath: &'v hir::QPath, id: NodeId, span: Span) { fn visit_qpath(&mut self, qpath: &'v hir::QPath, id: NodeId, span: Span) {
self.record("QPath", Id::None, qpath); self.record("QPath", Id::None, qpath);
hir_visit::walk_qpath(self, qpath, id, span) hir_visit::walk_qpath(self, qpath, id, span)
@ -349,11 +345,6 @@ impl<'v> ast_visit::Visitor<'v> for StatCollector<'v> {
ast_visit::walk_lifetime(self, lifetime) ast_visit::walk_lifetime(self, lifetime)
} }
fn visit_lifetime_def(&mut self, lifetime: &'v ast::LifetimeDef) {
self.record("LifetimeDef", Id::None, lifetime);
ast_visit::walk_lifetime_def(self, lifetime)
}
fn visit_mac(&mut self, mac: &'v ast::Mac) { fn visit_mac(&mut self, mac: &'v ast::Mac) {
self.record("Mac", Id::None, mac); self.record("Mac", Id::None, mac);
} }

View file

@ -1236,7 +1236,7 @@ impl<'a, 'tcx> Visitor<'tcx> for ObsoleteVisiblePrivateTypesVisitor<'a, 'tcx> {
} }
fn visit_generics(&mut self, generics: &'tcx hir::Generics) { fn visit_generics(&mut self, generics: &'tcx hir::Generics) {
for ty_param in generics.ty_params.iter() { for ty_param in generics.ty_params() {
for bound in ty_param.bounds.iter() { for bound in ty_param.bounds.iter() {
self.check_ty_param_bound(bound) self.check_ty_param_bound(bound)
} }

View file

@ -53,7 +53,7 @@ use syntax::util::lev_distance::find_best_match_for_name;
use syntax::visit::{self, FnKind, Visitor}; use syntax::visit::{self, FnKind, Visitor};
use syntax::attr; use syntax::attr;
use syntax::ast::{Arm, BindingMode, Block, Crate, Expr, ExprKind}; use syntax::ast::{Arm, BindingMode, Block, Crate, Expr, ExprKind};
use syntax::ast::{FnDecl, ForeignItem, ForeignItemKind, Generics}; use syntax::ast::{FnDecl, ForeignItem, ForeignItemKind, GenericParam, Generics};
use syntax::ast::{Item, ItemKind, ImplItem, ImplItemKind}; use syntax::ast::{Item, ItemKind, ImplItem, ImplItemKind};
use syntax::ast::{Local, Mutability, Pat, PatKind, Path}; use syntax::ast::{Local, Mutability, Pat, PatKind, Path};
use syntax::ast::{QSelf, TraitItemKind, TraitRef, Ty, TyKind}; use syntax::ast::{QSelf, TraitItemKind, TraitRef, Ty, TyKind};
@ -790,25 +790,30 @@ impl<'a, 'tcx> Visitor<'tcx> for Resolver<'a> {
// to following type parameters, as the Substs can only // to following type parameters, as the Substs can only
// provide previous type parameters as they're built. // provide previous type parameters as they're built.
let mut default_ban_rib = Rib::new(ForwardTyParamBanRibKind); let mut default_ban_rib = Rib::new(ForwardTyParamBanRibKind);
default_ban_rib.bindings.extend(generics.ty_params.iter() default_ban_rib.bindings.extend(generics.params.iter()
.filter_map(|p| if let GenericParam::Type(ref tp) = *p { Some(tp) } else { None })
.skip_while(|p| p.default.is_none()) .skip_while(|p| p.default.is_none())
.map(|p| (Ident::with_empty_ctxt(p.ident.name), Def::Err))); .map(|p| (Ident::with_empty_ctxt(p.ident.name), Def::Err)));
for param in &generics.ty_params { for param in &generics.params {
for bound in &param.bounds { match *param {
self.visit_ty_param_bound(bound); GenericParam::Lifetime(_) => self.visit_generic_param(param),
} GenericParam::Type(ref ty_param) => {
for bound in &ty_param.bounds {
self.visit_ty_param_bound(bound);
}
if let Some(ref ty) = param.default { if let Some(ref ty) = ty_param.default {
self.ribs[TypeNS].push(default_ban_rib); self.ribs[TypeNS].push(default_ban_rib);
self.visit_ty(ty); self.visit_ty(ty);
default_ban_rib = self.ribs[TypeNS].pop().unwrap(); default_ban_rib = self.ribs[TypeNS].pop().unwrap();
} }
// Allow all following defaults to refer to this type parameter. // Allow all following defaults to refer to this type parameter.
default_ban_rib.bindings.remove(&Ident::with_empty_ctxt(param.ident.name)); default_ban_rib.bindings.remove(&Ident::with_empty_ctxt(ty_param.ident.name));
}
}
} }
for lt in &generics.lifetimes { self.visit_lifetime_def(lt); }
for p in &generics.where_clause.predicates { self.visit_where_predicate(p); } for p in &generics.where_clause.predicates { self.visit_where_predicate(p); }
} }
} }
@ -2022,23 +2027,27 @@ impl<'a> Resolver<'a> {
HasTypeParameters(generics, rib_kind) => { HasTypeParameters(generics, rib_kind) => {
let mut function_type_rib = Rib::new(rib_kind); let mut function_type_rib = Rib::new(rib_kind);
let mut seen_bindings = FxHashMap(); let mut seen_bindings = FxHashMap();
for type_parameter in &generics.ty_params { for param in &generics.params {
let ident = type_parameter.ident.modern(); if let GenericParam::Type(ref type_parameter) = *param {
debug!("with_type_parameter_rib: {}", type_parameter.id); let ident = type_parameter.ident.modern();
debug!("with_type_parameter_rib: {}", type_parameter.id);
if seen_bindings.contains_key(&ident) { if seen_bindings.contains_key(&ident) {
let span = seen_bindings.get(&ident).unwrap(); let span = seen_bindings.get(&ident).unwrap();
let err = let err = ResolutionError::NameAlreadyUsedInTypeParameterList(
ResolutionError::NameAlreadyUsedInTypeParameterList(ident.name, span); ident.name,
resolve_error(self, type_parameter.span, err); span,
);
resolve_error(self, type_parameter.span, err);
}
seen_bindings.entry(ident).or_insert(type_parameter.span);
// plain insert (no renaming)
let def_id = self.definitions.local_def_id(type_parameter.id);
let def = Def::TyParam(def_id);
function_type_rib.bindings.insert(ident, def);
self.record_def(type_parameter.id, PathResolution::new(def));
} }
seen_bindings.entry(ident).or_insert(type_parameter.span);
// plain insert (no renaming)
let def_id = self.definitions.local_def_id(type_parameter.id);
let def = Def::TyParam(def_id);
function_type_rib.bindings.insert(ident, def);
self.record_def(type_parameter.id, PathResolution::new(def));
} }
self.ribs[TypeNS].push(function_type_rib); self.ribs[TypeNS].push(function_type_rib);
} }

View file

@ -36,7 +36,12 @@ use syntax::ast::{self, Attribute, NodeId, PatKind, CRATE_NODE_ID};
use syntax::parse::token; use syntax::parse::token;
use syntax::symbol::keywords; use syntax::symbol::keywords;
use syntax::visit::{self, Visitor}; use syntax::visit::{self, Visitor};
use syntax::print::pprust::{bounds_to_string, generics_to_string, path_to_string, ty_to_string}; use syntax::print::pprust::{
bounds_to_string,
generic_params_to_string,
path_to_string,
ty_to_string
};
use syntax::ptr::P; use syntax::ptr::P;
use syntax::codemap::{Spanned, DUMMY_SP}; use syntax::codemap::{Spanned, DUMMY_SP};
use syntax_pos::*; use syntax_pos::*;
@ -438,35 +443,37 @@ impl<'l, 'tcx: 'l, 'll, O: DumpOutput + 'll> DumpVisitor<'l, 'tcx, 'll, O> {
prefix: &str, prefix: &str,
id: NodeId, id: NodeId,
) { ) {
for param in &generics.ty_params { for param in &generics.params {
let param_ss = param.span; if let ast::GenericParam::Type(ref ty_param) = *param {
let name = escape(self.span.snippet(param_ss)); let param_ss = ty_param.span;
// Append $id to name to make sure each one is unique let name = escape(self.span.snippet(param_ss));
let qualname = format!("{}::{}${}", prefix, name, id); // Append $id to name to make sure each one is unique
if !self.span.filter_generated(Some(param_ss), full_span) { let qualname = format!("{}::{}${}", prefix, name, id);
let id = ::id_from_node_id(param.id, &self.save_ctxt); if !self.span.filter_generated(Some(param_ss), full_span) {
let span = self.span_from_span(param_ss); let id = ::id_from_node_id(ty_param.id, &self.save_ctxt);
let span = self.span_from_span(param_ss);
self.dumper.dump_def( self.dumper.dump_def(
&Access { &Access {
public: false, public: false,
reachable: false, reachable: false,
}, },
Def { Def {
kind: DefKind::Type, kind: DefKind::Type,
id, id,
span, span,
name, name,
qualname, qualname,
value: String::new(), value: String::new(),
parent: None, parent: None,
children: vec![], children: vec![],
decl_id: None, decl_id: None,
docs: String::new(), docs: String::new(),
sig: None, sig: None,
attributes: vec![], attributes: vec![],
}, },
); );
}
} }
} }
self.visit_generics(generics); self.visit_generics(generics);
@ -787,8 +794,8 @@ impl<'l, 'tcx: 'l, 'll, O: DumpOutput + 'll> DumpVisitor<'l, 'tcx, 'll, O> {
let name = item.ident.to_string(); let name = item.ident.to_string();
let qualname = format!("::{}", self.tcx.node_path_str(item.id)); let qualname = format!("::{}", self.tcx.node_path_str(item.id));
let mut val = name.clone(); let mut val = name.clone();
if !generics.lifetimes.is_empty() || !generics.ty_params.is_empty() { if !generics.params.is_empty() {
val.push_str(&generics_to_string(generics)); val.push_str(&generic_params_to_string(&generics.params));
} }
if !trait_refs.is_empty() { if !trait_refs.is_empty() {
val.push_str(": "); val.push_str(": ");
@ -1478,14 +1485,16 @@ impl<'l, 'tcx: 'l, 'll, O: DumpOutput + 'll> Visitor<'l> for DumpVisitor<'l, 'tc
} }
fn visit_generics(&mut self, generics: &'l ast::Generics) { fn visit_generics(&mut self, generics: &'l ast::Generics) {
for param in generics.ty_params.iter() { for param in &generics.params {
for bound in param.bounds.iter() { if let ast::GenericParam::Type(ref ty_param) = *param {
if let ast::TraitTyParamBound(ref trait_ref, _) = *bound { for bound in ty_param.bounds.iter() {
self.process_path(trait_ref.trait_ref.ref_id, &trait_ref.trait_ref.path) if let ast::TraitTyParamBound(ref trait_ref, _) = *bound {
self.process_path(trait_ref.trait_ref.ref_id, &trait_ref.trait_ref.path)
}
}
if let Some(ref ty) = ty_param.default {
self.visit_ty(&ty);
} }
}
if let Some(ref ty) = param.default {
self.visit_ty(&ty);
} }
} }
} }

View file

@ -886,21 +886,15 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> {
fn make_signature(decl: &ast::FnDecl, generics: &ast::Generics) -> String { fn make_signature(decl: &ast::FnDecl, generics: &ast::Generics) -> String {
let mut sig = "fn ".to_owned(); let mut sig = "fn ".to_owned();
if !generics.lifetimes.is_empty() || !generics.ty_params.is_empty() { if !generics.params.is_empty() {
sig.push('<'); sig.push('<');
sig.push_str(&generics sig.push_str(&generics
.lifetimes .params
.iter() .iter()
.map(|l| l.lifetime.ident.name.to_string()) .map(|param| match *param {
.collect::<Vec<_>>() ast::GenericParam::Lifetime(ref l) => l.lifetime.ident.name.to_string(),
.join(", ")); ast::GenericParam::Type(ref t) => t.ident.to_string(),
if !generics.lifetimes.is_empty() { })
sig.push_str(", ");
}
sig.push_str(&generics
.ty_params
.iter()
.map(|l| l.ident.to_string())
.collect::<Vec<_>>() .collect::<Vec<_>>()
.join(", ")); .join(", "));
sig.push_str("> "); sig.push_str("> ");

View file

@ -218,12 +218,17 @@ impl Sig for ast::Ty {
} }
ast::TyKind::BareFn(ref f) => { ast::TyKind::BareFn(ref f) => {
let mut text = String::new(); let mut text = String::new();
if !f.lifetimes.is_empty() { if !f.generic_params.is_empty() {
// FIXME defs, bounds on lifetimes // FIXME defs, bounds on lifetimes
text.push_str("for<"); text.push_str("for<");
text.push_str(&f.lifetimes text.push_str(&f.generic_params
.iter() .iter()
.map(|l| l.lifetime.ident.to_string()) .filter_map(|p| match *p {
ast::GenericParam::Lifetime(ref l) => {
Some(l.lifetime.ident.to_string())
}
_ => None,
})
.collect::<Vec<_>>() .collect::<Vec<_>>()
.join(", ")); .join(", "));
text.push('>'); text.push('>');
@ -615,50 +620,53 @@ impl Sig for ast::Path {
// This does not cover the where clause, which must be processed separately. // This does not cover the where clause, which must be processed separately.
impl Sig for ast::Generics { impl Sig for ast::Generics {
fn make(&self, offset: usize, _parent_id: Option<NodeId>, scx: &SaveContext) -> Result { fn make(&self, offset: usize, _parent_id: Option<NodeId>, scx: &SaveContext) -> Result {
let total = self.lifetimes.len() + self.ty_params.len(); if self.params.is_empty() {
if total == 0 {
return Ok(text_sig(String::new())); return Ok(text_sig(String::new()));
} }
let mut text = "<".to_owned(); let mut text = "<".to_owned();
let mut defs = vec![]; let mut defs = vec![];
for l in &self.lifetimes { for param in &self.params {
let mut l_text = l.lifetime.ident.to_string(); match *param {
defs.push(SigElement { ast::GenericParam::Lifetime(ref l) => {
id: id_from_node_id(l.lifetime.id, scx), let mut l_text = l.lifetime.ident.to_string();
start: offset + text.len(), defs.push(SigElement {
end: offset + text.len() + l_text.len(), id: id_from_node_id(l.lifetime.id, scx),
}); start: offset + text.len(),
end: offset + text.len() + l_text.len(),
});
if !l.bounds.is_empty() { if !l.bounds.is_empty() {
l_text.push_str(": "); l_text.push_str(": ");
let bounds = l.bounds let bounds = l.bounds
.iter() .iter()
.map(|l| l.ident.to_string()) .map(|l| l.ident.to_string())
.collect::<Vec<_>>() .collect::<Vec<_>>()
.join(" + "); .join(" + ");
l_text.push_str(&bounds); l_text.push_str(&bounds);
// FIXME add lifetime bounds refs. // FIXME add lifetime bounds refs.
} }
text.push_str(&l_text); text.push_str(&l_text);
text.push(','); text.push(',');
} }
for t in &self.ty_params { ast::GenericParam::Type(ref t) => {
let mut t_text = t.ident.to_string(); let mut t_text = t.ident.to_string();
defs.push(SigElement { defs.push(SigElement {
id: id_from_node_id(t.id, scx), id: id_from_node_id(t.id, scx),
start: offset + text.len(), start: offset + text.len(),
end: offset + text.len() + t_text.len(), end: offset + text.len() + t_text.len(),
}); });
if !t.bounds.is_empty() { if !t.bounds.is_empty() {
t_text.push_str(": "); t_text.push_str(": ");
t_text.push_str(&pprust::bounds_to_string(&t.bounds)); t_text.push_str(&pprust::bounds_to_string(&t.bounds));
// FIXME descend properly into bounds. // FIXME descend properly into bounds.
}
text.push_str(&t_text);
text.push(',');
}
} }
text.push_str(&t_text);
text.push(',');
} }
text.push('>'); text.push('>');

View file

@ -562,10 +562,10 @@ fn compare_number_of_generics<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
if num_impl_m_type_params != num_trait_m_type_params { if num_impl_m_type_params != num_trait_m_type_params {
let impl_m_node_id = tcx.hir.as_local_node_id(impl_m.def_id).unwrap(); let impl_m_node_id = tcx.hir.as_local_node_id(impl_m.def_id).unwrap();
let impl_m_item = tcx.hir.expect_impl_item(impl_m_node_id); let impl_m_item = tcx.hir.expect_impl_item(impl_m_node_id);
let span = if impl_m_item.generics.is_parameterized() { let span = if impl_m_item.generics.params.is_empty() {
impl_m_item.generics.span
} else {
impl_m_span impl_m_span
} else {
impl_m_item.generics.span
}; };
let mut err = struct_span_err!(tcx.sess, let mut err = struct_span_err!(tcx.sess,

View file

@ -4949,16 +4949,18 @@ pub fn check_bounds_are_used<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
generics: &hir::Generics, generics: &hir::Generics,
ty: Ty<'tcx>) { ty: Ty<'tcx>) {
debug!("check_bounds_are_used(n_tps={}, ty={:?})", debug!("check_bounds_are_used(n_tps={}, ty={:?})",
generics.ty_params.len(), ty); generics.ty_params().count(), ty);
// make a vector of booleans initially false, set to true when used // make a vector of booleans initially false, set to true when used
if generics.ty_params.is_empty() { return; } if generics.ty_params().next().is_none() { return; }
let mut tps_used = vec![false; generics.ty_params.len()]; let mut tps_used = vec![false; generics.ty_params().count()];
let lifetime_count = generics.lifetimes().count();
for leaf_ty in ty.walk() { for leaf_ty in ty.walk() {
if let ty::TyParam(ParamTy {idx, ..}) = leaf_ty.sty { if let ty::TyParam(ParamTy {idx, ..}) = leaf_ty.sty {
debug!("Found use of ty param num {}", idx); debug!("Found use of ty param num {}", idx);
tps_used[idx as usize - generics.lifetimes.len()] = true; tps_used[idx as usize - lifetime_count] = true;
} else if let ty::TyError = leaf_ty.sty { } else if let ty::TyError = leaf_ty.sty {
// If there already another error, do not emit an error for not using a type Parameter // If there already another error, do not emit an error for not using a type Parameter
assert!(tcx.sess.err_count() > 0); assert!(tcx.sess.err_count() > 0);
@ -4966,7 +4968,7 @@ pub fn check_bounds_are_used<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
} }
} }
for (&used, param) in tps_used.iter().zip(&generics.ty_params) { for (&used, param) in tps_used.iter().zip(generics.ty_params()) {
if !used { if !used {
struct_span_err!(tcx.sess, param.span, E0091, struct_span_err!(tcx.sess, param.span, E0091,
"type parameter `{}` is unused", "type parameter `{}` is unused",

View file

@ -592,13 +592,9 @@ impl<'a, 'gcx> CheckTypeWellFormedVisitor<'a, 'gcx> {
continue; continue;
} }
let (span, name) = if index < ast_generics.lifetimes.len() { let (span, name) = match ast_generics.params[index] {
(ast_generics.lifetimes[index].lifetime.span, hir::GenericParam::Lifetime(ref ld) => (ld.lifetime.span, ld.lifetime.name.name()),
ast_generics.lifetimes[index].lifetime.name.name()) hir::GenericParam::Type(ref tp) => (tp.span, tp.name),
} else {
let index = index - ast_generics.lifetimes.len();
(ast_generics.ty_params[index].span,
ast_generics.ty_params[index].name)
}; };
self.report_bivariance(span, name); self.report_bivariance(span, name);
} }

View file

@ -111,7 +111,7 @@ impl<'a, 'tcx> Visitor<'tcx> for CollectItemTypesVisitor<'a, 'tcx> {
} }
fn visit_generics(&mut self, generics: &'tcx hir::Generics) { fn visit_generics(&mut self, generics: &'tcx hir::Generics) {
for param in &generics.ty_params { for param in generics.ty_params() {
if param.default.is_some() { if param.default.is_some() {
let def_id = self.tcx.hir.local_def_id(param.id); let def_id = self.tcx.hir.local_def_id(param.id);
self.tcx.type_of(def_id); self.tcx.type_of(def_id);
@ -315,8 +315,7 @@ impl<'a, 'tcx> ItemCtxt<'a, 'tcx> {
-> Vec<ty::Predicate<'tcx>> -> Vec<ty::Predicate<'tcx>>
{ {
let from_ty_params = let from_ty_params =
ast_generics.ty_params ast_generics.ty_params()
.iter()
.filter(|p| p.id == param_id) .filter(|p| p.id == param_id)
.flat_map(|p| p.bounds.iter()) .flat_map(|p| p.bounds.iter())
.flat_map(|b| predicates_from_bound(self, ty, b)); .flat_map(|b| predicates_from_bound(self, ty, b));
@ -365,7 +364,7 @@ fn ensure_no_ty_param_bounds(tcx: TyCtxt,
thing: &'static str) { thing: &'static str) {
let mut warn = false; let mut warn = false;
for ty_param in generics.ty_params.iter() { for ty_param in generics.ty_params() {
for bound in ty_param.bounds.iter() { for bound in ty_param.bounds.iter() {
match *bound { match *bound {
hir::TraitTyParamBound(..) => { hir::TraitTyParamBound(..) => {
@ -804,7 +803,7 @@ fn has_late_bound_regions<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
let mut visitor = LateBoundRegionsDetector { let mut visitor = LateBoundRegionsDetector {
tcx, binder_depth: 1, has_late_bound_regions: None tcx, binder_depth: 1, has_late_bound_regions: None
}; };
for lifetime in &generics.lifetimes { for lifetime in generics.lifetimes() {
let hir_id = tcx.hir.node_to_hir_id(lifetime.lifetime.id); let hir_id = tcx.hir.node_to_hir_id(lifetime.lifetime.id);
if tcx.is_late_bound(hir_id) { if tcx.is_late_bound(hir_id) {
return Some(lifetime.lifetime.span); return Some(lifetime.lifetime.span);
@ -964,7 +963,7 @@ fn generics_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
// Now create the real type parameters. // Now create the real type parameters.
let type_start = own_start + regions.len() as u32; let type_start = own_start + regions.len() as u32;
let types = ast_generics.ty_params.iter().enumerate().map(|(i, p)| { let types = ast_generics.ty_params().enumerate().map(|(i, p)| {
if p.name == keywords::SelfType.name() { if p.name == keywords::SelfType.name() {
span_bug!(p.span, "`Self` should not be the name of a regular parameter"); span_bug!(p.span, "`Self` should not be the name of a regular parameter");
} }
@ -1359,8 +1358,7 @@ fn early_bound_lifetimes_from_generics<'a, 'tcx>(
-> impl Iterator<Item=&'a hir::LifetimeDef> -> impl Iterator<Item=&'a hir::LifetimeDef>
{ {
ast_generics ast_generics
.lifetimes .lifetimes()
.iter()
.filter(move |l| { .filter(move |l| {
let hir_id = tcx.hir.node_to_hir_id(l.lifetime.id); let hir_id = tcx.hir.node_to_hir_id(l.lifetime.id);
!tcx.is_late_bound(hir_id) !tcx.is_late_bound(hir_id)
@ -1492,7 +1490,7 @@ fn explicit_predicates_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
// Collect the predicates that were written inline by the user on each // Collect the predicates that were written inline by the user on each
// type parameter (e.g., `<T:Foo>`). // type parameter (e.g., `<T:Foo>`).
for param in &ast_generics.ty_params { for param in ast_generics.ty_params() {
let param_ty = ty::ParamTy::new(index, param.name).to_ty(tcx); let param_ty = ty::ParamTy::new(index, param.name).to_ty(tcx);
index += 1; index += 1;

View file

@ -105,7 +105,7 @@ fn enforce_impl_params_are_constrained<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
tcx, &impl_predicates.predicates.as_slice(), impl_trait_ref, &mut input_parameters); tcx, &impl_predicates.predicates.as_slice(), impl_trait_ref, &mut input_parameters);
// Disallow ANY unconstrained type parameters. // Disallow ANY unconstrained type parameters.
for (ty_param, param) in impl_generics.types.iter().zip(&impl_hir_generics.ty_params) { for (ty_param, param) in impl_generics.types.iter().zip(impl_hir_generics.ty_params()) {
let param_ty = ty::ParamTy::for_def(ty_param); let param_ty = ty::ParamTy::for_def(ty_param);
if !input_parameters.contains(&ctp::Parameter::from(param_ty)) { if !input_parameters.contains(&ctp::Parameter::from(param_ty)) {
report_unused_parameter(tcx, param.span, "type", &param_ty.to_string()); report_unused_parameter(tcx, param.span, "type", &param_ty.to_string());
@ -123,7 +123,7 @@ fn enforce_impl_params_are_constrained<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
ctp::parameters_for(&tcx.type_of(def_id), true) ctp::parameters_for(&tcx.type_of(def_id), true)
}).collect(); }).collect();
for (ty_lifetime, lifetime) in impl_generics.regions.iter() for (ty_lifetime, lifetime) in impl_generics.regions.iter()
.zip(&impl_hir_generics.lifetimes) .zip(impl_hir_generics.lifetimes())
{ {
let param = ctp::Parameter::from(ty_lifetime.to_early_bound_region_data()); let param = ctp::Parameter::from(ty_lifetime.to_early_bound_region_data());

View file

@ -186,7 +186,7 @@ fn check_main_fn_ty<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
Some(hir_map::NodeItem(it)) => { Some(hir_map::NodeItem(it)) => {
match it.node { match it.node {
hir::ItemFn(.., ref generics, _) => { hir::ItemFn(.., ref generics, _) => {
if generics.is_parameterized() { if !generics.params.is_empty() {
struct_span_err!(tcx.sess, generics.span, E0131, struct_span_err!(tcx.sess, generics.span, E0131,
"main function is not allowed to have type parameters") "main function is not allowed to have type parameters")
.span_label(generics.span, .span_label(generics.span,
@ -235,7 +235,7 @@ fn check_start_fn_ty<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
Some(hir_map::NodeItem(it)) => { Some(hir_map::NodeItem(it)) => {
match it.node { match it.node {
hir::ItemFn(..,ref ps,_) hir::ItemFn(..,ref ps,_)
if ps.is_parameterized() => { if !ps.params.is_empty() => {
struct_span_err!(tcx.sess, ps.span, E0132, struct_span_err!(tcx.sess, ps.span, E0132,
"start function is not allowed to have type parameters") "start function is not allowed to have type parameters")
.span_label(ps.span, .span_label(ps.span,

View file

@ -43,6 +43,7 @@ use rustc_typeck::hir_ty_to_ty;
use rustc::hir; use rustc::hir;
use rustc_const_math::ConstInt; use rustc_const_math::ConstInt;
use std::default::Default;
use std::{mem, slice, vec}; use std::{mem, slice, vec};
use std::iter::FromIterator; use std::iter::FromIterator;
use std::rc::Rc; use std::rc::Rc;
@ -856,7 +857,7 @@ impl TyParamBound {
did, did,
is_generic: false, is_generic: false,
}, },
lifetimes: vec![] generic_params: Vec::new(),
}, hir::TraitBoundModifier::Maybe) }, hir::TraitBoundModifier::Maybe)
} }
@ -951,7 +952,7 @@ impl<'tcx> Clean<TyParamBound> for ty::TraitRef<'tcx> {
if let &ty::RegionKind::ReLateBound(..) = *reg { if let &ty::RegionKind::ReLateBound(..) = *reg {
debug!(" hit an ReLateBound {:?}", reg); debug!(" hit an ReLateBound {:?}", reg);
if let Some(lt) = reg.clean(cx) { if let Some(lt) = reg.clean(cx) {
late_bounds.push(lt); late_bounds.push(GenericParam::Lifetime(lt));
} }
} }
} }
@ -967,7 +968,7 @@ impl<'tcx> Clean<TyParamBound> for ty::TraitRef<'tcx> {
did: self.def_id, did: self.def_id,
is_generic: false, is_generic: false,
}, },
lifetimes: late_bounds, generic_params: late_bounds,
}, },
hir::TraitBoundModifier::None hir::TraitBoundModifier::None
) )
@ -981,7 +982,7 @@ impl<'tcx> Clean<Option<Vec<TyParamBound>>> for Substs<'tcx> {
.map(RegionBound)); .map(RegionBound));
v.extend(self.types().map(|t| TraitBound(PolyTrait { v.extend(self.types().map(|t| TraitBound(PolyTrait {
trait_: t.clean(cx), trait_: t.clean(cx),
lifetimes: vec![] generic_params: Vec::new(),
}, hir::TraitBoundModifier::None))); }, hir::TraitBoundModifier::None)));
if !v.is_empty() {Some(v)} else {None} if !v.is_empty() {Some(v)} else {None}
} }
@ -1186,19 +1187,31 @@ impl<'tcx> Clean<Type> for ty::ProjectionTy<'tcx> {
} }
} }
// maybe use a Generic enum and use Vec<Generic>?
#[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Debug)] #[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Debug)]
pub enum GenericParam {
Lifetime(Lifetime),
Type(TyParam),
}
impl Clean<GenericParam> for hir::GenericParam {
fn clean(&self, cx: &DocContext) -> GenericParam {
match *self {
hir::GenericParam::Lifetime(ref l) => GenericParam::Lifetime(l.clean(cx)),
hir::GenericParam::Type(ref t) => GenericParam::Type(t.clean(cx)),
}
}
}
#[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Debug, Default)]
pub struct Generics { pub struct Generics {
pub lifetimes: Vec<Lifetime>, pub params: Vec<GenericParam>,
pub type_params: Vec<TyParam>,
pub where_predicates: Vec<WherePredicate>, pub where_predicates: Vec<WherePredicate>,
} }
impl Clean<Generics> for hir::Generics { impl Clean<Generics> for hir::Generics {
fn clean(&self, cx: &DocContext) -> Generics { fn clean(&self, cx: &DocContext) -> Generics {
let mut g = Generics { let mut g = Generics {
lifetimes: self.lifetimes.clean(cx), params: self.params.clean(cx),
type_params: self.ty_params.clean(cx),
where_predicates: self.where_clause.predicates.clean(cx) where_predicates: self.where_clause.predicates.clean(cx)
}; };
@ -1209,10 +1222,12 @@ impl Clean<Generics> for hir::Generics {
match *where_pred { match *where_pred {
WherePredicate::BoundPredicate { ty: Generic(ref name), ref mut bounds } => { WherePredicate::BoundPredicate { ty: Generic(ref name), ref mut bounds } => {
if bounds.is_empty() { if bounds.is_empty() {
for type_params in &mut g.type_params { for param in &mut g.params {
if &type_params.name == name { if let GenericParam::Type(ref mut type_param) = *param {
mem::swap(bounds, &mut type_params.bounds); if &type_param.name == name {
break mem::swap(bounds, &mut type_param.bounds);
break
}
} }
} }
} }
@ -1283,8 +1298,16 @@ impl<'a, 'tcx> Clean<Generics> for (&'a ty::Generics,
// and instead see `where T: Foo + Bar + Sized + 'a` // and instead see `where T: Foo + Bar + Sized + 'a`
Generics { Generics {
type_params: simplify::ty_params(stripped_typarams), params: gens.regions
lifetimes: gens.regions.clean(cx), .clean(cx)
.into_iter()
.map(|lp| GenericParam::Lifetime(lp))
.chain(
simplify::ty_params(stripped_typarams)
.into_iter()
.map(|tp| GenericParam::Type(tp))
)
.collect(),
where_predicates: simplify::where_clauses(cx, where_predicates), where_predicates: simplify::where_clauses(cx, where_predicates),
} }
} }
@ -1538,7 +1561,7 @@ impl Clean<PolyTrait> for hir::PolyTraitRef {
fn clean(&self, cx: &DocContext) -> PolyTrait { fn clean(&self, cx: &DocContext) -> PolyTrait {
PolyTrait { PolyTrait {
trait_: self.trait_ref.clean(cx), trait_: self.trait_ref.clean(cx),
lifetimes: self.bound_lifetimes.clean(cx) generic_params: self.bound_generic_params.clean(cx)
} }
} }
} }
@ -1590,11 +1613,7 @@ impl Clean<Item> for hir::ImplItem {
} }
hir::ImplItemKind::Type(ref ty) => TypedefItem(Typedef { hir::ImplItemKind::Type(ref ty) => TypedefItem(Typedef {
type_: ty.clean(cx), type_: ty.clean(cx),
generics: Generics { generics: Generics::default(),
lifetimes: Vec::new(),
type_params: Vec::new(),
where_predicates: Vec::new()
},
}, true), }, true),
}; };
Item { Item {
@ -1726,8 +1745,7 @@ impl<'tcx> Clean<Item> for ty::AssociatedItem {
TypedefItem(Typedef { TypedefItem(Typedef {
type_: cx.tcx.type_of(self.def_id).clean(cx), type_: cx.tcx.type_of(self.def_id).clean(cx),
generics: Generics { generics: Generics {
lifetimes: Vec::new(), params: Vec::new(),
type_params: Vec::new(),
where_predicates: Vec::new(), where_predicates: Vec::new(),
}, },
}, true) }, true)
@ -1757,7 +1775,7 @@ impl<'tcx> Clean<Item> for ty::AssociatedItem {
#[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Debug)] #[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Debug)]
pub struct PolyTrait { pub struct PolyTrait {
pub trait_: Type, pub trait_: Type,
pub lifetimes: Vec<Lifetime> pub generic_params: Vec<GenericParam>,
} }
/// A representation of a Type suitable for hyperlinking purposes. Ideally one can get the original /// A representation of a Type suitable for hyperlinking purposes. Ideally one can get the original
@ -2081,7 +2099,7 @@ impl Clean<Type> for hir::Ty {
let mut ty_substs = FxHashMap(); let mut ty_substs = FxHashMap();
let mut lt_substs = FxHashMap(); let mut lt_substs = FxHashMap();
provided_params.with_parameters(|provided_params| { provided_params.with_parameters(|provided_params| {
for (i, ty_param) in generics.ty_params.iter().enumerate() { for (i, ty_param) in generics.ty_params().enumerate() {
let ty_param_def = Def::TyParam(cx.tcx.hir.local_def_id(ty_param.id)); let ty_param_def = Def::TyParam(cx.tcx.hir.local_def_id(ty_param.id));
if let Some(ty) = provided_params.types.get(i).cloned() { if let Some(ty) = provided_params.types.get(i).cloned() {
ty_substs.insert(ty_param_def, ty.into_inner().clean(cx)); ty_substs.insert(ty_param_def, ty.into_inner().clean(cx));
@ -2089,7 +2107,8 @@ impl Clean<Type> for hir::Ty {
ty_substs.insert(ty_param_def, default.into_inner().clean(cx)); ty_substs.insert(ty_param_def, default.into_inner().clean(cx));
} }
} }
for (i, lt_param) in generics.lifetimes.iter().enumerate() {
for (i, lt_param) in generics.lifetimes().enumerate() {
if let Some(lt) = provided_params.lifetimes.get(i).cloned() { if let Some(lt) = provided_params.lifetimes.get(i).cloned() {
if !lt.is_elided() { if !lt.is_elided() {
let lt_def_id = cx.tcx.hir.local_def_id(lt_param.lifetime.id); let lt_def_id = cx.tcx.hir.local_def_id(lt_param.lifetime.id);
@ -2197,11 +2216,7 @@ impl<'tcx> Clean<Type> for Ty<'tcx> {
let sig = ty.fn_sig(cx.tcx); let sig = ty.fn_sig(cx.tcx);
BareFunction(box BareFunctionDecl { BareFunction(box BareFunctionDecl {
unsafety: sig.unsafety(), unsafety: sig.unsafety(),
generics: Generics { generic_params: Vec::new(),
lifetimes: Vec::new(),
type_params: Vec::new(),
where_predicates: Vec::new()
},
decl: (cx.tcx.hir.local_def_id(ast::CRATE_NODE_ID), sig).clean(cx), decl: (cx.tcx.hir.local_def_id(ast::CRATE_NODE_ID), sig).clean(cx),
abi: sig.abi(), abi: sig.abi(),
}) })
@ -2253,7 +2268,7 @@ impl<'tcx> Clean<Type> for Ty<'tcx> {
did, did,
is_generic: false, is_generic: false,
}, },
lifetimes: vec![] generic_params: Vec::new(),
}, hir::TraitBoundModifier::None); }, hir::TraitBoundModifier::None);
typarams.push(bound); typarams.push(bound);
} }
@ -2713,7 +2728,7 @@ impl Clean<Item> for doctree::Typedef {
#[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Debug)] #[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Debug)]
pub struct BareFunctionDecl { pub struct BareFunctionDecl {
pub unsafety: hir::Unsafety, pub unsafety: hir::Unsafety,
pub generics: Generics, pub generic_params: Vec<GenericParam>,
pub decl: FnDecl, pub decl: FnDecl,
pub abi: Abi, pub abi: Abi,
} }
@ -2722,11 +2737,7 @@ impl Clean<BareFunctionDecl> for hir::BareFnTy {
fn clean(&self, cx: &DocContext) -> BareFunctionDecl { fn clean(&self, cx: &DocContext) -> BareFunctionDecl {
BareFunctionDecl { BareFunctionDecl {
unsafety: self.unsafety, unsafety: self.unsafety,
generics: Generics { generic_params: self.generic_params.clean(cx),
lifetimes: self.lifetimes.clean(cx),
type_params: Vec::new(),
where_predicates: Vec::new()
},
decl: (&*self.decl, &self.arg_names[..]).clean(cx), decl: (&*self.decl, &self.arg_names[..]).clean(cx),
abi: self.abi, abi: self.abi,
} }

View file

@ -118,30 +118,11 @@ impl<'a> fmt::Display for TyParamBounds<'a> {
} }
} }
impl fmt::Display for clean::Generics { impl fmt::Display for clean::GenericParam {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
if self.lifetimes.is_empty() && self.type_params.is_empty() { return Ok(()) } match *self {
if f.alternate() { clean::GenericParam::Lifetime(ref lp) => write!(f, "{}", lp),
f.write_str("<")?; clean::GenericParam::Type(ref tp) => {
} else {
f.write_str("&lt;")?;
}
for (i, life) in self.lifetimes.iter().enumerate() {
if i > 0 {
f.write_str(", ")?;
}
write!(f, "{}", *life)?;
}
if !self.type_params.is_empty() {
if !self.lifetimes.is_empty() {
f.write_str(", ")?;
}
for (i, tp) in self.type_params.iter().enumerate() {
if i > 0 {
f.write_str(", ")?
}
f.write_str(&tp.name)?; f.write_str(&tp.name)?;
if !tp.bounds.is_empty() { if !tp.bounds.is_empty() {
@ -158,15 +139,22 @@ impl fmt::Display for clean::Generics {
} else { } else {
write!(f, "&nbsp;=&nbsp;{}", ty)?; write!(f, "&nbsp;=&nbsp;{}", ty)?;
} }
}; }
Ok(())
} }
} }
}
}
impl fmt::Display for clean::Generics {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
if self.params.is_empty() { return Ok(()) }
if f.alternate() { if f.alternate() {
f.write_str(">")?; write!(f, "<{:#}>", CommaSep(&self.params))
} else { } else {
f.write_str("&gt;")?; write!(f, "&lt;{}&gt;", CommaSep(&self.params))
} }
Ok(())
} }
} }
@ -259,22 +247,11 @@ impl fmt::Display for clean::Lifetime {
impl fmt::Display for clean::PolyTrait { impl fmt::Display for clean::PolyTrait {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
if !self.lifetimes.is_empty() { if !self.generic_params.is_empty() {
if f.alternate() { if f.alternate() {
f.write_str("for<")?; write!(f, "for<{:#}> ", CommaSep(&self.generic_params))?;
} else { } else {
f.write_str("for&lt;")?; write!(f, "for&lt;{}&gt; ", CommaSep(&self.generic_params))?;
}
for (i, lt) in self.lifetimes.iter().enumerate() {
if i > 0 {
f.write_str(", ")?;
}
write!(f, "{}", lt)?;
}
if f.alternate() {
f.write_str("> ")?;
} else {
f.write_str("&gt; ")?;
} }
} }
if f.alternate() { if f.alternate() {
@ -602,12 +579,12 @@ fn fmt_type(t: &clean::Type, f: &mut fmt::Formatter, use_absolute: bool) -> fmt:
write!(f, "{}{:#}fn{:#}{:#}", write!(f, "{}{:#}fn{:#}{:#}",
UnsafetySpace(decl.unsafety), UnsafetySpace(decl.unsafety),
AbiSpace(decl.abi), AbiSpace(decl.abi),
decl.generics, CommaSep(&decl.generic_params),
decl.decl) decl.decl)
} else { } else {
write!(f, "{}{}", UnsafetySpace(decl.unsafety), AbiSpace(decl.abi))?; write!(f, "{}{}", UnsafetySpace(decl.unsafety), AbiSpace(decl.abi))?;
primitive_link(f, PrimitiveType::Fn, "fn")?; primitive_link(f, PrimitiveType::Fn, "fn")?;
write!(f, "{}{}", decl.generics, decl.decl) write!(f, "{}{}", CommaSep(&decl.generic_params), decl.decl)
} }
} }
clean::Tuple(ref typs) => { clean::Tuple(ref typs) => {

View file

@ -1424,8 +1424,10 @@ impl DocFolder for Cache {
impl<'a> Cache { impl<'a> Cache {
fn generics(&mut self, generics: &clean::Generics) { fn generics(&mut self, generics: &clean::Generics) {
for typ in &generics.type_params { for param in &generics.params {
self.typarams.insert(typ.did, typ.name.clone()); if let clean::GenericParam::Type(ref typ) = *param {
self.typarams.insert(typ.did, typ.name.clone());
}
} }
} }
} }

View file

@ -301,30 +301,56 @@ pub struct TyParam {
pub span: Span, pub span: Span,
} }
/// Represents lifetimes and type parameters attached to a declaration #[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
/// of a function, enum, trait, etc. pub enum GenericParam {
Lifetime(LifetimeDef),
Type(TyParam),
}
impl GenericParam {
pub fn is_lifetime_param(&self) -> bool {
match *self {
GenericParam::Lifetime(_) => true,
_ => false,
}
}
pub fn is_type_param(&self) -> bool {
match *self {
GenericParam::Type(_) => true,
_ => false,
}
}
}
/// Represents lifetime, type and const parameters attached to a declaration of
/// a function, enum, trait, etc.
#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)] #[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
pub struct Generics { pub struct Generics {
pub lifetimes: Vec<LifetimeDef>, pub params: Vec<GenericParam>,
pub ty_params: Vec<TyParam>,
pub where_clause: WhereClause, pub where_clause: WhereClause,
pub span: Span, pub span: Span,
} }
impl Generics { impl Generics {
pub fn is_lt_parameterized(&self) -> bool { pub fn is_lt_parameterized(&self) -> bool {
!self.lifetimes.is_empty() self.params.iter().any(|param| param.is_lifetime_param())
} }
pub fn is_type_parameterized(&self) -> bool { pub fn is_type_parameterized(&self) -> bool {
!self.ty_params.is_empty() self.params.iter().any(|param| param.is_type_param())
} }
pub fn is_parameterized(&self) -> bool { pub fn is_parameterized(&self) -> bool {
self.is_lt_parameterized() || self.is_type_parameterized() !self.params.is_empty()
} }
pub fn span_for_name(&self, name: &str) -> Option<Span> { pub fn span_for_name(&self, name: &str) -> Option<Span> {
for t in &self.ty_params { for param in &self.params {
if t.ident.name == name { if let GenericParam::Type(ref t) = *param {
return Some(t.span); if t.ident.name == name {
return Some(t.span);
}
} }
} }
None None
@ -335,8 +361,7 @@ impl Default for Generics {
/// Creates an instance of `Generics`. /// Creates an instance of `Generics`.
fn default() -> Generics { fn default() -> Generics {
Generics { Generics {
lifetimes: Vec::new(), params: Vec::new(),
ty_params: Vec::new(),
where_clause: WhereClause { where_clause: WhereClause {
id: DUMMY_NODE_ID, id: DUMMY_NODE_ID,
predicates: Vec::new(), predicates: Vec::new(),
@ -372,8 +397,8 @@ pub enum WherePredicate {
#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)] #[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
pub struct WhereBoundPredicate { pub struct WhereBoundPredicate {
pub span: Span, pub span: Span,
/// Any lifetimes from a `for` binding /// Any generics from a `for` binding
pub bound_lifetimes: Vec<LifetimeDef>, pub bound_generic_params: Vec<GenericParam>,
/// The type being bounded /// The type being bounded
pub bounded_ty: P<Ty>, pub bounded_ty: P<Ty>,
/// Trait and lifetime bounds (`Clone+Send+'static`) /// Trait and lifetime bounds (`Clone+Send+'static`)
@ -1461,7 +1486,7 @@ impl fmt::Debug for Ty {
pub struct BareFnTy { pub struct BareFnTy {
pub unsafety: Unsafety, pub unsafety: Unsafety,
pub abi: Abi, pub abi: Abi,
pub lifetimes: Vec<LifetimeDef>, pub generic_params: Vec<GenericParam>,
pub decl: P<FnDecl> pub decl: P<FnDecl>
} }
@ -1820,7 +1845,7 @@ pub struct TraitRef {
#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)] #[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
pub struct PolyTraitRef { pub struct PolyTraitRef {
/// The `'a` in `<'a> Foo<&'a T>` /// The `'a` in `<'a> Foo<&'a T>`
pub bound_lifetimes: Vec<LifetimeDef>, pub bound_generic_params: Vec<GenericParam>,
/// The `Foo<&'a T>` in `<'a> Foo<&'a T>` /// The `Foo<&'a T>` in `<'a> Foo<&'a T>`
pub trait_ref: TraitRef, pub trait_ref: TraitRef,
@ -1829,9 +1854,9 @@ pub struct PolyTraitRef {
} }
impl PolyTraitRef { impl PolyTraitRef {
pub fn new(lifetimes: Vec<LifetimeDef>, path: Path, span: Span) -> Self { pub fn new(generic_params: Vec<GenericParam>, path: Path, span: Span) -> Self {
PolyTraitRef { PolyTraitRef {
bound_lifetimes: lifetimes, bound_generic_params: generic_params,
trait_ref: TraitRef { path: path, ref_id: DUMMY_NODE_ID }, trait_ref: TraitRef { path: path, ref_id: DUMMY_NODE_ID },
span, span,
} }

View file

@ -462,7 +462,7 @@ impl<'a> AstBuilder for ExtCtxt<'a> {
fn poly_trait_ref(&self, span: Span, path: ast::Path) -> ast::PolyTraitRef { fn poly_trait_ref(&self, span: Span, path: ast::Path) -> ast::PolyTraitRef {
ast::PolyTraitRef { ast::PolyTraitRef {
bound_lifetimes: Vec::new(), bound_generic_params: Vec::new(),
trait_ref: self.trait_ref(path), trait_ref: self.trait_ref(path),
span, span,
} }

View file

@ -1748,22 +1748,19 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
visit::walk_vis(self, vis); visit::walk_vis(self, vis);
} }
fn visit_generics(&mut self, g: &'a ast::Generics) { fn visit_generic_param(&mut self, param: &'a ast::GenericParam) {
for t in &g.ty_params { let (attrs, explain) = match *param {
if !t.attrs.is_empty() { ast::GenericParam::Lifetime(ref ld) =>
gate_feature_post!(&self, generic_param_attrs, t.attrs[0].span, (&ld.attrs, "attributes on lifetime bindings are experimental"),
"attributes on type parameter bindings are experimental"); ast::GenericParam::Type(ref t) =>
} (&t.attrs, "attributes on type parameter bindings are experimental"),
} };
visit::walk_generics(self, g)
}
fn visit_lifetime_def(&mut self, lifetime_def: &'a ast::LifetimeDef) { if !attrs.is_empty() {
if !lifetime_def.attrs.is_empty() { gate_feature_post!(&self, generic_param_attrs, attrs[0].span, explain);
gate_feature_post!(&self, generic_param_attrs, lifetime_def.attrs[0].span,
"attributes on lifetime bindings are experimental");
} }
visit::walk_lifetime_def(self, lifetime_def)
visit::walk_generic_param(self, param)
} }
fn visit_lifetime(&mut self, lt: &'a ast::Lifetime) { fn visit_lifetime(&mut self, lt: &'a ast::Lifetime) {

View file

@ -237,8 +237,12 @@ pub trait Folder : Sized {
noop_fold_ty_param(tp, self) noop_fold_ty_param(tp, self)
} }
fn fold_ty_params(&mut self, tps: Vec<TyParam>) -> Vec<TyParam> { fn fold_generic_param(&mut self, param: GenericParam) -> GenericParam {
noop_fold_ty_params(tps, self) noop_fold_generic_param(param, self)
}
fn fold_generic_params(&mut self, params: Vec<GenericParam>) -> Vec<GenericParam> {
noop_fold_generic_params(params, self)
} }
fn fold_tt(&mut self, tt: TokenTree) -> TokenTree { fn fold_tt(&mut self, tt: TokenTree) -> TokenTree {
@ -363,8 +367,8 @@ pub fn noop_fold_ty<T: Folder>(t: P<Ty>, fld: &mut T) -> P<Ty> {
TyKind::Rptr(fld.fold_opt_lifetime(region), fld.fold_mt(mt)) TyKind::Rptr(fld.fold_opt_lifetime(region), fld.fold_mt(mt))
} }
TyKind::BareFn(f) => { TyKind::BareFn(f) => {
TyKind::BareFn(f.map(|BareFnTy {lifetimes, unsafety, abi, decl}| BareFnTy { TyKind::BareFn(f.map(|BareFnTy {generic_params, unsafety, abi, decl}| BareFnTy {
lifetimes: fld.fold_lifetime_defs(lifetimes), generic_params: fld.fold_generic_params(generic_params),
unsafety, unsafety,
abi, abi,
decl: fld.fold_fn_decl(decl) decl: fld.fold_fn_decl(decl)
@ -677,8 +681,18 @@ pub fn noop_fold_ty_param<T: Folder>(tp: TyParam, fld: &mut T) -> TyParam {
} }
} }
pub fn noop_fold_ty_params<T: Folder>(tps: Vec<TyParam>, fld: &mut T) -> Vec<TyParam> { pub fn noop_fold_generic_param<T: Folder>(param: GenericParam, fld: &mut T) -> GenericParam {
tps.move_map(|tp| fld.fold_ty_param(tp)) match param {
GenericParam::Lifetime(l) => GenericParam::Lifetime(fld.fold_lifetime_def(l)),
GenericParam::Type(t) => GenericParam::Type(fld.fold_ty_param(t)),
}
}
pub fn noop_fold_generic_params<T: Folder>(
params: Vec<GenericParam>,
fld: &mut T
) -> Vec<GenericParam> {
params.move_map(|p| fld.fold_generic_param(p))
} }
pub fn noop_fold_lifetime<T: Folder>(l: Lifetime, fld: &mut T) -> Lifetime { pub fn noop_fold_lifetime<T: Folder>(l: Lifetime, fld: &mut T) -> Lifetime {
@ -716,11 +730,10 @@ pub fn noop_fold_opt_lifetime<T: Folder>(o_lt: Option<Lifetime>, fld: &mut T)
o_lt.map(|lt| fld.fold_lifetime(lt)) o_lt.map(|lt| fld.fold_lifetime(lt))
} }
pub fn noop_fold_generics<T: Folder>(Generics {ty_params, lifetimes, where_clause, span}: Generics, pub fn noop_fold_generics<T: Folder>(Generics { params, where_clause, span }: Generics,
fld: &mut T) -> Generics { fld: &mut T) -> Generics {
Generics { Generics {
ty_params: fld.fold_ty_params(ty_params), params: fld.fold_generic_params(params),
lifetimes: fld.fold_lifetime_defs(lifetimes),
where_clause: fld.fold_where_clause(where_clause), where_clause: fld.fold_where_clause(where_clause),
span: fld.new_span(span), span: fld.new_span(span),
} }
@ -744,12 +757,12 @@ pub fn noop_fold_where_predicate<T: Folder>(
fld: &mut T) fld: &mut T)
-> WherePredicate { -> WherePredicate {
match pred { match pred {
ast::WherePredicate::BoundPredicate(ast::WhereBoundPredicate{bound_lifetimes, ast::WherePredicate::BoundPredicate(ast::WhereBoundPredicate{bound_generic_params,
bounded_ty, bounded_ty,
bounds, bounds,
span}) => { span}) => {
ast::WherePredicate::BoundPredicate(ast::WhereBoundPredicate { ast::WherePredicate::BoundPredicate(ast::WhereBoundPredicate {
bound_lifetimes: fld.fold_lifetime_defs(bound_lifetimes), bound_generic_params: fld.fold_generic_params(bound_generic_params),
bounded_ty: fld.fold_ty(bounded_ty), bounded_ty: fld.fold_ty(bounded_ty),
bounds: bounds.move_map(|x| fld.fold_ty_param_bound(x)), bounds: bounds.move_map(|x| fld.fold_ty_param_bound(x)),
span: fld.new_span(span) span: fld.new_span(span)
@ -806,7 +819,7 @@ pub fn noop_fold_trait_ref<T: Folder>(p: TraitRef, fld: &mut T) -> TraitRef {
pub fn noop_fold_poly_trait_ref<T: Folder>(p: PolyTraitRef, fld: &mut T) -> PolyTraitRef { pub fn noop_fold_poly_trait_ref<T: Folder>(p: PolyTraitRef, fld: &mut T) -> PolyTraitRef {
ast::PolyTraitRef { ast::PolyTraitRef {
bound_lifetimes: fld.fold_lifetime_defs(p.bound_lifetimes), bound_generic_params: fld.fold_generic_params(p.bound_generic_params),
trait_ref: fld.fold_trait_ref(p.trait_ref), trait_ref: fld.fold_trait_ref(p.trait_ref),
span: fld.new_span(p.span), span: fld.new_span(p.span),
} }

View file

@ -905,9 +905,8 @@ mod tests {
node: ast::Constness::NotConst, node: ast::Constness::NotConst,
}, },
Abi::Rust, Abi::Rust,
ast::Generics{ // no idea on either of these: ast::Generics{
lifetimes: Vec::new(), params: Vec::new(),
ty_params: Vec::new(),
where_clause: ast::WhereClause { where_clause: ast::WhereClause {
id: ast::DUMMY_NODE_ID, id: ast::DUMMY_NODE_ID,
predicates: Vec::new(), predicates: Vec::new(),

View file

@ -21,6 +21,7 @@ use ast::EnumDef;
use ast::{Expr, ExprKind, RangeLimits}; use ast::{Expr, ExprKind, RangeLimits};
use ast::{Field, FnDecl}; use ast::{Field, FnDecl};
use ast::{ForeignItem, ForeignItemKind, FunctionRetTy}; use ast::{ForeignItem, ForeignItemKind, FunctionRetTy};
use ast::GenericParam;
use ast::{Ident, ImplItem, IsAuto, Item, ItemKind}; use ast::{Ident, ImplItem, IsAuto, Item, ItemKind};
use ast::{Lifetime, LifetimeDef, Lit, LitKind, UintTy}; use ast::{Lifetime, LifetimeDef, Lit, LitKind, UintTy};
use ast::Local; use ast::Local;
@ -1299,7 +1300,7 @@ impl<'a> Parser<'a> {
} }
/// parse a TyKind::BareFn type: /// parse a TyKind::BareFn type:
pub fn parse_ty_bare_fn(&mut self, lifetime_defs: Vec<LifetimeDef>) pub fn parse_ty_bare_fn(&mut self, generic_params: Vec<GenericParam>)
-> PResult<'a, TyKind> { -> PResult<'a, TyKind> {
/* /*
@ -1331,7 +1332,7 @@ impl<'a> Parser<'a> {
Ok(TyKind::BareFn(P(BareFnTy { Ok(TyKind::BareFn(P(BareFnTy {
abi, abi,
unsafety, unsafety,
lifetimes: lifetime_defs, generic_params,
decl, decl,
}))) })))
} }
@ -1621,9 +1622,9 @@ impl<'a> Parser<'a> {
Ok(P(ty)) Ok(P(ty))
} }
fn parse_remaining_bounds(&mut self, lifetime_defs: Vec<LifetimeDef>, path: ast::Path, fn parse_remaining_bounds(&mut self, generic_params: Vec<GenericParam>, path: ast::Path,
lo: Span, parse_plus: bool) -> PResult<'a, TyKind> { lo: Span, parse_plus: bool) -> PResult<'a, TyKind> {
let poly_trait_ref = PolyTraitRef::new(lifetime_defs, path, lo.to(self.prev_span)); let poly_trait_ref = PolyTraitRef::new(generic_params, path, lo.to(self.prev_span));
let mut bounds = vec![TraitTyParamBound(poly_trait_ref, TraitBoundModifier::None)]; let mut bounds = vec![TraitTyParamBound(poly_trait_ref, TraitBoundModifier::None)];
if parse_plus { if parse_plus {
self.bump(); // `+` self.bump(); // `+`
@ -4590,9 +4591,8 @@ impl<'a> Parser<'a> {
/// Parses (possibly empty) list of lifetime and type parameters, possibly including /// Parses (possibly empty) list of lifetime and type parameters, possibly including
/// trailing comma and erroneous trailing attributes. /// trailing comma and erroneous trailing attributes.
pub fn parse_generic_params(&mut self) -> PResult<'a, (Vec<LifetimeDef>, Vec<TyParam>)> { pub fn parse_generic_params(&mut self) -> PResult<'a, Vec<ast::GenericParam>> {
let mut lifetime_defs = Vec::new(); let mut params = Vec::new();
let mut ty_params = Vec::new();
let mut seen_ty_param = false; let mut seen_ty_param = false;
loop { loop {
let attrs = self.parse_outer_attributes()?; let attrs = self.parse_outer_attributes()?;
@ -4604,18 +4604,18 @@ impl<'a> Parser<'a> {
} else { } else {
Vec::new() Vec::new()
}; };
lifetime_defs.push(LifetimeDef { params.push(ast::GenericParam::Lifetime(LifetimeDef {
attrs: attrs.into(), attrs: attrs.into(),
lifetime, lifetime,
bounds, bounds,
}); }));
if seen_ty_param { if seen_ty_param {
self.span_err(self.prev_span, self.span_err(self.prev_span,
"lifetime parameters must be declared prior to type parameters"); "lifetime parameters must be declared prior to type parameters");
} }
} else if self.check_ident() { } else if self.check_ident() {
// Parse type parameter. // Parse type parameter.
ty_params.push(self.parse_ty_param(attrs)?); params.push(ast::GenericParam::Type(self.parse_ty_param(attrs)?));
seen_ty_param = true; seen_ty_param = true;
} else { } else {
// Check for trailing attributes and stop parsing. // Check for trailing attributes and stop parsing.
@ -4631,7 +4631,7 @@ impl<'a> Parser<'a> {
break break
} }
} }
Ok((lifetime_defs, ty_params)) Ok(params)
} }
/// Parse a set of optional generic type parameter declarations. Where /// Parse a set of optional generic type parameter declarations. Where
@ -4646,11 +4646,10 @@ impl<'a> Parser<'a> {
let span_lo = self.span; let span_lo = self.span;
if self.eat_lt() { if self.eat_lt() {
let (lifetime_defs, ty_params) = self.parse_generic_params()?; let params = self.parse_generic_params()?;
self.expect_gt()?; self.expect_gt()?;
Ok(ast::Generics { Ok(ast::Generics {
lifetimes: lifetime_defs, params,
ty_params,
where_clause: WhereClause { where_clause: WhereClause {
id: ast::DUMMY_NODE_ID, id: ast::DUMMY_NODE_ID,
predicates: Vec::new(), predicates: Vec::new(),
@ -4778,7 +4777,7 @@ impl<'a> Parser<'a> {
where_clause.predicates.push(ast::WherePredicate::BoundPredicate( where_clause.predicates.push(ast::WherePredicate::BoundPredicate(
ast::WhereBoundPredicate { ast::WhereBoundPredicate {
span: lo.to(self.prev_span), span: lo.to(self.prev_span),
bound_lifetimes: lifetime_defs, bound_generic_params: lifetime_defs,
bounded_ty: ty, bounded_ty: ty,
bounds, bounds,
} }
@ -5403,16 +5402,24 @@ impl<'a> Parser<'a> {
} }
} }
fn parse_late_bound_lifetime_defs(&mut self) -> PResult<'a, Vec<LifetimeDef>> { fn parse_late_bound_lifetime_defs(&mut self) -> PResult<'a, Vec<GenericParam>> {
if self.eat_keyword(keywords::For) { if self.eat_keyword(keywords::For) {
self.expect_lt()?; self.expect_lt()?;
let (lifetime_defs, ty_params) = self.parse_generic_params()?; let params = self.parse_generic_params()?;
self.expect_gt()?; self.expect_gt()?;
if !ty_params.is_empty() {
self.span_err(ty_params[0].span, let first_non_lifetime_param_span = params.iter()
"only lifetime parameters can be used in this context"); .filter_map(|param| match *param {
ast::GenericParam::Lifetime(_) => None,
ast::GenericParam::Type(ref t) => Some(t.span),
})
.next();
if let Some(span) = first_non_lifetime_param_span {
self.span_err(span, "only lifetime parameters can be used in this context");
} }
Ok(lifetime_defs)
Ok(params)
} else { } else {
Ok(Vec::new()) Ok(Vec::new())
} }

View file

@ -275,7 +275,7 @@ pub fn token_to_string(tok: &Token) -> String {
token::NtArm(ref e) => arm_to_string(e), token::NtArm(ref e) => arm_to_string(e),
token::NtImplItem(ref e) => impl_item_to_string(e), token::NtImplItem(ref e) => impl_item_to_string(e),
token::NtTraitItem(ref e) => trait_item_to_string(e), token::NtTraitItem(ref e) => trait_item_to_string(e),
token::NtGenerics(ref e) => generics_to_string(e), token::NtGenerics(ref e) => generic_params_to_string(&e.params),
token::NtWhereClause(ref e) => where_clause_to_string(e), token::NtWhereClause(ref e) => where_clause_to_string(e),
token::NtArg(ref e) => arg_to_string(e), token::NtArg(ref e) => arg_to_string(e),
token::NtVis(ref e) => vis_to_string(e), token::NtVis(ref e) => vis_to_string(e),
@ -339,8 +339,8 @@ pub fn trait_item_to_string(i: &ast::TraitItem) -> String {
to_string(|s| s.print_trait_item(i)) to_string(|s| s.print_trait_item(i))
} }
pub fn generics_to_string(generics: &ast::Generics) -> String { pub fn generic_params_to_string(generic_params: &[ast::GenericParam]) -> String {
to_string(|s| s.print_generics(generics)) to_string(|s| s.print_generic_params(generic_params))
} }
pub fn where_clause_to_string(i: &ast::WhereClause) -> String { pub fn where_clause_to_string(i: &ast::WhereClause) -> String {
@ -1043,21 +1043,11 @@ impl<'a> State<'a> {
self.pclose()?; self.pclose()?;
} }
ast::TyKind::BareFn(ref f) => { ast::TyKind::BareFn(ref f) => {
let generics = ast::Generics {
lifetimes: f.lifetimes.clone(),
ty_params: Vec::new(),
where_clause: ast::WhereClause {
id: ast::DUMMY_NODE_ID,
predicates: Vec::new(),
span: syntax_pos::DUMMY_SP,
},
span: syntax_pos::DUMMY_SP,
};
self.print_ty_fn(f.abi, self.print_ty_fn(f.abi,
f.unsafety, f.unsafety,
&f.decl, &f.decl,
None, None,
&generics)?; &f.generic_params)?;
} }
ast::TyKind::Path(None, ref path) => { ast::TyKind::Path(None, ref path) => {
self.print_path(path, false, 0, false)?; self.print_path(path, false, 0, false)?;
@ -1271,15 +1261,15 @@ impl<'a> State<'a> {
self.s.word(&ga.asm.as_str())?; self.s.word(&ga.asm.as_str())?;
self.end()?; self.end()?;
} }
ast::ItemKind::Ty(ref ty, ref params) => { ast::ItemKind::Ty(ref ty, ref generics) => {
self.ibox(INDENT_UNIT)?; self.ibox(INDENT_UNIT)?;
self.ibox(0)?; self.ibox(0)?;
self.word_nbsp(&visibility_qualified(&item.vis, "type"))?; self.word_nbsp(&visibility_qualified(&item.vis, "type"))?;
self.print_ident(item.ident)?; self.print_ident(item.ident)?;
self.print_generics(params)?; self.print_generic_params(&generics.params)?;
self.end()?; // end the inner ibox self.end()?; // end the inner ibox
self.print_where_clause(&params.where_clause)?; self.print_where_clause(&generics.where_clause)?;
self.s.space()?; self.s.space()?;
self.word_space("=")?; self.word_space("=")?;
self.print_type(ty)?; self.print_type(ty)?;
@ -1329,7 +1319,7 @@ impl<'a> State<'a> {
self.word_nbsp("impl")?; self.word_nbsp("impl")?;
if generics.is_parameterized() { if generics.is_parameterized() {
self.print_generics(generics)?; self.print_generic_params(&generics.params)?;
self.s.space()?; self.s.space()?;
} }
@ -1361,7 +1351,7 @@ impl<'a> State<'a> {
self.print_is_auto(is_auto)?; self.print_is_auto(is_auto)?;
self.word_nbsp("trait")?; self.word_nbsp("trait")?;
self.print_ident(item.ident)?; self.print_ident(item.ident)?;
self.print_generics(generics)?; self.print_generic_params(&generics.params)?;
let mut real_bounds = Vec::with_capacity(bounds.len()); let mut real_bounds = Vec::with_capacity(bounds.len());
for b in bounds.iter() { for b in bounds.iter() {
if let TraitTyParamBound(ref ptr, ast::TraitBoundModifier::Maybe) = *b { if let TraitTyParamBound(ref ptr, ast::TraitBoundModifier::Maybe) = *b {
@ -1386,7 +1376,7 @@ impl<'a> State<'a> {
self.print_visibility(&item.vis)?; self.print_visibility(&item.vis)?;
self.word_nbsp("trait")?; self.word_nbsp("trait")?;
self.print_ident(item.ident)?; self.print_ident(item.ident)?;
self.print_generics(generics)?; self.print_generic_params(&generics.params)?;
let mut real_bounds = Vec::with_capacity(bounds.len()); let mut real_bounds = Vec::with_capacity(bounds.len());
// FIXME(durka) this seems to be some quite outdated syntax // FIXME(durka) this seems to be some quite outdated syntax
for b in bounds.iter() { for b in bounds.iter() {
@ -1432,26 +1422,20 @@ impl<'a> State<'a> {
self.print_path(&t.path, false, 0, false) self.print_path(&t.path, false, 0, false)
} }
fn print_formal_lifetime_list(&mut self, lifetimes: &[ast::LifetimeDef]) -> io::Result<()> { fn print_formal_generic_params(
if !lifetimes.is_empty() { &mut self,
self.s.word("for<")?; generic_params: &[ast::GenericParam]
let mut comma = false; ) -> io::Result<()> {
for lifetime_def in lifetimes { if !generic_params.is_empty() {
if comma { self.s.word("for")?;
self.word_space(",")? self.print_generic_params(generic_params)?;
}
self.print_outer_attributes_inline(&lifetime_def.attrs)?;
self.print_lifetime_bounds(&lifetime_def.lifetime, &lifetime_def.bounds)?;
comma = true;
}
self.s.word(">")?;
self.nbsp()?; self.nbsp()?;
} }
Ok(()) Ok(())
} }
fn print_poly_trait_ref(&mut self, t: &ast::PolyTraitRef) -> io::Result<()> { fn print_poly_trait_ref(&mut self, t: &ast::PolyTraitRef) -> io::Result<()> {
self.print_formal_lifetime_list(&t.bound_lifetimes)?; self.print_formal_generic_params(&t.bound_generic_params)?;
self.print_trait_ref(&t.trait_ref) self.print_trait_ref(&t.trait_ref)
} }
@ -1461,7 +1445,7 @@ impl<'a> State<'a> {
visibility: &ast::Visibility) -> io::Result<()> { visibility: &ast::Visibility) -> io::Result<()> {
self.head(&visibility_qualified(visibility, "enum"))?; self.head(&visibility_qualified(visibility, "enum"))?;
self.print_ident(ident)?; self.print_ident(ident)?;
self.print_generics(generics)?; self.print_generic_params(&generics.params)?;
self.print_where_clause(&generics.where_clause)?; self.print_where_clause(&generics.where_clause)?;
self.s.space()?; self.s.space()?;
self.print_variants(&enum_definition.variants, span) self.print_variants(&enum_definition.variants, span)
@ -1517,7 +1501,7 @@ impl<'a> State<'a> {
span: syntax_pos::Span, span: syntax_pos::Span,
print_finalizer: bool) -> io::Result<()> { print_finalizer: bool) -> io::Result<()> {
self.print_ident(ident)?; self.print_ident(ident)?;
self.print_generics(generics)?; self.print_generic_params(&generics.params)?;
if !struct_def.is_struct() { if !struct_def.is_struct() {
if struct_def.is_tuple() { if struct_def.is_tuple() {
self.popen()?; self.popen()?;
@ -2764,7 +2748,7 @@ impl<'a> State<'a> {
self.nbsp()?; self.nbsp()?;
self.print_ident(name)?; self.print_ident(name)?;
} }
self.print_generics(generics)?; self.print_generic_params(&generics.params)?;
self.print_fn_args_and_ret(decl)?; self.print_fn_args_and_ret(decl)?;
self.print_where_clause(&generics.where_clause) self.print_where_clause(&generics.where_clause)
} }
@ -2870,31 +2854,23 @@ impl<'a> State<'a> {
Ok(()) Ok(())
} }
pub fn print_generics(&mut self, pub fn print_generic_params(
generics: &ast::Generics) &mut self,
-> io::Result<()> generic_params: &[ast::GenericParam]
{ ) -> io::Result<()> {
let total = generics.lifetimes.len() + generics.ty_params.len(); if generic_params.is_empty() {
if total == 0 {
return Ok(()); return Ok(());
} }
self.s.word("<")?; self.s.word("<")?;
let mut ints = Vec::new(); self.commasep(Inconsistent, &generic_params, |s, param| {
for i in 0..total { match *param {
ints.push(i); ast::GenericParam::Lifetime(ref lifetime_def) => {
} s.print_outer_attributes_inline(&lifetime_def.attrs)?;
s.print_lifetime_bounds(&lifetime_def.lifetime, &lifetime_def.bounds)
self.commasep(Inconsistent, &ints[..], |s, &idx| { },
if idx < generics.lifetimes.len() { ast::GenericParam::Type(ref ty_param) => s.print_ty_param(ty_param),
let lifetime_def = &generics.lifetimes[idx];
s.print_outer_attributes_inline(&lifetime_def.attrs)?;
s.print_lifetime_bounds(&lifetime_def.lifetime, &lifetime_def.bounds)
} else {
let idx = idx - generics.lifetimes.len();
let param = &generics.ty_params[idx];
s.print_ty_param(param)
} }
})?; })?;
@ -2931,11 +2907,13 @@ impl<'a> State<'a> {
} }
match *predicate { match *predicate {
ast::WherePredicate::BoundPredicate(ast::WhereBoundPredicate{ref bound_lifetimes, ast::WherePredicate::BoundPredicate(ast::WhereBoundPredicate {
ref bounded_ty, ref bound_generic_params,
ref bounds, ref bounded_ty,
..}) => { ref bounds,
self.print_formal_lifetime_list(bound_lifetimes)?; ..
}) => {
self.print_formal_generic_params(bound_generic_params)?;
self.print_type(bounded_ty)?; self.print_type(bounded_ty)?;
self.print_bounds(":", bounds)?; self.print_bounds(":", bounds)?;
} }
@ -3057,16 +3035,15 @@ impl<'a> State<'a> {
unsafety: ast::Unsafety, unsafety: ast::Unsafety,
decl: &ast::FnDecl, decl: &ast::FnDecl,
name: Option<ast::Ident>, name: Option<ast::Ident>,
generics: &ast::Generics) generic_params: &Vec<ast::GenericParam>)
-> io::Result<()> { -> io::Result<()> {
self.ibox(INDENT_UNIT)?; self.ibox(INDENT_UNIT)?;
if !generics.lifetimes.is_empty() || !generics.ty_params.is_empty() { if !generic_params.is_empty() {
self.s.word("for")?; self.s.word("for")?;
self.print_generics(generics)?; self.print_generic_params(generic_params)?;
} }
let generics = ast::Generics { let generics = ast::Generics {
lifetimes: Vec::new(), params: Vec::new(),
ty_params: Vec::new(),
where_clause: ast::WhereClause { where_clause: ast::WhereClause {
id: ast::DUMMY_NODE_ID, id: ast::DUMMY_NODE_ID,
predicates: Vec::new(), predicates: Vec::new(),

View file

@ -363,7 +363,10 @@ fn is_bench_fn(cx: &TestCtxt, i: &ast::Item) -> bool {
ast::FunctionRetTy::Ty(ref t) if t.node == ast::TyKind::Tup(vec![]) => true, ast::FunctionRetTy::Ty(ref t) if t.node == ast::TyKind::Tup(vec![]) => true,
_ => false _ => false
}; };
let tparm_cnt = generics.ty_params.len(); let tparm_cnt = generics.params.iter()
.filter(|param| param.is_type_param())
.count();
// NB: inadequate check, but we're running // NB: inadequate check, but we're running
// well before resolve, can't get too deep. // well before resolve, can't get too deep.
input_cnt == 1 input_cnt == 1

View file

@ -71,6 +71,10 @@ impl<'ast> Visitor<'ast> for NodeCounter {
self.count += 1; self.count += 1;
walk_ty(self, t) walk_ty(self, t)
} }
fn visit_generic_param(&mut self, param: &GenericParam) {
self.count += 1;
walk_generic_param(self, param)
}
fn visit_generics(&mut self, g: &Generics) { fn visit_generics(&mut self, g: &Generics) {
self.count += 1; self.count += 1;
walk_generics(self, g) walk_generics(self, g)
@ -121,10 +125,6 @@ impl<'ast> Visitor<'ast> for NodeCounter {
self.count += 1; self.count += 1;
walk_lifetime(self, lifetime) walk_lifetime(self, lifetime)
} }
fn visit_lifetime_def(&mut self, lifetime: &LifetimeDef) {
self.count += 1;
walk_lifetime_def(self, lifetime)
}
fn visit_mac(&mut self, _mac: &Mac) { fn visit_mac(&mut self, _mac: &Mac) {
self.count += 1; self.count += 1;
walk_mac(self, _mac) walk_mac(self, _mac)

View file

@ -72,6 +72,7 @@ pub trait Visitor<'ast>: Sized {
fn visit_expr(&mut self, ex: &'ast Expr) { walk_expr(self, ex) } fn visit_expr(&mut self, ex: &'ast Expr) { walk_expr(self, ex) }
fn visit_expr_post(&mut self, _ex: &'ast Expr) { } fn visit_expr_post(&mut self, _ex: &'ast Expr) { }
fn visit_ty(&mut self, t: &'ast Ty) { walk_ty(self, t) } fn visit_ty(&mut self, t: &'ast Ty) { walk_ty(self, t) }
fn visit_generic_param(&mut self, param: &'ast GenericParam) { walk_generic_param(self, param) }
fn visit_generics(&mut self, g: &'ast Generics) { walk_generics(self, g) } fn visit_generics(&mut self, g: &'ast Generics) { walk_generics(self, g) }
fn visit_where_predicate(&mut self, p: &'ast WherePredicate) { fn visit_where_predicate(&mut self, p: &'ast WherePredicate) {
walk_where_predicate(self, p) walk_where_predicate(self, p)
@ -103,9 +104,6 @@ pub trait Visitor<'ast>: Sized {
fn visit_lifetime(&mut self, lifetime: &'ast Lifetime) { fn visit_lifetime(&mut self, lifetime: &'ast Lifetime) {
walk_lifetime(self, lifetime) walk_lifetime(self, lifetime)
} }
fn visit_lifetime_def(&mut self, lifetime: &'ast LifetimeDef) {
walk_lifetime_def(self, lifetime)
}
fn visit_mac(&mut self, _mac: &'ast Mac) { fn visit_mac(&mut self, _mac: &'ast Mac) {
panic!("visit_mac disabled by default"); panic!("visit_mac disabled by default");
// NB: see note about macros above. // NB: see note about macros above.
@ -210,18 +208,12 @@ pub fn walk_lifetime<'a, V: Visitor<'a>>(visitor: &mut V, lifetime: &'a Lifetime
visitor.visit_ident(lifetime.span, lifetime.ident); visitor.visit_ident(lifetime.span, lifetime.ident);
} }
pub fn walk_lifetime_def<'a, V: Visitor<'a>>(visitor: &mut V, lifetime_def: &'a LifetimeDef) {
visitor.visit_lifetime(&lifetime_def.lifetime);
walk_list!(visitor, visit_lifetime, &lifetime_def.bounds);
walk_list!(visitor, visit_attribute, &*lifetime_def.attrs);
}
pub fn walk_poly_trait_ref<'a, V>(visitor: &mut V, pub fn walk_poly_trait_ref<'a, V>(visitor: &mut V,
trait_ref: &'a PolyTraitRef, trait_ref: &'a PolyTraitRef,
_: &TraitBoundModifier) _: &TraitBoundModifier)
where V: Visitor<'a>, where V: Visitor<'a>,
{ {
walk_list!(visitor, visit_lifetime_def, &trait_ref.bound_lifetimes); walk_list!(visitor, visit_generic_param, &trait_ref.bound_generic_params);
visitor.visit_trait_ref(&trait_ref.trait_ref); visitor.visit_trait_ref(&trait_ref.trait_ref);
} }
@ -339,7 +331,7 @@ pub fn walk_ty<'a, V: Visitor<'a>>(visitor: &mut V, typ: &'a Ty) {
} }
TyKind::BareFn(ref function_declaration) => { TyKind::BareFn(ref function_declaration) => {
walk_fn_decl(visitor, &function_declaration.decl); walk_fn_decl(visitor, &function_declaration.decl);
walk_list!(visitor, visit_lifetime_def, &function_declaration.lifetimes); walk_list!(visitor, visit_generic_param, &function_declaration.generic_params);
} }
TyKind::Path(ref maybe_qself, ref path) => { TyKind::Path(ref maybe_qself, ref path) => {
if let Some(ref qself) = *maybe_qself { if let Some(ref qself) = *maybe_qself {
@ -499,14 +491,24 @@ pub fn walk_ty_param_bound<'a, V: Visitor<'a>>(visitor: &mut V, bound: &'a TyPar
} }
} }
pub fn walk_generics<'a, V: Visitor<'a>>(visitor: &mut V, generics: &'a Generics) { pub fn walk_generic_param<'a, V: Visitor<'a>>(visitor: &mut V, param: &'a GenericParam) {
for param in &generics.ty_params { match *param {
visitor.visit_ident(param.span, param.ident); GenericParam::Lifetime(ref l) => {
walk_list!(visitor, visit_ty_param_bound, &param.bounds); visitor.visit_lifetime(&l.lifetime);
walk_list!(visitor, visit_ty, &param.default); walk_list!(visitor, visit_lifetime, &l.bounds);
walk_list!(visitor, visit_attribute, &*param.attrs); walk_list!(visitor, visit_attribute, &*l.attrs);
}
GenericParam::Type(ref t) => {
visitor.visit_ident(t.span, t.ident);
walk_list!(visitor, visit_ty_param_bound, &t.bounds);
walk_list!(visitor, visit_ty, &t.default);
walk_list!(visitor, visit_attribute, &*t.attrs);
}
} }
walk_list!(visitor, visit_lifetime_def, &generics.lifetimes); }
pub fn walk_generics<'a, V: Visitor<'a>>(visitor: &mut V, generics: &'a Generics) {
walk_list!(visitor, visit_generic_param, &generics.params);
walk_list!(visitor, visit_where_predicate, &generics.where_clause.predicates); walk_list!(visitor, visit_where_predicate, &generics.where_clause.predicates);
} }
@ -514,11 +516,11 @@ pub fn walk_where_predicate<'a, V: Visitor<'a>>(visitor: &mut V, predicate: &'a
match *predicate { match *predicate {
WherePredicate::BoundPredicate(WhereBoundPredicate{ref bounded_ty, WherePredicate::BoundPredicate(WhereBoundPredicate{ref bounded_ty,
ref bounds, ref bounds,
ref bound_lifetimes, ref bound_generic_params,
..}) => { ..}) => {
visitor.visit_ty(bounded_ty); visitor.visit_ty(bounded_ty);
walk_list!(visitor, visit_ty_param_bound, bounds); walk_list!(visitor, visit_ty_param_bound, bounds);
walk_list!(visitor, visit_lifetime_def, bound_lifetimes); walk_list!(visitor, visit_generic_param, bound_generic_params);
} }
WherePredicate::RegionPredicate(WhereRegionPredicate{ref lifetime, WherePredicate::RegionPredicate(WhereRegionPredicate{ref lifetime,
ref bounds, ref bounds,

View file

@ -45,15 +45,23 @@ pub fn expand_deriving_clone(cx: &mut ExtCtxt,
match *item { match *item {
Annotatable::Item(ref annitem) => { Annotatable::Item(ref annitem) => {
match annitem.node { match annitem.node {
ItemKind::Struct(_, Generics { ref ty_params, .. }) | ItemKind::Struct(_, Generics { ref params, .. }) |
ItemKind::Enum(_, Generics { ref ty_params, .. }) ItemKind::Enum(_, Generics { ref params, .. }) => {
if attr::contains_name(&annitem.attrs, "rustc_copy_clone_marker") && if attr::contains_name(&annitem.attrs, "rustc_copy_clone_marker") &&
ty_params.is_empty() => { !params.iter().any(|param| param.is_type_param())
bounds = vec![]; {
is_shallow = true; bounds = vec![];
substructure = combine_substructure(Box::new(|c, s, sub| { is_shallow = true;
cs_clone_shallow("Clone", c, s, sub, false) substructure = combine_substructure(Box::new(|c, s, sub| {
})); cs_clone_shallow("Clone", c, s, sub, false)
}));
} else {
bounds = vec![];
is_shallow = false;
substructure = combine_substructure(Box::new(|c, s, sub| {
cs_clone("Clone", c, s, sub)
}));
}
} }
ItemKind::Union(..) => { ItemKind::Union(..) => {
bounds = vec![Literal(path_std!(cx, marker::Copy))]; bounds = vec![Literal(path_std!(cx, marker::Copy))];

View file

@ -192,7 +192,9 @@ use std::collections::HashSet;
use std::vec; use std::vec;
use syntax::abi::Abi; use syntax::abi::Abi;
use syntax::ast::{self, BinOpKind, EnumDef, Expr, Generics, Ident, PatKind, VariantData}; use syntax::ast::{
self, BinOpKind, EnumDef, Expr, GenericParam, Generics, Ident, PatKind, VariantData
};
use syntax::attr; use syntax::attr;
use syntax::ext::base::{Annotatable, ExtCtxt}; use syntax::ext::base::{Annotatable, ExtCtxt};
use syntax::ext::build::AstBuilder; use syntax::ext::build::AstBuilder;
@ -417,7 +419,7 @@ impl<'a> TraitDef<'a> {
ast::ItemKind::Struct(_, ref generics) | ast::ItemKind::Struct(_, ref generics) |
ast::ItemKind::Enum(_, ref generics) | ast::ItemKind::Enum(_, ref generics) |
ast::ItemKind::Union(_, ref generics) => { ast::ItemKind::Union(_, ref generics) => {
generics.ty_params.is_empty() !generics.params.iter().any(|p| p.is_type_param())
} }
_ => { _ => {
// Non-ADT derive is an error, but it should have been // Non-ADT derive is an error, but it should have been
@ -537,32 +539,35 @@ impl<'a> TraitDef<'a> {
} }
}); });
let Generics { mut lifetimes, mut ty_params, mut where_clause, span } = self.generics let Generics { mut params, mut where_clause, span } = self.generics
.to_generics(cx, self.span, type_ident, generics); .to_generics(cx, self.span, type_ident, generics);
// Copy the lifetimes // Create the generic parameters
lifetimes.extend(generics.lifetimes.iter().cloned()); params.extend(generics.params.iter().map(|param| {
match *param {
ref l @ GenericParam::Lifetime(_) => l.clone(),
GenericParam::Type(ref ty_param) => {
// I don't think this can be moved out of the loop, since
// a TyParamBound requires an ast id
let mut bounds: Vec<_> =
// extra restrictions on the generics parameters to the
// type being derived upon
self.additional_bounds.iter().map(|p| {
cx.typarambound(p.to_path(cx, self.span,
type_ident, generics))
}).collect();
// Create the type parameters. // require the current trait
ty_params.extend(generics.ty_params.iter().map(|ty_param| { bounds.push(cx.typarambound(trait_path.clone()));
// I don't think this can be moved out of the loop, since
// a TyParamBound requires an ast id
let mut bounds: Vec<_> =
// extra restrictions on the generics parameters to the type being derived upon
self.additional_bounds.iter().map(|p| {
cx.typarambound(p.to_path(cx, self.span,
type_ident, generics))
}).collect();
// require the current trait // also add in any bounds from the declaration
bounds.push(cx.typarambound(trait_path.clone())); for declared_bound in ty_param.bounds.iter() {
bounds.push((*declared_bound).clone());
}
// also add in any bounds from the declaration GenericParam::Type(cx.typaram(self.span, ty_param.ident, vec![], bounds, None))
for declared_bound in ty_param.bounds.iter() { }
bounds.push((*declared_bound).clone());
} }
cx.typaram(self.span, ty_param.ident, vec![], bounds, None)
})); }));
// and similarly for where clauses // and similarly for where clauses
@ -571,7 +576,7 @@ impl<'a> TraitDef<'a> {
ast::WherePredicate::BoundPredicate(ref wb) => { ast::WherePredicate::BoundPredicate(ref wb) => {
ast::WherePredicate::BoundPredicate(ast::WhereBoundPredicate { ast::WherePredicate::BoundPredicate(ast::WhereBoundPredicate {
span: self.span, span: self.span,
bound_lifetimes: wb.bound_lifetimes.clone(), bound_generic_params: wb.bound_generic_params.clone(),
bounded_ty: wb.bounded_ty.clone(), bounded_ty: wb.bounded_ty.clone(),
bounds: wb.bounds.iter().cloned().collect(), bounds: wb.bounds.iter().cloned().collect(),
}) })
@ -594,49 +599,61 @@ impl<'a> TraitDef<'a> {
} }
})); }));
if !ty_params.is_empty() { {
let ty_param_names: Vec<ast::Name> = ty_params.iter() // Extra scope required here so ty_params goes out of scope before params is moved
.map(|ty_param| ty_param.ident.name)
.collect();
let mut processed_field_types = HashSet::new(); let mut ty_params = params.iter()
for field_ty in field_tys { .filter_map(|param| match *param {
let tys = find_type_parameters(&field_ty, &ty_param_names, self.span, cx); ast::GenericParam::Type(ref t) => Some(t),
_ => None,
})
.peekable();
for ty in tys { if ty_params.peek().is_some() {
// if we have already handled this type, skip it let ty_param_names: Vec<ast::Name> = ty_params
if let ast::TyKind::Path(_, ref p) = ty.node { .map(|ty_param| ty_param.ident.name)
if p.segments.len() == 1 && .collect();
ty_param_names.contains(&p.segments[0].identifier.name) ||
processed_field_types.contains(&p.segments) { let mut processed_field_types = HashSet::new();
continue; for field_ty in field_tys {
let tys = find_type_parameters(&field_ty, &ty_param_names, self.span, cx);
for ty in tys {
// if we have already handled this type, skip it
if let ast::TyKind::Path(_, ref p) = ty.node {
if p.segments.len() == 1 &&
ty_param_names.contains(&p.segments[0].identifier.name) ||
processed_field_types.contains(&p.segments) {
continue;
};
processed_field_types.insert(p.segments.clone());
}
let mut bounds: Vec<_> = self.additional_bounds
.iter()
.map(|p| {
cx.typarambound(p.to_path(cx, self.span, type_ident, generics))
})
.collect();
// require the current trait
bounds.push(cx.typarambound(trait_path.clone()));
let predicate = ast::WhereBoundPredicate {
span: self.span,
bound_generic_params: Vec::new(),
bounded_ty: ty,
bounds,
}; };
processed_field_types.insert(p.segments.clone());
let predicate = ast::WherePredicate::BoundPredicate(predicate);
where_clause.predicates.push(predicate);
} }
let mut bounds: Vec<_> = self.additional_bounds
.iter()
.map(|p| cx.typarambound(p.to_path(cx, self.span, type_ident, generics)))
.collect();
// require the current trait
bounds.push(cx.typarambound(trait_path.clone()));
let predicate = ast::WhereBoundPredicate {
span: self.span,
bound_lifetimes: vec![],
bounded_ty: ty,
bounds,
};
let predicate = ast::WherePredicate::BoundPredicate(predicate);
where_clause.predicates.push(predicate);
} }
} }
} }
let trait_generics = Generics { let trait_generics = Generics {
lifetimes, params,
ty_params,
where_clause, where_clause,
span, span,
}; };
@ -645,14 +662,21 @@ impl<'a> TraitDef<'a> {
let trait_ref = cx.trait_ref(trait_path); let trait_ref = cx.trait_ref(trait_path);
// Create the type parameters on the `self` path. // Create the type parameters on the `self` path.
let self_ty_params = generics.ty_params let self_ty_params = generics.params
.iter() .iter()
.map(|ty_param| cx.ty_ident(self.span, ty_param.ident)) .filter_map(|param| match *param {
GenericParam::Type(ref ty_param)
=> Some(cx.ty_ident(self.span, ty_param.ident)),
_ => None,
})
.collect(); .collect();
let self_lifetimes: Vec<ast::Lifetime> = generics.lifetimes let self_lifetimes: Vec<ast::Lifetime> = generics.params
.iter() .iter()
.map(|ld| ld.lifetime) .filter_map(|param| match *param {
GenericParam::Lifetime(ref ld) => Some(ld.lifetime),
_ => None,
})
.collect(); .collect();
// Create the type of `self`. // Create the type of `self`.

View file

@ -15,7 +15,7 @@ pub use self::PtrTy::*;
pub use self::Ty::*; pub use self::Ty::*;
use syntax::ast; use syntax::ast;
use syntax::ast::{Expr, Generics, Ident, SelfKind}; use syntax::ast::{Expr, GenericParam, Generics, Ident, SelfKind};
use syntax::ext::base::ExtCtxt; use syntax::ext::base::ExtCtxt;
use syntax::ext::build::AstBuilder; use syntax::ext::build::AstBuilder;
use syntax::codemap::respan; use syntax::codemap::respan;
@ -185,13 +185,20 @@ impl<'a> Ty<'a> {
-> ast::Path { -> ast::Path {
match *self { match *self {
Self_ => { Self_ => {
let self_params = self_generics.ty_params let self_params = self_generics.params
.iter() .iter()
.map(|ty_param| cx.ty_ident(span, ty_param.ident)) .filter_map(|param| match *param {
GenericParam::Type(ref ty_param) => Some(cx.ty_ident(span, ty_param.ident)),
_ => None,
})
.collect(); .collect();
let lifetimes = self_generics.lifetimes
let lifetimes: Vec<ast::Lifetime> = self_generics.params
.iter() .iter()
.map(|d| d.lifetime) .filter_map(|param| match *param {
GenericParam::Lifetime(ref ld) => Some(ld.lifetime),
_ => None,
})
.collect(); .collect();
cx.path_all(span, cx.path_all(span,
@ -226,11 +233,9 @@ fn mk_ty_param(cx: &ExtCtxt,
cx.typaram(span, cx.ident_of(name), attrs.to_owned(), bounds, None) cx.typaram(span, cx.ident_of(name), attrs.to_owned(), bounds, None)
} }
fn mk_generics(lifetimes: Vec<ast::LifetimeDef>, ty_params: Vec<ast::TyParam>, span: Span) fn mk_generics(params: Vec<GenericParam>, span: Span) -> Generics {
-> Generics {
Generics { Generics {
lifetimes, params,
ty_params,
where_clause: ast::WhereClause { where_clause: ast::WhereClause {
id: ast::DUMMY_NODE_ID, id: ast::DUMMY_NODE_ID,
predicates: Vec::new(), predicates: Vec::new(),
@ -260,26 +265,26 @@ impl<'a> LifetimeBounds<'a> {
self_ty: Ident, self_ty: Ident,
self_generics: &Generics) self_generics: &Generics)
-> Generics { -> Generics {
let lifetimes = self.lifetimes let generic_params = self.lifetimes
.iter() .iter()
.map(|&(lt, ref bounds)| { .map(|&(lt, ref bounds)| {
let bounds = bounds.iter() let bounds = bounds.iter()
.map(|b| cx.lifetime(span, Ident::from_str(b))) .map(|b| cx.lifetime(span, Ident::from_str(b)))
.collect(); .collect();
cx.lifetime_def(span, Ident::from_str(lt), vec![], bounds) GenericParam::Lifetime(cx.lifetime_def(span, Ident::from_str(lt), vec![], bounds))
}) })
.chain(self.bounds
.iter()
.map(|t| {
let (name, ref bounds) = *t;
GenericParam::Type(mk_ty_param(
cx, span, name, &[], &bounds, self_ty, self_generics
))
})
)
.collect(); .collect();
let ty_params = self.bounds
.iter() mk_generics(generic_params, span)
.map(|t| {
match *t {
(ref name, ref bounds) => {
mk_ty_param(cx, span, *name, &[], bounds, self_ty, self_generics)
}
}
})
.collect();
mk_generics(lifetimes, ty_params, span)
} }
} }

View file

@ -121,10 +121,12 @@ fn hygienic_type_parameter(item: &Annotatable, base: &str) -> String {
let mut typaram = String::from(base); let mut typaram = String::from(base);
if let Annotatable::Item(ref item) = *item { if let Annotatable::Item(ref item) = *item {
match item.node { match item.node {
ast::ItemKind::Struct(_, ast::Generics { ref ty_params, .. }) | ast::ItemKind::Struct(_, ast::Generics { ref params, .. }) |
ast::ItemKind::Enum(_, ast::Generics { ref ty_params, .. }) => { ast::ItemKind::Enum(_, ast::Generics { ref params, .. }) => {
for ty in ty_params.iter() { for param in params.iter() {
typaram.push_str(&ty.ident.name.as_str()); if let ast::GenericParam::Type(ref ty) = *param{
typaram.push_str(&ty.ident.name.as_str());
}
} }
} }

View file

@ -89,9 +89,9 @@ error[E0309]: the parameter type `T` may not live long enough
56 | with_signature(cell, t, |cell, t| require(cell, t)); 56 | with_signature(cell, t, |cell, t| require(cell, t));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^^^^^^^^^^^^
| |
= help: consider adding an explicit lifetime bound `T: ReFree(DefId(0/0:8 ~ projection_one_region_closure[317d]::no_relationships_late[0]), BrNamed(crate0:DefIndex(1:17), 'a))`... = help: consider adding an explicit lifetime bound `T: ReFree(DefId(0/0:8 ~ projection_one_region_closure[317d]::no_relationships_late[0]), BrNamed(crate0:DefIndex(1:16), 'a))`...
error: free region `ReEarlyBound(0, 'b)` does not outlive free region `ReFree(DefId(0/0:8 ~ projection_one_region_closure[317d]::no_relationships_late[0]), BrNamed(crate0:DefIndex(1:17), 'a))` error: free region `ReEarlyBound(0, 'b)` does not outlive free region `ReFree(DefId(0/0:8 ~ projection_one_region_closure[317d]::no_relationships_late[0]), BrNamed(crate0:DefIndex(1:16), 'a))`
--> $DIR/projection-one-region-closure.rs:56:20 --> $DIR/projection-one-region-closure.rs:56:20
| |
56 | with_signature(cell, t, |cell, t| require(cell, t)); 56 | with_signature(cell, t, |cell, t| require(cell, t));

View file

@ -94,7 +94,7 @@ note: External requirements
= note: number of external vids: 3 = note: number of external vids: 3
= note: where '_#1r: '_#2r = note: where '_#1r: '_#2r
error: free region `ReEarlyBound(0, 'b)` does not outlive free region `ReFree(DefId(0/0:8 ~ projection_one_region_trait_bound_closure[317d]::no_relationships_late[0]), BrNamed(crate0:DefIndex(1:17), 'a))` error: free region `ReEarlyBound(0, 'b)` does not outlive free region `ReFree(DefId(0/0:8 ~ projection_one_region_trait_bound_closure[317d]::no_relationships_late[0]), BrNamed(crate0:DefIndex(1:16), 'a))`
--> $DIR/projection-one-region-trait-bound-closure.rs:48:20 --> $DIR/projection-one-region-trait-bound-closure.rs:48:20
| |
48 | with_signature(cell, t, |cell, t| require(cell, t)); 48 | with_signature(cell, t, |cell, t| require(cell, t));

View file

@ -158,7 +158,7 @@ error[E0309]: the associated type `<T as Anything<'_#5r, '_#6r>>::AssocType` may
49 | with_signature(cell, t, |cell, t| require(cell, t)); 49 | with_signature(cell, t, |cell, t| require(cell, t));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^^^^^^^^^^^^
| |
= help: consider adding an explicit lifetime bound `<T as Anything<'_#5r, '_#6r>>::AssocType: ReFree(DefId(0/0:8 ~ projection_two_region_trait_bound_closure[317d]::no_relationships_late[0]), BrNamed(crate0:DefIndex(1:19), 'a))`... = help: consider adding an explicit lifetime bound `<T as Anything<'_#5r, '_#6r>>::AssocType: ReFree(DefId(0/0:8 ~ projection_two_region_trait_bound_closure[317d]::no_relationships_late[0]), BrNamed(crate0:DefIndex(1:18), 'a))`...
note: No external requirements note: No external requirements
--> $DIR/projection-two-region-trait-bound-closure.rs:45:1 --> $DIR/projection-two-region-trait-bound-closure.rs:45:1
@ -270,7 +270,7 @@ note: No external requirements
T T
] ]
error: free region `ReEarlyBound(0, 'b)` does not outlive free region `ReFree(DefId(0/0:13 ~ projection_two_region_trait_bound_closure[317d]::two_regions[0]), BrNamed(crate0:DefIndex(1:44), 'a))` error: free region `ReEarlyBound(0, 'b)` does not outlive free region `ReFree(DefId(0/0:13 ~ projection_two_region_trait_bound_closure[317d]::two_regions[0]), BrNamed(crate0:DefIndex(1:43), 'a))`
--> $DIR/projection-two-region-trait-bound-closure.rs:109:20 --> $DIR/projection-two-region-trait-bound-closure.rs:109:20
| |
109 | with_signature(cell, t, |cell, t| require(cell, t)); 109 | with_signature(cell, t, |cell, t| require(cell, t));

View file

@ -66,7 +66,7 @@ error[E0309]: the parameter type `T` may not live long enough
43 | twice(cell, value, |a, b| invoke(a, b)); 43 | twice(cell, value, |a, b| invoke(a, b));
| ^^^^^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^^^^^
| |
= help: consider adding an explicit lifetime bound `T: ReFree(DefId(0/0:6 ~ ty_param_closure_approximate_lower_bound[317d]::generic_fail[0]), BrNamed(crate0:DefIndex(1:16), 'a))`... = help: consider adding an explicit lifetime bound `T: ReFree(DefId(0/0:6 ~ ty_param_closure_approximate_lower_bound[317d]::generic_fail[0]), BrNamed(crate0:DefIndex(1:15), 'a))`...
note: No external requirements note: No external requirements
--> $DIR/ty-param-closure-approximate-lower-bound.rs:42:1 --> $DIR/ty-param-closure-approximate-lower-bound.rs:42:1

View file

@ -107,7 +107,7 @@ error[E0309]: the parameter type `T` may not live long enough
47 | | }) 47 | | })
| |_____^ | |_____^
| |
= help: consider adding an explicit lifetime bound `T: ReFree(DefId(0/0:6 ~ ty_param_closure_outlives_from_where_clause[317d]::no_region[0]), BrNamed(crate0:DefIndex(1:15), 'a))`... = help: consider adding an explicit lifetime bound `T: ReFree(DefId(0/0:6 ~ ty_param_closure_outlives_from_where_clause[317d]::no_region[0]), BrNamed(crate0:DefIndex(1:14), 'a))`...
note: No external requirements note: No external requirements
--> $DIR/ty-param-closure-outlives-from-where-clause.rs:37:1 --> $DIR/ty-param-closure-outlives-from-where-clause.rs:37:1
@ -154,7 +154,7 @@ error[E0309]: the parameter type `T` may not live long enough
81 | | }) 81 | | })
| |_____^ | |_____^
| |
= help: consider adding an explicit lifetime bound `T: ReFree(DefId(0/0:8 ~ ty_param_closure_outlives_from_where_clause[317d]::wrong_region[0]), BrNamed(crate0:DefIndex(1:21), 'a))`... = help: consider adding an explicit lifetime bound `T: ReFree(DefId(0/0:8 ~ ty_param_closure_outlives_from_where_clause[317d]::wrong_region[0]), BrNamed(crate0:DefIndex(1:20), 'a))`...
note: No external requirements note: No external requirements
--> $DIR/ty-param-closure-outlives-from-where-clause.rs:72:1 --> $DIR/ty-param-closure-outlives-from-where-clause.rs:72:1