about summary refs log tree commit diff
diff options
context:
space:
mode:
authorYuki Okushi <huyuumi.dev@gmail.com>2020-10-11 03:05:57 +0900
committerYuki Okushi <huyuumi.dev@gmail.com>2020-11-02 15:53:59 +0900
commitad978e55722bdf35e5beb32fcaa52de39650f132 (patch)
treeb5238975ff35c3d3713f3268961b8df13b226386
parentc2695255a51f0f9507be7c531fdbeef237179b44 (diff)
downloadrust-ad978e55722bdf35e5beb32fcaa52de39650f132.tar.gz
rust-ad978e55722bdf35e5beb32fcaa52de39650f132.zip
Separate complex multispan into some notes
-rw-r--r--compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs143
-rw-r--r--src/test/ui/async-await/issue-70935-complex-spans.stderr40
-rw-r--r--src/test/ui/async-await/issues/issue-65436-raw-ptr-not-send.stderr15
3 files changed, 144 insertions, 54 deletions
diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs
index c0881befe24..56eb5e3686a 100644
--- a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs
+++ b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs
@@ -1570,36 +1570,121 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
             format!("does not implement `{}`", trait_ref.print_only_trait_path())
         };
 
-        let mut explain_yield = |interior_span: Span,
-                                 yield_span: Span,
-                                 scope_span: Option<Span>| {
-            let mut span = MultiSpan::from_span(yield_span);
-            if let Ok(snippet) = source_map.span_to_snippet(interior_span) {
-                span.push_span_label(
-                    yield_span,
-                    format!("{} occurs here, with `{}` maybe used later", await_or_yield, snippet),
-                );
-                // If available, use the scope span to annotate the drop location.
-                if let Some(scope_span) = scope_span {
-                    span.push_span_label(
-                        source_map.end_point(scope_span),
-                        format!("`{}` is later dropped here", snippet),
-                    );
+        let mut explain_yield =
+            |interior_span: Span, yield_span: Span, scope_span: Option<Span>| {
+                let mut span = MultiSpan::from_span(yield_span);
+                if let Ok(snippet) = source_map.span_to_snippet(interior_span) {
+                    // #70935: If snippet contains newlines, display "the value" instead
+                    // so that we do not emit complex diagnostics.
+                    let snippet = &format!("`{}`", snippet);
+                    let snippet = if snippet.contains('\n') { "the value" } else { snippet };
+                    // The multispan can be complex here, like:
+                    // note: future is not `Send` as this value is used across an await
+                    //   --> $DIR/issue-70935-complex-spans.rs:13:9
+                    //    |
+                    // LL |            baz(|| async{
+                    //    |  __________^___-
+                    //    | | _________|
+                    //    | ||
+                    // LL | ||             foo(tx.clone());
+                    // LL | ||         }).await;
+                    //    | ||         -      ^- value is later dropped here
+                    //    | ||_________|______|
+                    //    | |__________|      await occurs here, with value maybe used later
+                    //    |            has type `closure` which is not `Send`
+                    //    = note: the return type of a function must have a statically known size
+                    // So, detect it and separate into some notes, like:
+                    // note: future is not `Send` as this value is used across an await
+                    //   --> $DIR/issue-70935-complex-spans.rs:13:9
+                    //    |
+                    // LL | /         baz(|| async{
+                    // LL | |             foo(tx.clone());
+                    // LL | |         }).await;
+                    //    | |________________^
+                    // note: first, await occurs here, with the value maybe used later
+                    //   --> $DIR/issue-70935-complex-spans.rs:13:9
+                    //    |
+                    // LL | /         baz(|| async{
+                    // LL | |             foo(tx.clone());
+                    // LL | |         }).await;
+                    //    | |________________^
+                    // note: ...but, the value is later dropped here
+                    //   --> $DIR/issue-70935-complex-spans.rs:15:17
+                    //    |
+                    // LL |         }).await;
+                    //    |                 ^
+                    //    = note: the return type of a function must have a statically known size
+
+                    // If available, use the scope span to annotate the drop location.
+                    if let Some(scope_span) = scope_span {
+                        let scope_span = source_map.end_point(scope_span);
+                        let is_overlapped =
+                            yield_span.overlaps(scope_span) || yield_span.overlaps(interior_span);
+                        if is_overlapped {
+                            err.span_note(
+                                span,
+                                &format!(
+                                    "{} {} as this value is used across {}",
+                                    future_or_generator, trait_explanation, an_await_or_yield
+                                ),
+                            );
+                            err.span_note(
+                                yield_span,
+                                &format!(
+                                    "first, {} occurs here, with {} maybe used later",
+                                    await_or_yield, snippet
+                                ),
+                            );
+                            err.span_note(
+                                scope_span,
+                                &format!("...but, {} is later dropped here", snippet),
+                            );
+                        } else {
+                            span.push_span_label(
+                                yield_span,
+                                format!(
+                                    "{} occurs here, with {} maybe used later",
+                                    await_or_yield, snippet
+                                ),
+                            );
+                            span.push_span_label(
+                                scope_span,
+                                format!("{} is later dropped here", snippet),
+                            );
+                            span.push_span_label(
+                                interior_span,
+                                format!("has type `{}` which {}", target_ty, trait_explanation),
+                            );
+                            err.span_note(
+                                span,
+                                &format!(
+                                    "{} {} as this value is used across {}",
+                                    future_or_generator, trait_explanation, an_await_or_yield
+                                ),
+                            );
+                        }
+                    } else {
+                        span.push_span_label(
+                            yield_span,
+                            format!(
+                                "{} occurs here, with {} maybe used later",
+                                await_or_yield, snippet
+                            ),
+                        );
+                        span.push_span_label(
+                            interior_span,
+                            format!("has type `{}` which {}", target_ty, trait_explanation),
+                        );
+                        err.span_note(
+                            span,
+                            &format!(
+                                "{} {} as this value is used across {}",
+                                future_or_generator, trait_explanation, an_await_or_yield
+                            ),
+                        );
+                    }
                 }
-            }
-            span.push_span_label(
-                interior_span,
-                format!("has type `{}` which {}", target_ty, trait_explanation),
-            );
-
-            err.span_note(
-                span,
-                &format!(
-                    "{} {} as this value is used across {}",
-                    future_or_generator, trait_explanation, an_await_or_yield
-                ),
-            );
-        };
+            };
         match interior_or_upvar_span {
             GeneratorInteriorOrUpvar::Interior(interior_span) => {
                 if let Some((scope_span, yield_span, expr, from_awaited_ty)) = interior_extra_info {
diff --git a/src/test/ui/async-await/issue-70935-complex-spans.stderr b/src/test/ui/async-await/issue-70935-complex-spans.stderr
index d9ce038f72b..c55f8abc42d 100644
--- a/src/test/ui/async-await/issue-70935-complex-spans.stderr
+++ b/src/test/ui/async-await/issue-70935-complex-spans.stderr
@@ -1,31 +1,29 @@
 error: future cannot be sent between threads safely
   --> $DIR/issue-70935-complex-spans.rs:10:45
    |
-LL |   fn foo(tx: std::sync::mpsc::Sender<i32>) -> impl Future + Send {
-   |                                               ^^^^^^^^^^^^^^^^^^ future created by async block is not `Send`
-LL |
-LL | /     async move {
-LL | |         baz(|| async{
-LL | |             foo(tx.clone());
-LL | |         }).await;
-LL | |     }
-   | |_____- this returned value is of type `impl std::future::Future`
+LL | fn foo(tx: std::sync::mpsc::Sender<i32>) -> impl Future + Send {
+   |                                             ^^^^^^^^^^^^^^^^^^ future created by async block is not `Send`
    |
-   = help: the trait `std::marker::Sync` is not implemented for `std::sync::mpsc::Sender<i32>`
+   = help: the trait `Sync` is not implemented for `Sender<i32>`
 note: future is not `Send` as this value is used across an await
   --> $DIR/issue-70935-complex-spans.rs:13:9
    |
-LL |            baz(|| async{
-   |  __________^___-
-   | | _________|
-   | ||
-LL | ||             foo(tx.clone());
-LL | ||         }).await;
-   | ||         -      ^- value is later dropped here
-   | ||_________|______|
-   | |__________|      await occurs here, with value maybe used later
-   |            has type `[closure@$DIR/issue-70935-complex-spans.rs:13:13: 15:10 tx:&std::sync::mpsc::Sender<i32>]` which is not `Send`
-   = note: the return type of a function must have a statically known size
+LL | /         baz(|| async{
+LL | |             foo(tx.clone());
+LL | |         }).await;
+   | |________________^
+note: first, await occurs here, with the value maybe used later
+  --> $DIR/issue-70935-complex-spans.rs:13:9
+   |
+LL | /         baz(|| async{
+LL | |             foo(tx.clone());
+LL | |         }).await;
+   | |________________^
+note: ...but, the value is later dropped here
+  --> $DIR/issue-70935-complex-spans.rs:15:17
+   |
+LL |         }).await;
+   |                 ^
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/async-await/issues/issue-65436-raw-ptr-not-send.stderr b/src/test/ui/async-await/issues/issue-65436-raw-ptr-not-send.stderr
index e4b2725686a..6ffbcd7ea65 100644
--- a/src/test/ui/async-await/issues/issue-65436-raw-ptr-not-send.stderr
+++ b/src/test/ui/async-await/issues/issue-65436-raw-ptr-not-send.stderr
@@ -12,10 +12,17 @@ note: future is not `Send` as this value is used across an await
   --> $DIR/issue-65436-raw-ptr-not-send.rs:14:9
    |
 LL |         bar(Foo(std::ptr::null())).await;
-   |         ^^^^^^^^----------------^^^^^^^^- `std::ptr::null()` is later dropped here
-   |         |       |
-   |         |       has type `*const u8` which is not `Send`
-   |         await occurs here, with `std::ptr::null()` maybe used later
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+note: first, await occurs here, with `std::ptr::null()` maybe used later
+  --> $DIR/issue-65436-raw-ptr-not-send.rs:14:9
+   |
+LL |         bar(Foo(std::ptr::null())).await;
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+note: ...but, `std::ptr::null()` is later dropped here
+  --> $DIR/issue-65436-raw-ptr-not-send.rs:14:41
+   |
+LL |         bar(Foo(std::ptr::null())).await;
+   |                                         ^
 help: consider moving this into a `let` binding to create a shorter lived borrow
   --> $DIR/issue-65436-raw-ptr-not-send.rs:14:13
    |