]> git.proxmox.com Git - rustc.git/blame - compiler/rustc_middle/src/ty/print/pretty.rs
New upstream version 1.55.0+dfsg1
[rustc.git] / compiler / rustc_middle / src / ty / print / pretty.rs
CommitLineData
532ac7d7 1use crate::middle::cstore::{ExternCrate, ExternCrateSource};
136023e0 2use crate::mir::interpret::{AllocRange, ConstValue, GlobalAlloc, Pointer, Provenance, Scalar};
dfeec247 3use crate::ty::subst::{GenericArg, GenericArgKind, Subst};
29967ef6 4use crate::ty::{self, ConstInt, DefIdTree, ParamConst, ScalarInt, Ty, TyCtxt, TypeFoldable};
dc9dc135 5use rustc_apfloat::ieee::{Double, Single};
1b1a35ee 6use rustc_data_structures::fx::FxHashMap;
cdc7bbd5 7use rustc_data_structures::sso::SsoHashSet;
ba9703b0 8use rustc_hir as hir;
1b1a35ee 9use rustc_hir::def::{self, CtorKind, DefKind, Namespace};
17df50a5 10use rustc_hir::def_id::{DefId, DefIdSet, CRATE_DEF_INDEX, LOCAL_CRATE};
1b1a35ee
XL
11use rustc_hir::definitions::{DefPathData, DefPathDataName, DisambiguatedDefPathData};
12use rustc_hir::ItemKind;
13use rustc_session::config::TrimmedDefPaths;
f9f354fc 14use rustc_span::symbol::{kw, Ident, Symbol};
29967ef6 15use rustc_target::abi::Size;
532ac7d7 16use rustc_target::spec::abi::Abi;
532ac7d7
XL
17
18use std::cell::Cell;
ba9703b0 19use std::char;
60c5eb7d 20use std::collections::BTreeMap;
29967ef6 21use std::convert::TryFrom;
532ac7d7 22use std::fmt::{self, Write as _};
cdc7bbd5 23use std::iter;
29967ef6 24use std::ops::{ControlFlow, Deref, DerefMut};
532ac7d7
XL
25
26// `pretty` is a separate module only for organization.
27use super::*;
28
29macro_rules! p {
29967ef6
XL
30 (@$lit:literal) => {
31 write!(scoped_cx!(), $lit)?
32 };
532ac7d7
XL
33 (@write($($data:expr),+)) => {
34 write!(scoped_cx!(), $($data),+)?
35 };
36 (@print($x:expr)) => {
37 scoped_cx!() = $x.print(scoped_cx!())?
38 };
39 (@$method:ident($($arg:expr),*)) => {
40 scoped_cx!() = scoped_cx!().$method($($arg),*)?
41 };
29967ef6
XL
42 ($($elem:tt $(($($args:tt)*))?),+) => {{
43 $(p!(@ $elem $(($($args)*))?);)+
532ac7d7
XL
44 }};
45}
46macro_rules! define_scoped_cx {
47 ($cx:ident) => {
48 #[allow(unused_macros)]
49 macro_rules! scoped_cx {
dfeec247
XL
50 () => {
51 $cx
52 };
532ac7d7
XL
53 }
54 };
55}
56
57thread_local! {
17df50a5
XL
58 static FORCE_IMPL_FILENAME_LINE: Cell<bool> = const { Cell::new(false) };
59 static SHOULD_PREFIX_WITH_CRATE: Cell<bool> = const { Cell::new(false) };
60 static NO_TRIMMED_PATH: Cell<bool> = const { Cell::new(false) };
61 static NO_QUERIES: Cell<bool> = const { Cell::new(false) };
60c5eb7d
XL
62}
63
64/// Avoids running any queries during any prints that occur
65/// during the closure. This may alter the appearance of some
66/// types (e.g. forcing verbose printing for opaque types).
29967ef6 67/// This method is used during some queries (e.g. `explicit_item_bounds`
60c5eb7d
XL
68/// for opaque types), to ensure that any debug printing that
69/// occurs during the query computation does not end up recursively
70/// calling the same query.
71pub fn with_no_queries<F: FnOnce() -> R, R>(f: F) -> R {
72 NO_QUERIES.with(|no_queries| {
74b04a01 73 let old = no_queries.replace(true);
60c5eb7d
XL
74 let result = f();
75 no_queries.set(old);
76 result
77 })
532ac7d7
XL
78}
79
80/// Force us to name impls with just the filename/line number. We
81/// normally try to use types. But at some points, notably while printing
82/// cycle errors, this can result in extra or suboptimal error output,
83/// so this variable disables that check.
84pub fn with_forced_impl_filename_line<F: FnOnce() -> R, R>(f: F) -> R {
85 FORCE_IMPL_FILENAME_LINE.with(|force| {
74b04a01 86 let old = force.replace(true);
532ac7d7
XL
87 let result = f();
88 force.set(old);
89 result
90 })
91}
92
93/// Adds the `crate::` prefix to paths where appropriate.
94pub fn with_crate_prefix<F: FnOnce() -> R, R>(f: F) -> R {
95 SHOULD_PREFIX_WITH_CRATE.with(|flag| {
74b04a01 96 let old = flag.replace(true);
532ac7d7
XL
97 let result = f();
98 flag.set(old);
99 result
100 })
101}
102
1b1a35ee
XL
103/// Prevent path trimming if it is turned on. Path trimming affects `Display` impl
104/// of various rustc types, for example `std::vec::Vec` would be trimmed to `Vec`,
105/// if no other `Vec` is found.
106pub fn with_no_trimmed_paths<F: FnOnce() -> R, R>(f: F) -> R {
107 NO_TRIMMED_PATH.with(|flag| {
108 let old = flag.replace(true);
109 let result = f();
110 flag.set(old);
111 result
112 })
113}
114
532ac7d7
XL
115/// The "region highlights" are used to control region printing during
116/// specific error messages. When a "region highlight" is enabled, it
117/// gives an alternate way to print specific regions. For now, we
118/// always print those regions using a number, so something like "`'0`".
119///
120/// Regions not selected by the region highlight mode are presently
121/// unaffected.
122#[derive(Copy, Clone, Default)]
123pub struct RegionHighlightMode {
124 /// If enabled, when we see the selected region, use "`'N`"
125 /// instead of the ordinary behavior.
126 highlight_regions: [Option<(ty::RegionKind, usize)>; 3],
127
128 /// If enabled, when printing a "free region" that originated from
fc512014 129 /// the given `ty::BoundRegionKind`, print it as "`'1`". Free regions that would ordinarily
532ac7d7
XL
130 /// have names print as normal.
131 ///
132 /// This is used when you have a signature like `fn foo(x: &u32,
133 /// y: &'a u32)` and we want to give a name to the region of the
134 /// reference `x`.
fc512014 135 highlight_bound_region: Option<(ty::BoundRegionKind, usize)>,
532ac7d7
XL
136}
137
138impl RegionHighlightMode {
139 /// If `region` and `number` are both `Some`, invokes
140 /// `highlighting_region`.
141 pub fn maybe_highlighting_region(
142 &mut self,
143 region: Option<ty::Region<'_>>,
144 number: Option<usize>,
145 ) {
146 if let Some(k) = region {
147 if let Some(n) = number {
148 self.highlighting_region(k, n);
149 }
150 }
151 }
152
153 /// Highlights the region inference variable `vid` as `'N`.
dfeec247 154 pub fn highlighting_region(&mut self, region: ty::Region<'_>, number: usize) {
532ac7d7 155 let num_slots = self.highlight_regions.len();
dfeec247 156 let first_avail_slot =
74b04a01 157 self.highlight_regions.iter_mut().find(|s| s.is_none()).unwrap_or_else(|| {
dfeec247 158 bug!("can only highlight {} placeholders at a time", num_slots,)
532ac7d7
XL
159 });
160 *first_avail_slot = Some((*region, number));
161 }
162
163 /// Convenience wrapper for `highlighting_region`.
dfeec247 164 pub fn highlighting_region_vid(&mut self, vid: ty::RegionVid, number: usize) {
532ac7d7
XL
165 self.highlighting_region(&ty::ReVar(vid), number)
166 }
167
168 /// Returns `Some(n)` with the number to use for the given region, if any.
169 fn region_highlighted(&self, region: ty::Region<'_>) -> Option<usize> {
f9f354fc
XL
170 self.highlight_regions.iter().find_map(|h| match h {
171 Some((r, n)) if r == region => Some(*n),
172 _ => None,
173 })
532ac7d7
XL
174 }
175
176 /// Highlight the given bound region.
177 /// We can only highlight one bound region at a time. See
178 /// the field `highlight_bound_region` for more detailed notes.
fc512014 179 pub fn highlighting_bound_region(&mut self, br: ty::BoundRegionKind, number: usize) {
532ac7d7
XL
180 assert!(self.highlight_bound_region.is_none());
181 self.highlight_bound_region = Some((br, number));
182 }
183}
184
185/// Trait for printers that pretty-print using `fmt::Write` to the printer.
dc9dc135
XL
186pub trait PrettyPrinter<'tcx>:
187 Printer<
188 'tcx,
532ac7d7
XL
189 Error = fmt::Error,
190 Path = Self,
191 Region = Self,
192 Type = Self,
193 DynExistential = Self,
dc9dc135
XL
194 Const = Self,
195 > + fmt::Write
532ac7d7
XL
196{
197 /// Like `print_def_path` but for value paths.
198 fn print_value_path(
199 self,
200 def_id: DefId,
e74abb32 201 substs: &'tcx [GenericArg<'tcx>],
532ac7d7
XL
202 ) -> Result<Self::Path, Self::Error> {
203 self.print_def_path(def_id, substs)
204 }
205
cdc7bbd5 206 fn in_binder<T>(self, value: &ty::Binder<'tcx, T>) -> Result<Self, Self::Error>
dc9dc135
XL
207 where
208 T: Print<'tcx, Self, Output = Self, Error = Self::Error> + TypeFoldable<'tcx>,
532ac7d7 209 {
f035d41b 210 value.as_ref().skip_binder().print(self)
532ac7d7
XL
211 }
212
fc512014
XL
213 fn wrap_binder<T, F: Fn(&T, Self) -> Result<Self, fmt::Error>>(
214 self,
cdc7bbd5 215 value: &ty::Binder<'tcx, T>,
fc512014
XL
216 f: F,
217 ) -> Result<Self, Self::Error>
218 where
219 T: Print<'tcx, Self, Output = Self, Error = Self::Error> + TypeFoldable<'tcx>,
220 {
221 f(value.as_ref().skip_binder(), self)
222 }
223
e1599b0c 224 /// Prints comma-separated elements.
dc9dc135
XL
225 fn comma_sep<T>(mut self, mut elems: impl Iterator<Item = T>) -> Result<Self, Self::Error>
226 where
227 T: Print<'tcx, Self, Output = Self, Error = Self::Error>,
532ac7d7
XL
228 {
229 if let Some(first) = elems.next() {
230 self = first.print(self)?;
231 for elem in elems {
232 self.write_str(", ")?;
233 self = elem.print(self)?;
234 }
235 }
236 Ok(self)
237 }
238
ba9703b0
XL
239 /// Prints `{f: t}` or `{f as t}` depending on the `cast` argument
240 fn typed_value(
241 mut self,
242 f: impl FnOnce(Self) -> Result<Self, Self::Error>,
243 t: impl FnOnce(Self) -> Result<Self, Self::Error>,
244 conversion: &str,
245 ) -> Result<Self::Const, Self::Error> {
246 self.write_str("{")?;
247 self = f(self)?;
248 self.write_str(conversion)?;
249 self = t(self)?;
250 self.write_str("}")?;
251 Ok(self)
252 }
253
e1599b0c 254 /// Prints `<...>` around what `f` prints.
532ac7d7
XL
255 fn generic_delimiters(
256 self,
257 f: impl FnOnce(Self) -> Result<Self, Self::Error>,
258 ) -> Result<Self, Self::Error>;
259
e1599b0c
XL
260 /// Returns `true` if the region should be printed in
261 /// optional positions, e.g., `&'a T` or `dyn Tr + 'b`.
532ac7d7 262 /// This is typically the case for all non-`'_` regions.
dfeec247 263 fn region_should_not_be_omitted(&self, region: ty::Region<'_>) -> bool;
532ac7d7 264
74b04a01 265 // Defaults (should not be overridden):
532ac7d7
XL
266
267 /// If possible, this returns a global path resolving to `def_id` that is visible
e1599b0c 268 /// from at least one local module, and returns `true`. If the crate defining `def_id` is
532ac7d7 269 /// declared with an `extern crate`, the path is guaranteed to use the `extern crate`.
dfeec247 270 fn try_print_visible_def_path(self, def_id: DefId) -> Result<(Self, bool), Self::Error> {
416331ca
XL
271 let mut callers = Vec::new();
272 self.try_print_visible_def_path_recur(def_id, &mut callers)
273 }
274
1b1a35ee
XL
275 /// Try to see if this path can be trimmed to a unique symbol name.
276 fn try_print_trimmed_def_path(
277 mut self,
278 def_id: DefId,
279 ) -> Result<(Self::Path, bool), Self::Error> {
280 if !self.tcx().sess.opts.debugging_opts.trim_diagnostic_paths
281 || matches!(self.tcx().sess.opts.trimmed_def_paths, TrimmedDefPaths::Never)
282 || NO_TRIMMED_PATH.with(|flag| flag.get())
283 || SHOULD_PREFIX_WITH_CRATE.with(|flag| flag.get())
284 {
285 return Ok((self, false));
286 }
287
17df50a5 288 match self.tcx().trimmed_def_paths(()).get(&def_id) {
1b1a35ee
XL
289 None => Ok((self, false)),
290 Some(symbol) => {
291 self.write_str(&symbol.as_str())?;
292 Ok((self, true))
293 }
294 }
295 }
296
416331ca
XL
297 /// Does the work of `try_print_visible_def_path`, building the
298 /// full definition path recursively before attempting to
299 /// post-process it into the valid and visible version that
300 /// accounts for re-exports.
301 ///
74b04a01 302 /// This method should only be called by itself or
416331ca
XL
303 /// `try_print_visible_def_path`.
304 ///
305 /// `callers` is a chain of visible_parent's leading to `def_id`,
306 /// to support cycle detection during recursion.
307 fn try_print_visible_def_path_recur(
532ac7d7
XL
308 mut self,
309 def_id: DefId,
416331ca 310 callers: &mut Vec<DefId>,
532ac7d7
XL
311 ) -> Result<(Self, bool), Self::Error> {
312 define_scoped_cx!(self);
313
314 debug!("try_print_visible_def_path: def_id={:?}", def_id);
315
316 // If `def_id` is a direct or injected extern crate, return the
317 // path to the crate followed by the path to the item within the crate.
318 if def_id.index == CRATE_DEF_INDEX {
319 let cnum = def_id.krate;
320
321 if cnum == LOCAL_CRATE {
322 return Ok((self.path_crate(cnum)?, true));
323 }
324
325 // In local mode, when we encounter a crate other than
326 // LOCAL_CRATE, execution proceeds in one of two ways:
327 //
e1599b0c 328 // 1. For a direct dependency, where user added an
532ac7d7
XL
329 // `extern crate` manually, we put the `extern
330 // crate` as the parent. So you wind up with
331 // something relative to the current crate.
e1599b0c 332 // 2. For an extern inferred from a path or an indirect crate,
532ac7d7
XL
333 // where there is no explicit `extern crate`, we just prepend
334 // the crate name.
dc9dc135 335 match self.tcx().extern_crate(def_id) {
f035d41b
XL
336 Some(&ExternCrate { src, dependency_of, span, .. }) => match (src, dependency_of) {
337 (ExternCrateSource::Extern(def_id), LOCAL_CRATE) => {
338 debug!("try_print_visible_def_path: def_id={:?}", def_id);
339 return Ok((
340 if !span.is_dummy() {
341 self.print_def_path(def_id, &[])?
342 } else {
343 self.path_crate(cnum)?
344 },
345 true,
346 ));
347 }
348 (ExternCrateSource::Path, LOCAL_CRATE) => {
349 debug!("try_print_visible_def_path: def_id={:?}", def_id);
350 return Ok((self.path_crate(cnum)?, true));
351 }
352 _ => {}
353 },
532ac7d7
XL
354 None => {
355 return Ok((self.path_crate(cnum)?, true));
356 }
532ac7d7
XL
357 }
358 }
359
360 if def_id.is_local() {
361 return Ok((self, false));
362 }
363
17df50a5 364 let visible_parent_map = self.tcx().visible_parent_map(());
532ac7d7
XL
365
366 let mut cur_def_key = self.tcx().def_key(def_id);
367 debug!("try_print_visible_def_path: cur_def_key={:?}", cur_def_key);
368
e1599b0c 369 // For a constructor, we want the name of its parent rather than <unnamed>.
ba9703b0
XL
370 if let DefPathData::Ctor = cur_def_key.disambiguated_data.data {
371 let parent = DefId {
372 krate: def_id.krate,
373 index: cur_def_key
374 .parent
375 .expect("`DefPathData::Ctor` / `VariantData` missing a parent"),
376 };
532ac7d7 377
ba9703b0 378 cur_def_key = self.tcx().def_key(parent);
532ac7d7
XL
379 }
380
381 let visible_parent = match visible_parent_map.get(&def_id).cloned() {
382 Some(parent) => parent,
383 None => return Ok((self, false)),
384 };
416331ca
XL
385 if callers.contains(&visible_parent) {
386 return Ok((self, false));
387 }
388 callers.push(visible_parent);
532ac7d7
XL
389 // HACK(eddyb) this bypasses `path_append`'s prefix printing to avoid
390 // knowing ahead of time whether the entire path will succeed or not.
391 // To support printers that do not implement `PrettyPrinter`, a `Vec` or
392 // linked list on the stack would need to be built, before any printing.
416331ca 393 match self.try_print_visible_def_path_recur(visible_parent, callers)? {
532ac7d7
XL
394 (cx, false) => return Ok((cx, false)),
395 (cx, true) => self = cx,
396 }
416331ca 397 callers.pop();
532ac7d7
XL
398 let actual_parent = self.tcx().parent(def_id);
399 debug!(
400 "try_print_visible_def_path: visible_parent={:?} actual_parent={:?}",
401 visible_parent, actual_parent,
402 );
403
404 let mut data = cur_def_key.disambiguated_data.data;
405 debug!(
406 "try_print_visible_def_path: data={:?} visible_parent={:?} actual_parent={:?}",
407 data, visible_parent, actual_parent,
408 );
409
410 match data {
411 // In order to output a path that could actually be imported (valid and visible),
412 // we need to handle re-exports correctly.
413 //
414 // For example, take `std::os::unix::process::CommandExt`, this trait is actually
415 // defined at `std::sys::unix::ext::process::CommandExt` (at time of writing).
416 //
417 // `std::os::unix` rexports the contents of `std::sys::unix::ext`. `std::sys` is
418 // private so the "true" path to `CommandExt` isn't accessible.
419 //
420 // In this case, the `visible_parent_map` will look something like this:
421 //
422 // (child) -> (parent)
423 // `std::sys::unix::ext::process::CommandExt` -> `std::sys::unix::ext::process`
424 // `std::sys::unix::ext::process` -> `std::sys::unix::ext`
425 // `std::sys::unix::ext` -> `std::os`
426 //
427 // This is correct, as the visible parent of `std::sys::unix::ext` is in fact
428 // `std::os`.
429 //
430 // When printing the path to `CommandExt` and looking at the `cur_def_key` that
431 // corresponds to `std::sys::unix::ext`, we would normally print `ext` and then go
432 // to the parent - resulting in a mangled path like
433 // `std::os::ext::process::CommandExt`.
434 //
435 // Instead, we must detect that there was a re-export and instead print `unix`
436 // (which is the name `std::sys::unix::ext` was re-exported as in `std::os`). To
437 // do this, we compare the parent of `std::sys::unix::ext` (`std::sys::unix`) with
438 // the visible parent (`std::os`). If these do not match, then we iterate over
439 // the children of the visible parent (as was done when computing
440 // `visible_parent_map`), looking for the specific child we currently have and then
441 // have access to the re-exported name.
532ac7d7 442 DefPathData::TypeNs(ref mut name) if Some(visible_parent) != actual_parent => {
dfeec247
XL
443 let reexport = self
444 .tcx()
445 .item_children(visible_parent)
532ac7d7 446 .iter()
f035d41b 447 .find(|child| child.res.opt_def_id() == Some(def_id))
e74abb32 448 .map(|child| child.ident.name);
532ac7d7
XL
449 if let Some(reexport) = reexport {
450 *name = reexport;
451 }
452 }
453 // Re-exported `extern crate` (#43189).
454 DefPathData::CrateRoot => {
17df50a5 455 data = DefPathData::TypeNs(self.tcx().crate_name(def_id.krate));
532ac7d7
XL
456 }
457 _ => {}
458 }
459 debug!("try_print_visible_def_path: data={:?}", data);
460
dfeec247 461 Ok((self.path_append(Ok, &DisambiguatedDefPathData { data, disambiguator: 0 })?, true))
532ac7d7
XL
462 }
463
464 fn pretty_path_qualified(
465 self,
466 self_ty: Ty<'tcx>,
467 trait_ref: Option<ty::TraitRef<'tcx>>,
468 ) -> Result<Self::Path, Self::Error> {
469 if trait_ref.is_none() {
470 // Inherent impls. Try to print `Foo::bar` for an inherent
471 // impl on `Foo`, but fallback to `<Foo>::bar` if self-type is
472 // anything other than a simple path.
1b1a35ee 473 match self_ty.kind() {
dfeec247
XL
474 ty::Adt(..)
475 | ty::Foreign(_)
476 | ty::Bool
477 | ty::Char
478 | ty::Str
479 | ty::Int(_)
480 | ty::Uint(_)
481 | ty::Float(_) => {
532ac7d7
XL
482 return self_ty.print(self);
483 }
484
485 _ => {}
486 }
487 }
488
489 self.generic_delimiters(|mut cx| {
490 define_scoped_cx!(cx);
491
492 p!(print(self_ty));
493 if let Some(trait_ref) = trait_ref {
29967ef6 494 p!(" as ", print(trait_ref.print_only_trait_path()));
532ac7d7
XL
495 }
496 Ok(cx)
497 })
498 }
499
500 fn pretty_path_append_impl(
501 mut self,
502 print_prefix: impl FnOnce(Self) -> Result<Self::Path, Self::Error>,
503 self_ty: Ty<'tcx>,
504 trait_ref: Option<ty::TraitRef<'tcx>>,
505 ) -> Result<Self::Path, Self::Error> {
506 self = print_prefix(self)?;
507
508 self.generic_delimiters(|mut cx| {
509 define_scoped_cx!(cx);
510
29967ef6 511 p!("impl ");
532ac7d7 512 if let Some(trait_ref) = trait_ref {
29967ef6 513 p!(print(trait_ref.print_only_trait_path()), " for ");
532ac7d7
XL
514 }
515 p!(print(self_ty));
516
517 Ok(cx)
518 })
519 }
520
dfeec247 521 fn pretty_print_type(mut self, ty: Ty<'tcx>) -> Result<Self::Type, Self::Error> {
532ac7d7
XL
522 define_scoped_cx!(self);
523
1b1a35ee 524 match *ty.kind() {
29967ef6
XL
525 ty::Bool => p!("bool"),
526 ty::Char => p!("char"),
60c5eb7d
XL
527 ty::Int(t) => p!(write("{}", t.name_str())),
528 ty::Uint(t) => p!(write("{}", t.name_str())),
529 ty::Float(t) => p!(write("{}", t.name_str())),
532ac7d7 530 ty::RawPtr(ref tm) => {
dfeec247
XL
531 p!(write(
532 "*{} ",
533 match tm.mutbl {
534 hir::Mutability::Mut => "mut",
535 hir::Mutability::Not => "const",
536 }
537 ));
532ac7d7
XL
538 p!(print(tm.ty))
539 }
540 ty::Ref(r, ty, mutbl) => {
29967ef6 541 p!("&");
532ac7d7 542 if self.region_should_not_be_omitted(r) {
29967ef6 543 p!(print(r), " ");
532ac7d7
XL
544 }
545 p!(print(ty::TypeAndMut { ty, mutbl }))
546 }
29967ef6 547 ty::Never => p!("!"),
532ac7d7 548 ty::Tuple(ref tys) => {
29967ef6 549 p!("(", comma_sep(tys.iter()));
ba9703b0 550 if tys.len() == 1 {
29967ef6 551 p!(",");
532ac7d7 552 }
29967ef6 553 p!(")")
532ac7d7
XL
554 }
555 ty::FnDef(def_id, substs) => {
556 let sig = self.tcx().fn_sig(def_id).subst(self.tcx(), substs);
29967ef6 557 p!(print(sig), " {{", print_value_path(def_id, substs), "}}");
532ac7d7 558 }
dfeec247 559 ty::FnPtr(ref bare_fn) => p!(print(bare_fn)),
dc9dc135 560 ty::Infer(infer_ty) => {
5869c6ff 561 let verbose = self.tcx().sess.verbose();
dc9dc135
XL
562 if let ty::TyVar(ty_vid) = infer_ty {
563 if let Some(name) = self.infer_ty_name(ty_vid) {
564 p!(write("{}", name))
565 } else {
5869c6ff
XL
566 if verbose {
567 p!(write("{:?}", infer_ty))
568 } else {
569 p!(write("{}", infer_ty))
570 }
dc9dc135
XL
571 }
572 } else {
5869c6ff 573 if verbose { p!(write("{:?}", infer_ty)) } else { p!(write("{}", infer_ty)) }
dc9dc135 574 }
dfeec247 575 }
29967ef6 576 ty::Error(_) => p!("[type error]"),
532ac7d7 577 ty::Param(ref param_ty) => p!(write("{}", param_ty)),
dfeec247 578 ty::Bound(debruijn, bound_ty) => match bound_ty.kind {
ba9703b0 579 ty::BoundTyKind::Anon => self.pretty_print_bound_var(debruijn, bound_ty.var)?,
dfeec247
XL
580 ty::BoundTyKind::Param(p) => p!(write("{}", p)),
581 },
532ac7d7
XL
582 ty::Adt(def, substs) => {
583 p!(print_def_path(def.did, substs));
584 }
585 ty::Dynamic(data, r) => {
586 let print_r = self.region_should_not_be_omitted(r);
587 if print_r {
29967ef6 588 p!("(");
532ac7d7 589 }
29967ef6 590 p!("dyn ", print(data));
532ac7d7 591 if print_r {
29967ef6 592 p!(" + ", print(r), ")");
532ac7d7
XL
593 }
594 }
595 ty::Foreign(def_id) => {
596 p!(print_def_path(def_id, &[]));
597 }
598 ty::Projection(ref data) => p!(print(data)),
dfeec247 599 ty::Placeholder(placeholder) => p!(write("Placeholder({:?})", placeholder)),
532ac7d7
XL
600 ty::Opaque(def_id, substs) => {
601 // FIXME(eddyb) print this with `print_def_path`.
60c5eb7d
XL
602 // We use verbose printing in 'NO_QUERIES' mode, to
603 // avoid needing to call `predicates_of`. This should
604 // only affect certain debug messages (e.g. messages printed
ba9703b0 605 // from `rustc_middle::ty` during the computation of `tcx.predicates_of`),
60c5eb7d 606 // and should have no effect on any compiler output.
dfeec247 607 if self.tcx().sess.verbose() || NO_QUERIES.with(|q| q.get()) {
532ac7d7
XL
608 p!(write("Opaque({:?}, {:?})", def_id, substs));
609 return Ok(self);
610 }
611
6a06907d 612 return with_no_queries(|| {
60c5eb7d
XL
613 let def_key = self.tcx().def_key(def_id);
614 if let Some(name) = def_key.disambiguated_data.data.get_opt_name() {
615 p!(write("{}", name));
60c5eb7d 616 // FIXME(eddyb) print this with `print_def_path`.
ba9703b0 617 if !substs.is_empty() {
29967ef6 618 p!("::");
f9f354fc 619 p!(generic_delimiters(|cx| cx.comma_sep(substs.iter())));
532ac7d7 620 }
60c5eb7d 621 return Ok(self);
532ac7d7 622 }
60c5eb7d
XL
623 // Grab the "TraitA + TraitB" from `impl TraitA + TraitB`,
624 // by looking up the projections associated with the def_id.
29967ef6 625 let bounds = self.tcx().explicit_item_bounds(def_id);
60c5eb7d
XL
626
627 let mut first = true;
628 let mut is_sized = false;
29967ef6
XL
629 p!("impl");
630 for (predicate, _) in bounds {
631 let predicate = predicate.subst(self.tcx(), substs);
5869c6ff
XL
632 let bound_predicate = predicate.kind();
633 if let ty::PredicateKind::Trait(pred, _) = bound_predicate.skip_binder() {
29967ef6 634 let trait_ref = bound_predicate.rebind(pred.trait_ref);
60c5eb7d
XL
635 // Don't print +Sized, but rather +?Sized if absent.
636 if Some(trait_ref.def_id()) == self.tcx().lang_items().sized_trait() {
637 is_sized = true;
638 continue;
639 }
532ac7d7 640
60c5eb7d 641 p!(
dfeec247
XL
642 write("{}", if first { " " } else { "+" }),
643 print(trait_ref.print_only_trait_path())
644 );
60c5eb7d
XL
645 first = false;
646 }
532ac7d7 647 }
60c5eb7d
XL
648 if !is_sized {
649 p!(write("{}?Sized", if first { " " } else { "+" }));
650 } else if first {
29967ef6 651 p!(" Sized");
60c5eb7d
XL
652 }
653 Ok(self)
6a06907d 654 });
532ac7d7 655 }
29967ef6 656 ty::Str => p!("str"),
532ac7d7 657 ty::Generator(did, substs, movability) => {
1b1a35ee 658 p!(write("["));
60c5eb7d 659 match movability {
1b1a35ee 660 hir::Movability::Movable => {}
29967ef6 661 hir::Movability::Static => p!("static "),
532ac7d7
XL
662 }
663
1b1a35ee 664 if !self.tcx().sess.verbose() {
29967ef6 665 p!("generator");
1b1a35ee
XL
666 // FIXME(eddyb) should use `def_span`.
667 if let Some(did) = did.as_local() {
668 let hir_id = self.tcx().hir().local_def_id_to_hir_id(did);
669 let span = self.tcx().hir().span(hir_id);
17df50a5
XL
670 p!(write(
671 "@{}",
672 // This may end up in stderr diagnostics but it may also be emitted
673 // into MIR. Hence we use the remapped path if available
674 self.tcx().sess.source_map().span_to_embeddable_string(span)
675 ));
1b1a35ee 676 } else {
29967ef6 677 p!(write("@"), print_def_path(did, substs));
532ac7d7
XL
678 }
679 } else {
1b1a35ee 680 p!(print_def_path(did, substs));
29967ef6
XL
681 p!(" upvar_tys=(");
682 if !substs.as_generator().is_valid() {
683 p!("unavailable");
684 } else {
685 self = self.comma_sep(substs.as_generator().upvar_tys())?;
532ac7d7 686 }
29967ef6 687 p!(")");
532ac7d7 688
136023e0
XL
689 if substs.as_generator().is_valid() {
690 p!(" ", print(substs.as_generator().witness()));
691 }
ba9703b0
XL
692 }
693
29967ef6 694 p!("]")
dfeec247 695 }
532ac7d7
XL
696 ty::GeneratorWitness(types) => {
697 p!(in_binder(&types));
698 }
699 ty::Closure(did, substs) => {
1b1a35ee
XL
700 p!(write("["));
701 if !self.tcx().sess.verbose() {
702 p!(write("closure"));
703 // FIXME(eddyb) should use `def_span`.
704 if let Some(did) = did.as_local() {
705 let hir_id = self.tcx().hir().local_def_id_to_hir_id(did);
706 if self.tcx().sess.opts.debugging_opts.span_free_formats {
29967ef6 707 p!("@", print_def_path(did.to_def_id(), substs));
1b1a35ee
XL
708 } else {
709 let span = self.tcx().hir().span(hir_id);
17df50a5
XL
710 p!(write(
711 "@{}",
712 // This may end up in stderr diagnostics but it may also be emitted
713 // into MIR. Hence we use the remapped path if available
714 self.tcx().sess.source_map().span_to_embeddable_string(span)
715 ));
ba9703b0 716 }
1b1a35ee 717 } else {
29967ef6 718 p!(write("@"), print_def_path(did, substs));
532ac7d7
XL
719 }
720 } else {
1b1a35ee 721 p!(print_def_path(did, substs));
29967ef6
XL
722 if !substs.as_closure().is_valid() {
723 p!(" closure_substs=(unavailable)");
724 } else {
725 p!(" closure_kind_ty=", print(substs.as_closure().kind_ty()));
726 p!(
727 " closure_sig_as_fn_ptr_ty=",
728 print(substs.as_closure().sig_as_fn_ptr_ty())
729 );
730 p!(" upvar_tys=(");
731 self = self.comma_sep(substs.as_closure().upvar_tys())?;
732 p!(")");
532ac7d7
XL
733 }
734 }
29967ef6 735 p!("]");
dfeec247 736 }
532ac7d7 737 ty::Array(ty, sz) => {
29967ef6 738 p!("[", print(ty), "; ");
e74abb32
XL
739 if self.tcx().sess.verbose() {
740 p!(write("{:?}", sz));
60c5eb7d 741 } else if let ty::ConstKind::Unevaluated(..) = sz.val {
f9f354fc 742 // Do not try to evaluate unevaluated constants. If we are const evaluating an
416331ca
XL
743 // array length anon const, rustc will (with debug assertions) print the
744 // constant's path. Which will end up here again.
29967ef6 745 p!("_");
ba9703b0 746 } else if let Some(n) = sz.val.try_to_bits(self.tcx().data_layout.pointer_size) {
dc9dc135 747 p!(write("{}", n));
f9f354fc
XL
748 } else if let ty::ConstKind::Param(param) = sz.val {
749 p!(write("{}", param));
dc9dc135 750 } else {
29967ef6 751 p!("_");
532ac7d7 752 }
29967ef6 753 p!("]")
532ac7d7 754 }
29967ef6 755 ty::Slice(ty) => p!("[", print(ty), "]"),
532ac7d7
XL
756 }
757
758 Ok(self)
759 }
760
ba9703b0
XL
761 fn pretty_print_bound_var(
762 &mut self,
763 debruijn: ty::DebruijnIndex,
764 var: ty::BoundVar,
765 ) -> Result<(), Self::Error> {
766 if debruijn == ty::INNERMOST {
767 write!(self, "^{}", var.index())
768 } else {
769 write!(self, "^{}_{}", debruijn.index(), var.index())
770 }
771 }
772
dc9dc135
XL
773 fn infer_ty_name(&self, _: ty::TyVid) -> Option<String> {
774 None
775 }
776
532ac7d7
XL
777 fn pretty_print_dyn_existential(
778 mut self,
cdc7bbd5 779 predicates: &'tcx ty::List<ty::Binder<'tcx, ty::ExistentialPredicate<'tcx>>>,
532ac7d7 780 ) -> Result<Self::DynExistential, Self::Error> {
532ac7d7
XL
781 // Generate the main trait ref, including associated types.
782 let mut first = true;
783
784 if let Some(principal) = predicates.principal() {
fc512014
XL
785 self = self.wrap_binder(&principal, |principal, mut cx| {
786 define_scoped_cx!(cx);
787 p!(print_def_path(principal.def_id, &[]));
788
789 let mut resugared = false;
790
791 // Special-case `Fn(...) -> ...` and resugar it.
792 let fn_trait_kind = cx.tcx().fn_trait_kind_from_lang_item(principal.def_id);
793 if !cx.tcx().sess.verbose() && fn_trait_kind.is_some() {
794 if let ty::Tuple(ref args) = principal.substs.type_at(0).kind() {
795 let mut projections = predicates.projection_bounds();
796 if let (Some(proj), None) = (projections.next(), projections.next()) {
797 let tys: Vec<_> = args.iter().map(|k| k.expect_ty()).collect();
798 p!(pretty_fn_sig(&tys, false, proj.skip_binder().ty));
799 resugared = true;
800 }
532ac7d7
XL
801 }
802 }
532ac7d7 803
fc512014
XL
804 // HACK(eddyb) this duplicates `FmtPrinter`'s `path_generic_args`,
805 // in order to place the projections inside the `<...>`.
806 if !resugared {
807 // Use a type that can't appear in defaults of type parameters.
808 let dummy_cx = cx.tcx().mk_ty_infer(ty::FreshTy(0));
809 let principal = principal.with_self_ty(cx.tcx(), dummy_cx);
810
811 let args = cx.generic_args_to_print(
812 cx.tcx().generics_of(principal.def_id),
813 principal.substs,
814 );
815
816 // Don't print `'_` if there's no unerased regions.
817 let print_regions = args.iter().any(|arg| match arg.unpack() {
818 GenericArgKind::Lifetime(r) => *r != ty::ReErased,
819 _ => false,
820 });
821 let mut args = args.iter().cloned().filter(|arg| match arg.unpack() {
822 GenericArgKind::Lifetime(_) => print_regions,
823 _ => true,
824 });
825 let mut projections = predicates.projection_bounds();
532ac7d7 826
fc512014
XL
827 let arg0 = args.next();
828 let projection0 = projections.next();
829 if arg0.is_some() || projection0.is_some() {
830 let args = arg0.into_iter().chain(args);
831 let projections = projection0.into_iter().chain(projections);
532ac7d7 832
fc512014
XL
833 p!(generic_delimiters(|mut cx| {
834 cx = cx.comma_sep(args)?;
835 if arg0.is_some() && projection0.is_some() {
836 write!(cx, ", ")?;
837 }
838 cx.comma_sep(projections)
839 }));
840 }
532ac7d7 841 }
fc512014
XL
842 Ok(cx)
843 })?;
844
532ac7d7
XL
845 first = false;
846 }
847
fc512014
XL
848 define_scoped_cx!(self);
849
532ac7d7
XL
850 // Builtin bounds.
851 // FIXME(eddyb) avoid printing twice (needed to ensure
852 // that the auto traits are sorted *and* printed via cx).
dfeec247
XL
853 let mut auto_traits: Vec<_> =
854 predicates.auto_traits().map(|did| (self.tcx().def_path_str(did), did)).collect();
532ac7d7
XL
855
856 // The auto traits come ordered by `DefPathHash`. While
857 // `DefPathHash` is *stable* in the sense that it depends on
858 // neither the host nor the phase of the moon, it depends
859 // "pseudorandomly" on the compiler version and the target.
860 //
861 // To avoid that causing instabilities in compiletest
862 // output, sort the auto-traits alphabetically.
863 auto_traits.sort();
864
865 for (_, def_id) in auto_traits {
866 if !first {
29967ef6 867 p!(" + ");
532ac7d7
XL
868 }
869 first = false;
870
871 p!(print_def_path(def_id, &[]));
872 }
873
874 Ok(self)
875 }
876
877 fn pretty_fn_sig(
878 mut self,
879 inputs: &[Ty<'tcx>],
880 c_variadic: bool,
881 output: Ty<'tcx>,
882 ) -> Result<Self, Self::Error> {
883 define_scoped_cx!(self);
884
29967ef6 885 p!("(", comma_sep(inputs.iter().copied()));
ba9703b0
XL
886 if c_variadic {
887 if !inputs.is_empty() {
29967ef6 888 p!(", ");
532ac7d7 889 }
29967ef6 890 p!("...");
532ac7d7 891 }
29967ef6 892 p!(")");
532ac7d7 893 if !output.is_unit() {
29967ef6 894 p!(" -> ", print(output));
532ac7d7
XL
895 }
896
897 Ok(self)
898 }
dc9dc135
XL
899
900 fn pretty_print_const(
901 mut self,
902 ct: &'tcx ty::Const<'tcx>,
dfeec247 903 print_ty: bool,
dc9dc135
XL
904 ) -> Result<Self::Const, Self::Error> {
905 define_scoped_cx!(self);
906
e74abb32
XL
907 if self.tcx().sess.verbose() {
908 p!(write("Const({:?}: {:?})", ct.val, ct.ty));
dc9dc135
XL
909 return Ok(self);
910 }
e74abb32 911
dfeec247
XL
912 macro_rules! print_underscore {
913 () => {{
dfeec247 914 if print_ty {
ba9703b0
XL
915 self = self.typed_value(
916 |mut this| {
917 write!(this, "_")?;
918 Ok(this)
919 },
920 |this| this.print_type(ct.ty),
921 ": ",
922 )?;
923 } else {
924 write!(self, "_")?;
dfeec247
XL
925 }
926 }};
927 }
928
ba9703b0 929 match ct.val {
cdc7bbd5 930 ty::ConstKind::Unevaluated(ty::Unevaluated { def, substs, promoted }) => {
dfeec247 931 if let Some(promoted) = promoted {
3dfed10e 932 p!(print_value_path(def.did, substs));
dfeec247
XL
933 p!(write("::{:?}", promoted));
934 } else {
3dfed10e 935 match self.tcx().def_kind(def.did) {
f9f354fc 936 DefKind::Static | DefKind::Const | DefKind::AssocConst => {
3dfed10e 937 p!(print_value_path(def.did, substs))
ba9703b0 938 }
dfeec247 939 _ => {
3dfed10e
XL
940 if def.is_local() {
941 let span = self.tcx().def_span(def.did);
dfeec247
XL
942 if let Ok(snip) = self.tcx().sess.source_map().span_to_snippet(span)
943 {
944 p!(write("{}", snip))
945 } else {
946 print_underscore!()
947 }
948 } else {
949 print_underscore!()
950 }
e74abb32 951 }
dfeec247 952 }
e74abb32 953 }
dfeec247 954 }
ba9703b0
XL
955 ty::ConstKind::Infer(..) => print_underscore!(),
956 ty::ConstKind::Param(ParamConst { name, .. }) => p!(write("{}", name)),
957 ty::ConstKind::Value(value) => {
dfeec247
XL
958 return self.pretty_print_const_value(value, ct.ty, print_ty);
959 }
60c5eb7d 960
ba9703b0
XL
961 ty::ConstKind::Bound(debruijn, bound_var) => {
962 self.pretty_print_bound_var(debruijn, bound_var)?
60c5eb7d 963 }
ba9703b0 964 ty::ConstKind::Placeholder(placeholder) => p!(write("Placeholder({:?})", placeholder)),
29967ef6 965 ty::ConstKind::Error(_) => p!("[const error]"),
60c5eb7d
XL
966 };
967 Ok(self)
968 }
969
ba9703b0 970 fn pretty_print_const_scalar(
6a06907d 971 self,
ba9703b0 972 scalar: Scalar,
60c5eb7d 973 ty: Ty<'tcx>,
dfeec247 974 print_ty: bool,
6a06907d
XL
975 ) -> Result<Self::Const, Self::Error> {
976 match scalar {
136023e0 977 Scalar::Ptr(ptr, _size) => self.pretty_print_const_scalar_ptr(ptr, ty, print_ty),
6a06907d
XL
978 Scalar::Int(int) => self.pretty_print_const_scalar_int(int, ty, print_ty),
979 }
980 }
981
982 fn pretty_print_const_scalar_ptr(
983 mut self,
984 ptr: Pointer,
985 ty: Ty<'tcx>,
986 print_ty: bool,
60c5eb7d
XL
987 ) -> Result<Self::Const, Self::Error> {
988 define_scoped_cx!(self);
989
136023e0 990 let (alloc_id, offset) = ptr.into_parts();
6a06907d 991 match ty.kind() {
ba9703b0 992 // Byte strings (&[u8; N])
6a06907d
XL
993 ty::Ref(
994 _,
995 ty::TyS {
996 kind:
997 ty::Array(
998 ty::TyS { kind: ty::Uint(ty::UintTy::U8), .. },
999 ty::Const {
1000 val: ty::ConstKind::Value(ConstValue::Scalar(int)), ..
1001 },
1002 ),
1003 ..
1004 },
1005 _,
136023e0 1006 ) => match self.tcx().get_global_alloc(alloc_id) {
f9f354fc 1007 Some(GlobalAlloc::Memory(alloc)) => {
17df50a5 1008 let len = int.assert_bits(self.tcx().data_layout.pointer_size);
136023e0 1009 let range = AllocRange { start: offset, size: Size::from_bytes(len) };
17df50a5 1010 if let Ok(byte_str) = alloc.get_bytes(&self.tcx(), range) {
f9f354fc
XL
1011 p!(pretty_print_byte_str(byte_str))
1012 } else {
29967ef6 1013 p!("<too short allocation>")
f9f354fc
XL
1014 }
1015 }
1016 // FIXME: for statics and functions, we could in principle print more detail.
1017 Some(GlobalAlloc::Static(def_id)) => p!(write("<static({:?})>", def_id)),
29967ef6
XL
1018 Some(GlobalAlloc::Function(_)) => p!("<function>"),
1019 None => p!("<dangling pointer>"),
f9f354fc 1020 },
6a06907d
XL
1021 ty::FnPtr(_) => {
1022 // FIXME: We should probably have a helper method to share code with the "Byte strings"
1023 // printing above (which also has to handle pointers to all sorts of things).
136023e0 1024 match self.tcx().get_global_alloc(alloc_id) {
6a06907d
XL
1025 Some(GlobalAlloc::Function(instance)) => {
1026 self = self.typed_value(
1027 |this| this.print_value_path(instance.def_id(), instance.substs),
1028 |this| this.print_type(ty),
1029 " as ",
1030 )?;
1031 }
1032 _ => self = self.pretty_print_const_pointer(ptr, ty, print_ty)?,
1033 }
1034 }
1035 // Any pointer values not covered by a branch above
1036 _ => {
1037 self = self.pretty_print_const_pointer(ptr, ty, print_ty)?;
1038 }
1039 }
1040 Ok(self)
1041 }
1042
1043 fn pretty_print_const_scalar_int(
1044 mut self,
1045 int: ScalarInt,
1046 ty: Ty<'tcx>,
1047 print_ty: bool,
1048 ) -> Result<Self::Const, Self::Error> {
1049 define_scoped_cx!(self);
1050
1051 match ty.kind() {
ba9703b0 1052 // Bool
6a06907d
XL
1053 ty::Bool if int == ScalarInt::FALSE => p!("false"),
1054 ty::Bool if int == ScalarInt::TRUE => p!("true"),
ba9703b0 1055 // Float
6a06907d 1056 ty::Float(ty::FloatTy::F32) => {
29967ef6 1057 p!(write("{}f32", Single::try_from(int).unwrap()))
dfeec247 1058 }
6a06907d 1059 ty::Float(ty::FloatTy::F64) => {
29967ef6 1060 p!(write("{}f64", Double::try_from(int).unwrap()))
dfeec247 1061 }
ba9703b0 1062 // Int
6a06907d 1063 ty::Uint(_) | ty::Int(_) => {
29967ef6
XL
1064 let int =
1065 ConstInt::new(int, matches!(ty.kind(), ty::Int(_)), ty.is_ptr_sized_integral());
f035d41b 1066 if print_ty { p!(write("{:#?}", int)) } else { p!(write("{:?}", int)) }
dfeec247 1067 }
ba9703b0 1068 // Char
6a06907d 1069 ty::Char if char::try_from(int).is_ok() => {
29967ef6 1070 p!(write("{:?}", char::try_from(int).unwrap()))
ba9703b0 1071 }
136023e0
XL
1072 // Pointer types
1073 ty::Ref(..) | ty::RawPtr(_) | ty::FnPtr(_) => {
29967ef6 1074 let data = int.assert_bits(self.tcx().data_layout.pointer_size);
ba9703b0
XL
1075 self = self.typed_value(
1076 |mut this| {
1077 write!(this, "0x{:x}", data)?;
1078 Ok(this)
1079 },
1080 |this| this.print_type(ty),
1081 " as ",
1082 )?;
dfeec247 1083 }
ba9703b0 1084 // For function type zsts just printing the path is enough
6a06907d 1085 ty::FnDef(d, s) if int == ScalarInt::ZST => {
29967ef6
XL
1086 p!(print_value_path(*d, s))
1087 }
ba9703b0 1088 // Nontrivial types with scalar bit representation
6a06907d 1089 _ => {
ba9703b0 1090 let print = |mut this: Self| {
29967ef6 1091 if int.size() == Size::ZERO {
ba9703b0 1092 write!(this, "transmute(())")?;
416331ca 1093 } else {
29967ef6 1094 write!(this, "transmute(0x{:x})", int)?;
dc9dc135 1095 }
ba9703b0
XL
1096 Ok(this)
1097 };
1098 self = if print_ty {
1099 self.typed_value(print, |this| this.print_type(ty), ": ")?
e74abb32 1100 } else {
ba9703b0 1101 print(self)?
e74abb32 1102 };
ba9703b0 1103 }
ba9703b0
XL
1104 }
1105 Ok(self)
1106 }
1107
1108 /// This is overridden for MIR printing because we only want to hide alloc ids from users, not
1109 /// from MIR where it is actually useful.
136023e0 1110 fn pretty_print_const_pointer<Tag: Provenance>(
ba9703b0 1111 mut self,
136023e0 1112 _: Pointer<Tag>,
ba9703b0
XL
1113 ty: Ty<'tcx>,
1114 print_ty: bool,
1115 ) -> Result<Self::Const, Self::Error> {
1116 if print_ty {
1117 self.typed_value(
1118 |mut this| {
1119 this.write_str("&_")?;
1120 Ok(this)
1121 },
1122 |this| this.print_type(ty),
1123 ": ",
1124 )
1125 } else {
1126 self.write_str("&_")?;
1127 Ok(self)
1128 }
1129 }
1130
1131 fn pretty_print_byte_str(mut self, byte_str: &'tcx [u8]) -> Result<Self::Const, Self::Error> {
1132 define_scoped_cx!(self);
29967ef6 1133 p!("b\"");
ba9703b0
XL
1134 for &c in byte_str {
1135 for e in std::ascii::escape_default(c) {
1136 self.write_char(e as char)?;
1137 }
1138 }
29967ef6 1139 p!("\"");
ba9703b0
XL
1140 Ok(self)
1141 }
1142
1143 fn pretty_print_const_value(
1144 mut self,
1145 ct: ConstValue<'tcx>,
1146 ty: Ty<'tcx>,
1147 print_ty: bool,
1148 ) -> Result<Self::Const, Self::Error> {
1149 define_scoped_cx!(self);
1150
1151 if self.tcx().sess.verbose() {
29967ef6 1152 p!(write("ConstValue({:?}: ", ct), print(ty), ")");
ba9703b0
XL
1153 return Ok(self);
1154 }
1155
1156 let u8_type = self.tcx().types.u8;
1157
1b1a35ee 1158 match (ct, ty.kind()) {
ba9703b0
XL
1159 // Byte/string slices, printed as (byte) string literals.
1160 (
1161 ConstValue::Slice { data, start, end },
1162 ty::Ref(_, ty::TyS { kind: ty::Slice(t), .. }, _),
1163 ) if *t == u8_type => {
1164 // The `inspect` here is okay since we checked the bounds, and there are
1165 // no relocations (we have an active slice reference here). We don't use
1166 // this result to affect interpreter execution.
3dfed10e 1167 let byte_str = data.inspect_with_uninit_and_ptr_outside_interpreter(start..end);
ba9703b0
XL
1168 self.pretty_print_byte_str(byte_str)
1169 }
1170 (
1171 ConstValue::Slice { data, start, end },
1172 ty::Ref(_, ty::TyS { kind: ty::Str, .. }, _),
1173 ) => {
1174 // The `inspect` here is okay since we checked the bounds, and there are no
1175 // relocations (we have an active `str` reference here). We don't use this
1176 // result to affect interpreter execution.
3dfed10e 1177 let slice = data.inspect_with_uninit_and_ptr_outside_interpreter(start..end);
29967ef6 1178 let s = std::str::from_utf8(slice).expect("non utf8 str from miri");
ba9703b0
XL
1179 p!(write("{:?}", s));
1180 Ok(self)
1181 }
1182 (ConstValue::ByRef { alloc, offset }, ty::Array(t, n)) if *t == u8_type => {
1183 let n = n.val.try_to_bits(self.tcx().data_layout.pointer_size).unwrap();
1184 // cast is ok because we already checked for pointer size (32 or 64 bit) above
17df50a5 1185 let range = AllocRange { start: offset, size: Size::from_bytes(n) };
ba9703b0 1186
17df50a5 1187 let byte_str = alloc.get_bytes(&self.tcx(), range).unwrap();
29967ef6 1188 p!("*");
ba9703b0
XL
1189 p!(pretty_print_byte_str(byte_str));
1190 Ok(self)
1191 }
1192
1193 // Aggregates, printed as array/tuple/struct/variant construction syntax.
1194 //
1195 // NB: the `has_param_types_or_consts` check ensures that we can use
1196 // the `destructure_const` query with an empty `ty::ParamEnv` without
1197 // introducing ICEs (e.g. via `layout_of`) from missing bounds.
1198 // E.g. `transmute([0usize; 2]): (u8, *mut T)` needs to know `T: Sized`
1199 // to be able to destructure the tuple into `(0u8, *mut T)
1200 //
1201 // FIXME(eddyb) for `--emit=mir`/`-Z dump-mir`, we should provide the
1202 // correct `ty::ParamEnv` to allow printing *all* constant values.
1203 (_, ty::Array(..) | ty::Tuple(..) | ty::Adt(..)) if !ty.has_param_types_or_consts() => {
1204 let contents = self.tcx().destructure_const(
1205 ty::ParamEnv::reveal_all()
1206 .and(self.tcx().mk_const(ty::Const { val: ty::ConstKind::Value(ct), ty })),
1207 );
1208 let fields = contents.fields.iter().copied();
1209
1b1a35ee 1210 match *ty.kind() {
ba9703b0 1211 ty::Array(..) => {
29967ef6 1212 p!("[", comma_sep(fields), "]");
ba9703b0
XL
1213 }
1214 ty::Tuple(..) => {
29967ef6 1215 p!("(", comma_sep(fields));
ba9703b0 1216 if contents.fields.len() == 1 {
29967ef6 1217 p!(",");
ba9703b0 1218 }
29967ef6 1219 p!(")");
dfeec247 1220 }
f035d41b
XL
1221 ty::Adt(def, substs) if def.variants.is_empty() => {
1222 p!(print_value_path(def.did, substs));
1223 }
ba9703b0 1224 ty::Adt(def, substs) => {
f035d41b
XL
1225 let variant_id =
1226 contents.variant.expect("destructed const of adt without variant id");
1227 let variant_def = &def.variants[variant_id];
ba9703b0
XL
1228 p!(print_value_path(variant_def.def_id, substs));
1229
1230 match variant_def.ctor_kind {
1231 CtorKind::Const => {}
1232 CtorKind::Fn => {
29967ef6 1233 p!("(", comma_sep(fields), ")");
ba9703b0
XL
1234 }
1235 CtorKind::Fictive => {
29967ef6 1236 p!(" {{ ");
ba9703b0 1237 let mut first = true;
cdc7bbd5 1238 for (field_def, field) in iter::zip(&variant_def.fields, fields) {
ba9703b0 1239 if !first {
29967ef6 1240 p!(", ");
ba9703b0
XL
1241 }
1242 p!(write("{}: ", field_def.ident), print(field));
1243 first = false;
1244 }
29967ef6 1245 p!(" }}");
ba9703b0
XL
1246 }
1247 }
1248 }
1249 _ => unreachable!(),
dc9dc135 1250 }
ba9703b0
XL
1251
1252 Ok(self)
dc9dc135 1253 }
ba9703b0
XL
1254
1255 (ConstValue::Scalar(scalar), _) => self.pretty_print_const_scalar(scalar, ty, print_ty),
1256
1257 // FIXME(oli-obk): also pretty print arrays and other aggregate constants by reading
1258 // their fields instead of just dumping the memory.
1259 _ => {
1260 // fallback
1261 p!(write("{:?}", ct));
1262 if print_ty {
29967ef6 1263 p!(": ", print(ty));
ba9703b0
XL
1264 }
1265 Ok(self)
1266 }
1267 }
dc9dc135 1268 }
532ac7d7
XL
1269}
1270
1271// HACK(eddyb) boxed to avoid moving around a large struct by-value.
dc9dc135 1272pub struct FmtPrinter<'a, 'tcx, F>(Box<FmtPrinterData<'a, 'tcx, F>>);
532ac7d7 1273
dc9dc135
XL
1274pub struct FmtPrinterData<'a, 'tcx, F> {
1275 tcx: TyCtxt<'tcx>,
532ac7d7
XL
1276 fmt: F,
1277
1278 empty_path: bool,
1279 in_value: bool,
ba9703b0 1280 pub print_alloc_ids: bool,
532ac7d7 1281
e74abb32 1282 used_region_names: FxHashSet<Symbol>,
532ac7d7
XL
1283 region_index: usize,
1284 binder_depth: usize,
6c58768f 1285 printed_type_count: usize,
532ac7d7
XL
1286
1287 pub region_highlight_mode: RegionHighlightMode,
dc9dc135 1288
5869c6ff 1289 pub name_resolver: Option<Box<&'a dyn Fn(ty::TyVid) -> Option<String>>>,
532ac7d7
XL
1290}
1291
dc9dc135
XL
1292impl<F> Deref for FmtPrinter<'a, 'tcx, F> {
1293 type Target = FmtPrinterData<'a, 'tcx, F>;
532ac7d7
XL
1294 fn deref(&self) -> &Self::Target {
1295 &self.0
1296 }
1297}
1298
dc9dc135 1299impl<F> DerefMut for FmtPrinter<'_, '_, F> {
532ac7d7
XL
1300 fn deref_mut(&mut self) -> &mut Self::Target {
1301 &mut self.0
1302 }
1303}
1304
dc9dc135
XL
1305impl<F> FmtPrinter<'a, 'tcx, F> {
1306 pub fn new(tcx: TyCtxt<'tcx>, fmt: F, ns: Namespace) -> Self {
532ac7d7
XL
1307 FmtPrinter(Box::new(FmtPrinterData {
1308 tcx,
1309 fmt,
1310 empty_path: false,
1311 in_value: ns == Namespace::ValueNS,
ba9703b0 1312 print_alloc_ids: false,
532ac7d7
XL
1313 used_region_names: Default::default(),
1314 region_index: 0,
1315 binder_depth: 0,
6c58768f 1316 printed_type_count: 0,
532ac7d7 1317 region_highlight_mode: RegionHighlightMode::default(),
dc9dc135 1318 name_resolver: None,
532ac7d7
XL
1319 }))
1320 }
1321}
1322
dfeec247
XL
1323// HACK(eddyb) get rid of `def_path_str` and/or pass `Namespace` explicitly always
1324// (but also some things just print a `DefId` generally so maybe we need this?)
1325fn guess_def_namespace(tcx: TyCtxt<'_>, def_id: DefId) -> Namespace {
1326 match tcx.def_key(def_id).disambiguated_data.data {
1327 DefPathData::TypeNs(..) | DefPathData::CrateRoot | DefPathData::ImplTrait => {
1328 Namespace::TypeNS
532ac7d7 1329 }
dfeec247
XL
1330
1331 DefPathData::ValueNs(..)
1332 | DefPathData::AnonConst
1333 | DefPathData::ClosureExpr
1334 | DefPathData::Ctor => Namespace::ValueNS,
1335
1336 DefPathData::MacroNs(..) => Namespace::MacroNS,
1337
1338 _ => Namespace::TypeNS,
532ac7d7 1339 }
dfeec247 1340}
532ac7d7 1341
dfeec247 1342impl TyCtxt<'t> {
532ac7d7
XL
1343 /// Returns a string identifying this `DefId`. This string is
1344 /// suitable for user output.
1345 pub fn def_path_str(self, def_id: DefId) -> String {
60c5eb7d
XL
1346 self.def_path_str_with_substs(def_id, &[])
1347 }
1348
1349 pub fn def_path_str_with_substs(self, def_id: DefId, substs: &'t [GenericArg<'t>]) -> String {
dfeec247 1350 let ns = guess_def_namespace(self, def_id);
532ac7d7
XL
1351 debug!("def_path_str: def_id={:?}, ns={:?}", def_id, ns);
1352 let mut s = String::new();
60c5eb7d 1353 let _ = FmtPrinter::new(self, &mut s, ns).print_def_path(def_id, substs);
532ac7d7
XL
1354 s
1355 }
1356}
1357
dc9dc135 1358impl<F: fmt::Write> fmt::Write for FmtPrinter<'_, '_, F> {
532ac7d7
XL
1359 fn write_str(&mut self, s: &str) -> fmt::Result {
1360 self.fmt.write_str(s)
1361 }
1362}
1363
dc9dc135 1364impl<F: fmt::Write> Printer<'tcx> for FmtPrinter<'_, 'tcx, F> {
532ac7d7
XL
1365 type Error = fmt::Error;
1366
1367 type Path = Self;
1368 type Region = Self;
1369 type Type = Self;
1370 type DynExistential = Self;
dc9dc135 1371 type Const = Self;
532ac7d7 1372
dc9dc135 1373 fn tcx(&'a self) -> TyCtxt<'tcx> {
532ac7d7
XL
1374 self.tcx
1375 }
1376
1377 fn print_def_path(
1378 mut self,
1379 def_id: DefId,
e74abb32 1380 substs: &'tcx [GenericArg<'tcx>],
532ac7d7
XL
1381 ) -> Result<Self::Path, Self::Error> {
1382 define_scoped_cx!(self);
1383
1384 if substs.is_empty() {
1b1a35ee
XL
1385 match self.try_print_trimmed_def_path(def_id)? {
1386 (cx, true) => return Ok(cx),
1387 (cx, false) => self = cx,
1388 }
1389
532ac7d7
XL
1390 match self.try_print_visible_def_path(def_id)? {
1391 (cx, true) => return Ok(cx),
1392 (cx, false) => self = cx,
1393 }
1394 }
1395
1396 let key = self.tcx.def_key(def_id);
1397 if let DefPathData::Impl = key.disambiguated_data.data {
1398 // Always use types for non-local impls, where types are always
1399 // available, and filename/line-number is mostly uninteresting.
dfeec247
XL
1400 let use_types = !def_id.is_local() || {
1401 // Otherwise, use filename/line-number if forced.
1402 let force_no_types = FORCE_IMPL_FILENAME_LINE.with(|f| f.get());
1403 !force_no_types
1404 };
532ac7d7
XL
1405
1406 if !use_types {
1407 // If no type info is available, fall back to
1408 // pretty printing some span information. This should
1409 // only occur very early in the compiler pipeline.
1410 let parent_def_id = DefId { index: key.parent.unwrap(), ..def_id };
1411 let span = self.tcx.def_span(def_id);
1412
1413 self = self.print_def_path(parent_def_id, &[])?;
1414
1415 // HACK(eddyb) copy of `path_append` to avoid
1416 // constructing a `DisambiguatedDefPathData`.
1417 if !self.empty_path {
1418 write!(self, "::")?;
1419 }
17df50a5
XL
1420 write!(
1421 self,
1422 "<impl at {}>",
1423 // This may end up in stderr diagnostics but it may also be emitted
1424 // into MIR. Hence we use the remapped path if available
1425 self.tcx.sess.source_map().span_to_embeddable_string(span)
1426 )?;
532ac7d7
XL
1427 self.empty_path = false;
1428
1429 return Ok(self);
1430 }
1431 }
1432
1433 self.default_print_def_path(def_id, substs)
1434 }
1435
dfeec247 1436 fn print_region(self, region: ty::Region<'_>) -> Result<Self::Region, Self::Error> {
532ac7d7
XL
1437 self.pretty_print_region(region)
1438 }
1439
6c58768f 1440 fn print_type(mut self, ty: Ty<'tcx>) -> Result<Self::Type, Self::Error> {
136023e0 1441 let type_length_limit = self.tcx.type_length_limit();
cdc7bbd5 1442 if type_length_limit.value_within_limit(self.printed_type_count) {
6c58768f
XL
1443 self.printed_type_count += 1;
1444 self.pretty_print_type(ty)
1445 } else {
1446 write!(self, "...")?;
1447 Ok(self)
1448 }
532ac7d7
XL
1449 }
1450
1451 fn print_dyn_existential(
1452 self,
cdc7bbd5 1453 predicates: &'tcx ty::List<ty::Binder<'tcx, ty::ExistentialPredicate<'tcx>>>,
532ac7d7
XL
1454 ) -> Result<Self::DynExistential, Self::Error> {
1455 self.pretty_print_dyn_existential(predicates)
1456 }
1457
dfeec247
XL
1458 fn print_const(self, ct: &'tcx ty::Const<'tcx>) -> Result<Self::Const, Self::Error> {
1459 self.pretty_print_const(ct, true)
dc9dc135
XL
1460 }
1461
dfeec247 1462 fn path_crate(mut self, cnum: CrateNum) -> Result<Self::Path, Self::Error> {
532ac7d7
XL
1463 self.empty_path = true;
1464 if cnum == LOCAL_CRATE {
1465 if self.tcx.sess.rust_2018() {
1466 // We add the `crate::` keyword on Rust 2018, only when desired.
1467 if SHOULD_PREFIX_WITH_CRATE.with(|flag| flag.get()) {
dc9dc135 1468 write!(self, "{}", kw::Crate)?;
532ac7d7
XL
1469 self.empty_path = false;
1470 }
1471 }
1472 } else {
1473 write!(self, "{}", self.tcx.crate_name(cnum))?;
1474 self.empty_path = false;
1475 }
1476 Ok(self)
1477 }
e1599b0c 1478
532ac7d7
XL
1479 fn path_qualified(
1480 mut self,
1481 self_ty: Ty<'tcx>,
1482 trait_ref: Option<ty::TraitRef<'tcx>>,
1483 ) -> Result<Self::Path, Self::Error> {
1484 self = self.pretty_path_qualified(self_ty, trait_ref)?;
1485 self.empty_path = false;
1486 Ok(self)
1487 }
1488
1489 fn path_append_impl(
1490 mut self,
1491 print_prefix: impl FnOnce(Self) -> Result<Self::Path, Self::Error>,
1492 _disambiguated_data: &DisambiguatedDefPathData,
1493 self_ty: Ty<'tcx>,
1494 trait_ref: Option<ty::TraitRef<'tcx>>,
1495 ) -> Result<Self::Path, Self::Error> {
dfeec247
XL
1496 self = self.pretty_path_append_impl(
1497 |mut cx| {
1498 cx = print_prefix(cx)?;
1499 if !cx.empty_path {
1500 write!(cx, "::")?;
1501 }
532ac7d7 1502
dfeec247
XL
1503 Ok(cx)
1504 },
1505 self_ty,
1506 trait_ref,
1507 )?;
532ac7d7
XL
1508 self.empty_path = false;
1509 Ok(self)
1510 }
e1599b0c 1511
532ac7d7
XL
1512 fn path_append(
1513 mut self,
1514 print_prefix: impl FnOnce(Self) -> Result<Self::Path, Self::Error>,
1515 disambiguated_data: &DisambiguatedDefPathData,
1516 ) -> Result<Self::Path, Self::Error> {
1517 self = print_prefix(self)?;
1518
1519 // Skip `::{{constructor}}` on tuple/unit structs.
ba9703b0
XL
1520 if let DefPathData::Ctor = disambiguated_data.data {
1521 return Ok(self);
532ac7d7
XL
1522 }
1523
1524 // FIXME(eddyb) `name` should never be empty, but it
1525 // currently is for `extern { ... }` "foreign modules".
1b1a35ee 1526 let name = disambiguated_data.data.name();
5869c6ff 1527 if name != DefPathDataName::Named(kw::Empty) {
532ac7d7
XL
1528 if !self.empty_path {
1529 write!(self, "::")?;
1530 }
532ac7d7 1531
1b1a35ee
XL
1532 if let DefPathDataName::Named(name) = name {
1533 if Ident::with_dummy_span(name).is_raw_guess() {
1534 write!(self, "r#")?;
1535 }
532ac7d7
XL
1536 }
1537
1b1a35ee
XL
1538 let verbose = self.tcx.sess.verbose();
1539 disambiguated_data.fmt_maybe_verbose(&mut self, verbose)?;
1540
532ac7d7
XL
1541 self.empty_path = false;
1542 }
1543
1544 Ok(self)
1545 }
e1599b0c 1546
532ac7d7
XL
1547 fn path_generic_args(
1548 mut self,
1549 print_prefix: impl FnOnce(Self) -> Result<Self::Path, Self::Error>,
e74abb32 1550 args: &[GenericArg<'tcx>],
532ac7d7
XL
1551 ) -> Result<Self::Path, Self::Error> {
1552 self = print_prefix(self)?;
1553
1554 // Don't print `'_` if there's no unerased regions.
dfeec247
XL
1555 let print_regions = args.iter().any(|arg| match arg.unpack() {
1556 GenericArgKind::Lifetime(r) => *r != ty::ReErased,
1557 _ => false,
532ac7d7 1558 });
dfeec247
XL
1559 let args = args.iter().cloned().filter(|arg| match arg.unpack() {
1560 GenericArgKind::Lifetime(_) => print_regions,
1561 _ => true,
532ac7d7
XL
1562 });
1563
1564 if args.clone().next().is_some() {
1565 if self.in_value {
1566 write!(self, "::")?;
1567 }
1568 self.generic_delimiters(|cx| cx.comma_sep(args))
1569 } else {
1570 Ok(self)
1571 }
1572 }
1573}
1574
dc9dc135
XL
1575impl<F: fmt::Write> PrettyPrinter<'tcx> for FmtPrinter<'_, 'tcx, F> {
1576 fn infer_ty_name(&self, id: ty::TyVid) -> Option<String> {
1577 self.0.name_resolver.as_ref().and_then(|func| func(id))
1578 }
1579
532ac7d7
XL
1580 fn print_value_path(
1581 mut self,
1582 def_id: DefId,
e74abb32 1583 substs: &'tcx [GenericArg<'tcx>],
532ac7d7
XL
1584 ) -> Result<Self::Path, Self::Error> {
1585 let was_in_value = std::mem::replace(&mut self.in_value, true);
1586 self = self.print_def_path(def_id, substs)?;
1587 self.in_value = was_in_value;
1588
1589 Ok(self)
1590 }
1591
cdc7bbd5 1592 fn in_binder<T>(self, value: &ty::Binder<'tcx, T>) -> Result<Self, Self::Error>
dc9dc135
XL
1593 where
1594 T: Print<'tcx, Self, Output = Self, Error = Self::Error> + TypeFoldable<'tcx>,
532ac7d7
XL
1595 {
1596 self.pretty_in_binder(value)
1597 }
1598
fc512014
XL
1599 fn wrap_binder<T, C: Fn(&T, Self) -> Result<Self, Self::Error>>(
1600 self,
cdc7bbd5 1601 value: &ty::Binder<'tcx, T>,
fc512014
XL
1602 f: C,
1603 ) -> Result<Self, Self::Error>
1604 where
1605 T: Print<'tcx, Self, Output = Self, Error = Self::Error> + TypeFoldable<'tcx>,
1606 {
1607 self.pretty_wrap_binder(value, f)
1608 }
1609
ba9703b0
XL
1610 fn typed_value(
1611 mut self,
1612 f: impl FnOnce(Self) -> Result<Self, Self::Error>,
1613 t: impl FnOnce(Self) -> Result<Self, Self::Error>,
1614 conversion: &str,
1615 ) -> Result<Self::Const, Self::Error> {
1616 self.write_str("{")?;
1617 self = f(self)?;
1618 self.write_str(conversion)?;
1619 let was_in_value = std::mem::replace(&mut self.in_value, false);
1620 self = t(self)?;
1621 self.in_value = was_in_value;
1622 self.write_str("}")?;
1623 Ok(self)
1624 }
1625
532ac7d7
XL
1626 fn generic_delimiters(
1627 mut self,
1628 f: impl FnOnce(Self) -> Result<Self, Self::Error>,
1629 ) -> Result<Self, Self::Error> {
1630 write!(self, "<")?;
1631
1632 let was_in_value = std::mem::replace(&mut self.in_value, false);
1633 let mut inner = f(self)?;
1634 inner.in_value = was_in_value;
1635
1636 write!(inner, ">")?;
1637 Ok(inner)
1638 }
1639
dfeec247 1640 fn region_should_not_be_omitted(&self, region: ty::Region<'_>) -> bool {
532ac7d7
XL
1641 let highlight = self.region_highlight_mode;
1642 if highlight.region_highlighted(region).is_some() {
1643 return true;
1644 }
1645
1646 if self.tcx.sess.verbose() {
1647 return true;
1648 }
1649
1650 let identify_regions = self.tcx.sess.opts.debugging_opts.identify_regions;
1651
1652 match *region {
1653 ty::ReEarlyBound(ref data) => {
5869c6ff 1654 data.name != kw::Empty && data.name != kw::UnderscoreLifetime
532ac7d7
XL
1655 }
1656
cdc7bbd5 1657 ty::ReLateBound(_, ty::BoundRegion { kind: br, .. })
dfeec247
XL
1658 | ty::ReFree(ty::FreeRegion { bound_region: br, .. })
1659 | ty::RePlaceholder(ty::Placeholder { name: br, .. }) => {
532ac7d7 1660 if let ty::BrNamed(_, name) = br {
5869c6ff 1661 if name != kw::Empty && name != kw::UnderscoreLifetime {
532ac7d7
XL
1662 return true;
1663 }
1664 }
1665
1666 if let Some((region, _)) = highlight.highlight_bound_region {
1667 if br == region {
1668 return true;
1669 }
1670 }
1671
1672 false
1673 }
1674
f9f354fc 1675 ty::ReVar(_) if identify_regions => true,
532ac7d7 1676
f9f354fc 1677 ty::ReVar(_) | ty::ReErased => false,
532ac7d7 1678
ba9703b0
XL
1679 ty::ReStatic | ty::ReEmpty(_) => true,
1680 }
1681 }
1682
136023e0 1683 fn pretty_print_const_pointer<Tag: Provenance>(
ba9703b0 1684 self,
136023e0 1685 p: Pointer<Tag>,
ba9703b0
XL
1686 ty: Ty<'tcx>,
1687 print_ty: bool,
1688 ) -> Result<Self::Const, Self::Error> {
1689 let print = |mut this: Self| {
1690 define_scoped_cx!(this);
1691 if this.print_alloc_ids {
1692 p!(write("{:?}", p));
1693 } else {
29967ef6 1694 p!("&_");
ba9703b0
XL
1695 }
1696 Ok(this)
1697 };
1698 if print_ty {
1699 self.typed_value(print, |this| this.print_type(ty), ": ")
1700 } else {
1701 print(self)
532ac7d7
XL
1702 }
1703 }
1704}
1705
1706// HACK(eddyb) limited to `FmtPrinter` because of `region_highlight_mode`.
dc9dc135 1707impl<F: fmt::Write> FmtPrinter<'_, '_, F> {
dfeec247 1708 pub fn pretty_print_region(mut self, region: ty::Region<'_>) -> Result<Self, fmt::Error> {
532ac7d7
XL
1709 define_scoped_cx!(self);
1710
1711 // Watch out for region highlights.
1712 let highlight = self.region_highlight_mode;
1713 if let Some(n) = highlight.region_highlighted(region) {
1714 p!(write("'{}", n));
1715 return Ok(self);
1716 }
1717
1718 if self.tcx.sess.verbose() {
1719 p!(write("{:?}", region));
1720 return Ok(self);
1721 }
1722
1723 let identify_regions = self.tcx.sess.opts.debugging_opts.identify_regions;
1724
1725 // These printouts are concise. They do not contain all the information
1726 // the user might want to diagnose an error, but there is basically no way
1727 // to fit that into a short string. Hence the recommendation to use
1728 // `explain_region()` or `note_and_explain_region()`.
1729 match *region {
1730 ty::ReEarlyBound(ref data) => {
5869c6ff 1731 if data.name != kw::Empty {
532ac7d7
XL
1732 p!(write("{}", data.name));
1733 return Ok(self);
1734 }
1735 }
cdc7bbd5 1736 ty::ReLateBound(_, ty::BoundRegion { kind: br, .. })
dfeec247
XL
1737 | ty::ReFree(ty::FreeRegion { bound_region: br, .. })
1738 | ty::RePlaceholder(ty::Placeholder { name: br, .. }) => {
532ac7d7 1739 if let ty::BrNamed(_, name) = br {
5869c6ff 1740 if name != kw::Empty && name != kw::UnderscoreLifetime {
532ac7d7
XL
1741 p!(write("{}", name));
1742 return Ok(self);
1743 }
1744 }
1745
1746 if let Some((region, counter)) = highlight.highlight_bound_region {
1747 if br == region {
1748 p!(write("'{}", counter));
1749 return Ok(self);
1750 }
1751 }
1752 }
532ac7d7
XL
1753 ty::ReVar(region_vid) if identify_regions => {
1754 p!(write("{:?}", region_vid));
1755 return Ok(self);
1756 }
1757 ty::ReVar(_) => {}
f9f354fc 1758 ty::ReErased => {}
532ac7d7 1759 ty::ReStatic => {
29967ef6 1760 p!("'static");
532ac7d7
XL
1761 return Ok(self);
1762 }
74b04a01 1763 ty::ReEmpty(ty::UniverseIndex::ROOT) => {
29967ef6 1764 p!("'<empty>");
532ac7d7
XL
1765 return Ok(self);
1766 }
74b04a01
XL
1767 ty::ReEmpty(ui) => {
1768 p!(write("'<empty:{:?}>", ui));
1769 return Ok(self);
1770 }
532ac7d7
XL
1771 }
1772
29967ef6 1773 p!("'_");
532ac7d7
XL
1774
1775 Ok(self)
1776 }
1777}
1778
136023e0
XL
1779/// Folds through bound vars and placeholders, naming them
1780struct RegionFolder<'a, 'tcx> {
1781 tcx: TyCtxt<'tcx>,
1782 current_index: ty::DebruijnIndex,
1783 region_map: BTreeMap<ty::BoundRegion, ty::Region<'tcx>>,
1784 name: &'a mut (dyn FnMut(ty::BoundRegion) -> ty::Region<'tcx> + 'a),
1785}
1786
1787impl<'a, 'tcx> ty::TypeFolder<'tcx> for RegionFolder<'a, 'tcx> {
1788 fn tcx<'b>(&'b self) -> TyCtxt<'tcx> {
1789 self.tcx
1790 }
1791
1792 fn fold_binder<T: TypeFoldable<'tcx>>(
1793 &mut self,
1794 t: ty::Binder<'tcx, T>,
1795 ) -> ty::Binder<'tcx, T> {
1796 self.current_index.shift_in(1);
1797 let t = t.super_fold_with(self);
1798 self.current_index.shift_out(1);
1799 t
1800 }
1801
1802 fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> {
1803 match *t.kind() {
1804 _ if t.has_vars_bound_at_or_above(self.current_index) || t.has_placeholders() => {
1805 return t.super_fold_with(self);
1806 }
1807 _ => {}
1808 }
1809 t
1810 }
1811
1812 fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> {
1813 let name = &mut self.name;
1814 let region = match *r {
1815 ty::ReLateBound(_, br) => self.region_map.entry(br).or_insert_with(|| name(br)),
1816 ty::RePlaceholder(ty::PlaceholderRegion { name: kind, .. }) => {
1817 // If this is an anonymous placeholder, don't rename. Otherwise, in some
1818 // async fns, we get a `for<'r> Send` bound
1819 match kind {
1820 ty::BrAnon(_) | ty::BrEnv => r,
1821 _ => {
1822 // Index doesn't matter, since this is just for naming and these never get bound
1823 let br = ty::BoundRegion { var: ty::BoundVar::from_u32(0), kind };
1824 self.region_map.entry(br).or_insert_with(|| name(br))
1825 }
1826 }
1827 }
1828 _ => return r,
1829 };
1830 if let ty::ReLateBound(debruijn1, br) = *region {
1831 assert_eq!(debruijn1, ty::INNERMOST);
1832 self.tcx.mk_region(ty::ReLateBound(self.current_index, br))
1833 } else {
1834 region
1835 }
1836 }
1837}
1838
532ac7d7
XL
1839// HACK(eddyb) limited to `FmtPrinter` because of `binder_depth`,
1840// `region_index` and `used_region_names`.
dc9dc135 1841impl<F: fmt::Write> FmtPrinter<'_, 'tcx, F> {
60c5eb7d
XL
1842 pub fn name_all_regions<T>(
1843 mut self,
cdc7bbd5 1844 value: &ty::Binder<'tcx, T>,
136023e0 1845 ) -> Result<(Self, T, BTreeMap<ty::BoundRegion, ty::Region<'tcx>>), fmt::Error>
dc9dc135
XL
1846 where
1847 T: Print<'tcx, Self, Output = Self, Error = fmt::Error> + TypeFoldable<'tcx>,
532ac7d7 1848 {
e74abb32 1849 fn name_by_region_index(index: usize) -> Symbol {
532ac7d7 1850 match index {
e74abb32
XL
1851 0 => Symbol::intern("'r"),
1852 1 => Symbol::intern("'s"),
dfeec247 1853 i => Symbol::intern(&format!("'t{}", i - 2)),
48663c56 1854 }
532ac7d7
XL
1855 }
1856
1857 // Replace any anonymous late-bound regions with named
e74abb32 1858 // variants, using new unique identifiers, so that we can
532ac7d7
XL
1859 // clearly differentiate between named and unnamed regions in
1860 // the output. We'll probably want to tweak this over time to
1861 // decide just how much information to give.
1862 if self.binder_depth == 0 {
1863 self.prepare_late_bound_region_info(value);
1864 }
1865
1866 let mut empty = true;
1867 let mut start_or_continue = |cx: &mut Self, start: &str, cont: &str| {
136023e0
XL
1868 let w = if empty {
1869 empty = false;
1870 start
1871 } else {
1872 cont
1873 };
1874 let _ = write!(cx, "{}", w);
1875 };
1876 let do_continue = |cx: &mut Self, cont: Symbol| {
1877 let _ = write!(cx, "{}", cont);
532ac7d7
XL
1878 };
1879
1880 define_scoped_cx!(self);
1881
60c5eb7d 1882 let mut region_index = self.region_index;
cdc7bbd5
XL
1883 // If we want to print verbosly, then print *all* binders, even if they
1884 // aren't named. Eventually, we might just want this as the default, but
1885 // this is not *quite* right and changes the ordering of some output
1886 // anyways.
136023e0 1887 let (new_value, map) = if self.tcx().sess.verbose() {
cdc7bbd5
XL
1888 // anon index + 1 (BrEnv takes 0) -> name
1889 let mut region_map: BTreeMap<u32, Symbol> = BTreeMap::default();
1890 let bound_vars = value.bound_vars();
1891 for var in bound_vars {
1892 match var {
1893 ty::BoundVariableKind::Region(ty::BrNamed(_, name)) => {
136023e0
XL
1894 start_or_continue(&mut self, "for<", ", ");
1895 do_continue(&mut self, name);
cdc7bbd5
XL
1896 }
1897 ty::BoundVariableKind::Region(ty::BrAnon(i)) => {
136023e0 1898 start_or_continue(&mut self, "for<", ", ");
cdc7bbd5
XL
1899 let name = loop {
1900 let name = name_by_region_index(region_index);
1901 region_index += 1;
1902 if !self.used_region_names.contains(&name) {
1903 break name;
1904 }
1905 };
136023e0 1906 do_continue(&mut self, name);
cdc7bbd5
XL
1907 region_map.insert(i + 1, name);
1908 }
1909 ty::BoundVariableKind::Region(ty::BrEnv) => {
136023e0 1910 start_or_continue(&mut self, "for<", ", ");
cdc7bbd5
XL
1911 let name = loop {
1912 let name = name_by_region_index(region_index);
1913 region_index += 1;
1914 if !self.used_region_names.contains(&name) {
1915 break name;
1916 }
1917 };
136023e0 1918 do_continue(&mut self, name);
cdc7bbd5
XL
1919 region_map.insert(0, name);
1920 }
1921 _ => continue,
532ac7d7 1922 }
cdc7bbd5 1923 }
136023e0 1924 start_or_continue(&mut self, "", "> ");
cdc7bbd5
XL
1925
1926 self.tcx.replace_late_bound_regions(value.clone(), |br| {
1927 let kind = match br.kind {
1928 ty::BrNamed(_, _) => br.kind,
1929 ty::BrAnon(i) => {
1930 let name = region_map[&(i + 1)];
1931 ty::BrNamed(DefId::local(CRATE_DEF_INDEX), name)
1932 }
1933 ty::BrEnv => {
1934 let name = region_map[&0];
1935 ty::BrNamed(DefId::local(CRATE_DEF_INDEX), name)
1936 }
1937 };
1938 self.tcx.mk_region(ty::ReLateBound(
1939 ty::INNERMOST,
1940 ty::BoundRegion { var: br.var, kind },
1941 ))
1942 })
1943 } else {
136023e0
XL
1944 let tcx = self.tcx;
1945 let mut name = |br: ty::BoundRegion| {
1946 start_or_continue(&mut self, "for<", ", ");
cdc7bbd5
XL
1947 let kind = match br.kind {
1948 ty::BrNamed(_, name) => {
136023e0 1949 do_continue(&mut self, name);
cdc7bbd5
XL
1950 br.kind
1951 }
1952 ty::BrAnon(_) | ty::BrEnv => {
1953 let name = loop {
1954 let name = name_by_region_index(region_index);
1955 region_index += 1;
1956 if !self.used_region_names.contains(&name) {
1957 break name;
1958 }
1959 };
136023e0 1960 do_continue(&mut self, name);
cdc7bbd5
XL
1961 ty::BrNamed(DefId::local(CRATE_DEF_INDEX), name)
1962 }
1963 };
136023e0
XL
1964 tcx.mk_region(ty::ReLateBound(ty::INNERMOST, ty::BoundRegion { var: br.var, kind }))
1965 };
1966 let mut folder = RegionFolder {
1967 tcx,
1968 current_index: ty::INNERMOST,
1969 name: &mut name,
1970 region_map: BTreeMap::new(),
1971 };
1972 let new_value = value.clone().skip_binder().fold_with(&mut folder);
1973 let region_map = folder.region_map;
1974 start_or_continue(&mut self, "", "> ");
1975 (new_value, region_map)
cdc7bbd5 1976 };
532ac7d7
XL
1977
1978 self.binder_depth += 1;
1979 self.region_index = region_index;
136023e0 1980 Ok((self, new_value, map))
60c5eb7d
XL
1981 }
1982
cdc7bbd5 1983 pub fn pretty_in_binder<T>(self, value: &ty::Binder<'tcx, T>) -> Result<Self, fmt::Error>
60c5eb7d
XL
1984 where
1985 T: Print<'tcx, Self, Output = Self, Error = fmt::Error> + TypeFoldable<'tcx>,
1986 {
1987 let old_region_index = self.region_index;
136023e0
XL
1988 let (new, new_value, _) = self.name_all_regions(value)?;
1989 let mut inner = new_value.print(new)?;
532ac7d7
XL
1990 inner.region_index = old_region_index;
1991 inner.binder_depth -= 1;
1992 Ok(inner)
1993 }
1994
fc512014
XL
1995 pub fn pretty_wrap_binder<T, C: Fn(&T, Self) -> Result<Self, fmt::Error>>(
1996 self,
cdc7bbd5 1997 value: &ty::Binder<'tcx, T>,
fc512014
XL
1998 f: C,
1999 ) -> Result<Self, fmt::Error>
2000 where
2001 T: Print<'tcx, Self, Output = Self, Error = fmt::Error> + TypeFoldable<'tcx>,
2002 {
2003 let old_region_index = self.region_index;
136023e0
XL
2004 let (new, new_value, _) = self.name_all_regions(value)?;
2005 let mut inner = f(&new_value, new)?;
fc512014
XL
2006 inner.region_index = old_region_index;
2007 inner.binder_depth -= 1;
2008 Ok(inner)
2009 }
2010
cdc7bbd5 2011 fn prepare_late_bound_region_info<T>(&mut self, value: &ty::Binder<'tcx, T>)
dfeec247
XL
2012 where
2013 T: TypeFoldable<'tcx>,
532ac7d7 2014 {
cdc7bbd5
XL
2015 debug!("prepare_late_bound_region_info(value: {:?})", value);
2016
2017 struct LateBoundRegionNameCollector<'a, 'tcx> {
2018 used_region_names: &'a mut FxHashSet<Symbol>,
2019 type_collector: SsoHashSet<Ty<'tcx>>,
2020 }
2021
2022 impl<'tcx> ty::fold::TypeVisitor<'tcx> for LateBoundRegionNameCollector<'_, 'tcx> {
2023 type BreakTy = ();
2024
fc512014 2025 fn visit_region(&mut self, r: ty::Region<'tcx>) -> ControlFlow<Self::BreakTy> {
cdc7bbd5
XL
2026 debug!("LateBoundRegionNameCollector::visit_region(r: {:?}, address: {:p})", r, &r);
2027 if let ty::ReLateBound(_, ty::BoundRegion { kind: ty::BrNamed(_, name), .. }) = *r {
2028 self.used_region_names.insert(name);
136023e0
XL
2029 } else if let ty::RePlaceholder(ty::PlaceholderRegion {
2030 name: ty::BrNamed(_, name),
2031 ..
2032 }) = *r
2033 {
2034 self.used_region_names.insert(name);
532ac7d7
XL
2035 }
2036 r.super_visit_with(self)
2037 }
cdc7bbd5
XL
2038
2039 // We collect types in order to prevent really large types from compiling for
2040 // a really long time. See issue #83150 for why this is necessary.
2041 fn visit_ty(&mut self, ty: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
2042 debug!("LateBoundRegionNameCollector::visit_ty(ty: {:?}", ty);
2043 let not_previously_inserted = self.type_collector.insert(ty);
2044 if not_previously_inserted {
2045 ty.super_visit_with(self)
2046 } else {
2047 ControlFlow::CONTINUE
2048 }
2049 }
532ac7d7
XL
2050 }
2051
2052 self.used_region_names.clear();
cdc7bbd5
XL
2053 let mut collector = LateBoundRegionNameCollector {
2054 used_region_names: &mut self.used_region_names,
2055 type_collector: SsoHashSet::new(),
2056 };
532ac7d7
XL
2057 value.visit_with(&mut collector);
2058 self.region_index = 0;
2059 }
2060}
2061
cdc7bbd5 2062impl<'tcx, T, P: PrettyPrinter<'tcx>> Print<'tcx, P> for ty::Binder<'tcx, T>
dc9dc135
XL
2063where
2064 T: Print<'tcx, P, Output = P, Error = P::Error> + TypeFoldable<'tcx>,
532ac7d7
XL
2065{
2066 type Output = P;
2067 type Error = P::Error;
2068 fn print(&self, cx: P) -> Result<Self::Output, Self::Error> {
2069 cx.in_binder(self)
2070 }
2071}
2072
dc9dc135
XL
2073impl<'tcx, T, U, P: PrettyPrinter<'tcx>> Print<'tcx, P> for ty::OutlivesPredicate<T, U>
2074where
2075 T: Print<'tcx, P, Output = P, Error = P::Error>,
2076 U: Print<'tcx, P, Output = P, Error = P::Error>,
532ac7d7
XL
2077{
2078 type Output = P;
2079 type Error = P::Error;
2080 fn print(&self, mut cx: P) -> Result<Self::Output, Self::Error> {
2081 define_scoped_cx!(cx);
29967ef6 2082 p!(print(self.0), ": ", print(self.1));
532ac7d7
XL
2083 Ok(cx)
2084 }
2085}
2086
2087macro_rules! forward_display_to_print {
2088 ($($ty:ty),+) => {
2089 $(impl fmt::Display for $ty {
2090 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2091 ty::tls::with(|tcx| {
29967ef6 2092 tcx.lift(*self)
532ac7d7
XL
2093 .expect("could not lift for printing")
2094 .print(FmtPrinter::new(tcx, f, Namespace::TypeNS))?;
2095 Ok(())
2096 })
2097 }
2098 })+
2099 };
2100}
2101
2102macro_rules! define_print_and_forward_display {
2103 (($self:ident, $cx:ident): $($ty:ty $print:block)+) => {
dc9dc135 2104 $(impl<'tcx, P: PrettyPrinter<'tcx>> Print<'tcx, P> for $ty {
532ac7d7
XL
2105 type Output = P;
2106 type Error = fmt::Error;
2107 fn print(&$self, $cx: P) -> Result<Self::Output, Self::Error> {
2108 #[allow(unused_mut)]
2109 let mut $cx = $cx;
2110 define_scoped_cx!($cx);
2111 let _: () = $print;
2112 #[allow(unreachable_code)]
2113 Ok($cx)
2114 }
2115 })+
2116
2117 forward_display_to_print!($($ty),+);
2118 };
2119}
2120
2121// HACK(eddyb) this is separate because `ty::RegionKind` doesn't need lifting.
2122impl fmt::Display for ty::RegionKind {
2123 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2124 ty::tls::with(|tcx| {
2125 self.print(FmtPrinter::new(tcx, f, Namespace::TypeNS))?;
2126 Ok(())
2127 })
2128 }
2129}
2130
60c5eb7d
XL
2131/// Wrapper type for `ty::TraitRef` which opts-in to pretty printing only
2132/// the trait path. That is, it will print `Trait<U>` instead of
2133/// `<T as Trait<U>>`.
2134#[derive(Copy, Clone, TypeFoldable, Lift)]
2135pub struct TraitRefPrintOnlyTraitPath<'tcx>(ty::TraitRef<'tcx>);
2136
2137impl fmt::Debug for TraitRefPrintOnlyTraitPath<'tcx> {
2138 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2139 fmt::Display::fmt(self, f)
2140 }
2141}
2142
2143impl ty::TraitRef<'tcx> {
2144 pub fn print_only_trait_path(self) -> TraitRefPrintOnlyTraitPath<'tcx> {
2145 TraitRefPrintOnlyTraitPath(self)
2146 }
2147}
2148
cdc7bbd5
XL
2149impl ty::Binder<'tcx, ty::TraitRef<'tcx>> {
2150 pub fn print_only_trait_path(self) -> ty::Binder<'tcx, TraitRefPrintOnlyTraitPath<'tcx>> {
60c5eb7d
XL
2151 self.map_bound(|tr| tr.print_only_trait_path())
2152 }
2153}
2154
532ac7d7
XL
2155forward_display_to_print! {
2156 Ty<'tcx>,
cdc7bbd5 2157 &'tcx ty::List<ty::Binder<'tcx, ty::ExistentialPredicate<'tcx>>>,
dc9dc135 2158 &'tcx ty::Const<'tcx>,
532ac7d7
XL
2159
2160 // HACK(eddyb) these are exhaustive instead of generic,
dc9dc135 2161 // because `for<'tcx>` isn't possible yet.
cdc7bbd5
XL
2162 ty::Binder<'tcx, ty::ExistentialPredicate<'tcx>>,
2163 ty::Binder<'tcx, ty::TraitRef<'tcx>>,
2164 ty::Binder<'tcx, TraitRefPrintOnlyTraitPath<'tcx>>,
2165 ty::Binder<'tcx, ty::FnSig<'tcx>>,
2166 ty::Binder<'tcx, ty::TraitPredicate<'tcx>>,
2167 ty::Binder<'tcx, ty::SubtypePredicate<'tcx>>,
2168 ty::Binder<'tcx, ty::ProjectionPredicate<'tcx>>,
2169 ty::Binder<'tcx, ty::OutlivesPredicate<Ty<'tcx>, ty::Region<'tcx>>>,
2170 ty::Binder<'tcx, ty::OutlivesPredicate<ty::Region<'tcx>, ty::Region<'tcx>>>,
532ac7d7
XL
2171
2172 ty::OutlivesPredicate<Ty<'tcx>, ty::Region<'tcx>>,
2173 ty::OutlivesPredicate<ty::Region<'tcx>, ty::Region<'tcx>>
2174}
2175
2176define_print_and_forward_display! {
2177 (self, cx):
2178
2179 &'tcx ty::List<Ty<'tcx>> {
29967ef6 2180 p!("{{", comma_sep(self.iter()), "}}")
532ac7d7
XL
2181 }
2182
2183 ty::TypeAndMut<'tcx> {
60c5eb7d 2184 p!(write("{}", self.mutbl.prefix_str()), print(self.ty))
532ac7d7
XL
2185 }
2186
2187 ty::ExistentialTraitRef<'tcx> {
2188 // Use a type that can't appear in defaults of type parameters.
48663c56 2189 let dummy_self = cx.tcx().mk_ty_infer(ty::FreshTy(0));
532ac7d7 2190 let trait_ref = self.with_self_ty(cx.tcx(), dummy_self);
60c5eb7d 2191 p!(print(trait_ref.print_only_trait_path()))
532ac7d7
XL
2192 }
2193
2194 ty::ExistentialProjection<'tcx> {
2195 let name = cx.tcx().associated_item(self.item_def_id).ident;
2196 p!(write("{} = ", name), print(self.ty))
2197 }
2198
2199 ty::ExistentialPredicate<'tcx> {
2200 match *self {
2201 ty::ExistentialPredicate::Trait(x) => p!(print(x)),
2202 ty::ExistentialPredicate::Projection(x) => p!(print(x)),
2203 ty::ExistentialPredicate::AutoTrait(def_id) => {
2204 p!(print_def_path(def_id, &[]));
2205 }
2206 }
2207 }
2208
2209 ty::FnSig<'tcx> {
60c5eb7d 2210 p!(write("{}", self.unsafety.prefix_str()));
532ac7d7
XL
2211
2212 if self.abi != Abi::Rust {
2213 p!(write("extern {} ", self.abi));
2214 }
2215
29967ef6 2216 p!("fn", pretty_fn_sig(self.inputs(), self.c_variadic, self.output()));
532ac7d7
XL
2217 }
2218
532ac7d7 2219 ty::TraitRef<'tcx> {
60c5eb7d
XL
2220 p!(write("<{} as {}>", self.self_ty(), self.print_only_trait_path()))
2221 }
2222
2223 TraitRefPrintOnlyTraitPath<'tcx> {
2224 p!(print_def_path(self.0.def_id, self.0.substs));
532ac7d7
XL
2225 }
2226
532ac7d7
XL
2227 ty::ParamTy {
2228 p!(write("{}", self.name))
2229 }
2230
2231 ty::ParamConst {
2232 p!(write("{}", self.name))
2233 }
2234
2235 ty::SubtypePredicate<'tcx> {
29967ef6 2236 p!(print(self.a), " <: ", print(self.b))
532ac7d7
XL
2237 }
2238
2239 ty::TraitPredicate<'tcx> {
29967ef6 2240 p!(print(self.trait_ref.self_ty()), ": ",
60c5eb7d 2241 print(self.trait_ref.print_only_trait_path()))
532ac7d7
XL
2242 }
2243
2244 ty::ProjectionPredicate<'tcx> {
29967ef6 2245 p!(print(self.projection_ty), " == ", print(self.ty))
532ac7d7
XL
2246 }
2247
2248 ty::ProjectionTy<'tcx> {
2249 p!(print_def_path(self.item_def_id, self.substs));
2250 }
2251
2252 ty::ClosureKind {
2253 match *self {
29967ef6
XL
2254 ty::ClosureKind::Fn => p!("Fn"),
2255 ty::ClosureKind::FnMut => p!("FnMut"),
2256 ty::ClosureKind::FnOnce => p!("FnOnce"),
532ac7d7
XL
2257 }
2258 }
2259
2260 ty::Predicate<'tcx> {
5869c6ff
XL
2261 let binder = self.kind();
2262 p!(print(binder))
3dfed10e
XL
2263 }
2264
5869c6ff 2265 ty::PredicateKind<'tcx> {
3dfed10e 2266 match *self {
5869c6ff 2267 ty::PredicateKind::Trait(ref data, constness) => {
74b04a01 2268 if let hir::Constness::Const = constness {
29967ef6 2269 p!("const ");
dfeec247
XL
2270 }
2271 p!(print(data))
2272 }
5869c6ff
XL
2273 ty::PredicateKind::Subtype(predicate) => p!(print(predicate)),
2274 ty::PredicateKind::RegionOutlives(predicate) => p!(print(predicate)),
2275 ty::PredicateKind::TypeOutlives(predicate) => p!(print(predicate)),
2276 ty::PredicateKind::Projection(predicate) => p!(print(predicate)),
2277 ty::PredicateKind::WellFormed(arg) => p!(print(arg), " well-formed"),
2278 ty::PredicateKind::ObjectSafe(trait_def_id) => {
29967ef6 2279 p!("the trait `", print_def_path(trait_def_id, &[]), "` is object-safe")
532ac7d7 2280 }
5869c6ff 2281 ty::PredicateKind::ClosureKind(closure_def_id, _closure_substs, kind) => {
29967ef6 2282 p!("the closure `",
3dfed10e
XL
2283 print_value_path(closure_def_id, &[]),
2284 write("` implements the trait `{}`", kind))
532ac7d7 2285 }
5869c6ff 2286 ty::PredicateKind::ConstEvaluatable(def, substs) => {
29967ef6 2287 p!("the constant `", print_value_path(def.did, substs), "` can be evaluated")
532ac7d7 2288 }
5869c6ff 2289 ty::PredicateKind::ConstEquate(c1, c2) => {
29967ef6 2290 p!("the constant `", print(c1), "` equals `", print(c2), "`")
f9f354fc 2291 }
5869c6ff 2292 ty::PredicateKind::TypeWellFormedFromEnv(ty) => {
29967ef6 2293 p!("the type `", print(ty), "` is found in the environment")
1b1a35ee 2294 }
532ac7d7
XL
2295 }
2296 }
2297
e74abb32 2298 GenericArg<'tcx> {
532ac7d7 2299 match self.unpack() {
e74abb32
XL
2300 GenericArgKind::Lifetime(lt) => p!(print(lt)),
2301 GenericArgKind::Type(ty) => p!(print(ty)),
2302 GenericArgKind::Const(ct) => p!(print(ct)),
532ac7d7
XL
2303 }
2304 }
2305}
1b1a35ee
XL
2306
2307fn for_each_def(tcx: TyCtxt<'_>, mut collect_fn: impl for<'b> FnMut(&'b Ident, Namespace, DefId)) {
2308 // Iterate all local crate items no matter where they are defined.
2309 let hir = tcx.hir();
2310 for item in hir.krate().items.values() {
2311 if item.ident.name.as_str().is_empty() || matches!(item.kind, ItemKind::Use(_, _)) {
2312 continue;
2313 }
2314
6a06907d
XL
2315 let def_id = item.def_id.to_def_id();
2316 let ns = tcx.def_kind(def_id).ns().unwrap_or(Namespace::TypeNS);
2317 collect_fn(&item.ident, ns, def_id);
1b1a35ee
XL
2318 }
2319
2320 // Now take care of extern crate items.
2321 let queue = &mut Vec::new();
2322 let mut seen_defs: DefIdSet = Default::default();
2323
136023e0 2324 for &cnum in tcx.crates(()).iter() {
1b1a35ee
XL
2325 let def_id = DefId { krate: cnum, index: CRATE_DEF_INDEX };
2326
2327 // Ignore crates that are not direct dependencies.
2328 match tcx.extern_crate(def_id) {
2329 None => continue,
2330 Some(extern_crate) => {
2331 if !extern_crate.is_direct() {
2332 continue;
2333 }
2334 }
2335 }
2336
2337 queue.push(def_id);
2338 }
2339
2340 // Iterate external crate defs but be mindful about visibility
2341 while let Some(def) = queue.pop() {
2342 for child in tcx.item_children(def).iter() {
2343 if child.vis != ty::Visibility::Public {
2344 continue;
2345 }
2346
2347 match child.res {
2348 def::Res::Def(DefKind::AssocTy, _) => {}
6a06907d 2349 def::Res::Def(DefKind::TyAlias, _) => {}
1b1a35ee
XL
2350 def::Res::Def(defkind, def_id) => {
2351 if let Some(ns) = defkind.ns() {
2352 collect_fn(&child.ident, ns, def_id);
2353 }
2354
2355 if seen_defs.insert(def_id) {
2356 queue.push(def_id);
2357 }
2358 }
2359 _ => {}
2360 }
2361 }
2362 }
2363}
2364
2365/// The purpose of this function is to collect public symbols names that are unique across all
2366/// crates in the build. Later, when printing about types we can use those names instead of the
2367/// full exported path to them.
2368///
2369/// So essentially, if a symbol name can only be imported from one place for a type, and as
2370/// long as it was not glob-imported anywhere in the current crate, we can trim its printed
2371/// path and print only the name.
2372///
2373/// This has wide implications on error messages with types, for example, shortening
2374/// `std::vec::Vec` to just `Vec`, as long as there is no other `Vec` importable anywhere.
2375///
2376/// The implementation uses similar import discovery logic to that of 'use' suggestions.
17df50a5 2377fn trimmed_def_paths(tcx: TyCtxt<'_>, (): ()) -> FxHashMap<DefId, Symbol> {
1b1a35ee
XL
2378 let mut map = FxHashMap::default();
2379
2380 if let TrimmedDefPaths::GoodPath = tcx.sess.opts.trimmed_def_paths {
2381 // For good paths causing this bug, the `rustc_middle::ty::print::with_no_trimmed_paths`
2382 // wrapper can be used to suppress this query, in exchange for full paths being formatted.
2383 tcx.sess.delay_good_path_bug("trimmed_def_paths constructed");
2384 }
2385
2386 let unique_symbols_rev: &mut FxHashMap<(Namespace, Symbol), Option<DefId>> =
2387 &mut FxHashMap::default();
2388
136023e0 2389 for symbol_set in tcx.resolutions(()).glob_map.values() {
1b1a35ee
XL
2390 for symbol in symbol_set {
2391 unique_symbols_rev.insert((Namespace::TypeNS, *symbol), None);
2392 unique_symbols_rev.insert((Namespace::ValueNS, *symbol), None);
2393 unique_symbols_rev.insert((Namespace::MacroNS, *symbol), None);
2394 }
2395 }
2396
2397 for_each_def(tcx, |ident, ns, def_id| {
2398 use std::collections::hash_map::Entry::{Occupied, Vacant};
2399
2400 match unique_symbols_rev.entry((ns, ident.name)) {
2401 Occupied(mut v) => match v.get() {
2402 None => {}
2403 Some(existing) => {
2404 if *existing != def_id {
2405 v.insert(None);
2406 }
2407 }
2408 },
2409 Vacant(v) => {
2410 v.insert(Some(def_id));
2411 }
2412 }
2413 });
2414
2415 for ((_, symbol), opt_def_id) in unique_symbols_rev.drain() {
2416 if let Some(def_id) = opt_def_id {
2417 map.insert(def_id, symbol);
2418 }
2419 }
2420
2421 map
2422}
2423
2424pub fn provide(providers: &mut ty::query::Providers) {
2425 *providers = ty::query::Providers { trimmed_def_paths, ..*providers };
2426}