1 // Copyright 2012-2015 The Rust Project Developers. See the COPYRIGHT
2 // file at the top-level directory of this distribution and at
3 // http://rust-lang.org/COPYRIGHT.
5 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8 // option. This file may not be copied, modified, or distributed
9 // except according to those terms.
11 use hir::map::DefPathData;
12 use hir::def_id::{CrateNum, DefId, CRATE_DEF_INDEX, LOCAL_CRATE};
13 use ty::{self, DefIdTree, Ty, TyCtxt};
14 use middle::cstore::{ExternCrate, ExternCrateSource};
16 use syntax::symbol::{keywords, LocalInternedString, Symbol};
17 use syntax_pos::edition::Edition;
23 static FORCE_ABSOLUTE: Cell<bool> = Cell::new(false);
24 static FORCE_IMPL_FILENAME_LINE: Cell<bool> = Cell::new(false);
25 static SHOULD_PREFIX_WITH_CRATE: Cell<bool> = Cell::new(false);
28 /// Enforces that item_path_str always returns an absolute path and
29 /// also enables "type-based" impl paths. This is used when building
30 /// symbols that contain types, where we want the crate name to be
31 /// part of the symbol.
32 pub fn with_forced_absolute_paths<F: FnOnce() -> R, R>(f: F) -> R {
33 FORCE_ABSOLUTE.with(|force| {
34 let old = force.get();
42 /// Force us to name impls with just the filename/line number. We
43 /// normally try to use types. But at some points, notably while printing
44 /// cycle errors, this can result in extra or suboptimal error output,
45 /// so this variable disables that check.
46 pub fn with_forced_impl_filename_line<F: FnOnce() -> R, R>(f: F) -> R {
47 FORCE_IMPL_FILENAME_LINE.with(|force| {
48 let old = force.get();
56 /// Add the `crate::` prefix to paths where appropriate.
57 pub fn with_crate_prefix<F: FnOnce() -> R, R>(f: F) -> R {
58 SHOULD_PREFIX_WITH_CRATE.with(|flag| {
67 impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
68 /// Returns a string identifying this def-id. This string is
69 /// suitable for user output. It is relative to the current crate
70 /// root, unless with_forced_absolute_paths was used.
71 pub fn item_path_str(self, def_id: DefId) -> String {
72 let mode = FORCE_ABSOLUTE.with(|force| {
79 let mut buffer = LocalPathBuffer::new(mode);
80 debug!("item_path_str: buffer={:?} def_id={:?}", buffer, def_id);
81 self.push_item_path(&mut buffer, def_id, false);
85 /// Returns a string identifying this local node-id.
86 pub fn node_path_str(self, id: ast::NodeId) -> String {
87 self.item_path_str(self.hir.local_def_id(id))
90 /// Returns a string identifying this def-id. This string is
91 /// suitable for user output. It always begins with a crate identifier.
92 pub fn absolute_item_path_str(self, def_id: DefId) -> String {
93 let mut buffer = LocalPathBuffer::new(RootMode::Absolute);
94 debug!("absolute_item_path_str: buffer={:?} def_id={:?}", buffer, def_id);
95 self.push_item_path(&mut buffer, def_id, false);
99 /// Returns the "path" to a particular crate. This can proceed in
100 /// various ways, depending on the `root_mode` of the `buffer`.
101 /// (See `RootMode` enum for more details.)
103 /// `pushed_prelude_crate` argument should be `true` when the buffer
104 /// has had a prelude crate pushed to it. If this is the case, then
105 /// we do not want to prepend `crate::` (as that would not be a valid
107 pub fn push_krate_path<T>(self, buffer: &mut T, cnum: CrateNum, pushed_prelude_crate: bool)
108 where T: ItemPathBuffer + Debug
111 "push_krate_path: buffer={:?} cnum={:?} LOCAL_CRATE={:?}",
112 buffer, cnum, LOCAL_CRATE
114 match *buffer.root_mode() {
116 // In local mode, when we encounter a crate other than
117 // LOCAL_CRATE, execution proceeds in one of two ways:
119 // 1. for a direct dependency, where user added an
120 // `extern crate` manually, we put the `extern
121 // crate` as the parent. So you wind up with
122 // something relative to the current crate.
123 // 2. for an extern inferred from a path or an indirect crate,
124 // where there is no explicit `extern crate`, we just prepend
127 // Returns `None` for the local crate.
128 if cnum != LOCAL_CRATE {
129 let opt_extern_crate = self.extern_crate(cnum.as_def_id());
130 if let Some(ExternCrate {
131 src: ExternCrateSource::Extern(def_id),
134 }) = *opt_extern_crate
136 debug!("push_krate_path: def_id={:?}", def_id);
137 self.push_item_path(buffer, def_id, pushed_prelude_crate);
139 let name = self.crate_name(cnum).as_str();
140 debug!("push_krate_path: name={:?}", name);
143 } else if self.sess.edition() == Edition::Edition2018 && !pushed_prelude_crate {
144 SHOULD_PREFIX_WITH_CRATE.with(|flag| {
145 // We only add the `crate::` keyword where appropriate. In particular,
146 // when we've not previously pushed a prelude crate to this path.
148 buffer.push(&keywords::Crate.name().as_str())
153 RootMode::Absolute => {
154 // In absolute mode, just write the crate name
156 let name = self.original_crate_name(cnum).as_str();
157 debug!("push_krate_path: original_name={:?}", name);
163 /// If possible, this pushes a global path resolving to `external_def_id` that is visible
164 /// from at least one local module and returns true. If the crate defining `external_def_id` is
165 /// declared with an `extern crate`, the path is guaranteed to use the `extern crate`.
166 pub fn try_push_visible_item_path<T>(
169 external_def_id: DefId,
170 pushed_prelude_crate: bool,
172 where T: ItemPathBuffer + Debug
175 "try_push_visible_item_path: buffer={:?} external_def_id={:?}",
176 buffer, external_def_id
178 let visible_parent_map = self.visible_parent_map(LOCAL_CRATE);
180 let (mut cur_def, mut cur_path) = (external_def_id, Vec::<LocalInternedString>::new());
183 "try_push_visible_item_path: cur_def={:?} cur_path={:?} CRATE_DEF_INDEX={:?}",
184 cur_def, cur_path, CRATE_DEF_INDEX,
186 // If `cur_def` is a direct or injected extern crate, push the path to the crate
187 // followed by the path to the item within the crate and return.
188 if cur_def.index == CRATE_DEF_INDEX {
189 match *self.extern_crate(cur_def) {
191 src: ExternCrateSource::Extern(def_id),
195 debug!("try_push_visible_item_path: def_id={:?}", def_id);
196 self.push_item_path(buffer, def_id, pushed_prelude_crate);
197 cur_path.iter().rev().for_each(|segment| buffer.push(&segment));
201 buffer.push(&self.crate_name(cur_def.krate).as_str());
202 cur_path.iter().rev().for_each(|segment| buffer.push(&segment));
209 let mut cur_def_key = self.def_key(cur_def);
210 debug!("try_push_visible_item_path: cur_def_key={:?}", cur_def_key);
212 // For a UnitStruct or TupleStruct we want the name of its parent rather than <unnamed>.
213 if let DefPathData::StructCtor = cur_def_key.disambiguated_data.data {
215 krate: cur_def.krate,
216 index: cur_def_key.parent.expect("DefPathData::StructCtor missing a parent"),
219 cur_def_key = self.def_key(parent);
222 let visible_parent = visible_parent_map.get(&cur_def).cloned();
223 let actual_parent = self.parent(cur_def);
225 "try_push_visible_item_path: visible_parent={:?} actual_parent={:?}",
226 visible_parent, actual_parent,
229 let data = cur_def_key.disambiguated_data.data;
230 let symbol = match data {
231 // In order to output a path that could actually be imported (valid and visible),
232 // we need to handle re-exports correctly.
234 // For example, take `std::os::unix::process::CommandExt`, this trait is actually
235 // defined at `std::sys::unix::ext::process::CommandExt` (at time of writing).
237 // `std::os::unix` rexports the contents of `std::sys::unix::ext`. `std::sys` is
238 // private so the "true" path to `CommandExt` isn't accessible.
240 // In this case, the `visible_parent_map` will look something like this:
242 // (child) -> (parent)
243 // `std::sys::unix::ext::process::CommandExt` -> `std::sys::unix::ext::process`
244 // `std::sys::unix::ext::process` -> `std::sys::unix::ext`
245 // `std::sys::unix::ext` -> `std::os`
247 // This is correct, as the visible parent of `std::sys::unix::ext` is in fact
250 // When printing the path to `CommandExt` and looking at the `cur_def_key` that
251 // corresponds to `std::sys::unix::ext`, we would normally print `ext` and then go
252 // to the parent - resulting in a mangled path like
253 // `std::os::ext::process::CommandExt`.
255 // Instead, we must detect that there was a re-export and instead print `unix`
256 // (which is the name `std::sys::unix::ext` was re-exported as in `std::os`). To
257 // do this, we compare the parent of `std::sys::unix::ext` (`std::sys::unix`) with
258 // the visible parent (`std::os`). If these do not match, then we iterate over
259 // the children of the visible parent (as was done when computing
260 // `visible_parent_map`), looking for the specific child we currently have and then
261 // have access to the re-exported name.
262 DefPathData::Module(module_name) if visible_parent != actual_parent => {
263 let mut name: Option<ast::Ident> = None;
264 if let Some(visible_parent) = visible_parent {
265 for child in self.item_children(visible_parent).iter() {
266 if child.def.def_id() == cur_def {
267 name = Some(child.ident);
271 name.map(|n| n.as_str()).unwrap_or(module_name.as_str())
274 data.get_opt_name().map(|n| n.as_str()).unwrap_or_else(|| {
275 // Re-exported `extern crate` (#43189).
276 if let DefPathData::CrateRoot = data {
277 self.original_crate_name(cur_def.krate).as_str()
279 Symbol::intern("<unnamed>").as_str()
284 debug!("try_push_visible_item_path: symbol={:?}", symbol);
285 cur_path.push(symbol);
287 match visible_parent {
288 Some(def) => cur_def = def,
289 None => return false,
294 pub fn push_item_path<T>(self, buffer: &mut T, def_id: DefId, pushed_prelude_crate: bool)
295 where T: ItemPathBuffer + Debug
298 "push_item_path: buffer={:?} def_id={:?} pushed_prelude_crate={:?}",
299 buffer, def_id, pushed_prelude_crate
301 match *buffer.root_mode() {
302 RootMode::Local if !def_id.is_local() =>
303 if self.try_push_visible_item_path(buffer, def_id, pushed_prelude_crate) { return },
307 let key = self.def_key(def_id);
308 debug!("push_item_path: key={:?}", key);
309 match key.disambiguated_data.data {
310 DefPathData::CrateRoot => {
311 assert!(key.parent.is_none());
312 self.push_krate_path(buffer, def_id.krate, pushed_prelude_crate);
315 DefPathData::Impl => {
316 self.push_impl_path(buffer, def_id, pushed_prelude_crate);
319 // Unclear if there is any value in distinguishing these.
320 // Probably eventually (and maybe we would even want
321 // finer-grained distinctions, e.g. between enum/struct).
322 data @ DefPathData::Misc |
323 data @ DefPathData::TypeNs(..) |
324 data @ DefPathData::Trait(..) |
325 data @ DefPathData::AssocTypeInTrait(..) |
326 data @ DefPathData::AssocTypeInImpl(..) |
327 data @ DefPathData::AssocExistentialInImpl(..) |
328 data @ DefPathData::ValueNs(..) |
329 data @ DefPathData::Module(..) |
330 data @ DefPathData::TypeParam(..) |
331 data @ DefPathData::LifetimeParam(..) |
332 data @ DefPathData::EnumVariant(..) |
333 data @ DefPathData::Field(..) |
334 data @ DefPathData::AnonConst |
335 data @ DefPathData::MacroDef(..) |
336 data @ DefPathData::ClosureExpr |
337 data @ DefPathData::ImplTrait |
338 data @ DefPathData::GlobalMetaData(..) => {
339 let parent_did = self.parent_def_id(def_id).unwrap();
341 // Keep track of whether we are one recursion away from the `CrateRoot` and
342 // pushing the name of a prelude crate. If we are, we'll want to know this when
343 // printing the `CrateRoot` so we don't prepend a `crate::` to paths.
344 let mut is_prelude_crate = false;
345 if let DefPathData::CrateRoot = self.def_key(parent_did).disambiguated_data.data {
346 if self.extern_prelude.contains_key(&data.as_interned_str().as_symbol()) {
347 is_prelude_crate = true;
352 buffer, parent_did, pushed_prelude_crate || is_prelude_crate
354 buffer.push(&data.as_interned_str().as_symbol().as_str());
357 DefPathData::StructCtor => { // present `X` instead of `X::{{constructor}}`
358 let parent_def_id = self.parent_def_id(def_id).unwrap();
359 self.push_item_path(buffer, parent_def_id, pushed_prelude_crate);
364 fn push_impl_path<T>(
368 pushed_prelude_crate: bool,
370 where T: ItemPathBuffer + Debug
372 debug!("push_impl_path: buffer={:?} impl_def_id={:?}", buffer, impl_def_id);
373 let parent_def_id = self.parent_def_id(impl_def_id).unwrap();
375 // Always use types for non-local impls, where types are always
376 // available, and filename/line-number is mostly uninteresting.
377 let use_types = !impl_def_id.is_local() || {
378 // Otherwise, use filename/line-number if forced.
379 let force_no_types = FORCE_IMPL_FILENAME_LINE.with(|f| f.get());
384 return self.push_impl_path_fallback(buffer, impl_def_id, pushed_prelude_crate);
387 // Decide whether to print the parent path for the impl.
388 // Logically, since impls are global, it's never needed, but
389 // users may find it useful. Currently, we omit the parent if
390 // the impl is either in the same module as the self-type or
392 let self_ty = self.type_of(impl_def_id);
393 let in_self_mod = match characteristic_def_id_of_type(self_ty) {
395 Some(ty_def_id) => self.parent_def_id(ty_def_id) == Some(parent_def_id),
398 let impl_trait_ref = self.impl_trait_ref(impl_def_id);
399 let in_trait_mod = match impl_trait_ref {
401 Some(trait_ref) => self.parent_def_id(trait_ref.def_id) == Some(parent_def_id),
404 if !in_self_mod && !in_trait_mod {
405 // If the impl is not co-located with either self-type or
406 // trait-type, then fallback to a format that identifies
407 // the module more clearly.
408 self.push_item_path(buffer, parent_def_id, pushed_prelude_crate);
409 if let Some(trait_ref) = impl_trait_ref {
410 buffer.push(&format!("<impl {} for {}>", trait_ref, self_ty));
412 buffer.push(&format!("<impl {}>", self_ty));
417 // Otherwise, try to give a good form that would be valid language
418 // syntax. Preferably using associated item notation.
420 if let Some(trait_ref) = impl_trait_ref {
422 buffer.push(&format!("<{} as {}>", self_ty, trait_ref));
426 // Inherent impls. Try to print `Foo::bar` for an inherent
427 // impl on `Foo`, but fallback to `<Foo>::bar` if self-type is
428 // anything other than a simple path.
430 ty::Adt(adt_def, substs) => {
431 if substs.types().next().is_none() { // ignore regions
432 self.push_item_path(buffer, adt_def.did, pushed_prelude_crate);
434 buffer.push(&format!("<{}>", self_ty));
438 ty::Foreign(did) => self.push_item_path(buffer, did, pushed_prelude_crate),
446 buffer.push(&self_ty.to_string());
450 buffer.push(&format!("<{}>", self_ty));
455 fn push_impl_path_fallback<T>(
459 pushed_prelude_crate: bool,
461 where T: ItemPathBuffer + Debug
463 // If no type info is available, fall back to
464 // pretty printing some span information. This should
465 // only occur very early in the compiler pipeline.
466 let parent_def_id = self.parent_def_id(impl_def_id).unwrap();
467 self.push_item_path(buffer, parent_def_id, pushed_prelude_crate);
468 let node_id = self.hir.as_local_node_id(impl_def_id).unwrap();
469 let item = self.hir.expect_item(node_id);
470 let span_str = self.sess.source_map().span_to_string(item.span);
471 buffer.push(&format!("<impl at {}>", span_str));
474 /// Returns the def-id of `def_id`'s parent in the def tree. If
475 /// this returns `None`, then `def_id` represents a crate root or
477 pub fn parent_def_id(self, def_id: DefId) -> Option<DefId> {
478 let key = self.def_key(def_id);
479 key.parent.map(|index| DefId { krate: def_id.krate, index: index })
483 /// As a heuristic, when we see an impl, if we see that the
484 /// 'self-type' is a type defined in the same module as the impl,
485 /// we can omit including the path to the impl itself. This
486 /// function tries to find a "characteristic def-id" for a
487 /// type. It's just a heuristic so it makes some questionable
488 /// decisions and we may want to adjust it later.
489 pub fn characteristic_def_id_of_type(ty: Ty<'_>) -> Option<DefId> {
491 ty::Adt(adt_def, _) => Some(adt_def.did),
493 ty::Dynamic(data, ..) => Some(data.principal().def_id()),
495 ty::Array(subty, _) |
496 ty::Slice(subty) => characteristic_def_id_of_type(subty),
498 ty::RawPtr(mt) => characteristic_def_id_of_type(mt.ty),
500 ty::Ref(_, ty, _) => characteristic_def_id_of_type(ty),
502 ty::Tuple(ref tys) => tys.iter()
503 .filter_map(|ty| characteristic_def_id_of_type(ty))
506 ty::FnDef(def_id, _) |
507 ty::Closure(def_id, _) |
508 ty::Generator(def_id, _, _) |
509 ty::Foreign(def_id) => Some(def_id),
518 ty::UnnormalizedProjection(..) |
524 ty::GeneratorWitness(..) |
526 ty::Float(_) => None,
530 /// Unifying Trait for different kinds of item paths we might
531 /// construct. The basic interface is that components get pushed: the
532 /// instance can also customize how we handle the root of a crate.
533 pub trait ItemPathBuffer {
534 fn root_mode(&self) -> &RootMode;
535 fn push(&mut self, text: &str);
540 /// Try to make a path relative to the local crate. In
541 /// particular, local paths have no prefix, and if the path comes
542 /// from an extern crate, start with the path to the `extern
543 /// crate` declaration.
546 /// Always prepend the crate name to the path, forming an absolute
547 /// path from within a given set of crates.
552 struct LocalPathBuffer {
557 impl LocalPathBuffer {
558 fn new(root_mode: RootMode) -> LocalPathBuffer {
565 fn into_string(self) -> String {
570 impl ItemPathBuffer for LocalPathBuffer {
571 fn root_mode(&self) -> &RootMode {
575 fn push(&mut self, text: &str) {
576 if !self.str.is_empty() {
577 self.str.push_str("::");
579 self.str.push_str(text);