1use chalk_ir::interner::{HasInterner, Interner};
2use chalk_ir::*;
3use chalk_ir::{cast::Cast, fold::TypeFoldable};
4use tracing::debug;
5
6mod canonicalize;
7pub(crate) mod instantiate;
8mod invert;
9mod test;
10pub mod ucanonicalize;
11pub mod unify;
12mod var;
13
14use self::var::*;
15
16#[derive(Clone)]
17pub struct InferenceTable<I: Interner> {
18 unify: ena::unify::InPlaceUnificationTable<EnaVariable<I>>,
19 vars: Vec<EnaVariable<I>>,
20 max_universe: UniverseIndex,
21}
22
23pub struct InferenceSnapshot<I: Interner> {
24 unify_snapshot: ena::unify::Snapshot<ena::unify::InPlace<EnaVariable<I>>>,
25 max_universe: UniverseIndex,
26 vars: Vec<EnaVariable<I>>,
27}
28
29#[allow(type_alias_bounds)]
30pub type ParameterEnaVariable<I: Interner> = WithKind<I, EnaVariable<I>>;
31
32impl<I: Interner> InferenceTable<I> {
33 pub fn new() -> Self {
35 InferenceTable {
36 unify: ena::unify::UnificationTable::new(),
37 vars: vec![],
38 max_universe: UniverseIndex::root(),
39 }
40 }
41
42 pub fn from_canonical<T>(
50 interner: I,
51 num_universes: usize,
52 canonical: Canonical<T>,
53 ) -> (Self, Substitution<I>, T)
54 where
55 T: HasInterner<Interner = I> + TypeFoldable<I> + Clone,
56 {
57 let mut table = InferenceTable::new();
58
59 assert!(num_universes >= 1); for _ in 1..num_universes {
61 table.new_universe();
62 }
63
64 let subst = table.fresh_subst(interner, canonical.binders.as_slice(interner));
65 let value = subst.apply(canonical.value, interner);
66 (table, subst, value)
69 }
70
71 pub fn new_universe(&mut self) -> UniverseIndex {
76 let u = self.max_universe.next();
77 self.max_universe = u;
78 debug!("created new universe: {:?}", u);
79 u
80 }
81
82 pub fn new_variable(&mut self, ui: UniverseIndex) -> EnaVariable<I> {
86 let var = self.unify.new_key(InferenceValue::Unbound(ui));
87 self.vars.push(var);
88 debug!(?var, ?ui, "created new variable");
89 var
90 }
91
92 pub fn snapshot(&mut self) -> InferenceSnapshot<I> {
99 let unify_snapshot = self.unify.snapshot();
100 let vars = self.vars.clone();
101 let max_universe = self.max_universe;
102 InferenceSnapshot {
103 unify_snapshot,
104 max_universe,
105 vars,
106 }
107 }
108
109 pub fn rollback_to(&mut self, snapshot: InferenceSnapshot<I>) {
111 self.unify.rollback_to(snapshot.unify_snapshot);
112 self.vars = snapshot.vars;
113 self.max_universe = snapshot.max_universe;
114 }
115
116 pub fn commit(&mut self, snapshot: InferenceSnapshot<I>) {
118 self.unify.commit(snapshot.unify_snapshot);
119 }
120
121 pub fn normalize_ty_shallow(&mut self, interner: I, leaf: &Ty<I>) -> Option<Ty<I>> {
122 self.normalize_ty_shallow_inner(interner, leaf)
127 .map(|ty| self.normalize_ty_shallow_inner(interner, &ty).unwrap_or(ty))
128 }
129
130 fn normalize_ty_shallow_inner(&mut self, interner: I, leaf: &Ty<I>) -> Option<Ty<I>> {
131 self.probe_var(leaf.inference_var(interner)?)
132 .map(|p| p.assert_ty_ref(interner).clone())
133 }
134
135 pub fn normalize_lifetime_shallow(
136 &mut self,
137 interner: I,
138 leaf: &Lifetime<I>,
139 ) -> Option<Lifetime<I>> {
140 self.probe_var(leaf.inference_var(interner)?)
141 .map(|p| p.assert_lifetime_ref(interner).clone())
142 }
143
144 pub fn normalize_const_shallow(&mut self, interner: I, leaf: &Const<I>) -> Option<Const<I>> {
145 self.probe_var(leaf.inference_var(interner)?)
146 .map(|p| p.assert_const_ref(interner).clone())
147 }
148
149 pub fn ty_root(&mut self, interner: I, leaf: &Ty<I>) -> Option<Ty<I>> {
150 Some(
151 self.unify
152 .find(leaf.inference_var(interner)?)
153 .to_ty(interner),
154 )
155 }
156
157 pub fn lifetime_root(&mut self, interner: I, leaf: &Lifetime<I>) -> Option<Lifetime<I>> {
158 Some(
159 self.unify
160 .find(leaf.inference_var(interner)?)
161 .to_lifetime(interner),
162 )
163 }
164
165 pub fn inference_var_root(&mut self, var: InferenceVar) -> InferenceVar {
173 self.unify.find(var).into()
174 }
175
176 pub fn probe_var(&mut self, leaf: InferenceVar) -> Option<GenericArg<I>> {
179 match self.unify.probe_value(EnaVariable::from(leaf)) {
180 InferenceValue::Unbound(_) => None,
181 InferenceValue::Bound(val) => Some(val),
182 }
183 }
184
185 fn universe_of_unbound_var(&mut self, var: EnaVariable<I>) -> UniverseIndex {
191 match self.unify.probe_value(var) {
192 InferenceValue::Unbound(ui) => ui,
193 InferenceValue::Bound(_) => panic!("var_universe invoked on bound variable"),
194 }
195 }
196}
197
198pub trait ParameterEnaVariableExt<I: Interner> {
199 fn to_generic_arg(&self, interner: I) -> GenericArg<I>;
200}
201
202impl<I: Interner> ParameterEnaVariableExt<I> for ParameterEnaVariable<I> {
203 fn to_generic_arg(&self, interner: I) -> GenericArg<I> {
204 let ena_variable = self.skip_kind();
206 match &self.kind {
207 VariableKind::Ty(kind) => ena_variable.to_ty_with_kind(interner, *kind).cast(interner),
208 VariableKind::Lifetime => ena_variable.to_lifetime(interner).cast(interner),
209 VariableKind::Const(ty) => ena_variable.to_const(interner, ty.clone()).cast(interner),
210 }
211 }
212}