diff --git a/src/librustc/traits/error_reporting.rs b/src/librustc/traits/error_reporting.rs index 0c9a73d78a5..c1df1149bbd 100644 --- a/src/librustc/traits/error_reporting.rs +++ b/src/librustc/traits/error_reporting.rs @@ -2479,19 +2479,21 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { ); eq }) - .map(|ty::GeneratorInteriorTypeCause { span, scope_span, .. }| { - (span, source_map.span_to_snippet(*span), scope_span) + .map(|ty::GeneratorInteriorTypeCause { span, scope_span, expr, .. }| { + (span, source_map.span_to_snippet(*span), scope_span, expr) }); + debug!( "maybe_note_obligation_cause_for_async_await: target_ty={:?} \ generator_interior_types={:?} target_span={:?}", target_ty, tables.generator_interior_types, target_span ); - if let Some((target_span, Ok(snippet), scope_span)) = target_span { + if let Some((target_span, Ok(snippet), scope_span, expr)) = target_span { self.note_obligation_cause_for_async_await( err, *target_span, scope_span, + *expr, snippet, generator_did, last_generator, @@ -2514,6 +2516,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { err: &mut DiagnosticBuilder<'_>, target_span: Span, scope_span: &Option, + expr: Option, snippet: String, first_generator: DefId, last_generator: Option, @@ -2549,6 +2552,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { // not implemented. let is_send = self.tcx.is_diagnostic_item(sym::send_trait, trait_ref.def_id); let is_sync = self.tcx.is_diagnostic_item(sym::sync_trait, trait_ref.def_id); + let hir = self.tcx.hir(); let trait_explanation = if is_send || is_sync { let (trait_name, trait_verb) = if is_send { ("`Send`", "sent") } else { ("`Sync`", "shared") }; @@ -2564,8 +2568,8 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { let message = if let Some(name) = last_generator .and_then(|generator_did| self.tcx.parent(generator_did)) - .and_then(|parent_did| self.tcx.hir().as_local_hir_id(parent_did)) - .and_then(|parent_hir_id| self.tcx.hir().opt_name(parent_hir_id)) + .and_then(|parent_did| hir.as_local_hir_id(parent_did)) + .and_then(|parent_hir_id| hir.opt_name(parent_hir_id)) { format!("future returned by `{}` is not {}", name, trait_name) } else { @@ -2581,7 +2585,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { }; // Look at the last interior type to get a span for the `.await`. - let await_span = tables.generator_interior_types.iter().map(|i| i.span).last().unwrap(); + let await_span = tables.generator_interior_types.iter().map(|t| t.span).last().unwrap(); let mut span = MultiSpan::from_span(await_span); span.push_span_label( await_span, @@ -2606,6 +2610,22 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { ), ); + if let Some(expr_id) = expr { + let expr = hir.expect_expr(expr_id); + let is_ref = tables.expr_adjustments(expr).iter().any(|adj| adj.is_region_borrow()); + let parent = hir.get_parent_node(expr_id); + if let Some(hir::Node::Expr(e)) = hir.find(parent) { + let method_span = hir.span(parent); + if tables.is_method_call(e) && is_ref { + err.span_help( + method_span, + "consider moving this method call into a `let` \ + binding to create a shorter lived borrow", + ); + } + } + } + // Add a note for the item obligation that remains - normally a note pointing to the // bound that introduced the obligation (e.g. `T: Send`). debug!("note_obligation_cause_for_async_await: next_code={:?}", next_code); diff --git a/src/librustc/ty/adjustment.rs b/src/librustc/ty/adjustment.rs index ebefb03b813..db034d1618c 100644 --- a/src/librustc/ty/adjustment.rs +++ b/src/librustc/ty/adjustment.rs @@ -81,6 +81,15 @@ pub struct Adjustment<'tcx> { pub target: Ty<'tcx>, } +impl Adjustment<'tcx> { + pub fn is_region_borrow(&self) -> bool { + match self.kind { + Adjust::Borrow(AutoBorrow::Ref(..)) => true, + _ => false, + } + } +} + #[derive(Clone, Debug, RustcEncodable, RustcDecodable, HashStable, TypeFoldable)] pub enum Adjust<'tcx> { /// Go from ! to any type. diff --git a/src/librustc/ty/context.rs b/src/librustc/ty/context.rs index 6b98fddb22e..ef776c88a8f 100644 --- a/src/librustc/ty/context.rs +++ b/src/librustc/ty/context.rs @@ -315,8 +315,7 @@ pub struct ResolvedOpaqueTy<'tcx> { /// /// Here, we would store the type `T`, the span of the value `x`, and the "scope-span" for /// the scope that contains `x`. -#[derive(RustcEncodable, RustcDecodable, Clone, Debug, Eq, Hash, PartialEq)] -#[derive(HashStable, TypeFoldable)] +#[derive(RustcEncodable, RustcDecodable, Clone, Debug, Eq, Hash, PartialEq, HashStable)] pub struct GeneratorInteriorTypeCause<'tcx> { /// Type of the captured binding. pub ty: Ty<'tcx>, @@ -324,6 +323,8 @@ pub struct GeneratorInteriorTypeCause<'tcx> { pub span: Span, /// Span of the scope of the captured binding. pub scope_span: Option, + /// Expr which the type evaluated from. + pub expr: Option, } #[derive(RustcEncodable, RustcDecodable, Debug)] @@ -436,7 +437,7 @@ pub struct TypeckTables<'tcx> { /// entire variable. pub upvar_list: ty::UpvarListMap, - /// Stores the type, span and optional scope span of all types + /// Stores the type, expression, span and optional scope span of all types /// that are live across the yield of this generator (if a generator). pub generator_interior_types: Vec>, } diff --git a/src/librustc_typeck/check/generator_interior.rs b/src/librustc_typeck/check/generator_interior.rs index 9d8805f225d..fc02d17a50f 100644 --- a/src/librustc_typeck/check/generator_interior.rs +++ b/src/librustc_typeck/check/generator_interior.rs @@ -97,6 +97,7 @@ impl<'a, 'tcx> InteriorVisitor<'a, 'tcx> { span: source_span, ty: &ty, scope_span, + expr: expr.map(|e| e.hir_id), }) .or_insert(entries); } @@ -164,17 +165,25 @@ pub fn resolve_interior<'a, 'tcx>( // which means that none of the regions inside relate to any other, even if // typeck had previously found constraints that would cause them to be related. let mut counter = 0; - let types = fcx.tcx.fold_regions(&types, &mut false, |_, current_depth| { + let fold_types: Vec<_> = types.iter().map(|(t, _)| t.ty).collect(); + let folded_types = fcx.tcx.fold_regions(&fold_types, &mut false, |_, current_depth| { counter += 1; fcx.tcx.mk_region(ty::ReLateBound(current_depth, ty::BrAnon(counter))) }); // Store the generator types and spans into the tables for this generator. - let interior_types = types.iter().map(|t| t.0.clone()).collect::>(); - visitor.fcx.inh.tables.borrow_mut().generator_interior_types = interior_types; + let types = types + .into_iter() + .zip(&folded_types) + .map(|((mut interior_cause, _), ty)| { + interior_cause.ty = ty; + interior_cause + }) + .collect(); + visitor.fcx.inh.tables.borrow_mut().generator_interior_types = types; // Extract type components - let type_list = fcx.tcx.mk_type_list(types.into_iter().map(|t| (t.0).ty)); + let type_list = fcx.tcx.mk_type_list(folded_types.iter()); let witness = fcx.tcx.mk_generator_witness(ty::Binder::bind(type_list)); diff --git a/src/test/ui/async-await/issue-64130-4-async-move.stderr b/src/test/ui/async-await/issue-64130-4-async-move.stderr index ddbb469b99c..77d0885c38d 100644 --- a/src/test/ui/async-await/issue-64130-4-async-move.stderr +++ b/src/test/ui/async-await/issue-64130-4-async-move.stderr @@ -16,6 +16,11 @@ LL | let _x = get().await; ... LL | } | - `client` is later dropped here +help: consider moving this method call into a `let` binding to create a shorter lived borrow + --> $DIR/issue-64130-4-async-move.rs:19:15 + | +LL | match client.status() { + | ^^^^^^^^^^^^^^^ = note: the return type of a function must have a statically known size error: aborting due to previous error diff --git a/src/test/ui/generator/not-send-sync.stderr b/src/test/ui/generator/not-send-sync.stderr index 0ac1d189b79..18d9012b3ac 100644 --- a/src/test/ui/generator/not-send-sync.stderr +++ b/src/test/ui/generator/not-send-sync.stderr @@ -20,7 +20,7 @@ LL | fn assert_sync(_: T) {} LL | assert_sync(|| { | ^^^^^^^^^^^ future returned by `main` is not `Sync` | - = help: within `[generator@$DIR/not-send-sync.rs:9:17: 13:6 {std::cell::Cell, ()}]`, the trait `std::marker::Sync` is not implemented for `std::cell::Cell` + = help: within `[generator@$DIR/not-send-sync.rs:9:17: 13:6 {std::cell::Cell, (), ()}]`, the trait `std::marker::Sync` is not implemented for `std::cell::Cell` note: future is not `Sync` as this value is used across an yield --> $DIR/not-send-sync.rs:12:9 | diff --git a/src/test/ui/impl-trait/recursive-impl-trait-type-indirect.stderr b/src/test/ui/impl-trait/recursive-impl-trait-type-indirect.stderr index b7ba0d6ab17..15a028f60ae 100644 --- a/src/test/ui/impl-trait/recursive-impl-trait-type-indirect.stderr +++ b/src/test/ui/impl-trait/recursive-impl-trait-type-indirect.stderr @@ -76,7 +76,7 @@ error[E0720]: opaque type expands to a recursive type LL | fn generator_capture() -> impl Sized { | ^^^^^^^^^^ expands to a recursive type | - = note: expanded type is `[generator@$DIR/recursive-impl-trait-type-indirect.rs:50:5: 50:26 x:impl Sized {()}]` + = note: expanded type is `[generator@$DIR/recursive-impl-trait-type-indirect.rs:50:5: 50:26 x:impl Sized {(), ()}]` error[E0720]: opaque type expands to a recursive type --> $DIR/recursive-impl-trait-type-indirect.rs:53:26 @@ -92,7 +92,7 @@ error[E0720]: opaque type expands to a recursive type LL | fn generator_hold() -> impl Sized { | ^^^^^^^^^^ expands to a recursive type | - = note: expanded type is `[generator@$DIR/recursive-impl-trait-type-indirect.rs:58:5: 62:6 {impl Sized, ()}]` + = note: expanded type is `[generator@$DIR/recursive-impl-trait-type-indirect.rs:58:5: 62:6 {impl Sized, (), ()}]` error[E0720]: opaque type expands to a recursive type --> $DIR/recursive-impl-trait-type-indirect.rs:69:26