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)
33 pub(crate) struct PrintConfig {
34 used_region_names: Option<FxHashSet<InternedString>>,
39 pub struct PrintCx<'a, 'gcx, 'tcx, P> {
40 pub tcx: TyCtxt<'a, 'gcx, 'tcx>,
42 pub(crate) config: &'a mut PrintConfig,
45 // HACK(eddyb) this is solely for `self: PrintCx<Self>`, e.g. to
46 // implement traits on the printer and call the methods on the context.
47 impl<P> Deref for PrintCx<'_, '_, '_, P> {
49 fn deref(&self) -> &P {
54 impl<'a, 'gcx, 'tcx, P> PrintCx<'a, 'gcx, 'tcx, P> {
56 tcx: TyCtxt<'a, 'gcx, 'tcx>,
58 f: impl FnOnce(PrintCx<'_, 'gcx, 'tcx, P>) -> R,
63 config: &mut PrintConfig::default(),
67 pub(crate) fn with_tls_tcx<R>(printer: P, f: impl FnOnce(PrintCx<'_, '_, '_, P>) -> R) -> R {
68 ty::tls::with(|tcx| PrintCx::with(tcx, printer, f))
70 fn prepare_late_bound_region_info<T>(&mut self, value: &ty::Binder<T>)
71 where T: TypeFoldable<'tcx>
73 let mut collector = LateBoundRegionNameCollector(Default::default());
74 value.visit_with(&mut collector);
75 self.config.used_region_names = Some(collector.0);
76 self.config.region_index = 0;
80 pub trait Print<'tcx, P> {
84 fn print(&self, cx: PrintCx<'_, '_, 'tcx, P>) -> Result<Self::Output, Self::Error>;
87 pub trait Printer: Sized {
95 self: PrintCx<'_, '_, 'tcx, Self>,
97 substs: Option<SubstsRef<'tcx>>,
98 projections: impl Iterator<Item = ty::ExistentialProjection<'tcx>>,
99 ) -> Result<Self::Path, Self::Error> {
100 self.default_print_def_path(def_id, substs, projections)
103 self: PrintCx<'_, '_, 'tcx, Self>,
105 substs: Option<SubstsRef<'tcx>>,
107 trait_ref: Option<ty::TraitRef<'tcx>>,
108 ) -> Result<Self::Path, Self::Error> {
109 self.default_print_impl_path(impl_def_id, substs, self_ty, trait_ref)
113 self: PrintCx<'_, '_, '_, Self>,
114 region: ty::Region<'_>,
115 ) -> Result<Self::Region, Self::Error>;
118 self: PrintCx<'_, '_, 'tcx, Self>,
120 ) -> Result<Self::Type, Self::Error>;
123 self: PrintCx<'_, '_, '_, Self>,
125 ) -> Result<Self::Path, Self::Error>;
127 self: PrintCx<'_, '_, 'tcx, Self>,
129 trait_ref: Option<ty::TraitRef<'tcx>>,
130 ) -> Result<Self::Path, Self::Error>;
132 fn path_append_impl<'gcx, 'tcx>(
133 self: PrintCx<'_, 'gcx, 'tcx, Self>,
134 print_prefix: impl FnOnce(
135 PrintCx<'_, 'gcx, 'tcx, Self>,
136 ) -> Result<Self::Path, Self::Error>,
138 trait_ref: Option<ty::TraitRef<'tcx>>,
139 ) -> Result<Self::Path, Self::Error>;
140 fn path_append<'gcx, 'tcx>(
141 self: PrintCx<'_, 'gcx, 'tcx, Self>,
142 print_prefix: impl FnOnce(
143 PrintCx<'_, 'gcx, 'tcx, Self>,
144 ) -> Result<Self::Path, Self::Error>,
146 ) -> Result<Self::Path, Self::Error>;
147 fn path_generic_args<'gcx, 'tcx>(
148 self: PrintCx<'_, 'gcx, 'tcx, Self>,
149 print_prefix: impl FnOnce(
150 PrintCx<'_, 'gcx, 'tcx, Self>,
151 ) -> Result<Self::Path, Self::Error>,
152 params: &[ty::GenericParamDef],
153 substs: SubstsRef<'tcx>,
154 projections: impl Iterator<Item = ty::ExistentialProjection<'tcx>>,
155 ) -> Result<Self::Path, Self::Error>;
158 impl<P: Printer> PrintCx<'a, 'gcx, 'tcx, P> {
159 pub fn default_print_def_path(
162 substs: Option<SubstsRef<'tcx>>,
163 projections: impl Iterator<Item = ty::ExistentialProjection<'tcx>>,
164 ) -> Result<P::Path, P::Error> {
165 debug!("default_print_def_path: def_id={:?}, substs={:?}", def_id, substs);
166 let key = self.tcx.def_key(def_id);
167 debug!("default_print_def_path: key={:?}", key);
169 match key.disambiguated_data.data {
170 DefPathData::CrateRoot => {
171 assert!(key.parent.is_none());
172 self.path_crate(def_id.krate)
175 DefPathData::Impl => {
176 let mut self_ty = self.tcx.type_of(def_id);
177 if let Some(substs) = substs {
178 self_ty = self_ty.subst(self.tcx, substs);
181 let mut impl_trait_ref = self.tcx.impl_trait_ref(def_id);
182 if let Some(substs) = substs {
183 impl_trait_ref = impl_trait_ref.subst(self.tcx, substs);
185 self.print_impl_path(def_id, substs, self_ty, impl_trait_ref)
189 let generics = substs.map(|_| self.tcx.generics_of(def_id));
190 let generics_parent = generics.as_ref().and_then(|g| g.parent);
191 let parent_def_id = DefId { index: key.parent.unwrap(), ..def_id };
192 let print_parent_path = |cx: PrintCx<'_, 'gcx, 'tcx, P>| {
193 if let Some(generics_parent_def_id) = generics_parent {
194 assert_eq!(parent_def_id, generics_parent_def_id);
196 // FIXME(eddyb) try to move this into the parent's printing
197 // logic, instead of doing it when printing the child.
198 let parent_generics = cx.tcx.generics_of(parent_def_id);
199 let parent_has_own_self =
200 parent_generics.has_self && parent_generics.parent_count == 0;
201 if let (Some(substs), true) = (substs, parent_has_own_self) {
202 let trait_ref = ty::TraitRef::new(parent_def_id, substs);
203 cx.path_qualified(trait_ref.self_ty(), Some(trait_ref))
205 cx.print_def_path(parent_def_id, substs, iter::empty())
208 cx.print_def_path(parent_def_id, None, iter::empty())
211 let print_path = |cx: PrintCx<'_, 'gcx, 'tcx, P>| {
212 match key.disambiguated_data.data {
213 // Skip `::{{constructor}}` on tuple/unit structs.
214 DefPathData::StructCtor => print_parent_path(cx),
219 &key.disambiguated_data.data.as_interned_str().as_str(),
225 if let (Some(generics), Some(substs)) = (generics, substs) {
226 let has_own_self = generics.has_self && generics.parent_count == 0;
227 let params = &generics.params[has_own_self as usize..];
228 self.path_generic_args(print_path, params, substs, projections)
236 fn default_print_impl_path(
239 _substs: Option<SubstsRef<'tcx>>,
241 impl_trait_ref: Option<ty::TraitRef<'tcx>>,
242 ) -> Result<P::Path, P::Error> {
243 debug!("default_print_impl_path: impl_def_id={:?}, self_ty={}, impl_trait_ref={:?}",
244 impl_def_id, self_ty, impl_trait_ref);
246 // Decide whether to print the parent path for the impl.
247 // Logically, since impls are global, it's never needed, but
248 // users may find it useful. Currently, we omit the parent if
249 // the impl is either in the same module as the self-type or
251 let parent_def_id = self.tcx.parent(impl_def_id).unwrap();
252 let in_self_mod = match characteristic_def_id_of_type(self_ty) {
254 Some(ty_def_id) => self.tcx.parent(ty_def_id) == Some(parent_def_id),
256 let in_trait_mod = match impl_trait_ref {
258 Some(trait_ref) => self.tcx.parent(trait_ref.def_id) == Some(parent_def_id),
261 if !in_self_mod && !in_trait_mod {
262 // If the impl is not co-located with either self-type or
263 // trait-type, then fallback to a format that identifies
264 // the module more clearly.
265 self.path_append_impl(
266 |cx| cx.print_def_path(parent_def_id, None, iter::empty()),
271 // Otherwise, try to give a good form that would be valid language
272 // syntax. Preferably using associated item notation.
273 self.path_qualified(self_ty, impl_trait_ref)
278 /// As a heuristic, when we see an impl, if we see that the
279 /// 'self type' is a type defined in the same module as the impl,
280 /// we can omit including the path to the impl itself. This
281 /// function tries to find a "characteristic `DefId`" for a
282 /// type. It's just a heuristic so it makes some questionable
283 /// decisions and we may want to adjust it later.
284 pub fn characteristic_def_id_of_type(ty: Ty<'_>) -> Option<DefId> {
286 ty::Adt(adt_def, _) => Some(adt_def.did),
288 ty::Dynamic(data, ..) => data.principal_def_id(),
290 ty::Array(subty, _) |
291 ty::Slice(subty) => characteristic_def_id_of_type(subty),
293 ty::RawPtr(mt) => characteristic_def_id_of_type(mt.ty),
295 ty::Ref(_, ty, _) => characteristic_def_id_of_type(ty),
297 ty::Tuple(ref tys) => tys.iter()
298 .filter_map(|ty| characteristic_def_id_of_type(ty))
301 ty::FnDef(def_id, _) |
302 ty::Closure(def_id, _) |
303 ty::Generator(def_id, _, _) |
304 ty::Foreign(def_id) => Some(def_id),
313 ty::Placeholder(..) |
314 ty::UnnormalizedProjection(..) |
320 ty::GeneratorWitness(..) |
322 ty::Float(_) => None,