Document syntax tree enums idiom
diff --git a/src/attr.rs b/src/attr.rs
index 429e058..bd104d8 100644
--- a/src/attr.rs
+++ b/src/attr.rs
@@ -258,6 +258,12 @@
///
/// A name-value meta is like the `path = "..."` in `#[path =
/// "sys/windows.rs"]`.
+ ///
+ /// # Syntax tree enum
+ ///
+ /// This type is a [syntax tree enum].
+ ///
+ /// [syntax tree enum]: enum.Expr.html#syntax-tree-enums
pub enum Meta {
pub Word(Ident),
/// A structured list within an attribute, like `derive(Copy, Clone)`.
diff --git a/src/data.rs b/src/data.rs
index cfea802..77dc725 100644
--- a/src/data.rs
+++ b/src/data.rs
@@ -28,6 +28,12 @@
ast_enum_of_structs! {
/// Data stored within an enum variant or struct.
+ ///
+ /// # Syntax tree enum
+ ///
+ /// This type is a [syntax tree enum].
+ ///
+ /// [syntax tree enum]: enum.Expr.html#syntax-tree-enums
pub enum Fields {
/// Named fields of a struct or struct variant such as `Point { x: f64,
/// y: f64 }`.
@@ -71,6 +77,12 @@
ast_enum_of_structs! {
/// The visibility level of an item: inherited or `pub` or
/// `pub(restricted)`.
+ ///
+ /// # Syntax tree enum
+ ///
+ /// This type is a [syntax tree enum].
+ ///
+ /// [syntax tree enum]: enum.Expr.html#syntax-tree-enums
pub enum Visibility {
/// A public visibility level: `pub`.
pub Public(VisPublic {
diff --git a/src/derive.rs b/src/derive.rs
index fa635f4..ea8ffdc 100644
--- a/src/derive.rs
+++ b/src/derive.rs
@@ -31,6 +31,12 @@
ast_enum_of_structs! {
/// The storage of a struct, enum or union data structure.
+ ///
+ /// # Syntax tree enum
+ ///
+ /// This type is a [syntax tree enum].
+ ///
+ /// [syntax tree enum]: enum.Expr.html#syntax-tree-enums
pub enum Data {
/// A struct input to a `proc_macro_derive` macro.
pub Struct(DataStruct {
diff --git a/src/expr.rs b/src/expr.rs
index 975c635..5f48b2c 100644
--- a/src/expr.rs
+++ b/src/expr.rs
@@ -18,6 +18,88 @@
ast_enum_of_structs! {
/// A Rust expression.
+ ///
+ /// # Syntax tree enums
+ ///
+ /// This type is a syntax tree enum. In Syn this and other syntax tree enums
+ /// are designed to be traversed using the following rebinding idiom.
+ ///
+ /// ```
+ /// # use syn::Expr;
+ /// #
+ /// # fn example(expr: Expr) {
+ /// # const IGNORE: &str = stringify! {
+ /// let expr: Expr = /* ... */;
+ /// # };
+ /// match expr {
+ /// Expr::MethodCall(expr) => {
+ /// /* ... */
+ /// }
+ /// Expr::Cast(expr) => {
+ /// /* ... */
+ /// }
+ /// Expr::IfLet(expr) => {
+ /// /* ... */
+ /// }
+ /// /* ... */
+ /// # _ => {}
+ /// }
+ /// # }
+ /// ```
+ ///
+ /// We begin with a variable `expr` of type `Expr` that has no fields
+ /// (because it is an enum), and by matching on it and rebinding a variable
+ /// with the same name `expr` we effectively imbue our variable with all of
+ /// the data fields provided by the variant that it turned out to be. So for
+ /// example above if we ended up in the `MethodCall` case then we get to use
+ /// `expr.receiver`, `expr.args` etc; if we ended up in the `IfLet` case we
+ /// get to use `expr.pat`, `expr.then_branch`, `expr.else_branch`.
+ ///
+ /// The pattern is similar if the input expression is borrowed:
+ ///
+ /// ```
+ /// # use syn::Expr;
+ /// #
+ /// # fn example(expr: &Expr) {
+ /// match *expr {
+ /// Expr::MethodCall(ref expr) => {
+ /// # }
+ /// # _ => {}
+ /// # }
+ /// # }
+ /// ```
+ ///
+ /// This approach avoids repeating the variant names twice on every line.
+ ///
+ /// ```
+ /// # use syn::{Expr, ExprMethodCall};
+ /// #
+ /// # fn example(expr: Expr) {
+ /// # match expr {
+ /// Expr::MethodCall(ExprMethodCall { method, args, .. }) => { // repetitive
+ /// # }
+ /// # _ => {}
+ /// # }
+ /// # }
+ /// ```
+ ///
+ /// In general, the name to which a syntax tree enum variant is bound should
+ /// be a suitable name for the complete syntax tree enum type.
+ ///
+ /// ```
+ /// # use syn::{Expr, ExprField};
+ /// #
+ /// # fn example(discriminant: &ExprField) {
+ /// // Binding is called `base` which is the name I would use if I were
+ /// // assigning `*discriminant.base` without an `if let`.
+ /// if let Expr::Tuple(ref base) = *discriminant.base {
+ /// # }
+ /// # }
+ /// ```
+ ///
+ /// A sign that you may not be choosing the right variable names is if you
+ /// see names getting repeated in your code, like accessing
+ /// `receiver.receiver` or `pat.pat` or `cond.cond`.
pub enum Expr {
/// A box expression: `box f`.
pub Box(ExprBox #full {
@@ -581,6 +663,12 @@
ast_enum_of_structs! {
/// A pattern in a local binding, function signature, match expression, or
/// various other places.
+ ///
+ /// # Syntax tree enum
+ ///
+ /// This type is a [syntax tree enum].
+ ///
+ /// [syntax tree enum]: enum.Expr.html#syntax-tree-enums
// Clippy false positive
// https://github.com/Manishearth/rust-clippy/issues/1241
#[cfg_attr(feature = "cargo-clippy", allow(enum_variant_names))]
diff --git a/src/generics.rs b/src/generics.rs
index ef48928..0e20052 100644
--- a/src/generics.rs
+++ b/src/generics.rs
@@ -24,6 +24,12 @@
ast_enum_of_structs! {
/// A generic type parameter, lifetime, or const generic: `T: Into<String>`,
/// `'a: 'b`, `const LEN: usize`.
+ ///
+ /// # Syntax tree enum
+ ///
+ /// This type is a [syntax tree enum].
+ ///
+ /// [syntax tree enum]: enum.Expr.html#syntax-tree-enums
pub enum GenericParam {
/// A generic type parameter: `T: Into<String>`.
pub Type(TypeParam {
@@ -187,6 +193,12 @@
ast_enum_of_structs! {
/// A single predicate in a `where` clause: `T: Deserialize<'de>`.
+ ///
+ /// # Syntax tree enum
+ ///
+ /// This type is a [syntax tree enum].
+ ///
+ /// [syntax tree enum]: enum.Expr.html#syntax-tree-enums
pub enum WherePredicate {
/// A type predicate in a `where` clause: `for<'c> Foo<'c>: Trait<'c>`.
pub Type(PredicateType {
diff --git a/src/item.rs b/src/item.rs
index 0cda50c..0bc57aa 100644
--- a/src/item.rs
+++ b/src/item.rs
@@ -19,6 +19,12 @@
ast_enum_of_structs! {
/// Things that can appear directly inside of a module or scope.
+ ///
+ /// # Syntax tree enum
+ ///
+ /// This type is a [syntax tree enum].
+ ///
+ /// [syntax tree enum]: enum.Expr.html#syntax-tree-enums
pub enum Item {
/// An `extern crate` item: `extern crate serde`.
pub ExternCrate(ItemExternCrate {
@@ -288,6 +294,12 @@
ast_enum_of_structs! {
/// A suffix of an import tree in a `use` item: `Type as Renamed` or `*`.
+ ///
+ /// # Syntax tree enum
+ ///
+ /// This type is a [syntax tree enum].
+ ///
+ /// [syntax tree enum]: enum.Expr.html#syntax-tree-enums
pub enum UseTree {
/// An identifier imported by a `use` item: `Type` or `Type as Renamed`.
pub Path(UsePath {
@@ -308,6 +320,12 @@
ast_enum_of_structs! {
/// An item within an `extern` block.
+ ///
+ /// # Syntax tree enum
+ ///
+ /// This type is a [syntax tree enum].
+ ///
+ /// [syntax tree enum]: enum.Expr.html#syntax-tree-enums
pub enum ForeignItem {
/// A foreign function in an `extern` block.
pub Fn(ForeignItemFn {
@@ -368,6 +386,12 @@
ast_enum_of_structs! {
/// An item declaration within the definition of a trait.
+ ///
+ /// # Syntax tree enum
+ ///
+ /// This type is a [syntax tree enum].
+ ///
+ /// [syntax tree enum]: enum.Expr.html#syntax-tree-enums
pub enum TraitItem {
/// An associated constant within the definition of a trait.
pub Const(TraitItemConst {
@@ -436,6 +460,12 @@
ast_enum_of_structs! {
/// An item within an impl block.
+ ///
+ /// # Syntax tree enum
+ ///
+ /// This type is a [syntax tree enum].
+ ///
+ /// [syntax tree enum]: enum.Expr.html#syntax-tree-enums
pub enum ImplItem {
/// An associated constant within an impl block.
pub Const(ImplItemConst {
@@ -535,6 +565,12 @@
/// An argument in a function signature.
///
/// E.g. `bar: usize` as in `fn foo(bar: usize)`
+ ///
+ /// # Syntax tree enum
+ ///
+ /// This type is a [syntax tree enum].
+ ///
+ /// [syntax tree enum]: enum.Expr.html#syntax-tree-enums
pub enum FnArg {
/// Self captured by reference in a function signature: `&self` or `&mut
/// self`.
diff --git a/src/lit.rs b/src/lit.rs
index 0d54641..56a354d 100644
--- a/src/lit.rs
+++ b/src/lit.rs
@@ -17,6 +17,12 @@
ast_enum_of_structs! {
/// A Rust literal such as a string or integer or boolean.
+ ///
+ /// # Syntax tree enum
+ ///
+ /// This type is a [syntax tree enum].
+ ///
+ /// [syntax tree enum]: enum.Expr.html#syntax-tree-enums
pub enum Lit {
/// A UTF-8 string literal: `"foo"`.
pub Str(LitStr #manual_extra_traits {
diff --git a/src/ty.rs b/src/ty.rs
index 9538260..39bae38 100644
--- a/src/ty.rs
+++ b/src/ty.rs
@@ -16,6 +16,12 @@
ast_enum_of_structs! {
/// The possible types that a Rust value could have.
+ ///
+ /// # Syntax tree enum
+ ///
+ /// This type is a [syntax tree enum].
+ ///
+ /// [syntax tree enum]: enum.Expr.html#syntax-tree-enums
pub enum Type {
/// A dynamically sized slice type: `[T]`.
pub Slice(TypeSlice {