]> git.lizzy.rs Git - rust.git/blob - src/librustc/infer/at.rs
Rollup merge of #59847 - Kampfkarren:try-block-catch, r=estebank
[rust.git] / src / librustc / infer / at.rs
1 //! A nice interface for working with the infcx. The basic idea is to
2 //! do `infcx.at(cause, param_env)`, which sets the "cause" of the
3 //! operation as well as the surrounding parameter environment. Then
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
30 use crate::ty::relate::{Relate, TypeRelation};
31
32 pub struct At<'a, 'gcx: 'tcx, 'tcx: 'a> {
33     pub infcx: &'a InferCtxt<'a, 'gcx, 'tcx>,
34     pub cause: &'a ObligationCause<'tcx>,
35     pub param_env: ty::ParamEnv<'tcx>,
36 }
37
38 pub struct Trace<'a, 'gcx: 'tcx, 'tcx: 'a> {
39     at: At<'a, 'gcx, 'tcx>,
40     a_is_expected: bool,
41     trace: TypeTrace<'tcx>,
42 }
43
44 impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
45     #[inline]
46     pub fn at(&'a self,
47               cause: &'a ObligationCause<'tcx>,
48               param_env: ty::ParamEnv<'tcx>)
49               -> At<'a, 'gcx, 'tcx>
50     {
51         At { infcx: self, cause, param_env }
52     }
53 }
54
55 pub trait ToTrace<'tcx>: Relate<'tcx> + Copy {
56     fn to_trace(cause: &ObligationCause<'tcx>,
57                 a_is_expected: bool,
58                 a: Self,
59                 b: Self)
60                 -> TypeTrace<'tcx>;
61 }
62
63 impl<'a, 'gcx, 'tcx> At<'a, 'gcx, 'tcx> {
64     /// Hacky routine for equating two impl headers in coherence.
65     pub fn eq_impl_headers(self,
66                            expected: &ty::ImplHeader<'tcx>,
67                            actual: &ty::ImplHeader<'tcx>)
68                            -> InferResult<'tcx, ()>
69     {
70         debug!("eq_impl_header({:?} = {:?})", expected, actual);
71         match (expected.trait_ref, actual.trait_ref) {
72             (Some(a_ref), Some(b_ref)) =>
73                 self.eq(a_ref, b_ref),
74             (None, None) =>
75                 self.eq(expected.self_ty, actual.self_ty),
76             _ =>
77                 bug!("mk_eq_impl_headers given mismatched impl kinds"),
78         }
79     }
80
81     /// Makes `a <: b`, where `a` may or may not be expected.
82     pub fn sub_exp<T>(self,
83                       a_is_expected: bool,
84                       a: T,
85                       b: T)
86                       -> InferResult<'tcx, ()>
87         where T: ToTrace<'tcx>
88     {
89         self.trace_exp(a_is_expected, a, b).sub(&a, &b)
90     }
91
92     /// Makes `actual <: expected`. For example, if type-checking a
93     /// call like `foo(x)`, where `foo: fn(i32)`, you might have
94     /// `sup(i32, x)`, since the "expected" type is the type that
95     /// appears in the signature.
96     pub fn sup<T>(self,
97                   expected: T,
98                   actual: T)
99                   -> InferResult<'tcx, ()>
100         where T: ToTrace<'tcx>
101     {
102         self.sub_exp(false, actual, expected)
103     }
104
105     /// Makes `expected <: actual`.
106     pub fn sub<T>(self,
107                   expected: T,
108                   actual: T)
109                   -> InferResult<'tcx, ()>
110         where T: ToTrace<'tcx>
111     {
112         self.sub_exp(true, expected, actual)
113     }
114
115     /// Makes `expected <: actual`.
116     pub fn eq_exp<T>(self,
117                      a_is_expected: bool,
118                      a: T,
119                      b: T)
120                      -> InferResult<'tcx, ()>
121         where T: ToTrace<'tcx>
122     {
123         self.trace_exp(a_is_expected, a, b).eq(&a, &b)
124     }
125
126     /// Makes `expected <: actual`.
127     pub fn eq<T>(self,
128                  expected: T,
129                  actual: T)
130                  -> InferResult<'tcx, ()>
131         where T: ToTrace<'tcx>
132     {
133         self.trace(expected, actual).eq(&expected, &actual)
134     }
135
136     pub fn relate<T>(
137         self,
138         expected: T,
139         variance: ty::Variance,
140         actual: T,
141     ) -> InferResult<'tcx, ()>
142         where T: ToTrace<'tcx>
143     {
144         match variance {
145             ty::Variance::Covariant => self.sub(expected, actual),
146             ty::Variance::Invariant => self.eq(expected, actual),
147             ty::Variance::Contravariant => self.sup(expected, actual),
148
149             // We could make this make sense but it's not readily
150             // exposed and I don't feel like dealing with it. Note
151             // that bivariance in general does a bit more than just
152             // *nothing*, it checks that the types are the same
153             // "modulo variance" basically.
154             ty::Variance::Bivariant => panic!("Bivariant given to `relate()`"),
155         }
156     }
157
158     /// Computes the least-upper-bound, or mutual supertype, of two
159     /// values. The order of the arguments doesn't matter, but since
160     /// this can result in an error (e.g., if asked to compute LUB of
161     /// u32 and i32), it is meaningful to call one of them the
162     /// "expected type".
163     pub fn lub<T>(self,
164                   expected: T,
165                   actual: T)
166                   -> InferResult<'tcx, T>
167         where T: ToTrace<'tcx>
168     {
169         self.trace(expected, actual).lub(&expected, &actual)
170     }
171
172     /// Computes the greatest-lower-bound, or mutual subtype, of two
173     /// values. As with `lub` order doesn't matter, except for error
174     /// cases.
175     pub fn glb<T>(self,
176                   expected: T,
177                   actual: T)
178                   -> InferResult<'tcx, T>
179         where T: ToTrace<'tcx>
180     {
181         self.trace(expected, actual).glb(&expected, &actual)
182     }
183
184     /// Sets the "trace" values that will be used for
185     /// error-reporting, but doesn't actually perform any operation
186     /// yet (this is useful when you want to set the trace using
187     /// distinct values from those you wish to operate upon).
188     pub fn trace<T>(self,
189                     expected: T,
190                     actual: T)
191                     -> Trace<'a, 'gcx, 'tcx>
192         where T: ToTrace<'tcx>
193     {
194         self.trace_exp(true, expected, actual)
195     }
196
197     /// Like `trace`, but the expected value is determined by the
198     /// boolean argument (if true, then the first argument `a` is the
199     /// "expected" value).
200     pub fn trace_exp<T>(self,
201                         a_is_expected: bool,
202                         a: T,
203                         b: T)
204                         -> Trace<'a, 'gcx, 'tcx>
205         where T: ToTrace<'tcx>
206     {
207         let trace = ToTrace::to_trace(self.cause, a_is_expected, a, b);
208         Trace { at: self, trace: trace, a_is_expected }
209     }
210 }
211
212 impl<'a, 'gcx, 'tcx> Trace<'a, 'gcx, 'tcx> {
213     /// Makes `a <: b` where `a` may or may not be expected (if
214     /// `a_is_expected` is true, then `a` is expected).
215     /// Makes `expected <: actual`.
216     pub fn sub<T>(self,
217                   a: &T,
218                   b: &T)
219                   -> InferResult<'tcx, ()>
220         where T: Relate<'tcx>
221     {
222         debug!("sub({:?} <: {:?})", a, b);
223         let Trace { at, trace, a_is_expected } = self;
224         at.infcx.commit_if_ok(|_| {
225             let mut fields = at.infcx.combine_fields(trace, at.param_env);
226             fields.sub(a_is_expected)
227                   .relate(a, b)
228                   .map(move |_| InferOk { value: (), obligations: fields.obligations })
229         })
230     }
231
232     /// Makes `a == b`; the expectation is set by the call to
233     /// `trace()`.
234     pub fn eq<T>(self,
235                  a: &T,
236                  b: &T)
237                  -> InferResult<'tcx, ()>
238         where T: Relate<'tcx>
239     {
240         debug!("eq({:?} == {:?})", a, b);
241         let Trace { at, trace, a_is_expected } = self;
242         at.infcx.commit_if_ok(|_| {
243             let mut fields = at.infcx.combine_fields(trace, at.param_env);
244             fields.equate(a_is_expected)
245                   .relate(a, b)
246                   .map(move |_| InferOk { value: (), obligations: fields.obligations })
247         })
248     }
249
250     pub fn lub<T>(self,
251                   a: &T,
252                   b: &T)
253                   -> InferResult<'tcx, T>
254         where T: Relate<'tcx>
255     {
256         debug!("lub({:?} \\/ {:?})", a, b);
257         let Trace { at, trace, a_is_expected } = self;
258         at.infcx.commit_if_ok(|_| {
259             let mut fields = at.infcx.combine_fields(trace, at.param_env);
260             fields.lub(a_is_expected)
261                   .relate(a, b)
262                   .map(move |t| InferOk { value: t, obligations: fields.obligations })
263         })
264     }
265
266     pub fn glb<T>(self,
267                   a: &T,
268                   b: &T)
269                   -> InferResult<'tcx, T>
270         where T: Relate<'tcx>
271     {
272         debug!("glb({:?} /\\ {:?})", a, b);
273         let Trace { at, trace, a_is_expected } = self;
274         at.infcx.commit_if_ok(|_| {
275             let mut fields = at.infcx.combine_fields(trace, at.param_env);
276             fields.glb(a_is_expected)
277                   .relate(a, b)
278                   .map(move |t| InferOk { value: t, obligations: fields.obligations })
279         })
280     }
281 }
282
283 impl<'tcx> ToTrace<'tcx> for Ty<'tcx> {
284     fn to_trace(cause: &ObligationCause<'tcx>,
285                 a_is_expected: bool,
286                 a: Self,
287                 b: Self)
288                 -> TypeTrace<'tcx>
289     {
290         TypeTrace {
291             cause: cause.clone(),
292             values: Types(ExpectedFound::new(a_is_expected, a, b))
293         }
294     }
295 }
296
297 impl<'tcx> ToTrace<'tcx> for ty::Region<'tcx> {
298     fn to_trace(cause: &ObligationCause<'tcx>,
299                 a_is_expected: bool,
300                 a: Self,
301                 b: Self)
302                 -> TypeTrace<'tcx>
303     {
304         TypeTrace {
305             cause: cause.clone(),
306             values: Regions(ExpectedFound::new(a_is_expected, a, b))
307         }
308     }
309 }
310
311 impl<'tcx> ToTrace<'tcx> for ty::TraitRef<'tcx> {
312     fn to_trace(cause: &ObligationCause<'tcx>,
313                 a_is_expected: bool,
314                 a: Self,
315                 b: Self)
316                 -> TypeTrace<'tcx>
317     {
318         TypeTrace {
319             cause: cause.clone(),
320             values: TraitRefs(ExpectedFound::new(a_is_expected, a, b))
321         }
322     }
323 }
324
325 impl<'tcx> ToTrace<'tcx> for ty::PolyTraitRef<'tcx> {
326     fn to_trace(cause: &ObligationCause<'tcx>,
327                 a_is_expected: bool,
328                 a: Self,
329                 b: Self)
330                 -> TypeTrace<'tcx>
331     {
332         TypeTrace {
333             cause: cause.clone(),
334             values: PolyTraitRefs(ExpectedFound::new(a_is_expected, a, b))
335         }
336     }
337 }