rustc_infer/infer/
resolve.rs

1use rustc_middle::bug;
2use rustc_middle::ty::fold::{FallibleTypeFolder, TypeFolder, TypeSuperFoldable};
3use rustc_middle::ty::visit::TypeVisitableExt;
4use rustc_middle::ty::{self, Const, InferConst, Ty, TyCtxt, TypeFoldable};
5use rustc_type_ir::data_structures::DelayedMap;
6
7use super::{FixupError, FixupResult, InferCtxt};
8
9///////////////////////////////////////////////////////////////////////////
10// OPPORTUNISTIC VAR RESOLVER
11
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
14/// been unified with (similar to `shallow_resolve`, but deep). This is
15/// useful for printing messages etc but also required at various
16/// points for correctness.
17pub struct OpportunisticVarResolver<'a, 'tcx> {
18    infcx: &'a InferCtxt<'tcx>,
19    /// We're able to use a cache here as the folder does
20    /// not have any mutable state.
21    cache: DelayedMap<Ty<'tcx>, Ty<'tcx>>,
22}
23
24impl<'a, 'tcx> OpportunisticVarResolver<'a, 'tcx> {
25    #[inline]
26    pub fn new(infcx: &'a InferCtxt<'tcx>) -> Self {
27        OpportunisticVarResolver { infcx, cache: Default::default() }
28    }
29}
30
31impl<'a, 'tcx> TypeFolder<TyCtxt<'tcx>> for OpportunisticVarResolver<'a, 'tcx> {
32    fn cx(&self) -> TyCtxt<'tcx> {
33        self.infcx.tcx
34    }
35
36    #[inline]
37    fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> {
38        if !t.has_non_region_infer() {
39            t // micro-optimize -- if there is nothing in this type that this fold affects...
40        } else if let Some(&ty) = self.cache.get(&t) {
41            ty
42        } else {
43            let shallow = self.infcx.shallow_resolve(t);
44            let res = shallow.super_fold_with(self);
45            assert!(self.cache.insert(t, res));
46            res
47        }
48    }
49
50    fn fold_const(&mut self, ct: Const<'tcx>) -> Const<'tcx> {
51        if !ct.has_non_region_infer() {
52            ct // micro-optimize -- if there is nothing in this const that this fold affects...
53        } else {
54            let ct = self.infcx.shallow_resolve_const(ct);
55            ct.super_fold_with(self)
56        }
57    }
58}
59
60/// The opportunistic region resolver opportunistically resolves regions
61/// variables to the variable with the least variable id. It is used when
62/// normalizing projections to avoid hitting the recursion limit by creating
63/// many versions of a predicate for types that in the end have to unify.
64///
65/// If you want to resolve type and const variables as well, call
66/// [InferCtxt::resolve_vars_if_possible] first.
67pub struct OpportunisticRegionResolver<'a, 'tcx> {
68    infcx: &'a InferCtxt<'tcx>,
69}
70
71impl<'a, 'tcx> OpportunisticRegionResolver<'a, 'tcx> {
72    pub fn new(infcx: &'a InferCtxt<'tcx>) -> Self {
73        OpportunisticRegionResolver { infcx }
74    }
75}
76
77impl<'a, 'tcx> TypeFolder<TyCtxt<'tcx>> for OpportunisticRegionResolver<'a, 'tcx> {
78    fn cx(&self) -> TyCtxt<'tcx> {
79        self.infcx.tcx
80    }
81
82    fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> {
83        if !t.has_infer_regions() {
84            t // micro-optimize -- if there is nothing in this type that this fold affects...
85        } else {
86            t.super_fold_with(self)
87        }
88    }
89
90    fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> {
91        match *r {
92            ty::ReVar(vid) => self
93                .infcx
94                .inner
95                .borrow_mut()
96                .unwrap_region_constraints()
97                .opportunistic_resolve_var(TypeFolder::cx(self), vid),
98            _ => r,
99        }
100    }
101
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// FULL TYPE RESOLUTION
113
114/// Full type resolution replaces all type and region variables with
115/// their concrete results. If any variable cannot be replaced (never unified, etc)
116/// then an `Err` result is returned.
117pub fn fully_resolve<'tcx, T>(infcx: &InferCtxt<'tcx>, value: T) -> FixupResult<T>
118where
119    T: TypeFoldable<TyCtxt<'tcx>>,
120{
121    value.try_fold_with(&mut FullTypeResolver { infcx })
122}
123
124struct FullTypeResolver<'a, 'tcx> {
125    infcx: &'a InferCtxt<'tcx>,
126}
127
128impl<'a, 'tcx> FallibleTypeFolder<TyCtxt<'tcx>> for FullTypeResolver<'a, 'tcx> {
129    type Error = FixupError;
130
131    fn cx(&self) -> TyCtxt<'tcx> {
132        self.infcx.tcx
133    }
134
135    fn try_fold_ty(&mut self, t: Ty<'tcx>) -> Result<Ty<'tcx>, Self::Error> {
136        if !t.has_infer() {
137            Ok(t) // micro-optimize -- if there is nothing in this type that this fold affects...
138        } else {
139            use super::TyOrConstInferVar::*;
140
141            let t = self.infcx.shallow_resolve(t);
142            match *t.kind() {
143                ty::Infer(ty::TyVar(vid)) => Err(FixupError { unresolved: Ty(vid) }),
144                ty::Infer(ty::IntVar(vid)) => Err(FixupError { unresolved: TyInt(vid) }),
145                ty::Infer(ty::FloatVar(vid)) => Err(FixupError { unresolved: TyFloat(vid) }),
146                ty::Infer(_) => {
147                    bug!("Unexpected type in full type resolver: {:?}", t);
148                }
149                _ => t.try_super_fold_with(self),
150            }
151        }
152    }
153
154    fn try_fold_region(&mut self, r: ty::Region<'tcx>) -> Result<ty::Region<'tcx>, Self::Error> {
155        match *r {
156            ty::ReVar(_) => Ok(self
157                .infcx
158                .lexical_region_resolutions
159                .borrow()
160                .as_ref()
161                .expect("region resolution not performed")
162                .resolve_region(self.infcx.tcx, r)),
163            _ => Ok(r),
164        }
165    }
166
167    fn try_fold_const(&mut self, c: ty::Const<'tcx>) -> Result<ty::Const<'tcx>, Self::Error> {
168        if !c.has_infer() {
169            Ok(c) // micro-optimize -- if there is nothing in this const that this fold affects...
170        } else {
171            let c = self.infcx.shallow_resolve_const(c);
172            match c.kind() {
173                ty::ConstKind::Infer(InferConst::Var(vid)) => {
174                    return Err(FixupError { unresolved: super::TyOrConstInferVar::Const(vid) });
175                }
176                ty::ConstKind::Infer(InferConst::Fresh(_)) => {
177                    bug!("Unexpected const in full const resolver: {:?}", c);
178                }
179                _ => {}
180            }
181            c.try_super_fold_with(self)
182        }
183    }
184}