2021-03-10 14:23:37 -08:00
|
|
|
use crate::hir::place::{
|
|
|
|
Place as HirPlace, PlaceBase as HirPlaceBase, ProjectionKind as HirProjectionKind,
|
|
|
|
};
|
2021-05-21 21:01:27 +02:00
|
|
|
use crate::{mir, ty};
|
2021-03-10 12:55:00 -08:00
|
|
|
|
|
|
|
use rustc_data_structures::fx::{FxHashMap, FxIndexMap};
|
|
|
|
use rustc_hir as hir;
|
|
|
|
use rustc_hir::def_id::{DefId, LocalDefId};
|
|
|
|
use rustc_span::Span;
|
|
|
|
|
2021-03-10 14:23:37 -08:00
|
|
|
use super::{Ty, TyCtxt};
|
|
|
|
|
|
|
|
use self::BorrowKind::*;
|
2021-03-10 12:55:00 -08:00
|
|
|
|
2021-05-21 21:01:27 +02:00
|
|
|
// Captures are represented using fields inside a structure.
|
|
|
|
// This represents accessing self in the closure structure
|
|
|
|
pub const CAPTURE_STRUCT_LOCAL: mir::Local = mir::Local::from_u32(1);
|
|
|
|
|
2021-03-10 12:55:00 -08:00
|
|
|
#[derive(
|
|
|
|
Clone,
|
|
|
|
Copy,
|
|
|
|
Debug,
|
|
|
|
PartialEq,
|
|
|
|
Eq,
|
|
|
|
Hash,
|
|
|
|
TyEncodable,
|
|
|
|
TyDecodable,
|
|
|
|
TypeFoldable,
|
|
|
|
HashStable
|
|
|
|
)]
|
|
|
|
pub struct UpvarPath {
|
|
|
|
pub hir_id: hir::HirId,
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Upvars do not get their own `NodeId`. Instead, we use the pair of
|
|
|
|
/// the original var ID (that is, the root variable that is referenced
|
|
|
|
/// by the upvar) and the ID of the closure expression.
|
|
|
|
#[derive(Clone, Copy, PartialEq, Eq, Hash, TyEncodable, TyDecodable, TypeFoldable, HashStable)]
|
|
|
|
pub struct UpvarId {
|
|
|
|
pub var_path: UpvarPath,
|
|
|
|
pub closure_expr_id: LocalDefId,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl UpvarId {
|
|
|
|
pub fn new(var_hir_id: hir::HirId, closure_def_id: LocalDefId) -> UpvarId {
|
|
|
|
UpvarId { var_path: UpvarPath { hir_id: var_hir_id }, closure_expr_id: closure_def_id }
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Information describing the capture of an upvar. This is computed
|
|
|
|
/// during `typeck`, specifically by `regionck`.
|
|
|
|
#[derive(PartialEq, Clone, Debug, Copy, TyEncodable, TyDecodable, TypeFoldable, HashStable)]
|
|
|
|
pub enum UpvarCapture<'tcx> {
|
|
|
|
/// Upvar is captured by value. This is always true when the
|
|
|
|
/// closure is labeled `move`, but can also be true in other cases
|
|
|
|
/// depending on inference.
|
|
|
|
///
|
|
|
|
/// If the upvar was inferred to be captured by value (e.g. `move`
|
|
|
|
/// was not used), then the `Span` points to a usage that
|
|
|
|
/// required it. There may be more than one such usage
|
|
|
|
/// (e.g. `|| { a; a; }`), in which case we pick an
|
|
|
|
/// arbitrary one.
|
|
|
|
ByValue(Option<Span>),
|
|
|
|
|
|
|
|
/// Upvar is captured by reference.
|
|
|
|
ByRef(UpvarBorrow<'tcx>),
|
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(PartialEq, Clone, Copy, TyEncodable, TyDecodable, TypeFoldable, HashStable)]
|
|
|
|
pub struct UpvarBorrow<'tcx> {
|
|
|
|
/// The kind of borrow: by-ref upvars have access to shared
|
|
|
|
/// immutable borrows, which are not part of the normal language
|
|
|
|
/// syntax.
|
|
|
|
pub kind: BorrowKind,
|
|
|
|
|
|
|
|
/// Region of the resulting reference.
|
|
|
|
pub region: ty::Region<'tcx>,
|
|
|
|
}
|
|
|
|
|
|
|
|
pub type UpvarListMap = FxHashMap<DefId, FxIndexMap<hir::HirId, UpvarId>>;
|
|
|
|
pub type UpvarCaptureMap<'tcx> = FxHashMap<UpvarId, UpvarCapture<'tcx>>;
|
|
|
|
|
|
|
|
/// Given the closure DefId this map provides a map of root variables to minimum
|
|
|
|
/// set of `CapturedPlace`s that need to be tracked to support all captures of that closure.
|
|
|
|
pub type MinCaptureInformationMap<'tcx> = FxHashMap<DefId, RootVariableMinCaptureList<'tcx>>;
|
|
|
|
|
|
|
|
/// Part of `MinCaptureInformationMap`; Maps a root variable to the list of `CapturedPlace`.
|
|
|
|
/// Used to track the minimum set of `Place`s that need to be captured to support all
|
|
|
|
/// Places captured by the closure starting at a given root variable.
|
|
|
|
///
|
|
|
|
/// This provides a convenient and quick way of checking if a variable being used within
|
|
|
|
/// a closure is a capture of a local variable.
|
|
|
|
pub type RootVariableMinCaptureList<'tcx> = FxIndexMap<hir::HirId, MinCaptureList<'tcx>>;
|
|
|
|
|
|
|
|
/// Part of `MinCaptureInformationMap`; List of `CapturePlace`s.
|
|
|
|
pub type MinCaptureList<'tcx> = Vec<CapturedPlace<'tcx>>;
|
|
|
|
|
|
|
|
/// Represents the various closure traits in the language. This
|
|
|
|
/// will determine the type of the environment (`self`, in the
|
|
|
|
/// desugaring) argument that the closure expects.
|
|
|
|
///
|
|
|
|
/// You can get the environment type of a closure using
|
|
|
|
/// `tcx.closure_env_ty()`.
|
|
|
|
#[derive(Clone, Copy, PartialOrd, Ord, PartialEq, Eq, Hash, Debug, TyEncodable, TyDecodable)]
|
|
|
|
#[derive(HashStable)]
|
|
|
|
pub enum ClosureKind {
|
|
|
|
// Warning: Ordering is significant here! The ordering is chosen
|
|
|
|
// because the trait Fn is a subtrait of FnMut and so in turn, and
|
|
|
|
// hence we order it so that Fn < FnMut < FnOnce.
|
|
|
|
Fn,
|
|
|
|
FnMut,
|
|
|
|
FnOnce,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<'tcx> ClosureKind {
|
|
|
|
// This is the initial value used when doing upvar inference.
|
|
|
|
pub const LATTICE_BOTTOM: ClosureKind = ClosureKind::Fn;
|
|
|
|
|
|
|
|
/// Returns `true` if a type that impls this closure kind
|
|
|
|
/// must also implement `other`.
|
|
|
|
pub fn extends(self, other: ty::ClosureKind) -> bool {
|
|
|
|
matches!(
|
|
|
|
(self, other),
|
|
|
|
(ClosureKind::Fn, ClosureKind::Fn)
|
|
|
|
| (ClosureKind::Fn, ClosureKind::FnMut)
|
|
|
|
| (ClosureKind::Fn, ClosureKind::FnOnce)
|
|
|
|
| (ClosureKind::FnMut, ClosureKind::FnMut)
|
|
|
|
| (ClosureKind::FnMut, ClosureKind::FnOnce)
|
|
|
|
| (ClosureKind::FnOnce, ClosureKind::FnOnce)
|
|
|
|
)
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Returns the representative scalar type for this closure kind.
|
|
|
|
/// See `TyS::to_opt_closure_kind` for more details.
|
|
|
|
pub fn to_ty(self, tcx: TyCtxt<'tcx>) -> Ty<'tcx> {
|
|
|
|
match self {
|
|
|
|
ty::ClosureKind::Fn => tcx.types.i8,
|
|
|
|
ty::ClosureKind::FnMut => tcx.types.i16,
|
|
|
|
ty::ClosureKind::FnOnce => tcx.types.i32,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// A composite describing a `Place` that is captured by a closure.
|
|
|
|
#[derive(PartialEq, Clone, Debug, TyEncodable, TyDecodable, TypeFoldable, HashStable)]
|
|
|
|
pub struct CapturedPlace<'tcx> {
|
|
|
|
/// The `Place` that is captured.
|
|
|
|
pub place: HirPlace<'tcx>,
|
|
|
|
|
|
|
|
/// `CaptureKind` and expression(s) that resulted in such capture of `place`.
|
|
|
|
pub info: CaptureInfo<'tcx>,
|
|
|
|
|
|
|
|
/// Represents if `place` can be mutated or not.
|
|
|
|
pub mutability: hir::Mutability,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl CapturedPlace<'tcx> {
|
2021-03-17 02:51:27 -04:00
|
|
|
pub fn to_string(&self, tcx: TyCtxt<'tcx>) -> String {
|
|
|
|
place_to_string_for_capture(tcx, &self.place)
|
|
|
|
}
|
|
|
|
|
2021-05-05 23:50:44 +08:00
|
|
|
/// Returns mangled names of captured upvars. Here are some examples:
|
|
|
|
/// - `_captured_val__name__field`
|
|
|
|
/// - `_captured_ref__name__field`
|
|
|
|
///
|
|
|
|
/// The purpose is to use those names in debuginfo. They should be human-understandable.
|
|
|
|
/// Without the names, the end users may get confused when the debuggers just print some
|
|
|
|
/// pointers in closures or generators.
|
|
|
|
pub fn to_mangled_name(&self, tcx: TyCtxt<'tcx>) -> String {
|
|
|
|
let prefix = match self.info.capture_kind {
|
|
|
|
ty::UpvarCapture::ByValue(_) => "_captured_val__",
|
|
|
|
ty::UpvarCapture::ByRef(_) => "_captured_ref__",
|
|
|
|
};
|
|
|
|
|
|
|
|
let hir_id = match self.place.base {
|
|
|
|
HirPlaceBase::Upvar(upvar_id) => upvar_id.var_path.hir_id,
|
|
|
|
base => bug!("Expected an upvar, found {:?}", base),
|
|
|
|
};
|
|
|
|
let name = tcx.hir().name(hir_id);
|
|
|
|
|
|
|
|
let mut ty = self.place.base_ty;
|
|
|
|
let mut fields = String::new();
|
|
|
|
for proj in self.place.projections.iter() {
|
|
|
|
match proj.kind {
|
|
|
|
HirProjectionKind::Field(idx, variant) => match ty.kind() {
|
|
|
|
ty::Tuple(_) => fields = format!("{}__{}", fields, idx),
|
|
|
|
ty::Adt(def, ..) => {
|
|
|
|
fields = format!(
|
|
|
|
"{}__{}",
|
|
|
|
fields,
|
|
|
|
def.variants[variant].fields[idx as usize].ident.name.as_str(),
|
|
|
|
);
|
|
|
|
}
|
|
|
|
ty => {
|
|
|
|
bug!("Unexpected type {:?} for `Field` projection", ty)
|
|
|
|
}
|
|
|
|
},
|
|
|
|
|
|
|
|
// Ignore derefs for now, as they are likely caused by
|
|
|
|
// autoderefs that don't appear in the original code.
|
|
|
|
HirProjectionKind::Deref => {}
|
|
|
|
proj => bug!("Unexpected projection {:?} in captured place", proj),
|
|
|
|
}
|
|
|
|
ty = proj.ty;
|
|
|
|
}
|
|
|
|
|
|
|
|
prefix.to_owned() + &name.to_string() + &fields
|
|
|
|
}
|
|
|
|
|
2021-03-10 12:55:00 -08:00
|
|
|
/// Returns the hir-id of the root variable for the captured place.
|
|
|
|
/// e.g., if `a.b.c` was captured, would return the hir-id for `a`.
|
|
|
|
pub fn get_root_variable(&self) -> hir::HirId {
|
|
|
|
match self.place.base {
|
|
|
|
HirPlaceBase::Upvar(upvar_id) => upvar_id.var_path.hir_id,
|
|
|
|
base => bug!("Expected upvar, found={:?}", base),
|
|
|
|
}
|
|
|
|
}
|
2020-12-23 15:38:22 -05:00
|
|
|
|
2021-04-19 15:57:08 +03:00
|
|
|
/// Returns the `LocalDefId` of the closure that captured this Place
|
2020-12-23 15:38:22 -05:00
|
|
|
pub fn get_closure_local_def_id(&self) -> LocalDefId {
|
|
|
|
match self.place.base {
|
|
|
|
HirPlaceBase::Upvar(upvar_id) => upvar_id.closure_expr_id,
|
|
|
|
base => bug!("expected upvar, found={:?}", base),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-03-17 02:51:27 -04:00
|
|
|
/// Return span pointing to use that resulted in selecting the captured path
|
|
|
|
pub fn get_path_span(&self, tcx: TyCtxt<'tcx>) -> Span {
|
|
|
|
if let Some(path_expr_id) = self.info.path_expr_id {
|
|
|
|
tcx.hir().span(path_expr_id)
|
|
|
|
} else if let Some(capture_kind_expr_id) = self.info.capture_kind_expr_id {
|
|
|
|
tcx.hir().span(capture_kind_expr_id)
|
|
|
|
} else {
|
|
|
|
// Fallback on upvars mentioned if neither path or capture expr id is captured
|
|
|
|
|
|
|
|
// Safe to unwrap since we know this place is captured by the closure, therefore the closure must have upvars.
|
|
|
|
tcx.upvars_mentioned(self.get_closure_local_def_id()).unwrap()
|
|
|
|
[&self.get_root_variable()]
|
|
|
|
.span
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-12-23 15:38:22 -05:00
|
|
|
/// Return span pointing to use that resulted in selecting the current capture kind
|
|
|
|
pub fn get_capture_kind_span(&self, tcx: TyCtxt<'tcx>) -> Span {
|
|
|
|
if let Some(capture_kind_expr_id) = self.info.capture_kind_expr_id {
|
|
|
|
tcx.hir().span(capture_kind_expr_id)
|
|
|
|
} else if let Some(path_expr_id) = self.info.path_expr_id {
|
|
|
|
tcx.hir().span(path_expr_id)
|
|
|
|
} else {
|
|
|
|
// Fallback on upvars mentioned if neither path or capture expr id is captured
|
|
|
|
|
|
|
|
// Safe to unwrap since we know this place is captured by the closure, therefore the closure must have upvars.
|
|
|
|
tcx.upvars_mentioned(self.get_closure_local_def_id()).unwrap()
|
|
|
|
[&self.get_root_variable()]
|
|
|
|
.span
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Return true if the `proj_possible_ancestor` represents an ancestor path
|
|
|
|
/// to `proj_capture` or `proj_possible_ancestor` is same as `proj_capture`,
|
|
|
|
/// assuming they both start off of the same root variable.
|
|
|
|
///
|
|
|
|
/// **Note:** It's the caller's responsibility to ensure that both lists of projections
|
|
|
|
/// start off of the same root variable.
|
|
|
|
///
|
|
|
|
/// Eg: 1. `foo.x` which is represented using `projections=[Field(x)]` is an ancestor of
|
|
|
|
/// `foo.x.y` which is represented using `projections=[Field(x), Field(y)]`.
|
|
|
|
/// Note both `foo.x` and `foo.x.y` start off of the same root variable `foo`.
|
|
|
|
/// 2. Since we only look at the projections here function will return `bar.x` as an a valid
|
|
|
|
/// ancestor of `foo.x.y`. It's the caller's responsibility to ensure that both projections
|
|
|
|
/// list are being applied to the same root variable.
|
|
|
|
pub fn is_ancestor_or_same_capture(
|
|
|
|
proj_possible_ancestor: &[HirProjectionKind],
|
|
|
|
proj_capture: &[HirProjectionKind],
|
|
|
|
) -> bool {
|
|
|
|
// We want to make sure `is_ancestor_or_same_capture("x.0.0", "x.0")` to return false.
|
|
|
|
// Therefore we can't just check if all projections are same in the zipped iterator below.
|
|
|
|
if proj_possible_ancestor.len() > proj_capture.len() {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
proj_possible_ancestor.iter().zip(proj_capture).all(|(a, b)| a == b)
|
2021-03-10 12:55:00 -08:00
|
|
|
}
|
2021-03-10 14:23:37 -08:00
|
|
|
|
|
|
|
/// Part of `MinCaptureInformationMap`; describes the capture kind (&, &mut, move)
|
|
|
|
/// for a particular capture as well as identifying the part of the source code
|
|
|
|
/// that triggered this capture to occur.
|
|
|
|
#[derive(PartialEq, Clone, Debug, Copy, TyEncodable, TyDecodable, TypeFoldable, HashStable)]
|
|
|
|
pub struct CaptureInfo<'tcx> {
|
|
|
|
/// Expr Id pointing to use that resulted in selecting the current capture kind
|
|
|
|
///
|
|
|
|
/// Eg:
|
|
|
|
/// ```rust,no_run
|
|
|
|
/// let mut t = (0,1);
|
|
|
|
///
|
|
|
|
/// let c = || {
|
|
|
|
/// println!("{}",t); // L1
|
|
|
|
/// t.1 = 4; // L2
|
|
|
|
/// };
|
|
|
|
/// ```
|
|
|
|
/// `capture_kind_expr_id` will point to the use on L2 and `path_expr_id` will point to the
|
|
|
|
/// use on L1.
|
|
|
|
///
|
|
|
|
/// If the user doesn't enable feature `capture_disjoint_fields` (RFC 2229) then, it is
|
|
|
|
/// possible that we don't see the use of a particular place resulting in capture_kind_expr_id being
|
|
|
|
/// None. In such case we fallback on uvpars_mentioned for span.
|
|
|
|
///
|
|
|
|
/// Eg:
|
|
|
|
/// ```rust,no_run
|
|
|
|
/// let x = 5;
|
|
|
|
///
|
|
|
|
/// let c = || {
|
|
|
|
/// let _ = x
|
|
|
|
/// };
|
|
|
|
/// ```
|
|
|
|
///
|
|
|
|
/// In this example, if `capture_disjoint_fields` is **not** set, then x will be captured,
|
|
|
|
/// but we won't see it being used during capture analysis, since it's essentially a discard.
|
|
|
|
pub capture_kind_expr_id: Option<hir::HirId>,
|
|
|
|
/// Expr Id pointing to use that resulted the corresponding place being captured
|
|
|
|
///
|
|
|
|
/// See `capture_kind_expr_id` for example.
|
|
|
|
///
|
|
|
|
pub path_expr_id: Option<hir::HirId>,
|
|
|
|
|
|
|
|
/// Capture mode that was selected
|
|
|
|
pub capture_kind: UpvarCapture<'tcx>,
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn place_to_string_for_capture(tcx: TyCtxt<'tcx>, place: &HirPlace<'tcx>) -> String {
|
|
|
|
let name = match place.base {
|
|
|
|
HirPlaceBase::Upvar(upvar_id) => tcx.hir().name(upvar_id.var_path.hir_id).to_string(),
|
|
|
|
_ => bug!("Capture_information should only contain upvars"),
|
|
|
|
};
|
|
|
|
let mut curr_string = name;
|
|
|
|
|
|
|
|
for (i, proj) in place.projections.iter().enumerate() {
|
|
|
|
match proj.kind {
|
|
|
|
HirProjectionKind::Deref => {
|
|
|
|
curr_string = format!("*{}", curr_string);
|
|
|
|
}
|
|
|
|
HirProjectionKind::Field(idx, variant) => match place.ty_before_projection(i).kind() {
|
|
|
|
ty::Adt(def, ..) => {
|
|
|
|
curr_string = format!(
|
|
|
|
"{}.{}",
|
|
|
|
curr_string,
|
|
|
|
def.variants[variant].fields[idx as usize].ident.name.as_str()
|
|
|
|
);
|
|
|
|
}
|
|
|
|
ty::Tuple(_) => {
|
|
|
|
curr_string = format!("{}.{}", curr_string, idx);
|
|
|
|
}
|
|
|
|
_ => {
|
|
|
|
bug!(
|
|
|
|
"Field projection applied to a type other than Adt or Tuple: {:?}.",
|
|
|
|
place.ty_before_projection(i).kind()
|
|
|
|
)
|
|
|
|
}
|
|
|
|
},
|
|
|
|
proj => bug!("{:?} unexpected because it isn't captured", proj),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
curr_string.to_string()
|
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(Clone, PartialEq, Debug, TyEncodable, TyDecodable, TypeFoldable, Copy, HashStable)]
|
|
|
|
pub enum BorrowKind {
|
|
|
|
/// Data must be immutable and is aliasable.
|
|
|
|
ImmBorrow,
|
|
|
|
|
|
|
|
/// 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 x: &mut isize = ...;
|
|
|
|
/// 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:
|
|
|
|
///
|
|
|
|
/// ```
|
|
|
|
/// struct Env { x: & &mut isize }
|
|
|
|
/// let x: &mut isize = ...;
|
|
|
|
/// let y = (&mut Env { &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 a `&mut` found
|
|
|
|
/// in an aliasable location. To solve, you'd have to translate with
|
|
|
|
/// an `&mut` borrow:
|
|
|
|
///
|
|
|
|
/// ```
|
|
|
|
/// struct Env { x: & &mut isize }
|
|
|
|
/// let x: &mut isize = ...;
|
|
|
|
/// let y = (&mut Env { &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.
|
|
|
|
UniqueImmBorrow,
|
|
|
|
|
|
|
|
/// Data is mutable and not aliasable.
|
|
|
|
MutBorrow,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl BorrowKind {
|
|
|
|
pub fn from_mutbl(m: hir::Mutability) -> BorrowKind {
|
|
|
|
match m {
|
|
|
|
hir::Mutability::Mut => MutBorrow,
|
|
|
|
hir::Mutability::Not => ImmBorrow,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Returns a mutability `m` such that an `&m T` pointer could be used to obtain this borrow
|
|
|
|
/// kind. Because borrow kinds are richer than mutabilities, we sometimes have to pick a
|
|
|
|
/// mutability that is stronger than necessary so that it at least *would permit* the borrow in
|
|
|
|
/// question.
|
|
|
|
pub fn to_mutbl_lossy(self) -> hir::Mutability {
|
|
|
|
match self {
|
|
|
|
MutBorrow => hir::Mutability::Mut,
|
|
|
|
ImmBorrow => hir::Mutability::Not,
|
|
|
|
|
|
|
|
// We have no type corresponding to a unique imm borrow, so
|
|
|
|
// use `&mut`. It gives all the capabilities of an `&uniq`
|
|
|
|
// and hence is a safe "over approximation".
|
|
|
|
UniqueImmBorrow => hir::Mutability::Mut,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|