Refactor ast::GenericParam as a struct

This commit is contained in:
varkor 2018-05-26 19:16:21 +01:00
parent fba1fe2108
commit 2c6ff2469a
16 changed files with 337 additions and 354 deletions

View file

@ -759,20 +759,20 @@ impl<'a> LoweringContext<'a> {
hir_name
}
// Evaluates `f` with the lifetimes in `lt_defs` in-scope.
// Evaluates `f` with the lifetimes in `params` in-scope.
// This is used to track which lifetimes have already been defined, and
// which are new in-band lifetimes that need to have a definition created
// for them.
fn with_in_scope_lifetime_defs<'l, T, F>(
&mut self,
lt_defs: impl Iterator<Item = &'l LifetimeDef>,
params: impl Iterator<Item = &'l GenericParamAST>,
f: F,
) -> T
where
F: FnOnce(&mut LoweringContext) -> T,
{
let old_len = self.in_scope_lifetimes.len();
let lt_def_names = lt_defs.map(|lt_def| lt_def.lifetime.ident.name);
let lt_def_names = params.map(|param| param.ident.name);
self.in_scope_lifetimes.extend(lt_def_names);
let res = f(self);
@ -781,8 +781,8 @@ impl<'a> LoweringContext<'a> {
res
}
// Same as the method above, but accepts `hir::LifetimeDef`s
// instead of `ast::LifetimeDef`s.
// Same as the method above, but accepts `hir::GenericParam`s
// instead of `ast::GenericParam`s.
// This should only be used with generics that have already had their
// in-band lifetimes added. In practice, this means that this function is
// only used when lowering a child item of a trait or impl.
@ -817,8 +817,8 @@ impl<'a> LoweringContext<'a> {
F: FnOnce(&mut LoweringContext) -> T,
{
let (in_band_defs, (mut lowered_generics, res)) = self.with_in_scope_lifetime_defs(
generics.params.iter().filter_map(|p| match p {
GenericParamAST::Lifetime(ld) => Some(ld),
generics.params.iter().filter_map(|param| match param.kind {
GenericParamKindAST::Lifetime { .. } => Some(param),
_ => None,
}),
|this| {
@ -1076,8 +1076,8 @@ impl<'a> LoweringContext<'a> {
hir::TyRptr(lifetime, self.lower_mt(mt, itctx))
}
TyKind::BareFn(ref f) => self.with_in_scope_lifetime_defs(
f.generic_params.iter().filter_map(|p| match p {
GenericParamAST::Lifetime(ld) => Some(ld),
f.generic_params.iter().filter_map(|param| match param.kind {
GenericParamKindAST::Lifetime { .. } => Some(param),
_ => None,
}),
|this| {
@ -1940,21 +1940,19 @@ impl<'a> LoweringContext<'a> {
add_bounds: &NodeMap<Vec<TyParamBound>>,
itctx: ImplTraitContext)
-> hir::GenericParam {
match param {
GenericParamAST::Lifetime(ref lifetime_def) => {
match param.kind {
GenericParamKindAST::Lifetime { ref bounds, ref lifetime, .. } => {
let was_collecting_in_band = self.is_collecting_in_band_lifetimes;
self.is_collecting_in_band_lifetimes = false;
let lifetime = self.lower_lifetime(&lifetime_def.lifetime);
let lifetime = self.lower_lifetime(lifetime);
let param = hir::GenericParam {
id: lifetime.id,
span: lifetime.span,
pure_wrt_drop: attr::contains_name(&lifetime_def.attrs, "may_dangle"),
pure_wrt_drop: attr::contains_name(&param.attrs, "may_dangle"),
kind: hir::GenericParamKind::Lifetime {
name: lifetime.name,
bounds: lifetime_def.bounds
.iter()
.map(|lt| self.lower_lifetime(lt)).collect(),
bounds: bounds.iter().map(|lt| self.lower_lifetime(lt)).collect(),
in_band: false,
lifetime_deprecated: lifetime,
}
@ -1964,8 +1962,8 @@ impl<'a> LoweringContext<'a> {
param
}
GenericParamAST::Type(ref ty_param) => {
let mut name = self.lower_ident(ty_param.ident);
GenericParamKindAST::Type { ref bounds, ref default } => {
let mut name = self.lower_ident(param.ident);
// Don't expose `Self` (recovered "keyword used as ident" parse error).
// `rustc::ty` expects `Self` to be only used for a trait's `Self`.
@ -1974,8 +1972,8 @@ impl<'a> LoweringContext<'a> {
name = Symbol::gensym("Self");
}
let mut bounds = self.lower_bounds(&ty_param.bounds, itctx);
let add_bounds = add_bounds.get(&ty_param.id).map_or(&[][..], |x| &x);
let mut bounds = self.lower_bounds(bounds, itctx);
let add_bounds = add_bounds.get(&param.id).map_or(&[][..], |x| &x);
if !add_bounds.is_empty() {
bounds = bounds
.into_iter()
@ -1984,22 +1982,20 @@ impl<'a> LoweringContext<'a> {
}
hir::GenericParam {
id: self.lower_node_id(ty_param.id).node_id,
span: ty_param.ident.span,
pure_wrt_drop: attr::contains_name(&ty_param.attrs, "may_dangle"),
id: self.lower_node_id(param.id).node_id,
span: param.ident.span,
pure_wrt_drop: attr::contains_name(&param.attrs, "may_dangle"),
kind: hir::GenericParamKind::Type {
name,
bounds,
default: ty_param.default.as_ref()
.map(|x| {
self.lower_ty(x, ImplTraitContext::Disallowed)
}),
synthetic: ty_param.attrs
.iter()
.filter(|attr| attr.check_name("rustc_synthetic"))
.map(|_| hir::SyntheticTyParamKind::ImplTrait)
.nth(0),
attrs: self.lower_attrs(&ty_param.attrs),
default: default.as_ref().map(|x| {
self.lower_ty(x, ImplTraitContext::Disallowed)
}),
synthetic: param.attrs.iter()
.filter(|attr| attr.check_name("rustc_synthetic"))
.map(|_| hir::SyntheticTyParamKind::ImplTrait)
.nth(0),
attrs: self.lower_attrs(&param.attrs),
}
}
}
@ -2015,13 +2011,18 @@ impl<'a> LoweringContext<'a> {
params.iter().map(|param| self.lower_generic_param(param, add_bounds, itctx)).collect()
}
fn lower_generics(&mut self, g: &Generics, itctx: ImplTraitContext) -> hir::Generics {
fn lower_generics(
&mut self,
generics: &Generics,
itctx: ImplTraitContext)
-> hir::Generics
{
// 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();
for pred in &g.where_clause.predicates {
for pred in &generics.where_clause.predicates {
if let WherePredicate::BoundPredicate(ref bound_pred) = *pred {
'next_bound: for bound in &bound_pred.bounds {
if let TraitTyParamBound(_, TraitBoundModifier::Maybe) = *bound {
@ -2045,15 +2046,17 @@ impl<'a> LoweringContext<'a> {
if let Some(node_id) =
self.resolver.definitions().as_local_node_id(def_id)
{
for param in &g.params {
if let GenericParamAST::Type(ref ty_param) = *param {
if node_id == ty_param.id {
add_bounds
.entry(ty_param.id)
.or_insert(Vec::new())
.push(bound.clone());
continue 'next_bound;
for param in &generics.params {
match param.kind {
GenericParamKindAST::Type { .. } => {
if node_id == param.id {
add_bounds.entry(param.id)
.or_insert(Vec::new())
.push(bound.clone());
continue 'next_bound;
}
}
_ => {}
}
}
}
@ -2068,9 +2071,9 @@ impl<'a> LoweringContext<'a> {
}
hir::Generics {
params: self.lower_generic_params(&g.params, &add_bounds, itctx),
where_clause: self.lower_where_clause(&g.where_clause),
span: g.span,
params: self.lower_generic_params(&generics.params, &add_bounds, itctx),
where_clause: self.lower_where_clause(&generics.where_clause),
span: generics.span,
}
}
@ -2093,8 +2096,8 @@ impl<'a> LoweringContext<'a> {
span,
}) => {
self.with_in_scope_lifetime_defs(
bound_generic_params.iter().filter_map(|p| match p {
GenericParamAST::Lifetime(ld) => Some(ld),
bound_generic_params.iter().filter_map(|param| match param.kind {
GenericParamKindAST::Lifetime { .. } => Some(param),
_ => None,
}),
|this| {
@ -2412,8 +2415,8 @@ impl<'a> LoweringContext<'a> {
);
let new_impl_items = self.with_in_scope_lifetime_defs(
ast_generics.params.iter().filter_map(|p| match p {
GenericParamAST::Lifetime(ld) => Some(ld),
ast_generics.params.iter().filter_map(|param| match param.kind {
GenericParamKindAST::Lifetime { .. } => Some(param),
_ => None,
}),
|this| {

View file

@ -171,24 +171,17 @@ impl<'a> visit::Visitor<'a> for DefCollector<'a> {
}
fn visit_generic_param(&mut self, param: &'a GenericParamAST) {
match *param {
GenericParamAST::Lifetime(ref lifetime_def) => {
self.create_def(
lifetime_def.lifetime.id,
DefPathData::LifetimeDef(lifetime_def.lifetime.ident.name.as_interned_str()),
REGULAR_SPACE,
lifetime_def.lifetime.ident.span
);
}
GenericParamAST::Type(ref ty_param) => {
self.create_def(
ty_param.id,
DefPathData::TypeParam(ty_param.ident.name.as_interned_str()),
REGULAR_SPACE,
ty_param.ident.span
);
}
}
let name = param.ident.name.as_interned_str();
let def_path_data = match param.kind {
GenericParamKindAST::Lifetime { .. } => DefPathData::LifetimeDef(name),
GenericParamKindAST::Type { .. } => DefPathData::TypeParam(name),
};
self.create_def(
param.id,
def_path_data,
REGULAR_SPACE,
param.ident.span
);
visit::walk_generic_param(self, param);
}

View file

@ -139,30 +139,24 @@ impl<'a> AstValidator<'a> {
}
fn check_late_bound_lifetime_defs(&self, params: &Vec<GenericParamAST>) {
// Check: Only lifetime parameters
let non_lifetime_param_spans : Vec<_> = params.iter()
.filter_map(|param| match *param {
GenericParamAST::Lifetime(_) => None,
GenericParamAST::Type(ref t) => Some(t.ident.span),
// Check only lifetime parameters are present and that the lifetime
// parameters that are present have no bounds.
let non_lifetime_param_spans: Vec<_> = params.iter()
.filter_map(|param| match param.kind {
GenericParamKindAST::Lifetime { ref bounds, .. } => {
if !bounds.is_empty() {
let spans: Vec<_> = bounds.iter().map(|b| b.ident.span).collect();
self.err_handler().span_err(spans,
"lifetime bounds cannot be used in this context");
}
None
}
_ => Some(param.ident.span),
}).collect();
if !non_lifetime_param_spans.is_empty() {
self.err_handler().span_err(non_lifetime_param_spans,
"only lifetime parameters can be used in this context");
}
// Check: No bounds on lifetime parameters
for param in params.iter() {
match *param {
GenericParamAST::Lifetime(ref l) => {
if !l.bounds.is_empty() {
let spans: Vec<_> = l.bounds.iter().map(|b| b.ident.span).collect();
self.err_handler().span_err(spans,
"lifetime bounds cannot be used in this context");
}
}
GenericParamAST::Type(_) => {}
}
}
}
}
@ -335,22 +329,21 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
}
ItemKind::TraitAlias(Generics { ref params, .. }, ..) => {
for param in params {
if let GenericParamAST::Type(TyParam {
ident,
ref bounds,
ref default,
..
}) = *param
{
if !bounds.is_empty() {
self.err_handler().span_err(ident.span,
"type parameters on the left side of a \
trait alias cannot be bounded");
}
if !default.is_none() {
self.err_handler().span_err(ident.span,
"type parameters on the left side of a \
trait alias cannot have defaults");
match param.kind {
GenericParamKindAST::Lifetime { .. } => {}
GenericParamKindAST::Type { ref bounds, ref default, .. } => {
if !bounds.is_empty() {
self.err_handler().span_err(param.ident.span,
"type parameters on the left side \
of a trait alias cannot be \
bounded");
}
if !default.is_none() {
self.err_handler().span_err(param.ident.span,
"type parameters on the left side \
of a trait alias cannot have \
defaults");
}
}
}
}
@ -413,24 +406,23 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
let mut seen_non_lifetime_param = false;
let mut seen_default = None;
for param in &g.params {
match (param, seen_non_lifetime_param) {
(&GenericParamAST::Lifetime(ref ld), true) => {
match (&param.kind, seen_non_lifetime_param) {
(GenericParamKindAST::Lifetime { .. }, true) => {
self.err_handler()
.span_err(ld.lifetime.ident.span, "lifetime parameters must be leading");
.span_err(param.ident.span, "lifetime parameters must be leading");
},
(&GenericParamAST::Lifetime(_), false) => {}
_ => {
(GenericParamKindAST::Lifetime { .. }, false) => {}
(GenericParamKindAST::Type { ref default, .. }, _) => {
seen_non_lifetime_param = true;
if default.is_some() {
seen_default = Some(param.ident.span);
} else if let Some(span) = seen_default {
self.err_handler()
.span_err(span, "type parameters with a default must be trailing");
break;
}
}
}
if let GenericParamAST::Type(ref ty_param @ TyParam { default: Some(_), .. }) = *param {
seen_default = Some(ty_param.ident.span);
} else if let Some(span) = seen_default {
self.err_handler()
.span_err(span, "type parameters with a default must be trailing");
break
}
}
for predicate in &g.where_clause.predicates {
if let WherePredicate::EqPredicate(ref predicate) = *predicate {

View file

@ -56,7 +56,7 @@ use syntax::util::lev_distance::find_best_match_for_name;
use syntax::visit::{self, FnKind, Visitor};
use syntax::attr;
use syntax::ast::{Arm, BindingMode, Block, Crate, Expr, ExprKind};
use syntax::ast::{FnDecl, ForeignItem, ForeignItemKind, GenericParamAST, Generics};
use syntax::ast::{FnDecl, ForeignItem, ForeignItemKind, GenericParamKindAST, Generics};
use syntax::ast::{Item, ItemKind, ImplItem, ImplItemKind};
use syntax::ast::{Label, Local, Mutability, Pat, PatKind, Path};
use syntax::ast::{QSelf, TraitItemKind, TraitRef, Ty, TyKind};
@ -797,31 +797,43 @@ impl<'a, 'tcx> Visitor<'tcx> for Resolver<'a> {
// put all the parameters on the ban list and then remove
// them one by one as they are processed and become available.
let mut default_ban_rib = Rib::new(ForwardTyParamBanRibKind);
let mut found_default = false;
default_ban_rib.bindings.extend(generics.params.iter()
.filter_map(|p| if let GenericParamAST::Type(ref tp) = *p { Some(tp) } else { None })
.skip_while(|p| p.default.is_none())
.map(|p| (Ident::with_empty_ctxt(p.ident.name), Def::Err)));
.filter_map(|param| match param.kind {
GenericParamKindAST::Lifetime { .. } => None,
GenericParamKindAST::Type { ref default, .. } => {
if default.is_some() {
found_default = true;
}
if found_default {
return Some((Ident::with_empty_ctxt(param.ident.name), Def::Err));
}
None
}
}));
for param in &generics.params {
match *param {
GenericParamAST::Lifetime(_) => self.visit_generic_param(param),
GenericParamAST::Type(ref ty_param) => {
for bound in &ty_param.bounds {
match param.kind {
GenericParamKindAST::Lifetime { .. } => self.visit_generic_param(param),
GenericParamKindAST::Type { ref bounds, ref default, .. } => {
for bound in bounds {
self.visit_ty_param_bound(bound);
}
if let Some(ref ty) = ty_param.default {
if let Some(ref ty) = default {
self.ribs[TypeNS].push(default_ban_rib);
self.visit_ty(ty);
default_ban_rib = self.ribs[TypeNS].pop().unwrap();
}
// Allow all following defaults to refer to this type parameter.
default_ban_rib.bindings.remove(&Ident::with_empty_ctxt(ty_param.ident.name));
default_ban_rib.bindings.remove(&Ident::with_empty_ctxt(param.ident.name));
}
}
}
for p in &generics.where_clause.predicates { self.visit_where_predicate(p); }
for p in &generics.where_clause.predicates {
self.visit_where_predicate(p);
}
}
}
@ -2198,25 +2210,28 @@ impl<'a> Resolver<'a> {
let mut function_type_rib = Rib::new(rib_kind);
let mut seen_bindings = FxHashMap();
for param in &generics.params {
if let GenericParamAST::Type(ref type_parameter) = *param {
let ident = type_parameter.ident.modern();
debug!("with_type_parameter_rib: {}", type_parameter.id);
match param.kind {
GenericParamKindAST::Type { .. } => {
let ident = param.ident.modern();
debug!("with_type_parameter_rib: {}", param.id);
if seen_bindings.contains_key(&ident) {
let span = seen_bindings.get(&ident).unwrap();
let err = ResolutionError::NameAlreadyUsedInTypeParameterList(
ident.name,
span,
);
resolve_error(self, type_parameter.ident.span, err);
if seen_bindings.contains_key(&ident) {
let span = seen_bindings.get(&ident).unwrap();
let err = ResolutionError::NameAlreadyUsedInTypeParameterList(
ident.name,
span,
);
resolve_error(self, param.ident.span, err);
}
seen_bindings.entry(ident).or_insert(param.ident.span);
// plain insert (no renaming)
let def_id = self.definitions.local_def_id(param.id);
let def = Def::TyParam(def_id);
function_type_rib.bindings.insert(ident, def);
self.record_def(param.id, PathResolution::new(def));
}
seen_bindings.entry(ident).or_insert(type_parameter.ident.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);

View file

@ -370,35 +370,38 @@ impl<'l, 'tcx: 'l, 'll, O: DumpOutput + 'll> DumpVisitor<'l, 'tcx, 'll, O> {
id: NodeId,
) {
for param in &generics.params {
if let ast::GenericParamAST::Type(ref ty_param) = *param {
let param_ss = ty_param.ident.span;
let name = escape(self.span.snippet(param_ss));
// Append $id to name to make sure each one is unique
let qualname = format!("{}::{}${}", prefix, name, id);
if !self.span.filter_generated(Some(param_ss), full_span) {
let id = ::id_from_node_id(ty_param.id, &self.save_ctxt);
let span = self.span_from_span(param_ss);
match param.kind {
ast::GenericParamKindAST::Lifetime { .. } => {}
ast::GenericParamKindAST::Type { .. } => {
let param_ss = param.ident.span;
let name = escape(self.span.snippet(param_ss));
// Append $id to name to make sure each one is unique.
let qualname = format!("{}::{}${}", prefix, name, id);
if !self.span.filter_generated(Some(param_ss), full_span) {
let id = ::id_from_node_id(param.id, &self.save_ctxt);
let span = self.span_from_span(param_ss);
self.dumper.dump_def(
&Access {
public: false,
reachable: false,
},
Def {
kind: DefKind::Type,
id,
span,
name,
qualname,
value: String::new(),
parent: None,
children: vec![],
decl_id: None,
docs: String::new(),
sig: None,
attributes: vec![],
},
);
self.dumper.dump_def(
&Access {
public: false,
reachable: false,
},
Def {
kind: DefKind::Type,
id,
span,
name,
qualname,
value: String::new(),
parent: None,
children: vec![],
decl_id: None,
docs: String::new(),
sig: None,
attributes: vec![],
},
);
}
}
}
}
@ -1479,14 +1482,17 @@ impl<'l, 'tcx: 'l, 'll, O: DumpOutput + 'll> Visitor<'l> for DumpVisitor<'l, 'tc
fn visit_generics(&mut self, generics: &'l ast::Generics) {
for param in &generics.params {
if let ast::GenericParamAST::Type(ref ty_param) = *param {
for bound in ty_param.bounds.iter() {
if let ast::TraitTyParamBound(ref trait_ref, _) = *bound {
self.process_path(trait_ref.trait_ref.ref_id, &trait_ref.trait_ref.path)
match param.kind {
ast::GenericParamKindAST::Lifetime { .. } => {}
ast::GenericParamKindAST::Type { ref bounds, ref default, .. } => {
for bound in bounds {
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) = default {
self.visit_ty(&ty);
}
}
if let Some(ref ty) = ty_param.default {
self.visit_ty(&ty);
}
}
}

View file

@ -934,9 +934,9 @@ fn make_signature(decl: &ast::FnDecl, generics: &ast::Generics) -> String {
sig.push_str(&generics
.params
.iter()
.map(|param| match *param {
ast::GenericParamAST::Lifetime(ref l) => l.lifetime.ident.name.to_string(),
ast::GenericParamAST::Type(ref t) => t.ident.to_string(),
.map(|param| match param.kind {
ast::GenericParamKindAST::Lifetime { .. } => param.ident.name.to_string(),
ast::GenericParamKindAST::Type { .. } => param.ident.to_string(),
})
.collect::<Vec<_>>()
.join(", "));

View file

@ -223,9 +223,9 @@ impl Sig for ast::Ty {
text.push_str("for<");
text.push_str(&f.generic_params
.iter()
.filter_map(|p| match *p {
ast::GenericParamAST::Lifetime(ref l) => {
Some(l.lifetime.ident.to_string())
.filter_map(|param| match param.kind {
ast::GenericParamKindAST::Lifetime { .. } => {
Some(param.ident.to_string())
}
_ => None,
})
@ -617,45 +617,34 @@ impl Sig for ast::Generics {
let mut defs = vec![];
for param in &self.params {
match *param {
ast::GenericParamAST::Lifetime(ref l) => {
let mut l_text = l.lifetime.ident.to_string();
defs.push(SigElement {
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() {
l_text.push_str(": ");
let bounds = l.bounds
.iter()
let mut param_text = param.ident.to_string();
defs.push(SigElement {
id: id_from_node_id(param.id, scx),
start: offset + text.len(),
end: offset + text.len() + param_text.len(),
});
match param.kind {
ast::GenericParamKindAST::Lifetime { ref bounds, .. } => {
if !bounds.is_empty() {
param_text.push_str(": ");
let bounds = bounds.iter()
.map(|l| l.ident.to_string())
.collect::<Vec<_>>()
.join(" + ");
l_text.push_str(&bounds);
param_text.push_str(&bounds);
// FIXME add lifetime bounds refs.
}
text.push_str(&l_text);
text.push(',');
}
ast::GenericParamAST::Type(ref t) => {
let mut t_text = t.ident.to_string();
defs.push(SigElement {
id: id_from_node_id(t.id, scx),
start: offset + text.len(),
end: offset + text.len() + t_text.len(),
});
if !t.bounds.is_empty() {
t_text.push_str(": ");
t_text.push_str(&pprust::bounds_to_string(&t.bounds));
ast::GenericParamKindAST::Type { ref bounds, .. } => {
if !bounds.is_empty() {
param_text.push_str(": ");
param_text.push_str(&pprust::bounds_to_string(bounds));
// FIXME descend properly into bounds.
}
text.push_str(&t_text);
text.push(',');
}
}
text.push_str(&param_text);
text.push(',');
}
text.push('>');

View file

@ -58,14 +58,6 @@ impl fmt::Debug for Lifetime {
}
}
/// A lifetime definition, e.g. `'a: 'b+'c+'d`
#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
pub struct LifetimeDef {
pub attrs: ThinVec<Attribute>,
pub lifetime: Lifetime,
pub bounds: Vec<Lifetime>
}
/// A "Path" is essentially Rust's notion of a name.
///
/// It's represented as a sequence of identifiers,
@ -329,31 +321,38 @@ pub enum TraitBoundModifier {
pub type TyParamBounds = Vec<TyParamBound>;
#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
pub struct TyParam {
pub attrs: ThinVec<Attribute>,
pub ident: Ident,
pub id: NodeId,
pub bounds: TyParamBounds,
pub default: Option<P<Ty>>,
pub enum GenericParamKindAST {
/// A lifetime definition, e.g. `'a: 'b+'c+'d`.
Lifetime {
bounds: Vec<Lifetime>,
lifetime: Lifetime,
},
Type {
bounds: TyParamBounds,
default: Option<P<Ty>>,
}
}
#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
pub enum GenericParamAST {
Lifetime(LifetimeDef),
Type(TyParam),
pub struct GenericParamAST {
pub ident: Ident,
pub id: NodeId,
pub attrs: ThinVec<Attribute>,
pub kind: GenericParamKindAST,
}
impl GenericParamAST {
pub fn is_lifetime_param(&self) -> bool {
match *self {
GenericParamAST::Lifetime(_) => true,
match self.kind {
GenericParamKindAST::Lifetime { .. } => true,
_ => false,
}
}
pub fn is_type_param(&self) -> bool {
match *self {
GenericParamAST::Type(_) => true,
match self.kind {
GenericParamKindAST::Type { .. } => true,
_ => false,
}
}
@ -383,10 +382,8 @@ impl Generics {
pub fn span_for_name(&self, name: &str) -> Option<Span> {
for param in &self.params {
if let GenericParamAST::Type(ref t) = *param {
if t.ident.name == name {
return Some(t.ident.span);
}
if param.ident.name == name {
return Some(param.ident.span);
}
}
None

View file

@ -69,7 +69,7 @@ pub trait AstBuilder {
id: ast::Ident,
attrs: Vec<ast::Attribute>,
bounds: ast::TyParamBounds,
default: Option<P<ast::Ty>>) -> ast::TyParam;
default: Option<P<ast::Ty>>) -> ast::GenericParamAST;
fn trait_ref(&self, path: ast::Path) -> ast::TraitRef;
fn poly_trait_ref(&self, span: Span, path: ast::Path) -> ast::PolyTraitRef;
@ -80,7 +80,7 @@ pub trait AstBuilder {
ident: ast::Ident,
attrs: Vec<ast::Attribute>,
bounds: Vec<ast::Lifetime>)
-> ast::LifetimeDef;
-> ast::GenericParamAST;
// statements
fn stmt_expr(&self, expr: P<ast::Expr>) -> ast::Stmt;
@ -437,13 +437,15 @@ impl<'a> AstBuilder for ExtCtxt<'a> {
ident: ast::Ident,
attrs: Vec<ast::Attribute>,
bounds: ast::TyParamBounds,
default: Option<P<ast::Ty>>) -> ast::TyParam {
ast::TyParam {
default: Option<P<ast::Ty>>) -> ast::GenericParamAST {
ast::GenericParamAST {
ident: ident.with_span_pos(span),
id: ast::DUMMY_NODE_ID,
attrs: attrs.into(),
bounds,
default,
kind: ast::GenericParamKindAST::Type {
bounds,
default,
}
}
}
@ -475,11 +477,16 @@ impl<'a> AstBuilder for ExtCtxt<'a> {
ident: ast::Ident,
attrs: Vec<ast::Attribute>,
bounds: Vec<ast::Lifetime>)
-> ast::LifetimeDef {
ast::LifetimeDef {
-> ast::GenericParamAST {
let lifetime = self.lifetime(span, ident);
ast::GenericParamAST {
ident: lifetime.ident,
id: lifetime.id,
attrs: attrs.into(),
lifetime: self.lifetime(span, ident),
bounds,
kind: ast::GenericParamKindAST::Lifetime {
lifetime,
bounds,
}
}
}

View file

@ -687,38 +687,23 @@ pub fn noop_fold_ty_param_bound<T>(tpb: TyParamBound, fld: &mut T)
}
}
pub fn noop_fold_ty_param<T: Folder>(tp: TyParam, fld: &mut T) -> TyParam {
let TyParam {attrs, id, ident, bounds, default} = tp;
let attrs: Vec<_> = attrs.into();
TyParam {
attrs: attrs.into_iter()
.flat_map(|x| fld.fold_attribute(x).into_iter())
.collect::<Vec<_>>()
.into(),
id: fld.new_id(id),
ident: fld.fold_ident(ident),
bounds: fld.fold_bounds(bounds),
default: default.map(|x| fld.fold_ty(x)),
}
}
pub fn noop_fold_generic_param<T: Folder>(param: GenericParamAST, fld: &mut T) -> GenericParamAST {
match param {
GenericParamAST::Lifetime(l) => {
let attrs: Vec<_> = l.attrs.into();
GenericParamAST::Lifetime { bounds, lifetime } => {
let attrs: Vec<_> = param.attrs.into();
GenericParamAST::Lifetime(LifetimeDef {
attrs: attrs.into_iter()
.flat_map(|x| fld.fold_attribute(x).into_iter())
.collect::<Vec<_>>()
.into(),
lifetime: Lifetime {
id: fld.new_id(l.lifetime.id),
ident: fld.fold_ident(l.lifetime.ident),
id: fld.new_id(param.id),
ident: fld.fold_ident(param.ident),
},
bounds: l.bounds.move_map(|l| noop_fold_lifetime(l, fld)),
bounds: bounds.move_map(|l| noop_fold_lifetime(l, fld)),
})
}
GenericParamAST::Type(t) => GenericParamAST::Type(fld.fold_ty_param(t)),
GenericParamAST::Type { .. } => GenericParamAST::Type(fld.fold_ty_param(param)),
}
}

View file

@ -21,10 +21,10 @@ use ast::EnumDef;
use ast::{Expr, ExprKind, RangeLimits};
use ast::{Field, FnDecl};
use ast::{ForeignItem, ForeignItemKind, FunctionRetTy};
use ast::GenericParamAST;
use ast::{GenericParamAST, GenericParamKindAST};
use ast::GenericArgAST;
use ast::{Ident, ImplItem, IsAuto, Item, ItemKind};
use ast::{Label, Lifetime, LifetimeDef, Lit, LitKind};
use ast::{Label, Lifetime, Lit, LitKind};
use ast::Local;
use ast::MacStmtStyle;
use ast::{Mac, Mac_, MacDelimiter};
@ -36,7 +36,7 @@ use ast::{VariantData, StructField};
use ast::StrStyle;
use ast::SelfKind;
use ast::{TraitItem, TraitRef, TraitObjectSyntax};
use ast::{Ty, TyKind, TypeBinding, TyParam, TyParamBounds};
use ast::{Ty, TyKind, TypeBinding, TyParamBounds};
use ast::{Visibility, VisibilityKind, WhereClause, CrateSugar};
use ast::{UseTree, UseTreeKind};
use ast::{BinOpKind, UnOp};
@ -1311,9 +1311,7 @@ impl<'a> Parser<'a> {
let lo = self.span;
let (name, node, generics) = if self.eat_keyword(keywords::Type) {
let (generics, TyParam {ident, bounds, default, ..}) =
self.parse_trait_item_assoc_ty(vec![])?;
(ident, TraitItemKind::Type(bounds, default), generics)
self.parse_trait_item_assoc_ty()?
} else if self.is_const_item() {
self.expect_keyword(keywords::Const)?;
let ident = self.parse_ident()?;
@ -4805,7 +4803,9 @@ impl<'a> Parser<'a> {
}
/// Matches typaram = IDENT (`?` unbound)? optbounds ( EQ ty )?
fn parse_ty_param(&mut self, preceding_attrs: Vec<Attribute>) -> PResult<'a, TyParam> {
fn parse_ty_param(&mut self,
preceding_attrs: Vec<Attribute>)
-> PResult<'a, GenericParamAST> {
let ident = self.parse_ident()?;
// Parse optional colon and param bounds.
@ -4821,19 +4821,21 @@ impl<'a> Parser<'a> {
None
};
Ok(TyParam {
attrs: preceding_attrs.into(),
Ok(GenericParamAST {
ident,
attrs: preceding_attrs.into(),
id: ast::DUMMY_NODE_ID,
bounds,
default,
kind: GenericParamKindAST::Type {
bounds,
default,
}
})
}
/// Parses the following grammar:
/// TraitItemAssocTy = Ident ["<"...">"] [":" [TyParamBounds]] ["where" ...] ["=" Ty]
fn parse_trait_item_assoc_ty(&mut self, preceding_attrs: Vec<Attribute>)
-> PResult<'a, (ast::Generics, TyParam)> {
fn parse_trait_item_assoc_ty(&mut self)
-> PResult<'a, (Ident, TraitItemKind, ast::Generics)> {
let ident = self.parse_ident()?;
let mut generics = self.parse_generics()?;
@ -4852,13 +4854,7 @@ impl<'a> Parser<'a> {
};
self.expect(&token::Semi)?;
Ok((generics, TyParam {
attrs: preceding_attrs.into(),
ident,
id: ast::DUMMY_NODE_ID,
bounds,
default,
}))
Ok((ident, TraitItemKind::Type(bounds, default), generics))
}
/// Parses (possibly empty) list of lifetime and type parameters, possibly including
@ -4876,18 +4872,22 @@ impl<'a> Parser<'a> {
} else {
Vec::new()
};
params.push(ast::GenericParamAST::Lifetime(LifetimeDef {
params.push(ast::GenericParamAST {
ident: lifetime.ident,
id: lifetime.id,
attrs: attrs.into(),
lifetime,
bounds,
}));
kind: ast::GenericParamKindAST::Lifetime {
lifetime,
bounds,
}
});
if seen_ty_param {
self.span_err(self.prev_span,
"lifetime parameters must be declared prior to type parameters");
}
} else if self.check_ident() {
// Parse type parameter.
params.push(ast::GenericParamAST::Type(self.parse_ty_param(attrs)?));
params.push(self.parse_ty_param(attrs)?);
seen_ty_param = true;
} else {
// Check for trailing attributes and stop parsing.

View file

@ -2878,12 +2878,24 @@ impl<'a> State<'a> {
self.s.word("<")?;
self.commasep(Inconsistent, &generic_params, |s, param| {
match *param {
ast::GenericParamAST::Lifetime(ref lifetime_def) => {
s.print_outer_attributes_inline(&lifetime_def.attrs)?;
s.print_lifetime_bounds(&lifetime_def.lifetime, &lifetime_def.bounds)
match param.kind {
ast::GenericParamKindAST::Lifetime { ref bounds, ref lifetime } => {
s.print_outer_attributes_inline(&param.attrs)?;
s.print_lifetime_bounds(lifetime, bounds)
},
ast::GenericParamAST::Type(ref ty_param) => s.print_ty_param(ty_param),
ast::GenericParamKindAST::Type { ref bounds, ref default } => {
s.print_outer_attributes_inline(&param.attrs)?;
s.print_ident(param.ident)?;
s.print_bounds(":", bounds)?;
match default {
Some(ref default) => {
s.s.space()?;
s.word_space("=")?;
s.print_type(default)
}
_ => Ok(())
}
}
}
})?;
@ -2891,20 +2903,6 @@ impl<'a> State<'a> {
Ok(())
}
pub fn print_ty_param(&mut self, param: &ast::TyParam) -> io::Result<()> {
self.print_outer_attributes_inline(&param.attrs)?;
self.print_ident(param.ident)?;
self.print_bounds(":", &param.bounds)?;
match param.default {
Some(ref default) => {
self.s.space()?;
self.word_space("=")?;
self.print_type(default)
}
_ => Ok(())
}
}
pub fn print_where_clause(&mut self, where_clause: &ast::WhereClause)
-> io::Result<()> {
if where_clause.predicates.is_empty() {

View file

@ -491,17 +491,17 @@ pub fn walk_ty_param_bound<'a, V: Visitor<'a>>(visitor: &mut V, bound: &'a TyPar
}
pub fn walk_generic_param<'a, V: Visitor<'a>>(visitor: &mut V, param: &'a GenericParamAST) {
match *param {
GenericParamAST::Lifetime(ref l) => {
visitor.visit_ident(l.lifetime.ident);
walk_list!(visitor, visit_lifetime, &l.bounds);
walk_list!(visitor, visit_attribute, &*l.attrs);
match param.kind {
GenericParamKindAST::Lifetime { ref bounds, ref lifetime, .. } => {
visitor.visit_ident(param.ident);
walk_list!(visitor, visit_lifetime, bounds);
walk_list!(visitor, visit_attribute, param.attrs.iter());
}
GenericParamAST::Type(ref t) => {
GenericParamKindAST::Type { ref bounds, ref default, .. } => {
visitor.visit_ident(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_ty_param_bound, bounds);
walk_list!(visitor, visit_ty, default);
walk_list!(visitor, visit_attribute, param.attrs.iter());
}
}
}

View file

@ -192,8 +192,8 @@ use std::collections::HashSet;
use std::vec;
use rustc_target::spec::abi::Abi;
use syntax::ast::{self, BinOpKind, EnumDef, Expr, GenericParamAST, Generics, Ident, PatKind};
use syntax::ast::{VariantData, GenericArgAST};
use syntax::ast::{self, BinOpKind, EnumDef, Expr, Generics, Ident, PatKind};
use syntax::ast::{VariantData, GenericParamKindAST, GenericArgAST};
use syntax::attr;
use syntax::ext::base::{Annotatable, ExtCtxt};
use syntax::ext::build::AstBuilder;
@ -547,9 +547,9 @@ impl<'a> TraitDef<'a> {
// Create the generic parameters
params.extend(generics.params.iter().map(|param| {
match *param {
ref l @ GenericParamAST::Lifetime(_) => l.clone(),
GenericParamAST::Type(ref ty_param) => {
match param.kind {
GenericParamKindAST::Lifetime { .. } => param.clone(),
GenericParamKindAST::Type { bounds: ref ty_bounds, .. } => {
// I don't think this can be moved out of the loop, since
// a TyParamBound requires an ast id
let mut bounds: Vec<_> =
@ -564,12 +564,11 @@ impl<'a> TraitDef<'a> {
bounds.push(cx.typarambound(trait_path.clone()));
// also add in any bounds from the declaration
for declared_bound in ty_param.bounds.iter() {
for declared_bound in ty_bounds {
bounds.push((*declared_bound).clone());
}
let ty_param = cx.typaram(self.span, ty_param.ident, vec![], bounds, None);
GenericParamAST::Type(ty_param)
cx.typaram(self.span, param.ident, vec![], bounds, None)
}
}
}));
@ -607,8 +606,8 @@ impl<'a> TraitDef<'a> {
// Extra scope required here so ty_params goes out of scope before params is moved
let mut ty_params = params.iter()
.filter_map(|param| match *param {
ast::GenericParamAST::Type(ref t) => Some(t),
.filter_map(|param| match param.kind {
ast::GenericParamKindAST::Type { .. } => Some(param),
_ => None,
})
.peekable();
@ -668,17 +667,16 @@ impl<'a> TraitDef<'a> {
// Create the type parameters on the `self` path.
let self_ty_params: Vec<P<ast::Ty>> = generics.params
.iter()
.filter_map(|param| match *param {
GenericParamAST::Type(ref ty_param)
=> Some(cx.ty_ident(self.span, ty_param.ident)),
.filter_map(|param| match param.kind {
GenericParamKindAST::Type { .. } => Some(cx.ty_ident(self.span, param.ident)),
_ => None,
})
.collect();
let self_lifetimes: Vec<ast::Lifetime> = generics.params
.iter()
.filter_map(|param| match *param {
GenericParamAST::Lifetime(ref ld) => Some(ld.lifetime),
.filter_map(|param| match param.kind {
GenericParamKindAST::Lifetime { ref lifetime, .. } => Some(*lifetime),
_ => None,
})
.collect();

View file

@ -15,7 +15,7 @@ pub use self::PtrTy::*;
pub use self::Ty::*;
use syntax::ast;
use syntax::ast::{Expr, GenericParamAST, Generics, Ident, SelfKind, GenericArgAST};
use syntax::ast::{Expr, GenericParamKindAST, Generics, Ident, SelfKind, GenericArgAST};
use syntax::ext::base::ExtCtxt;
use syntax::ext::build::AstBuilder;
use syntax::codemap::{respan, DUMMY_SP};
@ -191,9 +191,9 @@ impl<'a> Ty<'a> {
Self_ => {
let ty_params: Vec<P<ast::Ty>> = self_generics.params
.iter()
.filter_map(|param| match *param {
GenericParamAST::Type(ref ty_param) => {
Some(cx.ty_ident(span, ty_param.ident))
.filter_map(|param| match param.kind {
GenericParamKindAST::Type { .. } => {
Some(cx.ty_ident(span, param.ident))
}
_ => None,
})
@ -201,8 +201,8 @@ impl<'a> Ty<'a> {
let lifetimes: Vec<ast::Lifetime> = self_generics.params
.iter()
.filter_map(|param| match *param {
GenericParamAST::Lifetime(ref ld) => Some(ld.lifetime),
.filter_map(|param| match param.kind {
GenericParamKindAST::Lifetime { ref lifetime, .. } => Some(*lifetime),
_ => None,
})
.collect();
@ -234,7 +234,7 @@ fn mk_ty_param(cx: &ExtCtxt,
bounds: &[Path],
self_ident: Ident,
self_generics: &Generics)
-> ast::TyParam {
-> ast::GenericParamAST {
let bounds = bounds.iter()
.map(|b| {
let path = b.to_path(cx, span, self_ident, self_generics);
@ -244,7 +244,7 @@ fn mk_ty_param(cx: &ExtCtxt,
cx.typaram(span, cx.ident_of(name), attrs.to_owned(), bounds, None)
}
fn mk_generics(params: Vec<GenericParamAST>, span: Span) -> Generics {
fn mk_generics(params: Vec<ast::GenericParamAST>, span: Span) -> Generics {
Generics {
params,
where_clause: ast::WhereClause {
@ -282,16 +282,13 @@ impl<'a> LifetimeBounds<'a> {
let bounds = bounds.iter()
.map(|b| cx.lifetime(span, Ident::from_str(b)))
.collect();
let lifetime_def = cx.lifetime_def(span, Ident::from_str(lt), vec![], bounds);
GenericParamAST::Lifetime(lifetime_def)
cx.lifetime_def(span, Ident::from_str(lt), vec![], bounds)
})
.chain(self.bounds
.iter()
.map(|t| {
let (name, ref bounds) = *t;
GenericParamAST::Type(mk_ty_param(
cx, span, name, &[], &bounds, self_ty, self_generics
))
mk_ty_param(cx, span, name, &[], &bounds, self_ty, self_generics)
})
)
.collect();

View file

@ -134,9 +134,12 @@ fn hygienic_type_parameter(item: &Annotatable, base: &str) -> String {
match item.node {
ast::ItemKind::Struct(_, ast::Generics { ref params, .. }) |
ast::ItemKind::Enum(_, ast::Generics { ref params, .. }) => {
for param in params.iter() {
if let ast::GenericParamAST::Type(ref ty) = *param {
typaram.push_str(&ty.ident.as_str());
for param in params {
match param.kind {
ast::GenericParamKindAST::Type { .. } => {
typaram.push_str(&param.ident.as_str());
}
_ => {}
}
}
}