Skip to content

Commit 234099d

Browse files
committed
Auto merge of #75020 - JohnTitor:fix-multispan, r=estebank,tmandry
Avoid complex diagnostics in snippets which contain newlines Fixes #70935 r? `@estebank` `@tmandry`
2 parents 3e93027 + 8d65101 commit 234099d

File tree

4 files changed

+186
-33
lines changed

4 files changed

+186
-33
lines changed

compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs

+123-29
Original file line numberDiff line numberDiff line change
@@ -1570,36 +1570,130 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
15701570
format!("does not implement `{}`", trait_ref.print_only_trait_path())
15711571
};
15721572

1573-
let mut explain_yield = |interior_span: Span,
1574-
yield_span: Span,
1575-
scope_span: Option<Span>| {
1576-
let mut span = MultiSpan::from_span(yield_span);
1577-
if let Ok(snippet) = source_map.span_to_snippet(interior_span) {
1578-
span.push_span_label(
1579-
yield_span,
1580-
format!("{} occurs here, with `{}` maybe used later", await_or_yield, snippet),
1581-
);
1582-
// If available, use the scope span to annotate the drop location.
1583-
if let Some(scope_span) = scope_span {
1584-
span.push_span_label(
1585-
source_map.end_point(scope_span),
1586-
format!("`{}` is later dropped here", snippet),
1587-
);
1573+
let mut explain_yield =
1574+
|interior_span: Span, yield_span: Span, scope_span: Option<Span>| {
1575+
let mut span = MultiSpan::from_span(yield_span);
1576+
if let Ok(snippet) = source_map.span_to_snippet(interior_span) {
1577+
// #70935: If snippet contains newlines, display "the value" instead
1578+
// so that we do not emit complex diagnostics.
1579+
let snippet = &format!("`{}`", snippet);
1580+
let snippet = if snippet.contains('\n') { "the value" } else { snippet };
1581+
// The multispan can be complex here, like:
1582+
// note: future is not `Send` as this value is used across an await
1583+
// --> $DIR/issue-70935-complex-spans.rs:13:9
1584+
// |
1585+
// LL | baz(|| async{
1586+
// | __________^___-
1587+
// | | _________|
1588+
// | ||
1589+
// LL | || foo(tx.clone());
1590+
// LL | || }).await;
1591+
// | || - ^- value is later dropped here
1592+
// | ||_________|______|
1593+
// | |__________| await occurs here, with value maybe used later
1594+
// | has type `closure` which is not `Send`
1595+
//
1596+
// So, detect it and separate into some notes, like:
1597+
//
1598+
// note: future is not `Send` as this value is used across an await
1599+
// --> $DIR/issue-70935-complex-spans.rs:13:9
1600+
// |
1601+
// LL | / baz(|| async{
1602+
// LL | | foo(tx.clone());
1603+
// LL | | }).await;
1604+
// | |________________^ first, await occurs here, with the value maybe used later...
1605+
// note: the value is later dropped here
1606+
// --> $DIR/issue-70935-complex-spans.rs:15:17
1607+
// |
1608+
// LL | }).await;
1609+
// | ^
1610+
//
1611+
// If available, use the scope span to annotate the drop location.
1612+
if let Some(scope_span) = scope_span {
1613+
let scope_span = source_map.end_point(scope_span);
1614+
let is_overlapped =
1615+
yield_span.overlaps(scope_span) || yield_span.overlaps(interior_span);
1616+
if is_overlapped {
1617+
span.push_span_label(
1618+
yield_span,
1619+
format!(
1620+
"first, {} occurs here, with {} maybe used later...",
1621+
await_or_yield, snippet
1622+
),
1623+
);
1624+
err.span_note(
1625+
span,
1626+
&format!(
1627+
"{} {} as this value is used across {}",
1628+
future_or_generator, trait_explanation, an_await_or_yield
1629+
),
1630+
);
1631+
if source_map.is_multiline(interior_span) {
1632+
err.span_note(
1633+
scope_span,
1634+
&format!("{} is later dropped here", snippet),
1635+
);
1636+
err.span_note(
1637+
interior_span,
1638+
&format!(
1639+
"this has type `{}` which {}",
1640+
target_ty, trait_explanation
1641+
),
1642+
);
1643+
} else {
1644+
let mut span = MultiSpan::from_span(scope_span);
1645+
span.push_span_label(
1646+
interior_span,
1647+
format!("has type `{}` which {}", target_ty, trait_explanation),
1648+
);
1649+
err.span_note(span, &format!("{} is later dropped here", snippet));
1650+
}
1651+
} else {
1652+
span.push_span_label(
1653+
yield_span,
1654+
format!(
1655+
"{} occurs here, with {} maybe used later",
1656+
await_or_yield, snippet
1657+
),
1658+
);
1659+
span.push_span_label(
1660+
scope_span,
1661+
format!("{} is later dropped here", snippet),
1662+
);
1663+
span.push_span_label(
1664+
interior_span,
1665+
format!("has type `{}` which {}", target_ty, trait_explanation),
1666+
);
1667+
err.span_note(
1668+
span,
1669+
&format!(
1670+
"{} {} as this value is used across {}",
1671+
future_or_generator, trait_explanation, an_await_or_yield
1672+
),
1673+
);
1674+
}
1675+
} else {
1676+
span.push_span_label(
1677+
yield_span,
1678+
format!(
1679+
"{} occurs here, with {} maybe used later",
1680+
await_or_yield, snippet
1681+
),
1682+
);
1683+
span.push_span_label(
1684+
interior_span,
1685+
format!("has type `{}` which {}", target_ty, trait_explanation),
1686+
);
1687+
err.span_note(
1688+
span,
1689+
&format!(
1690+
"{} {} as this value is used across {}",
1691+
future_or_generator, trait_explanation, an_await_or_yield
1692+
),
1693+
);
1694+
}
15881695
}
1589-
}
1590-
span.push_span_label(
1591-
interior_span,
1592-
format!("has type `{}` which {}", target_ty, trait_explanation),
1593-
);
1594-
1595-
err.span_note(
1596-
span,
1597-
&format!(
1598-
"{} {} as this value is used across {}",
1599-
future_or_generator, trait_explanation, an_await_or_yield
1600-
),
1601-
);
1602-
};
1696+
};
16031697
match interior_or_upvar_span {
16041698
GeneratorInteriorOrUpvar::Interior(interior_span) => {
16051699
if let Some((scope_span, yield_span, expr, from_awaited_ty)) = interior_extra_info {
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
// edition:2018
2+
// #70935: Check if we do not emit snippet
3+
// with newlines which lead complex diagnostics.
4+
5+
use std::future::Future;
6+
7+
async fn baz<T>(_c: impl FnMut() -> T) where T: Future<Output=()> {
8+
}
9+
10+
fn foo(tx: std::sync::mpsc::Sender<i32>) -> impl Future + Send {
11+
//~^ ERROR: future cannot be sent between threads safely
12+
async move {
13+
baz(|| async{
14+
foo(tx.clone());
15+
}).await;
16+
}
17+
}
18+
19+
fn bar(_s: impl Future + Send) {
20+
}
21+
22+
fn main() {
23+
let (tx, _rx) = std::sync::mpsc::channel();
24+
bar(foo(tx));
25+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
error: future cannot be sent between threads safely
2+
--> $DIR/issue-70935-complex-spans.rs:10:45
3+
|
4+
LL | fn foo(tx: std::sync::mpsc::Sender<i32>) -> impl Future + Send {
5+
| ^^^^^^^^^^^^^^^^^^ future created by async block is not `Send`
6+
|
7+
= help: the trait `Sync` is not implemented for `Sender<i32>`
8+
note: future is not `Send` as this value is used across an await
9+
--> $DIR/issue-70935-complex-spans.rs:13:9
10+
|
11+
LL | / baz(|| async{
12+
LL | | foo(tx.clone());
13+
LL | | }).await;
14+
| |________________^ first, await occurs here, with the value maybe used later...
15+
note: the value is later dropped here
16+
--> $DIR/issue-70935-complex-spans.rs:15:17
17+
|
18+
LL | }).await;
19+
| ^
20+
note: this has type `[closure@$DIR/issue-70935-complex-spans.rs:13:13: 15:10]` which is not `Send`
21+
--> $DIR/issue-70935-complex-spans.rs:13:13
22+
|
23+
LL | baz(|| async{
24+
| _____________^
25+
LL | | foo(tx.clone());
26+
LL | | }).await;
27+
| |_________^
28+
29+
error: aborting due to previous error
30+

src/test/ui/async-await/issues/issue-65436-raw-ptr-not-send.stderr

+8-4
Original file line numberDiff line numberDiff line change
@@ -12,10 +12,14 @@ note: future is not `Send` as this value is used across an await
1212
--> $DIR/issue-65436-raw-ptr-not-send.rs:14:9
1313
|
1414
LL | bar(Foo(std::ptr::null())).await;
15-
| ^^^^^^^^----------------^^^^^^^^- `std::ptr::null()` is later dropped here
16-
| | |
17-
| | has type `*const u8` which is not `Send`
18-
| await occurs here, with `std::ptr::null()` maybe used later
15+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ first, await occurs here, with `std::ptr::null()` maybe used later...
16+
note: `std::ptr::null()` is later dropped here
17+
--> $DIR/issue-65436-raw-ptr-not-send.rs:14:41
18+
|
19+
LL | bar(Foo(std::ptr::null())).await;
20+
| ---------------- ^
21+
| |
22+
| has type `*const u8` which is not `Send`
1923
help: consider moving this into a `let` binding to create a shorter lived borrow
2024
--> $DIR/issue-65436-raw-ptr-not-send.rs:14:13
2125
|

0 commit comments

Comments
 (0)