Repository: rust-lang/rust-analyzer
Pull request #12628 (2022-06-23 18:09:39)

internal: Simplify


Patch:
diff --git a/crates/hir-def/src/generics.rs b/crates/hir-def/src/generics.rs
index f54f084ec3..0b2e78bdcf 100644
--- a/crates/hir-def/src/generics.rs
+++ b/crates/hir-def/src/generics.rs
@@ -146,6 +146,15 @@ impl GenericParams {
     ) -> Interned<GenericParams> {
         let _p = profile::span("generic_params_query");
 
+        macro_rules! id_to_generics {
+            ($id:ident) => {{
+                let id = $id.lookup(db).id;
+                let tree = id.item_tree(db);
+                let item = &tree[id.value];
+                item.generic_params.clone()
+            }};
+        }
+
         match def {
             GenericDefId::FunctionId(id) => {
                 let loc = id.lookup(db);
@@ -166,42 +175,12 @@ impl GenericParams {
 
                 Interned::new(generic_params)
             }
-            GenericDefId::AdtId(AdtId::StructId(id)) => {
-                let id = id.lookup(db).id;
-                let tree = id.item_tree(db);
-                let item = &tree[id.value];
-                item.generic_params.clone()
-            }
-            GenericDefId::AdtId(AdtId::EnumId(id)) => {
-                let id = id.lookup(db).id;
-                let tree = id.item_tree(db);
-                let item = &tree[id.value];
-                item.generic_params.clone()
-            }
-            GenericDefId::AdtId(AdtId::UnionId(id)) => {
-                let id = id.lookup(db).id;
-                let tree = id.item_tree(db);
-                let item = &tree[id.value];
-                item.generic_params.clone()
-            }
-            GenericDefId::TraitId(id) => {
-                let id = id.lookup(db).id;
-                let tree = id.item_tree(db);
-                let item = &tree[id.value];
-                item.generic_params.clone()
-            }
-            GenericDefId::TypeAliasId(id) => {
-                let id = id.lookup(db).id;
-                let tree = id.item_tree(db);
-                let item = &tree[id.value];
-                item.generic_params.clone()
-            }
-            GenericDefId::ImplId(id) => {
-                let id = id.lookup(db).id;
-                let tree = id.item_tree(db);
-                let item = &tree[id.value];
-                item.generic_params.clone()
-            }
+            GenericDefId::AdtId(AdtId::StructId(id)) => id_to_generics!(id),
+            GenericDefId::AdtId(AdtId::EnumId(id)) => id_to_generics!(id),
+            GenericDefId::AdtId(AdtId::UnionId(id)) => id_to_generics!(id),
+            GenericDefId::TraitId(id) => id_to_generics!(id),
+            GenericDefId::TypeAliasId(id) => id_to_generics!(id),
+            GenericDefId::ImplId(id) => id_to_generics!(id),
             GenericDefId::EnumVariantId(_) | GenericDefId::ConstId(_) => {
                 Interned::new(GenericParams::default())
             }
@@ -393,15 +372,14 @@ impl GenericParams {
 
     pub fn find_trait_self_param(&self) -> Option<LocalTypeOrConstParamId> {
         self.type_or_consts.iter().find_map(|(id, p)| {
-            if let TypeOrConstParamData::TypeParamData(p) = p {
-                if p.provenance == TypeParamProvenance::TraitSelf {
-                    Some(id)
-                } else {
-                    None
-                }
-            } else {
-                None
-            }
+            matches!(
+                p,
+                TypeOrConstParamData::TypeParamData(TypeParamData {
+                    provenance: TypeParamProvenance::TraitSelf,
+                    ..
+                })
+            )
+            .then(|| id)
         })
     }
 }
diff --git a/crates/hir-def/src/path.rs b/crates/hir-def/src/path.rs
index 37c09a0984..3aade788d7 100644
--- a/crates/hir-def/src/path.rs
+++ b/crates/hir-def/src/path.rs
@@ -11,7 +11,7 @@ use crate::{
     intern::Interned,
     type_ref::{ConstScalarOrPath, LifetimeRef},
 };
-use hir_expand::name::{name, Name};
+use hir_expand::name::Name;
 use syntax::ast;
 
 use crate::type_ref::{TypeBound, TypeRef};
@@ -134,9 +134,7 @@ impl Path {
     }
 
     pub fn is_self_type(&self) -> bool {
-        self.type_anchor.is_none()
-            && *self.generic_args == [None]
-            && self.mod_path.as_ident() == Some(&name!(Self))
+        self.type_anchor.is_none() && *self.generic_args == [None] && self.mod_path.is_Self()
     }
 }
 
diff --git a/crates/hir-def/src/type_ref.rs b/crates/hir-def/src/type_ref.rs
index 8e9336a0cc..6b16a0c876 100644
--- a/crates/hir-def/src/type_ref.rs
+++ b/crates/hir-def/src/type_ref.rs
@@ -109,7 +109,6 @@ pub enum TypeRef {
     Slice(Box<TypeRef>),
     /// A fn pointer. Last element of the vector is the return type.
     Fn(Vec<(Option<Name>, TypeRef)>, bool /*varargs*/),
-    // For
     ImplTrait(Vec<Interned<TypeBound>>),
     DynTrait(Vec<Interned<TypeBound>>),
     Macro(AstId<ast::MacroCall>),
diff --git a/crates/hir-expand/src/mod_path.rs b/crates/hir-expand/src/mod_path.rs
index bb2f6350c6..d38e4a52a8 100644
--- a/crates/hir-expand/src/mod_path.rs
+++ b/crates/hir-expand/src/mod_path.rs
@@ -80,6 +80,12 @@ impl ModPath {
         self.kind == PathKind::Super(0) && self.segments.is_empty()
     }
 
+    #[allow(non_snake_case)]
+    pub fn is_Self(&self) -> bool {
+        self.kind == PathKind::Plain
+            && matches!(&*self.segments, [name] if *name == known::SELF_TYPE)
+    }
+
     /// If this path is a single identifier, like `foo`, return its name.
     pub fn as_ident(&self) -> Option<&Name> {
         if self.kind != PathKind::Plain {
diff --git a/crates/hir-ty/src/lower.rs b/crates/hir-ty/src/lower.rs
index f64027c218..adee8cf958 100644
--- a/crates/hir-ty/src/lower.rs
+++ b/crates/hir-ty/src/lower.rs
@@ -5,31 +5,33 @@
 //!  - Building the type for an item: This happens through the `type_for_def` query.
 //!
 //! This usually involves resolving names, collecting generic arguments etc.
-use std::cell::{Cell, RefCell};
-use std::{iter, sync::Arc};
+use std::{
+    cell::{Cell, RefCell},
+    iter,
+    sync::Arc,
+};
 
 use base_db::CrateId;
-use chalk_ir::fold::Fold;
-use chalk_ir::interner::HasInterner;
-use chalk_ir::{cast::Cast, fold::Shift, Mutability, Safety};
-use hir_def::generics::TypeOrConstParamData;
-use hir_def::intern::Interned;
-use hir_def::lang_item::lang_attr;
-use hir_def::path::{ModPath, PathKind};
-use hir_def::type_ref::ConstScalarOrPath;
+use chalk_ir::{cast::Cast, fold::Fold, fold::Shift, interner::HasInterner, Mutability, Safety};
+
 use hir_def::{
     adt::StructKind,
     body::{Expander, LowerCtx},
     builtin_type::BuiltinType,
-    generics::{TypeParamProvenance, WherePredicate, WherePredicateTypeTarget},
-    path::{GenericArg, Path, PathSegment, PathSegments},
+    generics::{
+        TypeOrConstParamData, TypeParamProvenance, WherePredicate, WherePredicateTypeTarget,
+    },
+    intern::Interned,
+    lang_item::lang_attr,
+    path::{GenericArg, ModPath, Path, PathKind, PathSegment, PathSegments},
     resolver::{HasResolver, Resolver, TypeNs},
-    type_ref::{TraitBoundModifier, TraitRef as HirTraitRef, TypeBound, TypeRef},
-    AdtId, AssocItemId, ConstId, EnumId, EnumVariantId, FunctionId, GenericDefId, HasModule,
-    ImplId, ItemContainerId, LocalFieldId, Lookup, StaticId, StructId, TraitId, TypeAliasId,
-    UnionId, VariantId,
+    type_ref::{
+        ConstScalarOrPath, TraitBoundModifier, TraitRef as HirTraitRef, TypeBound, TypeRef,
+    },
+    AdtId, AssocItemId, ConstId, ConstParamId, EnumId, EnumVariantId, FunctionId, GenericDefId,
+    HasModule, ImplId, ItemContainerId, LocalFieldId, Lookup, StaticId, StructId, TraitId,
+    TypeAliasId, TypeOrConstParamId, TypeParamId, UnionId, VariantId,
 };
-use hir_def::{ConstParamId, TypeOrConstParamId, TypeParamId};
 use hir_expand::{name::Name, ExpandResult};
 use itertools::Either;
 use la_arena::ArenaMap;
@@ -38,20 +40,19 @@ use smallvec::SmallVec;
 use stdx::{impl_from, never};
 use syntax::{ast, SmolStr};
 
-use crate::consteval::{
-    intern_scalar_const, path_to_const, unknown_const, unknown_const_as_generic,
-};
-use crate::utils::Generics;
-use crate::{all_super_traits, make_binders, Const, GenericArgData, ParamKind};
 use crate::{
+    all_super_traits,
+    consteval::{intern_scalar_const, path_to_const, unknown_const, unknown_const_as_generic},
     db::HirDatabase,
+    make_binders,
     mapping::ToChalk,
     static_lifetime, to_assoc_type_id, to_chalk_trait_id, to_placeholder_idx,
+    utils::Generics,
     utils::{all_super_trait_refs, associated_type_by_name_including_super_traits, generics},
-    AliasEq, AliasTy, Binders, BoundVar, CallableSig, DebruijnIndex, DynTy, FnPointer, FnSig,
-    FnSubst, ImplTraitId, Interner, PolyFnSig, ProjectionTy, QuantifiedWhereClause,
-    QuantifiedWhereClauses, ReturnTypeImplTrait, ReturnTypeImplTraits, Substitution,
-    TraitEnvironment, TraitRef, TraitRefExt, Ty, TyBuilder, TyKind, WhereClause,
+    AliasEq, AliasTy, Binders, BoundVar, CallableSig, Const, DebruijnIndex, DynTy, FnPointer,
+    FnSig, FnSubst, GenericArgData, ImplTraitId, Interner, ParamKind, PolyFnSig, ProjectionTy,
+    QuantifiedWhereClause, QuantifiedWhereClauses, ReturnTypeImplTrait, ReturnTypeImplTraits,
+    Substitution, TraitEnvironment, TraitRef, TraitRefExt, Ty, TyBuilder, TyKind, WhereClause,
 };
 
 #[derive(Debug)]
diff --git a/crates/hir-ty/src/utils.rs b/crates/hir-ty/src/utils.rs
index e608f85774..2e14479368 100644
--- a/crates/hir-ty/src/utils.rs
+++ b/crates/hir-ty/src/utils.rs
@@ -12,13 +12,12 @@ use hir_def::{
         WherePredicateTypeTarget,
     },
     intern::Interned,
-    path::Path,
     resolver::{HasResolver, TypeNs},
     type_ref::{TraitBoundModifier, TypeRef},
     ConstParamId, FunctionId, GenericDefId, ItemContainerId, Lookup, TraitId, TypeAliasId,
     TypeOrConstParamId, TypeParamId,
 };
-use hir_expand::name::{known, name, Name};
+use hir_expand::name::{known, Name};
 use itertools::Either;
 use rustc_hash::FxHashSet;
 use smallvec::{smallvec, SmallVec};
@@ -53,25 +52,25 @@ fn direct_super_traits(db: &dyn DefDatabase, trait_: TraitId) -> SmallVec<[Trait
         .iter()
         .filter_map(|pred| match pred {
             WherePredicate::ForLifetime { target, bound, .. }
-            | WherePredicate::TypeBound { target, bound } => match target {
-                WherePredicateTypeTarget::TypeRef(type_ref) => match &**type_ref {
-                    TypeRef::Path(p) if p == &Path::from(name![Self]) => bound.as_path(),
-                    _ => None,
-                },
-                WherePredicateTypeTarget::TypeOrConstParam(local_id)
-                    if Some(*local_id) == trait_self =>
-                {
-                    bound.as_path()
+            | WherePredicate::TypeBound { target, bound } => {
+                let is_trait = match target {
+                    WherePredicateTypeTarget::TypeRef(type_ref) => match &**type_ref {
+                        TypeRef::Path(p) => p.is_self_type(),
+                        _ => false,
+                    },
+                    WherePredicateTypeTarget::TypeOrConstParam(local_id) => {
+                        Some(*local_id) == trait_self
+                    }
+                };
+                match is_trait {
+                    true => bound.as_path(),
+                    false => None,
                 }
-                _ => None,
-            },
+            }
             WherePredicate::Lifetime { .. } => None,
         })
-        .filter_map(|(path, bound_modifier)| match bound_modifier {
-            TraitBoundModifier::None => Some(path),
-            TraitBoundModifier::Maybe => None,
-        })
-        .filter_map(|path| match resolver.resolve_path_in_type_ns_fully(db, path.mod_path()) {
+        .filter(|(_, bound_modifier)| matches!(bound_modifier, TraitBoundModifier::None))
+        .filter_map(|(path, _)| match resolver.resolve_path_in_type_ns_fully(db, path.mod_path()) {
             Some(TypeNs::TraitId(t)) => Some(t),
             _ => None,
         })
diff --git a/crates/hir/src/lib.rs b/crates/hir/src/lib.rs
index cc4d14c12d..3f0d586bf6 100644
--- a/crates/hir/src/lib.rs
+++ b/crates/hir/src/lib.rs
@@ -3497,30 +3497,12 @@ impl HasCrate for AssocItem {
     }
 }
 
-impl HasCrate for Struct {
-    fn krate(&self, db: &dyn HirDatabase) -> Crate {
-        self.module(db).krate()
-    }
-}
-
-impl HasCrate for Union {
-    fn krate(&self, db: &dyn HirDatabase) -> Crate {
-        self.module(db).krate()
-    }
-}
-
 impl HasCrate for Field {
     fn krate(&self, db: &dyn HirDatabase) -> Crate {
         self.parent_def(db).module(db).krate()
     }
 }
 
-impl HasCrate for Variant {
-    fn krate(&self, db: &dyn HirDatabase) -> Crate {
-        self.module(db).krate()
-    }
-}
-
 impl HasCrate for Function {
     fn krate(&self, db: &dyn HirDatabase) -> Crate {
         self.module(db).krate()
diff --git a/crates/hir/src/semantics.rs b/crates/hir/src/semantics.rs
index aa10b0f878..592e7d3b97 100644
--- a/crates/hir/src/semantics.rs
+++ b/crates/hir/src/semantics.rs
@@ -2,7 +2,7 @@
 
 mod source_to_def;
 
-use std::{cell::RefCell, fmt, iter, ops};
+use std::{cell::RefCell, fmt, iter};
 
 use base_db::{FileId, FileRange};
 use hir_def::{
@@ -1449,11 +1449,3 @@ impl<'a> SemanticsScope<'a> {
 }
 
 pub struct VisibleTraits(pub FxHashSet<TraitId>);
-
-impl ops::Deref for VisibleTraits {
-    type Target = FxHashSet<TraitId>;
-
-    fn deref(&self) -> &Self::Target {
-        &self.0
-    }
-}
diff --git a/crates/ide-completion/src/completions.rs b/crates/ide-completion/src/completions.rs
index 81bb59681b..147563ef10 100644
--- a/crates/ide-completion/src/completions.rs
+++ b/crates/ide-completion/src/completions.rs
@@ -36,7 +36,7 @@ use crate::{
         const_::render_const,
         function::{render_fn, render_method},
         literal::{render_struct_literal, render_variant_lit},
-        macro_::render_macro,
+        macro_::{render_macro, render_macro_pat},
         pattern::{render_struct_pat, render_variant_pat},
         render_field, render_path_resolution, render_pattern_resolution, render_tuple_field,
         type_alias::{render_type_alias, render_type_alias_with_eq},
@@ -101,15 +101,15 @@ impl Completions {
     pub(crate) fn add_keyword_snippet_expr(
         &mut self,
         ctx: &CompletionContext,
-        incomplete_let: bool,
         kw: &str,
         snippet: &str,
+        incomplete_let: bool,
     ) {
         let mut item = CompletionItem::new(CompletionItemKind::Keyword, ctx.source_range(), kw);
 
         match ctx.config.snippet_cap {
             Some(cap) => {
-                if incomplete_let && snippet.ends_with('}') {
+                if snippet.ends_with('}') && incomplete_let {
                     // complete block expression snippets with a trailing semicolon, if inside an incomplete let
                     cov_mark::hit!(let_semi);
                     item.insert_snippet(cap, format!("{};", snippet));
@@ -181,17 +181,6 @@ impl Completions {
         );
     }
 
-    pub(crate) fn add_enum_variants(
-        &mut self,
-        ctx: &CompletionContext,
-        path_ctx: &PathCompletionCtx,
-        e: hir::Enum,
-    ) {
-        e.variants(ctx.db)
-            .into_iter()
-            .for_each(|variant| self.add_enum_variant(ctx, path_ctx, variant, None));
-    }
-
     pub(crate) fn add_module(
         &mut self,
         ctx: &CompletionContext,
@@ -230,6 +219,29 @@ impl Completions {
         );
     }
 
+    pub(crate) fn add_macro_pat(
+        &mut self,
+        ctx: &CompletionContext,
+        pattern_ctx: &PatternContext,
+        mac: hir::Macro,
+        local_name: hir::Name,
+    ) {
+        let is_private_editable = match ctx.is_visible(&mac) {
+            Visible::Yes => false,
+            Visible::Editable => true,
+            Visible::No => return,
+        };
+        self.add(
+            render_macro_pat(
+                RenderContext::new(ctx).private_editable(is_private_editable),
+                pattern_ctx,
+                local_name,
+                mac,
+            )
+            .build(),
+        );
+    }
+
     pub(crate) fn add_function(
         &mut self,
         ctx: &CompletionContext,
diff --git a/crates/ide-completion/src/completions/dot.rs b/crates/ide-completion/src/completions/dot.rs
index 911ef60930..bf0bce2198 100644
--- a/crates/ide-completion/src/completions/dot.rs
+++ b/crates/ide-completion/src/completions/dot.rs
@@ -121,7 +121,7 @@ fn complete_methods(
     receiver.iterate_method_candidates(
         ctx.db,
         &ctx.scope,
-        &ctx.traits_in_scope(),
+        &ctx.traits_in_scope().0,
         Some(ctx.module),
         None,
         |func| {
diff --git a/crates/ide-completion/src/completions/expr.rs b/crates/ide-completion/src/completions/expr.rs
index 058d0ab7bb..6b36801205 100644
--- a/crates/ide-completion/src/completions/expr.rs
+++ b/crates/ide-completion/src/completions/expr.rs
@@ -1,6 +1,7 @@
 //! Completion of names from the current scope in expression position.
 
 use hir::ScopeDef;
+use ide_db::FxHashSet;
 
 use crate::{
     context::{ExprCtx, PathCompletionCtx, Qualified},
@@ -32,24 +33,24 @@ pub(crate) fn complete_expr_path(
     let wants_mut_token =
         ref_expr_parent.as_ref().map(|it| it.mut_token().is_none()).unwrap_or(false);
 
-    let scope_def_applicable = |def| match def {
-        ScopeDef::GenericParam(hir::GenericParam::LifetimeParam(_)) | ScopeDef::Label(_) => false,
-        ScopeDef::ModuleDef(hir::ModuleDef::Macro(mac)) => mac.is_fn_like(ctx.db),
-        _ => true,
-    };
-
-    let add_assoc_item = |acc: &mut Completions, item| match item {
-        hir::AssocItem::Function(func) => acc.add_function(ctx, path_ctx, func, None),
-        hir::AssocItem::Const(ct) => acc.add_const(ctx, ct),
-        hir::AssocItem::TypeAlias(ty) => acc.add_type_alias(ctx, ty),
+    let scope_def_applicable = |def| {
+        match def {
+            ScopeDef::GenericParam(hir::GenericParam::LifetimeParam(_)) | ScopeDef::Label(_) => {
+                false
+            }
+            // Don't suggest attribute macros and derives.
+            ScopeDef::ModuleDef(hir::ModuleDef::Macro(mac)) => mac.is_fn_like(ctx.db),
+            _ => true,
+        }
     };
 
     match qualified {
         Qualified::Infer => ctx
             .traits_in_scope()
-            .iter()
-            .flat_map(|&it| hir::Trait::from(it).items(ctx.sema.db))
-            .for_each(|item| add_assoc_item(acc, item)),
+            .0
+            .into_iter()
+            .flat_map(|it| hir::Trait::from(it).items(ctx.sema.db))
+            .for_each(|item| add_assoc_item(acc, ctx, path_ctx, item)),
         Qualified::With { resolution: None, .. } => {}
         Qualified::With { resolution: Some(resolution), .. } => {
             // Add associated types on type parameters and `Self`.
@@ -66,32 +67,46 @@ pub(crate) fn complete_expr_path(
                         }
                     }
                 }
+
                 hir::PathResolution::Def(
                     def @ (hir::ModuleDef::Adt(_)
                     | hir::ModuleDef::TypeAlias(_)
                     | hir::ModuleDef::BuiltinType(_)),
                 ) => {
+                    if let &hir::ModuleDef::Adt(hir::Adt::Enum(e)) = def {
+                        add_enum_variants(acc, ctx, path_ctx, e);
+                    }
                     let ty = match def {
                         hir::ModuleDef::Adt(adt) => adt.ty(ctx.db),
-                        hir::ModuleDef::TypeAlias(a) => a.ty(ctx.db),
+                        hir::ModuleDef::TypeAlias(a) => {
+                            let ty = a.ty(ctx.db);
+                            if let Some(hir::Adt::Enum(e)) = ty.as_adt() {
+                                cov_mark::hit!(completes_variant_through_alias);
+                                add_enum_variants(acc, ctx, path_ctx, e);
+                            }
+                            ty
+                        }
                         hir::ModuleDef::BuiltinType(builtin) => {
                             cov_mark::hit!(completes_primitive_assoc_const);
                             builtin.ty(ctx.db)
                         }
-                        _ => return,
+                        _ => unreachable!(),
                     };
 
-                    if let Some(hir::Adt::Enum(e)) = ty.as_adt() {
-                        cov_mark::hit!(completes_variant_through_alias);
-                        acc.add_enum_variants(ctx, path_ctx, e);
-                    }
-
                     // XXX: For parity with Rust bug #22519, this does not complete Ty::AssocType.
                     // (where AssocType is defined on a trait, not an inherent impl)
 
-                    ctx.iterate_path_candidates(&ty, |item| {
-                        add_assoc_item(acc, item);
-                    });
+                    ty.iterate_path_candidates(
+                        ctx.db,
+                        &ctx.scope,
+                        &ctx.traits_in_scope().0,
+                        Some(ctx.module),
+                        None,
+                        |item| {
+                            add_assoc_item(acc, ctx, path_ctx, item);
+                            None::<()>
+                        },
+                    );
 
                     // Iterate assoc types separately
                     ty.iterate_assoc_items(ctx.db, ctx.krate, |item| {
@@ -104,7 +119,7 @@ pub(crate) fn complete_expr_path(
                 hir::PathResolution::Def(hir::ModuleDef::Trait(t)) => {
                     // Handles `Trait::assoc` as well as `<Ty as Trait>::assoc`.
                     for item in t.items(ctx.db) {
-                        add_assoc_item(acc, item);
+                        add_assoc_item(acc, ctx, path_ctx, item);
                     }
                 }
                 hir::PathResolution::TypeParam(_) | hir::PathResolution::SelfType(_) => {
@@ -115,12 +130,24 @@ pub(crate) fn complete_expr_path(
                     };
 
                     if let Some(hir::Adt::Enum(e)) = ty.as_adt() {
-                        acc.add_enum_variants(ctx, path_ctx, e);
+                        add_enum_variants(acc, ctx, path_ctx, e);
                     }
-
-                    ctx.iterate_path_candidates(&ty, |item| {
-                        add_assoc_item(acc, item);
-                    });
+                    let mut seen = FxHashSet::default();
+                    ty.iterate_path_candidates(
+                        ctx.db,
+                        &ctx.scope,
+                        &ctx.traits_in_scope().0,
+                        Some(ctx.module),
+                        None,
+                        |item| {
+                            // We might iterate candidates of a trait multiple times here, so deduplicate
+                            // them.
+                            if seen.insert(item) {
+                                add_assoc_item(acc, ctx, path_ctx, item);
+                            }
+                            None::<()>
+                        },
+                    );
                 }
                 _ => (),
             }
@@ -185,7 +212,7 @@ pub(crate) fn complete_expr_path(
 
             if is_func_update.is_none() {
                 let mut add_keyword =
-                    |kw, snippet| acc.add_keyword_snippet_expr(ctx, incomplete_let, kw, snippet);
+                    |kw, snippet| acc.add_keyword_snippet_expr(ctx, kw, snippet, incomplete_let);
 
                 if !in_block_expr {
                     add_keyword("unsafe", "unsafe {\n    $0\n}");
@@ -238,3 +265,27 @@ pub(crate) fn complete_expr_path(
         }
     }
 }
+
+fn add_assoc_item(
+    acc: &mut Completions,
+    ctx: &CompletionContext,
+    path_ctx: &PathCompletionCtx,
+    item: hir::AssocItem,
+) {
+    match item {
+        hir::AssocItem::Function(func) => acc.add_function(ctx, path_ctx, func, None),
+        hir::AssocItem::Const(ct) => acc.add_const(ctx, ct),
+        hir::AssocItem::TypeAlias(ty) => acc.add_type_alias(ctx, ty),
+    }
+}
+
+fn add_enum_variants(
+    acc: &mut Completions,
+    ctx: &CompletionContext,
+    path_ctx: &PathCompletionCtx,
+    e: hir::Enum,
+) {
+    e.variants(ctx.db)
+        .into_iter()
+        .for_each(|variant| acc.add_enum_variant(ctx, path_ctx, variant, None));
+}
diff --git a/crates/ide-completion/src/completions/pattern.rs b/crates/ide-completion/src/completions/pattern.rs
index 7a344c2c7b..4ea80a5077 100644
--- a/crates/ide-completion/src/completions/pattern.rs
+++ b/crates/ide-completion/src/completions/pattern.rs
@@ -1,6 +1,7 @@
 //! Completes constants and paths in unqualified patterns.
 
 use hir::{db::DefDatabase, AssocItem, ScopeDef};
+use ide_db::FxHashSet;
 use syntax::ast::Pat;
 
 use crate::{
@@ -80,7 +81,9 @@ pub(crate) fn complete_pattern(
                 hir::ModuleDef::Adt(hir::Adt::Enum(e)) => refutable || single_variant_enum(e),
                 hir::ModuleDef::Const(..) => refutable,
                 hir::ModuleDef::Module(..) => true,
-                hir::ModuleDef::Macro(mac) => mac.is_fn_like(ctx.db),
+                hir::ModuleDef::Macro(mac) if mac.is_fn_like(ctx.db) => {
+                    return acc.add_macro_pat(ctx, pattern_ctx, mac, name);
+                }
                 _ => false,
             },
             hir::ScopeDef::ImplSelfType(impl_) => match impl_.self_ty(ctx.db).as_adt() {
@@ -133,7 +136,12 @@ pub(crate) fn complete_pattern_path(
                         }
                     }
                 }
-                res => {
+                res @ (hir::PathResolution::TypeParam(_)
+                | hir::PathResolution::SelfType(_)
+                | hir::PathResolution::Def(hir::ModuleDef::Adt(hir::Adt::Struct(_)))
+                | hir::PathResolution::Def(hir::ModuleDef::Adt(hir::Adt::Enum(_)))
+                | hir::PathResolution::Def(hir::ModuleDef::Adt(hir::Adt::Union(_)))
+                | hir::PathResolution::Def(hir::ModuleDef::BuiltinType(_))) => {
                     let ty = match res {
                         hir::PathResolution::TypeParam(param) => param.ty(ctx.db),
                         hir::PathResolution::SelfType(impl_def) => impl_def.self_ty(ctx.db),
@@ -141,6 +149,10 @@ pub(crate) fn complete_pattern_path(
                             s.ty(ctx.db)
                         }
                         hir::PathResolution::Def(hir::ModuleDef::Adt(hir::Adt::Enum(e))) => {
+                            cov_mark::hit!(enum_plain_qualified_use_tree);
+                            e.variants(ctx.db).into_iter().for_each(|variant| {
+                                acc.add_enum_variant(ctx, path_ctx, variant, None)
+                            });
                             e.ty(ctx.db)
                         }
                         hir::PathResolution::Def(hir::ModuleDef::Adt(hir::Adt::Union(u))) => {
@@ -150,33 +162,41 @@ pub(crate) fn complete_pattern_path(
                         _ => return,
                     };
 
-                    if let Some(hir::Adt::Enum(e)) = ty.as_adt() {
-                        cov_mark::hit!(enum_plain_qualified_use_tree);
-                        acc.add_enum_variants(ctx, path_ctx, e);
-                    }
-
-                    ctx.iterate_path_candidates(&ty, |item| match item {
-                        AssocItem::TypeAlias(ta) => acc.add_type_alias(ctx, ta),
-                        AssocItem::Const(c) => acc.add_const(ctx, c),
-                        _ => {}
-                    });
+                    let mut seen = FxHashSet::default();
+                    ty.iterate_path_candidates(
+                        ctx.db,
+                        &ctx.scope,
+                        &ctx.scope.visible_traits().0,
+                        Some(ctx.module),
+                        None,
+                        |item| {
+                            match item {
+                                AssocItem::TypeAlias(ta) => {
+                                    // We might iterate candidates of a trait multiple times here, so deduplicate them.
+                                    if seen.insert(item) {
+                                        acc.add_type_alias(ctx, ta);
+                                    }
+                                }
+                                AssocItem::Const(c) => {
+                                    if seen.insert(item) {
+                                        acc.add_const(ctx, c);
+                                    }
+                                }
+                                _ => {}
+                            }
+                            None::<()>
+                        },
+                    );
                 }
+                _ => {}
             }
         }
+        // qualifier can only be none here if we are in a TuplePat or RecordPat in which case special characters have to follow the path
         Qualified::Absolute => acc.add_crate_roots(ctx, path_ctx),
         Qualified::No => {
-            // this will only be hit if there are brackets or braces, otherwise this will be parsed as an ident pattern
             ctx.process_all_names(&mut |name, res| {
-                // FIXME: we should check what kind of pattern we are in and filter accordingly
-                let add_completion = match res {
-                    ScopeDef::ModuleDef(hir::ModuleDef::Macro(mac)) => mac.is_fn_like(ctx.db),
-                    ScopeDef::ModuleDef(hir::ModuleDef::Adt(_)) => true,
-                    ScopeDef::ModuleDef(hir::ModuleDef::Variant(_)) => true,
-                    ScopeDef::ModuleDef(hir::ModuleDef::Module(_)) => true,
-                    ScopeDef::ImplSelfType(_) => true,
-                    _ => false,
-                };
-                if add_completion {
+                // FIXME: properly filter here
+                if let ScopeDef::ModuleDef(_) = res {
                     acc.add_path_resolution(ctx, path_ctx, name, res);
                 }
             });
diff --git a/crates/ide-completion/src/completions/record.rs b/crates/ide-completion/src/completions/record.rs
index 9f5922c5b0..8cef3a7018 100644
--- a/crates/ide-completion/src/completions/record.rs
+++ b/crates/ide-completion/src/completions/record.rs
@@ -17,7 +17,6 @@ pub(crate) fn complete_record_pattern_fields(
         complete_fields(acc, ctx, ctx.sema.record_pattern_missing_fields(record_pat));
     }
 }
-
 pub(crate) fn complete_record_expr_fields(
     acc: &mut Completions,
     ctx: &CompletionContext,
@@ -42,6 +41,7 @@ pub(crate) fn complete_record_expr_fields(
         }
         _ => {
             let missing_fields = ctx.sema.record_literal_missing_fields(record_expr);
+
             add_default_update(acc, ctx, ty, &missing_fields);
             if dot_prefix {
                 let mut item =
@@ -56,29 +56,6 @@ pub(crate) fn complete_record_expr_fields(
     complete_fields(acc, ctx, missing_fields);
 }
 
-// FIXME: This should probably be part of complete_path_expr
-pub(crate) fn complete_record_expr_func_update(
-    acc: &mut Completions,
-    ctx: &CompletionContext,
-    path_ctx: &PathCompletionCtx,
-    expr_ctx: &ExprCtx,
-) {
-    if !matches!(path_ctx.qualified, Qualified::No) {
-        return;
-    }
-    if let ExprCtx { is_func_update: Some(record_expr), .. } = expr_ctx {
-        let ty = ctx.sema.type_of_expr(&Expr::RecordExpr(record_expr.clone()));
-
-        match ty.as_ref().and_then(|t| t.original.as_adt()) {
-            Some(hir::Adt::Union(_)) => (),
-            _ => {
-                let missing_fields = ctx.sema.record_literal_missing_fields(record_expr);
-                add_default_update(acc, ctx, ty, &missing_fields);
-            }
-        };
-    }
-}
-
 fn add_default_update(
     acc: &mut Completions,
     ctx: &CompletionContext,
@@ -90,7 +67,6 @@ fn add_default_update(
         .zip(ty.as_ref())
         .map_or(false, |(default_trait, ty)| ty.original.impls_trait(ctx.db, default_trait, &[]));
     if impl_default_trait && !missing_fields.is_empty() {
-        // FIXME: This should make use of scope_def like completions so we get all the other goodies
         let completion_text = "..Default::default()";
         let mut item = CompletionItem::new(SymbolKind::Field, ctx.source_range(), completion_text);
         let completion_text =
@@ -103,6 +79,28 @@ fn add_default_update(
     }
 }
 
+pub(crate) fn complete_record_expr_func_update(
+    acc: &mut Completions,
+    ctx: &CompletionContext,
+    path_ctx: &PathCompletionCtx,
+    expr_ctx: &ExprCtx,
+) {
+    if !matches!(path_ctx.qualified, Qualified::No) {
+        return;
+    }
+    if let ExprCtx { is_func_update: Some(record_expr), .. } = expr_ctx {
+        let ty = ctx.sema.type_of_expr(&Expr::RecordExpr(record_expr.clone()));
+
+        match ty.as_ref().and_then(|t| t.original.as_adt()) {
+            Some(hir::Adt::Union(_)) => (),
+            _ => {
+                let missing_fields = ctx.sema.record_literal_missing_fields(record_expr);
+                add_default_update(acc, ctx, ty, &missing_fields);
+            }
+        };
+    }
+}
+
 fn complete_fields(
     acc: &mut Completions,
     ctx: &CompletionContext,
diff --git a/crates/ide-completion/src/completions/snippet.rs b/crates/ide-completion/src/completions/snippet.rs
index a530f4262e..9992a81fe0 100644
--- a/crates/ide-completion/src/completions/snippet.rs
+++ b/crates/ide-completion/src/completions/snippet.rs
@@ -9,6 +9,12 @@ use crate::{
     CompletionContext, CompletionItem, CompletionItemKind, Completions, SnippetScope,
 };
 
+fn snippet(ctx: &CompletionContext, cap: SnippetCap, label: &str, snippet: &str) -> Builder {
+    let mut item = CompletionItem::new(CompletionItemKind::Snippet, ctx.source_range(), label);
+    item.insert_snippet(cap, snippet);
+    item
+}
+
 pub(crate) fn complete_expr_snippet(
     acc: &mut Completions,
     ctx: &CompletionContext,
@@ -118,12 +124,6 @@ macro_rules! $1 {
     }
 }
 
-fn snippet(ctx: &CompletionContext, cap: SnippetCap, label: &str, snippet: &str) -> Builder {
-    let mut item = CompletionItem::new(CompletionItemKind::Snippet, ctx.source_range(), label);
-    item.insert_snippet(cap, snippet);
-    item
-}
-
 fn add_custom_completions(
     acc: &mut Completions,
     ctx: &CompletionContext,
diff --git a/crates/ide-completion/src/completions/type.rs b/crates/ide-completion/src/completions/type.rs
index 616d862154..c5b65d36ae 100644
--- a/crates/ide-completion/src/completions/type.rs
+++ b/crates/ide-completion/src/completions/type.rs
@@ -1,6 +1,7 @@
 //! Completion of names from the current scope in type position.
 
 use hir::{HirDisplay, ScopeDef};
+use ide_db::FxHashSet;
 use syntax::{ast, AstNode};
 
 use crate::{
@@ -51,8 +52,9 @@ pub(crate) fn complete_type_path(
     match qualified {
         Qualified::Infer => ctx
             .traits_in_scope()
-            .iter()
-            .flat_map(|&it| hir::Trait::from(it).items(ctx.sema.db))
+            .0
+            .into_iter()
+            .flat_map(|it| hir::Trait::from(it).items(ctx.sema.db))
             .for_each(|item| add_assoc_item(acc, item)),
         Qualified::With { resolution: None, .. } => {}
         Qualified::With { resolution: Some(resolution), .. } => {
@@ -86,9 +88,17 @@ pub(crate) fn complete_type_path(
                     // XXX: For parity with Rust bug #22519, this does not complete Ty::AssocType.
                     // (where AssocType is defined on a trait, not an inherent impl)
 
-                    ctx.iterate_path_candidates(&ty, |item| {
-                        add_assoc_item(acc, item);
-                    });
+                    ty.iterate_path_candidates(
+                        ctx.db,
+                        &ctx.scope,
+                        &ctx.traits_in_scope().0,
+                        Some(ctx.module),
+                        None,
+                        |item| {
+                            add_assoc_item(acc, item);
+                            None::<()>
+                        },
+                    );
 
                     // Iterate assoc types separately
                     ty.iterate_assoc_items(ctx.db, ctx.krate, |item| {
@@ -111,9 +121,22 @@ pub(crate) fn complete_type_path(
                         _ => return,
                     };
 
-                    ctx.iterate_path_candidates(&ty, |item| {
-                        add_assoc_item(acc, item);
-                    });
+                    let mut seen = FxHashSet::default();
+                    ty.iterate_path_candidates(
+                        ctx.db,
+                        &ctx.scope,
+                        &ctx.traits_in_scope().0,
+                        Some(ctx.module),
+                        None,
+                        |item| {
+                            // We might iterate candidates of a trait multiple times here, so deduplicate
+                            // them.
+                            if seen.insert(item) {
+                                add_assoc_item(acc, item);
+                            }
+                            None::<()>
+                        },
+                    );
                 }
                 _ => (),
             }
diff --git a/crates/ide-completion/src/context.rs b/crates/ide-completion/src/context.rs
index 01a2f96fd1..8ea03358ae 100644
--- a/crates/ide-completion/src/context.rs
+++ b/crates/ide-completion/src/context.rs
@@ -371,9 +371,7 @@ impl<'a> CompletionContext<'a> {
     where
         I: hir::HasVisibility + hir::HasAttrs + hir::HasCrate + Copy,
     {
-        let vis = item.visibility(self.db);
-        let attrs = item.attrs(self.db);
-        self.is_visible_impl(&vis, &attrs, item.krate(self.db))
+        self.is_visible_impl(&item.visibility(self.db), &item.attrs(self.db), item.krate(self.db))
     }
 
     pub(crate) fn is_scope_def_hidden(&self, scope_def: ScopeDef) -> bool {
@@ -393,7 +391,6 @@ impl<'a> CompletionContext<'a> {
             _ => false,
         }
     }
-
     /// Whether the given trait is an operator trait or not.
     pub(crate) fn is_ops_trait(&self, trait_: hir::Trait) -> bool {
         match trait_.attrs(self.db).lang() {
@@ -411,29 +408,6 @@ impl<'a> CompletionContext<'a> {
         traits_in_scope
     }
 
-    pub(crate) fn iterate_path_candidates(
-        &self,
-        ty: &hir::Type,
-        mut cb: impl FnMut(hir::AssocItem),
-    ) {
-        let mut seen = FxHashSet::default();
-        ty.iterate_path_candidates(
-            self.db,
-            &self.scope,
-            &self.traits_in_scope(),
-            Some(self.module),
-            None,
-            |item| {
-                // We might iterate candidates of a trait multiple times here, so deduplicate
-                // them.
-                if seen.insert(item) {
-                    cb(item)
-                }
-                None::<()>
-            },
-        );
-    }
-
     /// A version of [`SemanticsScope::process_all_names`] that filters out `#[doc(hidden)]` items.
     pub(crate) fn process_all_names(&self, f: &mut dyn FnMut(Name, ScopeDef)) {
         let _p = profile::span("CompletionContext::process_all_names");
diff --git a/crates/ide-completion/src/lib.rs b/crates/ide-completion/src/lib.rs
index b806d955d9..fe02f05fd1 100644
--- a/crates/ide-completion/src/lib.rs
+++ b/crates/ide-completion/src/lib.rs
@@ -148,7 +148,7 @@ pub fn completions(
     config: &CompletionConfig,
     position: FilePosition,
     trigger_character: Option<char>,
-) -> Option<Vec<CompletionItem>> {
+) -> Option<Completions> {
     let (ctx, analysis) = &CompletionContext::new(db, position, config)?;
     let mut completions = Completions::default();
 
@@ -163,7 +163,7 @@ pub fn completions(
             }
         }
         // prevent `(` from triggering unwanted completion noise
-        return Some(completions.into());
+        return Some(completions);
     }
 
     {
@@ -197,7 +197,7 @@ pub fn completions(
         }
     }
 
-    Some(completions.into())
+    Some(completions)
 }
 
 /// Resolves additional completion data at the position given.
diff --git a/crates/ide-completion/src/render/variant.rs b/crates/ide-completion/src/render/variant.rs
index 2c9fb9b35a..39a37dc9f8 100644
--- a/crates/ide-completion/src/render/variant.rs
+++ b/crates/ide-completion/src/render/variant.rs
@@ -1,7 +1,7 @@
 //! Code common to structs, unions, and enum variants.
 
 use crate::context::CompletionContext;
-use hir::{db::HirDatabase, HasAttrs, HasCrate, HasVisibility, HirDisplay, StructKind};
+use hir::{db::HirDatabase, HasAttrs, HasVisibility, HirDisplay, StructKind};
 use ide_db::SnippetCap;
 use itertools::Itertools;
 use syntax::SmolStr;
@@ -70,7 +70,7 @@ pub(crate) fn render_tuple_lit(
 pub(crate) fn visible_fields(
     ctx: &CompletionContext,
     fields: &[hir::Field],
-    item: impl HasAttrs + HasCrate + Copy,
+    item: impl HasAttrs,
 ) -> Option<(Vec<hir::Field>, bool)> {
     let module = ctx.module;
     let n_fields = fields.len();
@@ -79,10 +79,9 @@ pub(crate) fn visible_fields(
         .filter(|field| field.is_visible_from(ctx.db, module))
         .copied()
         .collect::<Vec<_>>();
-    let has_invisible_field = n_fields - fields.len() > 0;
-    let is_foreign_non_exhaustive = item.attrs(ctx.db).by_key("non_exhaustive").exists()
-        && item.krate(ctx.db) != module.krate();
-    let fields_omitted = has_invisible_field || is_foreign_non_exhaustive;
+
+    let fields_omitted =
+        n_fields - fields.len() > 0 || item.attrs(ctx.db).by_key("non_exhaustive").exists();
     Some((fields, fields_omitted))
 }
 


Test patch:
diff --git a/crates/ide-completion/src/tests/pattern.rs b/crates/ide-completion/src/tests/pattern.rs
index 7169209d81..8953f1b2fd 100644
--- a/crates/ide-completion/src/tests/pattern.rs
+++ b/crates/ide-completion/src/tests/pattern.rs
@@ -399,6 +399,7 @@ fn foo() {
 
 #[test]
 fn completes_no_delims_if_existing() {
+    // FIXME: We should not complete functions here
     check_empty(
         r#"
 struct Bar(u32);
@@ -409,7 +410,9 @@ fn foo() {
 }
 "#,
         expect![[r#"
+            fn foo     fn()
             st Bar
+            bt u32
             kw crate::
             kw self::
             kw super::
@@ -425,7 +428,9 @@ fn foo() {
 }
 "#,
         expect![[r#"
+            fn foo     fn()
             st Foo
+            bt u32
             kw crate::
             kw self::
             kw super::
diff --git a/crates/ide-completion/src/tests/special.rs b/crates/ide-completion/src/tests/special.rs
index f1557107e0..4535923b28 100644
--- a/crates/ide-completion/src/tests/special.rs
+++ b/crates/ide-completion/src/tests/special.rs
@@ -540,46 +540,6 @@ impl Foo {
     );
 }
 
-#[test]
-fn completes_non_exhaustive_variant_within_the_defining_crate() {
-    check(
-        r#"
-enum Foo {
-    #[non_exhaustive]
-    Bar,
-    Baz,
-}
-
-fn foo(self) {
-    Foo::$0
-}
-"#,
-        expect![[r#"
-                ev Bar Bar
-                ev Baz Baz
-            "#]],
-    );
-
-    check(
-        r#"
-//- /main.rs crate:main deps:e
-fn foo(self) {
-    e::Foo::$0
-}
-
-//- /e.rs crate:e
-enum Foo {
-    #[non_exhaustive]
-    Bar,
-    Baz,
-}
-"#,
-        expect![[r#"
-                ev Baz Baz
-            "#]],
-    );
-}
-
 #[test]
 fn completes_primitive_assoc_const() {
     cov_mark::check!(completes_primitive_assoc_const);