rustc_borrowck/diagnostics/
opaque_types.rs1use std::ops::ControlFlow;
2
3use either::Either;
4use itertools::Itertools as _;
5use rustc_data_structures::fx::FxIndexSet;
6use rustc_errors::{Diag, Subdiagnostic};
7use rustc_hir as hir;
8use rustc_hir::def_id::DefId;
9use rustc_middle::mir::{self, ConstraintCategory, Location};
10use rustc_middle::ty::{
11 self, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, TypeVisitableExt, TypeVisitor,
12};
13use rustc_span::Span;
14use rustc_trait_selection::error_reporting::infer::region::unexpected_hidden_region_diagnostic;
15use rustc_trait_selection::errors::impl_trait_overcapture_suggestion;
16
17use crate::MirBorrowckCtxt;
18use crate::borrow_set::BorrowData;
19use crate::consumers::RegionInferenceContext;
20use crate::region_infer::opaque_types::DeferredOpaqueTypeError;
21use crate::type_check::Locations;
22
23impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
24 pub(crate) fn report_opaque_type_errors(&mut self, errors: Vec<DeferredOpaqueTypeError<'tcx>>) {
25 if errors.is_empty() {
26 return;
27 }
28
29 let infcx = self.infcx;
30 let mut guar = None;
31 let mut last_unexpected_hidden_region: Option<(Span, Ty<'_>, ty::OpaqueTypeKey<'tcx>)> =
32 None;
33 for error in errors {
34 guar = Some(match error {
35 DeferredOpaqueTypeError::InvalidOpaqueTypeArgs(err) => err.report(infcx),
36 DeferredOpaqueTypeError::LifetimeMismatchOpaqueParam(err) => {
37 infcx.dcx().emit_err(err)
38 }
39 DeferredOpaqueTypeError::UnexpectedHiddenRegion {
40 opaque_type_key,
41 hidden_type,
42 member_region,
43 } => {
44 let named_ty =
45 self.regioncx.name_regions_for_member_constraint(infcx.tcx, hidden_type.ty);
46 let named_key = self
47 .regioncx
48 .name_regions_for_member_constraint(infcx.tcx, opaque_type_key);
49 let named_region =
50 self.regioncx.name_regions_for_member_constraint(infcx.tcx, member_region);
51 let diag = unexpected_hidden_region_diagnostic(
52 infcx,
53 self.mir_def_id(),
54 hidden_type.span,
55 named_ty,
56 named_region,
57 named_key,
58 );
59 if last_unexpected_hidden_region
60 != Some((hidden_type.span, named_ty, named_key))
61 {
62 last_unexpected_hidden_region =
63 Some((hidden_type.span, named_ty, named_key));
64 diag.emit()
65 } else {
66 diag.delay_as_bug()
67 }
68 }
69 DeferredOpaqueTypeError::NonDefiningUseInDefiningScope {
70 span,
71 opaque_type_key,
72 } => infcx.dcx().span_err(
73 span,
74 ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("non-defining use of `{0}` in the defining scope",
Ty::new_opaque(infcx.tcx, opaque_type_key.def_id.to_def_id(),
opaque_type_key.args)))
})format!(
75 "non-defining use of `{}` in the defining scope",
76 Ty::new_opaque(
77 infcx.tcx,
78 opaque_type_key.def_id.to_def_id(),
79 opaque_type_key.args
80 )
81 ),
82 ),
83 });
84 }
85 let guar = guar.unwrap();
86 self.root_cx.set_tainted_by_errors(guar);
87 self.infcx.set_tainted_by_errors(guar);
88 }
89
90 pub(crate) fn note_due_to_edition_2024_opaque_capture_rules(
95 &self,
96 borrow: &BorrowData<'tcx>,
97 diag: &mut Diag<'_>,
98 ) {
99 for ty in self.body.local_decls.iter().map(|local| local.ty) {
103 if !ty.has_opaque_types() {
104 continue;
105 }
106
107 let tcx = self.infcx.tcx;
108 let ControlFlow::Break((opaque_def_id, offending_region_idx, location)) = ty
109 .visit_with(&mut FindOpaqueRegion {
110 regioncx: &self.regioncx,
111 tcx,
112 borrow_region: borrow.region,
113 })
114 else {
115 continue;
116 };
117
118 if tcx.rendered_precise_capturing_args(opaque_def_id).is_some() {
121 continue;
122 }
123
124 let mut visitor = CheckExplicitRegionMentionAndCollectGenerics {
130 tcx,
131 generics: tcx.generics_of(opaque_def_id),
132 offending_region_idx,
133 seen_opaques: [opaque_def_id].into_iter().collect(),
134 seen_lifetimes: Default::default(),
135 };
136 if tcx
137 .explicit_item_bounds(opaque_def_id)
138 .skip_binder()
139 .visit_with(&mut visitor)
140 .is_break()
141 {
142 continue;
143 }
144
145 match self.body.stmt_at(location) {
148 Either::Right(mir::Terminator { source_info, .. }) => {
149 diag.span_note(
150 source_info.span,
151 "this call may capture more lifetimes than intended, \
152 because Rust 2024 has adjusted the `impl Trait` lifetime capture rules",
153 );
154 let mut captured_args = visitor.seen_lifetimes;
155 let mut next_generics = Some(visitor.generics);
159 let mut any_synthetic = false;
160 while let Some(generics) = next_generics {
161 for param in &generics.own_params {
162 if param.kind.is_ty_or_const() {
163 captured_args.insert(param.def_id);
164 }
165 if param.kind.is_synthetic() {
166 any_synthetic = true;
167 }
168 }
169 next_generics = generics.parent.map(|def_id| tcx.generics_of(def_id));
170 }
171
172 if let Some(opaque_def_id) = opaque_def_id.as_local()
173 && let hir::OpaqueTyOrigin::FnReturn { parent, .. } =
174 tcx.hir_expect_opaque_ty(opaque_def_id).origin
175 {
176 if let Some(sugg) = impl_trait_overcapture_suggestion(
177 tcx,
178 opaque_def_id,
179 parent,
180 captured_args,
181 ) {
182 sugg.add_to_diag(diag);
183 }
184 } else {
185 diag.span_help(
186 tcx.def_span(opaque_def_id),
187 ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("if you can modify this crate, add a precise capturing bound to avoid overcapturing: `+ use<{0}>`",
if any_synthetic {
"/* Args */".to_string()
} else {
captured_args.into_iter().map(|def_id|
tcx.item_name(def_id)).join(", ")
}))
})format!(
188 "if you can modify this crate, add a precise \
189 capturing bound to avoid overcapturing: `+ use<{}>`",
190 if any_synthetic {
191 "/* Args */".to_string()
192 } else {
193 captured_args
194 .into_iter()
195 .map(|def_id| tcx.item_name(def_id))
196 .join(", ")
197 }
198 ),
199 );
200 }
201 return;
202 }
203 Either::Left(_) => {}
204 }
205 }
206 }
207}
208
209struct FindOpaqueRegion<'a, 'tcx> {
211 tcx: TyCtxt<'tcx>,
212 regioncx: &'a RegionInferenceContext<'tcx>,
213 borrow_region: ty::RegionVid,
214}
215
216impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for FindOpaqueRegion<'_, 'tcx> {
217 type Result = ControlFlow<(DefId, usize, Location), ()>;
218
219 fn visit_ty(&mut self, ty: Ty<'tcx>) -> Self::Result {
220 if let ty::Alias(opaque @ ty::AliasTy { kind: ty::Opaque { def_id }, .. }) = *ty.kind()
223 && let hir::OpaqueTyOrigin::FnReturn { parent, in_trait_or_impl: None } =
224 self.tcx.opaque_ty_origin(def_id)
225 {
226 let variances = self.tcx.variances_of(def_id);
227 for (idx, (arg, variance)) in std::iter::zip(opaque.args, variances).enumerate() {
228 if *variance == ty::Bivariant {
230 continue;
231 }
232 let Some(opaque_region) = arg.as_region() else {
234 continue;
235 };
236 if opaque_region.is_bound() {
238 continue;
239 }
240 let opaque_region_vid = self.regioncx.to_region_vid(opaque_region);
241
242 if let Some(path) = self
244 .regioncx
245 .constraint_path_between_regions(self.borrow_region, opaque_region_vid)
246 {
247 for constraint in path {
248 if let ConstraintCategory::CallArgument(Some(call_ty)) = constraint.category
250 && let ty::FnDef(call_def_id, _) = *call_ty.kind()
251 && call_def_id == parent
253 && let Locations::Single(location) = constraint.locations
254 {
255 return ControlFlow::Break((def_id, idx, location));
256 }
257 }
258 }
259 }
260 }
261
262 ty.super_visit_with(self)
263 }
264}
265
266struct CheckExplicitRegionMentionAndCollectGenerics<'tcx> {
267 tcx: TyCtxt<'tcx>,
268 generics: &'tcx ty::Generics,
269 offending_region_idx: usize,
270 seen_opaques: FxIndexSet<DefId>,
271 seen_lifetimes: FxIndexSet<DefId>,
272}
273
274impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for CheckExplicitRegionMentionAndCollectGenerics<'tcx> {
275 type Result = ControlFlow<(), ()>;
276
277 fn visit_ty(&mut self, ty: Ty<'tcx>) -> Self::Result {
278 match *ty.kind() {
279 ty::Alias(opaque @ ty::AliasTy { kind: ty::Opaque { def_id }, .. }) => {
280 if self.seen_opaques.insert(def_id) {
281 for (bound, _) in self
282 .tcx
283 .explicit_item_bounds(def_id)
284 .iter_instantiated_copied(self.tcx, opaque.args)
285 {
286 bound.visit_with(self)?;
287 }
288 }
289 ControlFlow::Continue(())
290 }
291 _ => ty.super_visit_with(self),
292 }
293 }
294
295 fn visit_region(&mut self, r: ty::Region<'tcx>) -> Self::Result {
296 match r.kind() {
297 ty::ReEarlyParam(param) => {
298 if param.index as usize == self.offending_region_idx {
299 ControlFlow::Break(())
300 } else {
301 self.seen_lifetimes.insert(self.generics.region_param(param, self.tcx).def_id);
302 ControlFlow::Continue(())
303 }
304 }
305 _ => ControlFlow::Continue(()),
306 }
307 }
308}