]> git.lizzy.rs Git - rust.git/blob - src/librustc/ty/item_path.rs
Auto merge of #41433 - estebank:constructor, r=michaelwoerister
[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, Ty, TyCtxt};
14 use syntax::ast;
15 use syntax::symbol::Symbol;
16
17 use std::cell::Cell;
18
19 thread_local! {
20     static FORCE_ABSOLUTE: Cell<bool> = Cell::new(false)
21 }
22
23 /// Enforces that item_path_str always returns an absolute path.
24 /// This is useful when building symbols that contain types,
25 /// where we want the crate name to be part of the symbol.
26 pub fn with_forced_absolute_paths<F: FnOnce() -> R, R>(f: F) -> R {
27     FORCE_ABSOLUTE.with(|force| {
28         let old = force.get();
29         force.set(true);
30         let result = f();
31         force.set(old);
32         result
33     })
34 }
35
36 impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
37     /// Returns a string identifying this def-id. This string is
38     /// suitable for user output. It is relative to the current crate
39     /// root, unless with_forced_absolute_paths was used.
40     pub fn item_path_str(self, def_id: DefId) -> String {
41         let mode = FORCE_ABSOLUTE.with(|force| {
42             if force.get() {
43                 RootMode::Absolute
44             } else {
45                 RootMode::Local
46             }
47         });
48         let mut buffer = LocalPathBuffer::new(mode);
49         self.push_item_path(&mut buffer, def_id);
50         buffer.into_string()
51     }
52
53     /// Returns a string identifying this local node-id.
54     pub fn node_path_str(self, id: ast::NodeId) -> String {
55         self.item_path_str(self.hir.local_def_id(id))
56     }
57
58     /// Returns a string identifying this def-id. This string is
59     /// suitable for user output. It always begins with a crate identifier.
60     pub fn absolute_item_path_str(self, def_id: DefId) -> String {
61         let mut buffer = LocalPathBuffer::new(RootMode::Absolute);
62         self.push_item_path(&mut buffer, def_id);
63         buffer.into_string()
64     }
65
66     /// Returns the "path" to a particular crate. This can proceed in
67     /// various ways, depending on the `root_mode` of the `buffer`.
68     /// (See `RootMode` enum for more details.)
69     pub fn push_krate_path<T>(self, buffer: &mut T, cnum: CrateNum)
70         where T: ItemPathBuffer
71     {
72         match *buffer.root_mode() {
73             RootMode::Local => {
74                 // In local mode, when we encounter a crate other than
75                 // LOCAL_CRATE, execution proceeds in one of two ways:
76                 //
77                 // 1. for a direct dependency, where user added an
78                 //    `extern crate` manually, we put the `extern
79                 //    crate` as the parent. So you wind up with
80                 //    something relative to the current crate.
81                 // 2. for an indirect crate, where there is no extern
82                 //    crate, we just prepend the crate name.
83                 //
84                 // Returns `None` for the local crate.
85                 if cnum != LOCAL_CRATE {
86                     let opt_extern_crate = self.sess.cstore.extern_crate(cnum);
87                     let opt_extern_crate = opt_extern_crate.and_then(|extern_crate| {
88                         if extern_crate.direct {
89                             Some(extern_crate.def_id)
90                         } else {
91                             None
92                         }
93                     });
94                     if let Some(extern_crate_def_id) = opt_extern_crate {
95                         self.push_item_path(buffer, extern_crate_def_id);
96                     } else {
97                         buffer.push(&self.crate_name(cnum).as_str());
98                     }
99                 }
100             }
101             RootMode::Absolute => {
102                 // In absolute mode, just write the crate name
103                 // unconditionally.
104                 buffer.push(&self.original_crate_name(cnum).as_str());
105             }
106         }
107     }
108
109     /// If possible, this pushes a global path resolving to `external_def_id` that is visible
110     /// from at least one local module and returns true. If the crate defining `external_def_id` is
111     /// declared with an `extern crate`, the path is guarenteed to use the `extern crate`.
112     pub fn try_push_visible_item_path<T>(self, buffer: &mut T, external_def_id: DefId) -> bool
113         where T: ItemPathBuffer
114     {
115         let visible_parent_map = self.sess.cstore.visible_parent_map();
116
117         let (mut cur_def, mut cur_path) = (external_def_id, Vec::<ast::Name>::new());
118         loop {
119             // If `cur_def` is a direct or injected extern crate, push the path to the crate
120             // followed by the path to the item within the crate and return.
121             if cur_def.index == CRATE_DEF_INDEX {
122                 match self.sess.cstore.extern_crate(cur_def.krate) {
123                     Some(extern_crate) if extern_crate.direct => {
124                         self.push_item_path(buffer, extern_crate.def_id);
125                         cur_path.iter().rev().map(|segment| buffer.push(&segment.as_str())).count();
126                         return true;
127                     }
128                     None => {
129                         buffer.push(&self.crate_name(cur_def.krate).as_str());
130                         cur_path.iter().rev().map(|segment| buffer.push(&segment.as_str())).count();
131                         return true;
132                     }
133                     _ => {},
134                 }
135             }
136
137             cur_path.push(self.sess.cstore.def_key(cur_def)
138                               .disambiguated_data.data.get_opt_name().unwrap_or_else(||
139                 Symbol::intern("<unnamed>")));
140             match visible_parent_map.get(&cur_def) {
141                 Some(&def) => cur_def = def,
142                 None => return false,
143             };
144         }
145     }
146
147     pub fn push_item_path<T>(self, buffer: &mut T, def_id: DefId)
148         where T: ItemPathBuffer
149     {
150         match *buffer.root_mode() {
151             RootMode::Local if !def_id.is_local() =>
152                 if self.try_push_visible_item_path(buffer, def_id) { return },
153             _ => {}
154         }
155
156         let key = self.def_key(def_id);
157         match key.disambiguated_data.data {
158             DefPathData::CrateRoot => {
159                 assert!(key.parent.is_none());
160                 self.push_krate_path(buffer, def_id.krate);
161             }
162
163             DefPathData::Impl => {
164                 self.push_impl_path(buffer, def_id);
165             }
166
167             // Unclear if there is any value in distinguishing these.
168             // Probably eventually (and maybe we would even want
169             // finer-grained distinctions, e.g. between enum/struct).
170             data @ DefPathData::Misc |
171             data @ DefPathData::TypeNs(..) |
172             data @ DefPathData::ValueNs(..) |
173             data @ DefPathData::Module(..) |
174             data @ DefPathData::TypeParam(..) |
175             data @ DefPathData::LifetimeDef(..) |
176             data @ DefPathData::EnumVariant(..) |
177             data @ DefPathData::Field(..) |
178             data @ DefPathData::Initializer |
179             data @ DefPathData::MacroDef(..) |
180             data @ DefPathData::ClosureExpr |
181             data @ DefPathData::Binding(..) |
182             data @ DefPathData::ImplTrait |
183             data @ DefPathData::Typeof => {
184                 let parent_def_id = self.parent_def_id(def_id).unwrap();
185                 self.push_item_path(buffer, parent_def_id);
186                 buffer.push(&data.as_interned_str());
187             }
188             DefPathData::StructCtor => { // present `X` instead of `X::{{constructor}}`
189                 let parent_def_id = self.parent_def_id(def_id).unwrap();
190                 self.push_item_path(buffer, parent_def_id);
191             }
192         }
193     }
194
195     fn push_impl_path<T>(self,
196                          buffer: &mut T,
197                          impl_def_id: DefId)
198         where T: ItemPathBuffer
199     {
200         let parent_def_id = self.parent_def_id(impl_def_id).unwrap();
201
202         let use_types = if !impl_def_id.is_local() {
203             // always have full types available for extern crates
204             true
205         } else {
206             // for local crates, check whether type info is
207             // available; typeck might not have completed yet
208             self.maps.impl_trait_ref.borrow().contains_key(&impl_def_id) &&
209                 self.maps.type_of.borrow().contains_key(&impl_def_id)
210         };
211
212         if !use_types {
213             return self.push_impl_path_fallback(buffer, impl_def_id);
214         }
215
216         // Decide whether to print the parent path for the impl.
217         // Logically, since impls are global, it's never needed, but
218         // users may find it useful. Currently, we omit the parent if
219         // the impl is either in the same module as the self-type or
220         // as the trait.
221         let self_ty = self.type_of(impl_def_id);
222         let in_self_mod = match characteristic_def_id_of_type(self_ty) {
223             None => false,
224             Some(ty_def_id) => self.parent_def_id(ty_def_id) == Some(parent_def_id),
225         };
226
227         let impl_trait_ref = self.impl_trait_ref(impl_def_id);
228         let in_trait_mod = match impl_trait_ref {
229             None => false,
230             Some(trait_ref) => self.parent_def_id(trait_ref.def_id) == Some(parent_def_id),
231         };
232
233         if !in_self_mod && !in_trait_mod {
234             // If the impl is not co-located with either self-type or
235             // trait-type, then fallback to a format that identifies
236             // the module more clearly.
237             self.push_item_path(buffer, parent_def_id);
238             if let Some(trait_ref) = impl_trait_ref {
239                 buffer.push(&format!("<impl {} for {}>", trait_ref, self_ty));
240             } else {
241                 buffer.push(&format!("<impl {}>", self_ty));
242             }
243             return;
244         }
245
246         // Otherwise, try to give a good form that would be valid language
247         // syntax. Preferably using associated item notation.
248
249         if let Some(trait_ref) = impl_trait_ref {
250             // Trait impls.
251             buffer.push(&format!("<{} as {}>",
252                                  self_ty,
253                                  trait_ref));
254             return;
255         }
256
257         // Inherent impls. Try to print `Foo::bar` for an inherent
258         // impl on `Foo`, but fallback to `<Foo>::bar` if self-type is
259         // anything other than a simple path.
260         match self_ty.sty {
261             ty::TyAdt(adt_def, substs) => {
262                 if substs.types().next().is_none() { // ignore regions
263                     self.push_item_path(buffer, adt_def.did);
264                 } else {
265                     buffer.push(&format!("<{}>", self_ty));
266                 }
267             }
268
269             ty::TyBool |
270             ty::TyChar |
271             ty::TyInt(_) |
272             ty::TyUint(_) |
273             ty::TyFloat(_) |
274             ty::TyStr => {
275                 buffer.push(&format!("{}", self_ty));
276             }
277
278             _ => {
279                 buffer.push(&format!("<{}>", self_ty));
280             }
281         }
282     }
283
284     fn push_impl_path_fallback<T>(self,
285                                   buffer: &mut T,
286                                   impl_def_id: DefId)
287         where T: ItemPathBuffer
288     {
289         // If no type info is available, fall back to
290         // pretty printing some span information. This should
291         // only occur very early in the compiler pipeline.
292         let parent_def_id = self.parent_def_id(impl_def_id).unwrap();
293         self.push_item_path(buffer, parent_def_id);
294         let node_id = self.hir.as_local_node_id(impl_def_id).unwrap();
295         let item = self.hir.expect_item(node_id);
296         let span_str = self.sess.codemap().span_to_string(item.span);
297         buffer.push(&format!("<impl at {}>", span_str));
298     }
299
300     /// Returns the def-id of `def_id`'s parent in the def tree. If
301     /// this returns `None`, then `def_id` represents a crate root or
302     /// inlined root.
303     pub fn parent_def_id(self, def_id: DefId) -> Option<DefId> {
304         let key = self.def_key(def_id);
305         key.parent.map(|index| DefId { krate: def_id.krate, index: index })
306     }
307 }
308
309 /// As a heuristic, when we see an impl, if we see that the
310 /// 'self-type' is a type defined in the same module as the impl,
311 /// we can omit including the path to the impl itself. This
312 /// function tries to find a "characteristic def-id" for a
313 /// type. It's just a heuristic so it makes some questionable
314 /// decisions and we may want to adjust it later.
315 pub fn characteristic_def_id_of_type(ty: Ty) -> Option<DefId> {
316     match ty.sty {
317         ty::TyAdt(adt_def, _) => Some(adt_def.did),
318
319         ty::TyDynamic(data, ..) => data.principal().map(|p| p.def_id()),
320
321         ty::TyArray(subty, _) |
322         ty::TySlice(subty) => characteristic_def_id_of_type(subty),
323
324         ty::TyRawPtr(mt) |
325         ty::TyRef(_, mt) => characteristic_def_id_of_type(mt.ty),
326
327         ty::TyTuple(ref tys, _) => tys.iter()
328                                       .filter_map(|ty| characteristic_def_id_of_type(ty))
329                                       .next(),
330
331         ty::TyFnDef(def_id, ..) |
332         ty::TyClosure(def_id, _) => Some(def_id),
333
334         ty::TyBool |
335         ty::TyChar |
336         ty::TyInt(_) |
337         ty::TyUint(_) |
338         ty::TyStr |
339         ty::TyFnPtr(_) |
340         ty::TyProjection(_) |
341         ty::TyParam(_) |
342         ty::TyAnon(..) |
343         ty::TyInfer(_) |
344         ty::TyError |
345         ty::TyNever |
346         ty::TyFloat(_) => None,
347     }
348 }
349
350 /// Unifying Trait for different kinds of item paths we might
351 /// construct. The basic interface is that components get pushed: the
352 /// instance can also customize how we handle the root of a crate.
353 pub trait ItemPathBuffer {
354     fn root_mode(&self) -> &RootMode;
355     fn push(&mut self, text: &str);
356 }
357
358 #[derive(Debug)]
359 pub enum RootMode {
360     /// Try to make a path relative to the local crate.  In
361     /// particular, local paths have no prefix, and if the path comes
362     /// from an extern crate, start with the path to the `extern
363     /// crate` declaration.
364     Local,
365
366     /// Always prepend the crate name to the path, forming an absolute
367     /// path from within a given set of crates.
368     Absolute,
369 }
370
371 #[derive(Debug)]
372 struct LocalPathBuffer {
373     root_mode: RootMode,
374     str: String,
375 }
376
377 impl LocalPathBuffer {
378     fn new(root_mode: RootMode) -> LocalPathBuffer {
379         LocalPathBuffer {
380             root_mode: root_mode,
381             str: String::new(),
382         }
383     }
384
385     fn into_string(self) -> String {
386         self.str
387     }
388 }
389
390 impl ItemPathBuffer for LocalPathBuffer {
391     fn root_mode(&self) -> &RootMode {
392         &self.root_mode
393     }
394
395     fn push(&mut self, text: &str) {
396         if !self.str.is_empty() {
397             self.str.push_str("::");
398         }
399         self.str.push_str(text);
400     }
401 }