1use std::ops::Range;
4use std::{cmp, fmt, mem};
5
6use rustc_data_structures::fx::FxHashMap;
7use rustc_data_structures::undo_log::UndoLogs;
8use rustc_data_structures::unify as ut;
9use rustc_index::IndexVec;
10use rustc_macros::{TypeFoldable, TypeVisitable};
11use rustc_middle::ty::{self, ReBound, ReStatic, ReVar, Region, RegionVid, Ty, TyCtxt};
12use rustc_middle::{bug, span_bug};
13use tracing::{debug, instrument};
14
15use self::CombineMapType::*;
16use self::UndoLog::*;
17use super::{RegionVariableOrigin, Rollback, SubregionOrigin};
18use crate::infer::snapshot::undo_log::{InferCtxtUndoLogs, Snapshot};
19use crate::infer::unify_key::{RegionVariableValue, RegionVidKey};
20
21mod leak_check;
22
23#[derive(Clone, Default)]
24pub struct RegionConstraintStorage<'tcx> {
25 pub(super) var_infos: IndexVec<RegionVid, RegionVariableInfo>,
27
28 pub(super) data: RegionConstraintData<'tcx>,
29
30 lubs: CombineMap<'tcx>,
34
35 glbs: CombineMap<'tcx>,
39
40 pub(super) unification_table: ut::UnificationTableStorage<RegionVidKey<'tcx>>,
49
50 any_unifications: bool,
53}
54
55pub struct RegionConstraintCollector<'a, 'tcx> {
56 storage: &'a mut RegionConstraintStorage<'tcx>,
57 undo_log: &'a mut InferCtxtUndoLogs<'tcx>,
58}
59
60pub type VarInfos = IndexVec<RegionVid, RegionVariableInfo>;
61
62#[derive(Debug, Default, Clone)]
67pub struct RegionConstraintData<'tcx> {
68 pub constraints: Vec<(Constraint<'tcx>, SubregionOrigin<'tcx>)>,
71
72 pub verifys: Vec<Verify<'tcx>>,
79}
80
81#[derive(Clone, Copy, PartialEq, Eq, Debug, Hash)]
83pub enum ConstraintKind {
84 VarSubVar,
86
87 RegSubVar,
89
90 VarSubReg,
94
95 RegSubReg,
99}
100
101#[derive(Clone, Copy, PartialEq, Eq, Debug, Hash)]
103pub struct Constraint<'tcx> {
104 pub kind: ConstraintKind,
105 pub sub: Region<'tcx>,
107 pub sup: Region<'tcx>,
109}
110
111impl Constraint<'_> {
112 pub fn involves_placeholders(&self) -> bool {
113 self.sub.is_placeholder() || self.sup.is_placeholder()
114 }
115}
116
117#[derive(Debug, Clone)]
118pub struct Verify<'tcx> {
119 pub kind: GenericKind<'tcx>,
120 pub origin: SubregionOrigin<'tcx>,
121 pub region: Region<'tcx>,
122 pub bound: VerifyBound<'tcx>,
123}
124
125#[derive(Copy, Clone, PartialEq, Eq, Hash, TypeFoldable, TypeVisitable)]
126pub enum GenericKind<'tcx> {
127 Param(ty::ParamTy),
128 Placeholder(ty::PlaceholderType),
129 Alias(ty::AliasTy<'tcx>),
130}
131
132#[derive(Debug, Clone, TypeFoldable, TypeVisitable)]
150pub enum VerifyBound<'tcx> {
151 IfEq(ty::Binder<'tcx, VerifyIfEq<'tcx>>),
153
154 OutlivedBy(Region<'tcx>),
165
166 IsEmpty,
168
169 AnyBound(Vec<VerifyBound<'tcx>>),
180
181 AllBounds(Vec<VerifyBound<'tcx>>),
193}
194
195#[derive(Debug, Copy, Clone, TypeFoldable, TypeVisitable)]
234pub struct VerifyIfEq<'tcx> {
235 pub ty: Ty<'tcx>,
237
238 pub bound: Region<'tcx>,
240}
241
242#[derive(Copy, Clone, PartialEq, Eq, Hash)]
243pub(crate) struct TwoRegions<'tcx> {
244 a: Region<'tcx>,
245 b: Region<'tcx>,
246}
247
248#[derive(Copy, Clone, PartialEq)]
249pub(crate) enum UndoLog<'tcx> {
250 AddVar(RegionVid),
252
253 AddConstraint(usize),
255
256 AddVerify(usize),
258
259 AddCombination(CombineMapType, TwoRegions<'tcx>),
261}
262
263#[derive(Copy, Clone, PartialEq)]
264pub(crate) enum CombineMapType {
265 Lub,
266 Glb,
267}
268
269type CombineMap<'tcx> = FxHashMap<TwoRegions<'tcx>, RegionVid>;
270
271#[derive(Debug, Clone, Copy)]
272pub struct RegionVariableInfo {
273 pub origin: RegionVariableOrigin,
274 pub universe: ty::UniverseIndex,
287}
288
289pub(crate) struct RegionSnapshot {
290 any_unifications: bool,
291}
292
293impl<'tcx> RegionConstraintStorage<'tcx> {
294 #[inline]
295 pub(crate) fn with_log<'a>(
296 &'a mut self,
297 undo_log: &'a mut InferCtxtUndoLogs<'tcx>,
298 ) -> RegionConstraintCollector<'a, 'tcx> {
299 RegionConstraintCollector { storage: self, undo_log }
300 }
301}
302
303impl<'tcx> RegionConstraintCollector<'_, 'tcx> {
304 pub fn num_region_vars(&self) -> usize {
305 self.storage.var_infos.len()
306 }
307
308 pub fn take_and_reset_data(&mut self) -> RegionConstraintData<'tcx> {
321 assert!(!UndoLogs::<UndoLog<'_>>::in_snapshot(&self.undo_log));
322
323 let RegionConstraintStorage {
327 var_infos: _,
328 data,
329 lubs,
330 glbs,
331 unification_table: _,
332 any_unifications,
333 } = self.storage;
334
335 lubs.clear();
340 glbs.clear();
341
342 let data = mem::take(data);
343
344 if *any_unifications {
349 *any_unifications = false;
350 ut::UnificationTable::with_log(&mut self.storage.unification_table, &mut self.undo_log)
352 .reset_unifications(|key| RegionVariableValue::Unknown {
353 universe: self.storage.var_infos[key.vid].universe,
354 });
355 }
356
357 data
358 }
359
360 pub fn data(&self) -> &RegionConstraintData<'tcx> {
361 &self.storage.data
362 }
363
364 pub(super) fn start_snapshot(&self) -> RegionSnapshot {
365 debug!("RegionConstraintCollector: start_snapshot");
366 RegionSnapshot { any_unifications: self.storage.any_unifications }
367 }
368
369 pub(super) fn rollback_to(&mut self, snapshot: RegionSnapshot) {
370 debug!("RegionConstraintCollector: rollback_to({:?})", snapshot);
371 self.storage.any_unifications = snapshot.any_unifications;
372 }
373
374 pub(super) fn new_region_var(
375 &mut self,
376 universe: ty::UniverseIndex,
377 origin: RegionVariableOrigin,
378 ) -> RegionVid {
379 let vid = self.storage.var_infos.push(RegionVariableInfo { origin, universe });
380
381 let u_vid = self.unification_table_mut().new_key(RegionVariableValue::Unknown { universe });
382 assert_eq!(vid, u_vid.vid);
383 self.undo_log.push(AddVar(vid));
384 debug!("created new region variable {:?} in {:?} with origin {:?}", vid, universe, origin);
385 vid
386 }
387
388 pub(super) fn var_origin(&self, vid: RegionVid) -> RegionVariableOrigin {
390 self.storage.var_infos[vid].origin
391 }
392
393 fn add_constraint(&mut self, constraint: Constraint<'tcx>, origin: SubregionOrigin<'tcx>) {
394 debug!("RegionConstraintCollector: add_constraint({:?})", constraint);
396
397 let index = self.storage.data.constraints.len();
398 self.storage.data.constraints.push((constraint, origin));
399 self.undo_log.push(AddConstraint(index));
400 }
401
402 fn add_verify(&mut self, verify: Verify<'tcx>) {
403 debug!("RegionConstraintCollector: add_verify({:?})", verify);
405
406 if let VerifyBound::AllBounds(ref bs) = verify.bound
408 && bs.is_empty()
409 {
410 return;
411 }
412
413 let index = self.storage.data.verifys.len();
414 self.storage.data.verifys.push(verify);
415 self.undo_log.push(AddVerify(index));
416 }
417
418 pub(super) fn make_eqregion(
419 &mut self,
420 origin: SubregionOrigin<'tcx>,
421 a: Region<'tcx>,
422 b: Region<'tcx>,
423 ) {
424 if a != b {
425 self.make_subregion(origin.clone(), a, b);
428 self.make_subregion(origin, b, a);
429
430 match (a.kind(), b.kind()) {
431 (ty::ReVar(a), ty::ReVar(b)) => {
432 debug!("make_eqregion: unifying {:?} with {:?}", a, b);
433 if self.unification_table_mut().unify_var_var(a, b).is_ok() {
434 self.storage.any_unifications = true;
435 }
436 }
437 (ty::ReVar(vid), _) => {
438 debug!("make_eqregion: unifying {:?} with {:?}", vid, b);
439 if self
440 .unification_table_mut()
441 .unify_var_value(vid, RegionVariableValue::Known { value: b })
442 .is_ok()
443 {
444 self.storage.any_unifications = true;
445 };
446 }
447 (_, ty::ReVar(vid)) => {
448 debug!("make_eqregion: unifying {:?} with {:?}", a, vid);
449 if self
450 .unification_table_mut()
451 .unify_var_value(vid, RegionVariableValue::Known { value: a })
452 .is_ok()
453 {
454 self.storage.any_unifications = true;
455 };
456 }
457 (_, _) => {}
458 }
459 }
460 }
461
462 #[instrument(skip(self, origin), level = "debug")]
463 pub(super) fn make_subregion(
464 &mut self,
465 origin: SubregionOrigin<'tcx>,
466 sub: Region<'tcx>,
467 sup: Region<'tcx>,
468 ) {
469 debug!("origin = {:#?}", origin);
471
472 match (sub.kind(), sup.kind()) {
473 (ReBound(..), _) | (_, ReBound(..)) => {
474 span_bug!(origin.span(), "cannot relate bound region: {:?} <= {:?}", sub, sup);
475 }
476 (_, ReStatic) => {
477 }
479 (ReVar(sub_id), ReVar(sup_id)) => {
480 if sub_id != sup_id {
481 self.add_constraint(
482 Constraint { kind: ConstraintKind::VarSubVar, sub, sup },
483 origin,
484 );
485 }
486 }
487 (_, ReVar(_)) => self
488 .add_constraint(Constraint { kind: ConstraintKind::RegSubVar, sub, sup }, origin),
489 (ReVar(_), _) => self
490 .add_constraint(Constraint { kind: ConstraintKind::VarSubReg, sub, sup }, origin),
491 _ => {
492 if sub != sup {
493 self.add_constraint(
494 Constraint { kind: ConstraintKind::RegSubReg, sub, sup },
495 origin,
496 )
497 }
498 }
499 }
500 }
501
502 pub(super) fn verify_generic_bound(
503 &mut self,
504 origin: SubregionOrigin<'tcx>,
505 kind: GenericKind<'tcx>,
506 sub: Region<'tcx>,
507 bound: VerifyBound<'tcx>,
508 ) {
509 self.add_verify(Verify { kind, origin, region: sub, bound });
510 }
511
512 pub(super) fn lub_regions(
513 &mut self,
514 tcx: TyCtxt<'tcx>,
515 origin: SubregionOrigin<'tcx>,
516 a: Region<'tcx>,
517 b: Region<'tcx>,
518 ) -> Region<'tcx> {
519 debug!("RegionConstraintCollector: lub_regions({:?}, {:?})", a, b);
521 if a.is_static() || b.is_static() {
522 a } else if a == b {
524 a } else {
526 self.combine_vars(tcx, Lub, a, b, origin)
527 }
528 }
529
530 pub(super) fn glb_regions(
531 &mut self,
532 tcx: TyCtxt<'tcx>,
533 origin: SubregionOrigin<'tcx>,
534 a: Region<'tcx>,
535 b: Region<'tcx>,
536 ) -> Region<'tcx> {
537 debug!("RegionConstraintCollector: glb_regions({:?}, {:?})", a, b);
539 if a.is_static() {
540 b } else if b.is_static() {
542 a } else if a == b {
544 a } else {
546 self.combine_vars(tcx, Glb, a, b, origin)
547 }
548 }
549
550 pub fn opportunistic_resolve_var(
553 &mut self,
554 tcx: TyCtxt<'tcx>,
555 vid: ty::RegionVid,
556 ) -> ty::Region<'tcx> {
557 let mut ut = self.unification_table_mut();
558 let root_vid = ut.find(vid).vid;
559 match ut.probe_value(root_vid) {
560 RegionVariableValue::Known { value } => value,
561 RegionVariableValue::Unknown { .. } => ty::Region::new_var(tcx, root_vid),
562 }
563 }
564
565 pub fn probe_value(
566 &mut self,
567 vid: ty::RegionVid,
568 ) -> Result<ty::Region<'tcx>, ty::UniverseIndex> {
569 match self.unification_table_mut().probe_value(vid) {
570 RegionVariableValue::Known { value } => Ok(value),
571 RegionVariableValue::Unknown { universe } => Err(universe),
572 }
573 }
574
575 fn combine_map(&mut self, t: CombineMapType) -> &mut CombineMap<'tcx> {
576 match t {
577 Glb => &mut self.storage.glbs,
578 Lub => &mut self.storage.lubs,
579 }
580 }
581
582 fn combine_vars(
583 &mut self,
584 tcx: TyCtxt<'tcx>,
585 t: CombineMapType,
586 a: Region<'tcx>,
587 b: Region<'tcx>,
588 origin: SubregionOrigin<'tcx>,
589 ) -> Region<'tcx> {
590 let vars = TwoRegions { a, b };
591 if let Some(&c) = self.combine_map(t).get(&vars) {
592 return ty::Region::new_var(tcx, c);
593 }
594 let a_universe = self.universe(a);
595 let b_universe = self.universe(b);
596 let c_universe = cmp::max(a_universe, b_universe);
597 let c = self.new_region_var(c_universe, RegionVariableOrigin::Misc(origin.span()));
598 self.combine_map(t).insert(vars, c);
599 self.undo_log.push(AddCombination(t, vars));
600 let new_r = ty::Region::new_var(tcx, c);
601 for old_r in [a, b] {
602 match t {
603 Glb => self.make_subregion(origin.clone(), new_r, old_r),
604 Lub => self.make_subregion(origin.clone(), old_r, new_r),
605 }
606 }
607 debug!("combine_vars() c={:?}", c);
608 new_r
609 }
610
611 pub fn universe(&mut self, region: Region<'tcx>) -> ty::UniverseIndex {
612 match region.kind() {
613 ty::ReStatic
614 | ty::ReErased
615 | ty::ReLateParam(..)
616 | ty::ReEarlyParam(..)
617 | ty::ReError(_) => ty::UniverseIndex::ROOT,
618 ty::RePlaceholder(placeholder) => placeholder.universe,
619 ty::ReVar(vid) => match self.probe_value(vid) {
620 Ok(value) => self.universe(value),
621 Err(universe) => universe,
622 },
623 ty::ReBound(..) => bug!("universe(): encountered bound region {:?}", region),
624 }
625 }
626
627 pub fn vars_since_snapshot(
628 &self,
629 value_count: usize,
630 ) -> (Range<RegionVid>, Vec<RegionVariableOrigin>) {
631 let range =
632 RegionVid::from(value_count)..RegionVid::from(self.storage.unification_table.len());
633 (
634 range.clone(),
635 (range.start..range.end).map(|index| self.storage.var_infos[index].origin).collect(),
636 )
637 }
638
639 pub fn region_constraints_added_in_snapshot(&self, mark: &Snapshot<'tcx>) -> bool {
641 self.undo_log
642 .region_constraints_in_snapshot(mark)
643 .any(|&elt| matches!(elt, AddConstraint(_)))
644 }
645
646 #[inline]
647 fn unification_table_mut(&mut self) -> super::UnificationTable<'_, 'tcx, RegionVidKey<'tcx>> {
648 ut::UnificationTable::with_log(&mut self.storage.unification_table, self.undo_log)
649 }
650}
651
652impl fmt::Debug for RegionSnapshot {
653 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
654 write!(f, "RegionSnapshot")
655 }
656}
657
658impl<'tcx> fmt::Debug for GenericKind<'tcx> {
659 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
660 match *self {
661 GenericKind::Param(ref p) => write!(f, "{p:?}"),
662 GenericKind::Placeholder(ref p) => write!(f, "{p:?}"),
663 GenericKind::Alias(ref p) => write!(f, "{p:?}"),
664 }
665 }
666}
667
668impl<'tcx> fmt::Display for GenericKind<'tcx> {
669 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
670 match *self {
671 GenericKind::Param(ref p) => write!(f, "{p}"),
672 GenericKind::Placeholder(ref p) => write!(f, "{p}"),
673 GenericKind::Alias(ref p) => write!(f, "{p}"),
674 }
675 }
676}
677
678impl<'tcx> GenericKind<'tcx> {
679 pub fn to_ty(&self, tcx: TyCtxt<'tcx>) -> Ty<'tcx> {
680 match *self {
681 GenericKind::Param(ref p) => p.to_ty(tcx),
682 GenericKind::Placeholder(ref p) => Ty::new_placeholder(tcx, *p),
683 GenericKind::Alias(ref p) => p.to_ty(tcx),
684 }
685 }
686}
687
688impl<'tcx> VerifyBound<'tcx> {
689 pub fn must_hold(&self) -> bool {
690 match self {
691 VerifyBound::IfEq(..) => false,
692 VerifyBound::OutlivedBy(re) => re.is_static(),
693 VerifyBound::IsEmpty => false,
694 VerifyBound::AnyBound(bs) => bs.iter().any(|b| b.must_hold()),
695 VerifyBound::AllBounds(bs) => bs.iter().all(|b| b.must_hold()),
696 }
697 }
698
699 pub fn cannot_hold(&self) -> bool {
700 match self {
701 VerifyBound::IfEq(..) => false,
702 VerifyBound::IsEmpty => false,
703 VerifyBound::OutlivedBy(_) => false,
704 VerifyBound::AnyBound(bs) => bs.iter().all(|b| b.cannot_hold()),
705 VerifyBound::AllBounds(bs) => bs.iter().any(|b| b.cannot_hold()),
706 }
707 }
708
709 pub fn or(self, vb: VerifyBound<'tcx>) -> VerifyBound<'tcx> {
710 if self.must_hold() || vb.cannot_hold() {
711 self
712 } else if self.cannot_hold() || vb.must_hold() {
713 vb
714 } else {
715 VerifyBound::AnyBound(vec![self, vb])
716 }
717 }
718}
719
720impl<'tcx> RegionConstraintData<'tcx> {
721 pub fn is_empty(&self) -> bool {
724 let RegionConstraintData { constraints, verifys } = self;
725 constraints.is_empty() && verifys.is_empty()
726 }
727}
728
729impl<'tcx> Rollback<UndoLog<'tcx>> for RegionConstraintStorage<'tcx> {
730 fn reverse(&mut self, undo: UndoLog<'tcx>) {
731 match undo {
732 AddVar(vid) => {
733 self.var_infos.pop().unwrap();
734 assert_eq!(self.var_infos.len(), vid.index());
735 }
736 AddConstraint(index) => {
737 self.data.constraints.pop().unwrap();
738 assert_eq!(self.data.constraints.len(), index);
739 }
740 AddVerify(index) => {
741 self.data.verifys.pop();
742 assert_eq!(self.data.verifys.len(), index);
743 }
744 AddCombination(Glb, ref regions) => {
745 self.glbs.remove(regions);
746 }
747 AddCombination(Lub, ref regions) => {
748 self.lubs.remove(regions);
749 }
750 }
751 }
752}