librustc: Implement simple where clauses.

These `where` clauses are accepted everywhere generics are currently
accepted and desugar during type collection to the type parameter bounds
we have today.

A new keyword, `where`, has been added. Therefore, this is a breaking
change. Change uses of `where` to other identifiers.

[breaking-change]
This commit is contained in:
Patrick Walton 2014-08-11 09:32:26 -07:00
parent a8c8e3f80f
commit 604af3f6c0
25 changed files with 626 additions and 207 deletions

View file

@ -245,6 +245,7 @@ pub struct TyParam {
pub struct Generics {
pub lifetimes: Vec<LifetimeDef>,
pub ty_params: OwnedSlice<TyParam>,
pub where_clause: WhereClause,
}
impl Generics {
@ -259,9 +260,23 @@ impl Generics {
}
}
#[deriving(Clone, PartialEq, Eq, Encodable, Decodable, Hash, Show)]
pub struct WhereClause {
pub id: NodeId,
pub predicates: Vec<WherePredicate>,
}
#[deriving(Clone, PartialEq, Eq, Encodable, Decodable, Hash, Show)]
pub struct WherePredicate {
pub id: NodeId,
pub span: Span,
pub ident: Ident,
pub bounds: OwnedSlice<TyParamBound>,
}
/// The set of MetaItems that define the compilation environment of the crate,
/// used to drive conditional compilation
pub type CrateConfig = Vec<Gc<MetaItem>> ;
pub type CrateConfig = Vec<Gc<MetaItem>>;
#[deriving(Clone, PartialEq, Eq, Encodable, Decodable, Hash, Show)]
pub struct Crate {

View file

@ -431,11 +431,14 @@ impl Map {
/// the iterator will produce node id's for items with paths
/// such as `foo::bar::quux`, `bar::quux`, `other::bar::quux`, and
/// any other such items it can find in the map.
pub fn nodes_matching_suffix<'a, S:Str>(&'a self, parts: &'a [S]) -> NodesMatchingSuffix<'a,S> {
NodesMatchingSuffix { map: self,
item_name: parts.last().unwrap(),
where: parts.slice_to(parts.len() - 1),
idx: 0 }
pub fn nodes_matching_suffix<'a, S:Str>(&'a self, parts: &'a [S])
-> NodesMatchingSuffix<'a,S> {
NodesMatchingSuffix {
map: self,
item_name: parts.last().unwrap(),
in_which: parts.slice_to(parts.len() - 1),
idx: 0,
}
}
pub fn opt_span(&self, id: NodeId) -> Option<Span> {
@ -478,20 +481,20 @@ impl Map {
pub struct NodesMatchingSuffix<'a, S> {
map: &'a Map,
item_name: &'a S,
where: &'a [S],
in_which: &'a [S],
idx: NodeId,
}
impl<'a,S:Str> NodesMatchingSuffix<'a,S> {
/// Returns true only if some suffix of the module path for parent
/// matches `self.where`.
/// matches `self.in_which`.
///
/// In other words: let `[x_0,x_1,...,x_k]` be `self.where`;
/// In other words: let `[x_0,x_1,...,x_k]` be `self.in_which`;
/// returns true if parent's path ends with the suffix
/// `x_0::x_1::...::x_k`.
fn suffix_matches(&self, parent: NodeId) -> bool {
let mut cursor = parent;
for part in self.where.iter().rev() {
for part in self.in_which.iter().rev() {
let (mod_id, mod_name) = match find_first_mod_parent(self.map, cursor) {
None => return false,
Some((node_id, name)) => (node_id, name),

View file

@ -320,8 +320,14 @@ pub fn operator_prec(op: ast::BinOp) -> uint {
pub static as_prec: uint = 12u;
pub fn empty_generics() -> Generics {
Generics {lifetimes: Vec::new(),
ty_params: OwnedSlice::empty()}
Generics {
lifetimes: Vec::new(),
ty_params: OwnedSlice::empty(),
where_clause: WhereClause {
id: DUMMY_NODE_ID,
predicates: Vec::new(),
}
}
}
// ______________________________________________________________________

View file

@ -390,7 +390,7 @@ impl<'a> TraitDef<'a> {
methods: Vec<Gc<ast::Method>> ) -> Gc<ast::Item> {
let trait_path = self.path.to_path(cx, self.span, type_ident, generics);
let Generics { mut lifetimes, ty_params } =
let Generics { mut lifetimes, ty_params, where_clause: _ } =
self.generics.to_generics(cx, self.span, type_ident, generics);
let mut ty_params = ty_params.into_vec();
@ -418,7 +418,11 @@ impl<'a> TraitDef<'a> {
}));
let trait_generics = Generics {
lifetimes: lifetimes,
ty_params: OwnedSlice::from_vec(ty_params)
ty_params: OwnedSlice::from_vec(ty_params),
where_clause: ast::WhereClause {
id: ast::DUMMY_NODE_ID,
predicates: Vec::new(),
},
};
// Create the reference to the trait.

View file

@ -202,10 +202,15 @@ fn mk_ty_param(cx: &ExtCtxt, span: Span, name: &str,
cx.typaram(span, cx.ident_of(name), bounds, unbound, None)
}
fn mk_generics(lifetimes: Vec<ast::LifetimeDef>, ty_params: Vec<ast::TyParam> ) -> Generics {
fn mk_generics(lifetimes: Vec<ast::LifetimeDef>, ty_params: Vec<ast::TyParam>)
-> Generics {
Generics {
lifetimes: lifetimes,
ty_params: OwnedSlice::from_vec(ty_params)
ty_params: OwnedSlice::from_vec(ty_params),
where_clause: ast::WhereClause {
id: ast::DUMMY_NODE_ID,
predicates: Vec::new(),
},
}
}

View file

@ -244,6 +244,16 @@ pub trait Folder {
noop_fold_field(field, self)
}
fn fold_where_clause(&mut self, where_clause: &WhereClause)
-> WhereClause {
noop_fold_where_clause(where_clause, self)
}
fn fold_where_predicate(&mut self, where_predicate: &WherePredicate)
-> WherePredicate {
noop_fold_where_predicate(where_predicate, self)
}
// Helper methods:
fn map_exprs(&self, f: |Gc<Expr>| -> Gc<Expr>,
@ -698,8 +708,37 @@ pub fn noop_fold_opt_lifetime<T: Folder>(o_lt: &Option<Lifetime>, fld: &mut T)
}
pub fn noop_fold_generics<T: Folder>(generics: &Generics, fld: &mut T) -> Generics {
Generics {ty_params: fld.fold_ty_params(generics.ty_params.as_slice()),
lifetimes: fld.fold_lifetime_defs(generics.lifetimes.as_slice())}
Generics {
ty_params: fld.fold_ty_params(generics.ty_params.as_slice()),
lifetimes: fld.fold_lifetime_defs(generics.lifetimes.as_slice()),
where_clause: fld.fold_where_clause(&generics.where_clause),
}
}
pub fn noop_fold_where_clause<T: Folder>(
where_clause: &WhereClause,
fld: &mut T)
-> WhereClause {
WhereClause {
id: fld.new_id(where_clause.id),
predicates: where_clause.predicates.iter().map(|predicate| {
fld.fold_where_predicate(predicate)
}).collect(),
}
}
pub fn noop_fold_where_predicate<T: Folder>(
predicate: &WherePredicate,
fld: &mut T)
-> WherePredicate {
WherePredicate {
id: fld.new_id(predicate.id),
span: fld.new_span(predicate.span),
ident: fld.fold_ident(predicate.ident),
bounds: predicate.bounds.map(|x| {
fld.fold_ty_param_bound(x)
}),
}
}
pub fn noop_fold_struct_def<T: Folder>(struct_def: Gc<StructDef>,

View file

@ -543,7 +543,7 @@ impl<'a> StringReader<'a> {
// favors rustc debugging effectiveness over runtime efficiency.
/// Scan through input of form \x00name_NNNNNN,ctxt_CCCCCCC\x00
/// where: `NNNNNN` is a string of characters forming an integer
/// whence: `NNNNNN` is a string of characters forming an integer
/// (the name) and `CCCCCCC` is a string of characters forming an
/// integer (the ctxt), separate by a comma and delimited by a
/// `\x00` marker.
@ -552,22 +552,22 @@ impl<'a> StringReader<'a> {
fn bump_expecting_char<'a,D:fmt::Show>(r: &mut StringReader<'a>,
c: char,
described_c: D,
where: &str) {
whence: &str) {
match r.curr {
Some(r_c) if r_c == c => r.bump(),
Some(r_c) => fail!("expected {}, hit {}, {}", described_c, r_c, where),
None => fail!("expected {}, hit EOF, {}", described_c, where),
Some(r_c) => fail!("expected {}, hit {}, {}", described_c, r_c, whence),
None => fail!("expected {}, hit EOF, {}", described_c, whence),
}
}
let where = "while scanning embedded hygienic ident";
let whence = "while scanning embedded hygienic ident";
// skip over the leading `\x00`
bump_expecting_char(self, '\x00', "nul-byte", where);
bump_expecting_char(self, '\x00', "nul-byte", whence);
// skip over the "name_"
for c in "name_".chars() {
bump_expecting_char(self, c, c, where);
bump_expecting_char(self, c, c, whence);
}
let start_bpos = self.last_pos;
@ -578,16 +578,16 @@ impl<'a> StringReader<'a> {
let encoded_name : u32 = self.with_str_from(start_bpos, |s| {
num::from_str_radix(s, 10).unwrap_or_else(|| {
fail!("expected digits representing a name, got `{}`, {}, range [{},{}]",
s, where, start_bpos, self.last_pos);
s, whence, start_bpos, self.last_pos);
})
});
// skip over the `,`
bump_expecting_char(self, ',', "comma", where);
bump_expecting_char(self, ',', "comma", whence);
// skip over the "ctxt_"
for c in "ctxt_".chars() {
bump_expecting_char(self, c, c, where);
bump_expecting_char(self, c, c, whence);
}
// find the integer representing the ctxt
@ -595,12 +595,12 @@ impl<'a> StringReader<'a> {
self.scan_digits(base);
let encoded_ctxt : ast::SyntaxContext = self.with_str_from(start_bpos, |s| {
num::from_str_radix(s, 10).unwrap_or_else(|| {
fail!("expected digits representing a ctxt, got `{}`, {}", s, where);
fail!("expected digits representing a ctxt, got `{}`, {}", s, whence);
})
});
// skip over the `\x00`
bump_expecting_char(self, '\x00', "nul-byte", where);
bump_expecting_char(self, '\x00', "nul-byte", whence);
ast::Ident { name: ast::Name(encoded_name),
ctxt: encoded_ctxt, }

View file

@ -1053,6 +1053,10 @@ mod test {
ast::Generics{ // no idea on either of these:
lifetimes: Vec::new(),
ty_params: OwnedSlice::empty(),
where_clause: ast::WhereClause {
id: ast::DUMMY_NODE_ID,
predicates: Vec::new(),
}
},
ast::P(ast::Block {
view_items: Vec::new(),

View file

@ -60,7 +60,7 @@ use ast::{UnboxedClosureKind, UnboxedFnTy, UnboxedFnTyParamBound};
use ast::{UnnamedField, UnsafeBlock};
use ast::{UnsafeFn, ViewItem, ViewItem_, ViewItemExternCrate, ViewItemUse};
use ast::{ViewPath, ViewPathGlob, ViewPathList, ViewPathSimple};
use ast::Visibility;
use ast::{Visibility, WhereClause, WherePredicate};
use ast;
use ast_util::{as_prec, ident_to_path, lit_is_str, operator_prec};
use ast_util;
@ -1264,7 +1264,7 @@ impl<'a> Parser<'a> {
let style = p.parse_fn_style();
let ident = p.parse_ident();
let generics = p.parse_generics();
let mut generics = p.parse_generics();
let (explicit_self, d) = p.parse_fn_decl_with_self(|p| {
// This is somewhat dubious; We don't want to allow argument
@ -1272,6 +1272,8 @@ impl<'a> Parser<'a> {
p.parse_arg_general(false)
});
p.parse_where_clause(&mut generics);
let hi = p.last_span.hi;
match p.token {
token::SEMI => {
@ -3742,7 +3744,10 @@ impl<'a> Parser<'a> {
}
}
/// Parse a set of optional generic type parameter declarations
/// Parse a set of optional generic type parameter declarations. Where
/// clauses are not parsed here, and must be added later via
/// `parse_where_clause()`.
///
/// matches generics = ( ) | ( < > ) | ( < typaramseq ( , )? > ) | ( < lifetimes ( , )? > )
/// | ( < lifetimes , typaramseq ( , )? > )
/// where typaramseq = ( typaram ) | ( typaram , typaramseq )
@ -3762,7 +3767,14 @@ impl<'a> Parser<'a> {
}
ty_param
});
ast::Generics { lifetimes: lifetime_defs, ty_params: ty_params }
ast::Generics {
lifetimes: lifetime_defs,
ty_params: ty_params,
where_clause: WhereClause {
id: ast::DUMMY_NODE_ID,
predicates: Vec::new(),
}
}
} else {
ast_util::empty_generics()
}
@ -3788,6 +3800,52 @@ impl<'a> Parser<'a> {
}
}
/// Parses an optional `where` clause and places it in `generics`.
fn parse_where_clause(&mut self, generics: &mut ast::Generics) {
if !self.eat_keyword(keywords::Where) {
return
}
let mut parsed_something = false;
loop {
let lo = self.span.lo;
let ident = match self.token {
token::IDENT(..) => self.parse_ident(),
_ => break,
};
self.expect(&token::COLON);
let (_, bounds) = self.parse_ty_param_bounds(false);
let hi = self.span.hi;
let span = mk_sp(lo, hi);
if bounds.len() == 0 {
self.span_err(span,
"each predicate in a `where` clause must have \
at least one bound in it");
}
generics.where_clause.predicates.push(ast::WherePredicate {
id: ast::DUMMY_NODE_ID,
span: span,
ident: ident,
bounds: bounds,
});
parsed_something = true;
if !self.eat(&token::COMMA) {
break
}
}
if !parsed_something {
let last_span = self.last_span;
self.span_err(last_span,
"a `where` clause must have at least one predicate \
in it");
}
}
fn parse_fn_args(&mut self, named_args: bool, allow_variadic: bool)
-> (Vec<Arg> , bool) {
let sp = self.span;
@ -4143,8 +4201,9 @@ impl<'a> Parser<'a> {
/// Parse an item-position function declaration.
fn parse_item_fn(&mut self, fn_style: FnStyle, abi: abi::Abi) -> ItemInfo {
let (ident, generics) = self.parse_fn_header();
let (ident, mut generics) = self.parse_fn_header();
let decl = self.parse_fn_decl(false);
self.parse_where_clause(&mut generics);
let (inner_attrs, body) = self.parse_inner_attrs_and_block();
(ident, ItemFn(decl, fn_style, abi, generics, body), Some(inner_attrs))
}
@ -4200,10 +4259,11 @@ impl<'a> Parser<'a> {
};
let fn_style = self.parse_fn_style();
let ident = self.parse_ident();
let generics = self.parse_generics();
let mut generics = self.parse_generics();
let (explicit_self, decl) = self.parse_fn_decl_with_self(|p| {
p.parse_arg()
});
self.parse_where_clause(&mut generics);
let (inner_attrs, body) = self.parse_inner_attrs_and_block();
let new_attrs = attrs.append(inner_attrs.as_slice());
(ast::MethDecl(ident,
@ -4228,7 +4288,7 @@ impl<'a> Parser<'a> {
/// Parse trait Foo { ... }
fn parse_item_trait(&mut self) -> ItemInfo {
let ident = self.parse_ident();
let tps = self.parse_generics();
let mut tps = self.parse_generics();
let sized = self.parse_for_sized();
// Parse traits, if necessary.
@ -4240,6 +4300,8 @@ impl<'a> Parser<'a> {
traits = Vec::new();
}
self.parse_where_clause(&mut tps);
let meths = self.parse_trait_methods();
(ident, ItemTrait(tps, sized, traits, meths), None)
}
@ -4261,7 +4323,7 @@ impl<'a> Parser<'a> {
/// impl<T> ToString for ~[T] { ... }
fn parse_item_impl(&mut self) -> ItemInfo {
// First, parse type parameters if necessary.
let generics = self.parse_generics();
let mut generics = self.parse_generics();
// Special case: if the next identifier that follows is '(', don't
// allow this to be parsed as a trait.
@ -4297,6 +4359,7 @@ impl<'a> Parser<'a> {
None
};
self.parse_where_clause(&mut generics);
let (impl_items, attrs) = self.parse_impl_items();
let ident = ast_util::impl_pretty_name(&opt_trait, &*ty);
@ -4326,7 +4389,7 @@ impl<'a> Parser<'a> {
/// Parse struct Foo { ... }
fn parse_item_struct(&mut self, is_virtual: bool) -> ItemInfo {
let class_name = self.parse_ident();
let generics = self.parse_generics();
let mut generics = self.parse_generics();
let super_struct = if self.eat(&token::COLON) {
let ty = self.parse_ty(true);
@ -4343,6 +4406,8 @@ impl<'a> Parser<'a> {
None
};
self.parse_where_clause(&mut generics);
let mut fields: Vec<StructField>;
let is_tuple_like;
@ -4683,8 +4748,9 @@ impl<'a> Parser<'a> {
let lo = self.span.lo;
self.expect_keyword(keywords::Fn);
let (ident, generics) = self.parse_fn_header();
let (ident, mut generics) = self.parse_fn_header();
let decl = self.parse_fn_decl(true);
self.parse_where_clause(&mut generics);
let hi = self.span.hi;
self.expect(&token::SEMI);
box(GC) ast::ForeignItem { ident: ident,
@ -4834,7 +4900,8 @@ impl<'a> Parser<'a> {
/// Parse type Foo = Bar;
fn parse_item_type(&mut self) -> ItemInfo {
let ident = self.parse_ident();
let tps = self.parse_generics();
let mut tps = self.parse_generics();
self.parse_where_clause(&mut tps);
self.expect(&token::EQ);
let ty = self.parse_ty(true);
self.expect(&token::SEMI);
@ -4925,7 +4992,8 @@ impl<'a> Parser<'a> {
/// Parse an "enum" declaration
fn parse_item_enum(&mut self) -> ItemInfo {
let id = self.parse_ident();
let generics = self.parse_generics();
let mut generics = self.parse_generics();
self.parse_where_clause(&mut generics);
self.expect(&token::LBRACE);
let enum_definition = self.parse_enum_def(&generics);

View file

@ -499,18 +499,19 @@ declare_special_idents_and_keywords! {
(41, Proc, "proc");
(42, Box, "box");
(43, Const, "const");
(44, Where, "where");
'reserved:
(44, Alignof, "alignof");
(45, Be, "be");
(46, Offsetof, "offsetof");
(47, Priv, "priv");
(48, Pure, "pure");
(49, Sizeof, "sizeof");
(50, Typeof, "typeof");
(51, Unsized, "unsized");
(52, Yield, "yield");
(53, Do, "do");
(45, Alignof, "alignof");
(46, Be, "be");
(47, Offsetof, "offsetof");
(48, Priv, "priv");
(49, Pure, "pure");
(50, Sizeof, "sizeof");
(51, Typeof, "typeof");
(52, Unsized, "unsized");
(53, Yield, "yield");
(54, Do, "do");
}
}

View file

@ -584,7 +584,11 @@ impl<'a> State<'a> {
ast::TyBareFn(f) => {
let generics = ast::Generics {
lifetimes: f.lifetimes.clone(),
ty_params: OwnedSlice::empty()
ty_params: OwnedSlice::empty(),
where_clause: ast::WhereClause {
id: ast::DUMMY_NODE_ID,
predicates: Vec::new(),
},
};
try!(self.print_ty_fn(Some(f.abi),
None,
@ -601,7 +605,11 @@ impl<'a> State<'a> {
ast::TyClosure(f, ref region) => {
let generics = ast::Generics {
lifetimes: f.lifetimes.clone(),
ty_params: OwnedSlice::empty()
ty_params: OwnedSlice::empty(),
where_clause: ast::WhereClause {
id: ast::DUMMY_NODE_ID,
predicates: Vec::new(),
},
};
try!(self.print_ty_fn(None,
Some('&'),
@ -618,7 +626,11 @@ impl<'a> State<'a> {
ast::TyProc(ref f) => {
let generics = ast::Generics {
lifetimes: f.lifetimes.clone(),
ty_params: OwnedSlice::empty()
ty_params: OwnedSlice::empty(),
where_clause: ast::WhereClause {
id: ast::DUMMY_NODE_ID,
predicates: Vec::new(),
},
};
try!(self.print_ty_fn(None,
Some('~'),
@ -765,6 +777,7 @@ impl<'a> State<'a> {
try!(space(&mut self.s));
try!(self.word_space("="));
try!(self.print_type(&**ty));
try!(self.print_where_clause(params));
try!(word(&mut self.s, ";"));
try!(self.end()); // end the outer ibox
}
@ -808,6 +821,7 @@ impl<'a> State<'a> {
}
try!(self.print_type(&**ty));
try!(self.print_where_clause(generics));
try!(space(&mut self.s));
try!(self.bopen());
@ -845,6 +859,7 @@ impl<'a> State<'a> {
try!(self.print_path(&trait_.path, false));
}
}
try!(self.print_where_clause(generics));
try!(word(&mut self.s, " "));
try!(self.bopen());
for meth in methods.iter() {
@ -880,6 +895,7 @@ impl<'a> State<'a> {
try!(self.head(visibility_qualified(visibility, "enum").as_slice()));
try!(self.print_ident(ident));
try!(self.print_generics(generics));
try!(self.print_where_clause(generics));
try!(space(&mut self.s));
self.print_variants(enum_definition.variants.as_slice(), span)
}
@ -2010,7 +2026,8 @@ impl<'a> State<'a> {
try!(self.nbsp());
try!(self.print_ident(name));
try!(self.print_generics(generics));
self.print_fn_args_and_ret(decl, opt_explicit_self)
try!(self.print_fn_args_and_ret(decl, opt_explicit_self))
self.print_where_clause(generics)
}
pub fn print_fn_args(&mut self, decl: &ast::FnDecl,
@ -2201,54 +2218,83 @@ impl<'a> State<'a> {
Ok(())
}
pub fn print_generics(&mut self,
generics: &ast::Generics) -> IoResult<()> {
let total = generics.lifetimes.len() + generics.ty_params.len();
if total > 0 {
try!(word(&mut self.s, "<"));
fn print_type_parameters(&mut self,
lifetimes: &[ast::LifetimeDef],
ty_params: &[ast::TyParam])
-> IoResult<()> {
let total = lifetimes.len() + ty_params.len();
let mut ints = Vec::new();
for i in range(0u, total) {
ints.push(i);
}
let mut ints = Vec::new();
for i in range(0u, total) {
ints.push(i);
}
try!(self.commasep(
Inconsistent, ints.as_slice(),
|s, &idx| {
if idx < generics.lifetimes.len() {
let lifetime = generics.lifetimes.get(idx);
s.print_lifetime_def(lifetime)
} else {
let idx = idx - generics.lifetimes.len();
let param = generics.ty_params.get(idx);
match param.unbound {
Some(TraitTyParamBound(ref tref)) => {
try!(s.print_trait_ref(tref));
try!(s.word_space("?"));
}
_ => {}
}
try!(s.print_ident(param.ident));
try!(s.print_bounds(&None,
&param.bounds,
false,
false));
match param.default {
Some(ref default) => {
try!(space(&mut s.s));
try!(s.word_space("="));
s.print_type(&**default)
}
_ => Ok(())
}
self.commasep(Inconsistent, ints.as_slice(), |s, &idx| {
if idx < lifetimes.len() {
let lifetime = &lifetimes[idx];
s.print_lifetime_def(lifetime)
} else {
let idx = idx - lifetimes.len();
let param = &ty_params[idx];
match param.unbound {
Some(TraitTyParamBound(ref tref)) => {
try!(s.print_trait_ref(tref));
try!(s.word_space("?"));
}
}));
_ => {}
}
try!(s.print_ident(param.ident));
try!(s.print_bounds(&None,
&param.bounds,
false,
false));
match param.default {
Some(ref default) => {
try!(space(&mut s.s));
try!(s.word_space("="));
s.print_type(&**default)
}
_ => Ok(())
}
}
})
}
pub fn print_generics(&mut self, generics: &ast::Generics)
-> IoResult<()> {
if generics.lifetimes.len() + generics.ty_params.len() > 0 {
try!(word(&mut self.s, "<"));
try!(self.print_type_parameters(generics.lifetimes.as_slice(),
generics.ty_params.as_slice()));
word(&mut self.s, ">")
} else {
Ok(())
}
}
pub fn print_where_clause(&mut self, generics: &ast::Generics)
-> IoResult<()> {
if generics.where_clause.predicates.len() == 0 {
return Ok(())
}
try!(space(&mut self.s));
try!(self.word_space("where"));
for (i, predicate) in generics.where_clause
.predicates
.iter()
.enumerate() {
if i != 0 {
try!(self.word_space(","));
}
try!(self.print_ident(predicate.ident));
try!(self.print_bounds(&None, &predicate.bounds, false, false));
}
Ok(())
}
pub fn print_meta_item(&mut self, item: &ast::MetaItem) -> IoResult<()> {
try!(self.ibox(indent_unit));
match item.node {
@ -2472,6 +2518,11 @@ impl<'a> State<'a> {
}
}
match generics {
Some(generics) => try!(self.print_where_clause(generics)),
None => {}
}
self.end()
}

View file

@ -27,6 +27,7 @@
use abi::Abi;
use ast::*;
use ast;
use ast_util;
use codemap::Span;
use parse;
use owned_slice::OwnedSlice;
@ -58,12 +59,7 @@ pub fn generics_of_fn(fk: &FnKind) -> Generics {
FkMethod(_, generics, _) => {
(*generics).clone()
}
FkFnBlock(..) => {
Generics {
lifetimes: Vec::new(),
ty_params: OwnedSlice::empty(),
}
}
FkFnBlock(..) => ast_util::empty_generics(),
}
}
@ -559,7 +555,11 @@ pub fn walk_generics<E: Clone, V: Visitor<E>>(visitor: &mut V,
None => {}
}
}
walk_lifetime_decls(visitor, &generics.lifetimes, env);
walk_lifetime_decls(visitor, &generics.lifetimes, env.clone());
for predicate in generics.where_clause.predicates.iter() {
visitor.visit_ident(predicate.span, predicate.ident, env.clone());
walk_ty_param_bounds(visitor, &predicate.bounds, env.clone());
}
}
pub fn walk_fn_decl<E: Clone, V: Visitor<E>>(visitor: &mut V,