rustc_infer/infer/outlives/
test_type_match.rs1use std::collections::hash_map::Entry;
2
3use rustc_data_structures::fx::FxHashMap;
4use rustc_middle::ty::error::TypeError;
5use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitableExt};
6use tracing::instrument;
7
8use crate::infer::region_constraints::VerifyIfEq;
9use crate::infer::relate::{self as relate, Relate, RelateResult, TypeRelation};
10
11#[instrument(level = "debug", skip(tcx))]
37pub fn extract_verify_if_eq<'tcx>(
38 tcx: TyCtxt<'tcx>,
39 verify_if_eq_b: &ty::Binder<'tcx, VerifyIfEq<'tcx>>,
40 test_ty: Ty<'tcx>,
41) -> Option<ty::Region<'tcx>> {
42 assert!(!verify_if_eq_b.has_escaping_bound_vars());
43 let mut m = MatchAgainstHigherRankedOutlives::new(tcx);
44 let verify_if_eq = verify_if_eq_b.skip_binder();
45 m.relate(verify_if_eq.ty, test_ty).ok()?;
46
47 if let ty::RegionKind::ReBound(depth, br) = verify_if_eq.bound.kind() {
48 assert!(depth == ty::INNERMOST);
49 match m.map.get(&br) {
50 Some(&r) => Some(r),
51 None => {
52 Some(tcx.lifetimes.re_static)
55 }
56 }
57 } else {
58 Some(verify_if_eq.bound)
68 }
69}
70
71#[instrument(level = "debug", skip(tcx))]
73pub(super) fn can_match_erased_ty<'tcx>(
74 tcx: TyCtxt<'tcx>,
75 outlives_predicate: ty::Binder<'tcx, ty::TypeOutlivesPredicate<'tcx>>,
76 erased_ty: Ty<'tcx>,
77) -> bool {
78 assert!(!outlives_predicate.has_escaping_bound_vars());
79 let erased_outlives_predicate = tcx.erase_regions(outlives_predicate);
80 let outlives_ty = erased_outlives_predicate.skip_binder().0;
81 if outlives_ty == erased_ty {
82 true
84 } else {
85 MatchAgainstHigherRankedOutlives::new(tcx).relate(outlives_ty, erased_ty).is_ok()
86 }
87}
88
89struct MatchAgainstHigherRankedOutlives<'tcx> {
90 tcx: TyCtxt<'tcx>,
91 pattern_depth: ty::DebruijnIndex,
92 map: FxHashMap<ty::BoundRegion, ty::Region<'tcx>>,
93}
94
95impl<'tcx> MatchAgainstHigherRankedOutlives<'tcx> {
96 fn new(tcx: TyCtxt<'tcx>) -> MatchAgainstHigherRankedOutlives<'tcx> {
97 MatchAgainstHigherRankedOutlives {
98 tcx,
99 pattern_depth: ty::INNERMOST,
100 map: FxHashMap::default(),
101 }
102 }
103}
104
105impl<'tcx> MatchAgainstHigherRankedOutlives<'tcx> {
106 fn no_match<T>(&self) -> RelateResult<'tcx, T> {
108 Err(TypeError::Mismatch)
109 }
110
111 #[instrument(level = "trace", skip(self))]
114 fn bind(
115 &mut self,
116 br: ty::BoundRegion,
117 value: ty::Region<'tcx>,
118 ) -> RelateResult<'tcx, ty::Region<'tcx>> {
119 match self.map.entry(br) {
120 Entry::Occupied(entry) => {
121 if *entry.get() == value {
122 Ok(value)
123 } else {
124 self.no_match()
125 }
126 }
127 Entry::Vacant(entry) => {
128 entry.insert(value);
129 Ok(value)
130 }
131 }
132 }
133}
134
135impl<'tcx> TypeRelation<TyCtxt<'tcx>> for MatchAgainstHigherRankedOutlives<'tcx> {
136 fn cx(&self) -> TyCtxt<'tcx> {
137 self.tcx
138 }
139
140 #[instrument(level = "trace", skip(self))]
141 fn relate_with_variance<T: Relate<TyCtxt<'tcx>>>(
142 &mut self,
143 variance: ty::Variance,
144 _: ty::VarianceDiagInfo<TyCtxt<'tcx>>,
145 a: T,
146 b: T,
147 ) -> RelateResult<'tcx, T> {
148 if variance != ty::Bivariant { self.relate(a, b) } else { Ok(a) }
151 }
152
153 #[instrument(skip(self), level = "trace")]
154 fn regions(
155 &mut self,
156 pattern: ty::Region<'tcx>,
157 value: ty::Region<'tcx>,
158 ) -> RelateResult<'tcx, ty::Region<'tcx>> {
159 if let ty::RegionKind::ReBound(depth, br) = pattern.kind()
160 && depth == self.pattern_depth
161 {
162 self.bind(br, value)
163 } else if pattern == value {
164 Ok(pattern)
165 } else {
166 self.no_match()
167 }
168 }
169
170 #[instrument(skip(self), level = "trace")]
171 fn tys(&mut self, pattern: Ty<'tcx>, value: Ty<'tcx>) -> RelateResult<'tcx, Ty<'tcx>> {
172 if matches!(pattern.kind(), ty::Error(_) | ty::Bound(..)) {
174 self.no_match()
176 } else if pattern == value {
177 Ok(pattern)
178 } else {
179 relate::structurally_relate_tys(self, pattern, value)
180 }
181 }
182
183 #[instrument(skip(self), level = "trace")]
184 fn consts(
185 &mut self,
186 pattern: ty::Const<'tcx>,
187 value: ty::Const<'tcx>,
188 ) -> RelateResult<'tcx, ty::Const<'tcx>> {
189 if pattern == value {
190 Ok(pattern)
191 } else {
192 relate::structurally_relate_consts(self, pattern, value)
193 }
194 }
195
196 #[instrument(skip(self), level = "trace")]
197 fn binders<T>(
198 &mut self,
199 pattern: ty::Binder<'tcx, T>,
200 value: ty::Binder<'tcx, T>,
201 ) -> RelateResult<'tcx, ty::Binder<'tcx, T>>
202 where
203 T: Relate<TyCtxt<'tcx>>,
204 {
205 self.pattern_depth.shift_in(1);
206 let result = Ok(pattern.rebind(self.relate(pattern.skip_binder(), value.skip_binder())?));
207 self.pattern_depth.shift_out(1);
208 result
209 }
210}