Unnamed repository; edit this file 'description' to name the repository.
Display generic arguments for associated types
Ryo Yoshida 2022-10-27
parent 1fe10bf · commit 4dd6943
-rw-r--r--crates/hir-ty/src/display.rs36
-rw-r--r--crates/hir-ty/src/tests/display_source_code.rs31
-rw-r--r--crates/hir-ty/src/tls.rs28
3 files changed, 78 insertions, 17 deletions
diff --git a/crates/hir-ty/src/display.rs b/crates/hir-ty/src/display.rs
index 0221f922fe..5ad6613263 100644
--- a/crates/hir-ty/src/display.rs
+++ b/crates/hir-ty/src/display.rs
@@ -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)?;
}
diff --git a/crates/hir-ty/src/tests/display_source_code.rs b/crates/hir-ty/src/tests/display_source_code.rs
index 8a8ff08cfe..425432479e 100644
--- a/crates/hir-ty/src/tests/display_source_code.rs
+++ b/crates/hir-ty/src/tests/display_source_code.rs
@@ -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>
+}
+ "#,
+ );
+}
diff --git a/crates/hir-ty/src/tls.rs b/crates/hir-ty/src/tls.rs
index 547850b021..92711a24fe 100644
--- a/crates/hir-ty/src/tls.rs
+++ b/crates/hir-ty/src/tls.rs
@@ -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 {}", &params[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,
+ "<{}>",
+ trait_params[1..].iter().format_with(", ", |x, f| f(&format_args!("{:?}", x))),
+ )?;
+ }
+ 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,
"<{}>",
- &params[1..].iter().format_with(", ", |x, f| f(&format_args!("{:?}", x))),
+ proj_params.iter().format_with(", ", |x, f| f(&format_args!("{:?}", x))),
)?;
}
- write!(fmt, ">::{}", type_alias_data.name)
+
+ Ok(())
}
pub(crate) fn debug_fn_def_id(