]> git.proxmox.com Git - rustc.git/blame - src/librustc/ty/item_path.rs
New upstream version 1.17.0+dfsg1
[rustc.git] / src / librustc / ty / item_path.rs
CommitLineData
54a0048b
SL
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
11use hir::map::DefPathData;
9e0c209e 12use hir::def_id::{CrateNum, DefId, CRATE_DEF_INDEX, LOCAL_CRATE};
54a0048b
SL
13use ty::{self, Ty, TyCtxt};
14use syntax::ast;
476ff2be 15use syntax::symbol::Symbol;
3157f602
XL
16
17use std::cell::Cell;
18
19thread_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.
26pub 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}
54a0048b 35
a7813a04 36impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
54a0048b
SL
37 /// Returns a string identifying this def-id. This string is
38 /// suitable for user output. It is relative to the current crate
3157f602 39 /// root, unless with_forced_absolute_paths was used.
a7813a04 40 pub fn item_path_str(self, def_id: DefId) -> String {
3157f602
XL
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);
54a0048b
SL
49 self.push_item_path(&mut buffer, def_id);
50 buffer.into_string()
51 }
52
53 /// Returns a string identifying this local node-id.
a7813a04 54 pub fn node_path_str(self, id: ast::NodeId) -> String {
32a655c1 55 self.item_path_str(self.hir.local_def_id(id))
54a0048b
SL
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.
a7813a04 60 pub fn absolute_item_path_str(self, def_id: DefId) -> String {
54a0048b
SL
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.)
9e0c209e 69 pub fn push_krate_path<T>(self, buffer: &mut T, cnum: CrateNum)
54a0048b
SL
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 {
476ff2be 97 buffer.push(&self.crate_name(cnum).as_str());
54a0048b
SL
98 }
99 }
100 }
101 RootMode::Absolute => {
102 // In absolute mode, just write the crate name
103 // unconditionally.
476ff2be 104 buffer.push(&self.original_crate_name(cnum).as_str());
54a0048b
SL
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`.
a7813a04 112 pub fn try_push_visible_item_path<T>(self, buffer: &mut T, external_def_id: DefId) -> bool
54a0048b
SL
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 => {
476ff2be 129 buffer.push(&self.crate_name(cur_def.krate).as_str());
54a0048b
SL
130 cur_path.iter().rev().map(|segment| buffer.push(&segment.as_str())).count();
131 return true;
132 }
133 _ => {},
134 }
135 }
136
9e0c209e
SL
137 cur_path.push(self.sess.cstore.def_key(cur_def)
138 .disambiguated_data.data.get_opt_name().unwrap_or_else(||
476ff2be 139 Symbol::intern("<unnamed>")));
54a0048b
SL
140 match visible_parent_map.get(&cur_def) {
141 Some(&def) => cur_def = def,
142 None => return false,
143 };
144 }
145 }
146
a7813a04 147 pub fn push_item_path<T>(self, buffer: &mut T, def_id: DefId)
54a0048b
SL
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
54a0048b
SL
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(..) |
a7813a04 173 data @ DefPathData::Module(..) |
54a0048b
SL
174 data @ DefPathData::TypeParam(..) |
175 data @ DefPathData::LifetimeDef(..) |
176 data @ DefPathData::EnumVariant(..) |
177 data @ DefPathData::Field(..) |
178 data @ DefPathData::StructCtor |
179 data @ DefPathData::Initializer |
180 data @ DefPathData::MacroDef(..) |
181 data @ DefPathData::ClosureExpr |
5bcae85e 182 data @ DefPathData::Binding(..) |
8bb4bdeb
XL
183 data @ DefPathData::ImplTrait |
184 data @ DefPathData::Typeof => {
54a0048b
SL
185 let parent_def_id = self.parent_def_id(def_id).unwrap();
186 self.push_item_path(buffer, parent_def_id);
187 buffer.push(&data.as_interned_str());
188 }
189 }
190 }
191
a7813a04 192 fn push_impl_path<T>(self,
54a0048b
SL
193 buffer: &mut T,
194 impl_def_id: DefId)
195 where T: ItemPathBuffer
196 {
197 let parent_def_id = self.parent_def_id(impl_def_id).unwrap();
198
199 let use_types = if !impl_def_id.is_local() {
200 // always have full types available for extern crates
201 true
202 } else {
203 // for local crates, check whether type info is
204 // available; typeck might not have completed yet
8bb4bdeb 205 self.maps.impl_trait_ref.borrow().contains_key(&impl_def_id)
54a0048b
SL
206 };
207
208 if !use_types {
209 return self.push_impl_path_fallback(buffer, impl_def_id);
210 }
211
212 // Decide whether to print the parent path for the impl.
213 // Logically, since impls are global, it's never needed, but
214 // users may find it useful. Currently, we omit the parent if
215 // the impl is either in the same module as the self-type or
216 // as the trait.
476ff2be 217 let self_ty = self.item_type(impl_def_id);
a7813a04 218 let in_self_mod = match characteristic_def_id_of_type(self_ty) {
54a0048b
SL
219 None => false,
220 Some(ty_def_id) => self.parent_def_id(ty_def_id) == Some(parent_def_id),
221 };
222
223 let impl_trait_ref = self.impl_trait_ref(impl_def_id);
224 let in_trait_mod = match impl_trait_ref {
225 None => false,
226 Some(trait_ref) => self.parent_def_id(trait_ref.def_id) == Some(parent_def_id),
227 };
228
229 if !in_self_mod && !in_trait_mod {
230 // If the impl is not co-located with either self-type or
231 // trait-type, then fallback to a format that identifies
232 // the module more clearly.
233 self.push_item_path(buffer, parent_def_id);
234 if let Some(trait_ref) = impl_trait_ref {
235 buffer.push(&format!("<impl {} for {}>", trait_ref, self_ty));
236 } else {
237 buffer.push(&format!("<impl {}>", self_ty));
238 }
239 return;
240 }
241
242 // Otherwise, try to give a good form that would be valid language
243 // syntax. Preferably using associated item notation.
244
245 if let Some(trait_ref) = impl_trait_ref {
246 // Trait impls.
247 buffer.push(&format!("<{} as {}>",
248 self_ty,
249 trait_ref));
250 return;
251 }
252
253 // Inherent impls. Try to print `Foo::bar` for an inherent
254 // impl on `Foo`, but fallback to `<Foo>::bar` if self-type is
255 // anything other than a simple path.
256 match self_ty.sty {
9e0c209e
SL
257 ty::TyAdt(adt_def, substs) => {
258 if substs.types().next().is_none() { // ignore regions
54a0048b
SL
259 self.push_item_path(buffer, adt_def.did);
260 } else {
261 buffer.push(&format!("<{}>", self_ty));
262 }
263 }
264
265 ty::TyBool |
266 ty::TyChar |
267 ty::TyInt(_) |
268 ty::TyUint(_) |
269 ty::TyFloat(_) |
270 ty::TyStr => {
271 buffer.push(&format!("{}", self_ty));
272 }
273
274 _ => {
275 buffer.push(&format!("<{}>", self_ty));
276 }
277 }
278 }
279
a7813a04 280 fn push_impl_path_fallback<T>(self,
54a0048b
SL
281 buffer: &mut T,
282 impl_def_id: DefId)
283 where T: ItemPathBuffer
284 {
285 // If no type info is available, fall back to
286 // pretty printing some span information. This should
287 // only occur very early in the compiler pipeline.
288 let parent_def_id = self.parent_def_id(impl_def_id).unwrap();
289 self.push_item_path(buffer, parent_def_id);
32a655c1
SL
290 let node_id = self.hir.as_local_node_id(impl_def_id).unwrap();
291 let item = self.hir.expect_item(node_id);
54a0048b
SL
292 let span_str = self.sess.codemap().span_to_string(item.span);
293 buffer.push(&format!("<impl at {}>", span_str));
294 }
295
54a0048b
SL
296 /// Returns the def-id of `def_id`'s parent in the def tree. If
297 /// this returns `None`, then `def_id` represents a crate root or
298 /// inlined root.
9e0c209e 299 pub fn parent_def_id(self, def_id: DefId) -> Option<DefId> {
54a0048b
SL
300 let key = self.def_key(def_id);
301 key.parent.map(|index| DefId { krate: def_id.krate, index: index })
302 }
303}
304
a7813a04
XL
305/// As a heuristic, when we see an impl, if we see that the
306/// 'self-type' is a type defined in the same module as the impl,
307/// we can omit including the path to the impl itself. This
308/// function tries to find a "characteristic def-id" for a
309/// type. It's just a heuristic so it makes some questionable
310/// decisions and we may want to adjust it later.
311pub fn characteristic_def_id_of_type(ty: Ty) -> Option<DefId> {
312 match ty.sty {
9e0c209e 313 ty::TyAdt(adt_def, _) => Some(adt_def.did),
a7813a04 314
476ff2be 315 ty::TyDynamic(data, ..) => data.principal().map(|p| p.def_id()),
a7813a04
XL
316
317 ty::TyArray(subty, _) |
32a655c1 318 ty::TySlice(subty) => characteristic_def_id_of_type(subty),
a7813a04
XL
319
320 ty::TyRawPtr(mt) |
321 ty::TyRef(_, mt) => characteristic_def_id_of_type(mt.ty),
322
8bb4bdeb
XL
323 ty::TyTuple(ref tys, _) => tys.iter()
324 .filter_map(|ty| characteristic_def_id_of_type(ty))
325 .next(),
a7813a04 326
9e0c209e 327 ty::TyFnDef(def_id, ..) |
a7813a04
XL
328 ty::TyClosure(def_id, _) => Some(def_id),
329
330 ty::TyBool |
331 ty::TyChar |
332 ty::TyInt(_) |
333 ty::TyUint(_) |
334 ty::TyStr |
335 ty::TyFnPtr(_) |
336 ty::TyProjection(_) |
337 ty::TyParam(_) |
5bcae85e 338 ty::TyAnon(..) |
a7813a04
XL
339 ty::TyInfer(_) |
340 ty::TyError |
5bcae85e 341 ty::TyNever |
a7813a04
XL
342 ty::TyFloat(_) => None,
343 }
344}
345
54a0048b
SL
346/// Unifying Trait for different kinds of item paths we might
347/// construct. The basic interface is that components get pushed: the
348/// instance can also customize how we handle the root of a crate.
349pub trait ItemPathBuffer {
350 fn root_mode(&self) -> &RootMode;
351 fn push(&mut self, text: &str);
352}
353
354#[derive(Debug)]
355pub enum RootMode {
356 /// Try to make a path relative to the local crate. In
357 /// particular, local paths have no prefix, and if the path comes
358 /// from an extern crate, start with the path to the `extern
359 /// crate` declaration.
360 Local,
361
362 /// Always prepend the crate name to the path, forming an absolute
363 /// path from within a given set of crates.
364 Absolute,
365}
366
367#[derive(Debug)]
368struct LocalPathBuffer {
369 root_mode: RootMode,
370 str: String,
371}
372
373impl LocalPathBuffer {
374 fn new(root_mode: RootMode) -> LocalPathBuffer {
375 LocalPathBuffer {
376 root_mode: root_mode,
377 str: String::new()
378 }
379 }
380
381 fn into_string(self) -> String {
382 self.str
383 }
384
385}
386
387impl ItemPathBuffer for LocalPathBuffer {
388 fn root_mode(&self) -> &RootMode {
389 &self.root_mode
390 }
391
392 fn push(&mut self, text: &str) {
393 if !self.str.is_empty() {
394 self.str.push_str("::");
395 }
396 self.str.push_str(text);
397 }
398}