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