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