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, LocalDefId};
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, ConcreteOpaqueTypes, ConstraintCategory};
12use rustc_middle::ty::{
13 self, DefiningScopeKind, EarlyBinder, FallibleTypeFolder, GenericArg, GenericArgsRef,
14 OpaqueHiddenType, OpaqueTypeKey, Region, RegionVid, Ty, TyCtxt, TypeFoldable,
15 TypeSuperFoldable, 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::BorrowckInferCtxt;
28use crate::consumers::RegionInferenceContext;
29use crate::session_diagnostics::LifetimeMismatchOpaqueParam;
30use crate::type_check::canonical::fully_perform_op_raw;
31use crate::type_check::free_region_relations::UniversalRegionRelations;
32use crate::type_check::{Locations, MirTypeckRegionConstraints};
33use crate::universal_regions::{RegionClassification, UniversalRegions};
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 clone_and_resolve_opaque_types<'tcx>(
67 infcx: &BorrowckInferCtxt<'tcx>,
68 universal_region_relations: &Frozen<UniversalRegionRelations<'tcx>>,
69 constraints: &mut MirTypeckRegionConstraints<'tcx>,
70) -> (OpaqueTypeStorageEntries, Vec<(OpaqueTypeKey<'tcx>, OpaqueHiddenType<'tcx>)>) {
71 let opaque_types = infcx.clone_opaque_types();
72 let opaque_types_storage_num_entries = infcx.inner.borrow_mut().opaque_types().num_entries();
73 let opaque_types = opaque_types
74 .into_iter()
75 .map(|entry| {
76 fold_regions(infcx.tcx, infcx.resolve_vars_if_possible(entry), |r, _| {
77 let vid = if let ty::RePlaceholder(placeholder) = r.kind() {
78 constraints.placeholder_region(infcx, placeholder).as_var()
79 } else {
80 universal_region_relations.universal_regions.to_region_vid(r)
81 };
82 Region::new_var(infcx.tcx, vid)
83 })
84 })
85 .collect::<Vec<_>>();
86 (opaque_types_storage_num_entries, opaque_types)
87}
88
89fn nll_var_to_universal_region<'tcx>(
97 rcx: &RegionCtxt<'_, 'tcx>,
98 r: RegionVid,
99) -> Option<Region<'tcx>> {
100 let vid = rcx.representative(r).rvid();
103 match rcx.definitions[vid].origin {
104 NllRegionVariableOrigin::FreeRegion => rcx
109 .universal_regions()
110 .universal_regions_iter()
111 .filter(|&ur| {
112 !matches!(
114 rcx.universal_regions().region_classification(ur),
115 Some(RegionClassification::External)
116 )
117 })
118 .find(|&ur| rcx.universal_region_relations.equal(vid, ur))
119 .map(|ur| rcx.definitions[ur].external_name.unwrap()),
120 NllRegionVariableOrigin::Placeholder(placeholder) => {
121 Some(ty::Region::new_placeholder(rcx.infcx.tcx, placeholder))
122 }
123 NllRegionVariableOrigin::Existential { .. } => None,
126 }
127}
128
129fn add_concrete_opaque_type<'tcx>(
133 tcx: TyCtxt<'tcx>,
134 concrete_opaque_types: &mut ConcreteOpaqueTypes<'tcx>,
135 def_id: LocalDefId,
136 hidden_ty: OpaqueHiddenType<'tcx>,
137) {
138 if let Some(prev) = concrete_opaque_types.0.get_mut(&def_id) {
143 if prev.ty != hidden_ty.ty {
144 let guar = hidden_ty.ty.error_reported().err().unwrap_or_else(|| {
145 let (Ok(e) | Err(e)) = prev.build_mismatch_error(&hidden_ty, tcx).map(|d| d.emit());
146 e
147 });
148 prev.ty = Ty::new_error(tcx, guar);
149 }
150 prev.span = prev.span.substitute_dummy(hidden_ty.span);
153 } else {
154 concrete_opaque_types.0.insert(def_id, hidden_ty);
155 }
156}
157
158fn get_concrete_opaque_type<'tcx>(
159 concrete_opaque_types: &ConcreteOpaqueTypes<'tcx>,
160 def_id: LocalDefId,
161) -> Option<EarlyBinder<'tcx, OpaqueHiddenType<'tcx>>> {
162 concrete_opaque_types.0.get(&def_id).map(|ty| EarlyBinder::bind(*ty))
163}
164
165#[derive(Debug)]
166struct DefiningUse<'tcx> {
167 opaque_type_key: OpaqueTypeKey<'tcx>,
171 arg_regions: Vec<RegionVid>,
172 hidden_type: OpaqueHiddenType<'tcx>,
173}
174
175pub(crate) fn compute_concrete_opaque_types<'tcx>(
187 infcx: &BorrowckInferCtxt<'tcx>,
188 universal_region_relations: &Frozen<UniversalRegionRelations<'tcx>>,
189 constraints: &MirTypeckRegionConstraints<'tcx>,
190 location_map: Rc<DenseLocationMap>,
191 concrete_opaque_types: &mut ConcreteOpaqueTypes<'tcx>,
192 opaque_types: &[(OpaqueTypeKey<'tcx>, OpaqueHiddenType<'tcx>)],
193) -> Vec<DeferredOpaqueTypeError<'tcx>> {
194 let mut errors = Vec::new();
195 let mut rcx = RegionCtxt::new(infcx, universal_region_relations, location_map, constraints);
200
201 let defining_uses =
205 collect_defining_uses(&mut rcx, concrete_opaque_types, opaque_types, &mut errors);
206
207 apply_member_constraints(&mut rcx, &defining_uses);
211
212 compute_concrete_types_from_defining_uses(
216 &rcx,
217 concrete_opaque_types,
218 &defining_uses,
219 &mut errors,
220 );
221 errors
222}
223
224#[instrument(level = "debug", skip_all, ret)]
225fn collect_defining_uses<'tcx>(
226 rcx: &mut RegionCtxt<'_, 'tcx>,
227 concrete_opaque_types: &mut ConcreteOpaqueTypes<'tcx>,
228 opaque_types: &[(OpaqueTypeKey<'tcx>, OpaqueHiddenType<'tcx>)],
229 errors: &mut Vec<DeferredOpaqueTypeError<'tcx>>,
230) -> Vec<DefiningUse<'tcx>> {
231 let infcx = rcx.infcx;
232 let mut defining_uses = vec![];
233 for &(opaque_type_key, hidden_type) in opaque_types {
234 let non_nll_opaque_type_key = opaque_type_key.fold_captured_lifetime_args(infcx.tcx, |r| {
235 nll_var_to_universal_region(&rcx, r.as_var()).unwrap_or(r)
236 });
237 if let Err(err) = opaque_type_has_defining_use_args(
238 infcx,
239 non_nll_opaque_type_key,
240 hidden_type.span,
241 DefiningScopeKind::MirBorrowck,
242 ) {
243 if infcx.tcx.use_typing_mode_borrowck() {
246 match err {
247 NonDefiningUseReason::Tainted(guar) => add_concrete_opaque_type(
248 infcx.tcx,
249 concrete_opaque_types,
250 opaque_type_key.def_id,
251 OpaqueHiddenType::new_error(infcx.tcx, guar),
252 ),
253 _ => debug!(?non_nll_opaque_type_key, ?err, "ignoring non-defining use"),
254 }
255 } else {
256 errors.push(DeferredOpaqueTypeError::InvalidOpaqueTypeArgs(err));
257 }
258 continue;
259 }
260
261 let arg_regions = iter::once(rcx.universal_regions().fr_static)
263 .chain(
264 opaque_type_key
265 .iter_captured_args(infcx.tcx)
266 .filter_map(|(_, arg)| arg.as_region())
267 .map(Region::as_var),
268 )
269 .collect();
270 defining_uses.push(DefiningUse {
271 opaque_type_key: non_nll_opaque_type_key,
272 arg_regions,
273 hidden_type,
274 });
275 }
276
277 defining_uses
278}
279
280fn compute_concrete_types_from_defining_uses<'tcx>(
281 rcx: &RegionCtxt<'_, 'tcx>,
282 concrete_opaque_types: &mut ConcreteOpaqueTypes<'tcx>,
283 defining_uses: &[DefiningUse<'tcx>],
284 errors: &mut Vec<DeferredOpaqueTypeError<'tcx>>,
285) {
286 let infcx = rcx.infcx;
287 let tcx = infcx.tcx;
288 let mut decls_modulo_regions: FxIndexMap<OpaqueTypeKey<'tcx>, (OpaqueTypeKey<'tcx>, Span)> =
289 FxIndexMap::default();
290 for &DefiningUse { opaque_type_key, ref arg_regions, hidden_type } in defining_uses {
291 let hidden_type =
295 match hidden_type.try_fold_with(&mut ToArgRegionsFolder::new(rcx, arg_regions)) {
296 Ok(hidden_type) => hidden_type,
297 Err(r) => {
298 errors.push(DeferredOpaqueTypeError::UnexpectedHiddenRegion {
299 hidden_type,
300 opaque_type_key,
301 member_region: ty::Region::new_var(tcx, r),
302 });
303 let guar = tcx.dcx().span_delayed_bug(
304 hidden_type.span,
305 "opaque type with non-universal region args",
306 );
307 ty::OpaqueHiddenType::new_error(tcx, guar)
308 }
309 };
310
311 let ty = infcx
315 .infer_opaque_definition_from_instantiation(opaque_type_key, hidden_type)
316 .unwrap_or_else(|_| {
317 Ty::new_error_with_message(
318 rcx.infcx.tcx,
319 hidden_type.span,
320 "deferred invalid opaque type args",
321 )
322 });
323
324 if !rcx.infcx.tcx.use_typing_mode_borrowck() {
329 if let ty::Alias(ty::Opaque, alias_ty) = ty.kind()
330 && alias_ty.def_id == opaque_type_key.def_id.to_def_id()
331 && alias_ty.args == opaque_type_key.args
332 {
333 continue;
334 }
335 }
336
337 if let Some((prev_decl_key, prev_span)) = decls_modulo_regions.insert(
344 rcx.infcx.tcx.erase_and_anonymize_regions(opaque_type_key),
345 (opaque_type_key, hidden_type.span),
346 ) && let Some((arg1, arg2)) = std::iter::zip(
347 prev_decl_key.iter_captured_args(infcx.tcx).map(|(_, arg)| arg),
348 opaque_type_key.iter_captured_args(infcx.tcx).map(|(_, arg)| arg),
349 )
350 .find(|(arg1, arg2)| arg1 != arg2)
351 {
352 errors.push(DeferredOpaqueTypeError::LifetimeMismatchOpaqueParam(
353 LifetimeMismatchOpaqueParam {
354 arg: arg1,
355 prev: arg2,
356 span: prev_span,
357 prev_span: hidden_type.span,
358 },
359 ));
360 }
361 add_concrete_opaque_type(
362 tcx,
363 concrete_opaque_types,
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
486pub(crate) fn apply_computed_concrete_opaque_types<'tcx>(
493 infcx: &BorrowckInferCtxt<'tcx>,
494 body: &Body<'tcx>,
495 universal_regions: &UniversalRegions<'tcx>,
496 region_bound_pairs: &RegionBoundPairs<'tcx>,
497 known_type_outlives_obligations: &[ty::PolyTypeOutlivesPredicate<'tcx>],
498 constraints: &mut MirTypeckRegionConstraints<'tcx>,
499 concrete_opaque_types: &mut ConcreteOpaqueTypes<'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) = get_concrete_opaque_type(concrete_opaque_types, key.def_id) else {
506 if !tcx.use_typing_mode_borrowck() {
507 if let ty::Alias(ty::Opaque, alias_ty) = hidden_type.ty.kind()
508 && alias_ty.def_id == key.def_id.to_def_id()
509 && alias_ty.args == key.args
510 {
511 continue;
512 } else {
513 unreachable!("non-defining use in defining scope");
514 }
515 }
516 errors.push(DeferredOpaqueTypeError::NonDefiningUseInDefiningScope {
517 span: hidden_type.span,
518 opaque_type_key: key,
519 });
520 let guar = tcx.dcx().span_delayed_bug(
521 hidden_type.span,
522 "non-defining use in the defining scope with no defining uses",
523 );
524 add_concrete_opaque_type(
525 tcx,
526 concrete_opaque_types,
527 key.def_id,
528 OpaqueHiddenType::new_error(tcx, guar),
529 );
530 continue;
531 };
532
533 let expected = ty::fold_regions(tcx, expected.instantiate(tcx, key.args), |re, _dbi| {
535 match re.kind() {
536 ty::ReErased => infcx.next_nll_region_var(
537 NllRegionVariableOrigin::Existential { name: None },
538 || crate::RegionCtxt::Existential(None),
539 ),
540 _ => re,
541 }
542 });
543
544 let locations = Locations::All(hidden_type.span);
546 if let Err(guar) = fully_perform_op_raw(
547 infcx,
548 body,
549 universal_regions,
550 region_bound_pairs,
551 known_type_outlives_obligations,
552 constraints,
553 locations,
554 ConstraintCategory::OpaqueType,
555 CustomTypeOp::new(
556 |ocx| {
557 let cause = ObligationCause::misc(
558 hidden_type.span,
559 body.source.def_id().expect_local(),
560 );
561 let actual_ty = ocx.normalize(&cause, infcx.param_env, hidden_type.ty);
563 let expected_ty = ocx.normalize(&cause, infcx.param_env, expected.ty);
564 ocx.eq(&cause, infcx.param_env, actual_ty, expected_ty).map_err(|_| NoSolution)
565 },
566 "equating opaque types",
567 ),
568 ) {
569 add_concrete_opaque_type(
570 tcx,
571 concrete_opaque_types,
572 key.def_id,
573 OpaqueHiddenType::new_error(tcx, guar),
574 );
575 }
576 }
577 errors
578}
579
580pub(crate) fn detect_opaque_types_added_while_handling_opaque_types<'tcx>(
588 infcx: &InferCtxt<'tcx>,
589 opaque_types_storage_num_entries: OpaqueTypeStorageEntries,
590) {
591 for (key, hidden_type) in infcx
592 .inner
593 .borrow_mut()
594 .opaque_types()
595 .opaque_types_added_since(opaque_types_storage_num_entries)
596 {
597 let opaque_type_string = infcx.tcx.def_path_str(key.def_id);
598 let msg = format!("unexpected cyclic definition of `{opaque_type_string}`");
599 infcx.dcx().span_delayed_bug(hidden_type.span, msg);
600 }
601
602 let _ = infcx.take_opaque_types();
603}
604
605impl<'tcx> RegionInferenceContext<'tcx> {
606 pub(crate) fn name_regions_for_member_constraint<T>(&self, tcx: TyCtxt<'tcx>, ty: T) -> T
619 where
620 T: TypeFoldable<TyCtxt<'tcx>>,
621 {
622 fold_regions(tcx, ty, |region, _| match region.kind() {
623 ty::ReVar(vid) => {
624 let scc = self.constraint_sccs.scc(vid);
625
626 if !self.max_nameable_universe(scc).is_root() {
628 match self.scc_values.placeholders_contained_in(scc).enumerate().last() {
629 Some((0, placeholder)) => {
631 return ty::Region::new_placeholder(tcx, placeholder);
632 }
633
634 _ => return region,
636 }
637 }
638
639 let upper_bound = self.approx_universal_upper_bound(vid);
641 if let Some(universal_region) = self.definitions[upper_bound].external_name {
642 return universal_region;
643 }
644
645 let scc = self.constraint_sccs.scc(vid);
650 let rev_scc_graph =
651 ReverseSccGraph::compute(&self.constraint_sccs, self.universal_regions());
652 let upper_bounds: Vec<_> = rev_scc_graph
653 .upper_bounds(scc)
654 .filter_map(|vid| self.definitions[vid].external_name)
655 .filter(|r| !r.is_static())
656 .collect();
657 match &upper_bounds[..] {
658 [universal_region] => *universal_region,
659 _ => region,
660 }
661 }
662 _ => region,
663 })
664 }
665}
666
667#[extension(pub trait InferCtxtExt<'tcx>)]
668impl<'tcx> InferCtxt<'tcx> {
669 #[instrument(level = "debug", skip(self))]
693 fn infer_opaque_definition_from_instantiation(
694 &self,
695 opaque_type_key: OpaqueTypeKey<'tcx>,
696 instantiated_ty: OpaqueHiddenType<'tcx>,
697 ) -> Result<Ty<'tcx>, NonDefiningUseReason<'tcx>> {
698 opaque_type_has_defining_use_args(
699 self,
700 opaque_type_key,
701 instantiated_ty.span,
702 DefiningScopeKind::MirBorrowck,
703 )?;
704
705 let definition_ty = instantiated_ty
706 .remap_generic_params_to_declaration_params(
707 opaque_type_key,
708 self.tcx,
709 DefiningScopeKind::MirBorrowck,
710 )
711 .ty;
712
713 definition_ty.error_reported()?;
714 Ok(definition_ty)
715 }
716}