@@ -22,6 +22,14 @@ use std::fmt;
2222use super :: InferCtxtPrivExt ;
2323use 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.
2634pub 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
0 commit comments