Parse associated type bounds in path
diff --git a/src/gen/fold.rs b/src/gen/fold.rs
index df96cc3..2b65e2e 100644
--- a/src/gen/fold.rs
+++ b/src/gen/fold.rs
@@ -93,6 +93,10 @@
fn fold_const_param(&mut self, i: ConstParam) -> ConstParam {
fold_const_param(self, i)
}
+ #[cfg(any(feature = "full", feature = "derive"))]
+ fn fold_constraint(&mut self, i: Constraint) -> Constraint {
+ fold_constraint(self, i)
+ }
#[cfg(feature = "derive")]
fn fold_data(&mut self, i: Data) -> Data {
fold_data(self, i)
@@ -1126,6 +1130,14 @@
default: (_i.default).map(|it| _visitor.fold_expr(it)),
}
}
+#[cfg(any(feature = "full", feature = "derive"))]
+pub fn fold_constraint<V: Fold + ?Sized>(_visitor: &mut V, _i: Constraint) -> Constraint {
+ Constraint {
+ ident: _visitor.fold_ident(_i.ident),
+ colon_token: Token ! [ : ](tokens_helper(_visitor, &_i.colon_token.spans)),
+ bounds: FoldHelper::lift(_i.bounds, |it| _visitor.fold_type_param_bound(it)),
+ }
+}
#[cfg(feature = "derive")]
pub fn fold_data<V: Fold + ?Sized>(_visitor: &mut V, _i: Data) -> Data {
match _i {
@@ -1787,6 +1799,9 @@
GenericArgument::Binding(_binding_0) => {
GenericArgument::Binding(_visitor.fold_binding(_binding_0))
}
+ GenericArgument::Constraint(_binding_0) => {
+ GenericArgument::Constraint(_visitor.fold_constraint(_binding_0))
+ }
GenericArgument::Const(_binding_0) => {
GenericArgument::Const(_visitor.fold_expr(_binding_0))
}
diff --git a/src/gen/visit.rs b/src/gen/visit.rs
index 90b2607..ec84cd2 100644
--- a/src/gen/visit.rs
+++ b/src/gen/visit.rs
@@ -93,6 +93,10 @@
fn visit_const_param(&mut self, i: &'ast ConstParam) {
visit_const_param(self, i)
}
+ #[cfg(any(feature = "full", feature = "derive"))]
+ fn visit_constraint(&mut self, i: &'ast Constraint) {
+ visit_constraint(self, i)
+ }
#[cfg(feature = "derive")]
fn visit_data(&mut self, i: &'ast Data) {
visit_data(self, i)
@@ -1107,6 +1111,15 @@
_visitor.visit_expr(it)
};
}
+#[cfg(any(feature = "full", feature = "derive"))]
+pub fn visit_constraint<'ast, V: Visit<'ast> + ?Sized>(_visitor: &mut V, _i: &'ast Constraint) {
+ _visitor.visit_ident(&_i.ident);
+ tokens_helper(_visitor, &_i.colon_token.spans);
+ for el in Punctuated::pairs(&_i.bounds) {
+ let it = el.value();
+ _visitor.visit_type_param_bound(it)
+ }
+}
#[cfg(feature = "derive")]
pub fn visit_data<'ast, V: Visit<'ast> + ?Sized>(_visitor: &mut V, _i: &'ast Data) {
match *_i {
@@ -1959,6 +1972,9 @@
GenericArgument::Binding(ref _binding_0) => {
_visitor.visit_binding(_binding_0);
}
+ GenericArgument::Constraint(ref _binding_0) => {
+ _visitor.visit_constraint(_binding_0);
+ }
GenericArgument::Const(ref _binding_0) => {
_visitor.visit_expr(_binding_0);
}
diff --git a/src/gen/visit_mut.rs b/src/gen/visit_mut.rs
index 9380c7e..4668c9b 100644
--- a/src/gen/visit_mut.rs
+++ b/src/gen/visit_mut.rs
@@ -97,6 +97,10 @@
fn visit_const_param_mut(&mut self, i: &mut ConstParam) {
visit_const_param_mut(self, i)
}
+ #[cfg(any(feature = "full", feature = "derive"))]
+ fn visit_constraint_mut(&mut self, i: &mut Constraint) {
+ visit_constraint_mut(self, i)
+ }
#[cfg(feature = "derive")]
fn visit_data_mut(&mut self, i: &mut Data) {
visit_data_mut(self, i)
@@ -1105,6 +1109,15 @@
_visitor.visit_expr_mut(it)
};
}
+#[cfg(any(feature = "full", feature = "derive"))]
+pub fn visit_constraint_mut<V: VisitMut + ?Sized>(_visitor: &mut V, _i: &mut Constraint) {
+ _visitor.visit_ident_mut(&mut _i.ident);
+ tokens_helper(_visitor, &mut _i.colon_token.spans);
+ for mut el in Punctuated::pairs_mut(&mut _i.bounds) {
+ let it = el.value_mut();
+ _visitor.visit_type_param_bound_mut(it)
+ }
+}
#[cfg(feature = "derive")]
pub fn visit_data_mut<V: VisitMut + ?Sized>(_visitor: &mut V, _i: &mut Data) {
match *_i {
@@ -1933,6 +1946,9 @@
GenericArgument::Binding(ref mut _binding_0) => {
_visitor.visit_binding_mut(_binding_0);
}
+ GenericArgument::Constraint(ref mut _binding_0) => {
+ _visitor.visit_constraint_mut(_binding_0);
+ }
GenericArgument::Const(ref mut _binding_0) => {
_visitor.visit_expr_mut(_binding_0);
}
diff --git a/src/lib.rs b/src/lib.rs
index 2f05a3a..21621f0 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -427,8 +427,8 @@
mod path;
#[cfg(any(feature = "full", feature = "derive"))]
pub use path::{
- AngleBracketedGenericArguments, Binding, GenericArgument, ParenthesizedGenericArguments, Path,
- PathArguments, PathSegment, QSelf,
+ AngleBracketedGenericArguments, Binding, Constraint, GenericArgument,
+ ParenthesizedGenericArguments, Path, PathArguments, PathSegment, QSelf,
};
#[cfg(feature = "parsing")]
diff --git a/src/path.rs b/src/path.rs
index 443bac6..693d71c 100644
--- a/src/path.rs
+++ b/src/path.rs
@@ -108,6 +108,8 @@
/// A binding (equality constraint) on an associated type: the `Item =
/// u8` in `Iterator<Item = u8>`.
Binding(Binding),
+ /// An associated type bound: `Iterator<Item: Display>`.
+ Constraint(Constraint),
/// A const expression. Must be inside of a block.
///
/// NOTE: Identity expressions are represented as Type arguments, as
@@ -143,6 +145,18 @@
}
ast_struct! {
+ /// An associated type bound: `Iterator<Item: Display>`.
+ ///
+ /// *This type is available if Syn is built with the `"derive"` or `"full"`
+ /// feature.*
+ pub struct Constraint {
+ pub ident: Ident,
+ pub colon_token: Token![:],
+ pub bounds: Punctuated<TypeParamBound, Token![+]>,
+ }
+}
+
+ast_struct! {
/// Arguments of a function path segment: the `(A, B) -> C` in `Fn(A,B) ->
/// C`.
///
@@ -213,6 +227,10 @@
#[cfg(feature = "full")]
{
+ if input.peek(Ident) && input.peek2(Token![:]) && !input.peek2(Token![::]) {
+ return Ok(GenericArgument::Constraint(input.parse()?));
+ }
+
if input.peek(Lit) {
let lit = input.call(expr::parsing::expr_lit)?;
return Ok(GenericArgument::Const(Expr::Lit(lit)));
@@ -307,6 +325,32 @@
}
}
+ #[cfg(feature = "full")]
+ impl Parse for Constraint {
+ fn parse(input: ParseStream) -> Result<Self> {
+ Ok(Constraint {
+ ident: input.parse()?,
+ colon_token: input.parse()?,
+ bounds: {
+ let mut bounds = Punctuated::new();
+ loop {
+ if input.peek(Token![,]) || input.peek(Token![>]) {
+ break;
+ }
+ let value = input.parse()?;
+ bounds.push_value(value);
+ if !input.peek(Token![+]) {
+ break;
+ }
+ let punct = input.parse()?;
+ bounds.push_punct(punct);
+ }
+ bounds
+ },
+ })
+ }
+ }
+
impl Path {
/// Parse a `Path` containing no path arguments on any of its segments.
///
@@ -498,6 +542,7 @@
GenericArgument::Lifetime(ref lt) => lt.to_tokens(tokens),
GenericArgument::Type(ref ty) => ty.to_tokens(tokens),
GenericArgument::Binding(ref tb) => tb.to_tokens(tokens),
+ GenericArgument::Constraint(ref tc) => tc.to_tokens(tokens),
GenericArgument::Const(ref e) => match *e {
Expr::Lit(_) => e.to_tokens(tokens),
@@ -529,9 +574,15 @@
// not been settled yet. https://github.com/rust-lang/rust/issues/44580
let mut trailing_or_empty = true;
for param in self.args.pairs() {
- if let GenericArgument::Lifetime(_) = **param.value() {
- param.to_tokens(tokens);
- trailing_or_empty = param.punct().is_some();
+ match **param.value() {
+ GenericArgument::Lifetime(_) => {
+ param.to_tokens(tokens);
+ trailing_or_empty = param.punct().is_some();
+ }
+ GenericArgument::Type(_)
+ | GenericArgument::Binding(_)
+ | GenericArgument::Constraint(_)
+ | GenericArgument::Const(_) => {}
}
}
for param in self.args.pairs() {
@@ -543,16 +594,23 @@
param.to_tokens(tokens);
trailing_or_empty = param.punct().is_some();
}
- GenericArgument::Lifetime(_) | GenericArgument::Binding(_) => {}
+ GenericArgument::Lifetime(_)
+ | GenericArgument::Binding(_)
+ | GenericArgument::Constraint(_) => {}
}
}
for param in self.args.pairs() {
- if let GenericArgument::Binding(_) = **param.value() {
- if !trailing_or_empty {
- <Token![,]>::default().to_tokens(tokens);
- trailing_or_empty = true;
+ match **param.value() {
+ GenericArgument::Binding(_) | GenericArgument::Constraint(_) => {
+ if !trailing_or_empty {
+ <Token![,]>::default().to_tokens(tokens);
+ trailing_or_empty = true;
+ }
+ param.to_tokens(tokens);
}
- param.to_tokens(tokens);
+ GenericArgument::Lifetime(_)
+ | GenericArgument::Type(_)
+ | GenericArgument::Const(_) => {}
}
}
@@ -568,6 +626,14 @@
}
}
+ impl ToTokens for Constraint {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ self.ident.to_tokens(tokens);
+ self.colon_token.to_tokens(tokens);
+ self.bounds.to_tokens(tokens);
+ }
+ }
+
impl ToTokens for ParenthesizedGenericArguments {
fn to_tokens(&self, tokens: &mut TokenStream) {
self.paren_token.surround(tokens, |tokens| {