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, ConstraintCategory};
12use rustc_middle::ty::{
13 self, DefiningScopeKind, DefinitionSiteHiddenType, FallibleTypeFolder, GenericArg,
14 GenericArgsRef, OpaqueTypeKey, ProvisionalHiddenType, Region, RegionVid, Ty, TyCtxt,
15 TypeFoldable, 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: ProvisionalHiddenType<'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>, ProvisionalHiddenType<'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_hidden_type<'tcx>(
133 tcx: TyCtxt<'tcx>,
134 hidden_types: &mut FxIndexMap<LocalDefId, ty::DefinitionSiteHiddenType<'tcx>>,
135 def_id: LocalDefId,
136 hidden_ty: ty::DefinitionSiteHiddenType<'tcx>,
137) {
138 if let Some(prev) = hidden_types.get_mut(&def_id) {
143 if prev.ty == hidden_ty.ty {
144 prev.span = prev.span.substitute_dummy(hidden_ty.span);
147 } else {
148 let (Ok(guar) | Err(guar)) =
149 prev.build_mismatch_error(&hidden_ty, tcx).map(|d| d.emit());
150 *prev = ty::DefinitionSiteHiddenType::new_error(tcx, guar);
151 }
152 } else {
153 hidden_types.insert(def_id, hidden_ty);
154 }
155}
156
157#[derive(Debug)]
158struct DefiningUse<'tcx> {
159 opaque_type_key: OpaqueTypeKey<'tcx>,
163 arg_regions: Vec<RegionVid>,
164 hidden_type: ProvisionalHiddenType<'tcx>,
165}
166
167pub(crate) fn compute_definition_site_hidden_types<'tcx>(
179 infcx: &BorrowckInferCtxt<'tcx>,
180 universal_region_relations: &Frozen<UniversalRegionRelations<'tcx>>,
181 constraints: &MirTypeckRegionConstraints<'tcx>,
182 location_map: Rc<DenseLocationMap>,
183 hidden_types: &mut FxIndexMap<LocalDefId, ty::DefinitionSiteHiddenType<'tcx>>,
184 opaque_types: &[(OpaqueTypeKey<'tcx>, ProvisionalHiddenType<'tcx>)],
185) -> Vec<DeferredOpaqueTypeError<'tcx>> {
186 let mut errors = Vec::new();
187 let mut rcx = RegionCtxt::new(infcx, universal_region_relations, location_map, constraints);
192
193 let defining_uses = collect_defining_uses(&mut rcx, hidden_types, opaque_types, &mut errors);
197
198 apply_member_constraints(&mut rcx, &defining_uses);
202
203 compute_definition_site_hidden_types_from_defining_uses(
207 &rcx,
208 hidden_types,
209 &defining_uses,
210 &mut errors,
211 );
212 errors
213}
214
215#[instrument(level = "debug", skip_all, ret)]
216fn collect_defining_uses<'tcx>(
217 rcx: &mut RegionCtxt<'_, 'tcx>,
218 hidden_types: &mut FxIndexMap<LocalDefId, ty::DefinitionSiteHiddenType<'tcx>>,
219 opaque_types: &[(OpaqueTypeKey<'tcx>, ProvisionalHiddenType<'tcx>)],
220 errors: &mut Vec<DeferredOpaqueTypeError<'tcx>>,
221) -> Vec<DefiningUse<'tcx>> {
222 let infcx = rcx.infcx;
223 let mut defining_uses = vec![];
224 for &(opaque_type_key, hidden_type) in opaque_types {
225 let non_nll_opaque_type_key = opaque_type_key.fold_captured_lifetime_args(infcx.tcx, |r| {
226 nll_var_to_universal_region(&rcx, r.as_var()).unwrap_or(r)
227 });
228 if let Err(err) = opaque_type_has_defining_use_args(
229 infcx,
230 non_nll_opaque_type_key,
231 hidden_type.span,
232 DefiningScopeKind::MirBorrowck,
233 ) {
234 if infcx.tcx.use_typing_mode_borrowck() {
237 match err {
238 NonDefiningUseReason::Tainted(guar) => add_hidden_type(
239 infcx.tcx,
240 hidden_types,
241 opaque_type_key.def_id,
242 DefinitionSiteHiddenType::new_error(infcx.tcx, guar),
243 ),
244 _ => debug!(?non_nll_opaque_type_key, ?err, "ignoring non-defining use"),
245 }
246 } else {
247 errors.push(DeferredOpaqueTypeError::InvalidOpaqueTypeArgs(err));
248 debug!(
249 "collect_defining_uses: InvalidOpaqueTypeArgs for {:?} := {:?}",
250 non_nll_opaque_type_key, hidden_type
251 );
252 }
253 continue;
254 }
255
256 let arg_regions = iter::once(rcx.universal_regions().fr_static)
258 .chain(
259 opaque_type_key
260 .iter_captured_args(infcx.tcx)
261 .filter_map(|(_, arg)| arg.as_region())
262 .map(Region::as_var),
263 )
264 .collect();
265 defining_uses.push(DefiningUse {
266 opaque_type_key: non_nll_opaque_type_key,
267 arg_regions,
268 hidden_type,
269 });
270 }
271
272 defining_uses
273}
274
275#[instrument(level = "debug", skip(rcx, hidden_types, defining_uses, errors))]
276fn compute_definition_site_hidden_types_from_defining_uses<'tcx>(
277 rcx: &RegionCtxt<'_, 'tcx>,
278 hidden_types: &mut FxIndexMap<LocalDefId, ty::DefinitionSiteHiddenType<'tcx>>,
279 defining_uses: &[DefiningUse<'tcx>],
280 errors: &mut Vec<DeferredOpaqueTypeError<'tcx>>,
281) {
282 let infcx = rcx.infcx;
283 let tcx = infcx.tcx;
284 let mut decls_modulo_regions: FxIndexMap<OpaqueTypeKey<'tcx>, (OpaqueTypeKey<'tcx>, Span)> =
285 FxIndexMap::default();
286 for &DefiningUse { opaque_type_key, ref arg_regions, hidden_type } in defining_uses {
287 debug!(?opaque_type_key, ?arg_regions, ?hidden_type);
288 let hidden_type =
292 match hidden_type.try_fold_with(&mut ToArgRegionsFolder::new(rcx, arg_regions)) {
293 Ok(hidden_type) => hidden_type,
294 Err(r) => {
295 debug!("UnexpectedHiddenRegion: {:?}", r);
296 errors.push(DeferredOpaqueTypeError::UnexpectedHiddenRegion {
297 hidden_type,
298 opaque_type_key,
299 member_region: ty::Region::new_var(tcx, r),
300 });
301 let guar = tcx.dcx().span_delayed_bug(
302 hidden_type.span,
303 "opaque type with non-universal region args",
304 );
305 ty::ProvisionalHiddenType::new_error(tcx, guar)
306 }
307 };
308
309 let hidden_type = infcx
313 .infer_opaque_definition_from_instantiation(opaque_type_key, hidden_type)
314 .unwrap_or_else(|_| {
315 let guar = tcx
316 .dcx()
317 .span_delayed_bug(hidden_type.span, "deferred invalid opaque type args");
318 DefinitionSiteHiddenType::new_error(tcx, guar)
319 });
320
321 if !rcx.infcx.tcx.use_typing_mode_borrowck() {
326 if let ty::Alias(ty::Opaque, alias_ty) = hidden_type.ty.skip_binder().kind()
327 && alias_ty.def_id == opaque_type_key.def_id.to_def_id()
328 && alias_ty.args == opaque_type_key.args
329 {
330 continue;
331 }
332 }
333
334 if let Some((prev_decl_key, prev_span)) = decls_modulo_regions.insert(
341 rcx.infcx.tcx.erase_and_anonymize_regions(opaque_type_key),
342 (opaque_type_key, hidden_type.span),
343 ) && let Some((arg1, arg2)) = std::iter::zip(
344 prev_decl_key.iter_captured_args(infcx.tcx).map(|(_, arg)| arg),
345 opaque_type_key.iter_captured_args(infcx.tcx).map(|(_, arg)| arg),
346 )
347 .find(|(arg1, arg2)| arg1 != arg2)
348 {
349 errors.push(DeferredOpaqueTypeError::LifetimeMismatchOpaqueParam(
350 LifetimeMismatchOpaqueParam {
351 arg: arg1,
352 prev: arg2,
353 span: prev_span,
354 prev_span: hidden_type.span,
355 },
356 ));
357 }
358 add_hidden_type(tcx, hidden_types, opaque_type_key.def_id, hidden_type);
359 }
360}
361
362struct ToArgRegionsFolder<'a, 'tcx> {
369 rcx: &'a RegionCtxt<'a, 'tcx>,
370 erase_unknown_regions: bool,
376 arg_regions: &'a [RegionVid],
377}
378
379impl<'a, 'tcx> ToArgRegionsFolder<'a, 'tcx> {
380 fn new(
381 rcx: &'a RegionCtxt<'a, 'tcx>,
382 arg_regions: &'a [RegionVid],
383 ) -> ToArgRegionsFolder<'a, 'tcx> {
384 ToArgRegionsFolder { rcx, erase_unknown_regions: false, arg_regions }
385 }
386
387 fn fold_non_member_arg(&mut self, arg: GenericArg<'tcx>) -> GenericArg<'tcx> {
388 let prev = self.erase_unknown_regions;
389 self.erase_unknown_regions = true;
390 let res = arg.try_fold_with(self).unwrap();
391 self.erase_unknown_regions = prev;
392 res
393 }
394
395 fn fold_closure_args(
396 &mut self,
397 def_id: DefId,
398 args: GenericArgsRef<'tcx>,
399 ) -> Result<GenericArgsRef<'tcx>, RegionVid> {
400 let generics = self.cx().generics_of(def_id);
401 self.cx().mk_args_from_iter(args.iter().enumerate().map(|(index, arg)| {
402 if index < generics.parent_count {
403 Ok(self.fold_non_member_arg(arg))
404 } else {
405 arg.try_fold_with(self)
406 }
407 }))
408 }
409}
410impl<'tcx> FallibleTypeFolder<TyCtxt<'tcx>> for ToArgRegionsFolder<'_, 'tcx> {
411 type Error = RegionVid;
412 fn cx(&self) -> TyCtxt<'tcx> {
413 self.rcx.infcx.tcx
414 }
415
416 fn try_fold_region(&mut self, r: Region<'tcx>) -> Result<Region<'tcx>, RegionVid> {
417 match r.kind() {
418 ty::ReBound(_, _) => Ok(r),
420 _ => {
421 let r = r.as_var();
422 if let Some(arg_region) = self
423 .arg_regions
424 .iter()
425 .copied()
426 .find(|&arg_vid| self.rcx.eval_equal(r, arg_vid))
427 .and_then(|r| nll_var_to_universal_region(self.rcx, r))
428 {
429 Ok(arg_region)
430 } else if self.erase_unknown_regions {
431 Ok(self.cx().lifetimes.re_erased)
432 } else {
433 Err(r)
434 }
435 }
436 }
437 }
438
439 fn try_fold_ty(&mut self, ty: Ty<'tcx>) -> Result<Ty<'tcx>, RegionVid> {
440 if !ty.flags().intersects(ty::TypeFlags::HAS_FREE_REGIONS) {
441 return Ok(ty);
442 }
443
444 let tcx = self.cx();
445 Ok(match *ty.kind() {
446 ty::Closure(def_id, args) => {
447 Ty::new_closure(tcx, def_id, self.fold_closure_args(def_id, args)?)
448 }
449
450 ty::CoroutineClosure(def_id, args) => {
451 Ty::new_coroutine_closure(tcx, def_id, self.fold_closure_args(def_id, args)?)
452 }
453
454 ty::Coroutine(def_id, args) => {
455 Ty::new_coroutine(tcx, def_id, self.fold_closure_args(def_id, args)?)
456 }
457
458 ty::Alias(kind, ty::AliasTy { def_id, args, .. })
459 if let Some(variances) = tcx.opt_alias_variances(kind, def_id) =>
460 {
461 let args = tcx.mk_args_from_iter(std::iter::zip(variances, args.iter()).map(
462 |(&v, s)| {
463 if v == ty::Bivariant {
464 Ok(self.fold_non_member_arg(s))
465 } else {
466 s.try_fold_with(self)
467 }
468 },
469 ))?;
470 ty::AliasTy::new_from_args(tcx, def_id, args).to_ty(tcx)
471 }
472
473 _ => ty.try_super_fold_with(self)?,
474 })
475 }
476}
477
478pub(crate) fn apply_definition_site_hidden_types<'tcx>(
485 infcx: &BorrowckInferCtxt<'tcx>,
486 body: &Body<'tcx>,
487 universal_regions: &UniversalRegions<'tcx>,
488 region_bound_pairs: &RegionBoundPairs<'tcx>,
489 known_type_outlives_obligations: &[ty::PolyTypeOutlivesPredicate<'tcx>],
490 constraints: &mut MirTypeckRegionConstraints<'tcx>,
491 hidden_types: &mut FxIndexMap<LocalDefId, ty::DefinitionSiteHiddenType<'tcx>>,
492 opaque_types: &[(OpaqueTypeKey<'tcx>, ProvisionalHiddenType<'tcx>)],
493) -> Vec<DeferredOpaqueTypeError<'tcx>> {
494 let tcx = infcx.tcx;
495 let mut errors = Vec::new();
496 for &(key, hidden_type) in opaque_types {
497 let Some(expected) = hidden_types.get(&key.def_id) else {
498 if !tcx.use_typing_mode_borrowck() {
499 if let ty::Alias(ty::Opaque, alias_ty) = hidden_type.ty.kind()
500 && alias_ty.def_id == key.def_id.to_def_id()
501 && alias_ty.args == key.args
502 {
503 continue;
504 } else {
505 unreachable!("non-defining use in defining scope");
506 }
507 }
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 add_hidden_type(
517 tcx,
518 hidden_types,
519 key.def_id,
520 DefinitionSiteHiddenType::new_error(tcx, guar),
521 );
522 continue;
523 };
524
525 let expected_ty =
527 ty::fold_regions(tcx, expected.ty.instantiate(tcx, key.args), |re, _dbi| {
528 match re.kind() {
529 ty::ReErased => infcx.next_nll_region_var(
530 NllRegionVariableOrigin::Existential { name: None },
531 || crate::RegionCtxt::Existential(None),
532 ),
533 _ => re,
534 }
535 });
536
537 let locations = Locations::All(hidden_type.span);
539 if let Err(guar) = fully_perform_op_raw(
540 infcx,
541 body,
542 universal_regions,
543 region_bound_pairs,
544 known_type_outlives_obligations,
545 constraints,
546 locations,
547 ConstraintCategory::OpaqueType,
548 CustomTypeOp::new(
549 |ocx| {
550 let cause = ObligationCause::misc(
551 hidden_type.span,
552 body.source.def_id().expect_local(),
553 );
554 let actual_ty = ocx.normalize(&cause, infcx.param_env, hidden_type.ty);
556 let expected_ty = ocx.normalize(&cause, infcx.param_env, expected_ty);
557 ocx.eq(&cause, infcx.param_env, actual_ty, expected_ty).map_err(|_| NoSolution)
558 },
559 "equating opaque types",
560 ),
561 ) {
562 add_hidden_type(
563 tcx,
564 hidden_types,
565 key.def_id,
566 DefinitionSiteHiddenType::new_error(tcx, guar),
567 );
568 }
569 }
570 errors
571}
572
573pub(crate) fn detect_opaque_types_added_while_handling_opaque_types<'tcx>(
581 infcx: &InferCtxt<'tcx>,
582 opaque_types_storage_num_entries: OpaqueTypeStorageEntries,
583) {
584 for (key, hidden_type) in infcx
585 .inner
586 .borrow_mut()
587 .opaque_types()
588 .opaque_types_added_since(opaque_types_storage_num_entries)
589 {
590 let opaque_type_string = infcx.tcx.def_path_str(key.def_id);
591 let msg = format!("unexpected cyclic definition of `{opaque_type_string}`");
592 infcx.dcx().span_delayed_bug(hidden_type.span, msg);
593 }
594
595 let _ = infcx.take_opaque_types();
596}
597
598impl<'tcx> RegionInferenceContext<'tcx> {
599 pub(crate) fn name_regions_for_member_constraint<T>(&self, tcx: TyCtxt<'tcx>, ty: T) -> T
612 where
613 T: TypeFoldable<TyCtxt<'tcx>>,
614 {
615 fold_regions(tcx, ty, |region, _| match region.kind() {
616 ty::ReVar(vid) => {
617 let scc = self.constraint_sccs.scc(vid);
618
619 if !self.max_nameable_universe(scc).is_root() {
621 match self.scc_values.placeholders_contained_in(scc).enumerate().last() {
622 Some((0, placeholder)) => {
624 return ty::Region::new_placeholder(tcx, placeholder);
625 }
626
627 _ => return region,
629 }
630 }
631
632 let upper_bound = self.approx_universal_upper_bound(vid);
634 if let Some(universal_region) = self.definitions[upper_bound].external_name {
635 return universal_region;
636 }
637
638 let scc = self.constraint_sccs.scc(vid);
643 let rev_scc_graph =
644 ReverseSccGraph::compute(&self.constraint_sccs, self.universal_regions());
645 let upper_bounds: Vec<_> = rev_scc_graph
646 .upper_bounds(scc)
647 .filter_map(|vid| self.definitions[vid].external_name)
648 .filter(|r| !r.is_static())
649 .collect();
650 match &upper_bounds[..] {
651 [universal_region] => *universal_region,
652 _ => region,
653 }
654 }
655 _ => region,
656 })
657 }
658}
659
660#[extension(pub trait InferCtxtExt<'tcx>)]
661impl<'tcx> InferCtxt<'tcx> {
662 #[instrument(level = "debug", skip(self))]
679 fn infer_opaque_definition_from_instantiation(
680 &self,
681 opaque_type_key: OpaqueTypeKey<'tcx>,
682 instantiated_ty: ProvisionalHiddenType<'tcx>,
683 ) -> Result<ty::DefinitionSiteHiddenType<'tcx>, NonDefiningUseReason<'tcx>> {
684 opaque_type_has_defining_use_args(
685 self,
686 opaque_type_key,
687 instantiated_ty.span,
688 DefiningScopeKind::MirBorrowck,
689 )?;
690
691 let definition_ty = instantiated_ty.remap_generic_params_to_declaration_params(
692 opaque_type_key,
693 self.tcx,
694 DefiningScopeKind::MirBorrowck,
695 );
696 definition_ty.ty.skip_binder().error_reported()?;
697 Ok(definition_ty)
698 }
699}