Skip to content

Commit 382a963

Browse files
committed
filter upvars that cause trait obligation
1 parent d4bdcfd commit 382a963

File tree

1 file changed

+134
-120
lines changed

1 file changed

+134
-120
lines changed

src/librustc_trait_selection/traits/error_reporting/suggestions.rs

+134-120
Original file line numberDiff line numberDiff line change
@@ -125,19 +125,15 @@ pub trait InferCtxtExt<'tcx> {
125125
fn note_obligation_cause_for_async_await(
126126
&self,
127127
err: &mut DiagnosticBuilder<'_>,
128-
target_span: Span,
129-
scope_span: &Option<Span>,
130-
yield_span: Option<Span>,
131-
expr: Option<hir::HirId>,
132-
snippet: String,
128+
interior: Option<(Span, Option<Span>, Option<Span>, Option<hir::HirId>, Option<Span>)>,
129+
upvar: Option<(Ty<'tcx>, Span)>,
133130
inner_generator_body: Option<&hir::Body<'_>>,
134131
outer_generator: Option<DefId>,
135132
trait_ref: ty::TraitRef<'_>,
136133
target_ty: Ty<'tcx>,
137134
tables: &ty::TypeckTables<'_>,
138135
obligation: &PredicateObligation<'tcx>,
139136
next_code: Option<&ObligationCauseCode<'tcx>>,
140-
from_awaited_ty: Option<Span>,
141137
);
142138

143139
fn note_obligation_cause_code<T>(
@@ -1136,7 +1132,6 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
11361132
obligation.cause.span={:?}",
11371133
obligation.predicate, obligation.cause.span
11381134
);
1139-
let source_map = self.tcx.sess.source_map();
11401135
let hir = self.tcx.hir();
11411136

11421137
// Attempt to detect an async-await error by looking at the obligation causes, looking
@@ -1173,6 +1168,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
11731168
};
11741169
let mut generator = None;
11751170
let mut outer_generator = None;
1171+
let mut generator_substs = None;
11761172
let mut next_code = Some(&obligation.cause.code);
11771173
while let Some(code) = next_code {
11781174
debug!("maybe_note_obligation_cause_for_async_await: code={:?}", code);
@@ -1188,8 +1184,9 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
11881184
);
11891185

11901186
match ty.kind {
1191-
ty::Generator(did, ..) => {
1187+
ty::Generator(did, substs, ..) => {
11921188
generator = generator.or(Some(did));
1189+
generator_substs = generator_substs.or(Some(substs));
11931190
outer_generator = Some(did);
11941191
}
11951192
ty::GeneratorWitness(..) => {}
@@ -1212,12 +1209,13 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
12121209
target_ty={:?}",
12131210
generator, trait_ref, target_ty
12141211
);
1215-
let (generator_did, trait_ref, target_ty) = match (generator, trait_ref, target_ty) {
1216-
(Some(generator_did), Some(trait_ref), Some(target_ty)) => {
1217-
(generator_did, trait_ref, target_ty)
1218-
}
1219-
_ => return false,
1220-
};
1212+
let (generator_did, _generator_substs, trait_ref, target_ty) =
1213+
match (generator, generator_substs, trait_ref, target_ty) {
1214+
(Some(generator_did), Some(generator_substs), Some(trait_ref), Some(target_ty)) => {
1215+
(generator_did, generator_substs, trait_ref, target_ty)
1216+
}
1217+
_ => return false,
1218+
};
12211219

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

@@ -1285,7 +1283,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
12851283
);
12861284
eq
12871285
};
1288-
let target_span = tables
1286+
let interior = tables
12891287
.generator_interior_types
12901288
.iter()
12911289
.find(|ty::GeneratorInteriorTypeCause { ty, .. }| ty_matches(ty))
@@ -1306,39 +1304,36 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
13061304
.map(|expr| expr.span);
13071305
let ty::GeneratorInteriorTypeCause { span, scope_span, yield_span, expr, .. } =
13081306
cause;
1309-
(
1310-
span,
1311-
source_map.span_to_snippet(*span),
1312-
scope_span,
1313-
yield_span,
1314-
expr,
1315-
from_awaited_ty,
1316-
)
1307+
(*span, *scope_span, *yield_span, *expr, from_awaited_ty)
13171308
});
13181309

1310+
let upvar = if let Some(upvars) = self.tcx.upvars(generator_did) {
1311+
upvars.iter().find_map(|(upvar_id, upvar)| {
1312+
let upvar_ty = tables.node_type(*upvar_id);
1313+
let upvar_ty = self.resolve_vars_if_possible(&upvar_ty);
1314+
if ty_matches(&upvar_ty) { Some((upvar_ty, upvar.span)) } else { None }
1315+
})
1316+
} else {
1317+
None
1318+
};
1319+
13191320
debug!(
1320-
"maybe_note_obligation_cause_for_async_await: target_ty={:?} \
1321-
generator_interior_types={:?} target_span={:?}",
1322-
target_ty, tables.generator_interior_types, target_span
1321+
"maybe_note_obligation_cause_for_async_await: interior={:?} \
1322+
generator_interior_types={:?} upvar: {:?}",
1323+
interior, tables.generator_interior_types, upvar
13231324
);
1324-
if let Some((target_span, Ok(snippet), scope_span, yield_span, expr, from_awaited_ty)) =
1325-
target_span
1326-
{
1325+
if interior.is_some() || upvar.is_some() {
13271326
self.note_obligation_cause_for_async_await(
13281327
err,
1329-
*target_span,
1330-
scope_span,
1331-
*yield_span,
1332-
*expr,
1333-
snippet,
1328+
interior,
1329+
upvar,
13341330
generator_body,
13351331
outer_generator,
13361332
trait_ref,
13371333
target_ty,
13381334
tables,
13391335
obligation,
13401336
next_code,
1341-
from_awaited_ty,
13421337
);
13431338
true
13441339
} else {
@@ -1351,19 +1346,15 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
13511346
fn note_obligation_cause_for_async_await(
13521347
&self,
13531348
err: &mut DiagnosticBuilder<'_>,
1354-
target_span: Span,
1355-
scope_span: &Option<Span>,
1356-
yield_span: Option<Span>,
1357-
expr: Option<hir::HirId>,
1358-
snippet: String,
1349+
interior: Option<(Span, Option<Span>, Option<Span>, Option<hir::HirId>, Option<Span>)>,
1350+
upvar: Option<(Ty<'tcx>, Span)>,
13591351
inner_generator_body: Option<&hir::Body<'_>>,
13601352
outer_generator: Option<DefId>,
13611353
trait_ref: ty::TraitRef<'_>,
13621354
target_ty: Ty<'tcx>,
13631355
tables: &ty::TypeckTables<'_>,
13641356
obligation: &PredicateObligation<'tcx>,
13651357
next_code: Option<&ObligationCauseCode<'tcx>>,
1366-
from_awaited_ty: Option<Span>,
13671358
) {
13681359
let source_map = self.tcx.sess.source_map();
13691360

@@ -1424,99 +1415,122 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
14241415
format!("does not implement `{}`", trait_ref.print_only_trait_path())
14251416
};
14261417

1427-
if let Some(await_span) = from_awaited_ty {
1428-
// The type causing this obligation is one being awaited at await_span.
1429-
let mut span = MultiSpan::from_span(await_span);
1430-
1431-
span.push_span_label(
1432-
await_span,
1433-
format!("await occurs here on type `{}`, which {}", target_ty, trait_explanation),
1434-
);
1418+
if let Some((target_span, scope_span, yield_span, expr, from_awaited_ty)) = interior {
1419+
if let Some(await_span) = from_awaited_ty {
1420+
// The type causing this obligation is one being awaited at await_span.
1421+
let mut span = MultiSpan::from_span(await_span);
14351422

1436-
err.span_note(
1437-
span,
1438-
&format!(
1439-
"future {not_trait} as it awaits another future which {not_trait}",
1440-
not_trait = trait_explanation
1441-
),
1442-
);
1443-
} else {
1444-
// Look at the last interior type to get a span for the `.await`.
1445-
debug!(
1446-
"note_obligation_cause_for_async_await generator_interior_types: {:#?}",
1447-
tables.generator_interior_types
1448-
);
1449-
1450-
if let Some(yield_span) = yield_span {
1451-
let mut span = MultiSpan::from_span(yield_span);
14521423
span.push_span_label(
1453-
yield_span,
1454-
format!("{} occurs here, with `{}` maybe used later", await_or_yield, snippet),
1455-
);
1456-
1457-
span.push_span_label(
1458-
target_span,
1459-
format!("has type `{}` which {}", target_ty, trait_explanation),
1424+
await_span,
1425+
format!(
1426+
"await occurs here on type `{}`, which {}",
1427+
target_ty, trait_explanation
1428+
),
14601429
);
14611430

1462-
// If available, use the scope span to annotate the drop location.
1463-
if let Some(scope_span) = scope_span {
1464-
span.push_span_label(
1465-
source_map.end_point(*scope_span),
1466-
format!("`{}` is later dropped here", snippet),
1467-
);
1468-
}
1469-
14701431
err.span_note(
14711432
span,
14721433
&format!(
1473-
"{} {} as this value is used across {}",
1474-
future_or_generator, trait_explanation, an_await_or_yield
1434+
"future {not_trait} as it awaits another future which {not_trait}",
1435+
not_trait = trait_explanation
14751436
),
14761437
);
1477-
}
1478-
}
1438+
} else {
1439+
// Look at the last interior type to get a span for the `.await`.
1440+
debug!(
1441+
"note_obligation_cause_for_async_await generator_interior_types: {:#?}",
1442+
tables.generator_interior_types
1443+
);
14791444

1480-
if let Some(expr_id) = expr {
1481-
let expr = hir.expect_expr(expr_id);
1482-
debug!("target_ty evaluated from {:?}", expr);
1483-
1484-
let parent = hir.get_parent_node(expr_id);
1485-
if let Some(hir::Node::Expr(e)) = hir.find(parent) {
1486-
let parent_span = hir.span(parent);
1487-
let parent_did = parent.owner.to_def_id();
1488-
// ```rust
1489-
// impl T {
1490-
// fn foo(&self) -> i32 {}
1491-
// }
1492-
// T.foo();
1493-
// ^^^^^^^ a temporary `&T` created inside this method call due to `&self`
1494-
// ```
1495-
//
1496-
let is_region_borrow =
1497-
tables.expr_adjustments(expr).iter().any(|adj| adj.is_region_borrow());
1498-
1499-
// ```rust
1500-
// struct Foo(*const u8);
1501-
// bar(Foo(std::ptr::null())).await;
1502-
// ^^^^^^^^^^^^^^^^^^^^^ raw-ptr `*T` created inside this struct ctor.
1503-
// ```
1504-
debug!("parent_def_kind: {:?}", self.tcx.def_kind(parent_did));
1505-
let is_raw_borrow_inside_fn_like_call = match self.tcx.def_kind(parent_did) {
1506-
DefKind::Fn | DefKind::Ctor(..) => target_ty.is_unsafe_ptr(),
1507-
_ => false,
1508-
};
1445+
if let Some(yield_span) = yield_span {
1446+
let mut span = MultiSpan::from_span(yield_span);
1447+
if let Ok(snippet) = source_map.span_to_snippet(target_span) {
1448+
span.push_span_label(
1449+
yield_span,
1450+
format!(
1451+
"{} occurs here, with `{}` maybe used later",
1452+
await_or_yield, snippet
1453+
),
1454+
);
1455+
// If available, use the scope span to annotate the drop location.
1456+
if let Some(scope_span) = scope_span {
1457+
span.push_span_label(
1458+
source_map.end_point(scope_span),
1459+
format!("`{}` is later dropped here", snippet),
1460+
);
1461+
}
1462+
}
1463+
span.push_span_label(
1464+
target_span,
1465+
format!("has type `{}` which {}", target_ty, trait_explanation),
1466+
);
15091467

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

15221536
// Add a note for the item obligation that remains - normally a note pointing to the

0 commit comments

Comments
 (0)