rustc_infer/infer/lexical_region_resolve/
mod.rs

1//! Lexical region resolution.
2
3use std::fmt;
4
5use rustc_data_structures::fx::FxHashSet;
6use rustc_data_structures::graph::linked_graph::{
7    Direction, INCOMING, LinkedGraph, NodeIndex, OUTGOING,
8};
9use rustc_data_structures::intern::Interned;
10use rustc_data_structures::unord::UnordSet;
11use rustc_index::{IndexSlice, IndexVec};
12use rustc_middle::ty::{
13    self, ReBound, ReEarlyParam, ReErased, ReError, ReLateParam, RePlaceholder, ReStatic, ReVar,
14    Region, RegionVid, Ty, TyCtxt, TypeFoldable, fold_regions,
15};
16use rustc_middle::{bug, span_bug};
17use rustc_span::Span;
18use tracing::{debug, instrument};
19
20use super::outlives::test_type_match;
21use crate::infer::region_constraints::{
22    Constraint, ConstraintKind, GenericKind, RegionConstraintData, VarInfos, VerifyBound,
23};
24use crate::infer::{RegionRelations, RegionVariableOrigin, SubregionOrigin};
25
26/// This function performs lexical region resolution given a complete
27/// set of constraints and variable origins. It performs a fixed-point
28/// iteration to find region values which satisfy all constraints,
29/// assuming such values can be found. It returns the final values of
30/// all the variables as well as a set of errors that must be reported.
31#[instrument(level = "debug", skip(region_rels, var_infos, data))]
32pub(crate) fn resolve<'tcx>(
33    region_rels: &RegionRelations<'_, 'tcx>,
34    var_infos: VarInfos,
35    data: RegionConstraintData<'tcx>,
36) -> (LexicalRegionResolutions<'tcx>, Vec<RegionResolutionError<'tcx>>) {
37    let mut errors = vec![];
38    let mut resolver = LexicalResolver { region_rels, var_infos, data };
39    let values = resolver.infer_variable_values(&mut errors);
40    (values, errors)
41}
42
43/// Contains the result of lexical region resolution. Offers methods
44/// to lookup up the final value of a region variable.
45#[derive(Clone)]
46pub(crate) struct LexicalRegionResolutions<'tcx> {
47    pub(crate) values: IndexVec<RegionVid, VarValue<'tcx>>,
48}
49
50#[derive(Copy, Clone, Debug)]
51pub(crate) enum VarValue<'tcx> {
52    /// Empty lifetime is for data that is never accessed. We tag the
53    /// empty lifetime with a universe -- the idea is that we don't
54    /// want `exists<'a> { forall<'b> { 'b: 'a } }` to be satisfiable.
55    /// Therefore, the `'empty` in a universe `U` is less than all
56    /// regions visible from `U`, but not less than regions not visible
57    /// from `U`.
58    Empty(ty::UniverseIndex),
59    Value(Region<'tcx>),
60    ErrorValue,
61}
62
63#[derive(Clone, Debug)]
64pub enum RegionResolutionError<'tcx> {
65    /// `ConcreteFailure(o, a, b)`:
66    ///
67    /// `o` requires that `a <= b`, but this does not hold
68    ConcreteFailure(SubregionOrigin<'tcx>, Region<'tcx>, Region<'tcx>),
69
70    /// `GenericBoundFailure(p, s, a)`:
71    ///
72    /// The parameter/associated-type `p` must be known to outlive the lifetime
73    /// `a` (but none of the known bounds are sufficient).
74    GenericBoundFailure(SubregionOrigin<'tcx>, GenericKind<'tcx>, Region<'tcx>),
75
76    /// `SubSupConflict(v, v_origin, sub_origin, sub_r, sup_origin, sup_r)`:
77    ///
78    /// Could not infer a value for `v` (which has origin `v_origin`)
79    /// because `sub_r <= v` (due to `sub_origin`) but `v <= sup_r` (due to `sup_origin`) and
80    /// `sub_r <= sup_r` does not hold.
81    SubSupConflict(
82        RegionVid,
83        RegionVariableOrigin,
84        SubregionOrigin<'tcx>,
85        Region<'tcx>,
86        SubregionOrigin<'tcx>,
87        Region<'tcx>,
88        Vec<Span>, // All the influences on a given value that didn't meet its constraints.
89    ),
90
91    /// Indicates a `'b: 'a` constraint where `'a` is in a universe that
92    /// cannot name the placeholder `'b`.
93    UpperBoundUniverseConflict(
94        RegionVid,
95        RegionVariableOrigin,
96        ty::UniverseIndex,     // the universe index of the region variable
97        SubregionOrigin<'tcx>, // cause of the constraint
98        Region<'tcx>,          // the placeholder `'b`
99    ),
100
101    CannotNormalize(ty::PolyTypeOutlivesPredicate<'tcx>, SubregionOrigin<'tcx>),
102}
103
104impl<'tcx> RegionResolutionError<'tcx> {
105    pub fn origin(&self) -> &SubregionOrigin<'tcx> {
106        match self {
107            RegionResolutionError::ConcreteFailure(origin, _, _)
108            | RegionResolutionError::GenericBoundFailure(origin, _, _)
109            | RegionResolutionError::SubSupConflict(_, _, origin, _, _, _, _)
110            | RegionResolutionError::UpperBoundUniverseConflict(_, _, _, origin, _)
111            | RegionResolutionError::CannotNormalize(_, origin) => origin,
112        }
113    }
114}
115
116struct RegionAndOrigin<'tcx> {
117    region: Region<'tcx>,
118    origin: SubregionOrigin<'tcx>,
119}
120
121type RegionGraph<'tcx> = LinkedGraph<(), Constraint<'tcx>>;
122
123struct LexicalResolver<'cx, 'tcx> {
124    region_rels: &'cx RegionRelations<'cx, 'tcx>,
125    var_infos: VarInfos,
126    data: RegionConstraintData<'tcx>,
127}
128
129impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> {
130    fn tcx(&self) -> TyCtxt<'tcx> {
131        self.region_rels.tcx
132    }
133
134    fn infer_variable_values(
135        &mut self,
136        errors: &mut Vec<RegionResolutionError<'tcx>>,
137    ) -> LexicalRegionResolutions<'tcx> {
138        let mut var_data = self.construct_var_data();
139
140        // Deduplicating constraints is shown to have a positive perf impact.
141        let mut seen = UnordSet::default();
142        self.data.constraints.retain(|(constraint, _)| seen.insert(*constraint));
143
144        if cfg!(debug_assertions) {
145            self.dump_constraints();
146        }
147
148        self.expansion(&mut var_data);
149        self.collect_errors(&mut var_data, errors);
150        self.collect_var_errors(&var_data, errors);
151        var_data
152    }
153
154    fn num_vars(&self) -> usize {
155        self.var_infos.len()
156    }
157
158    /// Initially, the value for all variables is set to `'empty`, the
159    /// empty region. The `expansion` phase will grow this larger.
160    fn construct_var_data(&self) -> LexicalRegionResolutions<'tcx> {
161        LexicalRegionResolutions {
162            values: IndexVec::<RegionVid, _>::from_fn_n(
163                |vid| {
164                    let vid_universe = self.var_infos[vid].universe;
165                    VarValue::Empty(vid_universe)
166                },
167                self.num_vars(),
168            ),
169        }
170    }
171
172    #[instrument(level = "debug", skip(self))]
173    fn dump_constraints(&self) {
174        for (idx, (constraint, _)) in self.data.constraints.iter().enumerate() {
175            debug!("Constraint {} => {:?}", idx, constraint);
176        }
177    }
178
179    fn expansion(&self, var_values: &mut LexicalRegionResolutions<'tcx>) {
180        // In the first pass, we expand region vids according to constraints we
181        // have previously found. In the second pass, we loop through the region
182        // vids we expanded and expand *across* region vids (effectively
183        // "expanding" new `RegSubVar` constraints).
184
185        // Tracks the `VarSubVar` constraints generated for each region vid. We
186        // later use this to expand across vids.
187        let mut constraints = IndexVec::from_elem(Vec::new(), &var_values.values);
188        // Tracks the changed region vids.
189        let mut changes = Vec::new();
190        for (c, _) in &self.data.constraints {
191            match c.kind {
192                ConstraintKind::RegSubVar => {
193                    let sup_vid = c.sup.as_var();
194                    let sup_data = var_values.value_mut(sup_vid);
195
196                    if self.expand_node(c.sub, sup_vid, sup_data) {
197                        changes.push(sup_vid);
198                    }
199                }
200                ConstraintKind::VarSubVar => {
201                    let sub_vid = c.sub.as_var();
202                    let sup_vid = c.sup.as_var();
203                    match *var_values.value(sub_vid) {
204                        VarValue::ErrorValue => continue,
205                        VarValue::Empty(sub_universe) => {
206                            let sup_data = var_values.value_mut(sup_vid);
207
208                            let changed = match *sup_data {
209                                VarValue::Empty(sup_universe) => {
210                                    // Empty regions are ordered according to the universe
211                                    // they are associated with.
212                                    let ui = sub_universe.min(sup_universe);
213
214                                    debug!(
215                                        "Expanding value of {:?} \
216                                    from empty lifetime with universe {:?} \
217                                    to empty lifetime with universe {:?}",
218                                        sup_vid, sup_universe, ui
219                                    );
220
221                                    *sup_data = VarValue::Empty(ui);
222                                    true
223                                }
224                                VarValue::Value(cur_region) => {
225                                    match cur_region.kind() {
226                                        // If this empty region is from a universe that can name
227                                        // the placeholder universe, then the LUB is the
228                                        // Placeholder region (which is the cur_region). Otherwise,
229                                        // the LUB is the Static lifetime.
230                                        RePlaceholder(placeholder)
231                                            if !sub_universe.can_name(placeholder.universe) =>
232                                        {
233                                            let lub = self.tcx().lifetimes.re_static;
234                                            debug!(
235                                                "Expanding value of {:?} from {:?} to {:?}",
236                                                sup_vid, cur_region, lub
237                                            );
238
239                                            *sup_data = VarValue::Value(lub);
240                                            true
241                                        }
242
243                                        _ => false,
244                                    }
245                                }
246
247                                VarValue::ErrorValue => false,
248                            };
249
250                            if changed {
251                                changes.push(sup_vid);
252                            }
253                            match sup_data {
254                                VarValue::Value(Region(Interned(ReStatic, _)))
255                                | VarValue::ErrorValue => (),
256                                _ => {
257                                    constraints[sub_vid].push((sub_vid, sup_vid));
258                                    constraints[sup_vid].push((sub_vid, sup_vid));
259                                }
260                            }
261                        }
262                        VarValue::Value(sub_region) => {
263                            let sup_data = var_values.value_mut(sup_vid);
264
265                            if self.expand_node(sub_region, sup_vid, sup_data) {
266                                changes.push(sup_vid);
267                            }
268                            match sup_data {
269                                VarValue::Value(Region(Interned(ReStatic, _)))
270                                | VarValue::ErrorValue => (),
271                                _ => {
272                                    constraints[sub_vid].push((sub_vid, sup_vid));
273                                    constraints[sup_vid].push((sub_vid, sup_vid));
274                                }
275                            }
276                        }
277                    }
278                }
279                ConstraintKind::RegSubReg | ConstraintKind::VarSubReg => {
280                    // These constraints are checked after expansion
281                    // is done, in `collect_errors`.
282                    continue;
283                }
284            }
285        }
286
287        while let Some(vid) = changes.pop() {
288            constraints[vid].retain(|&(a_vid, b_vid)| {
289                let VarValue::Value(a_region) = *var_values.value(a_vid) else {
290                    return false;
291                };
292                let b_data = var_values.value_mut(b_vid);
293                if self.expand_node(a_region, b_vid, b_data) {
294                    changes.push(b_vid);
295                }
296                !matches!(
297                    b_data,
298                    VarValue::Value(Region(Interned(ReStatic, _))) | VarValue::ErrorValue
299                )
300            });
301        }
302    }
303
304    /// Expands the value of the region represented with `b_vid` with current
305    /// value `b_data` to the lub of `b_data` and `a_region`. The corresponds
306    /// with the constraint `'?b: 'a` (`'a <: '?b`), where `'a` is some known
307    /// region and `'?b` is some region variable.
308    fn expand_node(
309        &self,
310        a_region: Region<'tcx>,
311        b_vid: RegionVid,
312        b_data: &mut VarValue<'tcx>,
313    ) -> bool {
314        debug!("expand_node({:?}, {:?} == {:?})", a_region, b_vid, b_data);
315
316        match *b_data {
317            VarValue::Empty(empty_ui) => {
318                let lub = match a_region.kind() {
319                    RePlaceholder(placeholder) => {
320                        // If this empty region is from a universe that can
321                        // name the placeholder, then the placeholder is
322                        // larger; otherwise, the only ancestor is `'static`.
323                        if empty_ui.can_name(placeholder.universe) {
324                            ty::Region::new_placeholder(self.tcx(), placeholder)
325                        } else {
326                            self.tcx().lifetimes.re_static
327                        }
328                    }
329
330                    _ => a_region,
331                };
332
333                debug!("Expanding value of {:?} from empty lifetime to {:?}", b_vid, lub);
334
335                *b_data = VarValue::Value(lub);
336                true
337            }
338            VarValue::Value(cur_region) => {
339                // This is a specialized version of the `lub_concrete_regions`
340                // check below for a common case, here purely as an
341                // optimization.
342                let b_universe = self.var_infos[b_vid].universe;
343
344                let mut lub = self.lub_concrete_regions(a_region, cur_region);
345                if lub == cur_region {
346                    return false;
347                }
348
349                // Watch out for `'b: !1` relationships, where the
350                // universe of `'b` can't name the placeholder `!1`. In
351                // that case, we have to grow `'b` to be `'static` for the
352                // relationship to hold. This is obviously a kind of sub-optimal
353                // choice -- in the future, when we incorporate a knowledge
354                // of the parameter environment, we might be able to find a
355                // tighter bound than `'static`.
356                //
357                // (This might e.g. arise from being asked to prove `for<'a> { 'b: 'a }`.)
358                if let ty::RePlaceholder(p) = lub.kind()
359                    && b_universe.cannot_name(p.universe)
360                {
361                    lub = self.tcx().lifetimes.re_static;
362                }
363
364                debug!("Expanding value of {:?} from {:?} to {:?}", b_vid, cur_region, lub);
365
366                *b_data = VarValue::Value(lub);
367                true
368            }
369
370            VarValue::ErrorValue => false,
371        }
372    }
373
374    /// True if `a <= b`.
375    fn sub_region_values(&self, a: VarValue<'tcx>, b: VarValue<'tcx>) -> bool {
376        match (a, b) {
377            // Error region is `'static`
378            (VarValue::ErrorValue, _) | (_, VarValue::ErrorValue) => return true,
379            (VarValue::Empty(a_ui), VarValue::Empty(b_ui)) => {
380                // Empty regions are ordered according to the universe
381                // they are associated with.
382                a_ui.min(b_ui) == b_ui
383            }
384            (VarValue::Value(a), VarValue::Empty(_)) => {
385                match a.kind() {
386                    // this is always on an error path,
387                    // so it doesn't really matter if it's shorter or longer than an empty region
388                    ReError(_) => false,
389
390                    ReBound(..) | ReErased => {
391                        bug!("cannot relate region: {:?}", a);
392                    }
393
394                    ReVar(v_id) => {
395                        span_bug!(
396                            self.var_infos[v_id].origin.span(),
397                            "lub_concrete_regions invoked with non-concrete region: {:?}",
398                            a
399                        );
400                    }
401
402                    ReStatic | ReEarlyParam(_) | ReLateParam(_) => {
403                        // nothing lives longer than `'static`
404
405                        // All empty regions are less than early-bound, free,
406                        // and scope regions.
407
408                        false
409                    }
410
411                    RePlaceholder(_) => {
412                        // The LUB is either `a` or `'static`
413                        false
414                    }
415                }
416            }
417            (VarValue::Empty(a_ui), VarValue::Value(b)) => {
418                match b.kind() {
419                    // this is always on an error path,
420                    // so it doesn't really matter if it's shorter or longer than an empty region
421                    ReError(_) => false,
422
423                    ReBound(..) | ReErased => {
424                        bug!("cannot relate region: {:?}", b);
425                    }
426
427                    ReVar(v_id) => {
428                        span_bug!(
429                            self.var_infos[v_id].origin.span(),
430                            "lub_concrete_regions invoked with non-concrete regions: {:?}",
431                            b
432                        );
433                    }
434
435                    ReStatic | ReEarlyParam(_) | ReLateParam(_) => {
436                        // nothing lives longer than `'static`
437                        // All empty regions are less than early-bound, late-bound,
438                        // and scope regions.
439                        true
440                    }
441
442                    RePlaceholder(placeholder) => {
443                        // If this empty region is from a universe that can
444                        // name the placeholder, then the placeholder is
445                        // larger; otherwise, the only ancestor is `'static`.
446                        return a_ui.can_name(placeholder.universe);
447                    }
448                }
449            }
450            (VarValue::Value(a), VarValue::Value(b)) => self.sub_concrete_regions(a, b),
451        }
452    }
453
454    /// True if `a <= b`, but not defined over inference variables.
455    #[instrument(level = "trace", skip(self))]
456    fn sub_concrete_regions(&self, a: Region<'tcx>, b: Region<'tcx>) -> bool {
457        let tcx = self.tcx();
458        let sub_free_regions = |r1, r2| self.region_rels.free_regions.sub_free_regions(tcx, r1, r2);
459
460        // Check for the case where we know that `'b: 'static` -- in that case,
461        // `a <= b` for all `a`.
462        if b.is_free() && sub_free_regions(tcx.lifetimes.re_static, b) {
463            return true;
464        }
465
466        // If both `a` and `b` are free, consult the declared
467        // relationships. Note that this can be more precise than the
468        // `lub` relationship defined below, since sometimes the "lub"
469        // is actually the `postdom_upper_bound` (see
470        // `TransitiveRelation` for more details).
471        if a.is_free() && b.is_free() {
472            return sub_free_regions(a, b);
473        }
474
475        // For other cases, leverage the LUB code to find the LUB and
476        // check if it is equal to `b`.
477        self.lub_concrete_regions(a, b) == b
478    }
479
480    /// Returns the least-upper-bound of `a` and `b`; i.e., the
481    /// smallest region `c` such that `a <= c` and `b <= c`.
482    ///
483    /// Neither `a` nor `b` may be an inference variable (hence the
484    /// term "concrete regions").
485    #[instrument(level = "trace", skip(self), ret)]
486    fn lub_concrete_regions(&self, a: Region<'tcx>, b: Region<'tcx>) -> Region<'tcx> {
487        match (a.kind(), b.kind()) {
488            (ReBound(..), _) | (_, ReBound(..)) | (ReErased, _) | (_, ReErased) => {
489                bug!("cannot relate region: LUB({:?}, {:?})", a, b);
490            }
491
492            (ReVar(v_id), _) | (_, ReVar(v_id)) => {
493                span_bug!(
494                    self.var_infos[v_id].origin.span(),
495                    "lub_concrete_regions invoked with non-concrete \
496                     regions: {:?}, {:?}",
497                    a,
498                    b
499                );
500            }
501
502            (ReError(_), _) => a,
503
504            (_, ReError(_)) => b,
505
506            (ReStatic, _) | (_, ReStatic) => {
507                // nothing lives longer than `'static`
508                self.tcx().lifetimes.re_static
509            }
510
511            (ReEarlyParam(_) | ReLateParam(_), ReEarlyParam(_) | ReLateParam(_)) => {
512                self.region_rels.lub_param_regions(a, b)
513            }
514
515            // For these types, we cannot define any additional
516            // relationship:
517            (RePlaceholder(..), _) | (_, RePlaceholder(..)) => {
518                if a == b {
519                    a
520                } else {
521                    self.tcx().lifetimes.re_static
522                }
523            }
524        }
525    }
526
527    /// After expansion is complete, go and check upper bounds (i.e.,
528    /// cases where the region cannot grow larger than a fixed point)
529    /// and check that they are satisfied.
530    #[instrument(skip(self, var_data, errors))]
531    fn collect_errors(
532        &self,
533        var_data: &mut LexicalRegionResolutions<'tcx>,
534        errors: &mut Vec<RegionResolutionError<'tcx>>,
535    ) {
536        for (c, origin) in &self.data.constraints {
537            debug!(?c, ?origin);
538            match c.kind {
539                ConstraintKind::RegSubVar | ConstraintKind::VarSubVar => {
540                    // Expansion will ensure that these constraints hold. Ignore.
541                }
542
543                ConstraintKind::RegSubReg => {
544                    if self.sub_concrete_regions(c.sub, c.sup) {
545                        continue;
546                    }
547
548                    debug!(
549                        "region error at {:?}: cannot verify that {:?} <= {:?}",
550                        origin, c.sub, c.sup
551                    );
552
553                    errors.push(RegionResolutionError::ConcreteFailure(
554                        (*origin).clone(),
555                        c.sub,
556                        c.sup,
557                    ));
558                }
559
560                ConstraintKind::VarSubReg => {
561                    let sub_vid = c.sub.as_var();
562                    let sub_data = var_data.value_mut(sub_vid);
563                    debug!("contraction: {:?} == {:?}, {:?}", sub_vid, sub_data, c.sup);
564
565                    let VarValue::Value(sub_region) = *sub_data else {
566                        continue;
567                    };
568
569                    // Do not report these errors immediately:
570                    // instead, set the variable value to error and
571                    // collect them later.
572                    if !self.sub_concrete_regions(sub_region, c.sup) {
573                        debug!(
574                            "region error at {:?}: cannot verify that {:?}={:?} <= {:?}",
575                            origin, sub_vid, sub_region, c.sup
576                        );
577                        *sub_data = VarValue::ErrorValue;
578                    }
579                }
580            }
581        }
582
583        for verify in &self.data.verifys {
584            debug!("collect_errors: verify={:?}", verify);
585            let sub = var_data.normalize(self.tcx(), verify.region);
586
587            let verify_kind_ty = verify.kind.to_ty(self.tcx());
588            let verify_kind_ty = var_data.normalize(self.tcx(), verify_kind_ty);
589            if self.bound_is_met(&verify.bound, var_data, verify_kind_ty, sub) {
590                continue;
591            }
592
593            debug!(
594                "collect_errors: region error at {:?}: \
595                 cannot verify that {:?} <= {:?}",
596                verify.origin, verify.region, verify.bound
597            );
598
599            errors.push(RegionResolutionError::GenericBoundFailure(
600                verify.origin.clone(),
601                verify.kind,
602                sub,
603            ));
604        }
605    }
606
607    /// Go over the variables that were declared to be error variables
608    /// and create a `RegionResolutionError` for each of them.
609    fn collect_var_errors(
610        &self,
611        var_data: &LexicalRegionResolutions<'tcx>,
612        errors: &mut Vec<RegionResolutionError<'tcx>>,
613    ) {
614        debug!("collect_var_errors, var_data = {:#?}", var_data.values);
615
616        // This is the best way that I have found to suppress
617        // duplicate and related errors. Basically we keep a set of
618        // flags for every node. Whenever an error occurs, we will
619        // walk some portion of the graph looking to find pairs of
620        // conflicting regions to report to the user. As we walk, we
621        // trip the flags from false to true, and if we find that
622        // we've already reported an error involving any particular
623        // node we just stop and don't report the current error. The
624        // idea is to report errors that derive from independent
625        // regions of the graph, but not those that derive from
626        // overlapping locations.
627        let mut dup_vec = IndexVec::from_elem_n(None, self.num_vars());
628
629        // Only construct the graph when necessary, because it's moderately
630        // expensive.
631        let mut graph = None;
632
633        for (node_vid, value) in var_data.values.iter_enumerated() {
634            match *value {
635                VarValue::Empty(_) | VarValue::Value(_) => { /* Inference successful */ }
636                VarValue::ErrorValue => {
637                    // Inference impossible: this value contains
638                    // inconsistent constraints.
639                    //
640                    // I think that in this case we should report an
641                    // error now -- unlike the case above, we can't
642                    // wait to see whether the user needs the result
643                    // of this variable. The reason is that the mere
644                    // existence of this variable implies that the
645                    // region graph is inconsistent, whether or not it
646                    // is used.
647                    //
648                    // For example, we may have created a region
649                    // variable that is the GLB of two other regions
650                    // which do not have a GLB. Even if that variable
651                    // is not used, it implies that those two regions
652                    // *should* have a GLB.
653                    //
654                    // At least I think this is true. It may be that
655                    // the mere existence of a conflict in a region
656                    // variable that is not used is not a problem, so
657                    // if this rule starts to create problems we'll
658                    // have to revisit this portion of the code and
659                    // think hard about it. =) -- nikomatsakis
660
661                    // Obtain the spans for all the places that can
662                    // influence the constraints on this value for
663                    // richer diagnostics in `static_impl_trait`.
664
665                    let g = graph.get_or_insert_with(|| self.construct_graph());
666                    self.collect_error_for_expanding_node(g, &mut dup_vec, node_vid, errors);
667                }
668            }
669        }
670    }
671
672    fn construct_graph(&self) -> RegionGraph<'tcx> {
673        let num_vars = self.num_vars();
674
675        let mut graph = LinkedGraph::new();
676
677        for _ in 0..num_vars {
678            graph.add_node(());
679        }
680
681        // Issue #30438: two distinct dummy nodes, one for incoming
682        // edges (dummy_source) and another for outgoing edges
683        // (dummy_sink). In `dummy -> a -> b -> dummy`, using one
684        // dummy node leads one to think (erroneously) there exists a
685        // path from `b` to `a`. Two dummy nodes sidesteps the issue.
686        let dummy_source = graph.add_node(());
687        let dummy_sink = graph.add_node(());
688
689        for (c, _) in &self.data.constraints {
690            match c.kind {
691                ConstraintKind::VarSubVar => {
692                    let sub_vid = c.sub.as_var();
693                    let sup_vid = c.sup.as_var();
694                    graph.add_edge(NodeIndex(sub_vid.index()), NodeIndex(sup_vid.index()), *c);
695                }
696                ConstraintKind::RegSubVar => {
697                    graph.add_edge(dummy_source, NodeIndex(c.sup.as_var().index()), *c);
698                }
699                ConstraintKind::VarSubReg => {
700                    graph.add_edge(NodeIndex(c.sub.as_var().index()), dummy_sink, *c);
701                }
702                ConstraintKind::RegSubReg => {
703                    // this would be an edge from `dummy_source` to
704                    // `dummy_sink`; just ignore it.
705                }
706            }
707        }
708
709        graph
710    }
711
712    fn collect_error_for_expanding_node(
713        &self,
714        graph: &RegionGraph<'tcx>,
715        dup_vec: &mut IndexSlice<RegionVid, Option<RegionVid>>,
716        node_idx: RegionVid,
717        errors: &mut Vec<RegionResolutionError<'tcx>>,
718    ) {
719        // Errors in expanding nodes result from a lower-bound that is
720        // not contained by an upper-bound.
721        let (mut lower_bounds, lower_vid_bounds, lower_dup) =
722            self.collect_bounding_regions(graph, node_idx, INCOMING, Some(dup_vec));
723        let (mut upper_bounds, _, upper_dup) =
724            self.collect_bounding_regions(graph, node_idx, OUTGOING, Some(dup_vec));
725
726        if lower_dup || upper_dup {
727            return;
728        }
729
730        // We place late-bound regions first because we are special casing
731        // SubSupConflict(ReLateParam, ReLateParam) when reporting error, and so
732        // the user will more likely get a specific suggestion.
733        fn region_order_key(x: &RegionAndOrigin<'_>) -> u8 {
734            match x.region.kind() {
735                ReEarlyParam(_) => 0,
736                ReLateParam(_) => 1,
737                _ => 2,
738            }
739        }
740        lower_bounds.sort_by_key(region_order_key);
741        upper_bounds.sort_by_key(region_order_key);
742
743        let node_universe = self.var_infos[node_idx].universe;
744
745        for lower_bound in &lower_bounds {
746            let effective_lower_bound = if let ty::RePlaceholder(p) = lower_bound.region.kind() {
747                if node_universe.cannot_name(p.universe) {
748                    self.tcx().lifetimes.re_static
749                } else {
750                    lower_bound.region
751                }
752            } else {
753                lower_bound.region
754            };
755
756            for upper_bound in &upper_bounds {
757                if !self.sub_concrete_regions(effective_lower_bound, upper_bound.region) {
758                    let origin = self.var_infos[node_idx].origin;
759                    debug!(
760                        "region inference error at {:?} for {:?}: SubSupConflict sub: {:?} \
761                         sup: {:?}",
762                        origin, node_idx, lower_bound.region, upper_bound.region
763                    );
764
765                    errors.push(RegionResolutionError::SubSupConflict(
766                        node_idx,
767                        origin,
768                        lower_bound.origin.clone(),
769                        lower_bound.region,
770                        upper_bound.origin.clone(),
771                        upper_bound.region,
772                        vec![],
773                    ));
774                    return;
775                }
776            }
777        }
778
779        // If we have a scenario like `exists<'a> { forall<'b> { 'b:
780        // 'a } }`, we wind up without any lower-bound -- all we have
781        // are placeholders as upper bounds, but the universe of the
782        // variable `'a`, or some variable that `'a` has to outlive, doesn't
783        // permit those placeholders.
784        //
785        // We only iterate to find the min, which means it doesn't cause reproducibility issues
786        #[allow(rustc::potential_query_instability)]
787        let min_universe = lower_vid_bounds
788            .into_iter()
789            .map(|vid| self.var_infos[vid].universe)
790            .min()
791            .expect("lower_vid_bounds should at least include `node_idx`");
792
793        for upper_bound in &upper_bounds {
794            if let ty::RePlaceholder(p) = upper_bound.region.kind() {
795                if min_universe.cannot_name(p.universe) {
796                    let origin = self.var_infos[node_idx].origin;
797                    errors.push(RegionResolutionError::UpperBoundUniverseConflict(
798                        node_idx,
799                        origin,
800                        min_universe,
801                        upper_bound.origin.clone(),
802                        upper_bound.region,
803                    ));
804                    return;
805                }
806            }
807        }
808
809        // Errors in earlier passes can yield error variables without
810        // resolution errors here; ICE if no errors have been emitted yet.
811        assert!(
812            self.tcx().dcx().has_errors().is_some(),
813            "collect_error_for_expanding_node() could not find error for var {node_idx:?} in \
814            universe {node_universe:?}, lower_bounds={lower_bounds:#?}, \
815            upper_bounds={upper_bounds:#?}",
816        );
817    }
818
819    /// Collects all regions that "bound" the variable `orig_node_idx` in the
820    /// given direction.
821    ///
822    /// If `dup_vec` is `Some` it's used to track duplicates between successive
823    /// calls of this function.
824    ///
825    /// The return tuple fields are:
826    /// - a list of all concrete regions bounding the given region.
827    /// - the set of all region variables bounding the given region.
828    /// - a `bool` that's true if the returned region variables overlap with
829    ///   those returned by a previous call for another region.
830    fn collect_bounding_regions(
831        &self,
832        graph: &RegionGraph<'tcx>,
833        orig_node_idx: RegionVid,
834        dir: Direction,
835        mut dup_vec: Option<&mut IndexSlice<RegionVid, Option<RegionVid>>>,
836    ) -> (Vec<RegionAndOrigin<'tcx>>, FxHashSet<RegionVid>, bool) {
837        struct WalkState<'tcx> {
838            set: FxHashSet<RegionVid>,
839            stack: Vec<RegionVid>,
840            result: Vec<RegionAndOrigin<'tcx>>,
841            dup_found: bool,
842        }
843        let mut state = WalkState {
844            set: Default::default(),
845            stack: vec![orig_node_idx],
846            result: Vec::new(),
847            dup_found: false,
848        };
849        state.set.insert(orig_node_idx);
850
851        // to start off the process, walk the source node in the
852        // direction specified
853        process_edges(&self.data, &mut state, graph, orig_node_idx, dir);
854
855        while let Some(node_idx) = state.stack.pop() {
856            // check whether we've visited this node on some previous walk
857            if let Some(dup_vec) = &mut dup_vec {
858                if dup_vec[node_idx].is_none() {
859                    dup_vec[node_idx] = Some(orig_node_idx);
860                } else if dup_vec[node_idx] != Some(orig_node_idx) {
861                    state.dup_found = true;
862                }
863
864                debug!(
865                    "collect_concrete_regions(orig_node_idx={:?}, node_idx={:?})",
866                    orig_node_idx, node_idx
867                );
868            }
869
870            process_edges(&self.data, &mut state, graph, node_idx, dir);
871        }
872
873        let WalkState { result, dup_found, set, .. } = state;
874        return (result, set, dup_found);
875
876        fn process_edges<'tcx>(
877            this: &RegionConstraintData<'tcx>,
878            state: &mut WalkState<'tcx>,
879            graph: &RegionGraph<'tcx>,
880            source_vid: RegionVid,
881            dir: Direction,
882        ) {
883            debug!("process_edges(source_vid={:?}, dir={:?})", source_vid, dir);
884
885            let source_node_index = NodeIndex(source_vid.index());
886            for (_, edge) in graph.adjacent_edges(source_node_index, dir) {
887                let get_origin =
888                    || this.constraints.iter().find(|(c, _)| *c == edge.data).unwrap().1.clone();
889
890                match edge.data.kind {
891                    ConstraintKind::VarSubVar => {
892                        let from_vid = edge.data.sub.as_var();
893                        let to_vid = edge.data.sup.as_var();
894                        let opp_vid = if from_vid == source_vid { to_vid } else { from_vid };
895                        if state.set.insert(opp_vid) {
896                            state.stack.push(opp_vid);
897                        }
898                    }
899
900                    ConstraintKind::RegSubVar => {
901                        let origin = get_origin();
902                        state.result.push(RegionAndOrigin { region: edge.data.sub, origin });
903                    }
904
905                    ConstraintKind::VarSubReg => {
906                        let origin = get_origin();
907                        state.result.push(RegionAndOrigin { region: edge.data.sup, origin });
908                    }
909
910                    ConstraintKind::RegSubReg => panic!(
911                        "cannot reach reg-sub-reg edge in region inference \
912                         post-processing"
913                    ),
914                }
915            }
916        }
917    }
918
919    fn bound_is_met(
920        &self,
921        bound: &VerifyBound<'tcx>,
922        var_values: &LexicalRegionResolutions<'tcx>,
923        generic_ty: Ty<'tcx>,
924        min: ty::Region<'tcx>,
925    ) -> bool {
926        if let ty::ReError(_) = min.kind() {
927            return true;
928        }
929
930        match bound {
931            VerifyBound::IfEq(verify_if_eq_b) => {
932                let verify_if_eq_b = var_values.normalize(self.region_rels.tcx, *verify_if_eq_b);
933                match test_type_match::extract_verify_if_eq(self.tcx(), &verify_if_eq_b, generic_ty)
934                {
935                    Some(r) => {
936                        self.bound_is_met(&VerifyBound::OutlivedBy(r), var_values, generic_ty, min)
937                    }
938
939                    None => false,
940                }
941            }
942
943            VerifyBound::OutlivedBy(r) => {
944                let a = match min.kind() {
945                    ty::ReVar(rid) => var_values.values[rid],
946                    _ => VarValue::Value(min),
947                };
948                let b = match r.kind() {
949                    ty::ReVar(rid) => var_values.values[rid],
950                    _ => VarValue::Value(*r),
951                };
952                self.sub_region_values(a, b)
953            }
954
955            VerifyBound::IsEmpty => match min.kind() {
956                ty::ReVar(rid) => match var_values.values[rid] {
957                    VarValue::ErrorValue => false,
958                    VarValue::Empty(_) => true,
959                    VarValue::Value(_) => false,
960                },
961                _ => false,
962            },
963
964            VerifyBound::AnyBound(bs) => {
965                bs.iter().any(|b| self.bound_is_met(b, var_values, generic_ty, min))
966            }
967
968            VerifyBound::AllBounds(bs) => {
969                bs.iter().all(|b| self.bound_is_met(b, var_values, generic_ty, min))
970            }
971        }
972    }
973}
974
975impl<'tcx> fmt::Debug for RegionAndOrigin<'tcx> {
976    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
977        write!(f, "RegionAndOrigin({:?},{:?})", self.region, self.origin)
978    }
979}
980
981impl<'tcx> LexicalRegionResolutions<'tcx> {
982    fn normalize<T>(&self, tcx: TyCtxt<'tcx>, value: T) -> T
983    where
984        T: TypeFoldable<TyCtxt<'tcx>>,
985    {
986        fold_regions(tcx, value, |r, _db| self.resolve_region(tcx, r))
987    }
988
989    fn value(&self, rid: RegionVid) -> &VarValue<'tcx> {
990        &self.values[rid]
991    }
992
993    fn value_mut(&mut self, rid: RegionVid) -> &mut VarValue<'tcx> {
994        &mut self.values[rid]
995    }
996
997    pub(crate) fn resolve_region(
998        &self,
999        tcx: TyCtxt<'tcx>,
1000        r: ty::Region<'tcx>,
1001    ) -> ty::Region<'tcx> {
1002        let result = match r.kind() {
1003            ty::ReVar(rid) => match self.values[rid] {
1004                VarValue::Empty(_) => r,
1005                VarValue::Value(r) => r,
1006                VarValue::ErrorValue => tcx.lifetimes.re_static,
1007            },
1008            _ => r,
1009        };
1010        debug!("resolve_region({:?}) = {:?}", r, result);
1011        result
1012    }
1013}