rustc_borrowck/region_infer/opaque_types/
member_constraints.rs1use rustc_data_structures::fx::FxHashMap;
2use rustc_hir::def_id::DefId;
3use rustc_middle::bug;
4use rustc_middle::ty::{
5 self, GenericArgsRef, Region, RegionVid, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable,
6 TypeVisitor,
7};
8use tracing::{debug, instrument};
9
10use super::DefiningUse;
11use super::region_ctxt::RegionCtxt;
12use crate::constraints::ConstraintSccIndex;
13
14pub(super) fn apply_member_constraints<'tcx>(
15 rcx: &mut RegionCtxt<'_, 'tcx>,
16 defining_uses: &[DefiningUse<'tcx>],
17) {
18 let mut member_constraints = Default::default();
23 for defining_use in defining_uses {
24 let mut visitor = CollectMemberConstraintsVisitor {
25 rcx,
26 defining_use,
27 member_constraints: &mut member_constraints,
28 };
29 defining_use.hidden_type.ty.visit_with(&mut visitor);
30 }
31
32 debug!(?member_constraints);
40 for scc_a in rcx.constraint_sccs.all_sccs() {
41 debug!(?scc_a);
42 for &scc_b in rcx.constraint_sccs.successors(scc_a) {
48 debug!(?scc_b);
49 rcx.scc_values.add_region(scc_a, scc_b);
50 }
51
52 for defining_use in member_constraints.get(&scc_a).into_iter().flatten() {
53 apply_member_constraint(rcx, scc_a, &defining_use.arg_regions);
54 }
55 }
56}
57
58#[instrument(level = "debug", skip(rcx))]
59fn apply_member_constraint<'tcx>(
60 rcx: &mut RegionCtxt<'_, 'tcx>,
61 member: ConstraintSccIndex,
62 arg_regions: &[RegionVid],
63) {
64 if !rcx.max_placeholder_universe_reached(member).is_root() {
67 return;
68 }
69
70 let mut choice_regions = arg_regions
74 .iter()
75 .copied()
76 .map(|r| rcx.representative(r).rvid())
77 .filter(|&choice_region| {
78 rcx.scc_values.universal_regions_outlived_by(member).all(|lower_bound| {
79 rcx.universal_region_relations.outlives(choice_region, lower_bound)
80 })
81 })
82 .collect::<Vec<_>>();
83 debug!(?choice_regions, "after enforcing lower-bound");
84
85 for ub in rcx.rev_scc_graph.upper_bounds(member) {
94 choice_regions
95 .retain(|&choice_region| rcx.universal_region_relations.outlives(ub, choice_region));
96 }
97 debug!(?choice_regions, "after enforcing upper-bound");
98
99 let totally_ordered_subset = choice_regions.iter().copied().filter(|&r1| {
111 choice_regions.iter().all(|&r2| {
112 rcx.universal_region_relations.outlives(r1, r2)
113 || rcx.universal_region_relations.outlives(r2, r1)
114 })
115 });
116 let Some(min_choice) = totally_ordered_subset.reduce(|r1, r2| {
118 let r1_outlives_r2 = rcx.universal_region_relations.outlives(r1, r2);
119 let r2_outlives_r1 = rcx.universal_region_relations.outlives(r2, r1);
120 match (r1_outlives_r2, r2_outlives_r1) {
121 (true, true) => r1.min(r2),
122 (true, false) => r2,
123 (false, true) => r1,
124 (false, false) => bug!("incomparable regions in total order"),
125 }
126 }) else {
127 debug!("no unique minimum choice");
128 return;
129 };
130
131 debug!(?min_choice);
132 let min_choice_scc = rcx.constraint_sccs.scc(min_choice);
137 rcx.scc_values.add_region(member, min_choice_scc);
138}
139
140struct CollectMemberConstraintsVisitor<'a, 'b, 'tcx> {
141 rcx: &'a RegionCtxt<'a, 'tcx>,
142 defining_use: &'b DefiningUse<'tcx>,
143 member_constraints: &'a mut FxHashMap<ConstraintSccIndex, Vec<&'b DefiningUse<'tcx>>>,
144}
145impl<'tcx> CollectMemberConstraintsVisitor<'_, '_, 'tcx> {
146 fn cx(&self) -> TyCtxt<'tcx> {
147 self.rcx.infcx.tcx
148 }
149 fn visit_closure_args(&mut self, def_id: DefId, args: GenericArgsRef<'tcx>) {
150 let generics = self.cx().generics_of(def_id);
151 for arg in args.iter().skip(generics.parent_count) {
152 arg.visit_with(self);
153 }
154 }
155}
156impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for CollectMemberConstraintsVisitor<'_, '_, 'tcx> {
157 fn visit_region(&mut self, r: Region<'tcx>) {
158 match r.kind() {
159 ty::ReBound(..) => return,
160 ty::ReVar(vid) => {
161 let scc = self.rcx.constraint_sccs.scc(vid);
162 self.member_constraints.entry(scc).or_default().push(self.defining_use);
163 }
164 _ => unreachable!(),
165 }
166 }
167
168 fn visit_ty(&mut self, ty: Ty<'tcx>) {
169 if !ty.flags().intersects(ty::TypeFlags::HAS_FREE_REGIONS) {
170 return;
171 }
172
173 match *ty.kind() {
174 ty::Closure(def_id, args)
175 | ty::CoroutineClosure(def_id, args)
176 | ty::Coroutine(def_id, args) => self.visit_closure_args(def_id, args),
177
178 ty::Alias(kind, ty::AliasTy { def_id, args, .. })
179 if let Some(variances) = self.cx().opt_alias_variances(kind, def_id) =>
180 {
181 for (&v, arg) in std::iter::zip(variances, args.iter()) {
185 if v != ty::Bivariant {
186 arg.visit_with(self)
187 }
188 }
189 }
190
191 _ => ty.super_visit_with(self),
192 }
193 }
194}