Unnamed repository; edit this file 'description' to name the repository.
cleanup
Max Heller 2023-08-06
parent bed1114 · commit bb9d822
-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 480cb77b4f..125ebc98a5 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 f4efaecba8..621dea0b9a 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 8ec5c6c8bf..5537673d1e 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 dfceb67f20..87380067e8 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 4b44139109..f2ed724703 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::
"#]],