about summary refs log tree commit diff
diff options
context:
space:
mode:
authorMax Heller <max.a.heller@gmail.com>2023-08-06 12:04:29 -0400
committerMax Heller <max.a.heller@gmail.com>2023-08-06 12:04:29 -0400
commitbb9d8229b87163d073bc1329bdc4f42676bead07 (patch)
tree4a27a009d9f39b15a26a7a1aee97bc50ce3614f5
parentbed1114b8ba258acb243c938e7b2915424426474 (diff)
downloadrust-bb9d8229b87163d073bc1329bdc4f42676bead07.tar.gz
rust-bb9d8229b87163d073bc1329bdc4f42676bead07.zip
cleanup
-rw-r--r--crates/ide-completion/src/completions.rs4
-rw-r--r--crates/ide-completion/src/completions/type.rs115
-rw-r--r--crates/ide-completion/src/context.rs43
-rw-r--r--crates/ide-completion/src/context/analysis.rs51
-rw-r--r--crates/ide-completion/src/tests/type_pos.rs18
5 files changed, 120 insertions, 111 deletions
diff --git a/crates/ide-completion/src/completions.rs b/crates/ide-completion/src/completions.rs
index 480cb77b4fd..125ebc98a52 100644
--- a/crates/ide-completion/src/completions.rs
+++ b/crates/ide-completion/src/completions.rs
@@ -703,7 +703,9 @@ pub(super) fn complete_name_ref(
                         TypeLocation::TypeAscription(ascription) => {
                             r#type::complete_ascribed_type(acc, ctx, path_ctx, ascription);
                         }
-                        TypeLocation::GenericArgList(_)
+                        TypeLocation::GenericArg(_)
+                        | TypeLocation::AssocConstEq
+                        | TypeLocation::AssocTypeEq
                         | TypeLocation::TypeBound
                         | TypeLocation::ImplTarget
                         | TypeLocation::ImplTrait
diff --git a/crates/ide-completion/src/completions/type.rs b/crates/ide-completion/src/completions/type.rs
index f4efaecba8a..621dea0b9a5 100644
--- a/crates/ide-completion/src/completions/type.rs
+++ b/crates/ide-completion/src/completions/type.rs
@@ -1,7 +1,7 @@
 //! Completion of names from the current scope in type position.
 
 use hir::{HirDisplay, ScopeDef};
-use syntax::{ast, AstNode, SyntaxKind};
+use syntax::{ast, AstNode};
 
 use crate::{
     context::{PathCompletionCtx, Qualified, TypeAscriptionTarget, TypeLocation},
@@ -20,36 +20,15 @@ pub(crate) fn complete_type_path(
     let scope_def_applicable = |def| {
         use hir::{GenericParam::*, ModuleDef::*};
         match def {
-            ScopeDef::GenericParam(LifetimeParam(_)) => {
-                matches!(
-                    location,
-                    TypeLocation::GenericArgList(Some((
-                        _,
-                        Some(ast::GenericParam::LifetimeParam(_))
-                    )))
-                )
-            }
+            ScopeDef::GenericParam(LifetimeParam(_)) => location.complete_lifetimes(),
             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(_)) => match location
-            {
-                TypeLocation::GenericArgList(location) => match location {
-                    Some((_, Some(generic_param))) => {
-                        matches!(generic_param, ast::GenericParam::ConstParam(_))
-                    }
-                    _ => true,
-                },
-                _ => false,
-            },
-            ScopeDef::ImplSelfType(_) => match location {
-                TypeLocation::ImplTarget | TypeLocation::ImplTrait => false,
-                TypeLocation::GenericArgList(Some((_, Some(generic_param)))) => {
-                    matches!(generic_param, ast::GenericParam::TypeParam(_))
-                }
-                _ => true,
-            },
+            ScopeDef::ModuleDef(Const(_)) | ScopeDef::GenericParam(ConstParam(_)) => {
+                location.complete_consts()
+            }
+            ScopeDef::ImplSelfType(_) => location.complete_self_type(),
             // Don't suggest attribute macros and derives.
             ScopeDef::ModuleDef(Macro(mac)) => mac.is_fn_like(ctx.db),
             // Type things are fine
@@ -58,17 +37,12 @@ pub(crate) fn complete_type_path(
             )
             | ScopeDef::AdtSelfType(_)
             | ScopeDef::Unknown
-            | ScopeDef::GenericParam(TypeParam(_)) => match location {
-                TypeLocation::GenericArgList(Some((_, Some(generic_param)))) => {
-                    matches!(generic_param, ast::GenericParam::TypeParam(_))
-                }
-                _ => true,
-            },
+            | ScopeDef::GenericParam(TypeParam(_)) => location.complete_types(),
         }
     };
 
     let add_assoc_item = |acc: &mut Completions, item| match item {
-        hir::AssocItem::Const(ct) if matches!(location, TypeLocation::GenericArgList(_)) => {
+        hir::AssocItem::Const(ct) if matches!(location, TypeLocation::GenericArg(_)) => {
             acc.add_const(ctx, ct)
         }
         hir::AssocItem::Function(_) | hir::AssocItem::Const(_) => (),
@@ -182,55 +156,32 @@ pub(crate) fn complete_type_path(
                     });
                     return;
                 }
-                TypeLocation::GenericArgList(Some((arg_list, _))) => {
-                    let in_assoc_type_arg = ctx
-                        .original_token
-                        .parent_ancestors()
-                        .any(|node| node.kind() == SyntaxKind::ASSOC_TYPE_ARG);
-
-                    if !in_assoc_type_arg {
-                        if let Some(path_seg) =
-                            arg_list.syntax().parent().and_then(ast::PathSegment::cast)
-                        {
-                            if path_seg
-                                .syntax()
-                                .ancestors()
-                                .find_map(ast::TypeBound::cast)
-                                .is_some()
-                            {
-                                if let Some(hir::PathResolution::Def(hir::ModuleDef::Trait(
-                                    trait_,
-                                ))) = ctx.sema.resolve_path(&path_seg.parent_path())
-                                {
-                                    let arg_idx = arg_list
-                                        .generic_args()
-                                        .filter(|arg| {
-                                            arg.syntax().text_range().end()
-                                                < ctx.original_token.text_range().start()
-                                        })
-                                        .count();
-
-                                    let n_required_params =
-                                        trait_.type_or_const_param_count(ctx.sema.db, true);
-                                    if arg_idx >= n_required_params {
-                                        trait_
-                                            .items_with_supertraits(ctx.sema.db)
-                                            .into_iter()
-                                            .for_each(|it| {
-                                                if let hir::AssocItem::TypeAlias(alias) = it {
-                                                    cov_mark::hit!(
-                                                        complete_assoc_type_in_generics_list
-                                                    );
-                                                    acc.add_type_alias_with_eq(ctx, alias);
-                                                }
-                                            });
-
-                                        let n_params =
-                                            trait_.type_or_const_param_count(ctx.sema.db, false);
-                                        if arg_idx >= n_params {
-                                            return; // only show assoc types
+                TypeLocation::GenericArg(Some((arg_list, in_trait, _))) => {
+                    if let Some(trait_) = in_trait {
+                        if arg_list.syntax().ancestors().find_map(ast::TypeBound::cast).is_some() {
+                            let arg_idx = arg_list
+                                .generic_args()
+                                .filter(|arg| {
+                                    arg.syntax().text_range().end()
+                                        < ctx.original_token.text_range().start()
+                                })
+                                .count();
+
+                            let n_required_params =
+                                trait_.type_or_const_param_count(ctx.sema.db, true);
+                            if arg_idx >= n_required_params {
+                                trait_.items_with_supertraits(ctx.sema.db).into_iter().for_each(
+                                    |it| {
+                                        if let hir::AssocItem::TypeAlias(alias) = it {
+                                            cov_mark::hit!(complete_assoc_type_in_generics_list);
+                                            acc.add_type_alias_with_eq(ctx, alias);
                                         }
-                                    }
+                                    },
+                                );
+
+                                let n_params = trait_.type_or_const_param_count(ctx.sema.db, false);
+                                if arg_idx >= n_params {
+                                    return; // only show assoc types
                                 }
                             }
                         }
diff --git a/crates/ide-completion/src/context.rs b/crates/ide-completion/src/context.rs
index 8ec5c6c8bfd..5537673d1ee 100644
--- a/crates/ide-completion/src/context.rs
+++ b/crates/ide-completion/src/context.rs
@@ -155,13 +155,54 @@ pub(crate) struct ExprCtx {
 pub(crate) enum TypeLocation {
     TupleField,
     TypeAscription(TypeAscriptionTarget),
-    GenericArgList(Option<(ast::GenericArgList, Option<ast::GenericParam>)>),
+    /// Generic argument position e.g. `Foo<$0>`
+    GenericArg(Option<(ast::GenericArgList, Option<hir::Trait>, Option<ast::GenericParam>)>),
+    /// Associated type equality constraint e.g. `Foo<Bar = $0>`
+    AssocTypeEq,
+    /// Associated constant equality constraint e.g. `Foo<X = $0>`
+    AssocConstEq,
     TypeBound,
     ImplTarget,
     ImplTrait,
     Other,
 }
 
+impl TypeLocation {
+    pub(crate) fn complete_lifetimes(&self) -> bool {
+        match self {
+            TypeLocation::GenericArg(Some((_, _, Some(param)))) => {
+                matches!(param, ast::GenericParam::LifetimeParam(_))
+            }
+            _ => false,
+        }
+    }
+
+    pub(crate) fn complete_consts(&self) -> bool {
+        match self {
+            TypeLocation::GenericArg(Some((_, _, Some(param)))) => {
+                matches!(param, ast::GenericParam::ConstParam(_))
+            }
+            TypeLocation::AssocConstEq => true,
+            _ => false,
+        }
+    }
+
+    pub(crate) fn complete_types(&self) -> bool {
+        match self {
+            TypeLocation::GenericArg(Some((_, _, Some(param)))) => {
+                matches!(param, ast::GenericParam::TypeParam(_))
+            }
+            TypeLocation::AssocConstEq => false,
+            TypeLocation::AssocTypeEq => true,
+            _ => true,
+        }
+    }
+
+    pub(crate) fn complete_self_type(&self) -> bool {
+        self.complete_types() && !matches!(self, TypeLocation::ImplTarget | TypeLocation::ImplTrait)
+    }
+}
+
 #[derive(Clone, Debug, PartialEq, Eq)]
 pub(crate) enum TypeAscriptionTarget {
     Let(Option<ast::Pat>),
diff --git a/crates/ide-completion/src/context/analysis.rs b/crates/ide-completion/src/context/analysis.rs
index dfceb67f209..87380067e87 100644
--- a/crates/ide-completion/src/context/analysis.rs
+++ b/crates/ide-completion/src/context/analysis.rs
@@ -720,12 +720,14 @@ fn classify_name_ref(
     };
 
     let generic_arg_location = |arg: ast::GenericArg| {
+        let mut override_location = None;
         let location = find_opt_node_in_file_compensated(
             sema,
             original_file,
             arg.syntax().parent().and_then(ast::GenericArgList::cast),
         )
         .map(|args| {
+            let mut in_trait = None;
             let param = (|| {
                 let parent = args.syntax().parent()?;
                 let params = match_ast! {
@@ -743,7 +745,31 @@ fn classify_name_ref(
                                         variant.parent_enum(sema.db).source(sema.db)?.value.generic_param_list()
                                     }
                                     hir::ModuleDef::Trait(trait_) => {
-                                        trait_.source(sema.db)?.value.generic_param_list()
+                                        if let ast::GenericArg::AssocTypeArg(arg) = &arg {
+                                            let arg_name = arg.name_ref()?;
+                                            let arg_name = arg_name.text();
+                                            for item in trait_.items_with_supertraits(sema.db) {
+                                                match item {
+                                                    hir::AssocItem::TypeAlias(assoc_ty) => {
+                                                        if assoc_ty.name(sema.db).as_str()? == arg_name {
+                                                            override_location = Some(TypeLocation::AssocTypeEq);
+                                                            return None;
+                                                        }
+                                                    },
+                                                    hir::AssocItem::Const(const_) => {
+                                                        if const_.name(sema.db)?.as_str()? == arg_name {
+                                                            override_location =  Some(TypeLocation::AssocConstEq);
+                                                            return None;
+                                                        }
+                                                    },
+                                                    _ => (),
+                                                }
+                                            }
+                                            return None;
+                                        } else {
+                                            in_trait = Some(trait_);
+                                            trait_.source(sema.db)?.value.generic_param_list()
+                                        }
                                     }
                                     hir::ModuleDef::TraitAlias(trait_) => {
                                         trait_.source(sema.db)?.value.generic_param_list()
@@ -765,10 +791,12 @@ fn classify_name_ref(
                             match sema.resolve_path(&trait_.parent_path().top_path())? {
                                 hir::PathResolution::Def(def) => match def {
                                     hir::ModuleDef::Trait(trait_) => {
-                                        let trait_items = trait_.items(sema.db);
+                                        let arg_name = arg.name_ref()?;
+                                        let arg_name = arg_name.text();
+                                        let trait_items = trait_.items_with_supertraits(sema.db);
                                         let assoc_ty = trait_items.iter().find_map(|item| match item {
                                             hir::AssocItem::TypeAlias(assoc_ty) => {
-                                                (assoc_ty.name(sema.db).as_str()? == arg.name_ref()?.text())
+                                                (assoc_ty.name(sema.db).as_str()? == arg_name)
                                                     .then_some(assoc_ty)
                                             },
                                             _ => None,
@@ -784,11 +812,10 @@ fn classify_name_ref(
                     }
                 }?;
                 // Determine the index of the argument in the `GenericArgList` and match it with
-                // the corresponding parameter in the `GenericParamList`.
-                // Since lifetime parameters are often omitted, ignore them for the purposes of
-                // matching the argument with its parameter unless a lifetime argument is provided
-                // explicitly. That is, for `struct S<'a, 'b, T>`, match `S::<$0>` to to `T` and
-                // `S::<'a, $0, _>` to `'b`.
+                // the corresponding parameter in the `GenericParamList`. Since lifetime parameters
+                // are often omitted, ignore them for the purposes of matching the argument with
+                // its parameter unless a lifetime argument is provided explicitly. That is, for
+                // `struct S<'a, 'b, T>`, match `S::<$0>` to `T` and `S::<'a, $0, _>` to `'b`.
                 let mut explicit_lifetime_arg = false;
                 let arg_idx = arg
                     .syntax()
@@ -806,9 +833,9 @@ fn classify_name_ref(
                 };
                 params.generic_params().nth(param_idx)
             })();
-            (args, param)
+            (args, in_trait, param)
         });
-        TypeLocation::GenericArgList(location)
+        override_location.unwrap_or(TypeLocation::GenericArg(location))
     };
 
     let type_location = |node: &SyntaxNode| {
@@ -870,8 +897,8 @@ fn classify_name_ref(
                 // is this case needed?
                 ast::GenericArgList(it) => {
                     let location = find_opt_node_in_file_compensated(sema, original_file, Some(it))
-                        .map(|node| (node, None));
-                    TypeLocation::GenericArgList(location)
+                        .map(|node| (node, None, None));
+                    TypeLocation::GenericArg(location)
                 },
                 ast::TupleField(_) => TypeLocation::TupleField,
                 _ => return None,
diff --git a/crates/ide-completion/src/tests/type_pos.rs b/crates/ide-completion/src/tests/type_pos.rs
index 4b441391094..f2ed7247039 100644
--- a/crates/ide-completion/src/tests/type_pos.rs
+++ b/crates/ide-completion/src/tests/type_pos.rs
@@ -402,14 +402,13 @@ fn foo<'lt, T: Trait2<$0>, const CONST_PARAM: usize>(_: T) {}
     );
     check(
         r#"
-trait Trait2 {
+trait Trait2<T> {
     type Foo;
 }
 
 fn foo<'lt, T: Trait2<self::$0>, const CONST_PARAM: usize>(_: T) {}
     "#,
         expect![[r#"
-            ct CONST
             en Enum
             ma makro!(…) macro_rules! makro
             md module
@@ -620,7 +619,6 @@ trait MyTrait {
 fn f(t: impl MyTrait<Item1 = $0
 "#,
         expect![[r#"
-            ct CONST
             en Enum
             ma makro!(…) macro_rules! makro
             md module
@@ -639,24 +637,14 @@ fn f(t: impl MyTrait<Item1 = $0
     check(
         r#"
 trait MyTrait {
-    type Item1;
-    type Item2;
+    const C: usize;
 };
 
-fn f(t: impl MyTrait<Item1 = u8, Item2 = $0
+fn f(t: impl MyTrait<C = $0
 "#,
         expect![[r#"
             ct CONST
-            en Enum
             ma makro!(…) macro_rules! makro
-            md module
-            st Record
-            st Tuple
-            st Unit
-            tt MyTrait
-            tt Trait
-            un Union
-            bt u32
             kw crate::
             kw self::
         "#]],