diff --git a/clippy_lints/src/equatable_if_let.rs b/clippy_lints/src/equatable_if_let.rs
index 8905cc0de45..06d128f5527 100644
--- a/clippy_lints/src/equatable_if_let.rs
+++ b/clippy_lints/src/equatable_if_let.rs
@@ -67,20 +67,20 @@ fn is_structural_partial_eq(cx: &LateContext<'tcx>, ty: Ty<'tcx>, other: Ty<'tcx
 impl<'tcx> LateLintPass<'tcx> for PatternEquality {
     fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) {
         if_chain! {
-            if let ExprKind::Let(pat, exp, _) = expr.kind;
-            if unary_pattern(pat);
-            let exp_ty = cx.typeck_results().expr_ty(exp);
-            let pat_ty = cx.typeck_results().pat_ty(pat);
+            if let ExprKind::Let(let_expr) = expr.kind;
+            if unary_pattern(let_expr.pat);
+            let exp_ty = cx.typeck_results().expr_ty(let_expr.init);
+            let pat_ty = cx.typeck_results().pat_ty(let_expr.pat);
             if is_structural_partial_eq(cx, exp_ty, pat_ty);
             then {
 
                 let mut applicability = Applicability::MachineApplicable;
-                let pat_str = match pat.kind {
+                let pat_str = match let_expr.pat.kind {
                     PatKind::Struct(..) => format!(
                         "({})",
-                        snippet_with_context(cx, pat.span, expr.span.ctxt(), "..", &mut applicability).0,
+                        snippet_with_context(cx, let_expr.pat.span, expr.span.ctxt(), "..", &mut applicability).0,
                     ),
-                    _ => snippet_with_context(cx, pat.span, expr.span.ctxt(), "..", &mut applicability).0.to_string(),
+                    _ => snippet_with_context(cx, let_expr.pat.span, expr.span.ctxt(), "..", &mut applicability).0.to_string(),
                 };
                 span_lint_and_sugg(
                     cx,
@@ -90,7 +90,7 @@ impl<'tcx> LateLintPass<'tcx> for PatternEquality {
                     "try",
                     format!(
                         "{} == {}",
-                        snippet_with_context(cx, exp.span, expr.span.ctxt(), "..", &mut applicability).0,
+                        snippet_with_context(cx, let_expr.init.span, expr.span.ctxt(), "..", &mut applicability).0,
                         pat_str,
                     ),
                     applicability,
diff --git a/clippy_lints/src/loops/never_loop.rs b/clippy_lints/src/loops/never_loop.rs
index 68ffcd1abfb..a3aa6be6afd 100644
--- a/clippy_lints/src/loops/never_loop.rs
+++ b/clippy_lints/src/loops/never_loop.rs
@@ -115,12 +115,12 @@ fn never_loop_expr(expr: &Expr<'_>, main_loop_id: HirId) -> NeverLoopResult {
         | ExprKind::Unary(_, e)
         | ExprKind::Cast(e, _)
         | ExprKind::Type(e, _)
-        | ExprKind::Let(_, e, _)
         | ExprKind::Field(e, _)
         | ExprKind::AddrOf(_, _, e)
         | ExprKind::Struct(_, _, Some(e))
         | ExprKind::Repeat(e, _)
         | ExprKind::DropTemps(e) => never_loop_expr(e, main_loop_id),
+        ExprKind::Let(let_expr) => never_loop_expr(let_expr.init, main_loop_id),
         ExprKind::Array(es) | ExprKind::MethodCall(_, _, es, _) | ExprKind::Tup(es) => {
             never_loop_expr_all(&mut es.iter(), main_loop_id)
         },
diff --git a/clippy_lints/src/manual_assert.rs b/clippy_lints/src/manual_assert.rs
index ed3166086f7..5a2a965716c 100644
--- a/clippy_lints/src/manual_assert.rs
+++ b/clippy_lints/src/manual_assert.rs
@@ -50,7 +50,7 @@ impl LateLintPass<'_> for ManualAssert {
                 ..
             } = &expr;
             if is_expn_of(stmt.span, "panic").is_some();
-            if !matches!(cond.kind, ExprKind::Let(_, _, _));
+            if !matches!(cond.kind, ExprKind::Let(_));
             if let StmtKind::Semi(semi) = stmt.kind;
             if !cx.tcx.sess.source_map().is_multiline(cond.span);
 
diff --git a/clippy_lints/src/pattern_type_mismatch.rs b/clippy_lints/src/pattern_type_mismatch.rs
index c7d77d30927..be319ee110d 100644
--- a/clippy_lints/src/pattern_type_mismatch.rs
+++ b/clippy_lints/src/pattern_type_mismatch.rs
@@ -1,6 +1,6 @@
 use clippy_utils::diagnostics::span_lint_and_help;
 use rustc_hir::{
-    intravisit, Body, Expr, ExprKind, FnDecl, HirId, LocalSource, Mutability, Pat, PatKind, Stmt, StmtKind,
+    intravisit, Body, Expr, ExprKind, FnDecl, HirId, Let, LocalSource, Mutability, Pat, PatKind, Stmt, StmtKind,
 };
 use rustc_lint::{LateContext, LateLintPass, LintContext};
 use rustc_middle::lint::in_external_macro;
@@ -104,8 +104,8 @@ impl<'tcx> LateLintPass<'tcx> for PatternTypeMismatch {
                 }
             }
         }
-        if let ExprKind::Let(let_pat, ..) = expr.kind {
-            apply_lint(cx, let_pat, DerefPossible::Possible);
+        if let ExprKind::Let(Let { pat, .. }) = expr.kind {
+            apply_lint(cx, pat, DerefPossible::Possible);
         }
     }
 
diff --git a/clippy_lints/src/utils/author.rs b/clippy_lints/src/utils/author.rs
index f186e1f05a0..c1b811c2174 100644
--- a/clippy_lints/src/utils/author.rs
+++ b/clippy_lints/src/utils/author.rs
@@ -373,11 +373,18 @@ impl<'a, 'tcx> PrintVisitor<'a, 'tcx> {
         }
 
         match expr.value.kind {
-            ExprKind::Let(pat, expr, _) => {
-                bind!(self, pat, expr);
-                kind!("Let({pat}, {expr}, _)");
-                self.pat(pat);
-                self.expr(expr);
+            ExprKind::Let(let_expr) => {
+                bind!(self, let_expr);
+                kind!("Let({let_expr})");
+                self.pat(field!(let_expr.pat));
+                // Does what ExprKind::Cast does, only adds a clause for the type
+                // if it's a path
+                if let Some(TyKind::Path(ref qpath)) = let_expr.value.ty.as_ref().map(|ty| &ty.kind) {
+                    bind!(self, qpath);
+                    out!("if let TyKind::Path(ref {qpath}) = {let_expr}.ty.kind;");
+                    self.qpath(qpath);
+                }
+                self.expr(field!(let_expr.init));
             },
             ExprKind::Box(inner) => {
                 bind!(self, inner);
diff --git a/clippy_lints/src/utils/inspector.rs b/clippy_lints/src/utils/inspector.rs
index 43590cc7862..abf4826a069 100644
--- a/clippy_lints/src/utils/inspector.rs
+++ b/clippy_lints/src/utils/inspector.rs
@@ -142,9 +142,12 @@ fn print_expr(cx: &LateContext<'_>, expr: &hir::Expr<'_>, indent: usize) {
                 print_expr(cx, arg, indent + 1);
             }
         },
-        hir::ExprKind::Let(pat, expr, _) => {
+        hir::ExprKind::Let(hir::Let { pat, init, ty, .. }) => {
             print_pat(cx, pat, indent + 1);
-            print_expr(cx, expr, indent + 1);
+            if let Some(ty) = ty {
+                println!("{}  type annotation: {:?}", ind, ty);
+            }
+            print_expr(cx, init, indent + 1);
         },
         hir::ExprKind::MethodCall(path, _, args, _) => {
             println!("{}MethodCall", ind);
diff --git a/clippy_utils/src/higher.rs b/clippy_utils/src/higher.rs
index fc32e49420e..c764c35d444 100644
--- a/clippy_utils/src/higher.rs
+++ b/clippy_utils/src/higher.rs
@@ -101,7 +101,12 @@ impl<'hir> IfLet<'hir> {
     pub fn hir(cx: &LateContext<'_>, expr: &Expr<'hir>) -> Option<Self> {
         if let ExprKind::If(
             Expr {
-                kind: ExprKind::Let(let_pat, let_expr, _),
+                kind:
+                    ExprKind::Let(hir::Let {
+                        pat: let_pat,
+                        init: let_expr,
+                        ..
+                    }),
                 ..
             },
             if_then,
@@ -368,7 +373,12 @@ impl<'hir> WhileLet<'hir> {
                         kind:
                             ExprKind::If(
                                 Expr {
-                                    kind: ExprKind::Let(let_pat, let_expr, _),
+                                    kind:
+                                        ExprKind::Let(hir::Let {
+                                            pat: let_pat,
+                                            init: let_expr,
+                                            ..
+                                        }),
                                     ..
                                 },
                                 if_then,
diff --git a/clippy_utils/src/hir_utils.rs b/clippy_utils/src/hir_utils.rs
index b8e53e47ed9..ad50759effa 100644
--- a/clippy_utils/src/hir_utils.rs
+++ b/clippy_utils/src/hir_utils.rs
@@ -7,7 +7,7 @@ use rustc_hir::def::Res;
 use rustc_hir::HirIdMap;
 use rustc_hir::{
     BinOpKind, Block, BodyId, Expr, ExprField, ExprKind, FnRetTy, GenericArg, GenericArgs, Guard, HirId,
-    InlineAsmOperand, Lifetime, LifetimeName, ParamName, Pat, PatField, PatKind, Path, PathSegment, QPath, Stmt,
+    InlineAsmOperand, Let, Lifetime, LifetimeName, ParamName, Pat, PatField, PatKind, Path, PathSegment, QPath, Stmt,
     StmtKind, Ty, TyKind, TypeBinding,
 };
 use rustc_lexer::{tokenize, TokenKind};
@@ -234,7 +234,9 @@ impl HirEqInterExpr<'_, '_, '_> {
             (&ExprKind::If(lc, lt, ref le), &ExprKind::If(rc, rt, ref re)) => {
                 self.eq_expr(lc, rc) && self.eq_expr(&**lt, &**rt) && both(le, re, |l, r| self.eq_expr(l, r))
             },
-            (&ExprKind::Let(lp, le, _), &ExprKind::Let(rp, re, _)) => self.eq_pat(lp, rp) && self.eq_expr(le, re),
+            (&ExprKind::Let(l), &ExprKind::Let(r)) => {
+                self.eq_pat(l.pat, r.pat) && both(&l.ty, &r.ty, |l, r| self.eq_ty(l, r)) && self.eq_expr(l.init, r.init)
+            },
             (&ExprKind::Lit(ref l), &ExprKind::Lit(ref r)) => l.node == r.node,
             (&ExprKind::Loop(lb, ref ll, ref lls, _), &ExprKind::Loop(rb, ref rl, ref rls, _)) => {
                 lls == rls && self.eq_block(lb, rb) && both(ll, rl, |l, r| l.ident.name == r.ident.name)
@@ -668,8 +670,11 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> {
                     }
                 }
             },
-            ExprKind::Let(pat, expr, _) => {
-                self.hash_expr(expr);
+            ExprKind::Let(Let { pat, init, ty, .. }) => {
+                self.hash_expr(init);
+                if let Some(ty) = ty {
+                    self.hash_ty(ty);
+                }
                 self.hash_pat(pat);
             },
             ExprKind::LlvmInlineAsm(..) | ExprKind::Err => {},
diff --git a/clippy_utils/src/lib.rs b/clippy_utils/src/lib.rs
index d384c5a069e..7e054a54c3c 100644
--- a/clippy_utils/src/lib.rs
+++ b/clippy_utils/src/lib.rs
@@ -870,8 +870,8 @@ pub fn capture_local_usage(cx: &LateContext<'tcx>, e: &Expr<'_>) -> CaptureKind
                         capture_expr_ty = e;
                     }
                 },
-                ExprKind::Let(pat, ..) => {
-                    let mutability = match pat_capture_kind(cx, pat) {
+                ExprKind::Let(let_expr) => {
+                    let mutability = match pat_capture_kind(cx, let_expr.pat) {
                         CaptureKind::Value => Mutability::Not,
                         CaptureKind::Ref(m) => m,
                     };
diff --git a/tests/ui/author/if.stdout b/tests/ui/author/if.stdout
index 75ff3faf29a..8d92849b366 100644
--- a/tests/ui/author/if.stdout
+++ b/tests/ui/author/if.stdout
@@ -32,11 +32,11 @@ if_chain! {
 }
 if_chain! {
     if let ExprKind::If(cond, then, Some(else_expr)) = expr.kind;
-    if let ExprKind::Let(pat, expr1, _) = cond.kind;
-    if let PatKind::Lit(lit_expr) = pat.kind;
+    if let ExprKind::Let(let_expr) = cond.kind;
+    if let PatKind::Lit(lit_expr) = let_expr.pat.kind;
     if let ExprKind::Lit(ref lit) = lit_expr.kind;
     if let LitKind::Bool(true) = lit.node;
-    if let ExprKind::Path(ref qpath) = expr1.kind;
+    if let ExprKind::Path(ref qpath) = let_expr.init.kind;
     if match_qpath(qpath, &["a"]);
     if let ExprKind::Block(block, None) = then.kind;
     if block.stmts.is_empty();