]> git.lizzy.rs Git - rust.git/blob - src/librustc/ty/item_path.rs
87859ac00c396f09992274205b8563a2aa47d2c2
[rust.git] / src / librustc / ty / item_path.rs
1 use crate::hir::map::DefPathData;
2 use crate::hir::def_id::{CrateNum, DefId, CRATE_DEF_INDEX, LOCAL_CRATE};
3 use crate::ty::{self, DefIdTree, Ty, TyCtxt};
4 use crate::middle::cstore::{ExternCrate, ExternCrateSource};
5 use ty::print::PrintCx;
6 use syntax::ast;
7 use syntax::symbol::{keywords, Symbol};
8
9 use std::cell::Cell;
10
11 thread_local! {
12     static FORCE_ABSOLUTE: Cell<bool> = Cell::new(false);
13     static FORCE_IMPL_FILENAME_LINE: Cell<bool> = Cell::new(false);
14     static SHOULD_PREFIX_WITH_CRATE: Cell<bool> = Cell::new(false);
15 }
16
17 /// Enforces that item_path_str always returns an absolute path and
18 /// also enables "type-based" impl paths. This is used when building
19 /// symbols that contain types, where we want the crate name to be
20 /// part of the symbol.
21 pub fn with_forced_absolute_paths<F: FnOnce() -> R, R>(f: F) -> R {
22     FORCE_ABSOLUTE.with(|force| {
23         let old = force.get();
24         force.set(true);
25         let result = f();
26         force.set(old);
27         result
28     })
29 }
30
31 /// Force us to name impls with just the filename/line number. We
32 /// normally try to use types. But at some points, notably while printing
33 /// cycle errors, this can result in extra or suboptimal error output,
34 /// so this variable disables that check.
35 pub fn with_forced_impl_filename_line<F: FnOnce() -> R, R>(f: F) -> R {
36     FORCE_IMPL_FILENAME_LINE.with(|force| {
37         let old = force.get();
38         force.set(true);
39         let result = f();
40         force.set(old);
41         result
42     })
43 }
44
45 /// Adds the `crate::` prefix to paths where appropriate.
46 pub fn with_crate_prefix<F: FnOnce() -> R, R>(f: F) -> R {
47     SHOULD_PREFIX_WITH_CRATE.with(|flag| {
48         let old = flag.get();
49         flag.set(true);
50         let result = f();
51         flag.set(old);
52         result
53     })
54 }
55
56 impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
57     /// Returns a string identifying this `DefId`. This string is
58     /// suitable for user output. It is relative to the current crate
59     /// root, unless with_forced_absolute_paths was used.
60     pub fn item_path_str(self, def_id: DefId) -> String {
61         debug!("item_path_str: def_id={:?}", def_id);
62         if FORCE_ABSOLUTE.with(|force| force.get()) {
63             PrintCx::new(self, AbsolutePathPrinter).print_item_path(def_id)
64         } else {
65             PrintCx::new(self, LocalPathPrinter).print_item_path(def_id)
66         }
67     }
68
69     /// Returns a string identifying this local node-id.
70     pub fn node_path_str(self, id: ast::NodeId) -> String {
71         self.item_path_str(self.hir().local_def_id(id))
72     }
73
74     /// Returns a string identifying this def-id. This string is
75     /// suitable for user output. It always begins with a crate identifier.
76     pub fn absolute_item_path_str(self, def_id: DefId) -> String {
77         debug!("absolute_item_path_str: def_id={:?}", def_id);
78         PrintCx::new(self, AbsolutePathPrinter).print_item_path(def_id)
79     }
80 }
81
82 impl<P: ItemPathPrinter> PrintCx<'a, 'gcx, 'tcx, P> {
83     pub fn default_print_item_path(&mut self, def_id: DefId) -> P::Path {
84         debug!("default_print_item_path: def_id={:?}", def_id);
85         let key = self.tcx.def_key(def_id);
86         debug!("default_print_item_path: key={:?}", key);
87         match key.disambiguated_data.data {
88             DefPathData::CrateRoot => {
89                 assert!(key.parent.is_none());
90                 self.path_crate(def_id.krate)
91             }
92
93             DefPathData::Impl => {
94                 self.print_impl_path(def_id)
95             }
96
97             // Unclear if there is any value in distinguishing these.
98             // Probably eventually (and maybe we would even want
99             // finer-grained distinctions, e.g., between enum/struct).
100             data @ DefPathData::Misc |
101             data @ DefPathData::TypeNs(..) |
102             data @ DefPathData::Trait(..) |
103             data @ DefPathData::TraitAlias(..) |
104             data @ DefPathData::AssocTypeInTrait(..) |
105             data @ DefPathData::AssocTypeInImpl(..) |
106             data @ DefPathData::AssocExistentialInImpl(..) |
107             data @ DefPathData::ValueNs(..) |
108             data @ DefPathData::Module(..) |
109             data @ DefPathData::TypeParam(..) |
110             data @ DefPathData::LifetimeParam(..) |
111             data @ DefPathData::ConstParam(..) |
112             data @ DefPathData::EnumVariant(..) |
113             data @ DefPathData::Field(..) |
114             data @ DefPathData::AnonConst |
115             data @ DefPathData::MacroDef(..) |
116             data @ DefPathData::ClosureExpr |
117             data @ DefPathData::ImplTrait |
118             data @ DefPathData::GlobalMetaData(..) => {
119                 let parent_did = self.tcx.parent_def_id(def_id).unwrap();
120                 let path = self.print_item_path(parent_did);
121                 self.path_append(path, &data.as_interned_str().as_symbol().as_str())
122             },
123
124             DefPathData::StructCtor => { // present `X` instead of `X::{{constructor}}`
125                 let parent_def_id = self.tcx.parent_def_id(def_id).unwrap();
126                 self.print_item_path(parent_def_id)
127             }
128         }
129     }
130
131     fn default_print_impl_path(&mut self, impl_def_id: DefId) -> P::Path {
132         debug!("default_print_impl_path: impl_def_id={:?}", impl_def_id);
133         let parent_def_id = self.tcx.parent_def_id(impl_def_id).unwrap();
134
135         // Decide whether to print the parent path for the impl.
136         // Logically, since impls are global, it's never needed, but
137         // users may find it useful. Currently, we omit the parent if
138         // the impl is either in the same module as the self-type or
139         // as the trait.
140         let self_ty = self.tcx.type_of(impl_def_id);
141         let in_self_mod = match characteristic_def_id_of_type(self_ty) {
142             None => false,
143             Some(ty_def_id) => self.tcx.parent_def_id(ty_def_id) == Some(parent_def_id),
144         };
145
146         let impl_trait_ref = self.tcx.impl_trait_ref(impl_def_id);
147         let in_trait_mod = match impl_trait_ref {
148             None => false,
149             Some(trait_ref) => self.tcx.parent_def_id(trait_ref.def_id) == Some(parent_def_id),
150         };
151
152         if !in_self_mod && !in_trait_mod {
153             // If the impl is not co-located with either self-type or
154             // trait-type, then fallback to a format that identifies
155             // the module more clearly.
156             let path = self.print_item_path(parent_def_id);
157             if let Some(trait_ref) = impl_trait_ref {
158                 return self.path_append(path, &format!("<impl {} for {}>", trait_ref, self_ty));
159             } else {
160                 return self.path_append(path, &format!("<impl {}>", self_ty));
161             }
162         }
163
164         // Otherwise, try to give a good form that would be valid language
165         // syntax. Preferably using associated item notation.
166
167         if let Some(trait_ref) = impl_trait_ref {
168             // Trait impls.
169             return self.path_impl(&format!("<{} as {}>", self_ty, trait_ref));
170         }
171
172         // Inherent impls. Try to print `Foo::bar` for an inherent
173         // impl on `Foo`, but fallback to `<Foo>::bar` if self-type is
174         // anything other than a simple path.
175         match self_ty.sty {
176             ty::Adt(adt_def, substs) => {
177                 // FIXME(eddyb) always print without <> here.
178                 if substs.types().next().is_none() { // ignore regions
179                     self.print_item_path(adt_def.did)
180                 } else {
181                     self.path_impl(&format!("<{}>", self_ty))
182                 }
183             }
184
185             ty::Foreign(did) => self.print_item_path(did),
186
187             ty::Bool |
188             ty::Char |
189             ty::Int(_) |
190             ty::Uint(_) |
191             ty::Float(_) |
192             ty::Str => {
193                 self.path_impl(&self_ty.to_string())
194             }
195
196             _ => {
197                 self.path_impl(&format!("<{}>", self_ty))
198             }
199         }
200     }
201 }
202
203 impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
204     /// Returns the `DefId` of `def_id`'s parent in the def tree. If
205     /// this returns `None`, then `def_id` represents a crate root or
206     /// inlined root.
207     pub fn parent_def_id(self, def_id: DefId) -> Option<DefId> {
208         let key = self.def_key(def_id);
209         key.parent.map(|index| DefId { krate: def_id.krate, index: index })
210     }
211 }
212
213 /// As a heuristic, when we see an impl, if we see that the
214 /// 'self type' is a type defined in the same module as the impl,
215 /// we can omit including the path to the impl itself. This
216 /// function tries to find a "characteristic `DefId`" for a
217 /// type. It's just a heuristic so it makes some questionable
218 /// decisions and we may want to adjust it later.
219 pub fn characteristic_def_id_of_type(ty: Ty<'_>) -> Option<DefId> {
220     match ty.sty {
221         ty::Adt(adt_def, _) => Some(adt_def.did),
222
223         ty::Dynamic(data, ..) => data.principal_def_id(),
224
225         ty::Array(subty, _) |
226         ty::Slice(subty) => characteristic_def_id_of_type(subty),
227
228         ty::RawPtr(mt) => characteristic_def_id_of_type(mt.ty),
229
230         ty::Ref(_, ty, _) => characteristic_def_id_of_type(ty),
231
232         ty::Tuple(ref tys) => tys.iter()
233                                    .filter_map(|ty| characteristic_def_id_of_type(ty))
234                                    .next(),
235
236         ty::FnDef(def_id, _) |
237         ty::Closure(def_id, _) |
238         ty::Generator(def_id, _, _) |
239         ty::Foreign(def_id) => Some(def_id),
240
241         ty::Bool |
242         ty::Char |
243         ty::Int(_) |
244         ty::Uint(_) |
245         ty::Str |
246         ty::FnPtr(_) |
247         ty::Projection(_) |
248         ty::Placeholder(..) |
249         ty::UnnormalizedProjection(..) |
250         ty::Param(_) |
251         ty::Opaque(..) |
252         ty::Infer(_) |
253         ty::Bound(..) |
254         ty::Error |
255         ty::GeneratorWitness(..) |
256         ty::Never |
257         ty::Float(_) => None,
258     }
259 }
260
261 /// Unifying Trait for different kinds of item paths we might
262 /// construct. The basic interface is that components get appended.
263 pub trait ItemPathPrinter: Sized {
264     type Path;
265
266     fn print_item_path(self: &mut PrintCx<'_, '_, '_, Self>, def_id: DefId) -> Self::Path {
267         self.default_print_item_path(def_id)
268     }
269     fn print_impl_path(self: &mut PrintCx<'_, '_, '_, Self>, impl_def_id: DefId) -> Self::Path {
270         self.default_print_impl_path(impl_def_id)
271     }
272
273     fn path_crate(self: &mut PrintCx<'_, '_, '_, Self>, cnum: CrateNum) -> Self::Path;
274     fn path_impl(self: &mut PrintCx<'_, '_, '_, Self>, text: &str) -> Self::Path;
275     fn path_append(
276         self: &mut PrintCx<'_, '_, '_, Self>,
277         path: Self::Path,
278         text: &str,
279     ) -> Self::Path;
280 }
281
282 struct AbsolutePathPrinter;
283
284 impl ItemPathPrinter for AbsolutePathPrinter {
285     type Path = String;
286
287     fn path_crate(self: &mut PrintCx<'_, '_, '_, Self>, cnum: CrateNum) -> Self::Path {
288         self.tcx.original_crate_name(cnum).to_string()
289     }
290     fn path_impl(self: &mut PrintCx<'_, '_, '_, Self>, text: &str) -> Self::Path {
291         text.to_string()
292     }
293     fn path_append(
294         self: &mut PrintCx<'_, '_, '_, Self>,
295         mut path: Self::Path,
296         text: &str,
297     ) -> Self::Path {
298         if !path.is_empty() {
299             path.push_str("::");
300         }
301         path.push_str(text);
302         path
303     }
304 }
305
306 struct LocalPathPrinter;
307
308 impl LocalPathPrinter {
309     /// If possible, this returns a global path resolving to `def_id` that is visible
310     /// from at least one local module and returns true. If the crate defining `def_id` is
311     /// declared with an `extern crate`, the path is guaranteed to use the `extern crate`.
312     fn try_print_visible_item_path(
313         self: &mut PrintCx<'_, '_, '_, Self>,
314         def_id: DefId,
315     ) -> Option<<Self as ItemPathPrinter>::Path> {
316         debug!("try_print_visible_item_path: def_id={:?}", def_id);
317
318         // If `def_id` is a direct or injected extern crate, return the
319         // path to the crate followed by the path to the item within the crate.
320         if def_id.index == CRATE_DEF_INDEX {
321             let cnum = def_id.krate;
322
323             if cnum == LOCAL_CRATE {
324                 return Some(self.path_crate(cnum));
325             }
326
327             // In local mode, when we encounter a crate other than
328             // LOCAL_CRATE, execution proceeds in one of two ways:
329             //
330             // 1. for a direct dependency, where user added an
331             //    `extern crate` manually, we put the `extern
332             //    crate` as the parent. So you wind up with
333             //    something relative to the current crate.
334             // 2. for an extern inferred from a path or an indirect crate,
335             //    where there is no explicit `extern crate`, we just prepend
336             //    the crate name.
337             match *self.tcx.extern_crate(def_id) {
338                 Some(ExternCrate {
339                     src: ExternCrateSource::Extern(def_id),
340                     direct: true,
341                     span,
342                     ..
343                 }) => {
344                     debug!("try_print_visible_item_path: def_id={:?}", def_id);
345                     let path = if !span.is_dummy() {
346                         self.print_item_path(def_id)
347                     } else {
348                         self.path_crate(cnum)
349                     };
350                     return Some(path);
351                 }
352                 None => {
353                     return Some(self.path_crate(cnum));
354                 }
355                 _ => {},
356             }
357         }
358
359         if def_id.is_local() {
360             return None;
361         }
362
363         let visible_parent_map = self.tcx.visible_parent_map(LOCAL_CRATE);
364
365         let mut cur_def_key = self.tcx.def_key(def_id);
366         debug!("try_print_visible_item_path: cur_def_key={:?}", cur_def_key);
367
368         // For a UnitStruct or TupleStruct we want the name of its parent rather than <unnamed>.
369         if let DefPathData::StructCtor = cur_def_key.disambiguated_data.data {
370             let parent = DefId {
371                 krate: def_id.krate,
372                 index: cur_def_key.parent.expect("DefPathData::StructCtor missing a parent"),
373             };
374
375             cur_def_key = self.tcx.def_key(parent);
376         }
377
378         let visible_parent = visible_parent_map.get(&def_id).cloned()?;
379         let path = self.try_print_visible_item_path(visible_parent)?;
380         let actual_parent = self.tcx.parent(def_id);
381
382         let data = cur_def_key.disambiguated_data.data;
383         debug!(
384             "try_print_visible_item_path: data={:?} visible_parent={:?} actual_parent={:?}",
385             data, visible_parent, actual_parent,
386         );
387
388         let symbol = match data {
389             // In order to output a path that could actually be imported (valid and visible),
390             // we need to handle re-exports correctly.
391             //
392             // For example, take `std::os::unix::process::CommandExt`, this trait is actually
393             // defined at `std::sys::unix::ext::process::CommandExt` (at time of writing).
394             //
395             // `std::os::unix` rexports the contents of `std::sys::unix::ext`. `std::sys` is
396             // private so the "true" path to `CommandExt` isn't accessible.
397             //
398             // In this case, the `visible_parent_map` will look something like this:
399             //
400             // (child) -> (parent)
401             // `std::sys::unix::ext::process::CommandExt` -> `std::sys::unix::ext::process`
402             // `std::sys::unix::ext::process` -> `std::sys::unix::ext`
403             // `std::sys::unix::ext` -> `std::os`
404             //
405             // This is correct, as the visible parent of `std::sys::unix::ext` is in fact
406             // `std::os`.
407             //
408             // When printing the path to `CommandExt` and looking at the `cur_def_key` that
409             // corresponds to `std::sys::unix::ext`, we would normally print `ext` and then go
410             // to the parent - resulting in a mangled path like
411             // `std::os::ext::process::CommandExt`.
412             //
413             // Instead, we must detect that there was a re-export and instead print `unix`
414             // (which is the name `std::sys::unix::ext` was re-exported as in `std::os`). To
415             // do this, we compare the parent of `std::sys::unix::ext` (`std::sys::unix`) with
416             // the visible parent (`std::os`). If these do not match, then we iterate over
417             // the children of the visible parent (as was done when computing
418             // `visible_parent_map`), looking for the specific child we currently have and then
419             // have access to the re-exported name.
420             DefPathData::Module(actual_name) |
421             DefPathData::TypeNs(actual_name) if Some(visible_parent) != actual_parent => {
422                 self.tcx.item_children(visible_parent)
423                     .iter()
424                     .find(|child| child.def.def_id() == def_id)
425                     .map(|child| child.ident.as_str())
426                     .unwrap_or_else(|| actual_name.as_str())
427             }
428             _ => {
429                 data.get_opt_name().map(|n| n.as_str()).unwrap_or_else(|| {
430                     // Re-exported `extern crate` (#43189).
431                     if let DefPathData::CrateRoot = data {
432                         self.tcx.original_crate_name(def_id.krate).as_str()
433                     } else {
434                         Symbol::intern("<unnamed>").as_str()
435                     }
436                 })
437             },
438         };
439         debug!("try_print_visible_item_path: symbol={:?}", symbol);
440         Some(self.path_append(path, &symbol))
441     }
442 }
443
444 impl ItemPathPrinter for LocalPathPrinter {
445     type Path = String;
446
447     fn print_item_path(self: &mut PrintCx<'_, '_, '_, Self>, def_id: DefId) -> Self::Path {
448         self.try_print_visible_item_path(def_id)
449             .unwrap_or_else(|| self.default_print_item_path(def_id))
450     }
451     fn print_impl_path(self: &mut PrintCx<'_, '_, '_, Self>, impl_def_id: DefId) -> Self::Path {
452         // Always use types for non-local impls, where types are always
453         // available, and filename/line-number is mostly uninteresting.
454         let use_types = !impl_def_id.is_local() || {
455             // Otherwise, use filename/line-number if forced.
456             let force_no_types = FORCE_IMPL_FILENAME_LINE.with(|f| f.get());
457             !force_no_types
458         };
459
460         if !use_types {
461             // If no type info is available, fall back to
462             // pretty printing some span information. This should
463             // only occur very early in the compiler pipeline.
464             // FIXME(eddyb) this should just be using `tcx.def_span(impl_def_id)`
465             let parent_def_id = self.tcx.parent_def_id(impl_def_id).unwrap();
466             let path = self.print_item_path(parent_def_id);
467             let span = self.tcx.def_span(impl_def_id);
468             return self.path_append(path, &format!("<impl at {:?}>", span));
469         }
470
471         self.default_print_impl_path(impl_def_id)
472     }
473
474     fn path_crate(self: &mut PrintCx<'_, '_, '_, Self>, cnum: CrateNum) -> Self::Path {
475         if cnum == LOCAL_CRATE {
476             if self.tcx.sess.rust_2018() {
477                 // We add the `crate::` keyword on Rust 2018, only when desired.
478                 if SHOULD_PREFIX_WITH_CRATE.with(|flag| flag.get()) {
479                     return keywords::Crate.name().to_string();
480                 }
481             }
482             String::new()
483         } else {
484             self.tcx.crate_name(cnum).to_string()
485         }
486     }
487     fn path_impl(self: &mut PrintCx<'_, '_, '_, Self>, text: &str) -> Self::Path {
488         text.to_string()
489     }
490     fn path_append(
491         self: &mut PrintCx<'_, '_, '_, Self>,
492         mut path: Self::Path,
493         text: &str,
494     ) -> Self::Path {
495         if !path.is_empty() {
496             path.push_str("::");
497         }
498         path.push_str(text);
499         path
500     }
501 }