rustc_trait_selection/error_reporting/infer/nice_region_error/
find_anon_type.rs1use core::ops::ControlFlow;
2
3use rustc_hir::def_id::{DefId, LocalDefId};
4use rustc_hir::intravisit::{self, Visitor, VisitorExt};
5use rustc_hir::{self as hir, AmbigArg};
6use rustc_middle::hir::nested_filter;
7use rustc_middle::middle::resolve_bound_vars as rbv;
8use rustc_middle::ty::{self, Region, TyCtxt};
9use tracing::debug;
10
11pub fn find_anon_type<'tcx>(
27 tcx: TyCtxt<'tcx>,
28 generic_param_scope: LocalDefId,
29 region: Region<'tcx>,
30) -> Option<(&'tcx hir::Ty<'tcx>, &'tcx hir::FnSig<'tcx>)> {
31 let anon_reg = tcx.is_suitable_region(generic_param_scope, region)?;
32 let fn_sig = tcx.hir_node_by_def_id(anon_reg.scope).fn_sig()?;
33
34 fn_sig
35 .decl
36 .inputs
37 .iter()
38 .find_map(|arg| find_component_for_bound_region(tcx, arg, anon_reg.region_def_id))
39 .map(|ty| (ty, fn_sig))
40}
41
42fn find_component_for_bound_region<'tcx>(
45 tcx: TyCtxt<'tcx>,
46 arg: &'tcx hir::Ty<'tcx>,
47 region_def_id: DefId,
48) -> Option<&'tcx hir::Ty<'tcx>> {
49 FindNestedTypeVisitor { tcx, region_def_id, current_index: ty::INNERMOST }
50 .visit_ty_unambig(arg)
51 .break_value()
52}
53
54struct FindNestedTypeVisitor<'tcx> {
62 tcx: TyCtxt<'tcx>,
63 region_def_id: DefId,
65 current_index: ty::DebruijnIndex,
66}
67
68impl<'tcx> Visitor<'tcx> for FindNestedTypeVisitor<'tcx> {
69 type Result = ControlFlow<&'tcx hir::Ty<'tcx>>;
70 type NestedFilter = nested_filter::OnlyBodies;
71
72 fn maybe_tcx(&mut self) -> Self::MaybeTyCtxt {
73 self.tcx
74 }
75
76 fn visit_ty(&mut self, arg: &'tcx hir::Ty<'tcx, AmbigArg>) -> Self::Result {
77 match arg.kind {
78 hir::TyKind::BareFn(_) => {
79 self.current_index.shift_in(1);
80 let _ = intravisit::walk_ty(self, arg);
81 self.current_index.shift_out(1);
82 return ControlFlow::Continue(());
83 }
84
85 hir::TyKind::TraitObject(bounds, ..) => {
86 for bound in bounds {
87 self.current_index.shift_in(1);
88 let _ = self.visit_poly_trait_ref(bound);
89 self.current_index.shift_out(1);
90 }
91 }
92
93 hir::TyKind::Ref(lifetime, _) => {
94 let hir_id = lifetime.hir_id;
96 match self.tcx.named_bound_var(hir_id) {
97 Some(rbv::ResolvedArg::EarlyBound(id)) => {
101 debug!("EarlyBound id={:?}", id);
102 if id.to_def_id() == self.region_def_id {
103 return ControlFlow::Break(arg.as_unambig_ty());
104 }
105 }
106
107 Some(rbv::ResolvedArg::LateBound(debruijn_index, _, id)) => {
111 debug!(
112 "FindNestedTypeVisitor::visit_ty: LateBound depth = {:?}",
113 debruijn_index
114 );
115 debug!("LateBound id={:?}", id);
116 if debruijn_index == self.current_index
117 && id.to_def_id() == self.region_def_id
118 {
119 return ControlFlow::Break(arg.as_unambig_ty());
120 }
121 }
122
123 Some(
124 rbv::ResolvedArg::StaticLifetime
125 | rbv::ResolvedArg::Free(_, _)
126 | rbv::ResolvedArg::Error(_),
127 )
128 | None => {
129 debug!("no arg found");
130 }
131 }
132 }
133 hir::TyKind::Path(_) => {
135 intravisit::walk_ty(self, arg)?;
137
138 return if intravisit::walk_ty(
140 &mut TyPathVisitor {
141 tcx: self.tcx,
142 region_def_id: self.region_def_id,
143 current_index: self.current_index,
144 },
145 arg,
146 )
147 .is_break()
148 {
149 ControlFlow::Break(arg.as_unambig_ty())
150 } else {
151 ControlFlow::Continue(())
152 };
153 }
154 _ => {}
155 }
156 intravisit::walk_ty(self, arg)
159 }
160}
161
162struct TyPathVisitor<'tcx> {
169 tcx: TyCtxt<'tcx>,
170 region_def_id: DefId,
171 current_index: ty::DebruijnIndex,
172}
173
174impl<'tcx> Visitor<'tcx> for TyPathVisitor<'tcx> {
175 type Result = ControlFlow<()>;
176 type NestedFilter = nested_filter::OnlyBodies;
177
178 fn maybe_tcx(&mut self) -> Self::MaybeTyCtxt {
179 self.tcx
180 }
181
182 fn visit_lifetime(&mut self, lifetime: &hir::Lifetime) -> Self::Result {
183 match self.tcx.named_bound_var(lifetime.hir_id) {
184 Some(rbv::ResolvedArg::EarlyBound(id)) => {
186 debug!("EarlyBound id={:?}", id);
187 if id.to_def_id() == self.region_def_id {
188 return ControlFlow::Break(());
189 }
190 }
191
192 Some(rbv::ResolvedArg::LateBound(debruijn_index, _, id)) => {
193 debug!("FindNestedTypeVisitor::visit_ty: LateBound depth = {:?}", debruijn_index,);
194 debug!("id={:?}", id);
195 if debruijn_index == self.current_index && id.to_def_id() == self.region_def_id {
196 return ControlFlow::Break(());
197 }
198 }
199
200 Some(
201 rbv::ResolvedArg::StaticLifetime
202 | rbv::ResolvedArg::Free(_, _)
203 | rbv::ResolvedArg::Error(_),
204 )
205 | None => {
206 debug!("no arg found");
207 }
208 }
209 ControlFlow::Continue(())
210 }
211
212 fn visit_ty(&mut self, arg: &'tcx hir::Ty<'tcx, AmbigArg>) -> Self::Result {
213 debug!("`Ty` corresponding to a struct is {:?}", arg);
221 ControlFlow::Continue(())
222 }
223}