Skip to content

Commit c9e1465

Browse files
committed
checking on either interior or upvar
1 parent d2e5a8e commit c9e1465

File tree

4 files changed

+135
-123
lines changed

4 files changed

+135
-123
lines changed

src/librustc_middle/ty/context.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -305,7 +305,7 @@ pub struct GeneratorInteriorTypeCause<'tcx> {
305305
/// Span of the scope of the captured binding.
306306
pub scope_span: Option<Span>,
307307
/// Span of `.await` or `yield` expression.
308-
pub yield_span: Option<Span>,
308+
pub yield_span: Span,
309309
/// Expr which the type evaluated from.
310310
pub expr: Option<hir::HirId>,
311311
}

src/librustc_trait_selection/traits/error_reporting/suggestions.rs

+132-119
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,14 @@ use std::fmt;
2222
use super::InferCtxtPrivExt;
2323
use crate::traits::query::evaluate_obligation::InferCtxtExt as _;
2424

25+
#[derive(Debug)]
26+
pub enum GeneratorInteriorOrUpvar {
27+
// span of interior type
28+
Interior(Span),
29+
// span of upvar
30+
Upvar(Span),
31+
}
32+
2533
// This trait is public to expose the diagnostics methods to clippy.
2634
pub trait InferCtxtExt<'tcx> {
2735
fn suggest_restricting_param_bound(
@@ -125,8 +133,8 @@ pub trait InferCtxtExt<'tcx> {
125133
fn note_obligation_cause_for_async_await(
126134
&self,
127135
err: &mut DiagnosticBuilder<'_>,
128-
interior: Option<(Span, Option<Span>, Option<Span>, Option<hir::HirId>, Option<Span>)>,
129-
upvar: Option<(Ty<'tcx>, Span)>,
136+
interior_or_upvar_span: GeneratorInteriorOrUpvar,
137+
interior_extra_info: Option<(Option<Span>, Span, Option<hir::HirId>, Option<Span>)>,
130138
inner_generator_body: Option<&hir::Body<'_>>,
131139
outer_generator: Option<DefId>,
132140
trait_ref: ty::TraitRef<'_>,
@@ -1280,7 +1288,23 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
12801288
);
12811289
eq
12821290
};
1283-
let interior = tables
1291+
1292+
let mut interior_or_upvar_span = None;
1293+
let mut interior_extra_info = None;
1294+
1295+
if let Some(upvars) = self.tcx.upvars(generator_did) {
1296+
interior_or_upvar_span = upvars.iter().find_map(|(upvar_id, upvar)| {
1297+
let upvar_ty = tables.node_type(*upvar_id);
1298+
let upvar_ty = self.resolve_vars_if_possible(&upvar_ty);
1299+
if ty_matches(&upvar_ty) {
1300+
Some(GeneratorInteriorOrUpvar::Upvar(upvar.span))
1301+
} else {
1302+
None
1303+
}
1304+
});
1305+
};
1306+
1307+
tables
12841308
.generator_interior_types
12851309
.iter()
12861310
.find(|ty::GeneratorInteriorTypeCause { ty, .. }| ty_matches(ty))
@@ -1301,29 +1325,21 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
13011325
.map(|expr| expr.span);
13021326
let ty::GeneratorInteriorTypeCause { span, scope_span, yield_span, expr, .. } =
13031327
cause;
1304-
(*span, *scope_span, *yield_span, *expr, from_awaited_ty)
1305-
});
13061328

1307-
let upvar = if let Some(upvars) = self.tcx.upvars(generator_did) {
1308-
upvars.iter().find_map(|(upvar_id, upvar)| {
1309-
let upvar_ty = tables.node_type(*upvar_id);
1310-
let upvar_ty = self.resolve_vars_if_possible(&upvar_ty);
1311-
if ty_matches(&upvar_ty) { Some((upvar_ty, upvar.span)) } else { None }
1312-
})
1313-
} else {
1314-
None
1315-
};
1329+
interior_or_upvar_span = Some(GeneratorInteriorOrUpvar::Interior(*span));
1330+
interior_extra_info = Some((*scope_span, *yield_span, *expr, from_awaited_ty));
1331+
});
13161332

13171333
debug!(
1318-
"maybe_note_obligation_cause_for_async_await: interior={:?} \
1319-
generator_interior_types={:?} upvar: {:?}",
1320-
interior, tables.generator_interior_types, upvar
1334+
"maybe_note_obligation_cause_for_async_await: interior_or_upvar={:?} \
1335+
generator_interior_types={:?}",
1336+
interior_or_upvar_span, tables.generator_interior_types
13211337
);
1322-
if interior.is_some() || upvar.is_some() {
1338+
if let Some(interior_or_upvar_span) = interior_or_upvar_span {
13231339
self.note_obligation_cause_for_async_await(
13241340
err,
1325-
interior,
1326-
upvar,
1341+
interior_or_upvar_span,
1342+
interior_extra_info,
13271343
generator_body,
13281344
outer_generator,
13291345
trait_ref,
@@ -1343,8 +1359,8 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
13431359
fn note_obligation_cause_for_async_await(
13441360
&self,
13451361
err: &mut DiagnosticBuilder<'_>,
1346-
interior: Option<(Span, Option<Span>, Option<Span>, Option<hir::HirId>, Option<Span>)>,
1347-
upvar: Option<(Ty<'tcx>, Span)>,
1362+
interior_or_upvar_span: GeneratorInteriorOrUpvar,
1363+
interior_extra_info: Option<(Option<Span>, Span, Option<hir::HirId>, Option<Span>)>,
13481364
inner_generator_body: Option<&hir::Body<'_>>,
13491365
outer_generator: Option<DefId>,
13501366
trait_ref: ty::TraitRef<'_>,
@@ -1412,121 +1428,118 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
14121428
format!("does not implement `{}`", trait_ref.print_only_trait_path())
14131429
};
14141430

1415-
if let Some((target_span, scope_span, yield_span, expr, from_awaited_ty)) = interior {
1416-
if let Some(await_span) = from_awaited_ty {
1417-
// The type causing this obligation is one being awaited at await_span.
1418-
let mut span = MultiSpan::from_span(await_span);
1419-
1431+
let mut explain_yield = |interior_span: Span,
1432+
yield_span: Span,
1433+
scope_span: Option<Span>| {
1434+
let mut span = MultiSpan::from_span(yield_span);
1435+
if let Ok(snippet) = source_map.span_to_snippet(interior_span) {
14201436
span.push_span_label(
1421-
await_span,
1422-
format!(
1423-
"await occurs here on type `{}`, which {}",
1424-
target_ty, trait_explanation
1425-
),
1426-
);
1427-
1428-
err.span_note(
1429-
span,
1430-
&format!(
1431-
"future {not_trait} as it awaits another future which {not_trait}",
1432-
not_trait = trait_explanation
1433-
),
1434-
);
1435-
} else {
1436-
// Look at the last interior type to get a span for the `.await`.
1437-
debug!(
1438-
"note_obligation_cause_for_async_await generator_interior_types: {:#?}",
1439-
tables.generator_interior_types
1437+
yield_span,
1438+
format!("{} occurs here, with `{}` maybe used later", await_or_yield, snippet),
14401439
);
1440+
// If available, use the scope span to annotate the drop location.
1441+
if let Some(scope_span) = scope_span {
1442+
span.push_span_label(
1443+
source_map.end_point(scope_span),
1444+
format!("`{}` is later dropped here", snippet),
1445+
);
1446+
}
1447+
}
1448+
span.push_span_label(
1449+
interior_span,
1450+
format!("has type `{}` which {}", target_ty, trait_explanation),
1451+
);
14411452

1442-
if let Some(yield_span) = yield_span {
1443-
let mut span = MultiSpan::from_span(yield_span);
1444-
if let Ok(snippet) = source_map.span_to_snippet(target_span) {
1453+
err.span_note(
1454+
span,
1455+
&format!(
1456+
"{} {} as this value is used across {}",
1457+
future_or_generator, trait_explanation, an_await_or_yield
1458+
),
1459+
);
1460+
};
1461+
match interior_or_upvar_span {
1462+
GeneratorInteriorOrUpvar::Interior(interior_span) => {
1463+
if let Some((scope_span, yield_span, expr, from_awaited_ty)) = interior_extra_info {
1464+
if let Some(await_span) = from_awaited_ty {
1465+
// The type causing this obligation is one being awaited at await_span.
1466+
let mut span = MultiSpan::from_span(await_span);
14451467
span.push_span_label(
1446-
yield_span,
1468+
await_span,
14471469
format!(
1448-
"{} occurs here, with `{}` maybe used later",
1449-
await_or_yield, snippet
1470+
"await occurs here on type `{}`, which {}",
1471+
target_ty, trait_explanation
14501472
),
14511473
);
1452-
// If available, use the scope span to annotate the drop location.
1453-
if let Some(scope_span) = scope_span {
1454-
span.push_span_label(
1455-
source_map.end_point(scope_span),
1456-
format!("`{}` is later dropped here", snippet),
1457-
);
1458-
}
1474+
err.span_note(
1475+
span,
1476+
&format!(
1477+
"future {not_trait} as it awaits another future which {not_trait}",
1478+
not_trait = trait_explanation
1479+
),
1480+
);
1481+
} else {
1482+
// Look at the last interior type to get a span for the `.await`.
1483+
debug!(
1484+
"note_obligation_cause_for_async_await generator_interior_types: {:#?}",
1485+
tables.generator_interior_types
1486+
);
1487+
explain_yield(interior_span, yield_span, scope_span);
14591488
}
1460-
span.push_span_label(
1461-
target_span,
1462-
format!("has type `{}` which {}", target_ty, trait_explanation),
1463-
);
14641489

1465-
err.span_note(
1466-
span,
1467-
&format!(
1468-
"{} {} as this value is used across {}",
1469-
future_or_generator, trait_explanation, an_await_or_yield
1470-
),
1471-
);
1472-
}
1473-
}
1474-
if let Some((_, upvar_span)) = upvar {
1475-
let mut span = MultiSpan::from_span(upvar_span);
1476-
span.push_span_label(
1477-
upvar_span,
1478-
format!("has type `{}` which {}", target_ty, trait_explanation),
1479-
);
1480-
}
1481-
if let Some(expr_id) = expr {
1482-
let expr = hir.expect_expr(expr_id);
1483-
debug!("target_ty evaluated from {:?}", expr);
1484-
1485-
let parent = hir.get_parent_node(expr_id);
1486-
if let Some(hir::Node::Expr(e)) = hir.find(parent) {
1487-
let parent_span = hir.span(parent);
1488-
let parent_did = parent.owner.to_def_id();
1489-
// ```rust
1490-
// impl T {
1491-
// fn foo(&self) -> i32 {}
1492-
// }
1493-
// T.foo();
1494-
// ^^^^^^^ a temporary `&T` created inside this method call due to `&self`
1495-
// ```
1496-
//
1497-
let is_region_borrow =
1498-
tables.expr_adjustments(expr).iter().any(|adj| adj.is_region_borrow());
1499-
1500-
// ```rust
1501-
// struct Foo(*const u8);
1502-
// bar(Foo(std::ptr::null())).await;
1503-
// ^^^^^^^^^^^^^^^^^^^^^ raw-ptr `*T` created inside this struct ctor.
1504-
// ```
1505-
debug!("parent_def_kind: {:?}", self.tcx.def_kind(parent_did));
1506-
let is_raw_borrow_inside_fn_like_call = match self.tcx.def_kind(parent_did) {
1507-
DefKind::Fn | DefKind::Ctor(..) => target_ty.is_unsafe_ptr(),
1508-
_ => false,
1509-
};
1510-
1511-
if (tables.is_method_call(e) && is_region_borrow)
1512-
|| is_raw_borrow_inside_fn_like_call
1513-
{
1514-
err.span_help(
1515-
parent_span,
1516-
"consider moving this into a `let` \
1490+
if let Some(expr_id) = expr {
1491+
let expr = hir.expect_expr(expr_id);
1492+
debug!("target_ty evaluated from {:?}", expr);
1493+
1494+
let parent = hir.get_parent_node(expr_id);
1495+
if let Some(hir::Node::Expr(e)) = hir.find(parent) {
1496+
let parent_span = hir.span(parent);
1497+
let parent_did = parent.owner.to_def_id();
1498+
// ```rust
1499+
// impl T {
1500+
// fn foo(&self) -> i32 {}
1501+
// }
1502+
// T.foo();
1503+
// ^^^^^^^ a temporary `&T` created inside this method call due to `&self`
1504+
// ```
1505+
//
1506+
let is_region_borrow = tables
1507+
.expr_adjustments(expr)
1508+
.iter()
1509+
.any(|adj| adj.is_region_borrow());
1510+
1511+
// ```rust
1512+
// struct Foo(*const u8);
1513+
// bar(Foo(std::ptr::null())).await;
1514+
// ^^^^^^^^^^^^^^^^^^^^^ raw-ptr `*T` created inside this struct ctor.
1515+
// ```
1516+
debug!("parent_def_kind: {:?}", self.tcx.def_kind(parent_did));
1517+
let is_raw_borrow_inside_fn_like_call =
1518+
match self.tcx.def_kind(parent_did) {
1519+
DefKind::Fn | DefKind::Ctor(..) => target_ty.is_unsafe_ptr(),
1520+
_ => false,
1521+
};
1522+
1523+
if (tables.is_method_call(e) && is_region_borrow)
1524+
|| is_raw_borrow_inside_fn_like_call
1525+
{
1526+
err.span_help(
1527+
parent_span,
1528+
"consider moving this into a `let` \
15171529
binding to create a shorter lived borrow",
1518-
);
1530+
);
1531+
}
1532+
}
15191533
}
15201534
}
15211535
}
1522-
} else {
1523-
if let Some((_, upvar_span)) = upvar {
1536+
GeneratorInteriorOrUpvar::Upvar(upvar_span) => {
15241537
let mut span = MultiSpan::from_span(upvar_span);
15251538
span.push_span_label(
15261539
upvar_span,
15271540
format!("has type `{}` which {}", target_ty, trait_explanation),
15281541
);
1529-
err.span_note(span, &format!("captured outer value {}", trait_explanation));
1542+
err.span_note(span, &format!("captured value {}", trait_explanation));
15301543
}
15311544
}
15321545

src/librustc_typeck/check/generator_interior.rs

+1-2
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,7 @@ impl<'a, 'tcx> InteriorVisitor<'a, 'tcx> {
9696
span: source_span,
9797
ty: &ty,
9898
scope_span,
99-
yield_span: Some(yield_data.span),
99+
yield_span: yield_data.span,
100100
expr: expr.map(|e| e.hir_id),
101101
})
102102
.or_insert(entries);
@@ -130,7 +130,6 @@ pub fn resolve_interior<'a, 'tcx>(
130130
kind: hir::GeneratorKind,
131131
) {
132132
let body = fcx.tcx.hir().body(body_id);
133-
134133
let mut visitor = InteriorVisitor {
135134
fcx,
136135
types: FxHashMap::default(),

src/test/ui/async-await/issue-70818.stderr

+1-1
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ LL | async { (ty, ty1) }
88
| ------------------- this returned value is of type `impl std::future::Future`
99
|
1010
= help: within `impl std::future::Future`, the trait `std::marker::Send` is not implemented for `U`
11-
note: captured outer value is not `Send`
11+
note: captured value is not `Send`
1212
--> $DIR/issue-70818.rs:6:18
1313
|
1414
LL | async { (ty, ty1) }

0 commit comments

Comments
 (0)