From bc1595473bad5ab808b2734260286ba0f847546a Mon Sep 17 00:00:00 2001 From: csmoe Date: Thu, 16 Apr 2020 23:13:44 +0800 Subject: [PATCH 1/2] record await span inside GeneratorInteriorTypeCause --- src/librustc_middle/ty/context.rs | 8 +++-- .../traits/error_reporting/suggestions.rs | 30 +++++++++++-------- .../check/generator_interior.rs | 1 + 3 files changed, 24 insertions(+), 15 deletions(-) diff --git a/src/librustc_middle/ty/context.rs b/src/librustc_middle/ty/context.rs index a49dc105498ed..e127c222dacd4 100644 --- a/src/librustc_middle/ty/context.rs +++ b/src/librustc_middle/ty/context.rs @@ -298,14 +298,14 @@ pub struct ResolvedOpaqueTy<'tcx> { /// /// ```ignore (pseudo-Rust) /// async move { -/// let x: T = ...; +/// let x: T = expr; /// foo.await /// ... /// } /// ``` /// -/// Here, we would store the type `T`, the span of the value `x`, and the "scope-span" for -/// the scope that contains `x`. +/// Here, we would store the type `T`, the span of the value `x`, the "scope-span" for +/// the scope that contains `x`, the expr `T` evaluated from, and the span of `foo.await`. #[derive(RustcEncodable, RustcDecodable, Clone, Debug, Eq, Hash, PartialEq, HashStable)] pub struct GeneratorInteriorTypeCause<'tcx> { /// Type of the captured binding. @@ -314,6 +314,8 @@ pub struct GeneratorInteriorTypeCause<'tcx> { pub span: Span, /// Span of the scope of the captured binding. pub scope_span: Option, + /// Span of `.await` statement. + pub await_span: Span, /// Expr which the type evaluated from. pub expr: Option, } diff --git a/src/librustc_trait_selection/traits/error_reporting/suggestions.rs b/src/librustc_trait_selection/traits/error_reporting/suggestions.rs index 254db6cb869b1..c0e14d044ecb8 100644 --- a/src/librustc_trait_selection/traits/error_reporting/suggestions.rs +++ b/src/librustc_trait_selection/traits/error_reporting/suggestions.rs @@ -125,6 +125,7 @@ pub trait InferCtxtExt<'tcx> { err: &mut DiagnosticBuilder<'_>, target_span: Span, scope_span: &Option, + await_span: Span, expr: Option, snippet: String, inner_generator_body: Option<&hir::Body<'_>>, @@ -1260,20 +1261,31 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { ty_matches(ty) }) .map(|expr| expr.span); - let ty::GeneratorInteriorTypeCause { span, scope_span, expr, .. } = cause; - (span, source_map.span_to_snippet(*span), scope_span, expr, from_awaited_ty) + let ty::GeneratorInteriorTypeCause { span, scope_span, await_span, expr, .. } = + cause; + ( + span, + source_map.span_to_snippet(*span), + scope_span, + await_span, + expr, + from_awaited_ty, + ) }); debug!( "maybe_note_obligation_cause_for_async_await: target_ty={:?} \ - generator_interior_types={:?} target_span={:?}", - target_ty, tables.generator_interior_types, target_span + generator_interior_types={:?} target_span={:?} await_span={:?}", + target_ty, tables.generator_interior_types, target_span, await_span ); - if let Some((target_span, Ok(snippet), scope_span, expr, from_awaited_ty)) = target_span { + if let Some((target_span, Ok(snippet), scope_span, await_span, expr, from_awaited_ty)) = + target_span + { self.note_obligation_cause_for_async_await( err, *target_span, scope_span, + await_span, *expr, snippet, generator_body, @@ -1298,6 +1310,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { err: &mut DiagnosticBuilder<'_>, target_span: Span, scope_span: &Option, + await_span: Span, expr: Option, snippet: String, inner_generator_body: Option<&hir::Body<'_>>, @@ -1373,12 +1386,6 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { if let Some(await_span) = from_awaited_ty { // The type causing this obligation is one being awaited at await_span. let mut span = MultiSpan::from_span(await_span); - - span.push_span_label( - await_span, - format!("await occurs here on type `{}`, which {}", target_ty, trait_explanation), - ); - err.span_note( span, &format!( @@ -1392,7 +1399,6 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { "note_obligation_cause_for_async_await generator_interior_types: {:#?}", tables.generator_interior_types ); - 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, diff --git a/src/librustc_typeck/check/generator_interior.rs b/src/librustc_typeck/check/generator_interior.rs index db9c8c35c2cee..99e01a0332f49 100644 --- a/src/librustc_typeck/check/generator_interior.rs +++ b/src/librustc_typeck/check/generator_interior.rs @@ -96,6 +96,7 @@ impl<'a, 'tcx> InteriorVisitor<'a, 'tcx> { span: source_span, ty: &ty, scope_span, + await_span: yield_data.span, expr: expr.map(|e| e.hir_id), }) .or_insert(entries); From 00d12ef9016f2eab194488ac7d51567175eddebc Mon Sep 17 00:00:00 2001 From: csmoe Date: Thu, 16 Apr 2020 23:14:11 +0800 Subject: [PATCH 2/2] add test for correct await span --- src/librustc_middle/ty/context.rs | 4 ++-- .../traits/error_reporting/suggestions.rs | 24 ++++++++++++------- .../check/generator_interior.rs | 2 +- src/test/ui/async-await/issue-71137.rs | 21 ++++++++++++++++ src/test/ui/async-await/issue-71137.stderr | 23 ++++++++++++++++++ 5 files changed, 62 insertions(+), 12 deletions(-) create mode 100644 src/test/ui/async-await/issue-71137.rs create mode 100644 src/test/ui/async-await/issue-71137.stderr diff --git a/src/librustc_middle/ty/context.rs b/src/librustc_middle/ty/context.rs index e127c222dacd4..c6228a913cfe2 100644 --- a/src/librustc_middle/ty/context.rs +++ b/src/librustc_middle/ty/context.rs @@ -314,8 +314,8 @@ pub struct GeneratorInteriorTypeCause<'tcx> { pub span: Span, /// Span of the scope of the captured binding. pub scope_span: Option, - /// Span of `.await` statement. - pub await_span: Span, + /// Span of `.await` or `yield` expression. + pub yield_span: Span, /// Expr which the type evaluated from. pub expr: Option, } diff --git a/src/librustc_trait_selection/traits/error_reporting/suggestions.rs b/src/librustc_trait_selection/traits/error_reporting/suggestions.rs index c0e14d044ecb8..51ac552c31239 100644 --- a/src/librustc_trait_selection/traits/error_reporting/suggestions.rs +++ b/src/librustc_trait_selection/traits/error_reporting/suggestions.rs @@ -1261,13 +1261,13 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { ty_matches(ty) }) .map(|expr| expr.span); - let ty::GeneratorInteriorTypeCause { span, scope_span, await_span, expr, .. } = + let ty::GeneratorInteriorTypeCause { span, scope_span, yield_span, expr, .. } = cause; ( span, source_map.span_to_snippet(*span), scope_span, - await_span, + yield_span, expr, from_awaited_ty, ) @@ -1275,17 +1275,17 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { debug!( "maybe_note_obligation_cause_for_async_await: target_ty={:?} \ - generator_interior_types={:?} target_span={:?} await_span={:?}", - target_ty, tables.generator_interior_types, target_span, await_span + generator_interior_types={:?} target_span={:?}", + target_ty, tables.generator_interior_types, target_span ); - if let Some((target_span, Ok(snippet), scope_span, await_span, expr, from_awaited_ty)) = + if let Some((target_span, Ok(snippet), scope_span, yield_span, expr, from_awaited_ty)) = target_span { self.note_obligation_cause_for_async_await( err, *target_span, scope_span, - await_span, + *yield_span, *expr, snippet, generator_body, @@ -1310,7 +1310,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { err: &mut DiagnosticBuilder<'_>, target_span: Span, scope_span: &Option, - await_span: Span, + yield_span: Span, expr: Option, snippet: String, inner_generator_body: Option<&hir::Body<'_>>, @@ -1386,6 +1386,12 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { if let Some(await_span) = from_awaited_ty { // The type causing this obligation is one being awaited at await_span. let mut span = MultiSpan::from_span(await_span); + + span.push_span_label( + await_span, + format!("await occurs here on type `{}`, which {}", target_ty, trait_explanation), + ); + err.span_note( span, &format!( @@ -1399,9 +1405,9 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { "note_obligation_cause_for_async_await generator_interior_types: {:#?}", tables.generator_interior_types ); - let mut span = MultiSpan::from_span(await_span); + let mut span = MultiSpan::from_span(yield_span); span.push_span_label( - await_span, + yield_span, format!("{} occurs here, with `{}` maybe used later", await_or_yield, snippet), ); diff --git a/src/librustc_typeck/check/generator_interior.rs b/src/librustc_typeck/check/generator_interior.rs index 99e01a0332f49..716d23b4d173c 100644 --- a/src/librustc_typeck/check/generator_interior.rs +++ b/src/librustc_typeck/check/generator_interior.rs @@ -96,7 +96,7 @@ impl<'a, 'tcx> InteriorVisitor<'a, 'tcx> { span: source_span, ty: &ty, scope_span, - await_span: yield_data.span, + yield_span: yield_data.span, expr: expr.map(|e| e.hir_id), }) .or_insert(entries); diff --git a/src/test/ui/async-await/issue-71137.rs b/src/test/ui/async-await/issue-71137.rs new file mode 100644 index 0000000000000..ebb392a45308e --- /dev/null +++ b/src/test/ui/async-await/issue-71137.rs @@ -0,0 +1,21 @@ +// edition:2018 + +use std::future::Future; +use std::sync::Mutex; + +fn fake_spawn(f: F) { } + +async fn wrong_mutex() { + let m = Mutex::new(1); + { + let mut guard = m.lock().unwrap(); + (async { "right"; }).await; + *guard += 1; + } + + (async { "wrong"; }).await; +} + +fn main() { + fake_spawn(wrong_mutex()); //~ Error future cannot be sent between threads safely +} diff --git a/src/test/ui/async-await/issue-71137.stderr b/src/test/ui/async-await/issue-71137.stderr new file mode 100644 index 0000000000000..788a9bc2c7e47 --- /dev/null +++ b/src/test/ui/async-await/issue-71137.stderr @@ -0,0 +1,23 @@ +error: future cannot be sent between threads safely + --> $DIR/issue-71137.rs:20:3 + | +LL | fn fake_spawn(f: F) { } + | ---- required by this bound in `fake_spawn` +... +LL | fake_spawn(wrong_mutex()); + | ^^^^^^^^^^ future returned by `wrong_mutex` is not `Send` + | + = help: within `impl std::future::Future`, the trait `std::marker::Send` is not implemented for `std::sync::MutexGuard<'_, i32>` +note: future is not `Send` as this value is used across an await + --> $DIR/issue-71137.rs:12:5 + | +LL | let mut guard = m.lock().unwrap(); + | --------- has type `std::sync::MutexGuard<'_, i32>` which is not `Send` +LL | (async { "right"; }).await; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ await occurs here, with `mut guard` maybe used later +LL | *guard += 1; +LL | } + | - `mut guard` is later dropped here + +error: aborting due to previous error +