Accept `let` as an expression
diff --git a/src/expr.rs b/src/expr.rs
index 9440c1c..27dae63 100644
--- a/src/expr.rs
+++ b/src/expr.rs
@@ -41,7 +41,7 @@
     ///     Expr::Cast(expr) => {
     ///         /* ... */
     ///     }
-    ///     Expr::IfLet(expr) => {
+    ///     Expr::If(expr) => {
     ///         /* ... */
     ///     }
     ///     /* ... */
@@ -55,8 +55,8 @@
     /// 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`.
+    /// `expr.receiver`, `expr.args` etc; if we ended up in the `If` case we get
+    /// to use `expr.cond`, `expr.then_branch`, `expr.else_branch`.
     ///
     /// The pattern is similar if the input expression is borrowed:
     ///
@@ -216,11 +216,22 @@
             pub ty: Box<Type>,
         }),
 
+        /// A `let` guard: `let Some(x) = opt`.
+        ///
+        /// *This type is available if Syn is built with the `"full"` feature.*
+        pub Let(ExprLet #full {
+            pub attrs: Vec<Attribute>,
+            pub let_token: Token![let],
+            pub pats: Punctuated<Pat, Token![|]>,
+            pub eq_token: Token![=],
+            pub expr: Box<Expr>,
+        }),
+
         /// An `if` expression with an optional `else` block: `if expr { ... }
         /// else { ... }`.
         ///
-        /// The `else` branch expression may only be an `If`, `IfLet`, or
-        /// `Block` expression, not any of the other types of expression.
+        /// The `else` branch expression may only be an `If` or `Block`
+        /// expression, not any of the other types of expression.
         ///
         /// *This type is available if Syn is built with the `"full"` feature.*
         pub If(ExprIf #full {
@@ -231,24 +242,6 @@
             pub else_branch: Option<(Token![else], Box<Expr>)>,
         }),
 
-        /// An `if let` expression with an optional `else` block: `if let pat =
-        /// expr { ... } else { ... }`.
-        ///
-        /// The `else` branch expression may only be an `If`, `IfLet`, or
-        /// `Block` expression, not any of the other types of expression.
-        ///
-        /// *This type is available if Syn is built with the `"full"` feature.*
-        pub IfLet(ExprIfLet #full {
-            pub attrs: Vec<Attribute>,
-            pub if_token: Token![if],
-            pub let_token: Token![let],
-            pub pats: Punctuated<Pat, Token![|]>,
-            pub eq_token: Token![=],
-            pub expr: Box<Expr>,
-            pub then_branch: Block,
-            pub else_branch: Option<(Token![else], Box<Expr>)>,
-        }),
-
         /// A while loop: `while expr { ... }`.
         ///
         /// *This type is available if Syn is built with the `"full"` feature.*
@@ -260,20 +253,6 @@
             pub body: Block,
         }),
 
-        /// A while-let loop: `while let pat = expr { ... }`.
-        ///
-        /// *This type is available if Syn is built with the `"full"` feature.*
-        pub WhileLet(ExprWhileLet #full {
-            pub attrs: Vec<Attribute>,
-            pub label: Option<Label>,
-            pub while_token: Token![while],
-            pub let_token: Token![let],
-            pub pats: Punctuated<Pat, Token![|]>,
-            pub eq_token: Token![=],
-            pub expr: Box<Expr>,
-            pub body: Block,
-        }),
-
         /// A for loop: `for pat in expr { ... }`.
         ///
         /// *This type is available if Syn is built with the `"full"` feature.*
@@ -583,10 +562,9 @@
             | Expr::Lit(ExprLit { ref mut attrs, .. })
             | Expr::Cast(ExprCast { ref mut attrs, .. })
             | Expr::Type(ExprType { ref mut attrs, .. })
+            | Expr::Let(ExprLet { ref mut attrs, .. })
             | Expr::If(ExprIf { ref mut attrs, .. })
-            | Expr::IfLet(ExprIfLet { ref mut attrs, .. })
             | Expr::While(ExprWhile { ref mut attrs, .. })
-            | Expr::WhileLet(ExprWhileLet { ref mut attrs, .. })
             | Expr::ForLoop(ExprForLoop { ref mut attrs, .. })
             | Expr::Loop(ExprLoop { ref mut attrs, .. })
             | Expr::Match(ExprMatch { ref mut attrs, .. })
@@ -1008,10 +986,8 @@
         Expr::Unsafe(..)
         | Expr::Block(..)
         | Expr::If(..)
-        | Expr::IfLet(..)
         | Expr::Match(..)
         | Expr::While(..)
-        | Expr::WhileLet(..)
         | Expr::Loop(..)
         | Expr::ForLoop(..)
         | Expr::Async(..)
@@ -1532,18 +1508,12 @@
             expr_ret(input, allow_struct).map(Expr::Return)
         } else if input.peek(token::Bracket) {
             array_or_repeat(input)
+        } else if input.peek(Token![let]) {
+            input.call(expr_let).map(Expr::Let)
         } else if input.peek(Token![if]) {
-            if input.peek2(Token![let]) {
-                input.call(expr_if_let).map(Expr::IfLet)
-            } else {
-                input.call(expr_if).map(Expr::If)
-            }
+            input.call(expr_if).map(Expr::If)
         } else if input.peek(Token![while]) {
-            if input.peek2(Token![let]) {
-                input.call(expr_while_let).map(Expr::WhileLet)
-            } else {
-                input.call(expr_while).map(Expr::While)
-            }
+            input.call(expr_while).map(Expr::While)
         } else if input.peek(Token![for]) {
             input.call(expr_for_loop).map(Expr::ForLoop)
         } else if input.peek(Token![loop]) {
@@ -1561,11 +1531,7 @@
         } else if input.peek(Lifetime) {
             let the_label: Label = input.parse()?;
             let mut expr = if input.peek(Token![while]) {
-                if input.peek2(Token![let]) {
-                    Expr::WhileLet(input.call(expr_while_let)?)
-                } else {
-                    Expr::While(input.call(expr_while)?)
-                }
+                Expr::While(input.call(expr_while)?)
             } else if input.peek(Token![for]) {
                 Expr::ForLoop(input.call(expr_for_loop)?)
             } else if input.peek(Token![loop]) {
@@ -1576,8 +1542,7 @@
                 return Err(input.error("expected loop or block expression"));
             };
             match expr {
-                Expr::WhileLet(ExprWhileLet { ref mut label, .. })
-                | Expr::While(ExprWhile { ref mut label, .. })
+                Expr::While(ExprWhile { ref mut label, .. })
                 | Expr::ForLoop(ExprForLoop { ref mut label, .. })
                 | Expr::Loop(ExprLoop { ref mut label, .. })
                 | Expr::Block(ExprBlock { ref mut label, .. }) => *label = Some(the_label),
@@ -1741,17 +1706,9 @@
     fn expr_early(input: ParseStream) -> Result<Expr> {
         let mut attrs = input.call(Attribute::parse_outer)?;
         let mut expr = if input.peek(Token![if]) {
-            if input.peek2(Token![let]) {
-                Expr::IfLet(input.call(expr_if_let)?)
-            } else {
-                Expr::If(input.call(expr_if)?)
-            }
+            Expr::If(input.call(expr_if)?)
         } else if input.peek(Token![while]) {
-            if input.peek2(Token![let]) {
-                Expr::WhileLet(input.call(expr_while_let)?)
-            } else {
-                Expr::While(input.call(expr_while)?)
-            }
+            Expr::While(input.call(expr_while)?)
         } else if input.peek(Token![for]) {
             Expr::ForLoop(input.call(expr_for_loop)?)
         } else if input.peek(Token![loop]) {
@@ -1823,10 +1780,9 @@
     }
 
     #[cfg(feature = "full")]
-    fn expr_if_let(input: ParseStream) -> Result<ExprIfLet> {
-        Ok(ExprIfLet {
+    fn expr_let(input: ParseStream) -> Result<ExprLet> {
+        Ok(ExprLet {
             attrs: Vec::new(),
-            if_token: input.parse()?,
             let_token: input.parse()?,
             pats: {
                 let mut pats = Punctuated::new();
@@ -1842,14 +1798,6 @@
             },
             eq_token: input.parse()?,
             expr: Box::new(input.call(expr_no_struct)?),
-            then_branch: input.parse()?,
-            else_branch: {
-                if input.peek(Token![else]) {
-                    Some(input.call(else_block)?)
-                } else {
-                    None
-                }
-            },
         })
     }
 
@@ -1876,11 +1824,7 @@
 
         let lookahead = input.lookahead1();
         let else_branch = if input.peek(Token![if]) {
-            if input.peek2(Token![let]) {
-                input.call(expr_if_let).map(Expr::IfLet)?
-            } else {
-                input.call(expr_if).map(Expr::If)?
-            }
+            input.call(expr_if).map(Expr::If)?
         } else if input.peek(token::Brace) {
             Expr::Block(ExprBlock {
                 attrs: Vec::new(),
@@ -2140,45 +2084,6 @@
     }
 
     #[cfg(feature = "full")]
-    fn expr_while_let(input: ParseStream) -> Result<ExprWhileLet> {
-        let label: Option<Label> = input.parse()?;
-        let while_token: Token![while] = input.parse()?;
-        let let_token: Token![let] = input.parse()?;
-
-        let mut pats = Punctuated::new();
-        let value: Pat = input.parse()?;
-        pats.push_value(value);
-        while input.peek(Token![|]) && !input.peek(Token![||]) && !input.peek(Token![|=]) {
-            let punct = input.parse()?;
-            pats.push_punct(punct);
-            let value: Pat = input.parse()?;
-            pats.push_value(value);
-        }
-
-        let eq_token: Token![=] = input.parse()?;
-        let expr = expr_no_struct(input)?;
-
-        let content;
-        let brace_token = braced!(content in input);
-        let inner_attrs = content.call(Attribute::parse_inner)?;
-        let stmts = content.call(Block::parse_within)?;
-
-        Ok(ExprWhileLet {
-            attrs: inner_attrs,
-            label: label,
-            while_token: while_token,
-            let_token: let_token,
-            pats: pats,
-            eq_token: eq_token,
-            expr: Box::new(expr),
-            body: Block {
-                brace_token: brace_token,
-                stmts: stmts,
-            },
-        })
-    }
-
-    #[cfg(feature = "full")]
     impl Parse for Label {
         fn parse(input: ParseStream) -> Result<Self> {
             Ok(Label {
@@ -3204,7 +3109,7 @@
             // If we are not one of the valid expressions to exist in an else
             // clause, wrap ourselves in a block.
             match **else_ {
-                Expr::If(_) | Expr::IfLet(_) | Expr::Block(_) => {
+                Expr::If(_) | Expr::Block(_) => {
                     else_.to_tokens(tokens);
                 }
                 _ => {
@@ -3217,6 +3122,17 @@
     }
 
     #[cfg(feature = "full")]
+    impl ToTokens for ExprLet {
+        fn to_tokens(&self, tokens: &mut TokenStream) {
+            outer_attrs_to_tokens(&self.attrs, tokens);
+            self.let_token.to_tokens(tokens);
+            self.pats.to_tokens(tokens);
+            self.eq_token.to_tokens(tokens);
+            wrap_bare_struct(tokens, &self.expr);
+        }
+    }
+
+    #[cfg(feature = "full")]
     impl ToTokens for ExprIf {
         fn to_tokens(&self, tokens: &mut TokenStream) {
             outer_attrs_to_tokens(&self.attrs, tokens);
@@ -3228,20 +3144,6 @@
     }
 
     #[cfg(feature = "full")]
-    impl ToTokens for ExprIfLet {
-        fn to_tokens(&self, tokens: &mut TokenStream) {
-            outer_attrs_to_tokens(&self.attrs, tokens);
-            self.if_token.to_tokens(tokens);
-            self.let_token.to_tokens(tokens);
-            self.pats.to_tokens(tokens);
-            self.eq_token.to_tokens(tokens);
-            wrap_bare_struct(tokens, &self.expr);
-            self.then_branch.to_tokens(tokens);
-            maybe_wrap_else(tokens, &self.else_branch);
-        }
-    }
-
-    #[cfg(feature = "full")]
     impl ToTokens for ExprWhile {
         fn to_tokens(&self, tokens: &mut TokenStream) {
             outer_attrs_to_tokens(&self.attrs, tokens);
@@ -3256,23 +3158,6 @@
     }
 
     #[cfg(feature = "full")]
-    impl ToTokens for ExprWhileLet {
-        fn to_tokens(&self, tokens: &mut TokenStream) {
-            outer_attrs_to_tokens(&self.attrs, tokens);
-            self.label.to_tokens(tokens);
-            self.while_token.to_tokens(tokens);
-            self.let_token.to_tokens(tokens);
-            self.pats.to_tokens(tokens);
-            self.eq_token.to_tokens(tokens);
-            wrap_bare_struct(tokens, &self.expr);
-            self.body.brace_token.surround(tokens, |tokens| {
-                inner_attrs_to_tokens(&self.attrs, tokens);
-                tokens.append_all(&self.body.stmts);
-            });
-        }
-    }
-
-    #[cfg(feature = "full")]
     impl ToTokens for ExprForLoop {
         fn to_tokens(&self, tokens: &mut TokenStream) {
             outer_attrs_to_tokens(&self.attrs, tokens);
diff --git a/src/gen/fold.rs b/src/gen/fold.rs
index 31d1cf3..df96cc3 100644
--- a/src/gen/fold.rs
+++ b/src/gen/fold.rs
@@ -195,11 +195,6 @@
     }
     #[cfg(feature = "full")]
     #[cfg(any(feature = "full", feature = "derive"))]
-    fn fold_expr_if_let(&mut self, i: ExprIfLet) -> ExprIfLet {
-        fold_expr_if_let(self, i)
-    }
-    #[cfg(feature = "full")]
-    #[cfg(any(feature = "full", feature = "derive"))]
     fn fold_expr_in_place(&mut self, i: ExprInPlace) -> ExprInPlace {
         fold_expr_in_place(self, i)
     }
@@ -207,6 +202,11 @@
     fn fold_expr_index(&mut self, i: ExprIndex) -> ExprIndex {
         fold_expr_index(self, i)
     }
+    #[cfg(feature = "full")]
+    #[cfg(any(feature = "full", feature = "derive"))]
+    fn fold_expr_let(&mut self, i: ExprLet) -> ExprLet {
+        fold_expr_let(self, i)
+    }
     #[cfg(any(feature = "full", feature = "derive"))]
     fn fold_expr_lit(&mut self, i: ExprLit) -> ExprLit {
         fold_expr_lit(self, i)
@@ -304,11 +304,6 @@
     }
     #[cfg(feature = "full")]
     #[cfg(any(feature = "full", feature = "derive"))]
-    fn fold_expr_while_let(&mut self, i: ExprWhileLet) -> ExprWhileLet {
-        fold_expr_while_let(self, i)
-    }
-    #[cfg(feature = "full")]
-    #[cfg(any(feature = "full", feature = "derive"))]
     fn fold_expr_yield(&mut self, i: ExprYield) -> ExprYield {
         fold_expr_yield(self, i)
     }
@@ -1188,12 +1183,9 @@
         Expr::Lit(_binding_0) => Expr::Lit(_visitor.fold_expr_lit(_binding_0)),
         Expr::Cast(_binding_0) => Expr::Cast(_visitor.fold_expr_cast(_binding_0)),
         Expr::Type(_binding_0) => Expr::Type(full!(_visitor.fold_expr_type(_binding_0))),
+        Expr::Let(_binding_0) => Expr::Let(full!(_visitor.fold_expr_let(_binding_0))),
         Expr::If(_binding_0) => Expr::If(full!(_visitor.fold_expr_if(_binding_0))),
-        Expr::IfLet(_binding_0) => Expr::IfLet(full!(_visitor.fold_expr_if_let(_binding_0))),
         Expr::While(_binding_0) => Expr::While(full!(_visitor.fold_expr_while(_binding_0))),
-        Expr::WhileLet(_binding_0) => {
-            Expr::WhileLet(full!(_visitor.fold_expr_while_let(_binding_0)))
-        }
         Expr::ForLoop(_binding_0) => Expr::ForLoop(full!(_visitor.fold_expr_for_loop(_binding_0))),
         Expr::Loop(_binding_0) => Expr::Loop(full!(_visitor.fold_expr_loop(_binding_0))),
         Expr::Match(_binding_0) => Expr::Match(full!(_visitor.fold_expr_match(_binding_0))),
@@ -1397,25 +1389,6 @@
 }
 #[cfg(feature = "full")]
 #[cfg(any(feature = "full", feature = "derive"))]
-pub fn fold_expr_if_let<V: Fold + ?Sized>(_visitor: &mut V, _i: ExprIfLet) -> ExprIfLet {
-    ExprIfLet {
-        attrs: FoldHelper::lift(_i.attrs, |it| _visitor.fold_attribute(it)),
-        if_token: Token ! [ if ](tokens_helper(_visitor, &_i.if_token.span)),
-        let_token: Token ! [ let ](tokens_helper(_visitor, &_i.let_token.span)),
-        pats: FoldHelper::lift(_i.pats, |it| _visitor.fold_pat(it)),
-        eq_token: Token ! [ = ](tokens_helper(_visitor, &_i.eq_token.spans)),
-        expr: Box::new(_visitor.fold_expr(*_i.expr)),
-        then_branch: _visitor.fold_block(_i.then_branch),
-        else_branch: (_i.else_branch).map(|it| {
-            (
-                Token ! [ else ](tokens_helper(_visitor, &(it).0.span)),
-                Box::new(_visitor.fold_expr(*(it).1)),
-            )
-        }),
-    }
-}
-#[cfg(feature = "full")]
-#[cfg(any(feature = "full", feature = "derive"))]
 pub fn fold_expr_in_place<V: Fold + ?Sized>(_visitor: &mut V, _i: ExprInPlace) -> ExprInPlace {
     ExprInPlace {
         attrs: FoldHelper::lift(_i.attrs, |it| _visitor.fold_attribute(it)),
@@ -1433,6 +1406,17 @@
         index: Box::new(_visitor.fold_expr(*_i.index)),
     }
 }
+#[cfg(feature = "full")]
+#[cfg(any(feature = "full", feature = "derive"))]
+pub fn fold_expr_let<V: Fold + ?Sized>(_visitor: &mut V, _i: ExprLet) -> ExprLet {
+    ExprLet {
+        attrs: FoldHelper::lift(_i.attrs, |it| _visitor.fold_attribute(it)),
+        let_token: Token ! [ let ](tokens_helper(_visitor, &_i.let_token.span)),
+        pats: FoldHelper::lift(_i.pats, |it| _visitor.fold_pat(it)),
+        eq_token: Token ! [ = ](tokens_helper(_visitor, &_i.eq_token.spans)),
+        expr: Box::new(_visitor.fold_expr(*_i.expr)),
+    }
+}
 #[cfg(any(feature = "full", feature = "derive"))]
 pub fn fold_expr_lit<V: Fold + ?Sized>(_visitor: &mut V, _i: ExprLit) -> ExprLit {
     ExprLit {
@@ -1624,20 +1608,6 @@
 }
 #[cfg(feature = "full")]
 #[cfg(any(feature = "full", feature = "derive"))]
-pub fn fold_expr_while_let<V: Fold + ?Sized>(_visitor: &mut V, _i: ExprWhileLet) -> ExprWhileLet {
-    ExprWhileLet {
-        attrs: FoldHelper::lift(_i.attrs, |it| _visitor.fold_attribute(it)),
-        label: (_i.label).map(|it| _visitor.fold_label(it)),
-        while_token: Token ! [ while ](tokens_helper(_visitor, &_i.while_token.span)),
-        let_token: Token ! [ let ](tokens_helper(_visitor, &_i.let_token.span)),
-        pats: FoldHelper::lift(_i.pats, |it| _visitor.fold_pat(it)),
-        eq_token: Token ! [ = ](tokens_helper(_visitor, &_i.eq_token.spans)),
-        expr: Box::new(_visitor.fold_expr(*_i.expr)),
-        body: _visitor.fold_block(_i.body),
-    }
-}
-#[cfg(feature = "full")]
-#[cfg(any(feature = "full", feature = "derive"))]
 pub fn fold_expr_yield<V: Fold + ?Sized>(_visitor: &mut V, _i: ExprYield) -> ExprYield {
     ExprYield {
         attrs: FoldHelper::lift(_i.attrs, |it| _visitor.fold_attribute(it)),
diff --git a/src/gen/visit.rs b/src/gen/visit.rs
index 7ef88fd..90b2607 100644
--- a/src/gen/visit.rs
+++ b/src/gen/visit.rs
@@ -195,11 +195,6 @@
     }
     #[cfg(feature = "full")]
     #[cfg(any(feature = "full", feature = "derive"))]
-    fn visit_expr_if_let(&mut self, i: &'ast ExprIfLet) {
-        visit_expr_if_let(self, i)
-    }
-    #[cfg(feature = "full")]
-    #[cfg(any(feature = "full", feature = "derive"))]
     fn visit_expr_in_place(&mut self, i: &'ast ExprInPlace) {
         visit_expr_in_place(self, i)
     }
@@ -207,6 +202,11 @@
     fn visit_expr_index(&mut self, i: &'ast ExprIndex) {
         visit_expr_index(self, i)
     }
+    #[cfg(feature = "full")]
+    #[cfg(any(feature = "full", feature = "derive"))]
+    fn visit_expr_let(&mut self, i: &'ast ExprLet) {
+        visit_expr_let(self, i)
+    }
     #[cfg(any(feature = "full", feature = "derive"))]
     fn visit_expr_lit(&mut self, i: &'ast ExprLit) {
         visit_expr_lit(self, i)
@@ -304,11 +304,6 @@
     }
     #[cfg(feature = "full")]
     #[cfg(any(feature = "full", feature = "derive"))]
-    fn visit_expr_while_let(&mut self, i: &'ast ExprWhileLet) {
-        visit_expr_while_let(self, i)
-    }
-    #[cfg(feature = "full")]
-    #[cfg(any(feature = "full", feature = "derive"))]
     fn visit_expr_yield(&mut self, i: &'ast ExprYield) {
         visit_expr_yield(self, i)
     }
@@ -1194,18 +1189,15 @@
         Expr::Type(ref _binding_0) => {
             full!(_visitor.visit_expr_type(_binding_0));
         }
+        Expr::Let(ref _binding_0) => {
+            full!(_visitor.visit_expr_let(_binding_0));
+        }
         Expr::If(ref _binding_0) => {
             full!(_visitor.visit_expr_if(_binding_0));
         }
-        Expr::IfLet(ref _binding_0) => {
-            full!(_visitor.visit_expr_if_let(_binding_0));
-        }
         Expr::While(ref _binding_0) => {
             full!(_visitor.visit_expr_while(_binding_0));
         }
-        Expr::WhileLet(ref _binding_0) => {
-            full!(_visitor.visit_expr_while_let(_binding_0));
-        }
         Expr::ForLoop(ref _binding_0) => {
             full!(_visitor.visit_expr_for_loop(_binding_0));
         }
@@ -1484,26 +1476,6 @@
 }
 #[cfg(feature = "full")]
 #[cfg(any(feature = "full", feature = "derive"))]
-pub fn visit_expr_if_let<'ast, V: Visit<'ast> + ?Sized>(_visitor: &mut V, _i: &'ast ExprIfLet) {
-    for it in &_i.attrs {
-        _visitor.visit_attribute(it)
-    }
-    tokens_helper(_visitor, &_i.if_token.span);
-    tokens_helper(_visitor, &_i.let_token.span);
-    for el in Punctuated::pairs(&_i.pats) {
-        let it = el.value();
-        _visitor.visit_pat(it)
-    }
-    tokens_helper(_visitor, &_i.eq_token.spans);
-    _visitor.visit_expr(&*_i.expr);
-    _visitor.visit_block(&_i.then_branch);
-    if let Some(ref it) = _i.else_branch {
-        tokens_helper(_visitor, &(it).0.span);
-        _visitor.visit_expr(&*(it).1);
-    };
-}
-#[cfg(feature = "full")]
-#[cfg(any(feature = "full", feature = "derive"))]
 pub fn visit_expr_in_place<'ast, V: Visit<'ast> + ?Sized>(_visitor: &mut V, _i: &'ast ExprInPlace) {
     for it in &_i.attrs {
         _visitor.visit_attribute(it)
@@ -1521,6 +1493,20 @@
     tokens_helper(_visitor, &_i.bracket_token.span);
     _visitor.visit_expr(&*_i.index);
 }
+#[cfg(feature = "full")]
+#[cfg(any(feature = "full", feature = "derive"))]
+pub fn visit_expr_let<'ast, V: Visit<'ast> + ?Sized>(_visitor: &mut V, _i: &'ast ExprLet) {
+    for it in &_i.attrs {
+        _visitor.visit_attribute(it)
+    }
+    tokens_helper(_visitor, &_i.let_token.span);
+    for el in Punctuated::pairs(&_i.pats) {
+        let it = el.value();
+        _visitor.visit_pat(it)
+    }
+    tokens_helper(_visitor, &_i.eq_token.spans);
+    _visitor.visit_expr(&*_i.expr);
+}
 #[cfg(any(feature = "full", feature = "derive"))]
 pub fn visit_expr_lit<'ast, V: Visit<'ast> + ?Sized>(_visitor: &mut V, _i: &'ast ExprLit) {
     for it in &_i.attrs {
@@ -1752,28 +1738,6 @@
 }
 #[cfg(feature = "full")]
 #[cfg(any(feature = "full", feature = "derive"))]
-pub fn visit_expr_while_let<'ast, V: Visit<'ast> + ?Sized>(
-    _visitor: &mut V,
-    _i: &'ast ExprWhileLet,
-) {
-    for it in &_i.attrs {
-        _visitor.visit_attribute(it)
-    }
-    if let Some(ref it) = _i.label {
-        _visitor.visit_label(it)
-    };
-    tokens_helper(_visitor, &_i.while_token.span);
-    tokens_helper(_visitor, &_i.let_token.span);
-    for el in Punctuated::pairs(&_i.pats) {
-        let it = el.value();
-        _visitor.visit_pat(it)
-    }
-    tokens_helper(_visitor, &_i.eq_token.spans);
-    _visitor.visit_expr(&*_i.expr);
-    _visitor.visit_block(&_i.body);
-}
-#[cfg(feature = "full")]
-#[cfg(any(feature = "full", feature = "derive"))]
 pub fn visit_expr_yield<'ast, V: Visit<'ast> + ?Sized>(_visitor: &mut V, _i: &'ast ExprYield) {
     for it in &_i.attrs {
         _visitor.visit_attribute(it)
diff --git a/src/gen/visit_mut.rs b/src/gen/visit_mut.rs
index 0795daf..9380c7e 100644
--- a/src/gen/visit_mut.rs
+++ b/src/gen/visit_mut.rs
@@ -199,11 +199,6 @@
     }
     #[cfg(feature = "full")]
     #[cfg(any(feature = "full", feature = "derive"))]
-    fn visit_expr_if_let_mut(&mut self, i: &mut ExprIfLet) {
-        visit_expr_if_let_mut(self, i)
-    }
-    #[cfg(feature = "full")]
-    #[cfg(any(feature = "full", feature = "derive"))]
     fn visit_expr_in_place_mut(&mut self, i: &mut ExprInPlace) {
         visit_expr_in_place_mut(self, i)
     }
@@ -211,6 +206,11 @@
     fn visit_expr_index_mut(&mut self, i: &mut ExprIndex) {
         visit_expr_index_mut(self, i)
     }
+    #[cfg(feature = "full")]
+    #[cfg(any(feature = "full", feature = "derive"))]
+    fn visit_expr_let_mut(&mut self, i: &mut ExprLet) {
+        visit_expr_let_mut(self, i)
+    }
     #[cfg(any(feature = "full", feature = "derive"))]
     fn visit_expr_lit_mut(&mut self, i: &mut ExprLit) {
         visit_expr_lit_mut(self, i)
@@ -308,11 +308,6 @@
     }
     #[cfg(feature = "full")]
     #[cfg(any(feature = "full", feature = "derive"))]
-    fn visit_expr_while_let_mut(&mut self, i: &mut ExprWhileLet) {
-        visit_expr_while_let_mut(self, i)
-    }
-    #[cfg(feature = "full")]
-    #[cfg(any(feature = "full", feature = "derive"))]
     fn visit_expr_yield_mut(&mut self, i: &mut ExprYield) {
         visit_expr_yield_mut(self, i)
     }
@@ -1192,18 +1187,15 @@
         Expr::Type(ref mut _binding_0) => {
             full!(_visitor.visit_expr_type_mut(_binding_0));
         }
+        Expr::Let(ref mut _binding_0) => {
+            full!(_visitor.visit_expr_let_mut(_binding_0));
+        }
         Expr::If(ref mut _binding_0) => {
             full!(_visitor.visit_expr_if_mut(_binding_0));
         }
-        Expr::IfLet(ref mut _binding_0) => {
-            full!(_visitor.visit_expr_if_let_mut(_binding_0));
-        }
         Expr::While(ref mut _binding_0) => {
             full!(_visitor.visit_expr_while_mut(_binding_0));
         }
-        Expr::WhileLet(ref mut _binding_0) => {
-            full!(_visitor.visit_expr_while_let_mut(_binding_0));
-        }
         Expr::ForLoop(ref mut _binding_0) => {
             full!(_visitor.visit_expr_for_loop_mut(_binding_0));
         }
@@ -1476,26 +1468,6 @@
 }
 #[cfg(feature = "full")]
 #[cfg(any(feature = "full", feature = "derive"))]
-pub fn visit_expr_if_let_mut<V: VisitMut + ?Sized>(_visitor: &mut V, _i: &mut ExprIfLet) {
-    for it in &mut _i.attrs {
-        _visitor.visit_attribute_mut(it)
-    }
-    tokens_helper(_visitor, &mut _i.if_token.span);
-    tokens_helper(_visitor, &mut _i.let_token.span);
-    for mut el in Punctuated::pairs_mut(&mut _i.pats) {
-        let it = el.value_mut();
-        _visitor.visit_pat_mut(it)
-    }
-    tokens_helper(_visitor, &mut _i.eq_token.spans);
-    _visitor.visit_expr_mut(&mut *_i.expr);
-    _visitor.visit_block_mut(&mut _i.then_branch);
-    if let Some(ref mut it) = _i.else_branch {
-        tokens_helper(_visitor, &mut (it).0.span);
-        _visitor.visit_expr_mut(&mut *(it).1);
-    };
-}
-#[cfg(feature = "full")]
-#[cfg(any(feature = "full", feature = "derive"))]
 pub fn visit_expr_in_place_mut<V: VisitMut + ?Sized>(_visitor: &mut V, _i: &mut ExprInPlace) {
     for it in &mut _i.attrs {
         _visitor.visit_attribute_mut(it)
@@ -1513,6 +1485,20 @@
     tokens_helper(_visitor, &mut _i.bracket_token.span);
     _visitor.visit_expr_mut(&mut *_i.index);
 }
+#[cfg(feature = "full")]
+#[cfg(any(feature = "full", feature = "derive"))]
+pub fn visit_expr_let_mut<V: VisitMut + ?Sized>(_visitor: &mut V, _i: &mut ExprLet) {
+    for it in &mut _i.attrs {
+        _visitor.visit_attribute_mut(it)
+    }
+    tokens_helper(_visitor, &mut _i.let_token.span);
+    for mut el in Punctuated::pairs_mut(&mut _i.pats) {
+        let it = el.value_mut();
+        _visitor.visit_pat_mut(it)
+    }
+    tokens_helper(_visitor, &mut _i.eq_token.spans);
+    _visitor.visit_expr_mut(&mut *_i.expr);
+}
 #[cfg(any(feature = "full", feature = "derive"))]
 pub fn visit_expr_lit_mut<V: VisitMut + ?Sized>(_visitor: &mut V, _i: &mut ExprLit) {
     for it in &mut _i.attrs {
@@ -1732,25 +1718,6 @@
 }
 #[cfg(feature = "full")]
 #[cfg(any(feature = "full", feature = "derive"))]
-pub fn visit_expr_while_let_mut<V: VisitMut + ?Sized>(_visitor: &mut V, _i: &mut ExprWhileLet) {
-    for it in &mut _i.attrs {
-        _visitor.visit_attribute_mut(it)
-    }
-    if let Some(ref mut it) = _i.label {
-        _visitor.visit_label_mut(it)
-    };
-    tokens_helper(_visitor, &mut _i.while_token.span);
-    tokens_helper(_visitor, &mut _i.let_token.span);
-    for mut el in Punctuated::pairs_mut(&mut _i.pats) {
-        let it = el.value_mut();
-        _visitor.visit_pat_mut(it)
-    }
-    tokens_helper(_visitor, &mut _i.eq_token.spans);
-    _visitor.visit_expr_mut(&mut *_i.expr);
-    _visitor.visit_block_mut(&mut _i.body);
-}
-#[cfg(feature = "full")]
-#[cfg(any(feature = "full", feature = "derive"))]
 pub fn visit_expr_yield_mut<V: VisitMut + ?Sized>(_visitor: &mut V, _i: &mut ExprYield) {
     for it in &mut _i.attrs {
         _visitor.visit_attribute_mut(it)
diff --git a/src/lib.rs b/src/lib.rs
index d0a972e..2f05a3a 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -342,10 +342,10 @@
 pub use expr::{
     Expr, ExprArray, ExprAssign, ExprAssignOp, ExprAsync, ExprBinary, ExprBlock, ExprBox,
     ExprBreak, ExprCall, ExprCast, ExprClosure, ExprContinue, ExprField, ExprForLoop, ExprGroup,
-    ExprIf, ExprIfLet, ExprInPlace, ExprIndex, ExprLit, ExprLoop, ExprMacro, ExprMatch,
+    ExprIf, ExprInPlace, ExprIndex, ExprLet, ExprLit, ExprLoop, ExprMacro, ExprMatch,
     ExprMethodCall, ExprParen, ExprPath, ExprRange, ExprReference, ExprRepeat, ExprReturn,
     ExprStruct, ExprTry, ExprTryBlock, ExprTuple, ExprType, ExprUnary, ExprUnsafe, ExprVerbatim,
-    ExprWhile, ExprWhileLet, ExprYield, Index, Member,
+    ExprWhile, ExprYield, Index, Member,
 };
 
 #[cfg(feature = "full")]
diff --git a/tests/test_precedence.rs b/tests/test_precedence.rs
index 4d10090..90c48e8 100644
--- a/tests/test_precedence.rs
+++ b/tests/test_precedence.rs
@@ -303,7 +303,7 @@
         fn fold_expr(&mut self, expr: Expr) -> Expr {
             match expr {
                 Expr::Group(_) => unreachable!(),
-                Expr::If(..) | Expr::Unsafe(..) | Expr::Block(..) | Expr::IfLet(..) => {
+                Expr::If(..) | Expr::Unsafe(..) | Expr::Block(..) | Expr::Let(..) => {
                     fold_expr(self, expr)
                 }
                 node => Expr::Paren(ExprParen {