1 //! The `HirDisplay` trait, which serves two purposes: Turning various bits from
2 //! HIR back into source code, and just displaying them for debugging/testing
3 //! purposes.
4
5 use std::{
6 fmt::{self, Debug},
7 mem::size_of,
8 };
9
10 use base_db::CrateId;
11 use chalk_ir::{BoundVar, TyKind};
12 use hir_def::{
13 data::adt::VariantData,
14 db::DefDatabase,
15 find_path,
16 generics::{TypeOrConstParamData, TypeParamProvenance},
17 item_scope::ItemInNs,
18 lang_item::{LangItem, LangItemTarget},
19 nameres::DefMap,
20 path::{Path, PathKind},
21 type_ref::{TraitBoundModifier, TypeBound, TypeRef},
22 visibility::Visibility,
23 EnumVariantId, HasModule, ItemContainerId, LocalFieldId, Lookup, ModuleDefId, ModuleId,
24 TraitId,
25 };
26 use hir_expand::{hygiene::Hygiene, name::Name};
27 use intern::{Internable, Interned};
28 use itertools::Itertools;
29 use la_arena::ArenaMap;
30 use smallvec::SmallVec;
31 use stdx::never;
32
33 use crate::{
34 consteval::try_const_usize,
35 db::HirDatabase,
36 from_assoc_type_id, from_foreign_def_id, from_placeholder_idx,
37 layout::Layout,
38 lt_from_placeholder_idx,
39 mapping::from_chalk,
40 mir::pad16,
41 primitive, to_assoc_type_id,
42 utils::{self, detect_variant_from_bytes, generics, ClosureSubst},
43 AdtId, AliasEq, AliasTy, Binders, CallableDefId, CallableSig, Const, ConstScalar, ConstValue,
44 DomainGoal, GenericArg, ImplTraitId, Interner, Lifetime, LifetimeData, LifetimeOutlives,
45 MemoryMap, Mutability, OpaqueTy, ProjectionTy, ProjectionTyExt, QuantifiedWhereClause, Scalar,
46 Substitution, TraitRef, TraitRefExt, Ty, TyExt, WhereClause,
47 };
48
49 pub trait HirWrite: fmt::Write {
start_location_link(&mut self, location: ModuleDefId)50 fn start_location_link(&mut self, location: ModuleDefId);
end_location_link(&mut self)51 fn end_location_link(&mut self);
52 }
53
54 // String will ignore link metadata
55 impl HirWrite for String {
start_location_link(&mut self, _: ModuleDefId)56 fn start_location_link(&mut self, _: ModuleDefId) {}
57
end_location_link(&mut self)58 fn end_location_link(&mut self) {}
59 }
60
61 // `core::Formatter` will ignore metadata
62 impl HirWrite for fmt::Formatter<'_> {
start_location_link(&mut self, _: ModuleDefId)63 fn start_location_link(&mut self, _: ModuleDefId) {}
end_location_link(&mut self)64 fn end_location_link(&mut self) {}
65 }
66
67 pub struct HirFormatter<'a> {
68 pub db: &'a dyn HirDatabase,
69 fmt: &'a mut dyn HirWrite,
70 buf: String,
71 curr_size: usize,
72 pub(crate) max_size: Option<usize>,
73 omit_verbose_types: bool,
74 closure_style: ClosureStyle,
75 display_target: DisplayTarget,
76 }
77
78 impl HirFormatter<'_> {
start_location_link(&mut self, location: ModuleDefId)79 fn start_location_link(&mut self, location: ModuleDefId) {
80 self.fmt.start_location_link(location);
81 }
82
end_location_link(&mut self)83 fn end_location_link(&mut self) {
84 self.fmt.end_location_link();
85 }
86 }
87
88 pub trait HirDisplay {
hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError>89 fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError>;
90
91 /// Returns a `Display`able type that is human-readable.
into_displayable<'a>( &'a self, db: &'a dyn HirDatabase, max_size: Option<usize>, omit_verbose_types: bool, display_target: DisplayTarget, closure_style: ClosureStyle, ) -> HirDisplayWrapper<'a, Self> where Self: Sized,92 fn into_displayable<'a>(
93 &'a self,
94 db: &'a dyn HirDatabase,
95 max_size: Option<usize>,
96 omit_verbose_types: bool,
97 display_target: DisplayTarget,
98 closure_style: ClosureStyle,
99 ) -> HirDisplayWrapper<'a, Self>
100 where
101 Self: Sized,
102 {
103 assert!(
104 !matches!(display_target, DisplayTarget::SourceCode { .. }),
105 "HirDisplayWrapper cannot fail with DisplaySourceCodeError, use HirDisplay::hir_fmt directly instead"
106 );
107 HirDisplayWrapper {
108 db,
109 t: self,
110 max_size,
111 omit_verbose_types,
112 display_target,
113 closure_style,
114 }
115 }
116
117 /// Returns a `Display`able type that is human-readable.
118 /// Use this for showing types to the user (e.g. diagnostics)
display<'a>(&'a self, db: &'a dyn HirDatabase) -> HirDisplayWrapper<'a, Self> where Self: Sized,119 fn display<'a>(&'a self, db: &'a dyn HirDatabase) -> HirDisplayWrapper<'a, Self>
120 where
121 Self: Sized,
122 {
123 HirDisplayWrapper {
124 db,
125 t: self,
126 max_size: None,
127 omit_verbose_types: false,
128 closure_style: ClosureStyle::ImplFn,
129 display_target: DisplayTarget::Diagnostics,
130 }
131 }
132
133 /// Returns a `Display`able type that is human-readable and tries to be succinct.
134 /// Use this for showing types to the user where space is constrained (e.g. doc popups)
display_truncated<'a>( &'a self, db: &'a dyn HirDatabase, max_size: Option<usize>, ) -> HirDisplayWrapper<'a, Self> where Self: Sized,135 fn display_truncated<'a>(
136 &'a self,
137 db: &'a dyn HirDatabase,
138 max_size: Option<usize>,
139 ) -> HirDisplayWrapper<'a, Self>
140 where
141 Self: Sized,
142 {
143 HirDisplayWrapper {
144 db,
145 t: self,
146 max_size,
147 omit_verbose_types: true,
148 closure_style: ClosureStyle::ImplFn,
149 display_target: DisplayTarget::Diagnostics,
150 }
151 }
152
153 /// Returns a String representation of `self` that can be inserted into the given module.
154 /// Use this when generating code (e.g. assists)
display_source_code<'a>( &'a self, db: &'a dyn HirDatabase, module_id: ModuleId, allow_opaque: bool, ) -> Result<String, DisplaySourceCodeError>155 fn display_source_code<'a>(
156 &'a self,
157 db: &'a dyn HirDatabase,
158 module_id: ModuleId,
159 allow_opaque: bool,
160 ) -> Result<String, DisplaySourceCodeError> {
161 let mut result = String::new();
162 match self.hir_fmt(&mut HirFormatter {
163 db,
164 fmt: &mut result,
165 buf: String::with_capacity(20),
166 curr_size: 0,
167 max_size: None,
168 omit_verbose_types: false,
169 closure_style: ClosureStyle::ImplFn,
170 display_target: DisplayTarget::SourceCode { module_id, allow_opaque },
171 }) {
172 Ok(()) => {}
173 Err(HirDisplayError::FmtError) => panic!("Writing to String can't fail!"),
174 Err(HirDisplayError::DisplaySourceCodeError(e)) => return Err(e),
175 };
176 Ok(result)
177 }
178
179 /// Returns a String representation of `self` for test purposes
display_test<'a>(&'a self, db: &'a dyn HirDatabase) -> HirDisplayWrapper<'a, Self> where Self: Sized,180 fn display_test<'a>(&'a self, db: &'a dyn HirDatabase) -> HirDisplayWrapper<'a, Self>
181 where
182 Self: Sized,
183 {
184 HirDisplayWrapper {
185 db,
186 t: self,
187 max_size: None,
188 omit_verbose_types: false,
189 closure_style: ClosureStyle::ImplFn,
190 display_target: DisplayTarget::Test,
191 }
192 }
193 }
194
195 impl<'a> HirFormatter<'a> {
write_joined<T: HirDisplay>( &mut self, iter: impl IntoIterator<Item = T>, sep: &str, ) -> Result<(), HirDisplayError>196 pub fn write_joined<T: HirDisplay>(
197 &mut self,
198 iter: impl IntoIterator<Item = T>,
199 sep: &str,
200 ) -> Result<(), HirDisplayError> {
201 let mut first = true;
202 for e in iter {
203 if !first {
204 write!(self, "{sep}")?;
205 }
206 first = false;
207
208 // Abbreviate multiple omitted types with a single ellipsis.
209 if self.should_truncate() {
210 return write!(self, "{TYPE_HINT_TRUNCATION}");
211 }
212
213 e.hir_fmt(self)?;
214 }
215 Ok(())
216 }
217
218 /// This allows using the `write!` macro directly with a `HirFormatter`.
write_fmt(&mut self, args: fmt::Arguments<'_>) -> Result<(), HirDisplayError>219 pub fn write_fmt(&mut self, args: fmt::Arguments<'_>) -> Result<(), HirDisplayError> {
220 // We write to a buffer first to track output size
221 self.buf.clear();
222 fmt::write(&mut self.buf, args)?;
223 self.curr_size += self.buf.len();
224
225 // Then we write to the internal formatter from the buffer
226 self.fmt.write_str(&self.buf).map_err(HirDisplayError::from)
227 }
228
write_str(&mut self, s: &str) -> Result<(), HirDisplayError>229 pub fn write_str(&mut self, s: &str) -> Result<(), HirDisplayError> {
230 self.fmt.write_str(s)?;
231 Ok(())
232 }
233
write_char(&mut self, c: char) -> Result<(), HirDisplayError>234 pub fn write_char(&mut self, c: char) -> Result<(), HirDisplayError> {
235 self.fmt.write_char(c)?;
236 Ok(())
237 }
238
should_truncate(&self) -> bool239 pub fn should_truncate(&self) -> bool {
240 match self.max_size {
241 Some(max_size) => self.curr_size >= max_size,
242 None => false,
243 }
244 }
245
omit_verbose_types(&self) -> bool246 pub fn omit_verbose_types(&self) -> bool {
247 self.omit_verbose_types
248 }
249 }
250
251 #[derive(Clone, Copy)]
252 pub enum DisplayTarget {
253 /// Display types for inlays, doc popups, autocompletion, etc...
254 /// Showing `{unknown}` or not qualifying paths is fine here.
255 /// There's no reason for this to fail.
256 Diagnostics,
257 /// Display types for inserting them in source files.
258 /// The generated code should compile, so paths need to be qualified.
259 SourceCode { module_id: ModuleId, allow_opaque: bool },
260 /// Only for test purpose to keep real types
261 Test,
262 }
263
264 impl DisplayTarget {
is_source_code(self) -> bool265 fn is_source_code(self) -> bool {
266 matches!(self, Self::SourceCode { .. })
267 }
268
is_test(self) -> bool269 fn is_test(self) -> bool {
270 matches!(self, Self::Test)
271 }
272
allows_opaque(self) -> bool273 fn allows_opaque(self) -> bool {
274 match self {
275 Self::SourceCode { allow_opaque, .. } => allow_opaque,
276 _ => true,
277 }
278 }
279 }
280
281 #[derive(Debug)]
282 pub enum DisplaySourceCodeError {
283 PathNotFound,
284 UnknownType,
285 Generator,
286 OpaqueType,
287 }
288
289 pub enum HirDisplayError {
290 /// Errors that can occur when generating source code
291 DisplaySourceCodeError(DisplaySourceCodeError),
292 /// `FmtError` is required to be compatible with std::fmt::Display
293 FmtError,
294 }
295 impl From<fmt::Error> for HirDisplayError {
from(_: fmt::Error) -> Self296 fn from(_: fmt::Error) -> Self {
297 Self::FmtError
298 }
299 }
300
301 pub struct HirDisplayWrapper<'a, T> {
302 db: &'a dyn HirDatabase,
303 t: &'a T,
304 max_size: Option<usize>,
305 omit_verbose_types: bool,
306 closure_style: ClosureStyle,
307 display_target: DisplayTarget,
308 }
309
310 #[derive(Debug, PartialEq, Eq, Clone, Copy)]
311 pub enum ClosureStyle {
312 /// `impl FnX(i32, i32) -> i32`, where `FnX` is the most special trait between `Fn`, `FnMut`, `FnOnce` that the
313 /// closure implements. This is the default.
314 ImplFn,
315 /// `|i32, i32| -> i32`
316 RANotation,
317 /// `{closure#14825}`, useful for some diagnostics (like type mismatch) and internal usage.
318 ClosureWithId,
319 /// `{closure#14825}<i32, ()>`, useful for internal usage.
320 ClosureWithSubst,
321 /// `…`, which is the `TYPE_HINT_TRUNCATION`
322 Hide,
323 }
324
325 impl<T: HirDisplay> HirDisplayWrapper<'_, T> {
write_to<F: HirWrite>(&self, f: &mut F) -> Result<(), HirDisplayError>326 pub fn write_to<F: HirWrite>(&self, f: &mut F) -> Result<(), HirDisplayError> {
327 self.t.hir_fmt(&mut HirFormatter {
328 db: self.db,
329 fmt: f,
330 buf: String::with_capacity(20),
331 curr_size: 0,
332 max_size: self.max_size,
333 omit_verbose_types: self.omit_verbose_types,
334 display_target: self.display_target,
335 closure_style: self.closure_style,
336 })
337 }
338
with_closure_style(mut self, c: ClosureStyle) -> Self339 pub fn with_closure_style(mut self, c: ClosureStyle) -> Self {
340 self.closure_style = c;
341 self
342 }
343 }
344
345 impl<'a, T> fmt::Display for HirDisplayWrapper<'a, T>
346 where
347 T: HirDisplay,
348 {
fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result349 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
350 match self.write_to(f) {
351 Ok(()) => Ok(()),
352 Err(HirDisplayError::FmtError) => Err(fmt::Error),
353 Err(HirDisplayError::DisplaySourceCodeError(_)) => {
354 // This should never happen
355 panic!("HirDisplay::hir_fmt failed with DisplaySourceCodeError when calling Display::fmt!")
356 }
357 }
358 }
359 }
360
361 const TYPE_HINT_TRUNCATION: &str = "…";
362
363 impl<T: HirDisplay> HirDisplay for &'_ T {
hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError>364 fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> {
365 HirDisplay::hir_fmt(*self, f)
366 }
367 }
368
369 impl<T: HirDisplay + Internable> HirDisplay for Interned<T> {
hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError>370 fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> {
371 HirDisplay::hir_fmt(self.as_ref(), f)
372 }
373 }
374
375 impl HirDisplay for ProjectionTy {
hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError>376 fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> {
377 if f.should_truncate() {
378 return write!(f, "{TYPE_HINT_TRUNCATION}");
379 }
380
381 let trait_ref = self.trait_ref(f.db);
382 write!(f, "<")?;
383 fmt_trait_ref(f, &trait_ref, true)?;
384 write!(
385 f,
386 ">::{}",
387 f.db.type_alias_data(from_assoc_type_id(self.associated_ty_id))
388 .name
389 .display(f.db.upcast())
390 )?;
391 let proj_params_count =
392 self.substitution.len(Interner) - trait_ref.substitution.len(Interner);
393 let proj_params = &self.substitution.as_slice(Interner)[..proj_params_count];
394 if !proj_params.is_empty() {
395 write!(f, "<")?;
396 f.write_joined(proj_params, ", ")?;
397 write!(f, ">")?;
398 }
399 Ok(())
400 }
401 }
402
403 impl HirDisplay for OpaqueTy {
hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError>404 fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> {
405 if f.should_truncate() {
406 return write!(f, "{TYPE_HINT_TRUNCATION}");
407 }
408
409 self.substitution.at(Interner, 0).hir_fmt(f)
410 }
411 }
412
413 impl HirDisplay for GenericArg {
hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError>414 fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> {
415 match self.interned() {
416 crate::GenericArgData::Ty(ty) => ty.hir_fmt(f),
417 crate::GenericArgData::Lifetime(lt) => lt.hir_fmt(f),
418 crate::GenericArgData::Const(c) => c.hir_fmt(f),
419 }
420 }
421 }
422
423 impl HirDisplay for Const {
hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError>424 fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> {
425 let data = self.interned();
426 match &data.value {
427 ConstValue::BoundVar(idx) => idx.hir_fmt(f),
428 ConstValue::InferenceVar(..) => write!(f, "#c#"),
429 ConstValue::Placeholder(idx) => {
430 let id = from_placeholder_idx(f.db, *idx);
431 let generics = generics(f.db.upcast(), id.parent);
432 let param_data = &generics.params.type_or_consts[id.local_id];
433 write!(f, "{}", param_data.name().unwrap().display(f.db.upcast()))?;
434 Ok(())
435 }
436 ConstValue::Concrete(c) => match &c.interned {
437 ConstScalar::Bytes(b, m) => render_const_scalar(f, &b, m, &data.ty),
438 ConstScalar::UnevaluatedConst(c, parameters) => {
439 write!(f, "{}", c.name(f.db.upcast()))?;
440 hir_fmt_generics(f, parameters, c.generic_def(f.db.upcast()))?;
441 Ok(())
442 }
443 ConstScalar::Unknown => f.write_char('_'),
444 },
445 }
446 }
447 }
448
449 pub struct HexifiedConst(pub Const);
450
451 impl HirDisplay for HexifiedConst {
hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError>452 fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> {
453 let data = &self.0.data(Interner);
454 if let TyKind::Scalar(s) = data.ty.kind(Interner) {
455 if matches!(s, Scalar::Int(_) | Scalar::Uint(_)) {
456 if let ConstValue::Concrete(c) = &data.value {
457 if let ConstScalar::Bytes(b, m) = &c.interned {
458 let value = u128::from_le_bytes(pad16(b, false));
459 if value >= 10 {
460 render_const_scalar(f, &b, m, &data.ty)?;
461 return write!(f, " ({:#X})", value);
462 }
463 }
464 }
465 }
466 }
467 self.0.hir_fmt(f)
468 }
469 }
470
render_const_scalar( f: &mut HirFormatter<'_>, b: &[u8], memory_map: &MemoryMap, ty: &Ty, ) -> Result<(), HirDisplayError>471 fn render_const_scalar(
472 f: &mut HirFormatter<'_>,
473 b: &[u8],
474 memory_map: &MemoryMap,
475 ty: &Ty,
476 ) -> Result<(), HirDisplayError> {
477 // FIXME: We need to get krate from the final callers of the hir display
478 // infrastructure and have it here as a field on `f`.
479 let krate = *f.db.crate_graph().crates_in_topological_order().last().unwrap();
480 match ty.kind(Interner) {
481 TyKind::Scalar(s) => match s {
482 Scalar::Bool => write!(f, "{}", if b[0] == 0 { false } else { true }),
483 Scalar::Char => {
484 let x = u128::from_le_bytes(pad16(b, false)) as u32;
485 let Ok(c) = char::try_from(x) else {
486 return f.write_str("<unicode-error>");
487 };
488 write!(f, "{c:?}")
489 }
490 Scalar::Int(_) => {
491 let x = i128::from_le_bytes(pad16(b, true));
492 write!(f, "{x}")
493 }
494 Scalar::Uint(_) => {
495 let x = u128::from_le_bytes(pad16(b, false));
496 write!(f, "{x}")
497 }
498 Scalar::Float(fl) => match fl {
499 chalk_ir::FloatTy::F32 => {
500 let x = f32::from_le_bytes(b.try_into().unwrap());
501 write!(f, "{x:?}")
502 }
503 chalk_ir::FloatTy::F64 => {
504 let x = f64::from_le_bytes(b.try_into().unwrap());
505 write!(f, "{x:?}")
506 }
507 },
508 },
509 TyKind::Ref(_, _, t) => match t.kind(Interner) {
510 TyKind::Str => {
511 let addr = usize::from_le_bytes(b[0..b.len() / 2].try_into().unwrap());
512 let size = usize::from_le_bytes(b[b.len() / 2..].try_into().unwrap());
513 let Some(bytes) = memory_map.get(addr, size) else {
514 return f.write_str("<ref-data-not-available>");
515 };
516 let s = std::str::from_utf8(&bytes).unwrap_or("<utf8-error>");
517 write!(f, "{s:?}")
518 }
519 TyKind::Slice(ty) => {
520 let addr = usize::from_le_bytes(b[0..b.len() / 2].try_into().unwrap());
521 let count = usize::from_le_bytes(b[b.len() / 2..].try_into().unwrap());
522 let Ok(layout) = f.db.layout_of_ty(ty.clone(), krate) else {
523 return f.write_str("<layout-error>");
524 };
525 let size_one = layout.size.bytes_usize();
526 let Some(bytes) = memory_map.get(addr, size_one * count) else {
527 return f.write_str("<ref-data-not-available>");
528 };
529 f.write_str("&[")?;
530 let mut first = true;
531 for i in 0..count {
532 if first {
533 first = false;
534 } else {
535 f.write_str(", ")?;
536 }
537 let offset = size_one * i;
538 render_const_scalar(f, &bytes[offset..offset + size_one], memory_map, &ty)?;
539 }
540 f.write_str("]")
541 }
542 TyKind::Dyn(_) => {
543 let addr = usize::from_le_bytes(b[0..b.len() / 2].try_into().unwrap());
544 let ty_id = usize::from_le_bytes(b[b.len() / 2..].try_into().unwrap());
545 let Ok(t) = memory_map.vtable.ty(ty_id) else {
546 return f.write_str("<ty-missing-in-vtable-map>");
547 };
548 let Ok(layout) = f.db.layout_of_ty(t.clone(), krate) else {
549 return f.write_str("<layout-error>");
550 };
551 let size = layout.size.bytes_usize();
552 let Some(bytes) = memory_map.get(addr, size) else {
553 return f.write_str("<ref-data-not-available>");
554 };
555 f.write_str("&")?;
556 render_const_scalar(f, bytes, memory_map, t)
557 }
558 TyKind::Adt(adt, _) if b.len() == 2 * size_of::<usize>() => match adt.0 {
559 hir_def::AdtId::StructId(s) => {
560 let data = f.db.struct_data(s);
561 write!(f, "&{}", data.name.display(f.db.upcast()))?;
562 Ok(())
563 }
564 _ => {
565 return f.write_str("<unsized-enum-or-union>");
566 }
567 },
568 _ => {
569 let addr = usize::from_le_bytes(match b.try_into() {
570 Ok(b) => b,
571 Err(_) => {
572 never!(
573 "tried rendering ty {:?} in const ref with incorrect byte count {}",
574 t,
575 b.len()
576 );
577 return f.write_str("<layout-error>");
578 }
579 });
580 let Ok(layout) = f.db.layout_of_ty(t.clone(), krate) else {
581 return f.write_str("<layout-error>");
582 };
583 let size = layout.size.bytes_usize();
584 let Some(bytes) = memory_map.get(addr, size) else {
585 return f.write_str("<ref-data-not-available>");
586 };
587 f.write_str("&")?;
588 render_const_scalar(f, bytes, memory_map, t)
589 }
590 },
591 TyKind::Tuple(_, subst) => {
592 let Ok(layout) = f.db.layout_of_ty(ty.clone(), krate) else {
593 return f.write_str("<layout-error>");
594 };
595 f.write_str("(")?;
596 let mut first = true;
597 for (id, ty) in subst.iter(Interner).enumerate() {
598 if first {
599 first = false;
600 } else {
601 f.write_str(", ")?;
602 }
603 let ty = ty.assert_ty_ref(Interner); // Tuple only has type argument
604 let offset = layout.fields.offset(id).bytes_usize();
605 let Ok(layout) = f.db.layout_of_ty(ty.clone(), krate) else {
606 f.write_str("<layout-error>")?;
607 continue;
608 };
609 let size = layout.size.bytes_usize();
610 render_const_scalar(f, &b[offset..offset + size], memory_map, &ty)?;
611 }
612 f.write_str(")")
613 }
614 TyKind::Adt(adt, subst) => {
615 let Ok(layout) = f.db.layout_of_adt(adt.0, subst.clone(), krate) else {
616 return f.write_str("<layout-error>");
617 };
618 match adt.0 {
619 hir_def::AdtId::StructId(s) => {
620 let data = f.db.struct_data(s);
621 write!(f, "{}", data.name.display(f.db.upcast()))?;
622 let field_types = f.db.field_types(s.into());
623 render_variant_after_name(
624 &data.variant_data,
625 f,
626 &field_types,
627 adt.0.module(f.db.upcast()).krate(),
628 &layout,
629 subst,
630 b,
631 memory_map,
632 )
633 }
634 hir_def::AdtId::UnionId(u) => {
635 write!(f, "{}", f.db.union_data(u).name.display(f.db.upcast()))
636 }
637 hir_def::AdtId::EnumId(e) => {
638 let Some((var_id, var_layout)) =
639 detect_variant_from_bytes(&layout, f.db, krate, b, e) else {
640 return f.write_str("<failed-to-detect-variant>");
641 };
642 let data = &f.db.enum_data(e).variants[var_id];
643 write!(f, "{}", data.name.display(f.db.upcast()))?;
644 let field_types =
645 f.db.field_types(EnumVariantId { parent: e, local_id: var_id }.into());
646 render_variant_after_name(
647 &data.variant_data,
648 f,
649 &field_types,
650 adt.0.module(f.db.upcast()).krate(),
651 &var_layout,
652 subst,
653 b,
654 memory_map,
655 )
656 }
657 }
658 }
659 TyKind::FnDef(..) => ty.hir_fmt(f),
660 TyKind::Function(_) | TyKind::Raw(_, _) => {
661 let x = u128::from_le_bytes(pad16(b, false));
662 write!(f, "{:#X} as ", x)?;
663 ty.hir_fmt(f)
664 }
665 TyKind::Array(ty, len) => {
666 let Some(len) = try_const_usize(f.db, len) else {
667 return f.write_str("<unknown-array-len>");
668 };
669 let Ok(layout) = f.db.layout_of_ty(ty.clone(), krate) else {
670 return f.write_str("<layout-error>");
671 };
672 let size_one = layout.size.bytes_usize();
673 f.write_str("[")?;
674 let mut first = true;
675 for i in 0..len as usize {
676 if first {
677 first = false;
678 } else {
679 f.write_str(", ")?;
680 }
681 let offset = size_one * i;
682 render_const_scalar(f, &b[offset..offset + size_one], memory_map, &ty)?;
683 }
684 f.write_str("]")
685 }
686 TyKind::Never => f.write_str("!"),
687 TyKind::Closure(_, _) => f.write_str("<closure>"),
688 TyKind::Generator(_, _) => f.write_str("<generator>"),
689 TyKind::GeneratorWitness(_, _) => f.write_str("<generator-witness>"),
690 // The below arms are unreachable, since const eval will bail out before here.
691 TyKind::Foreign(_) => f.write_str("<extern-type>"),
692 TyKind::Error
693 | TyKind::Placeholder(_)
694 | TyKind::Alias(_)
695 | TyKind::AssociatedType(_, _)
696 | TyKind::OpaqueType(_, _)
697 | TyKind::BoundVar(_)
698 | TyKind::InferenceVar(_, _) => f.write_str("<placeholder-or-unknown-type>"),
699 // The below arms are unreachable, since we handled them in ref case.
700 TyKind::Slice(_) | TyKind::Str | TyKind::Dyn(_) => f.write_str("<unsized-value>"),
701 }
702 }
703
render_variant_after_name( data: &VariantData, f: &mut HirFormatter<'_>, field_types: &ArenaMap<LocalFieldId, Binders<Ty>>, krate: CrateId, layout: &Layout, subst: &Substitution, b: &[u8], memory_map: &MemoryMap, ) -> Result<(), HirDisplayError>704 fn render_variant_after_name(
705 data: &VariantData,
706 f: &mut HirFormatter<'_>,
707 field_types: &ArenaMap<LocalFieldId, Binders<Ty>>,
708 krate: CrateId,
709 layout: &Layout,
710 subst: &Substitution,
711 b: &[u8],
712 memory_map: &MemoryMap,
713 ) -> Result<(), HirDisplayError> {
714 match data {
715 VariantData::Record(fields) | VariantData::Tuple(fields) => {
716 let render_field = |f: &mut HirFormatter<'_>, id: LocalFieldId| {
717 let offset = layout.fields.offset(u32::from(id.into_raw()) as usize).bytes_usize();
718 let ty = field_types[id].clone().substitute(Interner, subst);
719 let Ok(layout) = f.db.layout_of_ty(ty.clone(), krate) else {
720 return f.write_str("<layout-error>");
721 };
722 let size = layout.size.bytes_usize();
723 render_const_scalar(f, &b[offset..offset + size], memory_map, &ty)
724 };
725 let mut it = fields.iter();
726 if matches!(data, VariantData::Record(_)) {
727 write!(f, " {{")?;
728 if let Some((id, data)) = it.next() {
729 write!(f, " {}: ", data.name.display(f.db.upcast()))?;
730 render_field(f, id)?;
731 }
732 for (id, data) in it {
733 write!(f, ", {}: ", data.name.display(f.db.upcast()))?;
734 render_field(f, id)?;
735 }
736 write!(f, " }}")?;
737 } else {
738 let mut it = it.map(|x| x.0);
739 write!(f, "(")?;
740 if let Some(id) = it.next() {
741 render_field(f, id)?;
742 }
743 for id in it {
744 write!(f, ", ")?;
745 render_field(f, id)?;
746 }
747 write!(f, ")")?;
748 }
749 return Ok(());
750 }
751 VariantData::Unit => Ok(()),
752 }
753 }
754
755 impl HirDisplay for BoundVar {
hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError>756 fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> {
757 write!(f, "?{}.{}", self.debruijn.depth(), self.index)
758 }
759 }
760
761 impl HirDisplay for Ty {
762 fn hir_fmt(
763 &self,
764 f @ &mut HirFormatter { db, .. }: &mut HirFormatter<'_>,
765 ) -> Result<(), HirDisplayError> {
766 if f.should_truncate() {
767 return write!(f, "{TYPE_HINT_TRUNCATION}");
768 }
769
770 match self.kind(Interner) {
771 TyKind::Never => write!(f, "!")?,
772 TyKind::Str => write!(f, "str")?,
773 TyKind::Scalar(Scalar::Bool) => write!(f, "bool")?,
774 TyKind::Scalar(Scalar::Char) => write!(f, "char")?,
775 &TyKind::Scalar(Scalar::Float(t)) => write!(f, "{}", primitive::float_ty_to_string(t))?,
776 &TyKind::Scalar(Scalar::Int(t)) => write!(f, "{}", primitive::int_ty_to_string(t))?,
777 &TyKind::Scalar(Scalar::Uint(t)) => write!(f, "{}", primitive::uint_ty_to_string(t))?,
778 TyKind::Slice(t) => {
779 write!(f, "[")?;
780 t.hir_fmt(f)?;
781 write!(f, "]")?;
782 }
783 TyKind::Array(t, c) => {
784 write!(f, "[")?;
785 t.hir_fmt(f)?;
786 write!(f, "; ")?;
787 c.hir_fmt(f)?;
788 write!(f, "]")?;
789 }
790 TyKind::Raw(m, t) | TyKind::Ref(m, _, t) => {
791 if matches!(self.kind(Interner), TyKind::Raw(..)) {
792 write!(
793 f,
794 "*{}",
795 match m {
796 Mutability::Not => "const ",
797 Mutability::Mut => "mut ",
798 }
799 )?;
800 } else {
801 write!(
802 f,
803 "&{}",
804 match m {
805 Mutability::Not => "",
806 Mutability::Mut => "mut ",
807 }
808 )?;
809 }
810
811 // FIXME: all this just to decide whether to use parentheses...
812 let contains_impl_fn = |bounds: &[QuantifiedWhereClause]| {
813 bounds.iter().any(|bound| {
814 if let WhereClause::Implemented(trait_ref) = bound.skip_binders() {
815 let trait_ = trait_ref.hir_trait_id();
816 fn_traits(db.upcast(), trait_).any(|it| it == trait_)
817 } else {
818 false
819 }
820 })
821 };
822 let (preds_to_print, has_impl_fn_pred) = match t.kind(Interner) {
823 TyKind::Dyn(dyn_ty) if dyn_ty.bounds.skip_binders().interned().len() > 1 => {
824 let bounds = dyn_ty.bounds.skip_binders().interned();
825 (bounds.len(), contains_impl_fn(bounds))
826 }
827 TyKind::Alias(AliasTy::Opaque(OpaqueTy {
828 opaque_ty_id,
829 substitution: parameters,
830 }))
831 | TyKind::OpaqueType(opaque_ty_id, parameters) => {
832 let impl_trait_id = db.lookup_intern_impl_trait_id((*opaque_ty_id).into());
833 if let ImplTraitId::ReturnTypeImplTrait(func, idx) = impl_trait_id {
834 let datas = db
835 .return_type_impl_traits(func)
836 .expect("impl trait id without data");
837 let data =
838 (*datas).as_ref().map(|rpit| rpit.impl_traits[idx].bounds.clone());
839 let bounds = data.substitute(Interner, parameters);
840 let mut len = bounds.skip_binders().len();
841
842 // Don't count Sized but count when it absent
843 // (i.e. when explicit ?Sized bound is set).
844 let default_sized = SizedByDefault::Sized {
845 anchor: func.lookup(db.upcast()).module(db.upcast()).krate(),
846 };
847 let sized_bounds = bounds
848 .skip_binders()
849 .iter()
850 .filter(|b| {
851 matches!(
852 b.skip_binders(),
853 WhereClause::Implemented(trait_ref)
854 if default_sized.is_sized_trait(
855 trait_ref.hir_trait_id(),
856 db.upcast(),
857 ),
858 )
859 })
860 .count();
861 match sized_bounds {
862 0 => len += 1,
863 _ => {
864 len = len.saturating_sub(sized_bounds);
865 }
866 }
867
868 (len, contains_impl_fn(bounds.skip_binders()))
869 } else {
870 (0, false)
871 }
872 }
873 _ => (0, false),
874 };
875
876 if has_impl_fn_pred && preds_to_print <= 2 {
877 return t.hir_fmt(f);
878 }
879
880 if preds_to_print > 1 {
881 write!(f, "(")?;
882 t.hir_fmt(f)?;
883 write!(f, ")")?;
884 } else {
885 t.hir_fmt(f)?;
886 }
887 }
888 TyKind::Tuple(_, substs) => {
889 if substs.len(Interner) == 1 {
890 write!(f, "(")?;
891 substs.at(Interner, 0).hir_fmt(f)?;
892 write!(f, ",)")?;
893 } else {
894 write!(f, "(")?;
895 f.write_joined(&*substs.as_slice(Interner), ", ")?;
896 write!(f, ")")?;
897 }
898 }
899 TyKind::Function(fn_ptr) => {
900 let sig = CallableSig::from_fn_ptr(fn_ptr);
901 sig.hir_fmt(f)?;
902 }
903 TyKind::FnDef(def, parameters) => {
904 let def = from_chalk(db, *def);
905 let sig = db.callable_item_signature(def).substitute(Interner, parameters);
906 f.start_location_link(def.into());
907 match def {
908 CallableDefId::FunctionId(ff) => {
909 write!(f, "fn {}", db.function_data(ff).name.display(f.db.upcast()))?
910 }
911 CallableDefId::StructId(s) => {
912 write!(f, "{}", db.struct_data(s).name.display(f.db.upcast()))?
913 }
914 CallableDefId::EnumVariantId(e) => write!(
915 f,
916 "{}",
917 db.enum_data(e.parent).variants[e.local_id].name.display(f.db.upcast())
918 )?,
919 };
920 f.end_location_link();
921 if parameters.len(Interner) > 0 {
922 let generics = generics(db.upcast(), def.into());
923 let (parent_params, self_param, type_params, const_params, _impl_trait_params) =
924 generics.provenance_split();
925 let total_len = parent_params + self_param + type_params + const_params;
926 // We print all params except implicit impl Trait params. Still a bit weird; should we leave out parent and self?
927 if total_len > 0 {
928 // `parameters` are in the order of fn's params (including impl traits),
929 // parent's params (those from enclosing impl or trait, if any).
930 let parameters = parameters.as_slice(Interner);
931 let fn_params_len = self_param + type_params + const_params;
932 let fn_params = parameters.get(..fn_params_len);
933 let parent_params = parameters.get(parameters.len() - parent_params..);
934 let params = parent_params.into_iter().chain(fn_params).flatten();
935 write!(f, "<")?;
936 f.write_joined(params, ", ")?;
937 write!(f, ">")?;
938 }
939 }
940 write!(f, "(")?;
941 f.write_joined(sig.params(), ", ")?;
942 write!(f, ")")?;
943 let ret = sig.ret();
944 if !ret.is_unit() {
945 write!(f, " -> ")?;
946 ret.hir_fmt(f)?;
947 }
948 }
949 TyKind::Adt(AdtId(def_id), parameters) => {
950 f.start_location_link((*def_id).into());
951 match f.display_target {
952 DisplayTarget::Diagnostics | DisplayTarget::Test => {
953 let name = match *def_id {
954 hir_def::AdtId::StructId(it) => db.struct_data(it).name.clone(),
955 hir_def::AdtId::UnionId(it) => db.union_data(it).name.clone(),
956 hir_def::AdtId::EnumId(it) => db.enum_data(it).name.clone(),
957 };
958 write!(f, "{}", name.display(f.db.upcast()))?;
959 }
960 DisplayTarget::SourceCode { module_id, allow_opaque: _ } => {
961 if let Some(path) = find_path::find_path(
962 db.upcast(),
963 ItemInNs::Types((*def_id).into()),
964 module_id,
965 false,
966 ) {
967 write!(f, "{}", path.display(f.db.upcast()))?;
968 } else {
969 return Err(HirDisplayError::DisplaySourceCodeError(
970 DisplaySourceCodeError::PathNotFound,
971 ));
972 }
973 }
974 }
975 f.end_location_link();
976
977 let generic_def = self.as_generic_def(db);
978
979 hir_fmt_generics(f, parameters, generic_def)?;
980 }
981 TyKind::AssociatedType(assoc_type_id, parameters) => {
982 let type_alias = from_assoc_type_id(*assoc_type_id);
983 let trait_ = match type_alias.lookup(db.upcast()).container {
984 ItemContainerId::TraitId(it) => it,
985 _ => panic!("not an associated type"),
986 };
987 let trait_data = db.trait_data(trait_);
988 let type_alias_data = db.type_alias_data(type_alias);
989
990 // Use placeholder associated types when the target is test (https://rust-lang.github.io/chalk/book/clauses/type_equality.html#placeholder-associated-types)
991 if f.display_target.is_test() {
992 f.start_location_link(trait_.into());
993 write!(f, "{}", trait_data.name.display(f.db.upcast()))?;
994 f.end_location_link();
995 write!(f, "::")?;
996
997 f.start_location_link(type_alias.into());
998 write!(f, "{}", type_alias_data.name.display(f.db.upcast()))?;
999 f.end_location_link();
1000 // Note that the generic args for the associated type come before those for the
1001 // trait (including the self type).
1002 // FIXME: reconsider the generic args order upon formatting?
1003 if parameters.len(Interner) > 0 {
1004 write!(f, "<")?;
1005 f.write_joined(parameters.as_slice(Interner), ", ")?;
1006 write!(f, ">")?;
1007 }
1008 } else {
1009 let projection_ty = ProjectionTy {
1010 associated_ty_id: to_assoc_type_id(type_alias),
1011 substitution: parameters.clone(),
1012 };
1013
1014 projection_ty.hir_fmt(f)?;
1015 }
1016 }
1017 TyKind::Foreign(type_alias) => {
1018 let alias = from_foreign_def_id(*type_alias);
1019 let type_alias = db.type_alias_data(alias);
1020 f.start_location_link(alias.into());
1021 write!(f, "{}", type_alias.name.display(f.db.upcast()))?;
1022 f.end_location_link();
1023 }
1024 TyKind::OpaqueType(opaque_ty_id, parameters) => {
1025 if !f.display_target.allows_opaque() {
1026 return Err(HirDisplayError::DisplaySourceCodeError(
1027 DisplaySourceCodeError::OpaqueType,
1028 ));
1029 }
1030 let impl_trait_id = db.lookup_intern_impl_trait_id((*opaque_ty_id).into());
1031 match impl_trait_id {
1032 ImplTraitId::ReturnTypeImplTrait(func, idx) => {
1033 let datas =
1034 db.return_type_impl_traits(func).expect("impl trait id without data");
1035 let data =
1036 (*datas).as_ref().map(|rpit| rpit.impl_traits[idx].bounds.clone());
1037 let bounds = data.substitute(Interner, ¶meters);
1038 let krate = func.lookup(db.upcast()).module(db.upcast()).krate();
1039 write_bounds_like_dyn_trait_with_prefix(
1040 f,
1041 "impl",
1042 bounds.skip_binders(),
1043 SizedByDefault::Sized { anchor: krate },
1044 )?;
1045 // FIXME: it would maybe be good to distinguish this from the alias type (when debug printing), and to show the substitution
1046 }
1047 ImplTraitId::AsyncBlockTypeImplTrait(body, ..) => {
1048 let future_trait = db
1049 .lang_item(body.module(db.upcast()).krate(), LangItem::Future)
1050 .and_then(LangItemTarget::as_trait);
1051 let output = future_trait.and_then(|t| {
1052 db.trait_data(t).associated_type_by_name(&hir_expand::name!(Output))
1053 });
1054 write!(f, "impl ")?;
1055 if let Some(t) = future_trait {
1056 f.start_location_link(t.into());
1057 }
1058 write!(f, "Future")?;
1059 if let Some(_) = future_trait {
1060 f.end_location_link();
1061 }
1062 write!(f, "<")?;
1063 if let Some(t) = output {
1064 f.start_location_link(t.into());
1065 }
1066 write!(f, "Output")?;
1067 if let Some(_) = output {
1068 f.end_location_link();
1069 }
1070 write!(f, " = ")?;
1071 parameters.at(Interner, 0).hir_fmt(f)?;
1072 write!(f, ">")?;
1073 }
1074 }
1075 }
1076 TyKind::Closure(id, substs) => {
1077 if f.display_target.is_source_code() {
1078 if !f.display_target.allows_opaque() {
1079 return Err(HirDisplayError::DisplaySourceCodeError(
1080 DisplaySourceCodeError::OpaqueType,
1081 ));
1082 } else if f.closure_style != ClosureStyle::ImplFn {
1083 never!("Only `impl Fn` is valid for displaying closures in source code");
1084 }
1085 }
1086 match f.closure_style {
1087 ClosureStyle::Hide => return write!(f, "{TYPE_HINT_TRUNCATION}"),
1088 ClosureStyle::ClosureWithId => {
1089 return write!(f, "{{closure#{:?}}}", id.0.as_u32())
1090 }
1091 ClosureStyle::ClosureWithSubst => {
1092 write!(f, "{{closure#{:?}}}", id.0.as_u32())?;
1093 return hir_fmt_generics(f, substs, None);
1094 }
1095 _ => (),
1096 }
1097 let sig = ClosureSubst(substs).sig_ty().callable_sig(db);
1098 if let Some(sig) = sig {
1099 let (def, _) = db.lookup_intern_closure((*id).into());
1100 let infer = db.infer(def);
1101 let (_, kind) = infer.closure_info(id);
1102 match f.closure_style {
1103 ClosureStyle::ImplFn => write!(f, "impl {kind:?}(")?,
1104 ClosureStyle::RANotation => write!(f, "|")?,
1105 _ => unreachable!(),
1106 }
1107 if sig.params().is_empty() {
1108 } else if f.should_truncate() {
1109 write!(f, "{TYPE_HINT_TRUNCATION}")?;
1110 } else {
1111 f.write_joined(sig.params(), ", ")?;
1112 };
1113 match f.closure_style {
1114 ClosureStyle::ImplFn => write!(f, ")")?,
1115 ClosureStyle::RANotation => write!(f, "|")?,
1116 _ => unreachable!(),
1117 }
1118 if f.closure_style == ClosureStyle::RANotation || !sig.ret().is_unit() {
1119 write!(f, " -> ")?;
1120 sig.ret().hir_fmt(f)?;
1121 }
1122 } else {
1123 write!(f, "{{closure}}")?;
1124 }
1125 }
1126 TyKind::Placeholder(idx) => {
1127 let id = from_placeholder_idx(db, *idx);
1128 let generics = generics(db.upcast(), id.parent);
1129 let param_data = &generics.params.type_or_consts[id.local_id];
1130 match param_data {
1131 TypeOrConstParamData::TypeParamData(p) => match p.provenance {
1132 TypeParamProvenance::TypeParamList | TypeParamProvenance::TraitSelf => {
1133 write!(
1134 f,
1135 "{}",
1136 p.name.clone().unwrap_or_else(Name::missing).display(f.db.upcast())
1137 )?
1138 }
1139 TypeParamProvenance::ArgumentImplTrait => {
1140 let substs = generics.placeholder_subst(db);
1141 let bounds = db
1142 .generic_predicates(id.parent)
1143 .iter()
1144 .map(|pred| pred.clone().substitute(Interner, &substs))
1145 .filter(|wc| match &wc.skip_binders() {
1146 WhereClause::Implemented(tr) => {
1147 &tr.self_type_parameter(Interner) == self
1148 }
1149 WhereClause::AliasEq(AliasEq {
1150 alias: AliasTy::Projection(proj),
1151 ty: _,
1152 }) => &proj.self_type_parameter(db) == self,
1153 _ => false,
1154 })
1155 .collect::<Vec<_>>();
1156 let krate = id.parent.module(db.upcast()).krate();
1157 write_bounds_like_dyn_trait_with_prefix(
1158 f,
1159 "impl",
1160 &bounds,
1161 SizedByDefault::Sized { anchor: krate },
1162 )?;
1163 }
1164 },
1165 TypeOrConstParamData::ConstParamData(p) => {
1166 write!(f, "{}", p.name.display(f.db.upcast()))?;
1167 }
1168 }
1169 }
1170 TyKind::BoundVar(idx) => idx.hir_fmt(f)?,
1171 TyKind::Dyn(dyn_ty) => {
1172 // Reorder bounds to satisfy `write_bounds_like_dyn_trait()`'s expectation.
1173 // FIXME: `Iterator::partition_in_place()` or `Vec::drain_filter()` may make it
1174 // more efficient when either of them hits stable.
1175 let mut bounds: SmallVec<[_; 4]> =
1176 dyn_ty.bounds.skip_binders().iter(Interner).cloned().collect();
1177 let (auto_traits, others): (SmallVec<[_; 4]>, _) =
1178 bounds.drain(1..).partition(|b| b.skip_binders().trait_id().is_some());
1179 bounds.extend(others);
1180 bounds.extend(auto_traits);
1181
1182 write_bounds_like_dyn_trait_with_prefix(
1183 f,
1184 "dyn",
1185 &bounds,
1186 SizedByDefault::NotSized,
1187 )?;
1188 }
1189 TyKind::Alias(AliasTy::Projection(p_ty)) => p_ty.hir_fmt(f)?,
1190 TyKind::Alias(AliasTy::Opaque(opaque_ty)) => {
1191 if !f.display_target.allows_opaque() {
1192 return Err(HirDisplayError::DisplaySourceCodeError(
1193 DisplaySourceCodeError::OpaqueType,
1194 ));
1195 }
1196 let impl_trait_id = db.lookup_intern_impl_trait_id(opaque_ty.opaque_ty_id.into());
1197 match impl_trait_id {
1198 ImplTraitId::ReturnTypeImplTrait(func, idx) => {
1199 let datas =
1200 db.return_type_impl_traits(func).expect("impl trait id without data");
1201 let data =
1202 (*datas).as_ref().map(|rpit| rpit.impl_traits[idx].bounds.clone());
1203 let bounds = data.substitute(Interner, &opaque_ty.substitution);
1204 let krate = func.lookup(db.upcast()).module(db.upcast()).krate();
1205 write_bounds_like_dyn_trait_with_prefix(
1206 f,
1207 "impl",
1208 bounds.skip_binders(),
1209 SizedByDefault::Sized { anchor: krate },
1210 )?;
1211 }
1212 ImplTraitId::AsyncBlockTypeImplTrait(..) => {
1213 write!(f, "{{async block}}")?;
1214 }
1215 };
1216 }
1217 TyKind::Error => {
1218 if f.display_target.is_source_code() {
1219 return Err(HirDisplayError::DisplaySourceCodeError(
1220 DisplaySourceCodeError::UnknownType,
1221 ));
1222 }
1223 write!(f, "{{unknown}}")?;
1224 }
1225 TyKind::InferenceVar(..) => write!(f, "_")?,
1226 TyKind::Generator(_, subst) => {
1227 if f.display_target.is_source_code() {
1228 return Err(HirDisplayError::DisplaySourceCodeError(
1229 DisplaySourceCodeError::Generator,
1230 ));
1231 }
1232 let subst = subst.as_slice(Interner);
1233 let a: Option<SmallVec<[&Ty; 3]>> = subst
1234 .get(subst.len() - 3..)
1235 .map(|args| args.iter().map(|arg| arg.ty(Interner)).collect())
1236 .flatten();
1237
1238 if let Some([resume_ty, yield_ty, ret_ty]) = a.as_deref() {
1239 write!(f, "|")?;
1240 resume_ty.hir_fmt(f)?;
1241 write!(f, "|")?;
1242
1243 write!(f, " yields ")?;
1244 yield_ty.hir_fmt(f)?;
1245
1246 write!(f, " -> ")?;
1247 ret_ty.hir_fmt(f)?;
1248 } else {
1249 // This *should* be unreachable, but fallback just in case.
1250 write!(f, "{{generator}}")?;
1251 }
1252 }
1253 TyKind::GeneratorWitness(..) => write!(f, "{{generator witness}}")?,
1254 }
1255 Ok(())
1256 }
1257 }
1258
hir_fmt_generics( f: &mut HirFormatter<'_>, parameters: &Substitution, generic_def: Option<hir_def::GenericDefId>, ) -> Result<(), HirDisplayError>1259 fn hir_fmt_generics(
1260 f: &mut HirFormatter<'_>,
1261 parameters: &Substitution,
1262 generic_def: Option<hir_def::GenericDefId>,
1263 ) -> Result<(), HirDisplayError> {
1264 let db = f.db;
1265 let lifetime_args_count = generic_def.map_or(0, |g| db.generic_params(g).lifetimes.len());
1266 if parameters.len(Interner) + lifetime_args_count > 0 {
1267 let parameters_to_write = if f.display_target.is_source_code() || f.omit_verbose_types() {
1268 match generic_def
1269 .map(|generic_def_id| db.generic_defaults(generic_def_id))
1270 .filter(|defaults| !defaults.is_empty())
1271 {
1272 None => parameters.as_slice(Interner),
1273 Some(default_parameters) => {
1274 fn should_show(
1275 parameter: &GenericArg,
1276 default_parameters: &[Binders<GenericArg>],
1277 i: usize,
1278 parameters: &Substitution,
1279 ) -> bool {
1280 if parameter.ty(Interner).map(|x| x.kind(Interner)) == Some(&TyKind::Error)
1281 {
1282 return true;
1283 }
1284 if let Some(ConstValue::Concrete(c)) =
1285 parameter.constant(Interner).map(|x| &x.data(Interner).value)
1286 {
1287 if c.interned == ConstScalar::Unknown {
1288 return true;
1289 }
1290 }
1291 let default_parameter = match default_parameters.get(i) {
1292 Some(x) => x,
1293 None => return true,
1294 };
1295 let actual_default =
1296 default_parameter.clone().substitute(Interner, ¶meters);
1297 parameter != &actual_default
1298 }
1299 let mut default_from = 0;
1300 for (i, parameter) in parameters.iter(Interner).enumerate() {
1301 if should_show(parameter, &default_parameters, i, parameters) {
1302 default_from = i + 1;
1303 }
1304 }
1305 ¶meters.as_slice(Interner)[0..default_from]
1306 }
1307 }
1308 } else {
1309 parameters.as_slice(Interner)
1310 };
1311 if !parameters_to_write.is_empty() || lifetime_args_count != 0 {
1312 write!(f, "<")?;
1313 let mut first = true;
1314 for _ in 0..lifetime_args_count {
1315 if !first {
1316 write!(f, ", ")?;
1317 }
1318 first = false;
1319 write!(f, "'_")?;
1320 }
1321 for generic_arg in parameters_to_write {
1322 if !first {
1323 write!(f, ", ")?;
1324 }
1325 first = false;
1326 if f.display_target.is_source_code()
1327 && generic_arg.ty(Interner).map(|ty| ty.kind(Interner)) == Some(&TyKind::Error)
1328 {
1329 write!(f, "_")?;
1330 } else {
1331 generic_arg.hir_fmt(f)?;
1332 }
1333 }
1334
1335 write!(f, ">")?;
1336 }
1337 }
1338 Ok(())
1339 }
1340
1341 impl HirDisplay for CallableSig {
hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError>1342 fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> {
1343 write!(f, "fn(")?;
1344 f.write_joined(self.params(), ", ")?;
1345 if self.is_varargs {
1346 if self.params().is_empty() {
1347 write!(f, "...")?;
1348 } else {
1349 write!(f, ", ...")?;
1350 }
1351 }
1352 write!(f, ")")?;
1353 let ret = self.ret();
1354 if !ret.is_unit() {
1355 write!(f, " -> ")?;
1356 ret.hir_fmt(f)?;
1357 }
1358 Ok(())
1359 }
1360 }
1361
fn_traits(db: &dyn DefDatabase, trait_: TraitId) -> impl Iterator<Item = TraitId> + '_1362 fn fn_traits(db: &dyn DefDatabase, trait_: TraitId) -> impl Iterator<Item = TraitId> + '_ {
1363 let krate = trait_.lookup(db).container.krate();
1364 utils::fn_traits(db, krate)
1365 }
1366
1367 #[derive(Clone, Copy, PartialEq, Eq)]
1368 pub enum SizedByDefault {
1369 NotSized,
1370 Sized { anchor: CrateId },
1371 }
1372
1373 impl SizedByDefault {
is_sized_trait(self, trait_: TraitId, db: &dyn DefDatabase) -> bool1374 fn is_sized_trait(self, trait_: TraitId, db: &dyn DefDatabase) -> bool {
1375 match self {
1376 Self::NotSized => false,
1377 Self::Sized { anchor } => {
1378 let sized_trait = db
1379 .lang_item(anchor, LangItem::Sized)
1380 .and_then(|lang_item| lang_item.as_trait());
1381 Some(trait_) == sized_trait
1382 }
1383 }
1384 }
1385 }
1386
write_bounds_like_dyn_trait_with_prefix( f: &mut HirFormatter<'_>, prefix: &str, predicates: &[QuantifiedWhereClause], default_sized: SizedByDefault, ) -> Result<(), HirDisplayError>1387 pub fn write_bounds_like_dyn_trait_with_prefix(
1388 f: &mut HirFormatter<'_>,
1389 prefix: &str,
1390 predicates: &[QuantifiedWhereClause],
1391 default_sized: SizedByDefault,
1392 ) -> Result<(), HirDisplayError> {
1393 write!(f, "{prefix}")?;
1394 if !predicates.is_empty()
1395 || predicates.is_empty() && matches!(default_sized, SizedByDefault::Sized { .. })
1396 {
1397 write!(f, " ")?;
1398 write_bounds_like_dyn_trait(f, predicates, default_sized)
1399 } else {
1400 Ok(())
1401 }
1402 }
1403
write_bounds_like_dyn_trait( f: &mut HirFormatter<'_>, predicates: &[QuantifiedWhereClause], default_sized: SizedByDefault, ) -> Result<(), HirDisplayError>1404 fn write_bounds_like_dyn_trait(
1405 f: &mut HirFormatter<'_>,
1406 predicates: &[QuantifiedWhereClause],
1407 default_sized: SizedByDefault,
1408 ) -> Result<(), HirDisplayError> {
1409 // Note: This code is written to produce nice results (i.e.
1410 // corresponding to surface Rust) for types that can occur in
1411 // actual Rust. It will have weird results if the predicates
1412 // aren't as expected (i.e. self types = $0, projection
1413 // predicates for a certain trait come after the Implemented
1414 // predicate for that trait).
1415 let mut first = true;
1416 let mut angle_open = false;
1417 let mut is_fn_trait = false;
1418 let mut is_sized = false;
1419 for p in predicates.iter() {
1420 match p.skip_binders() {
1421 WhereClause::Implemented(trait_ref) => {
1422 let trait_ = trait_ref.hir_trait_id();
1423 if default_sized.is_sized_trait(trait_, f.db.upcast()) {
1424 is_sized = true;
1425 if matches!(default_sized, SizedByDefault::Sized { .. }) {
1426 // Don't print +Sized, but rather +?Sized if absent.
1427 continue;
1428 }
1429 }
1430 if !is_fn_trait {
1431 is_fn_trait = fn_traits(f.db.upcast(), trait_).any(|it| it == trait_);
1432 }
1433 if !is_fn_trait && angle_open {
1434 write!(f, ">")?;
1435 angle_open = false;
1436 }
1437 if !first {
1438 write!(f, " + ")?;
1439 }
1440 // We assume that the self type is ^0.0 (i.e. the
1441 // existential) here, which is the only thing that's
1442 // possible in actual Rust, and hence don't print it
1443 f.start_location_link(trait_.into());
1444 write!(f, "{}", f.db.trait_data(trait_).name.display(f.db.upcast()))?;
1445 f.end_location_link();
1446 if let [_, params @ ..] = &*trait_ref.substitution.as_slice(Interner) {
1447 if is_fn_trait {
1448 if let Some(args) =
1449 params.first().and_then(|it| it.assert_ty_ref(Interner).as_tuple())
1450 {
1451 write!(f, "(")?;
1452 f.write_joined(args.as_slice(Interner), ", ")?;
1453 write!(f, ")")?;
1454 }
1455 } else if !params.is_empty() {
1456 write!(f, "<")?;
1457 f.write_joined(params, ", ")?;
1458 // there might be assoc type bindings, so we leave the angle brackets open
1459 angle_open = true;
1460 }
1461 }
1462 }
1463 WhereClause::AliasEq(alias_eq) if is_fn_trait => {
1464 is_fn_trait = false;
1465 if !alias_eq.ty.is_unit() {
1466 write!(f, " -> ")?;
1467 alias_eq.ty.hir_fmt(f)?;
1468 }
1469 }
1470 WhereClause::AliasEq(AliasEq { ty, alias }) => {
1471 // in types in actual Rust, these will always come
1472 // after the corresponding Implemented predicate
1473 if angle_open {
1474 write!(f, ", ")?;
1475 } else {
1476 write!(f, "<")?;
1477 angle_open = true;
1478 }
1479 if let AliasTy::Projection(proj) = alias {
1480 let assoc_ty_id = from_assoc_type_id(proj.associated_ty_id);
1481 let type_alias = f.db.type_alias_data(assoc_ty_id);
1482 f.start_location_link(assoc_ty_id.into());
1483 write!(f, "{}", type_alias.name.display(f.db.upcast()))?;
1484 f.end_location_link();
1485
1486 let proj_arg_count = generics(f.db.upcast(), assoc_ty_id.into()).len_self();
1487 if proj_arg_count > 0 {
1488 write!(f, "<")?;
1489 f.write_joined(
1490 &proj.substitution.as_slice(Interner)[..proj_arg_count],
1491 ", ",
1492 )?;
1493 write!(f, ">")?;
1494 }
1495 write!(f, " = ")?;
1496 }
1497 ty.hir_fmt(f)?;
1498 }
1499
1500 // FIXME implement these
1501 WhereClause::LifetimeOutlives(_) => {}
1502 WhereClause::TypeOutlives(_) => {}
1503 }
1504 first = false;
1505 }
1506 if angle_open {
1507 write!(f, ">")?;
1508 }
1509 if let SizedByDefault::Sized { anchor } = default_sized {
1510 let sized_trait =
1511 f.db.lang_item(anchor, LangItem::Sized).and_then(|lang_item| lang_item.as_trait());
1512 if !is_sized {
1513 if !first {
1514 write!(f, " + ")?;
1515 }
1516 if let Some(sized_trait) = sized_trait {
1517 f.start_location_link(sized_trait.into());
1518 }
1519 write!(f, "?Sized")?;
1520 } else if first {
1521 if let Some(sized_trait) = sized_trait {
1522 f.start_location_link(sized_trait.into());
1523 }
1524 write!(f, "Sized")?;
1525 }
1526 if let Some(_) = sized_trait {
1527 f.end_location_link();
1528 }
1529 }
1530 Ok(())
1531 }
1532
fmt_trait_ref( f: &mut HirFormatter<'_>, tr: &TraitRef, use_as: bool, ) -> Result<(), HirDisplayError>1533 fn fmt_trait_ref(
1534 f: &mut HirFormatter<'_>,
1535 tr: &TraitRef,
1536 use_as: bool,
1537 ) -> Result<(), HirDisplayError> {
1538 if f.should_truncate() {
1539 return write!(f, "{TYPE_HINT_TRUNCATION}");
1540 }
1541
1542 tr.self_type_parameter(Interner).hir_fmt(f)?;
1543 if use_as {
1544 write!(f, " as ")?;
1545 } else {
1546 write!(f, ": ")?;
1547 }
1548 let trait_ = tr.hir_trait_id();
1549 f.start_location_link(trait_.into());
1550 write!(f, "{}", f.db.trait_data(trait_).name.display(f.db.upcast()))?;
1551 f.end_location_link();
1552 if tr.substitution.len(Interner) > 1 {
1553 write!(f, "<")?;
1554 f.write_joined(&tr.substitution.as_slice(Interner)[1..], ", ")?;
1555 write!(f, ">")?;
1556 }
1557 Ok(())
1558 }
1559
1560 impl HirDisplay for TraitRef {
hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError>1561 fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> {
1562 fmt_trait_ref(f, self, false)
1563 }
1564 }
1565
1566 impl HirDisplay for WhereClause {
hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError>1567 fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> {
1568 if f.should_truncate() {
1569 return write!(f, "{TYPE_HINT_TRUNCATION}");
1570 }
1571
1572 match self {
1573 WhereClause::Implemented(trait_ref) => trait_ref.hir_fmt(f)?,
1574 WhereClause::AliasEq(AliasEq { alias: AliasTy::Projection(projection_ty), ty }) => {
1575 write!(f, "<")?;
1576 fmt_trait_ref(f, &projection_ty.trait_ref(f.db), true)?;
1577 write!(f, ">::",)?;
1578 let type_alias = from_assoc_type_id(projection_ty.associated_ty_id);
1579 f.start_location_link(type_alias.into());
1580 write!(f, "{}", f.db.type_alias_data(type_alias).name.display(f.db.upcast()),)?;
1581 f.end_location_link();
1582 write!(f, " = ")?;
1583 ty.hir_fmt(f)?;
1584 }
1585 WhereClause::AliasEq(_) => write!(f, "{{error}}")?,
1586
1587 // FIXME implement these
1588 WhereClause::TypeOutlives(..) => {}
1589 WhereClause::LifetimeOutlives(..) => {}
1590 }
1591 Ok(())
1592 }
1593 }
1594
1595 impl HirDisplay for LifetimeOutlives {
hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError>1596 fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> {
1597 self.a.hir_fmt(f)?;
1598 write!(f, ": ")?;
1599 self.b.hir_fmt(f)
1600 }
1601 }
1602
1603 impl HirDisplay for Lifetime {
hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError>1604 fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> {
1605 self.interned().hir_fmt(f)
1606 }
1607 }
1608
1609 impl HirDisplay for LifetimeData {
hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError>1610 fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> {
1611 match self {
1612 LifetimeData::BoundVar(idx) => idx.hir_fmt(f),
1613 LifetimeData::InferenceVar(_) => write!(f, "_"),
1614 LifetimeData::Placeholder(idx) => {
1615 let id = lt_from_placeholder_idx(f.db, *idx);
1616 let generics = generics(f.db.upcast(), id.parent);
1617 let param_data = &generics.params.lifetimes[id.local_id];
1618 write!(f, "{}", param_data.name.display(f.db.upcast()))?;
1619 Ok(())
1620 }
1621 LifetimeData::Static => write!(f, "'static"),
1622 LifetimeData::Erased => Ok(()),
1623 LifetimeData::Phantom(_, _) => Ok(()),
1624 }
1625 }
1626 }
1627
1628 impl HirDisplay for DomainGoal {
hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError>1629 fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> {
1630 match self {
1631 DomainGoal::Holds(wc) => {
1632 write!(f, "Holds(")?;
1633 wc.hir_fmt(f)?;
1634 write!(f, ")")?;
1635 }
1636 _ => write!(f, "?")?,
1637 }
1638 Ok(())
1639 }
1640 }
1641
write_visibility( module_id: ModuleId, vis: Visibility, f: &mut HirFormatter<'_>, ) -> Result<(), HirDisplayError>1642 pub fn write_visibility(
1643 module_id: ModuleId,
1644 vis: Visibility,
1645 f: &mut HirFormatter<'_>,
1646 ) -> Result<(), HirDisplayError> {
1647 match vis {
1648 Visibility::Public => write!(f, "pub "),
1649 Visibility::Module(vis_id) => {
1650 let def_map = module_id.def_map(f.db.upcast());
1651 let root_module_id = def_map.module_id(DefMap::ROOT);
1652 if vis_id == module_id {
1653 // pub(self) or omitted
1654 Ok(())
1655 } else if root_module_id == vis_id {
1656 write!(f, "pub(crate) ")
1657 } else if module_id.containing_module(f.db.upcast()) == Some(vis_id) {
1658 write!(f, "pub(super) ")
1659 } else {
1660 write!(f, "pub(in ...) ")
1661 }
1662 }
1663 }
1664 }
1665
1666 impl HirDisplay for TypeRef {
hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError>1667 fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> {
1668 match self {
1669 TypeRef::Never => write!(f, "!")?,
1670 TypeRef::Placeholder => write!(f, "_")?,
1671 TypeRef::Tuple(elems) => {
1672 write!(f, "(")?;
1673 f.write_joined(elems, ", ")?;
1674 if elems.len() == 1 {
1675 write!(f, ",")?;
1676 }
1677 write!(f, ")")?;
1678 }
1679 TypeRef::Path(path) => path.hir_fmt(f)?,
1680 TypeRef::RawPtr(inner, mutability) => {
1681 let mutability = match mutability {
1682 hir_def::type_ref::Mutability::Shared => "*const ",
1683 hir_def::type_ref::Mutability::Mut => "*mut ",
1684 };
1685 write!(f, "{mutability}")?;
1686 inner.hir_fmt(f)?;
1687 }
1688 TypeRef::Reference(inner, lifetime, mutability) => {
1689 let mutability = match mutability {
1690 hir_def::type_ref::Mutability::Shared => "",
1691 hir_def::type_ref::Mutability::Mut => "mut ",
1692 };
1693 write!(f, "&")?;
1694 if let Some(lifetime) = lifetime {
1695 write!(f, "{} ", lifetime.name.display(f.db.upcast()))?;
1696 }
1697 write!(f, "{mutability}")?;
1698 inner.hir_fmt(f)?;
1699 }
1700 TypeRef::Array(inner, len) => {
1701 write!(f, "[")?;
1702 inner.hir_fmt(f)?;
1703 write!(f, "; {}]", len.display(f.db.upcast()))?;
1704 }
1705 TypeRef::Slice(inner) => {
1706 write!(f, "[")?;
1707 inner.hir_fmt(f)?;
1708 write!(f, "]")?;
1709 }
1710 &TypeRef::Fn(ref parameters, is_varargs, is_unsafe) => {
1711 // FIXME: Function pointer qualifiers.
1712 if is_unsafe {
1713 write!(f, "unsafe ")?;
1714 }
1715 write!(f, "fn(")?;
1716 if let Some(((_, return_type), function_parameters)) = parameters.split_last() {
1717 for index in 0..function_parameters.len() {
1718 let (param_name, param_type) = &function_parameters[index];
1719 if let Some(name) = param_name {
1720 write!(f, "{}: ", name.display(f.db.upcast()))?;
1721 }
1722
1723 param_type.hir_fmt(f)?;
1724
1725 if index != function_parameters.len() - 1 {
1726 write!(f, ", ")?;
1727 }
1728 }
1729 if is_varargs {
1730 write!(f, "{}...", if parameters.len() == 1 { "" } else { ", " })?;
1731 }
1732 write!(f, ")")?;
1733 match &return_type {
1734 TypeRef::Tuple(tup) if tup.is_empty() => {}
1735 _ => {
1736 write!(f, " -> ")?;
1737 return_type.hir_fmt(f)?;
1738 }
1739 }
1740 }
1741 }
1742 TypeRef::ImplTrait(bounds) => {
1743 write!(f, "impl ")?;
1744 f.write_joined(bounds, " + ")?;
1745 }
1746 TypeRef::DynTrait(bounds) => {
1747 write!(f, "dyn ")?;
1748 f.write_joined(bounds, " + ")?;
1749 }
1750 TypeRef::Macro(macro_call) => {
1751 let macro_call = macro_call.to_node(f.db.upcast());
1752 let ctx = hir_def::lower::LowerCtx::with_hygiene(
1753 f.db.upcast(),
1754 &Hygiene::new_unhygienic(),
1755 );
1756 match macro_call.path() {
1757 Some(path) => match Path::from_src(path, &ctx) {
1758 Some(path) => path.hir_fmt(f)?,
1759 None => write!(f, "{{macro}}")?,
1760 },
1761 None => write!(f, "{{macro}}")?,
1762 }
1763 write!(f, "!(..)")?;
1764 }
1765 TypeRef::Error => write!(f, "{{error}}")?,
1766 }
1767 Ok(())
1768 }
1769 }
1770
1771 impl HirDisplay for TypeBound {
hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError>1772 fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> {
1773 match self {
1774 TypeBound::Path(path, modifier) => {
1775 match modifier {
1776 TraitBoundModifier::None => (),
1777 TraitBoundModifier::Maybe => write!(f, "?")?,
1778 }
1779 path.hir_fmt(f)
1780 }
1781 TypeBound::Lifetime(lifetime) => write!(f, "{}", lifetime.name.display(f.db.upcast())),
1782 TypeBound::ForLifetime(lifetimes, path) => {
1783 write!(
1784 f,
1785 "for<{}> ",
1786 lifetimes.iter().map(|it| it.display(f.db.upcast())).format(", ")
1787 )?;
1788 path.hir_fmt(f)
1789 }
1790 TypeBound::Error => write!(f, "{{error}}"),
1791 }
1792 }
1793 }
1794
1795 impl HirDisplay for Path {
hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError>1796 fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> {
1797 match (self.type_anchor(), self.kind()) {
1798 (Some(anchor), _) => {
1799 write!(f, "<")?;
1800 anchor.hir_fmt(f)?;
1801 write!(f, ">")?;
1802 }
1803 (_, PathKind::Plain) => {}
1804 (_, PathKind::Abs) => {}
1805 (_, PathKind::Crate) => write!(f, "crate")?,
1806 (_, PathKind::Super(0)) => write!(f, "self")?,
1807 (_, PathKind::Super(n)) => {
1808 for i in 0..*n {
1809 if i > 0 {
1810 write!(f, "::")?;
1811 }
1812 write!(f, "super")?;
1813 }
1814 }
1815 (_, PathKind::DollarCrate(id)) => {
1816 // Resolve `$crate` to the crate's display name.
1817 // FIXME: should use the dependency name instead if available, but that depends on
1818 // the crate invoking `HirDisplay`
1819 let crate_graph = f.db.crate_graph();
1820 let name = crate_graph[*id]
1821 .display_name
1822 .as_ref()
1823 .map(|name| name.canonical_name())
1824 .unwrap_or("$crate");
1825 write!(f, "{name}")?
1826 }
1827 }
1828
1829 for (seg_idx, segment) in self.segments().iter().enumerate() {
1830 if !matches!(self.kind(), PathKind::Plain) || seg_idx > 0 {
1831 write!(f, "::")?;
1832 }
1833 write!(f, "{}", segment.name.display(f.db.upcast()))?;
1834 if let Some(generic_args) = segment.args_and_bindings {
1835 // We should be in type context, so format as `Foo<Bar>` instead of `Foo::<Bar>`.
1836 // Do we actually format expressions?
1837 if generic_args.desugared_from_fn {
1838 // First argument will be a tuple, which already includes the parentheses.
1839 // If the tuple only contains 1 item, write it manually to avoid the trailing `,`.
1840 if let hir_def::path::GenericArg::Type(TypeRef::Tuple(v)) =
1841 &generic_args.args[0]
1842 {
1843 if v.len() == 1 {
1844 write!(f, "(")?;
1845 v[0].hir_fmt(f)?;
1846 write!(f, ")")?;
1847 } else {
1848 generic_args.args[0].hir_fmt(f)?;
1849 }
1850 }
1851 if let Some(ret) = &generic_args.bindings[0].type_ref {
1852 if !matches!(ret, TypeRef::Tuple(v) if v.is_empty()) {
1853 write!(f, " -> ")?;
1854 ret.hir_fmt(f)?;
1855 }
1856 }
1857 return Ok(());
1858 }
1859
1860 write!(f, "<")?;
1861 let mut first = true;
1862 for arg in generic_args.args.iter() {
1863 if first {
1864 first = false;
1865 if generic_args.has_self_type {
1866 // FIXME: Convert to `<Ty as Trait>` form.
1867 write!(f, "Self = ")?;
1868 }
1869 } else {
1870 write!(f, ", ")?;
1871 }
1872 arg.hir_fmt(f)?;
1873 }
1874 for binding in generic_args.bindings.iter() {
1875 if first {
1876 first = false;
1877 } else {
1878 write!(f, ", ")?;
1879 }
1880 write!(f, "{}", binding.name.display(f.db.upcast()))?;
1881 match &binding.type_ref {
1882 Some(ty) => {
1883 write!(f, " = ")?;
1884 ty.hir_fmt(f)?
1885 }
1886 None => {
1887 write!(f, ": ")?;
1888 f.write_joined(binding.bounds.iter(), " + ")?;
1889 }
1890 }
1891 }
1892 write!(f, ">")?;
1893 }
1894 }
1895 Ok(())
1896 }
1897 }
1898
1899 impl HirDisplay for hir_def::path::GenericArg {
hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError>1900 fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> {
1901 match self {
1902 hir_def::path::GenericArg::Type(ty) => ty.hir_fmt(f),
1903 hir_def::path::GenericArg::Const(c) => write!(f, "{}", c.display(f.db.upcast())),
1904 hir_def::path::GenericArg::Lifetime(lifetime) => {
1905 write!(f, "{}", lifetime.name.display(f.db.upcast()))
1906 }
1907 }
1908 }
1909 }
1910