From 8397734cfe26793d3e9f9ec5f8392655a4b8e106 Mon Sep 17 00:00:00 2001 From: Florian Diebold Date: Sat, 15 May 2021 20:28:07 +0200 Subject: Fix HIR expecting errors to unify with anything --- crates/hir/src/lib.rs | 9 +++---- crates/hir_ty/src/infer/unify.rs | 8 ++++-- crates/hir_ty/src/lib.rs | 56 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 65 insertions(+), 8 deletions(-) (limited to 'crates') diff --git a/crates/hir/src/lib.rs b/crates/hir/src/lib.rs index 21b1a8e4a..1429384cb 100644 --- a/crates/hir/src/lib.rs +++ b/crates/hir/src/lib.rs @@ -2051,11 +2051,7 @@ impl Type { name: Option<&Name>, mut callback: impl FnMut(&Ty, AssocItem) -> Option, ) -> Option { - // There should be no inference vars in types passed here - // FIXME check that? - // FIXME replace Unknown by bound vars here - let canonical = - Canonical { value: self.ty.clone(), binders: CanonicalVarKinds::empty(&Interner) }; + let canonical = hir_ty::replace_errors_with_variables(self.ty.clone()); let env = self.env.clone(); let krate = krate.id; @@ -2224,7 +2220,8 @@ impl Type { } pub fn could_unify_with(&self, db: &dyn HirDatabase, other: &Type) -> bool { - could_unify(db, self.env.clone(), &self.ty, &other.ty) + let tys = hir_ty::replace_errors_with_variables((self.ty.clone(), other.ty.clone())); + could_unify(db, self.env.clone(), &tys) } } diff --git a/crates/hir_ty/src/infer/unify.rs b/crates/hir_ty/src/infer/unify.rs index 56e06b7d0..d8edfb4e9 100644 --- a/crates/hir_ty/src/infer/unify.rs +++ b/crates/hir_ty/src/infer/unify.rs @@ -86,8 +86,12 @@ impl> Canonicalized { } } -pub fn could_unify(db: &dyn HirDatabase, env: Arc, t1: &Ty, t2: &Ty) -> bool { - InferenceTable::new(db, env).unify(t1, t2) +pub fn could_unify( + db: &dyn HirDatabase, + env: Arc, + tys: &Canonical<(Ty, Ty)>, +) -> bool { + unify(db, env, tys).is_some() } pub(crate) fn unify( diff --git a/crates/hir_ty/src/lib.rs b/crates/hir_ty/src/lib.rs index 06d5cd0b6..56f60c46b 100644 --- a/crates/hir_ty/src/lib.rs +++ b/crates/hir_ty/src/lib.rs @@ -43,6 +43,7 @@ use hir_def::{ type_ref::{ConstScalar, Rawness}, TypeParamId, }; +use stdx::always; use crate::{db::HirDatabase, display::HirDisplay, utils::generics}; @@ -326,3 +327,58 @@ pub(crate) fn fold_tys + Fold>( } t.fold_with(&mut TyFolder(f), binders).expect("fold failed unexpectedly") } + +pub fn replace_errors_with_variables(t: T) -> Canonical +where + T: HasInterner + Fold, + T::Result: HasInterner, +{ + use chalk_ir::{ + fold::{Folder, SuperFold}, + Fallible, + }; + struct ErrorReplacer { + vars: usize, + } + impl<'i> Folder<'i, Interner> for ErrorReplacer { + fn as_dyn(&mut self) -> &mut dyn Folder<'i, Interner> { + self + } + + fn interner(&self) -> &'i Interner { + &Interner + } + + fn fold_ty(&mut self, ty: Ty, outer_binder: DebruijnIndex) -> Fallible { + if let TyKind::Error = ty.kind(&Interner) { + let index = self.vars; + self.vars += 1; + Ok(TyKind::BoundVar(BoundVar::new(outer_binder, index)).intern(&Interner)) + } else { + let ty = ty.super_fold_with(self.as_dyn(), outer_binder)?; + Ok(ty) + } + } + + fn fold_inference_ty( + &mut self, + var: InferenceVar, + kind: TyVariableKind, + _outer_binder: DebruijnIndex, + ) -> Fallible { + always!(false); + Ok(TyKind::InferenceVar(var, kind).intern(&Interner)) + } + } + let mut error_replacer = ErrorReplacer { vars: 0 }; + let value = t + .fold_with(&mut error_replacer, DebruijnIndex::INNERMOST) + .expect("fold failed unexpectedly"); + let kinds = (0..error_replacer.vars).map(|_| { + chalk_ir::CanonicalVarKind::new( + chalk_ir::VariableKind::Ty(TyVariableKind::General), + chalk_ir::UniverseIndex::ROOT, + ) + }); + Canonical { value, binders: chalk_ir::CanonicalVarKinds::from_iter(&Interner, kinds) } +} -- cgit v1.2.3