From 212f0477f29ec27a3981a916de432fc9ef872ff3 Mon Sep 17 00:00:00 2001 From: Florian Diebold Date: Sat, 15 May 2021 19:28:58 +0200 Subject: Make diverging type variables work again Chalk doesn't know about the `diverging` flag, so we need to instead propagate it before fully resolving the variables. --- crates/hir_ty/src/infer.rs | 3 +++ crates/hir_ty/src/infer/unify.rs | 20 ++++++++++++++++++++ 2 files changed, 23 insertions(+) (limited to 'crates') diff --git a/crates/hir_ty/src/infer.rs b/crates/hir_ty/src/infer.rs index f3cccca68..7898740be 100644 --- a/crates/hir_ty/src/infer.rs +++ b/crates/hir_ty/src/infer.rs @@ -284,6 +284,9 @@ impl<'a> InferenceContext<'a> { fn resolve_all(mut self) -> InferenceResult { // FIXME resolve obligations as well (use Guidance if necessary) + + // make sure diverging type variables are marked as such + self.table.propagate_diverging_flag(); let mut result = std::mem::take(&mut self.result); for ty in result.type_of_expr.values_mut() { let resolved = self.table.resolve_ty_completely(ty.clone()); diff --git a/crates/hir_ty/src/infer/unify.rs b/crates/hir_ty/src/infer/unify.rs index e7718aa22..56e06b7d0 100644 --- a/crates/hir_ty/src/infer/unify.rs +++ b/crates/hir_ty/src/infer/unify.rs @@ -179,8 +179,28 @@ impl<'a> InferenceTable<'a> { } } + /// Chalk doesn't know about the `diverging` flag, so when it unifies two + /// type variables of which one is diverging, the chosen root might not be + /// diverging and we have no way of marking it as such at that time. This + /// function goes through all type variables and make sure their root is + /// marked as diverging if necessary, so that resolving them gives the right + /// result. + pub(super) fn propagate_diverging_flag(&mut self) { + for i in 0..self.type_variable_table.inner.len() { + if !self.type_variable_table.inner[i].diverging { + continue; + } + let v = InferenceVar::from(i as u32); + let root = self.var_unification_table.inference_var_root(v); + if let Some(data) = self.type_variable_table.inner.get_mut(root.index() as usize) { + data.diverging = true; + } + } + } + fn new_var(&mut self, kind: TyVariableKind, diverging: bool) -> Ty { let var = self.var_unification_table.new_variable(UniverseIndex::ROOT); + // Chalk might have created some type variables for its own purposes that we don't know about... self.type_variable_table.inner.extend( (0..1 + var.index() as usize - self.type_variable_table.inner.len()) .map(|_| TypeVariableData { diverging: false }), -- cgit v1.2.3