Unnamed repository; edit this file 'description' to name the repository.
Diffstat (limited to 'crates/hir-ty/src/mir/borrowck.rs')
-rw-r--r--crates/hir-ty/src/mir/borrowck.rs141
1 files changed, 81 insertions, 60 deletions
diff --git a/crates/hir-ty/src/mir/borrowck.rs b/crates/hir-ty/src/mir/borrowck.rs
index 3ff2db15aa..17715d3fcd 100644
--- a/crates/hir-ty/src/mir/borrowck.rs
+++ b/crates/hir-ty/src/mir/borrowck.rs
@@ -8,17 +8,16 @@ use std::iter;
use hir_def::{DefWithBodyId, ExpressionStoreOwnerId, HasModule};
use la_arena::ArenaMap;
use rustc_hash::FxHashMap;
-use rustc_type_ir::inherent::GenericArgs as _;
use stdx::never;
use triomphe::Arc;
use crate::{
- InferenceResult,
- db::{HirDatabase, InternedClosure, InternedClosureId},
+ closure_analysis::ProjectionKind as HirProjectionKind,
+ db::{HirDatabase, InternedClosureId},
display::DisplayTarget,
mir::OperandKind,
next_solver::{
- DbInterner, GenericArgs, ParamEnv, StoredTy, Ty, TypingMode,
+ DbInterner, ParamEnv, StoredTy, Ty, TypingMode,
infer::{DbInternerInferExt, InferCtxt},
},
};
@@ -68,25 +67,49 @@ pub struct BorrowckResult {
fn all_mir_bodies(
db: &dyn HirDatabase,
def: DefWithBodyId,
- mut cb: impl FnMut(Arc<MirBody>),
-) -> Result<(), MirLowerError> {
+ mut cb: impl FnMut(Arc<MirBody>) -> BorrowckResult,
+ mut merge_from_closures: impl FnMut(&mut BorrowckResult, &BorrowckResult),
+) -> Result<Arc<[BorrowckResult]>, MirLowerError> {
fn for_closure(
db: &dyn HirDatabase,
c: InternedClosureId,
- cb: &mut impl FnMut(Arc<MirBody>),
+ results: &mut Vec<BorrowckResult>,
+ cb: &mut impl FnMut(Arc<MirBody>) -> BorrowckResult,
+ merge_from_closures: &mut impl FnMut(&mut BorrowckResult, &BorrowckResult),
) -> Result<(), MirLowerError> {
match db.mir_body_for_closure(c) {
Ok(body) => {
- cb(body.clone());
- body.closures.iter().try_for_each(|&it| for_closure(db, it, cb))
+ let parent_index = results.len();
+ results.push(cb(body.clone()));
+ body.closures
+ .iter()
+ .try_for_each(|&it| for_closure(db, it, results, cb, merge_from_closures))?;
+ merge(results, merge_from_closures, parent_index);
+ Ok(())
}
Err(e) => Err(e),
}
}
+
+ fn merge(
+ results: &mut [BorrowckResult],
+ merge: &mut impl FnMut(&mut BorrowckResult, &BorrowckResult),
+ parent_index: usize,
+ ) {
+ let (parent_and_before, children) = results.split_at_mut(parent_index + 1);
+ let parent = &mut parent_and_before[parent_and_before.len() - 1];
+ children.iter().for_each(|child| merge(parent, child));
+ }
+
+ let mut results = Vec::new();
match db.mir_body(def) {
Ok(body) => {
- cb(body.clone());
- body.closures.iter().try_for_each(|&it| for_closure(db, it, &mut cb))
+ results.push(cb(body.clone()));
+ body.closures.iter().try_for_each(|&it| {
+ for_closure(db, it, &mut results, &mut cb, &mut merge_from_closures)
+ })?;
+ merge(&mut results, &mut merge_from_closures, 0);
+ Ok(results.into())
}
Err(e) => Err(e),
}
@@ -100,34 +123,50 @@ pub fn borrowck_query(
let module = def.module(db);
let interner = DbInterner::new_with(db, module.krate(db));
let env = db.trait_environment(ExpressionStoreOwnerId::from(def));
- let mut res = vec![];
// This calculates opaques defining scope which is a bit costly therefore is put outside `all_mir_bodies()`.
let typing_mode = TypingMode::borrowck(interner, def.into());
- all_mir_bodies(db, def, |body| {
- // FIXME(next-solver): Opaques.
- let infcx = interner.infer_ctxt().build(typing_mode);
- res.push(BorrowckResult {
- mutability_of_locals: mutability_of_locals(&infcx, env, &body),
- moved_out_of_ref: moved_out_of_ref(&infcx, env, &body),
- partially_moved: partially_moved(&infcx, env, &body),
- borrow_regions: borrow_regions(db, &body),
- mir_body: body,
- });
- })?;
- Ok(res.into())
-}
-
-fn make_fetch_closure_field<'db>(
- db: &'db dyn HirDatabase,
-) -> impl FnOnce(InternedClosureId, GenericArgs<'db>, usize) -> Ty<'db> + use<'db> {
- |c: InternedClosureId, subst: GenericArgs<'db>, f: usize| {
- let InternedClosure(owner, _) = db.lookup_intern_closure(c);
- let interner = DbInterner::new_no_crate(db);
- let infer = InferenceResult::of(db, owner);
- let (captures, _) = infer.closure_info(c);
- let parent_subst = subst.as_closure().parent_args();
- captures.get(f).expect("broken closure field").ty.get().instantiate(interner, parent_subst)
- }
+ let res = all_mir_bodies(
+ db,
+ def,
+ |body| {
+ // FIXME(next-solver): Opaques.
+ let infcx = interner.infer_ctxt().build(typing_mode);
+ BorrowckResult {
+ mutability_of_locals: mutability_of_locals(&infcx, env, &body),
+ moved_out_of_ref: moved_out_of_ref(&infcx, env, &body),
+ partially_moved: partially_moved(&infcx, env, &body),
+ borrow_regions: borrow_regions(db, &body),
+ mir_body: body,
+ }
+ },
+ |parent, child| {
+ for (upvar, child_locals) in &child.mir_body.upvar_locals {
+ let Some(&parent_local) = parent.mir_body.binding_locals.get(*upvar) else {
+ continue;
+ };
+ for (child_local, capture_place) in child_locals {
+ if !capture_place
+ .projections
+ .iter()
+ .any(|proj| matches!(proj.kind, HirProjectionKind::Deref))
+ {
+ let parent_mol = &mut parent.mutability_of_locals[parent_local];
+ match (&*parent_mol, &child.mutability_of_locals[*child_local]) {
+ (MutabilityReason::Mut { .. }, _) => {}
+ (_, MutabilityReason::Mut { .. }) => {
+ // FIXME: Fix the child spans.
+ *parent_mol = MutabilityReason::Mut { spans: Vec::new() }
+ }
+ (MutabilityReason::Not, _) => {}
+ (_, MutabilityReason::Not) => *parent_mol = MutabilityReason::Not,
+ (MutabilityReason::Unused, MutabilityReason::Unused) => {}
+ }
+ }
+ }
+ }
+ },
+ )?;
+ Ok(res)
}
fn moved_out_of_ref<'db>(
@@ -145,13 +184,7 @@ fn moved_out_of_ref<'db>(
if *proj == ProjectionElem::Deref && ty.as_reference().is_some() {
is_dereference_of_ref = true;
}
- ty = proj.projected_ty(
- infcx,
- env,
- ty,
- make_fetch_closure_field(db),
- body.owner.module(db).krate(db),
- );
+ ty = proj.projected_ty(infcx, env, ty, body.owner.module(db).krate(db));
}
if is_dereference_of_ref
&& !infcx.type_is_copy_modulo_regions(env, ty)
@@ -160,7 +193,7 @@ fn moved_out_of_ref<'db>(
result.push(MovedOutOfRef { span: op.span.unwrap_or(span), ty: ty.store() });
}
}
- OperandKind::Constant { .. } | OperandKind::Static(_) => (),
+ OperandKind::Constant { .. } | OperandKind::Static(_) | OperandKind::Allocation { .. } => {}
};
for (_, block) in body.basic_blocks.iter() {
db.unwind_if_revision_cancelled();
@@ -242,19 +275,13 @@ fn partially_moved<'db>(
OperandKind::Copy(p) | OperandKind::Move(p) => {
let mut ty: Ty<'db> = body.locals[p.local].ty.as_ref();
for proj in p.projection.lookup(&body.projection_store) {
- ty = proj.projected_ty(
- infcx,
- env,
- ty,
- make_fetch_closure_field(db),
- body.owner.module(db).krate(db),
- );
+ ty = proj.projected_ty(infcx, env, ty, body.owner.module(db).krate(db));
}
if !infcx.type_is_copy_modulo_regions(env, ty) && !ty.references_non_lt_error() {
result.push(PartiallyMoved { span, ty: ty.store(), local: p.local });
}
}
- OperandKind::Constant { .. } | OperandKind::Static(_) => (),
+ OperandKind::Constant { .. } | OperandKind::Static(_) | OperandKind::Allocation { .. } => {}
};
for (_, block) in body.basic_blocks.iter() {
db.unwind_if_revision_cancelled();
@@ -397,13 +424,7 @@ fn place_case<'db>(
}
ProjectionElem::OpaqueCast(_) => (),
}
- ty = proj.projected_ty(
- infcx,
- env,
- ty,
- make_fetch_closure_field(db),
- body.owner.module(db).krate(db),
- );
+ ty = proj.projected_ty(infcx, env, ty, body.owner.module(db).krate(db));
}
if is_part_of { ProjectionCase::DirectPart } else { ProjectionCase::Direct }
}