Generate the right MIR for by use closures
This commit is contained in:
parent
81a926cc2a
commit
57cb498989
10 changed files with 65 additions and 47 deletions
|
@ -1086,7 +1086,7 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx
|
||||||
);
|
);
|
||||||
|
|
||||||
match capture_info.capture_kind {
|
match capture_info.capture_kind {
|
||||||
ty::UpvarCapture::ByValue => {
|
ty::UpvarCapture::ByValue | ty::UpvarCapture::ByUse => {
|
||||||
self.consume_or_copy(&place_with_id, place_with_id.hir_id);
|
self.consume_or_copy(&place_with_id, place_with_id.hir_id);
|
||||||
}
|
}
|
||||||
ty::UpvarCapture::ByRef(upvar_borrow) => {
|
ty::UpvarCapture::ByRef(upvar_borrow) => {
|
||||||
|
|
|
@ -670,9 +670,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
origin = updated.1;
|
origin = updated.1;
|
||||||
|
|
||||||
let (place, capture_kind) = match capture_clause {
|
let (place, capture_kind) = match capture_clause {
|
||||||
hir::CaptureBy::Value { .. } | hir::CaptureBy::Use { .. } => {
|
hir::CaptureBy::Value { .. } => adjust_for_move_closure(place, capture_kind),
|
||||||
adjust_for_move_closure(place, capture_kind)
|
hir::CaptureBy::Use { .. } => adjust_for_use_closure(place, capture_kind),
|
||||||
}
|
|
||||||
hir::CaptureBy::Ref => adjust_for_non_move_closure(place, capture_kind),
|
hir::CaptureBy::Ref => adjust_for_non_move_closure(place, capture_kind),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1307,7 +1306,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
for captured_place in root_var_min_capture_list.iter() {
|
for captured_place in root_var_min_capture_list.iter() {
|
||||||
match captured_place.info.capture_kind {
|
match captured_place.info.capture_kind {
|
||||||
// Only care about captures that are moved into the closure
|
// Only care about captures that are moved into the closure
|
||||||
ty::UpvarCapture::ByValue => {
|
ty::UpvarCapture::ByValue | ty::UpvarCapture::ByUse => {
|
||||||
projections_list.push(captured_place.place.projections.as_slice());
|
projections_list.push(captured_place.place.projections.as_slice());
|
||||||
diagnostics_info.insert(UpvarMigrationInfo::CapturingPrecise {
|
diagnostics_info.insert(UpvarMigrationInfo::CapturingPrecise {
|
||||||
source_expr: captured_place.info.path_expr_id,
|
source_expr: captured_place.info.path_expr_id,
|
||||||
|
@ -1931,7 +1930,7 @@ fn apply_capture_kind_on_capture_ty<'tcx>(
|
||||||
region: ty::Region<'tcx>,
|
region: ty::Region<'tcx>,
|
||||||
) -> Ty<'tcx> {
|
) -> Ty<'tcx> {
|
||||||
match capture_kind {
|
match capture_kind {
|
||||||
ty::UpvarCapture::ByValue => ty,
|
ty::UpvarCapture::ByValue | ty::UpvarCapture::ByUse => ty,
|
||||||
ty::UpvarCapture::ByRef(kind) => Ty::new_ref(tcx, region, ty, kind.to_mutbl_lossy()),
|
ty::UpvarCapture::ByRef(kind) => Ty::new_ref(tcx, region, ty, kind.to_mutbl_lossy()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2168,6 +2167,20 @@ fn adjust_for_move_closure(
|
||||||
(place, ty::UpvarCapture::ByValue)
|
(place, ty::UpvarCapture::ByValue)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Truncate deref of any reference.
|
||||||
|
fn adjust_for_use_closure(
|
||||||
|
mut place: Place<'_>,
|
||||||
|
mut kind: ty::UpvarCapture,
|
||||||
|
) -> (Place<'_>, ty::UpvarCapture) {
|
||||||
|
let first_deref = place.projections.iter().position(|proj| proj.kind == ProjectionKind::Deref);
|
||||||
|
|
||||||
|
if let Some(idx) = first_deref {
|
||||||
|
truncate_place_to_len_and_update_capture_kind(&mut place, &mut kind, idx);
|
||||||
|
}
|
||||||
|
|
||||||
|
(place, ty::UpvarCapture::ByUse)
|
||||||
|
}
|
||||||
|
|
||||||
/// Adjust closure capture just that if taking ownership of data, only move data
|
/// Adjust closure capture just that if taking ownership of data, only move data
|
||||||
/// from enclosing stack frame.
|
/// from enclosing stack frame.
|
||||||
fn adjust_for_non_move_closure(
|
fn adjust_for_non_move_closure(
|
||||||
|
@ -2178,7 +2191,7 @@ fn adjust_for_non_move_closure(
|
||||||
place.projections.iter().position(|proj| proj.kind == ProjectionKind::Deref);
|
place.projections.iter().position(|proj| proj.kind == ProjectionKind::Deref);
|
||||||
|
|
||||||
match kind {
|
match kind {
|
||||||
ty::UpvarCapture::ByValue => {
|
ty::UpvarCapture::ByValue | ty::UpvarCapture::ByUse => {
|
||||||
if let Some(idx) = contains_deref {
|
if let Some(idx) = contains_deref {
|
||||||
truncate_place_to_len_and_update_capture_kind(&mut place, &mut kind, idx);
|
truncate_place_to_len_and_update_capture_kind(&mut place, &mut kind, idx);
|
||||||
}
|
}
|
||||||
|
@ -2223,6 +2236,7 @@ fn construct_capture_kind_reason_string<'tcx>(
|
||||||
|
|
||||||
let capture_kind_str = match capture_info.capture_kind {
|
let capture_kind_str = match capture_info.capture_kind {
|
||||||
ty::UpvarCapture::ByValue => "ByValue".into(),
|
ty::UpvarCapture::ByValue => "ByValue".into(),
|
||||||
|
ty::UpvarCapture::ByUse => "ByUse".into(),
|
||||||
ty::UpvarCapture::ByRef(kind) => format!("{kind:?}"),
|
ty::UpvarCapture::ByRef(kind) => format!("{kind:?}"),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -2244,6 +2258,7 @@ fn construct_capture_info_string<'tcx>(
|
||||||
|
|
||||||
let capture_kind_str = match capture_info.capture_kind {
|
let capture_kind_str = match capture_info.capture_kind {
|
||||||
ty::UpvarCapture::ByValue => "ByValue".into(),
|
ty::UpvarCapture::ByValue => "ByValue".into(),
|
||||||
|
ty::UpvarCapture::ByUse => "ByUse".into(),
|
||||||
ty::UpvarCapture::ByRef(kind) => format!("{kind:?}"),
|
ty::UpvarCapture::ByRef(kind) => format!("{kind:?}"),
|
||||||
};
|
};
|
||||||
format!("{place_str} -> {capture_kind_str}")
|
format!("{place_str} -> {capture_kind_str}")
|
||||||
|
@ -2339,8 +2354,11 @@ fn determine_capture_info(
|
||||||
// expressions.
|
// expressions.
|
||||||
let eq_capture_kind = match (capture_info_a.capture_kind, capture_info_b.capture_kind) {
|
let eq_capture_kind = match (capture_info_a.capture_kind, capture_info_b.capture_kind) {
|
||||||
(ty::UpvarCapture::ByValue, ty::UpvarCapture::ByValue) => true,
|
(ty::UpvarCapture::ByValue, ty::UpvarCapture::ByValue) => true,
|
||||||
|
(ty::UpvarCapture::ByUse, ty::UpvarCapture::ByUse) => true,
|
||||||
(ty::UpvarCapture::ByRef(ref_a), ty::UpvarCapture::ByRef(ref_b)) => ref_a == ref_b,
|
(ty::UpvarCapture::ByRef(ref_a), ty::UpvarCapture::ByRef(ref_b)) => ref_a == ref_b,
|
||||||
(ty::UpvarCapture::ByValue, _) | (ty::UpvarCapture::ByRef(_), _) => false,
|
(ty::UpvarCapture::ByValue, _)
|
||||||
|
| (ty::UpvarCapture::ByUse, _)
|
||||||
|
| (ty::UpvarCapture::ByRef(_), _) => false,
|
||||||
};
|
};
|
||||||
|
|
||||||
if eq_capture_kind {
|
if eq_capture_kind {
|
||||||
|
@ -2350,8 +2368,10 @@ fn determine_capture_info(
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// We select the CaptureKind which ranks higher based the following priority order:
|
// We select the CaptureKind which ranks higher based the following priority order:
|
||||||
// ByValue > MutBorrow > UniqueImmBorrow > ImmBorrow
|
// (ByUse | ByValue) > MutBorrow > UniqueImmBorrow > ImmBorrow
|
||||||
match (capture_info_a.capture_kind, capture_info_b.capture_kind) {
|
match (capture_info_a.capture_kind, capture_info_b.capture_kind) {
|
||||||
|
(ty::UpvarCapture::ByUse, _) => capture_info_a,
|
||||||
|
(_, ty::UpvarCapture::ByUse) => capture_info_b,
|
||||||
(ty::UpvarCapture::ByValue, _) => capture_info_a,
|
(ty::UpvarCapture::ByValue, _) => capture_info_a,
|
||||||
(_, ty::UpvarCapture::ByValue) => capture_info_b,
|
(_, ty::UpvarCapture::ByValue) => capture_info_b,
|
||||||
(ty::UpvarCapture::ByRef(ref_a), ty::UpvarCapture::ByRef(ref_b)) => {
|
(ty::UpvarCapture::ByRef(ref_a), ty::UpvarCapture::ByRef(ref_b)) => {
|
||||||
|
@ -2405,7 +2425,7 @@ fn truncate_place_to_len_and_update_capture_kind<'tcx>(
|
||||||
}
|
}
|
||||||
|
|
||||||
ty::UpvarCapture::ByRef(..) => {}
|
ty::UpvarCapture::ByRef(..) => {}
|
||||||
ty::UpvarCapture::ByValue => {}
|
ty::UpvarCapture::ByValue | ty::UpvarCapture::ByUse => {}
|
||||||
}
|
}
|
||||||
|
|
||||||
place.projections.truncate(len);
|
place.projections.truncate(len);
|
||||||
|
|
|
@ -51,6 +51,9 @@ pub enum UpvarCapture {
|
||||||
/// depending on inference.
|
/// depending on inference.
|
||||||
ByValue,
|
ByValue,
|
||||||
|
|
||||||
|
/// Upvar is captured by use. This is true when the closure is labeled `use`.
|
||||||
|
ByUse,
|
||||||
|
|
||||||
/// Upvar is captured by reference.
|
/// Upvar is captured by reference.
|
||||||
ByRef(BorrowKind),
|
ByRef(BorrowKind),
|
||||||
}
|
}
|
||||||
|
@ -178,7 +181,7 @@ impl<'tcx> CapturedPlace<'tcx> {
|
||||||
|
|
||||||
pub fn is_by_ref(&self) -> bool {
|
pub fn is_by_ref(&self) -> bool {
|
||||||
match self.info.capture_kind {
|
match self.info.capture_kind {
|
||||||
ty::UpvarCapture::ByValue => false,
|
ty::UpvarCapture::ByValue | ty::UpvarCapture::ByUse => false,
|
||||||
ty::UpvarCapture::ByRef(..) => true,
|
ty::UpvarCapture::ByRef(..) => true,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -214,7 +217,7 @@ impl<'tcx> TyCtxt<'tcx> {
|
||||||
pub fn closure_captures(self, def_id: LocalDefId) -> &'tcx [&'tcx ty::CapturedPlace<'tcx>] {
|
pub fn closure_captures(self, def_id: LocalDefId) -> &'tcx [&'tcx ty::CapturedPlace<'tcx>] {
|
||||||
if !self.is_closure_like(def_id.to_def_id()) {
|
if !self.is_closure_like(def_id.to_def_id()) {
|
||||||
return &[];
|
return &[];
|
||||||
};
|
}
|
||||||
self.closure_typeinfo(def_id).captures
|
self.closure_typeinfo(def_id).captures
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -37,7 +37,7 @@ pub(crate) fn closure_saved_names_of_captured_variables<'tcx>(
|
||||||
.map(|captured_place| {
|
.map(|captured_place| {
|
||||||
let name = captured_place.to_symbol();
|
let name = captured_place.to_symbol();
|
||||||
match captured_place.info.capture_kind {
|
match captured_place.info.capture_kind {
|
||||||
ty::UpvarCapture::ByValue => name,
|
ty::UpvarCapture::ByValue | ty::UpvarCapture::ByUse => name,
|
||||||
ty::UpvarCapture::ByRef(..) => Symbol::intern(&format!("_ref__{name}")),
|
ty::UpvarCapture::ByRef(..) => Symbol::intern(&format!("_ref__{name}")),
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
@ -871,7 +871,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||||
let mut projs = closure_env_projs.clone();
|
let mut projs = closure_env_projs.clone();
|
||||||
projs.push(ProjectionElem::Field(FieldIdx::new(i), ty));
|
projs.push(ProjectionElem::Field(FieldIdx::new(i), ty));
|
||||||
match capture {
|
match capture {
|
||||||
ty::UpvarCapture::ByValue => {}
|
ty::UpvarCapture::ByValue | ty::UpvarCapture::ByUse => {}
|
||||||
ty::UpvarCapture::ByRef(..) => {
|
ty::UpvarCapture::ByRef(..) => {
|
||||||
projs.push(ProjectionElem::Deref);
|
projs.push(ProjectionElem::Deref);
|
||||||
}
|
}
|
||||||
|
|
|
@ -652,7 +652,7 @@ impl<'tcx> ThirBuildCx<'tcx> {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
hir::ExprKind::Closure { .. } => {
|
hir::ExprKind::Closure(hir::Closure { .. }) => {
|
||||||
let closure_ty = self.typeck_results.expr_ty(expr);
|
let closure_ty = self.typeck_results.expr_ty(expr);
|
||||||
let (def_id, args, movability) = match *closure_ty.kind() {
|
let (def_id, args, movability) = match *closure_ty.kind() {
|
||||||
ty::Closure(def_id, args) => (def_id, UpvarArgs::Closure(args), None),
|
ty::Closure(def_id, args) => (def_id, UpvarArgs::Closure(args), None),
|
||||||
|
@ -1252,6 +1252,17 @@ impl<'tcx> ThirBuildCx<'tcx> {
|
||||||
|
|
||||||
match upvar_capture {
|
match upvar_capture {
|
||||||
ty::UpvarCapture::ByValue => captured_place_expr,
|
ty::UpvarCapture::ByValue => captured_place_expr,
|
||||||
|
ty::UpvarCapture::ByUse => {
|
||||||
|
let span = captured_place_expr.span;
|
||||||
|
let expr_id = self.thir.exprs.push(captured_place_expr);
|
||||||
|
|
||||||
|
Expr {
|
||||||
|
temp_lifetime: TempLifetime { temp_lifetime, backwards_incompatible },
|
||||||
|
ty: upvar_ty,
|
||||||
|
span: closure_expr.span,
|
||||||
|
kind: ExprKind::ByUse { expr: expr_id, span },
|
||||||
|
}
|
||||||
|
}
|
||||||
ty::UpvarCapture::ByRef(upvar_borrow) => {
|
ty::UpvarCapture::ByRef(upvar_borrow) => {
|
||||||
let borrow_kind = match upvar_borrow {
|
let borrow_kind = match upvar_borrow {
|
||||||
ty::BorrowKind::Immutable => BorrowKind::Shared,
|
ty::BorrowKind::Immutable => BorrowKind::Shared,
|
||||||
|
|
|
@ -170,7 +170,7 @@ pub(crate) fn coroutine_by_move_body_def_id<'tcx>(
|
||||||
// this when building the field projection in the MIR body later on.
|
// this when building the field projection in the MIR body later on.
|
||||||
let mut parent_capture_ty = parent_capture.place.ty();
|
let mut parent_capture_ty = parent_capture.place.ty();
|
||||||
parent_capture_ty = match parent_capture.info.capture_kind {
|
parent_capture_ty = match parent_capture.info.capture_kind {
|
||||||
ty::UpvarCapture::ByValue => parent_capture_ty,
|
ty::UpvarCapture::ByValue | ty::UpvarCapture::ByUse => parent_capture_ty,
|
||||||
ty::UpvarCapture::ByRef(kind) => Ty::new_ref(
|
ty::UpvarCapture::ByRef(kind) => Ty::new_ref(
|
||||||
tcx,
|
tcx,
|
||||||
tcx.lifetimes.re_erased,
|
tcx.lifetimes.re_erased,
|
||||||
|
|
|
@ -706,7 +706,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
|
||||||
);
|
);
|
||||||
self.acc(self.exit_ln, var, ACC_READ | ACC_USE);
|
self.acc(self.exit_ln, var, ACC_READ | ACC_USE);
|
||||||
}
|
}
|
||||||
ty::UpvarCapture::ByValue => {}
|
ty::UpvarCapture::ByValue | ty::UpvarCapture::ByUse => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1500,7 +1500,7 @@ impl<'tcx> Liveness<'_, 'tcx> {
|
||||||
for (&var_hir_id, min_capture_list) in closure_min_captures {
|
for (&var_hir_id, min_capture_list) in closure_min_captures {
|
||||||
for captured_place in min_capture_list {
|
for captured_place in min_capture_list {
|
||||||
match captured_place.info.capture_kind {
|
match captured_place.info.capture_kind {
|
||||||
ty::UpvarCapture::ByValue => {}
|
ty::UpvarCapture::ByValue | ty::UpvarCapture::ByUse => {}
|
||||||
ty::UpvarCapture::ByRef(..) => continue,
|
ty::UpvarCapture::ByRef(..) => continue,
|
||||||
};
|
};
|
||||||
let span = captured_place.get_capture_kind_span(self.ir.tcx);
|
let span = captured_place.get_capture_kind_span(self.ir.tcx);
|
||||||
|
|
|
@ -3,18 +3,27 @@
|
||||||
|
|
||||||
#![feature(ergonomic_clones)]
|
#![feature(ergonomic_clones)]
|
||||||
|
|
||||||
fn ergonomic_clone_closure() -> i32 {
|
fn ergonomic_clone_closure_no_captures() -> i32 {
|
||||||
let cl = use || {
|
let cl = use || {
|
||||||
1
|
1
|
||||||
};
|
};
|
||||||
cl()
|
cl()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn ergonomic_clone_closure_with_captures() -> String {
|
||||||
|
let s = String::from("hi");
|
||||||
|
|
||||||
|
let cl = use || {
|
||||||
|
s
|
||||||
|
};
|
||||||
|
cl()
|
||||||
|
}
|
||||||
|
|
||||||
fn ergonomic_clone_async_closures() -> String {
|
fn ergonomic_clone_async_closures() -> String {
|
||||||
let s = String::from("hi");
|
let s = String::from("hi");
|
||||||
|
|
||||||
async use {
|
async use {
|
||||||
22
|
s
|
||||||
};
|
};
|
||||||
|
|
||||||
s
|
s
|
||||||
|
|
|
@ -13,7 +13,6 @@ fn ergonomic_closure_clone() {
|
||||||
|
|
||||||
let s3 = use || {
|
let s3 = use || {
|
||||||
//~^ ERROR `.use` calls are experimental [E0658]
|
//~^ ERROR `.use` calls are experimental [E0658]
|
||||||
//~| ERROR use of moved value: `s1` [E0382]
|
|
||||||
s1
|
s1
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -28,30 +28,6 @@ LL | let s3 = use || {
|
||||||
= help: add `#![feature(ergonomic_clones)]` to the crate attributes to enable
|
= help: add `#![feature(ergonomic_clones)]` to the crate attributes to enable
|
||||||
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
|
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
|
||||||
|
|
||||||
error[E0382]: use of moved value: `s1`
|
error: aborting due to 3 previous errors
|
||||||
--> $DIR/feature-gate-ergonomic-clones.rs:14:14
|
|
||||||
|
|
|
||||||
LL | let s1 = String::from("hi!");
|
|
||||||
| -- move occurs because `s1` has type `String`, which does not implement the `Copy` trait
|
|
||||||
LL |
|
|
||||||
LL | let s2 = use || {
|
|
||||||
| ------ value moved into closure here
|
|
||||||
LL |
|
|
||||||
LL | s1
|
|
||||||
| -- variable moved due to use in closure
|
|
||||||
...
|
|
||||||
LL | let s3 = use || {
|
|
||||||
| ^^^^^^ value used here after move
|
|
||||||
...
|
|
||||||
LL | s1
|
|
||||||
| -- use occurs due to use in closure
|
|
||||||
|
|
|
||||||
help: consider cloning the value if the performance cost is acceptable
|
|
||||||
|
|
|
||||||
LL | s1.clone()
|
|
||||||
| ++++++++
|
|
||||||
|
|
||||||
error: aborting due to 4 previous errors
|
For more information about this error, try `rustc --explain E0658`.
|
||||||
|
|
||||||
Some errors have detailed explanations: E0382, E0658.
|
|
||||||
For more information about an error, try `rustc --explain E0382`.
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue