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::{MiscVariable, 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 Constraint<'tcx> {
84 VarSubVar(RegionVid, RegionVid),
86
87 RegSubVar(Region<'tcx>, RegionVid),
89
90 VarSubReg(RegionVid, Region<'tcx>),
94
95 RegSubReg(Region<'tcx>, Region<'tcx>),
99}
100
101impl Constraint<'_> {
102 pub fn involves_placeholders(&self) -> bool {
103 match self {
104 Constraint::VarSubVar(_, _) => false,
105 Constraint::VarSubReg(_, r) | Constraint::RegSubVar(r, _) => r.is_placeholder(),
106 Constraint::RegSubReg(r, s) => r.is_placeholder() || s.is_placeholder(),
107 }
108 }
109}
110
111#[derive(Debug, Clone)]
112pub struct Verify<'tcx> {
113 pub kind: GenericKind<'tcx>,
114 pub origin: SubregionOrigin<'tcx>,
115 pub region: Region<'tcx>,
116 pub bound: VerifyBound<'tcx>,
117}
118
119#[derive(Copy, Clone, PartialEq, Eq, Hash, TypeFoldable, TypeVisitable)]
120pub enum GenericKind<'tcx> {
121 Param(ty::ParamTy),
122 Placeholder(ty::PlaceholderType),
123 Alias(ty::AliasTy<'tcx>),
124}
125
126#[derive(Debug, Clone, TypeFoldable, TypeVisitable)]
144pub enum VerifyBound<'tcx> {
145 IfEq(ty::Binder<'tcx, VerifyIfEq<'tcx>>),
147
148 OutlivedBy(Region<'tcx>),
159
160 IsEmpty,
162
163 AnyBound(Vec<VerifyBound<'tcx>>),
174
175 AllBounds(Vec<VerifyBound<'tcx>>),
187}
188
189#[derive(Debug, Copy, Clone, TypeFoldable, TypeVisitable)]
228pub struct VerifyIfEq<'tcx> {
229 pub ty: Ty<'tcx>,
231
232 pub bound: Region<'tcx>,
234}
235
236#[derive(Copy, Clone, PartialEq, Eq, Hash)]
237pub(crate) struct TwoRegions<'tcx> {
238 a: Region<'tcx>,
239 b: Region<'tcx>,
240}
241
242#[derive(Copy, Clone, PartialEq)]
243pub(crate) enum UndoLog<'tcx> {
244 AddVar(RegionVid),
246
247 AddConstraint(usize),
249
250 AddVerify(usize),
252
253 AddCombination(CombineMapType, TwoRegions<'tcx>),
255}
256
257#[derive(Copy, Clone, PartialEq)]
258pub(crate) enum CombineMapType {
259 Lub,
260 Glb,
261}
262
263type CombineMap<'tcx> = FxHashMap<TwoRegions<'tcx>, RegionVid>;
264
265#[derive(Debug, Clone, Copy)]
266pub struct RegionVariableInfo {
267 pub origin: RegionVariableOrigin,
268 pub universe: ty::UniverseIndex,
281}
282
283pub(crate) struct RegionSnapshot {
284 any_unifications: bool,
285}
286
287impl<'tcx> RegionConstraintStorage<'tcx> {
288 #[inline]
289 pub(crate) fn with_log<'a>(
290 &'a mut self,
291 undo_log: &'a mut InferCtxtUndoLogs<'tcx>,
292 ) -> RegionConstraintCollector<'a, 'tcx> {
293 RegionConstraintCollector { storage: self, undo_log }
294 }
295}
296
297impl<'tcx> RegionConstraintCollector<'_, 'tcx> {
298 pub fn num_region_vars(&self) -> usize {
299 self.storage.var_infos.len()
300 }
301
302 pub fn take_and_reset_data(&mut self) -> RegionConstraintData<'tcx> {
315 assert!(!UndoLogs::<UndoLog<'_>>::in_snapshot(&self.undo_log));
316
317 let RegionConstraintStorage {
321 var_infos: _,
322 data,
323 lubs,
324 glbs,
325 unification_table: _,
326 any_unifications,
327 } = self.storage;
328
329 lubs.clear();
334 glbs.clear();
335
336 let data = mem::take(data);
337
338 if *any_unifications {
343 *any_unifications = false;
344 ut::UnificationTable::with_log(&mut self.storage.unification_table, &mut self.undo_log)
346 .reset_unifications(|key| RegionVariableValue::Unknown {
347 universe: self.storage.var_infos[key.vid].universe,
348 });
349 }
350
351 data
352 }
353
354 pub fn data(&self) -> &RegionConstraintData<'tcx> {
355 &self.storage.data
356 }
357
358 pub(super) fn start_snapshot(&self) -> RegionSnapshot {
359 debug!("RegionConstraintCollector: start_snapshot");
360 RegionSnapshot { any_unifications: self.storage.any_unifications }
361 }
362
363 pub(super) fn rollback_to(&mut self, snapshot: RegionSnapshot) {
364 debug!("RegionConstraintCollector: rollback_to({:?})", snapshot);
365 self.storage.any_unifications = snapshot.any_unifications;
366 }
367
368 pub(super) fn new_region_var(
369 &mut self,
370 universe: ty::UniverseIndex,
371 origin: RegionVariableOrigin,
372 ) -> RegionVid {
373 let vid = self.storage.var_infos.push(RegionVariableInfo { origin, universe });
374
375 let u_vid = self.unification_table_mut().new_key(RegionVariableValue::Unknown { universe });
376 assert_eq!(vid, u_vid.vid);
377 self.undo_log.push(AddVar(vid));
378 debug!("created new region variable {:?} in {:?} with origin {:?}", vid, universe, origin);
379 vid
380 }
381
382 pub(super) fn var_origin(&self, vid: RegionVid) -> RegionVariableOrigin {
384 self.storage.var_infos[vid].origin
385 }
386
387 fn add_constraint(&mut self, constraint: Constraint<'tcx>, origin: SubregionOrigin<'tcx>) {
388 debug!("RegionConstraintCollector: add_constraint({:?})", constraint);
390
391 let index = self.storage.data.constraints.len();
392 self.storage.data.constraints.push((constraint, origin));
393 self.undo_log.push(AddConstraint(index));
394 }
395
396 fn add_verify(&mut self, verify: Verify<'tcx>) {
397 debug!("RegionConstraintCollector: add_verify({:?})", verify);
399
400 if let VerifyBound::AllBounds(ref bs) = verify.bound
402 && bs.is_empty()
403 {
404 return;
405 }
406
407 let index = self.storage.data.verifys.len();
408 self.storage.data.verifys.push(verify);
409 self.undo_log.push(AddVerify(index));
410 }
411
412 pub(super) fn make_eqregion(
413 &mut self,
414 origin: SubregionOrigin<'tcx>,
415 a: Region<'tcx>,
416 b: Region<'tcx>,
417 ) {
418 if a != b {
419 self.make_subregion(origin.clone(), a, b);
422 self.make_subregion(origin, b, a);
423
424 match (a.kind(), b.kind()) {
425 (ty::ReVar(a), ty::ReVar(b)) => {
426 debug!("make_eqregion: unifying {:?} with {:?}", a, b);
427 if self.unification_table_mut().unify_var_var(a, b).is_ok() {
428 self.storage.any_unifications = true;
429 }
430 }
431 (ty::ReVar(vid), _) => {
432 debug!("make_eqregion: unifying {:?} with {:?}", vid, b);
433 if self
434 .unification_table_mut()
435 .unify_var_value(vid, RegionVariableValue::Known { value: b })
436 .is_ok()
437 {
438 self.storage.any_unifications = true;
439 };
440 }
441 (_, ty::ReVar(vid)) => {
442 debug!("make_eqregion: unifying {:?} with {:?}", a, vid);
443 if self
444 .unification_table_mut()
445 .unify_var_value(vid, RegionVariableValue::Known { value: a })
446 .is_ok()
447 {
448 self.storage.any_unifications = true;
449 };
450 }
451 (_, _) => {}
452 }
453 }
454 }
455
456 #[instrument(skip(self, origin), level = "debug")]
457 pub(super) fn make_subregion(
458 &mut self,
459 origin: SubregionOrigin<'tcx>,
460 sub: Region<'tcx>,
461 sup: Region<'tcx>,
462 ) {
463 debug!("origin = {:#?}", origin);
465
466 match (*sub, *sup) {
467 (ReBound(..), _) | (_, ReBound(..)) => {
468 span_bug!(origin.span(), "cannot relate bound region: {:?} <= {:?}", sub, sup);
469 }
470 (_, ReStatic) => {
471 }
473 (ReVar(sub_id), ReVar(sup_id)) => {
474 self.add_constraint(Constraint::VarSubVar(sub_id, sup_id), origin);
475 }
476 (_, ReVar(sup_id)) => {
477 self.add_constraint(Constraint::RegSubVar(sub, sup_id), origin);
478 }
479 (ReVar(sub_id), _) => {
480 self.add_constraint(Constraint::VarSubReg(sub_id, sup), origin);
481 }
482 _ => {
483 self.add_constraint(Constraint::RegSubReg(sub, sup), origin);
484 }
485 }
486 }
487
488 pub(super) fn verify_generic_bound(
489 &mut self,
490 origin: SubregionOrigin<'tcx>,
491 kind: GenericKind<'tcx>,
492 sub: Region<'tcx>,
493 bound: VerifyBound<'tcx>,
494 ) {
495 self.add_verify(Verify { kind, origin, region: sub, bound });
496 }
497
498 pub(super) fn lub_regions(
499 &mut self,
500 tcx: TyCtxt<'tcx>,
501 origin: SubregionOrigin<'tcx>,
502 a: Region<'tcx>,
503 b: Region<'tcx>,
504 ) -> Region<'tcx> {
505 debug!("RegionConstraintCollector: lub_regions({:?}, {:?})", a, b);
507 if a.is_static() || b.is_static() {
508 a } else if a == b {
510 a } else {
512 self.combine_vars(tcx, Lub, a, b, origin)
513 }
514 }
515
516 pub(super) fn glb_regions(
517 &mut self,
518 tcx: TyCtxt<'tcx>,
519 origin: SubregionOrigin<'tcx>,
520 a: Region<'tcx>,
521 b: Region<'tcx>,
522 ) -> Region<'tcx> {
523 debug!("RegionConstraintCollector: glb_regions({:?}, {:?})", a, b);
525 if a.is_static() {
526 b } else if b.is_static() {
528 a } else if a == b {
530 a } else {
532 self.combine_vars(tcx, Glb, a, b, origin)
533 }
534 }
535
536 pub fn opportunistic_resolve_var(
539 &mut self,
540 tcx: TyCtxt<'tcx>,
541 vid: ty::RegionVid,
542 ) -> ty::Region<'tcx> {
543 let mut ut = self.unification_table_mut();
544 let root_vid = ut.find(vid).vid;
545 match ut.probe_value(root_vid) {
546 RegionVariableValue::Known { value } => value,
547 RegionVariableValue::Unknown { .. } => ty::Region::new_var(tcx, root_vid),
548 }
549 }
550
551 pub fn probe_value(
552 &mut self,
553 vid: ty::RegionVid,
554 ) -> Result<ty::Region<'tcx>, ty::UniverseIndex> {
555 match self.unification_table_mut().probe_value(vid) {
556 RegionVariableValue::Known { value } => Ok(value),
557 RegionVariableValue::Unknown { universe } => Err(universe),
558 }
559 }
560
561 fn combine_map(&mut self, t: CombineMapType) -> &mut CombineMap<'tcx> {
562 match t {
563 Glb => &mut self.storage.glbs,
564 Lub => &mut self.storage.lubs,
565 }
566 }
567
568 fn combine_vars(
569 &mut self,
570 tcx: TyCtxt<'tcx>,
571 t: CombineMapType,
572 a: Region<'tcx>,
573 b: Region<'tcx>,
574 origin: SubregionOrigin<'tcx>,
575 ) -> Region<'tcx> {
576 let vars = TwoRegions { a, b };
577 if let Some(&c) = self.combine_map(t).get(&vars) {
578 return ty::Region::new_var(tcx, c);
579 }
580 let a_universe = self.universe(a);
581 let b_universe = self.universe(b);
582 let c_universe = cmp::max(a_universe, b_universe);
583 let c = self.new_region_var(c_universe, MiscVariable(origin.span()));
584 self.combine_map(t).insert(vars, c);
585 self.undo_log.push(AddCombination(t, vars));
586 let new_r = ty::Region::new_var(tcx, c);
587 for old_r in [a, b] {
588 match t {
589 Glb => self.make_subregion(origin.clone(), new_r, old_r),
590 Lub => self.make_subregion(origin.clone(), old_r, new_r),
591 }
592 }
593 debug!("combine_vars() c={:?}", c);
594 new_r
595 }
596
597 pub fn universe(&mut self, region: Region<'tcx>) -> ty::UniverseIndex {
598 match *region {
599 ty::ReStatic
600 | ty::ReErased
601 | ty::ReLateParam(..)
602 | ty::ReEarlyParam(..)
603 | ty::ReError(_) => ty::UniverseIndex::ROOT,
604 ty::RePlaceholder(placeholder) => placeholder.universe,
605 ty::ReVar(vid) => match self.probe_value(vid) {
606 Ok(value) => self.universe(value),
607 Err(universe) => universe,
608 },
609 ty::ReBound(..) => bug!("universe(): encountered bound region {:?}", region),
610 }
611 }
612
613 pub fn vars_since_snapshot(
614 &self,
615 value_count: usize,
616 ) -> (Range<RegionVid>, Vec<RegionVariableOrigin>) {
617 let range =
618 RegionVid::from(value_count)..RegionVid::from(self.storage.unification_table.len());
619 (
620 range.clone(),
621 (range.start.index()..range.end.index())
622 .map(|index| self.storage.var_infos[ty::RegionVid::from(index)].origin)
623 .collect(),
624 )
625 }
626
627 pub fn region_constraints_added_in_snapshot(&self, mark: &Snapshot<'tcx>) -> bool {
629 self.undo_log
630 .region_constraints_in_snapshot(mark)
631 .any(|&elt| matches!(elt, AddConstraint(_)))
632 }
633
634 #[inline]
635 fn unification_table_mut(&mut self) -> super::UnificationTable<'_, 'tcx, RegionVidKey<'tcx>> {
636 ut::UnificationTable::with_log(&mut self.storage.unification_table, self.undo_log)
637 }
638}
639
640impl fmt::Debug for RegionSnapshot {
641 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
642 write!(f, "RegionSnapshot")
643 }
644}
645
646impl<'tcx> fmt::Debug for GenericKind<'tcx> {
647 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
648 match *self {
649 GenericKind::Param(ref p) => write!(f, "{p:?}"),
650 GenericKind::Placeholder(ref p) => write!(f, "{p:?}"),
651 GenericKind::Alias(ref p) => write!(f, "{p:?}"),
652 }
653 }
654}
655
656impl<'tcx> fmt::Display for GenericKind<'tcx> {
657 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
658 match *self {
659 GenericKind::Param(ref p) => write!(f, "{p}"),
660 GenericKind::Placeholder(ref p) => write!(f, "{p:?}"),
661 GenericKind::Alias(ref p) => write!(f, "{p}"),
662 }
663 }
664}
665
666impl<'tcx> GenericKind<'tcx> {
667 pub fn to_ty(&self, tcx: TyCtxt<'tcx>) -> Ty<'tcx> {
668 match *self {
669 GenericKind::Param(ref p) => p.to_ty(tcx),
670 GenericKind::Placeholder(ref p) => Ty::new_placeholder(tcx, *p),
671 GenericKind::Alias(ref p) => p.to_ty(tcx),
672 }
673 }
674}
675
676impl<'tcx> VerifyBound<'tcx> {
677 pub fn must_hold(&self) -> bool {
678 match self {
679 VerifyBound::IfEq(..) => false,
680 VerifyBound::OutlivedBy(re) => re.is_static(),
681 VerifyBound::IsEmpty => false,
682 VerifyBound::AnyBound(bs) => bs.iter().any(|b| b.must_hold()),
683 VerifyBound::AllBounds(bs) => bs.iter().all(|b| b.must_hold()),
684 }
685 }
686
687 pub fn cannot_hold(&self) -> bool {
688 match self {
689 VerifyBound::IfEq(..) => false,
690 VerifyBound::IsEmpty => false,
691 VerifyBound::OutlivedBy(_) => false,
692 VerifyBound::AnyBound(bs) => bs.iter().all(|b| b.cannot_hold()),
693 VerifyBound::AllBounds(bs) => bs.iter().any(|b| b.cannot_hold()),
694 }
695 }
696
697 pub fn or(self, vb: VerifyBound<'tcx>) -> VerifyBound<'tcx> {
698 if self.must_hold() || vb.cannot_hold() {
699 self
700 } else if self.cannot_hold() || vb.must_hold() {
701 vb
702 } else {
703 VerifyBound::AnyBound(vec![self, vb])
704 }
705 }
706}
707
708impl<'tcx> RegionConstraintData<'tcx> {
709 pub fn is_empty(&self) -> bool {
712 let RegionConstraintData { constraints, verifys } = self;
713 constraints.is_empty() && verifys.is_empty()
714 }
715}
716
717impl<'tcx> Rollback<UndoLog<'tcx>> for RegionConstraintStorage<'tcx> {
718 fn reverse(&mut self, undo: UndoLog<'tcx>) {
719 match undo {
720 AddVar(vid) => {
721 self.var_infos.pop().unwrap();
722 assert_eq!(self.var_infos.len(), vid.index());
723 }
724 AddConstraint(index) => {
725 self.data.constraints.pop().unwrap();
726 assert_eq!(self.data.constraints.len(), index);
727 }
728 AddVerify(index) => {
729 self.data.verifys.pop();
730 assert_eq!(self.data.verifys.len(), index);
731 }
732 AddCombination(Glb, ref regions) => {
733 self.glbs.remove(regions);
734 }
735 AddCombination(Lub, ref regions) => {
736 self.lubs.remove(regions);
737 }
738 }
739 }
740}