cleanup
This commit is contained in:
parent
bed1114b8b
commit
bb9d8229b8
@ -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
|
||||
|
@ -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);
|
||||
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();
|
||||
|
||||
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
|
||||
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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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>),
|
||||
|
@ -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,
|
||||
|
@ -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::
|
||||
"#]],
|
||||
|
Loading…
x
Reference in New Issue
Block a user