summaryrefslogtreecommitdiffstats
path: root/vendor/chalk-solve-0.87.0/src/clauses/generalize.rs
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/chalk-solve-0.87.0/src/clauses/generalize.rs')
-rw-r--r--vendor/chalk-solve-0.87.0/src/clauses/generalize.rs99
1 files changed, 99 insertions, 0 deletions
diff --git a/vendor/chalk-solve-0.87.0/src/clauses/generalize.rs b/vendor/chalk-solve-0.87.0/src/clauses/generalize.rs
new file mode 100644
index 000000000..bff05b369
--- /dev/null
+++ b/vendor/chalk-solve-0.87.0/src/clauses/generalize.rs
@@ -0,0 +1,99 @@
+//! This gets rid of free variables in a type by replacing them by fresh bound
+//! ones. We use this when building clauses that contain types passed to
+//! `program_clauses`; these may contain variables, and just copying those
+//! variables verbatim leads to problems. Instead, we return a slightly more
+//! general program clause, with new variables in those places. This can only
+//! happen with `dyn Trait` currently; that's the only case where we use the
+//! types passed to `program_clauses` in the clauses we generate.
+
+use chalk_derive::FallibleTypeFolder;
+use chalk_ir::{
+ fold::{TypeFoldable, TypeFolder},
+ interner::{HasInterner, Interner},
+ Binders, BoundVar, Const, ConstData, ConstValue, DebruijnIndex, Lifetime, LifetimeData, Ty,
+ TyKind, TyVariableKind, VariableKind, VariableKinds,
+};
+use rustc_hash::FxHashMap;
+
+#[derive(FallibleTypeFolder)]
+pub struct Generalize<I: Interner> {
+ binders: Vec<VariableKind<I>>,
+ mapping: FxHashMap<BoundVar, usize>,
+ interner: I,
+}
+
+impl<I: Interner> Generalize<I> {
+ pub fn apply<T>(interner: I, value: T) -> Binders<T>
+ where
+ T: HasInterner<Interner = I> + TypeFoldable<I>,
+ {
+ let mut generalize = Generalize {
+ binders: Vec::new(),
+ mapping: FxHashMap::default(),
+ interner,
+ };
+ let value = value
+ .try_fold_with(&mut generalize, DebruijnIndex::INNERMOST)
+ .unwrap();
+ Binders::new(
+ VariableKinds::from_iter(interner, generalize.binders),
+ value,
+ )
+ }
+}
+
+impl<I: Interner> TypeFolder<I> for Generalize<I> {
+ fn as_dyn(&mut self) -> &mut dyn TypeFolder<I> {
+ self
+ }
+
+ fn fold_free_var_ty(&mut self, bound_var: BoundVar, outer_binder: DebruijnIndex) -> Ty<I> {
+ let binder_vec = &mut self.binders;
+ let new_index = self.mapping.entry(bound_var).or_insert_with(|| {
+ let i = binder_vec.len();
+ binder_vec.push(VariableKind::Ty(TyVariableKind::General));
+ i
+ });
+ let new_var = BoundVar::new(outer_binder, *new_index);
+ TyKind::BoundVar(new_var).intern(TypeFolder::interner(self))
+ }
+
+ fn fold_free_var_const(
+ &mut self,
+ ty: Ty<I>,
+ bound_var: BoundVar,
+ outer_binder: DebruijnIndex,
+ ) -> Const<I> {
+ let binder_vec = &mut self.binders;
+ let new_index = self.mapping.entry(bound_var).or_insert_with(|| {
+ let i = binder_vec.len();
+ binder_vec.push(VariableKind::Const(ty.clone()));
+ i
+ });
+ let new_var = BoundVar::new(outer_binder, *new_index);
+ ConstData {
+ ty,
+ value: ConstValue::BoundVar(new_var),
+ }
+ .intern(TypeFolder::interner(self))
+ }
+
+ fn fold_free_var_lifetime(
+ &mut self,
+ bound_var: BoundVar,
+ outer_binder: DebruijnIndex,
+ ) -> Lifetime<I> {
+ let binder_vec = &mut self.binders;
+ let new_index = self.mapping.entry(bound_var).or_insert_with(|| {
+ let i = binder_vec.len();
+ binder_vec.push(VariableKind::Lifetime);
+ i
+ });
+ let new_var = BoundVar::new(outer_binder, *new_index);
+ LifetimeData::BoundVar(new_var).intern(TypeFolder::interner(self))
+ }
+
+ fn interner(&self) -> I {
+ self.interner
+ }
+}