1 use crate::hir::def::Namespace;
2 use crate::hir::map::DefPathData;
3 use crate::hir::def_id::{CrateNum, DefId, CRATE_DEF_INDEX, LOCAL_CRATE};
4 use crate::ty::{self, DefIdTree, Ty, TyCtxt, TypeFoldable};
5 use crate::ty::subst::{Subst, SubstsRef};
6 use crate::middle::cstore::{ExternCrate, ExternCrateSource};
8 use syntax::symbol::{keywords, Symbol};
10 use rustc_data_structures::fx::FxHashSet;
11 use syntax::symbol::InternedString;
18 static FORCE_ABSOLUTE: Cell<bool> = Cell::new(false);
19 static FORCE_IMPL_FILENAME_LINE: Cell<bool> = Cell::new(false);
20 static SHOULD_PREFIX_WITH_CRATE: Cell<bool> = Cell::new(false);
23 /// Enforces that def_path_str always returns an absolute path and
24 /// also enables "type-based" impl paths. This is used when building
25 /// symbols that contain types, where we want the crate name to be
26 /// part of the symbol.
27 pub fn with_forced_absolute_paths<F: FnOnce() -> R, R>(f: F) -> R {
28 FORCE_ABSOLUTE.with(|force| {
29 let old = force.get();
37 /// Force us to name impls with just the filename/line number. We
38 /// normally try to use types. But at some points, notably while printing
39 /// cycle errors, this can result in extra or suboptimal error output,
40 /// so this variable disables that check.
41 pub fn with_forced_impl_filename_line<F: FnOnce() -> R, R>(f: F) -> R {
42 FORCE_IMPL_FILENAME_LINE.with(|force| {
43 let old = force.get();
51 /// Adds the `crate::` prefix to paths where appropriate.
52 pub fn with_crate_prefix<F: FnOnce() -> R, R>(f: F) -> R {
53 SHOULD_PREFIX_WITH_CRATE.with(|flag| {
62 // FIXME(eddyb) this module uses `pub(crate)` for things used only
63 // from `ppaux` - when that is removed, they can be re-privatized.
65 struct LateBoundRegionNameCollector(FxHashSet<InternedString>);
66 impl<'tcx> ty::fold::TypeVisitor<'tcx> for LateBoundRegionNameCollector {
67 fn visit_region(&mut self, r: ty::Region<'tcx>) -> bool {
69 ty::ReLateBound(_, ty::BrNamed(_, name)) => {
74 r.super_visit_with(self)
78 pub struct PrintCx<'a, 'gcx, 'tcx, P> {
79 pub tcx: TyCtxt<'a, 'gcx, 'tcx>,
81 pub(crate) is_debug: bool,
82 pub(crate) is_verbose: bool,
83 pub(crate) identify_regions: bool,
84 pub(crate) used_region_names: Option<FxHashSet<InternedString>>,
85 pub(crate) region_index: usize,
86 pub(crate) binder_depth: usize,
89 // HACK(eddyb) this is solely for `self: &mut PrintCx<Self>`, e.g. to
90 // implement traits on the printer and call the methods on the context.
91 impl<P> Deref for PrintCx<'_, '_, '_, P> {
93 fn deref(&self) -> &P {
98 impl<P> PrintCx<'a, 'gcx, 'tcx, P> {
99 pub fn new(tcx: TyCtxt<'a, 'gcx, 'tcx>, printer: P) -> Self {
104 is_verbose: tcx.sess.verbose(),
105 identify_regions: tcx.sess.opts.debugging_opts.identify_regions,
106 used_region_names: None,
112 pub(crate) fn with<R>(printer: P, f: impl FnOnce(PrintCx<'_, '_, '_, P>) -> R) -> R {
113 ty::tls::with(|tcx| f(PrintCx::new(tcx, printer)))
115 pub(crate) fn prepare_late_bound_region_info<T>(&mut self, value: &ty::Binder<T>)
116 where T: TypeFoldable<'tcx>
118 let mut collector = LateBoundRegionNameCollector(Default::default());
119 value.visit_with(&mut collector);
120 self.used_region_names = Some(collector.0);
121 self.region_index = 0;
125 pub trait Print<'tcx, P> {
128 fn print(&self, cx: &mut PrintCx<'_, '_, 'tcx, P>) -> Self::Output;
129 fn print_display(&self, cx: &mut PrintCx<'_, '_, 'tcx, P>) -> Self::Output {
130 let old_debug = cx.is_debug;
132 let result = self.print(cx);
133 cx.is_debug = old_debug;
136 fn print_debug(&self, cx: &mut PrintCx<'_, '_, 'tcx, P>) -> Self::Output {
137 let old_debug = cx.is_debug;
139 let result = self.print(cx);
140 cx.is_debug = old_debug;
145 pub trait Printer: Sized {
149 self: &mut PrintCx<'_, '_, 'tcx, Self>,
151 substs: Option<SubstsRef<'tcx>>,
154 self.default_print_def_path(def_id, substs, ns)
157 self: &mut PrintCx<'_, '_, 'tcx, Self>,
159 substs: Option<SubstsRef<'tcx>>,
162 self.default_print_impl_path(impl_def_id, substs, ns)
165 fn path_crate(self: &mut PrintCx<'_, '_, '_, Self>, cnum: CrateNum) -> Self::Path;
166 fn path_impl(self: &mut PrintCx<'_, '_, '_, Self>, text: &str) -> Self::Path;
168 self: &mut PrintCx<'_, '_, '_, Self>,
174 impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
175 // HACK(eddyb) get rid of `def_path_str` and/or pass `Namespace` explicitly always
176 // (but also some things just print a `DefId` generally so maybe we need this?)
177 fn guess_def_namespace(self, def_id: DefId) -> Namespace {
178 match self.def_key(def_id).disambiguated_data.data {
179 DefPathData::ValueNs(..) |
180 DefPathData::EnumVariant(..) |
181 DefPathData::Field(..) |
182 DefPathData::AnonConst |
183 DefPathData::ClosureExpr |
184 DefPathData::StructCtor => Namespace::ValueNS,
186 DefPathData::MacroDef(..) => Namespace::MacroNS,
188 _ => Namespace::TypeNS,
192 /// Returns a string identifying this `DefId`. This string is
193 /// suitable for user output. It is relative to the current crate
194 /// root, unless with_forced_absolute_paths was used.
195 pub fn def_path_str_with_substs_and_ns(
198 substs: Option<SubstsRef<'tcx>>,
201 debug!("def_path_str: def_id={:?}, substs={:?}, ns={:?}", def_id, substs, ns);
202 if FORCE_ABSOLUTE.with(|force| force.get()) {
203 PrintCx::new(self, AbsolutePathPrinter).print_def_path(def_id, substs, ns)
205 PrintCx::new(self, LocalPathPrinter).print_def_path(def_id, substs, ns)
209 /// Returns a string identifying this `DefId`. This string is
210 /// suitable for user output. It is relative to the current crate
211 /// root, unless with_forced_absolute_paths was used.
212 pub fn def_path_str(self, def_id: DefId) -> String {
213 let ns = self.guess_def_namespace(def_id);
214 self.def_path_str_with_substs_and_ns(def_id, None, ns)
217 /// Returns a string identifying this local node-id.
218 // FIXME(eddyb) remove in favor of calling `def_path_str` directly.
219 pub fn node_path_str(self, id: ast::NodeId) -> String {
220 self.def_path_str(self.hir().local_def_id(id))
223 /// Returns a string identifying this `DefId`. This string is
224 /// suitable for user output. It always begins with a crate identifier.
225 pub fn absolute_def_path_str(self, def_id: DefId) -> String {
226 debug!("absolute_def_path_str: def_id={:?}", def_id);
227 let ns = self.guess_def_namespace(def_id);
228 PrintCx::new(self, AbsolutePathPrinter).print_def_path(def_id, None, ns)
232 impl<P: Printer> PrintCx<'a, 'gcx, 'tcx, P> {
233 pub fn default_print_def_path(
236 substs: Option<SubstsRef<'tcx>>,
239 debug!("default_print_def_path: def_id={:?}, substs={:?}, ns={:?}", def_id, substs, ns);
240 let key = self.tcx.def_key(def_id);
241 debug!("default_print_def_path: key={:?}", key);
242 match key.disambiguated_data.data {
243 DefPathData::CrateRoot => {
244 assert!(key.parent.is_none());
245 self.path_crate(def_id.krate)
248 DefPathData::Impl => {
249 self.print_impl_path(def_id, substs, ns)
252 // Unclear if there is any value in distinguishing these.
253 // Probably eventually (and maybe we would even want
254 // finer-grained distinctions, e.g., between enum/struct).
255 data @ DefPathData::Misc |
256 data @ DefPathData::TypeNs(..) |
257 data @ DefPathData::Trait(..) |
258 data @ DefPathData::TraitAlias(..) |
259 data @ DefPathData::AssocTypeInTrait(..) |
260 data @ DefPathData::AssocTypeInImpl(..) |
261 data @ DefPathData::AssocExistentialInImpl(..) |
262 data @ DefPathData::ValueNs(..) |
263 data @ DefPathData::Module(..) |
264 data @ DefPathData::TypeParam(..) |
265 data @ DefPathData::LifetimeParam(..) |
266 data @ DefPathData::ConstParam(..) |
267 data @ DefPathData::EnumVariant(..) |
268 data @ DefPathData::Field(..) |
269 data @ DefPathData::AnonConst |
270 data @ DefPathData::MacroDef(..) |
271 data @ DefPathData::ClosureExpr |
272 data @ DefPathData::ImplTrait |
273 data @ DefPathData::GlobalMetaData(..) => {
274 let parent_did = self.tcx.parent(def_id).unwrap();
275 let path = self.print_def_path(parent_did, None, ns);
276 self.path_append(path, &data.as_interned_str().as_symbol().as_str())
279 DefPathData::StructCtor => { // present `X` instead of `X::{{constructor}}`
280 let parent_def_id = self.tcx.parent(def_id).unwrap();
281 self.print_def_path(parent_def_id, substs, ns)
286 fn default_print_impl_path(
289 substs: Option<SubstsRef<'tcx>>,
292 debug!("default_print_impl_path: impl_def_id={:?}", impl_def_id);
293 let parent_def_id = self.tcx.parent(impl_def_id).unwrap();
295 // Decide whether to print the parent path for the impl.
296 // Logically, since impls are global, it's never needed, but
297 // users may find it useful. Currently, we omit the parent if
298 // the impl is either in the same module as the self-type or
300 let mut self_ty = self.tcx.type_of(impl_def_id);
301 if let Some(substs) = substs {
302 self_ty = self_ty.subst(self.tcx, substs);
304 let in_self_mod = match characteristic_def_id_of_type(self_ty) {
306 Some(ty_def_id) => self.tcx.parent(ty_def_id) == Some(parent_def_id),
309 let mut impl_trait_ref = self.tcx.impl_trait_ref(impl_def_id);
310 if let Some(substs) = substs {
311 impl_trait_ref = impl_trait_ref.subst(self.tcx, substs);
313 let in_trait_mod = match impl_trait_ref {
315 Some(trait_ref) => self.tcx.parent(trait_ref.def_id) == Some(parent_def_id),
318 if !in_self_mod && !in_trait_mod {
319 // If the impl is not co-located with either self-type or
320 // trait-type, then fallback to a format that identifies
321 // the module more clearly.
322 let path = self.print_def_path(parent_def_id, None, ns);
323 if let Some(trait_ref) = impl_trait_ref {
324 return self.path_append(path, &format!("<impl {} for {}>", trait_ref, self_ty));
326 return self.path_append(path, &format!("<impl {}>", self_ty));
330 // Otherwise, try to give a good form that would be valid language
331 // syntax. Preferably using associated item notation.
333 if let Some(trait_ref) = impl_trait_ref {
335 return self.path_impl(&format!("<{} as {}>", self_ty, trait_ref));
338 // Inherent impls. Try to print `Foo::bar` for an inherent
339 // impl on `Foo`, but fallback to `<Foo>::bar` if self-type is
340 // anything other than a simple path.
342 ty::Adt(adt_def, substs) => {
343 // FIXME(eddyb) this should recurse to build the path piecewise.
344 // self.print_def_path(adt_def.did, Some(substs), ns)
345 let mut s = String::new();
346 crate::util::ppaux::parameterized(&mut s, adt_def.did, substs, ns).unwrap();
350 ty::Foreign(did) => self.print_def_path(did, None, ns),
358 self.path_impl(&self_ty.to_string())
362 self.path_impl(&format!("<{}>", self_ty))
368 /// As a heuristic, when we see an impl, if we see that the
369 /// 'self type' is a type defined in the same module as the impl,
370 /// we can omit including the path to the impl itself. This
371 /// function tries to find a "characteristic `DefId`" for a
372 /// type. It's just a heuristic so it makes some questionable
373 /// decisions and we may want to adjust it later.
374 pub fn characteristic_def_id_of_type(ty: Ty<'_>) -> Option<DefId> {
376 ty::Adt(adt_def, _) => Some(adt_def.did),
378 ty::Dynamic(data, ..) => data.principal_def_id(),
380 ty::Array(subty, _) |
381 ty::Slice(subty) => characteristic_def_id_of_type(subty),
383 ty::RawPtr(mt) => characteristic_def_id_of_type(mt.ty),
385 ty::Ref(_, ty, _) => characteristic_def_id_of_type(ty),
387 ty::Tuple(ref tys) => tys.iter()
388 .filter_map(|ty| characteristic_def_id_of_type(ty))
391 ty::FnDef(def_id, _) |
392 ty::Closure(def_id, _) |
393 ty::Generator(def_id, _, _) |
394 ty::Foreign(def_id) => Some(def_id),
403 ty::Placeholder(..) |
404 ty::UnnormalizedProjection(..) |
410 ty::GeneratorWitness(..) |
412 ty::Float(_) => None,
416 // FIXME(eddyb) remove, alongside `FORCE_ABSOLUTE` and `absolute_def_path_str`.
417 struct AbsolutePathPrinter;
419 impl Printer for AbsolutePathPrinter {
422 fn path_crate(self: &mut PrintCx<'_, '_, '_, Self>, cnum: CrateNum) -> Self::Path {
423 self.tcx.original_crate_name(cnum).to_string()
425 fn path_impl(self: &mut PrintCx<'_, '_, '_, Self>, text: &str) -> Self::Path {
429 self: &mut PrintCx<'_, '_, '_, Self>,
430 mut path: Self::Path,
433 if !path.is_empty() {
441 pub struct FmtPrinter<F: fmt::Write> {
445 // FIXME(eddyb) integrate into `FmtPrinter`.
446 struct LocalPathPrinter;
448 impl LocalPathPrinter {
449 /// If possible, this returns a global path resolving to `def_id` that is visible
450 /// from at least one local module and returns true. If the crate defining `def_id` is
451 /// declared with an `extern crate`, the path is guaranteed to use the `extern crate`.
452 fn try_print_visible_def_path(
453 self: &mut PrintCx<'_, '_, '_, Self>,
456 ) -> Option<<Self as Printer>::Path> {
457 debug!("try_print_visible_def_path: def_id={:?}", def_id);
459 // If `def_id` is a direct or injected extern crate, return the
460 // path to the crate followed by the path to the item within the crate.
461 if def_id.index == CRATE_DEF_INDEX {
462 let cnum = def_id.krate;
464 if cnum == LOCAL_CRATE {
465 return Some(self.path_crate(cnum));
468 // In local mode, when we encounter a crate other than
469 // LOCAL_CRATE, execution proceeds in one of two ways:
471 // 1. for a direct dependency, where user added an
472 // `extern crate` manually, we put the `extern
473 // crate` as the parent. So you wind up with
474 // something relative to the current crate.
475 // 2. for an extern inferred from a path or an indirect crate,
476 // where there is no explicit `extern crate`, we just prepend
478 match *self.tcx.extern_crate(def_id) {
480 src: ExternCrateSource::Extern(def_id),
485 debug!("try_print_visible_def_path: def_id={:?}", def_id);
486 let path = if !span.is_dummy() {
487 self.print_def_path(def_id, None, ns)
489 self.path_crate(cnum)
494 return Some(self.path_crate(cnum));
500 if def_id.is_local() {
504 let visible_parent_map = self.tcx.visible_parent_map(LOCAL_CRATE);
506 let mut cur_def_key = self.tcx.def_key(def_id);
507 debug!("try_print_visible_def_path: cur_def_key={:?}", cur_def_key);
509 // For a UnitStruct or TupleStruct we want the name of its parent rather than <unnamed>.
510 if let DefPathData::StructCtor = cur_def_key.disambiguated_data.data {
513 index: cur_def_key.parent.expect("DefPathData::StructCtor missing a parent"),
516 cur_def_key = self.tcx.def_key(parent);
519 let visible_parent = visible_parent_map.get(&def_id).cloned()?;
520 let path = self.try_print_visible_def_path(visible_parent, ns)?;
521 let actual_parent = self.tcx.parent(def_id);
523 let data = cur_def_key.disambiguated_data.data;
525 "try_print_visible_def_path: data={:?} visible_parent={:?} actual_parent={:?}",
526 data, visible_parent, actual_parent,
529 let symbol = match data {
530 // In order to output a path that could actually be imported (valid and visible),
531 // we need to handle re-exports correctly.
533 // For example, take `std::os::unix::process::CommandExt`, this trait is actually
534 // defined at `std::sys::unix::ext::process::CommandExt` (at time of writing).
536 // `std::os::unix` rexports the contents of `std::sys::unix::ext`. `std::sys` is
537 // private so the "true" path to `CommandExt` isn't accessible.
539 // In this case, the `visible_parent_map` will look something like this:
541 // (child) -> (parent)
542 // `std::sys::unix::ext::process::CommandExt` -> `std::sys::unix::ext::process`
543 // `std::sys::unix::ext::process` -> `std::sys::unix::ext`
544 // `std::sys::unix::ext` -> `std::os`
546 // This is correct, as the visible parent of `std::sys::unix::ext` is in fact
549 // When printing the path to `CommandExt` and looking at the `cur_def_key` that
550 // corresponds to `std::sys::unix::ext`, we would normally print `ext` and then go
551 // to the parent - resulting in a mangled path like
552 // `std::os::ext::process::CommandExt`.
554 // Instead, we must detect that there was a re-export and instead print `unix`
555 // (which is the name `std::sys::unix::ext` was re-exported as in `std::os`). To
556 // do this, we compare the parent of `std::sys::unix::ext` (`std::sys::unix`) with
557 // the visible parent (`std::os`). If these do not match, then we iterate over
558 // the children of the visible parent (as was done when computing
559 // `visible_parent_map`), looking for the specific child we currently have and then
560 // have access to the re-exported name.
561 DefPathData::Module(actual_name) |
562 DefPathData::TypeNs(actual_name) if Some(visible_parent) != actual_parent => {
563 self.tcx.item_children(visible_parent)
565 .find(|child| child.def.def_id() == def_id)
566 .map(|child| child.ident.as_str())
567 .unwrap_or_else(|| actual_name.as_str())
570 data.get_opt_name().map(|n| n.as_str()).unwrap_or_else(|| {
571 // Re-exported `extern crate` (#43189).
572 if let DefPathData::CrateRoot = data {
573 self.tcx.original_crate_name(def_id.krate).as_str()
575 Symbol::intern("<unnamed>").as_str()
580 debug!("try_print_visible_def_path: symbol={:?}", symbol);
581 Some(self.path_append(path, &symbol))
585 impl Printer for LocalPathPrinter {
589 self: &mut PrintCx<'_, '_, 'tcx, Self>,
591 substs: Option<SubstsRef<'tcx>>,
594 self.try_print_visible_def_path(def_id, ns)
595 .unwrap_or_else(|| self.default_print_def_path(def_id, substs, ns))
598 self: &mut PrintCx<'_, '_, 'tcx, Self>,
600 substs: Option<SubstsRef<'tcx>>,
603 // Always use types for non-local impls, where types are always
604 // available, and filename/line-number is mostly uninteresting.
605 let use_types = !impl_def_id.is_local() || {
606 // Otherwise, use filename/line-number if forced.
607 let force_no_types = FORCE_IMPL_FILENAME_LINE.with(|f| f.get());
612 // If no type info is available, fall back to
613 // pretty printing some span information. This should
614 // only occur very early in the compiler pipeline.
615 // FIXME(eddyb) this should just be using `tcx.def_span(impl_def_id)`
616 let parent_def_id = self.tcx.parent(impl_def_id).unwrap();
617 let path = self.print_def_path(parent_def_id, None, ns);
618 let span = self.tcx.def_span(impl_def_id);
619 return self.path_append(path, &format!("<impl at {:?}>", span));
622 self.default_print_impl_path(impl_def_id, substs, ns)
625 fn path_crate(self: &mut PrintCx<'_, '_, '_, Self>, cnum: CrateNum) -> Self::Path {
626 if cnum == LOCAL_CRATE {
627 if self.tcx.sess.rust_2018() {
628 // We add the `crate::` keyword on Rust 2018, only when desired.
629 if SHOULD_PREFIX_WITH_CRATE.with(|flag| flag.get()) {
630 return keywords::Crate.name().to_string();
635 self.tcx.crate_name(cnum).to_string()
638 fn path_impl(self: &mut PrintCx<'_, '_, '_, Self>, text: &str) -> Self::Path {
642 self: &mut PrintCx<'_, '_, '_, Self>,
643 mut path: Self::Path,
646 if !path.is_empty() {