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