]>
Commit | Line | Data |
---|---|---|
9fa01778 | 1 | //! A nice interface for working with the infcx. The basic idea is to |
7cac9316 | 2 | //! do `infcx.at(cause, param_env)`, which sets the "cause" of the |
9fa01778 | 3 | //! operation as well as the surrounding parameter environment. Then |
7cac9316 XL |
4 | //! you can do something like `.sub(a, b)` or `.eq(a, b)` to create a |
5 | //! subtype or equality relationship respectively. The first argument | |
6 | //! is always the "expected" output from the POV of diagnostics. | |
7 | //! | |
8 | //! Examples: | |
9 | //! | |
10 | //! infcx.at(cause, param_env).sub(a, b) | |
11 | //! // requires that `a <: b`, with `a` considered the "expected" type | |
12 | //! | |
13 | //! infcx.at(cause, param_env).sup(a, b) | |
14 | //! // requires that `b <: a`, with `a` considered the "expected" type | |
15 | //! | |
16 | //! infcx.at(cause, param_env).eq(a, b) | |
17 | //! // requires that `a == b`, with `a` considered the "expected" type | |
18 | //! | |
19 | //! For finer-grained control, you can also do use `trace`: | |
20 | //! | |
21 | //! infcx.at(...).trace(a, b).sub(&c, &d) | |
22 | //! | |
23 | //! This will set `a` and `b` as the "root" values for | |
24 | //! error-reporting, but actually operate on `c` and `d`. This is | |
25 | //! sometimes useful when the types of `c` and `d` are not traceable | |
26 | //! things. (That system should probably be refactored.) | |
27 | ||
28 | use super::*; | |
29 | ||
ba9703b0 | 30 | use rustc_middle::ty::relate::{Relate, TypeRelation}; |
ee023bcb | 31 | use rustc_middle::ty::{Const, ImplSubject}; |
7cac9316 | 32 | |
dc9dc135 XL |
33 | pub struct At<'a, 'tcx> { |
34 | pub infcx: &'a InferCtxt<'a, 'tcx>, | |
0531ce1d XL |
35 | pub cause: &'a ObligationCause<'tcx>, |
36 | pub param_env: ty::ParamEnv<'tcx>, | |
ee023bcb FG |
37 | /// Whether we should define opaque types |
38 | /// or just treat them opaquely. | |
39 | /// Currently only used to prevent predicate | |
40 | /// matching from matching anything against opaque | |
41 | /// types. | |
42 | pub define_opaque_types: bool, | |
7cac9316 XL |
43 | } |
44 | ||
dc9dc135 XL |
45 | pub struct Trace<'a, 'tcx> { |
46 | at: At<'a, 'tcx>, | |
7cac9316 XL |
47 | a_is_expected: bool, |
48 | trace: TypeTrace<'tcx>, | |
49 | } | |
50 | ||
dc9dc135 | 51 | impl<'a, 'tcx> InferCtxt<'a, 'tcx> { |
a1dfa0c6 | 52 | #[inline] |
dc9dc135 XL |
53 | pub fn at( |
54 | &'a self, | |
55 | cause: &'a ObligationCause<'tcx>, | |
56 | param_env: ty::ParamEnv<'tcx>, | |
57 | ) -> At<'a, 'tcx> { | |
ee023bcb | 58 | At { infcx: self, cause, param_env, define_opaque_types: true } |
7cac9316 | 59 | } |
5099ac24 FG |
60 | |
61 | /// Forks the inference context, creating a new inference context with the same inference | |
62 | /// variables in the same state. This can be used to "branch off" many tests from the same | |
63 | /// common state. Used in coherence. | |
64 | pub fn fork(&self) -> Self { | |
65 | Self { | |
66 | tcx: self.tcx.clone(), | |
67 | defining_use_anchor: self.defining_use_anchor.clone(), | |
68 | in_progress_typeck_results: self.in_progress_typeck_results.clone(), | |
69 | inner: self.inner.clone(), | |
70 | skip_leak_check: self.skip_leak_check.clone(), | |
71 | lexical_region_resolutions: self.lexical_region_resolutions.clone(), | |
72 | selection_cache: self.selection_cache.clone(), | |
73 | evaluation_cache: self.evaluation_cache.clone(), | |
74 | reported_trait_errors: self.reported_trait_errors.clone(), | |
75 | reported_closure_mismatch: self.reported_closure_mismatch.clone(), | |
76 | tainted_by_errors_flag: self.tainted_by_errors_flag.clone(), | |
77 | err_count_on_creation: self.err_count_on_creation, | |
78 | in_snapshot: self.in_snapshot.clone(), | |
79 | universe: self.universe.clone(), | |
80 | } | |
81 | } | |
7cac9316 XL |
82 | } |
83 | ||
84 | pub trait ToTrace<'tcx>: Relate<'tcx> + Copy { | |
dfeec247 | 85 | fn to_trace( |
6a06907d | 86 | tcx: TyCtxt<'tcx>, |
dfeec247 XL |
87 | cause: &ObligationCause<'tcx>, |
88 | a_is_expected: bool, | |
89 | a: Self, | |
90 | b: Self, | |
91 | ) -> TypeTrace<'tcx>; | |
7cac9316 XL |
92 | } |
93 | ||
dc9dc135 | 94 | impl<'a, 'tcx> At<'a, 'tcx> { |
ee023bcb FG |
95 | pub fn define_opaque_types(self, define_opaque_types: bool) -> Self { |
96 | Self { define_opaque_types, ..self } | |
97 | } | |
98 | ||
7cac9316 | 99 | /// Hacky routine for equating two impl headers in coherence. |
dfeec247 XL |
100 | pub fn eq_impl_headers( |
101 | self, | |
102 | expected: &ty::ImplHeader<'tcx>, | |
103 | actual: &ty::ImplHeader<'tcx>, | |
104 | ) -> InferResult<'tcx, ()> { | |
7cac9316 XL |
105 | debug!("eq_impl_header({:?} = {:?})", expected, actual); |
106 | match (expected.trait_ref, actual.trait_ref) { | |
dfeec247 XL |
107 | (Some(a_ref), Some(b_ref)) => self.eq(a_ref, b_ref), |
108 | (None, None) => self.eq(expected.self_ty, actual.self_ty), | |
109 | _ => bug!("mk_eq_impl_headers given mismatched impl kinds"), | |
7cac9316 XL |
110 | } |
111 | } | |
112 | ||
9fa01778 | 113 | /// Makes `a <: b`, where `a` may or may not be expected. |
dfeec247 XL |
114 | pub fn sub_exp<T>(self, a_is_expected: bool, a: T, b: T) -> InferResult<'tcx, ()> |
115 | where | |
116 | T: ToTrace<'tcx>, | |
7cac9316 | 117 | { |
f035d41b | 118 | self.trace_exp(a_is_expected, a, b).sub(a, b) |
7cac9316 XL |
119 | } |
120 | ||
9fa01778 | 121 | /// Makes `actual <: expected`. For example, if type-checking a |
7cac9316 XL |
122 | /// call like `foo(x)`, where `foo: fn(i32)`, you might have |
123 | /// `sup(i32, x)`, since the "expected" type is the type that | |
124 | /// appears in the signature. | |
dfeec247 XL |
125 | pub fn sup<T>(self, expected: T, actual: T) -> InferResult<'tcx, ()> |
126 | where | |
127 | T: ToTrace<'tcx>, | |
7cac9316 XL |
128 | { |
129 | self.sub_exp(false, actual, expected) | |
130 | } | |
131 | ||
9fa01778 | 132 | /// Makes `expected <: actual`. |
dfeec247 XL |
133 | pub fn sub<T>(self, expected: T, actual: T) -> InferResult<'tcx, ()> |
134 | where | |
135 | T: ToTrace<'tcx>, | |
7cac9316 XL |
136 | { |
137 | self.sub_exp(true, expected, actual) | |
138 | } | |
139 | ||
9fa01778 | 140 | /// Makes `expected <: actual`. |
dfeec247 XL |
141 | pub fn eq_exp<T>(self, a_is_expected: bool, a: T, b: T) -> InferResult<'tcx, ()> |
142 | where | |
143 | T: ToTrace<'tcx>, | |
7cac9316 | 144 | { |
f035d41b | 145 | self.trace_exp(a_is_expected, a, b).eq(a, b) |
7cac9316 XL |
146 | } |
147 | ||
9fa01778 | 148 | /// Makes `expected <: actual`. |
dfeec247 XL |
149 | pub fn eq<T>(self, expected: T, actual: T) -> InferResult<'tcx, ()> |
150 | where | |
151 | T: ToTrace<'tcx>, | |
7cac9316 | 152 | { |
f035d41b | 153 | self.trace(expected, actual).eq(expected, actual) |
7cac9316 XL |
154 | } |
155 | ||
dfeec247 XL |
156 | pub fn relate<T>(self, expected: T, variance: ty::Variance, actual: T) -> InferResult<'tcx, ()> |
157 | where | |
158 | T: ToTrace<'tcx>, | |
0bf4aa26 XL |
159 | { |
160 | match variance { | |
161 | ty::Variance::Covariant => self.sub(expected, actual), | |
162 | ty::Variance::Invariant => self.eq(expected, actual), | |
163 | ty::Variance::Contravariant => self.sup(expected, actual), | |
164 | ||
165 | // We could make this make sense but it's not readily | |
166 | // exposed and I don't feel like dealing with it. Note | |
167 | // that bivariance in general does a bit more than just | |
168 | // *nothing*, it checks that the types are the same | |
169 | // "modulo variance" basically. | |
170 | ty::Variance::Bivariant => panic!("Bivariant given to `relate()`"), | |
171 | } | |
172 | } | |
173 | ||
9fa01778 | 174 | /// Computes the least-upper-bound, or mutual supertype, of two |
7cac9316 XL |
175 | /// values. The order of the arguments doesn't matter, but since |
176 | /// this can result in an error (e.g., if asked to compute LUB of | |
177 | /// u32 and i32), it is meaningful to call one of them the | |
178 | /// "expected type". | |
dfeec247 XL |
179 | pub fn lub<T>(self, expected: T, actual: T) -> InferResult<'tcx, T> |
180 | where | |
181 | T: ToTrace<'tcx>, | |
7cac9316 | 182 | { |
f035d41b | 183 | self.trace(expected, actual).lub(expected, actual) |
7cac9316 XL |
184 | } |
185 | ||
9fa01778 | 186 | /// Computes the greatest-lower-bound, or mutual subtype, of two |
7cac9316 XL |
187 | /// values. As with `lub` order doesn't matter, except for error |
188 | /// cases. | |
dfeec247 XL |
189 | pub fn glb<T>(self, expected: T, actual: T) -> InferResult<'tcx, T> |
190 | where | |
191 | T: ToTrace<'tcx>, | |
7cac9316 | 192 | { |
f035d41b | 193 | self.trace(expected, actual).glb(expected, actual) |
7cac9316 XL |
194 | } |
195 | ||
196 | /// Sets the "trace" values that will be used for | |
3b2f2976 | 197 | /// error-reporting, but doesn't actually perform any operation |
7cac9316 XL |
198 | /// yet (this is useful when you want to set the trace using |
199 | /// distinct values from those you wish to operate upon). | |
dc9dc135 XL |
200 | pub fn trace<T>(self, expected: T, actual: T) -> Trace<'a, 'tcx> |
201 | where | |
202 | T: ToTrace<'tcx>, | |
7cac9316 XL |
203 | { |
204 | self.trace_exp(true, expected, actual) | |
205 | } | |
206 | ||
207 | /// Like `trace`, but the expected value is determined by the | |
208 | /// boolean argument (if true, then the first argument `a` is the | |
209 | /// "expected" value). | |
dc9dc135 XL |
210 | pub fn trace_exp<T>(self, a_is_expected: bool, a: T, b: T) -> Trace<'a, 'tcx> |
211 | where | |
212 | T: ToTrace<'tcx>, | |
7cac9316 | 213 | { |
6a06907d | 214 | let trace = ToTrace::to_trace(self.infcx.tcx, self.cause, a_is_expected, a, b); |
74b04a01 | 215 | Trace { at: self, trace, a_is_expected } |
7cac9316 XL |
216 | } |
217 | } | |
218 | ||
dc9dc135 | 219 | impl<'a, 'tcx> Trace<'a, 'tcx> { |
9fa01778 | 220 | /// Makes `a <: b` where `a` may or may not be expected (if |
7cac9316 | 221 | /// `a_is_expected` is true, then `a` is expected). |
c295e0f8 | 222 | #[instrument(skip(self), level = "debug")] |
f035d41b | 223 | pub fn sub<T>(self, a: T, b: T) -> InferResult<'tcx, ()> |
dfeec247 XL |
224 | where |
225 | T: Relate<'tcx>, | |
7cac9316 | 226 | { |
7cac9316 XL |
227 | let Trace { at, trace, a_is_expected } = self; |
228 | at.infcx.commit_if_ok(|_| { | |
ee023bcb | 229 | let mut fields = at.infcx.combine_fields(trace, at.param_env, at.define_opaque_types); |
dfeec247 XL |
230 | fields |
231 | .sub(a_is_expected) | |
232 | .relate(a, b) | |
233 | .map(move |_| InferOk { value: (), obligations: fields.obligations }) | |
7cac9316 XL |
234 | }) |
235 | } | |
236 | ||
9fa01778 | 237 | /// Makes `a == b`; the expectation is set by the call to |
7cac9316 | 238 | /// `trace()`. |
c295e0f8 | 239 | #[instrument(skip(self), level = "debug")] |
f035d41b | 240 | pub fn eq<T>(self, a: T, b: T) -> InferResult<'tcx, ()> |
dfeec247 XL |
241 | where |
242 | T: Relate<'tcx>, | |
7cac9316 | 243 | { |
7cac9316 XL |
244 | let Trace { at, trace, a_is_expected } = self; |
245 | at.infcx.commit_if_ok(|_| { | |
ee023bcb | 246 | let mut fields = at.infcx.combine_fields(trace, at.param_env, at.define_opaque_types); |
dfeec247 XL |
247 | fields |
248 | .equate(a_is_expected) | |
249 | .relate(a, b) | |
250 | .map(move |_| InferOk { value: (), obligations: fields.obligations }) | |
7cac9316 XL |
251 | }) |
252 | } | |
253 | ||
c295e0f8 | 254 | #[instrument(skip(self), level = "debug")] |
f035d41b | 255 | pub fn lub<T>(self, a: T, b: T) -> InferResult<'tcx, T> |
dfeec247 XL |
256 | where |
257 | T: Relate<'tcx>, | |
7cac9316 | 258 | { |
7cac9316 XL |
259 | let Trace { at, trace, a_is_expected } = self; |
260 | at.infcx.commit_if_ok(|_| { | |
ee023bcb | 261 | let mut fields = at.infcx.combine_fields(trace, at.param_env, at.define_opaque_types); |
dfeec247 XL |
262 | fields |
263 | .lub(a_is_expected) | |
264 | .relate(a, b) | |
265 | .map(move |t| InferOk { value: t, obligations: fields.obligations }) | |
7cac9316 XL |
266 | }) |
267 | } | |
268 | ||
c295e0f8 | 269 | #[instrument(skip(self), level = "debug")] |
f035d41b | 270 | pub fn glb<T>(self, a: T, b: T) -> InferResult<'tcx, T> |
dfeec247 XL |
271 | where |
272 | T: Relate<'tcx>, | |
7cac9316 | 273 | { |
7cac9316 XL |
274 | let Trace { at, trace, a_is_expected } = self; |
275 | at.infcx.commit_if_ok(|_| { | |
ee023bcb | 276 | let mut fields = at.infcx.combine_fields(trace, at.param_env, at.define_opaque_types); |
dfeec247 XL |
277 | fields |
278 | .glb(a_is_expected) | |
279 | .relate(a, b) | |
280 | .map(move |t| InferOk { value: t, obligations: fields.obligations }) | |
7cac9316 XL |
281 | }) |
282 | } | |
283 | } | |
284 | ||
ee023bcb FG |
285 | impl<'tcx> ToTrace<'tcx> for ImplSubject<'tcx> { |
286 | fn to_trace( | |
287 | tcx: TyCtxt<'tcx>, | |
288 | cause: &ObligationCause<'tcx>, | |
289 | a_is_expected: bool, | |
290 | a: Self, | |
291 | b: Self, | |
292 | ) -> TypeTrace<'tcx> { | |
293 | match (a, b) { | |
294 | (ImplSubject::Trait(trait_ref_a), ImplSubject::Trait(trait_ref_b)) => { | |
295 | ToTrace::to_trace(tcx, cause, a_is_expected, trait_ref_a, trait_ref_b) | |
296 | } | |
297 | (ImplSubject::Inherent(ty_a), ImplSubject::Inherent(ty_b)) => { | |
298 | ToTrace::to_trace(tcx, cause, a_is_expected, ty_a, ty_b) | |
299 | } | |
300 | (ImplSubject::Trait(_), ImplSubject::Inherent(_)) | |
301 | | (ImplSubject::Inherent(_), ImplSubject::Trait(_)) => { | |
302 | bug!("can not trace TraitRef and Ty"); | |
303 | } | |
304 | } | |
305 | } | |
306 | } | |
307 | ||
7cac9316 | 308 | impl<'tcx> ToTrace<'tcx> for Ty<'tcx> { |
dfeec247 | 309 | fn to_trace( |
6a06907d | 310 | _: TyCtxt<'tcx>, |
dfeec247 XL |
311 | cause: &ObligationCause<'tcx>, |
312 | a_is_expected: bool, | |
313 | a: Self, | |
314 | b: Self, | |
315 | ) -> TypeTrace<'tcx> { | |
5099ac24 FG |
316 | TypeTrace { |
317 | cause: cause.clone(), | |
318 | values: Terms(ExpectedFound::new(a_is_expected, a.into(), b.into())), | |
319 | } | |
7cac9316 XL |
320 | } |
321 | } | |
322 | ||
0531ce1d | 323 | impl<'tcx> ToTrace<'tcx> for ty::Region<'tcx> { |
dfeec247 | 324 | fn to_trace( |
6a06907d | 325 | _: TyCtxt<'tcx>, |
dfeec247 XL |
326 | cause: &ObligationCause<'tcx>, |
327 | a_is_expected: bool, | |
328 | a: Self, | |
329 | b: Self, | |
330 | ) -> TypeTrace<'tcx> { | |
331 | TypeTrace { cause: cause.clone(), values: Regions(ExpectedFound::new(a_is_expected, a, b)) } | |
0531ce1d XL |
332 | } |
333 | } | |
334 | ||
5099ac24 FG |
335 | impl<'tcx> ToTrace<'tcx> for Const<'tcx> { |
336 | fn to_trace( | |
337 | _: TyCtxt<'tcx>, | |
338 | cause: &ObligationCause<'tcx>, | |
339 | a_is_expected: bool, | |
340 | a: Self, | |
341 | b: Self, | |
342 | ) -> TypeTrace<'tcx> { | |
343 | TypeTrace { | |
344 | cause: cause.clone(), | |
345 | values: Terms(ExpectedFound::new(a_is_expected, a.into(), b.into())), | |
346 | } | |
347 | } | |
348 | } | |
349 | ||
350 | impl<'tcx> ToTrace<'tcx> for ty::Term<'tcx> { | |
dfeec247 | 351 | fn to_trace( |
6a06907d | 352 | _: TyCtxt<'tcx>, |
dfeec247 XL |
353 | cause: &ObligationCause<'tcx>, |
354 | a_is_expected: bool, | |
355 | a: Self, | |
356 | b: Self, | |
357 | ) -> TypeTrace<'tcx> { | |
5099ac24 | 358 | TypeTrace { cause: cause.clone(), values: Terms(ExpectedFound::new(a_is_expected, a, b)) } |
48663c56 XL |
359 | } |
360 | } | |
361 | ||
7cac9316 | 362 | impl<'tcx> ToTrace<'tcx> for ty::TraitRef<'tcx> { |
dfeec247 | 363 | fn to_trace( |
6a06907d | 364 | _: TyCtxt<'tcx>, |
dfeec247 XL |
365 | cause: &ObligationCause<'tcx>, |
366 | a_is_expected: bool, | |
367 | a: Self, | |
368 | b: Self, | |
369 | ) -> TypeTrace<'tcx> { | |
7cac9316 XL |
370 | TypeTrace { |
371 | cause: cause.clone(), | |
dfeec247 | 372 | values: TraitRefs(ExpectedFound::new(a_is_expected, a, b)), |
7cac9316 XL |
373 | } |
374 | } | |
375 | } | |
376 | ||
377 | impl<'tcx> ToTrace<'tcx> for ty::PolyTraitRef<'tcx> { | |
dfeec247 | 378 | fn to_trace( |
6a06907d | 379 | _: TyCtxt<'tcx>, |
dfeec247 XL |
380 | cause: &ObligationCause<'tcx>, |
381 | a_is_expected: bool, | |
382 | a: Self, | |
383 | b: Self, | |
384 | ) -> TypeTrace<'tcx> { | |
7cac9316 XL |
385 | TypeTrace { |
386 | cause: cause.clone(), | |
dfeec247 | 387 | values: PolyTraitRefs(ExpectedFound::new(a_is_expected, a, b)), |
7cac9316 XL |
388 | } |
389 | } | |
390 | } | |
6a06907d XL |
391 | |
392 | impl<'tcx> ToTrace<'tcx> for ty::ProjectionTy<'tcx> { | |
393 | fn to_trace( | |
394 | tcx: TyCtxt<'tcx>, | |
395 | cause: &ObligationCause<'tcx>, | |
396 | a_is_expected: bool, | |
397 | a: Self, | |
398 | b: Self, | |
399 | ) -> TypeTrace<'tcx> { | |
400 | let a_ty = tcx.mk_projection(a.item_def_id, a.substs); | |
401 | let b_ty = tcx.mk_projection(b.item_def_id, b.substs); | |
402 | TypeTrace { | |
403 | cause: cause.clone(), | |
5099ac24 | 404 | values: Terms(ExpectedFound::new(a_is_expected, a_ty.into(), b_ty.into())), |
6a06907d XL |
405 | } |
406 | } | |
407 | } |