Skip to main content

rustc_infer/infer/
resolve.rs

1use rustc_middle::ty::{
2    self, Const, DelayedMap, FallibleTypeFolder, InferConst, Ty, TyCtxt, TypeFoldable, TypeFolder,
3    TypeSuperFoldable, TypeVisitableExt,
4};
5use rustc_span::bug;
6use rustc_type_ir::PredicateProxy;
7
8use super::{FixupError, FixupResult, InferCtxt};
9use crate::infer::TyOrConstInferVar;
10
11///////////////////////////////////////////////////////////////////////////
12// DEEP VAR RESOLVER
13
14/// The type and const resolver can be used at any time. It simply replaces
15/// type/const variables that have been unified with the things they have
16/// been unified with (similar to `shallow_resolve`, but deep). This is
17/// useful for printing messages etc but also required at various
18/// points for correctness.
19pub struct DeepResolverIgnoringRegions<'a, 'tcx> {
20    infcx: &'a InferCtxt<'tcx>,
21    /// We're able to use a cache here as the folder does
22    /// not have any mutable state.
23    cache: DelayedMap<Ty<'tcx>, Ty<'tcx>>,
24}
25
26impl<'a, 'tcx> DeepResolverIgnoringRegions<'a, 'tcx> {
27    #[inline]
28    pub fn new(infcx: &'a InferCtxt<'tcx>) -> Self {
29        DeepResolverIgnoringRegions { infcx, cache: Default::default() }
30    }
31}
32
33impl<'a, 'tcx> TypeFolder<TyCtxt<'tcx>> for DeepResolverIgnoringRegions<'a, 'tcx> {
34    fn cx(&self) -> TyCtxt<'tcx> {
35        self.infcx.tcx
36    }
37
38    #[inline]
39    fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> {
40        if !t.has_non_region_infer() {
41            t // micro-optimize -- if there is nothing in this type that this fold affects...
42        } else if let Some(&ty) = self.cache.get(&t) {
43            ty
44        } else {
45            let shallow = self.infcx.shallow_resolve(t);
46            let res = shallow.super_fold_with(self);
47            if !self.cache.insert(t, res) {
    ::core::panicking::panic("assertion failed: self.cache.insert(t, res)")
};assert!(self.cache.insert(t, res));
48            res
49        }
50    }
51
52    fn fold_const(&mut self, ct: Const<'tcx>) -> Const<'tcx> {
53        if !ct.has_non_region_infer() {
54            ct // micro-optimize -- if there is nothing in this const that this fold affects...
55        } else {
56            let ct = self.infcx.shallow_resolve_const(ct);
57            ct.super_fold_with(self)
58        }
59    }
60
61    fn fold_predicate<P: PredicateProxy<TyCtxt<'tcx>>>(&mut self, p: P) -> P {
62        if !p.has_non_region_infer() { p } else { p.super_fold_with(self) }
63    }
64
65    fn fold_clauses(&mut self, c: ty::Clauses<'tcx>) -> ty::Clauses<'tcx> {
66        if !c.has_non_region_infer() { c } else { c.super_fold_with(self) }
67    }
68}
69
70///////////////////////////////////////////////////////////////////////////
71// FULL TYPE RESOLUTION
72
73/// Full type resolution replaces all type and region variables with
74/// their concrete results. If any variable cannot be replaced (never unified, etc)
75/// then an `Err` result is returned.
76pub fn deeply_resolve_via_region_graph<'tcx, T>(infcx: &InferCtxt<'tcx>, value: T) -> FixupResult<T>
77where
78    T: TypeFoldable<TyCtxt<'tcx>>,
79{
80    value.try_fold_with(&mut FullTypeResolver { infcx })
81}
82
83struct FullTypeResolver<'a, 'tcx> {
84    infcx: &'a InferCtxt<'tcx>,
85}
86
87impl<'a, 'tcx> FallibleTypeFolder<TyCtxt<'tcx>> for FullTypeResolver<'a, 'tcx> {
88    type Error = FixupError;
89
90    fn cx(&self) -> TyCtxt<'tcx> {
91        self.infcx.tcx
92    }
93
94    fn try_fold_ty(&mut self, t: Ty<'tcx>) -> Result<Ty<'tcx>, Self::Error> {
95        if !t.has_infer() {
96            Ok(t) // micro-optimize -- if there is nothing in this type that this fold affects...
97        } else {
98            let t = self.infcx.shallow_resolve(t);
99            match *t.kind() {
100                ty::Infer(ty::TyVar(vid)) => {
101                    Err(FixupError { unresolved: TyOrConstInferVar::Ty(vid) })
102                }
103                ty::Infer(ty::IntVar(vid)) => {
104                    Err(FixupError { unresolved: TyOrConstInferVar::TyInt(vid) })
105                }
106                ty::Infer(ty::FloatVar(vid)) => {
107                    Err(FixupError { unresolved: TyOrConstInferVar::TyFloat(vid) })
108                }
109                ty::Infer(_) => {
110                    bug_impl(None,
    format_args!("Unexpected type in full type resolver: {0:?}", t),
    Location::caller());bug!("Unexpected type in full type resolver: {:?}", t);
111                }
112                _ => t.try_super_fold_with(self),
113            }
114        }
115    }
116
117    fn try_fold_region(&mut self, r: ty::Region<'tcx>) -> Result<ty::Region<'tcx>, Self::Error> {
118        match r.kind() {
119            ty::ReVar(_) => Ok(self
120                .infcx
121                .lexical_region_resolutions
122                .borrow()
123                .as_ref()
124                .expect("region resolution not performed")
125                .resolve_region(self.infcx.tcx, r)),
126            _ => Ok(r),
127        }
128    }
129
130    fn try_fold_const(&mut self, c: ty::Const<'tcx>) -> Result<ty::Const<'tcx>, Self::Error> {
131        if !c.has_infer() {
132            Ok(c) // micro-optimize -- if there is nothing in this const that this fold affects...
133        } else {
134            let c = self.infcx.shallow_resolve_const(c);
135            match c.kind() {
136                ty::ConstKind::Infer(InferConst::Var(vid)) => {
137                    return Err(FixupError { unresolved: super::TyOrConstInferVar::Const(vid) });
138                }
139                ty::ConstKind::Infer(InferConst::Fresh(_)) => {
140                    bug_impl(None,
    format_args!("Unexpected const in full const resolver: {0:?}", c),
    Location::caller());bug!("Unexpected const in full const resolver: {:?}", c);
141                }
142                _ => {}
143            }
144            c.try_super_fold_with(self)
145        }
146    }
147}