diff --git a/crates/ide-completion/src/completions/type.rs b/crates/ide-completion/src/completions/type.rs index e4705475638..de855242ee3 100644 --- a/crates/ide-completion/src/completions/type.rs +++ b/crates/ide-completion/src/completions/type.rs @@ -24,12 +24,23 @@ pub(crate) fn complete_type_path( // 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(_)) => { - matches!(location, TypeLocation::GenericArgList(_)) - } - ScopeDef::ImplSelfType(_) => { - !matches!(location, TypeLocation::ImplTarget | TypeLocation::ImplTrait) - } + 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, + }, // Don't suggest attribute macros and derives. ScopeDef::ModuleDef(Macro(mac)) => mac.is_fn_like(ctx.db), // Type things are fine @@ -38,7 +49,12 @@ pub(crate) fn complete_type_path( ) | ScopeDef::AdtSelfType(_) | ScopeDef::Unknown - | ScopeDef::GenericParam(TypeParam(_)) => true, + | ScopeDef::GenericParam(TypeParam(_)) => match location { + TypeLocation::GenericArgList(Some((_, Some(generic_param)))) => { + matches!(generic_param, ast::GenericParam::TypeParam(_)) + } + _ => true, + }, } }; @@ -157,7 +173,7 @@ pub(crate) fn complete_type_path( }); return; } - TypeLocation::GenericArgList(Some(arg_list)) => { + TypeLocation::GenericArgList(Some((arg_list, generic_param))) => { let in_assoc_type_arg = ctx .original_token .parent_ancestors() diff --git a/crates/ide-completion/src/context.rs b/crates/ide-completion/src/context.rs index 3cb65b2729a..8ec5c6c8bfd 100644 --- a/crates/ide-completion/src/context.rs +++ b/crates/ide-completion/src/context.rs @@ -155,7 +155,7 @@ pub(crate) struct ExprCtx { pub(crate) enum TypeLocation { TupleField, TypeAscription(TypeAscriptionTarget), - GenericArgList(Option), + GenericArgList(Option<(ast::GenericArgList, Option)>), TypeBound, ImplTarget, ImplTrait, diff --git a/crates/ide-completion/src/context/analysis.rs b/crates/ide-completion/src/context/analysis.rs index aeec1ea6f77..cc9e4581bed 100644 --- a/crates/ide-completion/src/context/analysis.rs +++ b/crates/ide-completion/src/context/analysis.rs @@ -1,11 +1,11 @@ //! Module responsible for analyzing the code surrounding the cursor for completion. use std::iter; -use hir::{Semantics, Type, TypeInfo, Variant}; +use hir::{HasSource, Semantics, Type, TypeInfo, Variant}; use ide_db::{active_parameter::ActiveParameter, RootDatabase}; use syntax::{ algo::{find_node_at_offset, non_trivia_sibling}, - ast::{self, AttrKind, HasArgList, HasLoopBody, HasName, NameOrNameRef}, + ast::{self, AttrKind, HasArgList, HasGenericParams, HasLoopBody, HasName, NameOrNameRef}, match_ast, AstNode, AstToken, Direction, NodeOrToken, SyntaxElement, SyntaxKind, SyntaxNode, SyntaxToken, TextRange, TextSize, T, }; @@ -774,9 +774,40 @@ fn classify_name_ref( ast::TypeBound(_) => TypeLocation::TypeBound, // is this case needed? ast::TypeBoundList(_) => TypeLocation::TypeBound, - ast::GenericArg(it) => TypeLocation::GenericArgList(find_opt_node_in_file_compensated(sema, original_file, it.syntax().parent().and_then(ast::GenericArgList::cast))), + ast::GenericArg(it) => { + let location = find_opt_node_in_file_compensated(sema, original_file, it.syntax().parent().and_then(ast::GenericArgList::cast)) + .map(|args| { + // Determine the index of the parameter in the `GenericArgList` + // (subtract 1 because `siblings` includes the node itself) + let param_idx = it.syntax().siblings(Direction::Prev).count() - 1; + let param = args + .syntax() + .parent() + .and_then(|p| ast::PathSegment::cast(p)) + .and_then(|segment| sema.resolve_path(&segment.parent_path().top_path())) + .and_then(|resolved| { + match resolved { + hir::PathResolution::Def(def) => match def { + hir::ModuleDef::Function(func) => { + let src = func.source(sema.db)?; + let params = src.value.generic_param_list()?; + params.generic_params().nth(param_idx) + } + _ => None, + }, + _ => None, + } + }); + (args, param) + }); + TypeLocation::GenericArgList(location) + }, // is this case needed? - ast::GenericArgList(it) => TypeLocation::GenericArgList(find_opt_node_in_file_compensated(sema, original_file, Some(it))), + ast::GenericArgList(it) => { + let location = find_opt_node_in_file_compensated(sema, original_file, Some(it)) + .map(|node| (node, None)); + TypeLocation::GenericArgList(location) + }, ast::TupleField(_) => TypeLocation::TupleField, _ => return None, } @@ -883,25 +914,8 @@ fn classify_name_ref( } }; let make_path_kind_type = |ty: ast::Type| { - let location = type_location(ty.syntax()).unwrap_or(TypeLocation::Other); - match &location { - TypeLocation::TupleField => (), - TypeLocation::TypeAscription(_) => (), - TypeLocation::GenericArgList(args) => { - dbg!(&args); - if let Some(segment) = - args.as_ref().and_then(|args| ast::PathSegment::cast(args.syntax().parent()?)) - { - let path = dbg!(segment.parent_path().top_path()); - dbg!(sema.resolve_path(&path)); - } - } - TypeLocation::TypeBound => (), - TypeLocation::ImplTarget => (), - TypeLocation::ImplTrait => (), - TypeLocation::Other => (), - } - PathKind::Type { location } + let location = type_location(ty.syntax()); + PathKind::Type { location: location.unwrap_or(TypeLocation::Other) } }; let mut kind_macro_call = |it: ast::MacroCall| { diff --git a/crates/ide-completion/src/tests/type_pos.rs b/crates/ide-completion/src/tests/type_pos.rs index 4869ac17ad9..2a05aef17f9 100644 --- a/crates/ide-completion/src/tests/type_pos.rs +++ b/crates/ide-completion/src/tests/type_pos.rs @@ -726,15 +726,21 @@ fn completes_const_and_type_generics_separately() { r#" struct Foo; const X: usize = 0; -mod foo { - fn foo() {} -} +fn foo() {} fn main() { - self::foo::foo::(); + foo::(); } "#, expect![[r#" + en Enum + ma makro!(…) macro_rules! makro + md module st Foo + st Record + st Tuple + st Unit + tt Trait + un Union bt u32 kw crate:: kw self:: @@ -744,13 +750,15 @@ fn main() { r#" struct Foo; const X: usize = 0; -fn foo() {} +fn foo() {} fn main() { - foo::(); + foo::<_, $0>(); } "#, expect![[r#" + ct CONST ct X + ma makro!(…) macro_rules! makro kw crate:: kw self:: "#]],