diff --git a/crates/completion/src/completions/pattern.rs b/crates/completion/src/completions/pattern.rs
index 7ab7f09febc..4f63ff0ef67 100644
--- a/crates/completion/src/completions/pattern.rs
+++ b/crates/completion/src/completions/pattern.rs
@@ -4,7 +4,7 @@ use crate::{CompletionContext, Completions};
 
 /// Completes constats and paths in patterns.
 pub(crate) fn complete_pattern(acc: &mut Completions, ctx: &CompletionContext) {
-    if !ctx.is_pat_binding_or_const {
+    if !(ctx.is_pat_binding_or_const || ctx.is_irrefutable_let_pat_binding) {
         return;
     }
     if ctx.record_pat_syntax.is_some() {
@@ -14,20 +14,27 @@ pub(crate) fn complete_pattern(acc: &mut Completions, ctx: &CompletionContext) {
     // FIXME: ideally, we should look at the type we are matching against and
     // suggest variants + auto-imports
     ctx.scope.process_all_names(&mut |name, res| {
-        match &res {
-            hir::ScopeDef::ModuleDef(def) => match def {
-                hir::ModuleDef::Adt(hir::Adt::Enum(..))
-                | hir::ModuleDef::Adt(hir::Adt::Struct(..))
-                | hir::ModuleDef::EnumVariant(..)
-                | hir::ModuleDef::Const(..)
-                | hir::ModuleDef::Module(..) => (),
-                _ => return,
-            },
-            hir::ScopeDef::MacroDef(_) => (),
-            _ => return,
+        let add_resolution = match &res {
+            hir::ScopeDef::ModuleDef(def) => {
+                if ctx.is_irrefutable_let_pat_binding {
+                    matches!(def, hir::ModuleDef::Adt(hir::Adt::Struct(_)))
+                } else {
+                    matches!(
+                        def,
+                        hir::ModuleDef::Adt(hir::Adt::Enum(..))
+                            | hir::ModuleDef::Adt(hir::Adt::Struct(..))
+                            | hir::ModuleDef::EnumVariant(..)
+                            | hir::ModuleDef::Const(..)
+                            | hir::ModuleDef::Module(..)
+                    )
+                }
+            }
+            hir::ScopeDef::MacroDef(_) => true,
+            _ => false,
         };
-
-        acc.add_resolution(ctx, name.to_string(), &res)
+        if add_resolution {
+            acc.add_resolution(ctx, name.to_string(), &res);
+        }
     });
 }
 
@@ -85,4 +92,26 @@ fn foo() {
             "#]],
         );
     }
+
+    #[test]
+    fn completes_in_irrefutable_let() {
+        check(
+            r#"
+enum E { X }
+use self::E::X;
+const Z: E = E::X;
+mod m {}
+
+static FOO: E = E::X;
+struct Bar { f: u32 }
+
+fn foo() {
+   let <|>
+}
+"#,
+            expect![[r#"
+                st Bar
+            "#]],
+        );
+    }
 }
diff --git a/crates/completion/src/context.rs b/crates/completion/src/context.rs
index bf70ee478e3..5cd11cf775c 100644
--- a/crates/completion/src/context.rs
+++ b/crates/completion/src/context.rs
@@ -51,6 +51,7 @@ pub(crate) struct CompletionContext<'a> {
     /// If a name-binding or reference to a const in a pattern.
     /// Irrefutable patterns (like let) are excluded.
     pub(super) is_pat_binding_or_const: bool,
+    pub(super) is_irrefutable_let_pat_binding: bool,
     /// A single-indent path, like `foo`. `::foo` should not be considered a trivial path.
     pub(super) is_trivial_path: bool,
     /// If not a trivial path, the prefix (qualifier).
@@ -146,6 +147,7 @@ impl<'a> CompletionContext<'a> {
             active_parameter: ActiveParameter::at(db, position),
             is_param: false,
             is_pat_binding_or_const: false,
+            is_irrefutable_let_pat_binding: false,
             is_trivial_path: false,
             path_qual: None,
             after_if: false,
@@ -330,6 +332,7 @@ impl<'a> CompletionContext<'a> {
                         if pat.syntax().text_range().contains_range(bind_pat.syntax().text_range())
                         {
                             self.is_pat_binding_or_const = false;
+                            self.is_irrefutable_let_pat_binding = true;
                         }
                     }
                 }