Make ToTokens more lenient when generating tokens for invalid ASTs
diff --git a/src/data.rs b/src/data.rs
index 937de27..4821a7a 100644
--- a/src/data.rs
+++ b/src/data.rs
@@ -212,8 +212,10 @@
tokens.append_all(&self.attrs);
self.ident.to_tokens(tokens);
self.data.to_tokens(tokens);
- self.eq_token.to_tokens(tokens);
- self.discriminant.to_tokens(tokens);
+ if let Some(ref disc) = self.discriminant {
+ self.eq_token.unwrap_or_default().to_tokens(tokens);
+ disc.to_tokens(tokens);
+ }
}
}
@@ -239,8 +241,10 @@
fn to_tokens(&self, tokens: &mut Tokens) {
tokens.append_all(&self.attrs);
self.vis.to_tokens(tokens);
- self.ident.to_tokens(tokens);
- self.colon_token.to_tokens(tokens);
+ if let Some(ref ident) = self.ident {
+ ident.to_tokens(tokens);
+ self.colon_token.unwrap_or_default().to_tokens(tokens);
+ }
self.ty.to_tokens(tokens);
}
}
@@ -264,6 +268,8 @@
fn to_tokens(&self, tokens: &mut Tokens) {
self.pub_token.to_tokens(tokens);
self.paren_token.surround(tokens, |tokens| {
+ // XXX: If we have a path which is not "self" or "super",
+ // automatically add the "in" token.
self.in_token.to_tokens(tokens);
self.path.to_tokens(tokens);
});
diff --git a/src/expr.rs b/src/expr.rs
index db3fb55..3d4fbb3 100644
--- a/src/expr.rs
+++ b/src/expr.rs
@@ -527,7 +527,7 @@
pub hi: Box<Expr>,
pub limits: RangeLimits,
}),
- /// `[a, b, ..i, y, z]` is represented as:
+ /// `[a, b, i.., y, z]` is represented as:
pub Slice(PatSlice {
pub front: Delimited<Pat, tokens::Comma>,
pub middle: Option<Box<Pat>>,
@@ -622,6 +622,16 @@
}
}
+#[cfg(any(feature = "parsing", feature = "printing"))]
+#[cfg(feature = "full")]
+fn arm_requires_comma(arm: &Arm) -> bool {
+ if let ExprKind::Block(ExprBlock { unsafety: Unsafety::Normal, .. }) = arm.body.node {
+ false
+ } else {
+ true
+ }
+}
+
#[cfg(feature = "parsing")]
pub mod parsing {
use super::*;
@@ -1497,15 +1507,6 @@
}
#[cfg(feature = "full")]
- fn arm_requires_comma(arm: &Arm) -> bool {
- if let ExprKind::Block(ExprBlock { unsafety: Unsafety::Normal, .. }) = arm.body.node {
- false
- } else {
- true
- }
- }
-
- #[cfg(feature = "full")]
impl Synom for Arm {
named!(parse -> Self, do_parse!(
attrs: many0!(call!(Attribute::parse_outer)) >>
@@ -2265,6 +2266,19 @@
use attr::FilterAttrs;
use quote::{Tokens, ToTokens};
+ /// If the given expression is a bare `ExprStruct`, wraps it in parenthesis
+ /// before appending it to `Tokens`.
+ #[cfg(feature = "full")]
+ fn wrap_bare_struct(tokens: &mut Tokens, e: &Expr) {
+ if let ExprKind::Struct(_) = e.node {
+ tokens::Paren::default().surround(tokens, |tokens| {
+ e.to_tokens(tokens);
+ });
+ } else {
+ e.to_tokens(tokens);
+ }
+ }
+
impl ToTokens for Expr {
#[cfg(feature = "full")]
fn to_tokens(&self, tokens: &mut Tokens) {
@@ -2298,7 +2312,15 @@
InPlaceKind::In(ref _in) => {
_in.to_tokens(tokens);
self.place.to_tokens(tokens);
- self.value.to_tokens(tokens);
+ // NOTE: The second operand must be in a block, add one if
+ // it is not present.
+ if let ExprKind::Block(_) = self.value.node {
+ self.value.to_tokens(tokens);
+ } else {
+ tokens::Brace::default().surround(tokens, |tokens| {
+ self.value.to_tokens(tokens);
+ })
+ }
}
}
}
@@ -2328,10 +2350,12 @@
self.expr.to_tokens(tokens);
self.dot_token.to_tokens(tokens);
self.method.to_tokens(tokens);
- self.colon2_token.to_tokens(tokens);
- self.lt_token.to_tokens(tokens);
- self.typarams.to_tokens(tokens);
- self.gt_token.to_tokens(tokens);
+ if !self.typarams.is_empty() {
+ self.colon2_token.unwrap_or_default().to_tokens(tokens);
+ self.lt_token.unwrap_or_default().to_tokens(tokens);
+ self.typarams.to_tokens(tokens);
+ self.gt_token.unwrap_or_default().to_tokens(tokens);
+ }
self.paren_token.surround(tokens, |tokens| {
self.args.to_tokens(tokens);
});
@@ -2343,6 +2367,15 @@
fn to_tokens(&self, tokens: &mut Tokens) {
self.paren_token.surround(tokens, |tokens| {
self.args.to_tokens(tokens);
+ // If we only have one argument, we need a trailing comma to
+ // distinguish ExprTup from ExprParen.
+ if self.args.len() == 1 && !self.args.trailing_delim() {
+ tokens::Comma::default().to_tokens(tokens);
+ }
+ // XXX: Not sure how to handle this, but we never parse it yet.
+ // Is this for an expression like (0,)? Can't we use the
+ // trailing delimiter on Delimited for that? (,) isn't a valid
+ // expression as far as I know.
self.lone_comma.to_tokens(tokens);
})
}
@@ -2380,13 +2413,37 @@
}
#[cfg(feature = "full")]
+ fn maybe_wrap_else(tokens: &mut Tokens,
+ else_token: &Option<tokens::Else>,
+ if_false: &Option<Box<Expr>>)
+ {
+ if let Some(ref if_false) = *if_false {
+ else_token.unwrap_or_default().to_tokens(tokens);
+
+ // If we are not one of the valid expressions to exist in an else
+ // clause, wrap ourselves in a block.
+ match if_false.node {
+ ExprKind::If(_) |
+ ExprKind::IfLet(_) |
+ ExprKind::Block(_) => {
+ if_false.to_tokens(tokens);
+ }
+ _ => {
+ tokens::Brace::default().surround(tokens, |tokens| {
+ if_false.to_tokens(tokens);
+ });
+ }
+ }
+ }
+ }
+
+ #[cfg(feature = "full")]
impl ToTokens for ExprIf {
fn to_tokens(&self, tokens: &mut Tokens) {
self.if_token.to_tokens(tokens);
- self.cond.to_tokens(tokens);
+ wrap_bare_struct(tokens, &self.cond);
self.if_true.to_tokens(tokens);
- self.else_token.to_tokens(tokens);
- self.if_false.to_tokens(tokens);
+ maybe_wrap_else(tokens, &self.else_token, &self.if_false);
}
}
@@ -2397,20 +2454,21 @@
self.let_token.to_tokens(tokens);
self.pat.to_tokens(tokens);
self.eq_token.to_tokens(tokens);
- self.expr.to_tokens(tokens);
+ wrap_bare_struct(tokens, &self.expr);
self.if_true.to_tokens(tokens);
- self.else_token.to_tokens(tokens);
- self.if_false.to_tokens(tokens);
+ maybe_wrap_else(tokens, &self.else_token, &self.if_false);
}
}
#[cfg(feature = "full")]
impl ToTokens for ExprWhile {
fn to_tokens(&self, tokens: &mut Tokens) {
- self.label.to_tokens(tokens);
- self.colon_token.to_tokens(tokens);
+ if self.label.is_some() {
+ self.label.to_tokens(tokens);
+ self.colon_token.unwrap_or_default().to_tokens(tokens);
+ }
self.while_token.to_tokens(tokens);
- self.cond.to_tokens(tokens);
+ wrap_bare_struct(tokens, &self.cond);
self.body.to_tokens(tokens);
}
}
@@ -2418,13 +2476,15 @@
#[cfg(feature = "full")]
impl ToTokens for ExprWhileLet {
fn to_tokens(&self, tokens: &mut Tokens) {
- self.label.to_tokens(tokens);
- self.colon_token.to_tokens(tokens);
+ if self.label.is_some() {
+ self.label.to_tokens(tokens);
+ self.colon_token.unwrap_or_default().to_tokens(tokens);
+ }
self.while_token.to_tokens(tokens);
self.let_token.to_tokens(tokens);
self.pat.to_tokens(tokens);
self.eq_token.to_tokens(tokens);
- self.expr.to_tokens(tokens);
+ wrap_bare_struct(tokens, &self.expr);
self.body.to_tokens(tokens);
}
}
@@ -2432,12 +2492,14 @@
#[cfg(feature = "full")]
impl ToTokens for ExprForLoop {
fn to_tokens(&self, tokens: &mut Tokens) {
- self.label.to_tokens(tokens);
- self.colon_token.to_tokens(tokens);
+ if self.label.is_some() {
+ self.label.to_tokens(tokens);
+ self.colon_token.unwrap_or_default().to_tokens(tokens);
+ }
self.for_token.to_tokens(tokens);
self.pat.to_tokens(tokens);
self.in_token.to_tokens(tokens);
- self.expr.to_tokens(tokens);
+ wrap_bare_struct(tokens, &self.expr);
self.body.to_tokens(tokens);
}
}
@@ -2445,8 +2507,10 @@
#[cfg(feature = "full")]
impl ToTokens for ExprLoop {
fn to_tokens(&self, tokens: &mut Tokens) {
- self.label.to_tokens(tokens);
- self.colon_token.to_tokens(tokens);
+ if self.label.is_some() {
+ self.label.to_tokens(tokens);
+ self.colon_token.unwrap_or_default().to_tokens(tokens);
+ }
self.loop_token.to_tokens(tokens);
self.body.to_tokens(tokens);
}
@@ -2456,9 +2520,17 @@
impl ToTokens for ExprMatch {
fn to_tokens(&self, tokens: &mut Tokens) {
self.match_token.to_tokens(tokens);
- self.expr.to_tokens(tokens);
+ wrap_bare_struct(tokens, &self.expr);
self.brace_token.surround(tokens, |tokens| {
- tokens.append_all(&self.arms);
+ for (i, arm) in self.arms.iter().enumerate() {
+ arm.to_tokens(tokens);
+ // Ensure that we have a comma after a non-block arm, except
+ // for the last one.
+ let is_last = i == self.arms.len() - 1;
+ if !is_last && arm_requires_comma(arm) && arm.comma.is_none() {
+ tokens::Comma::default().to_tokens(tokens);
+ }
+ }
});
}
}
@@ -2531,6 +2603,8 @@
fn to_tokens(&self, tokens: &mut Tokens) {
self.expr.to_tokens(tokens);
self.dot_token.to_tokens(tokens);
+ // XXX: I don't think we can do anything if someone shoves a
+ // nonsense Lit in here.
self.field.to_tokens(tokens);
}
}
@@ -2608,8 +2682,10 @@
self.path.to_tokens(tokens);
self.brace_token.surround(tokens, |tokens| {
self.fields.to_tokens(tokens);
- self.dot2_token.to_tokens(tokens);
- self.rest.to_tokens(tokens);
+ if self.rest.is_some() {
+ self.dot2_token.unwrap_or_default().to_tokens(tokens);
+ self.rest.to_tokens(tokens);
+ }
})
}
}
@@ -2653,8 +2729,11 @@
impl ToTokens for FieldValue {
fn to_tokens(&self, tokens: &mut Tokens) {
self.ident.to_tokens(tokens);
+ // XXX: Override self.is_shorthand if expr is not an IdentExpr with
+ // the ident self.ident?
if !self.is_shorthand {
- self.colon_token.to_tokens(tokens);
+ self.colon_token.unwrap_or_default()
+ .to_tokens(tokens);
self.expr.to_tokens(tokens);
}
}
@@ -2665,8 +2744,10 @@
fn to_tokens(&self, tokens: &mut Tokens) {
tokens.append_all(&self.attrs);
self.pats.to_tokens(tokens);
- self.if_token.to_tokens(tokens);
- self.guard.to_tokens(tokens);
+ if self.guard.is_some() {
+ self.if_token.unwrap_or_default().to_tokens(tokens);
+ self.guard.to_tokens(tokens);
+ }
self.rocket_token.to_tokens(tokens);
self.body.to_tokens(tokens);
self.comma.to_tokens(tokens);
@@ -2685,8 +2766,10 @@
fn to_tokens(&self, tokens: &mut Tokens) {
self.mode.to_tokens(tokens);
self.ident.to_tokens(tokens);
- self.at_token.to_tokens(tokens);
- self.subpat.to_tokens(tokens);
+ if self.subpat.is_some() {
+ self.at_token.unwrap_or_default().to_tokens(tokens);
+ self.subpat.to_tokens(tokens);
+ }
}
}
@@ -2696,6 +2779,10 @@
self.path.to_tokens(tokens);
self.brace_token.surround(tokens, |tokens| {
self.fields.to_tokens(tokens);
+ // NOTE: We need a comma before the dot2 token if it is present.
+ if !self.fields.empty_or_trailing() && self.dot2_token.is_some() {
+ tokens::Comma::default().to_tokens(tokens);
+ }
self.dot2_token.to_tokens(tokens);
});
}
@@ -2722,13 +2809,17 @@
self.paren_token.surround(tokens, |tokens| {
for (i, token) in self.pats.iter().enumerate() {
if Some(i) == self.dots_pos {
- self.dot2_token.to_tokens(tokens);
- self.comma_token.to_tokens(tokens);
+ self.dot2_token.unwrap_or_default().to_tokens(tokens);
+ self.comma_token.unwrap_or_default().to_tokens(tokens);
}
token.to_tokens(tokens);
}
if Some(self.pats.len()) == self.dots_pos {
+ // Ensure there is a comma before the .. token.
+ if !self.pats.empty_or_trailing() {
+ tokens::Comma::default().to_tokens(tokens);
+ }
self.dot2_token.to_tokens(tokens);
}
});
@@ -2771,12 +2862,34 @@
#[cfg(feature = "full")]
impl ToTokens for PatSlice {
fn to_tokens(&self, tokens: &mut Tokens) {
+ // XXX: This is a mess, and it will be so easy to screw it up. How
+ // do we make this correct itself better?
self.bracket_token.surround(tokens, |tokens| {
self.front.to_tokens(tokens);
- self.middle.to_tokens(tokens);
- self.dot2_token.to_tokens(tokens);
- self.comma_token.to_tokens(tokens);
- self.back.to_tokens(tokens);
+
+ // If we need a comma before the middle or standalone .. token,
+ // then make sure it's present.
+ if !self.front.empty_or_trailing() &&
+ (self.middle.is_some() || self.dot2_token.is_some())
+ {
+ tokens::Comma::default().to_tokens(tokens);
+ }
+
+ // If we have an identifier, we always need a .. token.
+ if self.middle.is_some() {
+ self.middle.to_tokens(tokens);
+ self.dot2_token.unwrap_or_default().to_tokens(tokens);
+ } else if self.dot2_token.is_some() {
+ self.dot2_token.to_tokens(tokens);
+ }
+
+ // Make sure we have a comma before the back half.
+ if !self.back.is_empty() {
+ self.comma_token.unwrap_or_default().to_tokens(tokens);
+ self.back.to_tokens(tokens);
+ } else {
+ self.comma_token.to_tokens(tokens);
+ }
})
}
}
@@ -2794,9 +2907,10 @@
#[cfg(feature = "full")]
impl ToTokens for FieldPat {
fn to_tokens(&self, tokens: &mut Tokens) {
+ // XXX: Override is_shorthand if it was wrong?
if !self.is_shorthand {
self.ident.to_tokens(tokens);
- self.colon_token.to_tokens(tokens);
+ self.colon_token.unwrap_or_default().to_tokens(tokens);
}
self.pat.to_tokens(tokens);
}
@@ -2870,10 +2984,14 @@
tokens.append_all(self.attrs.outer());
self.let_token.to_tokens(tokens);
self.pat.to_tokens(tokens);
- self.colon_token.to_tokens(tokens);
- self.ty.to_tokens(tokens);
- self.eq_token.to_tokens(tokens);
- self.init.to_tokens(tokens);
+ if self.ty.is_some() {
+ self.colon_token.unwrap_or_default().to_tokens(tokens);
+ self.ty.to_tokens(tokens);
+ }
+ if self.init.is_some() {
+ self.eq_token.unwrap_or_default().to_tokens(tokens);
+ self.init.to_tokens(tokens);
+ }
self.semi_token.to_tokens(tokens);
}
}
diff --git a/src/generics.rs b/src/generics.rs
index 7cb6c82..b169f8a 100644
--- a/src/generics.rs
+++ b/src/generics.rs
@@ -357,54 +357,85 @@
use attr::FilterAttrs;
use quote::{Tokens, ToTokens};
+ /// Returns true if the generics object has no lifetimes or ty_params.
+ fn empty_normal_generics(generics: &Generics) -> bool {
+ generics.lifetimes.is_empty() && generics.ty_params.is_empty()
+ }
+
+ /// We need a comma between the lifetimes list and the ty_params list if
+ /// there are more than 0 lifetimes, the lifetimes list didn't have a
+ /// trailing delimiter, and there are more than 0 type parameters. This is a
+ /// helper method for adding that comma.
+ fn maybe_add_lifetime_params_comma(tokens: &mut Tokens, generics: &Generics) {
+ // We may need to require a trailing comma if we have any ty_params.
+ if !generics.lifetimes.empty_or_trailing() && !generics.ty_params.is_empty() {
+ tokens::Comma::default().to_tokens(tokens);
+ }
+ }
+
impl ToTokens for Generics {
fn to_tokens(&self, tokens: &mut Tokens) {
- self.lt_token.to_tokens(tokens);
+ if empty_normal_generics(self) {
+ return;
+ }
+
+ self.lt_token.unwrap_or_default().to_tokens(tokens);
self.lifetimes.to_tokens(tokens);
+ maybe_add_lifetime_params_comma(tokens, self);
self.ty_params.to_tokens(tokens);
- self.gt_token.to_tokens(tokens);
+ self.gt_token.unwrap_or_default().to_tokens(tokens);
}
}
impl<'a> ToTokens for ImplGenerics<'a> {
fn to_tokens(&self, tokens: &mut Tokens) {
- self.0.lt_token.to_tokens(tokens);
+ if empty_normal_generics(&self.0) {
+ return;
+ }
+
+ self.0.lt_token.unwrap_or_default().to_tokens(tokens);
self.0.lifetimes.to_tokens(tokens);
+ maybe_add_lifetime_params_comma(tokens, &self.0);
for param in self.0.ty_params.iter() {
// Leave off the type parameter defaults
let item = param.item();
tokens.append_all(item.attrs.outer());
item.ident.to_tokens(tokens);
- item.colon_token.to_tokens(tokens);
- item.bounds.to_tokens(tokens);
+ if !item.bounds.is_empty() {
+ item.colon_token.unwrap_or_default().to_tokens(tokens);
+ item.bounds.to_tokens(tokens);
+ }
param.delimiter().to_tokens(tokens);
}
- self.0.gt_token.to_tokens(tokens);
+ self.0.gt_token.unwrap_or_default().to_tokens(tokens);
}
}
impl<'a> ToTokens for TyGenerics<'a> {
fn to_tokens(&self, tokens: &mut Tokens) {
- self.0.lt_token.to_tokens(tokens);
+ if empty_normal_generics(&self.0) {
+ return;
+ }
+
+ self.0.lt_token.unwrap_or_default().to_tokens(tokens);
// Leave off the lifetime bounds and attributes
for param in self.0.lifetimes.iter() {
param.item().lifetime.to_tokens(tokens);
param.delimiter().to_tokens(tokens);
}
+ maybe_add_lifetime_params_comma(tokens, &self.0);
// Leave off the type parameter defaults
for param in self.0.ty_params.iter() {
param.item().ident.to_tokens(tokens);
param.delimiter().to_tokens(tokens);
}
- self.0.gt_token.to_tokens(tokens);
+ self.0.gt_token.unwrap_or_default().to_tokens(tokens);
}
}
impl<'a> ToTokens for Turbofish<'a> {
fn to_tokens(&self, tokens: &mut Tokens) {
- let has_lifetimes = !self.0.lifetimes.is_empty();
- let has_ty_params = !self.0.ty_params.is_empty();
- if has_lifetimes || has_ty_params {
+ if !empty_normal_generics(&self.0) {
tokens::Colon2::default().to_tokens(tokens);
TyGenerics(self.0).to_tokens(tokens);
}
@@ -424,8 +455,10 @@
fn to_tokens(&self, tokens: &mut Tokens) {
tokens.append_all(self.attrs.outer());
self.lifetime.to_tokens(tokens);
- self.colon_token.to_tokens(tokens);
- self.bounds.to_tokens(tokens);
+ if !self.bounds.is_empty() {
+ self.colon_token.unwrap_or_default().to_tokens(tokens);
+ self.bounds.to_tokens(tokens);
+ }
}
}
@@ -433,10 +466,14 @@
fn to_tokens(&self, tokens: &mut Tokens) {
tokens.append_all(self.attrs.outer());
self.ident.to_tokens(tokens);
- self.colon_token.to_tokens(tokens);
- self.bounds.to_tokens(tokens);
- self.eq_token.to_tokens(tokens);
- self.default.to_tokens(tokens);
+ if !self.bounds.is_empty() {
+ self.colon_token.unwrap_or_default().to_tokens(tokens);
+ self.bounds.to_tokens(tokens);
+ }
+ if self.default.is_some() {
+ self.eq_token.unwrap_or_default().to_tokens(tokens);
+ self.default.to_tokens(tokens);
+ }
}
}
@@ -463,8 +500,10 @@
impl ToTokens for WhereClause {
fn to_tokens(&self, tokens: &mut Tokens) {
- self.where_token.to_tokens(tokens);
- self.predicates.to_tokens(tokens);
+ if !self.predicates.is_empty() {
+ self.where_token.unwrap_or_default().to_tokens(tokens);
+ self.predicates.to_tokens(tokens);
+ }
}
}
@@ -480,8 +519,10 @@
impl ToTokens for WhereRegionPredicate {
fn to_tokens(&self, tokens: &mut Tokens) {
self.lifetime.to_tokens(tokens);
- self.colon_token.to_tokens(tokens);
- self.bounds.to_tokens(tokens);
+ if !self.bounds.is_empty() {
+ self.colon_token.unwrap_or_default().to_tokens(tokens);
+ self.bounds.to_tokens(tokens);
+ }
}
}
diff --git a/src/item.rs b/src/item.rs
index 618c20b..dca8543 100644
--- a/src/item.rs
+++ b/src/item.rs
@@ -1366,8 +1366,9 @@
tokens.append_all(self.attrs.inner());
tokens.append_all(items);
});
+ } else {
+ item.semi.unwrap_or_default().to_tokens(tokens);
}
- item.semi.to_tokens(tokens);
}
ItemKind::ForeignMod(ref item) => {
item.abi.to_tokens(tokens);
@@ -1408,12 +1409,13 @@
VariantData::Tuple(..) => {
item.data.to_tokens(tokens);
item.generics.where_clause.to_tokens(tokens);
+ item.semi_token.unwrap_or_default().to_tokens(tokens);
}
VariantData::Unit => {
item.generics.where_clause.to_tokens(tokens);
+ item.semi_token.unwrap_or_default().to_tokens(tokens);
}
}
- item.semi_token.to_tokens(tokens);
}
ItemKind::Union(ref item) => {
item.vis.to_tokens(tokens);
@@ -1421,6 +1423,8 @@
item.ident.to_tokens(tokens);
item.generics.to_tokens(tokens);
item.generics.where_clause.to_tokens(tokens);
+ // XXX: Should we handle / complain when using a
+ // non-VariantData::Struct Variant in Union?
item.data.to_tokens(tokens);
}
ItemKind::Trait(ref item) => {
@@ -1429,8 +1433,10 @@
item.trait_token.to_tokens(tokens);
item.ident.to_tokens(tokens);
item.generics.to_tokens(tokens);
- item.colon_token.to_tokens(tokens);
- item.supertraits.to_tokens(tokens);
+ if !item.supertraits.is_empty() {
+ item.colon_token.unwrap_or_default().to_tokens(tokens);
+ item.supertraits.to_tokens(tokens);
+ }
item.generics.where_clause.to_tokens(tokens);
item.brace_token.surround(tokens, |tokens| {
tokens.append_all(&item.items);
@@ -1475,8 +1481,10 @@
impl ToTokens for PathSimple {
fn to_tokens(&self, tokens: &mut Tokens) {
self.path.to_tokens(tokens);
- self.as_token.to_tokens(tokens);
- self.rename.to_tokens(tokens);
+ if self.rename.is_some() {
+ self.as_token.unwrap_or_default().to_tokens(tokens);
+ self.rename.to_tokens(tokens);
+ }
}
}
@@ -1501,8 +1509,10 @@
impl ToTokens for PathListItem {
fn to_tokens(&self, tokens: &mut Tokens) {
self.name.to_tokens(tokens);
- self.as_token.to_tokens(tokens);
- self.rename.to_tokens(tokens);
+ if self.rename.is_some() {
+ self.as_token.unwrap_or_default().to_tokens(tokens);
+ self.rename.to_tokens(tokens);
+ }
}
}
@@ -1531,15 +1541,17 @@
});
}
None => {
- item.semi_token.to_tokens(tokens);
+ item.semi_token.unwrap_or_default().to_tokens(tokens);
}
}
}
TraitItemKind::Type(ref item) => {
item.type_token.to_tokens(tokens);
item.ident.to_tokens(tokens);
- item.colon_token.to_tokens(tokens);
- item.bounds.to_tokens(tokens);
+ if !item.bounds.is_empty() {
+ item.colon_token.unwrap_or_default().to_tokens(tokens);
+ item.bounds.to_tokens(tokens);
+ }
if let Some((ref eq_token, ref default)) = item.default {
eq_token.to_tokens(tokens);
default.to_tokens(tokens);
@@ -1638,7 +1650,13 @@
self.0.generics.to_tokens(tokens);
self.0.paren_token.surround(tokens, |tokens| {
self.0.inputs.to_tokens(tokens);
- self.0.dot_tokens.to_tokens(tokens);
+
+ if self.0.variadic {
+ if !self.0.inputs.empty_or_trailing() {
+ tokens::Comma::default().to_tokens(tokens);
+ }
+ self.0.dot_tokens.unwrap_or_default().to_tokens(tokens);
+ }
});
self.0.output.to_tokens(tokens);
self.0.generics.where_clause.to_tokens(tokens);
diff --git a/src/mac.rs b/src/mac.rs
index 55b33cf..6645c00 100644
--- a/src/mac.rs
+++ b/src/mac.rs
@@ -177,6 +177,7 @@
fn to_tokens(&self, tokens: &mut Tokens) {
self.path.to_tokens(tokens);
self.bang_token.to_tokens(tokens);
+ self.ident.to_tokens(tokens);
tokens.append_all(&self.tokens);
}
}
diff --git a/src/ty.rs b/src/ty.rs
index 83aecd4..cc9d2c8 100644
--- a/src/ty.rs
+++ b/src/ty.rs
@@ -258,7 +258,8 @@
pub struct QSelf {
pub lt_token: tokens::Lt,
pub ty: Box<Ty>,
- pub position: Option<(tokens::As, usize)>,
+ pub position: usize,
+ pub as_token: Option<tokens::As>,
pub gt_token: tokens::Gt,
}
}
@@ -547,7 +548,7 @@
colon2: syn!(Colon2) >>
rest: call!(Delimited::parse_separated_nonempty) >>
({
- let (pos, path) = match path {
+ let (pos, as_, path) = match path {
Some((as_, mut path)) => {
let pos = path.segments.len();
if !path.segments.is_empty() && !path.segments.trailing_delim() {
@@ -556,10 +557,10 @@
for item in rest {
path.segments.push(item);
}
- (Some((as_, pos)), path)
+ (pos, Some(as_), path)
}
None => {
- (None, Path {
+ (0, None, Path {
leading_colon: Some(colon2),
segments: rest,
})
@@ -569,6 +570,7 @@
lt_token: lt,
ty: Box::new(this),
position: pos,
+ as_token: as_,
gt_token: gt,
}), path)
})
@@ -835,8 +837,12 @@
impl ToTokens for TyPtr {
fn to_tokens(&self, tokens: &mut Tokens) {
self.star_token.to_tokens(tokens);
- self.const_token.to_tokens(tokens);
- self.ty.mutability.to_tokens(tokens);
+ match self.ty.mutability {
+ Mutability::Mutable(ref tok) => tok.to_tokens(tokens),
+ Mutability::Immutable => {
+ self.const_token.unwrap_or_default().to_tokens(tokens);
+ }
+ }
self.ty.ty.to_tokens(tokens);
}
}
@@ -866,6 +872,7 @@
fn to_tokens(&self, tokens: &mut Tokens) {
self.paren_token.surround(tokens, |tokens| {
self.tys.to_tokens(tokens);
+ // XXX: I don't think (,) is a thing.
self.lone_comma.to_tokens(tokens);
})
}
@@ -885,9 +892,16 @@
};
qself.lt_token.to_tokens(tokens);
qself.ty.to_tokens(tokens);
+
+ // XXX: Gross.
+ let pos = if qself.position > 0 && qself.position >= self.1.segments.len() {
+ self.1.segments.len() - 1
+ } else {
+ qself.position
+ };
let mut segments = self.1.segments.iter();
- if let Some((ref as_token, pos)) = qself.position {
- as_token.to_tokens(tokens);
+ if pos > 0 {
+ qself.as_token.unwrap_or_default().to_tokens(tokens);
self.1.leading_colon.to_tokens(tokens);
for (i, segment) in (&mut segments).take(pos).enumerate() {
if i + 1 == pos {
@@ -984,7 +998,21 @@
self.turbofish.to_tokens(tokens);
self.lt_token.to_tokens(tokens);
self.lifetimes.to_tokens(tokens);
+ if !self.lifetimes.empty_or_trailing() && !self.types.is_empty() {
+ tokens::Comma::default().to_tokens(tokens);
+ }
self.types.to_tokens(tokens);
+ if (
+ // If we have no trailing delimiter after a non-empty types list, or
+ !self.types.empty_or_trailing() ||
+ // If we have no trailing delimiter after a non-empty lifetimes
+ // list before an empty types list, and
+ (self.types.is_empty() && !self.lifetimes.empty_or_trailing())) &&
+ // We have some bindings, then we need a comma.
+ !self.bindings.is_empty()
+ {
+ tokens::Comma::default().to_tokens(tokens);
+ }
self.bindings.to_tokens(tokens);
self.gt_token.to_tokens(tokens);
}
@@ -1034,6 +1062,9 @@
self.fn_token.to_tokens(tokens);
self.paren_token.surround(tokens, |tokens| {
self.inputs.to_tokens(tokens);
+ if self.variadic.is_some() && !self.inputs.empty_or_trailing() {
+ tokens::Comma::default().to_tokens(tokens);
+ }
self.variadic.to_tokens(tokens);
});
self.output.to_tokens(tokens);