]> git.lizzy.rs Git - rust.git/blob - compiler/rustc_mir/src/borrow_check/type_check/constraint_conversion.rs
use std::mem::take(x) instead of std::mem::replace(x, Default::default()) (clippy...
[rust.git] / compiler / rustc_mir / src / borrow_check / type_check / constraint_conversion.rs
1 use rustc_infer::infer::canonical::QueryOutlivesConstraint;
2 use rustc_infer::infer::canonical::QueryRegionConstraints;
3 use rustc_infer::infer::outlives::env::RegionBoundPairs;
4 use rustc_infer::infer::outlives::obligations::{TypeOutlives, TypeOutlivesDelegate};
5 use rustc_infer::infer::region_constraints::{GenericKind, VerifyBound};
6 use rustc_infer::infer::{self, InferCtxt, SubregionOrigin};
7 use rustc_middle::mir::ConstraintCategory;
8 use rustc_middle::ty::subst::GenericArgKind;
9 use rustc_middle::ty::{self, TyCtxt};
10 use rustc_span::DUMMY_SP;
11
12 use crate::borrow_check::{
13     constraints::OutlivesConstraint,
14     nll::ToRegionVid,
15     region_infer::TypeTest,
16     type_check::{Locations, MirTypeckRegionConstraints},
17     universal_regions::UniversalRegions,
18 };
19
20 crate struct ConstraintConversion<'a, 'tcx> {
21     infcx: &'a InferCtxt<'a, 'tcx>,
22     tcx: TyCtxt<'tcx>,
23     universal_regions: &'a UniversalRegions<'tcx>,
24     region_bound_pairs: &'a RegionBoundPairs<'tcx>,
25     implicit_region_bound: Option<ty::Region<'tcx>>,
26     param_env: ty::ParamEnv<'tcx>,
27     locations: Locations,
28     category: ConstraintCategory,
29     constraints: &'a mut MirTypeckRegionConstraints<'tcx>,
30 }
31
32 impl<'a, 'tcx> ConstraintConversion<'a, 'tcx> {
33     crate fn new(
34         infcx: &'a InferCtxt<'a, 'tcx>,
35         universal_regions: &'a UniversalRegions<'tcx>,
36         region_bound_pairs: &'a RegionBoundPairs<'tcx>,
37         implicit_region_bound: Option<ty::Region<'tcx>>,
38         param_env: ty::ParamEnv<'tcx>,
39         locations: Locations,
40         category: ConstraintCategory,
41         constraints: &'a mut MirTypeckRegionConstraints<'tcx>,
42     ) -> Self {
43         Self {
44             infcx,
45             tcx: infcx.tcx,
46             universal_regions,
47             region_bound_pairs,
48             implicit_region_bound,
49             param_env,
50             locations,
51             category,
52             constraints,
53         }
54     }
55
56     pub(super) fn convert_all(&mut self, query_constraints: &QueryRegionConstraints<'tcx>) {
57         debug!("convert_all(query_constraints={:#?})", query_constraints);
58
59         let QueryRegionConstraints { outlives, member_constraints } = query_constraints;
60
61         // Annoying: to invoke `self.to_region_vid`, we need access to
62         // `self.constraints`, but we also want to be mutating
63         // `self.member_constraints`. For now, just swap out the value
64         // we want and replace at the end.
65         let mut tmp = std::mem::take(&mut self.constraints.member_constraints);
66         for member_constraint in member_constraints {
67             tmp.push_constraint(member_constraint, |r| self.to_region_vid(r));
68         }
69         self.constraints.member_constraints = tmp;
70
71         for query_constraint in outlives {
72             self.convert(query_constraint);
73         }
74     }
75
76     pub(super) fn convert(&mut self, query_constraint: &QueryOutlivesConstraint<'tcx>) {
77         debug!("generate: constraints at: {:#?}", self.locations);
78
79         // Extract out various useful fields we'll need below.
80         let ConstraintConversion {
81             tcx, region_bound_pairs, implicit_region_bound, param_env, ..
82         } = *self;
83
84         // At the moment, we never generate any "higher-ranked"
85         // region constraints like `for<'a> 'a: 'b`. At some point
86         // when we move to universes, we will, and this assertion
87         // will start to fail.
88         let ty::OutlivesPredicate(k1, r2) = query_constraint.no_bound_vars().unwrap_or_else(|| {
89             bug!("query_constraint {:?} contained bound vars", query_constraint,);
90         });
91
92         match k1.unpack() {
93             GenericArgKind::Lifetime(r1) => {
94                 let r1_vid = self.to_region_vid(r1);
95                 let r2_vid = self.to_region_vid(r2);
96                 self.add_outlives(r1_vid, r2_vid);
97             }
98
99             GenericArgKind::Type(t1) => {
100                 // we don't actually use this for anything, but
101                 // the `TypeOutlives` code needs an origin.
102                 let origin = infer::RelateParamBound(DUMMY_SP, t1);
103
104                 TypeOutlives::new(
105                     &mut *self,
106                     tcx,
107                     region_bound_pairs,
108                     implicit_region_bound,
109                     param_env,
110                 )
111                 .type_must_outlive(origin, t1, r2);
112             }
113
114             GenericArgKind::Const(_) => {
115                 // Consts cannot outlive one another, so we
116                 // don't need to handle any relations here.
117             }
118         }
119     }
120
121     fn verify_to_type_test(
122         &mut self,
123         generic_kind: GenericKind<'tcx>,
124         region: ty::Region<'tcx>,
125         verify_bound: VerifyBound<'tcx>,
126     ) -> TypeTest<'tcx> {
127         let lower_bound = self.to_region_vid(region);
128
129         TypeTest { generic_kind, lower_bound, locations: self.locations, verify_bound }
130     }
131
132     fn to_region_vid(&mut self, r: ty::Region<'tcx>) -> ty::RegionVid {
133         if let ty::RePlaceholder(placeholder) = r {
134             self.constraints.placeholder_region(self.infcx, *placeholder).to_region_vid()
135         } else {
136             self.universal_regions.to_region_vid(r)
137         }
138     }
139
140     fn add_outlives(&mut self, sup: ty::RegionVid, sub: ty::RegionVid) {
141         self.constraints.outlives_constraints.push(OutlivesConstraint {
142             locations: self.locations,
143             category: self.category,
144             sub,
145             sup,
146         });
147     }
148
149     fn add_type_test(&mut self, type_test: TypeTest<'tcx>) {
150         debug!("add_type_test(type_test={:?})", type_test);
151         self.constraints.type_tests.push(type_test);
152     }
153 }
154
155 impl<'a, 'b, 'tcx> TypeOutlivesDelegate<'tcx> for &'a mut ConstraintConversion<'b, 'tcx> {
156     fn push_sub_region_constraint(
157         &mut self,
158         _origin: SubregionOrigin<'tcx>,
159         a: ty::Region<'tcx>,
160         b: ty::Region<'tcx>,
161     ) {
162         let b = self.to_region_vid(b);
163         let a = self.to_region_vid(a);
164         self.add_outlives(b, a);
165     }
166
167     fn push_verify(
168         &mut self,
169         _origin: SubregionOrigin<'tcx>,
170         kind: GenericKind<'tcx>,
171         a: ty::Region<'tcx>,
172         bound: VerifyBound<'tcx>,
173     ) {
174         let type_test = self.verify_to_type_test(kind, a, bound);
175         self.add_type_test(type_test);
176     }
177 }