hir_ty/next_solver/infer/
resolve.rs

1//! Things for resolving vars in the infer context of the next-trait-solver.
2
3use rustc_type_ir::{
4    TypeFolder, TypeSuperFoldable, TypeVisitableExt,
5    data_structures::DelayedMap,
6    inherent::{Const as _, Ty as _},
7};
8
9use crate::next_solver::{Const, DbInterner, ErrorGuaranteed, Region, Ty};
10
11use super::InferCtxt;
12
13///////////////////////////////////////////////////////////////////////////
14// OPPORTUNISTIC VAR RESOLVER
15
16/// The opportunistic resolver can be used at any time. It simply replaces
17/// type/const variables that have been unified with the things they have
18/// been unified with (similar to `shallow_resolve`, but deep). This is
19/// useful for printing messages etc but also required at various
20/// points for correctness.
21pub struct OpportunisticVarResolver<'a, 'db> {
22    infcx: &'a InferCtxt<'db>,
23    /// We're able to use a cache here as the folder does
24    /// not have any mutable state.
25    cache: DelayedMap<Ty<'db>, Ty<'db>>,
26}
27
28impl<'a, 'db> OpportunisticVarResolver<'a, 'db> {
29    #[inline]
30    pub fn new(infcx: &'a InferCtxt<'db>) -> Self {
31        OpportunisticVarResolver { infcx, cache: Default::default() }
32    }
33}
34
35impl<'a, 'db> TypeFolder<DbInterner<'db>> for OpportunisticVarResolver<'a, 'db> {
36    fn cx(&self) -> DbInterner<'db> {
37        self.infcx.interner
38    }
39
40    #[inline]
41    fn fold_ty(&mut self, t: Ty<'db>) -> Ty<'db> {
42        if !t.has_non_region_infer() {
43            t // micro-optimize -- if there is nothing in this type that this fold affects...
44        } else if let Some(ty) = self.cache.get(&t) {
45            *ty
46        } else {
47            let shallow = self.infcx.shallow_resolve(t);
48            let res = shallow.super_fold_with(self);
49            assert!(self.cache.insert(t, res));
50            res
51        }
52    }
53
54    fn fold_const(&mut self, ct: Const<'db>) -> Const<'db> {
55        if !ct.has_non_region_infer() {
56            ct // micro-optimize -- if there is nothing in this const that this fold affects...
57        } else {
58            let ct = self.infcx.shallow_resolve_const(ct);
59            ct.super_fold_with(self)
60        }
61    }
62}
63
64pub struct ReplaceInferWithError<'db> {
65    interner: DbInterner<'db>,
66}
67
68impl<'db> ReplaceInferWithError<'db> {
69    #[inline]
70    pub fn new(interner: DbInterner<'db>) -> Self {
71        Self { interner }
72    }
73}
74
75impl<'db> TypeFolder<DbInterner<'db>> for ReplaceInferWithError<'db> {
76    fn cx(&self) -> DbInterner<'db> {
77        self.interner
78    }
79
80    fn fold_ty(&mut self, t: Ty<'db>) -> Ty<'db> {
81        if !t.has_infer() {
82            return t;
83        }
84
85        if t.is_infer() {
86            Ty::new_error(self.interner, ErrorGuaranteed)
87        } else {
88            t.super_fold_with(self)
89        }
90    }
91
92    fn fold_const(&mut self, c: Const<'db>) -> Const<'db> {
93        if !c.has_infer() {
94            return c;
95        }
96
97        if c.is_ct_infer() {
98            Const::new_error(self.interner, ErrorGuaranteed)
99        } else {
100            c.super_fold_with(self)
101        }
102    }
103
104    fn fold_region(&mut self, r: Region<'db>) -> Region<'db> {
105        if r.is_var() { Region::error(self.interner) } else { r }
106    }
107}