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.rs202
1 files changed, 119 insertions, 83 deletions
diff --git a/crates/hir-ty/src/mir/borrowck.rs b/crates/hir-ty/src/mir/borrowck.rs
index fb0c0dee09..db16c94396 100644
--- a/crates/hir-ty/src/mir/borrowck.rs
+++ b/crates/hir-ty/src/mir/borrowck.rs
@@ -12,11 +12,14 @@ use stdx::never;
use triomphe::Arc;
use crate::{
- ClosureId, Interner, Substitution, Ty, TyExt, TypeFlags,
- db::{HirDatabase, InternedClosure},
+ TraitEnvironment,
+ db::{HirDatabase, InternedClosure, InternedClosureId},
display::DisplayTarget,
mir::OperandKind,
- utils::ClosureSubst,
+ next_solver::{
+ DbInterner, GenericArgs, SolverDefIds, Ty, TypingMode,
+ infer::{DbInternerInferExt, InferCtxt},
+ },
};
use super::{
@@ -33,45 +36,45 @@ pub enum MutabilityReason {
}
#[derive(Debug, Clone, PartialEq, Eq)]
-pub struct MovedOutOfRef {
- pub ty: Ty,
+pub struct MovedOutOfRef<'db> {
+ pub ty: Ty<'db>,
pub span: MirSpan,
}
#[derive(Debug, Clone, PartialEq, Eq)]
-pub struct PartiallyMoved {
- pub ty: Ty,
+pub struct PartiallyMoved<'db> {
+ pub ty: Ty<'db>,
pub span: MirSpan,
- pub local: LocalId,
+ pub local: LocalId<'db>,
}
#[derive(Debug, Clone, PartialEq, Eq)]
-pub struct BorrowRegion {
- pub local: LocalId,
+pub struct BorrowRegion<'db> {
+ pub local: LocalId<'db>,
pub kind: BorrowKind,
pub places: Vec<MirSpan>,
}
#[derive(Debug, Clone, PartialEq, Eq)]
-pub struct BorrowckResult {
- pub mir_body: Arc<MirBody>,
- pub mutability_of_locals: ArenaMap<LocalId, MutabilityReason>,
- pub moved_out_of_ref: Vec<MovedOutOfRef>,
- pub partially_moved: Vec<PartiallyMoved>,
- pub borrow_regions: Vec<BorrowRegion>,
+pub struct BorrowckResult<'db> {
+ pub mir_body: Arc<MirBody<'db>>,
+ pub mutability_of_locals: ArenaMap<LocalId<'db>, MutabilityReason>,
+ pub moved_out_of_ref: Vec<MovedOutOfRef<'db>>,
+ pub partially_moved: Vec<PartiallyMoved<'db>>,
+ pub borrow_regions: Vec<BorrowRegion<'db>>,
}
-fn all_mir_bodies(
- db: &dyn HirDatabase,
+fn all_mir_bodies<'db>(
+ db: &'db dyn HirDatabase,
def: DefWithBodyId,
- mut cb: impl FnMut(Arc<MirBody>),
-) -> Result<(), MirLowerError> {
- fn for_closure(
- db: &dyn HirDatabase,
- c: ClosureId,
- cb: &mut impl FnMut(Arc<MirBody>),
- ) -> Result<(), MirLowerError> {
- match db.mir_body_for_closure(c.into()) {
+ mut cb: impl FnMut(Arc<MirBody<'db>>),
+) -> Result<(), MirLowerError<'db>> {
+ fn for_closure<'db>(
+ db: &'db dyn HirDatabase,
+ c: InternedClosureId,
+ cb: &mut impl FnMut(Arc<MirBody<'db>>),
+ ) -> Result<(), MirLowerError<'db>> {
+ match db.mir_body_for_closure(c) {
Ok(body) => {
cb(body.clone());
body.closures.iter().try_for_each(|&it| for_closure(db, it, cb))
@@ -88,17 +91,24 @@ fn all_mir_bodies(
}
}
-pub fn borrowck_query(
- db: &dyn HirDatabase,
+pub fn borrowck_query<'db>(
+ db: &'db dyn HirDatabase,
def: DefWithBodyId,
-) -> Result<Arc<[BorrowckResult]>, MirLowerError> {
+) -> Result<Arc<[BorrowckResult<'db>]>, MirLowerError<'db>> {
let _p = tracing::info_span!("borrowck_query").entered();
+ let module = def.module(db);
+ let interner = DbInterner::new_with(db, Some(module.krate()), module.containing_block());
+ let env = db.trait_environment_for_body(def);
let mut res = vec![];
all_mir_bodies(db, def, |body| {
+ // FIXME(next-solver): Opaques.
+ let infcx = interner.infer_ctxt().build(TypingMode::Borrowck {
+ defining_opaque_types: SolverDefIds::new_from_iter(interner, []),
+ });
res.push(BorrowckResult {
- mutability_of_locals: mutability_of_locals(db, &body),
- moved_out_of_ref: moved_out_of_ref(db, &body),
- partially_moved: partially_moved(db, &body),
+ mutability_of_locals: mutability_of_locals(&infcx, &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,
});
@@ -106,43 +116,49 @@ pub fn borrowck_query(
Ok(res.into())
}
-fn make_fetch_closure_field(
- db: &dyn HirDatabase,
-) -> impl FnOnce(ClosureId, &Substitution, usize) -> Ty + '_ {
- |c: ClosureId, subst: &Substitution, f: usize| {
- let InternedClosure(def, _) = db.lookup_intern_closure(c.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(def, _) = db.lookup_intern_closure(c);
let infer = db.infer(def);
- let (captures, _) = infer.closure_info(&c);
- let parent_subst = ClosureSubst(subst).parent_subst();
- captures.get(f).expect("broken closure field").ty.clone().substitute(Interner, parent_subst)
+ let (captures, _) = infer.closure_info(c);
+ let parent_subst = subst.split_closure_args_untupled().parent_args;
+ let interner = DbInterner::new_with(db, None, None);
+ captures.get(f).expect("broken closure field").ty.instantiate(interner, parent_subst)
}
}
-fn moved_out_of_ref(db: &dyn HirDatabase, body: &MirBody) -> Vec<MovedOutOfRef> {
+fn moved_out_of_ref<'db>(
+ infcx: &InferCtxt<'db>,
+ env: &TraitEnvironment<'db>,
+ body: &MirBody<'db>,
+) -> Vec<MovedOutOfRef<'db>> {
+ let db = infcx.interner.db;
let mut result = vec![];
- let mut for_operand = |op: &Operand, span: MirSpan| match op.kind {
+ let mut for_operand = |op: &Operand<'db>, span: MirSpan| match op.kind {
OperandKind::Copy(p) | OperandKind::Move(p) => {
- let mut ty: Ty = body.locals[p.local].ty.clone();
+ let mut ty: Ty<'db> = body.locals[p.local].ty;
let mut is_dereference_of_ref = false;
for proj in p.projection.lookup(&body.projection_store) {
if *proj == ProjectionElem::Deref && ty.as_reference().is_some() {
is_dereference_of_ref = true;
}
ty = proj.projected_ty(
+ infcx,
ty,
- db,
make_fetch_closure_field(db),
body.owner.module(db).krate(),
);
}
if is_dereference_of_ref
- && !ty.clone().is_copy(db, body.owner)
- && !ty.data(Interner).flags.intersects(TypeFlags::HAS_ERROR)
+ && !infcx.type_is_copy_modulo_regions(env.env, ty)
+ && !ty.references_non_lt_error()
{
result.push(MovedOutOfRef { span: op.span.unwrap_or(span), ty });
}
}
- OperandKind::Constant(_) | OperandKind::Static(_) => (),
+ OperandKind::Constant { .. } | OperandKind::Static(_) => (),
};
for (_, block) in body.basic_blocks.iter() {
db.unwind_if_revision_cancelled();
@@ -213,26 +229,29 @@ fn moved_out_of_ref(db: &dyn HirDatabase, body: &MirBody) -> Vec<MovedOutOfRef>
result
}
-fn partially_moved(db: &dyn HirDatabase, body: &MirBody) -> Vec<PartiallyMoved> {
+fn partially_moved<'db>(
+ infcx: &InferCtxt<'db>,
+ env: &TraitEnvironment<'db>,
+ body: &MirBody<'db>,
+) -> Vec<PartiallyMoved<'db>> {
+ let db = infcx.interner.db;
let mut result = vec![];
- let mut for_operand = |op: &Operand, span: MirSpan| match op.kind {
+ let mut for_operand = |op: &Operand<'db>, span: MirSpan| match op.kind {
OperandKind::Copy(p) | OperandKind::Move(p) => {
- let mut ty: Ty = body.locals[p.local].ty.clone();
+ let mut ty: Ty<'db> = body.locals[p.local].ty;
for proj in p.projection.lookup(&body.projection_store) {
ty = proj.projected_ty(
+ infcx,
ty,
- db,
make_fetch_closure_field(db),
body.owner.module(db).krate(),
);
}
- if !ty.clone().is_copy(db, body.owner)
- && !ty.data(Interner).flags.intersects(TypeFlags::HAS_ERROR)
- {
+ if !infcx.type_is_copy_modulo_regions(env.env, ty) && !ty.references_non_lt_error() {
result.push(PartiallyMoved { span, ty, local: p.local });
}
}
- OperandKind::Constant(_) | OperandKind::Static(_) => (),
+ OperandKind::Constant { .. } | OperandKind::Static(_) => (),
};
for (_, block) in body.basic_blocks.iter() {
db.unwind_if_revision_cancelled();
@@ -303,7 +322,7 @@ fn partially_moved(db: &dyn HirDatabase, body: &MirBody) -> Vec<PartiallyMoved>
result
}
-fn borrow_regions(db: &dyn HirDatabase, body: &MirBody) -> Vec<BorrowRegion> {
+fn borrow_regions<'db>(db: &'db dyn HirDatabase, body: &MirBody<'db>) -> Vec<BorrowRegion<'db>> {
let mut borrows = FxHashMap::default();
for (_, block) in body.basic_blocks.iter() {
db.unwind_if_revision_cancelled();
@@ -311,7 +330,7 @@ fn borrow_regions(db: &dyn HirDatabase, body: &MirBody) -> Vec<BorrowRegion> {
if let StatementKind::Assign(_, Rvalue::Ref(kind, p)) = &statement.kind {
borrows
.entry(p.local)
- .and_modify(|it: &mut BorrowRegion| {
+ .and_modify(|it: &mut BorrowRegion<'db>| {
it.places.push(statement.span);
})
.or_insert_with(|| BorrowRegion {
@@ -353,9 +372,14 @@ enum ProjectionCase {
Indirect,
}
-fn place_case(db: &dyn HirDatabase, body: &MirBody, lvalue: &Place) -> ProjectionCase {
+fn place_case<'db>(
+ infcx: &InferCtxt<'db>,
+ body: &MirBody<'db>,
+ lvalue: &Place<'db>,
+) -> ProjectionCase {
+ let db = infcx.interner.db;
let mut is_part_of = false;
- let mut ty = body.locals[lvalue.local].ty.clone();
+ let mut ty = body.locals[lvalue.local].ty;
for proj in lvalue.projection.lookup(&body.projection_store).iter() {
match proj {
ProjectionElem::Deref if ty.as_adt().is_none() => return ProjectionCase::Indirect, // It's indirect in case of reference and raw
@@ -369,7 +393,12 @@ fn place_case(db: &dyn HirDatabase, body: &MirBody, lvalue: &Place) -> Projectio
}
ProjectionElem::OpaqueCast(_) => (),
}
- ty = proj.projected_ty(ty, db, make_fetch_closure_field(db), body.owner.module(db).krate());
+ ty = proj.projected_ty(
+ infcx,
+ ty,
+ make_fetch_closure_field(db),
+ body.owner.module(db).krate(),
+ );
}
if is_part_of { ProjectionCase::DirectPart } else { ProjectionCase::Direct }
}
@@ -377,18 +406,18 @@ fn place_case(db: &dyn HirDatabase, body: &MirBody, lvalue: &Place) -> Projectio
/// Returns a map from basic blocks to the set of locals that might be ever initialized before
/// the start of the block. Only `StorageDead` can remove something from this map, and we ignore
/// `Uninit` and `drop` and similar after initialization.
-fn ever_initialized_map(
- db: &dyn HirDatabase,
- body: &MirBody,
-) -> ArenaMap<BasicBlockId, ArenaMap<LocalId, bool>> {
- let mut result: ArenaMap<BasicBlockId, ArenaMap<LocalId, bool>> =
+fn ever_initialized_map<'db>(
+ db: &'db dyn HirDatabase,
+ body: &MirBody<'db>,
+) -> ArenaMap<BasicBlockId<'db>, ArenaMap<LocalId<'db>, bool>> {
+ let mut result: ArenaMap<BasicBlockId<'db>, ArenaMap<LocalId<'db>, bool>> =
body.basic_blocks.iter().map(|it| (it.0, ArenaMap::default())).collect();
- fn dfs(
- db: &dyn HirDatabase,
- body: &MirBody,
- l: LocalId,
- stack: &mut Vec<BasicBlockId>,
- result: &mut ArenaMap<BasicBlockId, ArenaMap<LocalId, bool>>,
+ fn dfs<'db>(
+ db: &'db dyn HirDatabase,
+ body: &MirBody<'db>,
+ l: LocalId<'db>,
+ stack: &mut Vec<BasicBlockId<'db>>,
+ result: &mut ArenaMap<BasicBlockId<'db>, ArenaMap<LocalId<'db>, bool>>,
) {
while let Some(b) = stack.pop() {
let mut is_ever_initialized = result[b][l]; // It must be filled, as we use it as mark for dfs
@@ -476,7 +505,11 @@ fn ever_initialized_map(
result
}
-fn push_mut_span(local: LocalId, span: MirSpan, result: &mut ArenaMap<LocalId, MutabilityReason>) {
+fn push_mut_span<'db>(
+ local: LocalId<'db>,
+ span: MirSpan,
+ result: &mut ArenaMap<LocalId<'db>, MutabilityReason>,
+) {
match &mut result[local] {
MutabilityReason::Mut { spans } => spans.push(span),
it @ (MutabilityReason::Not | MutabilityReason::Unused) => {
@@ -485,23 +518,27 @@ fn push_mut_span(local: LocalId, span: MirSpan, result: &mut ArenaMap<LocalId, M
};
}
-fn record_usage(local: LocalId, result: &mut ArenaMap<LocalId, MutabilityReason>) {
+fn record_usage<'db>(local: LocalId<'db>, result: &mut ArenaMap<LocalId<'db>, MutabilityReason>) {
if let it @ MutabilityReason::Unused = &mut result[local] {
*it = MutabilityReason::Not;
};
}
-fn record_usage_for_operand(arg: &Operand, result: &mut ArenaMap<LocalId, MutabilityReason>) {
+fn record_usage_for_operand<'db>(
+ arg: &Operand<'db>,
+ result: &mut ArenaMap<LocalId<'db>, MutabilityReason>,
+) {
if let OperandKind::Copy(p) | OperandKind::Move(p) = arg.kind {
record_usage(p.local, result);
}
}
-fn mutability_of_locals(
- db: &dyn HirDatabase,
- body: &MirBody,
-) -> ArenaMap<LocalId, MutabilityReason> {
- let mut result: ArenaMap<LocalId, MutabilityReason> =
+fn mutability_of_locals<'db>(
+ infcx: &InferCtxt<'db>,
+ body: &MirBody<'db>,
+) -> ArenaMap<LocalId<'db>, MutabilityReason> {
+ let db = infcx.interner.db;
+ let mut result: ArenaMap<LocalId<'db>, MutabilityReason> =
body.locals.iter().map(|it| (it.0, MutabilityReason::Unused)).collect();
let ever_init_maps = ever_initialized_map(db, body);
@@ -510,7 +547,7 @@ fn mutability_of_locals(
for statement in &block.statements {
match &statement.kind {
StatementKind::Assign(place, value) => {
- match place_case(db, body, place) {
+ match place_case(infcx, body, place) {
ProjectionCase::Direct => {
if ever_init_map.get(place.local).copied().unwrap_or_default() {
push_mut_span(place.local, statement.span, &mut result);
@@ -559,10 +596,9 @@ fn mutability_of_locals(
},
p,
) = value
+ && place_case(infcx, body, p) != ProjectionCase::Indirect
{
- if place_case(db, body, p) != ProjectionCase::Indirect {
- push_mut_span(p.local, statement.span, &mut result);
- }
+ push_mut_span(p.local, statement.span, &mut result);
}
}
StatementKind::FakeRead(p) => {