1 use crate::ty::subst::{GenericArg, Subst};
2 use crate::ty::{self, DefIdTree, Ty, TyCtxt};
4 use rustc_data_structures::fx::FxHashSet;
5 use rustc_data_structures::sso::SsoHashSet;
6 use rustc_hir::def_id::{CrateNum, DefId};
7 use rustc_hir::definitions::{DefPathData, DisambiguatedDefPathData};
9 // `pretty` is a separate module only for organization.
11 pub use self::pretty::*;
13 // FIXME(eddyb) false positive, the lifetime parameters are used with `P: Printer<...>`.
14 #[allow(unused_lifetimes)]
15 pub trait Print<'tcx, P> {
19 fn print(&self, cx: P) -> Result<Self::Output, Self::Error>;
22 /// Interface for outputting user-facing "type-system entities"
23 /// (paths, types, lifetimes, constants, etc.) as a side-effect
24 /// (e.g. formatting, like `PrettyPrinter` implementors do) or by
25 /// constructing some alternative representation (e.g. an AST),
26 /// which the associated types allow passing through the methods.
28 /// For pretty-printing/formatting in particular, see `PrettyPrinter`.
30 // FIXME(eddyb) find a better name; this is more general than "printing".
31 pub trait Printer<'tcx>: Sized {
40 fn tcx<'a>(&'a self) -> TyCtxt<'tcx>;
45 substs: &'tcx [GenericArg<'tcx>],
46 ) -> Result<Self::Path, Self::Error> {
47 self.default_print_def_path(def_id, substs)
53 substs: &'tcx [GenericArg<'tcx>],
55 trait_ref: Option<ty::TraitRef<'tcx>>,
56 ) -> Result<Self::Path, Self::Error> {
57 self.default_print_impl_path(impl_def_id, substs, self_ty, trait_ref)
60 fn print_region(self, region: ty::Region<'_>) -> Result<Self::Region, Self::Error>;
62 fn print_type(self, ty: Ty<'tcx>) -> Result<Self::Type, Self::Error>;
64 fn print_dyn_existential(
66 predicates: &'tcx ty::List<ty::Binder<'tcx, ty::ExistentialPredicate<'tcx>>>,
67 ) -> Result<Self::DynExistential, Self::Error>;
69 fn print_const(self, ct: ty::Const<'tcx>) -> Result<Self::Const, Self::Error>;
71 fn path_crate(self, cnum: CrateNum) -> Result<Self::Path, Self::Error>;
76 trait_ref: Option<ty::TraitRef<'tcx>>,
77 ) -> Result<Self::Path, Self::Error>;
81 print_prefix: impl FnOnce(Self) -> Result<Self::Path, Self::Error>,
82 disambiguated_data: &DisambiguatedDefPathData,
84 trait_ref: Option<ty::TraitRef<'tcx>>,
85 ) -> Result<Self::Path, Self::Error>;
89 print_prefix: impl FnOnce(Self) -> Result<Self::Path, Self::Error>,
90 disambiguated_data: &DisambiguatedDefPathData,
91 ) -> Result<Self::Path, Self::Error>;
95 print_prefix: impl FnOnce(Self) -> Result<Self::Path, Self::Error>,
96 args: &[GenericArg<'tcx>],
97 ) -> Result<Self::Path, Self::Error>;
99 // Defaults (should not be overridden):
101 #[instrument(skip(self), level = "debug")]
102 fn default_print_def_path(
105 substs: &'tcx [GenericArg<'tcx>],
106 ) -> Result<Self::Path, Self::Error> {
107 let key = self.tcx().def_key(def_id);
110 match key.disambiguated_data.data {
111 DefPathData::CrateRoot => {
112 assert!(key.parent.is_none());
113 self.path_crate(def_id.krate)
116 DefPathData::Impl => {
117 let generics = self.tcx().generics_of(def_id);
118 let mut self_ty = self.tcx().type_of(def_id);
119 let mut impl_trait_ref = self.tcx().impl_trait_ref(def_id);
120 if substs.len() >= generics.count() {
121 self_ty = self_ty.subst(self.tcx(), substs);
122 impl_trait_ref = impl_trait_ref.subst(self.tcx(), substs);
124 self.print_impl_path(def_id, substs, self_ty, impl_trait_ref)
128 let parent_def_id = DefId { index: key.parent.unwrap(), ..def_id };
130 let mut parent_substs = substs;
131 let mut trait_qualify_parent = false;
132 if !substs.is_empty() {
133 let generics = self.tcx().generics_of(def_id);
134 parent_substs = &substs[..generics.parent_count.min(substs.len())];
136 match key.disambiguated_data.data {
137 // Closures' own generics are only captures, don't print them.
138 DefPathData::ClosureExpr => {}
140 // If we have any generic arguments to print, we do that
141 // on top of the same path, but without its own generics.
143 if !generics.params.is_empty() && substs.len() >= generics.count() {
144 let args = self.generic_args_to_print(generics, substs);
145 return self.path_generic_args(
146 |cx| cx.print_def_path(def_id, parent_substs),
153 // FIXME(eddyb) try to move this into the parent's printing
154 // logic, instead of doing it when printing the child.
155 trait_qualify_parent = generics.has_self
156 && generics.parent == Some(parent_def_id)
157 && parent_substs.len() == generics.parent_count
158 && self.tcx().generics_of(parent_def_id).parent_count == 0;
163 if trait_qualify_parent {
164 let trait_ref = ty::TraitRef::new(
166 cx.tcx().intern_substs(parent_substs),
168 cx.path_qualified(trait_ref.self_ty(), Some(trait_ref))
170 cx.print_def_path(parent_def_id, parent_substs)
173 &key.disambiguated_data,
179 fn generic_args_to_print(
181 generics: &'tcx ty::Generics,
182 substs: &'tcx [GenericArg<'tcx>],
183 ) -> &'tcx [GenericArg<'tcx>] {
184 let mut own_params = generics.parent_count..generics.count();
186 // Don't print args for `Self` parameters (of traits).
187 if generics.has_self && own_params.start == 0 {
188 own_params.start = 1;
191 // Don't print args that are the defaults of their respective parameters.
192 own_params.end -= generics
196 .take_while(|param| match param.kind {
197 ty::GenericParamDefKind::Lifetime => false,
198 ty::GenericParamDefKind::Type { has_default, .. } => {
200 && substs[param.index as usize]
202 self.tcx().type_of(param.def_id).subst(self.tcx(), substs),
205 ty::GenericParamDefKind::Const { has_default } => {
207 && substs[param.index as usize]
208 == GenericArg::from(self.tcx().const_param_default(param.def_id))
216 fn default_print_impl_path(
219 _substs: &'tcx [GenericArg<'tcx>],
221 impl_trait_ref: Option<ty::TraitRef<'tcx>>,
222 ) -> Result<Self::Path, Self::Error> {
224 "default_print_impl_path: impl_def_id={:?}, self_ty={}, impl_trait_ref={:?}",
225 impl_def_id, self_ty, impl_trait_ref
228 let key = self.tcx().def_key(impl_def_id);
229 let parent_def_id = DefId { index: key.parent.unwrap(), ..impl_def_id };
231 // Decide whether to print the parent path for the impl.
232 // Logically, since impls are global, it's never needed, but
233 // users may find it useful. Currently, we omit the parent if
234 // the impl is either in the same module as the self-type or
236 let in_self_mod = match characteristic_def_id_of_type(self_ty) {
238 Some(ty_def_id) => self.tcx().parent(ty_def_id) == Some(parent_def_id),
240 let in_trait_mod = match impl_trait_ref {
242 Some(trait_ref) => self.tcx().parent(trait_ref.def_id) == Some(parent_def_id),
245 if !in_self_mod && !in_trait_mod {
246 // If the impl is not co-located with either self-type or
247 // trait-type, then fallback to a format that identifies
248 // the module more clearly.
249 self.path_append_impl(
250 |cx| cx.print_def_path(parent_def_id, &[]),
251 &key.disambiguated_data,
256 // Otherwise, try to give a good form that would be valid language
257 // syntax. Preferably using associated item notation.
258 self.path_qualified(self_ty, impl_trait_ref)
263 /// As a heuristic, when we see an impl, if we see that the
264 /// 'self type' is a type defined in the same module as the impl,
265 /// we can omit including the path to the impl itself. This
266 /// function tries to find a "characteristic `DefId`" for a
267 /// type. It's just a heuristic so it makes some questionable
268 /// decisions and we may want to adjust it later.
270 /// Visited set is needed to avoid full iteration over
271 /// deeply nested tuples that have no DefId.
272 fn characteristic_def_id_of_type_cached<'a>(
274 visited: &mut SsoHashSet<Ty<'a>>,
277 ty::Adt(adt_def, _) => Some(adt_def.did()),
279 ty::Dynamic(data, ..) => data.principal_def_id(),
281 ty::Array(subty, _) | ty::Slice(subty) => {
282 characteristic_def_id_of_type_cached(subty, visited)
285 ty::RawPtr(mt) => characteristic_def_id_of_type_cached(mt.ty, visited),
287 ty::Ref(_, ty, _) => characteristic_def_id_of_type_cached(ty, visited),
289 ty::Tuple(ref tys) => tys.iter().find_map(|ty| {
290 if visited.insert(ty) {
291 return characteristic_def_id_of_type_cached(ty, visited);
297 | ty::Closure(def_id, _)
298 | ty::Generator(def_id, _, _)
299 | ty::Foreign(def_id) => Some(def_id),
308 | ty::Placeholder(..)
314 | ty::GeneratorWitness(..)
316 | ty::Float(_) => None,
319 pub fn characteristic_def_id_of_type(ty: Ty<'_>) -> Option<DefId> {
320 characteristic_def_id_of_type_cached(ty, &mut SsoHashSet::new())
323 impl<'tcx, P: Printer<'tcx>> Print<'tcx, P> for ty::Region<'_> {
324 type Output = P::Region;
325 type Error = P::Error;
326 fn print(&self, cx: P) -> Result<Self::Output, Self::Error> {
327 cx.print_region(*self)
331 impl<'tcx, P: Printer<'tcx>> Print<'tcx, P> for Ty<'tcx> {
332 type Output = P::Type;
333 type Error = P::Error;
334 fn print(&self, cx: P) -> Result<Self::Output, Self::Error> {
339 impl<'tcx, P: Printer<'tcx>> Print<'tcx, P>
340 for &'tcx ty::List<ty::Binder<'tcx, ty::ExistentialPredicate<'tcx>>>
342 type Output = P::DynExistential;
343 type Error = P::Error;
344 fn print(&self, cx: P) -> Result<Self::Output, Self::Error> {
345 cx.print_dyn_existential(self)
349 impl<'tcx, P: Printer<'tcx>> Print<'tcx, P> for ty::Const<'tcx> {
350 type Output = P::Const;
351 type Error = P::Error;
352 fn print(&self, cx: P) -> Result<Self::Output, Self::Error> {
353 cx.print_const(*self)