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 debug!(
258 "collect_defining_uses: InvalidOpaqueTypeArgs for {:?} := {:?}",
259 non_nll_opaque_type_key, hidden_type
260 );
261 }
262 continue;
263 }
264
265 let arg_regions = iter::once(rcx.universal_regions().fr_static)
267 .chain(
268 opaque_type_key
269 .iter_captured_args(infcx.tcx)
270 .filter_map(|(_, arg)| arg.as_region())
271 .map(Region::as_var),
272 )
273 .collect();
274 defining_uses.push(DefiningUse {
275 opaque_type_key: non_nll_opaque_type_key,
276 arg_regions,
277 hidden_type,
278 });
279 }
280
281 defining_uses
282}
283
284#[instrument(level = "debug", skip(rcx, concrete_opaque_types, defining_uses, errors))]
285fn compute_concrete_types_from_defining_uses<'tcx>(
286 rcx: &RegionCtxt<'_, 'tcx>,
287 concrete_opaque_types: &mut ConcreteOpaqueTypes<'tcx>,
288 defining_uses: &[DefiningUse<'tcx>],
289 errors: &mut Vec<DeferredOpaqueTypeError<'tcx>>,
290) {
291 let infcx = rcx.infcx;
292 let tcx = infcx.tcx;
293 let mut decls_modulo_regions: FxIndexMap<OpaqueTypeKey<'tcx>, (OpaqueTypeKey<'tcx>, Span)> =
294 FxIndexMap::default();
295 for &DefiningUse { opaque_type_key, ref arg_regions, hidden_type } in defining_uses {
296 debug!(?opaque_type_key, ?arg_regions, ?hidden_type);
297 let hidden_type =
301 match hidden_type.try_fold_with(&mut ToArgRegionsFolder::new(rcx, arg_regions)) {
302 Ok(hidden_type) => hidden_type,
303 Err(r) => {
304 debug!("UnexpectedHiddenRegion: {:?}", r);
305 errors.push(DeferredOpaqueTypeError::UnexpectedHiddenRegion {
306 hidden_type,
307 opaque_type_key,
308 member_region: ty::Region::new_var(tcx, r),
309 });
310 let guar = tcx.dcx().span_delayed_bug(
311 hidden_type.span,
312 "opaque type with non-universal region args",
313 );
314 ty::OpaqueHiddenType::new_error(tcx, guar)
315 }
316 };
317
318 let ty = infcx
322 .infer_opaque_definition_from_instantiation(opaque_type_key, hidden_type)
323 .unwrap_or_else(|_| {
324 Ty::new_error_with_message(
325 rcx.infcx.tcx,
326 hidden_type.span,
327 "deferred invalid opaque type args",
328 )
329 });
330
331 if !rcx.infcx.tcx.use_typing_mode_borrowck() {
336 if let ty::Alias(ty::Opaque, alias_ty) = ty.kind()
337 && alias_ty.def_id == opaque_type_key.def_id.to_def_id()
338 && alias_ty.args == opaque_type_key.args
339 {
340 continue;
341 }
342 }
343
344 if let Some((prev_decl_key, prev_span)) = decls_modulo_regions.insert(
351 rcx.infcx.tcx.erase_and_anonymize_regions(opaque_type_key),
352 (opaque_type_key, hidden_type.span),
353 ) && let Some((arg1, arg2)) = std::iter::zip(
354 prev_decl_key.iter_captured_args(infcx.tcx).map(|(_, arg)| arg),
355 opaque_type_key.iter_captured_args(infcx.tcx).map(|(_, arg)| arg),
356 )
357 .find(|(arg1, arg2)| arg1 != arg2)
358 {
359 errors.push(DeferredOpaqueTypeError::LifetimeMismatchOpaqueParam(
360 LifetimeMismatchOpaqueParam {
361 arg: arg1,
362 prev: arg2,
363 span: prev_span,
364 prev_span: hidden_type.span,
365 },
366 ));
367 }
368 add_concrete_opaque_type(
369 tcx,
370 concrete_opaque_types,
371 opaque_type_key.def_id,
372 OpaqueHiddenType { span: hidden_type.span, ty },
373 );
374 }
375}
376
377struct ToArgRegionsFolder<'a, 'tcx> {
384 rcx: &'a RegionCtxt<'a, 'tcx>,
385 erase_unknown_regions: bool,
391 arg_regions: &'a [RegionVid],
392}
393
394impl<'a, 'tcx> ToArgRegionsFolder<'a, 'tcx> {
395 fn new(
396 rcx: &'a RegionCtxt<'a, 'tcx>,
397 arg_regions: &'a [RegionVid],
398 ) -> ToArgRegionsFolder<'a, 'tcx> {
399 ToArgRegionsFolder { rcx, erase_unknown_regions: false, arg_regions }
400 }
401
402 fn fold_non_member_arg(&mut self, arg: GenericArg<'tcx>) -> GenericArg<'tcx> {
403 let prev = self.erase_unknown_regions;
404 self.erase_unknown_regions = true;
405 let res = arg.try_fold_with(self).unwrap();
406 self.erase_unknown_regions = prev;
407 res
408 }
409
410 fn fold_closure_args(
411 &mut self,
412 def_id: DefId,
413 args: GenericArgsRef<'tcx>,
414 ) -> Result<GenericArgsRef<'tcx>, RegionVid> {
415 let generics = self.cx().generics_of(def_id);
416 self.cx().mk_args_from_iter(args.iter().enumerate().map(|(index, arg)| {
417 if index < generics.parent_count {
418 Ok(self.fold_non_member_arg(arg))
419 } else {
420 arg.try_fold_with(self)
421 }
422 }))
423 }
424}
425impl<'tcx> FallibleTypeFolder<TyCtxt<'tcx>> for ToArgRegionsFolder<'_, 'tcx> {
426 type Error = RegionVid;
427 fn cx(&self) -> TyCtxt<'tcx> {
428 self.rcx.infcx.tcx
429 }
430
431 fn try_fold_region(&mut self, r: Region<'tcx>) -> Result<Region<'tcx>, RegionVid> {
432 match r.kind() {
433 ty::ReBound(_, _) => Ok(r),
435 _ => {
436 let r = r.as_var();
437 if let Some(arg_region) = self
438 .arg_regions
439 .iter()
440 .copied()
441 .find(|&arg_vid| self.rcx.eval_equal(r, arg_vid))
442 .and_then(|r| nll_var_to_universal_region(self.rcx, r))
443 {
444 Ok(arg_region)
445 } else if self.erase_unknown_regions {
446 Ok(self.cx().lifetimes.re_erased)
447 } else {
448 Err(r)
449 }
450 }
451 }
452 }
453
454 fn try_fold_ty(&mut self, ty: Ty<'tcx>) -> Result<Ty<'tcx>, RegionVid> {
455 if !ty.flags().intersects(ty::TypeFlags::HAS_FREE_REGIONS) {
456 return Ok(ty);
457 }
458
459 let tcx = self.cx();
460 Ok(match *ty.kind() {
461 ty::Closure(def_id, args) => {
462 Ty::new_closure(tcx, def_id, self.fold_closure_args(def_id, args)?)
463 }
464
465 ty::CoroutineClosure(def_id, args) => {
466 Ty::new_coroutine_closure(tcx, def_id, self.fold_closure_args(def_id, args)?)
467 }
468
469 ty::Coroutine(def_id, args) => {
470 Ty::new_coroutine(tcx, def_id, self.fold_closure_args(def_id, args)?)
471 }
472
473 ty::Alias(kind, ty::AliasTy { def_id, args, .. })
474 if let Some(variances) = tcx.opt_alias_variances(kind, def_id) =>
475 {
476 let args = tcx.mk_args_from_iter(std::iter::zip(variances, args.iter()).map(
477 |(&v, s)| {
478 if v == ty::Bivariant {
479 Ok(self.fold_non_member_arg(s))
480 } else {
481 s.try_fold_with(self)
482 }
483 },
484 ))?;
485 ty::AliasTy::new_from_args(tcx, def_id, args).to_ty(tcx)
486 }
487
488 _ => ty.try_super_fold_with(self)?,
489 })
490 }
491}
492
493pub(crate) fn apply_computed_concrete_opaque_types<'tcx>(
500 infcx: &BorrowckInferCtxt<'tcx>,
501 body: &Body<'tcx>,
502 universal_regions: &UniversalRegions<'tcx>,
503 region_bound_pairs: &RegionBoundPairs<'tcx>,
504 known_type_outlives_obligations: &[ty::PolyTypeOutlivesPredicate<'tcx>],
505 constraints: &mut MirTypeckRegionConstraints<'tcx>,
506 concrete_opaque_types: &mut ConcreteOpaqueTypes<'tcx>,
507 opaque_types: &[(OpaqueTypeKey<'tcx>, OpaqueHiddenType<'tcx>)],
508) -> Vec<DeferredOpaqueTypeError<'tcx>> {
509 let tcx = infcx.tcx;
510 let mut errors = Vec::new();
511 for &(key, hidden_type) in opaque_types {
512 let Some(expected) = get_concrete_opaque_type(concrete_opaque_types, key.def_id) else {
513 if !tcx.use_typing_mode_borrowck() {
514 if let ty::Alias(ty::Opaque, alias_ty) = hidden_type.ty.kind()
515 && alias_ty.def_id == key.def_id.to_def_id()
516 && alias_ty.args == key.args
517 {
518 continue;
519 } else {
520 unreachable!("non-defining use in defining scope");
521 }
522 }
523 errors.push(DeferredOpaqueTypeError::NonDefiningUseInDefiningScope {
524 span: hidden_type.span,
525 opaque_type_key: key,
526 });
527 let guar = tcx.dcx().span_delayed_bug(
528 hidden_type.span,
529 "non-defining use in the defining scope with no defining uses",
530 );
531 add_concrete_opaque_type(
532 tcx,
533 concrete_opaque_types,
534 key.def_id,
535 OpaqueHiddenType::new_error(tcx, guar),
536 );
537 continue;
538 };
539
540 let expected = ty::fold_regions(tcx, expected.instantiate(tcx, key.args), |re, _dbi| {
542 match re.kind() {
543 ty::ReErased => infcx.next_nll_region_var(
544 NllRegionVariableOrigin::Existential { name: None },
545 || crate::RegionCtxt::Existential(None),
546 ),
547 _ => re,
548 }
549 });
550
551 let locations = Locations::All(hidden_type.span);
553 if let Err(guar) = fully_perform_op_raw(
554 infcx,
555 body,
556 universal_regions,
557 region_bound_pairs,
558 known_type_outlives_obligations,
559 constraints,
560 locations,
561 ConstraintCategory::OpaqueType,
562 CustomTypeOp::new(
563 |ocx| {
564 let cause = ObligationCause::misc(
565 hidden_type.span,
566 body.source.def_id().expect_local(),
567 );
568 let actual_ty = ocx.normalize(&cause, infcx.param_env, hidden_type.ty);
570 let expected_ty = ocx.normalize(&cause, infcx.param_env, expected.ty);
571 ocx.eq(&cause, infcx.param_env, actual_ty, expected_ty).map_err(|_| NoSolution)
572 },
573 "equating opaque types",
574 ),
575 ) {
576 add_concrete_opaque_type(
577 tcx,
578 concrete_opaque_types,
579 key.def_id,
580 OpaqueHiddenType::new_error(tcx, guar),
581 );
582 }
583 }
584 errors
585}
586
587pub(crate) fn detect_opaque_types_added_while_handling_opaque_types<'tcx>(
595 infcx: &InferCtxt<'tcx>,
596 opaque_types_storage_num_entries: OpaqueTypeStorageEntries,
597) {
598 for (key, hidden_type) in infcx
599 .inner
600 .borrow_mut()
601 .opaque_types()
602 .opaque_types_added_since(opaque_types_storage_num_entries)
603 {
604 let opaque_type_string = infcx.tcx.def_path_str(key.def_id);
605 let msg = format!("unexpected cyclic definition of `{opaque_type_string}`");
606 infcx.dcx().span_delayed_bug(hidden_type.span, msg);
607 }
608
609 let _ = infcx.take_opaque_types();
610}
611
612impl<'tcx> RegionInferenceContext<'tcx> {
613 pub(crate) fn name_regions_for_member_constraint<T>(&self, tcx: TyCtxt<'tcx>, ty: T) -> T
626 where
627 T: TypeFoldable<TyCtxt<'tcx>>,
628 {
629 fold_regions(tcx, ty, |region, _| match region.kind() {
630 ty::ReVar(vid) => {
631 let scc = self.constraint_sccs.scc(vid);
632
633 if !self.max_nameable_universe(scc).is_root() {
635 match self.scc_values.placeholders_contained_in(scc).enumerate().last() {
636 Some((0, placeholder)) => {
638 return ty::Region::new_placeholder(tcx, placeholder);
639 }
640
641 _ => return region,
643 }
644 }
645
646 let upper_bound = self.approx_universal_upper_bound(vid);
648 if let Some(universal_region) = self.definitions[upper_bound].external_name {
649 return universal_region;
650 }
651
652 let scc = self.constraint_sccs.scc(vid);
657 let rev_scc_graph =
658 ReverseSccGraph::compute(&self.constraint_sccs, self.universal_regions());
659 let upper_bounds: Vec<_> = rev_scc_graph
660 .upper_bounds(scc)
661 .filter_map(|vid| self.definitions[vid].external_name)
662 .filter(|r| !r.is_static())
663 .collect();
664 match &upper_bounds[..] {
665 [universal_region] => *universal_region,
666 _ => region,
667 }
668 }
669 _ => region,
670 })
671 }
672}
673
674#[extension(pub trait InferCtxtExt<'tcx>)]
675impl<'tcx> InferCtxt<'tcx> {
676 #[instrument(level = "debug", skip(self))]
700 fn infer_opaque_definition_from_instantiation(
701 &self,
702 opaque_type_key: OpaqueTypeKey<'tcx>,
703 instantiated_ty: OpaqueHiddenType<'tcx>,
704 ) -> Result<Ty<'tcx>, NonDefiningUseReason<'tcx>> {
705 opaque_type_has_defining_use_args(
706 self,
707 opaque_type_key,
708 instantiated_ty.span,
709 DefiningScopeKind::MirBorrowck,
710 )?;
711
712 let definition_ty = instantiated_ty
713 .remap_generic_params_to_declaration_params(
714 opaque_type_key,
715 self.tcx,
716 DefiningScopeKind::MirBorrowck,
717 )
718 .ty;
719
720 definition_ty.error_reported()?;
721 Ok(definition_ty)
722 }
723}