1 use crate::ty::{self, Ty, TyCtxt, TyVid, IntVid, FloatVid, RegionVid};
2 use crate::ty::fold::{TypeFoldable, TypeFolder};
3 use crate::mir::interpret::ConstValue;
6 use super::RegionVariableOrigin;
7 use super::type_variable::TypeVariableOrigin;
11 impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
12 /// This rather funky routine is used while processing expected
13 /// types. What happens here is that we want to propagate a
14 /// coercion through the return type of a fn to its
15 /// argument. Consider the type of `Option::Some`, which is
16 /// basically `for<T> fn(T) -> Option<T>`. So if we have an
17 /// expression `Some(&[1, 2, 3])`, and that has the expected type
18 /// `Option<&[u32]>`, we would like to type check `&[1, 2, 3]`
19 /// with the expectation of `&[u32]`. This will cause us to coerce
20 /// from `&[u32; 3]` to `&[u32]` and make the users life more
23 /// The way we do this is using `fudge_inference_if_ok`. What the
24 /// routine actually does is to start a snapshot and execute the
25 /// closure `f`. In our example above, what this closure will do
26 /// is to unify the expectation (`Option<&[u32]>`) with the actual
27 /// return type (`Option<?T>`, where `?T` represents the variable
28 /// instantiated for `T`). This will cause `?T` to be unified
29 /// with `&?a [u32]`, where `?a` is a fresh lifetime variable. The
30 /// input type (`?T`) is then returned by `f()`.
32 /// At this point, `fudge_inference_if_ok` will normalize all type
33 /// variables, converting `?T` to `&?a [u32]` and end the
34 /// snapshot. The problem is that we can't just return this type
35 /// out, because it references the region variable `?a`, and that
36 /// region variable was popped when we popped the snapshot.
38 /// So what we do is to keep a list (`region_vars`, in the code below)
39 /// of region variables created during the snapshot (here, `?a`). We
40 /// fold the return value and replace any such regions with a *new*
41 /// region variable (e.g., `?b`) and return the result (`&?b [u32]`).
42 /// This can then be used as the expectation for the fn argument.
44 /// The important point here is that, for soundness purposes, the
45 /// regions in question are not particularly important. We will
46 /// use the expected types to guide coercions, but we will still
47 /// type-check the resulting types from those coercions against
48 /// the actual types (`?T`, `Option<?T>`) -- and remember that
49 /// after the snapshot is popped, the variable `?T` is no longer
51 pub fn fudge_inference_if_ok<T, E, F>(
54 ) -> Result<T, E> where
55 F: FnOnce() -> Result<T, E>,
56 T: TypeFoldable<'tcx>,
58 debug!("fudge_inference_if_ok()");
60 let (mut fudger, value) = self.probe(|snapshot| {
63 let value = self.resolve_type_vars_if_possible(&value);
65 // At this point, `value` could in principle refer
66 // to inference variables that have been created during
67 // the snapshot. Once we exit `probe()`, those are
68 // going to be popped, so we will have to
69 // eliminate any references to them.
71 let type_vars = self.type_variables.borrow_mut().vars_since_snapshot(
72 &snapshot.type_snapshot,
74 let int_vars = self.int_unification_table.borrow_mut().vars_since_snapshot(
75 &snapshot.int_snapshot,
77 let float_vars = self.float_unification_table.borrow_mut().vars_since_snapshot(
78 &snapshot.float_snapshot,
80 let region_vars = self.borrow_region_constraints().vars_since_snapshot(
81 &snapshot.region_constraints_snapshot,
84 let fudger = InferenceFudger {
98 // At this point, we need to replace any of the now-popped
99 // type/region variables that appear in `value` with a fresh
100 // variable of the appropriate kind. We can't do this during
101 // the probe because they would just get popped then too. =)
103 // Micro-optimization: if no variables have been created, then
104 // `value` can't refer to any of them. =) So we can just return it.
105 if fudger.type_vars.0.is_empty() &&
106 fudger.int_vars.is_empty() &&
107 fudger.float_vars.is_empty() &&
108 fudger.region_vars.0.is_empty() {
111 Ok(value.fold_with(&mut fudger))
116 pub struct InferenceFudger<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
117 infcx: &'a InferCtxt<'a, 'gcx, 'tcx>,
118 type_vars: (Range<TyVid>, Vec<TypeVariableOrigin>),
119 int_vars: Range<IntVid>,
120 float_vars: Range<FloatVid>,
121 region_vars: (Range<RegionVid>, Vec<RegionVariableOrigin>),
124 impl<'a, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for InferenceFudger<'a, 'gcx, 'tcx> {
125 fn tcx<'b>(&'b self) -> TyCtxt<'b, 'gcx, 'tcx> {
129 fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> {
131 ty::Infer(ty::InferTy::TyVar(vid)) => {
132 if self.type_vars.0.contains(&vid) {
133 // This variable was created during the fudging.
134 // Recreate it with a fresh variable here.
135 let idx = (vid.index - self.type_vars.0.start.index) as usize;
136 let origin = self.type_vars.1[idx];
137 self.infcx.next_ty_var(origin)
139 // This variable was created before the
140 // "fudging". Since we refresh all type
141 // variables to their binding anyhow, we know
142 // that it is unbound, so we can just return
144 debug_assert!(self.infcx.type_variables.borrow_mut()
150 ty::Infer(ty::InferTy::IntVar(vid)) => {
151 if self.int_vars.contains(&vid) {
152 self.infcx.next_int_var()
157 ty::Infer(ty::InferTy::FloatVar(vid)) => {
158 if self.float_vars.contains(&vid) {
159 self.infcx.next_float_var()
164 _ => ty.super_fold_with(self),
168 fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> {
169 if let ty::ReVar(vid) = r {
170 if self.region_vars.0.contains(&vid) {
171 let idx = (vid.index() - self.region_vars.0.start.index()) as usize;
172 let origin = self.region_vars.1[idx];
173 return self.infcx.next_region_var(origin);
179 fn fold_const(&mut self, ct: &'tcx ty::LazyConst<'tcx>) -> &'tcx ty::LazyConst<'tcx> {
180 if let ty::LazyConst::Evaluated(ty::Const {
181 val: ConstValue::Infer(ty::InferConst::Var(vid)),
184 if self.const_variables.contains(&vid) {
185 // This variable was created during the
186 // fudging. Recreate it with a fresh variable
188 let origin = self.infcx.const_unification_table.borrow_mut()
191 self.infcx.next_const_var(ty, origin)
196 ct.super_fold_with(self)