resolve.rs 8.5 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;
A
Alan Egerton 已提交
4 5 6
use rustc_middle::ty::fold::{FallibleTypeFolder, TypeFolder, TypeSuperFoldable};
use rustc_middle::ty::visit::{TypeSuperVisitable, TypeVisitor};
use rustc_middle::ty::{self, Const, InferConst, Ty, TyCtxt, TypeFoldable, TypeVisitable};
7

8 9
use std::ops::ControlFlow;

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

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

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

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

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

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

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

57 58
/// The opportunistic region resolver opportunistically resolves regions
/// variables to the variable with the least variable id. It is used when
Y
Yuri Astrakhan 已提交
59
/// normalizing projections to avoid hitting the recursion limit by creating
60 61 62 63 64
/// 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> {
65
    infcx: &'a InferCtxt<'a, 'tcx>,
66 67
}

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

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

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

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

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

111 112 113
///////////////////////////////////////////////////////////////////////////
// UNRESOLVED TYPE FINDER

114 115 116
/// 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
117
/// involve some hashing and so forth).
118
pub struct UnresolvedTypeFinder<'a, 'tcx> {
119
    infcx: &'a InferCtxt<'a, 'tcx>,
120 121
}

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

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

164
///////////////////////////////////////////////////////////////////////////
165 166 167 168 169
// 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 已提交
170
pub fn fully_resolve<'a, 'tcx, T>(infcx: &InferCtxt<'a, 'tcx>, value: T) -> FixupResult<'tcx, T>
171 172
where
    T: TypeFoldable<'tcx>,
173
{
174
    value.try_fold_with(&mut FullTypeResolver { infcx })
175 176
}

177
// N.B. This type is not public because the protocol around checking the
M
Matthias Krüger 已提交
178
// `err` field is not enforceable otherwise.
179
struct FullTypeResolver<'a, 'tcx> {
180
    infcx: &'a InferCtxt<'a, 'tcx>,
181 182
}

A
Alan Egerton 已提交
183
impl<'a, 'tcx> FallibleTypeFolder<'tcx> for FullTypeResolver<'a, 'tcx> {
184 185
    type Error = FixupError<'tcx>;

186
    fn tcx<'b>(&'b self) -> TyCtxt<'tcx> {
187 188 189
        self.infcx.tcx
    }

190
    fn try_fold_ty(&mut self, t: Ty<'tcx>) -> Result<Ty<'tcx>, Self::Error> {
191
        if !t.needs_infer() {
192
            Ok(t) // micro-optimize -- if there is nothing in this type that this fold affects...
193
        } else {
V
varkor 已提交
194
            let t = self.infcx.shallow_resolve(t);
L
LeSeulArtichaut 已提交
195
            match *t.kind() {
196 197 198
                ty::Infer(ty::TyVar(vid)) => Err(FixupError::UnresolvedTy(vid)),
                ty::Infer(ty::IntVar(vid)) => Err(FixupError::UnresolvedIntTy(vid)),
                ty::Infer(ty::FloatVar(vid)) => Err(FixupError::UnresolvedFloatTy(vid)),
V
varkor 已提交
199
                ty::Infer(_) => {
200
                    bug!("Unexpected type in full type resolver: {:?}", t);
201
                }
202
                _ => t.try_super_fold_with(self),
203
            }
204 205 206
        }
    }

207
    fn try_fold_region(&mut self, r: ty::Region<'tcx>) -> Result<ty::Region<'tcx>, Self::Error> {
208
        match *r {
209
            ty::ReVar(rid) => Ok(self
M
Mark Rousskov 已提交
210 211 212 213 214
                .infcx
                .lexical_region_resolutions
                .borrow()
                .as_ref()
                .expect("region resolution not performed")
215 216
                .resolve_var(rid)),
            _ => Ok(r),
217 218
        }
    }
219

N
Nicholas Nethercote 已提交
220
    fn try_fold_const(&mut self, c: ty::Const<'tcx>) -> Result<ty::Const<'tcx>, Self::Error> {
221
        if !c.needs_infer() {
222
            Ok(c) // micro-optimize -- if there is nothing in this const that this fold affects...
223
        } else {
V
varkor 已提交
224
            let c = self.infcx.shallow_resolve(c);
225
            match c.kind() {
226
                ty::ConstKind::Infer(InferConst::Var(vid)) => {
227
                    return Err(FixupError::UnresolvedConst(vid));
V
varkor 已提交
228
                }
229
                ty::ConstKind::Infer(InferConst::Fresh(_)) => {
V
varkor 已提交
230
                    bug!("Unexpected const in full const resolver: {:?}", c);
231 232 233
                }
                _ => {}
            }
234
            c.try_super_fold_with(self)
235 236
        }
    }
237
}