Skip to content

Commit

Permalink
Auto merge of rust-lang#12695 - xuhongxu96:fix-12140, r=jonas-schievink
Browse files Browse the repository at this point in the history
Complete type param/associated type in trait generic arg per arg index

- Fix rust-lang#12140
- Also fix tidy check does not work for marks in multiline
  • Loading branch information
bors committed Jul 6, 2022
2 parents c46570e + 3248601 commit c296e77
Show file tree
Hide file tree
Showing 5 changed files with 347 additions and 50 deletions.
14 changes: 13 additions & 1 deletion crates/hir-def/src/generics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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)]
Expand All @@ -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),
Expand Down Expand Up @@ -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());
}
}
Expand Down
21 changes: 21 additions & 0 deletions crates/hir/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ use hir_def::{
adt::{ReprKind, VariantData},
body::{BodyDiagnostic, SyntheticSyntax},
expr::{BindingAnnotation, LabelId, Pat, PatId},
generics::{TypeOrConstParamData, TypeParamProvenance},
item_tree::ItemTreeNode,
lang_item::LangItemTarget,
nameres::{self, diagnostics::DefDiagnostic},
Expand Down Expand Up @@ -1707,6 +1708,26 @@ impl Trait {
pub fn is_unsafe(&self, db: &dyn HirDatabase) -> bool {
db.trait_data(self.id).is_unsafe
}

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()
.filter(|(_, ty)| match ty {
TypeOrConstParamData::TypeParamData(ty)
if ty.provenance != TypeParamProvenance::TypeParamList =>
{
false
}
_ => true,
})
.filter(|(_, ty)| !count_required_only || !ty.has_default())
.count()
}
}

impl HasVisibility for Trait {
Expand Down
102 changes: 73 additions & 29 deletions crates/ide-completion/src/completions/type.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
//! Completion of names from the current scope in type position.

use hir::{HirDisplay, ScopeDef};
use syntax::{ast, AstNode};
use syntax::{ast, AstNode, SyntaxKind};

use crate::{
context::{PathCompletionCtx, Qualified, TypeAscriptionTarget, TypeLocation},
Expand Down Expand Up @@ -120,39 +120,83 @@ pub(crate) fn complete_type_path(
}
Qualified::Absolute => acc.add_crate_roots(ctx, path_ctx),
Qualified::No => {
acc.add_nameref_keywords_with_colon(ctx);
if let TypeLocation::TypeBound = location {
ctx.process_all_names(&mut |name, res| {
let add_resolution = match res {
ScopeDef::ModuleDef(hir::ModuleDef::Macro(mac)) => mac.is_fn_like(ctx.db),
ScopeDef::ModuleDef(
hir::ModuleDef::Trait(_) | hir::ModuleDef::Module(_),
) => true,
_ => false,
};
if add_resolution {
acc.add_path_resolution(ctx, path_ctx, name, res);
}
});
return;
}
if let TypeLocation::GenericArgList(Some(arg_list)) = location {
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())
match location {
TypeLocation::TypeBound => {
acc.add_nameref_keywords_with_colon(ctx);
ctx.process_all_names(&mut |name, res| {
let add_resolution = match res {
ScopeDef::ModuleDef(hir::ModuleDef::Macro(mac)) => {
mac.is_fn_like(ctx.db)
}
ScopeDef::ModuleDef(
hir::ModuleDef::Trait(_) | hir::ModuleDef::Module(_),
) => true,
_ => false,
};
if add_resolution {
acc.add_path_resolution(ctx, path_ctx, name, res);
}
});
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)
{
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)
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
}
}
}
});
}
}
}
}
}
_ => {}
};

acc.add_nameref_keywords_with_colon(ctx);
ctx.process_all_names(&mut |name, def| {
if scope_def_applicable(def) {
acc.add_path_resolution(ctx, path_ctx, name, def);
Expand Down
Loading

0 comments on commit c296e77

Please sign in to comment.