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};
5 use crate::ty::print::PrintCx;
6 use crate::ty::subst::{Subst, Substs};
7 use crate::middle::cstore::{ExternCrate, ExternCrateSource};
9 use syntax::symbol::{keywords, Symbol};
14 static FORCE_ABSOLUTE: Cell<bool> = Cell::new(false);
15 static FORCE_IMPL_FILENAME_LINE: Cell<bool> = Cell::new(false);
16 static SHOULD_PREFIX_WITH_CRATE: Cell<bool> = Cell::new(false);
19 /// Enforces that item_path_str always returns an absolute path and
20 /// also enables "type-based" impl paths. This is used when building
21 /// symbols that contain types, where we want the crate name to be
22 /// part of the symbol.
23 pub fn with_forced_absolute_paths<F: FnOnce() -> R, R>(f: F) -> R {
24 FORCE_ABSOLUTE.with(|force| {
25 let old = force.get();
33 /// Force us to name impls with just the filename/line number. We
34 /// normally try to use types. But at some points, notably while printing
35 /// cycle errors, this can result in extra or suboptimal error output,
36 /// so this variable disables that check.
37 pub fn with_forced_impl_filename_line<F: FnOnce() -> R, R>(f: F) -> R {
38 FORCE_IMPL_FILENAME_LINE.with(|force| {
39 let old = force.get();
47 /// Adds the `crate::` prefix to paths where appropriate.
48 pub fn with_crate_prefix<F: FnOnce() -> R, R>(f: F) -> R {
49 SHOULD_PREFIX_WITH_CRATE.with(|flag| {
58 impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
59 // HACK(eddyb) get rid of `item_path_str` and/or pass `Namespace` explicitly always
60 // (but also some things just print a `DefId` generally so maybe we need this?)
61 fn guess_def_namespace(self, def_id: DefId) -> Namespace {
62 match self.def_key(def_id).disambiguated_data.data {
63 DefPathData::ValueNs(..) |
64 DefPathData::EnumVariant(..) |
65 DefPathData::Field(..) |
66 DefPathData::AnonConst |
67 DefPathData::ClosureExpr |
68 DefPathData::StructCtor => Namespace::ValueNS,
70 DefPathData::MacroDef(..) => Namespace::MacroNS,
72 _ => Namespace::TypeNS,
76 /// Returns a string identifying this `DefId`. This string is
77 /// suitable for user output. It is relative to the current crate
78 /// root, unless with_forced_absolute_paths was used.
79 pub fn item_path_str_with_substs_and_ns(
82 substs: Option<&Substs<'tcx>>,
85 debug!("item_path_str: def_id={:?}, substs={:?}, ns={:?}", def_id, substs, ns);
86 if FORCE_ABSOLUTE.with(|force| force.get()) {
87 PrintCx::new(self, AbsolutePathPrinter).print_item_path(def_id, substs, ns)
89 PrintCx::new(self, LocalPathPrinter).print_item_path(def_id, substs, ns)
93 /// Returns a string identifying this def-id. This string is
94 /// suitable for user output. It is relative to the current crate
95 /// root, unless with_forced_absolute_paths was used.
96 pub fn item_path_str(self, def_id: DefId) -> String {
97 let ns = self.guess_def_namespace(def_id);
98 self.item_path_str_with_substs_and_ns(def_id, None, ns)
101 /// Returns a string identifying this local node-id.
102 pub fn node_path_str(self, id: ast::NodeId) -> String {
103 self.item_path_str(self.hir().local_def_id(id))
106 /// Returns a string identifying this def-id. This string is
107 /// suitable for user output. It always begins with a crate identifier.
108 pub fn absolute_item_path_str(self, def_id: DefId) -> String {
109 debug!("absolute_item_path_str: def_id={:?}", def_id);
110 let ns = self.guess_def_namespace(def_id);
111 PrintCx::new(self, AbsolutePathPrinter).print_item_path(def_id, None, ns)
115 impl<P: ItemPathPrinter> PrintCx<'a, 'gcx, 'tcx, P> {
116 pub fn default_print_item_path(
119 substs: Option<&Substs<'tcx>>,
122 debug!("default_print_item_path: def_id={:?}, substs={:?}, ns={:?}", def_id, substs, ns);
123 let key = self.tcx.def_key(def_id);
124 debug!("default_print_item_path: key={:?}", key);
125 match key.disambiguated_data.data {
126 DefPathData::CrateRoot => {
127 assert!(key.parent.is_none());
128 self.path_crate(def_id.krate)
131 DefPathData::Impl => {
132 self.print_impl_path(def_id, substs, ns)
135 // Unclear if there is any value in distinguishing these.
136 // Probably eventually (and maybe we would even want
137 // finer-grained distinctions, e.g., between enum/struct).
138 data @ DefPathData::Misc |
139 data @ DefPathData::TypeNs(..) |
140 data @ DefPathData::Trait(..) |
141 data @ DefPathData::TraitAlias(..) |
142 data @ DefPathData::AssocTypeInTrait(..) |
143 data @ DefPathData::AssocTypeInImpl(..) |
144 data @ DefPathData::AssocExistentialInImpl(..) |
145 data @ DefPathData::ValueNs(..) |
146 data @ DefPathData::Module(..) |
147 data @ DefPathData::TypeParam(..) |
148 data @ DefPathData::LifetimeParam(..) |
149 data @ DefPathData::ConstParam(..) |
150 data @ DefPathData::EnumVariant(..) |
151 data @ DefPathData::Field(..) |
152 data @ DefPathData::AnonConst |
153 data @ DefPathData::MacroDef(..) |
154 data @ DefPathData::ClosureExpr |
155 data @ DefPathData::ImplTrait |
156 data @ DefPathData::GlobalMetaData(..) => {
157 let parent_did = self.tcx.parent_def_id(def_id).unwrap();
158 let path = self.print_item_path(parent_did, None, ns);
159 self.path_append(path, &data.as_interned_str().as_symbol().as_str())
162 DefPathData::StructCtor => { // present `X` instead of `X::{{constructor}}`
163 let parent_def_id = self.tcx.parent_def_id(def_id).unwrap();
164 self.print_item_path(parent_def_id, substs, ns)
169 fn default_print_impl_path(
172 substs: Option<&Substs<'tcx>>,
175 debug!("default_print_impl_path: impl_def_id={:?}", impl_def_id);
176 let parent_def_id = self.tcx.parent_def_id(impl_def_id).unwrap();
178 // Decide whether to print the parent path for the impl.
179 // Logically, since impls are global, it's never needed, but
180 // users may find it useful. Currently, we omit the parent if
181 // the impl is either in the same module as the self-type or
183 let mut self_ty = self.tcx.type_of(impl_def_id);
184 if let Some(substs) = substs {
185 self_ty = self_ty.subst(self.tcx, substs);
187 let in_self_mod = match characteristic_def_id_of_type(self_ty) {
189 Some(ty_def_id) => self.tcx.parent_def_id(ty_def_id) == Some(parent_def_id),
192 let mut impl_trait_ref = self.tcx.impl_trait_ref(impl_def_id);
193 if let Some(substs) = substs {
194 impl_trait_ref = impl_trait_ref.subst(self.tcx, substs);
196 let in_trait_mod = match impl_trait_ref {
198 Some(trait_ref) => self.tcx.parent_def_id(trait_ref.def_id) == Some(parent_def_id),
201 if !in_self_mod && !in_trait_mod {
202 // If the impl is not co-located with either self-type or
203 // trait-type, then fallback to a format that identifies
204 // the module more clearly.
205 let path = self.print_item_path(parent_def_id, None, ns);
206 if let Some(trait_ref) = impl_trait_ref {
207 return self.path_append(path, &format!("<impl {} for {}>", trait_ref, self_ty));
209 return self.path_append(path, &format!("<impl {}>", self_ty));
213 // Otherwise, try to give a good form that would be valid language
214 // syntax. Preferably using associated item notation.
216 if let Some(trait_ref) = impl_trait_ref {
218 return self.path_impl(&format!("<{} as {}>", self_ty, trait_ref));
221 // Inherent impls. Try to print `Foo::bar` for an inherent
222 // impl on `Foo`, but fallback to `<Foo>::bar` if self-type is
223 // anything other than a simple path.
225 ty::Adt(adt_def, substs) => {
226 // FIXME(eddyb) this should recurse to build the path piecewise.
227 // self.print_item_path(adt_def.did, Some(substs), ns)
228 let mut s = String::new();
229 crate::util::ppaux::parameterized(&mut s, adt_def.did, substs, ns).unwrap();
233 ty::Foreign(did) => self.print_item_path(did, None, ns),
241 self.path_impl(&self_ty.to_string())
245 self.path_impl(&format!("<{}>", self_ty))
251 impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
252 /// Returns the `DefId` of `def_id`'s parent in the def tree. If
253 /// this returns `None`, then `def_id` represents a crate root or
255 pub fn parent_def_id(self, def_id: DefId) -> Option<DefId> {
256 let key = self.def_key(def_id);
257 key.parent.map(|index| DefId { krate: def_id.krate, index: index })
261 /// As a heuristic, when we see an impl, if we see that the
262 /// 'self type' is a type defined in the same module as the impl,
263 /// we can omit including the path to the impl itself. This
264 /// function tries to find a "characteristic `DefId`" for a
265 /// type. It's just a heuristic so it makes some questionable
266 /// decisions and we may want to adjust it later.
267 pub fn characteristic_def_id_of_type(ty: Ty<'_>) -> Option<DefId> {
269 ty::Adt(adt_def, _) => Some(adt_def.did),
271 ty::Dynamic(data, ..) => data.principal_def_id(),
273 ty::Array(subty, _) |
274 ty::Slice(subty) => characteristic_def_id_of_type(subty),
276 ty::RawPtr(mt) => characteristic_def_id_of_type(mt.ty),
278 ty::Ref(_, ty, _) => characteristic_def_id_of_type(ty),
280 ty::Tuple(ref tys) => tys.iter()
281 .filter_map(|ty| characteristic_def_id_of_type(ty))
284 ty::FnDef(def_id, _) |
285 ty::Closure(def_id, _) |
286 ty::Generator(def_id, _, _) |
287 ty::Foreign(def_id) => Some(def_id),
296 ty::Placeholder(..) |
297 ty::UnnormalizedProjection(..) |
303 ty::GeneratorWitness(..) |
305 ty::Float(_) => None,
309 /// Unifying Trait for different kinds of item paths we might
310 /// construct. The basic interface is that components get appended.
311 pub trait ItemPathPrinter: Sized {
315 self: &mut PrintCx<'_, '_, 'tcx, Self>,
317 substs: Option<&Substs<'tcx>>,
320 self.default_print_item_path(def_id, substs, ns)
323 self: &mut PrintCx<'_, '_, 'tcx, Self>,
325 substs: Option<&Substs<'tcx>>,
328 self.default_print_impl_path(impl_def_id, substs, ns)
331 fn path_crate(self: &mut PrintCx<'_, '_, '_, Self>, cnum: CrateNum) -> Self::Path;
332 fn path_impl(self: &mut PrintCx<'_, '_, '_, Self>, text: &str) -> Self::Path;
334 self: &mut PrintCx<'_, '_, '_, Self>,
340 struct AbsolutePathPrinter;
342 impl ItemPathPrinter for AbsolutePathPrinter {
345 fn path_crate(self: &mut PrintCx<'_, '_, '_, Self>, cnum: CrateNum) -> Self::Path {
346 self.tcx.original_crate_name(cnum).to_string()
348 fn path_impl(self: &mut PrintCx<'_, '_, '_, Self>, text: &str) -> Self::Path {
352 self: &mut PrintCx<'_, '_, '_, Self>,
353 mut path: Self::Path,
356 if !path.is_empty() {
364 struct LocalPathPrinter;
366 impl LocalPathPrinter {
367 /// If possible, this returns a global path resolving to `def_id` that is visible
368 /// from at least one local module and returns true. If the crate defining `def_id` is
369 /// declared with an `extern crate`, the path is guaranteed to use the `extern crate`.
370 fn try_print_visible_item_path(
371 self: &mut PrintCx<'_, '_, '_, Self>,
374 ) -> Option<<Self as ItemPathPrinter>::Path> {
375 debug!("try_print_visible_item_path: def_id={:?}", def_id);
377 // If `def_id` is a direct or injected extern crate, return the
378 // path to the crate followed by the path to the item within the crate.
379 if def_id.index == CRATE_DEF_INDEX {
380 let cnum = def_id.krate;
382 if cnum == LOCAL_CRATE {
383 return Some(self.path_crate(cnum));
386 // In local mode, when we encounter a crate other than
387 // LOCAL_CRATE, execution proceeds in one of two ways:
389 // 1. for a direct dependency, where user added an
390 // `extern crate` manually, we put the `extern
391 // crate` as the parent. So you wind up with
392 // something relative to the current crate.
393 // 2. for an extern inferred from a path or an indirect crate,
394 // where there is no explicit `extern crate`, we just prepend
396 match *self.tcx.extern_crate(def_id) {
398 src: ExternCrateSource::Extern(def_id),
403 debug!("try_print_visible_item_path: def_id={:?}", def_id);
404 let path = if !span.is_dummy() {
405 self.print_item_path(def_id, None, ns)
407 self.path_crate(cnum)
412 return Some(self.path_crate(cnum));
418 if def_id.is_local() {
422 let visible_parent_map = self.tcx.visible_parent_map(LOCAL_CRATE);
424 let mut cur_def_key = self.tcx.def_key(def_id);
425 debug!("try_print_visible_item_path: cur_def_key={:?}", cur_def_key);
427 // For a UnitStruct or TupleStruct we want the name of its parent rather than <unnamed>.
428 if let DefPathData::StructCtor = cur_def_key.disambiguated_data.data {
431 index: cur_def_key.parent.expect("DefPathData::StructCtor missing a parent"),
434 cur_def_key = self.tcx.def_key(parent);
437 let visible_parent = visible_parent_map.get(&def_id).cloned()?;
438 let path = self.try_print_visible_item_path(visible_parent, ns)?;
439 let actual_parent = self.tcx.parent(def_id);
441 let data = cur_def_key.disambiguated_data.data;
443 "try_print_visible_item_path: data={:?} visible_parent={:?} actual_parent={:?}",
444 data, visible_parent, actual_parent,
447 let symbol = match data {
448 // In order to output a path that could actually be imported (valid and visible),
449 // we need to handle re-exports correctly.
451 // For example, take `std::os::unix::process::CommandExt`, this trait is actually
452 // defined at `std::sys::unix::ext::process::CommandExt` (at time of writing).
454 // `std::os::unix` rexports the contents of `std::sys::unix::ext`. `std::sys` is
455 // private so the "true" path to `CommandExt` isn't accessible.
457 // In this case, the `visible_parent_map` will look something like this:
459 // (child) -> (parent)
460 // `std::sys::unix::ext::process::CommandExt` -> `std::sys::unix::ext::process`
461 // `std::sys::unix::ext::process` -> `std::sys::unix::ext`
462 // `std::sys::unix::ext` -> `std::os`
464 // This is correct, as the visible parent of `std::sys::unix::ext` is in fact
467 // When printing the path to `CommandExt` and looking at the `cur_def_key` that
468 // corresponds to `std::sys::unix::ext`, we would normally print `ext` and then go
469 // to the parent - resulting in a mangled path like
470 // `std::os::ext::process::CommandExt`.
472 // Instead, we must detect that there was a re-export and instead print `unix`
473 // (which is the name `std::sys::unix::ext` was re-exported as in `std::os`). To
474 // do this, we compare the parent of `std::sys::unix::ext` (`std::sys::unix`) with
475 // the visible parent (`std::os`). If these do not match, then we iterate over
476 // the children of the visible parent (as was done when computing
477 // `visible_parent_map`), looking for the specific child we currently have and then
478 // have access to the re-exported name.
479 DefPathData::Module(actual_name) |
480 DefPathData::TypeNs(actual_name) if Some(visible_parent) != actual_parent => {
481 self.tcx.item_children(visible_parent)
483 .find(|child| child.def.def_id() == def_id)
484 .map(|child| child.ident.as_str())
485 .unwrap_or_else(|| actual_name.as_str())
488 data.get_opt_name().map(|n| n.as_str()).unwrap_or_else(|| {
489 // Re-exported `extern crate` (#43189).
490 if let DefPathData::CrateRoot = data {
491 self.tcx.original_crate_name(def_id.krate).as_str()
493 Symbol::intern("<unnamed>").as_str()
498 debug!("try_print_visible_item_path: symbol={:?}", symbol);
499 Some(self.path_append(path, &symbol))
503 impl ItemPathPrinter for LocalPathPrinter {
507 self: &mut PrintCx<'_, '_, 'tcx, Self>,
509 substs: Option<&Substs<'tcx>>,
512 self.try_print_visible_item_path(def_id, ns)
513 .unwrap_or_else(|| self.default_print_item_path(def_id, substs, ns))
516 self: &mut PrintCx<'_, '_, 'tcx, Self>,
518 substs: Option<&Substs<'tcx>>,
521 // Always use types for non-local impls, where types are always
522 // available, and filename/line-number is mostly uninteresting.
523 let use_types = !impl_def_id.is_local() || {
524 // Otherwise, use filename/line-number if forced.
525 let force_no_types = FORCE_IMPL_FILENAME_LINE.with(|f| f.get());
530 // If no type info is available, fall back to
531 // pretty printing some span information. This should
532 // only occur very early in the compiler pipeline.
533 // FIXME(eddyb) this should just be using `tcx.def_span(impl_def_id)`
534 let parent_def_id = self.tcx.parent_def_id(impl_def_id).unwrap();
535 let path = self.print_item_path(parent_def_id, None, ns);
536 let span = self.tcx.def_span(impl_def_id);
537 return self.path_append(path, &format!("<impl at {:?}>", span));
540 self.default_print_impl_path(impl_def_id, substs, ns)
543 fn path_crate(self: &mut PrintCx<'_, '_, '_, Self>, cnum: CrateNum) -> Self::Path {
544 if cnum == LOCAL_CRATE {
545 if self.tcx.sess.rust_2018() {
546 // We add the `crate::` keyword on Rust 2018, only when desired.
547 if SHOULD_PREFIX_WITH_CRATE.with(|flag| flag.get()) {
548 return keywords::Crate.name().to_string();
553 self.tcx.crate_name(cnum).to_string()
556 fn path_impl(self: &mut PrintCx<'_, '_, '_, Self>, text: &str) -> Self::Path {
560 self: &mut PrintCx<'_, '_, '_, Self>,
561 mut path: Self::Path,
564 if !path.is_empty() {