1use std::iter;
2use std::rc::Rc;
3
4use rustc_data_structures::frozen::Frozen;
5use rustc_data_structures::fx::FxIndexMap;
6use rustc_hir::def_id::DefId;
7use rustc_infer::infer::outlives::env::RegionBoundPairs;
8use rustc_infer::infer::{InferCtxt, NllRegionVariableOrigin, OpaqueTypeStorageEntries};
9use rustc_infer::traits::ObligationCause;
10use rustc_macros::extension;
11use rustc_middle::mir::{Body, ConstraintCategory};
12use rustc_middle::ty::{
13 self, DefiningScopeKind, FallibleTypeFolder, GenericArg, GenericArgsRef, OpaqueHiddenType,
14 OpaqueTypeKey, Region, RegionVid, Ty, TyCtxt, TypeFoldable, TypeSuperFoldable,
15 TypeVisitableExt, fold_regions,
16};
17use rustc_mir_dataflow::points::DenseLocationMap;
18use rustc_span::Span;
19use rustc_trait_selection::opaque_types::{
20 NonDefiningUseReason, opaque_type_has_defining_use_args,
21};
22use rustc_trait_selection::solve::NoSolution;
23use rustc_trait_selection::traits::query::type_op::custom::CustomTypeOp;
24use tracing::{debug, instrument};
25
26use super::reverse_sccs::ReverseSccGraph;
27use crate::consumers::RegionInferenceContext;
28use crate::session_diagnostics::LifetimeMismatchOpaqueParam;
29use crate::type_check::canonical::fully_perform_op_raw;
30use crate::type_check::free_region_relations::UniversalRegionRelations;
31use crate::type_check::{Locations, MirTypeckRegionConstraints};
32use crate::universal_regions::{RegionClassification, UniversalRegions};
33use crate::{BorrowCheckRootCtxt, BorrowckInferCtxt};
34
35mod member_constraints;
36mod region_ctxt;
37
38use member_constraints::apply_member_constraints;
39use region_ctxt::RegionCtxt;
40
41pub(crate) enum DeferredOpaqueTypeError<'tcx> {
45 InvalidOpaqueTypeArgs(NonDefiningUseReason<'tcx>),
46 LifetimeMismatchOpaqueParam(LifetimeMismatchOpaqueParam<'tcx>),
47 UnexpectedHiddenRegion {
48 opaque_type_key: OpaqueTypeKey<'tcx>,
50 hidden_type: OpaqueHiddenType<'tcx>,
52 member_region: Region<'tcx>,
54 },
55 NonDefiningUseInDefiningScope {
56 span: Span,
57 opaque_type_key: OpaqueTypeKey<'tcx>,
58 },
59}
60
61pub(crate) fn handle_opaque_type_uses<'tcx>(
69 root_cx: &mut BorrowCheckRootCtxt<'tcx>,
70 infcx: &BorrowckInferCtxt<'tcx>,
71 body: &Body<'tcx>,
72 universal_region_relations: &Frozen<UniversalRegionRelations<'tcx>>,
73 region_bound_pairs: &RegionBoundPairs<'tcx>,
74 known_type_outlives_obligations: &[ty::PolyTypeOutlivesPredicate<'tcx>],
75 location_map: &Rc<DenseLocationMap>,
76 constraints: &mut MirTypeckRegionConstraints<'tcx>,
77) -> Vec<DeferredOpaqueTypeError<'tcx>> {
78 let tcx = infcx.tcx;
79 let opaque_types = infcx.clone_opaque_types();
80 if opaque_types.is_empty() {
81 return Vec::new();
82 }
83
84 let opaque_types_storage_num_entries = infcx.inner.borrow_mut().opaque_types().num_entries();
90 let opaque_types = opaque_types
91 .into_iter()
92 .map(|entry| {
93 fold_regions(tcx, infcx.resolve_vars_if_possible(entry), |r, _| {
94 let vid = if let ty::RePlaceholder(placeholder) = r.kind() {
95 constraints.placeholder_region(infcx, placeholder).as_var()
96 } else {
97 universal_region_relations.universal_regions.to_region_vid(r)
98 };
99 Region::new_var(tcx, vid)
100 })
101 })
102 .collect::<Vec<_>>();
103
104 debug!(?opaque_types);
105
106 let errors = compute_concrete_opaque_types(
107 root_cx,
108 infcx,
109 constraints,
110 universal_region_relations,
111 Rc::clone(location_map),
112 &opaque_types,
113 );
114
115 if !errors.is_empty() {
116 return errors;
117 }
118
119 let errors = apply_computed_concrete_opaque_types(
120 root_cx,
121 infcx,
122 body,
123 &universal_region_relations.universal_regions,
124 region_bound_pairs,
125 known_type_outlives_obligations,
126 constraints,
127 &opaque_types,
128 );
129
130 detect_opaque_types_added_while_handling_opaque_types(infcx, opaque_types_storage_num_entries);
131
132 errors
133}
134
135fn nll_var_to_universal_region<'tcx>(
143 rcx: &RegionCtxt<'_, 'tcx>,
144 r: RegionVid,
145) -> Option<Region<'tcx>> {
146 let vid = rcx.representative(r).rvid();
149 match rcx.definitions[vid].origin {
150 NllRegionVariableOrigin::FreeRegion => rcx
155 .universal_regions()
156 .universal_regions_iter()
157 .filter(|&ur| {
158 !matches!(
160 rcx.universal_regions().region_classification(ur),
161 Some(RegionClassification::External)
162 )
163 })
164 .find(|&ur| rcx.universal_region_relations.equal(vid, ur))
165 .map(|ur| rcx.definitions[ur].external_name.unwrap()),
166 NllRegionVariableOrigin::Placeholder(placeholder) => {
167 Some(ty::Region::new_placeholder(rcx.infcx.tcx, placeholder))
168 }
169 NllRegionVariableOrigin::Existential { .. } => None,
172 }
173}
174
175#[derive(Debug)]
176struct DefiningUse<'tcx> {
177 opaque_type_key: OpaqueTypeKey<'tcx>,
181 arg_regions: Vec<RegionVid>,
182 hidden_type: OpaqueHiddenType<'tcx>,
183}
184
185fn compute_concrete_opaque_types<'tcx>(
197 root_cx: &mut BorrowCheckRootCtxt<'tcx>,
198 infcx: &BorrowckInferCtxt<'tcx>,
199 constraints: &MirTypeckRegionConstraints<'tcx>,
200 universal_region_relations: &Frozen<UniversalRegionRelations<'tcx>>,
201 location_map: Rc<DenseLocationMap>,
202 opaque_types: &[(OpaqueTypeKey<'tcx>, OpaqueHiddenType<'tcx>)],
203) -> Vec<DeferredOpaqueTypeError<'tcx>> {
204 let mut errors = Vec::new();
205 let mut rcx = RegionCtxt::new(infcx, universal_region_relations, location_map, constraints);
210
211 let defining_uses = collect_defining_uses(root_cx, &mut rcx, opaque_types, &mut errors);
215
216 apply_member_constraints(&mut rcx, &defining_uses);
220
221 compute_concrete_types_from_defining_uses(root_cx, &rcx, &defining_uses, &mut errors);
225 errors
226}
227
228#[instrument(level = "debug", skip_all, ret)]
229fn collect_defining_uses<'tcx>(
230 root_cx: &mut BorrowCheckRootCtxt<'tcx>,
231 rcx: &mut RegionCtxt<'_, 'tcx>,
232 opaque_types: &[(OpaqueTypeKey<'tcx>, OpaqueHiddenType<'tcx>)],
233 errors: &mut Vec<DeferredOpaqueTypeError<'tcx>>,
234) -> Vec<DefiningUse<'tcx>> {
235 let infcx = rcx.infcx;
236 let mut defining_uses = vec![];
237 for &(opaque_type_key, hidden_type) in opaque_types {
238 let non_nll_opaque_type_key = opaque_type_key.fold_captured_lifetime_args(infcx.tcx, |r| {
239 nll_var_to_universal_region(&rcx, r.as_var()).unwrap_or(r)
240 });
241 if let Err(err) = opaque_type_has_defining_use_args(
242 infcx,
243 non_nll_opaque_type_key,
244 hidden_type.span,
245 DefiningScopeKind::MirBorrowck,
246 ) {
247 if infcx.tcx.use_typing_mode_borrowck() {
250 match err {
251 NonDefiningUseReason::Tainted(guar) => root_cx.add_concrete_opaque_type(
252 opaque_type_key.def_id,
253 OpaqueHiddenType::new_error(infcx.tcx, guar),
254 ),
255 _ => debug!(?non_nll_opaque_type_key, ?err, "ignoring non-defining use"),
256 }
257 } else {
258 errors.push(DeferredOpaqueTypeError::InvalidOpaqueTypeArgs(err));
259 }
260 continue;
261 }
262
263 let arg_regions = iter::once(rcx.universal_regions().fr_static)
265 .chain(
266 opaque_type_key
267 .iter_captured_args(infcx.tcx)
268 .filter_map(|(_, arg)| arg.as_region())
269 .map(Region::as_var),
270 )
271 .collect();
272 defining_uses.push(DefiningUse {
273 opaque_type_key: non_nll_opaque_type_key,
274 arg_regions,
275 hidden_type,
276 });
277 }
278
279 defining_uses
280}
281
282fn compute_concrete_types_from_defining_uses<'tcx>(
283 root_cx: &mut BorrowCheckRootCtxt<'tcx>,
284 rcx: &RegionCtxt<'_, 'tcx>,
285 defining_uses: &[DefiningUse<'tcx>],
286 errors: &mut Vec<DeferredOpaqueTypeError<'tcx>>,
287) {
288 let infcx = rcx.infcx;
289 let tcx = infcx.tcx;
290 let mut decls_modulo_regions: FxIndexMap<OpaqueTypeKey<'tcx>, (OpaqueTypeKey<'tcx>, Span)> =
291 FxIndexMap::default();
292 for &DefiningUse { opaque_type_key, ref arg_regions, hidden_type } in defining_uses {
293 let hidden_type =
297 match hidden_type.try_fold_with(&mut ToArgRegionsFolder::new(rcx, arg_regions)) {
298 Ok(hidden_type) => hidden_type,
299 Err(r) => {
300 errors.push(DeferredOpaqueTypeError::UnexpectedHiddenRegion {
301 hidden_type,
302 opaque_type_key,
303 member_region: ty::Region::new_var(tcx, r),
304 });
305 let guar = tcx.dcx().span_delayed_bug(
306 hidden_type.span,
307 "opaque type with non-universal region args",
308 );
309 ty::OpaqueHiddenType::new_error(tcx, guar)
310 }
311 };
312
313 let ty = infcx
317 .infer_opaque_definition_from_instantiation(opaque_type_key, hidden_type)
318 .unwrap_or_else(|_| {
319 Ty::new_error_with_message(
320 rcx.infcx.tcx,
321 hidden_type.span,
322 "deferred invalid opaque type args",
323 )
324 });
325
326 if !rcx.infcx.tcx.use_typing_mode_borrowck() {
331 if let ty::Alias(ty::Opaque, alias_ty) = ty.kind()
332 && alias_ty.def_id == opaque_type_key.def_id.to_def_id()
333 && alias_ty.args == opaque_type_key.args
334 {
335 continue;
336 }
337 }
338
339 if let Some((prev_decl_key, prev_span)) = decls_modulo_regions.insert(
346 rcx.infcx.tcx.erase_regions(opaque_type_key),
347 (opaque_type_key, hidden_type.span),
348 ) && let Some((arg1, arg2)) = std::iter::zip(
349 prev_decl_key.iter_captured_args(infcx.tcx).map(|(_, arg)| arg),
350 opaque_type_key.iter_captured_args(infcx.tcx).map(|(_, arg)| arg),
351 )
352 .find(|(arg1, arg2)| arg1 != arg2)
353 {
354 errors.push(DeferredOpaqueTypeError::LifetimeMismatchOpaqueParam(
355 LifetimeMismatchOpaqueParam {
356 arg: arg1,
357 prev: arg2,
358 span: prev_span,
359 prev_span: hidden_type.span,
360 },
361 ));
362 }
363 root_cx.add_concrete_opaque_type(
364 opaque_type_key.def_id,
365 OpaqueHiddenType { span: hidden_type.span, ty },
366 );
367 }
368}
369
370struct ToArgRegionsFolder<'a, 'tcx> {
377 rcx: &'a RegionCtxt<'a, 'tcx>,
378 erase_unknown_regions: bool,
384 arg_regions: &'a [RegionVid],
385}
386
387impl<'a, 'tcx> ToArgRegionsFolder<'a, 'tcx> {
388 fn new(
389 rcx: &'a RegionCtxt<'a, 'tcx>,
390 arg_regions: &'a [RegionVid],
391 ) -> ToArgRegionsFolder<'a, 'tcx> {
392 ToArgRegionsFolder { rcx, erase_unknown_regions: false, arg_regions }
393 }
394
395 fn fold_non_member_arg(&mut self, arg: GenericArg<'tcx>) -> GenericArg<'tcx> {
396 let prev = self.erase_unknown_regions;
397 self.erase_unknown_regions = true;
398 let res = arg.try_fold_with(self).unwrap();
399 self.erase_unknown_regions = prev;
400 res
401 }
402
403 fn fold_closure_args(
404 &mut self,
405 def_id: DefId,
406 args: GenericArgsRef<'tcx>,
407 ) -> Result<GenericArgsRef<'tcx>, RegionVid> {
408 let generics = self.cx().generics_of(def_id);
409 self.cx().mk_args_from_iter(args.iter().enumerate().map(|(index, arg)| {
410 if index < generics.parent_count {
411 Ok(self.fold_non_member_arg(arg))
412 } else {
413 arg.try_fold_with(self)
414 }
415 }))
416 }
417}
418impl<'tcx> FallibleTypeFolder<TyCtxt<'tcx>> for ToArgRegionsFolder<'_, 'tcx> {
419 type Error = RegionVid;
420 fn cx(&self) -> TyCtxt<'tcx> {
421 self.rcx.infcx.tcx
422 }
423
424 fn try_fold_region(&mut self, r: Region<'tcx>) -> Result<Region<'tcx>, RegionVid> {
425 match r.kind() {
426 ty::ReBound(_, _) => Ok(r),
428 _ => {
429 let r = r.as_var();
430 if let Some(arg_region) = self
431 .arg_regions
432 .iter()
433 .copied()
434 .find(|&arg_vid| self.rcx.eval_equal(r, arg_vid))
435 .and_then(|r| nll_var_to_universal_region(self.rcx, r))
436 {
437 Ok(arg_region)
438 } else if self.erase_unknown_regions {
439 Ok(self.cx().lifetimes.re_erased)
440 } else {
441 Err(r)
442 }
443 }
444 }
445 }
446
447 fn try_fold_ty(&mut self, ty: Ty<'tcx>) -> Result<Ty<'tcx>, RegionVid> {
448 if !ty.flags().intersects(ty::TypeFlags::HAS_FREE_REGIONS) {
449 return Ok(ty);
450 }
451
452 let tcx = self.cx();
453 Ok(match *ty.kind() {
454 ty::Closure(def_id, args) => {
455 Ty::new_closure(tcx, def_id, self.fold_closure_args(def_id, args)?)
456 }
457
458 ty::CoroutineClosure(def_id, args) => {
459 Ty::new_coroutine_closure(tcx, def_id, self.fold_closure_args(def_id, args)?)
460 }
461
462 ty::Coroutine(def_id, args) => {
463 Ty::new_coroutine(tcx, def_id, self.fold_closure_args(def_id, args)?)
464 }
465
466 ty::Alias(kind, ty::AliasTy { def_id, args, .. })
467 if let Some(variances) = tcx.opt_alias_variances(kind, def_id) =>
468 {
469 let args = tcx.mk_args_from_iter(std::iter::zip(variances, args.iter()).map(
470 |(&v, s)| {
471 if v == ty::Bivariant {
472 Ok(self.fold_non_member_arg(s))
473 } else {
474 s.try_fold_with(self)
475 }
476 },
477 ))?;
478 ty::AliasTy::new_from_args(tcx, def_id, args).to_ty(tcx)
479 }
480
481 _ => ty.try_super_fold_with(self)?,
482 })
483 }
484}
485
486fn apply_computed_concrete_opaque_types<'tcx>(
493 root_cx: &mut BorrowCheckRootCtxt<'tcx>,
494 infcx: &BorrowckInferCtxt<'tcx>,
495 body: &Body<'tcx>,
496 universal_regions: &UniversalRegions<'tcx>,
497 region_bound_pairs: &RegionBoundPairs<'tcx>,
498 known_type_outlives_obligations: &[ty::PolyTypeOutlivesPredicate<'tcx>],
499 constraints: &mut MirTypeckRegionConstraints<'tcx>,
500 opaque_types: &[(OpaqueTypeKey<'tcx>, OpaqueHiddenType<'tcx>)],
501) -> Vec<DeferredOpaqueTypeError<'tcx>> {
502 let tcx = infcx.tcx;
503 let mut errors = Vec::new();
504 for &(key, hidden_type) in opaque_types {
505 let Some(expected) = root_cx.get_concrete_opaque_type(key.def_id) else {
506 assert!(tcx.use_typing_mode_borrowck(), "non-defining use in defining scope");
507 errors.push(DeferredOpaqueTypeError::NonDefiningUseInDefiningScope {
508 span: hidden_type.span,
509 opaque_type_key: key,
510 });
511 let guar = tcx.dcx().span_delayed_bug(
512 hidden_type.span,
513 "non-defining use in the defining scope with no defining uses",
514 );
515 root_cx.add_concrete_opaque_type(key.def_id, OpaqueHiddenType::new_error(tcx, guar));
516 continue;
517 };
518
519 let expected = ty::fold_regions(tcx, expected.instantiate(tcx, key.args), |re, _dbi| {
521 match re.kind() {
522 ty::ReErased => infcx.next_nll_region_var(
523 NllRegionVariableOrigin::Existential { name: None },
524 || crate::RegionCtxt::Existential(None),
525 ),
526 _ => re,
527 }
528 });
529
530 let locations = Locations::All(hidden_type.span);
532 if let Err(guar) = fully_perform_op_raw(
533 infcx,
534 body,
535 universal_regions,
536 region_bound_pairs,
537 known_type_outlives_obligations,
538 constraints,
539 locations,
540 ConstraintCategory::OpaqueType,
541 CustomTypeOp::new(
542 |ocx| {
543 let cause = ObligationCause::misc(
544 hidden_type.span,
545 body.source.def_id().expect_local(),
546 );
547 let actual_ty = ocx.normalize(&cause, infcx.param_env, hidden_type.ty);
549 let expected_ty = ocx.normalize(&cause, infcx.param_env, expected.ty);
550 ocx.eq(&cause, infcx.param_env, actual_ty, expected_ty).map_err(|_| NoSolution)
551 },
552 "equating opaque types",
553 ),
554 ) {
555 root_cx.add_concrete_opaque_type(key.def_id, OpaqueHiddenType::new_error(tcx, guar));
556 }
557 }
558 errors
559}
560
561fn detect_opaque_types_added_while_handling_opaque_types<'tcx>(
569 infcx: &InferCtxt<'tcx>,
570 opaque_types_storage_num_entries: OpaqueTypeStorageEntries,
571) {
572 for (key, hidden_type) in infcx
573 .inner
574 .borrow_mut()
575 .opaque_types()
576 .opaque_types_added_since(opaque_types_storage_num_entries)
577 {
578 let opaque_type_string = infcx.tcx.def_path_str(key.def_id);
579 let msg = format!("unexpected cyclic definition of `{opaque_type_string}`");
580 infcx.dcx().span_delayed_bug(hidden_type.span, msg);
581 }
582
583 let _ = infcx.take_opaque_types();
584}
585
586impl<'tcx> RegionInferenceContext<'tcx> {
587 pub(crate) fn name_regions_for_member_constraint<T>(&self, tcx: TyCtxt<'tcx>, ty: T) -> T
600 where
601 T: TypeFoldable<TyCtxt<'tcx>>,
602 {
603 fold_regions(tcx, ty, |region, _| match region.kind() {
604 ty::ReVar(vid) => {
605 let scc = self.constraint_sccs.scc(vid);
606
607 if !self.max_nameable_universe(scc).is_root() {
609 match self.scc_values.placeholders_contained_in(scc).enumerate().last() {
610 Some((0, placeholder)) => {
612 return ty::Region::new_placeholder(tcx, placeholder);
613 }
614
615 _ => return region,
617 }
618 }
619
620 let upper_bound = self.approx_universal_upper_bound(vid);
622 if let Some(universal_region) = self.definitions[upper_bound].external_name {
623 return universal_region;
624 }
625
626 let scc = self.constraint_sccs.scc(vid);
631 let rev_scc_graph =
632 ReverseSccGraph::compute(&self.constraint_sccs, self.universal_regions());
633 let upper_bounds: Vec<_> = rev_scc_graph
634 .upper_bounds(scc)
635 .filter_map(|vid| self.definitions[vid].external_name)
636 .filter(|r| !r.is_static())
637 .collect();
638 match &upper_bounds[..] {
639 [universal_region] => *universal_region,
640 _ => region,
641 }
642 }
643 _ => region,
644 })
645 }
646}
647
648#[extension(pub trait InferCtxtExt<'tcx>)]
649impl<'tcx> InferCtxt<'tcx> {
650 #[instrument(level = "debug", skip(self))]
674 fn infer_opaque_definition_from_instantiation(
675 &self,
676 opaque_type_key: OpaqueTypeKey<'tcx>,
677 instantiated_ty: OpaqueHiddenType<'tcx>,
678 ) -> Result<Ty<'tcx>, NonDefiningUseReason<'tcx>> {
679 opaque_type_has_defining_use_args(
680 self,
681 opaque_type_key,
682 instantiated_ty.span,
683 DefiningScopeKind::MirBorrowck,
684 )?;
685
686 let definition_ty = instantiated_ty
687 .remap_generic_params_to_declaration_params(
688 opaque_type_key,
689 self.tcx,
690 DefiningScopeKind::MirBorrowck,
691 )
692 .ty;
693
694 definition_ty.error_reported()?;
695 Ok(definition_ty)
696 }
697}