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.
10 //! infcx.at(cause, param_env).sub(a, b)
11 //! // requires that `a <: b`, with `a` considered the "expected" type
13 //! infcx.at(cause, param_env).sup(a, b)
14 //! // requires that `b <: a`, with `a` considered the "expected" type
16 //! infcx.at(cause, param_env).eq(a, b)
17 //! // requires that `a == b`, with `a` considered the "expected" type
19 //! For finer-grained control, you can also do use `trace`:
21 //! infcx.at(...).trace(a, b).sub(&c, &d)
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.)
31 use crate::ty::relate::{Relate, TypeRelation};
33 pub struct At<'a, 'gcx: 'tcx, 'tcx: 'a> {
34 pub infcx: &'a InferCtxt<'a, 'gcx, 'tcx>,
35 pub cause: &'a ObligationCause<'tcx>,
36 pub param_env: ty::ParamEnv<'tcx>,
39 pub struct Trace<'a, 'gcx: 'tcx, 'tcx: 'a> {
40 at: At<'a, 'gcx, 'tcx>,
42 trace: TypeTrace<'tcx>,
45 impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
48 cause: &'a ObligationCause<'tcx>,
49 param_env: ty::ParamEnv<'tcx>)
52 At { infcx: self, cause, param_env }
56 pub trait ToTrace<'tcx>: Relate<'tcx> + Copy {
57 fn to_trace(cause: &ObligationCause<'tcx>,
64 impl<'a, 'gcx, 'tcx> At<'a, 'gcx, 'tcx> {
65 /// Hacky routine for equating two impl headers in coherence.
66 pub fn eq_impl_headers(self,
67 expected: &ty::ImplHeader<'tcx>,
68 actual: &ty::ImplHeader<'tcx>)
69 -> InferResult<'tcx, ()>
71 debug!("eq_impl_header({:?} = {:?})", expected, actual);
72 match (expected.trait_ref, actual.trait_ref) {
73 (Some(a_ref), Some(b_ref)) =>
74 self.eq(a_ref, b_ref),
76 self.eq(expected.self_ty, actual.self_ty),
78 bug!("mk_eq_impl_headers given mismatched impl kinds"),
82 /// Makes `a <: b`, where `a` may or may not be expected.
83 pub fn sub_exp<T>(self,
87 -> InferResult<'tcx, ()>
88 where T: ToTrace<'tcx>
90 self.trace_exp(a_is_expected, a, b).sub(&a, &b)
93 /// Makes `actual <: expected`. For example, if type-checking a
94 /// call like `foo(x)`, where `foo: fn(i32)`, you might have
95 /// `sup(i32, x)`, since the "expected" type is the type that
96 /// appears in the signature.
100 -> InferResult<'tcx, ()>
101 where T: ToTrace<'tcx>
103 self.sub_exp(false, actual, expected)
106 /// Makes `expected <: actual`.
110 -> InferResult<'tcx, ()>
111 where T: ToTrace<'tcx>
113 self.sub_exp(true, expected, actual)
116 /// Makes `expected <: actual`.
117 pub fn eq_exp<T>(self,
121 -> InferResult<'tcx, ()>
122 where T: ToTrace<'tcx>
124 self.trace_exp(a_is_expected, a, b).eq(&a, &b)
127 /// Makes `expected <: actual`.
131 -> InferResult<'tcx, ()>
132 where T: ToTrace<'tcx>
134 self.trace(expected, actual).eq(&expected, &actual)
140 variance: ty::Variance,
142 ) -> InferResult<'tcx, ()>
143 where T: ToTrace<'tcx>
146 ty::Variance::Covariant => self.sub(expected, actual),
147 ty::Variance::Invariant => self.eq(expected, actual),
148 ty::Variance::Contravariant => self.sup(expected, actual),
150 // We could make this make sense but it's not readily
151 // exposed and I don't feel like dealing with it. Note
152 // that bivariance in general does a bit more than just
153 // *nothing*, it checks that the types are the same
154 // "modulo variance" basically.
155 ty::Variance::Bivariant => panic!("Bivariant given to `relate()`"),
159 /// Computes the least-upper-bound, or mutual supertype, of two
160 /// values. The order of the arguments doesn't matter, but since
161 /// this can result in an error (e.g., if asked to compute LUB of
162 /// u32 and i32), it is meaningful to call one of them the
167 -> InferResult<'tcx, T>
168 where T: ToTrace<'tcx>
170 self.trace(expected, actual).lub(&expected, &actual)
173 /// Computes the greatest-lower-bound, or mutual subtype, of two
174 /// values. As with `lub` order doesn't matter, except for error
179 -> InferResult<'tcx, T>
180 where T: ToTrace<'tcx>
182 self.trace(expected, actual).glb(&expected, &actual)
185 /// Sets the "trace" values that will be used for
186 /// error-reporting, but doesn't actually perform any operation
187 /// yet (this is useful when you want to set the trace using
188 /// distinct values from those you wish to operate upon).
189 pub fn trace<T>(self,
192 -> Trace<'a, 'gcx, 'tcx>
193 where T: ToTrace<'tcx>
195 self.trace_exp(true, expected, actual)
198 /// Like `trace`, but the expected value is determined by the
199 /// boolean argument (if true, then the first argument `a` is the
200 /// "expected" value).
201 pub fn trace_exp<T>(self,
205 -> Trace<'a, 'gcx, 'tcx>
206 where T: ToTrace<'tcx>
208 let trace = ToTrace::to_trace(self.cause, a_is_expected, a, b);
209 Trace { at: self, trace: trace, a_is_expected }
213 impl<'a, 'gcx, 'tcx> Trace<'a, 'gcx, 'tcx> {
214 /// Makes `a <: b` where `a` may or may not be expected (if
215 /// `a_is_expected` is true, then `a` is expected).
216 /// Makes `expected <: actual`.
220 -> InferResult<'tcx, ()>
221 where T: Relate<'tcx>
223 debug!("sub({:?} <: {:?})", a, b);
224 let Trace { at, trace, a_is_expected } = self;
225 at.infcx.commit_if_ok(|_| {
226 let mut fields = at.infcx.combine_fields(trace, at.param_env);
227 fields.sub(a_is_expected)
229 .map(move |_| InferOk { value: (), obligations: fields.obligations })
233 /// Makes `a == b`; the expectation is set by the call to
238 -> InferResult<'tcx, ()>
239 where T: Relate<'tcx>
241 debug!("eq({:?} == {:?})", 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);
245 fields.equate(a_is_expected)
247 .map(move |_| InferOk { value: (), obligations: fields.obligations })
254 -> InferResult<'tcx, T>
255 where T: Relate<'tcx>
257 debug!("lub({:?} \\/ {:?})", a, b);
258 let Trace { at, trace, a_is_expected } = self;
259 at.infcx.commit_if_ok(|_| {
260 let mut fields = at.infcx.combine_fields(trace, at.param_env);
261 fields.lub(a_is_expected)
263 .map(move |t| InferOk { value: t, obligations: fields.obligations })
270 -> InferResult<'tcx, T>
271 where T: Relate<'tcx>
273 debug!("glb({:?} /\\ {:?})", a, b);
274 let Trace { at, trace, a_is_expected } = self;
275 at.infcx.commit_if_ok(|_| {
276 let mut fields = at.infcx.combine_fields(trace, at.param_env);
277 fields.glb(a_is_expected)
279 .map(move |t| InferOk { value: t, obligations: fields.obligations })
284 impl<'tcx> ToTrace<'tcx> for Ty<'tcx> {
285 fn to_trace(cause: &ObligationCause<'tcx>,
292 cause: cause.clone(),
293 values: Types(ExpectedFound::new(a_is_expected, a, b))
298 impl<'tcx> ToTrace<'tcx> for ty::Region<'tcx> {
299 fn to_trace(cause: &ObligationCause<'tcx>,
306 cause: cause.clone(),
307 values: Regions(ExpectedFound::new(a_is_expected, a, b))
312 impl<'tcx> ToTrace<'tcx> for &'tcx Const<'tcx> {
313 fn to_trace(cause: &ObligationCause<'tcx>,
320 cause: cause.clone(),
321 values: Consts(ExpectedFound::new(a_is_expected, a, b))
326 impl<'tcx> ToTrace<'tcx> for ty::TraitRef<'tcx> {
327 fn to_trace(cause: &ObligationCause<'tcx>,
334 cause: cause.clone(),
335 values: TraitRefs(ExpectedFound::new(a_is_expected, a, b))
340 impl<'tcx> ToTrace<'tcx> for ty::PolyTraitRef<'tcx> {
341 fn to_trace(cause: &ObligationCause<'tcx>,
348 cause: cause.clone(),
349 values: PolyTraitRefs(ExpectedFound::new(a_is_expected, a, b))