handle more cases

This commit is contained in:
Max Heller 2023-08-02 17:59:26 -04:00
parent f4038a6bf1
commit 1b3e20fe68
3 changed files with 136 additions and 106 deletions

View file

@ -173,7 +173,7 @@ pub(crate) fn complete_type_path(
}); });
return; return;
} }
TypeLocation::GenericArgList(Some((arg_list, generic_param))) => { TypeLocation::GenericArgList(Some((arg_list, _))) => {
let in_assoc_type_arg = ctx let in_assoc_type_arg = ctx
.original_token .original_token
.parent_ancestors() .parent_ancestors()

View file

@ -726,20 +726,30 @@ fn classify_name_ref(
arg.syntax().parent().and_then(ast::GenericArgList::cast), arg.syntax().parent().and_then(ast::GenericArgList::cast),
) )
.map(|args| { .map(|args| {
// Determine the index of the parameter in the `GenericArgList` let param = (|| {
// (subtract 1 because `siblings` includes the node itself) let parent = args.syntax().parent()?;
let param_idx = arg.syntax().siblings(Direction::Prev).count() - 1; let params = match_ast! {
let parent = args.syntax().parent();
let param = parent.and_then(|parent| {
match_ast! {
match parent { match parent {
ast::PathSegment(segment) => { ast::PathSegment(segment) => {
match sema.resolve_path(&segment.parent_path().top_path())? { match sema.resolve_path(&segment.parent_path().top_path())? {
hir::PathResolution::Def(def) => match def { hir::PathResolution::Def(def) => match def {
hir::ModuleDef::Function(func) => { hir::ModuleDef::Function(func) => {
let src = func.source(sema.db)?; func.source(sema.db)?.value.generic_param_list()
let params = src.value.generic_param_list()?; }
params.generic_params().nth(param_idx) hir::ModuleDef::Adt(adt) => {
adt.source(sema.db)?.value.generic_param_list()
}
hir::ModuleDef::Variant(variant) => {
variant.parent_enum(sema.db).source(sema.db)?.value.generic_param_list()
}
hir::ModuleDef::Trait(trait_) => {
trait_.source(sema.db)?.value.generic_param_list()
}
hir::ModuleDef::TraitAlias(trait_) => {
trait_.source(sema.db)?.value.generic_param_list()
}
hir::ModuleDef::TypeAlias(ty_) => {
ty_.source(sema.db)?.value.generic_param_list()
} }
_ => None, _ => None,
}, },
@ -748,9 +758,7 @@ fn classify_name_ref(
}, },
ast::MethodCallExpr(call) => { ast::MethodCallExpr(call) => {
let func = sema.resolve_method_call(&call)?; let func = sema.resolve_method_call(&call)?;
let src = func.source(sema.db)?; func.source(sema.db)?.value.generic_param_list()
let params = src.value.generic_param_list()?;
params.generic_params().nth(param_idx)
}, },
ast::AssocTypeArg(arg) => { ast::AssocTypeArg(arg) => {
let trait_ = ast::PathSegment::cast(arg.syntax().parent()?.parent()?)?; let trait_ = ast::PathSegment::cast(arg.syntax().parent()?.parent()?)?;
@ -765,9 +773,7 @@ fn classify_name_ref(
}, },
_ => None, _ => None,
})?; })?;
let src = assoc_ty.source(sema.db)?; assoc_ty.source(sema.db)?.value.generic_param_list()
let params = src.value.generic_param_list()?;
params.generic_params().nth(param_idx)
} }
_ => None, _ => None,
}, },
@ -776,8 +782,12 @@ fn classify_name_ref(
}, },
_ => None, _ => None,
} }
} }?;
}); // Determine the index of the parameter in the `GenericArgList`
// (subtract 1 because `siblings` includes the node itself)
let param_idx = arg.syntax().siblings(Direction::Prev).count() - 1;
params.generic_params().nth(param_idx)
})();
(args, param) (args, param)
}); });
TypeLocation::GenericArgList(location) TypeLocation::GenericArgList(location)

View file

@ -722,16 +722,31 @@ pub struct S;
#[test] #[test]
fn completes_const_and_type_generics_separately() { fn completes_const_and_type_generics_separately() {
check( let type_completion_cases = [
// Function
r#" r#"
struct Foo; struct Foo;
const X: usize = 0; const X: usize = 0;
fn foo<T, const N: usize>() {} fn foo<T, const N: usize>() {}
fn main() { fn main() {
foo::<F$0, _>(); foo::<F$0, _>();
} }
"#, "#,
expect![[r#" // Method
r#"
const X: usize = 0;
struct Foo;
impl Foo { fn bar<const N: usize, T>(self) {} }
fn main() {
Foo.bar::<_, $0>();
}
"#,
];
for case in type_completion_cases {
check(
case,
expect![[r#"
en Enum en Enum
ma makro!() macro_rules! makro ma makro!() macro_rules! makro
md module md module
@ -745,66 +760,8 @@ fn completes_const_and_type_generics_separately() {
kw crate:: kw crate::
kw self:: kw self::
"#]], "#]],
); )
check(
r#"
struct Foo;
const X: usize = 0;
fn foo<T, const N: usize>() {}
fn main() {
foo::<_, $0>();
} }
"#,
expect![[r#"
ct CONST
ct X
ma makro!() macro_rules! makro
kw crate::
kw self::
"#]],
);
check(
r#"
const X: usize = 0;
struct Foo;
impl Foo { fn bar<const N: usize, T>(self) {} }
fn main() {
Foo.bar::<X$0, _>();
}
"#,
expect![[r#"
ct CONST
ct X
ma makro!() macro_rules! makro
kw crate::
kw self::
"#]],
);
check(
r#"
const X: usize = 0;
struct Foo;
impl Foo { fn bar<const N: usize, T>(self) {} }
fn main() {
Foo.bar::<_, $0>();
}
"#,
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::
"#]],
);
check( check(
r#" r#"
@ -813,25 +770,8 @@ struct Foo;
trait Bar { trait Bar {
type Baz<T, const X: usize>; type Baz<T, const X: usize>;
} }
fn foo<T: Bar<Baz<(), $0> = ()>>() {} fn foo(_: impl Bar<Baz<F$0, 0> = ()>) {}
"#, "#,
expect![[r#"
ct CONST
ct X
ma makro!() macro_rules! makro
kw crate::
kw self::
"#]],
);
check(
r#"
const X: usize = 0;
struct Foo;
trait Bar {
type Baz<T, const X: usize>;
}
fn foo<T: Bar<Baz<F$0, 0> = ()>>() {}
"#,
expect![[r#" expect![[r#"
en Enum en Enum
ma makro!() macro_rules! makro ma makro!() macro_rules! makro
@ -842,11 +782,91 @@ fn foo<T: Bar<Baz<F$0, 0> = ()>>() {}
st Unit st Unit
tt Bar tt Bar
tt Trait tt Trait
tp T
un Union un Union
bt u32 bt u32
kw crate:: kw crate::
kw self:: kw self::
"#]], "#]],
); );
let const_completion_cases = [
// Function params
r#"
struct Foo;
const X: usize = 0;
fn foo<T, const N: usize>() {}
fn main() {
foo::<_, $0>();
}
"#,
// Method params
r#"
const X: usize = 0;
struct Foo;
impl Foo { fn bar<const N: usize, T>(self) {} }
fn main() {
Foo.bar::<X$0, _>();
}
"#,
// Associated type params
r#"
const X: usize = 0;
struct Foo;
trait Bar {
type Baz<T, const X: usize>;
}
fn foo<T: Bar<Baz<(), $0> = ()>>() {}
"#,
// Type params
r#"
const X: usize = 0;
struct Foo<T, const N: usize>(T);
fn main() {
let _: Foo::<_, $0> = todo!();
}
"#,
// Enum variant params
r#"
const X: usize = 0;
struct Foo<T, const N: usize>(T);
type Bar<const X: usize, U> = Foo<U, X>;
fn main() {
let _: Bar::<X$0, _> = todo!();
}
"#,
r#"
const X: usize = 0;
enum Foo<T, const N: usize> { A(T), B }
fn main() {
Foo::B::<(), $0>;
}
"#,
// Trait params
r#"
const X: usize = 0;
trait Foo<T, const N: usize> {}
impl Foo<(), $0> for () {}
"#,
// Trait alias params
r#"
#![feature(trait_alias)]
const X: usize = 0;
trait Foo<T, const N: usize> {}
trait Bar<const M: usize, U> = Foo<U, M>;
fn foo<T: Bar<X$0, ()>>() {}
"#,
];
for case in const_completion_cases {
check(
case,
expect![[r#"
ct CONST
ct X
ma makro!() macro_rules! makro
kw crate::
kw self::
"#]],
);
}
} }