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}