mirror of
https://github.com/rust-lang/rust-analyzer
synced 2024-12-28 14:03:35 +00:00
Handle generic args per arg index
Add more test cases for generic args
This commit is contained in:
parent
0f2eba54db
commit
75fb3de310
4 changed files with 220 additions and 45 deletions
|
@ -47,6 +47,7 @@ pub struct LifetimeParamData {
|
|||
pub struct ConstParamData {
|
||||
pub name: Name,
|
||||
pub ty: Interned<TypeRef>,
|
||||
pub has_default: bool,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, PartialEq, Eq, Debug, Hash)]
|
||||
|
@ -70,6 +71,13 @@ impl TypeOrConstParamData {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn has_default(&self) -> bool {
|
||||
match self {
|
||||
TypeOrConstParamData::TypeParamData(x) => x.default.is_some(),
|
||||
TypeOrConstParamData::ConstParamData(x) => x.has_default,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn type_param(&self) -> Option<&TypeParamData> {
|
||||
match self {
|
||||
TypeOrConstParamData::TypeParamData(x) => Some(x),
|
||||
|
@ -232,7 +240,11 @@ impl GenericParams {
|
|||
let ty = const_param
|
||||
.ty()
|
||||
.map_or(TypeRef::Error, |it| TypeRef::from_ast(lower_ctx, it));
|
||||
let param = ConstParamData { name, ty: Interned::new(ty) };
|
||||
let param = ConstParamData {
|
||||
name,
|
||||
ty: Interned::new(ty),
|
||||
has_default: const_param.default_val().is_some(),
|
||||
};
|
||||
self.type_or_consts.alloc(param.into());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1709,7 +1709,11 @@ impl Trait {
|
|||
db.trait_data(self.id).is_unsafe
|
||||
}
|
||||
|
||||
pub fn type_parameters(&self, db: &dyn HirDatabase) -> Vec<TypeOrConstParamData> {
|
||||
pub fn type_or_const_param_count(
|
||||
&self,
|
||||
db: &dyn HirDatabase,
|
||||
count_required_only: bool,
|
||||
) -> usize {
|
||||
db.generic_params(GenericDefId::from(self.id))
|
||||
.type_or_consts
|
||||
.iter()
|
||||
|
@ -1721,9 +1725,9 @@ impl Trait {
|
|||
}
|
||||
_ => true,
|
||||
})
|
||||
.map(|(_, ty)|ty.clone())
|
||||
.collect()
|
||||
}
|
||||
.filter(|(_, ty)| !count_required_only || !ty.has_default())
|
||||
.count()
|
||||
}
|
||||
}
|
||||
|
||||
impl HasVisibility for Trait {
|
||||
|
|
|
@ -1,8 +1,7 @@
|
|||
//! Completion of names from the current scope in type position.
|
||||
|
||||
use hir::{HirDisplay, ScopeDef};
|
||||
use itertools::Itertools;
|
||||
use syntax::{ast, AstNode};
|
||||
use syntax::{ast, AstNode, SyntaxKind};
|
||||
|
||||
use crate::{
|
||||
context::{PathCompletionCtx, Qualified, TypeAscriptionTarget, TypeLocation},
|
||||
|
@ -141,34 +140,36 @@ pub(crate) fn complete_type_path(
|
|||
return;
|
||||
}
|
||||
TypeLocation::GenericArgList(Some(arg_list)) => {
|
||||
// the current token is in which generic arg
|
||||
let arg_pos = if let Some((pos, _)) =
|
||||
arg_list.generic_args().find_position(|arg| {
|
||||
arg.syntax()
|
||||
.descendants_with_tokens()
|
||||
.any(|t| t.as_token() == Some(&ctx.original_token))
|
||||
}) {
|
||||
pos
|
||||
} else {
|
||||
0
|
||||
};
|
||||
let in_assoc_type_arg = ctx
|
||||
.original_token
|
||||
.parent_ancestors()
|
||||
.any(|node| node.kind() == SyntaxKind::ASSOC_TYPE_ARG);
|
||||
|
||||
match arg_list.generic_args().next() {
|
||||
Some(ast::GenericArg::AssocTypeArg(_)) => {}
|
||||
_ => {
|
||||
if let Some(path_seg) =
|
||||
arg_list.syntax().parent().and_then(ast::PathSegment::cast)
|
||||
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 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())
|
||||
{
|
||||
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()
|
||||
|
@ -180,10 +181,12 @@ pub(crate) fn complete_type_path(
|
|||
acc.add_type_alias_with_eq(ctx, alias);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
if arg_pos >= trait_.type_parameters(ctx.sema.db).len() {
|
||||
return; // only AssocTypeArgs make sense
|
||||
}
|
||||
let n_params =
|
||||
trait_.type_or_const_param_count(ctx.sema.db, false);
|
||||
if arg_idx >= n_params {
|
||||
return; // only show assoc types
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -399,7 +399,7 @@ fn foo<'lt, T: Trait2<$0>, const CONST_PARAM: usize>(_: T) {}
|
|||
ct CONST
|
||||
cp CONST_PARAM
|
||||
en Enum
|
||||
ma makro!(…) macro_rules! makro
|
||||
ma makro!(…) macro_rules! makro
|
||||
md module
|
||||
st Record
|
||||
st Tuple
|
||||
|
@ -407,8 +407,6 @@ fn foo<'lt, T: Trait2<$0>, const CONST_PARAM: usize>(_: T) {}
|
|||
tt Trait
|
||||
tt Trait1
|
||||
tt Trait2
|
||||
ta Foo = (as Trait2) type Foo
|
||||
ta Super = (as Trait1) type Super
|
||||
tp T
|
||||
un Union
|
||||
bt u32
|
||||
|
@ -490,17 +488,147 @@ fn func(_: Enum::$0) {}
|
|||
}
|
||||
|
||||
#[test]
|
||||
fn completes_associated_type_only() {
|
||||
fn completes_type_parameter_or_associated_type() {
|
||||
check(
|
||||
r#"
|
||||
trait MyTrait<T> {
|
||||
type Item;
|
||||
trait MyTrait<T, U> {
|
||||
type Item1;
|
||||
type Item2;
|
||||
};
|
||||
|
||||
fn f(t: impl MyTrait<u8,I$0
|
||||
fn f(t: impl MyTrait<u$0
|
||||
"#,
|
||||
expect![[r#"
|
||||
ta Item = (as MyTrait) type Item
|
||||
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::
|
||||
kw super::
|
||||
"#]],
|
||||
);
|
||||
|
||||
check(
|
||||
r#"
|
||||
trait MyTrait<T, U> {
|
||||
type Item1;
|
||||
type Item2;
|
||||
};
|
||||
|
||||
fn f(t: impl MyTrait<u8, u$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::
|
||||
kw super::
|
||||
"#]],
|
||||
);
|
||||
|
||||
check(
|
||||
r#"
|
||||
trait MyTrait<T, U> {
|
||||
type Item1;
|
||||
type Item2;
|
||||
};
|
||||
|
||||
fn f(t: impl MyTrait<u8, u8, I$0
|
||||
"#,
|
||||
expect![[r#"
|
||||
ta Item1 = (as MyTrait) type Item1
|
||||
ta Item2 = (as MyTrait) type Item2
|
||||
"#]],
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn completes_type_parameter_or_associated_type_with_default_value() {
|
||||
check(
|
||||
r#"
|
||||
trait MyTrait<T = u8, U> {
|
||||
type Item1;
|
||||
type Item2;
|
||||
};
|
||||
|
||||
fn f(t: impl MyTrait<u$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::
|
||||
kw super::
|
||||
"#]],
|
||||
);
|
||||
|
||||
check(
|
||||
r#"
|
||||
trait MyTrait<T = u8, U> {
|
||||
type Item1;
|
||||
type Item2;
|
||||
};
|
||||
|
||||
fn f(t: impl MyTrait<u8, u$0
|
||||
"#,
|
||||
expect![[r#"
|
||||
ct CONST
|
||||
en Enum
|
||||
ma makro!(…) macro_rules! makro
|
||||
md module
|
||||
st Record
|
||||
st Tuple
|
||||
st Unit
|
||||
tt MyTrait
|
||||
tt Trait
|
||||
ta Item1 = (as MyTrait) type Item1
|
||||
ta Item2 = (as MyTrait) type Item2
|
||||
un Union
|
||||
bt u32
|
||||
kw crate::
|
||||
kw self::
|
||||
kw super::
|
||||
"#]],
|
||||
);
|
||||
|
||||
check(
|
||||
r#"
|
||||
trait MyTrait<T = u8, U> {
|
||||
type Item1;
|
||||
type Item2;
|
||||
};
|
||||
|
||||
fn f(t: impl MyTrait<u8, u8, I$0
|
||||
"#,
|
||||
expect![[r#"
|
||||
ta Item1 = (as MyTrait) type Item1
|
||||
ta Item2 = (as MyTrait) type Item2
|
||||
"#]],
|
||||
);
|
||||
}
|
||||
|
@ -510,10 +638,38 @@ fn completes_types_after_associated_type() {
|
|||
check(
|
||||
r#"
|
||||
trait MyTrait {
|
||||
type Item;
|
||||
type Item1;
|
||||
type Item2;
|
||||
};
|
||||
|
||||
fn f(t: impl MyTrait<Item = $0
|
||||
fn f(t: impl MyTrait<Item1 = $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::
|
||||
kw super::
|
||||
"#]],
|
||||
);
|
||||
|
||||
check(
|
||||
r#"
|
||||
trait MyTrait {
|
||||
type Item1;
|
||||
type Item2;
|
||||
};
|
||||
|
||||
fn f(t: impl MyTrait<Item1 = u8, Item2 = $0
|
||||
"#,
|
||||
expect![[r#"
|
||||
ct CONST
|
||||
|
|
Loading…
Reference in a new issue