Skip to content

Commit 5c7d530

Browse files
authored
Rollup merge of rust-lang#79149 - sexxi-goose:upvar_ref, r=nikomatsakis
Move capture lowering from THIR to MIR This allows us to: - Handle precise Places captured by a closure directly in MIR. Handling captures in MIR is easier since we can rely on/ tweak PlaceBuilder to generate `mir::Place`s that resemble how we store captures (`hir::Place`). - Handle `let _ = x` case when feature `capture_disjoint_fields` is enabled directly in MIR. This is required to be done in MIR since patterns are desugared in MIR. Closes: rust-lang/project-rfc-2229#25 r? ```@nikomatsakis```
2 parents 62838c6 + 9f70e78 commit 5c7d530

File tree

7 files changed

+108
-124
lines changed

7 files changed

+108
-124
lines changed

compiler/rustc_mir_build/src/build/expr/as_place.rs

+79-1
Original file line numberDiff line numberDiff line change
@@ -160,7 +160,30 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
160160
expr_span,
161161
source_info,
162162
),
163-
ExprKind::SelfRef => block.and(PlaceBuilder::from(Local::new(1))),
163+
ExprKind::UpvarRef { closure_def_id, var_hir_id } => {
164+
let capture = this
165+
.hir
166+
.typeck_results
167+
.closure_captures
168+
.get(&closure_def_id)
169+
.and_then(|captures| captures.get_full(&var_hir_id));
170+
171+
if capture.is_none() {
172+
if !this.hir.tcx().features().capture_disjoint_fields {
173+
bug!(
174+
"No associated capture found for {:?} even though \
175+
capture_disjoint_fields isn't enabled",
176+
expr.kind
177+
)
178+
}
179+
// FIXME(project-rfc-2229#24): Handle this case properly
180+
}
181+
182+
// Unwrap until the FIXME has been resolved
183+
let (capture_index, _, upvar_id) = capture.unwrap();
184+
this.lower_closure_capture(block, capture_index, *upvar_id)
185+
}
186+
164187
ExprKind::VarRef { id } => {
165188
let place_builder = if this.is_bound_var_in_guard(id) {
166189
let index = this.var_local_id(id, RefWithinGuard);
@@ -270,6 +293,61 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
270293
}
271294
}
272295

296+
/// Lower a closure/generator capture by representing it as a field
297+
/// access within the desugared closure/generator.
298+
///
299+
/// `capture_index` is the index of the capture within the desugared
300+
/// closure/generator.
301+
fn lower_closure_capture(
302+
&mut self,
303+
block: BasicBlock,
304+
capture_index: usize,
305+
upvar_id: ty::UpvarId,
306+
) -> BlockAnd<PlaceBuilder<'tcx>> {
307+
let closure_ty = self
308+
.hir
309+
.typeck_results()
310+
.node_type(self.hir.tcx().hir().local_def_id_to_hir_id(upvar_id.closure_expr_id));
311+
312+
// Captures are represented using fields inside a structure.
313+
// This represents accessing self in the closure structure
314+
let mut place_builder = PlaceBuilder::from(Local::new(1));
315+
316+
// In case of Fn/FnMut closures we must deref to access the fields
317+
// Generators are considered FnOnce, so we ignore this step for them.
318+
if let ty::Closure(_, closure_substs) = closure_ty.kind() {
319+
match self.hir.infcx().closure_kind(closure_substs).unwrap() {
320+
ty::ClosureKind::Fn | ty::ClosureKind::FnMut => {
321+
place_builder = place_builder.deref();
322+
}
323+
ty::ClosureKind::FnOnce => {}
324+
}
325+
}
326+
327+
let substs = match closure_ty.kind() {
328+
ty::Closure(_, substs) => ty::UpvarSubsts::Closure(substs),
329+
ty::Generator(_, substs, _) => ty::UpvarSubsts::Generator(substs),
330+
_ => bug!("Lowering capture for non-closure type {:?}", closure_ty)
331+
};
332+
333+
// Access the capture by accessing the field within the Closure struct.
334+
//
335+
// We must have inferred the capture types since we are building MIR, therefore
336+
// it's safe to call `upvar_tys` and we can unwrap here because
337+
// we know that the capture exists and is the `capture_index`-th capture.
338+
let var_ty = substs.upvar_tys().nth(capture_index).unwrap();
339+
place_builder = place_builder.field(Field::new(capture_index), var_ty);
340+
341+
// If the variable is captured via ByRef(Immutable/Mutable) Borrow,
342+
// we need to deref it
343+
match self.hir.typeck_results.upvar_capture(upvar_id) {
344+
ty::UpvarCapture::ByRef(_) => {
345+
block.and(place_builder.deref())
346+
}
347+
ty::UpvarCapture::ByValue(_) => block.and(place_builder),
348+
}
349+
}
350+
273351
/// Lower an index expression
274352
///
275353
/// This has two complications;

compiler/rustc_mir_build/src/build/expr/as_rvalue.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -250,7 +250,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
250250
| ExprKind::Deref { .. }
251251
| ExprKind::Index { .. }
252252
| ExprKind::VarRef { .. }
253-
| ExprKind::SelfRef
253+
| ExprKind::UpvarRef { .. }
254254
| ExprKind::Break { .. }
255255
| ExprKind::Continue { .. }
256256
| ExprKind::Return { .. }

compiler/rustc_mir_build/src/build/expr/category.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ impl Category {
3838
ExprKind::Field { .. }
3939
| ExprKind::Deref { .. }
4040
| ExprKind::Index { .. }
41-
| ExprKind::SelfRef
41+
| ExprKind::UpvarRef { .. }
4242
| ExprKind::VarRef { .. }
4343
| ExprKind::PlaceTypeAscription { .. }
4444
| ExprKind::ValueTypeAscription { .. } => Some(Category::Place),

compiler/rustc_mir_build/src/build/expr/into.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -400,7 +400,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
400400

401401
// Avoid creating a temporary
402402
ExprKind::VarRef { .. }
403-
| ExprKind::SelfRef
403+
| ExprKind::UpvarRef { .. }
404404
| ExprKind::PlaceTypeAscription { .. }
405405
| ExprKind::ValueTypeAscription { .. } => {
406406
debug_assert!(Category::of(&expr.kind) == Some(Category::Place));

compiler/rustc_mir_build/src/thir/cx/expr.rs

+14-118
Original file line numberDiff line numberDiff line change
@@ -880,130 +880,26 @@ fn convert_path_expr<'a, 'tcx>(
880880
ExprKind::Deref { arg: Expr { ty, temp_lifetime, span: expr.span, kind }.to_ref() }
881881
}
882882

883-
Res::Local(var_hir_id) => convert_var(cx, expr, var_hir_id),
883+
Res::Local(var_hir_id) => convert_var(cx, var_hir_id),
884884

885885
_ => span_bug!(expr.span, "res `{:?}` not yet implemented", res),
886886
}
887887
}
888888

889-
fn convert_var<'tcx>(
890-
cx: &mut Cx<'_, 'tcx>,
891-
expr: &'tcx hir::Expr<'tcx>,
892-
var_hir_id: hir::HirId,
893-
) -> ExprKind<'tcx> {
894-
let upvar_index = cx
895-
.typeck_results()
896-
.closure_captures
897-
.get(&cx.body_owner)
898-
.and_then(|upvars| upvars.get_full(&var_hir_id).map(|(i, _, _)| i));
899-
900-
debug!(
901-
"convert_var({:?}): upvar_index={:?}, body_owner={:?}",
902-
var_hir_id, upvar_index, cx.body_owner
903-
);
904-
905-
let temp_lifetime = cx.region_scope_tree.temporary_scope(expr.hir_id.local_id);
906-
907-
match upvar_index {
908-
None => ExprKind::VarRef { id: var_hir_id },
889+
fn convert_var<'tcx>(cx: &mut Cx<'_, 'tcx>, var_hir_id: hir::HirId) -> ExprKind<'tcx> {
890+
// We want upvars here not captures.
891+
// Captures will be handled in MIR.
892+
let is_upvar = cx
893+
.tcx
894+
.upvars_mentioned(cx.body_owner)
895+
.map_or(false, |upvars| upvars.contains_key(&var_hir_id));
909896

910-
Some(upvar_index) => {
911-
let closure_def_id = cx.body_owner;
912-
let upvar_id = ty::UpvarId {
913-
var_path: ty::UpvarPath { hir_id: var_hir_id },
914-
closure_expr_id: closure_def_id.expect_local(),
915-
};
916-
let var_ty = cx.typeck_results().node_type(var_hir_id);
897+
debug!("convert_var({:?}): is_upvar={}, body_owner={:?}", var_hir_id, is_upvar, cx.body_owner);
917898

918-
// FIXME free regions in closures are not right
919-
let closure_ty = cx
920-
.typeck_results()
921-
.node_type(cx.tcx.hir().local_def_id_to_hir_id(upvar_id.closure_expr_id));
922-
923-
// FIXME we're just hard-coding the idea that the
924-
// signature will be &self or &mut self and hence will
925-
// have a bound region with number 0
926-
let region = ty::ReFree(ty::FreeRegion {
927-
scope: closure_def_id,
928-
bound_region: ty::BoundRegion::BrAnon(0),
929-
});
930-
let region = cx.tcx.mk_region(region);
931-
932-
let self_expr = if let ty::Closure(_, closure_substs) = closure_ty.kind() {
933-
match cx.infcx.closure_kind(closure_substs).unwrap() {
934-
ty::ClosureKind::Fn => {
935-
let ref_closure_ty = cx.tcx.mk_ref(
936-
region,
937-
ty::TypeAndMut { ty: closure_ty, mutbl: hir::Mutability::Not },
938-
);
939-
Expr {
940-
ty: closure_ty,
941-
temp_lifetime,
942-
span: expr.span,
943-
kind: ExprKind::Deref {
944-
arg: Expr {
945-
ty: ref_closure_ty,
946-
temp_lifetime,
947-
span: expr.span,
948-
kind: ExprKind::SelfRef,
949-
}
950-
.to_ref(),
951-
},
952-
}
953-
}
954-
ty::ClosureKind::FnMut => {
955-
let ref_closure_ty = cx.tcx.mk_ref(
956-
region,
957-
ty::TypeAndMut { ty: closure_ty, mutbl: hir::Mutability::Mut },
958-
);
959-
Expr {
960-
ty: closure_ty,
961-
temp_lifetime,
962-
span: expr.span,
963-
kind: ExprKind::Deref {
964-
arg: Expr {
965-
ty: ref_closure_ty,
966-
temp_lifetime,
967-
span: expr.span,
968-
kind: ExprKind::SelfRef,
969-
}
970-
.to_ref(),
971-
},
972-
}
973-
}
974-
ty::ClosureKind::FnOnce => Expr {
975-
ty: closure_ty,
976-
temp_lifetime,
977-
span: expr.span,
978-
kind: ExprKind::SelfRef,
979-
},
980-
}
981-
} else {
982-
Expr { ty: closure_ty, temp_lifetime, span: expr.span, kind: ExprKind::SelfRef }
983-
};
984-
985-
// at this point we have `self.n`, which loads up the upvar
986-
let field_kind =
987-
ExprKind::Field { lhs: self_expr.to_ref(), name: Field::new(upvar_index) };
988-
989-
// ...but the upvar might be an `&T` or `&mut T` capture, at which
990-
// point we need an implicit deref
991-
match cx.typeck_results().upvar_capture(upvar_id) {
992-
ty::UpvarCapture::ByValue(_) => field_kind,
993-
ty::UpvarCapture::ByRef(borrow) => ExprKind::Deref {
994-
arg: Expr {
995-
temp_lifetime,
996-
ty: cx.tcx.mk_ref(
997-
borrow.region,
998-
ty::TypeAndMut { ty: var_ty, mutbl: borrow.kind.to_mutbl_lossy() },
999-
),
1000-
span: expr.span,
1001-
kind: field_kind,
1002-
}
1003-
.to_ref(),
1004-
},
1005-
}
1006-
}
899+
if is_upvar {
900+
ExprKind::UpvarRef { closure_def_id: cx.body_owner, var_hir_id }
901+
} else {
902+
ExprKind::VarRef { id: var_hir_id }
1007903
}
1008904
}
1009905

@@ -1102,7 +998,7 @@ fn capture_upvar<'tcx>(
1102998
temp_lifetime,
1103999
ty: var_ty,
11041000
span: closure_expr.span,
1105-
kind: convert_var(cx, closure_expr, var_hir_id),
1001+
kind: convert_var(cx, var_hir_id),
11061002
};
11071003
match upvar_capture {
11081004
ty::UpvarCapture::ByValue(_) => captured_var.to_ref(),

compiler/rustc_mir_build/src/thir/cx/mod.rs

+4
Original file line numberDiff line numberDiff line change
@@ -186,6 +186,10 @@ impl<'a, 'tcx> Cx<'a, 'tcx> {
186186
ty.needs_drop(self.tcx, self.param_env)
187187
}
188188

189+
crate fn infcx(&self) -> &'a InferCtxt<'a, 'tcx> {
190+
self.infcx
191+
}
192+
189193
crate fn tcx(&self) -> TyCtxt<'tcx> {
190194
self.tcx
191195
}

compiler/rustc_mir_build/src/thir/mod.rs

+8-2
Original file line numberDiff line numberDiff line change
@@ -211,8 +211,14 @@ crate enum ExprKind<'tcx> {
211211
VarRef {
212212
id: hir::HirId,
213213
},
214-
/// first argument, used for self in a closure
215-
SelfRef,
214+
/// Used to represent upvars mentioned in a closure/generator
215+
UpvarRef {
216+
/// DefId of the closure/generator
217+
closure_def_id: DefId,
218+
219+
/// HirId of the root variable
220+
var_hir_id: hir::HirId,
221+
},
216222
Borrow {
217223
borrow_kind: BorrowKind,
218224
arg: ExprRef<'tcx>,

0 commit comments

Comments
 (0)