From 5144d3222f76b1f0b7c4bffbff5ebc40a29c3c63 Mon Sep 17 00:00:00 2001 From: Ramana Venkata Date: Sun, 12 Nov 2017 21:49:02 +0530 Subject: [PATCH] Fix printing of upvar in closures --- src/librustc_mir/borrow_check.rs | 82 +++++++++++-------- .../borrowck/borrowck-describe-lvalue.rs | 24 ++++++ 2 files changed, 70 insertions(+), 36 deletions(-) diff --git a/src/librustc_mir/borrow_check.rs b/src/librustc_mir/borrow_check.rs index 520f672d0cd..2a7a62cd64b 100644 --- a/src/librustc_mir/borrow_check.rs +++ b/src/librustc_mir/borrow_check.rs @@ -11,7 +11,6 @@ //! This query borrow-checks the MIR to (further) ensure it is not broken. use rustc::hir; -use rustc::hir::def::Def; use rustc::hir::def_id::{DefId}; use rustc::infer::{InferCtxt}; use rustc::ty::{self, TyCtxt, ParamEnv}; @@ -1022,7 +1021,7 @@ fn each_borrow_involving_path(&mut self, access_lvalue: (ShallowOrDeep, &Lvalue<'tcx>), flow_state: &InProgress<'b, 'gcx, 'tcx>, mut op: F) - where F: FnMut(&mut Self, BorrowIndex, &BorrowData<'tcx>, &Lvalue) -> Control + where F: FnMut(&mut Self, BorrowIndex, &BorrowData<'tcx>, &Lvalue<'tcx>) -> Control { let (access, lvalue) = access_lvalue; @@ -1249,7 +1248,7 @@ impl<'c, 'b, 'a: 'b+'c, 'gcx, 'tcx: 'a> MirBorrowckCtxt<'c, 'b, 'a, 'gcx, 'tcx> fn report_use_of_moved_or_uninitialized(&mut self, _context: Context, desired_action: &str, - (lvalue, span): (&Lvalue, Span), + (lvalue, span): (&Lvalue<'tcx>, Span), mpi: MovePathIndex, curr_move_out: &IdxSetBuf) { @@ -1291,8 +1290,8 @@ fn report_use_of_moved_or_uninitialized(&mut self, fn report_move_out_while_borrowed(&mut self, _context: Context, - (lvalue, span): (&Lvalue, Span), - borrow: &BorrowData) { + (lvalue, span): (&Lvalue<'tcx>, Span), + borrow: &BorrowData<'tcx>) { self.tcx.cannot_move_when_borrowed(span, &self.describe_lvalue(lvalue), Origin::Mir) @@ -1306,8 +1305,8 @@ fn report_move_out_while_borrowed(&mut self, fn report_use_while_mutably_borrowed(&mut self, _context: Context, - (lvalue, span): (&Lvalue, Span), - borrow : &BorrowData) { + (lvalue, span): (&Lvalue<'tcx>, Span), + borrow : &BorrowData<'tcx>) { let mut err = self.tcx.cannot_use_when_mutably_borrowed( span, &self.describe_lvalue(lvalue), @@ -1383,8 +1382,8 @@ fn find_closure_span( fn report_conflicting_borrow(&mut self, context: Context, - common_prefix: &Lvalue, - (lvalue, span): (&Lvalue, Span), + common_prefix: &Lvalue<'tcx>, + (lvalue, span): (&Lvalue<'tcx>, Span), gen_borrow_kind: BorrowKind, issued_borrow: &BorrowData, end_issued_loan_span: Option) { @@ -1454,7 +1453,7 @@ fn report_conflicting_borrow(&mut self, fn report_illegal_mutation_of_borrowed(&mut self, _: Context, - (lvalue, span): (&Lvalue, Span), + (lvalue, span): (&Lvalue<'tcx>, Span), loan: &BorrowData) { let mut err = self.tcx.cannot_assign_to_borrowed( span, self.retrieve_borrow_span(loan), &self.describe_lvalue(lvalue), Origin::Mir); @@ -1464,7 +1463,7 @@ fn report_illegal_mutation_of_borrowed(&mut self, fn report_illegal_reassignment(&mut self, _context: Context, - (lvalue, span): (&Lvalue, Span), + (lvalue, span): (&Lvalue<'tcx>, Span), assigned_span: Span) { self.tcx.cannot_reassign_immutable(span, &self.describe_lvalue(lvalue), @@ -1475,7 +1474,9 @@ fn report_illegal_reassignment(&mut self, .emit(); } - fn report_assignment_to_static(&mut self, _context: Context, (lvalue, span): (&Lvalue, Span)) { + fn report_assignment_to_static(&mut self, + _context: Context, + (lvalue, span): (&Lvalue<'tcx>, Span)) { let mut err = self.tcx.cannot_assign_static( span, &self.describe_lvalue(lvalue), Origin::Mir); err.emit(); @@ -1484,14 +1485,17 @@ fn report_assignment_to_static(&mut self, _context: Context, (lvalue, span): (&L impl<'c, 'b, 'a: 'b+'c, 'gcx, 'tcx: 'a> MirBorrowckCtxt<'c, 'b, 'a, 'gcx, 'tcx> { // End-user visible description of `lvalue` - fn describe_lvalue(&self, lvalue: &Lvalue) -> String { + fn describe_lvalue(&self, lvalue: &Lvalue<'tcx>) -> String { let mut buf = String::new(); self.append_lvalue_to_string(lvalue, &mut buf, None); buf } // Appends end-user visible description of `lvalue` to `buf`. - fn append_lvalue_to_string(&self, lvalue: &Lvalue, buf: &mut String, autoderef: Option) { + fn append_lvalue_to_string(&self, + lvalue: &Lvalue<'tcx>, + buf: &mut String, + autoderef: Option) { match *lvalue { Lvalue::Local(local) => { self.append_local_to_string(local, buf, "_"); @@ -1501,41 +1505,50 @@ fn append_lvalue_to_string(&self, lvalue: &Lvalue, buf: &mut String, autoderef: } Lvalue::Projection(ref proj) => { let mut autoderef = autoderef.unwrap_or(false); - let (prefix, suffix, index_operand) = match proj.elem { + + match proj.elem { ProjectionElem::Deref => { if autoderef { - ("", format!(""), None) + self.append_lvalue_to_string(&proj.base, buf, Some(autoderef)); } else { - ("(*", format!(")"), None) + buf.push_str(&"(*"); + self.append_lvalue_to_string(&proj.base, buf, Some(autoderef)); + buf.push_str(&")"); } }, - ProjectionElem::Downcast(..) => - ("", format!(""), None), // (dont emit downcast info) + ProjectionElem::Downcast(..) => { + self.append_lvalue_to_string(&proj.base, buf, Some(autoderef)); + }, ProjectionElem::Field(field, _ty) => { autoderef = true; - ("", format!(".{}", self.describe_field(&proj.base, field.index())), None) + let is_projection_from_ty_closure = proj.base.ty(self.mir, self.tcx) + .to_ty(self.tcx).is_closure(); + + let field_name = self.describe_field(&proj.base, field.index()); + if is_projection_from_ty_closure { + buf.push_str(&format!("{}", field_name)); + } else { + self.append_lvalue_to_string(&proj.base, buf, Some(autoderef)); + buf.push_str(&format!(".{}", field_name)); + } }, ProjectionElem::Index(index) => { autoderef = true; - ("", format!(""), Some(index)) + + self.append_lvalue_to_string(&proj.base, buf, Some(autoderef)); + buf.push_str("["); + self.append_local_to_string(index, buf, ".."); + buf.push_str("]"); }, ProjectionElem::ConstantIndex { .. } | ProjectionElem::Subslice { .. } => { autoderef = true; // Since it isn't possible to borrow an element on a particular index and // then use another while the borrow is held, don't output indices details // to avoid confusing the end-user - ("", format!("[..]"), None) + self.append_lvalue_to_string(&proj.base, buf, Some(autoderef)); + buf.push_str(&"[..]"); }, }; - buf.push_str(prefix); - self.append_lvalue_to_string(&proj.base, buf, Some(autoderef)); - if let Some(index) = index_operand { - buf.push_str("["); - self.append_local_to_string(index, buf, ".."); - buf.push_str("]"); - } else { - buf.push_str(&suffix); - } } } } @@ -1609,12 +1622,9 @@ fn describe_field_from_ty(&self, ty: &ty::Ty, field_index: usize) -> String { // the closure comes from another crate. But in that case we wouldn't // be borrowck'ing it, so we can just unwrap: let node_id = self.tcx.hir.as_local_node_id(closure_def_id).unwrap(); - let local_def = self.tcx.with_freevars(node_id, |fv| fv[field_index].def); + let freevar = self.tcx.with_freevars(node_id, |fv| fv[field_index]); - match local_def { - Def::Local(local_node_id) => self.tcx.hir.name(local_node_id).to_string(), - _ => unreachable!() - } + self.tcx.hir.name(freevar.var_id()).to_string() } _ => { // Might need a revision when the fields in trait RFC is implemented diff --git a/src/test/compile-fail/borrowck/borrowck-describe-lvalue.rs b/src/test/compile-fail/borrowck/borrowck-describe-lvalue.rs index cff913b17be..06d61242ec2 100644 --- a/src/test/compile-fail/borrowck/borrowck-describe-lvalue.rs +++ b/src/test/compile-fail/borrowck/borrowck-describe-lvalue.rs @@ -327,4 +327,28 @@ unsafe fn bump2(mut block: *mut Block2) { _ => panic!("other case") } } + // Field from upvar + { + let mut x = 0; + || { + let y = &mut x; + &mut x; //[ast]~ ERROR cannot borrow `**x` as mutable more than once at a time + //[mir]~^ ERROR cannot borrow `**x` as mutable more than once at a time (Ast) + //[mir]~| ERROR cannot borrow `(*x)` as mutable more than once at a time (Mir) + *y = 1; + }; + } + // Field from upvar nested + { + let mut x = 0; + || { + || { + let y = &mut x; + &mut x; //[ast]~ ERROR cannot borrow `**x` as mutable more than once at a time + //[mir]~^ ERROR cannot borrow `**x` as mutable more than once at a time (Ast) + //[mir]~| ERROR cannot borrow `(*x)` as mutable more than once at a time (Mir) + *y = 1; + } + }; + } }