rustc_infer/infer/
resolve.rs

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