]> git.lizzy.rs Git - rust.git/blob - src/librustc/ty/item_path.rs
d9a8deb80e46ac1a798937926e5121c571b3c547
[rust.git] / src / librustc / ty / item_path.rs
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};
8 use syntax::ast;
9 use syntax::symbol::{keywords, Symbol};
10
11 use std::cell::Cell;
12
13 thread_local! {
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);
17 }
18
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();
26         force.set(true);
27         let result = f();
28         force.set(old);
29         result
30     })
31 }
32
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();
40         force.set(true);
41         let result = f();
42         force.set(old);
43         result
44     })
45 }
46
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| {
50         let old = flag.get();
51         flag.set(true);
52         let result = f();
53         flag.set(old);
54         result
55     })
56 }
57
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,
69
70             DefPathData::MacroDef(..) => Namespace::MacroNS,
71
72             _ => Namespace::TypeNS,
73         }
74     }
75
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(
80         self,
81         def_id: DefId,
82         substs: Option<&Substs<'tcx>>,
83         ns: Namespace,
84     ) -> String {
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)
88         } else {
89             PrintCx::new(self, LocalPathPrinter).print_item_path(def_id, substs, ns)
90         }
91     }
92
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)
99     }
100
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))
104     }
105
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)
112     }
113 }
114
115 impl<P: ItemPathPrinter> PrintCx<'a, 'gcx, 'tcx, P> {
116     pub fn default_print_item_path(
117         &mut self,
118         def_id: DefId,
119         substs: Option<&Substs<'tcx>>,
120         ns: Namespace,
121     ) -> P::Path {
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)
129             }
130
131             DefPathData::Impl => {
132                 self.print_impl_path(def_id, substs, ns)
133             }
134
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())
160             },
161
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)
165             }
166         }
167     }
168
169     fn default_print_impl_path(
170         &mut self,
171         impl_def_id: DefId,
172         substs: Option<&Substs<'tcx>>,
173         ns: Namespace,
174     ) -> P::Path {
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();
177
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
182         // as the trait.
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);
186         }
187         let in_self_mod = match characteristic_def_id_of_type(self_ty) {
188             None => false,
189             Some(ty_def_id) => self.tcx.parent_def_id(ty_def_id) == Some(parent_def_id),
190         };
191
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);
195         }
196         let in_trait_mod = match impl_trait_ref {
197             None => false,
198             Some(trait_ref) => self.tcx.parent_def_id(trait_ref.def_id) == Some(parent_def_id),
199         };
200
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));
208             } else {
209                 return self.path_append(path, &format!("<impl {}>", self_ty));
210             }
211         }
212
213         // Otherwise, try to give a good form that would be valid language
214         // syntax. Preferably using associated item notation.
215
216         if let Some(trait_ref) = impl_trait_ref {
217             // Trait impls.
218             return self.path_impl(&format!("<{} as {}>", self_ty, trait_ref));
219         }
220
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.
224         match self_ty.sty {
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();
230                 self.path_impl(&s)
231             }
232
233             ty::Foreign(did) => self.print_item_path(did, None, ns),
234
235             ty::Bool |
236             ty::Char |
237             ty::Int(_) |
238             ty::Uint(_) |
239             ty::Float(_) |
240             ty::Str => {
241                 self.path_impl(&self_ty.to_string())
242             }
243
244             _ => {
245                 self.path_impl(&format!("<{}>", self_ty))
246             }
247         }
248     }
249 }
250
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
254     /// inlined root.
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 })
258     }
259 }
260
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> {
268     match ty.sty {
269         ty::Adt(adt_def, _) => Some(adt_def.did),
270
271         ty::Dynamic(data, ..) => data.principal_def_id(),
272
273         ty::Array(subty, _) |
274         ty::Slice(subty) => characteristic_def_id_of_type(subty),
275
276         ty::RawPtr(mt) => characteristic_def_id_of_type(mt.ty),
277
278         ty::Ref(_, ty, _) => characteristic_def_id_of_type(ty),
279
280         ty::Tuple(ref tys) => tys.iter()
281                                    .filter_map(|ty| characteristic_def_id_of_type(ty))
282                                    .next(),
283
284         ty::FnDef(def_id, _) |
285         ty::Closure(def_id, _) |
286         ty::Generator(def_id, _, _) |
287         ty::Foreign(def_id) => Some(def_id),
288
289         ty::Bool |
290         ty::Char |
291         ty::Int(_) |
292         ty::Uint(_) |
293         ty::Str |
294         ty::FnPtr(_) |
295         ty::Projection(_) |
296         ty::Placeholder(..) |
297         ty::UnnormalizedProjection(..) |
298         ty::Param(_) |
299         ty::Opaque(..) |
300         ty::Infer(_) |
301         ty::Bound(..) |
302         ty::Error |
303         ty::GeneratorWitness(..) |
304         ty::Never |
305         ty::Float(_) => None,
306     }
307 }
308
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 {
312     type Path;
313
314     fn print_item_path(
315         self: &mut PrintCx<'_, '_, 'tcx, Self>,
316         def_id: DefId,
317         substs: Option<&Substs<'tcx>>,
318         ns: Namespace,
319     ) -> Self::Path {
320         self.default_print_item_path(def_id, substs, ns)
321     }
322     fn print_impl_path(
323         self: &mut PrintCx<'_, '_, 'tcx, Self>,
324         impl_def_id: DefId,
325         substs: Option<&Substs<'tcx>>,
326         ns: Namespace,
327     ) -> Self::Path {
328         self.default_print_impl_path(impl_def_id, substs, ns)
329     }
330
331     fn path_crate(self: &mut PrintCx<'_, '_, '_, Self>, cnum: CrateNum) -> Self::Path;
332     fn path_impl(self: &mut PrintCx<'_, '_, '_, Self>, text: &str) -> Self::Path;
333     fn path_append(
334         self: &mut PrintCx<'_, '_, '_, Self>,
335         path: Self::Path,
336         text: &str,
337     ) -> Self::Path;
338 }
339
340 struct AbsolutePathPrinter;
341
342 impl ItemPathPrinter for AbsolutePathPrinter {
343     type Path = String;
344
345     fn path_crate(self: &mut PrintCx<'_, '_, '_, Self>, cnum: CrateNum) -> Self::Path {
346         self.tcx.original_crate_name(cnum).to_string()
347     }
348     fn path_impl(self: &mut PrintCx<'_, '_, '_, Self>, text: &str) -> Self::Path {
349         text.to_string()
350     }
351     fn path_append(
352         self: &mut PrintCx<'_, '_, '_, Self>,
353         mut path: Self::Path,
354         text: &str,
355     ) -> Self::Path {
356         if !path.is_empty() {
357             path.push_str("::");
358         }
359         path.push_str(text);
360         path
361     }
362 }
363
364 struct LocalPathPrinter;
365
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>,
372         def_id: DefId,
373         ns: Namespace,
374     ) -> Option<<Self as ItemPathPrinter>::Path> {
375         debug!("try_print_visible_item_path: def_id={:?}", def_id);
376
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;
381
382             if cnum == LOCAL_CRATE {
383                 return Some(self.path_crate(cnum));
384             }
385
386             // In local mode, when we encounter a crate other than
387             // LOCAL_CRATE, execution proceeds in one of two ways:
388             //
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
395             //    the crate name.
396             match *self.tcx.extern_crate(def_id) {
397                 Some(ExternCrate {
398                     src: ExternCrateSource::Extern(def_id),
399                     direct: true,
400                     span,
401                     ..
402                 }) => {
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)
406                     } else {
407                         self.path_crate(cnum)
408                     };
409                     return Some(path);
410                 }
411                 None => {
412                     return Some(self.path_crate(cnum));
413                 }
414                 _ => {},
415             }
416         }
417
418         if def_id.is_local() {
419             return None;
420         }
421
422         let visible_parent_map = self.tcx.visible_parent_map(LOCAL_CRATE);
423
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);
426
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 {
429             let parent = DefId {
430                 krate: def_id.krate,
431                 index: cur_def_key.parent.expect("DefPathData::StructCtor missing a parent"),
432             };
433
434             cur_def_key = self.tcx.def_key(parent);
435         }
436
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);
440
441         let data = cur_def_key.disambiguated_data.data;
442         debug!(
443             "try_print_visible_item_path: data={:?} visible_parent={:?} actual_parent={:?}",
444             data, visible_parent, actual_parent,
445         );
446
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.
450             //
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).
453             //
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.
456             //
457             // In this case, the `visible_parent_map` will look something like this:
458             //
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`
463             //
464             // This is correct, as the visible parent of `std::sys::unix::ext` is in fact
465             // `std::os`.
466             //
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`.
471             //
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)
482                     .iter()
483                     .find(|child| child.def.def_id() == def_id)
484                     .map(|child| child.ident.as_str())
485                     .unwrap_or_else(|| actual_name.as_str())
486             }
487             _ => {
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()
492                     } else {
493                         Symbol::intern("<unnamed>").as_str()
494                     }
495                 })
496             },
497         };
498         debug!("try_print_visible_item_path: symbol={:?}", symbol);
499         Some(self.path_append(path, &symbol))
500     }
501 }
502
503 impl ItemPathPrinter for LocalPathPrinter {
504     type Path = String;
505
506     fn print_item_path(
507         self: &mut PrintCx<'_, '_, 'tcx, Self>,
508         def_id: DefId,
509         substs: Option<&Substs<'tcx>>,
510         ns: Namespace,
511     ) -> Self::Path {
512         self.try_print_visible_item_path(def_id, ns)
513             .unwrap_or_else(|| self.default_print_item_path(def_id, substs, ns))
514     }
515     fn print_impl_path(
516         self: &mut PrintCx<'_, '_, 'tcx, Self>,
517         impl_def_id: DefId,
518         substs: Option<&Substs<'tcx>>,
519         ns: Namespace,
520     ) -> Self::Path {
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());
526             !force_no_types
527         };
528
529         if !use_types {
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));
538         }
539
540         self.default_print_impl_path(impl_def_id, substs, ns)
541     }
542
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();
549                 }
550             }
551             String::new()
552         } else {
553             self.tcx.crate_name(cnum).to_string()
554         }
555     }
556     fn path_impl(self: &mut PrintCx<'_, '_, '_, Self>, text: &str) -> Self::Path {
557         text.to_string()
558     }
559     fn path_append(
560         self: &mut PrintCx<'_, '_, '_, Self>,
561         mut path: Self::Path,
562         text: &str,
563     ) -> Self::Path {
564         if !path.is_empty() {
565             path.push_str("::");
566         }
567         path.push_str(text);
568         path
569     }
570 }