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 | 113 |
1 files changed, 89 insertions, 24 deletions
diff --git a/crates/hir-ty/src/infer.rs b/crates/hir-ty/src/infer.rs index 45d423d03c..062ea27815 100644 --- a/crates/hir-ty/src/infer.rs +++ b/crates/hir-ty/src/infer.rs @@ -22,7 +22,7 @@ mod pat; mod path; pub(crate) mod unify; -use std::{convert::identity, iter, ops::Index}; +use std::{cell::OnceCell, convert::identity, iter, ops::Index}; use chalk_ir::{ cast::Cast, @@ -49,17 +49,17 @@ use hir_expand::name::Name; use indexmap::IndexSet; use intern::sym; use la_arena::{ArenaMap, Entry}; -use once_cell::unsync::OnceCell; use rustc_hash::{FxHashMap, FxHashSet}; use stdx::{always, never}; use triomphe::Arc; use crate::{ db::HirDatabase, - error_lifetime, fold_tys, + fold_tys, generics::Generics, infer::{coerce::CoerceMany, unify::InferenceTable}, lower::ImplTraitLoweringMode, + mir::MirSpan, to_assoc_type_id, traits::FnTrait, utils::{InTypeConstIdMetadata, UnevaluatedConstEvaluatorFolder}, @@ -328,13 +328,13 @@ pub struct Adjustment { } impl Adjustment { - pub fn borrow(m: Mutability, ty: Ty) -> Self { - let ty = TyKind::Ref(m, error_lifetime(), ty).intern(Interner); - Adjustment { kind: Adjust::Borrow(AutoBorrow::Ref(m)), target: ty } + pub fn borrow(m: Mutability, ty: Ty, lt: Lifetime) -> Self { + let ty = TyKind::Ref(m, lt.clone(), ty).intern(Interner); + Adjustment { kind: Adjust::Borrow(AutoBorrow::Ref(lt, m)), target: ty } } } -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] +#[derive(Clone, Debug, PartialEq, Eq, Hash)] pub enum Adjust { /// Go from ! to any type. NeverToAny, @@ -354,18 +354,18 @@ pub enum Adjust { #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] pub struct OverloadedDeref(pub Option<Mutability>); -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] +#[derive(Clone, Debug, PartialEq, Eq, Hash)] pub enum AutoBorrow { /// Converts from T to &T. - Ref(Mutability), + Ref(Lifetime, Mutability), /// Converts from T to *T. RawPtr(Mutability), } impl AutoBorrow { - fn mutability(self) -> Mutability { - let (AutoBorrow::Ref(m) | AutoBorrow::RawPtr(m)) = self; - m + fn mutability(&self) -> Mutability { + let (AutoBorrow::Ref(_, m) | AutoBorrow::RawPtr(m)) = self; + *m } } @@ -554,6 +554,12 @@ pub(crate) struct InferenceContext<'a> { // fields related to closure capture current_captures: Vec<CapturedItemWithoutTy>, + /// A stack that has an entry for each projection in the current capture. + /// + /// For example, in `a.b.c`, we capture the spans of `a`, `a.b`, and `a.b.c`. + /// We do that because sometimes we truncate projections (when a closure captures + /// both `a.b` and `a.b.c`), and we want to provide accurate spans in this case. + current_capture_span_stack: Vec<MirSpan>, current_closure: Option<ClosureId>, /// Stores the list of closure ids that need to be analyzed before this closure. See the /// comment on `InferenceContext::sort_closures` @@ -605,6 +611,11 @@ fn find_continuable( } } +enum ImplTraitReplacingMode { + ReturnPosition(FxHashSet<Ty>), + TypeAlias, +} + impl<'a> InferenceContext<'a> { fn new( db: &'a dyn HirDatabase, @@ -630,6 +641,7 @@ impl<'a> InferenceContext<'a> { breakables: Vec::new(), deferred_cast_checks: Vec::new(), current_captures: Vec::new(), + current_capture_span_stack: Vec::new(), current_closure: None, deferred_closures: FxHashMap::default(), closure_dependencies: FxHashMap::default(), @@ -826,13 +838,19 @@ impl<'a> InferenceContext<'a> { self.write_binding_ty(self_param, ty); } } - let mut params_and_ret_tys = Vec::new(); + let mut tait_candidates = FxHashSet::default(); for (ty, pat) in param_tys.zip(&*self.body.params) { let ty = self.insert_type_vars(ty); let ty = self.normalize_associated_types_in(ty); self.infer_top_pat(*pat, &ty); - params_and_ret_tys.push(ty); + if ty + .data(Interner) + .flags + .intersects(TypeFlags::HAS_TY_OPAQUE.union(TypeFlags::HAS_TY_INFER)) + { + tait_candidates.insert(ty); + } } let return_ty = &*data.ret_type; @@ -845,7 +863,12 @@ 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); - let result = self.insert_inference_vars_for_impl_trait(return_ty, fn_placeholders); + let mut mode = ImplTraitReplacingMode::ReturnPosition(FxHashSet::default()); + let result = + self.insert_inference_vars_for_impl_trait(return_ty, fn_placeholders, &mut mode); + if let ImplTraitReplacingMode::ReturnPosition(taits) = mode { + tait_candidates.extend(taits); + } let rpits = rpits.skip_binders(); for (id, _) in rpits.impl_traits.iter() { if let Entry::Vacant(e) = self.result.type_of_rpit.entry(id) { @@ -864,11 +887,23 @@ impl<'a> InferenceContext<'a> { // Functions might be defining usage sites of TAITs. // To define an TAITs, that TAIT must appear in the function's signatures. // So, it suffices to check for params and return types. - params_and_ret_tys.push(self.return_ty.clone()); - self.make_tait_coercion_table(params_and_ret_tys.iter()); + if self + .return_ty + .data(Interner) + .flags + .intersects(TypeFlags::HAS_TY_OPAQUE.union(TypeFlags::HAS_TY_INFER)) + { + tait_candidates.insert(self.return_ty.clone()); + } + self.make_tait_coercion_table(tait_candidates.iter()); } - fn insert_inference_vars_for_impl_trait<T>(&mut self, t: T, placeholders: Substitution) -> T + fn insert_inference_vars_for_impl_trait<T>( + &mut self, + t: T, + placeholders: Substitution, + mode: &mut ImplTraitReplacingMode, + ) -> T where T: crate::HasInterner<Interner = Interner> + crate::TypeFoldable<Interner>, { @@ -881,10 +916,31 @@ impl<'a> InferenceContext<'a> { }; let (impl_traits, idx) = match self.db.lookup_intern_impl_trait_id(opaque_ty_id.into()) { + // We don't replace opaque types from other kind with inference vars + // because `insert_inference_vars_for_impl_traits` for each kinds + // and unreplaced opaque types of other kind are resolved while + // inferencing because of `tait_coercion_table`. + // Moreover, calling `insert_inference_vars_for_impl_traits` with same + // `placeholders` for other kind may cause trouble because + // the substs for the bounds of each impl traits do not match ImplTraitId::ReturnTypeImplTrait(def, idx) => { + if matches!(mode, ImplTraitReplacingMode::TypeAlias) { + // RPITs don't have `tait_coercion_table`, so use inserted inference + // vars for them. + if let Some(ty) = self.result.type_of_rpit.get(idx) { + return ty.clone(); + } + return ty; + } (self.db.return_type_impl_traits(def), idx) } ImplTraitId::TypeAliasImplTrait(def, idx) => { + if let ImplTraitReplacingMode::ReturnPosition(taits) = mode { + // Gather TAITs while replacing RPITs because TAITs inside RPITs + // may not visited while replacing TAITs + taits.insert(ty.clone()); + return ty; + } (self.db.type_alias_impl_traits(def), idx) } _ => unreachable!(), @@ -893,16 +949,20 @@ impl<'a> InferenceContext<'a> { return ty; }; let bounds = (*impl_traits) - .map_ref(|rpits| rpits.impl_traits[idx].bounds.map_ref(|it| it.iter())); + .map_ref(|its| its.impl_traits[idx].bounds.map_ref(|it| it.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, &placeholders); + let predicate = bound.map(|it| it.cloned()); + let predicate = predicate.substitute(Interner, &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_impl_trait(var_predicate, placeholders.clone()); + let var_predicate = self.insert_inference_vars_for_impl_trait( + var_predicate, + placeholders.clone(), + mode, + ); self.push_obligation(var_predicate.cast(Interner)); } self.result.type_of_rpit.insert(idx, var.clone()); @@ -1039,7 +1099,11 @@ impl<'a> InferenceContext<'a> { self.db.lookup_intern_impl_trait_id(id.into()) { let subst = TyBuilder::placeholder_subst(self.db, alias_id); - let ty = self.insert_inference_vars_for_impl_trait(ty, subst); + let ty = self.insert_inference_vars_for_impl_trait( + ty, + subst, + &mut ImplTraitReplacingMode::TypeAlias, + ); Some((id, ty)) } else { None @@ -1436,7 +1500,8 @@ impl<'a> InferenceContext<'a> { let remaining = unresolved.map(|it| path.segments()[it..].len()).filter(|it| it > &0); let ty = match ty.kind(Interner) { TyKind::Alias(AliasTy::Projection(proj_ty)) => { - self.db.normalize_projection(proj_ty.clone(), self.table.trait_env.clone()) + let ty = self.table.normalize_projection_ty(proj_ty.clone()); + self.table.resolve_ty_shallow(&ty) } _ => ty, }; |