Skip to content

Use the "nice E0277 errors"[1] for !Send impl Future from foreign crate #89889

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Oct 25, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -151,7 +151,7 @@ pub trait InferCtxtExt<'tcx> {
outer_generator: Option<DefId>,
trait_ref: ty::TraitRef<'tcx>,
target_ty: Ty<'tcx>,
typeck_results: &ty::TypeckResults<'tcx>,
typeck_results: Option<&ty::TypeckResults<'tcx>>,
obligation: &PredicateObligation<'tcx>,
next_code: Option<&ObligationCauseCode<'tcx>>,
);
Expand Down Expand Up @@ -1463,11 +1463,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
}

// Only continue if a generator was found.
debug!(
"maybe_note_obligation_cause_for_async_await: generator={:?} trait_ref={:?} \
target_ty={:?}",
generator, trait_ref, target_ty
);
debug!(?generator, ?trait_ref, ?target_ty, "maybe_note_obligation_cause_for_async_await");
let (generator_did, trait_ref, target_ty) = match (generator, trait_ref, target_ty) {
(Some(generator_did), Some(trait_ref), Some(target_ty)) => {
(generator_did, trait_ref, target_ty)
Expand All @@ -1477,14 +1473,6 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {

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

// Do not ICE on closure typeck (#66868).
if !generator_did.is_local() {
return false;
}

// Get the typeck results from the infcx if the generator is the function we are
// currently type-checking; otherwise, get them by performing a query.
// This is needed to avoid cycles.
let in_progress_typeck_results = self.in_progress_typeck_results.map(|t| t.borrow());
let generator_did_root = self.tcx.closure_base_def_id(generator_did);
debug!(
Expand All @@ -1495,14 +1483,6 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
in_progress_typeck_results.as_ref().map(|t| t.hir_owner),
span
);
let query_typeck_results;
let typeck_results: &TypeckResults<'tcx> = match &in_progress_typeck_results {
Some(t) if t.hir_owner.to_def_id() == generator_did_root => t,
_ => {
query_typeck_results = self.tcx.typeck(generator_did.expect_local());
&query_typeck_results
}
};

let generator_body = generator_did
.as_local()
Expand Down Expand Up @@ -1545,51 +1525,59 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
let mut interior_or_upvar_span = None;
let mut interior_extra_info = None;

if let Some(upvars) = self.tcx.upvars_mentioned(generator_did) {
interior_or_upvar_span = upvars.iter().find_map(|(upvar_id, upvar)| {
let upvar_ty = typeck_results.node_type(*upvar_id);
let upvar_ty = self.resolve_vars_if_possible(upvar_ty);
if ty_matches(ty::Binder::dummy(upvar_ty)) {
Some(GeneratorInteriorOrUpvar::Upvar(upvar.span))
} else {
None
}
});
// Get the typeck results from the infcx if the generator is the function we are currently
// type-checking; otherwise, get them by performing a query. This is needed to avoid
// cycles. If we can't use resolved types because the generator comes from another crate,
// we still provide a targeted error but without all the relevant spans.
let query_typeck_results;
let typeck_results: Option<&TypeckResults<'tcx>> = match &in_progress_typeck_results {
Some(t) if t.hir_owner.to_def_id() == generator_did_root => Some(&t),
_ if generator_did.is_local() => {
query_typeck_results = self.tcx.typeck(generator_did.expect_local());
Some(&query_typeck_results)
}
_ => None, // Do not ICE on closure typeck (#66868).
};
if let Some(typeck_results) = typeck_results {
if let Some(upvars) = self.tcx.upvars_mentioned(generator_did) {
interior_or_upvar_span = upvars.iter().find_map(|(upvar_id, upvar)| {
let upvar_ty = typeck_results.node_type(*upvar_id);
let upvar_ty = self.resolve_vars_if_possible(upvar_ty);
if ty_matches(ty::Binder::dummy(upvar_ty)) {
Some(GeneratorInteriorOrUpvar::Upvar(upvar.span))
} else {
None
}
});
};

// The generator interior types share the same binders
if let Some(cause) =
typeck_results.generator_interior_types.as_ref().skip_binder().iter().find(
|ty::GeneratorInteriorTypeCause { ty, .. }| {
ty_matches(typeck_results.generator_interior_types.rebind(ty))
},
)
{
// Check to see if any awaited expressions have the target type.
let from_awaited_ty = visitor
.awaits
.into_iter()
.map(|id| hir.expect_expr(id))
.find(|await_expr| {
let ty = typeck_results.expr_ty_adjusted(&await_expr);
debug!(
"maybe_note_obligation_cause_for_async_await: await_expr={:?}",
await_expr
);
ty_matches(ty::Binder::dummy(ty))
})
.map(|expr| expr.span);
let ty::GeneratorInteriorTypeCause { span, scope_span, yield_span, expr, .. } = cause;
// The generator interior types share the same binders
if let Some(cause) =
typeck_results.generator_interior_types.as_ref().skip_binder().iter().find(
|ty::GeneratorInteriorTypeCause { ty, .. }| {
ty_matches(typeck_results.generator_interior_types.rebind(ty))
},
)
{
// Check to see if any awaited expressions have the target type.
let from_awaited_ty = visitor
.awaits
.into_iter()
.map(|id| hir.expect_expr(id))
.find(|await_expr| {
ty_matches(ty::Binder::dummy(typeck_results.expr_ty_adjusted(&await_expr)))
})
.map(|expr| expr.span);
let ty::GeneratorInteriorTypeCause { span, scope_span, yield_span, expr, .. } =
cause;

interior_or_upvar_span = Some(GeneratorInteriorOrUpvar::Interior(*span));
interior_extra_info = Some((*scope_span, *yield_span, *expr, from_awaited_ty));
};
interior_or_upvar_span = Some(GeneratorInteriorOrUpvar::Interior(*span));
interior_extra_info = Some((*scope_span, *yield_span, *expr, from_awaited_ty));
};
} else {
interior_or_upvar_span = Some(GeneratorInteriorOrUpvar::Interior(span));
}

debug!(
"maybe_note_obligation_cause_for_async_await: interior_or_upvar={:?} \
generator_interior_types={:?}",
interior_or_upvar_span, typeck_results.generator_interior_types
);
if let Some(interior_or_upvar_span) = interior_or_upvar_span {
self.note_obligation_cause_for_async_await(
err,
Expand Down Expand Up @@ -1620,7 +1608,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
outer_generator: Option<DefId>,
trait_ref: ty::TraitRef<'tcx>,
target_ty: Ty<'tcx>,
typeck_results: &ty::TypeckResults<'tcx>,
typeck_results: Option<&ty::TypeckResults<'tcx>>,
obligation: &PredicateObligation<'tcx>,
next_code: Option<&ObligationCauseCode<'tcx>>,
) {
Expand Down Expand Up @@ -1831,7 +1819,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
// Look at the last interior type to get a span for the `.await`.
debug!(
"note_obligation_cause_for_async_await generator_interior_types: {:#?}",
typeck_results.generator_interior_types
typeck_results.as_ref().map(|t| &t.generator_interior_types)
);
explain_yield(interior_span, yield_span, scope_span);
}
Expand All @@ -1852,10 +1840,14 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
// ^^^^^^^ a temporary `&T` created inside this method call due to `&self`
// ```
//
let is_region_borrow = typeck_results
.expr_adjustments(expr)
.iter()
.any(|adj| adj.is_region_borrow());
let is_region_borrow = if let Some(typeck_results) = typeck_results {
typeck_results
.expr_adjustments(expr)
.iter()
.any(|adj| adj.is_region_borrow())
} else {
false
};

// ```rust
// struct Foo(*const u8);
Expand All @@ -1868,15 +1860,16 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
DefKind::Fn | DefKind::Ctor(..) => target_ty.is_unsafe_ptr(),
_ => false,
};

if (typeck_results.is_method_call(e) && is_region_borrow)
|| is_raw_borrow_inside_fn_like_call
{
err.span_help(
parent_span,
"consider moving this into a `let` \
if let Some(typeck_results) = typeck_results {
if (typeck_results.is_method_call(e) && is_region_borrow)
|| is_raw_borrow_inside_fn_like_call
{
err.span_help(
parent_span,
"consider moving this into a `let` \
binding to create a shorter lived borrow",
);
);
}
}
}
}
Expand Down
2 changes: 1 addition & 1 deletion src/test/ui/async-await/issues/issue-67893.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,5 +7,5 @@ fn g(_: impl Send) {}

fn main() {
g(issue_67893::run())
//~^ ERROR: `MutexGuard<'_, ()>` cannot be sent between threads safely
//~^ ERROR generator cannot be sent between threads safely
}
15 changes: 2 additions & 13 deletions src/test/ui/async-await/issues/issue-67893.stderr
Original file line number Diff line number Diff line change
@@ -1,20 +1,10 @@
error[E0277]: `MutexGuard<'_, ()>` cannot be sent between threads safely
error: generator cannot be sent between threads safely
--> $DIR/issue-67893.rs:9:5
|
LL | g(issue_67893::run())
| ^ `MutexGuard<'_, ()>` cannot be sent between threads safely
|
::: $DIR/auxiliary/issue_67893.rs:7:20
|
LL | pub async fn run() {
| - within this `impl Future`
| ^ generator is not `Send`
|
= help: within `impl Future`, the trait `Send` is not implemented for `MutexGuard<'_, ()>`
= 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}`
= note: required because it appears within the type `[static generator@run::{closure#0}]`
= note: required because it appears within the type `from_generator::GenFuture<[static generator@run::{closure#0}]>`
= note: required because it appears within the type `impl Future`
= note: required because it appears within the type `impl Future`
note: required by a bound in `g`
--> $DIR/issue-67893.rs:6:14
|
Expand All @@ -23,4 +13,3 @@ LL | fn g(_: impl Send) {}

error: aborting due to previous error

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