aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_hir_ty/src/display.rs
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ra_hir_ty/src/display.rs')
-rw-r--r--crates/ra_hir_ty/src/display.rs239
1 files changed, 176 insertions, 63 deletions
diff --git a/crates/ra_hir_ty/src/display.rs b/crates/ra_hir_ty/src/display.rs
index d03bbd5a7..b9c4d2e89 100644
--- a/crates/ra_hir_ty/src/display.rs
+++ b/crates/ra_hir_ty/src/display.rs
@@ -6,28 +6,42 @@ use crate::{
6 db::HirDatabase, utils::generics, ApplicationTy, CallableDef, FnSig, GenericPredicate, 6 db::HirDatabase, utils::generics, ApplicationTy, CallableDef, FnSig, GenericPredicate,
7 Obligation, ProjectionTy, Substs, TraitRef, Ty, TypeCtor, 7 Obligation, ProjectionTy, Substs, TraitRef, Ty, TypeCtor,
8}; 8};
9use hir_def::{generics::TypeParamProvenance, AdtId, AssocContainerId, Lookup}; 9use hir_def::{
10 find_path, generics::TypeParamProvenance, item_scope::ItemInNs, AdtId, AssocContainerId,
11 Lookup, ModuleId,
12};
10use hir_expand::name::Name; 13use hir_expand::name::Name;
11 14
12pub struct HirFormatter<'a, 'b> { 15pub struct HirFormatter<'a> {
13 pub db: &'a dyn HirDatabase, 16 pub db: &'a dyn HirDatabase,
14 fmt: &'a mut fmt::Formatter<'b>, 17 fmt: &'a mut dyn fmt::Write,
15 buf: String, 18 buf: String,
16 curr_size: usize, 19 curr_size: usize,
17 pub(crate) max_size: Option<usize>, 20 pub(crate) max_size: Option<usize>,
18 omit_verbose_types: bool, 21 omit_verbose_types: bool,
22 display_target: DisplayTarget,
19} 23}
20 24
21pub trait HirDisplay { 25pub trait HirDisplay {
22 fn hir_fmt(&self, f: &mut HirFormatter) -> fmt::Result; 26 fn hir_fmt(&self, f: &mut HirFormatter) -> Result<(), HirDisplayError>;
23 27
28 /// Returns a `Display`able type that is human-readable.
29 /// Use this for showing types to the user (e.g. diagnostics)
24 fn display<'a>(&'a self, db: &'a dyn HirDatabase) -> HirDisplayWrapper<'a, Self> 30 fn display<'a>(&'a self, db: &'a dyn HirDatabase) -> HirDisplayWrapper<'a, Self>
25 where 31 where
26 Self: Sized, 32 Self: Sized,
27 { 33 {
28 HirDisplayWrapper(db, self, None, false) 34 HirDisplayWrapper {
35 db,
36 t: self,
37 max_size: None,
38 omit_verbose_types: false,
39 display_target: DisplayTarget::Diagnostics,
40 }
29 } 41 }
30 42
43 /// Returns a `Display`able type that is human-readable and tries to be succinct.
44 /// Use this for showing types to the user where space is constrained (e.g. doc popups)
31 fn display_truncated<'a>( 45 fn display_truncated<'a>(
32 &'a self, 46 &'a self,
33 db: &'a dyn HirDatabase, 47 db: &'a dyn HirDatabase,
@@ -36,16 +50,46 @@ pub trait HirDisplay {
36 where 50 where
37 Self: Sized, 51 Self: Sized,
38 { 52 {
39 HirDisplayWrapper(db, self, max_size, true) 53 HirDisplayWrapper {
54 db,
55 t: self,
56 max_size,
57 omit_verbose_types: true,
58 display_target: DisplayTarget::Diagnostics,
59 }
60 }
61
62 /// Returns a String representation of `self` that can be inserted into the given module.
63 /// Use this when generating code (e.g. assists)
64 fn display_source_code<'a>(
65 &'a self,
66 db: &'a dyn HirDatabase,
67 module_id: ModuleId,
68 ) -> Result<String, DisplaySourceCodeError> {
69 let mut result = String::new();
70 match self.hir_fmt(&mut HirFormatter {
71 db,
72 fmt: &mut result,
73 buf: String::with_capacity(20),
74 curr_size: 0,
75 max_size: None,
76 omit_verbose_types: false,
77 display_target: DisplayTarget::SourceCode { module_id },
78 }) {
79 Ok(()) => {}
80 Err(HirDisplayError::FmtError) => panic!("Writing to String can't fail!"),
81 Err(HirDisplayError::DisplaySourceCodeError(e)) => return Err(e),
82 };
83 Ok(result)
40 } 84 }
41} 85}
42 86
43impl<'a, 'b> HirFormatter<'a, 'b> { 87impl<'a> HirFormatter<'a> {
44 pub fn write_joined<T: HirDisplay>( 88 pub fn write_joined<T: HirDisplay>(
45 &mut self, 89 &mut self,
46 iter: impl IntoIterator<Item = T>, 90 iter: impl IntoIterator<Item = T>,
47 sep: &str, 91 sep: &str,
48 ) -> fmt::Result { 92 ) -> Result<(), HirDisplayError> {
49 let mut first = true; 93 let mut first = true;
50 for e in iter { 94 for e in iter {
51 if !first { 95 if !first {
@@ -58,14 +102,14 @@ impl<'a, 'b> HirFormatter<'a, 'b> {
58 } 102 }
59 103
60 /// This allows using the `write!` macro directly with a `HirFormatter`. 104 /// This allows using the `write!` macro directly with a `HirFormatter`.
61 pub fn write_fmt(&mut self, args: fmt::Arguments) -> fmt::Result { 105 pub fn write_fmt(&mut self, args: fmt::Arguments) -> Result<(), HirDisplayError> {
62 // We write to a buffer first to track output size 106 // We write to a buffer first to track output size
63 self.buf.clear(); 107 self.buf.clear();
64 fmt::write(&mut self.buf, args)?; 108 fmt::write(&mut self.buf, args)?;
65 self.curr_size += self.buf.len(); 109 self.curr_size += self.buf.len();
66 110
67 // Then we write to the internal formatter from the buffer 111 // Then we write to the internal formatter from the buffer
68 self.fmt.write_str(&self.buf) 112 self.fmt.write_str(&self.buf).map_err(HirDisplayError::from)
69 } 113 }
70 114
71 pub fn should_truncate(&self) -> bool { 115 pub fn should_truncate(&self) -> bool {
@@ -81,34 +125,82 @@ impl<'a, 'b> HirFormatter<'a, 'b> {
81 } 125 }
82} 126}
83 127
84pub struct HirDisplayWrapper<'a, T>(&'a dyn HirDatabase, &'a T, Option<usize>, bool); 128#[derive(Clone, Copy)]
129enum DisplayTarget {
130 /// Display types for inlays, doc popups, autocompletion, etc...
131 /// Showing `{unknown}` or not qualifying paths is fine here.
132 /// There's no reason for this to fail.
133 Diagnostics,
134 /// Display types for inserting them in source files.
135 /// The generated code should compile, so paths need to be qualified.
136 SourceCode { module_id: ModuleId },
137}
138
139impl DisplayTarget {
140 fn is_source_code(&self) -> bool {
141 matches!(self, Self::SourceCode {..})
142 }
143}
144
145#[derive(Debug)]
146pub enum DisplaySourceCodeError {
147 PathNotFound,
148}
149
150pub enum HirDisplayError {
151 /// Errors that can occur when generating source code
152 DisplaySourceCodeError(DisplaySourceCodeError),
153 /// `FmtError` is required to be compatible with std::fmt::Display
154 FmtError,
155}
156impl From<fmt::Error> for HirDisplayError {
157 fn from(_: fmt::Error) -> Self {
158 Self::FmtError
159 }
160}
161
162pub struct HirDisplayWrapper<'a, T> {
163 db: &'a dyn HirDatabase,
164 t: &'a T,
165 max_size: Option<usize>,
166 omit_verbose_types: bool,
167 display_target: DisplayTarget,
168}
85 169
86impl<'a, T> fmt::Display for HirDisplayWrapper<'a, T> 170impl<'a, T> fmt::Display for HirDisplayWrapper<'a, T>
87where 171where
88 T: HirDisplay, 172 T: HirDisplay,
89{ 173{
90 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 174 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
91 self.1.hir_fmt(&mut HirFormatter { 175 match self.t.hir_fmt(&mut HirFormatter {
92 db: self.0, 176 db: self.db,
93 fmt: f, 177 fmt: f,
94 buf: String::with_capacity(20), 178 buf: String::with_capacity(20),
95 curr_size: 0, 179 curr_size: 0,
96 max_size: self.2, 180 max_size: self.max_size,
97 omit_verbose_types: self.3, 181 omit_verbose_types: self.omit_verbose_types,
98 }) 182 display_target: self.display_target,
183 }) {
184 Ok(()) => Ok(()),
185 Err(HirDisplayError::FmtError) => Err(fmt::Error),
186 Err(HirDisplayError::DisplaySourceCodeError(_)) => {
187 // This should never happen
188 panic!("HirDisplay failed when calling Display::fmt!")
189 }
190 }
99 } 191 }
100} 192}
101 193
102const TYPE_HINT_TRUNCATION: &str = "…"; 194const TYPE_HINT_TRUNCATION: &str = "…";
103 195
104impl HirDisplay for &Ty { 196impl HirDisplay for &Ty {
105 fn hir_fmt(&self, f: &mut HirFormatter) -> fmt::Result { 197 fn hir_fmt(&self, f: &mut HirFormatter) -> Result<(), HirDisplayError> {
106 HirDisplay::hir_fmt(*self, f) 198 HirDisplay::hir_fmt(*self, f)
107 } 199 }
108} 200}
109 201
110impl HirDisplay for ApplicationTy { 202impl HirDisplay for ApplicationTy {
111 fn hir_fmt(&self, f: &mut HirFormatter) -> fmt::Result { 203 fn hir_fmt(&self, f: &mut HirFormatter) -> Result<(), HirDisplayError> {
112 if f.should_truncate() { 204 if f.should_truncate() {
113 return write!(f, "{}", TYPE_HINT_TRUNCATION); 205 return write!(f, "{}", TYPE_HINT_TRUNCATION);
114 } 206 }
@@ -191,45 +283,66 @@ impl HirDisplay for ApplicationTy {
191 } 283 }
192 } 284 }
193 TypeCtor::Adt(def_id) => { 285 TypeCtor::Adt(def_id) => {
194 let name = match def_id { 286 match f.display_target {
195 AdtId::StructId(it) => f.db.struct_data(it).name.clone(), 287 DisplayTarget::Diagnostics => {
196 AdtId::UnionId(it) => f.db.union_data(it).name.clone(), 288 let name = match def_id {
197 AdtId::EnumId(it) => f.db.enum_data(it).name.clone(), 289 AdtId::StructId(it) => f.db.struct_data(it).name.clone(),
198 }; 290 AdtId::UnionId(it) => f.db.union_data(it).name.clone(),
199 write!(f, "{}", name)?; 291 AdtId::EnumId(it) => f.db.enum_data(it).name.clone(),
292 };
293 write!(f, "{}", name)?;
294 }
295 DisplayTarget::SourceCode { module_id } => {
296 if let Some(path) = find_path::find_path(
297 f.db.upcast(),
298 ItemInNs::Types(def_id.into()),
299 module_id,
300 ) {
301 write!(f, "{}", path)?;
302 } else {
303 return Err(HirDisplayError::DisplaySourceCodeError(
304 DisplaySourceCodeError::PathNotFound,
305 ));
306 }
307 }
308 }
309
200 if self.parameters.len() > 0 { 310 if self.parameters.len() > 0 {
201 let mut non_default_parameters = Vec::with_capacity(self.parameters.len()); 311 let mut non_default_parameters = Vec::with_capacity(self.parameters.len());
202 let parameters_to_write = if f.omit_verbose_types() { 312 let parameters_to_write =
203 match self 313 if f.display_target.is_source_code() || f.omit_verbose_types() {
204 .ctor 314 match self
205 .as_generic_def() 315 .ctor
206 .map(|generic_def_id| f.db.generic_defaults(generic_def_id)) 316 .as_generic_def()
207 .filter(|defaults| !defaults.is_empty()) 317 .map(|generic_def_id| f.db.generic_defaults(generic_def_id))
208 { 318 .filter(|defaults| !defaults.is_empty())
209 None => self.parameters.0.as_ref(), 319 {
210 Some(default_parameters) => { 320 None => self.parameters.0.as_ref(),
211 for (i, parameter) in self.parameters.iter().enumerate() { 321 Some(default_parameters) => {
212 match (parameter, default_parameters.get(i)) { 322 for (i, parameter) in self.parameters.iter().enumerate() {
213 (&Ty::Unknown, _) | (_, None) => { 323 match (parameter, default_parameters.get(i)) {
214 non_default_parameters.push(parameter.clone()) 324 (&Ty::Unknown, _) | (_, None) => {
325 non_default_parameters.push(parameter.clone())
326 }
327 (_, Some(default_parameter))
328 if parameter != default_parameter =>
329 {
330 non_default_parameters.push(parameter.clone())
331 }
332 _ => (),
215 } 333 }
216 (_, Some(default_parameter))
217 if parameter != default_parameter =>
218 {
219 non_default_parameters.push(parameter.clone())
220 }
221 _ => (),
222 } 334 }
335 &non_default_parameters
223 } 336 }
224 &non_default_parameters
225 } 337 }
226 } 338 } else {
227 } else { 339 self.parameters.0.as_ref()
228 self.parameters.0.as_ref() 340 };
229 }; 341 if !parameters_to_write.is_empty() {
230 write!(f, "<")?; 342 write!(f, "<")?;
231 f.write_joined(parameters_to_write, ", ")?; 343 f.write_joined(parameters_to_write, ", ")?;
232 write!(f, ">")?; 344 write!(f, ">")?;
345 }
233 } 346 }
234 } 347 }
235 TypeCtor::AssociatedType(type_alias) => { 348 TypeCtor::AssociatedType(type_alias) => {
@@ -269,7 +382,7 @@ impl HirDisplay for ApplicationTy {
269} 382}
270 383
271impl HirDisplay for ProjectionTy { 384impl HirDisplay for ProjectionTy {
272 fn hir_fmt(&self, f: &mut HirFormatter) -> fmt::Result { 385 fn hir_fmt(&self, f: &mut HirFormatter) -> Result<(), HirDisplayError> {
273 if f.should_truncate() { 386 if f.should_truncate() {
274 return write!(f, "{}", TYPE_HINT_TRUNCATION); 387 return write!(f, "{}", TYPE_HINT_TRUNCATION);
275 } 388 }
@@ -287,7 +400,7 @@ impl HirDisplay for ProjectionTy {
287} 400}
288 401
289impl HirDisplay for Ty { 402impl HirDisplay for Ty {
290 fn hir_fmt(&self, f: &mut HirFormatter) -> fmt::Result { 403 fn hir_fmt(&self, f: &mut HirFormatter) -> Result<(), HirDisplayError> {
291 if f.should_truncate() { 404 if f.should_truncate() {
292 return write!(f, "{}", TYPE_HINT_TRUNCATION); 405 return write!(f, "{}", TYPE_HINT_TRUNCATION);
293 } 406 }
@@ -332,7 +445,7 @@ impl HirDisplay for Ty {
332fn write_bounds_like_dyn_trait( 445fn write_bounds_like_dyn_trait(
333 predicates: &[GenericPredicate], 446 predicates: &[GenericPredicate],
334 f: &mut HirFormatter, 447 f: &mut HirFormatter,
335) -> fmt::Result { 448) -> Result<(), HirDisplayError> {
336 // Note: This code is written to produce nice results (i.e. 449 // Note: This code is written to produce nice results (i.e.
337 // corresponding to surface Rust) for types that can occur in 450 // corresponding to surface Rust) for types that can occur in
338 // actual Rust. It will have weird results if the predicates 451 // actual Rust. It will have weird results if the predicates
@@ -394,7 +507,7 @@ fn write_bounds_like_dyn_trait(
394} 507}
395 508
396impl TraitRef { 509impl TraitRef {
397 fn hir_fmt_ext(&self, f: &mut HirFormatter, use_as: bool) -> fmt::Result { 510 fn hir_fmt_ext(&self, f: &mut HirFormatter, use_as: bool) -> Result<(), HirDisplayError> {
398 if f.should_truncate() { 511 if f.should_truncate() {
399 return write!(f, "{}", TYPE_HINT_TRUNCATION); 512 return write!(f, "{}", TYPE_HINT_TRUNCATION);
400 } 513 }
@@ -416,19 +529,19 @@ impl TraitRef {
416} 529}
417 530
418impl HirDisplay for TraitRef { 531impl HirDisplay for TraitRef {
419 fn hir_fmt(&self, f: &mut HirFormatter) -> fmt::Result { 532 fn hir_fmt(&self, f: &mut HirFormatter) -> Result<(), HirDisplayError> {
420 self.hir_fmt_ext(f, false) 533 self.hir_fmt_ext(f, false)
421 } 534 }
422} 535}
423 536
424impl HirDisplay for &GenericPredicate { 537impl HirDisplay for &GenericPredicate {
425 fn hir_fmt(&self, f: &mut HirFormatter) -> fmt::Result { 538 fn hir_fmt(&self, f: &mut HirFormatter) -> Result<(), HirDisplayError> {
426 HirDisplay::hir_fmt(*self, f) 539 HirDisplay::hir_fmt(*self, f)
427 } 540 }
428} 541}
429 542
430impl HirDisplay for GenericPredicate { 543impl HirDisplay for GenericPredicate {
431 fn hir_fmt(&self, f: &mut HirFormatter) -> fmt::Result { 544 fn hir_fmt(&self, f: &mut HirFormatter) -> Result<(), HirDisplayError> {
432 if f.should_truncate() { 545 if f.should_truncate() {
433 return write!(f, "{}", TYPE_HINT_TRUNCATION); 546 return write!(f, "{}", TYPE_HINT_TRUNCATION);
434 } 547 }
@@ -452,15 +565,15 @@ impl HirDisplay for GenericPredicate {
452} 565}
453 566
454impl HirDisplay for Obligation { 567impl HirDisplay for Obligation {
455 fn hir_fmt(&self, f: &mut HirFormatter) -> fmt::Result { 568 fn hir_fmt(&self, f: &mut HirFormatter) -> Result<(), HirDisplayError> {
456 match self { 569 Ok(match self {
457 Obligation::Trait(tr) => write!(f, "Implements({})", tr.display(f.db)), 570 Obligation::Trait(tr) => write!(f, "Implements({})", tr.display(f.db))?,
458 Obligation::Projection(proj) => write!( 571 Obligation::Projection(proj) => write!(
459 f, 572 f,
460 "Normalize({} => {})", 573 "Normalize({} => {})",
461 proj.projection_ty.display(f.db), 574 proj.projection_ty.display(f.db),
462 proj.ty.display(f.db) 575 proj.ty.display(f.db)
463 ), 576 )?,
464 } 577 })
465 } 578 }
466} 579}