]> git.lizzy.rs Git - rust.git/blob - src/librustc_mir/interpret/intrinsics/type_name.rs
032d16a49db4baa3d0f181e85c96292bbefa4f3c
[rust.git] / src / librustc_mir / interpret / intrinsics / type_name.rs
1 use rustc::ty::{
2     TyCtxt, Ty,
3     subst::{UnpackedKind, Kind},
4     print::{Printer, PrettyPrinter, Print},
5     self,
6 };
7 use rustc::hir::map::{DefPathData, DisambiguatedDefPathData};
8 use rustc::hir::def_id::CrateNum;
9 use std::fmt::Write;
10 use rustc::mir::interpret::{Allocation, ConstValue};
11
12 struct AbsolutePathPrinter<'tcx> {
13     tcx: TyCtxt<'tcx>,
14     path: String,
15 }
16
17 impl<'tcx> Printer<'tcx> for AbsolutePathPrinter<'tcx> {
18     type Error = std::fmt::Error;
19
20     type Path = Self;
21     type Region = Self;
22     type Type = Self;
23     type DynExistential = Self;
24     type Const = Self;
25
26     fn tcx(&self) -> TyCtxt<'tcx> {
27         self.tcx
28     }
29
30     fn print_region(self, _region: ty::Region<'_>) -> Result<Self::Region, Self::Error> {
31         Ok(self)
32     }
33
34     fn print_type(mut self, ty: Ty<'tcx>) -> Result<Self::Type, Self::Error> {
35         match ty.sty {
36             // Types without identity.
37             | ty::Bool
38             | ty::Char
39             | ty::Int(_)
40             | ty::Uint(_)
41             | ty::Float(_)
42             | ty::Str
43             | ty::Array(_, _)
44             | ty::Slice(_)
45             | ty::RawPtr(_)
46             | ty::Ref(_, _, _)
47             | ty::FnPtr(_)
48             | ty::Never
49             | ty::Tuple(_)
50             | ty::Dynamic(_, _)
51             => self.pretty_print_type(ty),
52
53             // Placeholders (all printed as `_` to uniformize them).
54             | ty::Param(_)
55             | ty::Bound(..)
56             | ty::Placeholder(_)
57             | ty::Infer(_)
58             | ty::Error
59             => {
60                 write!(self, "_")?;
61                 Ok(self)
62             }
63
64             // Types with identity (print the module path).
65             | ty::Adt(&ty::AdtDef { did: def_id, .. }, substs)
66             | ty::FnDef(def_id, substs)
67             | ty::Opaque(def_id, substs)
68             | ty::Projection(ty::ProjectionTy { item_def_id: def_id, substs })
69             | ty::UnnormalizedProjection(ty::ProjectionTy { item_def_id: def_id, substs })
70             | ty::Closure(def_id, ty::ClosureSubsts { substs })
71             | ty::Generator(def_id, ty::GeneratorSubsts { substs }, _)
72             => self.print_def_path(def_id, substs),
73             ty::Foreign(def_id) => self.print_def_path(def_id, &[]),
74
75             ty::GeneratorWitness(_) => {
76                 bug!("type_name: unexpected `GeneratorWitness`")
77             }
78         }
79     }
80
81     fn print_const(
82         self,
83         _: &'tcx ty::Const<'tcx>,
84     ) -> Result<Self::Const, Self::Error> {
85         // don't print constants to the user
86         Ok(self)
87     }
88
89     fn print_dyn_existential(
90         mut self,
91         predicates: &'tcx ty::List<ty::ExistentialPredicate<'tcx>>,
92     ) -> Result<Self::DynExistential, Self::Error> {
93         let mut first = true;
94         for p in predicates {
95             if !first {
96                 write!(self, "+")?;
97             }
98             first = false;
99             self = p.print(self)?;
100         }
101         Ok(self)
102     }
103
104     fn path_crate(mut self, cnum: CrateNum) -> Result<Self::Path, Self::Error> {
105         self.path.push_str(&self.tcx.original_crate_name(cnum).as_str());
106         Ok(self)
107     }
108
109     fn path_qualified(
110         self,
111         self_ty: Ty<'tcx>,
112         trait_ref: Option<ty::TraitRef<'tcx>>,
113     ) -> Result<Self::Path, Self::Error> {
114         self.pretty_path_qualified(self_ty, trait_ref)
115     }
116
117     fn path_append_impl(
118         self,
119         print_prefix: impl FnOnce(Self) -> Result<Self::Path, Self::Error>,
120         _disambiguated_data: &DisambiguatedDefPathData,
121         self_ty: Ty<'tcx>,
122         trait_ref: Option<ty::TraitRef<'tcx>>,
123     ) -> Result<Self::Path, Self::Error> {
124         self.pretty_path_append_impl(
125             |mut cx| {
126                 cx = print_prefix(cx)?;
127
128                 cx.path.push_str("::");
129
130                 Ok(cx)
131             },
132             self_ty,
133             trait_ref,
134         )
135     }
136
137     fn path_append(
138         mut self,
139         print_prefix: impl FnOnce(Self) -> Result<Self::Path, Self::Error>,
140         disambiguated_data: &DisambiguatedDefPathData,
141     ) -> Result<Self::Path, Self::Error> {
142         self = print_prefix(self)?;
143
144         // Skip `::{{constructor}}` on tuple/unit structs.
145         match disambiguated_data.data {
146             DefPathData::Ctor => return Ok(self),
147             _ => {}
148         }
149
150         self.path.push_str("::");
151
152         self.path.push_str(&disambiguated_data.data.as_interned_str().as_str());
153         Ok(self)
154     }
155
156     fn path_generic_args(
157         mut self,
158         print_prefix: impl FnOnce(Self) -> Result<Self::Path, Self::Error>,
159         args: &[Kind<'tcx>],
160     ) -> Result<Self::Path, Self::Error> {
161         self = print_prefix(self)?;
162         let args = args.iter().cloned().filter(|arg| {
163             match arg.unpack() {
164                 UnpackedKind::Lifetime(_) => false,
165                 _ => true,
166             }
167         });
168         if args.clone().next().is_some() {
169             self.generic_delimiters(|cx| cx.comma_sep(args))
170         } else {
171             Ok(self)
172         }
173     }
174 }
175 impl PrettyPrinter<'tcx> for AbsolutePathPrinter<'tcx> {
176     fn region_should_not_be_omitted(
177         &self,
178         _region: ty::Region<'_>,
179     ) -> bool {
180         false
181     }
182     fn comma_sep<T>(mut self, mut elems: impl Iterator<Item = T>) -> Result<Self, Self::Error>
183     where
184         T: Print<'tcx, Self, Output = Self, Error = Self::Error>,
185     {
186         if let Some(first) = elems.next() {
187             self = first.print(self)?;
188             for elem in elems {
189                 self.path.push_str(", ");
190                 self = elem.print(self)?;
191             }
192         }
193         Ok(self)
194     }
195
196     fn generic_delimiters(
197         mut self,
198         f: impl FnOnce(Self) -> Result<Self, Self::Error>,
199     ) -> Result<Self, Self::Error> {
200         write!(self, "<")?;
201
202         self = f(self)?;
203
204         write!(self, ">")?;
205
206         Ok(self)
207     }
208 }
209
210 impl Write for AbsolutePathPrinter<'_> {
211     fn write_str(&mut self, s: &str) -> std::fmt::Result {
212         Ok(self.path.push_str(s))
213     }
214 }
215
216 /// Produces an absolute path representation of the given type. See also the documentation on
217 /// `std::any::type_name`
218 pub fn type_name<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> &'tcx ty::Const<'tcx> {
219     let alloc = alloc_type_name(tcx, ty);
220     tcx.mk_const(ty::Const {
221         val: ConstValue::Slice {
222             data: alloc,
223             start: 0,
224             end: alloc.len(),
225         },
226         ty: tcx.mk_static_str(),
227     })
228 }
229
230 /// Directly returns an `Allocation` containing an absolute path representation of the given type.
231 pub(super) fn alloc_type_name<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> &'tcx Allocation {
232     let path = AbsolutePathPrinter { tcx, path: String::new() }.print_type(ty).unwrap().path;
233     let alloc = Allocation::from_byte_aligned_bytes(path.into_bytes());
234     tcx.intern_const_alloc(alloc)
235 }