1 use crate::hir::map::DefPathData;
2 use crate::hir::def_id::{CrateNum, DefId};
3 use crate::ty::{self, DefIdTree, Ty, TyCtxt, TypeFoldable};
4 use crate::ty::subst::{Subst, SubstsRef};
6 use rustc_data_structures::fx::FxHashSet;
7 use syntax::symbol::InternedString;
12 // `pretty` is a separate module only for organization.
14 pub use self::pretty::*;
16 // FIXME(eddyb) this module uses `pub(crate)` for things used only
17 // from `ppaux` - when that is removed, they can be re-privatized.
19 struct LateBoundRegionNameCollector(FxHashSet<InternedString>);
20 impl<'tcx> ty::fold::TypeVisitor<'tcx> for LateBoundRegionNameCollector {
21 fn visit_region(&mut self, r: ty::Region<'tcx>) -> bool {
23 ty::ReLateBound(_, ty::BrNamed(_, name)) => {
28 r.super_visit_with(self)
32 pub(crate) struct PrintConfig {
33 pub(crate) is_debug: bool,
34 pub(crate) is_verbose: bool,
35 pub(crate) identify_regions: bool,
36 used_region_names: Option<FxHashSet<InternedString>>,
42 fn new(tcx: TyCtxt<'_, '_, '_>) -> Self {
45 is_verbose: tcx.sess.verbose(),
46 identify_regions: tcx.sess.opts.debugging_opts.identify_regions,
47 used_region_names: None,
54 pub struct PrintCx<'a, 'gcx, 'tcx, P> {
55 pub tcx: TyCtxt<'a, 'gcx, 'tcx>,
57 pub(crate) config: &'a mut PrintConfig,
60 // HACK(eddyb) this is solely for `self: PrintCx<Self>`, e.g. to
61 // implement traits on the printer and call the methods on the context.
62 impl<P> Deref for PrintCx<'_, '_, '_, P> {
64 fn deref(&self) -> &P {
69 impl<'a, 'gcx, 'tcx, P> PrintCx<'a, 'gcx, 'tcx, P> {
71 tcx: TyCtxt<'a, 'gcx, 'tcx>,
73 f: impl FnOnce(PrintCx<'_, 'gcx, 'tcx, P>) -> R,
78 config: &mut PrintConfig::new(tcx),
82 pub(crate) fn with_tls_tcx<R>(printer: P, f: impl FnOnce(PrintCx<'_, '_, '_, P>) -> R) -> R {
83 ty::tls::with(|tcx| PrintCx::with(tcx, printer, f))
85 fn prepare_late_bound_region_info<T>(&mut self, value: &ty::Binder<T>)
86 where T: TypeFoldable<'tcx>
88 let mut collector = LateBoundRegionNameCollector(Default::default());
89 value.visit_with(&mut collector);
90 self.config.used_region_names = Some(collector.0);
91 self.config.region_index = 0;
95 pub trait Print<'tcx, P> {
99 fn print(&self, cx: PrintCx<'_, '_, 'tcx, P>) -> Result<Self::Output, Self::Error>;
102 cx: PrintCx<'_, '_, 'tcx, P>,
103 ) -> Result<Self::Output, Self::Error> {
104 let old_debug = cx.config.is_debug;
105 cx.config.is_debug = false;
106 let result = self.print(PrintCx {
111 cx.config.is_debug = old_debug;
114 fn print_debug(&self, cx: PrintCx<'_, '_, 'tcx, P>) -> Result<Self::Output, Self::Error> {
115 let old_debug = cx.config.is_debug;
116 cx.config.is_debug = true;
117 let result = self.print(PrintCx {
122 cx.config.is_debug = old_debug;
127 pub trait Printer: Sized {
135 self: PrintCx<'_, '_, 'tcx, Self>,
137 substs: Option<SubstsRef<'tcx>>,
138 projections: impl Iterator<Item = ty::ExistentialProjection<'tcx>>,
139 ) -> Result<Self::Path, Self::Error> {
140 self.default_print_def_path(def_id, substs, projections)
143 self: PrintCx<'_, '_, 'tcx, Self>,
145 substs: Option<SubstsRef<'tcx>>,
147 trait_ref: Option<ty::TraitRef<'tcx>>,
148 ) -> Result<Self::Path, Self::Error> {
149 self.default_print_impl_path(impl_def_id, substs, self_ty, trait_ref)
153 self: PrintCx<'_, '_, '_, Self>,
154 region: ty::Region<'_>,
155 ) -> Result<Self::Region, Self::Error>;
158 self: PrintCx<'_, '_, 'tcx, Self>,
160 ) -> Result<Self::Type, Self::Error>;
163 self: PrintCx<'_, '_, '_, Self>,
165 ) -> Result<Self::Path, Self::Error>;
167 self: PrintCx<'_, '_, 'tcx, Self>,
169 trait_ref: Option<ty::TraitRef<'tcx>>,
170 ) -> Result<Self::Path, Self::Error>;
172 fn path_append_impl<'gcx, 'tcx>(
173 self: PrintCx<'_, 'gcx, 'tcx, Self>,
174 print_prefix: impl FnOnce(
175 PrintCx<'_, 'gcx, 'tcx, Self>,
176 ) -> Result<Self::Path, Self::Error>,
178 trait_ref: Option<ty::TraitRef<'tcx>>,
179 ) -> Result<Self::Path, Self::Error>;
180 fn path_append<'gcx, 'tcx>(
181 self: PrintCx<'_, 'gcx, 'tcx, Self>,
182 print_prefix: impl FnOnce(
183 PrintCx<'_, 'gcx, 'tcx, Self>,
184 ) -> Result<Self::Path, Self::Error>,
186 ) -> Result<Self::Path, Self::Error>;
187 fn path_generic_args<'gcx, 'tcx>(
188 self: PrintCx<'_, 'gcx, 'tcx, Self>,
189 print_prefix: impl FnOnce(
190 PrintCx<'_, 'gcx, 'tcx, Self>,
191 ) -> Result<Self::Path, Self::Error>,
192 params: &[ty::GenericParamDef],
193 substs: SubstsRef<'tcx>,
194 projections: impl Iterator<Item = ty::ExistentialProjection<'tcx>>,
195 ) -> Result<Self::Path, Self::Error>;
198 impl<P: Printer> PrintCx<'a, 'gcx, 'tcx, P> {
199 pub fn default_print_def_path(
202 substs: Option<SubstsRef<'tcx>>,
203 projections: impl Iterator<Item = ty::ExistentialProjection<'tcx>>,
204 ) -> Result<P::Path, P::Error> {
205 debug!("default_print_def_path: def_id={:?}, substs={:?}", def_id, substs);
206 let key = self.tcx.def_key(def_id);
207 debug!("default_print_def_path: key={:?}", key);
209 match key.disambiguated_data.data {
210 DefPathData::CrateRoot => {
211 assert!(key.parent.is_none());
212 self.path_crate(def_id.krate)
215 DefPathData::Impl => {
216 let mut self_ty = self.tcx.type_of(def_id);
217 if let Some(substs) = substs {
218 self_ty = self_ty.subst(self.tcx, substs);
221 let mut impl_trait_ref = self.tcx.impl_trait_ref(def_id);
222 if let Some(substs) = substs {
223 impl_trait_ref = impl_trait_ref.subst(self.tcx, substs);
225 self.print_impl_path(def_id, substs, self_ty, impl_trait_ref)
229 let generics = substs.map(|_| self.tcx.generics_of(def_id));
230 let generics_parent = generics.as_ref().and_then(|g| g.parent);
231 let parent_def_id = DefId { index: key.parent.unwrap(), ..def_id };
232 let print_parent_path = |cx: PrintCx<'_, 'gcx, 'tcx, P>| {
233 if let Some(generics_parent_def_id) = generics_parent {
234 assert_eq!(parent_def_id, generics_parent_def_id);
236 // FIXME(eddyb) try to move this into the parent's printing
237 // logic, instead of doing it when printing the child.
238 let parent_generics = cx.tcx.generics_of(parent_def_id);
239 let parent_has_own_self =
240 parent_generics.has_self && parent_generics.parent_count == 0;
241 if let (Some(substs), true) = (substs, parent_has_own_self) {
242 let trait_ref = ty::TraitRef::new(parent_def_id, substs);
243 cx.path_qualified(trait_ref.self_ty(), Some(trait_ref))
245 cx.print_def_path(parent_def_id, substs, iter::empty())
248 cx.print_def_path(parent_def_id, None, iter::empty())
251 let print_path = |cx: PrintCx<'_, 'gcx, 'tcx, P>| {
252 match key.disambiguated_data.data {
253 // Skip `::{{constructor}}` on tuple/unit structs.
254 DefPathData::StructCtor => print_parent_path(cx),
259 &key.disambiguated_data.data.as_interned_str().as_str(),
265 if let (Some(generics), Some(substs)) = (generics, substs) {
266 let has_own_self = generics.has_self && generics.parent_count == 0;
267 let params = &generics.params[has_own_self as usize..];
268 self.path_generic_args(print_path, params, substs, projections)
276 fn default_print_impl_path(
279 _substs: Option<SubstsRef<'tcx>>,
281 impl_trait_ref: Option<ty::TraitRef<'tcx>>,
282 ) -> Result<P::Path, P::Error> {
283 debug!("default_print_impl_path: impl_def_id={:?}, self_ty={}, impl_trait_ref={:?}",
284 impl_def_id, self_ty, impl_trait_ref);
286 // Decide whether to print the parent path for the impl.
287 // Logically, since impls are global, it's never needed, but
288 // users may find it useful. Currently, we omit the parent if
289 // the impl is either in the same module as the self-type or
291 let parent_def_id = self.tcx.parent(impl_def_id).unwrap();
292 let in_self_mod = match characteristic_def_id_of_type(self_ty) {
294 Some(ty_def_id) => self.tcx.parent(ty_def_id) == Some(parent_def_id),
296 let in_trait_mod = match impl_trait_ref {
298 Some(trait_ref) => self.tcx.parent(trait_ref.def_id) == Some(parent_def_id),
301 if !in_self_mod && !in_trait_mod {
302 // If the impl is not co-located with either self-type or
303 // trait-type, then fallback to a format that identifies
304 // the module more clearly.
305 self.path_append_impl(
306 |cx| cx.print_def_path(parent_def_id, None, iter::empty()),
311 // Otherwise, try to give a good form that would be valid language
312 // syntax. Preferably using associated item notation.
313 self.path_qualified(self_ty, impl_trait_ref)
318 /// As a heuristic, when we see an impl, if we see that the
319 /// 'self type' is a type defined in the same module as the impl,
320 /// we can omit including the path to the impl itself. This
321 /// function tries to find a "characteristic `DefId`" for a
322 /// type. It's just a heuristic so it makes some questionable
323 /// decisions and we may want to adjust it later.
324 pub fn characteristic_def_id_of_type(ty: Ty<'_>) -> Option<DefId> {
326 ty::Adt(adt_def, _) => Some(adt_def.did),
328 ty::Dynamic(data, ..) => data.principal_def_id(),
330 ty::Array(subty, _) |
331 ty::Slice(subty) => characteristic_def_id_of_type(subty),
333 ty::RawPtr(mt) => characteristic_def_id_of_type(mt.ty),
335 ty::Ref(_, ty, _) => characteristic_def_id_of_type(ty),
337 ty::Tuple(ref tys) => tys.iter()
338 .filter_map(|ty| characteristic_def_id_of_type(ty))
341 ty::FnDef(def_id, _) |
342 ty::Closure(def_id, _) |
343 ty::Generator(def_id, _, _) |
344 ty::Foreign(def_id) => Some(def_id),
353 ty::Placeholder(..) |
354 ty::UnnormalizedProjection(..) |
360 ty::GeneratorWitness(..) |
362 ty::Float(_) => None,