]> git.proxmox.com Git - rustc.git/blame - src/librustc_infer/infer/at.rs
New upstream version 1.47.0+dfsg1
[rustc.git] / src / librustc_infer / infer / at.rs
CommitLineData
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
28use super::*;
29
ba9703b0
XL
30use rustc_middle::ty::relate::{Relate, TypeRelation};
31use rustc_middle::ty::Const;
7cac9316 32
dc9dc135
XL
33pub 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
39pub struct Trace<'a, 'tcx> {
40 at: At<'a, 'tcx>,
7cac9316
XL
41 a_is_expected: bool,
42 trace: TypeTrace<'tcx>,
43}
44
dc9dc135 45impl<'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
56pub 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 65impl<'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 84 {
f035d41b 85 self.trace_exp(a_is_expected, a, b).sub(a, b)
7cac9316
XL
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 111 {
f035d41b 112 self.trace_exp(a_is_expected, a, b).eq(a, b)
7cac9316
XL
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 119 {
f035d41b 120 self.trace(expected, actual).eq(expected, actual)
7cac9316
XL
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 149 {
f035d41b 150 self.trace(expected, actual).lub(expected, actual)
7cac9316
XL
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 159 {
f035d41b 160 self.trace(expected, actual).glb(expected, actual)
7cac9316
XL
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 186impl<'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).
f035d41b 189 pub fn sub<T>(self, a: T, b: T) -> InferResult<'tcx, ()>
dfeec247
XL
190 where
191 T: Relate<'tcx>,
7cac9316
XL
192 {
193 debug!("sub({:?} <: {:?})", a, b);
194 let Trace { at, trace, a_is_expected } = self;
195 at.infcx.commit_if_ok(|_| {
196 let mut fields = at.infcx.combine_fields(trace, at.param_env);
dfeec247
XL
197 fields
198 .sub(a_is_expected)
199 .relate(a, b)
200 .map(move |_| InferOk { value: (), obligations: fields.obligations })
7cac9316
XL
201 })
202 }
203
9fa01778 204 /// Makes `a == b`; the expectation is set by the call to
7cac9316 205 /// `trace()`.
f035d41b 206 pub fn eq<T>(self, a: T, b: T) -> InferResult<'tcx, ()>
dfeec247
XL
207 where
208 T: Relate<'tcx>,
7cac9316
XL
209 {
210 debug!("eq({:?} == {:?})", a, b);
211 let Trace { at, trace, a_is_expected } = self;
212 at.infcx.commit_if_ok(|_| {
213 let mut fields = at.infcx.combine_fields(trace, at.param_env);
dfeec247
XL
214 fields
215 .equate(a_is_expected)
216 .relate(a, b)
217 .map(move |_| InferOk { value: (), obligations: fields.obligations })
7cac9316
XL
218 })
219 }
220
f035d41b 221 pub fn lub<T>(self, a: T, b: T) -> InferResult<'tcx, T>
dfeec247
XL
222 where
223 T: Relate<'tcx>,
7cac9316
XL
224 {
225 debug!("lub({:?} \\/ {:?})", a, b);
226 let Trace { at, trace, a_is_expected } = self;
227 at.infcx.commit_if_ok(|_| {
228 let mut fields = at.infcx.combine_fields(trace, at.param_env);
dfeec247
XL
229 fields
230 .lub(a_is_expected)
231 .relate(a, b)
232 .map(move |t| InferOk { value: t, obligations: fields.obligations })
7cac9316
XL
233 })
234 }
235
f035d41b 236 pub fn glb<T>(self, a: T, b: T) -> InferResult<'tcx, T>
dfeec247
XL
237 where
238 T: Relate<'tcx>,
7cac9316
XL
239 {
240 debug!("glb({:?} /\\ {:?})", 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);
dfeec247
XL
244 fields
245 .glb(a_is_expected)
246 .relate(a, b)
247 .map(move |t| InferOk { value: t, obligations: fields.obligations })
7cac9316
XL
248 })
249 }
250}
251
252impl<'tcx> ToTrace<'tcx> for Ty<'tcx> {
dfeec247
XL
253 fn to_trace(
254 cause: &ObligationCause<'tcx>,
255 a_is_expected: bool,
256 a: Self,
257 b: Self,
258 ) -> TypeTrace<'tcx> {
259 TypeTrace { cause: cause.clone(), values: Types(ExpectedFound::new(a_is_expected, a, b)) }
7cac9316
XL
260 }
261}
262
0531ce1d 263impl<'tcx> ToTrace<'tcx> for ty::Region<'tcx> {
dfeec247
XL
264 fn to_trace(
265 cause: &ObligationCause<'tcx>,
266 a_is_expected: bool,
267 a: Self,
268 b: Self,
269 ) -> TypeTrace<'tcx> {
270 TypeTrace { cause: cause.clone(), values: Regions(ExpectedFound::new(a_is_expected, a, b)) }
0531ce1d
XL
271 }
272}
273
48663c56 274impl<'tcx> ToTrace<'tcx> for &'tcx Const<'tcx> {
dfeec247
XL
275 fn to_trace(
276 cause: &ObligationCause<'tcx>,
277 a_is_expected: bool,
278 a: Self,
279 b: Self,
280 ) -> TypeTrace<'tcx> {
281 TypeTrace { cause: cause.clone(), values: Consts(ExpectedFound::new(a_is_expected, a, b)) }
48663c56
XL
282 }
283}
284
7cac9316 285impl<'tcx> ToTrace<'tcx> for ty::TraitRef<'tcx> {
dfeec247
XL
286 fn to_trace(
287 cause: &ObligationCause<'tcx>,
288 a_is_expected: bool,
289 a: Self,
290 b: Self,
291 ) -> TypeTrace<'tcx> {
7cac9316
XL
292 TypeTrace {
293 cause: cause.clone(),
dfeec247 294 values: TraitRefs(ExpectedFound::new(a_is_expected, a, b)),
7cac9316
XL
295 }
296 }
297}
298
299impl<'tcx> ToTrace<'tcx> for ty::PolyTraitRef<'tcx> {
dfeec247
XL
300 fn to_trace(
301 cause: &ObligationCause<'tcx>,
302 a_is_expected: bool,
303 a: Self,
304 b: Self,
305 ) -> TypeTrace<'tcx> {
7cac9316
XL
306 TypeTrace {
307 cause: cause.clone(),
dfeec247 308 values: PolyTraitRefs(ExpectedFound::new(a_is_expected, a, b)),
7cac9316
XL
309 }
310 }
311}