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