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 InvalidOpaqueTypeArgs, check_opaque_type_parameter_valid,
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(InvalidOpaqueTypeArgs<'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) = check_opaque_type_parameter_valid(
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 InvalidOpaqueTypeArgs::AlreadyReported(guar) => root_cx
252 .add_concrete_opaque_type(
253 opaque_type_key.def_id,
254 OpaqueHiddenType::new_error(infcx.tcx, guar),
255 ),
256 _ => debug!(?non_nll_opaque_type_key, ?err, "ignoring non-defining use"),
257 }
258 } else {
259 errors.push(DeferredOpaqueTypeError::InvalidOpaqueTypeArgs(err));
260 }
261 continue;
262 }
263
264 let arg_regions = iter::once(rcx.universal_regions().fr_static)
266 .chain(
267 opaque_type_key
268 .iter_captured_args(infcx.tcx)
269 .filter_map(|(_, arg)| arg.as_region())
270 .map(Region::as_var),
271 )
272 .collect();
273 defining_uses.push(DefiningUse {
274 opaque_type_key: non_nll_opaque_type_key,
275 arg_regions,
276 hidden_type,
277 });
278 }
279
280 defining_uses
281}
282
283fn compute_concrete_types_from_defining_uses<'tcx>(
284 root_cx: &mut BorrowCheckRootCtxt<'tcx>,
285 rcx: &RegionCtxt<'_, 'tcx>,
286 defining_uses: &[DefiningUse<'tcx>],
287 errors: &mut Vec<DeferredOpaqueTypeError<'tcx>>,
288) {
289 let infcx = rcx.infcx;
290 let tcx = infcx.tcx;
291 let mut decls_modulo_regions: FxIndexMap<OpaqueTypeKey<'tcx>, (OpaqueTypeKey<'tcx>, Span)> =
292 FxIndexMap::default();
293 for &DefiningUse { opaque_type_key, ref arg_regions, hidden_type } in defining_uses {
294 let hidden_type =
298 match hidden_type.try_fold_with(&mut ToArgRegionsFolder::new(rcx, arg_regions)) {
299 Ok(hidden_type) => hidden_type,
300 Err(r) => {
301 errors.push(DeferredOpaqueTypeError::UnexpectedHiddenRegion {
302 hidden_type,
303 opaque_type_key,
304 member_region: ty::Region::new_var(tcx, r),
305 });
306 let guar = tcx.dcx().span_delayed_bug(
307 hidden_type.span,
308 "opaque type with non-universal region args",
309 );
310 ty::OpaqueHiddenType::new_error(tcx, guar)
311 }
312 };
313
314 let ty = infcx
318 .infer_opaque_definition_from_instantiation(opaque_type_key, hidden_type)
319 .unwrap_or_else(|_| {
320 Ty::new_error_with_message(
321 rcx.infcx.tcx,
322 hidden_type.span,
323 "deferred invalid opaque type args",
324 )
325 });
326
327 if !rcx.infcx.tcx.use_typing_mode_borrowck() {
332 if let ty::Alias(ty::Opaque, alias_ty) = ty.kind()
333 && alias_ty.def_id == opaque_type_key.def_id.to_def_id()
334 && alias_ty.args == opaque_type_key.args
335 {
336 continue;
337 }
338 }
339
340 if let Some((prev_decl_key, prev_span)) = decls_modulo_regions.insert(
347 rcx.infcx.tcx.erase_regions(opaque_type_key),
348 (opaque_type_key, hidden_type.span),
349 ) && let Some((arg1, arg2)) = std::iter::zip(
350 prev_decl_key.iter_captured_args(infcx.tcx).map(|(_, arg)| arg),
351 opaque_type_key.iter_captured_args(infcx.tcx).map(|(_, arg)| arg),
352 )
353 .find(|(arg1, arg2)| arg1 != arg2)
354 {
355 errors.push(DeferredOpaqueTypeError::LifetimeMismatchOpaqueParam(
356 LifetimeMismatchOpaqueParam {
357 arg: arg1,
358 prev: arg2,
359 span: prev_span,
360 prev_span: hidden_type.span,
361 },
362 ));
363 }
364 root_cx.add_concrete_opaque_type(
365 opaque_type_key.def_id,
366 OpaqueHiddenType { span: hidden_type.span, ty },
367 );
368 }
369}
370
371struct ToArgRegionsFolder<'a, 'tcx> {
378 rcx: &'a RegionCtxt<'a, 'tcx>,
379 erase_unknown_regions: bool,
385 arg_regions: &'a [RegionVid],
386}
387
388impl<'a, 'tcx> ToArgRegionsFolder<'a, 'tcx> {
389 fn new(
390 rcx: &'a RegionCtxt<'a, 'tcx>,
391 arg_regions: &'a [RegionVid],
392 ) -> ToArgRegionsFolder<'a, 'tcx> {
393 ToArgRegionsFolder { rcx, erase_unknown_regions: false, arg_regions }
394 }
395
396 fn fold_non_member_arg(&mut self, arg: GenericArg<'tcx>) -> GenericArg<'tcx> {
397 let prev = self.erase_unknown_regions;
398 self.erase_unknown_regions = true;
399 let res = arg.try_fold_with(self).unwrap();
400 self.erase_unknown_regions = prev;
401 res
402 }
403
404 fn fold_closure_args(
405 &mut self,
406 def_id: DefId,
407 args: GenericArgsRef<'tcx>,
408 ) -> Result<GenericArgsRef<'tcx>, RegionVid> {
409 let generics = self.cx().generics_of(def_id);
410 self.cx().mk_args_from_iter(args.iter().enumerate().map(|(index, arg)| {
411 if index < generics.parent_count {
412 Ok(self.fold_non_member_arg(arg))
413 } else {
414 arg.try_fold_with(self)
415 }
416 }))
417 }
418}
419impl<'tcx> FallibleTypeFolder<TyCtxt<'tcx>> for ToArgRegionsFolder<'_, 'tcx> {
420 type Error = RegionVid;
421 fn cx(&self) -> TyCtxt<'tcx> {
422 self.rcx.infcx.tcx
423 }
424
425 fn try_fold_region(&mut self, r: Region<'tcx>) -> Result<Region<'tcx>, RegionVid> {
426 match r.kind() {
427 ty::ReBound(_, _) => Ok(r),
429 _ => {
430 let r = r.as_var();
431 if let Some(arg_region) = self
432 .arg_regions
433 .iter()
434 .copied()
435 .find(|&arg_vid| self.rcx.eval_equal(r, arg_vid))
436 .and_then(|r| nll_var_to_universal_region(self.rcx, r))
437 {
438 Ok(arg_region)
439 } else if self.erase_unknown_regions {
440 Ok(self.cx().lifetimes.re_erased)
441 } else {
442 Err(r)
443 }
444 }
445 }
446 }
447
448 fn try_fold_ty(&mut self, ty: Ty<'tcx>) -> Result<Ty<'tcx>, RegionVid> {
449 if !ty.flags().intersects(ty::TypeFlags::HAS_FREE_REGIONS) {
450 return Ok(ty);
451 }
452
453 let tcx = self.cx();
454 Ok(match *ty.kind() {
455 ty::Closure(def_id, args) => {
456 Ty::new_closure(tcx, def_id, self.fold_closure_args(def_id, args)?)
457 }
458
459 ty::CoroutineClosure(def_id, args) => {
460 Ty::new_coroutine_closure(tcx, def_id, self.fold_closure_args(def_id, args)?)
461 }
462
463 ty::Coroutine(def_id, args) => {
464 Ty::new_coroutine(tcx, def_id, self.fold_closure_args(def_id, args)?)
465 }
466
467 ty::Alias(kind, ty::AliasTy { def_id, args, .. })
468 if let Some(variances) = tcx.opt_alias_variances(kind, def_id) =>
469 {
470 let args = tcx.mk_args_from_iter(std::iter::zip(variances, args.iter()).map(
471 |(&v, s)| {
472 if v == ty::Bivariant {
473 Ok(self.fold_non_member_arg(s))
474 } else {
475 s.try_fold_with(self)
476 }
477 },
478 ))?;
479 ty::AliasTy::new_from_args(tcx, def_id, args).to_ty(tcx)
480 }
481
482 _ => ty.try_super_fold_with(self)?,
483 })
484 }
485}
486
487fn apply_computed_concrete_opaque_types<'tcx>(
494 root_cx: &mut BorrowCheckRootCtxt<'tcx>,
495 infcx: &BorrowckInferCtxt<'tcx>,
496 body: &Body<'tcx>,
497 universal_regions: &UniversalRegions<'tcx>,
498 region_bound_pairs: &RegionBoundPairs<'tcx>,
499 known_type_outlives_obligations: &[ty::PolyTypeOutlivesPredicate<'tcx>],
500 constraints: &mut MirTypeckRegionConstraints<'tcx>,
501 opaque_types: &[(OpaqueTypeKey<'tcx>, OpaqueHiddenType<'tcx>)],
502) -> Vec<DeferredOpaqueTypeError<'tcx>> {
503 let tcx = infcx.tcx;
504 let mut errors = Vec::new();
505 for &(key, hidden_type) in opaque_types {
506 let Some(expected) = root_cx.get_concrete_opaque_type(key.def_id) else {
507 assert!(tcx.use_typing_mode_borrowck(), "non-defining use in defining scope");
508 errors.push(DeferredOpaqueTypeError::NonDefiningUseInDefiningScope {
509 span: hidden_type.span,
510 opaque_type_key: key,
511 });
512 let guar = tcx.dcx().span_delayed_bug(
513 hidden_type.span,
514 "non-defining use in the defining scope with no defining uses",
515 );
516 root_cx.add_concrete_opaque_type(key.def_id, OpaqueHiddenType::new_error(tcx, guar));
517 continue;
518 };
519
520 let expected = ty::fold_regions(tcx, expected.instantiate(tcx, key.args), |re, _dbi| {
522 match re.kind() {
523 ty::ReErased => infcx.next_nll_region_var(
524 NllRegionVariableOrigin::Existential { name: None },
525 || crate::RegionCtxt::Existential(None),
526 ),
527 _ => re,
528 }
529 });
530
531 let locations = Locations::All(hidden_type.span);
533 if let Err(guar) = fully_perform_op_raw(
534 infcx,
535 body,
536 universal_regions,
537 region_bound_pairs,
538 known_type_outlives_obligations,
539 constraints,
540 locations,
541 ConstraintCategory::OpaqueType,
542 CustomTypeOp::new(
543 |ocx| {
544 let cause = ObligationCause::misc(
545 hidden_type.span,
546 body.source.def_id().expect_local(),
547 );
548 let actual_ty = ocx.normalize(&cause, infcx.param_env, hidden_type.ty);
550 let expected_ty = ocx.normalize(&cause, infcx.param_env, expected.ty);
551 ocx.eq(&cause, infcx.param_env, actual_ty, expected_ty).map_err(|_| NoSolution)
552 },
553 "equating opaque types",
554 ),
555 ) {
556 root_cx.add_concrete_opaque_type(key.def_id, OpaqueHiddenType::new_error(tcx, guar));
557 }
558 }
559 errors
560}
561
562fn detect_opaque_types_added_while_handling_opaque_types<'tcx>(
570 infcx: &InferCtxt<'tcx>,
571 opaque_types_storage_num_entries: OpaqueTypeStorageEntries,
572) {
573 for (key, hidden_type) in infcx
574 .inner
575 .borrow_mut()
576 .opaque_types()
577 .opaque_types_added_since(opaque_types_storage_num_entries)
578 {
579 let opaque_type_string = infcx.tcx.def_path_str(key.def_id);
580 let msg = format!("unexpected cyclic definition of `{opaque_type_string}`");
581 infcx.dcx().span_delayed_bug(hidden_type.span, msg);
582 }
583
584 let _ = infcx.take_opaque_types();
585}
586
587impl<'tcx> RegionInferenceContext<'tcx> {
588 pub(crate) fn name_regions_for_member_constraint<T>(&self, tcx: TyCtxt<'tcx>, ty: T) -> T
601 where
602 T: TypeFoldable<TyCtxt<'tcx>>,
603 {
604 fold_regions(tcx, ty, |region, _| match region.kind() {
605 ty::ReVar(vid) => {
606 let scc = self.constraint_sccs.scc(vid);
607
608 if !self.max_nameable_universe(scc).is_root() {
610 match self.scc_values.placeholders_contained_in(scc).enumerate().last() {
611 Some((0, placeholder)) => {
613 return ty::Region::new_placeholder(tcx, placeholder);
614 }
615
616 _ => return region,
618 }
619 }
620
621 let upper_bound = self.approx_universal_upper_bound(vid);
623 if let Some(universal_region) = self.definitions[upper_bound].external_name {
624 return universal_region;
625 }
626
627 let scc = self.constraint_sccs.scc(vid);
632 let rev_scc_graph =
633 ReverseSccGraph::compute(&self.constraint_sccs, self.universal_regions());
634 let upper_bounds: Vec<_> = rev_scc_graph
635 .upper_bounds(scc)
636 .filter_map(|vid| self.definitions[vid].external_name)
637 .filter(|r| !r.is_static())
638 .collect();
639 match &upper_bounds[..] {
640 [universal_region] => *universal_region,
641 _ => region,
642 }
643 }
644 _ => region,
645 })
646 }
647}
648
649#[extension(pub trait InferCtxtExt<'tcx>)]
650impl<'tcx> InferCtxt<'tcx> {
651 #[instrument(level = "debug", skip(self))]
675 fn infer_opaque_definition_from_instantiation(
676 &self,
677 opaque_type_key: OpaqueTypeKey<'tcx>,
678 instantiated_ty: OpaqueHiddenType<'tcx>,
679 ) -> Result<Ty<'tcx>, InvalidOpaqueTypeArgs<'tcx>> {
680 check_opaque_type_parameter_valid(
681 self,
682 opaque_type_key,
683 instantiated_ty.span,
684 DefiningScopeKind::MirBorrowck,
685 )?;
686
687 let definition_ty = instantiated_ty
688 .remap_generic_params_to_declaration_params(
689 opaque_type_key,
690 self.tcx,
691 DefiningScopeKind::MirBorrowck,
692 )
693 .ty;
694
695 definition_ty.error_reported()?;
696 Ok(definition_ty)
697 }
698}