mirror of
https://github.com/rust-lang/rust-analyzer
synced 2024-11-14 17:07:26 +00:00
Auto merge of #16669 - ShoyuVanilla:merge-borrow-kind-unique, r=Veykril
Merge `BorrowKind::Unique` into `BorrowKind::Mut` Resolves #15170
This commit is contained in:
commit
e1983d2b90
7 changed files with 68 additions and 83 deletions
|
@ -23,7 +23,7 @@ use stdx::never;
|
|||
use crate::{
|
||||
db::{HirDatabase, InternedClosure},
|
||||
from_placeholder_idx, make_binders,
|
||||
mir::{BorrowKind, MirSpan, ProjectionElem},
|
||||
mir::{BorrowKind, MirSpan, MutBorrowKind, ProjectionElem},
|
||||
static_lifetime, to_chalk_trait_id,
|
||||
traits::FnTrait,
|
||||
utils::{self, generics, Generics},
|
||||
|
@ -142,9 +142,13 @@ impl HirPlace {
|
|||
mut current_capture: CaptureKind,
|
||||
len: usize,
|
||||
) -> CaptureKind {
|
||||
if let CaptureKind::ByRef(BorrowKind::Mut { .. }) = current_capture {
|
||||
if let CaptureKind::ByRef(BorrowKind::Mut {
|
||||
kind: MutBorrowKind::Default | MutBorrowKind::TwoPhasedBorrow,
|
||||
}) = current_capture
|
||||
{
|
||||
if self.projections[len..].iter().any(|it| *it == ProjectionElem::Deref) {
|
||||
current_capture = CaptureKind::ByRef(BorrowKind::Unique);
|
||||
current_capture =
|
||||
CaptureKind::ByRef(BorrowKind::Mut { kind: MutBorrowKind::ClosureCapture });
|
||||
}
|
||||
}
|
||||
current_capture
|
||||
|
@ -377,7 +381,7 @@ impl InferenceContext<'_> {
|
|||
if let Some(place) = self.place_of_expr(expr) {
|
||||
self.add_capture(
|
||||
place,
|
||||
CaptureKind::ByRef(BorrowKind::Mut { allow_two_phase_borrow: false }),
|
||||
CaptureKind::ByRef(BorrowKind::Mut { kind: MutBorrowKind::Default }),
|
||||
expr.into(),
|
||||
);
|
||||
}
|
||||
|
@ -426,9 +430,7 @@ impl InferenceContext<'_> {
|
|||
|
||||
fn ref_capture_with_adjusts(&mut self, m: Mutability, tgt_expr: ExprId, rest: &[Adjustment]) {
|
||||
let capture_kind = match m {
|
||||
Mutability::Mut => {
|
||||
CaptureKind::ByRef(BorrowKind::Mut { allow_two_phase_borrow: false })
|
||||
}
|
||||
Mutability::Mut => CaptureKind::ByRef(BorrowKind::Mut { kind: MutBorrowKind::Default }),
|
||||
Mutability::Not => CaptureKind::ByRef(BorrowKind::Shared),
|
||||
};
|
||||
if let Some(place) = self.place_of_expr_without_adjust(tgt_expr) {
|
||||
|
@ -648,7 +650,7 @@ impl InferenceContext<'_> {
|
|||
self.walk_pat_inner(
|
||||
pat,
|
||||
&mut update_result,
|
||||
BorrowKind::Mut { allow_two_phase_borrow: false },
|
||||
BorrowKind::Mut { kind: MutBorrowKind::Default },
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -699,7 +701,7 @@ impl InferenceContext<'_> {
|
|||
},
|
||||
}
|
||||
if self.result.pat_adjustments.get(&p).map_or(false, |it| !it.is_empty()) {
|
||||
for_mut = BorrowKind::Unique;
|
||||
for_mut = BorrowKind::Mut { kind: MutBorrowKind::ClosureCapture };
|
||||
}
|
||||
self.body.walk_pats_shallow(p, |p| self.walk_pat_inner(p, update_result, for_mut));
|
||||
}
|
||||
|
@ -880,7 +882,7 @@ impl InferenceContext<'_> {
|
|||
}
|
||||
BindingMode::Ref(Mutability::Not) => BorrowKind::Shared,
|
||||
BindingMode::Ref(Mutability::Mut) => {
|
||||
BorrowKind::Mut { allow_two_phase_borrow: false }
|
||||
BorrowKind::Mut { kind: MutBorrowKind::Default }
|
||||
}
|
||||
};
|
||||
self.add_capture(place, CaptureKind::ByRef(capture_kind), pat.into());
|
||||
|
@ -930,9 +932,7 @@ impl InferenceContext<'_> {
|
|||
r = cmp::min(
|
||||
r,
|
||||
match &it.kind {
|
||||
CaptureKind::ByRef(BorrowKind::Unique | BorrowKind::Mut { .. }) => {
|
||||
FnTrait::FnMut
|
||||
}
|
||||
CaptureKind::ByRef(BorrowKind::Mut { .. }) => FnTrait::FnMut,
|
||||
CaptureKind::ByRef(BorrowKind::Shallow | BorrowKind::Shared) => FnTrait::Fn,
|
||||
CaptureKind::ByValue => FnTrait::FnOnce,
|
||||
},
|
||||
|
@ -949,8 +949,12 @@ impl InferenceContext<'_> {
|
|||
};
|
||||
self.consume_expr(*body);
|
||||
for item in &self.current_captures {
|
||||
if matches!(item.kind, CaptureKind::ByRef(BorrowKind::Mut { .. }))
|
||||
&& !item.place.projections.contains(&ProjectionElem::Deref)
|
||||
if matches!(
|
||||
item.kind,
|
||||
CaptureKind::ByRef(BorrowKind::Mut {
|
||||
kind: MutBorrowKind::Default | MutBorrowKind::TwoPhasedBorrow
|
||||
})
|
||||
) && !item.place.projections.contains(&ProjectionElem::Deref)
|
||||
{
|
||||
// FIXME: remove the `mutated_bindings_in_closure` completely and add proper fake reads in
|
||||
// MIR. I didn't do that due duplicate diagnostics.
|
||||
|
|
|
@ -659,66 +659,33 @@ pub enum BorrowKind {
|
|||
/// We can also report errors with this kind of borrow differently.
|
||||
Shallow,
|
||||
|
||||
/// Data must be immutable but not aliasable. This kind of borrow
|
||||
/// cannot currently be expressed by the user and is used only in
|
||||
/// implicit closure bindings. It is needed when the closure is
|
||||
/// borrowing or mutating a mutable referent, e.g.:
|
||||
/// ```
|
||||
/// let mut z = 3;
|
||||
/// let x: &mut isize = &mut z;
|
||||
/// let y = || *x += 5;
|
||||
/// ```
|
||||
/// If we were to try to translate this closure into a more explicit
|
||||
/// form, we'd encounter an error with the code as written:
|
||||
/// ```compile_fail,E0594
|
||||
/// struct Env<'a> { x: &'a &'a mut isize }
|
||||
/// let mut z = 3;
|
||||
/// let x: &mut isize = &mut z;
|
||||
/// let y = (&mut Env { x: &x }, fn_ptr); // Closure is pair of env and fn
|
||||
/// fn fn_ptr(env: &mut Env) { **env.x += 5; }
|
||||
/// ```
|
||||
/// This is then illegal because you cannot mutate an `&mut` found
|
||||
/// in an aliasable location. To solve, you'd have to translate with
|
||||
/// an `&mut` borrow:
|
||||
/// ```compile_fail,E0596
|
||||
/// struct Env<'a> { x: &'a mut &'a mut isize }
|
||||
/// let mut z = 3;
|
||||
/// let x: &mut isize = &mut z;
|
||||
/// let y = (&mut Env { x: &mut x }, fn_ptr); // changed from &x to &mut x
|
||||
/// fn fn_ptr(env: &mut Env) { **env.x += 5; }
|
||||
/// ```
|
||||
/// Now the assignment to `**env.x` is legal, but creating a
|
||||
/// mutable pointer to `x` is not because `x` is not mutable. We
|
||||
/// could fix this by declaring `x` as `let mut x`. This is ok in
|
||||
/// user code, if awkward, but extra weird for closures, since the
|
||||
/// borrow is hidden.
|
||||
///
|
||||
/// So we introduce a "unique imm" borrow -- the referent is
|
||||
/// immutable, but not aliasable. This solves the problem. For
|
||||
/// simplicity, we don't give users the way to express this
|
||||
/// borrow, it's just used when translating closures.
|
||||
Unique,
|
||||
|
||||
/// Data is mutable and not aliasable.
|
||||
Mut {
|
||||
/// `true` if this borrow arose from method-call auto-ref
|
||||
/// (i.e., `adjustment::Adjust::Borrow`).
|
||||
allow_two_phase_borrow: bool,
|
||||
},
|
||||
Mut { kind: MutBorrowKind },
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Eq, Clone, Copy, PartialOrd, Ord)]
|
||||
pub enum MutBorrowKind {
|
||||
Default,
|
||||
/// This borrow arose from method-call auto-ref
|
||||
/// (i.e., adjustment::Adjust::Borrow).
|
||||
TwoPhasedBorrow,
|
||||
/// Data must be immutable but not aliasable. This kind of borrow cannot currently
|
||||
/// be expressed by the user and is used only in implicit closure bindings.
|
||||
ClosureCapture,
|
||||
}
|
||||
|
||||
impl BorrowKind {
|
||||
fn from_hir(m: hir_def::type_ref::Mutability) -> Self {
|
||||
match m {
|
||||
hir_def::type_ref::Mutability::Shared => BorrowKind::Shared,
|
||||
hir_def::type_ref::Mutability::Mut => BorrowKind::Mut { allow_two_phase_borrow: false },
|
||||
hir_def::type_ref::Mutability::Mut => BorrowKind::Mut { kind: MutBorrowKind::Default },
|
||||
}
|
||||
}
|
||||
|
||||
fn from_chalk(m: Mutability) -> Self {
|
||||
match m {
|
||||
Mutability::Not => BorrowKind::Shared,
|
||||
Mutability::Mut => BorrowKind::Mut { allow_two_phase_borrow: false },
|
||||
Mutability::Mut => BorrowKind::Mut { kind: MutBorrowKind::Default },
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -19,8 +19,8 @@ use crate::{
|
|||
};
|
||||
|
||||
use super::{
|
||||
BasicBlockId, BorrowKind, LocalId, MirBody, MirLowerError, MirSpan, Place, ProjectionElem,
|
||||
Rvalue, StatementKind, TerminatorKind,
|
||||
BasicBlockId, BorrowKind, LocalId, MirBody, MirLowerError, MirSpan, MutBorrowKind, Place,
|
||||
ProjectionElem, Rvalue, StatementKind, TerminatorKind,
|
||||
};
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
|
@ -540,7 +540,13 @@ fn mutability_of_locals(
|
|||
}
|
||||
Rvalue::ShallowInitBox(_, _) | Rvalue::ShallowInitBoxWithAlloc(_) => (),
|
||||
}
|
||||
if let Rvalue::Ref(BorrowKind::Mut { .. }, p) = value {
|
||||
if let Rvalue::Ref(
|
||||
BorrowKind::Mut {
|
||||
kind: MutBorrowKind::Default | MutBorrowKind::TwoPhasedBorrow,
|
||||
},
|
||||
p,
|
||||
) = value
|
||||
{
|
||||
if place_case(db, body, p) != ProjectionCase::Indirect {
|
||||
push_mut_span(p.local, statement.span, &mut result);
|
||||
}
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
//! MIR lowering for places
|
||||
|
||||
use crate::mir::MutBorrowKind;
|
||||
|
||||
use super::*;
|
||||
use hir_def::FunctionId;
|
||||
use hir_expand::name;
|
||||
|
@ -328,7 +330,7 @@ impl MirLowerCtx<'_> {
|
|||
Mutability::Mut,
|
||||
LangItem::DerefMut,
|
||||
name![deref_mut],
|
||||
BorrowKind::Mut { allow_two_phase_borrow: false },
|
||||
BorrowKind::Mut { kind: MutBorrowKind::Default },
|
||||
)
|
||||
};
|
||||
let ty_ref = TyKind::Ref(chalk_mut, static_lifetime(), source_ty.clone()).intern(Interner);
|
||||
|
|
|
@ -3,12 +3,15 @@
|
|||
use hir_def::{hir::LiteralOrConst, resolver::HasResolver, AssocItemId};
|
||||
|
||||
use crate::{
|
||||
mir::lower::{
|
||||
BasicBlockId, BinOp, BindingId, BorrowKind, Either, Expr, FieldId, Idx, Interner,
|
||||
MemoryMap, MirLowerCtx, MirLowerError, MirSpan, Mutability, Operand, Pat, PatId, Place,
|
||||
PlaceElem, ProjectionElem, RecordFieldPat, ResolveValueResult, Result, Rvalue,
|
||||
Substitution, SwitchTargets, TerminatorKind, TupleFieldId, TupleId, TyBuilder, TyKind,
|
||||
ValueNs, VariantData, VariantId,
|
||||
mir::{
|
||||
lower::{
|
||||
BasicBlockId, BinOp, BindingId, BorrowKind, Either, Expr, FieldId, Idx, Interner,
|
||||
MemoryMap, MirLowerCtx, MirLowerError, MirSpan, Mutability, Operand, Pat, PatId, Place,
|
||||
PlaceElem, ProjectionElem, RecordFieldPat, ResolveValueResult, Result, Rvalue,
|
||||
Substitution, SwitchTargets, TerminatorKind, TupleFieldId, TupleId, TyBuilder, TyKind,
|
||||
ValueNs, VariantData, VariantId,
|
||||
},
|
||||
MutBorrowKind,
|
||||
},
|
||||
BindingMode,
|
||||
};
|
||||
|
@ -450,7 +453,7 @@ impl MirLowerCtx<'_> {
|
|||
BindingMode::Move => Operand::Copy(cond_place).into(),
|
||||
BindingMode::Ref(Mutability::Not) => Rvalue::Ref(BorrowKind::Shared, cond_place),
|
||||
BindingMode::Ref(Mutability::Mut) => {
|
||||
Rvalue::Ref(BorrowKind::Mut { allow_two_phase_borrow: false }, cond_place)
|
||||
Rvalue::Ref(BorrowKind::Mut { kind: MutBorrowKind::Default }, cond_place)
|
||||
}
|
||||
},
|
||||
span,
|
||||
|
|
|
@ -18,7 +18,8 @@ use crate::{
|
|||
};
|
||||
|
||||
use super::{
|
||||
AggregateKind, BasicBlockId, BorrowKind, LocalId, MirBody, Operand, Place, Rvalue, UnOp,
|
||||
AggregateKind, BasicBlockId, BorrowKind, LocalId, MirBody, MutBorrowKind, Operand, Place,
|
||||
Rvalue, UnOp,
|
||||
};
|
||||
|
||||
macro_rules! w {
|
||||
|
@ -366,8 +367,10 @@ impl<'a> MirPrettyCtx<'a> {
|
|||
match r {
|
||||
BorrowKind::Shared => w!(self, "&"),
|
||||
BorrowKind::Shallow => w!(self, "&shallow "),
|
||||
BorrowKind::Unique => w!(self, "&uniq "),
|
||||
BorrowKind::Mut { .. } => w!(self, "&mut "),
|
||||
BorrowKind::Mut { kind: MutBorrowKind::ClosureCapture } => w!(self, "&uniq "),
|
||||
BorrowKind::Mut {
|
||||
kind: MutBorrowKind::Default | MutBorrowKind::TwoPhasedBorrow,
|
||||
} => w!(self, "&mut "),
|
||||
}
|
||||
self.place(p);
|
||||
}
|
||||
|
|
|
@ -68,7 +68,7 @@ use hir_ty::{
|
|||
known_const_to_ast,
|
||||
layout::{Layout as TyLayout, RustcEnumVariantIdx, RustcFieldIdx, TagEncoding},
|
||||
method_resolution::{self, TyFingerprint},
|
||||
mir::interpret_mir,
|
||||
mir::{interpret_mir, MutBorrowKind},
|
||||
primitive::UintTy,
|
||||
traits::FnTrait,
|
||||
AliasTy, CallableDefId, CallableSig, Canonical, CanonicalVarKinds, Cast, ClosureId, GenericArg,
|
||||
|
@ -3754,12 +3754,12 @@ impl ClosureCapture {
|
|||
hir_ty::CaptureKind::ByRef(
|
||||
hir_ty::mir::BorrowKind::Shallow | hir_ty::mir::BorrowKind::Shared,
|
||||
) => CaptureKind::SharedRef,
|
||||
hir_ty::CaptureKind::ByRef(hir_ty::mir::BorrowKind::Unique) => {
|
||||
CaptureKind::UniqueSharedRef
|
||||
}
|
||||
hir_ty::CaptureKind::ByRef(hir_ty::mir::BorrowKind::Mut { .. }) => {
|
||||
CaptureKind::MutableRef
|
||||
}
|
||||
hir_ty::CaptureKind::ByRef(hir_ty::mir::BorrowKind::Mut {
|
||||
kind: MutBorrowKind::ClosureCapture,
|
||||
}) => CaptureKind::UniqueSharedRef,
|
||||
hir_ty::CaptureKind::ByRef(hir_ty::mir::BorrowKind::Mut {
|
||||
kind: MutBorrowKind::Default | MutBorrowKind::TwoPhasedBorrow,
|
||||
}) => CaptureKind::MutableRef,
|
||||
hir_ty::CaptureKind::ByValue => CaptureKind::Move,
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue