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.rs113
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,
};