@@ -20,6 +20,7 @@ use syntax::ast::{self, Ident, Path};
20
20
use syntax:: util:: lev_distance:: find_best_match_for_name;
21
21
22
22
use crate :: imports:: { ImportDirective , ImportDirectiveSubclass , ImportResolver } ;
23
+ use crate :: lifetimes:: { ElisionFailureInfo , LifetimeContext } ;
23
24
use crate :: path_names_to_string;
24
25
use crate :: { AmbiguityError , AmbiguityErrorMisc , AmbiguityKind } ;
25
26
use crate :: { BindingError , CrateLint , HasGenericParams , LegacyScope , Module , ModuleOrUniformRoot } ;
@@ -48,6 +49,40 @@ crate struct ImportSuggestion {
48
49
pub path : Path ,
49
50
}
50
51
52
+ crate enum MissingLifetimeSpot < ' tcx > {
53
+ Generics ( & ' tcx hir:: Generics < ' tcx > ) ,
54
+ HigherRanked { span : Span , span_type : ForLifetimeSpanType } ,
55
+ }
56
+
57
+ crate enum ForLifetimeSpanType {
58
+ BoundEmpty ,
59
+ BoundTail ,
60
+ TypeEmpty ,
61
+ TypeTail ,
62
+ }
63
+
64
+ impl ForLifetimeSpanType {
65
+ crate fn descr ( & self ) -> & ' static str {
66
+ match self {
67
+ Self :: BoundEmpty | Self :: BoundTail => "bound" ,
68
+ Self :: TypeEmpty | Self :: TypeTail => "type" ,
69
+ }
70
+ }
71
+
72
+ crate fn suggestion ( & self , sugg : & str ) -> String {
73
+ match self {
74
+ Self :: BoundEmpty | Self :: TypeEmpty => format ! ( "for<{}> " , sugg) ,
75
+ Self :: BoundTail | Self :: TypeTail => format ! ( ", {}" , sugg) ,
76
+ }
77
+ }
78
+ }
79
+
80
+ impl < ' tcx > Into < MissingLifetimeSpot < ' tcx > > for & ' tcx hir:: Generics < ' tcx > {
81
+ fn into ( self ) -> MissingLifetimeSpot < ' tcx > {
82
+ MissingLifetimeSpot :: Generics ( self )
83
+ }
84
+ }
85
+
51
86
/// Adjust the impl span so that just the `impl` keyword is taken by removing
52
87
/// everything after `<` (`"impl<T> Iterator for A<T> {}" -> "impl"`) and
53
88
/// everything after the first whitespace (`"impl Iterator for A" -> "impl"`).
@@ -1457,72 +1492,206 @@ crate fn show_candidates(
1457
1492
}
1458
1493
}
1459
1494
1460
- crate fn report_missing_lifetime_specifiers (
1461
- sess : & Session ,
1462
- span : Span ,
1463
- count : usize ,
1464
- ) -> DiagnosticBuilder < ' _ > {
1465
- struct_span_err ! ( sess, span, E0106 , "missing lifetime specifier{}" , pluralize!( count) )
1466
- }
1495
+ impl < ' tcx > LifetimeContext < ' _ , ' tcx > {
1496
+ crate fn report_missing_lifetime_specifiers (
1497
+ & self ,
1498
+ span : Span ,
1499
+ count : usize ,
1500
+ ) -> DiagnosticBuilder < ' tcx > {
1501
+ struct_span_err ! (
1502
+ self . tcx. sess,
1503
+ span,
1504
+ E0106 ,
1505
+ "missing lifetime specifier{}" ,
1506
+ pluralize!( count)
1507
+ )
1508
+ }
1467
1509
1468
- crate fn add_missing_lifetime_specifiers_label (
1469
- err : & mut DiagnosticBuilder < ' _ > ,
1470
- span : Span ,
1471
- count : usize ,
1472
- lifetime_names : & FxHashSet < ast:: Ident > ,
1473
- snippet : Option < & str > ,
1474
- missing_named_lifetime_spots : & [ & hir:: Generics < ' _ > ] ,
1475
- ) {
1476
- if count > 1 {
1477
- err. span_label ( span, format ! ( "expected {} lifetime parameters" , count) ) ;
1478
- } else {
1479
- let suggest_existing = |err : & mut DiagnosticBuilder < ' _ > , sugg| {
1480
- err. span_suggestion (
1481
- span,
1482
- "consider using the named lifetime" ,
1483
- sugg,
1484
- Applicability :: MaybeIncorrect ,
1485
- ) ;
1486
- } ;
1487
- let suggest_new = |err : & mut DiagnosticBuilder < ' _ > , sugg| {
1488
- err. span_label ( span, "expected named lifetime parameter" ) ;
1489
-
1490
- if let Some ( generics) = missing_named_lifetime_spots. iter ( ) . last ( ) {
1491
- let mut introduce_suggestion = vec ! [ ] ;
1492
- introduce_suggestion. push ( match & generics. params {
1493
- [ ] => ( generics. span , "<'lifetime>" . to_string ( ) ) ,
1494
- [ param, ..] => ( param. span . shrink_to_lo ( ) , "'lifetime, " . to_string ( ) ) ,
1495
- } ) ;
1496
- introduce_suggestion. push ( ( span, sugg) ) ;
1497
- err. multipart_suggestion (
1498
- "consider introducing a named lifetime parameter" ,
1499
- introduce_suggestion,
1500
- Applicability :: MaybeIncorrect ,
1501
- ) ;
1510
+ crate fn emit_undeclared_lifetime_error ( & self , lifetime_ref : & hir:: Lifetime ) {
1511
+ let mut err = struct_span_err ! (
1512
+ self . tcx. sess,
1513
+ lifetime_ref. span,
1514
+ E0261 ,
1515
+ "use of undeclared lifetime name `{}`" ,
1516
+ lifetime_ref
1517
+ ) ;
1518
+ err. span_label ( lifetime_ref. span , "undeclared lifetime" ) ;
1519
+ for missing in & self . missing_named_lifetime_spots {
1520
+ match missing {
1521
+ MissingLifetimeSpot :: Generics ( generics) => {
1522
+ let ( span, sugg) = if let Some ( param) = generics
1523
+ . params
1524
+ . iter ( )
1525
+ . filter ( |p| match p. kind {
1526
+ hir:: GenericParamKind :: Type {
1527
+ synthetic : Some ( hir:: SyntheticTyParamKind :: ImplTrait ) ,
1528
+ ..
1529
+ } => false ,
1530
+ _ => true ,
1531
+ } )
1532
+ . next ( )
1533
+ {
1534
+ ( param. span . shrink_to_lo ( ) , format ! ( "{}, " , lifetime_ref) )
1535
+ } else {
1536
+ ( generics. span , format ! ( "<{}>" , lifetime_ref) )
1537
+ } ;
1538
+ err. span_suggestion (
1539
+ span,
1540
+ & format ! ( "consider introducing lifetime `{}` here" , lifetime_ref) ,
1541
+ sugg,
1542
+ Applicability :: MaybeIncorrect ,
1543
+ ) ;
1544
+ }
1545
+ MissingLifetimeSpot :: HigherRanked { span, span_type } => {
1546
+ err. span_suggestion (
1547
+ * span,
1548
+ & format ! (
1549
+ "consider making the {} lifetime-generic with a new `{}` lifetime" ,
1550
+ span_type. descr( ) ,
1551
+ lifetime_ref
1552
+ ) ,
1553
+ span_type. suggestion ( & lifetime_ref. to_string ( ) ) ,
1554
+ Applicability :: MaybeIncorrect ,
1555
+ ) ;
1556
+ err. note (
1557
+ "for more information on higher-ranked polymorphism, visit \
1558
+ https://doc.rust-lang.org/nomicon/hrtb.html",
1559
+ ) ;
1560
+ }
1502
1561
}
1503
- } ;
1562
+ }
1563
+ err. emit ( ) ;
1564
+ }
1504
1565
1505
- match ( lifetime_names. len ( ) , lifetime_names. iter ( ) . next ( ) , snippet) {
1506
- ( 1 , Some ( name) , Some ( "&" ) ) => {
1507
- suggest_existing ( err, format ! ( "&{} " , name) ) ;
1508
- }
1509
- ( 1 , Some ( name) , Some ( "'_" ) ) => {
1510
- suggest_existing ( err, name. to_string ( ) ) ;
1511
- }
1512
- ( 1 , Some ( name) , Some ( snippet) ) if !snippet. ends_with ( ">" ) => {
1513
- suggest_existing ( err, format ! ( "{}<{}>" , snippet, name) ) ;
1514
- }
1515
- ( 0 , _, Some ( "&" ) ) => {
1516
- suggest_new ( err, "&'lifetime " . to_string ( ) ) ;
1517
- }
1518
- ( 0 , _, Some ( "'_" ) ) => {
1519
- suggest_new ( err, "'lifetime" . to_string ( ) ) ;
1520
- }
1521
- ( 0 , _, Some ( snippet) ) if !snippet. ends_with ( ">" ) => {
1522
- suggest_new ( err, format ! ( "{}<'lifetime>" , snippet) ) ;
1566
+ crate fn is_trait_ref_fn_scope ( & mut self , trait_ref : & ' tcx hir:: PolyTraitRef < ' tcx > ) -> bool {
1567
+ if let def:: Res :: Def ( _, did) = trait_ref. trait_ref . path . res {
1568
+ if [
1569
+ self . tcx . lang_items ( ) . fn_once_trait ( ) ,
1570
+ self . tcx . lang_items ( ) . fn_trait ( ) ,
1571
+ self . tcx . lang_items ( ) . fn_mut_trait ( ) ,
1572
+ ]
1573
+ . contains ( & Some ( did) )
1574
+ {
1575
+ let ( span, span_type) = match & trait_ref. bound_generic_params {
1576
+ [ ] => ( trait_ref. span . shrink_to_lo ( ) , ForLifetimeSpanType :: BoundEmpty ) ,
1577
+ [ .., bound] => ( bound. span . shrink_to_hi ( ) , ForLifetimeSpanType :: BoundTail ) ,
1578
+ } ;
1579
+ self . missing_named_lifetime_spots
1580
+ . push ( MissingLifetimeSpot :: HigherRanked { span, span_type } ) ;
1581
+ return true ;
1523
1582
}
1524
- _ => {
1525
- err. span_label ( span, "expected lifetime parameter" ) ;
1583
+ } ;
1584
+ false
1585
+ }
1586
+
1587
+ crate fn add_missing_lifetime_specifiers_label (
1588
+ & self ,
1589
+ err : & mut DiagnosticBuilder < ' _ > ,
1590
+ span : Span ,
1591
+ count : usize ,
1592
+ lifetime_names : & FxHashSet < ast:: Ident > ,
1593
+ params : & [ ElisionFailureInfo ] ,
1594
+ ) {
1595
+ if count > 1 {
1596
+ err. span_label ( span, format ! ( "expected {} lifetime parameters" , count) ) ;
1597
+ } else {
1598
+ let snippet = self . tcx . sess . source_map ( ) . span_to_snippet ( span) . ok ( ) ;
1599
+ let suggest_existing = |err : & mut DiagnosticBuilder < ' _ > , sugg| {
1600
+ err. span_suggestion (
1601
+ span,
1602
+ "consider using the named lifetime" ,
1603
+ sugg,
1604
+ Applicability :: MaybeIncorrect ,
1605
+ ) ;
1606
+ } ;
1607
+ let suggest_new =
1608
+ |err : & mut DiagnosticBuilder < ' _ > , sugg : & str | {
1609
+ err. span_label ( span, "expected named lifetime parameter" ) ;
1610
+
1611
+ for missing in self . missing_named_lifetime_spots . iter ( ) . rev ( ) {
1612
+ let mut introduce_suggestion = vec ! [ ] ;
1613
+ let msg;
1614
+ let should_break;
1615
+ introduce_suggestion. push ( match missing {
1616
+ MissingLifetimeSpot :: Generics ( generics) => {
1617
+ msg = "consider introducing a named lifetime parameter" . to_string ( ) ;
1618
+ should_break = true ;
1619
+ if let Some ( param) = generics. params . iter ( ) . filter ( |p| match p. kind {
1620
+ hir:: GenericParamKind :: Type {
1621
+ synthetic : Some ( hir:: SyntheticTyParamKind :: ImplTrait ) ,
1622
+ ..
1623
+ } => false ,
1624
+ _ => true ,
1625
+ } ) . next ( ) {
1626
+ ( param. span . shrink_to_lo ( ) , "'a, " . to_string ( ) )
1627
+ } else {
1628
+ ( generics. span , "<'a>" . to_string ( ) )
1629
+ }
1630
+ }
1631
+ MissingLifetimeSpot :: HigherRanked { span, span_type } => {
1632
+ msg = format ! (
1633
+ "consider making the {} lifetime-generic with a new `'a` lifetime" ,
1634
+ span_type. descr( ) ,
1635
+ ) ;
1636
+ should_break = false ;
1637
+ err. note (
1638
+ "for more information on higher-ranked polymorphism, visit \
1639
+ https://doc.rust-lang.org/nomicon/hrtb.html",
1640
+ ) ;
1641
+ ( * span, span_type. suggestion ( "'a" ) )
1642
+ }
1643
+ } ) ;
1644
+ for param in params {
1645
+ if let Ok ( snippet) =
1646
+ self . tcx . sess . source_map ( ) . span_to_snippet ( param. span )
1647
+ {
1648
+ if snippet. starts_with ( "&" ) && !snippet. starts_with ( "&'" ) {
1649
+ introduce_suggestion
1650
+ . push ( ( param. span , format ! ( "&'a {}" , & snippet[ 1 ..] ) ) ) ;
1651
+ } else if snippet. starts_with ( "&'_ " ) {
1652
+ introduce_suggestion
1653
+ . push ( ( param. span , format ! ( "&'a {}" , & snippet[ 4 ..] ) ) ) ;
1654
+ }
1655
+ }
1656
+ }
1657
+ introduce_suggestion. push ( ( span, sugg. to_string ( ) ) ) ;
1658
+ err. multipart_suggestion (
1659
+ & msg,
1660
+ introduce_suggestion,
1661
+ Applicability :: MaybeIncorrect ,
1662
+ ) ;
1663
+ if should_break {
1664
+ break ;
1665
+ }
1666
+ }
1667
+ } ;
1668
+
1669
+ match (
1670
+ lifetime_names. len ( ) ,
1671
+ lifetime_names. iter ( ) . next ( ) ,
1672
+ snippet. as_ref ( ) . map ( |s| s. as_str ( ) ) ,
1673
+ ) {
1674
+ ( 1 , Some ( name) , Some ( "&" ) ) => {
1675
+ suggest_existing ( err, format ! ( "&{} " , name) ) ;
1676
+ }
1677
+ ( 1 , Some ( name) , Some ( "'_" ) ) => {
1678
+ suggest_existing ( err, name. to_string ( ) ) ;
1679
+ }
1680
+ ( 1 , Some ( name) , Some ( snippet) ) if !snippet. ends_with ( ">" ) => {
1681
+ suggest_existing ( err, format ! ( "{}<{}>" , snippet, name) ) ;
1682
+ }
1683
+ ( 0 , _, Some ( "&" ) ) => {
1684
+ suggest_new ( err, "&'a " ) ;
1685
+ }
1686
+ ( 0 , _, Some ( "'_" ) ) => {
1687
+ suggest_new ( err, "'a" ) ;
1688
+ }
1689
+ ( 0 , _, Some ( snippet) ) if !snippet. ends_with ( ">" ) => {
1690
+ suggest_new ( err, & format ! ( "{}<'a>" , snippet) ) ;
1691
+ }
1692
+ _ => {
1693
+ err. span_label ( span, "expected lifetime parameter" ) ;
1694
+ }
1526
1695
}
1527
1696
}
1528
1697
}
0 commit comments