rustc_ty_utils/
sig_types.rs1use rustc_hir::def::DefKind;
5use rustc_hir::def_id::LocalDefId;
6use rustc_middle::span_bug;
7use rustc_middle::ty::{self, TyCtxt, TypeVisitable, VisitorResult, try_visit};
8use rustc_span::Span;
9use tracing::{instrument, trace};
10
11pub trait SpannedTypeVisitor<'tcx> {
12 type Result: VisitorResult = ();
13 fn visit(&mut self, span: Span, value: impl TypeVisitable<TyCtxt<'tcx>>) -> Self::Result;
14}
15
16#[instrument(level = "trace", skip(tcx, visitor))]
17pub fn walk_types<'tcx, V: SpannedTypeVisitor<'tcx>>(
18 tcx: TyCtxt<'tcx>,
19 item: LocalDefId,
20 visitor: &mut V,
21) -> V::Result {
22 let kind = tcx.def_kind(item);
23 trace!(?kind);
24 match kind {
25 DefKind::AssocFn | DefKind::Fn => {
27 let hir_sig = tcx.hir_node_by_def_id(item).fn_decl().unwrap();
28 if hir_sig.output.is_suggestable_infer_ty().is_some() {
32 return V::Result::output();
33 }
34 let ty_sig = tcx.fn_sig(item).instantiate_identity();
35 try_visit!(visitor.visit(hir_sig.output.span(), ty_sig.output()));
37 for (hir, ty) in hir_sig.inputs.iter().zip(ty_sig.inputs().iter()) {
38 try_visit!(visitor.visit(hir.span, ty.map_bound(|x| *x)));
39 }
40 for (pred, span) in tcx.explicit_predicates_of(item).instantiate_identity(tcx) {
41 try_visit!(visitor.visit(span, pred));
42 }
43 }
44 DefKind::TyAlias { .. } | DefKind::AssocTy |
46 DefKind::Static { .. } | DefKind::Const | DefKind::AssocConst | DefKind::AnonConst => {
48 if let Some(ty) = tcx.hir_node_by_def_id(item).ty() {
49 if ty.is_suggestable_infer_ty() {
53 return V::Result::output();
54 }
55 try_visit!(visitor.visit(ty.span, tcx.type_of(item).instantiate_identity()));
57 }
58 for (pred, span) in tcx.explicit_predicates_of(item).instantiate_identity(tcx) {
59 try_visit!(visitor.visit(span, pred));
60 }
61 }
62 DefKind::OpaqueTy => {
63 for (pred, span) in tcx.explicit_item_bounds(item).iter_identity_copied() {
64 try_visit!(visitor.visit(span, pred));
65 }
66 }
67 DefKind::Struct | DefKind::Union | DefKind::Enum => {
69 let span = tcx.def_ident_span(item).unwrap();
70 let ty = tcx.type_of(item).instantiate_identity();
71 try_visit!(visitor.visit(span, ty));
72 let ty::Adt(def, args) = ty.kind() else {
73 span_bug!(span, "invalid type for {kind:?}: {:#?}", ty.kind())
74 };
75 for field in def.all_fields() {
76 let span = tcx.def_ident_span(field.did).unwrap();
77 let ty = field.ty(tcx, args);
78 try_visit!(visitor.visit(span, ty));
79 }
80 for (pred, span) in tcx.explicit_predicates_of(item).instantiate_identity(tcx) {
81 try_visit!(visitor.visit(span, pred));
82 }
83 }
84 DefKind::InlineConst | DefKind::Closure | DefKind::SyntheticCoroutineBody => {}
88 DefKind::Impl { of_trait } => {
89 if of_trait {
90 let span = tcx.hir_node_by_def_id(item).expect_item().expect_impl().of_trait.unwrap().path.span;
91 let args = &tcx.impl_trait_ref(item).unwrap().instantiate_identity().args[1..];
92 try_visit!(visitor.visit(span, args));
93 }
94 let span = match tcx.hir_node_by_def_id(item).ty() {
95 Some(ty) => ty.span,
96 _ => tcx.def_span(item),
97 };
98 try_visit!(visitor.visit(span, tcx.type_of(item).instantiate_identity()));
99 for (pred, span) in tcx.explicit_predicates_of(item).instantiate_identity(tcx) {
100 try_visit!(visitor.visit(span, pred));
101 }
102 }
103 DefKind::TraitAlias | DefKind::Trait => {
104 for (pred, span) in tcx.explicit_predicates_of(item).instantiate_identity(tcx) {
105 try_visit!(visitor.visit(span, pred));
106 }
107 }
108 | DefKind::Variant
109 | DefKind::TyParam
110 | DefKind::ConstParam
111 | DefKind::Ctor(_, _)
112 | DefKind::Field
113 | DefKind::LifetimeParam => {
114 span_bug!(
115 tcx.def_span(item),
116 "{kind:?} has not seen any uses of `walk_types` yet, ping oli-obk if you'd like any help"
117 )
118 }
119 | DefKind::ExternCrate
121 | DefKind::ForeignMod
122 | DefKind::ForeignTy
123 | DefKind::Macro(_)
124 | DefKind::GlobalAsm
125 | DefKind::Mod
126 | DefKind::Use => {}
127 }
128 V::Result::output()
129}