Skip to content

Commit 4dd6943

Browse files
committed
Display generic arguments for associated types
1 parent 1fe10bf commit 4dd6943

File tree

3 files changed

+78
-17
lines changed

3 files changed

+78
-17
lines changed

crates/hir-ty/src/display.rs

+26-10
Original file line numberDiff line numberDiff line change
@@ -289,16 +289,18 @@ impl HirDisplay for ProjectionTy {
289289
return write!(f, "{}", TYPE_HINT_TRUNCATION);
290290
}
291291

292-
let trait_ = f.db.trait_data(self.trait_(f.db));
292+
let trait_ref = self.trait_ref(f.db);
293293
write!(f, "<")?;
294-
self.self_type_parameter(f.db).hir_fmt(f)?;
295-
write!(f, " as {}", trait_.name)?;
296-
if self.substitution.len(Interner) > 1 {
294+
fmt_trait_ref(&trait_ref, f, true)?;
295+
write!(f, ">::{}", f.db.type_alias_data(from_assoc_type_id(self.associated_ty_id)).name)?;
296+
let proj_params_count =
297+
self.substitution.len(Interner) - trait_ref.substitution.len(Interner);
298+
let proj_params = &self.substitution.as_slice(Interner)[..proj_params_count];
299+
if !proj_params.is_empty() {
297300
write!(f, "<")?;
298-
f.write_joined(&self.substitution.as_slice(Interner)[1..], ", ")?;
301+
f.write_joined(proj_params, ", ")?;
299302
write!(f, ">")?;
300303
}
301-
write!(f, ">::{}", f.db.type_alias_data(from_assoc_type_id(self.associated_ty_id)).name)?;
302304
Ok(())
303305
}
304306
}
@@ -641,9 +643,12 @@ impl HirDisplay for Ty {
641643
// Use placeholder associated types when the target is test (https://rust-lang.github.io/chalk/book/clauses/type_equality.html#placeholder-associated-types)
642644
if f.display_target.is_test() {
643645
write!(f, "{}::{}", trait_.name, type_alias_data.name)?;
646+
// Note that the generic args for the associated type come before those for the
647+
// trait (including the self type).
648+
// FIXME: reconsider the generic args order upon formatting?
644649
if parameters.len(Interner) > 0 {
645650
write!(f, "<")?;
646-
f.write_joined(&*parameters.as_slice(Interner), ", ")?;
651+
f.write_joined(parameters.as_slice(Interner), ", ")?;
647652
write!(f, ">")?;
648653
}
649654
} else {
@@ -972,9 +977,20 @@ fn write_bounds_like_dyn_trait(
972977
angle_open = true;
973978
}
974979
if let AliasTy::Projection(proj) = alias {
975-
let type_alias =
976-
f.db.type_alias_data(from_assoc_type_id(proj.associated_ty_id));
977-
write!(f, "{} = ", type_alias.name)?;
980+
let assoc_ty_id = from_assoc_type_id(proj.associated_ty_id);
981+
let type_alias = f.db.type_alias_data(assoc_ty_id);
982+
write!(f, "{}", type_alias.name)?;
983+
984+
let proj_arg_count = generics(f.db.upcast(), assoc_ty_id.into()).len_self();
985+
if proj_arg_count > 0 {
986+
write!(f, "<")?;
987+
f.write_joined(
988+
&proj.substitution.as_slice(Interner)[..proj_arg_count],
989+
", ",
990+
)?;
991+
write!(f, ">")?;
992+
}
993+
write!(f, " = ")?;
978994
}
979995
ty.hir_fmt(f)?;
980996
}

crates/hir-ty/src/tests/display_source_code.rs

+31
Original file line numberDiff line numberDiff line change
@@ -196,3 +196,34 @@ fn test(
196196
"#,
197197
);
198198
}
199+
200+
#[test]
201+
fn projection_type_correct_arguments_order() {
202+
check_types_source_code(
203+
r#"
204+
trait Foo<T> {
205+
type Assoc<U>;
206+
}
207+
fn f<T: Foo<i32>>(a: T::Assoc<usize>) {
208+
a;
209+
//^ <T as Foo<i32>>::Assoc<usize>
210+
}
211+
"#,
212+
);
213+
}
214+
215+
#[test]
216+
fn generic_associated_type_binding_in_impl_trait() {
217+
check_types_source_code(
218+
r#"
219+
//- minicore: sized
220+
trait Foo<T> {
221+
type Assoc<U>;
222+
}
223+
fn f(a: impl Foo<i8, Assoc<i16> = i32>) {
224+
a;
225+
//^ impl Foo<i8, Assoc<i16> = i32>
226+
}
227+
"#,
228+
);
229+
}

crates/hir-ty/src/tls.rs

+21-7
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ use itertools::Itertools;
55

66
use crate::{
77
chalk_db, db::HirDatabase, from_assoc_type_id, from_chalk_trait_id, mapping::from_chalk,
8-
CallableDefId, Interner,
8+
CallableDefId, Interner, ProjectionTyExt,
99
};
1010
use hir_def::{AdtId, ItemContainerId, Lookup, TypeAliasId};
1111

@@ -63,17 +63,31 @@ impl DebugContext<'_> {
6363
ItemContainerId::TraitId(t) => t,
6464
_ => panic!("associated type not in trait"),
6565
};
66-
let trait_data = self.0.trait_data(trait_);
67-
let params = projection_ty.substitution.as_slice(Interner);
68-
write!(fmt, "<{:?} as {}", &params[0], trait_data.name,)?;
69-
if params.len() > 1 {
66+
let trait_name = &self.0.trait_data(trait_).name;
67+
let trait_ref = projection_ty.trait_ref(self.0);
68+
let trait_params = trait_ref.substitution.as_slice(Interner);
69+
let self_ty = trait_ref.self_type_parameter(Interner);
70+
write!(fmt, "<{:?} as {}", self_ty, trait_name)?;
71+
if trait_params.len() > 1 {
72+
write!(
73+
fmt,
74+
"<{}>",
75+
trait_params[1..].iter().format_with(", ", |x, f| f(&format_args!("{:?}", x))),
76+
)?;
77+
}
78+
write!(fmt, ">::{}", type_alias_data.name)?;
79+
80+
let proj_params_count = projection_ty.substitution.len(Interner) - trait_params.len();
81+
let proj_params = &projection_ty.substitution.as_slice(Interner)[..proj_params_count];
82+
if !proj_params.is_empty() {
7083
write!(
7184
fmt,
7285
"<{}>",
73-
&params[1..].iter().format_with(", ", |x, f| f(&format_args!("{:?}", x))),
86+
proj_params.iter().format_with(", ", |x, f| f(&format_args!("{:?}", x))),
7487
)?;
7588
}
76-
write!(fmt, ">::{}", type_alias_data.name)
89+
90+
Ok(())
7791
}
7892

7993
pub(crate) fn debug_fn_def_id(

0 commit comments

Comments
 (0)