@@ -7,6 +7,7 @@ use rustc::ty::{self, DefIdTree};
7
7
use rustc_data_structures:: fx:: FxHashSet ;
8
8
use rustc_errors:: { pluralize, struct_span_err, Applicability , DiagnosticBuilder } ;
9
9
use rustc_feature:: BUILTIN_ATTRIBUTES ;
10
+ use rustc_hir as hir;
10
11
use rustc_hir:: def:: Namespace :: { self , * } ;
11
12
use rustc_hir:: def:: { self , CtorKind , CtorOf , DefKind , NonMacroAttrKind } ;
12
13
use rustc_hir:: def_id:: { DefId , CRATE_DEF_INDEX , LOCAL_CRATE } ;
@@ -19,7 +20,7 @@ use syntax::print::pprust;
19
20
use syntax:: util:: lev_distance:: find_best_match_for_name;
20
21
21
22
use crate :: imports:: { ImportDirective , ImportDirectiveSubclass , ImportResolver } ;
22
- use crate :: lifetimes:: { ElisionFailureInfo , MissingLifetimeSpot } ;
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"`).
@@ -1452,104 +1487,185 @@ crate fn show_candidates(
1452
1487
}
1453
1488
}
1454
1489
1455
- crate fn report_missing_lifetime_specifiers (
1456
- sess : & Session ,
1457
- span : Span ,
1458
- count : usize ,
1459
- ) -> DiagnosticBuilder < ' _ > {
1460
- struct_span_err ! ( sess, span, E0106 , "missing lifetime specifier{}" , pluralize!( count) )
1461
- }
1490
+ impl < ' tcx > LifetimeContext < ' _ , ' tcx > {
1491
+ crate fn report_missing_lifetime_specifiers (
1492
+ & self ,
1493
+ span : Span ,
1494
+ count : usize ,
1495
+ ) -> DiagnosticBuilder < ' tcx > {
1496
+ struct_span_err ! (
1497
+ self . tcx. sess,
1498
+ span,
1499
+ E0106 ,
1500
+ "missing lifetime specifier{}" ,
1501
+ pluralize!( count)
1502
+ )
1503
+ }
1462
1504
1463
- crate fn add_missing_lifetime_specifiers_label (
1464
- err : & mut DiagnosticBuilder < ' _ > ,
1465
- source_map : & SourceMap ,
1466
- span : Span ,
1467
- count : usize ,
1468
- lifetime_names : & FxHashSet < ast:: Ident > ,
1469
- snippet : Option < & str > ,
1470
- missing_named_lifetime_spots : & [ MissingLifetimeSpot < ' _ > ] ,
1471
- params : & [ ElisionFailureInfo ] ,
1472
- ) {
1473
- if count > 1 {
1474
- err. span_label ( span, format ! ( "expected {} lifetime parameters" , count) ) ;
1475
- } else {
1476
- let suggest_existing = |err : & mut DiagnosticBuilder < ' _ > , sugg| {
1477
- err. span_suggestion (
1478
- span,
1479
- "consider using the named lifetime" ,
1480
- sugg,
1481
- Applicability :: MaybeIncorrect ,
1482
- ) ;
1505
+ crate fn emit_undeclared_lifetime_error ( & self , lifetime_ref : & hir:: Lifetime ) {
1506
+ let mut err = struct_span_err ! (
1507
+ self . tcx. sess,
1508
+ lifetime_ref. span,
1509
+ E0261 ,
1510
+ "use of undeclared lifetime name `{}`" ,
1511
+ lifetime_ref
1512
+ ) ;
1513
+ err. span_label ( lifetime_ref. span , "undeclared lifetime" ) ;
1514
+ for missing in & self . missing_named_lifetime_spots {
1515
+ match missing {
1516
+ MissingLifetimeSpot :: Generics ( generics) => {
1517
+ let ( span, sugg) = match & generics. params {
1518
+ [ ] => ( generics. span , format ! ( "<{}>" , lifetime_ref) ) ,
1519
+ [ param, ..] => ( param. span . shrink_to_lo ( ) , format ! ( "{}, " , lifetime_ref) ) ,
1520
+ } ;
1521
+ err. span_suggestion (
1522
+ span,
1523
+ & format ! ( "consider introducing lifetime `{}` here" , lifetime_ref) ,
1524
+ sugg,
1525
+ Applicability :: MaybeIncorrect ,
1526
+ ) ;
1527
+ }
1528
+ MissingLifetimeSpot :: HigherRanked { span, span_type } => {
1529
+ err. span_suggestion (
1530
+ * span,
1531
+ & format ! (
1532
+ "consider making the {} lifetime-generic with a new `{}` lifetime" ,
1533
+ span_type. descr( ) ,
1534
+ lifetime_ref
1535
+ ) ,
1536
+ span_type. suggestion ( & lifetime_ref. to_string ( ) ) ,
1537
+ Applicability :: MaybeIncorrect ,
1538
+ ) ;
1539
+ err. note (
1540
+ "for more information on higher-ranked polymorphism, visit \
1541
+ https://doc.rust-lang.org/nomicon/hrtb.html",
1542
+ ) ;
1543
+ }
1544
+ }
1545
+ }
1546
+ err. emit ( ) ;
1547
+ }
1548
+
1549
+ crate fn is_trait_ref_fn_scope ( & mut self , trait_ref : & ' tcx hir:: PolyTraitRef < ' tcx > ) -> bool {
1550
+ if let def:: Res :: Def ( _, did) = trait_ref. trait_ref . path . res {
1551
+ if [
1552
+ self . tcx . lang_items ( ) . fn_once_trait ( ) ,
1553
+ self . tcx . lang_items ( ) . fn_trait ( ) ,
1554
+ self . tcx . lang_items ( ) . fn_mut_trait ( ) ,
1555
+ ]
1556
+ . contains ( & Some ( did) )
1557
+ {
1558
+ let ( span, span_type) = match & trait_ref. bound_generic_params {
1559
+ [ ] => ( trait_ref. span . shrink_to_lo ( ) , ForLifetimeSpanType :: BoundEmpty ) ,
1560
+ [ .., bound] => ( bound. span . shrink_to_hi ( ) , ForLifetimeSpanType :: BoundTail ) ,
1561
+ } ;
1562
+ self . missing_named_lifetime_spots
1563
+ . push ( MissingLifetimeSpot :: HigherRanked { span, span_type } ) ;
1564
+ return true ;
1565
+ }
1483
1566
} ;
1484
- let suggest_new = |err : & mut DiagnosticBuilder < ' _ > , sugg : & str | {
1485
- err. span_label ( span, "expected named lifetime parameter" ) ;
1486
-
1487
- for missing in missing_named_lifetime_spots. iter ( ) . rev ( ) {
1488
- let mut introduce_suggestion = vec ! [ ] ;
1489
- let msg;
1490
- let should_break;
1491
- introduce_suggestion. push ( match missing {
1492
- MissingLifetimeSpot :: Generics ( generics) => {
1493
- msg = "consider introducing a named lifetime parameter" . to_string ( ) ;
1494
- should_break = true ;
1495
- match & generics. params {
1496
- [ ] => ( generics. span , "<'a>" . to_string ( ) ) ,
1497
- [ param, ..] => ( param. span . shrink_to_lo ( ) , "'a, " . to_string ( ) ) ,
1567
+ false
1568
+ }
1569
+
1570
+ crate fn add_missing_lifetime_specifiers_label (
1571
+ & self ,
1572
+ err : & mut DiagnosticBuilder < ' _ > ,
1573
+ span : Span ,
1574
+ count : usize ,
1575
+ lifetime_names : & FxHashSet < ast:: Ident > ,
1576
+ params : & [ ElisionFailureInfo ] ,
1577
+ ) {
1578
+ if count > 1 {
1579
+ err. span_label ( span, format ! ( "expected {} lifetime parameters" , count) ) ;
1580
+ } else {
1581
+ let snippet = self . tcx . sess . source_map ( ) . span_to_snippet ( span) . ok ( ) ;
1582
+ let suggest_existing = |err : & mut DiagnosticBuilder < ' _ > , sugg| {
1583
+ err. span_suggestion (
1584
+ span,
1585
+ "consider using the named lifetime" ,
1586
+ sugg,
1587
+ Applicability :: MaybeIncorrect ,
1588
+ ) ;
1589
+ } ;
1590
+ let suggest_new = |err : & mut DiagnosticBuilder < ' _ > , sugg : & str | {
1591
+ err. span_label ( span, "expected named lifetime parameter" ) ;
1592
+
1593
+ for missing in self . missing_named_lifetime_spots . iter ( ) . rev ( ) {
1594
+ let mut introduce_suggestion = vec ! [ ] ;
1595
+ let msg;
1596
+ let should_break;
1597
+ introduce_suggestion. push ( match missing {
1598
+ MissingLifetimeSpot :: Generics ( generics) => {
1599
+ msg = "consider introducing a named lifetime parameter" . to_string ( ) ;
1600
+ should_break = true ;
1601
+ match & generics. params {
1602
+ [ ] => ( generics. span , "<'a>" . to_string ( ) ) ,
1603
+ [ param, ..] => ( param. span . shrink_to_lo ( ) , "'a, " . to_string ( ) ) ,
1604
+ }
1498
1605
}
1499
- }
1500
- MissingLifetimeSpot :: HigherRanked { span, span_type } => {
1501
- msg = format ! (
1502
- "consider making the {} lifetime-generic with a new `'a` lifetime" ,
1503
- span_type. descr( ) ,
1504
- ) ;
1505
- should_break = false ;
1506
- err. note (
1507
- "for more information on higher-ranked polymorphism, visit \
1606
+ MissingLifetimeSpot :: HigherRanked { span, span_type } => {
1607
+ msg = format ! (
1608
+ "consider making the {} lifetime-generic with a new `'a` lifetime" ,
1609
+ span_type. descr( ) ,
1610
+ ) ;
1611
+ should_break = false ;
1612
+ err. note (
1613
+ "for more information on higher-ranked polymorphism, visit \
1508
1614
https://doc.rust-lang.org/nomicon/hrtb.html",
1509
- ) ;
1510
- ( * span, span_type. suggestion ( "'a" ) )
1511
- }
1512
- } ) ;
1513
- for param in params {
1514
- if let Ok ( snippet) = source_map. span_to_snippet ( param. span ) {
1515
- if snippet. starts_with ( "&" ) && !snippet. starts_with ( "&'" ) {
1516
- introduce_suggestion
1517
- . push ( ( param. span , format ! ( "&'a {}" , & snippet[ 1 ..] ) ) ) ;
1518
- } else if snippet. starts_with ( "&'_ " ) {
1519
- introduce_suggestion
1520
- . push ( ( param. span , format ! ( "&'a {}" , & snippet[ 4 ..] ) ) ) ;
1615
+ ) ;
1616
+ ( * span, span_type. suggestion ( "'a" ) )
1617
+ }
1618
+ } ) ;
1619
+ for param in params {
1620
+ if let Ok ( snippet) = self . tcx . sess . source_map ( ) . span_to_snippet ( param. span )
1621
+ {
1622
+ if snippet. starts_with ( "&" ) && !snippet. starts_with ( "&'" ) {
1623
+ introduce_suggestion
1624
+ . push ( ( param. span , format ! ( "&'a {}" , & snippet[ 1 ..] ) ) ) ;
1625
+ } else if snippet. starts_with ( "&'_ " ) {
1626
+ introduce_suggestion
1627
+ . push ( ( param. span , format ! ( "&'a {}" , & snippet[ 4 ..] ) ) ) ;
1628
+ }
1521
1629
}
1522
1630
}
1631
+ introduce_suggestion. push ( ( span, sugg. to_string ( ) ) ) ;
1632
+ err. multipart_suggestion (
1633
+ & msg,
1634
+ introduce_suggestion,
1635
+ Applicability :: MaybeIncorrect ,
1636
+ ) ;
1637
+ if should_break {
1638
+ break ;
1639
+ }
1523
1640
}
1524
- introduce_suggestion. push ( ( span, sugg. to_string ( ) ) ) ;
1525
- err. multipart_suggestion ( & msg, introduce_suggestion, Applicability :: MaybeIncorrect ) ;
1526
- if should_break {
1527
- break ;
1528
- }
1529
- }
1530
- } ;
1641
+ } ;
1531
1642
1532
- match ( lifetime_names. len ( ) , lifetime_names. iter ( ) . next ( ) , snippet) {
1533
- ( 1 , Some ( name) , Some ( "&" ) ) => {
1534
- suggest_existing ( err, format ! ( "&{} " , name) ) ;
1535
- }
1536
- ( 1 , Some ( name) , Some ( "'_" ) ) => {
1537
- suggest_existing ( err, name. to_string ( ) ) ;
1538
- }
1539
- ( 1 , Some ( name) , Some ( snippet) ) if !snippet. ends_with ( ">" ) => {
1540
- suggest_existing ( err, format ! ( "{}<{}>" , snippet, name) ) ;
1541
- }
1542
- ( 0 , _, Some ( "&" ) ) => {
1543
- suggest_new ( err, "&'a " ) ;
1544
- }
1545
- ( 0 , _, Some ( "'_" ) ) => {
1546
- suggest_new ( err, "'a" ) ;
1547
- }
1548
- ( 0 , _, Some ( snippet) ) if !snippet. ends_with ( ">" ) => {
1549
- suggest_new ( err, & format ! ( "{}<'a>" , snippet) ) ;
1550
- }
1551
- _ => {
1552
- err. span_label ( span, "expected lifetime parameter" ) ;
1643
+ match (
1644
+ lifetime_names. len ( ) ,
1645
+ lifetime_names. iter ( ) . next ( ) ,
1646
+ snippet. as_ref ( ) . map ( |s| s. as_str ( ) ) ,
1647
+ ) {
1648
+ ( 1 , Some ( name) , Some ( "&" ) ) => {
1649
+ suggest_existing ( err, format ! ( "&{} " , name) ) ;
1650
+ }
1651
+ ( 1 , Some ( name) , Some ( "'_" ) ) => {
1652
+ suggest_existing ( err, name. to_string ( ) ) ;
1653
+ }
1654
+ ( 1 , Some ( name) , Some ( snippet) ) if !snippet. ends_with ( ">" ) => {
1655
+ suggest_existing ( err, format ! ( "{}<{}>" , snippet, name) ) ;
1656
+ }
1657
+ ( 0 , _, Some ( "&" ) ) => {
1658
+ suggest_new ( err, "&'a " ) ;
1659
+ }
1660
+ ( 0 , _, Some ( "'_" ) ) => {
1661
+ suggest_new ( err, "'a" ) ;
1662
+ }
1663
+ ( 0 , _, Some ( snippet) ) if !snippet. ends_with ( ">" ) => {
1664
+ suggest_new ( err, & format ! ( "{}<'a>" , snippet) ) ;
1665
+ }
1666
+ _ => {
1667
+ err. span_label ( span, "expected lifetime parameter" ) ;
1668
+ }
1553
1669
}
1554
1670
}
1555
1671
}
0 commit comments