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