diff --git a/crates/hir_ty/src/display.rs b/crates/hir_ty/src/display.rs index d2e151f25247..822ef4477ebb 100644 --- a/crates/hir_ty/src/display.rs +++ b/crates/hir_ty/src/display.rs @@ -82,6 +82,20 @@ pub trait HirDisplay { }; Ok(result) } + + /// Returns a String representation of `self` for test purposes + fn display_test<'a>(&'a self, db: &'a dyn HirDatabase) -> HirDisplayWrapper<'a, Self> + where + Self: Sized, + { + HirDisplayWrapper { + db, + t: self, + max_size: None, + omit_verbose_types: false, + display_target: DisplayTarget::Test, + } + } } impl<'a> HirFormatter<'a> { @@ -134,12 +148,17 @@ enum DisplayTarget { /// Display types for inserting them in source files. /// The generated code should compile, so paths need to be qualified. SourceCode { module_id: ModuleId }, + /// Only for test purpose to keep real types + Test, } impl DisplayTarget { fn is_source_code(&self) -> bool { matches!(self, Self::SourceCode {..}) } + fn is_test(&self) -> bool { + matches!(self, Self::Test) + } } #[derive(Debug)] @@ -313,14 +332,18 @@ impl HirDisplay for ApplicationTy { let ret_display = if f.omit_verbose_types() { ret.display_truncated(f.db, f.max_size) } else { - ret.display(f.db) + if f.display_target.is_test() { + ret.display_test(f.db) + } else { + ret.display(f.db) + } }; write!(f, " -> {}", ret_display)?; } } TypeCtor::Adt(def_id) => { match f.display_target { - DisplayTarget::Diagnostics => { + DisplayTarget::Diagnostics | DisplayTarget::Test => { let name = match def_id { AdtId::StructId(it) => f.db.struct_data(it).name.clone(), AdtId::UnionId(it) => f.db.union_data(it).name.clone(), @@ -389,12 +412,23 @@ impl HirDisplay for ApplicationTy { _ => panic!("not an associated type"), }; let trait_ = f.db.trait_data(trait_); - let type_alias = f.db.type_alias_data(type_alias); - write!(f, "{}::{}", trait_.name, type_alias.name)?; - if self.parameters.len() > 0 { - write!(f, "<")?; - f.write_joined(&*self.parameters.0, ", ")?; - write!(f, ">")?; + let type_alias_data = f.db.type_alias_data(type_alias); + + // 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)?; + if self.parameters.len() > 0 { + write!(f, "<")?; + f.write_joined(&*self.parameters.0, ", ")?; + write!(f, ">")?; + } + } else { + let projection_ty = ProjectionTy { + associated_ty: type_alias, + parameters: self.parameters.clone(), + }; + + projection_ty.hir_fmt(f)?; } } TypeCtor::ForeignType(type_alias) => { @@ -442,7 +476,11 @@ impl HirDisplay for ApplicationTy { let ret_display = if f.omit_verbose_types() { sig.ret().display_truncated(f.db, f.max_size) } else { - sig.ret().display(f.db) + if f.display_target.is_test() { + sig.ret().display_test(f.db) + } else { + sig.ret().display(f.db) + } }; write!(f, " -> {}", ret_display)?; } else { diff --git a/crates/hir_ty/src/tests.rs b/crates/hir_ty/src/tests.rs index 0445efc9e042..104ef334c689 100644 --- a/crates/hir_ty/src/tests.rs +++ b/crates/hir_ty/src/tests.rs @@ -74,7 +74,7 @@ fn check_types_impl(ra_fixture: &str, display_source: bool) { let module = db.module_for_file(file_id); ty.display_source_code(&db, module).unwrap() } else { - ty.display(&db).to_string() + ty.display_test(&db).to_string() }; assert_eq!(expected, actual); checked_one = true; @@ -163,7 +163,7 @@ fn infer_with_mismatches(content: &str, include_mismatches: bool) -> String { macro_prefix, range, ellipsize(text, 15), - ty.display(&db) + ty.display_test(&db) ); } if include_mismatches { @@ -179,8 +179,8 @@ fn infer_with_mismatches(content: &str, include_mismatches: bool) -> String { "{}{:?}: expected {}, got {}\n", macro_prefix, range, - mismatch.expected.display(&db), - mismatch.actual.display(&db), + mismatch.expected.display_test(&db), + mismatch.actual.display_test(&db), ); } } diff --git a/crates/ide/src/inlay_hints.rs b/crates/ide/src/inlay_hints.rs index 49d8e4ae14eb..adb93efd7e1b 100644 --- a/crates/ide/src/inlay_hints.rs +++ b/crates/ide/src/inlay_hints.rs @@ -1235,4 +1235,25 @@ fn main() { "#, ); } + + #[test] + fn infer_call_method_return_associated_types_with_generic() { + check( + r#" + pub trait Default { + fn default() -> Self; + } + pub trait Foo { + type Bar: Default; + } + + pub fn quux() -> T::Bar { + let y = Default::default(); + //^ ::Bar + + y + } + "#, + ); + } }