resolve.rs 8.9 KB
Newer Older
1
use super::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
M
Mark Rousskov 已提交
2
use super::{FixupError, FixupResult, InferCtxt, Span};
3
use rustc_middle::mir;
M
Mazdak Farrokhzad 已提交
4 5
use rustc_middle::ty::fold::{TypeFolder, TypeVisitor};
use rustc_middle::ty::{self, Const, InferConst, Ty, TyCtxt, TypeFoldable};
6

7 8
use std::ops::ControlFlow;

9
///////////////////////////////////////////////////////////////////////////
V
varkor 已提交
10
// OPPORTUNISTIC VAR RESOLVER
11

V
varkor 已提交
12
/// The opportunistic resolver can be used at any time. It simply replaces
13
/// type/const variables that have been unified with the things they have
V
varkor 已提交
14
/// been unified with (similar to `shallow_resolve`, but deep). This is
15 16
/// useful for printing messages etc but also required at various
/// points for correctness.
17
pub struct OpportunisticVarResolver<'a, 'tcx> {
18
    infcx: &'a InferCtxt<'a, 'tcx>,
19 20
}

21
impl<'a, 'tcx> OpportunisticVarResolver<'a, 'tcx> {
22
    #[inline]
23
    pub fn new(infcx: &'a InferCtxt<'a, 'tcx>) -> Self {
24
        OpportunisticVarResolver { infcx }
25
    }
26 27
}

28 29
impl<'a, 'tcx> TypeFolder<'tcx> for OpportunisticVarResolver<'a, 'tcx> {
    fn tcx<'b>(&'b self) -> TyCtxt<'tcx> {
30 31 32
        self.infcx.tcx
    }

33
    fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> {
M
Matthew Jasper 已提交
34
        if !t.has_infer_types_or_consts() {
35 36
            t // micro-optimize -- if there is nothing in this type that this fold affects...
        } else {
37 38 39 40 41 42
            let t = self.infcx.shallow_resolve(t);
            t.super_fold_with(self)
        }
    }

    fn fold_const(&mut self, ct: &'tcx Const<'tcx>) -> &'tcx Const<'tcx> {
M
Matthew Jasper 已提交
43
        if !ct.has_infer_types_or_consts() {
44 45 46 47
            ct // micro-optimize -- if there is nothing in this const that this fold affects...
        } else {
            let ct = self.infcx.shallow_resolve(ct);
            ct.super_fold_with(self)
48 49
        }
    }
50 51 52 53

    fn fold_mir_const(&mut self, constant: mir::ConstantKind<'tcx>) -> mir::ConstantKind<'tcx> {
        constant.super_fold_with(self)
    }
54
}
55

56 57 58 59 60 61 62 63
/// The opportunistic region resolver opportunistically resolves regions
/// variables to the variable with the least variable id. It is used when
/// normlizing projections to avoid hitting the recursion limit by creating
/// many versions of a predicate for types that in the end have to unify.
///
/// If you want to resolve type and const variables as well, call
/// [InferCtxt::resolve_vars_if_possible] first.
pub struct OpportunisticRegionResolver<'a, 'tcx> {
64
    infcx: &'a InferCtxt<'a, 'tcx>,
65 66
}

67
impl<'a, 'tcx> OpportunisticRegionResolver<'a, 'tcx> {
68
    pub fn new(infcx: &'a InferCtxt<'a, 'tcx>) -> Self {
69
        OpportunisticRegionResolver { infcx }
70 71 72
    }
}

73
impl<'a, 'tcx> TypeFolder<'tcx> for OpportunisticRegionResolver<'a, 'tcx> {
74
    fn tcx<'b>(&'b self) -> TyCtxt<'tcx> {
75 76 77 78
        self.infcx.tcx
    }

    fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> {
79
        if !t.has_infer_regions() {
80 81
            t // micro-optimize -- if there is nothing in this type that this fold affects...
        } else {
82
            t.super_fold_with(self)
83 84 85
        }
    }

N
Niko Matsakis 已提交
86
    fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> {
87
        match *r {
88 89 90 91 92 93 94
            ty::ReVar(rid) => {
                let resolved = self
                    .infcx
                    .inner
                    .borrow_mut()
                    .unwrap_region_constraints()
                    .opportunistic_resolve_var(rid);
95
                self.tcx().reuse_or_mk_region(r, ty::ReVar(resolved))
96
            }
M
Mark Rousskov 已提交
97
            _ => r,
98 99
        }
    }
100

V
varkor 已提交
101
    fn fold_const(&mut self, ct: &'tcx ty::Const<'tcx>) -> &'tcx ty::Const<'tcx> {
102
        if !ct.has_infer_regions() {
103 104
            ct // micro-optimize -- if there is nothing in this const that this fold affects...
        } else {
105
            ct.super_fold_with(self)
106 107
        }
    }
108 109
}

110 111 112
///////////////////////////////////////////////////////////////////////////
// UNRESOLVED TYPE FINDER

113 114 115
/// The unresolved type **finder** walks a type searching for
/// type variables that don't yet have a value. The first unresolved type is stored.
/// It does not construct the fully resolved type (which might
116
/// involve some hashing and so forth).
117
pub struct UnresolvedTypeFinder<'a, 'tcx> {
118
    infcx: &'a InferCtxt<'a, 'tcx>,
119 120
}

121 122
impl<'a, 'tcx> UnresolvedTypeFinder<'a, 'tcx> {
    pub fn new(infcx: &'a InferCtxt<'a, 'tcx>) -> Self {
123
        UnresolvedTypeFinder { infcx }
124 125 126
    }
}

127
impl<'a, 'tcx> TypeVisitor<'tcx> for UnresolvedTypeFinder<'a, 'tcx> {
128
    type BreakTy = (Ty<'tcx>, Option<Span>);
L
lcnr 已提交
129

L
lcnr 已提交
130 131
    fn tcx_for_anon_const_substs(&self) -> Option<TyCtxt<'tcx>> {
        Some(self.infcx.tcx)
L
lcnr 已提交
132 133
    }

L
LeSeulArtichaut 已提交
134
    fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
V
varkor 已提交
135
        let t = self.infcx.shallow_resolve(t);
136
        if t.has_infer_types() {
L
LeSeulArtichaut 已提交
137
            if let ty::Infer(infer_ty) = *t.kind() {
138 139
                // Since we called `shallow_resolve` above, this must
                // be an (as yet...) unresolved inference variable.
M
Mark Rousskov 已提交
140
                let ty_var_span = if let ty::TyVar(ty_vid) = infer_ty {
141 142
                    let mut inner = self.infcx.inner.borrow_mut();
                    let ty_vars = &inner.type_variables();
143
                    if let TypeVariableOrigin {
144
                        kind: TypeVariableOriginKind::TypeParameterDefinition(_, _),
145 146
                        span,
                    } = *ty_vars.var_origin(ty_vid)
147 148 149 150 151 152 153 154
                    {
                        Some(span)
                    } else {
                        None
                    }
                } else {
                    None
                };
155
                ControlFlow::Break((t, ty_var_span))
156 157 158 159 160
            } else {
                // Otherwise, visit its contents.
                t.super_visit_with(self)
            }
        } else {
161 162
            // All type variables in inference types must already be resolved,
            // - no need to visit the contents, continue visiting.
163
            ControlFlow::CONTINUE
164 165 166 167
        }
    }
}

168
///////////////////////////////////////////////////////////////////////////
169 170 171 172 173
// FULL TYPE RESOLUTION

/// Full type resolution replaces all type and region variables with
/// their concrete results. If any variable cannot be replaced (never unified, etc)
/// then an `Err` result is returned.
B
Bastian Kauschke 已提交
174
pub fn fully_resolve<'a, 'tcx, T>(infcx: &InferCtxt<'a, 'tcx>, value: T) -> FixupResult<'tcx, T>
175 176
where
    T: TypeFoldable<'tcx>,
177
{
178
    let mut full_resolver = FullTypeResolver { infcx, err: None };
179 180 181 182 183
    let result = value.fold_with(&mut full_resolver);
    match full_resolver.err {
        None => Ok(result),
        Some(e) => Err(e),
    }
184 185
}

186
// N.B. This type is not public because the protocol around checking the
M
Matthias Krüger 已提交
187
// `err` field is not enforceable otherwise.
188
struct FullTypeResolver<'a, 'tcx> {
189
    infcx: &'a InferCtxt<'a, 'tcx>,
190
    err: Option<FixupError<'tcx>>,
191 192
}

193 194
impl<'a, 'tcx> TypeFolder<'tcx> for FullTypeResolver<'a, 'tcx> {
    fn tcx<'b>(&'b self) -> TyCtxt<'tcx> {
195 196 197 198
        self.infcx.tcx
    }

    fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> {
199
        if !t.needs_infer() {
200 201
            t // micro-optimize -- if there is nothing in this type that this fold affects...
        } else {
V
varkor 已提交
202
            let t = self.infcx.shallow_resolve(t);
L
LeSeulArtichaut 已提交
203
            match *t.kind() {
V
varkor 已提交
204
                ty::Infer(ty::TyVar(vid)) => {
J
Jared Roesch 已提交
205
                    self.err = Some(FixupError::UnresolvedTy(vid));
206
                    self.tcx().ty_error()
207
                }
V
varkor 已提交
208
                ty::Infer(ty::IntVar(vid)) => {
J
Jared Roesch 已提交
209
                    self.err = Some(FixupError::UnresolvedIntTy(vid));
210
                    self.tcx().ty_error()
211
                }
V
varkor 已提交
212
                ty::Infer(ty::FloatVar(vid)) => {
J
Jared Roesch 已提交
213
                    self.err = Some(FixupError::UnresolvedFloatTy(vid));
214
                    self.tcx().ty_error()
215
                }
V
varkor 已提交
216
                ty::Infer(_) => {
217
                    bug!("Unexpected type in full type resolver: {:?}", t);
218
                }
M
Mark Rousskov 已提交
219
                _ => t.super_fold_with(self),
220
            }
221 222 223
        }
    }

N
Niko Matsakis 已提交
224
    fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> {
225
        match *r {
M
Mark Rousskov 已提交
226 227 228 229 230 231 232
            ty::ReVar(rid) => self
                .infcx
                .lexical_region_resolutions
                .borrow()
                .as_ref()
                .expect("region resolution not performed")
                .resolve_var(rid),
233
            _ => r,
234 235
        }
    }
236

V
varkor 已提交
237
    fn fold_const(&mut self, c: &'tcx ty::Const<'tcx>) -> &'tcx ty::Const<'tcx> {
238
        if !c.needs_infer() {
239 240
            c // micro-optimize -- if there is nothing in this const that this fold affects...
        } else {
V
varkor 已提交
241
            let c = self.infcx.shallow_resolve(c);
V
varkor 已提交
242
            match c.val {
243
                ty::ConstKind::Infer(InferConst::Var(vid)) => {
V
varkor 已提交
244
                    self.err = Some(FixupError::UnresolvedConst(vid));
245
                    return self.tcx().const_error(c.ty);
V
varkor 已提交
246
                }
247
                ty::ConstKind::Infer(InferConst::Fresh(_)) => {
V
varkor 已提交
248
                    bug!("Unexpected const in full const resolver: {:?}", c);
249 250 251 252 253 254
                }
                _ => {}
            }
            c.super_fold_with(self)
        }
    }
255
}