);
eq
})
- .map(|ty::GeneratorInteriorTypeCause { span, scope_span, .. }| {
- (span, source_map.span_to_snippet(*span), scope_span)
+ .map(|ty::GeneratorInteriorTypeCause { span, scope_span, expr, .. }| {
+ (span, source_map.span_to_snippet(*span), scope_span, expr)
});
+
debug!(
"maybe_note_obligation_cause_for_async_await: target_ty={:?} \
generator_interior_types={:?} target_span={:?}",
target_ty, tables.generator_interior_types, target_span
);
- if let Some((target_span, Ok(snippet), scope_span)) = target_span {
+ if let Some((target_span, Ok(snippet), scope_span, expr)) = target_span {
self.note_obligation_cause_for_async_await(
err,
*target_span,
scope_span,
+ *expr,
snippet,
generator_did,
last_generator,
err: &mut DiagnosticBuilder<'_>,
target_span: Span,
scope_span: &Option<Span>,
+ expr: Option<hir::HirId>,
snippet: String,
first_generator: DefId,
last_generator: Option<DefId>,
// not implemented.
let is_send = self.tcx.is_diagnostic_item(sym::send_trait, trait_ref.def_id);
let is_sync = self.tcx.is_diagnostic_item(sym::sync_trait, trait_ref.def_id);
+ let hir = self.tcx.hir();
let trait_explanation = if is_send || is_sync {
let (trait_name, trait_verb) =
if is_send { ("`Send`", "sent") } else { ("`Sync`", "shared") };
let message = if let Some(name) = last_generator
.and_then(|generator_did| self.tcx.parent(generator_did))
- .and_then(|parent_did| self.tcx.hir().as_local_hir_id(parent_did))
- .and_then(|parent_hir_id| self.tcx.hir().opt_name(parent_hir_id))
+ .and_then(|parent_did| hir.as_local_hir_id(parent_did))
+ .and_then(|parent_hir_id| hir.opt_name(parent_hir_id))
{
format!("future returned by `{}` is not {}", name, trait_name)
} else {
};
// Look at the last interior type to get a span for the `.await`.
- let await_span = tables.generator_interior_types.iter().map(|i| i.span).last().unwrap();
+ let await_span = tables.generator_interior_types.iter().map(|t| t.span).last().unwrap();
let mut span = MultiSpan::from_span(await_span);
span.push_span_label(
await_span,
),
);
+ if let Some(expr_id) = expr {
+ let expr = hir.expect_expr(expr_id);
+ let is_ref = tables.expr_adjustments(expr).iter().any(|adj| adj.is_region_borrow());
+ let parent = hir.get_parent_node(expr_id);
+ if let Some(hir::Node::Expr(e)) = hir.find(parent) {
+ let method_span = hir.span(parent);
+ if tables.is_method_call(e) && is_ref {
+ err.span_help(
+ method_span,
+ "consider moving this method call into a `let` \
+ binding to create a shorter lived borrow",
+ );
+ }
+ }
+ }
+
// Add a note for the item obligation that remains - normally a note pointing to the
// bound that introduced the obligation (e.g. `T: Send`).
debug!("note_obligation_cause_for_async_await: next_code={:?}", next_code);
pub target: Ty<'tcx>,
}
+impl Adjustment<'tcx> {
+ pub fn is_region_borrow(&self) -> bool {
+ match self.kind {
+ Adjust::Borrow(AutoBorrow::Ref(..)) => true,
+ _ => false,
+ }
+ }
+}
+
#[derive(Clone, Debug, RustcEncodable, RustcDecodable, HashStable, TypeFoldable)]
pub enum Adjust<'tcx> {
/// Go from ! to any type.
///
/// Here, we would store the type `T`, the span of the value `x`, and the "scope-span" for
/// the scope that contains `x`.
-#[derive(RustcEncodable, RustcDecodable, Clone, Debug, Eq, Hash, PartialEq)]
-#[derive(HashStable, TypeFoldable)]
+#[derive(RustcEncodable, RustcDecodable, Clone, Debug, Eq, Hash, PartialEq, HashStable)]
pub struct GeneratorInteriorTypeCause<'tcx> {
/// Type of the captured binding.
pub ty: Ty<'tcx>,
pub span: Span,
/// Span of the scope of the captured binding.
pub scope_span: Option<Span>,
+ /// Expr which the type evaluated from.
+ pub expr: Option<hir::HirId>,
}
#[derive(RustcEncodable, RustcDecodable, Debug)]
/// entire variable.
pub upvar_list: ty::UpvarListMap,
- /// Stores the type, span and optional scope span of all types
+ /// Stores the type, expression, span and optional scope span of all types
/// that are live across the yield of this generator (if a generator).
pub generator_interior_types: Vec<GeneratorInteriorTypeCause<'tcx>>,
}
span: source_span,
ty: &ty,
scope_span,
+ expr: expr.map(|e| e.hir_id),
})
.or_insert(entries);
}
// which means that none of the regions inside relate to any other, even if
// typeck had previously found constraints that would cause them to be related.
let mut counter = 0;
- let types = fcx.tcx.fold_regions(&types, &mut false, |_, current_depth| {
+ let fold_types: Vec<_> = types.iter().map(|(t, _)| t.ty).collect();
+ let folded_types = fcx.tcx.fold_regions(&fold_types, &mut false, |_, current_depth| {
counter += 1;
fcx.tcx.mk_region(ty::ReLateBound(current_depth, ty::BrAnon(counter)))
});
// Store the generator types and spans into the tables for this generator.
- let interior_types = types.iter().map(|t| t.0.clone()).collect::<Vec<_>>();
- visitor.fcx.inh.tables.borrow_mut().generator_interior_types = interior_types;
+ let types = types
+ .into_iter()
+ .zip(&folded_types)
+ .map(|((mut interior_cause, _), ty)| {
+ interior_cause.ty = ty;
+ interior_cause
+ })
+ .collect();
+ visitor.fcx.inh.tables.borrow_mut().generator_interior_types = types;
// Extract type components
- let type_list = fcx.tcx.mk_type_list(types.into_iter().map(|t| (t.0).ty));
+ let type_list = fcx.tcx.mk_type_list(folded_types.iter());
let witness = fcx.tcx.mk_generator_witness(ty::Binder::bind(type_list));
...
LL | }
| - `client` is later dropped here
+help: consider moving this method call into a `let` binding to create a shorter lived borrow
+ --> $DIR/issue-64130-4-async-move.rs:19:15
+ |
+LL | match client.status() {
+ | ^^^^^^^^^^^^^^^
= note: the return type of a function must have a statically known size
error: aborting due to previous error
LL | assert_sync(|| {
| ^^^^^^^^^^^ future returned by `main` is not `Sync`
|
- = help: within `[generator@$DIR/not-send-sync.rs:9:17: 13:6 {std::cell::Cell<i32>, ()}]`, the trait `std::marker::Sync` is not implemented for `std::cell::Cell<i32>`
+ = help: within `[generator@$DIR/not-send-sync.rs:9:17: 13:6 {std::cell::Cell<i32>, (), ()}]`, the trait `std::marker::Sync` is not implemented for `std::cell::Cell<i32>`
note: future is not `Sync` as this value is used across an yield
--> $DIR/not-send-sync.rs:12:9
|
LL | fn generator_capture() -> impl Sized {
| ^^^^^^^^^^ expands to a recursive type
|
- = note: expanded type is `[generator@$DIR/recursive-impl-trait-type-indirect.rs:50:5: 50:26 x:impl Sized {()}]`
+ = note: expanded type is `[generator@$DIR/recursive-impl-trait-type-indirect.rs:50:5: 50:26 x:impl Sized {(), ()}]`
error[E0720]: opaque type expands to a recursive type
--> $DIR/recursive-impl-trait-type-indirect.rs:53:26
LL | fn generator_hold() -> impl Sized {
| ^^^^^^^^^^ expands to a recursive type
|
- = note: expanded type is `[generator@$DIR/recursive-impl-trait-type-indirect.rs:58:5: 62:6 {impl Sized, ()}]`
+ = note: expanded type is `[generator@$DIR/recursive-impl-trait-type-indirect.rs:58:5: 62:6 {impl Sized, (), ()}]`
error[E0720]: opaque type expands to a recursive type
--> $DIR/recursive-impl-trait-type-indirect.rs:69:26