about summary refs log tree commit diff
diff options
context:
space:
mode:
authorLukas Wirth <lukastw97@gmail.com>2022-05-05 22:21:42 +0200
committerLukas Wirth <lukastw97@gmail.com>2022-05-05 22:21:42 +0200
commit0c4e23b8ef80d3a2b590246e17272b91d252b979 (patch)
tree8cf979b1239398f04a1dd3ee89816a0f152be343
parent16d2e79b50d043d14e6f56bb22a088ebaa0fccaf (diff)
downloadrust-0c4e23b8ef80d3a2b590246e17272b91d252b979.tar.gz
rust-0c4e23b8ef80d3a2b590246e17272b91d252b979.zip
internal: Remove unqualified_path completions module
-rw-r--r--crates/hir/src/lib.rs2
-rw-r--r--crates/hir/src/semantics.rs8
-rw-r--r--crates/ide-assists/src/handlers/convert_iter_for_each_to_for.rs3
-rw-r--r--crates/ide-assists/src/handlers/generate_is_empty_from_len.rs12
-rw-r--r--crates/ide-completion/src/completions.rs1
-rw-r--r--crates/ide-completion/src/completions/dot.rs11
-rw-r--r--crates/ide-completion/src/completions/expr.rs145
-rw-r--r--crates/ide-completion/src/completions/pattern.rs3
-rw-r--r--crates/ide-completion/src/completions/qualified_path.rs670
-rw-r--r--crates/ide-completion/src/completions/type.rs155
-rw-r--r--crates/ide-completion/src/completions/use_.rs2
-rw-r--r--crates/ide-completion/src/context.rs31
-rw-r--r--crates/ide-completion/src/lib.rs1
-rw-r--r--crates/ide-completion/src/tests/special.rs455
-rw-r--r--crates/ide-ssr/src/resolving.rs2
15 files changed, 769 insertions, 732 deletions
diff --git a/crates/hir/src/lib.rs b/crates/hir/src/lib.rs
index c91fbce5eac..8b537a1d385 100644
--- a/crates/hir/src/lib.rs
+++ b/crates/hir/src/lib.rs
@@ -88,7 +88,7 @@ pub use crate::{
         UnresolvedModule, UnresolvedProcMacro,
     },
     has_source::HasSource,
-    semantics::{PathResolution, Semantics, SemanticsScope, TypeInfo},
+    semantics::{PathResolution, Semantics, SemanticsScope, TypeInfo, VisibleTraits},
 };
 
 // Be careful with these re-exports.
diff --git a/crates/hir/src/semantics.rs b/crates/hir/src/semantics.rs
index 8b565ef1fa5..d887dae99c1 100644
--- a/crates/hir/src/semantics.rs
+++ b/crates/hir/src/semantics.rs
@@ -1370,10 +1370,10 @@ impl<'a> SemanticsScope<'a> {
         &self.resolver
     }
 
-    /// Note: `FxHashSet<TraitId>` should be treated as an opaque type, passed into `Type
-    pub fn visible_traits(&self) -> FxHashSet<TraitId> {
+    /// Note: `VisibleTraits` should be treated as an opaque type, passed into `Type
+    pub fn visible_traits(&self) -> VisibleTraits {
         let resolver = &self.resolver;
-        resolver.traits_in_scope(self.db.upcast())
+        VisibleTraits(resolver.traits_in_scope(self.db.upcast()))
     }
 
     pub fn process_all_names(&self, f: &mut dyn FnMut(Name, ScopeDef)) {
@@ -1424,3 +1424,5 @@ impl<'a> SemanticsScope<'a> {
         )
     }
 }
+
+pub struct VisibleTraits(pub FxHashSet<TraitId>);
diff --git a/crates/ide-assists/src/handlers/convert_iter_for_each_to_for.rs b/crates/ide-assists/src/handlers/convert_iter_for_each_to_for.rs
index 711b9145610..82a67fb51db 100644
--- a/crates/ide-assists/src/handlers/convert_iter_for_each_to_for.rs
+++ b/crates/ide-assists/src/handlers/convert_iter_for_each_to_for.rs
@@ -148,14 +148,13 @@ fn is_ref_and_impls_iter_method(
     let ty = sema.type_of_expr(&expr_behind_ref)?.adjusted();
     let scope = sema.scope(iterable.syntax())?;
     let krate = scope.krate();
-    let traits_in_scope = scope.visible_traits();
     let iter_trait = FamousDefs(sema, krate).core_iter_Iterator()?;
 
     let has_wanted_method = ty
         .iterate_method_candidates(
             sema.db,
             &scope,
-            &traits_in_scope,
+            &scope.visible_traits().0,
             None,
             Some(&wanted_method),
             |func| {
diff --git a/crates/ide-assists/src/handlers/generate_is_empty_from_len.rs b/crates/ide-assists/src/handlers/generate_is_empty_from_len.rs
index 1ad1cea43fc..062b12a50bc 100644
--- a/crates/ide-assists/src/handlers/generate_is_empty_from_len.rs
+++ b/crates/ide-assists/src/handlers/generate_is_empty_from_len.rs
@@ -95,10 +95,14 @@ fn get_impl_method(
 
     let scope = ctx.sema.scope(impl_.syntax())?;
     let ty = impl_def.self_ty(db);
-    let traits_in_scope = scope.visible_traits();
-    ty.iterate_method_candidates(db, &scope, &traits_in_scope, None, Some(fn_name), |func| {
-        Some(func)
-    })
+    ty.iterate_method_candidates(
+        db,
+        &scope,
+        &scope.visible_traits().0,
+        None,
+        Some(fn_name),
+        |func| Some(func),
+    )
 }
 
 #[cfg(test)]
diff --git a/crates/ide-completion/src/completions.rs b/crates/ide-completion/src/completions.rs
index b22124cc695..687a598bacc 100644
--- a/crates/ide-completion/src/completions.rs
+++ b/crates/ide-completion/src/completions.rs
@@ -13,7 +13,6 @@ pub(crate) mod lifetime;
 pub(crate) mod mod_;
 pub(crate) mod pattern;
 pub(crate) mod postfix;
-pub(crate) mod qualified_path;
 pub(crate) mod record;
 pub(crate) mod snippet;
 pub(crate) mod trait_impl;
diff --git a/crates/ide-completion/src/completions/dot.rs b/crates/ide-completion/src/completions/dot.rs
index 01a5f856c1b..8cd09a4c0e7 100644
--- a/crates/ide-completion/src/completions/dot.rs
+++ b/crates/ide-completion/src/completions/dot.rs
@@ -78,18 +78,10 @@ fn complete_methods(
     mut f: impl FnMut(hir::Function),
 ) {
     let mut seen_methods = FxHashSet::default();
-    let mut traits_in_scope = ctx.scope.visible_traits();
-
-    // Remove drop from the environment as calling `Drop::drop` is not allowed
-    if let Some(drop_trait) = ctx.famous_defs().core_ops_Drop() {
-        cov_mark::hit!(dot_remove_drop_trait);
-        traits_in_scope.remove(&drop_trait.into());
-    }
-
     receiver.iterate_method_candidates(
         ctx.db,
         &ctx.scope,
-        &traits_in_scope,
+        &ctx.traits_in_scope().0,
         Some(ctx.module),
         None,
         |func| {
@@ -758,7 +750,6 @@ fn main() {
 
     #[test]
     fn postfix_drop_completion() {
-        cov_mark::check!(dot_remove_drop_trait);
         cov_mark::check!(postfix_drop_completion);
         check_edit(
             "drop",
diff --git a/crates/ide-completion/src/completions/expr.rs b/crates/ide-completion/src/completions/expr.rs
index f9717f1c2c1..fb9955c5e8c 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::{PathCompletionCtx, PathKind, PathQualifierCtx},
@@ -20,8 +21,129 @@ pub(crate) fn complete_expr_path(acc: &mut Completions, ctx: &CompletionContext)
         _ => return,
     };
 
+    let scope_def_applicable = |def| {
+        use hir::{GenericParam::*, ModuleDef::*};
+        match def {
+            ScopeDef::GenericParam(LifetimeParam(_)) | ScopeDef::Label(_) => false,
+            // Don't suggest attribute macros and derives.
+            ScopeDef::ModuleDef(Macro(mac)) => mac.is_fn_like(ctx.db),
+            _ => true,
+        }
+    };
+
     match qualifier {
-        Some(PathQualifierCtx { .. }) => return,
+        Some(PathQualifierCtx { is_infer_qualifier, resolution, .. }) => {
+            if *is_infer_qualifier {
+                ctx.traits_in_scope()
+                    .0
+                    .into_iter()
+                    .flat_map(|it| hir::Trait::from(it).items(ctx.sema.db))
+                    .for_each(|item| add_assoc_item(acc, ctx, item));
+                return;
+            }
+            let resolution = match resolution {
+                Some(it) => it,
+                None => return,
+            };
+            // Add associated types on type parameters and `Self`.
+            ctx.scope.assoc_type_shorthand_candidates(resolution, |_, alias| {
+                acc.add_type_alias(ctx, alias);
+                None::<()>
+            });
+            match resolution {
+                hir::PathResolution::Def(hir::ModuleDef::Module(module)) => {
+                    let module_scope = module.scope(ctx.db, Some(ctx.module));
+                    for (name, def) in module_scope {
+                        if scope_def_applicable(def) {
+                            acc.add_resolution(ctx, name, def);
+                        }
+                    }
+                }
+
+                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, e);
+                    }
+                    let ty = match def {
+                        hir::ModuleDef::Adt(adt) => adt.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, e);
+                            }
+                            ty
+                        }
+                        hir::ModuleDef::BuiltinType(builtin) => {
+                            cov_mark::hit!(completes_primitive_assoc_const);
+                            builtin.ty(ctx.db)
+                        }
+                        _ => unreachable!(),
+                    };
+
+                    // XXX: For parity with Rust bug #22519, this does not complete Ty::AssocType.
+                    // (where AssocType is defined on a trait, not an inherent impl)
+
+                    ty.iterate_path_candidates(
+                        ctx.db,
+                        &ctx.scope,
+                        &ctx.traits_in_scope().0,
+                        Some(ctx.module),
+                        None,
+                        |item| {
+                            add_assoc_item(acc, ctx, item);
+                            None::<()>
+                        },
+                    );
+
+                    // Iterate assoc types separately
+                    ty.iterate_assoc_items(ctx.db, ctx.krate, |item| {
+                        if let hir::AssocItem::TypeAlias(ty) = item {
+                            acc.add_type_alias(ctx, ty)
+                        }
+                        None::<()>
+                    });
+                }
+                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, ctx, item);
+                    }
+                }
+                hir::PathResolution::TypeParam(_) | hir::PathResolution::SelfType(_) => {
+                    let ty = match resolution {
+                        hir::PathResolution::TypeParam(param) => param.ty(ctx.db),
+                        hir::PathResolution::SelfType(impl_def) => impl_def.self_ty(ctx.db),
+                        _ => return,
+                    };
+
+                    if let Some(hir::Adt::Enum(e)) = ty.as_adt() {
+                        add_enum_variants(acc, ctx, e);
+                    }
+                    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, item);
+                            }
+                            None::<()>
+                        },
+                    );
+                }
+                _ => (),
+            }
+        }
         None if is_absolute_path => acc.add_crate_roots(ctx),
         None => {
             acc.add_nameref_keywords_with_colon(ctx);
@@ -33,17 +155,22 @@ pub(crate) fn complete_expr_path(acc: &mut Completions, ctx: &CompletionContext)
                 });
             }
             ctx.process_all_names(&mut |name, def| {
-                use hir::{GenericParam::*, ModuleDef::*};
-                let add_resolution = match def {
-                    ScopeDef::GenericParam(LifetimeParam(_)) | ScopeDef::Label(_) => false,
-                    // Don't suggest attribute macros and derives.
-                    ScopeDef::ModuleDef(Macro(mac)) => mac.is_fn_like(ctx.db),
-                    _ => true,
-                };
-                if add_resolution {
+                if scope_def_applicable(def) {
                     acc.add_resolution(ctx, name, def);
                 }
             });
         }
     }
 }
+
+fn add_assoc_item(acc: &mut Completions, ctx: &CompletionContext, item: hir::AssocItem) {
+    match item {
+        hir::AssocItem::Function(func) => acc.add_function(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, e: hir::Enum) {
+    e.variants(ctx.db).into_iter().for_each(|variant| acc.add_enum_variant(ctx, variant, None));
+}
diff --git a/crates/ide-completion/src/completions/pattern.rs b/crates/ide-completion/src/completions/pattern.rs
index a761eeebb2f..963ee309590 100644
--- a/crates/ide-completion/src/completions/pattern.rs
+++ b/crates/ide-completion/src/completions/pattern.rs
@@ -163,12 +163,11 @@ fn pattern_path_completion(
                         _ => return,
                     };
 
-                    let traits_in_scope = ctx.scope.visible_traits();
                     let mut seen = FxHashSet::default();
                     ty.iterate_path_candidates(
                         ctx.db,
                         &ctx.scope,
-                        &traits_in_scope,
+                        &ctx.scope.visible_traits().0,
                         Some(ctx.module),
                         None,
                         |item| {
diff --git a/crates/ide-completion/src/completions/qualified_path.rs b/crates/ide-completion/src/completions/qualified_path.rs
deleted file mode 100644
index d12f8490bd1..00000000000
--- a/crates/ide-completion/src/completions/qualified_path.rs
+++ /dev/null
@@ -1,670 +0,0 @@
-//! Completion of paths, i.e. `some::prefix::$0`.
-
-use hir::{ScopeDef, Trait};
-use ide_db::FxHashSet;
-use syntax::ast;
-
-use crate::{
-    context::{PathCompletionCtx, PathKind},
-    CompletionContext, Completions,
-};
-
-pub(crate) fn complete_qualified_path(acc: &mut Completions, ctx: &CompletionContext) {
-    if ctx.is_path_disallowed() || ctx.has_unfinished_impl_or_trait_prev_sibling() {
-        return;
-    }
-    if ctx.pattern_ctx.is_some() {
-        return;
-    }
-    let (qualifier, kind) = match ctx.path_context {
-        // let ... else, syntax would come in really handy here right now
-        Some(PathCompletionCtx { qualifier: Some(ref qualifier), kind, .. }) => (qualifier, kind),
-        _ => return,
-    };
-    let traits_in_scope = |ctx: &CompletionContext| {
-        let mut traits_in_scope = ctx.scope.visible_traits();
-        if let Some(drop) = ctx.famous_defs().core_ops_Drop() {
-            traits_in_scope.remove(&drop.into());
-        }
-        traits_in_scope
-    };
-
-    // special case `<_>::$0` as this doesn't resolve to anything.
-    if qualifier.path.qualifier().is_none() {
-        if matches!(
-            qualifier.path.segment().and_then(|it| it.kind()),
-            Some(ast::PathSegmentKind::Type {
-                type_ref: Some(ast::Type::InferType(_)),
-                trait_ref: None,
-            })
-        ) {
-            cov_mark::hit!(completion_type_anchor_empty);
-            traits_in_scope(ctx)
-                .into_iter()
-                .flat_map(|it| Trait::from(it).items(ctx.sema.db))
-                .for_each(|item| add_assoc_item(acc, ctx, item));
-            return;
-        }
-    }
-
-    let resolution = match &qualifier.resolution {
-        Some(res) => res,
-        None => return,
-    };
-
-    match kind {
-        Some(
-            PathKind::Pat
-            | PathKind::Attr { .. }
-            | PathKind::Vis { .. }
-            | PathKind::Use
-            | PathKind::Item
-            | PathKind::Derive,
-        ) => {
-            return;
-        }
-        _ => {
-            // Add associated types on type parameters and `Self`.
-            ctx.scope.assoc_type_shorthand_candidates(resolution, |_, alias| {
-                acc.add_type_alias(ctx, alias);
-                None::<()>
-            });
-        }
-    }
-
-    match resolution {
-        hir::PathResolution::Def(hir::ModuleDef::Module(module)) => {
-            let module_scope = module.scope(ctx.db, Some(ctx.module));
-            for (name, def) in module_scope {
-                let add_resolution = match def {
-                    // Don't suggest attribute macros and derives.
-                    ScopeDef::ModuleDef(hir::ModuleDef::Macro(mac)) => mac.is_fn_like(ctx.db),
-                    // no values in type places
-                    ScopeDef::ModuleDef(
-                        hir::ModuleDef::Function(_)
-                        | hir::ModuleDef::Variant(_)
-                        | hir::ModuleDef::Static(_),
-                    )
-                    | ScopeDef::Local(_) => !ctx.expects_type(),
-                    // unless its a constant in a generic arg list position
-                    ScopeDef::ModuleDef(hir::ModuleDef::Const(_)) => {
-                        !ctx.expects_type() || ctx.expects_generic_arg()
-                    }
-                    _ => true,
-                };
-
-                if add_resolution {
-                    acc.add_resolution(ctx, name, def);
-                }
-            }
-        }
-        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, e);
-            }
-            let ty = match def {
-                hir::ModuleDef::Adt(adt) => adt.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, e);
-                    }
-                    ty
-                }
-                hir::ModuleDef::BuiltinType(builtin) => {
-                    cov_mark::hit!(completes_primitive_assoc_const);
-                    builtin.ty(ctx.db)
-                }
-                _ => unreachable!(),
-            };
-
-            // XXX: For parity with Rust bug #22519, this does not complete Ty::AssocType.
-            // (where AssocType is defined on a trait, not an inherent impl)
-
-            let traits_in_scope = traits_in_scope(ctx);
-            ty.iterate_path_candidates(
-                ctx.db,
-                &ctx.scope,
-                &traits_in_scope,
-                Some(ctx.module),
-                None,
-                |item| {
-                    add_assoc_item(acc, ctx, item);
-                    None::<()>
-                },
-            );
-
-            // Iterate assoc types separately
-            ty.iterate_assoc_items(ctx.db, ctx.krate, |item| {
-                if let hir::AssocItem::TypeAlias(ty) = item {
-                    acc.add_type_alias(ctx, ty)
-                }
-                None::<()>
-            });
-        }
-        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, ctx, item);
-            }
-        }
-        hir::PathResolution::TypeParam(_) | hir::PathResolution::SelfType(_) => {
-            let ty = match resolution {
-                hir::PathResolution::TypeParam(param) => param.ty(ctx.db),
-                hir::PathResolution::SelfType(impl_def) => impl_def.self_ty(ctx.db),
-                _ => return,
-            };
-
-            if let Some(hir::Adt::Enum(e)) = ty.as_adt() {
-                add_enum_variants(acc, ctx, e);
-            }
-            let traits_in_scope = traits_in_scope(ctx);
-            let mut seen = FxHashSet::default();
-            ty.iterate_path_candidates(
-                ctx.db,
-                &ctx.scope,
-                &traits_in_scope,
-                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, item);
-                    }
-                    None::<()>
-                },
-            );
-        }
-        _ => {}
-    }
-}
-
-fn add_assoc_item(acc: &mut Completions, ctx: &CompletionContext, item: hir::AssocItem) {
-    match item {
-        hir::AssocItem::Function(func) if !ctx.expects_type() => acc.add_function(ctx, func, None),
-        hir::AssocItem::Const(ct) if !ctx.expects_type() || ctx.expects_generic_arg() => {
-            acc.add_const(ctx, ct)
-        }
-        hir::AssocItem::TypeAlias(ty) => acc.add_type_alias(ctx, ty),
-        _ => (),
-    }
-}
-
-fn add_enum_variants(acc: &mut Completions, ctx: &CompletionContext, e: hir::Enum) {
-    if ctx.expects_type() {
-        return;
-    }
-    e.variants(ctx.db).into_iter().for_each(|variant| acc.add_enum_variant(ctx, variant, None));
-}
-
-#[cfg(test)]
-mod tests {
-    use expect_test::{expect, Expect};
-
-    use crate::tests::{check_edit, completion_list_no_kw};
-
-    fn check(ra_fixture: &str, expect: Expect) {
-        let actual = completion_list_no_kw(ra_fixture);
-        expect.assert_eq(&actual);
-    }
-
-    #[test]
-    fn associated_item_visibility() {
-        check(
-            r#"
-//- /lib.rs crate:lib new_source_root:library
-pub struct S;
-
-impl S {
-    pub fn public_method() { }
-    fn private_method() { }
-    pub type PublicType = u32;
-    type PrivateType = u32;
-    pub const PUBLIC_CONST: u32 = 1;
-    const PRIVATE_CONST: u32 = 1;
-}
-
-//- /main.rs crate:main deps:lib new_source_root:local
-fn foo() { let _ = lib::S::$0 }
-"#,
-            expect![[r#"
-                ct PUBLIC_CONST    pub const PUBLIC_CONST: u32
-                fn public_method() fn()
-                ta PublicType      pub type PublicType = u32
-            "#]],
-        );
-    }
-
-    #[test]
-    fn completes_union_associated_method() {
-        check(
-            r#"
-union U {};
-impl U { fn m() { } }
-
-fn foo() { let _ = U::$0 }
-"#,
-            expect![[r#"
-                fn m() fn()
-            "#]],
-        );
-    }
-
-    #[test]
-    fn completes_trait_associated_method_1() {
-        check(
-            r#"
-trait Trait { fn m(); }
-
-fn foo() { let _ = Trait::$0 }
-"#,
-            expect![[r#"
-                fn m() (as Trait) fn()
-            "#]],
-        );
-    }
-
-    #[test]
-    fn completes_trait_associated_method_2() {
-        check(
-            r#"
-trait Trait { fn m(); }
-
-struct S;
-impl Trait for S {}
-
-fn foo() { let _ = S::$0 }
-"#,
-            expect![[r#"
-                fn m() (as Trait) fn()
-            "#]],
-        );
-    }
-
-    #[test]
-    fn completes_trait_associated_method_3() {
-        check(
-            r#"
-trait Trait { fn m(); }
-
-struct S;
-impl Trait for S {}
-
-fn foo() { let _ = <S as Trait>::$0 }
-"#,
-            expect![[r#"
-                fn m() (as Trait) fn()
-            "#]],
-        );
-    }
-
-    #[test]
-    fn completes_ty_param_assoc_ty() {
-        check(
-            r#"
-trait Super {
-    type Ty;
-    const CONST: u8;
-    fn func() {}
-    fn method(&self) {}
-}
-
-trait Sub: Super {
-    type SubTy;
-    const C2: ();
-    fn subfunc() {}
-    fn submethod(&self) {}
-}
-
-fn foo<T: Sub>() { T::$0 }
-"#,
-            expect![[r#"
-                ct C2 (as Sub)           const C2: ()
-                ct CONST (as Super)      const CONST: u8
-                fn func() (as Super)     fn()
-                fn subfunc() (as Sub)    fn()
-                ta SubTy (as Sub)        type SubTy
-                ta Ty (as Super)         type Ty
-                me method(…) (as Super)  fn(&self)
-                me submethod(…) (as Sub) fn(&self)
-            "#]],
-        );
-    }
-
-    #[test]
-    fn completes_self_param_assoc_ty() {
-        check(
-            r#"
-trait Super {
-    type Ty;
-    const CONST: u8 = 0;
-    fn func() {}
-    fn method(&self) {}
-}
-
-trait Sub: Super {
-    type SubTy;
-    const C2: () = ();
-    fn subfunc() {}
-    fn submethod(&self) {}
-}
-
-struct Wrap<T>(T);
-impl<T> Super for Wrap<T> {}
-impl<T> Sub for Wrap<T> {
-    fn subfunc() {
-        // Should be able to assume `Self: Sub + Super`
-        Self::$0
-    }
-}
-"#,
-            expect![[r#"
-                ct C2 (as Sub)           const C2: ()
-                ct CONST (as Super)      const CONST: u8
-                fn func() (as Super)     fn()
-                fn subfunc() (as Sub)    fn()
-                ta SubTy (as Sub)        type SubTy
-                ta Ty (as Super)         type Ty
-                me method(…) (as Super)  fn(&self)
-                me submethod(…) (as Sub) fn(&self)
-            "#]],
-        );
-    }
-
-    #[test]
-    fn completes_type_alias() {
-        check(
-            r#"
-struct S;
-impl S { fn foo() {} }
-type T = S;
-impl T { fn bar() {} }
-
-fn main() { T::$0; }
-"#,
-            expect![[r#"
-                fn bar() fn()
-                fn foo() fn()
-            "#]],
-        );
-    }
-
-    #[test]
-    fn completes_qualified_macros() {
-        check(
-            r#"
-#[macro_export]
-macro_rules! foo { () => {} }
-
-fn main() { let _ = crate::$0 }
-"#,
-            expect![[r#"
-                fn main()  fn()
-                ma foo!(…) macro_rules! foo
-            "#]],
-        );
-    }
-
-    #[test]
-    fn does_not_complete_non_fn_macros() {
-        check(
-            r#"
-mod m {
-    #[rustc_builtin_macro]
-    pub macro Clone {}
-}
-
-fn f() {m::$0}
-"#,
-            expect![[r#""#]],
-        );
-        check(
-            r#"
-mod m {
-    #[rustc_builtin_macro]
-    pub macro bench {}
-}
-
-fn f() {m::$0}
-"#,
-            expect![[r#""#]],
-        );
-    }
-
-    #[test]
-    fn completes_reexported_items_under_correct_name() {
-        check(
-            r#"
-fn foo() { self::m::$0 }
-
-mod m {
-    pub use super::p::wrong_fn as right_fn;
-    pub use super::p::WRONG_CONST as RIGHT_CONST;
-    pub use super::p::WrongType as RightType;
-}
-mod p {
-    fn wrong_fn() {}
-    const WRONG_CONST: u32 = 1;
-    struct WrongType {};
-}
-"#,
-            expect![[r#"
-                ct RIGHT_CONST
-                fn right_fn()  fn()
-                st RightType
-            "#]],
-        );
-
-        check_edit(
-            "RightType",
-            r#"
-fn foo() { self::m::$0 }
-
-mod m {
-    pub use super::p::wrong_fn as right_fn;
-    pub use super::p::WRONG_CONST as RIGHT_CONST;
-    pub use super::p::WrongType as RightType;
-}
-mod p {
-    fn wrong_fn() {}
-    const WRONG_CONST: u32 = 1;
-    struct WrongType {};
-}
-"#,
-            r#"
-fn foo() { self::m::RightType }
-
-mod m {
-    pub use super::p::wrong_fn as right_fn;
-    pub use super::p::WRONG_CONST as RIGHT_CONST;
-    pub use super::p::WrongType as RightType;
-}
-mod p {
-    fn wrong_fn() {}
-    const WRONG_CONST: u32 = 1;
-    struct WrongType {};
-}
-"#,
-        );
-    }
-
-    #[test]
-    fn completes_in_simple_macro_call() {
-        check(
-            r#"
-macro_rules! m { ($e:expr) => { $e } }
-fn main() { m!(self::f$0); }
-fn foo() {}
-"#,
-            expect![[r#"
-                fn foo()  fn()
-                fn main() fn()
-            "#]],
-        );
-    }
-
-    #[test]
-    fn function_mod_share_name() {
-        check(
-            r#"
-fn foo() { self::m::$0 }
-
-mod m {
-    pub mod z {}
-    pub fn z() {}
-}
-"#,
-            expect![[r#"
-                fn z() fn()
-                md z
-            "#]],
-        );
-    }
-
-    #[test]
-    fn completes_hashmap_new() {
-        check(
-            r#"
-struct RandomState;
-struct HashMap<K, V, S = RandomState> {}
-
-impl<K, V> HashMap<K, V, RandomState> {
-    pub fn new() -> HashMap<K, V, RandomState> { }
-}
-fn foo() {
-    HashMap::$0
-}
-"#,
-            expect![[r#"
-                fn new() fn() -> HashMap<K, V, RandomState>
-            "#]],
-        );
-    }
-
-    #[test]
-    fn completes_variant_through_self() {
-        check(
-            r#"
-enum Foo {
-    Bar,
-    Baz,
-}
-
-impl Foo {
-    fn foo(self) {
-        Self::$0
-    }
-}
-"#,
-            expect![[r#"
-                ev Bar    Bar
-                ev Baz    Baz
-                me foo(…) fn(self)
-            "#]],
-        );
-    }
-
-    #[test]
-    fn completes_primitive_assoc_const() {
-        cov_mark::check!(completes_primitive_assoc_const);
-        check(
-            r#"
-//- /lib.rs crate:lib deps:core
-fn f() {
-    u8::$0
-}
-
-//- /core.rs crate:core
-#[lang = "u8"]
-impl u8 {
-    pub const MAX: Self = 255;
-
-    pub fn func(self) {}
-}
-"#,
-            expect![[r#"
-                ct MAX     pub const MAX: Self
-                me func(…) fn(self)
-            "#]],
-        );
-    }
-
-    #[test]
-    fn completes_variant_through_alias() {
-        cov_mark::check!(completes_variant_through_alias);
-        check(
-            r#"
-enum Foo {
-    Bar
-}
-type Foo2 = Foo;
-fn main() {
-    Foo2::$0
-}
-"#,
-            expect![[r#"
-                ev Bar Bar
-            "#]],
-        );
-    }
-
-    #[test]
-    fn respects_doc_hidden() {
-        cov_mark::check!(qualified_path_doc_hidden);
-        check(
-            r#"
-//- /lib.rs crate:lib deps:dep
-fn f() {
-    dep::$0
-}
-
-//- /dep.rs crate:dep
-#[doc(hidden)]
-#[macro_export]
-macro_rules! m {
-    () => {}
-}
-
-#[doc(hidden)]
-pub fn f() {}
-
-#[doc(hidden)]
-pub struct S;
-
-#[doc(hidden)]
-pub mod m {}
-            "#,
-            expect![[r#""#]],
-        )
-    }
-
-    #[test]
-    fn type_anchor_empty() {
-        cov_mark::check!(completion_type_anchor_empty);
-        check(
-            r#"
-trait Foo {
-    fn foo() -> Self;
-}
-struct Bar;
-impl Foo for Bar {
-    fn foo() -> {
-        Bar
-    }
-}
-fn bar() -> Bar {
-    <_>::$0
-}
-"#,
-            expect![[r#"
-                fn foo() (as Foo) fn() -> Self
-            "#]],
-        )
-    }
-}
diff --git a/crates/ide-completion/src/completions/type.rs b/crates/ide-completion/src/completions/type.rs
index 4d0e2fb59ac..64c3bd3fdf1 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::ScopeDef;
+use ide_db::FxHashSet;
 use syntax::{ast, AstNode};
 
 use crate::{
@@ -22,8 +23,126 @@ pub(crate) fn complete_type_path(acc: &mut Completions, ctx: &CompletionContext)
         _ => return,
     };
 
+    let scope_def_applicable = |def| {
+        use hir::{GenericParam::*, ModuleDef::*};
+        match def {
+            ScopeDef::GenericParam(LifetimeParam(_)) | ScopeDef::Label(_) => false,
+            // no values in type places
+            ScopeDef::ModuleDef(Function(_) | Variant(_) | Static(_)) | ScopeDef::Local(_) => false,
+            // unless its a constant in a generic arg list position
+            ScopeDef::ModuleDef(Const(_)) | ScopeDef::GenericParam(ConstParam(_)) => {
+                ctx.expects_generic_arg()
+            }
+            ScopeDef::ImplSelfType(_) => {
+                !ctx.previous_token_is(syntax::T![impl]) && !ctx.previous_token_is(syntax::T![for])
+            }
+            // Don't suggest attribute macros and derives.
+            ScopeDef::ModuleDef(Macro(mac)) => mac.is_fn_like(ctx.db),
+            // Type things are fine
+            ScopeDef::ModuleDef(BuiltinType(_) | Adt(_) | Module(_) | Trait(_) | TypeAlias(_))
+            | ScopeDef::AdtSelfType(_)
+            | ScopeDef::Unknown
+            | ScopeDef::GenericParam(TypeParam(_)) => true,
+        }
+    };
+
     match qualifier {
-        Some(PathQualifierCtx { .. }) => return,
+        Some(PathQualifierCtx { is_infer_qualifier, resolution, .. }) => {
+            if *is_infer_qualifier {
+                ctx.traits_in_scope()
+                    .0
+                    .into_iter()
+                    .flat_map(|it| hir::Trait::from(it).items(ctx.sema.db))
+                    .for_each(|item| add_assoc_item(acc, ctx, item));
+                return;
+            }
+            let resolution = match resolution {
+                Some(it) => it,
+                None => return,
+            };
+            // Add associated types on type parameters and `Self`.
+            ctx.scope.assoc_type_shorthand_candidates(resolution, |_, alias| {
+                acc.add_type_alias(ctx, alias);
+                None::<()>
+            });
+
+            match resolution {
+                hir::PathResolution::Def(hir::ModuleDef::Module(module)) => {
+                    let module_scope = module.scope(ctx.db, Some(ctx.module));
+                    for (name, def) in module_scope {
+                        if scope_def_applicable(def) {
+                            acc.add_resolution(ctx, name, def);
+                        }
+                    }
+                }
+                hir::PathResolution::Def(
+                    def @ (hir::ModuleDef::Adt(_)
+                    | hir::ModuleDef::TypeAlias(_)
+                    | hir::ModuleDef::BuiltinType(_)),
+                ) => {
+                    let ty = match def {
+                        hir::ModuleDef::Adt(adt) => adt.ty(ctx.db),
+                        hir::ModuleDef::TypeAlias(a) => a.ty(ctx.db),
+                        hir::ModuleDef::BuiltinType(builtin) => builtin.ty(ctx.db),
+                        _ => unreachable!(),
+                    };
+
+                    // XXX: For parity with Rust bug #22519, this does not complete Ty::AssocType.
+                    // (where AssocType is defined on a trait, not an inherent impl)
+
+                    ty.iterate_path_candidates(
+                        ctx.db,
+                        &ctx.scope,
+                        &ctx.traits_in_scope().0,
+                        Some(ctx.module),
+                        None,
+                        |item| {
+                            add_assoc_item(acc, ctx, item);
+                            None::<()>
+                        },
+                    );
+
+                    // Iterate assoc types separately
+                    ty.iterate_assoc_items(ctx.db, ctx.krate, |item| {
+                        if let hir::AssocItem::TypeAlias(ty) = item {
+                            acc.add_type_alias(ctx, ty)
+                        }
+                        None::<()>
+                    });
+                }
+                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, ctx, item);
+                    }
+                }
+                hir::PathResolution::TypeParam(_) | hir::PathResolution::SelfType(_) => {
+                    let ty = match resolution {
+                        hir::PathResolution::TypeParam(param) => param.ty(ctx.db),
+                        hir::PathResolution::SelfType(impl_def) => impl_def.self_ty(ctx.db),
+                        _ => return,
+                    };
+
+                    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, item);
+                            }
+                            None::<()>
+                        },
+                    );
+                }
+                _ => (),
+            }
+        }
         None if is_absolute_path => acc.add_crate_roots(ctx),
         None => {
             acc.add_nameref_keywords_with_colon(ctx);
@@ -57,34 +176,18 @@ pub(crate) fn complete_type_path(acc: &mut Completions, ctx: &CompletionContext)
                 }
             }
             ctx.process_all_names(&mut |name, def| {
-                use hir::{GenericParam::*, ModuleDef::*};
-                let add_resolution = match def {
-                    ScopeDef::GenericParam(LifetimeParam(_)) | ScopeDef::Label(_) => false,
-                    // no values in type places
-                    ScopeDef::ModuleDef(Function(_) | Variant(_) | Static(_))
-                    | ScopeDef::Local(_) => false,
-                    // unless its a constant in a generic arg list position
-                    ScopeDef::ModuleDef(Const(_)) | ScopeDef::GenericParam(ConstParam(_)) => {
-                        ctx.expects_generic_arg()
-                    }
-                    ScopeDef::ImplSelfType(_) => {
-                        !ctx.previous_token_is(syntax::T![impl])
-                            && !ctx.previous_token_is(syntax::T![for])
-                    }
-                    // Don't suggest attribute macros and derives.
-                    ScopeDef::ModuleDef(Macro(mac)) => mac.is_fn_like(ctx.db),
-                    // Type things are fine
-                    ScopeDef::ModuleDef(
-                        BuiltinType(_) | Adt(_) | Module(_) | Trait(_) | TypeAlias(_),
-                    )
-                    | ScopeDef::AdtSelfType(_)
-                    | ScopeDef::Unknown
-                    | ScopeDef::GenericParam(TypeParam(_)) => true,
-                };
-                if add_resolution {
+                if scope_def_applicable(def) {
                     acc.add_resolution(ctx, name, def);
                 }
             });
         }
     }
 }
+
+fn add_assoc_item(acc: &mut Completions, ctx: &CompletionContext, item: hir::AssocItem) {
+    match item {
+        hir::AssocItem::Const(ct) if ctx.expects_generic_arg() => acc.add_const(ctx, ct),
+        hir::AssocItem::Function(_) | hir::AssocItem::Const(_) => (),
+        hir::AssocItem::TypeAlias(ty) => acc.add_type_alias(ctx, ty),
+    }
+}
diff --git a/crates/ide-completion/src/completions/use_.rs b/crates/ide-completion/src/completions/use_.rs
index 25eb3fb908c..fd6d7709a0e 100644
--- a/crates/ide-completion/src/completions/use_.rs
+++ b/crates/ide-completion/src/completions/use_.rs
@@ -19,7 +19,7 @@ pub(crate) fn complete_use_tree(acc: &mut Completions, ctx: &CompletionContext)
     };
 
     match qualifier {
-        Some(PathQualifierCtx { path, resolution, is_super_chain, use_tree_parent }) => {
+        Some(PathQualifierCtx { path, resolution, is_super_chain, use_tree_parent, .. }) => {
             if *is_super_chain {
                 acc.add_keyword(ctx, "super::");
             }
diff --git a/crates/ide-completion/src/context.rs b/crates/ide-completion/src/context.rs
index 87677e28e85..c4de8dc52e1 100644
--- a/crates/ide-completion/src/context.rs
+++ b/crates/ide-completion/src/context.rs
@@ -75,6 +75,7 @@ pub(crate) struct PathCompletionCtx {
     // FIXME: use this
     /// The parent of the path we are completing.
     pub(super) parent: Option<ast::Path>,
+    // FIXME: This should be PathKind, the none case should never occur
     pub(super) kind: Option<PathKind>,
     /// Whether the path segment has type args or not.
     pub(super) has_type_args: bool,
@@ -91,6 +92,8 @@ pub(crate) struct PathQualifierCtx {
     pub(crate) is_super_chain: bool,
     /// Whether the qualifier comes from a use tree parent or not
     pub(crate) use_tree_parent: bool,
+    /// <_>
+    pub(crate) is_infer_qualifier: bool,
 }
 
 #[derive(Debug)]
@@ -378,6 +381,15 @@ impl<'a> CompletionContext<'a> {
         }
     }
 
+    /// Returns the traits in scope, with the [`Drop`] trait removed.
+    pub(crate) fn traits_in_scope(&self) -> hir::VisibleTraits {
+        let mut traits_in_scope = self.scope.visible_traits();
+        if let Some(drop) = self.famous_defs().core_ops_Drop() {
+            traits_in_scope.0.remove(&drop.into());
+        }
+        traits_in_scope
+    }
+
     /// 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");
@@ -1046,7 +1058,24 @@ impl<'a> CompletionContext<'a> {
                 let res = sema.resolve_path(&path);
                 let is_super_chain = iter::successors(Some(path.clone()), |p| p.qualifier())
                     .all(|p| p.segment().and_then(|s| s.super_token()).is_some());
-                PathQualifierCtx { path, resolution: res, is_super_chain, use_tree_parent }
+
+                // `<_>::$0`
+                let is_infer_qualifier = path.qualifier().is_none()
+                    && matches!(
+                        path.segment().and_then(|it| it.kind()),
+                        Some(ast::PathSegmentKind::Type {
+                            type_ref: Some(ast::Type::InferType(_)),
+                            trait_ref: None,
+                        })
+                    );
+
+                PathQualifierCtx {
+                    path,
+                    resolution: res,
+                    is_super_chain,
+                    use_tree_parent,
+                    is_infer_qualifier,
+                }
             });
             return Some((path_ctx, pat_ctx));
         }
diff --git a/crates/ide-completion/src/lib.rs b/crates/ide-completion/src/lib.rs
index 3a0bd042daf..bc18e80516c 100644
--- a/crates/ide-completion/src/lib.rs
+++ b/crates/ide-completion/src/lib.rs
@@ -166,7 +166,6 @@ pub fn completions(
         completions::mod_::complete_mod(acc, ctx);
         completions::pattern::complete_pattern(acc, ctx);
         completions::postfix::complete_postfix(acc, ctx);
-        completions::qualified_path::complete_qualified_path(acc, ctx);
         completions::record::complete_record_literal(acc, ctx);
         completions::record::complete_record(acc, ctx);
         completions::snippet::complete_expr_snippet(acc, ctx);
diff --git a/crates/ide-completion/src/tests/special.rs b/crates/ide-completion/src/tests/special.rs
index 79235e5ca01..6195537a18e 100644
--- a/crates/ide-completion/src/tests/special.rs
+++ b/crates/ide-completion/src/tests/special.rs
@@ -1,3 +1,5 @@
+//! Tests that don't fit into a specific category.
+
 use expect_test::{expect, Expect};
 
 use crate::tests::{check_edit, completion_list_no_kw};
@@ -181,3 +183,456 @@ pub mod prelude {
             "#]],
     );
 }
+
+#[test]
+fn associated_item_visibility() {
+    check(
+        r#"
+//- /lib.rs crate:lib new_source_root:library
+pub struct S;
+
+impl S {
+    pub fn public_method() { }
+    fn private_method() { }
+    pub type PublicType = u32;
+    type PrivateType = u32;
+    pub const PUBLIC_CONST: u32 = 1;
+    const PRIVATE_CONST: u32 = 1;
+}
+
+//- /main.rs crate:main deps:lib new_source_root:local
+fn foo() { let _ = lib::S::$0 }
+"#,
+        expect![[r#"
+                ct PUBLIC_CONST    pub const PUBLIC_CONST: u32
+                fn public_method() fn()
+                ta PublicType      pub type PublicType = u32
+            "#]],
+    );
+}
+
+#[test]
+fn completes_union_associated_method() {
+    check(
+        r#"
+union U {};
+impl U { fn m() { } }
+
+fn foo() { let _ = U::$0 }
+"#,
+        expect![[r#"
+                fn m() fn()
+            "#]],
+    );
+}
+
+#[test]
+fn completes_trait_associated_method_1() {
+    check(
+        r#"
+trait Trait { fn m(); }
+
+fn foo() { let _ = Trait::$0 }
+"#,
+        expect![[r#"
+                fn m() (as Trait) fn()
+            "#]],
+    );
+}
+
+#[test]
+fn completes_trait_associated_method_2() {
+    check(
+        r#"
+trait Trait { fn m(); }
+
+struct S;
+impl Trait for S {}
+
+fn foo() { let _ = S::$0 }
+"#,
+        expect![[r#"
+                fn m() (as Trait) fn()
+            "#]],
+    );
+}
+
+#[test]
+fn completes_trait_associated_method_3() {
+    check(
+        r#"
+trait Trait { fn m(); }
+
+struct S;
+impl Trait for S {}
+
+fn foo() { let _ = <S as Trait>::$0 }
+"#,
+        expect![[r#"
+                fn m() (as Trait) fn()
+            "#]],
+    );
+}
+
+#[test]
+fn completes_ty_param_assoc_ty() {
+    check(
+        r#"
+trait Super {
+    type Ty;
+    const CONST: u8;
+    fn func() {}
+    fn method(&self) {}
+}
+
+trait Sub: Super {
+    type SubTy;
+    const C2: ();
+    fn subfunc() {}
+    fn submethod(&self) {}
+}
+
+fn foo<T: Sub>() { T::$0 }
+"#,
+        expect![[r#"
+                ct C2 (as Sub)           const C2: ()
+                ct CONST (as Super)      const CONST: u8
+                fn func() (as Super)     fn()
+                fn subfunc() (as Sub)    fn()
+                ta SubTy (as Sub)        type SubTy
+                ta Ty (as Super)         type Ty
+                me method(…) (as Super)  fn(&self)
+                me submethod(…) (as Sub) fn(&self)
+            "#]],
+    );
+}
+
+#[test]
+fn completes_self_param_assoc_ty() {
+    check(
+        r#"
+trait Super {
+    type Ty;
+    const CONST: u8 = 0;
+    fn func() {}
+    fn method(&self) {}
+}
+
+trait Sub: Super {
+    type SubTy;
+    const C2: () = ();
+    fn subfunc() {}
+    fn submethod(&self) {}
+}
+
+struct Wrap<T>(T);
+impl<T> Super for Wrap<T> {}
+impl<T> Sub for Wrap<T> {
+    fn subfunc() {
+        // Should be able to assume `Self: Sub + Super`
+        Self::$0
+    }
+}
+"#,
+        expect![[r#"
+                ct C2 (as Sub)           const C2: ()
+                ct CONST (as Super)      const CONST: u8
+                fn func() (as Super)     fn()
+                fn subfunc() (as Sub)    fn()
+                ta SubTy (as Sub)        type SubTy
+                ta Ty (as Super)         type Ty
+                me method(…) (as Super)  fn(&self)
+                me submethod(…) (as Sub) fn(&self)
+            "#]],
+    );
+}
+
+#[test]
+fn completes_type_alias() {
+    check(
+        r#"
+struct S;
+impl S { fn foo() {} }
+type T = S;
+impl T { fn bar() {} }
+
+fn main() { T::$0; }
+"#,
+        expect![[r#"
+                fn bar() fn()
+                fn foo() fn()
+            "#]],
+    );
+}
+
+#[test]
+fn completes_qualified_macros() {
+    check(
+        r#"
+#[macro_export]
+macro_rules! foo { () => {} }
+
+fn main() { let _ = crate::$0 }
+"#,
+        expect![[r#"
+                fn main()  fn()
+                ma foo!(…) macro_rules! foo
+            "#]],
+    );
+}
+
+#[test]
+fn does_not_complete_non_fn_macros() {
+    check(
+        r#"
+mod m {
+    #[rustc_builtin_macro]
+    pub macro Clone {}
+}
+
+fn f() {m::$0}
+"#,
+        expect![[r#""#]],
+    );
+    check(
+        r#"
+mod m {
+    #[rustc_builtin_macro]
+    pub macro bench {}
+}
+
+fn f() {m::$0}
+"#,
+        expect![[r#""#]],
+    );
+}
+
+#[test]
+fn completes_reexported_items_under_correct_name() {
+    check(
+        r#"
+fn foo() { self::m::$0 }
+
+mod m {
+    pub use super::p::wrong_fn as right_fn;
+    pub use super::p::WRONG_CONST as RIGHT_CONST;
+    pub use super::p::WrongType as RightType;
+}
+mod p {
+    fn wrong_fn() {}
+    const WRONG_CONST: u32 = 1;
+    struct WrongType {};
+}
+"#,
+        expect![[r#"
+                ct RIGHT_CONST
+                fn right_fn()  fn()
+                st RightType
+            "#]],
+    );
+
+    check_edit(
+        "RightType",
+        r#"
+fn foo() { self::m::$0 }
+
+mod m {
+    pub use super::p::wrong_fn as right_fn;
+    pub use super::p::WRONG_CONST as RIGHT_CONST;
+    pub use super::p::WrongType as RightType;
+}
+mod p {
+    fn wrong_fn() {}
+    const WRONG_CONST: u32 = 1;
+    struct WrongType {};
+}
+"#,
+        r#"
+fn foo() { self::m::RightType }
+
+mod m {
+    pub use super::p::wrong_fn as right_fn;
+    pub use super::p::WRONG_CONST as RIGHT_CONST;
+    pub use super::p::WrongType as RightType;
+}
+mod p {
+    fn wrong_fn() {}
+    const WRONG_CONST: u32 = 1;
+    struct WrongType {};
+}
+"#,
+    );
+}
+
+#[test]
+fn completes_in_simple_macro_call() {
+    check(
+        r#"
+macro_rules! m { ($e:expr) => { $e } }
+fn main() { m!(self::f$0); }
+fn foo() {}
+"#,
+        expect![[r#"
+                fn foo()  fn()
+                fn main() fn()
+            "#]],
+    );
+}
+
+#[test]
+fn function_mod_share_name() {
+    check(
+        r#"
+fn foo() { self::m::$0 }
+
+mod m {
+    pub mod z {}
+    pub fn z() {}
+}
+"#,
+        expect![[r#"
+                fn z() fn()
+                md z
+            "#]],
+    );
+}
+
+#[test]
+fn completes_hashmap_new() {
+    check(
+        r#"
+struct RandomState;
+struct HashMap<K, V, S = RandomState> {}
+
+impl<K, V> HashMap<K, V, RandomState> {
+    pub fn new() -> HashMap<K, V, RandomState> { }
+}
+fn foo() {
+    HashMap::$0
+}
+"#,
+        expect![[r#"
+                fn new() fn() -> HashMap<K, V, RandomState>
+            "#]],
+    );
+}
+
+#[test]
+fn completes_variant_through_self() {
+    check(
+        r#"
+enum Foo {
+    Bar,
+    Baz,
+}
+
+impl Foo {
+    fn foo(self) {
+        Self::$0
+    }
+}
+"#,
+        expect![[r#"
+                ev Bar    Bar
+                ev Baz    Baz
+                me foo(…) fn(self)
+            "#]],
+    );
+}
+
+#[test]
+fn completes_primitive_assoc_const() {
+    cov_mark::check!(completes_primitive_assoc_const);
+    check(
+        r#"
+//- /lib.rs crate:lib deps:core
+fn f() {
+    u8::$0
+}
+
+//- /core.rs crate:core
+#[lang = "u8"]
+impl u8 {
+    pub const MAX: Self = 255;
+
+    pub fn func(self) {}
+}
+"#,
+        expect![[r#"
+                ct MAX     pub const MAX: Self
+                me func(…) fn(self)
+            "#]],
+    );
+}
+
+#[test]
+fn completes_variant_through_alias() {
+    cov_mark::check!(completes_variant_through_alias);
+    check(
+        r#"
+enum Foo {
+    Bar
+}
+type Foo2 = Foo;
+fn main() {
+    Foo2::$0
+}
+"#,
+        expect![[r#"
+                ev Bar Bar
+            "#]],
+    );
+}
+
+#[test]
+fn respects_doc_hidden2() {
+    cov_mark::check!(qualified_path_doc_hidden);
+    check(
+        r#"
+//- /lib.rs crate:lib deps:dep
+fn f() {
+    dep::$0
+}
+
+//- /dep.rs crate:dep
+#[doc(hidden)]
+#[macro_export]
+macro_rules! m {
+    () => {}
+}
+
+#[doc(hidden)]
+pub fn f() {}
+
+#[doc(hidden)]
+pub struct S;
+
+#[doc(hidden)]
+pub mod m {}
+            "#,
+        expect![[r#""#]],
+    )
+}
+
+#[test]
+fn type_anchor_empty() {
+    check(
+        r#"
+trait Foo {
+    fn foo() -> Self;
+}
+struct Bar;
+impl Foo for Bar {
+    fn foo() -> {
+        Bar
+    }
+}
+fn bar() -> Bar {
+    <_>::$0
+}
+"#,
+        expect![[r#"
+                fn foo() (as Foo) fn() -> Self
+            "#]],
+    )
+}
diff --git a/crates/ide-ssr/src/resolving.rs b/crates/ide-ssr/src/resolving.rs
index d46ca05e558..f3b1af8e77f 100644
--- a/crates/ide-ssr/src/resolving.rs
+++ b/crates/ide-ssr/src/resolving.rs
@@ -230,7 +230,7 @@ impl<'db> ResolutionScope<'db> {
             adt.ty(self.scope.db).iterate_path_candidates(
                 self.scope.db,
                 &self.scope,
-                &self.scope.visible_traits(),
+                &self.scope.visible_traits().0,
                 Some(module),
                 None,
                 |assoc_item| {