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