about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs152
-rw-r--r--src/test/ui/async-await/issue-70935-complex-spans.rs25
-rw-r--r--src/test/ui/async-await/issue-70935-complex-spans.stderr30
-rw-r--r--src/test/ui/async-await/issues/issue-65436-raw-ptr-not-send.stderr12
4 files changed, 186 insertions, 33 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..1c6e661782f 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,130 @@ 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`
+                    //
+                    // 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;
+                    //    | |________________^ first, await occurs here, with the value maybe used later...
+                    // note: the value is later dropped here
+                    //   --> $DIR/issue-70935-complex-spans.rs:15:17
+                    //    |
+                    // LL |         }).await;
+                    //    |                 ^
+                    //
+                    // 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 {
+                            span.push_span_label(
+                                yield_span,
+                                format!(
+                                    "first, {} occurs here, with {} maybe used later...",
+                                    await_or_yield, snippet
+                                ),
+                            );
+                            err.span_note(
+                                span,
+                                &format!(
+                                    "{} {} as this value is used across {}",
+                                    future_or_generator, trait_explanation, an_await_or_yield
+                                ),
+                            );
+                            if source_map.is_multiline(interior_span) {
+                                err.span_note(
+                                    scope_span,
+                                    &format!("{} is later dropped here", snippet),
+                                );
+                                err.span_note(
+                                    interior_span,
+                                    &format!(
+                                        "this has type `{}` which {}",
+                                        target_ty, trait_explanation
+                                    ),
+                                );
+                            } else {
+                                let mut span = MultiSpan::from_span(scope_span);
+                                span.push_span_label(
+                                    interior_span,
+                                    format!("has type `{}` which {}", target_ty, trait_explanation),
+                                );
+                                err.span_note(span, &format!("{} 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.rs b/src/test/ui/async-await/issue-70935-complex-spans.rs
new file mode 100644
index 00000000000..2965a7e0654
--- /dev/null
+++ b/src/test/ui/async-await/issue-70935-complex-spans.rs
@@ -0,0 +1,25 @@
+// edition:2018
+// #70935: Check if we do not emit snippet
+// with newlines which lead complex diagnostics.
+
+use std::future::Future;
+
+async fn baz<T>(_c: impl FnMut() -> T) where T: Future<Output=()> {
+}
+
+fn foo(tx: std::sync::mpsc::Sender<i32>) -> impl Future + Send {
+    //~^ ERROR: future cannot be sent between threads safely
+    async move {
+        baz(|| async{
+            foo(tx.clone());
+        }).await;
+    }
+}
+
+fn bar(_s: impl Future + Send) {
+}
+
+fn main() {
+    let (tx, _rx) = std::sync::mpsc::channel();
+    bar(foo(tx));
+}
diff --git a/src/test/ui/async-await/issue-70935-complex-spans.stderr b/src/test/ui/async-await/issue-70935-complex-spans.stderr
new file mode 100644
index 00000000000..8451fb84099
--- /dev/null
+++ b/src/test/ui/async-await/issue-70935-complex-spans.stderr
@@ -0,0 +1,30 @@
+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`
+   |
+   = 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;
+   | |________________^ first, await occurs here, with the value maybe used later...
+note: the value is later dropped here
+  --> $DIR/issue-70935-complex-spans.rs:15:17
+   |
+LL |         }).await;
+   |                 ^
+note: this has type `[closure@$DIR/issue-70935-complex-spans.rs:13:13: 15:10]` which is not `Send`
+  --> $DIR/issue-70935-complex-spans.rs:13:13
+   |
+LL |           baz(|| async{
+   |  _____________^
+LL | |             foo(tx.clone());
+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..5568dab8655 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,14 @@ 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
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ first, await occurs here, with `std::ptr::null()` maybe used later...
+note: `std::ptr::null()` is later dropped here
+  --> $DIR/issue-65436-raw-ptr-not-send.rs:14:41
+   |
+LL |         bar(Foo(std::ptr::null())).await;
+   |                 ----------------        ^
+   |                 |
+   |                 has type `*const u8` which is not `Send`
 help: consider moving this into a `let` binding to create a shorter lived borrow
   --> $DIR/issue-65436-raw-ptr-not-send.rs:14:13
    |