Unnamed repository; edit this file 'description' to name the repository.
Diffstat (limited to 'crates/hir-ty/src/infer.rs')
| -rw-r--r-- | crates/hir-ty/src/infer.rs | 86 |
1 files changed, 55 insertions, 31 deletions
diff --git a/crates/hir-ty/src/infer.rs b/crates/hir-ty/src/infer.rs index b4da1a308d..d90ca77b55 100644 --- a/crates/hir-ty/src/infer.rs +++ b/crates/hir-ty/src/infer.rs @@ -33,7 +33,7 @@ use hir_def::{ TraitId, TypeAliasId, VariantId, }; use hir_expand::name::{name, Name}; -use la_arena::ArenaMap; +use la_arena::{ArenaMap, Entry}; use rustc_hash::{FxHashMap, FxHashSet}; use stdx::{always, never}; @@ -676,36 +676,16 @@ impl<'a> InferenceContext<'a> { let return_ty = if let Some(rpits) = self.db.return_type_impl_traits(func) { // RPIT opaque types use substitution of their parent function. let fn_placeholders = TyBuilder::placeholder_subst(self.db, func); - fold_tys( - return_ty, - |ty, _| { - let opaque_ty_id = match ty.kind(Interner) { - TyKind::OpaqueType(opaque_ty_id, _) => *opaque_ty_id, - _ => return ty, - }; - let idx = match self.db.lookup_intern_impl_trait_id(opaque_ty_id.into()) { - ImplTraitId::ReturnTypeImplTrait(_, idx) => idx, - _ => unreachable!(), - }; - let bounds = (*rpits).map_ref(|rpits| { - rpits.impl_traits[idx].bounds.map_ref(|it| it.into_iter()) - }); - let var = self.table.new_type_var(); - let var_subst = Substitution::from1(Interner, var.clone()); - for bound in bounds { - let predicate = - bound.map(|it| it.cloned()).substitute(Interner, &fn_placeholders); - let (var_predicate, binders) = predicate - .substitute(Interner, &var_subst) - .into_value_and_skipped_binders(); - always!(binders.is_empty(Interner)); // quantified where clauses not yet handled - self.push_obligation(var_predicate.cast(Interner)); - } - self.result.type_of_rpit.insert(idx, var.clone()); - var - }, - DebruijnIndex::INNERMOST, - ) + let result = + self.insert_inference_vars_for_rpit(return_ty, rpits.clone(), fn_placeholders); + let rpits = rpits.skip_binders(); + for (id, _) in rpits.impl_traits.iter() { + if let Entry::Vacant(e) = self.result.type_of_rpit.entry(id) { + never!("Missed RPIT in `insert_inference_vars_for_rpit`"); + e.insert(TyKind::Error.intern(Interner)); + } + } + result } else { return_ty }; @@ -714,6 +694,50 @@ impl<'a> InferenceContext<'a> { self.return_coercion = Some(CoerceMany::new(self.return_ty.clone())); } + fn insert_inference_vars_for_rpit<T>( + &mut self, + t: T, + rpits: Arc<chalk_ir::Binders<crate::ReturnTypeImplTraits>>, + fn_placeholders: Substitution, + ) -> T + where + T: crate::HasInterner<Interner = Interner> + crate::TypeFoldable<Interner>, + { + fold_tys( + t, + |ty, _| { + let opaque_ty_id = match ty.kind(Interner) { + TyKind::OpaqueType(opaque_ty_id, _) => *opaque_ty_id, + _ => return ty, + }; + let idx = match self.db.lookup_intern_impl_trait_id(opaque_ty_id.into()) { + ImplTraitId::ReturnTypeImplTrait(_, idx) => idx, + _ => unreachable!(), + }; + let bounds = (*rpits) + .map_ref(|rpits| rpits.impl_traits[idx].bounds.map_ref(|it| it.into_iter())); + let var = self.table.new_type_var(); + let var_subst = Substitution::from1(Interner, var.clone()); + for bound in bounds { + let predicate = + bound.map(|it| it.cloned()).substitute(Interner, &fn_placeholders); + let (var_predicate, binders) = + predicate.substitute(Interner, &var_subst).into_value_and_skipped_binders(); + always!(binders.is_empty(Interner)); // quantified where clauses not yet handled + let var_predicate = self.insert_inference_vars_for_rpit( + var_predicate, + rpits.clone(), + fn_placeholders.clone(), + ); + self.push_obligation(var_predicate.cast(Interner)); + } + self.result.type_of_rpit.insert(idx, var.clone()); + var + }, + DebruijnIndex::INNERMOST, + ) + } + fn infer_body(&mut self) { match self.return_coercion { Some(_) => self.infer_return(self.body.body_expr), |