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