2 use crate::infer::{CombinedSnapshot, PlaceholderMap};
3 use crate::ty::error::TypeError;
4 use crate::ty::relate::RelateResult;
6 impl<'tcx> RegionConstraintCollector<'tcx> {
7 /// Searches region constraints created since `snapshot` that
8 /// affect one of the placeholders in `placeholder_map`, returning
9 /// an error if any of the placeholders are related to another
10 /// placeholder or would have to escape into some parent universe
11 /// that cannot name them.
13 /// This is a temporary backwards compatibility measure to try and
14 /// retain the older (arguably incorrect) behavior of the
17 /// NB. Although `_snapshot` isn't used, it's passed in to prove
18 /// that we are in a snapshot, which guarantees that we can just
19 /// search the "undo log" for edges. This is mostly an efficiency
20 /// thing -- we could search *all* region constraints, but that'd be
21 /// a bigger set and the data structures are not setup for that. If
22 /// we wind up keeping some form of this check long term, it would
23 /// probably be better to remove the snapshot parameter and to
24 /// refactor the constraint set.
28 overly_polymorphic: bool,
29 placeholder_map: &PlaceholderMap<'tcx>,
30 _snapshot: &CombinedSnapshot<'_, 'tcx>,
31 ) -> RelateResult<'tcx, ()> {
32 debug!("leak_check(placeholders={:?})", placeholder_map);
34 assert!(self.in_snapshot());
36 // If the user gave `-Zno-leak-check`, then skip the leak
37 // check completely. This is wildly unsound and also not
38 // unlikely to cause an ICE or two. It is intended for use
39 // only during a transition period, in which the MIR typeck
40 // uses the "universe-style" check, and the rest of typeck
41 // uses the more conservative leak check. Since the leak
42 // check is more conservative, we can't test the
43 // universe-style check without disabling it.
44 if tcx.sess.opts.debugging_opts.no_leak_check {
48 // Go through each placeholder that we created.
49 for (_, &placeholder_region) in placeholder_map {
50 // Find the universe this placeholder inhabits.
51 let placeholder = match placeholder_region {
52 ty::RePlaceholder(p) => p,
54 "leak_check: expected placeholder found {:?}",
59 // Find all regions that are related to this placeholder
60 // in some way. This means any region that either outlives
61 // or is outlived by a placeholder.
62 let mut taint_set = TaintSet::new(
63 TaintDirections::both(),
66 taint_set.fixed_point(tcx, &self.undo_log, &self.data.verifys);
67 let tainted_regions = taint_set.into_set();
69 // Report an error if two placeholders in the same universe
70 // are related to one another, or if a placeholder is related
71 // to something from a parent universe.
72 for &tainted_region in &tainted_regions {
73 if let ty::RePlaceholder(_) = tainted_region {
74 // Two placeholders cannot be related:
75 if tainted_region == placeholder_region {
78 } else if self.universe(tainted_region).can_name(placeholder.universe) {
82 return Err(if overly_polymorphic {
83 debug!("overly polymorphic!");
84 TypeError::RegionsOverlyPolymorphic(placeholder.name, tainted_region)
86 debug!("not as polymorphic!");
87 TypeError::RegionsInsufficientlyPolymorphic(placeholder.name, tainted_region)
97 struct TaintSet<'tcx> {
98 directions: TaintDirections,
99 regions: FxHashSet<ty::Region<'tcx>>,
102 impl<'tcx> TaintSet<'tcx> {
103 fn new(directions: TaintDirections, initial_region: ty::Region<'tcx>) -> Self {
104 let mut regions = FxHashSet::default();
105 regions.insert(initial_region);
107 directions: directions,
115 undo_log: &[UndoLog<'tcx>],
116 verifys: &[Verify<'tcx>],
118 let mut prev_len = 0;
119 while prev_len < self.len() {
121 "tainted: prev_len = {:?} new_len = {:?}",
126 prev_len = self.len();
128 for undo_entry in undo_log {
130 &AddConstraint(Constraint::VarSubVar(a, b)) => {
131 self.add_edge(tcx.mk_region(ReVar(a)), tcx.mk_region(ReVar(b)));
133 &AddConstraint(Constraint::RegSubVar(a, b)) => {
134 self.add_edge(a, tcx.mk_region(ReVar(b)));
136 &AddConstraint(Constraint::VarSubReg(a, b)) => {
137 self.add_edge(tcx.mk_region(ReVar(a)), b);
139 &AddConstraint(Constraint::RegSubReg(a, b)) => {
143 self.add_edge(a, tcx.mk_region(ReVar(b)));
145 &AddVerify(i) => span_bug!(
146 verifys[i].origin.span(),
147 "we never add verifications while doing higher-ranked things",
149 &Purged | &AddCombination(..) | &AddVar(..) => {}
155 fn into_set(self) -> FxHashSet<ty::Region<'tcx>> {
159 fn len(&self) -> usize {
163 fn add_edge(&mut self, source: ty::Region<'tcx>, target: ty::Region<'tcx>) {
164 if self.directions.incoming {
165 if self.regions.contains(&target) {
166 self.regions.insert(source);
170 if self.directions.outgoing {
171 if self.regions.contains(&source) {
172 self.regions.insert(target);