1use std::cell::Cell;2use std::fmt::{self, Write as _};3use std::iter;4use std::ops::{Deref, DerefMut};56use rustc_abi::{ExternAbi, Size};7use rustc_apfloat::Float;8use rustc_apfloat::ieee::{Double, Half, Quad, Single};9use rustc_attr_ir::lang_items::LangItem;10use rustc_crate_store::{ExternCrate, ExternCrateSource};11use rustc_data_structures::fx::{FxIndexMap, IndexEntry};12use rustc_data_structures::unord::UnordMap;13use rustc_hir as hir;14use rustc_hir::def::{self, CtorKind, DefKind, Namespace};15use rustc_hir::def_id::{DefIdMap, DefIdSet, LOCAL_CRATE, ModId};16use rustc_hir::definitions::{DefKey, DefPathDataName};17use rustc_macros::{Lift, extension};18use rustc_span::{Ident, RemapPathScopeComponents, Symbol, bug, kw, sym};19use rustc_structures::Limit;20use rustc_type_ir::{FieldInfo, Unnormalized, Upcast as _, elaborate};21use smallvec::SmallVec;2223// `pretty` is a separate module only for organization.24use super::*;25use crate::mir::interpret::{AllocRange, GlobalAlloc, Pointer, Provenance, Scalar};26use crate::query::{IntoQueryKey, Providers};27use crate::ty::{28 ConstInt, Expr, GenericArgKind, ParamConst, ScalarInt, Term, TermKind, TraitClause,29 TypeFoldable, TypeSuperFoldable, TypeSuperVisitable, TypeVisitable, TypeVisitableExt,30};3132thread_local! {33 static FORCE_IMPL_FILENAME_LINE: Cell<bool> = const { Cell::new(false) };34 static SHOULD_PREFIX_WITH_CRATE_NAME: Cell<bool> = const { Cell::new(false) };35 static SHOULD_PREFIX_WITH_CRATE: Cell<bool> = const { Cell::new(false) };36 static NO_TRIMMED_PATH: Cell<bool> = const { Cell::new(false) };37 static FORCE_TRIMMED_PATH: Cell<bool> = const { Cell::new(false) };38 static REDUCED_QUERIES: Cell<bool> = const { Cell::new(false) };39 static NO_VISIBLE_PATH: Cell<bool> = const { Cell::new(false) };40 static NO_VISIBLE_PATH_IF_DOC_HIDDEN: Cell<bool> = const { Cell::new(false) };41 static RTN_MODE: Cell<RtnMode> = const { Cell::new(RtnMode::ForDiagnostic) };42}4344/// Rendering style for RTN types.45#[derive(Copy, Clone, PartialEq, Eq, Debug)]46pub enum RtnMode {47 /// Print the RTN type as an impl trait with its path, i.e.e `impl Sized { T::method(..) }`.48 ForDiagnostic,49 /// Print the RTN type as an impl trait, i.e. `impl Sized`.50 ForSignature,51 /// Print the RTN type as a value path, i.e. `T::method(..): ...`.52 ForSuggestion,53}5455macro_rules! define_helper {56 ($($(#[$a:meta])* fn $name:ident($helper:ident, $tl:ident);)+) => {57 $(58 #[must_use]59 pub struct $helper(bool);6061 impl $helper {62 pub fn new() -> $helper {63 $helper($tl.replace(true))64 }65 }6667 $(#[$a])*68 pub macro $name($e:expr) {69 {70 let _guard = $helper::new();71 $e72 }73 }7475 impl Drop for $helper {76 fn drop(&mut self) {77 $tl.set(self.0)78 }79 }8081 pub fn $name() -> bool {82 $tl.get()83 }84 )+85 }86}8788define_helper!(89 /// Avoids running select queries during any prints that occur90 /// during the closure. This may alter the appearance of some91 /// types (e.g. forcing verbose printing for opaque types).92 /// This method is used during some queries (e.g. `explicit_item_bounds`93 /// for opaque types), to ensure that any debug printing that94 /// occurs during the query computation does not end up recursively95 /// calling the same query.96 fn with_reduced_queries(ReducedQueriesGuard, REDUCED_QUERIES);97 /// Force us to name impls with just the filename/line number. We98 /// normally try to use types. But at some points, notably while printing99 /// cycle errors, this can result in extra or suboptimal error output,100 /// so this variable disables that check.101 fn with_forced_impl_filename_line(ForcedImplGuard, FORCE_IMPL_FILENAME_LINE);102 /// Adds the crate name prefix to paths where appropriate.103 /// Unlike `with_crate_prefix`, this unconditionally uses `tcx.crate_name` instead of sometimes104 /// using `crate::` for local items.105 ///106 /// Overrides `with_crate_prefix`.107108 // This function is used by `rustc_public` and downstream rustc-driver in109 // Ferrocene. Please check with them before removing it.110 fn with_resolve_crate_name(CrateNamePrefixGuard, SHOULD_PREFIX_WITH_CRATE_NAME);111 /// Adds the `crate::` prefix to paths where appropriate.112 ///113 /// Ignored if `with_resolve_crate_name` is active.114 fn with_crate_prefix(CratePrefixGuard, SHOULD_PREFIX_WITH_CRATE);115 /// Prevent path trimming if it is turned on. Path trimming affects `Display` impl116 /// of various rustc types, for example `std::vec::Vec` would be trimmed to `Vec`,117 /// if no other `Vec` is found.118 fn with_no_trimmed_paths(NoTrimmedGuard, NO_TRIMMED_PATH);119 fn with_forced_trimmed_paths(ForceTrimmedGuard, FORCE_TRIMMED_PATH);120 /// Prevent selection of visible paths. `Display` impl of DefId will prefer121 /// visible (public) reexports of types as paths.122 fn with_no_visible_paths(NoVisibleGuard, NO_VISIBLE_PATH);123 /// Prevent selection of visible paths if the paths are through a doc hidden path.124 fn with_no_visible_paths_if_doc_hidden(NoVisibleIfDocHiddenGuard, NO_VISIBLE_PATH_IF_DOC_HIDDEN);125);126127#[must_use]128pub struct RtnModeHelper(RtnMode);129130impl RtnModeHelper {131 pub fn with(mode: RtnMode) -> RtnModeHelper {132 RtnModeHelper(RTN_MODE.with(|c| c.replace(mode)))133 }134}135136impl Drop for RtnModeHelper {137 fn drop(&mut self) {138 RTN_MODE.with(|c| c.set(self.0))139 }140}141142/// Print types for the purposes of a suggestion.143///144/// Specifically, this will render RPITITs as `T::method(..)` which is suitable for145/// things like where-clauses.146pub macro with_types_for_suggestion($e:expr) {{147 let _guard = $crate::ty::print::pretty::RtnModeHelper::with(RtnMode::ForSuggestion);148 $e149}}150151/// Print types for the purposes of a signature suggestion.152///153/// Specifically, this will render RPITITs as `impl Trait` rather than `T::method(..)`.154pub macro with_types_for_signature($e:expr) {{155 let _guard = $crate::ty::print::pretty::RtnModeHelper::with(RtnMode::ForSignature);156 $e157}}158159/// Avoids running any queries during prints.160pub macro with_no_queries($e:expr) {{161 $crate::ty::print::with_reduced_queries!($crate::ty::print::with_forced_impl_filename_line!(162 $crate::ty::print::with_no_trimmed_paths!($crate::ty::print::with_no_visible_paths!($e))163 ))164}}165166#[derive(Copy, Clone, Debug, PartialEq, Eq)]167pub enum WrapBinderMode {168 ForAll,169 Unsafe,170}171impl WrapBinderMode {172 pub fn start_str(self) -> &'static str {173 match self {174 WrapBinderMode::ForAll => "for<",175 WrapBinderMode::Unsafe => "unsafe<",176 }177 }178}179180/// The "region highlights" are used to control region printing during181/// specific error messages. When a "region highlight" is enabled, it182/// gives an alternate way to print specific regions. For now, we183/// always print those regions using a number, so something like "`'0`".184///185/// Regions not selected by the region highlight mode are presently186/// unaffected.187#[derive(Copy, Clone, Default)]188pub struct RegionHighlightMode<'tcx> {189 /// If enabled, when we see the selected region, use "`'N`"190 /// instead of the ordinary behavior.191 highlight_regions: [Option<(ty::Region<'tcx>, usize)>; 3],192193 /// If set to `true`, types that include regions will always be included in the output, while194 /// other types will be free to be trimmed.195 pub keep_regions: bool,196197 /// If enabled, when printing a "free region" that originated from198 /// the given `ty::BoundRegionKind`, print it as "`'1`". Free regions that would ordinarily199 /// have names print as normal.200 ///201 /// This is used when you have a signature like `fn foo(x: &u32,202 /// y: &'a u32)` and we want to give a name to the region of the203 /// reference `x`.204 highlight_bound_region: Option<(ty::BoundRegionKind<'tcx>, usize)>,205}206207impl<'tcx> RegionHighlightMode<'tcx> {208 /// If `region` and `number` are both `Some`, invokes209 /// `highlighting_region`.210 pub fn maybe_highlighting_region(211 &mut self,212 region: Option<ty::Region<'tcx>>,213 number: Option<usize>,214 ) {215 self.keep_regions = true;216 if let Some(k) = region217 && let Some(n) = number218 {219 self.highlighting_region(k, n);220 }221 }222223 /// Highlights the region inference variable `vid` as `'N`.224 pub fn highlighting_region(&mut self, region: ty::Region<'tcx>, number: usize) {225 let num_slots = self.highlight_regions.len();226 let first_avail_slot =227 self.highlight_regions.iter_mut().find(|s| s.is_none()).unwrap_or_else(|| {228 bug!("can only highlight {} placeholders at a time", num_slots,)229 });230 *first_avail_slot = Some((region, number));231 self.keep_regions = true;232 }233234 /// Convenience wrapper for `highlighting_region`.235 pub fn highlighting_region_vid(236 &mut self,237 tcx: TyCtxt<'tcx>,238 vid: ty::RegionVid,239 number: usize,240 ) {241 self.highlighting_region(ty::Region::new_var(tcx, vid), number)242 }243244 /// Returns `Some(n)` with the number to use for the given region, if any.245 fn region_highlighted(&self, region: ty::Region<'tcx>) -> Option<usize> {246 self.highlight_regions.iter().find_map(|h| match h {247 Some((r, n)) if *r == region => Some(*n),248 _ => None,249 })250 }251252 /// Highlight the given bound region.253 /// We can only highlight one bound region at a time. See254 /// the field `highlight_bound_region` for more detailed notes.255 pub fn highlighting_bound_region(&mut self, br: ty::BoundRegionKind<'tcx>, number: usize) {256 assert!(self.highlight_bound_region.is_none());257 self.highlight_bound_region = Some((br, number));258 }259}260261/// Trait for printers that pretty-print using `fmt::Write` to the printer.262pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write {263 /// Like `print_def_path` but for value paths.264 fn pretty_print_value_path(265 &mut self,266 def_id: DefId,267 args: &'tcx [GenericArg<'tcx>],268 ) -> Result<(), PrintError> {269 self.print_def_path(def_id, args)270 }271272 fn pretty_print_in_binder<T>(&mut self, value: &ty::Binder<'tcx, T>) -> Result<(), PrintError>273 where274 T: Print<Self> + TypeFoldable<TyCtxt<'tcx>>,275 {276 value.as_ref().skip_binder().print(self)277 }278279 fn wrap_binder<T, F: FnOnce(&T, &mut Self) -> Result<(), fmt::Error>>(280 &mut self,281 value: &ty::Binder<'tcx, T>,282 _mode: WrapBinderMode,283 f: F,284 ) -> Result<(), PrintError>285 where286 T: TypeFoldable<TyCtxt<'tcx>>,287 {288 f(value.as_ref().skip_binder(), self)289 }290291 /// Prints comma-separated elements. If `comma_sep_has_space` is `true`, there is a space after292 /// each comma.293 fn comma_sep<T>(&mut self, mut elems: impl Iterator<Item = T>) -> Result<(), PrintError>294 where295 T: Print<Self>,296 {297 if let Some(first) = elems.next() {298 first.print(self)?;299 for elem in elems {300 if self.comma_sep_has_space() {301 self.write_str(", ")?;302 } else {303 self.write_str(",")?;304 }305 elem.print(self)?;306 }307 }308 Ok(())309 }310311 fn comma_sep_has_space(&self) -> bool {312 true313 }314315 /// Prints `{f: t}` or `{f as t}` depending on the `cast` argument316 fn typed_value(317 &mut self,318 f: impl FnOnce(&mut Self) -> Result<(), PrintError>,319 t: impl FnOnce(&mut Self) -> Result<(), PrintError>,320 conversion: &str,321 ) -> Result<(), PrintError> {322 self.write_str("{")?;323 f(self)?;324 self.write_str(conversion)?;325 t(self)?;326 self.write_str("}")?;327 Ok(())328 }329330 /// Prints `(...)` around what `f` prints.331 fn parenthesized(332 &mut self,333 f: impl FnOnce(&mut Self) -> Result<(), PrintError>,334 ) -> Result<(), PrintError> {335 self.write_str("(")?;336 f(self)?;337 self.write_str(")")?;338 Ok(())339 }340341 /// Prints `(...)` around what `f` prints if `parenthesized` is true, otherwise just prints `f`.342 fn maybe_parenthesized(343 &mut self,344 f: impl FnOnce(&mut Self) -> Result<(), PrintError>,345 parenthesized: bool,346 ) -> Result<(), PrintError> {347 if parenthesized {348 self.parenthesized(f)?;349 } else {350 f(self)?;351 }352 Ok(())353 }354355 /// Prints `<...>` around what `f` prints.356 fn generic_delimiters(357 &mut self,358 f: impl FnOnce(&mut Self) -> Result<(), PrintError>,359 ) -> Result<(), PrintError>;360361 fn should_truncate(&mut self) -> bool {362 false363 }364365 /// Returns `true` if the region should be printed in optional positions,366 /// e.g., `&'a T` or `dyn Tr + 'b`. (Regions like the one in `Cow<'static, T>`367 /// will always be printed.)368 fn should_print_optional_region(&self, region: ty::Region<'tcx>) -> bool;369370 fn reset_type_limit(&mut self) {}371372 // Defaults (should not be overridden):373374 /// If possible, this returns a global path resolving to `def_id` that is visible375 /// from at least one local module, and returns `true`. If the crate defining `def_id` is376 /// declared with an `extern crate`, the path is guaranteed to use the `extern crate`.377 fn try_print_visible_def_path(&mut self, def_id: DefId) -> Result<bool, PrintError> {378 if with_no_visible_paths() {379 return Ok(false);380 }381382 let mut callers = Vec::new();383 self.try_print_visible_def_path_recur(def_id, &mut callers)384 }385386 // Given a `DefId`, produce a short name. For types and traits, it prints *only* its name,387 // For associated items on traits it prints out the trait's name and the associated item's name.388 // For enum variants, if they have an unique name, then we only print the name, otherwise we389 // print the enum name and the variant name. Otherwise, we do not print anything and let the390 // caller use the `print_def_path` fallback.391 fn force_print_trimmed_def_path(&mut self, def_id: DefId) -> Result<bool, PrintError> {392 let key = self.tcx().def_key(def_id);393 let visible_parent_map = self.tcx().visible_parent_map(());394 let kind = self.tcx().def_kind(def_id);395396 let get_local_name = |this: &Self, name, def_id, key: DefKey| {397 if let Some(visible_parent) = visible_parent_map.get(&def_id)398 && let actual_parent = this.tcx().opt_parent(def_id)399 && let DefPathData::TypeNs(_) = key.disambiguated_data.data400 && Some(*visible_parent) != actual_parent401 {402 this.tcx()403 .module_children(ModId::new_unchecked(*visible_parent))404 .iter()405 .filter(|child| child.res.opt_def_id() == Some(def_id))406 .find(|child| child.vis.is_public() && child.ident.name != kw::Underscore)407 .map(|child| child.ident.name)408 .unwrap_or(name)409 } else {410 name411 }412 };413 if let DefKind::Variant = kind414 && let Some(symbol) = self.tcx().trimmed_def_paths(()).get(&def_id)415 {416 // If `Assoc` is unique, we don't want to talk about `Trait::Assoc`.417 self.write_str(get_local_name(self, *symbol, def_id, key).as_str())?;418 return Ok(true);419 }420 if let Some(symbol) = key.get_opt_name() {421 if let DefKind::AssocConst | DefKind::AssocFn | DefKind::AssocTy = kind422 && let Some(parent) = self.tcx().opt_parent(def_id)423 && let parent_key = self.tcx().def_key(parent)424 && let Some(symbol) = parent_key.get_opt_name()425 {426 // Trait427 self.write_str(get_local_name(self, symbol, parent, parent_key).as_str())?;428 self.write_str("::")?;429 } else if let DefKind::Variant = kind430 && let Some(parent) = self.tcx().opt_parent(def_id)431 && let parent_key = self.tcx().def_key(parent)432 && let Some(symbol) = parent_key.get_opt_name()433 {434 // Enum435436 // For associated items and variants, we want the "full" path, namely, include437 // the parent type in the path. For example, `Iterator::Item`.438 self.write_str(get_local_name(self, symbol, parent, parent_key).as_str())?;439 self.write_str("::")?;440 } else if let DefKind::Struct441 | DefKind::Union442 | DefKind::Enum443 | DefKind::Trait444 | DefKind::TyAlias445 | DefKind::Fn446 | DefKind::Const447 | DefKind::Static { .. } = kind448 {449 } else {450 // If not covered above, like for example items out of `impl` blocks, fallback.451 return Ok(false);452 }453 self.write_str(get_local_name(self, symbol, def_id, key).as_str())?;454 return Ok(true);455 }456 Ok(false)457 }458459 /// Try to see if this path can be trimmed to a unique symbol name.460 fn try_print_trimmed_def_path(&mut self, def_id: DefId) -> Result<bool, PrintError> {461 if with_forced_trimmed_paths() && self.force_print_trimmed_def_path(def_id)? {462 return Ok(true);463 }464 if self.tcx().sess.opts.unstable_opts.trim_diagnostic_paths465 && self.tcx().sess.opts.trimmed_def_paths466 && !with_no_trimmed_paths()467 && !with_crate_prefix()468 && let Some(symbol) = self.tcx().trimmed_def_paths(()).get(&def_id)469 {470 write!(self, "{}", Ident::with_dummy_span(*symbol))?;471 Ok(true)472 } else {473 Ok(false)474 }475 }476477 /// Does the work of `try_print_visible_def_path`, building the478 /// full definition path recursively before attempting to479 /// post-process it into the valid and visible version that480 /// accounts for re-exports.481 ///482 /// This method should only be called by itself or483 /// `try_print_visible_def_path`.484 ///485 /// `callers` is a chain of visible_parent's leading to `def_id`,486 /// to support cycle detection during recursion.487 ///488 /// This method returns false if we can't print the visible path, so489 /// `print_def_path` can fall back on the item's real definition path.490 fn try_print_visible_def_path_recur(491 &mut self,492 def_id: DefId,493 callers: &mut Vec<DefId>,494 ) -> Result<bool, PrintError> {495 debug!("try_print_visible_def_path: def_id={:?}", def_id);496497 // If `def_id` is a direct or injected extern crate, return the498 // path to the crate followed by the path to the item within the crate.499 if let Some(cnum) = def_id.as_crate_root() {500 if cnum == LOCAL_CRATE {501 self.print_crate_name(cnum)?;502 return Ok(true);503 }504505 // In local mode, when we encounter a crate other than506 // LOCAL_CRATE, execution proceeds in one of two ways:507 //508 // 1. For a direct dependency, where user added an509 // `extern crate` manually, we put the `extern510 // crate` as the parent. So you wind up with511 // something relative to the current crate.512 // 2. For an extern inferred from a path or an indirect crate,513 // where there is no explicit `extern crate`, we just prepend514 // the crate name.515 match self.tcx().extern_crate(cnum) {516 Some(&ExternCrate { src, dependency_of, span, .. }) => match (src, dependency_of) {517 (ExternCrateSource::Extern(def_id), LOCAL_CRATE) => {518 // NOTE(eddyb) the only reason `span` might be dummy,519 // that we're aware of, is that it's the `std`/`core`520 // `extern crate` injected by default.521 // FIXME(eddyb) find something better to key this on,522 // or avoid ending up with `ExternCrateSource::Extern`,523 // for the injected `std`/`core`.524 if span.is_dummy() {525 self.print_crate_name(cnum)?;526 return Ok(true);527 }528529 // Disable `try_print_trimmed_def_path` behavior within530 // the `print_def_path` call, to avoid infinite recursion531 // in cases where the `extern crate foo` has non-trivial532 // parents, e.g. it's nested in `impl foo::Trait for Bar`533 // (see also issues #55779 and #87932).534 with_no_visible_paths!(self.print_def_path(def_id, &[])?);535536 return Ok(true);537 }538 (ExternCrateSource::Path, LOCAL_CRATE) => {539 self.print_crate_name(cnum)?;540 return Ok(true);541 }542 _ => {}543 },544 None => {545 self.print_crate_name(cnum)?;546 return Ok(true);547 }548 }549 }550551 if def_id.is_local() {552 return Ok(false);553 }554555 let visible_parent_map = self.tcx().visible_parent_map(());556557 let mut cur_def_key = self.tcx().def_key(def_id);558 debug!("try_print_visible_def_path: cur_def_key={:?}", cur_def_key);559560 // For a constructor, we want the name of its parent rather than <unnamed>.561 if let DefPathData::Ctor = cur_def_key.disambiguated_data.data {562 let parent = DefId {563 krate: def_id.krate,564 index: cur_def_key565 .parent566 .expect("`DefPathData::Ctor` / `VariantData` missing a parent"),567 };568569 cur_def_key = self.tcx().def_key(parent);570 }571572 let Some(visible_parent) = visible_parent_map.get(&def_id).cloned() else {573 return Ok(false);574 };575576 if self.tcx().is_doc_hidden(visible_parent) && with_no_visible_paths_if_doc_hidden() {577 return Ok(false);578 }579580 let actual_parent = self.tcx().opt_parent(def_id);581 debug!(582 "try_print_visible_def_path: visible_parent={:?} actual_parent={:?}",583 visible_parent, actual_parent,584 );585586 let mut data = cur_def_key.disambiguated_data.data;587 debug!(588 "try_print_visible_def_path: data={:?} visible_parent={:?} actual_parent={:?}",589 data, visible_parent, actual_parent,590 );591592 match data {593 // In order to output a path that could actually be imported (valid and visible),594 // we need to handle re-exports correctly.595 //596 // For example, take `std::os::unix::process::CommandExt`, this trait is actually597 // defined at `std::sys::unix::ext::process::CommandExt` (at time of writing).598 //599 // `std::os::unix` reexports the contents of `std::sys::unix::ext`. `std::sys` is600 // private so the "true" path to `CommandExt` isn't accessible.601 //602 // In this case, the `visible_parent_map` will look something like this:603 //604 // (child) -> (parent)605 // `std::sys::unix::ext::process::CommandExt` -> `std::sys::unix::ext::process`606 // `std::sys::unix::ext::process` -> `std::sys::unix::ext`607 // `std::sys::unix::ext` -> `std::os`608 //609 // This is correct, as the visible parent of `std::sys::unix::ext` is in fact610 // `std::os`.611 //612 // When printing the path to `CommandExt` and looking at the `cur_def_key` that613 // corresponds to `std::sys::unix::ext`, we would normally print `ext` and then go614 // to the parent - resulting in a mangled path like615 // `std::os::ext::process::CommandExt`.616 //617 // Instead, we must detect that there was a re-export and instead print `unix`618 // (which is the name `std::sys::unix::ext` was re-exported as in `std::os`). To619 // do this, we compare the parent of `std::sys::unix::ext` (`std::sys::unix`) with620 // the visible parent (`std::os`). If these do not match, then we iterate over621 // the children of the visible parent (as was done when computing622 // `visible_parent_map`), looking for the specific child we currently have and then623 // have access to the re-exported name.624 DefPathData::TypeNs(ref mut name) if Some(visible_parent) != actual_parent => {625 // Item might be re-exported several times, but filter for the one626 // that's public and whose identifier isn't `_`.627 let reexport = self628 .tcx()629 .module_children(ModId::new_unchecked(visible_parent))630 .iter()631 .filter(|child| child.res.opt_def_id() == Some(def_id))632 .find(|child| child.vis.is_public() && child.ident.name != kw::Underscore)633 .map(|child| child.ident.name);634635 if let Some(new_name) = reexport {636 *name = new_name;637 } else {638 // There is no name that is public and isn't `_`, so bail.639 return Ok(false);640 }641 }642 // Re-exported `extern crate` (#43189).643 DefPathData::CrateRoot => {644 data = DefPathData::TypeNs(self.tcx().crate_name(def_id.krate));645 }646 _ => {}647 }648 debug!("try_print_visible_def_path: data={:?}", data);649650 if callers.contains(&visible_parent) {651 return Ok(false);652 }653 callers.push(visible_parent);654 // HACK(eddyb) this bypasses `print_path_with_simple`'s prefix printing to avoid655 // knowing ahead of time whether the entire path will succeed or not.656 // To support printers that do not implement `PrettyPrinter`, a `Vec` or657 // linked list on the stack would need to be built, before any printing.658 match self.try_print_visible_def_path_recur(visible_parent, callers)? {659 false => return Ok(false),660 true => {}661 }662 callers.pop();663 self.print_path_with_simple(664 |_| Ok(()),665 &DisambiguatedDefPathData { data, disambiguator: 0 },666 )?;667 Ok(true)668 }669670 fn pretty_print_path_with_qualified(671 &mut self,672 self_ty: Ty<'tcx>,673 trait_ref: Option<ty::TraitRef<'tcx>>,674 ) -> Result<(), PrintError> {675 if trait_ref.is_none() {676 // Inherent impls. Try to print `Foo::bar` for an inherent677 // impl on `Foo`, but fallback to `<Foo>::bar` if self-type is678 // anything other than a simple path.679 match self_ty.kind() {680 ty::Adt(..)681 | ty::Foreign(_)682 | ty::Bool683 | ty::Char684 | ty::Str685 | ty::Int(_)686 | ty::Uint(_)687 | ty::Float(_) => {688 return self_ty.print(self);689 }690691 _ => {}692 }693 }694695 self.generic_delimiters(|p| {696 self_ty.print(p)?;697 if let Some(trait_ref) = trait_ref {698 write!(p, " as ")?;699 trait_ref.print_only_trait_path().print(p)?;700 }701 Ok(())702 })703 }704705 fn pretty_print_path_with_impl(706 &mut self,707 print_prefix: impl FnOnce(&mut Self) -> Result<(), PrintError>,708 self_ty: Ty<'tcx>,709 trait_ref: Option<ty::TraitRef<'tcx>>,710 ) -> Result<(), PrintError> {711 print_prefix(self)?;712713 self.generic_delimiters(|p| {714 write!(p, "impl ")?;715 if let Some(trait_ref) = trait_ref {716 trait_ref.print_only_trait_path().print(p)?;717 write!(p, " for ")?;718 }719 self_ty.print(p)?;720721 Ok(())722 })723 }724725 fn pretty_print_closure_inner(726 &mut self,727 did: DefId,728 args: ty::GenericArgsRef<'tcx>,729 ) -> Result<(), PrintError> {730 if self.should_truncate() {731 write!(self, "@...")732 } else if self.tcx().sess.opts.unstable_opts.span_free_formats {733 write!(self, "@")?;734 self.print_def_path(did, args)735 } else if let Some(did) = did.as_local() {736 let span = self.tcx().def_span(did);737 let loc = if with_forced_trimmed_paths() {738 self.tcx()739 .sess740 .source_map()741 .span_to_short_string(span, RemapPathScopeComponents::DIAGNOSTICS)742 } else {743 self.tcx().sess.source_map().span_to_diagnostic_string(span)744 };745 write!(746 self,747 "@{}",748 // This may end up in stderr diagnostics but it may also be749 // emitted into MIR. Hence we use the remapped path if750 // available751 loc752 )753 } else {754 write!(self, "@")?;755 self.print_def_path(did, args)756 }757 }758759 fn pretty_print_type(&mut self, ty: Ty<'tcx>) -> Result<(), PrintError> {760 match *ty.kind() {761 ty::Bool => write!(self, "bool")?,762 ty::Char => write!(self, "char")?,763 ty::Int(t) => write!(self, "{}", t.name_str())?,764 ty::Uint(t) => write!(self, "{}", t.name_str())?,765 ty::Float(t) => write!(self, "{}", t.name_str())?,766 ty::Pat(ty, pat) => {767 write!(self, "pattern_type!(")?;768 ty.print(self)?;769 write!(self, " is {pat:?})")?;770 }771 ty::RawPtr(ty, mutbl) => {772 write!(self, "*{} ", mutbl.ptr_str())?;773 ty.print(self)?;774 }775 ty::Ref(r, ty, mutbl) => {776 write!(self, "&")?;777 if self.should_print_optional_region(r) {778 r.print(self)?;779 write!(self, " ")?;780 }781 ty::TypeAndMut { ty, mutbl }.print(self)?;782 }783 ty::Never => write!(self, "!")?,784 ty::Tuple(tys) => {785 write!(self, "(")?;786 self.comma_sep(tys.iter())?;787 if tys.len() == 1 {788 write!(self, ",")?;789 }790 write!(self, ")")?;791 }792 ty::FnDef(def_id, args) => {793 let args = args.no_bound_vars().unwrap();794 if with_reduced_queries() {795 self.print_def_path(def_id, args)?;796 } else {797 let mut sig =798 self.tcx().fn_sig(def_id).instantiate(self.tcx(), args).skip_norm_wip();799 if self.tcx().codegen_fn_attrs(def_id).safe_target_features {800 write!(self, "#[target_feature(..)] ")?;801 sig = sig.map_bound(|mut sig| {802 sig.fn_sig_kind = sig.fn_sig_kind.set_safety(hir::Safety::Safe);803 sig804 });805 }806 sig.print(self)?;807 write!(self, " {{")?;808 self.pretty_print_value_path(def_id, args)?;809 write!(self, "}}")?;810 }811 }812 ty::FnPtr(ref sig_tys, hdr) => sig_tys.with(hdr).print(self)?,813 ty::UnsafeBinder(ref bound_ty) => {814 self.wrap_binder(bound_ty, WrapBinderMode::Unsafe, |ty, p| {815 p.pretty_print_type(*ty)816 })?;817 }818 ty::Infer(infer_ty) => {819 if self.should_print_verbose() {820 write!(self, "{:?}", ty.kind())?;821 return Ok(());822 }823824 if let ty::TyVar(ty_vid) = infer_ty {825 if let Some(name) = self.ty_infer_name(ty_vid) {826 write!(self, "{name}")?;827 } else {828 write!(self, "{infer_ty}")?;829 }830 } else {831 write!(self, "{infer_ty}")?;832 }833 }834 ty::Error(_) => write!(self, "{{type error}}")?,835 ty::Param(ref param_ty) => param_ty.print(self)?,836 ty::Bound(debruijn, bound_ty) => match bound_ty.kind {837 ty::BoundTyKind::Anon => {838 rustc_type_ir::debug_bound_var(self, debruijn, bound_ty.var)?839 }840 ty::BoundTyKind::Param(def_id) => match self.should_print_verbose() {841 true => write!(self, "{:?}", ty.kind())?,842 false => write!(self, "{}", self.tcx().item_name(def_id))?,843 },844 },845 ty::Adt(def, args)846 if let Some(FieldInfo { base, variant, name, .. }) =847 def.field_representing_type_info(self.tcx(), args) =>848 {849 if let Some(variant) = variant {850 write!(self, "field_of!({base}, {variant}.{name})")?;851 } else {852 write!(self, "field_of!({base}, {name})")?;853 }854 }855 ty::Adt(def, args) => self.print_def_path(def.did(), args)?,856 ty::Dynamic(data, r) => {857 let print_r = self.should_print_optional_region(r);858 if print_r {859 write!(self, "(")?;860 }861 write!(self, "dyn ")?;862 data.print(self)?;863 if print_r {864 write!(self, " + ")?;865 r.print(self)?;866 write!(self, ")")?;867 }868 }869 ty::Foreign(def_id) => self.print_def_path(def_id, &[])?,870 ty::Alias(871 _,872 ref data @ ty::AliasTy {873 kind: ty::Projection { .. } | ty::Inherent { .. } | ty::Free { .. },874 ..875 },876 ) => data.print(self)?,877 ty::Placeholder(placeholder) => placeholder.print(self)?,878 ty::Alias(_, ty::AliasTy { kind: ty::Opaque { def_id }, args, .. }) => {879 // We use verbose printing in 'NO_QUERIES' mode, to880 // avoid needing to call `clauses_of`. This should881 // only affect certain debug messages (e.g. messages printed882 // from `rustc_middle::ty` during the computation of `tcx.clauses_of`),883 // and should have no effect on any compiler output.884 // [Unless `-Zverbose-internals` is used, e.g. in the output of885 // `tests/ui/nll/ty-outlives/impl-trait-captures.rs`, for886 // example.]887 if self.should_print_verbose() {888 // FIXME(eddyb) print this with `print_def_path`.889 write!(self, "Opaque({:?}, {})", def_id, args.print_as_list())?;890 return Ok(());891 }892893 let parent = self.tcx().parent(def_id);894 match self.tcx().def_kind(parent) {895 DefKind::TyAlias | DefKind::AssocTy => {896 // NOTE: I know we should check for NO_QUERIES here, but it's alright.897 // `type_of` on a type alias or assoc type should never cause a cycle.898 if let ty::Alias(_, ty::AliasTy { kind: ty::Opaque { def_id: d }, .. }) =899 *self900 .tcx()901 .type_of(parent)902 .instantiate_identity()903 .skip_norm_wip()904 .kind()905 {906 if d == def_id {907 // If the type alias directly starts with the `impl` of the908 // opaque type we're printing, then skip the `::{opaque#1}`.909 self.print_def_path(parent, args)?;910 return Ok(());911 }912 }913 // Complex opaque type, e.g. `type Foo = (i32, impl Debug);`914 self.print_def_path(def_id, args)?;915 return Ok(());916 }917 _ => {918 if with_reduced_queries() {919 self.print_def_path(def_id, &[])?;920 return Ok(());921 } else {922 return self.pretty_print_opaque_impl_type(def_id, args);923 }924 }925 }926 }927 ty::Str => write!(self, "str")?,928 ty::Coroutine(did, args) => {929 write!(self, "{{")?;930 let coroutine_kind = self.tcx().coroutine_kind(did).unwrap();931 let should_print_movability = self.should_print_verbose()932 || matches!(coroutine_kind, hir::CoroutineKind::Coroutine(_));933934 if should_print_movability {935 match coroutine_kind.movability() {936 hir::Movability::Movable => {}937 hir::Movability::Static => write!(self, "static ")?,938 }939 }940941 if !self.should_print_verbose() {942 write!(self, "{coroutine_kind}")?;943 if coroutine_kind.is_fn_like() {944 // If we are printing an `async fn` coroutine type, then give the path945 // of the fn, instead of its span, because that will in most cases be946 // more helpful for the reader than just a source location.947 //948 // This will look like:949 // {async fn body of some_fn()}950 write!(self, " of ")?;951 let did_of_the_fn_item = self.tcx().parent(did);952 self.print_def_path(did_of_the_fn_item, args)?;953 write!(self, "()")?;954 } else {955 self.pretty_print_closure_inner(did, args)?;956 }957 } else {958 self.print_def_path(did, args)?;959 write!(self, " upvar_tys=")?;960 args.as_coroutine().tupled_upvars_ty().print(self)?;961 write!(self, " resume_ty=")?;962 args.as_coroutine().resume_ty().print(self)?;963 write!(self, " yield_ty=")?;964 args.as_coroutine().yield_ty().print(self)?;965 write!(self, " return_ty=")?;966 args.as_coroutine().return_ty().print(self)?;967 }968969 write!(self, "}}")?970 }971 ty::CoroutineWitness(did, args) => {972 write!(self, "{{")?;973 if !self.should_print_verbose() {974 write!(self, "coroutine witness")?;975 self.pretty_print_closure_inner(did, args)?;976 } else {977 self.print_def_path(did, args)?;978 }979 write!(self, "}}")?980 }981 ty::Closure(did, args) => {982 write!(self, "{{")?;983 if !self.should_print_verbose() {984 write!(self, "closure")?;985 self.pretty_print_closure_inner(did, args)?;986 } else {987 self.print_def_path(did, args)?;988 write!(self, " closure_kind_ty=")?;989 args.as_closure().kind_ty().print(self)?;990 write!(self, " closure_sig_as_fn_ptr_ty=")?;991 args.as_closure().sig_as_fn_ptr_ty().print(self)?;992 write!(self, " upvar_tys=")?;993 args.as_closure().tupled_upvars_ty().print(self)?;994 }995 write!(self, "}}")?;996 }997 ty::CoroutineClosure(did, args) => {998 write!(self, "{{")?;999 if !self.should_print_verbose() {1000 match self.tcx().coroutine_kind(self.tcx().coroutine_for_closure(did)).unwrap()1001 {1002 hir::CoroutineKind::Desugared(1003 desugaring,1004 hir::CoroutineSource::Closure,1005 ) => write!(self, "{desugaring}closure")?,1006 _ => unreachable!(1007 "coroutine from coroutine-closure should have CoroutineSource::Closure"1008 ),1009 };1010 self.pretty_print_closure_inner(did, args)?;1011 } else {1012 self.print_def_path(did, args)?;1013 write!(self, " closure_kind_ty=")?;1014 args.as_coroutine_closure().kind_ty().print(self)?;1015 write!(self, " signature_parts_ty=")?;1016 args.as_coroutine_closure().signature_parts_ty().print(self)?;1017 write!(self, " upvar_tys=")?;1018 args.as_coroutine_closure().tupled_upvars_ty().print(self)?;1019 write!(self, " coroutine_captures_by_ref_ty=")?;1020 args.as_coroutine_closure().coroutine_captures_by_ref_ty().print(self)?;1021 }1022 write!(self, "}}")?;1023 }1024 ty::Array(ty, sz) => {1025 write!(self, "[")?;1026 ty.print(self)?;1027 write!(self, "; ")?;1028 sz.print(self)?;1029 write!(self, "]")?;1030 }1031 ty::Slice(ty) => {1032 write!(self, "[")?;1033 ty.print(self)?;1034 write!(self, "]")?;1035 }1036 }10371038 Ok(())1039 }10401041 fn pretty_print_opaque_impl_type(1042 &mut self,1043 def_id: DefId,1044 args: ty::GenericArgsRef<'tcx>,1045 ) -> Result<(), PrintError> {1046 let tcx = self.tcx();10471048 // Grab the "TraitA + TraitB" from `impl TraitA + TraitB`,1049 // by looking up the projections associated with the def_id.1050 let bounds = tcx.explicit_item_bounds(def_id);10511052 let mut traits = FxIndexMap::default();1053 let mut fn_traits = FxIndexMap::default();1054 let mut lifetimes = SmallVec::<[ty::Region<'tcx>; 1]>::new();10551056 let mut has_sized_bound = false;1057 let mut has_negative_sized_bound = false;1058 let mut has_meta_sized_bound = false;10591060 for (predicate, _) in1061 bounds.iter_instantiated_copied(tcx, args).map(Unnormalized::skip_norm_wip)1062 {1063 let bound_predicate = predicate.kind();10641065 match bound_predicate.skip_binder() {1066 ty::ClauseKind::Trait(pred) => {1067 // With `feature(sized_hierarchy)`, don't print `?Sized` as an alias for1068 // `MetaSized`, and skip sizedness bounds to be added at the end.1069 match tcx.as_lang_item(pred.def_id()) {1070 Some(LangItem::Sized) => match pred.polarity {1071 ty::ClausePolarity::Positive => {1072 has_sized_bound = true;1073 continue;1074 }1075 ty::ClausePolarity::Negative => has_negative_sized_bound = true,1076 },1077 Some(LangItem::MetaSized) => {1078 has_meta_sized_bound = true;1079 continue;1080 }1081 Some(LangItem::PointeeSized) => {1082 bug!("`PointeeSized` is removed during lowering");1083 }1084 _ => (),1085 }10861087 self.insert_trait_and_projection(1088 bound_predicate.rebind(pred),1089 None,1090 &mut traits,1091 &mut fn_traits,1092 );1093 }1094 ty::ClauseKind::Projection(pred) => {1095 let proj = bound_predicate.rebind(pred);1096 let trait_ref = proj.map_bound(|proj| TraitClause {1097 trait_ref: proj.projection_term.trait_ref(tcx),1098 polarity: ty::ClausePolarity::Positive,1099 });11001101 self.insert_trait_and_projection(1102 trait_ref,1103 Some((proj.item_def_id(), proj.term())),1104 &mut traits,1105 &mut fn_traits,1106 );1107 }1108 ty::ClauseKind::TypeOutlives(outlives) => {1109 lifetimes.push(outlives.1);1110 }1111 _ => {}1112 }1113 }11141115 write!(self, "impl ")?;11161117 let mut first = true;1118 // Insert parenthesis around (Fn(A, B) -> C) if the opaque ty has more than one other trait1119 let paren_needed = fn_traits.len() > 1 || traits.len() > 0 || !has_sized_bound;11201121 for ((bound_args_and_self_ty, is_async), entry) in fn_traits {1122 write!(self, "{}", if first { "" } else { " + " })?;1123 write!(self, "{}", if paren_needed { "(" } else { "" })?;11241125 let trait_def_id = if is_async {1126 tcx.async_fn_trait_kind_to_def_id(entry.kind).expect("expected AsyncFn lang items")1127 } else {1128 tcx.fn_trait_kind_to_def_id(entry.kind).expect("expected Fn lang items")1129 };11301131 if let Some(return_ty) = entry.return_ty {1132 self.wrap_binder(1133 &bound_args_and_self_ty,1134 WrapBinderMode::ForAll,1135 |(args, _), p| {1136 write!(p, "{}", tcx.item_name(trait_def_id))?;1137 write!(p, "(")?;11381139 for (idx, ty) in args.iter().enumerate() {1140 if idx > 0 {1141 write!(p, ", ")?;1142 }1143 ty.print(p)?;1144 }11451146 write!(p, ")")?;1147 if let Some(ty) = return_ty.skip_binder().as_type() {1148 if !ty.is_unit() {1149 write!(p, " -> ")?;1150 return_ty.print(p)?;1151 }1152 }1153 write!(p, "{}", if paren_needed { ")" } else { "" })?;11541155 first = false;1156 Ok(())1157 },1158 )?;1159 } else {1160 // Otherwise, render this like a regular trait.1161 traits.insert(1162 bound_args_and_self_ty.map_bound(|(args, self_ty)| ty::TraitClause {1163 polarity: ty::ClausePolarity::Positive,1164 trait_ref: ty::TraitRef::new(1165 tcx,1166 trait_def_id,1167 [self_ty, Ty::new_tup(tcx, args)],1168 ),1169 }),1170 FxIndexMap::default(),1171 );1172 }1173 }11741175 // Print the rest of the trait types (that aren't Fn* family of traits)1176 for (trait_pred, assoc_items) in traits {1177 write!(self, "{}", if first { "" } else { " + " })?;11781179 self.wrap_binder(&trait_pred, WrapBinderMode::ForAll, |trait_pred, p| {1180 if trait_pred.polarity == ty::ClausePolarity::Negative {1181 write!(p, "!")?;1182 }1183 trait_pred.trait_ref.print_only_trait_name().print(p)?;11841185 let generics = tcx.generics_of(trait_pred.def_id());1186 let own_args = generics.own_args_no_defaults(tcx, trait_pred.trait_ref.args);11871188 if !own_args.is_empty() || !assoc_items.is_empty() {1189 let mut first = true;11901191 for ty in own_args {1192 if first {1193 write!(p, "<")?;1194 first = false;1195 } else {1196 write!(p, ", ")?;1197 }1198 ty.print(p)?;1199 }12001201 for (assoc_item_def_id, term) in assoc_items {1202 if first {1203 write!(p, "<")?;1204 first = false;1205 } else {1206 write!(p, ", ")?;1207 }12081209 write!(p, "{} = ", tcx.associated_item(assoc_item_def_id).name())?;12101211 match term.skip_binder().kind() {1212 TermKind::Ty(ty) => ty.print(p)?,1213 TermKind::Const(c) => c.print(p)?,1214 };1215 }12161217 if !first {1218 write!(p, ">")?;1219 }1220 }12211222 first = false;1223 Ok(())1224 })?;1225 }12261227 let using_sized_hierarchy = self.tcx().features().sized_hierarchy();1228 let add_sized = has_sized_bound && (first || has_negative_sized_bound);1229 let add_maybe_sized =1230 has_meta_sized_bound && !has_negative_sized_bound && !using_sized_hierarchy;1231 // Set `has_pointee_sized_bound` if there were no `Sized` or `MetaSized` bounds.1232 let has_pointee_sized_bound =1233 !has_sized_bound && !has_meta_sized_bound && !has_negative_sized_bound;1234 if add_sized || add_maybe_sized {1235 if !first {1236 write!(self, " + ")?;1237 }1238 if add_maybe_sized {1239 write!(self, "?")?;1240 }1241 write!(self, "Sized")?;1242 } else if has_meta_sized_bound && using_sized_hierarchy {1243 if !first {1244 write!(self, " + ")?;1245 }1246 write!(self, "MetaSized")?;1247 } else if has_pointee_sized_bound && using_sized_hierarchy {1248 if !first {1249 write!(self, " + ")?;1250 }1251 write!(self, "PointeeSized")?;1252 }12531254 if !with_forced_trimmed_paths() {1255 for re in lifetimes {1256 write!(self, " + ")?;1257 self.print_region(re)?;1258 }1259 }12601261 Ok(())1262 }12631264 /// Insert the trait ref and optionally a projection type associated with it into either the1265 /// traits map or fn_traits map, depending on if the trait is in the Fn* family of traits.1266 fn insert_trait_and_projection(1267 &mut self,1268 trait_pred: ty::PolyTraitClause<'tcx>,1269 proj_ty: Option<(DefId, ty::Binder<'tcx, Term<'tcx>>)>,1270 traits: &mut FxIndexMap<1271 ty::PolyTraitClause<'tcx>,1272 FxIndexMap<DefId, ty::Binder<'tcx, Term<'tcx>>>,1273 >,1274 fn_traits: &mut FxIndexMap<1275 (ty::Binder<'tcx, (&'tcx ty::List<Ty<'tcx>>, Ty<'tcx>)>, bool),1276 OpaqueFnEntry<'tcx>,1277 >,1278 ) {1279 let tcx = self.tcx();1280 let trait_def_id = trait_pred.def_id();12811282 let fn_trait_and_async = if let Some(kind) = tcx.fn_trait_kind_from_def_id(trait_def_id) {1283 Some((kind, false))1284 } else if let Some(kind) = tcx.async_fn_trait_kind_from_def_id(trait_def_id) {1285 Some((kind, true))1286 } else {1287 None1288 };12891290 if trait_pred.polarity() == ty::ClausePolarity::Positive1291 && let Some((kind, is_async)) = fn_trait_and_async1292 && let ty::Tuple(types) = *trait_pred.skip_binder().trait_ref.args.type_at(1).kind()1293 {1294 let entry = fn_traits1295 .entry((trait_pred.rebind((types, trait_pred.skip_binder().self_ty())), is_async))1296 .or_insert_with(|| OpaqueFnEntry { kind, return_ty: None });1297 if kind.extends(entry.kind) {1298 entry.kind = kind;1299 }1300 if let Some((proj_def_id, proj_ty)) = proj_ty1301 && tcx.item_name(proj_def_id) == sym::Output1302 {1303 entry.return_ty = Some(proj_ty);1304 }1305 return;1306 }13071308 // Otherwise, just group our traits and projection types.1309 traits.entry(trait_pred).or_default().extend(proj_ty);1310 }13111312 fn pretty_print_inherent_projection(1313 &mut self,1314 alias_term: ty::AliasTerm<'tcx>,1315 ) -> Result<(), PrintError> {1316 let alias_def_id = alias_term.expect_inherent_def_id();1317 let def_key = self.tcx().def_key(alias_def_id);1318 self.print_path_with_generic_args(1319 |p| {1320 p.print_path_with_simple(1321 |p| p.print_path_with_qualified(alias_term.self_ty(), None),1322 &def_key.disambiguated_data,1323 )1324 },1325 &alias_term.args[1..],1326 )1327 }13281329 fn pretty_print_rpitit(1330 &mut self,1331 def_id: DefId,1332 args: ty::GenericArgsRef<'tcx>,1333 ) -> Result<(), PrintError> {1334 let fn_args = if self.tcx().features().return_type_notation()1335 && let Some(ty::ImplTraitInTraitData::Trait { fn_def_id, .. }) =1336 self.tcx().opt_rpitit_info(def_id)1337 && let ty::Alias(_, alias_ty) =1338 self.tcx().fn_sig(fn_def_id).skip_binder().output().skip_binder().kind()1339 && let Some(projection_ty) = alias_ty.try_to_projection()1340 && projection_ty.kind == def_id1341 && let generics = self.tcx().generics_of(fn_def_id)1342 // FIXME(return_type_notation): We only support lifetime params for now.1343 && generics1344 .own_params1345 .iter()1346 .all(|param| matches!(param.kind, ty::GenericParamDefKind::Lifetime))1347 {1348 let num_args = generics.count();1349 Some((fn_def_id, &args[..num_args]))1350 } else {1351 None1352 };13531354 match (fn_args, RTN_MODE.with(|c| c.get())) {1355 (Some((fn_def_id, fn_args)), RtnMode::ForDiagnostic) => {1356 self.pretty_print_opaque_impl_type(def_id, args)?;1357 write!(self, " {{ ")?;1358 self.print_def_path(fn_def_id, fn_args)?;1359 write!(self, "(..) }}")?;1360 }1361 (Some((fn_def_id, fn_args)), RtnMode::ForSuggestion) => {1362 self.print_def_path(fn_def_id, fn_args)?;1363 write!(self, "(..)")?;1364 }1365 _ => {1366 self.pretty_print_opaque_impl_type(def_id, args)?;1367 }1368 }13691370 Ok(())1371 }13721373 fn ty_infer_name(&self, _: ty::TyVid) -> Option<Symbol> {1374 None1375 }13761377 fn const_infer_name(&self, _: ty::ConstVid) -> Option<Symbol> {1378 None1379 }13801381 fn pretty_print_dyn_existential(1382 &mut self,1383 predicates: &'tcx ty::List<ty::PolyExistentialPredicate<'tcx>>,1384 ) -> Result<(), PrintError> {1385 // Generate the main trait ref, including associated types.1386 let mut first = true;13871388 if let Some(bound_principal) = predicates.principal() {1389 self.wrap_binder(&bound_principal, WrapBinderMode::ForAll, |principal, p| {1390 p.print_def_path(principal.def_id, &[])?;13911392 let mut resugared = false;13931394 // Special-case `Fn(...) -> ...` and re-sugar it.1395 let fn_trait_kind = p.tcx().fn_trait_kind_from_def_id(principal.def_id);1396 if !p.should_print_verbose() && fn_trait_kind.is_some() {1397 if let ty::Tuple(tys) = principal.args.type_at(0).kind() {1398 let mut projections = predicates.projection_bounds();1399 if let (Some(proj), None) = (projections.next(), projections.next()) {1400 p.pretty_print_fn_sig(1401 tys,1402 false,1403 // FIXME(splat): support splatted arguments here?1404 None,1405 proj.skip_binder().term.as_type().expect("Return type was a const"),1406 )?;1407 resugared = true;1408 }1409 }1410 }14111412 // HACK(eddyb) this duplicates `FmtPrinter`'s `print_path_with_generic_args`,1413 // in order to place the projections inside the `<...>`.1414 if !resugared {1415 let principal_with_self =1416 principal.with_self_ty(p.tcx(), p.tcx().types.trait_object_dummy_self);14171418 let args = p1419 .tcx()1420 .generics_of(principal_with_self.def_id)1421 .own_args_no_defaults(p.tcx(), principal_with_self.args);14221423 let bound_principal_with_self = bound_principal1424 .with_self_ty(p.tcx(), p.tcx().types.trait_object_dummy_self);14251426 let clause: ty::Clause<'tcx> = bound_principal_with_self.upcast(p.tcx());1427 let super_projections: Vec<_> = elaborate::elaborate(p.tcx(), [clause])1428 .filter_only_self()1429 .filter_map(|clause| clause.as_projection_clause())1430 .collect();14311432 let mut projections: Vec<_> = predicates1433 .projection_bounds()1434 .filter(|&proj| {1435 // Filter out projections that are implied by the super predicates.1436 let proj_is_implied = super_projections.iter().any(|&super_proj| {1437 let super_proj = super_proj.map_bound(|super_proj| {1438 ty::ExistentialProjection::erase_self_ty(p.tcx(), super_proj)1439 });14401441 // This function is sometimes called on types with erased and1442 // anonymized regions, but the super projections can still1443 // contain named regions. So we erase and anonymize everything1444 // here to compare the types modulo regions below.1445 let proj = p.tcx().erase_and_anonymize_regions(proj);1446 let super_proj = p.tcx().erase_and_anonymize_regions(super_proj);14471448 proj == super_proj1449 });1450 !proj_is_implied1451 })1452 .map(|proj| {1453 // Skip the binder, because we don't want to print the binder in1454 // front of the associated item.1455 proj.skip_binder()1456 })1457 .collect();14581459 projections1460 .sort_by_cached_key(|proj| p.tcx().item_name(proj.def_id).to_string());14611462 if !args.is_empty() || !projections.is_empty() {1463 p.generic_delimiters(|p| {1464 p.comma_sep(args.iter().copied())?;1465 if !args.is_empty() && !projections.is_empty() {1466 write!(p, ", ")?;1467 }1468 p.comma_sep(projections.iter().copied())1469 })?;1470 }1471 }1472 Ok(())1473 })?;14741475 first = false;1476 }14771478 // Builtin bounds.1479 // FIXME(eddyb) avoid printing twice (needed to ensure1480 // that the auto traits are sorted *and* printed via p).1481 let mut auto_traits: Vec<_> = predicates.auto_traits().collect();14821483 // The auto traits come ordered by `DefPathHash`. While1484 // `DefPathHash` is *stable* in the sense that it depends on1485 // neither the host nor the phase of the moon, it depends1486 // "pseudorandomly" on the compiler version and the target.1487 //1488 // To avoid causing instabilities in compiletest1489 // output, sort the auto-traits alphabetically.1490 auto_traits.sort_by_cached_key(|did| with_no_trimmed_paths!(self.tcx().def_path_str(*did)));14911492 for def_id in auto_traits {1493 if !first {1494 write!(self, " + ")?;1495 }1496 first = false;14971498 self.print_def_path(def_id, &[])?;1499 }15001501 Ok(())1502 }15031504 fn pretty_print_fn_sig(1505 &mut self,1506 inputs: &[Ty<'tcx>],1507 c_variadic: bool,1508 splatted: Option<u8>,1509 output: Ty<'tcx>,1510 ) -> Result<(), PrintError> {1511 write!(self, "(")?;1512 let splatted_arg_index = splatted.map(usize::from);1513 let mut input_iter = inputs.iter().copied();1514 if let Some(index) = splatted_arg_index {1515 self.comma_sep((&mut input_iter).take(index))?;1516 // Splitting the comma-separated list can miss a comma, but we only need that comma if1517 // there are arguments before the splat.1518 // FIXME(splat): if splatting becomes part of the type, we can remove this hack1519 if index > 0 {1520 if self.comma_sep_has_space() {1521 write!(self, ", ")?;1522 } else {1523 write!(self, ",")?;1524 }1525 }1526 write!(self, "#[rustc_splat] ")?;1527 self.comma_sep(input_iter)?;1528 } else {1529 self.comma_sep(input_iter)?;1530 }1531 if c_variadic {1532 if !inputs.is_empty() {1533 // In legacy mangling, most comma-separated lists have no spaces. But here we print1534 // a space before the `...` for readability.1535 write!(self, ", ")?;1536 }1537 write!(self, "...")?;1538 }1539 write!(self, ")")?;1540 if !output.is_unit() {1541 write!(self, " -> ")?;1542 output.print(self)?;1543 }15441545 Ok(())1546 }15471548 fn pretty_print_const(1549 &mut self,1550 ct: ty::Const<'tcx>,1551 print_ty: bool,1552 ) -> Result<(), PrintError> {1553 if self.should_print_verbose() {1554 write!(self, "{ct:?}")?;1555 return Ok(());1556 }15571558 match ct.kind() {1559 ty::ConstKind::Alias(_, ty::AliasConst { kind, args, .. }) => {1560 match kind {1561 ty::AliasConstKind::Projection { def_id }1562 | ty::AliasConstKind::InherentSelf { def_id }1563 | ty::AliasConstKind::InherentImpl { def_id }1564 | ty::AliasConstKind::Free { def_id } => {1565 self.pretty_print_value_path(def_id, args)?;1566 }1567 ty::AliasConstKind::Anon { def_id } => {1568 if def_id.is_local()1569 && let span = self.tcx().def_span(def_id)1570 && let Ok(snip) = self.tcx().sess.source_map().span_to_snippet(span)1571 {1572 write!(self, "{snip}")?;1573 } else {1574 // Do not call `pretty_print_value_path` as if a parent of this anon1575 // const is an impl it will attempt to print out the impl trait ref1576 // i.e. `<T as Trait>::{constant#0}`. This would cause printing to1577 // enter an infinite recursion if the anon const is in the self type1578 // i.e. `impl<T: Default> Default for [T; 32 - 1 - 1 - 1] {` where we1579 // would try to print `<[T; /* print constant#0 again */] as //1580 // Default>::{constant#0}`.1581 write!(1582 self,1583 "{}::{}",1584 self.tcx().crate_name(def_id.krate),1585 self.tcx().def_path(def_id).to_string_no_crate_verbose()1586 )?;1587 }1588 }1589 }1590 }1591 ty::ConstKind::Infer(infer_ct) => match infer_ct {1592 ty::InferConst::Var(ct_vid) if let Some(name) = self.const_infer_name(ct_vid) => {1593 write!(self, "{name}")?;1594 }1595 _ => write!(self, "_")?,1596 },1597 ty::ConstKind::Param(ParamConst { name, .. }) => write!(self, "{name}")?,1598 ty::ConstKind::Value(cv) => {1599 return self.pretty_print_const_valtree(cv, print_ty);1600 }16011602 ty::ConstKind::Bound(debruijn, bound_var) => {1603 rustc_type_ir::debug_bound_var(self, debruijn, bound_var)?1604 }1605 ty::ConstKind::Placeholder(placeholder) => write!(self, "{placeholder:?}")?,1606 // FIXME(generic_const_exprs):1607 // write out some legible representation of an abstract const?1608 ty::ConstKind::Expr(expr) => self.pretty_print_const_expr(expr, print_ty)?,1609 ty::ConstKind::Error(_) => write!(self, "{{const error}}")?,1610 };1611 Ok(())1612 }16131614 fn pretty_print_const_expr(1615 &mut self,1616 expr: Expr<'tcx>,1617 print_ty: bool,1618 ) -> Result<(), PrintError> {1619 match expr.kind {1620 ty::ExprKind::Binop(op) => {1621 let (_, _, c1, c2) = expr.binop_args();16221623 let precedence = |binop: crate::mir::BinOp| binop.to_hir_binop().precedence();1624 let op_precedence = precedence(op);1625 let formatted_op = op.to_hir_binop().as_str();1626 let (lhs_parenthesized, rhs_parenthesized) = match (c1.kind(), c2.kind()) {1627 (1628 ty::ConstKind::Expr(ty::Expr { kind: ty::ExprKind::Binop(lhs_op), .. }),1629 ty::ConstKind::Expr(ty::Expr { kind: ty::ExprKind::Binop(rhs_op), .. }),1630 ) => (precedence(lhs_op) < op_precedence, precedence(rhs_op) < op_precedence),1631 (1632 ty::ConstKind::Expr(ty::Expr { kind: ty::ExprKind::Binop(lhs_op), .. }),1633 ty::ConstKind::Expr(_),1634 ) => (precedence(lhs_op) < op_precedence, true),1635 (1636 ty::ConstKind::Expr(_),1637 ty::ConstKind::Expr(ty::Expr { kind: ty::ExprKind::Binop(rhs_op), .. }),1638 ) => (true, precedence(rhs_op) < op_precedence),1639 (ty::ConstKind::Expr(_), ty::ConstKind::Expr(_)) => (true, true),1640 (1641 ty::ConstKind::Expr(ty::Expr { kind: ty::ExprKind::Binop(lhs_op), .. }),1642 _,1643 ) => (precedence(lhs_op) < op_precedence, false),1644 (1645 _,1646 ty::ConstKind::Expr(ty::Expr { kind: ty::ExprKind::Binop(rhs_op), .. }),1647 ) => (false, precedence(rhs_op) < op_precedence),1648 (ty::ConstKind::Expr(_), _) => (true, false),1649 (_, ty::ConstKind::Expr(_)) => (false, true),1650 _ => (false, false),1651 };16521653 self.maybe_parenthesized(1654 |this| this.pretty_print_const(c1, print_ty),1655 lhs_parenthesized,1656 )?;1657 write!(self, " {formatted_op} ")?;1658 self.maybe_parenthesized(1659 |this| this.pretty_print_const(c2, print_ty),1660 rhs_parenthesized,1661 )?;1662 }1663 ty::ExprKind::UnOp(op) => {1664 let (_, ct) = expr.unop_args();16651666 use crate::mir::UnOp;1667 let formatted_op = match op {1668 UnOp::Not => "!",1669 UnOp::Neg => "-",1670 UnOp::PtrMetadata => "PtrMetadata",1671 };1672 let parenthesized = match ct.kind() {1673 _ if op == UnOp::PtrMetadata => true,1674 ty::ConstKind::Expr(ty::Expr { kind: ty::ExprKind::UnOp(c_op), .. }) => {1675 c_op != op1676 }1677 ty::ConstKind::Expr(_) => true,1678 _ => false,1679 };1680 write!(self, "{formatted_op}")?;1681 self.maybe_parenthesized(1682 |this| this.pretty_print_const(ct, print_ty),1683 parenthesized,1684 )?1685 }1686 ty::ExprKind::FunctionCall => {1687 let (_, fn_def, fn_args) = expr.call_args();16881689 write!(self, "(")?;1690 self.pretty_print_const(fn_def, print_ty)?;1691 write!(self, ")(")?;1692 self.comma_sep(fn_args)?;1693 write!(self, ")")?;1694 }1695 ty::ExprKind::Cast(kind) => {1696 let (_, value, to_ty) = expr.cast_args();16971698 use ty::abstract_const::CastKind;1699 if kind == CastKind::As || (kind == CastKind::Use && self.should_print_verbose()) {1700 let parenthesized = match value.kind() {1701 ty::ConstKind::Expr(ty::Expr {1702 kind: ty::ExprKind::Cast { .. }, ..1703 }) => false,1704 ty::ConstKind::Expr(_) => true,1705 _ => false,1706 };1707 self.maybe_parenthesized(1708 |this| {1709 this.typed_value(1710 |this| this.pretty_print_const(value, print_ty),1711 |this| this.pretty_print_type(to_ty),1712 " as ",1713 )1714 },1715 parenthesized,1716 )?;1717 } else {1718 self.pretty_print_const(value, print_ty)?1719 }1720 }1721 }1722 Ok(())1723 }17241725 fn pretty_print_const_scalar(1726 &mut self,1727 scalar: Scalar,1728 ty: Ty<'tcx>,1729 ) -> Result<(), PrintError> {1730 match scalar {1731 Scalar::Ptr(ptr, _size) => self.pretty_print_const_scalar_ptr(ptr, ty),1732 Scalar::Int(int) => {1733 self.pretty_print_const_scalar_int(int, ty, /* print_ty */ true)1734 }1735 }1736 }17371738 fn pretty_print_const_scalar_ptr(1739 &mut self,1740 ptr: Pointer,1741 ty: Ty<'tcx>,1742 ) -> Result<(), PrintError> {1743 let (prov, offset) = ptr.prov_and_relative_offset();1744 match ty.kind() {1745 // Byte strings (&[u8; N])1746 ty::Ref(_, inner, _) => {1747 if let ty::Array(elem, ct_len) = inner.kind()1748 && let ty::Uint(ty::UintTy::U8) = elem.kind()1749 && let Some(len) = ct_len.try_to_target_usize(self.tcx())1750 {1751 match self.tcx().try_get_global_alloc(prov.alloc_id()) {1752 Some(GlobalAlloc::Memory(alloc)) => {1753 let range = AllocRange { start: offset, size: Size::from_bytes(len) };1754 if let Ok(byte_str) =1755 alloc.inner().get_bytes_strip_provenance(&self.tcx(), range)1756 {1757 self.pretty_print_byte_str(byte_str)?;1758 } else {1759 write!(self, "<too short allocation>")?;1760 }1761 }1762 // FIXME: for statics, vtables, and functions, we could in principle print more detail.1763 Some(GlobalAlloc::Static(def_id)) => {1764 write!(self, "<static({def_id:?})>")?;1765 }1766 Some(GlobalAlloc::Function { .. }) => write!(self, "<function>")?,1767 Some(GlobalAlloc::VTable(..)) => write!(self, "<vtable>")?,1768 Some(GlobalAlloc::TypeId { .. }) => write!(self, "<typeid>")?,1769 None => write!(self, "<dangling pointer>")?,1770 }1771 return Ok(());1772 }1773 }1774 ty::FnPtr(..) => {1775 // FIXME: We should probably have a helper method to share code with the "Byte strings"1776 // printing above (which also has to handle pointers to all sorts of things).1777 if let Some(GlobalAlloc::Function { instance, .. }) =1778 self.tcx().try_get_global_alloc(prov.alloc_id())1779 {1780 self.typed_value(1781 |this| this.pretty_print_value_path(instance.def_id(), instance.args),1782 |this| this.print_type(ty),1783 " as ",1784 )?;1785 return Ok(());1786 }1787 }1788 _ => {}1789 }1790 // Any pointer values not covered by a branch above1791 self.pretty_print_const_pointer(ptr, ty)?;1792 Ok(())1793 }17941795 fn pretty_print_const_scalar_int(1796 &mut self,1797 int: ScalarInt,1798 ty: Ty<'tcx>,1799 print_ty: bool,1800 ) -> Result<(), PrintError> {1801 match ty.kind() {1802 // Bool1803 ty::Bool if int == ScalarInt::FALSE => write!(self, "false")?,1804 ty::Bool if int == ScalarInt::TRUE => write!(self, "true")?,1805 // Float1806 ty::Float(fty) => match fty {1807 ty::FloatTy::F16 => {1808 let val = Half::try_from(int).unwrap();1809 write!(self, "{}{}f16", val, if val.is_finite() { "" } else { "_" })?;1810 }1811 ty::FloatTy::F32 => {1812 let val = Single::try_from(int).unwrap();1813 write!(self, "{}{}f32", val, if val.is_finite() { "" } else { "_" })?;1814 }1815 ty::FloatTy::F64 => {1816 let val = Double::try_from(int).unwrap();1817 write!(self, "{}{}f64", val, if val.is_finite() { "" } else { "_" })?;1818 }1819 ty::FloatTy::F128 => {1820 let val = Quad::try_from(int).unwrap();1821 write!(self, "{}{}f128", val, if val.is_finite() { "" } else { "_" })?;1822 }1823 },1824 // Int1825 ty::Uint(_) | ty::Int(_) => {1826 let int =1827 ConstInt::new(int, matches!(ty.kind(), ty::Int(_)), ty.is_ptr_sized_integral());1828 if print_ty { write!(self, "{int:#?}")? } else { write!(self, "{int:?}")? }1829 }1830 // Char1831 ty::Char if char::try_from(int).is_ok() => {1832 write!(self, "{:?}", char::try_from(int).unwrap())?;1833 }1834 // Pointer types1835 ty::Ref(..) | ty::RawPtr(_, _) | ty::FnPtr(..) => {1836 let data = int.to_bits(self.tcx().data_layout.pointer_size());1837 self.typed_value(1838 |this| {1839 write!(this, "0x{data:x}")?;1840 Ok(())1841 },1842 |this| this.print_type(ty),1843 " as ",1844 )?;1845 }1846 ty::Pat(base_ty, pat) if self.tcx().validate_scalar_in_layout(int, ty) => {1847 self.pretty_print_const_scalar_int(int, *base_ty, print_ty)?;1848 write!(self, " is {pat:?}")?;1849 }1850 // Nontrivial types with scalar bit representation1851 _ => {1852 let print = |this: &mut Self| {1853 if int.size() == Size::ZERO {1854 write!(this, "transmute(())")?;1855 } else {1856 write!(this, "transmute(0x{int:x})")?;1857 }1858 Ok(())1859 };1860 if print_ty {1861 self.typed_value(print, |this| this.print_type(ty), ": ")?1862 } else {1863 print(self)?1864 };1865 }1866 }1867 Ok(())1868 }18691870 /// This is overridden for MIR printing because we only want to hide alloc ids from users, not1871 /// from MIR where it is actually useful.1872 fn pretty_print_const_pointer<Prov: Provenance>(1873 &mut self,1874 _: Pointer<Prov>,1875 ty: Ty<'tcx>,1876 ) -> Result<(), PrintError> {1877 self.typed_value(1878 |this| {1879 this.write_str("&_")?;1880 Ok(())1881 },1882 |this| this.print_type(ty),1883 ": ",1884 )1885 }18861887 fn pretty_print_byte_str(&mut self, byte_str: &'tcx [u8]) -> Result<(), PrintError> {1888 write!(self, "b\"{}\"", byte_str.escape_ascii())?;1889 Ok(())1890 }18911892 fn pretty_print_const_valtree(1893 &mut self,1894 cv: ty::Value<'tcx>,1895 print_ty: bool,1896 ) -> Result<(), PrintError> {1897 if with_reduced_queries() || self.should_print_verbose() {1898 write!(self, "ValTree({:?}: ", cv.valtree)?;1899 cv.ty.print(self)?;1900 write!(self, ")")?;1901 return Ok(());1902 }19031904 let u8_type = self.tcx().types.u8;1905 match (*cv.valtree, *cv.ty.kind()) {1906 (ty::ValTreeKind::Branch(_), ty::Ref(_, inner_ty, _)) => match inner_ty.kind() {1907 ty::Slice(t) if *t == u8_type => {1908 let bytes = cv.try_to_raw_bytes(self.tcx()).unwrap_or_else(|| {1909 bug!(1910 "expected to convert valtree {:?} to raw bytes for type {:?}",1911 cv.valtree,1912 t1913 )1914 });1915 return self.pretty_print_byte_str(bytes);1916 }1917 ty::Str => {1918 let bytes = cv.try_to_raw_bytes(self.tcx()).unwrap_or_else(|| {1919 bug!("expected to convert valtree to raw bytes for type {:?}", cv.ty)1920 });1921 write!(self, "{:?}", String::from_utf8_lossy(bytes))?;1922 return Ok(());1923 }1924 _ => {1925 let cv = ty::Value { valtree: cv.valtree, ty: inner_ty };1926 write!(self, "&")?;1927 self.pretty_print_const_valtree(cv, print_ty)?;1928 return Ok(());1929 }1930 },1931 // If it is a branch with an array, and this array can be printed as raw bytes, then dump its bytes1932 (ty::ValTreeKind::Branch(_), ty::Array(t, _))1933 if t == u8_type1934 && let Some(bytes) = cv.try_to_raw_bytes(self.tcx()) =>1935 {1936 write!(self, "*")?;1937 self.pretty_print_byte_str(bytes)?;1938 return Ok(());1939 }1940 // Otherwise, print the array separated by commas (or if it's a tuple)1941 (ty::ValTreeKind::Branch(fields), ty::Array(..) | ty::Tuple(..)) => {1942 let fields_iter = fields.iter();19431944 match *cv.ty.kind() {1945 ty::Array(..) => {1946 write!(self, "[")?;1947 self.comma_sep(fields_iter)?;1948 write!(self, "]")?;1949 }1950 ty::Tuple(..) => {1951 write!(self, "(")?;1952 self.comma_sep(fields_iter)?;1953 if fields.len() == 1 {1954 write!(self, ",")?;1955 }1956 write!(self, ")")?;1957 }1958 _ => unreachable!(),1959 }1960 return Ok(());1961 }1962 (ty::ValTreeKind::Branch(_), ty::Adt(def, args)) => {1963 let contents = cv.destructure_adt_const();1964 let fields = contents.fields.iter().copied();19651966 if def.variants().is_empty() {1967 self.typed_value(1968 |this| {1969 write!(this, "unreachable()")?;1970 Ok(())1971 },1972 |this| this.print_type(cv.ty),1973 ": ",1974 )?;1975 } else {1976 let variant_idx = contents.variant;1977 let variant_def = &def.variant(variant_idx);1978 self.pretty_print_value_path(variant_def.def_id, args)?;1979 match variant_def.ctor_kind() {1980 Some(CtorKind::Const) => {}1981 Some(CtorKind::Fn) => {1982 write!(self, "(")?;1983 self.comma_sep(fields)?;1984 write!(self, ")")?;1985 }1986 None => {1987 write!(self, " {{ ")?;1988 let mut first = true;1989 for (field_def, field) in iter::zip(&variant_def.fields, fields) {1990 if !first {1991 // FIXME(legacy mangling): if this appears, should we enable1992 // spaces depending on `comma_sep_has_space`?1993 write!(self, ", ")?;1994 }1995 write!(self, "{}: ", field_def.name)?;1996 field.print(self)?;1997 first = false;1998 }1999 write!(self, " }}")?;2000 }
Findings
✓ No findings reported for this file.