diff options
| author | Max Heller <max.a.heller@gmail.com> | 2023-08-06 12:04:29 -0400 |
|---|---|---|
| committer | Max Heller <max.a.heller@gmail.com> | 2023-08-06 12:04:29 -0400 |
| commit | bb9d8229b87163d073bc1329bdc4f42676bead07 (patch) | |
| tree | 4a27a009d9f39b15a26a7a1aee97bc50ce3614f5 | |
| parent | bed1114b8ba258acb243c938e7b2915424426474 (diff) | |
| download | rust-bb9d8229b87163d073bc1329bdc4f42676bead07.tar.gz rust-bb9d8229b87163d073bc1329bdc4f42676bead07.zip | |
cleanup
| -rw-r--r-- | crates/ide-completion/src/completions.rs | 4 | ||||
| -rw-r--r-- | crates/ide-completion/src/completions/type.rs | 115 | ||||
| -rw-r--r-- | crates/ide-completion/src/context.rs | 43 | ||||
| -rw-r--r-- | crates/ide-completion/src/context/analysis.rs | 51 | ||||
| -rw-r--r-- | crates/ide-completion/src/tests/type_pos.rs | 18 |
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:: "#]], |
