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.rs | 141 |
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 } } |