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.rs136
1 files changed, 95 insertions, 41 deletions
diff --git a/crates/hir-ty/src/infer.rs b/crates/hir-ty/src/infer.rs
index 0c41b92026..d90ca77b55 100644
--- a/crates/hir-ty/src/infer.rs
+++ b/crates/hir-ty/src/infer.rs
@@ -18,11 +18,12 @@ use std::{convert::identity, ops::Index};
use chalk_ir::{cast::Cast, DebruijnIndex, Mutability, Safety, Scalar, TypeFlags};
use either::Either;
+use hir_def::hir::LabelId;
use hir_def::{
body::Body,
builtin_type::{BuiltinInt, BuiltinType, BuiltinUint},
data::{ConstData, StaticData},
- expr::{BindingAnnotation, BindingId, ExprId, ExprOrPatId, PatId},
+ hir::{BindingAnnotation, BindingId, ExprId, ExprOrPatId, PatId},
lang_item::{LangItem, LangItemTarget},
layout::Integer,
path::{ModPath, Path},
@@ -32,15 +33,15 @@ 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};
use crate::{
db::HirDatabase, fold_tys, infer::coerce::CoerceMany, lower::ImplTraitLoweringMode,
- static_lifetime, to_assoc_type_id, AliasEq, AliasTy, DomainGoal, GenericArg, Goal, ImplTraitId,
- InEnvironment, Interner, ProjectionTy, RpitId, Substitution, TraitRef, Ty, TyBuilder, TyExt,
- TyKind,
+ static_lifetime, to_assoc_type_id, traits::FnTrait, AliasEq, AliasTy, ClosureId, DomainGoal,
+ GenericArg, Goal, ImplTraitId, InEnvironment, Interner, ProjectionTy, RpitId, Substitution,
+ TraitRef, Ty, TyBuilder, TyExt, TyKind,
};
// This lint has a false positive here. See the link below for details.
@@ -51,6 +52,8 @@ pub use coerce::could_coerce;
#[allow(unreachable_pub)]
pub use unify::could_unify;
+pub(crate) use self::closure::{CaptureKind, CapturedItem, CapturedItemWithoutTy};
+
pub(crate) mod unify;
mod path;
mod expr;
@@ -102,6 +105,8 @@ pub(crate) fn infer_query(db: &dyn HirDatabase, def: DefWithBodyId) -> Arc<Infer
ctx.infer_mut_body();
+ ctx.infer_closures();
+
Arc::new(ctx.resolve_all())
}
@@ -188,7 +193,7 @@ pub enum InferenceDiagnostic {
/// Contains the type the field resolves to
field_with_same_name: Option<Ty>,
},
- // FIXME: Make this proper
+ // FIXME: This should be emitted in body lowering
BreakOutsideOfLoop {
expr: ExprId,
is_break: bool,
@@ -311,6 +316,13 @@ pub enum AutoBorrow {
RawPtr(Mutability),
}
+impl AutoBorrow {
+ fn mutability(self) -> Mutability {
+ let (AutoBorrow::Ref(m) | AutoBorrow::RawPtr(m)) = self;
+ m
+ }
+}
+
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub enum PointerCast {
/// Go from a fn-item type to a fn-pointer type.
@@ -372,6 +384,9 @@ pub struct InferenceResult {
pub pat_adjustments: FxHashMap<PatId, Vec<Ty>>,
pub pat_binding_modes: FxHashMap<PatId, BindingMode>,
pub expr_adjustments: FxHashMap<ExprId, Vec<Adjustment>>,
+ pub(crate) closure_info: FxHashMap<ClosureId, (Vec<CapturedItem>, FnTrait)>,
+ // FIXME: remove this field
+ pub mutated_bindings_in_closure: FxHashSet<BindingId>,
}
impl InferenceResult {
@@ -408,6 +423,9 @@ impl InferenceResult {
_ => None,
})
}
+ pub(crate) fn closure_info(&self, closure: &ClosureId) -> &(Vec<CapturedItem>, FnTrait) {
+ self.closure_info.get(closure).unwrap()
+ }
}
impl Index<ExprId> for InferenceResult {
@@ -459,6 +477,14 @@ pub(crate) struct InferenceContext<'a> {
resume_yield_tys: Option<(Ty, Ty)>,
diverges: Diverges,
breakables: Vec<BreakableContext>,
+
+ // fields related to closure capture
+ current_captures: Vec<CapturedItemWithoutTy>,
+ 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`
+ closure_dependecies: FxHashMap<ClosureId, Vec<ClosureId>>,
+ deferred_closures: FxHashMap<ClosureId, Vec<(Ty, Ty, Vec<Ty>, ExprId)>>,
}
#[derive(Clone, Debug)]
@@ -468,7 +494,7 @@ struct BreakableContext {
/// The coercion target of the context.
coerce: Option<CoerceMany>,
/// The optional label of the context.
- label: Option<name::Name>,
+ label: Option<LabelId>,
kind: BreakableKind,
}
@@ -483,21 +509,21 @@ enum BreakableKind {
fn find_breakable<'c>(
ctxs: &'c mut [BreakableContext],
- label: Option<&name::Name>,
+ label: Option<LabelId>,
) -> Option<&'c mut BreakableContext> {
let mut ctxs = ctxs
.iter_mut()
.rev()
.take_while(|it| matches!(it.kind, BreakableKind::Block | BreakableKind::Loop));
match label {
- Some(_) => ctxs.find(|ctx| ctx.label.as_ref() == label),
+ Some(_) => ctxs.find(|ctx| ctx.label == label),
None => ctxs.find(|ctx| matches!(ctx.kind, BreakableKind::Loop)),
}
}
fn find_continuable<'c>(
ctxs: &'c mut [BreakableContext],
- label: Option<&name::Name>,
+ label: Option<LabelId>,
) -> Option<&'c mut BreakableContext> {
match label {
Some(_) => find_breakable(ctxs, label).filter(|it| matches!(it.kind, BreakableKind::Loop)),
@@ -526,6 +552,10 @@ impl<'a> InferenceContext<'a> {
resolver,
diverges: Diverges::Maybe,
breakables: Vec::new(),
+ current_captures: vec![],
+ current_closure: None,
+ deferred_closures: FxHashMap::default(),
+ closure_dependecies: FxHashMap::default(),
}
}
@@ -617,7 +647,7 @@ impl<'a> InferenceContext<'a> {
let ctx = crate::lower::TyLoweringContext::new(self.db, &self.resolver)
.with_impl_trait_mode(ImplTraitLoweringMode::Param);
let mut param_tys =
- data.params.iter().map(|(_, type_ref)| ctx.lower_ty(type_ref)).collect::<Vec<_>>();
+ data.params.iter().map(|type_ref| ctx.lower_ty(type_ref)).collect::<Vec<_>>();
// Check if function contains a va_list, if it does then we append it to the parameter types
// that are collected from the function data
if data.is_varargs() {
@@ -646,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
};
@@ -684,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),