Skip to content

Commit 6dcff4e

Browse files
committed
Use the "nice E0277 errors"[1] for !Send impl Future from foreign crate
Partly address rust-lang#78543 by making the error quieter. We don't have access to the `typeck` tables from foreign crates, so we used to completely skip the new code when checking foreign crates. Now, we carry on and don't provide as nice output (we don't clarify *what* is making the `Future: !Send`), but at least we no longer emit a sea of derived obligations in the output. [1]: https://blog.rust-lang.org/inside-rust/2019/10/11/AsyncAwait-Not-Send-Error-Improvements.html
1 parent ed08a67 commit 6dcff4e

File tree

3 files changed

+73
-91
lines changed

3 files changed

+73
-91
lines changed

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

+70-77
Original file line numberDiff line numberDiff line change
@@ -151,7 +151,7 @@ pub trait InferCtxtExt<'tcx> {
151151
outer_generator: Option<DefId>,
152152
trait_ref: ty::TraitRef<'tcx>,
153153
target_ty: Ty<'tcx>,
154-
typeck_results: &ty::TypeckResults<'tcx>,
154+
typeck_results: Option<&ty::TypeckResults<'tcx>>,
155155
obligation: &PredicateObligation<'tcx>,
156156
next_code: Option<&ObligationCauseCode<'tcx>>,
157157
);
@@ -1463,11 +1463,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
14631463
}
14641464

14651465
// Only continue if a generator was found.
1466-
debug!(
1467-
"maybe_note_obligation_cause_for_async_await: generator={:?} trait_ref={:?} \
1468-
target_ty={:?}",
1469-
generator, trait_ref, target_ty
1470-
);
1466+
debug!(?generator, ?trait_ref, ?target_ty, "maybe_note_obligation_cause_for_async_await");
14711467
let (generator_did, trait_ref, target_ty) = match (generator, trait_ref, target_ty) {
14721468
(Some(generator_did), Some(trait_ref), Some(target_ty)) => {
14731469
(generator_did, trait_ref, target_ty)
@@ -1477,14 +1473,6 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
14771473

14781474
let span = self.tcx.def_span(generator_did);
14791475

1480-
// Do not ICE on closure typeck (#66868).
1481-
if !generator_did.is_local() {
1482-
return false;
1483-
}
1484-
1485-
// Get the typeck results from the infcx if the generator is the function we are
1486-
// currently type-checking; otherwise, get them by performing a query.
1487-
// This is needed to avoid cycles.
14881476
let in_progress_typeck_results = self.in_progress_typeck_results.map(|t| t.borrow());
14891477
let generator_did_root = self.tcx.closure_base_def_id(generator_did);
14901478
debug!(
@@ -1495,14 +1483,6 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
14951483
in_progress_typeck_results.as_ref().map(|t| t.hir_owner),
14961484
span
14971485
);
1498-
let query_typeck_results;
1499-
let typeck_results: &TypeckResults<'tcx> = match &in_progress_typeck_results {
1500-
Some(t) if t.hir_owner.to_def_id() == generator_did_root => t,
1501-
_ => {
1502-
query_typeck_results = self.tcx.typeck(generator_did.expect_local());
1503-
&query_typeck_results
1504-
}
1505-
};
15061486

15071487
let generator_body = generator_did
15081488
.as_local()
@@ -1545,51 +1525,59 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
15451525
let mut interior_or_upvar_span = None;
15461526
let mut interior_extra_info = None;
15471527

1548-
if let Some(upvars) = self.tcx.upvars_mentioned(generator_did) {
1549-
interior_or_upvar_span = upvars.iter().find_map(|(upvar_id, upvar)| {
1550-
let upvar_ty = typeck_results.node_type(*upvar_id);
1551-
let upvar_ty = self.resolve_vars_if_possible(upvar_ty);
1552-
if ty_matches(ty::Binder::dummy(upvar_ty)) {
1553-
Some(GeneratorInteriorOrUpvar::Upvar(upvar.span))
1554-
} else {
1555-
None
1556-
}
1557-
});
1528+
// Get the typeck results from the infcx if the generator is the function we are currently
1529+
// type-checking; otherwise, get them by performing a query. This is needed to avoid
1530+
// cycles. If we can't use resolved types because the generator comes from another crate,
1531+
// we still provide a targeted error but without all the relevant spans.
1532+
let query_typeck_results;
1533+
let typeck_results: Option<&TypeckResults<'tcx>> = match &in_progress_typeck_results {
1534+
Some(t) if t.hir_owner.to_def_id() == generator_did_root => Some(&t),
1535+
_ if generator_did.is_local() => {
1536+
query_typeck_results = self.tcx.typeck(generator_did.expect_local());
1537+
Some(&query_typeck_results)
1538+
}
1539+
_ => None, // Do not ICE on closure typeck (#66868).
15581540
};
1541+
if let Some(typeck_results) = typeck_results {
1542+
if let Some(upvars) = self.tcx.upvars_mentioned(generator_did) {
1543+
interior_or_upvar_span = upvars.iter().find_map(|(upvar_id, upvar)| {
1544+
let upvar_ty = typeck_results.node_type(*upvar_id);
1545+
let upvar_ty = self.resolve_vars_if_possible(upvar_ty);
1546+
if ty_matches(ty::Binder::dummy(upvar_ty)) {
1547+
Some(GeneratorInteriorOrUpvar::Upvar(upvar.span))
1548+
} else {
1549+
None
1550+
}
1551+
});
1552+
};
15591553

1560-
// The generator interior types share the same binders
1561-
if let Some(cause) =
1562-
typeck_results.generator_interior_types.as_ref().skip_binder().iter().find(
1563-
|ty::GeneratorInteriorTypeCause { ty, .. }| {
1564-
ty_matches(typeck_results.generator_interior_types.rebind(ty))
1565-
},
1566-
)
1567-
{
1568-
// Check to see if any awaited expressions have the target type.
1569-
let from_awaited_ty = visitor
1570-
.awaits
1571-
.into_iter()
1572-
.map(|id| hir.expect_expr(id))
1573-
.find(|await_expr| {
1574-
let ty = typeck_results.expr_ty_adjusted(&await_expr);
1575-
debug!(
1576-
"maybe_note_obligation_cause_for_async_await: await_expr={:?}",
1577-
await_expr
1578-
);
1579-
ty_matches(ty::Binder::dummy(ty))
1580-
})
1581-
.map(|expr| expr.span);
1582-
let ty::GeneratorInteriorTypeCause { span, scope_span, yield_span, expr, .. } = cause;
1554+
// The generator interior types share the same binders
1555+
if let Some(cause) =
1556+
typeck_results.generator_interior_types.as_ref().skip_binder().iter().find(
1557+
|ty::GeneratorInteriorTypeCause { ty, .. }| {
1558+
ty_matches(typeck_results.generator_interior_types.rebind(ty))
1559+
},
1560+
)
1561+
{
1562+
// Check to see if any awaited expressions have the target type.
1563+
let from_awaited_ty = visitor
1564+
.awaits
1565+
.into_iter()
1566+
.map(|id| hir.expect_expr(id))
1567+
.find(|await_expr| {
1568+
ty_matches(ty::Binder::dummy(typeck_results.expr_ty_adjusted(&await_expr)))
1569+
})
1570+
.map(|expr| expr.span);
1571+
let ty::GeneratorInteriorTypeCause { span, scope_span, yield_span, expr, .. } =
1572+
cause;
15831573

1584-
interior_or_upvar_span = Some(GeneratorInteriorOrUpvar::Interior(*span));
1585-
interior_extra_info = Some((*scope_span, *yield_span, *expr, from_awaited_ty));
1586-
};
1574+
interior_or_upvar_span = Some(GeneratorInteriorOrUpvar::Interior(*span));
1575+
interior_extra_info = Some((*scope_span, *yield_span, *expr, from_awaited_ty));
1576+
};
1577+
} else {
1578+
interior_or_upvar_span = Some(GeneratorInteriorOrUpvar::Interior(span));
1579+
}
15871580

1588-
debug!(
1589-
"maybe_note_obligation_cause_for_async_await: interior_or_upvar={:?} \
1590-
generator_interior_types={:?}",
1591-
interior_or_upvar_span, typeck_results.generator_interior_types
1592-
);
15931581
if let Some(interior_or_upvar_span) = interior_or_upvar_span {
15941582
self.note_obligation_cause_for_async_await(
15951583
err,
@@ -1620,7 +1608,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
16201608
outer_generator: Option<DefId>,
16211609
trait_ref: ty::TraitRef<'tcx>,
16221610
target_ty: Ty<'tcx>,
1623-
typeck_results: &ty::TypeckResults<'tcx>,
1611+
typeck_results: Option<&ty::TypeckResults<'tcx>>,
16241612
obligation: &PredicateObligation<'tcx>,
16251613
next_code: Option<&ObligationCauseCode<'tcx>>,
16261614
) {
@@ -1831,7 +1819,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
18311819
// Look at the last interior type to get a span for the `.await`.
18321820
debug!(
18331821
"note_obligation_cause_for_async_await generator_interior_types: {:#?}",
1834-
typeck_results.generator_interior_types
1822+
typeck_results.as_ref().map(|t| &t.generator_interior_types)
18351823
);
18361824
explain_yield(interior_span, yield_span, scope_span);
18371825
}
@@ -1852,10 +1840,14 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
18521840
// ^^^^^^^ a temporary `&T` created inside this method call due to `&self`
18531841
// ```
18541842
//
1855-
let is_region_borrow = typeck_results
1856-
.expr_adjustments(expr)
1857-
.iter()
1858-
.any(|adj| adj.is_region_borrow());
1843+
let is_region_borrow = if let Some(typeck_results) = typeck_results {
1844+
typeck_results
1845+
.expr_adjustments(expr)
1846+
.iter()
1847+
.any(|adj| adj.is_region_borrow())
1848+
} else {
1849+
false
1850+
};
18591851

18601852
// ```rust
18611853
// struct Foo(*const u8);
@@ -1868,15 +1860,16 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
18681860
DefKind::Fn | DefKind::Ctor(..) => target_ty.is_unsafe_ptr(),
18691861
_ => false,
18701862
};
1871-
1872-
if (typeck_results.is_method_call(e) && is_region_borrow)
1873-
|| is_raw_borrow_inside_fn_like_call
1874-
{
1875-
err.span_help(
1876-
parent_span,
1877-
"consider moving this into a `let` \
1863+
if let Some(typeck_results) = typeck_results {
1864+
if (typeck_results.is_method_call(e) && is_region_borrow)
1865+
|| is_raw_borrow_inside_fn_like_call
1866+
{
1867+
err.span_help(
1868+
parent_span,
1869+
"consider moving this into a `let` \
18781870
binding to create a shorter lived borrow",
1879-
);
1871+
);
1872+
}
18801873
}
18811874
}
18821875
}

src/test/ui/async-await/issues/issue-67893.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -7,5 +7,5 @@ fn g(_: impl Send) {}
77

88
fn main() {
99
g(issue_67893::run())
10-
//~^ ERROR: `MutexGuard<'_, ()>` cannot be sent between threads safely
10+
//~^ ERROR generator cannot be sent between threads safely
1111
}
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,10 @@
1-
error[E0277]: `MutexGuard<'_, ()>` cannot be sent between threads safely
1+
error: generator cannot be sent between threads safely
22
--> $DIR/issue-67893.rs:9:5
33
|
44
LL | g(issue_67893::run())
5-
| ^ `MutexGuard<'_, ()>` cannot be sent between threads safely
6-
|
7-
::: $DIR/auxiliary/issue_67893.rs:7:20
8-
|
9-
LL | pub async fn run() {
10-
| - within this `impl Future`
5+
| ^ generator is not `Send`
116
|
127
= help: within `impl Future`, the trait `Send` is not implemented for `MutexGuard<'_, ()>`
13-
= note: required because it appears within the type `for<'r, 's, 't0, 't1, 't2, 't3> {ResumeTy, Arc<Mutex<()>>, &'r Mutex<()>, Result<MutexGuard<'s, ()>, PoisonError<MutexGuard<'t0, ()>>>, &'t1 MutexGuard<'t2, ()>, MutexGuard<'t3, ()>, (), impl Future}`
14-
= note: required because it appears within the type `[static generator@run::{closure#0}]`
15-
= note: required because it appears within the type `from_generator::GenFuture<[static generator@run::{closure#0}]>`
16-
= note: required because it appears within the type `impl Future`
17-
= note: required because it appears within the type `impl Future`
188
note: required by a bound in `g`
199
--> $DIR/issue-67893.rs:6:14
2010
|
@@ -23,4 +13,3 @@ LL | fn g(_: impl Send) {}
2313

2414
error: aborting due to previous error
2515

26-
For more information about this error, try `rustc --explain E0277`.

0 commit comments

Comments
 (0)