mirror of
https://github.com/rust-lang/rust-analyzer
synced 2025-01-14 14:13:58 +00:00
Display generic arguments for associated types
This commit is contained in:
parent
1fe10bff1d
commit
4dd694371a
3 changed files with 78 additions and 17 deletions
|
@ -289,16 +289,18 @@ impl HirDisplay for ProjectionTy {
|
|||
return write!(f, "{}", TYPE_HINT_TRUNCATION);
|
||||
}
|
||||
|
||||
let trait_ = f.db.trait_data(self.trait_(f.db));
|
||||
let trait_ref = self.trait_ref(f.db);
|
||||
write!(f, "<")?;
|
||||
self.self_type_parameter(f.db).hir_fmt(f)?;
|
||||
write!(f, " as {}", trait_.name)?;
|
||||
if self.substitution.len(Interner) > 1 {
|
||||
fmt_trait_ref(&trait_ref, f, true)?;
|
||||
write!(f, ">::{}", f.db.type_alias_data(from_assoc_type_id(self.associated_ty_id)).name)?;
|
||||
let proj_params_count =
|
||||
self.substitution.len(Interner) - trait_ref.substitution.len(Interner);
|
||||
let proj_params = &self.substitution.as_slice(Interner)[..proj_params_count];
|
||||
if !proj_params.is_empty() {
|
||||
write!(f, "<")?;
|
||||
f.write_joined(&self.substitution.as_slice(Interner)[1..], ", ")?;
|
||||
f.write_joined(proj_params, ", ")?;
|
||||
write!(f, ">")?;
|
||||
}
|
||||
write!(f, ">::{}", f.db.type_alias_data(from_assoc_type_id(self.associated_ty_id)).name)?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
@ -641,9 +643,12 @@ impl HirDisplay for Ty {
|
|||
// Use placeholder associated types when the target is test (https://rust-lang.github.io/chalk/book/clauses/type_equality.html#placeholder-associated-types)
|
||||
if f.display_target.is_test() {
|
||||
write!(f, "{}::{}", trait_.name, type_alias_data.name)?;
|
||||
// Note that the generic args for the associated type come before those for the
|
||||
// trait (including the self type).
|
||||
// FIXME: reconsider the generic args order upon formatting?
|
||||
if parameters.len(Interner) > 0 {
|
||||
write!(f, "<")?;
|
||||
f.write_joined(&*parameters.as_slice(Interner), ", ")?;
|
||||
f.write_joined(parameters.as_slice(Interner), ", ")?;
|
||||
write!(f, ">")?;
|
||||
}
|
||||
} else {
|
||||
|
@ -972,9 +977,20 @@ fn write_bounds_like_dyn_trait(
|
|||
angle_open = true;
|
||||
}
|
||||
if let AliasTy::Projection(proj) = alias {
|
||||
let type_alias =
|
||||
f.db.type_alias_data(from_assoc_type_id(proj.associated_ty_id));
|
||||
write!(f, "{} = ", type_alias.name)?;
|
||||
let assoc_ty_id = from_assoc_type_id(proj.associated_ty_id);
|
||||
let type_alias = f.db.type_alias_data(assoc_ty_id);
|
||||
write!(f, "{}", type_alias.name)?;
|
||||
|
||||
let proj_arg_count = generics(f.db.upcast(), assoc_ty_id.into()).len_self();
|
||||
if proj_arg_count > 0 {
|
||||
write!(f, "<")?;
|
||||
f.write_joined(
|
||||
&proj.substitution.as_slice(Interner)[..proj_arg_count],
|
||||
", ",
|
||||
)?;
|
||||
write!(f, ">")?;
|
||||
}
|
||||
write!(f, " = ")?;
|
||||
}
|
||||
ty.hir_fmt(f)?;
|
||||
}
|
||||
|
|
|
@ -196,3 +196,34 @@ fn test(
|
|||
"#,
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn projection_type_correct_arguments_order() {
|
||||
check_types_source_code(
|
||||
r#"
|
||||
trait Foo<T> {
|
||||
type Assoc<U>;
|
||||
}
|
||||
fn f<T: Foo<i32>>(a: T::Assoc<usize>) {
|
||||
a;
|
||||
//^ <T as Foo<i32>>::Assoc<usize>
|
||||
}
|
||||
"#,
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn generic_associated_type_binding_in_impl_trait() {
|
||||
check_types_source_code(
|
||||
r#"
|
||||
//- minicore: sized
|
||||
trait Foo<T> {
|
||||
type Assoc<U>;
|
||||
}
|
||||
fn f(a: impl Foo<i8, Assoc<i16> = i32>) {
|
||||
a;
|
||||
//^ impl Foo<i8, Assoc<i16> = i32>
|
||||
}
|
||||
"#,
|
||||
);
|
||||
}
|
||||
|
|
|
@ -5,7 +5,7 @@ use itertools::Itertools;
|
|||
|
||||
use crate::{
|
||||
chalk_db, db::HirDatabase, from_assoc_type_id, from_chalk_trait_id, mapping::from_chalk,
|
||||
CallableDefId, Interner,
|
||||
CallableDefId, Interner, ProjectionTyExt,
|
||||
};
|
||||
use hir_def::{AdtId, ItemContainerId, Lookup, TypeAliasId};
|
||||
|
||||
|
@ -63,17 +63,31 @@ impl DebugContext<'_> {
|
|||
ItemContainerId::TraitId(t) => t,
|
||||
_ => panic!("associated type not in trait"),
|
||||
};
|
||||
let trait_data = self.0.trait_data(trait_);
|
||||
let params = projection_ty.substitution.as_slice(Interner);
|
||||
write!(fmt, "<{:?} as {}", ¶ms[0], trait_data.name,)?;
|
||||
if params.len() > 1 {
|
||||
let trait_name = &self.0.trait_data(trait_).name;
|
||||
let trait_ref = projection_ty.trait_ref(self.0);
|
||||
let trait_params = trait_ref.substitution.as_slice(Interner);
|
||||
let self_ty = trait_ref.self_type_parameter(Interner);
|
||||
write!(fmt, "<{:?} as {}", self_ty, trait_name)?;
|
||||
if trait_params.len() > 1 {
|
||||
write!(
|
||||
fmt,
|
||||
"<{}>",
|
||||
¶ms[1..].iter().format_with(", ", |x, f| f(&format_args!("{:?}", x))),
|
||||
trait_params[1..].iter().format_with(", ", |x, f| f(&format_args!("{:?}", x))),
|
||||
)?;
|
||||
}
|
||||
write!(fmt, ">::{}", type_alias_data.name)
|
||||
write!(fmt, ">::{}", type_alias_data.name)?;
|
||||
|
||||
let proj_params_count = projection_ty.substitution.len(Interner) - trait_params.len();
|
||||
let proj_params = &projection_ty.substitution.as_slice(Interner)[..proj_params_count];
|
||||
if !proj_params.is_empty() {
|
||||
write!(
|
||||
fmt,
|
||||
"<{}>",
|
||||
proj_params.iter().format_with(", ", |x, f| f(&format_args!("{:?}", x))),
|
||||
)?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub(crate) fn debug_fn_def_id(
|
||||
|
|
Loading…
Reference in a new issue