1
Fork 0

Rollup merge of #65277 - csmoe:fix-move, r=estebank

Query generator kind for error reporting

Fixes https://github.com/rust-lang/rust/pull/65166#discussion_r333114545
r? @estebank
cc @cramertj
This commit is contained in:
Tyler Mandry 2019-10-11 15:09:56 -07:00 committed by GitHub
commit 60482be070
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 55 additions and 26 deletions

View file

@ -1366,6 +1366,10 @@ impl Body {
hir_id: self.value.hir_id, hir_id: self.value.hir_id,
} }
} }
pub fn generator_kind(&self) -> Option<GeneratorKind> {
self.generator_kind
}
} }
/// The type of source expression that caused this generator to be created. /// The type of source expression that caused this generator to be created.

View file

@ -1,5 +1,6 @@
use rustc::hir; use rustc::hir;
use rustc::hir::def_id::DefId; use rustc::hir::def_id::DefId;
use rustc::hir::{AsyncGeneratorKind, GeneratorKind};
use rustc::mir::{ use rustc::mir::{
self, AggregateKind, BindingForm, BorrowKind, ClearCrossCrate, ConstraintCategory, Local, self, AggregateKind, BindingForm, BorrowKind, ClearCrossCrate, ConstraintCategory, Local,
LocalDecl, LocalKind, Location, Operand, Place, PlaceBase, PlaceRef, ProjectionElem, Rvalue, LocalDecl, LocalKind, Location, Operand, Place, PlaceBase, PlaceRef, ProjectionElem, Rvalue,
@ -788,7 +789,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
.. ..
}, },
) if borrow_spans.for_closure() => self.report_escaping_closure_capture( ) if borrow_spans.for_closure() => self.report_escaping_closure_capture(
borrow_spans.args_or_use(), borrow_spans,
borrow_span, borrow_span,
region_name, region_name,
category, category,
@ -806,7 +807,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
}, },
) if borrow_spans.for_generator() => self.report_escaping_closure_capture( ) if borrow_spans.for_generator() => self.report_escaping_closure_capture(
borrow_spans.args_or_use(), borrow_spans,
borrow_span, borrow_span,
region_name, region_name,
category, category,
@ -1195,7 +1196,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
fn report_escaping_closure_capture( fn report_escaping_closure_capture(
&mut self, &mut self,
args_span: Span, use_span: UseSpans,
var_span: Span, var_span: Span,
fr_name: &RegionName, fr_name: &RegionName,
category: ConstraintCategory, category: ConstraintCategory,
@ -1203,7 +1204,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
captured_var: &str, captured_var: &str,
) -> DiagnosticBuilder<'cx> { ) -> DiagnosticBuilder<'cx> {
let tcx = self.infcx.tcx; let tcx = self.infcx.tcx;
let args_span = use_span.args_or_use();
let mut err = self.cannot_capture_in_long_lived_closure( let mut err = self.cannot_capture_in_long_lived_closure(
args_span, args_span,
captured_var, captured_var,
@ -1223,12 +1224,25 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
}, },
Err(_) => "move |<args>| <body>".to_string() Err(_) => "move |<args>| <body>".to_string()
}; };
let kind = match use_span.generator_kind() {
Some(generator_kind) => match generator_kind {
GeneratorKind::Async(async_kind) => match async_kind {
AsyncGeneratorKind::Block => "async block",
AsyncGeneratorKind::Closure => "async closure",
_ => bug!("async block/closure expected, but async funtion found."),
},
GeneratorKind::Gen => "generator",
}
None => "closure",
};
err.span_suggestion( err.span_suggestion(
args_span, args_span,
&format!("to force the closure to take ownership of {} (and any \ &format!(
other referenced variables), use the `move` keyword", "to force the {} to take ownership of {} (and any \
captured_var), other referenced variables), use the `move` keyword",
kind,
captured_var
),
suggestion, suggestion,
Applicability::MachineApplicable, Applicability::MachineApplicable,
); );

View file

@ -1,6 +1,7 @@
use rustc::hir; use rustc::hir;
use rustc::hir::def::Namespace; use rustc::hir::def::Namespace;
use rustc::hir::def_id::DefId; use rustc::hir::def_id::DefId;
use rustc::hir::GeneratorKind;
use rustc::mir::{ use rustc::mir::{
AggregateKind, Constant, Field, Local, LocalKind, Location, Operand, AggregateKind, Constant, Field, Local, LocalKind, Location, Operand,
Place, PlaceBase, PlaceRef, ProjectionElem, Rvalue, Statement, StatementKind, Place, PlaceBase, PlaceRef, ProjectionElem, Rvalue, Statement, StatementKind,
@ -14,7 +15,7 @@ use syntax_pos::Span;
use syntax::symbol::sym; use syntax::symbol::sym;
use super::borrow_set::BorrowData; use super::borrow_set::BorrowData;
use super::{MirBorrowckCtxt}; use super::MirBorrowckCtxt;
use crate::dataflow::move_paths::{InitLocation, LookupResult}; use crate::dataflow::move_paths::{InitLocation, LookupResult};
pub(super) struct IncludingDowncast(pub(super) bool); pub(super) struct IncludingDowncast(pub(super) bool);
@ -604,7 +605,7 @@ pub(super) enum UseSpans {
// The access is caused by capturing a variable for a closure. // The access is caused by capturing a variable for a closure.
ClosureUse { ClosureUse {
// This is true if the captured variable was from a generator. // This is true if the captured variable was from a generator.
is_generator: bool, generator_kind: Option<GeneratorKind>,
// The span of the args of the closure, including the `move` keyword if // The span of the args of the closure, including the `move` keyword if
// it's present. // it's present.
args_span: Span, args_span: Span,
@ -631,6 +632,13 @@ impl UseSpans {
} }
} }
pub(super) fn generator_kind(self) -> Option<GeneratorKind> {
match self {
UseSpans::ClosureUse { generator_kind, .. } => generator_kind,
_ => None,
}
}
// Add a span label to the arguments of the closure, if it exists. // Add a span label to the arguments of the closure, if it exists.
pub(super) fn args_span_label( pub(super) fn args_span_label(
self, self,
@ -656,7 +664,7 @@ impl UseSpans {
/// Returns `false` if this place is not used in a closure. /// Returns `false` if this place is not used in a closure.
pub(super) fn for_closure(&self) -> bool { pub(super) fn for_closure(&self) -> bool {
match *self { match *self {
UseSpans::ClosureUse { is_generator, .. } => !is_generator, UseSpans::ClosureUse { generator_kind, .. } => generator_kind.is_none(),
_ => false, _ => false,
} }
} }
@ -664,7 +672,7 @@ impl UseSpans {
/// Returns `false` if this place is not used in a generator. /// Returns `false` if this place is not used in a generator.
pub(super) fn for_generator(&self) -> bool { pub(super) fn for_generator(&self) -> bool {
match *self { match *self {
UseSpans::ClosureUse { is_generator, .. } => is_generator, UseSpans::ClosureUse { generator_kind, .. } => generator_kind.is_some(),
_ => false, _ => false,
} }
} }
@ -672,7 +680,7 @@ impl UseSpans {
/// Describe the span associated with a use of a place. /// Describe the span associated with a use of a place.
pub(super) fn describe(&self) -> String { pub(super) fn describe(&self) -> String {
match *self { match *self {
UseSpans::ClosureUse { is_generator, .. } => if is_generator { UseSpans::ClosureUse { generator_kind, .. } => if generator_kind.is_some() {
" in generator".to_string() " in generator".to_string()
} else { } else {
" in closure".to_string() " in closure".to_string()
@ -794,19 +802,20 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
if let StatementKind::Assign( if let StatementKind::Assign(
box(_, Rvalue::Aggregate(ref kind, ref places)) box(_, Rvalue::Aggregate(ref kind, ref places))
) = stmt.kind { ) = stmt.kind {
let (def_id, is_generator) = match kind { let def_id = match kind {
box AggregateKind::Closure(def_id, _) => (def_id, false), box AggregateKind::Closure(def_id, _)
box AggregateKind::Generator(def_id, _, _) => (def_id, true), | box AggregateKind::Generator(def_id, _, _) => def_id,
_ => return OtherUse(stmt.source_info.span), _ => return OtherUse(stmt.source_info.span),
}; };
debug!( debug!(
"move_spans: def_id={:?} is_generator={:?} places={:?}", "move_spans: def_id={:?} places={:?}",
def_id, is_generator, places def_id, places
); );
if let Some((args_span, var_span)) = self.closure_span(*def_id, moved_place, places) { if let Some((args_span, generator_kind, var_span))
= self.closure_span(*def_id, moved_place, places) {
return ClosureUse { return ClosureUse {
is_generator, generator_kind,
args_span, args_span,
var_span, var_span,
}; };
@ -857,11 +866,11 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
"borrow_spans: def_id={:?} is_generator={:?} places={:?}", "borrow_spans: def_id={:?} is_generator={:?} places={:?}",
def_id, is_generator, places def_id, is_generator, places
); );
if let Some((args_span, var_span)) = self.closure_span( if let Some((args_span, generator_kind, var_span)) = self.closure_span(
*def_id, Place::from(target).as_ref(), places *def_id, Place::from(target).as_ref(), places
) { ) {
return ClosureUse { return ClosureUse {
is_generator, generator_kind,
args_span, args_span,
var_span, var_span,
}; };
@ -884,7 +893,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
def_id: DefId, def_id: DefId,
target_place: PlaceRef<'cx, 'tcx>, target_place: PlaceRef<'cx, 'tcx>,
places: &Vec<Operand<'tcx>>, places: &Vec<Operand<'tcx>>,
) -> Option<(Span, Span)> { ) -> Option<(Span, Option<GeneratorKind>, Span)> {
debug!( debug!(
"closure_span: def_id={:?} target_place={:?} places={:?}", "closure_span: def_id={:?} target_place={:?} places={:?}",
def_id, target_place, places def_id, target_place, places
@ -893,14 +902,16 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
let expr = &self.infcx.tcx.hir().expect_expr(hir_id).kind; let expr = &self.infcx.tcx.hir().expect_expr(hir_id).kind;
debug!("closure_span: hir_id={:?} expr={:?}", hir_id, expr); debug!("closure_span: hir_id={:?} expr={:?}", hir_id, expr);
if let hir::ExprKind::Closure( if let hir::ExprKind::Closure(
.., args_span, _ .., body_id, args_span, _
) = expr { ) = expr {
for (upvar, place) in self.infcx.tcx.upvars(def_id)?.values().zip(places) { for (upvar, place) in self.infcx.tcx.upvars(def_id)?.values().zip(places) {
match place { match place {
Operand::Copy(place) | Operand::Copy(place) |
Operand::Move(place) if target_place == place.as_ref() => { Operand::Move(place) if target_place == place.as_ref() => {
debug!("closure_span: found captured local {:?}", place); debug!("closure_span: found captured local {:?}", place);
return Some((*args_span, upvar.span)); let body = self.infcx.tcx.hir().body(*body_id);
let generator_kind = body.generator_kind();
return Some((*args_span, generator_kind, upvar.span));
}, },
_ => {} _ => {}
} }

View file

@ -12,7 +12,7 @@ note: generator is returned here
| |
LL | fn foo() -> Box<impl std::future::Future<Output = u32>> { LL | fn foo() -> Box<impl std::future::Future<Output = u32>> {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
help: to force the closure to take ownership of `x` (and any other referenced variables), use the `move` keyword help: to force the async block to take ownership of `x` (and any other referenced variables), use the `move` keyword
| |
LL | Box::new(async move { x } ) LL | Box::new(async move { x } )
| ^^^^^^^^^^ | ^^^^^^^^^^